Merge remote-tracking branch 'origin/release-candidate' into release-0.71.0

pull/12447/head
Diego Sampaio 8 years ago
commit a5b58a978e
No known key found for this signature in database
GPG Key ID: E060152B30502562
  1. 14
      .circleci/config.yml
  2. 2
      .docker/Dockerfile.rhel
  3. 3
      .eslintrc
  4. 469
      .github/history.json
  5. 1
      .meteor/packages
  6. 2
      .sandstorm/sandstorm-pkgdef.capnp
  7. 2
      .travis/snap.sh
  8. 146
      HISTORY.md
  9. 20
      README.md
  10. 4
      client/notifications/notification.js
  11. 2
      client/startup/unread.js
  12. 528
      package-lock.json
  13. 6
      package.json
  14. 2
      packages/rocketchat-api/package.js
  15. 11
      packages/rocketchat-api/server/api.js
  16. 6
      packages/rocketchat-api/server/helpers/composeRoomWithLastMessage.js
  17. 55
      packages/rocketchat-api/server/v1/channels.js
  18. 17
      packages/rocketchat-api/server/v1/chat.js
  19. 26
      packages/rocketchat-api/server/v1/groups.js
  20. 8
      packages/rocketchat-api/server/v1/im.js
  21. 5
      packages/rocketchat-api/server/v1/rooms.js
  22. 28
      packages/rocketchat-api/server/v1/users.js
  23. 3
      packages/rocketchat-apps/server/bridges/api.js
  24. 6
      packages/rocketchat-apps/server/bridges/bridges.js
  25. 2
      packages/rocketchat-apps/server/bridges/index.js
  26. 19
      packages/rocketchat-apps/server/bridges/internal.js
  27. 23
      packages/rocketchat-apps/server/bridges/rooms.js
  28. 6
      packages/rocketchat-apps/server/converters/messages.js
  29. 8
      packages/rocketchat-blockstack/client/main.js
  30. 3
      packages/rocketchat-blockstack/client/routes.js
  31. 13
      packages/rocketchat-channel-settings/client/views/channelSettings.js
  32. 2
      packages/rocketchat-e2e/client/rocketchat.e2e.room.js
  33. 4
      packages/rocketchat-emoji-emojione/rocketchat.js
  34. 2
      packages/rocketchat-emoji/client/emojiButton.js
  35. 4
      packages/rocketchat-emoji/client/emojiParser.js
  36. 47
      packages/rocketchat-file-upload/server/lib/FileUpload.js
  37. 11
      packages/rocketchat-file-upload/server/methods/sendFileMessage.js
  38. 2
      packages/rocketchat-grant/server/authenticate.js
  39. 41
      packages/rocketchat-graphql/server/resolvers/channels/deleteChannel.js
  40. 3
      packages/rocketchat-graphql/server/resolvers/channels/index.js
  41. 3
      packages/rocketchat-graphql/server/schemas/channels/deleteChannel.graphqls
  42. 2
      packages/rocketchat-highlight-words/client/client.js
  43. 2
      packages/rocketchat-iframe-login/iframe_server.js
  44. 1
      packages/rocketchat-importer-hipchat-enterprise/server/importer.js
  45. 7
      packages/rocketchat-importer-slack/server/importer.js
  46. 4
      packages/rocketchat-importer/server/classes/ImporterBase.js
  47. 12
      packages/rocketchat-ldap/server/loginHandler.js
  48. 2
      packages/rocketchat-lib/package.js
  49. 2
      packages/rocketchat-lib/rocketchat.info
  50. 20
      packages/rocketchat-lib/server/functions/composeMessageObjectWithUser.js
  51. 2
      packages/rocketchat-lib/server/functions/deleteMessage.js
  52. 1
      packages/rocketchat-lib/server/functions/isTheLastMessage.js
  53. 23
      packages/rocketchat-lib/server/functions/loadMessageHistory.js
  54. 76
      packages/rocketchat-lib/server/functions/saveUser.js
  55. 4
      packages/rocketchat-lib/server/functions/settings.js
  56. 17
      packages/rocketchat-lib/server/methods/getChannelHistory.js
  57. 4
      packages/rocketchat-lib/server/models/Rooms.js
  58. 2
      packages/rocketchat-lib/server/startup/settings.js
  59. 5
      packages/rocketchat-livechat/.app/client/lib/_livechat.js
  60. 4
      packages/rocketchat-livechat/.app/i18n/pt-BR.i18n.json
  61. 2
      packages/rocketchat-livechat/client/lib/dateHandler.js
  62. 2
      packages/rocketchat-livechat/server/api/v1/config.js
  63. 7
      packages/rocketchat-livechat/server/lib/Livechat.js
  64. 8
      packages/rocketchat-livechat/server/methods/closeByVisitor.js
  65. 8
      packages/rocketchat-livechat/server/methods/closeRoom.js
  66. 12
      packages/rocketchat-livechat/server/models/LivechatDepartment.js
  67. 1
      packages/rocketchat-mailer/package.js
  68. 6
      packages/rocketchat-mailer/server/api.js
  69. 22
      packages/rocketchat-message-attachments/client/messageAttachment.html
  70. 10
      packages/rocketchat-message-attachments/client/messageAttachment.js
  71. 10
      packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.css
  72. 1
      packages/rocketchat-message-pin/package.js
  73. 13
      packages/rocketchat-message-pin/server/models/Rooms.js
  74. 9
      packages/rocketchat-message-pin/server/pinMessage.js
  75. 1
      packages/rocketchat-message-snippet/package.js
  76. 4
      packages/rocketchat-message-snippet/server/methods/snippetMessage.js
  77. 17
      packages/rocketchat-message-snippet/server/models/Rooms.js
  78. 5
      packages/rocketchat-message-star/client/actionButton.js
  79. 1
      packages/rocketchat-message-star/package.js
  80. 21
      packages/rocketchat-message-star/server/models/Rooms.js
  81. 4
      packages/rocketchat-message-star/server/starMessage.js
  82. 3
      packages/rocketchat-oembed/client/oembedAudioWidget.js
  83. 3
      packages/rocketchat-oembed/client/oembedFrameWidget.js
  84. 9
      packages/rocketchat-oembed/client/oembedImageWidget.js
  85. 3
      packages/rocketchat-oembed/client/oembedUrlWidget.js
  86. 3
      packages/rocketchat-oembed/client/oembedVideoWidget.js
  87. 10
      packages/rocketchat-push-notifications/client/views/pushNotificationsFlexTab.js
  88. 1
      packages/rocketchat-reactions/package.js
  89. 7
      packages/rocketchat-reactions/server/models/Rooms.js
  90. 10
      packages/rocketchat-reactions/setReaction.js
  91. 17
      packages/rocketchat-theme/client/imports/components/sidebar/sidebar-header.css
  92. 23
      packages/rocketchat-ui-account/client/accountPreferences.js
  93. 2
      packages/rocketchat-ui-account/client/avatar/prompt.js
  94. 2
      packages/rocketchat-ui-admin/client/admin.js
  95. 41
      packages/rocketchat-ui-message/client/message.js
  96. 2
      packages/rocketchat-ui-message/client/messageBox.js
  97. 2
      packages/rocketchat-ui-message/package.js
  98. 11
      packages/rocketchat-ui-sidenav/client/roomList.js
  99. 2
      packages/rocketchat-ui-sidenav/client/sideNav.js
  100. 10
      packages/rocketchat-ui-sidenav/client/sortlist.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -80,6 +80,8 @@ jobs:
- run:
name: Build Rocket.Chat
environment:
TOOL_NODE_FLAGS: --max_old_space_size=4096
command: |
if [[ $CIRCLE_TAG ]]; then meteor reset; fi
set +e
@ -139,7 +141,7 @@ jobs:
environment:
TEST_MODE: "true"
MONGO_URL: mongodb://localhost:27017/testwithoplog
MONGO_URL: mongodb://localhost:27017/rocketchat
MONGO_OPLOG_URL: mongodb://localhost:27017/local
steps:
@ -172,7 +174,7 @@ jobs:
- run:
name: Run Tests
command: |
for i in $(seq 1 5); do npm test && s=0 && break || s=$? && sleep 1; done; (exit $s)
for i in $(seq 1 5); do mongo rocketchat --eval 'db.dropDatabase()' && npm test && s=0 && break || s=$? && sleep 1; done; (exit $s)
- store_artifacts:
path: .screenshots/
@ -185,7 +187,7 @@ jobs:
environment:
TEST_MODE: "true"
MONGO_URL: mongodb://localhost:27017/testwithoplog
MONGO_URL: mongodb://localhost:27017/rocketchat
steps:
- attach_workspace:
@ -197,9 +199,11 @@ jobs:
name: Install dependencies
command: |
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
echo "deb [ arch=amd64 ] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google.list
echo "deb [ arch=amd64 ] http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list
sudo apt-get update
sudo apt-get install -y google-chrome-stable
sudo apt-get install -y mongodb-org-shell google-chrome-stable
- run:
name: NPM install
@ -209,7 +213,7 @@ jobs:
- run:
name: Run Tests
command: |
for i in $(seq 1 5); do npm test && s=0 && break || s=$? && sleep 1; done; (exit $s)
for i in $(seq 1 5); do mongo rocketchat --eval 'db.dropDatabase()' && npm test && s=0 && break || s=$? && sleep 1; done; (exit $s)
- store_artifacts:
path: .screenshots/

@ -1,6 +1,6 @@
FROM registry.access.redhat.com/rhscl/nodejs-8-rhel7
ENV RC_VERSION 0.70.4
ENV RC_VERSION 0.71.0-rc.2
MAINTAINER buildmaster@rocket.chat

@ -1,5 +1,6 @@
{
"extends": ["@rocket.chat/eslint-config"],
"parser": "babel-eslint",
"globals": {
"__meteor_runtime_config__" : false,
"AccountBox" : false,
@ -30,7 +31,7 @@
"LivechatDepartment" : false,
"LivechatDepartmentAgents" : false,
"livechatManagerRoutes" : true,
"LivechatMonitoring" : false,
"LivechatMonitoring" : false,
"LivechatPageVisited" : false,
"LivechatTrigger" : false,
"Logger" : false,

@ -19834,9 +19834,31 @@
]
},
"0.70.2": {
"node_version": "8.11.3",
"npm_version": "5.6.0",
"pull_requests": []
},
"0.70.3": {
"node_version": "8.11.3",
"npm_version": "5.6.0",
"pull_requests": [
{
"pr": "12281",
"title": "Release 0.70.3",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12276",
"title": "Release 0.70.2",
"userLogin": "sampaiodiego",
"contributors": [
"Hudell",
"sampaiodiego"
]
},
{
"pr": "12272",
"title": "[FIX] E2E alert shows up when encryption is disabled",
@ -19848,16 +19870,334 @@
}
]
},
"0.70.3": {
"0.70.4": {
"node_version": "8.11.3",
"npm_version": "5.6.0",
"pull_requests": [
{
"pr": "12276",
"title": "Release 0.70.2",
"pr": "12299",
"title": "Release 0.70.4",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12283",
"title": "[FIX] Modal confirm on enter",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12298",
"title": "Fix: Add wizard opt-in fields",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
}
]
},
"0.71.0-rc.0": {
"node_version": "8.11.3",
"npm_version": "5.6.0",
"pull_requests": [
{
"pr": "11521",
"title": "[FIX] Add image dimensions to attachment even when no reorientation is required",
"userLogin": "tassoevan",
"contributors": [
"tassoevan",
"sampaiodiego",
"web-flow"
]
},
{
"pr": "12158",
"title": "[FIX] iframe login token not checked",
"userLogin": "nimetu",
"contributors": [
"nimetu",
"web-flow"
]
},
{
"pr": "11431",
"title": "[FIX] REST `users.setAvatar` endpoint wasn't allowing update the avatar of other users even with correct permissions",
"userLogin": "MarcosSpessatto",
"milestone": "0.71.0",
"contributors": [
"MarcosSpessatto",
"sampaiodiego"
]
},
{
"pr": "11875",
"title": "[FIX] Slack importer: image previews not showing",
"userLogin": "madguy02",
"milestone": "0.71.0",
"contributors": [
"madguy02",
"Hudell",
"web-flow",
"sampaiodiego"
]
},
{
"pr": "12235",
"title": "[FIX] Edit room name with uppercase letters",
"userLogin": "nikeee",
"milestone": "0.71.0",
"contributors": [
"nikeee",
"web-flow"
]
},
{
"pr": "12256",
"title": "[FIX] Custom OAuth Configuration can't be removed",
"userLogin": "Hudell",
"milestone": "0.71.0",
"contributors": [
"Hudell"
]
},
{
"pr": "12360",
"title": "[IMPROVE] Livechat room closure endpoints",
"userLogin": "renatobecker",
"milestone": "0.71.0",
"contributors": [
"renatobecker"
]
},
{
"pr": "12266",
"title": "[BREAK] Update `lastMessage` rooms property and convert the \"starred\" property, to the same format",
"userLogin": "MarcosSpessatto",
"milestone": "0.71.0",
"contributors": [
"MarcosSpessatto",
"sampaiodiego",
"web-flow"
]
},
{
"pr": "12384",
"title": "Fix: wrong saveUser permission validations",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "11860",
"title": "[NEW] Add delete channel mutation to GraphQL API",
"userLogin": "MarcosSpessatto",
"milestone": "0.71.0",
"contributors": [
"MarcosSpessatto"
]
},
{
"pr": "12344",
"title": "[FIX] Remove e2e from users endpoint responses",
"userLogin": "MarcosSpessatto",
"contributors": [
"MarcosSpessatto",
"sampaiodiego",
"web-flow"
]
},
{
"pr": "12372",
"title": "[NEW] sidenav size on large screens",
"userLogin": "ggazzo",
"milestone": "0.71.0",
"contributors": [
"ggazzo",
"tassoevan",
"web-flow"
]
},
{
"pr": "12375",
"title": "Regression: do not render pdf preview on safari <= 12",
"userLogin": "ggazzo",
"milestone": "0.71.0",
"contributors": [
"ggazzo",
"web-flow"
]
},
{
"pr": "12373",
"title": "[FIX] email api TAPi18n is undefined",
"userLogin": "ggazzo",
"contributors": [
"ggazzo"
]
},
{
"pr": "12338",
"title": "[FIX] Blockstack errors in IE 11",
"userLogin": "tassoevan",
"milestone": "0.71.0",
"contributors": [
"tassoevan",
"sampaiodiego"
]
},
{
"pr": "12365",
"title": "[FIX] avatar?_dc=undefined",
"userLogin": "geekgonecrazy",
"contributors": [
"geekgonecrazy",
"web-flow"
]
},
{
"pr": "12186",
"title": "[BREAK] Add expiration to API login tokens and fix duplicate login tokens created by LDAP",
"userLogin": "MarcosSpessatto",
"milestone": "0.71.0",
"contributors": [
"MarcosSpessatto"
]
},
{
"pr": "12358",
"title": "Improve: Drop database between running tests on CI",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12161",
"title": "[IMPROVE] Set Livechat department before register guest",
"userLogin": "renatobecker",
"milestone": "0.71.0",
"contributors": [
"renatobecker"
]
},
{
"pr": "12330",
"title": "[IMPROVE] Add missing livechat i18n keys",
"userLogin": "MarcosEllys",
"contributors": [
"MarcosEllys",
"web-flow"
]
},
{
"pr": "12297",
"title": "[FIX] users.register endpoint to not create an user if username already being used",
"userLogin": "MarcosSpessatto",
"milestone": "0.71.0",
"contributors": [
"MarcosSpessatto"
]
},
{
"pr": "12345",
"title": "[FIX] Date range check on livechat analytics",
"userLogin": "teresy",
"contributors": [
"teresy"
]
},
{
"pr": "12194",
"title": "[FIX] Cast env var setting to int based on option type",
"userLogin": "crazy-max",
"milestone": "0.71.0",
"contributors": [
"crazy-max"
]
},
{
"pr": "12355",
"title": "[FIX] Links in home layout",
"userLogin": "upiksaleh",
"contributors": [
"upiksaleh"
]
},
{
"pr": "11212",
"title": "[IMPROVE] Avoid unnecessary calls to Meteor.user() on client",
"userLogin": "ggazzo",
"contributors": [
"ggazzo",
"web-flow",
"tassoevan"
]
},
{
"pr": "12346",
"title": "Fix: update check on err.details",
"userLogin": "teresy",
"milestone": "0.71.0",
"contributors": [
"teresy"
]
},
{
"pr": "12350",
"title": "[FIX] Last message not updating after message delete if show deleted status is on",
"userLogin": "sampaiodiego",
"milestone": "0.71.0",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12353",
"title": "[NEW] Ability to disable user presence monitor",
"userLogin": "sampaiodiego",
"milestone": "0.71.0",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12354",
"title": "[FIX] Invalid destructuring on Livechat API endpoint",
"userLogin": "renatobecker",
"milestone": "0.71.0",
"contributors": [
"renatobecker"
]
},
{
"pr": "10519",
"title": "[NEW] PDF message attachment preview (client side rendering)",
"userLogin": "kb0304",
"milestone": "0.71.0",
"contributors": [
"kb0304",
"ggazzo",
"web-flow"
]
},
{
"pr": "12298",
"title": "Fix: Add wizard opt-in fields",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12283",
"title": "[FIX] Modal confirm on enter",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
@ -19869,30 +20209,139 @@
"contributors": [
"Hudell"
]
},
{
"pr": "12299",
"title": "Release 0.70.4",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "12276",
"title": "Release 0.70.2",
"userLogin": "sampaiodiego",
"contributors": [
"Hudell",
"sampaiodiego"
]
}
]
},
"0.70.4": {
"0.71.0-rc.1": {
"node_version": "8.11.3",
"npm_version": "5.6.0",
"pull_requests": [
{
"pr": "12283",
"title": "[FIX] Modal confirm on enter",
"userLogin": "sampaiodiego",
"pr": "12398",
"title": "[FIX] E2E: Decrypting UTF-8 encoded messages",
"userLogin": "pmmaga",
"milestone": "0.71.0",
"contributors": [
"pmmaga",
"web-flow"
]
},
{
"pr": "12442",
"title": "Update Apps Framework to version 1.2.1",
"userLogin": "rodrigok",
"milestone": "0.71.0",
"contributors": [
"rodrigok"
]
},
{
"pr": "12424",
"title": "[FIX] Ignore errors when creating image preview for uploads",
"userLogin": "tassoevan",
"milestone": "0.71.0",
"contributors": [
"tassoevan",
"web-flow"
]
},
{
"pr": "12405",
"title": "Regression: Change `starred` message property from object to array",
"userLogin": "MarcosSpessatto",
"milestone": "0.71.0",
"contributors": [
"MarcosSpessatto",
"sampaiodiego"
]
},
{
"pr": "12298",
"title": "Fix: Add wizard opt-in fields",
"pr": "12425",
"title": "[IMPROVE] Allow the imports to accept any file type",
"userLogin": "graywolf336",
"milestone": "0.71.0",
"contributors": [
"graywolf336"
]
},
{
"pr": "12409",
"title": "Apps: Room’s usernames was not working",
"userLogin": "rodrigok",
"milestone": "0.71.0",
"contributors": [
"rodrigok"
]
},
{
"pr": "12436",
"title": "[FIX] Attachment actions not being collapsable",
"userLogin": "graywolf336",
"milestone": "0.71.0",
"contributors": [
"graywolf336"
]
},
{
"pr": "12432",
"title": "[NEW] Add \"help wanted\" section to Readme",
"userLogin": "isabellarussell",
"contributors": [
"isabellarussell",
"Sing-Li",
"web-flow"
]
},
{
"pr": "12392",
"title": "Regression: Fix email headers not being used",
"userLogin": "sampaiodiego",
"contributors": [
"sampaiodiego"
]
}
]
},
"0.71.0-rc.2": {
"node_version": "8.11.3",
"npm_version": "5.6.0",
"pull_requests": [
{
"pr": "12445",
"title": "[FIX] Attachment timestamp from and to Apps system not working",
"userLogin": "graywolf336",
"milestone": "0.71.0",
"contributors": [
"graywolf336"
]
},
{
"pr": "12391",
"title": "[FIX] Apps not being able to state how the action buttons are aligned",
"userLogin": "graywolf336",
"milestone": "0.71.0",
"contributors": [
"graywolf336"
]
}
]
}
}
}
}

@ -195,7 +195,6 @@ rocketchat:e2e
rocketchat:blockstack
rocketchat:version-check
rocketchat:search
chatpal:search
rocketchat:lazy-load

@ -21,7 +21,7 @@ const pkgdef :Spk.PackageDefinition = (
appVersion = 110, # Increment this for every release.
appMarketingVersion = (defaultText = "0.70.4"),
appMarketingVersion = (defaultText = "0.71.0-rc.2"),
# Human-readable representation of appVersion. Should match the way you
# identify versions of your app in documentation and marketing.

@ -17,7 +17,7 @@ elif [[ $TRAVIS_TAG ]]; then
RC_VERSION=$TRAVIS_TAG
else
CHANNEL=edge
RC_VERSION=0.70.4
RC_VERSION=0.71.0-rc.2
fi
echo "Preparing to trigger a snap release for $CHANNEL channel"

@ -1,47 +1,156 @@
# 0.70.4
`2018-10-09 · 1 🐛 · 1 🔍 · 1 👩💻👨💻`
# 0.71.0 (Under Release Candidate Process)
### Engine versions
- Node: `8.11.3`
- NPM: `5.6.0`
## 0.71.0-rc.2
`2018-10-27 · 2 🐛 · 1 👩💻👨💻`
### 🐛 Bug fixes
- Modal confirm on enter ([#12283](https://github.com/RocketChat/Rocket.Chat/pull/12283))
- Attachment timestamp from and to Apps system not working ([#12445](https://github.com/RocketChat/Rocket.Chat/pull/12445))
- Apps not being able to state how the action buttons are aligned ([#12391](https://github.com/RocketChat/Rocket.Chat/pull/12391))
### 👩💻👨💻 Core Team 🤓
- [@graywolf336](https://github.com/graywolf336)
## 0.71.0-rc.1
`2018-10-26 · 1 🎉 · 1 🚀 · 3 🐛 · 4 🔍 · 8 👩💻👨💻`
### 🎉 New features
- Add "help wanted" section to Readme ([#12432](https://github.com/RocketChat/Rocket.Chat/pull/12432))
### 🚀 Improvements
- Allow the imports to accept any file type ([#12425](https://github.com/RocketChat/Rocket.Chat/pull/12425))
### 🐛 Bug fixes
- E2E: Decrypting UTF-8 encoded messages ([#12398](https://github.com/RocketChat/Rocket.Chat/pull/12398) by [@pmmaga](https://github.com/pmmaga))
- Ignore errors when creating image preview for uploads ([#12424](https://github.com/RocketChat/Rocket.Chat/pull/12424))
- Attachment actions not being collapsable ([#12436](https://github.com/RocketChat/Rocket.Chat/pull/12436))
<details>
<summary>🔍 Minor changes</summary>
- Fix: Add wizard opt-in fields ([#12298](https://github.com/RocketChat/Rocket.Chat/pull/12298))
- Update Apps Framework to version 1.2.1 ([#12442](https://github.com/RocketChat/Rocket.Chat/pull/12442))
- Regression: Change `starred` message property from object to array ([#12405](https://github.com/RocketChat/Rocket.Chat/pull/12405))
- Apps: Room’s usernames was not working ([#12409](https://github.com/RocketChat/Rocket.Chat/pull/12409))
- Regression: Fix email headers not being used ([#12392](https://github.com/RocketChat/Rocket.Chat/pull/12392))
</details>
### 👩💻👨💻 Contributors 😍
- [@pmmaga](https://github.com/pmmaga)
### 👩💻👨💻 Core Team 🤓
- [@MarcosSpessatto](https://github.com/MarcosSpessatto)
- [@Sing-Li](https://github.com/Sing-Li)
- [@graywolf336](https://github.com/graywolf336)
- [@isabellarussell](https://github.com/isabellarussell)
- [@rodrigok](https://github.com/rodrigok)
- [@sampaiodiego](https://github.com/sampaiodiego)
- [@tassoevan](https://github.com/tassoevan)
# 0.70.3
`2018-10-08 · 1 🔍 · 2 👩💻👨💻`
## 0.71.0-rc.0
`2018-10-20 · 2 · 4 🎉 · 4 🚀 · 16 🐛 · 4 🔍 · 15 👩💻👨💻`
### ⚠ BREAKING CHANGES
- Update `lastMessage` rooms property and convert the "starred" property, to the same format ([#12266](https://github.com/RocketChat/Rocket.Chat/pull/12266))
- Add expiration to API login tokens and fix duplicate login tokens created by LDAP ([#12186](https://github.com/RocketChat/Rocket.Chat/pull/12186))
### 🎉 New features
- Add delete channel mutation to GraphQL API ([#11860](https://github.com/RocketChat/Rocket.Chat/pull/11860))
- sidenav size on large screens ([#12372](https://github.com/RocketChat/Rocket.Chat/pull/12372))
- Ability to disable user presence monitor ([#12353](https://github.com/RocketChat/Rocket.Chat/pull/12353))
- PDF message attachment preview (client side rendering) ([#10519](https://github.com/RocketChat/Rocket.Chat/pull/10519) by [@kb0304](https://github.com/kb0304))
### 🚀 Improvements
- Livechat room closure endpoints ([#12360](https://github.com/RocketChat/Rocket.Chat/pull/12360))
- Set Livechat department before register guest ([#12161](https://github.com/RocketChat/Rocket.Chat/pull/12161))
- Add missing livechat i18n keys ([#12330](https://github.com/RocketChat/Rocket.Chat/pull/12330) by [@MarcosEllys](https://github.com/MarcosEllys))
- Avoid unnecessary calls to Meteor.user() on client ([#11212](https://github.com/RocketChat/Rocket.Chat/pull/11212))
### 🐛 Bug fixes
- Add image dimensions to attachment even when no reorientation is required ([#11521](https://github.com/RocketChat/Rocket.Chat/pull/11521))
- iframe login token not checked ([#12158](https://github.com/RocketChat/Rocket.Chat/pull/12158) by [@nimetu](https://github.com/nimetu))
- REST `users.setAvatar` endpoint wasn't allowing update the avatar of other users even with correct permissions ([#11431](https://github.com/RocketChat/Rocket.Chat/pull/11431))
- Slack importer: image previews not showing ([#11875](https://github.com/RocketChat/Rocket.Chat/pull/11875) by [@madguy02](https://github.com/madguy02))
- Edit room name with uppercase letters ([#12235](https://github.com/RocketChat/Rocket.Chat/pull/12235) by [@nikeee](https://github.com/nikeee))
- Custom OAuth Configuration can't be removed ([#12256](https://github.com/RocketChat/Rocket.Chat/pull/12256))
- Remove e2e from users endpoint responses ([#12344](https://github.com/RocketChat/Rocket.Chat/pull/12344))
- email api TAPi18n is undefined ([#12373](https://github.com/RocketChat/Rocket.Chat/pull/12373))
- Blockstack errors in IE 11 ([#12338](https://github.com/RocketChat/Rocket.Chat/pull/12338))
- avatar?_dc=undefined ([#12365](https://github.com/RocketChat/Rocket.Chat/pull/12365))
- users.register endpoint to not create an user if username already being used ([#12297](https://github.com/RocketChat/Rocket.Chat/pull/12297))
- Date range check on livechat analytics ([#12345](https://github.com/RocketChat/Rocket.Chat/pull/12345) by [@teresy](https://github.com/teresy))
- Cast env var setting to int based on option type ([#12194](https://github.com/RocketChat/Rocket.Chat/pull/12194) by [@crazy-max](https://github.com/crazy-max))
- Links in home layout ([#12355](https://github.com/RocketChat/Rocket.Chat/pull/12355) by [@upiksaleh](https://github.com/upiksaleh))
- Last message not updating after message delete if show deleted status is on ([#12350](https://github.com/RocketChat/Rocket.Chat/pull/12350))
- Invalid destructuring on Livechat API endpoint ([#12354](https://github.com/RocketChat/Rocket.Chat/pull/12354))
<details>
<summary>🔍 Minor changes</summary>
- Fix: wrong saveUser permission validations ([#12384](https://github.com/RocketChat/Rocket.Chat/pull/12384))
- Regression: do not render pdf preview on safari <= 12 ([#12375](https://github.com/RocketChat/Rocket.Chat/pull/12375))
- Improve: Drop database between running tests on CI ([#12358](https://github.com/RocketChat/Rocket.Chat/pull/12358))
- Fix: update check on err.details ([#12346](https://github.com/RocketChat/Rocket.Chat/pull/12346) by [@teresy](https://github.com/teresy))
</details>
### 👩💻👨💻 Contributors 😍
- [@MarcosEllys](https://github.com/MarcosEllys)
- [@crazy-max](https://github.com/crazy-max)
- [@kb0304](https://github.com/kb0304)
- [@madguy02](https://github.com/madguy02)
- [@nikeee](https://github.com/nikeee)
- [@nimetu](https://github.com/nimetu)
- [@teresy](https://github.com/teresy)
- [@upiksaleh](https://github.com/upiksaleh)
### 👩💻👨💻 Core Team 🤓
- [@Hudell](https://github.com/Hudell)
- [@MarcosSpessatto](https://github.com/MarcosSpessatto)
- [@geekgonecrazy](https://github.com/geekgonecrazy)
- [@ggazzo](https://github.com/ggazzo)
- [@renatobecker](https://github.com/renatobecker)
- [@sampaiodiego](https://github.com/sampaiodiego)
- [@tassoevan](https://github.com/tassoevan)
# 0.70.4
`2018-10-09 · 1 🐛 · 2 🔍 · 1 👩💻👨💻`
### Engine versions
- Node: `8.11.3`
- NPM: `5.6.0`
### 🐛 Bug fixes
- Modal confirm on enter ([#12283](https://github.com/RocketChat/Rocket.Chat/pull/12283))
<details>
<summary>🔍 Minor changes</summary>
- Release 0.70.2 ([#12276](https://github.com/RocketChat/Rocket.Chat/pull/12276))
- Release 0.70.4 ([#12299](https://github.com/RocketChat/Rocket.Chat/pull/12299))
- Fix: Add wizard opt-in fields ([#12298](https://github.com/RocketChat/Rocket.Chat/pull/12298))
</details>
### 👩💻👨💻 Core Team 🤓
- [@Hudell](https://github.com/Hudell)
- [@sampaiodiego](https://github.com/sampaiodiego)
# 0.70.2
`2018-10-05 · 1 🐛 · 1 👩💻👨💻`
# 0.70.3
`2018-10-08 · 1 🐛 · 2 🔍 · 2 👩💻👨💻`
### Engine versions
- Node: `8.11.3`
@ -51,9 +160,18 @@
- E2E alert shows up when encryption is disabled ([#12272](https://github.com/RocketChat/Rocket.Chat/pull/12272))
<details>
<summary>🔍 Minor changes</summary>
- Release 0.70.3 ([#12281](https://github.com/RocketChat/Rocket.Chat/pull/12281))
- Release 0.70.2 ([#12276](https://github.com/RocketChat/Rocket.Chat/pull/12276))
</details>
### 👩💻👨💻 Core Team 🤓
- [@Hudell](https://github.com/Hudell)
- [@sampaiodiego](https://github.com/sampaiodiego)
# 0.70.1
`2018-10-05 · 8 🐛 · 5 🔍 · 11 👩💻👨💻`
@ -3393,4 +3511,4 @@
- [@marceloschmidt](https://github.com/marceloschmidt)
- [@mrsimpson](https://github.com/mrsimpson)
- [@rodrigok](https://github.com/rodrigok)
- [@sampaiodiego](https://github.com/sampaiodiego)
- [@sampaiodiego](https://github.com/sampaiodiego)

@ -11,6 +11,7 @@
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/RocketChat/Rocket.Chat/raw/master/LICENSE)
* [**NEW!** Help Wanted](#help-wanted)
* [Community](#community)
* [Mobile Apps](#mobile-apps)
* [Desktop Apps](#desktop-apps)
@ -55,6 +56,21 @@
* [Credits](#credits)
* [Donate](#donate)
# Help Wanted
At Rocket.Chat, our community drives *everything* we do. The Rocket.Chat team is expanding, and we know no better place to find qualified new team members than *right here* - in our Github community.
If you are passionate about our project, want to work with a world-leading open source team, and enjoy working remotely at a location of your choice, then we want to talk to you!
Explore current openings below:
- [Lead Security Researcher and Developer](https://rocketchat.recruitee.com/o/lead-security-researcher-and-developer)
- [Sales Engineer](https://rocketchat.recruitee.com/o/sales-engineer)
- [Business Developer/Sales/Channel](https://rocketchat.recruitee.com/o/business-developer-sales-channel)
- [Front-End Developer](https://rocketchat.recruitee.com/o/frontend-developer)
# Community
Join thousands of members worldwide 24/7 in our [community server](https://open.rocket.chat).
@ -351,7 +367,7 @@ Read about [how it all started](https://blog.blackducksoftware.com/rocket-chat-e
## Feature Requests
[Feature Request Forums](https://forums.rocket.chat/c/feature-requests) are used to suggest, discuss and upvote feature suggestions.
[Feature Request Forums](https://forums.rocket.chat/c/feature-requests) are used to suggest, discuss and upvote feature suggestions.
### Stack Overflow
@ -413,7 +429,7 @@ It is based on [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branchi
See also this [Git Workflows Comparison](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for more details.
## Translations
We are experimenting [Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard).
We are experimenting [Lingohub](https://translate.lingohub.com/rocketchat/dashboard).
If you want to help, send an email to support at rocket.chat to be invited to the translation project.
## How to Contribute

@ -29,7 +29,7 @@ Meteor.startup(function() {
// This logic is duplicated in /client/startup/unread.coffee.
const hasFocus = readMessage.isEnable();
const messageIsInOpenedRoom = openedRoomId === notification.payload.rid;
const muteFocusedConversations = RocketChat.getUserPreference(Meteor.user(), 'muteFocusedConversations');
const muteFocusedConversations = RocketChat.getUserPreference(Meteor.userId(), 'muteFocusedConversations');
fireGlobalEvent('notification', {
notification,
@ -60,7 +60,7 @@ Meteor.startup(function() {
// This logic is duplicated in /client/startup/unread.coffee.
const hasFocus = readMessage.isEnable();
const messageIsInOpenedRoom = openedRoomId === notification.payload.rid;
const muteFocusedConversations = RocketChat.getUserPreference(Meteor.user(), 'muteFocusedConversations');
const muteFocusedConversations = RocketChat.getUserPreference(Meteor.userId(), 'muteFocusedConversations');
if (RocketChat.Layout.isEmbedded()) {
if (!hasFocus && messageIsInOpenedRoom) {

@ -32,7 +32,7 @@ Meteor.startup(function() {
// Increment the total unread count.
unreadCount += subscription.unread;
if (subscription.alert === true && subscription.unreadAlert !== 'nothing') {
const userUnreadAlert = RocketChat.getUserPreference(Meteor.user(), 'unreadAlert');
const userUnreadAlert = RocketChat.getUserPreference(Meteor.userId(), 'unreadAlert');
if (subscription.unreadAlert === 'all' || userUnreadAlert !== false) {
unreadAlert = '•';
}

528
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,7 +1,7 @@
{
"name": "Rocket.Chat",
"description": "The Ultimate Open Source WebChat Platform",
"version": "0.70.4",
"version": "0.71.0-rc.2",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
@ -91,6 +91,7 @@
"@octokit/rest": "^15.8.1",
"@rocket.chat/eslint-config": "^0.1.2",
"autoprefixer": "^8.6.0",
"babel-eslint": "^10.0.1",
"babel-mocha-es6-compiler": "^0.1.0",
"babel-plugin-array-includes": "^2.0.3",
"chimp": "^0.51.1",
@ -116,7 +117,7 @@
"@google-cloud/language": "^1.2.0",
"@google-cloud/storage": "^1.7.0",
"@google-cloud/vision": "^0.19.0",
"@rocket.chat/apps-engine": "1.1.1",
"@rocket.chat/apps-engine": "1.2.1",
"@slack/client": "^4.2.2",
"adm-zip": "^0.4.11",
"archiver": "^2.1.1",
@ -171,6 +172,7 @@
"moment-timezone": "^0.5.17",
"node-dogstatsd": "^0.0.7",
"object-path": "^0.11.4",
"pdfjs-dist": "^2.0.489",
"photoswipe": "^4.1.2",
"poplib": "^0.1.7",
"prom-client": "^11.0.0",

@ -16,6 +16,7 @@ Package.onUse(function(api) {
api.addFiles('server/settings.js', 'server');
// Register helpers
api.addFiles('server/helpers/composeRoomWithLastMessage.js', 'server');
api.addFiles('server/helpers/requestParams.js', 'server');
api.addFiles('server/helpers/getPaginationItems.js', 'server');
api.addFiles('server/helpers/getUserFromParams.js', 'server');
@ -47,4 +48,5 @@ Package.onUse(function(api) {
api.addFiles('server/v1/stats.js', 'server');
api.addFiles('server/v1/users.js', 'server');
api.addFiles('server/v1/assets.js', 'server');
api.addFiles('server/v1/e2e.js', 'server');
});

@ -11,6 +11,7 @@ class API extends Restivus {
joinCode: 0,
members: 0,
importIds: 0,
e2e: 0,
};
this.limitedUserFieldsToExclude = {
avatarOrigin: 0,
@ -261,16 +262,6 @@ class API extends Restivus {
this.userId = this.user._id;
// Remove tokenExpires to keep the old behavior
Meteor.users.update({
_id: this.user._id,
'services.resume.loginTokens.hashedToken': Accounts._hashLoginToken(auth.token),
}, {
$unset: {
'services.resume.loginTokens.$.when': 1,
},
});
const response = {
status: 'success',
data: {

@ -0,0 +1,6 @@
RocketChat.API.helperMethods.set('composeRoomWithLastMessage', function _composeRoomWithLastMessage(room, userId) {
if (room.lastMessage) {
room.lastMessage = RocketChat.composeMessageObjectWithUser(room.lastMessage, userId);
}
return room;
});

@ -1,7 +1,7 @@
import _ from 'underscore';
// Returns the channel IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
function findChannelByIdOrName({ params, checkedArchived = true }) {
function findChannelByIdOrName({ params, checkedArchived = true, userId }) {
if ((!params.roomId || !params.roomId.trim()) && (!params.roomName || !params.roomName.trim())) {
throw new Meteor.Error('error-roomid-param-not-provided', 'The parameter "roomId" or "roomName" is required');
}
@ -22,6 +22,9 @@ function findChannelByIdOrName({ params, checkedArchived = true }) {
if (checkedArchived && room.archived) {
throw new Meteor.Error('error-room-archived', `The channel, ${ room.name }, is archived`);
}
if (userId && room.lastMessage) {
room.lastMessage = RocketChat.composeMessageObjectWithUser(room.lastMessage, userId);
}
return room;
}
@ -35,7 +38,7 @@ RocketChat.API.v1.addRoute('channels.addAll', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -175,14 +178,10 @@ function createChannelValidator(params) {
function createChannel(userId, params) {
const readOnly = typeof params.readOnly !== 'undefined' ? params.readOnly : false;
let id;
Meteor.runAsUser(userId, () => {
id = Meteor.call('createChannel', params.name, params.members ? params.members : [], readOnly, params.customFields);
});
const id = Meteor.runAsUser(userId, () => Meteor.call('createChannel', params.name, params.members ? params.members : [], readOnly, params.customFields));
return {
channel: RocketChat.models.Rooms.findOneById(id.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: { roomId: id.rid }, userId: this.userId }),
};
}
@ -236,9 +235,7 @@ RocketChat.API.v1.addRoute('channels.delete', { authRequired: true }, {
Meteor.call('eraseRoom', findResult._id);
});
return RocketChat.API.v1.success({
channel: findResult,
});
return RocketChat.API.v1.success();
},
});
@ -367,10 +364,12 @@ RocketChat.API.v1.addRoute('channels.history', { authRequired: true }, {
RocketChat.API.v1.addRoute('channels.info', { authRequired: true }, {
get() {
const findResult = findChannelByIdOrName({ params: this.requestParams(), checkedArchived: false });
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({
params: this.requestParams(),
checkedArchived: false,
userId: this.userId,
}),
});
},
});
@ -386,7 +385,7 @@ RocketChat.API.v1.addRoute('channels.invite', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -400,7 +399,7 @@ RocketChat.API.v1.addRoute('channels.join', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -416,7 +415,7 @@ RocketChat.API.v1.addRoute('channels.kick', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -430,7 +429,7 @@ RocketChat.API.v1.addRoute('channels.leave', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -465,7 +464,7 @@ RocketChat.API.v1.addRoute('channels.list', { authRequired: true }, {
const rooms = cursor.fetch();
return RocketChat.API.v1.success({
channels: rooms,
channels: rooms.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
count: rooms.length,
offset,
total,
@ -491,7 +490,7 @@ RocketChat.API.v1.addRoute('channels.list.joined', { authRequired: true }, {
const rooms = cursor.fetch();
return RocketChat.API.v1.success({
channels: rooms,
channels: rooms.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
offset,
count: rooms.length,
total: totalCount,
@ -526,7 +525,7 @@ RocketChat.API.v1.addRoute('channels.members', { authRequired: true }, {
const users = RocketChat.models.Users.find({ _id: { $in: members } }, {
fields: { _id: 1, username: 1, name: 1, status: 1, utcOffset: 1 },
sort: { username: sort.username != null ? sort.username : 1 },
sort: { username: sort.username != null ? sort.username : 1 },
}).fetch();
return RocketChat.API.v1.success({
@ -568,7 +567,7 @@ RocketChat.API.v1.addRoute('channels.messages', { authRequired: true }, {
const messages = cursor.fetch();
return RocketChat.API.v1.success({
messages,
messages: messages.map((record) => RocketChat.composeMessageObjectWithUser(record, this.userId)),
count: messages.length,
offset,
total,
@ -703,7 +702,7 @@ RocketChat.API.v1.addRoute('channels.rename', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: { roomId: this.bodyParams.roomId }, userId: this.userId }),
});
},
});
@ -721,7 +720,7 @@ RocketChat.API.v1.addRoute('channels.setCustomFields', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -743,7 +742,7 @@ RocketChat.API.v1.addRoute('channels.setDefault', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -783,7 +782,7 @@ RocketChat.API.v1.addRoute('channels.setJoinCode', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -827,7 +826,7 @@ RocketChat.API.v1.addRoute('channels.setReadOnly', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: findChannelByIdOrName({ params: this.requestParams(), userId: this.userId }),
});
},
});
@ -889,7 +888,7 @@ RocketChat.API.v1.addRoute('channels.setType', { authRequired: true }, {
});
return RocketChat.API.v1.success({
channel: RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
channel: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult._id, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});

@ -58,7 +58,10 @@ RocketChat.API.v1.addRoute('chat.syncMessages', { authRequired: true }, {
}
return RocketChat.API.v1.success({
result,
result: {
updated: result.updated.map((message) => RocketChat.composeMessageObjectWithUser(message, this.userId)),
deleted: result.deleted.map((message) => RocketChat.composeMessageObjectWithUser(message, this.userId)),
},
});
},
});
@ -79,7 +82,7 @@ RocketChat.API.v1.addRoute('chat.getMessage', { authRequired: true }, {
}
return RocketChat.API.v1.success({
message: msg,
message: RocketChat.composeMessageObjectWithUser(msg, this.userId),
});
},
});
@ -100,7 +103,7 @@ RocketChat.API.v1.addRoute('chat.pinMessage', { authRequired: true }, {
Meteor.runAsUser(this.userId, () => pinnedMessage = Meteor.call('pinMessage', msg));
return RocketChat.API.v1.success({
message: pinnedMessage,
message: RocketChat.composeMessageObjectWithUser(pinnedMessage, this.userId),
});
},
});
@ -116,7 +119,7 @@ RocketChat.API.v1.addRoute('chat.postMessage', { authRequired: true }, {
return RocketChat.API.v1.success({
ts: Date.now(),
channel: messageReturn.channel,
message: messageReturn.message,
message: RocketChat.composeMessageObjectWithUser(messageReturn.message, this.userId),
});
},
});
@ -138,7 +141,7 @@ RocketChat.API.v1.addRoute('chat.search', { authRequired: true }, {
Meteor.runAsUser(this.userId, () => result = Meteor.call('messageSearch', searchText, roomId, count).message.docs);
return RocketChat.API.v1.success({
messages: result,
messages: result.map((message) => RocketChat.composeMessageObjectWithUser(message, this.userId)),
});
},
});
@ -156,7 +159,7 @@ RocketChat.API.v1.addRoute('chat.sendMessage', { authRequired: true }, {
Meteor.runAsUser(this.userId, () => message = Meteor.call('sendMessage', this.bodyParams.message));
return RocketChat.API.v1.success({
message,
message: RocketChat.composeMessageObjectWithUser(message, this.userId),
});
},
});
@ -248,7 +251,7 @@ RocketChat.API.v1.addRoute('chat.update', { authRequired: true }, {
});
return RocketChat.API.v1.success({
message: RocketChat.models.Messages.findOneById(msg._id),
message: RocketChat.composeMessageObjectWithUser(RocketChat.models.Messages.findOneById(msg._id), this.userId),
});
},
});

@ -33,7 +33,7 @@ RocketChat.API.v1.addRoute('groups.addAll', { authRequired: true }, {
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -202,7 +202,7 @@ RocketChat.API.v1.addRoute('groups.create', { authRequired: true }, {
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(id.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(id.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -215,9 +215,7 @@ RocketChat.API.v1.addRoute('groups.delete', { authRequired: true }, {
Meteor.call('eraseRoom', findResult.rid);
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
});
return RocketChat.API.v1.success();
},
});
@ -331,7 +329,7 @@ RocketChat.API.v1.addRoute('groups.info', { authRequired: true }, {
const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId, checkedArchived: false });
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -355,7 +353,7 @@ RocketChat.API.v1.addRoute('groups.invite', { authRequired: true }, {
Meteor.runAsUser(this.userId, () => Meteor.call('addUserToRoom', { rid, username }));
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -405,7 +403,7 @@ RocketChat.API.v1.addRoute('groups.list', { authRequired: true }, {
return RocketChat.API.v1.success({
groups: rooms,
groups: rooms.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
offset,
count: rooms.length,
total: totalCount,
@ -434,7 +432,7 @@ RocketChat.API.v1.addRoute('groups.listAll', { authRequired: true }, {
});
return RocketChat.API.v1.success({
groups: rooms,
groups: rooms.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
offset,
count: rooms.length,
total: totalCount,
@ -495,7 +493,7 @@ RocketChat.API.v1.addRoute('groups.messages', { authRequired: true }, {
}).fetch();
return RocketChat.API.v1.success({
messages,
messages: messages.map((message) => RocketChat.composeMessageObjectWithUser(message, this.userId)),
count: messages.length,
offset,
total: RocketChat.models.Messages.find(ourQuery).count(),
@ -608,7 +606,7 @@ RocketChat.API.v1.addRoute('groups.rename', { authRequired: true }, {
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -626,7 +624,7 @@ RocketChat.API.v1.addRoute('groups.setCustomFields', { authRequired: true }, {
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -684,7 +682,7 @@ RocketChat.API.v1.addRoute('groups.setReadOnly', { authRequired: true }, {
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});
@ -724,7 +722,7 @@ RocketChat.API.v1.addRoute('groups.setType', { authRequired: true }, {
});
return RocketChat.API.v1.success({
group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }),
group: this.composeRoomWithLastMessage(RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }), this.userId),
});
},
});

@ -219,7 +219,7 @@ RocketChat.API.v1.addRoute(['dm.messages', 'im.messages'], { authRequired: true
}).fetch();
return RocketChat.API.v1.success({
messages,
messages: messages.map((message) => RocketChat.composeMessageObjectWithUser(message, this.userId)),
count: messages.length,
offset,
total: RocketChat.models.Messages.find(ourQuery).count(),
@ -259,7 +259,7 @@ RocketChat.API.v1.addRoute(['dm.messages.others', 'im.messages.others'], { authR
}).fetch();
return RocketChat.API.v1.success({
messages: msgs,
messages: msgs.map((message) => RocketChat.composeMessageObjectWithUser(message, this.userId)),
offset,
count: msgs.length,
total: RocketChat.models.Messages.find(ourQuery).count(),
@ -285,7 +285,7 @@ RocketChat.API.v1.addRoute(['dm.list', 'im.list'], { authRequired: true }, {
const rooms = cursor.fetch();
return RocketChat.API.v1.success({
ims: rooms,
ims: rooms.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
offset,
count: rooms.length,
total,
@ -312,7 +312,7 @@ RocketChat.API.v1.addRoute(['dm.list.everyone', 'im.list.everyone'], { authRequi
}).fetch();
return RocketChat.API.v1.success({
ims: rooms,
ims: rooms.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
offset,
count: rooms.length,
total: RocketChat.models.Rooms.find(ourQuery).count(),

@ -46,7 +46,10 @@ RocketChat.API.v1.addRoute('rooms.get', { authRequired: true }, {
};
}
return RocketChat.API.v1.success(result);
return RocketChat.API.v1.success({
update: result.update.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
remove: result.remove.map((room) => this.composeRoomWithLastMessage(room, this.userId)),
});
},
});

@ -166,6 +166,10 @@ RocketChat.API.v1.addRoute('users.register', { authRequired: false }, {
username: String,
}));
if (!RocketChat.checkUsernameAvailability(this.bodyParams.username)) {
return RocketChat.API.v1.failure('Username is already in use');
}
// Register the user
const userId = Meteor.call('registerUser', this.bodyParams);
@ -220,24 +224,44 @@ RocketChat.API.v1.addRoute('users.setAvatar', { authRequired: true }, {
RocketChat.setUserAvatar(user, this.bodyParams.avatarUrl, '', 'url');
} else {
const busboy = new Busboy({ headers: this.request.headers });
const fields = {};
const getUserFromFormData = (fields) => {
if (fields.userId) {
return RocketChat.models.Users.findOneById(fields.userId, { _id: 1 });
}
if (fields.username) {
return RocketChat.models.Users.findOneByUsername(fields.username, { _id: 1 });
}
};
Meteor.wrapAsync((callback) => {
busboy.on('file', Meteor.bindEnvironment((fieldname, file, filename, encoding, mimetype) => {
if (fieldname !== 'image') {
return callback(new Meteor.Error('invalid-field'));
}
const imageData = [];
file.on('data', Meteor.bindEnvironment((data) => {
imageData.push(data);
}));
file.on('end', Meteor.bindEnvironment(() => {
const sentTheUserByFormData = fields.userId || fields.username;
if (sentTheUserByFormData) {
user = getUserFromFormData(fields);
if (!user) {
return callback(new Meteor.Error('error-invalid-user', 'The optional "userId" or "username" param provided does not match any users'));
}
if (!RocketChat.authz.hasPermission(this.userId, 'edit-other-user-info')) {
return callback(new Meteor.Error('error-not-allowed', 'Not allowed'));
}
}
RocketChat.setUserAvatar(user, Buffer.concat(imageData), mimetype, 'rest');
callback();
}));
}));
busboy.on('field', (fieldname, val) => {
fields[fieldname] = val;
});
this.request.pipe(busboy);
})();
}

@ -2,6 +2,9 @@ import express from 'express';
import { WebApp } from 'meteor/webapp';
const apiServer = express();
apiServer.set('x-powered-by', false);
WebApp.connectHandlers.use(apiServer);
export class AppApisBridge {

@ -10,6 +10,7 @@ import { AppListenerBridge } from './listeners';
import { AppMessageBridge } from './messages';
import { AppPersistenceBridge } from './persistence';
import { AppRoomBridge } from './rooms';
import { AppInternalBridge } from './internal';
import { AppSettingBridge } from './settings';
import { AppUserBridge } from './users';
@ -27,6 +28,7 @@ export class RealAppBridges extends AppBridges {
this._msgBridge = new AppMessageBridge(orch);
this._persistBridge = new AppPersistenceBridge(orch);
this._roomBridge = new AppRoomBridge(orch);
this._internalBridge = new AppInternalBridge(orch);
this._setsBridge = new AppSettingBridge(orch);
this._userBridge = new AppUserBridge(orch);
}
@ -71,6 +73,10 @@ export class RealAppBridges extends AppBridges {
return this._roomBridge;
}
getInternalBridge() {
return this._internalBridge;
}
getServerSettingBridge() {
return this._setsBridge;
}

@ -7,6 +7,7 @@ import { AppListenerBridge } from './listeners';
import { AppMessageBridge } from './messages';
import { AppPersistenceBridge } from './persistence';
import { AppRoomBridge } from './rooms';
import { AppInternalBridge } from './internal';
import { AppSettingBridge } from './settings';
import { AppUserBridge } from './users';
@ -22,4 +23,5 @@ export {
AppRoomBridge,
AppSettingBridge,
AppUserBridge,
AppInternalBridge,
};

@ -0,0 +1,19 @@
export class AppInternalBridge {
constructor(orch) {
this.orch = orch;
}
getUsernamesOfRoomById(roomId) {
const records = RocketChat.models.Subscriptions.findByRoomIdWhenUsernameExists(roomId, {
fields: {
'u.username': 1,
},
}).fetch();
if (!records || records.length === 0) {
return [];
}
return records.map((s) => s.u.username);
}
}

@ -5,7 +5,7 @@ export class AppRoomBridge {
this.orch = orch;
}
async create(room, appId) {
async create(room, members, appId) {
console.log(`The App ${ appId } is creating a new room.`, room);
const rcRoom = this.orch.getConverters().get('rooms').convertAppRoom(room);
@ -24,7 +24,12 @@ export class AppRoomBridge {
let rid;
Meteor.runAsUser(room.creator.id, () => {
const info = Meteor.call(method, rcRoom.members);
const extraData = Object.assign({}, rcRoom);
delete extraData.name;
delete extraData.t;
delete extraData.ro;
delete extraData.customFields;
const info = Meteor.call(method, rcRoom.name, members, rcRoom.ro, rcRoom.customFields, extraData);
rid = info.rid;
});
@ -67,15 +72,25 @@ export class AppRoomBridge {
return this.orch.getConverters().get('users').convertById(room.u._id);
}
async update(room, appId) {
async update(room, members = [], appId) {
console.log(`The App ${ appId } is updating a room.`);
if (!room.id || RocketChat.models.Rooms.findOneById(room.id)) {
if (!room.id || !RocketChat.models.Rooms.findOneById(room.id)) {
throw new Error('A room must exist to update.');
}
const rm = this.orch.getConverters().get('rooms').convertAppRoom(room);
RocketChat.models.Rooms.update(rm._id, rm);
for (const username of members) {
const member = RocketChat.models.Users.findOneByUsername(username);
if (!member) {
continue;
}
RocketChat.addUserToRoom(rm._id, member);
}
}
}

@ -120,7 +120,7 @@ export class AppMessagesConverter {
collapsed: attachment.collapsed,
color: attachment.color,
text: attachment.text,
ts: attachment.timestamp,
ts: attachment.timestamp ? attachment.timestamp.toJSON() : attachment.timestamp,
message_link: attachment.timestampLink,
thumb_url: attachment.thumbnailUrl,
author_name: attachment.author ? attachment.author.name : undefined,
@ -133,6 +133,7 @@ export class AppMessagesConverter {
audio_url: attachment.audioUrl,
video_url: attachment.videoUrl,
fields: attachment.fields,
button_alignment: attachment.actionButtonsAlignment,
actions: attachment.actions,
type: attachment.type,
description: attachment.description,
@ -175,7 +176,7 @@ export class AppMessagesConverter {
collapsed: attachment.collapsed,
color: attachment.color,
text: attachment.text,
timestamp: attachment.ts,
timestamp: new Date(attachment.ts),
timestampLink: attachment.message_link,
thumbnailUrl: attachment.thumb_url,
author,
@ -184,6 +185,7 @@ export class AppMessagesConverter {
audioUrl: attachment.audio_url,
videoUrl: attachment.video_url,
fields: attachment.fields,
actionButtonsAlignment: attachment.button_alignment,
actions: attachment.actions,
type: attachment.type,
description: attachment.description,

@ -2,9 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { ServiceConfiguration } from 'meteor/service-configuration';
import { check, Match } from 'meteor/check';
import { Session } from 'meteor/session';
import './routes';
import { redirectToSignIn, signUserOut } from 'blockstack';
const handleError = (error) => error && Session.set('errorMessage', error.reason || 'Unknown error');
@ -29,7 +27,8 @@ Meteor.loginWithBlockstack = (options, callback = handleError) => {
manifestURI: String,
}));
return redirectToSignIn(options.redirectURI, options.manifestURI, options.scopes);
import('blockstack/dist/blockstack').then(({ redirectToSignIn }) =>
redirectToSignIn(options.redirectURI, options.manifestURI, options.scopes));
} catch (err) {
callback.call(Meteor, err);
}
@ -45,7 +44,8 @@ Meteor.logout = (...args) => {
if (serviceConfig && blockstackAuth) {
Session.delete('blockstack_auth');
signUserOut(window.location.href);
import('blockstack/dist/blockstack').then(({ signUserOut }) =>
signUserOut(window.location.href));
}
return meteorLogout(...args);

@ -1,7 +1,6 @@
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { FlowRouter } from 'meteor/kadira:flow-router';
import blockstack from 'blockstack';
const blockstackLogin = (authResponse, userData = {}) => {
Accounts.callLoginMethod({
@ -19,6 +18,8 @@ const blockstackLogin = (authResponse, userData = {}) => {
FlowRouter.route('/_blockstack/validate', {
name: 'blockstackValidate',
async action(params, queryParams) {
const blockstack = await import('blockstack/dist/blockstack');
if (Meteor.userId()) {
console.log('Blockstack Auth requested when already logged in. Reloading.');
return FlowRouter.go('home');

@ -118,7 +118,20 @@ function roomMaxAge(room) {
return roomMaxAgeDefault(room.t);
}
const fixRoomName = (old) => {
if (RocketChat.settings.get('UI_Allow_room_names_with_special_chars')) {
return old;
}
const reg = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
return [...old.replace(' ', '').toLocaleLowerCase()].filter((f) => reg.test(f)).join('');
};
Template.channelSettingsEditing.events({
'input [name="name"]'(e) {
const input = e.currentTarget;
const modified = fixRoomName(input.value);
input.value = modified;
},
'input .js-input'(e) {
this.value.set(e.currentTarget.value);
},

@ -285,7 +285,7 @@ export class E2ERoom {
try {
const result = await decryptAES(vector, this.groupSessionKey, cipherText);
return EJSON.parse(toString(result));
return EJSON.parse(new TextDecoder('UTF-8').decode(new Uint8Array(result)));
} catch (error) {
return console.error('E2E -> Error decrypting message: ', error, message);
}

@ -35,8 +35,8 @@ for (const key in emojione.emojioneList) {
Meteor.startup(function() {
Tracker.autorun(function() {
if (isSetNotNull(() => RocketChat.emoji.packages.emojione)) {
if (isSetNotNull(() => RocketChat.getUserPreference(Meteor.user(), 'convertAsciiEmoji'))) {
RocketChat.emoji.packages.emojione.ascii = RocketChat.getUserPreference(Meteor.user(), 'convertAsciiEmoji');
if (isSetNotNull(() => RocketChat.getUserPreference(Meteor.userId(), 'convertAsciiEmoji'))) {
RocketChat.emoji.packages.emojione.ascii = RocketChat.getUserPreference(Meteor.userId(), 'convertAsciiEmoji');
} else {
RocketChat.emoji.packages.emojione.ascii = true;
}

@ -4,7 +4,7 @@ Template.messageBox.events({
event.stopPropagation();
event.preventDefault();
if (!RocketChat.getUserPreference(Meteor.user(), 'useEmojis')) {
if (!RocketChat.getUserPreference(Meteor.userId(), 'useEmojis')) {
return false;
}

@ -6,8 +6,8 @@ import s from 'underscore.string';
* @param {Object} message - The message object
*/
RocketChat.callbacks.add('renderMessage', (message) => {
if (isSetNotNull(() => RocketChat.getUserPreference(Meteor.user(), 'useEmojis')) &&
!RocketChat.getUserPreference(Meteor.user(), 'useEmojis')) {
if (isSetNotNull(() => RocketChat.getUserPreference(Meteor.userId(), 'useEmojis')) &&
!RocketChat.getUserPreference(Meteor.userId(), 'useEmojis')) {
return message;
}

@ -161,29 +161,34 @@ Object.assign(FileUpload, {
},
};
if (metadata.orientation == null) {
return fut.return();
}
s.rotate()
.toFile(`${ tmpFile }.tmp`)
.then(Meteor.bindEnvironment(() => {
fs.unlink(tmpFile, Meteor.bindEnvironment(() => {
fs.rename(`${ tmpFile }.tmp`, tmpFile, Meteor.bindEnvironment(() => {
const { size } = fs.lstatSync(tmpFile);
this.getCollection().direct.update({ _id: file._id }, {
$set: {
size,
identify,
},
});
fut.return();
const reorientation = (cb) => {
if (!metadata.orientation) {
return cb();
}
s.rotate()
.toFile(`${ tmpFile }.tmp`)
.then(Meteor.bindEnvironment(() => {
fs.unlink(tmpFile, Meteor.bindEnvironment(() => {
fs.rename(`${ tmpFile }.tmp`, tmpFile, Meteor.bindEnvironment(() => {
cb();
}));
}));
}));
})).catch((err) => {
console.error(err);
fut.return();
})).catch((err) => {
console.error(err);
fut.return();
});
return;
};
reorientation(() => {
const { size } = fs.lstatSync(tmpFile);
this.getCollection().direct.update({ _id: file._id }, {
$set: { size, identify },
});
fut.return();
});
}));
return fut.wait();

@ -1,7 +1,7 @@
import _ from 'underscore';
Meteor.methods({
async 'sendFileMessage'(roomId, store, file, msgData = {}) {
async sendFileMessage(roomId, store, file, msgData = {}) {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'sendFileMessage' });
}
@ -39,7 +39,14 @@ Meteor.methods({
if (file.identify && file.identify.size) {
attachment.image_dimensions = file.identify.size;
}
attachment.image_preview = await FileUpload.resizeImagePreview(file);
try {
attachment.image_preview = await FileUpload.resizeImagePreview(file);
} catch (e) {
delete attachment.image_url;
delete attachment.image_type;
delete attachment.image_size;
delete attachment.image_dimensions;
}
} else if (/^audio\/.+/.test(file.type)) {
attachment.audio_url = fileUrl;
attachment.audio_type = file.type;

@ -10,7 +10,7 @@ const setAvatarFromUrl = (userId, url) => new Promise((resolve, reject) => {
Meteor.runAsUser(userId, () => {
Meteor.call('setAvatarFromService', url, '', 'url', (err) => {
if (err) {
if (err.details.timeToReset && err.details.timeToReset) {
if (err.details && err.details.timeToReset) {
reject((t('error-too-many-requests', {
seconds: parseInt(err.details.timeToReset / 1000),
})));

@ -0,0 +1,41 @@
import { Meteor } from 'meteor/meteor';
import { RocketChat } from 'meteor/rocketchat:lib';
import { authenticated } from '../../helpers/authenticated';
import schema from '../../schemas/channels/deleteChannel.graphqls';
const resolver = {
Mutation: {
deleteChannel: authenticated((root, { channelId }, { user }) => {
const channel = RocketChat.models.Rooms.findOne({
_id: channelId,
t: 'c',
});
if (!channel) {
throw new Error('error-room-not-found', 'The required "channelId" param provided does not match any channel');
}
const sub = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(channel._id, user._id);
if (!sub) {
throw new Error(`The user/callee is not in the channel "${ channel.name }.`);
}
if (!sub.open) {
throw new Error(`The channel, ${ channel.name }, is already closed to the sender`);
}
Meteor.runAsUser(user._id, () => {
Meteor.call('eraseRoom', channel._id);
});
return true;
}),
},
};
export {
schema,
resolver,
};

@ -9,6 +9,7 @@ import * as channelsByUser from './channelsByUser';
import * as createChannel from './createChannel';
import * as leaveChannel from './leaveChannel';
import * as hideChannel from './hideChannel';
import * as deleteChannel from './deleteChannel';
// types
import * as ChannelType from './Channel-type';
import * as ChannelSort from './ChannelSort-enum';
@ -26,6 +27,7 @@ export const schema = mergeTypes([
createChannel.schema,
leaveChannel.schema,
hideChannel.schema,
deleteChannel.schema,
// types
ChannelType.schema,
ChannelSort.schema,
@ -44,6 +46,7 @@ export const resolvers = mergeResolvers([
createChannel.resolver,
leaveChannel.resolver,
hideChannel.resolver,
deleteChannel.resolver,
// types
ChannelType.resolver,
]);

@ -0,0 +1,3 @@
type Mutation {
deleteChannel(channelId: String!): Boolean
}

@ -15,7 +15,7 @@ function HighlightWordsClient(message) {
}
}
const to_highlight = RocketChat.getUserPreference(Meteor.user(), 'highlights');
const to_highlight = RocketChat.getUserPreference(Meteor.userId(), 'highlights');
if (Array.isArray(to_highlight)) {
to_highlight.forEach((highlight) => {
if (!s.isBlank(highlight)) {

@ -5,6 +5,8 @@ Accounts.registerLoginHandler('iframe', function(result) {
return;
}
check(result.token, String);
console.log('[Method] registerLoginHandler');
const user = Meteor.users.findOne({

@ -495,6 +495,7 @@ export class HipChatEnterpriseImporter extends Base {
super.updateProgress(ProgressStep.FINISHING);
super.updateProgress(ProgressStep.DONE);
} catch (e) {
super.updateRecord({ 'error-record': JSON.stringify(e, Object.getOwnPropertyNames(e)) });
this.logger.error(e);
super.updateProgress(ProgressStep.ERROR);
}

@ -304,6 +304,13 @@ export class SlackImporter extends Base {
}
if (message.type === 'message') {
if (message.files && message.files[0].url_private_download !== undefined) {
const msgObj = {
...msgDataDefaults,
msg: this.convertSlackMessageToRocketChat(message.files[0].url_private_download),
};
RocketChat.sendMessage(this.getRocketUser(message.user), msgObj, room, true);
}
if (message.subtype) {
if (message.subtype === 'channel_join') {
if (this.getRocketUser(message.user)) {

@ -192,12 +192,16 @@ export class Base {
this.oldSettings.FileUpload_MaxFileSize = RocketChat.models.Settings.findOneById('FileUpload_MaxFileSize').value;
RocketChat.models.Settings.updateValueById('FileUpload_MaxFileSize', -1);
this.oldSettings.FileUpload_MediaTypeWhiteList = RocketChat.models.Settings.findOneById('FileUpload_MediaTypeWhiteList').value;
RocketChat.models.Settings.updateValueById('FileUpload_MediaTypeWhiteList', '*');
break;
case ProgressStep.DONE:
case ProgressStep.ERROR:
RocketChat.models.Settings.updateValueById('Accounts_AllowedDomainsList', this.oldSettings.Accounts_AllowedDomainsList);
RocketChat.models.Settings.updateValueById('Accounts_AllowUsernameChange', this.oldSettings.Accounts_AllowUsernameChange);
RocketChat.models.Settings.updateValueById('FileUpload_MaxFileSize', this.oldSettings.FileUpload_MaxFileSize);
RocketChat.models.Settings.updateValueById('FileUpload_MediaTypeWhiteList', this.oldSettings.FileUpload_MediaTypeWhiteList);
break;
}

@ -116,23 +116,14 @@ Accounts.registerLoginHandler('ldap', function(loginRequest) {
logger.info('Logging user');
const stampedToken = Accounts._generateStampedLoginToken();
Meteor.users.update(user._id, {
$push: {
'services.resume.loginTokens': Accounts._hashStampedToken(stampedToken),
},
});
syncUserData(user, ldapUser);
if (RocketChat.settings.get('LDAP_Login_Fallback') === true && typeof loginRequest.ldapPass === 'string' && loginRequest.ldapPass.trim() !== '') {
Accounts.setPassword(user._id, loginRequest.ldapPass, { logout: false });
}
RocketChat.callbacks.run('afterLDAPLogin', { user, ldapUser, ldap });
return {
userId: user._id,
token: stampedToken.token,
};
}
@ -152,6 +143,7 @@ Accounts.registerLoginHandler('ldap', function(loginRequest) {
if (result instanceof Error) {
throw result;
}
RocketChat.callbacks.run('afterLDAPLogin', { user: result, ldapUser, ldap });
return result;
});

@ -82,11 +82,13 @@ Package.onUse(function(api) {
// SERVER FUNCTIONS
api.addFiles('server/functions/isDocker.js', 'server');
api.addFiles('server/functions/isTheLastMessage.js', 'server');
api.addFiles('server/functions/addUserToDefaultChannels.js', 'server');
api.addFiles('server/functions/addUserToRoom.js', 'server');
api.addFiles('server/functions/archiveRoom.js', 'server');
api.addFiles('server/functions/checkUsernameAvailability.js', 'server');
api.addFiles('server/functions/checkEmailAvailability.js', 'server');
api.addFiles('server/functions/composeMessageObjectWithUser.js', 'server');
api.addFiles('server/functions/createRoom.js', 'server');
api.addFiles('server/functions/cleanRoomHistory.js', 'server');
api.addFiles('server/functions/deleteMessage.js', 'server');

@ -1,3 +1,3 @@
{
"version": "0.70.4"
"version": "0.71.0-rc.2"
}

@ -0,0 +1,20 @@
const getUser = (userId) => RocketChat.models.Users.findOneById(userId);
RocketChat.composeMessageObjectWithUser = function(message, userId) {
if (message) {
if (message.starred && Array.isArray(message.starred)) {
message.starred = message.starred.filter((star) => star._id === userId);
}
if (message.u && message.u._id && RocketChat.settings.get('UI_Use_Real_Name')) {
const user = getUser(message.u._id);
message.u.name = user && user.name;
}
if (message.mentions && message.mentions.length && RocketChat.settings.get('UI_Use_Real_Name')) {
message.mentions.forEach((mention) => {
const user = getUser(mention._id);
mention.name = user && user.name;
});
}
}
return message;
};

@ -39,7 +39,7 @@ RocketChat.deleteMessage = function(message, user) {
if (RocketChat.settings.get('Store_Last_Message')) {
const room = RocketChat.models.Rooms.findOneById(message.rid, { fields: { lastMessage: 1 } });
if (!room.lastMessage || room.lastMessage._id === message._id) {
RocketChat.models.Rooms.resetLastMessageById(message.rid);
RocketChat.models.Rooms.resetLastMessageById(message.rid, message._id);
}
}

@ -0,0 +1 @@
RocketChat.isTheLastMessage = (room, message) => RocketChat.settings.get('Store_Last_Message') && (!room.lastMessage || room.lastMessage._id === message._id);

@ -1,5 +1,3 @@
import _ from 'underscore';
const hideMessagesOfType = [];
RocketChat.settings.get(/Message_HideType_.+/, function(key, value) {
@ -39,26 +37,7 @@ RocketChat.loadMessageHistory = function loadMessageHistory({ userId, rid, end,
} else {
records = RocketChat.models.Messages.findVisibleByRoomIdNotContainingTypes(rid, hideMessagesOfType, options).fetch();
}
const UI_Use_Real_Name = RocketChat.settings.get('UI_Use_Real_Name') === true;
const messages = records.map((message) => {
message.starred = _.findWhere(message.starred, {
_id: userId,
});
if (message.u && message.u._id && UI_Use_Real_Name) {
const user = RocketChat.models.Users.findOneById(message.u._id);
message.u.name = user && user.name;
}
if (message.mentions && message.mentions.length && UI_Use_Real_Name) {
message.mentions.forEach((mention) => {
const user = RocketChat.models.Users.findOneById(mention._id);
mention.name = user && user.name;
});
}
return message;
});
const messages = records.map((record) => RocketChat.composeMessageObjectWithUser(record, userId));
let unreadNotLoaded = 0;
let firstUnread;

@ -94,6 +94,48 @@ function validateUserData(userId, userData) {
}
}
function validateUserEditing(userId, userData) {
const editingMyself = userData._id && userId === userData._id;
const canEditOtherUserInfo = RocketChat.authz.hasPermission(userId, 'edit-other-user-info');
const canEditOtherUserPassword = RocketChat.authz.hasPermission(userId, 'edit-other-user-password');
if (!RocketChat.settings.get('Accounts_AllowUserProfileChange') && !canEditOtherUserInfo && !canEditOtherUserPassword) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user profile is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.username && !RocketChat.settings.get('Accounts_AllowUsernameChange') && (!canEditOtherUserInfo || editingMyself)) {
throw new Meteor.Error('error-action-not-allowed', 'Edit username is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.name && !RocketChat.settings.get('Accounts_AllowRealNameChange') && (!canEditOtherUserInfo || editingMyself)) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user real name is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.email && !RocketChat.settings.get('Accounts_AllowEmailChange') && (!canEditOtherUserInfo || editingMyself)) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user email is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.password && !RocketChat.settings.get('Accounts_AllowPasswordChange') && (!canEditOtherUserPassword || editingMyself)) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user password is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
}
RocketChat.saveUser = function(userId, userData) {
validateUserData(userId, userData);
@ -169,40 +211,8 @@ RocketChat.saveUser = function(userId, userData) {
return _id;
}
if (!RocketChat.settings.get('Accounts_AllowUserProfileChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-password')) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user profile is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.username && !RocketChat.settings.get('Accounts_AllowUsernameChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info')) {
throw new Meteor.Error('error-action-not-allowed', 'Edit username is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.name && !RocketChat.settings.get('Accounts_AllowRealNameChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info')) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user real name is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.email && !RocketChat.settings.get('Accounts_AllowEmailChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info')) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user email is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
if (userData.password && !RocketChat.settings.get('Accounts_AllowPasswordChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-password')) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user password is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}
validateUserEditing(userId, userData);
// update user
if (userData.username) {

@ -50,6 +50,8 @@ RocketChat.settings.add = function(_id, value, options = {}) {
value = true;
} else if (value.toLowerCase() === 'false') {
value = false;
} else if (options.type === 'int') {
value = parseInt(value);
}
options.processEnvValue = value;
options.valueSource = 'processEnvValue';
@ -83,6 +85,8 @@ RocketChat.settings.add = function(_id, value, options = {}) {
value = true;
} else if (value.toLowerCase() === 'false') {
value = false;
} else if (options.type === 'int') {
value = parseInt(value);
}
options.value = value;
options.processEnvValue = value;

@ -51,22 +51,7 @@ Meteor.methods({
records = RocketChat.models.Messages.findVisibleByRoomIdBetweenTimestamps(rid, oldest, latest, options).fetch();
}
const UI_Use_Real_Name = RocketChat.settings.get('UI_Use_Real_Name') === true;
const messages = _.map(records, (message) => {
message.starred = _.findWhere(message.starred, { _id: fromUserId });
if (message.u && message.u._id && UI_Use_Real_Name) {
const user = RocketChat.models.Users.findOneById(message.u._id);
message.u.name = user && user.name;
}
if (message.mentions && message.mentions.length && UI_Use_Real_Name) {
message.mentions.forEach((mention) => {
const user = RocketChat.models.Users.findOneById(mention._id);
mention.name = user && user.name;
});
}
return message;
});
const messages = records.map((record) => RocketChat.composeMessageObjectWithUser(record, fromUserId));
if (unreads) {
let unreadNotLoaded = 0;

@ -435,9 +435,9 @@ class ModelRooms extends RocketChat.models._Base {
return this.update(query, update);
}
resetLastMessageById(_id) {
resetLastMessageById(_id, messageId) {
const query = { _id };
const lastMessage = RocketChat.models.Messages.getLastVisibleMessageSentWithNoTypeByRoomId(_id);
const lastMessage = RocketChat.models.Messages.getLastVisibleMessageSentWithNoTypeByRoomId(_id, messageId);
const update = lastMessage ? {
$set: {

@ -1194,7 +1194,7 @@ RocketChat.settings.addGroup('Layout', function() {
type: 'string',
public: true,
});
this.add('Layout_Home_Body', '<p>Welcome to Rocket.Chat!</p>\n<p>The Rocket.Chat desktops apps for Windows, macOS and Linux are available to download <a title="Rocket.Chat desktop apps" href="https: //rocket.chat/download" target="_blank" rel="noopener">here</a>.</p><p>The native mobile app, Rocket.Chat+,\n for Android and iOS is available from <a title="Rocket.Chat+ on Google Play" href="https: //play.google.com/store/apps/details?id=chat.rocket.android" target="_blank" rel="noopener">Google Play</a> and the <a title="Rocket.Chat+ on the App Store" href="https: //itunes.apple.com/app/rocket-chat/id1148741252" target="_blank" rel="noopener">App Store</a>.</p>\n<p>For further help, please consult the <a title="Rocket.Chat Documentation" href="https: //rocket.chat/docs/" target="_blank" rel="noopener">documentation</a>.</p>\n<p>If you\'re an admin, feel free to change this content via <strong>Administration</strong> -> <strong>Layout</strong> -> <strong>Home Body</strong>. Or clicking <a title="Home Body Layout" href="/admin/Layout">here</a>.</p>', {
this.add('Layout_Home_Body', '<p>Welcome to Rocket.Chat!</p>\n<p>The Rocket.Chat desktops apps for Windows, macOS and Linux are available to download <a title="Rocket.Chat desktop apps" href="https://rocket.chat/download" target="_blank" rel="noopener">here</a>.</p><p>The native mobile app, Rocket.Chat+,\n for Android and iOS is available from <a title="Rocket.Chat+ on Google Play" href="https://play.google.com/store/apps/details?id=chat.rocket.android" target="_blank" rel="noopener">Google Play</a> and the <a title="Rocket.Chat+ on the App Store" href="https://itunes.apple.com/app/rocket-chat/id1148741252" target="_blank" rel="noopener">App Store</a>.</p>\n<p>For further help, please consult the <a title="Rocket.Chat Documentation" href="https://rocket.chat/docs/" target="_blank" rel="noopener">documentation</a>.</p>\n<p>If you\'re an admin, feel free to change this content via <strong>Administration</strong> -> <strong>Layout</strong> -> <strong>Home Body</strong>. Or clicking <a title="Home Body Layout" href="/admin/Layout">here</a>.</p>', {
type: 'code',
code: 'text/html',
multiline: true,

@ -209,10 +209,7 @@ this.Livechat = new (class Livechat {
}
set department(departmentId) {
const dept = Department.findOne({ _id: departmentId }) || Department.findOne({ name: departmentId });
if (dept) {
this._department.set(dept._id);
}
this._department.set(dept && dept._id);
}
set agent(agentData) {
this._agent.set(agentData);

@ -17,6 +17,7 @@
"How_satisfied_were_you_with_this_chat": "Você ficou satisfeito com este bate-papo?",
"Installation": "Instalação",
"New_messages": "Novas mensagens",
"New_livechat_in_queue": "Novo chat na roleta",
"No": "Não",
"Options": "Opções",
"Please_answer_survey": "Por favor, tire um momento para responder uma rápida pesquisa sobre este chat",
@ -38,6 +39,7 @@
"Type_your_email": "Digite seu e-mail",
"Type_your_message": "Digite sua mensagem",
"Type_your_name": "Digite seu nome",
"Upload_file_question": "Enviar arquivo?",
"User_joined": "Usuário entrou",
"User_left": "Usuário saiu",
"We_are_not_online_right_now_please_leave_a_message": "Nós não estamos online agora. Por favor, deixe uma mensagem.",
@ -45,4 +47,4 @@
"Yes": "Sim",
"You": "Você",
"You_must_complete_all_fields": "Você deve preencher todos os campos"
}
}

@ -13,7 +13,7 @@ export const checkDaterangeValue = (value, from, to) => {
if (moment().startOf('day').isSame(from) && moment().startOf('day').isSame(to)) {
return 'today';
}
if (moment().startOf('day').subtract(1, 'days').isSame(from) && moment().startOf('day').subtract(1, 'days').isSame(from)) {
if (moment().startOf('day').subtract(1, 'days').isSame(from) && moment().startOf('day').subtract(1, 'days').isSame(to)) {
return 'yesterday';
}
if (moment().startOf('week').isSame(from) && moment().endOf('week').isSame(to)) {

@ -12,7 +12,7 @@ RocketChat.API.v1.addRoute('livechat/config', {
return RocketChat.API.v1.success({ config: { enabled: false } });
}
const { status } = online();
const status = online();
let guest;
let room;

@ -221,7 +221,8 @@ RocketChat.Livechat = {
}
if (department) {
updateUser.$set.department = department;
const dep = RocketChat.models.LivechatDepartment.findOneByIdOrName(department);
updateUser.$set.department = dep && dep._id;
}
LivechatVisitors.updateById(userId, updateUser);
@ -267,6 +268,10 @@ RocketChat.Livechat = {
},
closeRoom({ user, visitor, room, comment }) {
if (!room || room.t !== 'l' || !room.open) {
return false;
}
const now = new Date();
const closeData = {

@ -2,19 +2,13 @@ import LivechatVisitors from '../models/LivechatVisitors';
Meteor.methods({
'livechat:closeByVisitor'({ roomId, token }) {
const room = RocketChat.models.Rooms.findOneOpenByRoomIdAndVisitorToken(roomId, token);
if (!room || !room.open) {
return false;
}
const visitor = LivechatVisitors.getVisitorByToken(token);
const language = (visitor && visitor.language) || RocketChat.settings.get('language') || 'en';
return RocketChat.Livechat.closeRoom({
visitor,
room,
room: RocketChat.models.Rooms.findOneOpenByRoomIdAndVisitorToken(roomId, token),
comment: TAPi18n.__('Closed_by_visitor', { lng: language }),
});
},

@ -5,12 +5,6 @@ Meteor.methods({
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'livechat:closeRoom' });
}
const room = RocketChat.models.Rooms.findOneById(roomId);
if (!room || room.t !== 'l') {
throw new Meteor.Error('room-not-found', 'Room not found', { method: 'livechat:closeRoom' });
}
const user = Meteor.user();
const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(roomId, user._id, { _id: 1 });
@ -20,7 +14,7 @@ Meteor.methods({
return RocketChat.Livechat.closeRoom({
user,
room,
room: RocketChat.models.Rooms.findOneById(roomId),
comment,
});
},

@ -78,6 +78,18 @@ class LivechatDepartment extends RocketChat.models._Base {
};
return this.find(query);
}
findOneByIdOrName(_idOrName, options) {
const query = {
$or: [{
_id: _idOrName,
}, {
name: _idOrName,
}],
};
return this.findOne(query, options);
}
}
RocketChat.models.LivechatDepartment = new LivechatDepartment();

@ -8,6 +8,7 @@ Package.onUse(function(api) {
api.use([
'ecmascript',
'ddp-rate-limiter',
'rocketchat:i18n',
]);
api.mainModule('server/api.js', 'server');

@ -81,14 +81,14 @@ export const rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-
export const checkAddressFormat = (from) => rfcMailPatternWithName.test(from);
export const sendNoWrap = ({ to, from, subject, html }) => {
export const sendNoWrap = ({ to, from, subject, html, headers }) => {
if (!checkAddressFormat(to)) {
return;
}
Meteor.defer(() => Email.send({ to, from, subject, html }));
Meteor.defer(() => Email.send({ to, from, subject, html, headers }));
};
export const send = ({ to, from, subject, html, data }) => sendNoWrap({ to, from, subject: replace(subject, data), html: wrap(html, data) });
export const send = ({ to, from, subject, html, data, headers }) => sendNoWrap({ to, from, subject: replace(subject, data), html: wrap(html, data), headers });
export const checkAddressFormatAndThrow = (from, func) => {
if (checkAddressFormat(from)) {

@ -130,6 +130,14 @@
{{/unless}}
{{/if}}
{{#if isPDF}}
{{#unless collapsed}}
<div id="js-loading-{{fileId}}" class="attachment-pdf-loading">
{{> icon block="rc-input__icon-svg" icon="loading"}}
</div>
<canvas id="{{fileId}}" class="attachment-canvas"></canvas>
{{/unless}}
{{/if}}
{{#if fields}}
{{#unless collapsed}}
<div class="attachment-fields">
@ -148,13 +156,15 @@
<div class="attachment-description">{{description}}</div>
{{/if}}
{{/unless}}
{{#if actions}}
<div class="actions-container">
{{#each actions}}
{{> messageAction}}
{{/each}}
</div>
{{#unless collapsed}}
<div class="actions-container">
{{#each actions}}
{{> messageAction}}
{{/each}}
</div>
{{/unless}}
{{/if}}
{{#each attachments}}

@ -50,8 +50,7 @@ Template.messageAttachment.helpers({
if (this.collapsed != null) {
return this.collapsed;
} else {
const user = Meteor.user();
return RocketChat.getUserPreference(user, 'collapseMediaByDefault') === true;
return RocketChat.getUserPreference(Meteor.userId(), 'collapseMediaByDefault') === true;
}
},
time() {
@ -69,4 +68,11 @@ Template.messageAttachment.helpers({
isFile() {
return this.type === 'file';
},
isPDF() {
if (this.type === 'file' && this.title_link.endsWith('.pdf') && Template.parentData().file) {
this.fileId = Template.parentData().file._id;
return true;
}
return false;
},
});

@ -145,6 +145,16 @@ html.rtl .attachment {
border-radius: 5px;
}
& .attachment-canvas {
display: none;
}
& .attachment-pdf-loading {
display: none;
font-size: 1.5rem;
}
& .actions-container {
margin-top: 6px;
}

@ -25,6 +25,7 @@ Package.onUse(function(api) {
], 'client');
api.addFiles([
'server/models/Rooms.js',
'server/settings.js',
'server/pinMessage.js',
'server/publications/pinnedMessages.js',

@ -0,0 +1,13 @@
RocketChat.models.Rooms.setLastMessagePinned = function(roomId, pinnedBy, pinned, pinnedAt) {
const query = { _id: roomId };
const update = {
$set: {
'lastMessage.pinned': pinned,
'lastMessage.pinnedAt': pinnedAt || new Date,
'lastMessage.pinnedBy': pinnedBy,
},
};
return this.update(query, update);
};

@ -50,7 +50,7 @@ Meteor.methods({
if (RocketChat.settings.get('Message_KeepHistory')) {
RocketChat.models.Messages.cloneAndSaveAsHistoryById(message._id);
}
const room = Meteor.call('canAccessRoom', message.rid, Meteor.userId());
const me = RocketChat.models.Users.findOneById(userId);
originalMessage.pinned = true;
@ -63,6 +63,9 @@ Meteor.methods({
originalMessage = RocketChat.callbacks.run('beforeSaveMessage', originalMessage);
RocketChat.models.Messages.setPinnedByIdAndUserId(originalMessage._id, originalMessage.pinnedBy, originalMessage.pinned);
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.setLastMessagePinned(room._id, originalMessage.pinnedBy, originalMessage.pinned);
}
const attachments = [];
@ -134,6 +137,10 @@ Meteor.methods({
username: me.username,
};
originalMessage = RocketChat.callbacks.run('beforeSaveMessage', originalMessage);
const room = Meteor.call('canAccessRoom', message.rid, Meteor.userId());
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.setLastMessagePinned(room._id, originalMessage.pinnedBy, originalMessage.pinned);
}
return RocketChat.models.Messages.setPinnedByIdAndUserId(originalMessage._id, originalMessage.pinnedBy, originalMessage.pinned);
},

@ -28,6 +28,7 @@ Package.onUse(function(api) {
// Server
api.addFiles([
'server/startup/settings.js',
'server/models/Rooms.js',
'server/methods/snippetMessage.js',
'server/requests.js',
'server/publications/snippetedMessagesByRoom.js',

@ -36,6 +36,10 @@ Meteor.methods({
// Create the SnippetMessage
RocketChat.models.Messages.setSnippetedByIdAndUserId(message, filename, message.snippetedBy,
message.snippeted, Date.now, filename);
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.setLastMessageSnippeted(room._id, message, filename, message.snippetedBy,
message.snippeted, Date.now, filename);
}
RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser(
'message_snippeted', message.rid, '', me, { snippetId: message._id, snippetName: filename });

@ -0,0 +1,17 @@
RocketChat.models.Rooms.setLastMessageSnippeted = function(roomId, message, snippetName, snippetedBy, snippeted, snippetedAt) {
const query = { _id: roomId };
const msg = `\`\`\`${ message.msg }\`\`\``;
const update = {
$set: {
'lastMessage.msg': msg,
'lastMessage.snippeted': snippeted,
'lastMessage.snippetedAt': snippetedAt || new Date,
'lastMessage.snippetedBy': snippetedBy,
'lastMessage.snippetName': snippetName,
},
};
return this.update(query, update);
};

@ -1,4 +1,3 @@
import _ from 'underscore';
import toastr from 'toastr';
Meteor.startup(function() {
@ -21,7 +20,7 @@ Meteor.startup(function() {
return false;
}
return !_.findWhere(message.starred, { _id: Meteor.userId() });
return !message.starred || !message.starred.find((star) => star._id === Meteor.userId());
},
order: 10,
group: 'menu',
@ -46,7 +45,7 @@ Meteor.startup(function() {
return false;
}
return Boolean(_.findWhere(message.starred, { _id: Meteor.userId() }));
return message.starred && message.starred.find((star) => star._id === Meteor.userId());
},
order: 10,
group: 'menu',

@ -25,6 +25,7 @@ Package.onUse(function(api) {
], 'client');
api.addFiles([
'server/models/Rooms.js',
'server/settings.js',
'server/starMessage.js',
'server/publications/starredMessages.js',

@ -0,0 +1,21 @@
RocketChat.models.Rooms.updateLastMessageStar = function(roomId, userId, starred) {
let update;
const query = { _id: roomId };
if (starred) {
update = {
$addToSet: {
'lastMessage.starred': { _id: userId },
},
};
} else {
update = {
$pull: {
'lastMessage.starred': { _id: userId },
},
};
}
return this.update(query, update);
};

@ -17,6 +17,10 @@ Meteor.methods({
if (!subscription) {
return false;
}
const room = Meteor.call('canAccessRoom', message.rid, Meteor.userId());
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.updateLastMessageStar(room._id, Meteor.userId(), message.starred);
}
return RocketChat.models.Messages.updateUserStarById(message._id, Meteor.userId(), message.starred);
},

@ -3,8 +3,7 @@ Template.oembedAudioWidget.helpers({
if (this.collapsed) {
return this.collapsed;
} else {
const user = Meteor.user();
return RocketChat.getUserPreference(user, 'collapseMediaByDefault') === true;
return RocketChat.getUserPreference(Meteor.userId(), 'collapseMediaByDefault') === true;
}
},
});

@ -3,8 +3,7 @@ Template.oembedFrameWidget.helpers({
if (this.collapsed) {
return this.collapsed;
} else {
const user = Meteor.user();
return RocketChat.getUserPreference(user, 'collapseMediaByDefault') === true;
return RocketChat.getUserPreference(Meteor.userId(), 'collapseMediaByDefault') === true;
}
},
});

@ -1,11 +1,9 @@
Template.oembedImageWidget.helpers({
loadImage() {
const user = Meteor.user();
if (RocketChat.getUserPreference(user, 'autoImageLoad') === false && this.downloadImages == null) {
if (RocketChat.getUserPreference(Meteor.userId(), 'autoImageLoad') === false && this.downloadImages == null) {
return false;
}
if (Meteor.Device.isPhone() && RocketChat.getUserPreference(user, 'saveMobileBandwidth') && this.downloadImages == null) {
if (Meteor.Device.isPhone() && RocketChat.getUserPreference(Meteor.userId(), 'saveMobileBandwidth') && this.downloadImages == null) {
return false;
}
return true;
@ -14,8 +12,7 @@ Template.oembedImageWidget.helpers({
if (this.collapsed != null) {
return this.collapsed;
} else {
const user = Meteor.user();
return RocketChat.getUserPreference(user, 'collapseMediaByDefault') === true;
return RocketChat.getUserPreference(Meteor.userId(), 'collapseMediaByDefault') === true;
}
},
});

@ -62,8 +62,7 @@ Template.oembedUrlWidget.helpers({
if (this.collapsed != null) {
return this.collapsed;
} else {
const user = Meteor.user();
return RocketChat.getUserPreference(user, 'collapseMediaByDefault') === true;
return RocketChat.getUserPreference(Meteor.userId(), 'collapseMediaByDefault') === true;
}
},
});

@ -27,8 +27,7 @@ Template.oembedVideoWidget.helpers({
if (this.collapsed) {
return this.collapsed;
} else {
const user = Meteor.user();
return RocketChat.getUserPreference(user, 'collapseMediaByDefault') === true;
return RocketChat.getUserPreference(Meteor.userId(), 'collapseMediaByDefault') === true;
}
},

@ -73,21 +73,21 @@ Template.pushNotificationsFlexTab.helpers({
}
},
defaultAudioNotification() {
let preference = RocketChat.getUserPreference(Meteor.user(), 'audioNotifications');
let preference = RocketChat.getUserPreference(Meteor.userId(), 'audioNotifications');
if (preference === 'default') {
preference = RocketChat.settings.get('Accounts_Default_User_Preferences_audioNotifications');
}
return notificationLabels[preference];
},
defaultDesktopNotification() {
let preference = RocketChat.getUserPreference(Meteor.user(), 'desktopNotifications');
let preference = RocketChat.getUserPreference(Meteor.userId(), 'desktopNotifications');
if (preference === 'default') {
preference = RocketChat.settings.get('Accounts_Default_User_Preferences_desktopNotifications');
}
return notificationLabels[preference];
},
defaultMobileNotification() {
let preference = RocketChat.getUserPreference(Meteor.user(), 'mobileNotifications');
let preference = RocketChat.getUserPreference(Meteor.userId(), 'mobileNotifications');
if (preference === 'default') {
preference = RocketChat.settings.get('Accounts_Default_User_Preferences_mobileNotifications');
}
@ -190,7 +190,7 @@ Template.pushNotificationsFlexTab.events({
'click [data-play]'(e) {
e.preventDefault();
const user = Meteor.user();
const user = Meteor.userId();
let value = Template.instance().form.audioNotificationValue.get();
if (value === '0') {
@ -340,7 +340,7 @@ Template.pushNotificationsPopover.helpers({
return Template.instance().data.options;
},
defaultDesktopNotification() {
let preference = RocketChat.getUserPreference(Meteor.user(), 'desktopNotifications');
let preference = RocketChat.getUserPreference(Meteor.userId(), 'desktopNotifications');
if (preference === 'default') {
preference = RocketChat.settings.get('Accounts_Default_User_Preferences_desktopNotifications');
}

@ -16,6 +16,7 @@ Package.onUse(function(api) {
api.addFiles('client/init.js', 'client');
api.addFiles('server/models/Messages.js');
api.addFiles('server/models/Rooms.js');
api.addFiles('client/methods/setReaction.js', 'client');
api.addFiles('setReaction.js', 'server');

@ -0,0 +1,7 @@
RocketChat.models.Rooms.setReactionsInLastMessage = function(roomId, lastMessage) {
return this.update({ _id: roomId }, { $set: { lastMessage } });
};
RocketChat.models.Rooms.unsetReactionsInLastMessage = function(roomId) {
return this.update({ _id: roomId }, { $unset: { lastMessage: { reactions: 1 } } });
};

@ -61,9 +61,15 @@ Meteor.methods({
if (_.isEmpty(message.reactions)) {
delete message.reactions;
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.unsetReactionsInLastMessage(room._id);
}
RocketChat.models.Messages.unsetReactions(messageId);
RocketChat.callbacks.run('unsetReaction', messageId, reaction);
} else {
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.setReactionsInLastMessage(room._id, message);
}
RocketChat.models.Messages.setReactions(messageId, message.reactions);
RocketChat.callbacks.run('setReaction', messageId, reaction);
}
@ -77,7 +83,9 @@ Meteor.methods({
};
}
message.reactions[reaction].usernames.push(user.username);
if (RocketChat.isTheLastMessage(room, message)) {
RocketChat.models.Rooms.setReactionsInLastMessage(room._id, message);
}
RocketChat.models.Messages.setReactions(messageId, message.reactions);
RocketChat.callbacks.run('setReaction', messageId, reaction);
}

@ -129,3 +129,20 @@
}
}
}
@media (min-width: 1372px) { /* 1440px -68px (eletron menu) */
.sidebar {
flex: 0 0 20%;
width: 20%;
max-width: 20%;
&__toolbar {
justify-content: flex-end;
&-button {
margin: 0 6px;
}
}
}
}

@ -18,7 +18,7 @@ function checkedSelected(property, value, defaultValue = undefined) {
if (defaultValue && defaultValue.hash) {
defaultValue = undefined;
}
return RocketChat.getUserPreference(Meteor.user(), property, defaultValue) === value;
return RocketChat.getUserPreference(Meteor.userId(), property, defaultValue) === value;
}
Template.accountPreferences.helpers({
@ -26,13 +26,13 @@ Template.accountPreferences.helpers({
return (RocketChat.CustomSounds && RocketChat.CustomSounds.getList && RocketChat.CustomSounds.getList()) || [];
},
newMessageNotification() {
return RocketChat.getUserPreference(Meteor.user(), 'newMessageNotification');
return RocketChat.getUserPreference(Meteor.userId(), 'newMessageNotification');
},
newRoomNotification() {
return RocketChat.getUserPreference(Meteor.user(), 'newRoomNotification');
return RocketChat.getUserPreference(Meteor.userId(), 'newRoomNotification');
},
muteFocusedConversations() {
return RocketChat.getUserPreference(Meteor.user(), 'muteFocusedConversations');
return RocketChat.getUserPreference(Meteor.userId(), 'muteFocusedConversations');
},
languages() {
const languages = TAPi18n.getLanguages();
@ -60,7 +60,7 @@ Template.accountPreferences.helpers({
return checkedSelected(property, value, defaultValue);
},
highlights() {
const userHighlights = RocketChat.getUserPreference(Meteor.user(), 'highlights');
const userHighlights = RocketChat.getUserPreference(Meteor.userId(), 'highlights');
return userHighlights ? userHighlights.join(',\n') : undefined;
},
desktopNotificationEnabled() {
@ -70,14 +70,14 @@ Template.accountPreferences.helpers({
return KonchatNotification.notificationStatus.get() === 'denied' || (window.Notification && Notification.permission === 'denied');
},
desktopNotificationDuration() {
const userPref = RocketChat.getUserPreference(Meteor.user(), 'desktopNotificationDuration', 'undefined');
const userPref = RocketChat.getUserPreference(Meteor.userId(), 'desktopNotificationDuration', 'undefined');
return userPref !== 'undefined' ? userPref : undefined;
},
defaultDesktopNotificationDuration() {
return RocketChat.settings.get('Accounts_Default_User_Preferences_desktopNotificationDuration');
},
idleTimeLimit() {
return RocketChat.getUserPreference(Meteor.user(), 'idleTimeLimit');
return RocketChat.getUserPreference(Meteor.userId(), 'idleTimeLimit');
},
defaultIdleTimeLimit() {
return RocketChat.settings.get('Accounts_Default_User_Preferences_idleTimeLimit');
@ -98,15 +98,14 @@ Template.accountPreferences.helpers({
return RocketChat.settings.get('UserData_EnableDownload') !== false;
},
notificationsSoundVolume() {
return RocketChat.getUserPreference(Meteor.user(), 'notificationsSoundVolume');
return RocketChat.getUserPreference(Meteor.userId(), 'notificationsSoundVolume');
},
dontAskAgainList() {
return RocketChat.getUserPreference(Meteor.user(), 'dontAskAgainList');
return RocketChat.getUserPreference(Meteor.userId(), 'dontAskAgainList');
},
});
Template.accountPreferences.onCreated(function() {
const user = Meteor.user();
const settingsTemplate = this.parentTemplate(3);
if (settingsTemplate.child == null) {
@ -115,7 +114,7 @@ Template.accountPreferences.onCreated(function() {
settingsTemplate.child.push(this);
this.useEmojis = new ReactiveVar(RocketChat.getUserPreference(user, 'useEmojis'));
this.useEmojis = new ReactiveVar(RocketChat.getUserPreference(Meteor.userId(), 'useEmojis'));
let instance = this;
@ -172,7 +171,7 @@ Template.accountPreferences.onCreated(function() {
}
// if highlights changed we need page reload
const highlights = RocketChat.getUserPreference(Meteor.user(), 'highlights');
const highlights = RocketChat.getUserPreference(Meteor.userId(), 'highlights');
if (highlights && highlights.join('\n') !== data.highlights.join('\n')) {
reload = true;
}

@ -65,7 +65,7 @@ Template.avatarPrompt.events({
if (s.trim($('#avatarurl').val())) {
Meteor.call('setAvatarFromService', $('#avatarurl').val(), '', this.service, function(err) {
if (err) {
if (err.details.timeToReset && err.details.timeToReset) {
if (err.details && err.details.timeToReset) {
toastr.error(t('error-too-many-requests', {
seconds: parseInt(err.details.timeToReset / 1000),
}));

@ -474,7 +474,7 @@ Template.admin.events({
}
});
},
'click .rc-header__section-button .remove-custom-oauth'() {
'click .remove-custom-oauth'() {
const name = this.section.replace('Custom OAuth: ', '');
const config = {
title: TAPi18n.__('Are_you_sure'),

@ -3,6 +3,39 @@ import _ from 'underscore';
import moment from 'moment';
import { DateFormat } from 'meteor/rocketchat:lib';
async function renderPdfToCanvas(canvasId, pdfLink) {
if (navigator.userAgent.toLowerCase().indexOf('safari/') > -1) {
const [, version] = /Version\/([0-9]+)/.exec(navigator.userAgent) || [null, 0];
if (version <= 12) {
return;
}
}
if (!pdfLink || /\.pdf$/i.test(pdfLink)) { return; }
const canvas = document.getElementById(canvasId);
if (!canvas) { return; }
const pdfjsLib = await import('pdfjs-dist');
pdfjsLib.GlobalWorkerOptions.workerSrc = `${ Meteor.absoluteUrl() }node_modules/pdfjs-dist/build/pdf.worker.js`;
const loader = document.getElementById('js-loading-${canvasId}');
if (loader) { loader.style.display = 'block'; }
const pdf = await pdfjsLib.getDocument(pdfLink);
const page = await pdf.getPage(1);
const scale = 0.5;
const viewport = page.getViewport(scale);
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({
canvasContext: context,
viewport,
});
if (loader) { loader.style.display = 'none'; }
canvas.style.maxWidth = '-webkit-fill-available';
canvas.style.maxWidth = '-moz-available';
canvas.style.display = 'block';
}
Template.message.helpers({
encodeURI(text) {
return encodeURI(text);
@ -26,8 +59,7 @@ Template.message.helpers({
}
},
roleTags() {
const user = Meteor.user();
if (!RocketChat.settings.get('UI_DisplayRoles') || RocketChat.getUserPreference(user, 'hideRoles')) {
if (!RocketChat.settings.get('UI_DisplayRoles') || RocketChat.getUserPreference(Meteor.userId(), 'hideRoles')) {
return [];
}
@ -364,7 +396,10 @@ Template.message.onCreated(function() {
});
Template.message.onViewRendered = function(context) {
return this._domrange.onAttached(function(domRange) {
return this._domrange.onAttached((domRange) => {
if (context.file && context.file.type === 'application/pdf') {
Meteor.defer(() => { renderPdfToCanvas(context.file._id, context.attachments[0].title_link); });
}
const currentNode = domRange.lastNode();
const currentDataset = currentNode.dataset;
const getPreviousSentMessage = (currentNode) => {

@ -267,7 +267,7 @@ Template.messageBox.helpers({
return RocketChat.Layout.isEmbedded();
},
isEmojiEnable() {
return RocketChat.getUserPreference(Meteor.user(), 'useEmojis');
return RocketChat.getUserPreference(Meteor.userId(), 'useEmojis');
},
dataReply() {
return Template.instance().dataReply.get();

@ -44,5 +44,7 @@ Package.onUse(function(api) {
api.addFiles('startup/messageBoxActions.js', 'client');
api.addAssets('../../node_modules/pdfjs-dist/build/pdf.worker.js', 'client');
api.export('renderMessageBody');
});

@ -13,7 +13,16 @@ Template.roomList.helpers({
if (this.anonymous) {
return RocketChat.models.Rooms.find({ t: 'c' }, { sort: { name: 1 } });
}
const user = Meteor.userId();
const user = RocketChat.models.Users.findOne(Meteor.userId(), {
fields: {
'settings.preferences.sidebarSortby': 1,
'settings.preferences.sidebarShowFavorites': 1,
'settings.preferences.sidebarShowUnread': 1,
'services.tokenpass': 1,
},
});
const sortBy = RocketChat.getUserPreference(user, 'sidebarSortby') || 'alphabetical';
const query = {
open: true,

@ -37,7 +37,7 @@ Template.sideNav.helpers({
},
sidebarHideAvatar() {
return RocketChat.getUserPreference(Meteor.user(), 'sidebarHideAvatar');
return RocketChat.getUserPreference(Meteor.userId(), 'sidebarHideAvatar');
},
});

@ -1,18 +1,18 @@
/* globals popover */
const checked = function(prop, field) {
const user = Meteor.userId();
const userId = Meteor.userId();
if (prop === 'sidebarShowFavorites') {
return RocketChat.getUserPreference(user, 'sidebarShowFavorites');
return RocketChat.getUserPreference(userId, 'sidebarShowFavorites');
}
if (prop === 'sidebarGroupByType') {
return RocketChat.getUserPreference(user, 'sidebarGroupByType');
return RocketChat.getUserPreference(userId, 'sidebarGroupByType');
}
if (prop === 'sidebarShowUnread') {
return RocketChat.getUserPreference(user, 'sidebarShowUnread');
return RocketChat.getUserPreference(userId, 'sidebarShowUnread');
}
if (prop === 'sidebarSortby') {
return (RocketChat.getUserPreference(user, 'sidebarSortby') || 'alphabetical') === field;
return (RocketChat.getUserPreference(userId, 'sidebarSortby') || 'alphabetical') === field;
}
};

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

Loading…
Cancel
Save