Resolve conflicts

pull/6158/head
Maki Nishifuji 8 years ago
commit 1d051ddb00
  1. 2
      .docker/Dockerfile
  2. 44
      .github/ISSUE_TEMPLATE.md
  3. 2
      .github/changelog.js
  4. 7
      .gitignore
  5. 1
      .meteor/.finished-upgraders
  6. 34
      .meteor/packages
  7. 2
      .meteor/release
  8. 85
      .meteor/versions
  9. 26
      .openshift/rocket-chat-ephemeral.json
  10. 64
      .openshift/rocket-chat-persistent.json
  11. 5
      .postcssrc
  12. 2
      .sandstorm/sandstorm-pkgdef.capnp
  13. 243
      .scripts/set-version.js
  14. 2
      .snapcraft/candidate/snapcraft.yaml
  15. 2
      .snapcraft/edge/snapcraft.yaml
  16. 2
      .snapcraft/stable/snapcraft.yaml
  17. 221
      .stylelintrc
  18. 6
      .travis/setartname.sh
  19. 2
      .travis/snap.sh
  20. 273
      HISTORY.md
  21. 8
      README.md
  22. 1
      app.json
  23. 4
      client/lib/handleError.js
  24. 18
      client/methods/deleteMessage.js
  25. 13
      client/routes/router.js
  26. 32
      example-build-run.sh
  27. 16
      example-build.sh
  28. 5669
      package-lock.json
  29. 97
      package.json
  30. 4
      packages/meteor-accounts-saml/saml_client.js
  31. 4
      packages/meteor-accounts-saml/saml_server.js
  32. 17
      packages/meteor-accounts-saml/saml_utils.js
  33. 44
      packages/meteor-autocomplete/client/autocomplete-client.js
  34. 1
      packages/meteor-autocomplete/client/collection.js
  35. 3
      packages/meteor-autocomplete/client/templates.js
  36. 13
      packages/meteor-autocomplete/package.js
  37. 2
      packages/rocketchat-2fa/client/accountSecurity.html
  38. 22
      packages/rocketchat-action-links/client/stylesheets/actionLinks.css
  39. 3
      packages/rocketchat-action-links/package.js
  40. 28
      packages/rocketchat-analytics/client/loadScript.js
  41. 2
      packages/rocketchat-analytics/client/trackEvents.js
  42. 26
      packages/rocketchat-analytics/server/settings.js
  43. 5
      packages/rocketchat-api/server/api.js
  44. 103
      packages/rocketchat-api/server/v1/channels.js
  45. 85
      packages/rocketchat-api/server/v1/chat.js
  46. 106
      packages/rocketchat-api/server/v1/groups.js
  47. 157
      packages/rocketchat-api/server/v1/im.js
  48. 67
      packages/rocketchat-api/server/v1/users.js
  49. 48
      packages/rocketchat-authorization/client/stylesheets/permissions.css
  50. 14
      packages/rocketchat-authorization/client/usersNameChanged.js
  51. 2
      packages/rocketchat-authorization/client/views/permissions.html
  52. 8
      packages/rocketchat-authorization/client/views/permissions.js
  53. 7
      packages/rocketchat-authorization/package.js
  54. 3
      packages/rocketchat-authorization/server/startup.js
  55. 6
      packages/rocketchat-autolinker/client/client.js
  56. 4
      packages/rocketchat-autolinker/package.js
  57. 0
      packages/rocketchat-autolinker/server/settings.js
  58. 2
      packages/rocketchat-autotranslate/client/lib/tabBar.js
  59. 41
      packages/rocketchat-autotranslate/client/stylesheets/autotranslate.css
  60. 3
      packages/rocketchat-autotranslate/package.js
  61. 4
      packages/rocketchat-cas/client/cas_client.js
  62. 7
      packages/rocketchat-cas/package.js
  63. 0
      packages/rocketchat-cas/server/cas_rocketchat.js
  64. 6
      packages/rocketchat-cas/server/cas_server.js
  65. 9
      packages/rocketchat-channel-settings/client/lib/ChannelSettings.js
  66. 2
      packages/rocketchat-channel-settings/client/startup/tabBar.js
  67. 8
      packages/rocketchat-channel-settings/client/startup/trackSettingsChange.js
  68. 76
      packages/rocketchat-channel-settings/client/stylesheets/channel-settings.css
  69. 174
      packages/rocketchat-channel-settings/client/views/channelSettings.html
  70. 33
      packages/rocketchat-channel-settings/client/views/channelSettings.js
  71. 3
      packages/rocketchat-channel-settings/package.js
  72. 34
      packages/rocketchat-channel-settings/server/functions/saveRoomName.js
  73. 10
      packages/rocketchat-chatops/client/tabBar.js
  74. 0
      packages/rocketchat-colors/client/client.js
  75. 12
      packages/rocketchat-colors/client/style.css
  76. 6
      packages/rocketchat-colors/package.js
  77. 0
      packages/rocketchat-colors/server/settings.js
  78. 6
      packages/rocketchat-cors/cors.js
  79. 6
      packages/rocketchat-custom-oauth/client/custom_oauth_client.js
  80. 4
      packages/rocketchat-custom-oauth/package.js
  81. 0
      packages/rocketchat-custom-oauth/server/custom_oauth_server.js
  82. 73
      packages/rocketchat-custom-sounds/assets/stylesheets/customSoundsAdmin.css
  83. 0
      packages/rocketchat-custom-sounds/client/admin/adminSoundEdit.html
  84. 0
      packages/rocketchat-custom-sounds/client/admin/adminSoundInfo.html
  85. 0
      packages/rocketchat-custom-sounds/client/admin/adminSounds.html
  86. 4
      packages/rocketchat-custom-sounds/client/admin/adminSounds.js
  87. 0
      packages/rocketchat-custom-sounds/client/admin/route.js
  88. 2
      packages/rocketchat-custom-sounds/client/admin/soundEdit.html
  89. 0
      packages/rocketchat-custom-sounds/client/admin/soundEdit.js
  90. 0
      packages/rocketchat-custom-sounds/client/admin/soundInfo.html
  91. 0
      packages/rocketchat-custom-sounds/client/admin/soundInfo.js
  92. 0
      packages/rocketchat-custom-sounds/client/admin/startup.js
  93. 25
      packages/rocketchat-custom-sounds/package.js
  94. 3
      packages/rocketchat-custom-sounds/server/methods/uploadCustomSound.js
  95. 5
      packages/rocketchat-dolphin/login-button.css
  96. 2
      packages/rocketchat-drupal/login-button.css
  97. 4
      packages/rocketchat-emoji-custom/admin/adminEmoji.js
  98. 97
      packages/rocketchat-emoji-custom/assets/stylesheets/emojiCustomAdmin.css
  99. 2
      packages/rocketchat-emoji-custom/client/lib/emojiCustom.js
  100. 3
      packages/rocketchat-emoji-custom/package.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,6 +1,6 @@
FROM rocketchat/base:4
ENV RC_VERSION 0.57.0-develop
ENV RC_VERSION 0.59.0-develop
MAINTAINER buildmaster@rocket.chat

@ -1,6 +1,40 @@
<!-- INSTRUCTION: Complete the information below from your Administration page -->
<!--
Rocket.Chat Version:
Running Instances:
DB Replicaset OpLog:
Node Version:
Please see our guide for opening issues: https://rocket.chat/docs/contributing/reporting-issues
If you have questions or are looking for help/support please see: https://rocket.chat/docs/getting-support
If you are experiencing a bug please search our issues to be sure it is not already present: https://github.com/RocketChat/Rocket.Chat/issues
-->
### Description:
<!-- Description of the issue -->
### Server Setup Information:
* Version of Rocket.Chat Server:
* Operating System:
* Deployment Method(snap/docker/tar/etc):
* Number of Running Instances:
* DB Replicaset Oplog:
* Node Version:
### Steps to Reproduce:
1. <!-- First Step -->
2. <!-- Second Step -->
3. <!-- and so on... -->
### Expected behavior:
<!-- What you expect to happen -->
### Actual behavior:
<!-- What actually happens -->
### Relevant logs:
<!-- Logs from both server and browser -->
<!-- For more information about collecting logs please see: https://rocket.chat/docs/contributing/reporting-issues#gathering-logs -->

@ -70,7 +70,7 @@ var writerOpts = {
// GitHub issue URLs.
commit.subject = commit.subject.replace(/#([0-9]+)/g, function(_, issue) {
issues.push(issue);
return '[#' + issue + '](' + gitUrl + '/issue/' + issue + ')';
return '[#' + issue + '](' + gitUrl + '/issues/' + issue + ')';
});
// GitHub user URLs.
commit.subject = commit.subject.replace(/@([a-zA-Z0-9_]+)/g, '[@$1](https://github.com/$1)');

7
.gitignore vendored

@ -3,6 +3,8 @@
**/node_modules/*
**/tmp/*
**/.meteor/dev_bundle
**/.meteor/local*
**/.meteor/meteorite
/private/certs/*
*.bak
*.iml
@ -34,13 +36,10 @@
.env
.externalToolBuilders
.idea
.vscode
.loadpath
.map
.metadata
.meteor/local*
.meteor/meteorite
.meteor/dev_bundle
packages/rocketchat-livechat/app/.meteor/dev_bundle
packages/rocketchat-livechat/assets/rocketchat-livechat.min.js
.mule
.pmd

@ -15,3 +15,4 @@ notices-for-facebook-graph-api-2
1.4.0-remove-old-dev-bundle-link
1.4.1-add-shell-server-package
1.4.3-split-account-service-packages
1.5-add-dynamic-import-package

@ -4,37 +4,36 @@
# but you can also edit it by hand.
rocketchat:cors
accounts-facebook@1.1.1
accounts-github@1.2.1
accounts-google@1.1.2
accounts-meteor-developer@1.2.1
accounts-password@1.3.6
accounts-twitter@1.2.1
accounts-facebook@1.2.1
accounts-github@1.3.0
accounts-google@1.2.0
accounts-meteor-developer@1.3.0
accounts-password@1.4.0
accounts-twitter@1.3.0
blaze-html-templates
check@1.2.5
coffeescript@1.11.1_4
ddp-rate-limiter@1.0.7
ecmascript@0.7.3
ecmascript@0.8.1
ejson@1.0.13
email@1.2.1
email@1.2.3
fastclick@1.0.13
http@1.2.12
jquery@1.11.10
less@2.7.9
logging@1.1.17
meteor-base@1.0.4
meteor-base@1.1.0
mobile-experience@1.0.4
mongo@1.1.17
mongo@1.1.19
random@1.0.10
rate-limit@1.0.8
reactive-dict@1.1.8
reactive-dict@1.1.9
reactive-var@1.0.11
reload@1.1.11
service-configuration@1.0.11
session@1.1.7
shell-server@0.2.3
shell-server@0.2.4
spacebars
standard-minifier-js@2.0.0
standard-minifier-js@2.1.1
tracker@1.1.3
rocketchat:2fa
@ -63,6 +62,7 @@ rocketchat:file
rocketchat:file-upload
rocketchat:github-enterprise
rocketchat:gitlab
rocketchat:google-vision
rocketchat:highlight-words
rocketchat:iframe-login
rocketchat:importer
@ -73,6 +73,7 @@ rocketchat:importer-slack
rocketchat:integrations
rocketchat:internal-hubot
rocketchat:irc
rocketchat:issuelinks
rocketchat:katex
rocketchat:ldap
rocketchat:lib
@ -99,6 +100,7 @@ rocketchat:slackbridge
rocketchat:slashcommands-archive
rocketchat:slashcommands-asciiarts
rocketchat:slashcommands-create
rocketchat:slashcommands-help
rocketchat:slashcommands-invite
rocketchat:slashcommands-invite-all
rocketchat:slashcommands-join
@ -110,6 +112,7 @@ rocketchat:slashcommands-mute
rocketchat:slashcommands-open
rocketchat:slashcommands-topic
rocketchat:slashcommands-unarchive
rocketchat:slider
rocketchat:smarsh-connector
rocketchat:spotify
rocketchat:statistics
@ -150,7 +153,7 @@ jalik:ufs-gridfs
jparker:gravatar
kadira:blaze-layout
kadira:flow-router
kenton:accounts-sandstorm
#kenton:accounts-sandstorm
mizzao:autocomplete
mizzao:timesync
mrt:reactive-store
@ -172,3 +175,4 @@ yasaricli:slugify
yasinuslu:blaze-meta
deepwell:bootstrap-datepicker2
rocketchat:postcss
dynamic-import@0.1.1

@ -1 +1 @@
METEOR@1.4.4.2
METEOR@1.5.1

@ -1,45 +1,49 @@
accounts-base@1.2.17
accounts-facebook@1.1.1
accounts-github@1.2.1
accounts-google@1.1.2
accounts-meteor-developer@1.2.1
accounts-base@1.3.1
accounts-facebook@1.2.1
accounts-github@1.3.0
accounts-google@1.2.0
accounts-meteor-developer@1.3.0
accounts-oauth@1.1.15
accounts-password@1.3.6
accounts-twitter@1.2.1
accounts-password@1.4.0
accounts-twitter@1.3.0
aldeed:simple-schema@1.5.3
allow-deny@1.0.5
allow-deny@1.0.6
autoupdate@1.3.12
babel-compiler@6.18.2
babel-compiler@6.19.4
babel-runtime@1.0.1
base64@1.0.10
binary-heap@1.0.10
blaze@2.3.2
blaze-html-templates@1.1.2
blaze-tools@1.0.10
boilerplate-generator@1.0.11
boilerplate-generator@1.1.1
caching-compiler@1.1.9
caching-html-compiler@1.1.2
callback-hook@1.0.10
cfs:http-methods@0.0.32
check@1.2.5
coffeescript@1.12.3_1
coffeescript@1.12.7_1
coffeescript-compiler@1.12.7_1
dandv:caret-position@2.1.1
ddp@1.2.5
ddp-client@1.3.4
ddp-common@1.2.8
ddp@1.3.0
ddp-client@2.0.0
ddp-common@1.2.9
ddp-rate-limiter@1.0.7
ddp-server@1.3.14
ddp-server@2.0.0
deepwell:bootstrap-datepicker2@1.3.0
deps@1.0.12
diff-sequence@1.0.7
dispatch:run-as-user@1.1.1
ecmascript@0.7.3
ecmascript-runtime@0.3.15
dynamic-import@0.1.1
ecmascript@0.8.2
ecmascript-runtime@0.4.1
ecmascript-runtime-client@0.4.3
ecmascript-runtime-server@0.4.1
edgee:slingshot@0.7.1
ejson@1.0.13
email@1.2.1
email@1.2.3
emojione:emojione@2.2.6
facebook-oauth@1.3.0
facebook-oauth@1.3.2
fastclick@1.0.13
francocatena:status@1.5.3
geojson-utils@1.0.10
@ -59,7 +63,6 @@ jparker:gravatar@0.5.1
jquery@1.11.10
kadira:blaze-layout@2.3.0
kadira:flow-router@2.12.1
kenton:accounts-sandstorm@0.6.0
konecty:change-case@2.3.0
konecty:delayed-task@1.0.0
konecty:mongo-counter@0.0.5_3
@ -69,46 +72,44 @@ konecty:user-presence@1.2.9
launch-screen@1.1.1
less@2.7.9
livedata@1.0.18
localstorage@1.0.12
localstorage@1.1.1
logging@1.1.17
matb33:collection-hooks@0.8.4
mdg:validation-error@0.5.1
meteor@1.6.1
meteor-base@1.0.4
meteor@1.7.1
meteor-base@1.1.0
meteor-developer-oauth@1.2.0
meteorhacks:inject-initial@1.0.4
meteorhacks:meteorx@1.4.1
meteorspark:util@0.2.0
minifier-css@1.2.16
minifier-js@2.0.0
minimongo@1.0.23
minifier-js@2.1.1
minimongo@1.2.1
mizzao:autocomplete@0.5.1
mizzao:timesync@0.3.4
mobile-experience@1.0.4
mobile-status-bar@1.0.14
modules@0.8.2
modules-runtime@0.7.10
mongo@1.1.17
modules@0.9.4
modules-runtime@0.8.0
mongo@1.1.22
mongo-id@1.0.6
mongo-livedata@1.0.12
mrt:reactive-store@0.0.1
mystor:device-detection@0.2.0
nimble:restivus@0.8.12
nooitaf:colors@1.1.2_1
npm-bcrypt@0.9.2
npm-mongo@2.2.24
npm-bcrypt@0.9.3
npm-mongo@2.2.30
oauth@1.1.13
oauth1@1.1.11
oauth2@1.1.11
observe-sequence@1.0.16
ordered-dict@1.0.9
ostrio:cookies@2.2.1
pauli:accounts-linkedin@2.1.2
ostrio:cookies@2.2.2
pauli:accounts-linkedin@2.1.3
pauli:linkedin-oauth@1.1.0
peerlibrary:aws-sdk@2.4.9_1
peerlibrary:blocking@0.5.2
percolate:synced-cron@1.3.2
promise@0.8.8
promise@0.8.9
raix:eventemitter@0.1.3
raix:eventstate@0.0.4
raix:handlebar-helpers@0.2.5
@ -116,7 +117,7 @@ raix:push@3.0.3-rc.7
raix:ui-dropped-event@0.0.7
random@1.0.10
rate-limit@1.0.8
reactive-dict@1.1.8
reactive-dict@1.1.9
reactive-var@1.0.11
reload@1.1.11
retry@1.0.9
@ -148,6 +149,7 @@ rocketchat:file@0.0.1
rocketchat:file-upload@0.0.1
rocketchat:github-enterprise@0.0.1
rocketchat:gitlab@0.0.1
rocketchat:google-vision@0.0.1
rocketchat:highlight-words@0.0.1
rocketchat:i18n@0.0.1
rocketchat:iframe-login@1.0.0
@ -159,6 +161,7 @@ rocketchat:importer-slack@0.0.1
rocketchat:integrations@0.0.1
rocketchat:internal-hubot@0.0.1
rocketchat:irc@0.0.2
rocketchat:issuelinks@0.0.1
rocketchat:katex@0.0.1
rocketchat:ldap@0.0.1
rocketchat:ldapjs@1.0.0
@ -190,6 +193,7 @@ rocketchat:slackbridge@0.0.1
rocketchat:slashcommands-archive@0.0.1
rocketchat:slashcommands-asciiarts@0.0.1
rocketchat:slashcommands-create@0.0.1
rocketchat:slashcommands-help@0.0.1
rocketchat:slashcommands-invite@0.0.1
rocketchat:slashcommands-invite-all@0.0.1
rocketchat:slashcommands-join@0.0.1
@ -201,6 +205,7 @@ rocketchat:slashcommands-mute@0.0.1
rocketchat:slashcommands-open@0.0.1
rocketchat:slashcommands-topic@0.0.1
rocketchat:slashcommands-unarchive@0.0.1
rocketchat:slider@0.0.1
rocketchat:smarsh-connector@0.0.1
rocketchat:sms@0.0.1
rocketchat:spotify@0.0.1
@ -226,13 +231,13 @@ routepolicy@1.0.12
service-configuration@1.0.11
session@1.1.7
sha@1.0.9
shell-server@0.2.3
shell-server@0.2.4
simple:json-routes@2.1.0
smoral:sweetalert@1.1.1
spacebars@1.0.15
spacebars-compiler@1.1.2
spacebars-compiler@1.1.3
srp@1.0.10
standard-minifier-js@2.0.0
standard-minifier-js@2.1.1
steffo:meteor-accounts-saml@0.0.1
tap:i18n@1.8.2
templating@1.3.2
@ -248,7 +253,7 @@ ui@1.0.13
underscore@1.0.10
underscorestring:underscore.string@3.3.4
url@1.1.0
webapp@1.3.15
webapp@1.3.17
webapp-hashing@1.0.9
yasaricli:slugify@0.0.7
yasinuslu:blaze-meta@0.3.3

@ -262,6 +262,30 @@
"mountPath": "/app/uploads"
}
],
"readinessProbe": {
"httpGet": {
"path": "/api/v1/info",
"port": 3000,
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
},
"livenessProbe": {
"httpGet": {
"path": "/api/v1/info",
"port": 3000,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
},
"terminationMessagePath": "/dev/termination-log",
"imagePullPolicy": "Always"
}
@ -416,4 +440,4 @@
"required": true
}
]
}
}

@ -11,21 +11,21 @@
},
"objects": [
{
"kind": "PersistentVolumeClaim",
"apiVersion": "v1",
"metadata": {
"name": "${DATABASE_SERVICE_NAME}"
},
"spec": {
"accessModes": [
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "${VOLUME_CAPACITY}"
}
"kind": "PersistentVolumeClaim",
"apiVersion": "v1",
"metadata": {
"name": "${DATABASE_SERVICE_NAME}"
},
"spec": {
"accessModes": [
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "${VOLUME_CAPACITY}"
}
}
}
}
},
{
"kind": "DeploymentConfig",
@ -151,7 +151,7 @@
{
"name": "${DATABASE_SERVICE_NAME}-data",
"persistentVolumeClaim": {
"claimName": "${DATABASE_SERVICE_NAME}"
"claimName": "${DATABASE_SERVICE_NAME}"
}
}
],
@ -282,6 +282,30 @@
"mountPath": "/app/uploads"
}
],
"readinessProbe": {
"httpGet": {
"path": "/api/v1/info",
"port": 3000,
"scheme": "HTTP"
},
"initialDelaySeconds": 5,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
},
"livenessProbe": {
"httpGet": {
"path": "/api/v1/info",
"port": 3000,
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"timeoutSeconds": 1,
"periodSeconds": 10,
"successThreshold": 1,
"failureThreshold": 3
},
"terminationMessagePath": "/dev/termination-log",
"imagePullPolicy": "Always"
}
@ -436,11 +460,11 @@
"required": true
},
{
"name": "VOLUME_CAPACITY",
"displayName": "Volume Capacity",
"description": "Volume space available for data, e.g. 512Mi, 2Gi.",
"value": "1Gi",
"required": true
"name": "VOLUME_CAPACITY",
"displayName": "Volume Capacity",
"description": "Volume space available for data, e.g. 512Mi, 2Gi.",
"value": "1Gi",
"required": true
}
]
}

@ -2,6 +2,11 @@
"plugins": {
"postcss-smart-import": {},
"postcss-cssnext": {
"features": {
"customProperties": {
"preserve": true
}
},
"browsers": [
"ie > 10",
"last 2 Edge versions",

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

@ -5,8 +5,7 @@ const fs = require('fs');
const semver = require('semver');
const inquirer = require('inquirer');
const execSync = require('child_process').execSync;
const git = require('simple-git')(process.cwd());
const git = require('simple-git/promise')(process.cwd());
let pkgJson = {};
@ -26,165 +25,99 @@ const files = [
'./.docker/Dockerfile',
'./packages/rocketchat-lib/rocketchat.info'
];
class Actions {
static release_rc() {
function processVersion(version) {
// console.log('Updating files to version ' + version);
files.forEach(function(file) {
const data = fs.readFileSync(file, 'utf8');
fs.writeFileSync(file, data.replace(pkgJson.version, version), 'utf8');
});
execSync('conventional-changelog --config .github/changelog.js -i HISTORY.md -s');
inquirer.prompt([{
type: 'confirm',
message: 'Commit files?',
name: 'commit'
}]).then(function(answers) {
if (!answers.commit) {
return;
}
git.status((error, status) => {
inquirer.prompt([{
type: 'checkbox',
message: 'Select files to commit?',
name: 'files',
choices: status.files.map(file => { return {name: `${ file.working_dir } ${ file.path }`, checked: true}; })
}]).then(function(answers) {
if (answers.files.length) {
git.add(answers.files.map(file => file.slice(2)), () => {
git.commit(`Bump version to ${ version }`, () => {
inquirer.prompt([{
type: 'confirm',
message: `Add tag ${ version }?`,
name: 'tag'
}]).then(function(answers) {
if (answers.tag) {
// TODO: Add annotated tag
git.addTag(version);
// TODO: Push
// Useg GitHub api to create the release with history
}
});
});
});
}
});
});
});
}
inquirer.prompt([{
type: 'list',
message: `The current version is ${ pkgJson.version }. Update to version:`,
name: 'version',
choices: [
semver.inc(pkgJson.version, 'prerelease', 'rc'),
// semver.inc(pkgJson.version, 'patch'),
'custom'
]
}]).then(function(answers) {
if (answers.version === 'custom') {
inquirer.prompt([{
name: 'version',
message: 'Enter your custom version:'
}]).then(function(answers) {
processVersion(answers.version);
});
} else {
processVersion(answers.version);
const readFile = (file) => {
return new Promise((resolve, reject) => {
fs.readFile(file, 'utf8', (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
}
static release_gm() {
function processVersion(version) {
// console.log('Updating files to version ' + version);
files.forEach(function(file) {
const data = fs.readFileSync(file, 'utf8');
fs.writeFileSync(file, data.replace(pkgJson.version, version), 'utf8');
});
execSync('conventional-changelog --config .github/changelog.js -i HISTORY.md -s');
// TODO improve HISTORY generation for GM
inquirer.prompt([{
type: 'confirm',
message: 'Commit files?',
name: 'commit'
}]).then(function(answers) {
if (!answers.commit) {
return;
}
git.status((error, status) => {
inquirer.prompt([{
type: 'checkbox',
message: 'Select files to commit?',
name: 'files',
choices: status.files.map(file => { return {name: `${ file.working_dir } ${ file.path }`, checked: true}; })
}]).then(function(answers) {
if (answers.files.length) {
git.add(answers.files.map(file => file.slice(2)), () => {
git.commit(`Bump version to ${ version }`, () => {
inquirer.prompt([{
type: 'confirm',
message: `Add tag ${ version }?`,
name: 'tag'
}]).then(function(answers) {
if (answers.tag) {
// TODO: Add annotated tag
git.addTag(version);
// TODO: Push
// Useg GitHub api to create the release with history
}
});
});
});
}
});
});
});
}
inquirer.prompt([{
type: 'list',
message: `The current version is ${ pkgJson.version }. Update to version:`,
name: 'version',
choices: [
semver.inc(pkgJson.version, 'patch'),
'custom'
]
}]).then(function(answers) {
if (answers.version === 'custom') {
inquirer.prompt([{
name: 'version',
message: 'Enter your custom version:'
}]).then(function(answers) {
processVersion(answers.version);
});
} else {
processVersion(answers.version);
})
}
const writeFile = (file, data) => {
return new Promise((resolve, reject) => {
fs.writeFile(file, data, 'utf8', (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
}
})
}
git.status((err, status) => {
let selectedVersion;
git.status()
.then(status => {
if (status.current === 'release-candidate') {
Actions.release_rc();
} else if (status.current === 'master') {
Actions.release_gm();
} else {
console.log(`No release action for branch ${ status.current }`);
return semver.inc(pkgJson.version, 'prerelease', 'rc');
}
if (status.current === 'master') {
return semver.inc(pkgJson.version, 'patch');
}
if (status.current === 'develop') {
return semver.inc(semver.inc(pkgJson.version, 'minor'), 'minor')+'-develop';
}
return Promise.reject(`No release action for branch ${ status.current }`);
})
.then(nextVersion => inquirer.prompt([{
type: 'list',
message: `The current version is ${ pkgJson.version }. Update to version:`,
name: 'version',
choices: [
nextVersion,
'custom'
]
}]))
.then(answers => {
if (answers.version === 'custom') {
return inquirer.prompt([{
name: 'version',
message: 'Enter your custom version:'
}]);
}
return answers;
})
.then(({ version }) => {
selectedVersion = version;
return Promise.all(files.map(file => {
return readFile(file)
.then(data => {
return writeFile(file, data.replace(pkgJson.version, version));
});
}));
})
.then(() => {
execSync('conventional-changelog --config .github/changelog.js -i HISTORY.md -s');
return inquirer.prompt([{
type: 'confirm',
message: 'Commit files?',
name: 'commit'
}])
})
.then(answers => {
if (!answers.commit) {
return Promise.reject(answers);
}
return git.status();
})
.then(status => inquirer.prompt([{
type: 'checkbox',
message: 'Select files to commit?',
name: 'files',
choices: status.files.map(file => { return {name: `${ file.working_dir } ${ file.path }`, checked: true}; })
}]))
.then(answers => answers.files.length && git.add(answers.files.map(file => file.slice(2))))
.then(() => git.commit(`Bump version to ${ selectedVersion }`))
.then(() => inquirer.prompt([{
type: 'confirm',
message: `Add tag ${ selectedVersion }?`,
name: 'tag'
}]))
.then(answers => answers.tag && git.addTag(selectedVersion))
.catch((error) => {
console.error(error);
});

@ -39,7 +39,7 @@ apps:
parts:
node:
plugin: nodejs
node-engine: 4.8.1
node-engine: 4.8.3
node-packages:
- promise
- fibers

@ -39,7 +39,7 @@ apps:
parts:
node:
plugin: nodejs
node-engine: 4.8.1
node-engine: 4.8.3
node-packages:
- promise
- fibers

@ -39,7 +39,7 @@ apps:
parts:
node:
plugin: nodejs
node-engine: 4.8.1
node-engine: 4.8.3
node-packages:
- promise
- fibers

@ -1,5 +1,8 @@
{
"rules": {
"plugins": [
"stylelint-order"
],
"rules": {
"at-rule-empty-line-before": [ "always", {
except: [
"blockless-after-same-name-blockless",
@ -43,7 +46,6 @@
"declaration-colon-newline-after": "always-multi-line",
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"declaration-empty-line-before": "never",
"font-family-no-duplicate-names": true,
"function-calc-no-unspaced-operator": true,
"function-comma-newline-after": "always-multi-line",
@ -107,5 +109,220 @@
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
"value-list-max-empty-lines": 0,
"order/properties-order": [
[
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"position",
"z-index",
"top",
"right",
"bottom",
"left"
]
},
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"display",
"visibility",
"float",
"clear",
"overflow",
"overflow-x",
"overflow-y",
"clip",
"zoom",
"flex-direction",
"flex-order",
"flex-pack",
"flex-align",
"flex"
]
},
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"box-sizing",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left"
]
},
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"table-layout",
"empty-cells",
"caption-side",
"border-spacing",
"border-collapse",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image"
]
},
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"content",
"quotes",
"counter-reset",
"counter-increment",
"resize",
"cursor",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"transition",
"transition-delay",
"transition-timing-function",
"transition-duration",
"transition-property",
"transform",
"transform-origin",
"animation",
"animation-name",
"animation-duration",
"animation-play-state",
"animation-timing-function",
"animation-delay",
"animation-iteration-count",
"animation-direction",
"text-align",
"text-align-last",
"vertical-align",
"white-space",
"text-decoration",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-indent",
"text-justify",
"text-transform",
"letter-spacing",
"word-spacing",
"text-outline",
"text-transform",
"text-wrap",
"text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"word-wrap",
"word-break",
"tab-size",
"hyphens",
"pointer-events"
]
},
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"opacity",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"color",
"border",
"border-collapse",
"border-width",
"border-style",
"border-color",
"border-top",
"border-top-width",
"border-top-style",
"border-top-color",
"border-right",
"border-right-width",
"border-right-style",
"border-right-color",
"border-bottom",
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
"border-left",
"border-left-width",
"border-left-style",
"border-left-color",
"border-radius",
"border-top-left-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
"border-image",
"border-image-source",
"border-image-slice",
"border-image-width",
"border-image-outset",
"border-image-repeat",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"background",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"background-color",
"background-image",
"background-repeat",
"background-attachment",
"background-position",
"background-position-x",
"background-position-y",
"background-clip",
"background-origin",
"background-size",
"box-decoration-break",
"box-shadow",
"filter:progid:DXImageTransform.Microsoft.gradient",
"text-shadow"
]
},
{
"emptyLineBefore": "always",
"order": "strict",
"properties": [
"font",
"font-family",
"font-size",
"font-weight",
"font-style",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"line-height"
]
}
],
{ unspecified: "bottomAlphabetical" }
]
}
}

@ -1,6 +1,6 @@
if [[ $TRAVIS_BRANCH ]]
if [[ $TRAVIS_TAG ]]
then
export ARTIFACT_NAME="$(meteor npm run version --silent).$TRAVIS_BUILD_NUMBER"
else
export ARTIFACT_NAME="$(meteor npm run version --silent)"
else
export ARTIFACT_NAME="$(meteor npm run version --silent).$TRAVIS_BUILD_NUMBER"
fi

@ -17,7 +17,7 @@ elif [[ $TRAVIS_TAG ]]; then
RC_VERSION=$TRAVIS_TAG
else
CHANNEL=edge
RC_VERSION=0.57.0-develop
RC_VERSION=0.59.0-develop
fi
echo "Preparing to trigger a snap release for $CHANNEL channel"

@ -1,10 +1,277 @@
<a name="0.56.0"></a>
# NEXT
<a name="0.57.2"></a>
## 0.57.2 (2017-07-14)
### Bug Fixes
- [#7472](https://github.com/RocketChat/Rocket.Chat/pull/7472) Always set LDAP properties on login
- [#7431](https://github.com/RocketChat/Rocket.Chat/pull/7431) Fix Emails in User Admin View
- [#7469](https://github.com/RocketChat/Rocket.Chat/pull/7469) Fix file upload on Slack import
- [#7432](https://github.com/RocketChat/Rocket.Chat/pull/7432) Fix Private Channel List Submit
- [#7403](https://github.com/RocketChat/Rocket.Chat/pull/7403) Fix Unread Bar Disappearing
- [#7443](https://github.com/RocketChat/Rocket.Chat/pull/7443) S3 uploads not working for custom URLs
<a name="0.57.1"></a>
## 0.57.1 (2017-07-06)
- :hand: [#7428](https://github.com/RocketChat/Rocket.Chat/pull/7428) Fix migration of avatars from version 0.57.0
<details>
<summary>Others</summary>
- [#7428](https://github.com/RocketChat/Rocket.Chat/pull/7428) Run avatar migration on startup
</details>
<a name="0.57.0"></a>
# 0.57.0 (2017-07-03)
### Breaking Changes
- [#7095](https://github.com/RocketChat/Rocket.Chat/pull/7095) Internal hubot does not load [hubot-scripts](https://github.com/github/hubot-scripts) anymore.
- :hand: [#7095](https://github.com/RocketChat/Rocket.Chat/pull/7095) Internal hubot does not load [hubot-scripts](https://github.com/github/hubot-scripts) anymore.
### New Features
- [#7085](https://github.com/RocketChat/Rocket.Chat/pull/7085) API method and REST Endpoint for getting a single message by id
- [#6919](https://github.com/RocketChat/Rocket.Chat/pull/6919) Feature/delete any message permission
- [#6938](https://github.com/RocketChat/Rocket.Chat/pull/6938) Improve CI/Docker build/release
- [#7059](https://github.com/RocketChat/Rocket.Chat/pull/7059) Increase unread message count on [@here](https://github.com/here) mention
- [#6921](https://github.com/RocketChat/Rocket.Chat/pull/6921) LDAP: Use variables in User_Data_FieldMap for name mapping
- [#6857](https://github.com/RocketChat/Rocket.Chat/pull/6857) Make channel/group delete call answer to roomName
- [#7080](https://github.com/RocketChat/Rocket.Chat/pull/7080) Migration to add <html> tags to email header and footer
- [#6788](https://github.com/RocketChat/Rocket.Chat/pull/6788) New avatar storage types
- [#6690](https://github.com/RocketChat/Rocket.Chat/pull/6690) Show full name in mentions if use full name setting enabled
- [#6953](https://github.com/RocketChat/Rocket.Chat/pull/6953) Show info about multiple instances at admin page
- [#6605](https://github.com/RocketChat/Rocket.Chat/pull/6605) Start running unit tests
- [#7311](https://github.com/RocketChat/Rocket.Chat/pull/7311) Force use of MongoDB for spotlight queries
### Bug Fixes
- [#7025](https://github.com/RocketChat/Rocket.Chat/pull/7025) Add <html> and </html> to header and footer
- [#7084](https://github.com/RocketChat/Rocket.Chat/pull/7084) Add option to ignore TLS in SMTP server settings
- [#7072](https://github.com/RocketChat/Rocket.Chat/pull/7072) Add support for carriage return in markdown code blocks
- [#6910](https://github.com/RocketChat/Rocket.Chat/pull/6910) Allow image insert from slack through slackbridge
- [#6904](https://github.com/RocketChat/Rocket.Chat/pull/6904) Bugs in `isUserFromParams` helper
- [#6840](https://github.com/RocketChat/Rocket.Chat/pull/6840) Check that username is not in the room when being muted / unmuted
- [#7103](https://github.com/RocketChat/Rocket.Chat/pull/7103) clipboard (permalink, copy, pin, star buttons)
- [#7030](https://github.com/RocketChat/Rocket.Chat/pull/7030) do only store password if LDAP_Login_Fallback is on
- [#7105](https://github.com/RocketChat/Rocket.Chat/pull/7105) edit button on firefox
- [#6935](https://github.com/RocketChat/Rocket.Chat/pull/6935) Error when trying to show preview of undefined filetype
- [#7045](https://github.com/RocketChat/Rocket.Chat/pull/7045) Fix avatar upload via users.setAvatar REST endpoint
- [#6950](https://github.com/RocketChat/Rocket.Chat/pull/6950) Fix badge counter on iOS push notifications
- [#7121](https://github.com/RocketChat/Rocket.Chat/pull/7121) fix bug in preview image
- [#6972](https://github.com/RocketChat/Rocket.Chat/pull/6972) Fix error handling for non-valid avatar URL
- [#6974](https://github.com/RocketChat/Rocket.Chat/pull/6974) Fix login with Meteor saving an object as email address
- [#7104](https://github.com/RocketChat/Rocket.Chat/pull/7104) Fix missing CSS files on production builds
- [#6986](https://github.com/RocketChat/Rocket.Chat/pull/6986) Fix the other tests failing due chimp update
- [#7049](https://github.com/RocketChat/Rocket.Chat/pull/7049) Improve Tests
- [#6968](https://github.com/RocketChat/Rocket.Chat/pull/6968) make channels.create API check for create-c
- [#7044](https://github.com/RocketChat/Rocket.Chat/pull/7044) New screen sharing Chrome extension checking method
- [#6999](https://github.com/RocketChat/Rocket.Chat/pull/6999) overlapping text for users-typing-message
- [#7014](https://github.com/RocketChat/Rocket.Chat/pull/7014) Parse HTML on admin setting's descriptions
- [#6997](https://github.com/RocketChat/Rocket.Chat/pull/6997) Parse markdown links last
- [#7033](https://github.com/RocketChat/Rocket.Chat/pull/7033) Prevent Ctrl key on message field from reloading messages list
- [#6912](https://github.com/RocketChat/Rocket.Chat/pull/6912) Remove room from roomPick setting
- [#6961](https://github.com/RocketChat/Rocket.Chat/pull/6961) SAML: Only set KeyDescriptor when non empty
- [#7023](https://github.com/RocketChat/Rocket.Chat/pull/7023) Sidenav roomlist
- [#6913](https://github.com/RocketChat/Rocket.Chat/pull/6913) Slackbridge text replacements
- [#6903](https://github.com/RocketChat/Rocket.Chat/pull/6903) Updating Incoming Integration Post As Field Not Allowed
- [#6947](https://github.com/RocketChat/Rocket.Chat/pull/6947) Use AWS Signature Version 4 signed URLs for uploads
- [#7012](https://github.com/RocketChat/Rocket.Chat/pull/7012) video message recording dialog is shown in an incorrect position
- [#7157](https://github.com/RocketChat/Rocket.Chat/pull/7157) Fix all reactions having the same username
- [#7215](https://github.com/RocketChat/Rocket.Chat/pull/7215/) Fix the Zapier oAuth return url to the new one
- [#7209](https://github.com/RocketChat/Rocket.Chat/pull/7209) "requirePasswordChange" property not being saved when set to false
- [#7208](https://github.com/RocketChat/Rocket.Chat/pull/7208) Fix oembed previews not being shown
- [#7200](https://github.com/RocketChat/Rocket.Chat/pull/7200) Fix editing others messages
- [#7160](https://github.com/RocketChat/Rocket.Chat/pull/7160) Removing the kadira package install from example build script.
- [#7345](https://github.com/RocketChat/Rocket.Chat/pull/7345) click on image in a message
- [#7207](https://github.com/RocketChat/Rocket.Chat/pull/7207) Fix Block Delete Message After (n) Minutes
- [#7320](https://github.com/RocketChat/Rocket.Chat/pull/7320) Fix jump to unread button
- [#7321](https://github.com/RocketChat/Rocket.Chat/pull/7321) Fix Secret Url
- [#7358](https://github.com/RocketChat/Rocket.Chat/pull/7358) Fix user's customFields not being saved correctly
- [#7352](https://github.com/RocketChat/Rocket.Chat/pull/7352) Improve avatar migration
- [#7304](https://github.com/RocketChat/Rocket.Chat/pull/7304) Proxy upload to correct instance
- [#7379](https://github.com/RocketChat/Rocket.Chat/pull/7379) Message being displayed unescaped
<details>
<summary>Others</summary>
- [#7094](https://github.com/RocketChat/Rocket.Chat/pull/7094) [FIX]Fix the failing tests
- [#7092](https://github.com/RocketChat/Rocket.Chat/pull/7092) [FIX]Fixed typo hmtl -> html
- [#7145](https://github.com/RocketChat/Rocket.Chat/pull/7145) Convert file unsubscribe.coffee to js
- [#7146](https://github.com/RocketChat/Rocket.Chat/pull/7146) Convert hipchat importer to js
- [#7022](https://github.com/RocketChat/Rocket.Chat/pull/7022) Convert irc package to js
- [#7096](https://github.com/RocketChat/Rocket.Chat/pull/7096) Convert Livechat from Coffeescript to JavaScript
- [#6936](https://github.com/RocketChat/Rocket.Chat/pull/6936) Convert meteor-autocomplete package to js
- [#7017](https://github.com/RocketChat/Rocket.Chat/pull/7017) Convert oauth2-server-config package to js
- [#6795](https://github.com/RocketChat/Rocket.Chat/pull/6795) Convert Ui Account Package to Js
- [#6911](https://github.com/RocketChat/Rocket.Chat/pull/6911) Convert ui-admin package to js
- [#6775](https://github.com/RocketChat/Rocket.Chat/pull/6775) Convert WebRTC Package to Js
- [#7018](https://github.com/RocketChat/Rocket.Chat/pull/7018) converted rocketchat-importer
- [#6836](https://github.com/RocketChat/Rocket.Chat/pull/6836) converted rocketchat-ui coffee to js part 2
- [#6976](https://github.com/RocketChat/Rocket.Chat/pull/6976) fix the crashing tests
- [#7055](https://github.com/RocketChat/Rocket.Chat/pull/7055) Ldap: User_Data_FieldMap description
- [#7114](https://github.com/RocketChat/Rocket.Chat/pull/7114) LingoHub based on develop
- [#7005](https://github.com/RocketChat/Rocket.Chat/pull/7005) LingoHub based on develop
- [#6978](https://github.com/RocketChat/Rocket.Chat/pull/6978) LingoHub based on develop
- [#7062](https://github.com/RocketChat/Rocket.Chat/pull/7062) Remove Useless Jasmine Tests
- [#6914](https://github.com/RocketChat/Rocket.Chat/pull/6914) Rocketchat ui message
- [#7006](https://github.com/RocketChat/Rocket.Chat/pull/7006) Rocketchat ui3
- [#6987](https://github.com/RocketChat/Rocket.Chat/pull/6987) rocketchat-importer-slack coffee to js
- [#6735](https://github.com/RocketChat/Rocket.Chat/pull/6735) rocketchat-lib[4] coffee to js
- [#7154](https://github.com/RocketChat/Rocket.Chat/pull/7154) Remove missing CoffeeScript dependencies
- [#7308](https://github.com/RocketChat/Rocket.Chat/pull/7308) Escape error messages
- [#7102](https://github.com/RocketChat/Rocket.Chat/pull/7102) add server methods getRoomNameById
</details>
<details>
<summary>Details</summary>
## 0.57.0-rc.3 (2017-06-28)
### New Features
- [#7311](https://github.com/RocketChat/Rocket.Chat/pull/7311) Force use of MongoDB for spotlight queries
### Bug Fixes
- [#7345](https://github.com/RocketChat/Rocket.Chat/pull/7345) click on image in a message
- [#7207](https://github.com/RocketChat/Rocket.Chat/pull/7207) Fix Block Delete Message After (n) Minutes
- [#7320](https://github.com/RocketChat/Rocket.Chat/pull/7320) Fix jump to unread button
- [#7321](https://github.com/RocketChat/Rocket.Chat/pull/7321) Fix Secret Url
- [#7358](https://github.com/RocketChat/Rocket.Chat/pull/7358) Fix user's customFields not being saved correctly
- [#7352](https://github.com/RocketChat/Rocket.Chat/pull/7352) Improve avatar migration
- [#7304](https://github.com/RocketChat/Rocket.Chat/pull/7304) Proxy upload to correct instance
<details>
<summary>Others</summary>
- [#7308](https://github.com/RocketChat/Rocket.Chat/pull/7308) Escape error messages
</details>
## 0.57.0-rc.2 (2017-06-12)
### Bug Fixes
- [#7215](https://github.com/RocketChat/Rocket.Chat/pull/7215/) Fix the Zapier oAuth return url to the new one
- [#7209](https://github.com/RocketChat/Rocket.Chat/pull/7209) "requirePasswordChange" property not being saved when set to false
- [#7208](https://github.com/RocketChat/Rocket.Chat/pull/7208) Fix oembed previews not being shown
- [#7200](https://github.com/RocketChat/Rocket.Chat/pull/7200) Fix editing others messages
- [#7160](https://github.com/RocketChat/Rocket.Chat/pull/7160) Removing the kadira package install from example build script.
## 0.57.0-rc.1 (2017-06-02)
### Bug Fixes
- [#7157](https://github.com/RocketChat/Rocket.Chat/pull/7157) Fix all reactions having the same username
<details>
<summary>Others</summary>
- [#7154](https://github.com/RocketChat/Rocket.Chat/pull/7154) Remove missing CoffeeScript dependencies
</details>
## 0.57.0-rc.0 (2017-06-01)
### New Features
- [#7085](https://github.com/RocketChat/Rocket.Chat/pull/7085) API method and REST Endpoint for getting a single message by id
- [#6919](https://github.com/RocketChat/Rocket.Chat/pull/6919) Feature/delete any message permission
- [#6938](https://github.com/RocketChat/Rocket.Chat/pull/6938) Improve CI/Docker build/release
- [#7059](https://github.com/RocketChat/Rocket.Chat/pull/7059) Increase unread message count on [@here](https://github.com/here) mention
- [#6921](https://github.com/RocketChat/Rocket.Chat/pull/6921) LDAP: Use variables in User_Data_FieldMap for name mapping
- [#6857](https://github.com/RocketChat/Rocket.Chat/pull/6857) Make channel/group delete call answer to roomName
- [#7080](https://github.com/RocketChat/Rocket.Chat/pull/7080) Migration to add <html> tags to email header and footer
- [#6788](https://github.com/RocketChat/Rocket.Chat/pull/6788) New avatar storage types
- [#6690](https://github.com/RocketChat/Rocket.Chat/pull/6690) Show full name in mentions if use full name setting enabled
- [#6953](https://github.com/RocketChat/Rocket.Chat/pull/6953) Show info about multiple instances at admin page
- [#6605](https://github.com/RocketChat/Rocket.Chat/pull/6605) Start running unit tests
### Bug Fixes
- [#7025](https://github.com/RocketChat/Rocket.Chat/pull/7025) Add <html> and </html> to header and footer
- [#7084](https://github.com/RocketChat/Rocket.Chat/pull/7084) Add option to ignore TLS in SMTP server settings
- [#7072](https://github.com/RocketChat/Rocket.Chat/pull/7072) Add support for carriage return in markdown code blocks
- [#6910](https://github.com/RocketChat/Rocket.Chat/pull/6910) Allow image insert from slack through slackbridge
- [#6904](https://github.com/RocketChat/Rocket.Chat/pull/6904) Bugs in `isUserFromParams` helper
- [#6840](https://github.com/RocketChat/Rocket.Chat/pull/6840) Check that username is not in the room when being muted / unmuted
- [#7103](https://github.com/RocketChat/Rocket.Chat/pull/7103) clipboard (permalink, copy, pin, star buttons)
- [#7030](https://github.com/RocketChat/Rocket.Chat/pull/7030) do only store password if LDAP_Login_Fallback is on
- [#7105](https://github.com/RocketChat/Rocket.Chat/pull/7105) edit button on firefox
- [#6935](https://github.com/RocketChat/Rocket.Chat/pull/6935) Error when trying to show preview of undefined filetype
- [#7045](https://github.com/RocketChat/Rocket.Chat/pull/7045) Fix avatar upload via users.setAvatar REST endpoint
- [#6950](https://github.com/RocketChat/Rocket.Chat/pull/6950) Fix badge counter on iOS push notifications
- [#7121](https://github.com/RocketChat/Rocket.Chat/pull/7121) fix bug in preview image
- [#6972](https://github.com/RocketChat/Rocket.Chat/pull/6972) Fix error handling for non-valid avatar URL
- [#6974](https://github.com/RocketChat/Rocket.Chat/pull/6974) Fix login with Meteor saving an object as email address
- [#7104](https://github.com/RocketChat/Rocket.Chat/pull/7104) Fix missing CSS files on production builds
- [#6986](https://github.com/RocketChat/Rocket.Chat/pull/6986) Fix the other tests failing due chimp update
- [#7049](https://github.com/RocketChat/Rocket.Chat/pull/7049) Improve Tests
- [#6968](https://github.com/RocketChat/Rocket.Chat/pull/6968) make channels.create API check for create-c
- [#7044](https://github.com/RocketChat/Rocket.Chat/pull/7044) New screen sharing Chrome extension checking method
- [#6999](https://github.com/RocketChat/Rocket.Chat/pull/6999) overlapping text for users-typing-message
- [#7014](https://github.com/RocketChat/Rocket.Chat/pull/7014) Parse HTML on admin setting's descriptions
- [#6997](https://github.com/RocketChat/Rocket.Chat/pull/6997) Parse markdown links last
- [#7033](https://github.com/RocketChat/Rocket.Chat/pull/7033) Prevent Ctrl key on message field from reloading messages list
- [#6912](https://github.com/RocketChat/Rocket.Chat/pull/6912) Remove room from roomPick setting
- [#6961](https://github.com/RocketChat/Rocket.Chat/pull/6961) SAML: Only set KeyDescriptor when non empty
- [#7023](https://github.com/RocketChat/Rocket.Chat/pull/7023) Sidenav roomlist
- [#6913](https://github.com/RocketChat/Rocket.Chat/pull/6913) Slackbridge text replacements
- [#6903](https://github.com/RocketChat/Rocket.Chat/pull/6903) Updating Incoming Integration Post As Field Not Allowed
- [#6947](https://github.com/RocketChat/Rocket.Chat/pull/6947) Use AWS Signature Version 4 signed URLs for uploads
- [#7012](https://github.com/RocketChat/Rocket.Chat/pull/7012) video message recording dialog is shown in an incorrect position
<details>
<summary>Others</summary>
- [#7094](https://github.com/RocketChat/Rocket.Chat/pull/7094) [FIX]Fix the failing tests
- [#7092](https://github.com/RocketChat/Rocket.Chat/pull/7092) [FIX]Fixed typo hmtl -> html
- [#7145](https://github.com/RocketChat/Rocket.Chat/pull/7145) Convert file unsubscribe.coffee to js
- [#7146](https://github.com/RocketChat/Rocket.Chat/pull/7146) Convert hipchat importer to js
- [#7022](https://github.com/RocketChat/Rocket.Chat/pull/7022) Convert irc package to js
- [#7096](https://github.com/RocketChat/Rocket.Chat/pull/7096) Convert Livechat from Coffeescript to JavaScript
- [#6936](https://github.com/RocketChat/Rocket.Chat/pull/6936) Convert meteor-autocomplete package to js
- [#7017](https://github.com/RocketChat/Rocket.Chat/pull/7017) Convert oauth2-server-config package to js
- [#6795](https://github.com/RocketChat/Rocket.Chat/pull/6795) Convert Ui Account Package to Js
- [#6911](https://github.com/RocketChat/Rocket.Chat/pull/6911) Convert ui-admin package to js
- [#6775](https://github.com/RocketChat/Rocket.Chat/pull/6775) Convert WebRTC Package to Js
- [#7018](https://github.com/RocketChat/Rocket.Chat/pull/7018) converted rocketchat-importer
- [#6836](https://github.com/RocketChat/Rocket.Chat/pull/6836) converted rocketchat-ui coffee to js part 2
- [#6976](https://github.com/RocketChat/Rocket.Chat/pull/6976) fix the crashing tests
- [#7055](https://github.com/RocketChat/Rocket.Chat/pull/7055) Ldap: User_Data_FieldMap description
- [#7114](https://github.com/RocketChat/Rocket.Chat/pull/7114) LingoHub based on develop
- [#7005](https://github.com/RocketChat/Rocket.Chat/pull/7005) LingoHub based on develop
- [#6978](https://github.com/RocketChat/Rocket.Chat/pull/6978) LingoHub based on develop
- [#7062](https://github.com/RocketChat/Rocket.Chat/pull/7062) Remove Useless Jasmine Tests
- [#6914](https://github.com/RocketChat/Rocket.Chat/pull/6914) Rocketchat ui message
- [#7006](https://github.com/RocketChat/Rocket.Chat/pull/7006) Rocketchat ui3
- [#6987](https://github.com/RocketChat/Rocket.Chat/pull/6987) rocketchat-importer-slack coffee to js
- [#6735](https://github.com/RocketChat/Rocket.Chat/pull/6735) rocketchat-lib[4] coffee to js
</details>
</details>
<a name="0.56.0"></a>
# 0.56.0 (2017-05-15)
### New Features

@ -23,6 +23,7 @@
* [Ubuntu 16.04](#ubuntu-1604)
* [Cloudron.io](#cloudronio)
* [Heroku](#heroku)
* [Helm Kubernetes](#helm-kubernetes)
* [Scalingo](#scalingo)
* [Sloppy.io](#sloppyio)
* [Docker](#docker)
@ -84,7 +85,7 @@ Install Rocket.Chat in seconds on Linux (Ubuntu and others) with:
sudo snap install rocketchat-server
```
[![Rocket.Chat Snap is recommended for Linux deployments](https://github.com/Sing-Li/bbug/raw/master/images/ubuntulogo.png)](https://uappexplorer.com/app/rocketchat-server.rocketchat)
[![Rocket.Chat Snap is recommended for Linux deployments](https://github.com/Sing-Li/bbug/raw/master/images/ubuntulogo.png)](https://uappexplorer.com/snap/ubuntu/rocketchat-server)
Installing snaps is very quick. By running that command you have your full Rocket.Chat server up and running. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when we release new versions.
@ -118,7 +119,7 @@ Get your Rocket.Chat instance hosted in a "as a Service" style. You register and
[![Rocket.Chat on IndieHosters](https://indie.host/signup.png)](https://indiehosters.net/shop/product/rocket-chat-21)
## Ubuntu 16.04
[![Ubuntu Apps Explorer](https://raw.githubusercontent.com/Sing-Li/bbug/master/images/uappexplorer.png)](https://uappexplorer.com/app/rocketchat-server.rocketchat)
[![Ubuntu Apps Explorer](https://raw.githubusercontent.com/Sing-Li/bbug/master/images/uappexplorer.png)](https://uappexplorer.com/snap/ubuntu/rocketchat-server)
Deploy from shell:
@ -137,6 +138,9 @@ Host your own Rocket.Chat server for **FREE** with [One-Click Deploy](https://he
[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/master)
## Helm Kubernetes
Deploy on Kubernetes using the official [helm chart](https://github.com/kubernetes/charts/pull/752).
## Scalingo
Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com)

@ -6,7 +6,6 @@
"keywords": ["meteor", "social", "community", "chat"],
"website": "https://rocket.chat",
"env": {
"NODE_ENV": "production",
"BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git",
"HEROKU_APP_NAME": {
"description": "Please re-enter your App Name from the top.",

@ -9,8 +9,8 @@ this.handleError = function(error, useToastr = true) {
}
if (useToastr) {
return toastr.error(TAPi18n.__(error.error, error.details), error.details && error.details.errorTitle ? TAPi18n.__(error.details.errorTitle) : null);
return toastr.error(_.escapeHTML(TAPi18n.__(error.error, error.details)), error.details && error.details.errorTitle ? _.escapeHTML(TAPi18n.__(error.details.errorTitle)) : null);
}
return TAPi18n.__(error.error, error.details);
return _.escapeHTML(TAPi18n.__(error.error, error.details));
};

@ -1,5 +1,4 @@
import moment from 'moment';
import toastr from 'toastr';
Meteor.methods({
deleteMessage(message) {
@ -22,17 +21,14 @@ Meteor.methods({
return false;
}
const blockDeleteInMinutes = RocketChat.settings.get('Message_AllowDeleting_BlockDeleteInMinutes');
if (!(forceDelete) || (_.isNumber(blockDeleteInMinutes) && blockDeleteInMinutes !== 0)) {
if (message.ts) {
const msgTs = moment(message.ts);
if (msgTs) {
const currentTsDiff = moment().diff(msgTs, 'minutes');
if (currentTsDiff > blockDeleteInMinutes) {
toastr.error(t('error-message-deleting-blocked'));
return false;
}
}
if (!forceDelete && _.isNumber(blockDeleteInMinutes) && blockDeleteInMinutes !== 0) {
const msgTs = moment(message.ts);
const currentTsDiff = moment().diff(msgTs, 'minutes');
if (currentTsDiff > blockDeleteInMinutes) {
return false;
}
}
Tracker.nonreactive(function() {

@ -68,14 +68,6 @@ FlowRouter.route('/home', {
}
});
FlowRouter.route('/changeavatar', {
name: 'changeAvatar',
action() {
BlazeLayout.render('main', {center: 'avatarPrompt'});
}
});
FlowRouter.route('/account/:group?', {
name: 'account',
@ -85,7 +77,10 @@ FlowRouter.route('/account/:group?', {
}
params.group = _.capitalize(params.group, true);
BlazeLayout.render('main', { center: `account${ params.group }` });
}
},
triggersExit: [function() {
$('.main-content').addClass('rc-old');
}]
});
FlowRouter.route('/history/private', {

@ -0,0 +1,32 @@
#!/bin/bash
set -x
set -euvo pipefail
IFS=$'\n\t'
# Requies Node.js version 4.x
# Do not run as root
DEPLOY_DIR=/var/www/rocket.chat
### BUILD
meteor npm install
# on the very first build, meteor build command should fail due to a bug on emojione package (related to phantomjs installation)
# the command below forces the error to happen before build command (not needed on subsequent builds)
set +e
meteor add rocketchat:lib
set -e
meteor build --server-only --directory $DEPLOY_DIR
### RUN
cd $DEPLOY_DIR/bundle/programs/server
npm install
cd $DEPLOY_DIR/bundle
NODE_ENV=production \
PORT=3000 \
ROOT_URL=http://localhost:3000 \
MONGO_URL=mongodb://localhost:27017/rocketchat \
MONGO_OPLOG_URL=mongodb://localhost:27017/local \
node main.js

@ -1,16 +0,0 @@
#!/bin/bash
set -x
set -euvo pipefail
IFS=$'\n\t'
# Build
export NODE_ENV=production
meteor add rocketchat:internal-hubot meteorhacks:kadira
meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat
# Run
export METEOR_SETTINGS=$(cat settings.json)
cd /var/www/rocket.chat/bundle/programs/server
npm install
cd /var/www/rocket.chat/current
pm2 startOrRestart /var/www/rocket.chat/current/pm2.json

5669
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,33 +1,49 @@
{
"name": "Rocket.Chat",
"description": "The Ultimate Open Source WebChat Platform",
"version": "0.57.0-develop",
"version": "0.59.0-develop",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
},
"contributors": [{
"name": "Aaron Ogle",
"email": "aaron.ogle@rocket.chat"
}, {
"name": "Bradley Hilton",
"email": "bradley.hilton@rocket.chat"
}, {
"name": "Diego Sampaio",
"email": "diego.sampaio@rocket.chat"
}, {
"name": "Gabriel Engel",
"email": "gabriel.engel@rocket.chat"
}, {
"name": "Marcelo Schmidt",
"email": "marcelo.schmidt@rocket.chat"
}, {
"name": "Rodrigo Nascimento",
"email": "rodrigo.nascimento@rocket.chat"
}, {
"name": "Sing Li",
"email": "sing.li@rocket.chat"
}],
"contributors": [
{
"name": "Aaron Ogle",
"email": "aaron.ogle@rocket.chat"
},
{
"name": "Bradley Hilton",
"email": "bradley.hilton@rocket.chat"
},
{
"name": "Diego Sampaio",
"email": "diego.sampaio@rocket.chat"
},
{
"name": "Gabriel Engel",
"email": "gabriel.engel@rocket.chat"
},
{
"name": "Guilherme Gazzo",
"email": "guilherme.gazzo@rocket.chat"
},
{
"name": "Karl Prieb",
"email": "karl.priebk@rocket.chat"
},
{
"name": "Marcelo Schmidt",
"email": "marcelo.schmidt@rocket.chat"
},
{
"name": "Rodrigo Nascimento",
"email": "rodrigo.nascimento@rocket.chat"
},
{
"name": "Sing Li",
"email": "sing.li@rocket.chat"
}
],
"mocha": {
"tests": [
"packages/**/*.tests.js"
@ -46,7 +62,7 @@
"start": "meteor npm i && meteor",
"lint": "eslint .",
"lint-fix": "eslint . --fix",
"stylelint": "stylelint packages/**/*.{less,css}",
"stylelint": "stylelint packages/**/*.css",
"test": "node .scripts/start.js",
"deploy": "npm run build && pm2 startOrRestart pm2.json",
"chimp-watch": "chimp --ddp=http://localhost:3000 --watch --mocha --path=tests/end-to-end",
@ -71,30 +87,33 @@
"devDependencies": {
"babel-mocha-es6-compiler": "^0.1.0",
"babel-plugin-array-includes": "^2.0.3",
"chimp": "^0.49.0",
"conventional-changelog": "^1.1.3",
"eslint": "^3.19.0",
"chimp": "^0.49.1",
"conventional-changelog-cli": "^1.3.2",
"eslint": "^4.5.0",
"postcss-cssnext": "^2.11.0",
"postcss-smart-import": "^0.7.2",
"stylelint": "^7.10.1",
"postcss-smart-import": "^0.7.5",
"simple-git": "^1.75.0",
"stylelint": "^8.0.0",
"stylelint-order": "^0.6.0",
"supertest": "^3.0.0"
},
"dependencies": {
"@google-cloud/storage": "^1.1.1",
"aws-sdk": "^2.55.0",
"babel-runtime": "^6.23.0",
"@google-cloud/storage": "^1.2.1",
"aws-sdk": "^2.100.0",
"babel-runtime": "^6.26.0",
"bcrypt": "^1.0.2",
"codemirror": "^5.26.0",
"file-type": "^4.3.0",
"highlight.js": "^9.11.0",
"codemirror": "^5.28.0",
"file-type": "^6.1.0",
"highlight.js": "^9.12.0",
"jquery": "^3.2.1",
"mime-db": "^1.28.0",
"mime-db": "^1.29.0",
"mime-type": "^3.0.5",
"moment": "^2.18.1",
"moment-timezone": "^0.5.13",
"photoswipe": "^4.1.2",
"prom-client": "^9.0.0",
"semver": "^5.3.0",
"toastr": "^2.1.2"
"prom-client": "^10.0.3",
"semver": "^5.4.1",
"toastr": "^2.1.2",
"wolfy87-eventemitter": "^5.2.2"
}
}

@ -61,7 +61,7 @@ const openCenteredPopup = function(url, width, height) {
const left = screenX + (outerWidth - width) / 2;
const top = screenY + (outerHeight - height) / 2;
const features = (`width=${ width },height=${ height
},left=${ left },top=${ top },scrollbars=yes`);
},left=${ left },top=${ top },scrollbars=yes`);
newwindow = window.open(url, 'Login', features);
if (newwindow.focus) {
@ -101,7 +101,7 @@ Accounts.saml.initiateLogin = function(options, callback, dimensions) {
Meteor.loginWithSaml = function(options, callback) {
options = options || {};
const credentialToken = Random.id();
const credentialToken = `id-${ Random.id() }`;
options.credentialToken = credentialToken;
Accounts.saml.initiateLogin(options, function(/*error, result*/) {

@ -21,8 +21,8 @@ RoutePolicy.declare('/_saml/', 'network');
function getSamlProviderConfig(provider) {
if (! provider) {
throw new Meteor.Error('no-saml-provider',
'SAML internal error',
{ method: 'getSamlProviderConfig' });
'SAML internal error',
{ method: 'getSamlProviderConfig' });
}
const samlProvider = function(element) {
return (element.provider === provider);

@ -49,7 +49,7 @@ SAML.prototype.initialize = function(options) {
SAML.prototype.generateUniqueID = function() {
const chars = 'abcdef0123456789';
let uniqueID = '';
let uniqueID = 'id-';
for (let i = 0; i < 20; i++) {
uniqueID += chars.substr(Math.floor((Math.random() * 15)), 1);
}
@ -85,12 +85,12 @@ SAML.prototype.generateAuthorizeRequest = function(req) {
let request =
`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="${ id }" Version="2.0" IssueInstant="${ instant
}" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="${ callbackUrl }" Destination="${
this.options.entryPoint }">` +
this.options.entryPoint }">` +
`<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">${ this.options.issuer }</saml:Issuer>\n`;
if (this.options.identifierFormat) {
request += `<samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Format="${ this.options.identifierFormat
}" AllowCreate="true"></samlp:NameIDPolicy>\n`;
}" AllowCreate="true"></samlp:NameIDPolicy>\n`;
}
request +=
@ -112,7 +112,7 @@ SAML.prototype.generateLogoutRequest = function(options) {
let request = `${ '<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ' +
'xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="' }${ id }" Version="2.0" IssueInstant="${ instant
}" Destination="${ this.options.idpSLORedirectURL }">` +
}" Destination="${ this.options.idpSLORedirectURL }">` +
`<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">${ this.options.issuer }</saml:Issuer>` +
`<saml:NameID Format="${ this.options.identifierFormat }">${ options.nameID }</saml:NameID>` +
'</samlp:LogoutRequest>';
@ -128,7 +128,7 @@ SAML.prototype.generateLogoutRequest = function(options) {
'NameQualifier="http://id.init8.net:8080/openam" ' +
`SPNameQualifier="${ this.options.issuer }" ` +
`Format="${ this.options.identifierFormat }">${
options.nameID }</saml:NameID>` +
options.nameID }</saml:NameID>` +
`<samlp:SessionIndex xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">${ options.sessionIndex }</samlp:SessionIndex>` +
'</samlp:LogoutRequest>';
if (Meteor.settings.debug) {
@ -258,6 +258,10 @@ SAML.prototype.getElement = function(parentElement, elementName) {
return parentElement[`saml2p:${ elementName }`];
} else if (parentElement[`saml2:${ elementName }`]) {
return parentElement[`saml2:${ elementName }`];
} else if (parentElement[`ns0:${ elementName }`]) {
return parentElement[`ns0:${ elementName }`];
} else if (parentElement[`ns1:${ elementName }`]) {
return parentElement[`ns1:${ elementName }`];
}
return parentElement[elementName];
};
@ -314,7 +318,8 @@ SAML.prototype.validateResponse = function(samlResponse, relayState, callback) {
console.log(`Validating response with relay state: ${ xml }`);
}
const parser = new xml2js.Parser({
explicitRoot: true
explicitRoot: true,
xmlns:true
});
parser.parseString(xml, function(err, doc) {

@ -1,5 +1,5 @@
/* globals Deps, getCaretCoordinates*/
const AutoCompleteRecords = new Mongo.Collection('autocompleteRecords');
import AutoCompleteRecords from './collection';
const isServerSearch = function(rule) {
return _.isString(rule.collection);
@ -74,6 +74,11 @@ this.AutoComplete = class {
this.limit = settings.limit || 5;
this.position = settings.position || 'bottom';
this.rules = settings.rules;
this.selector = {
constainer: '.-autocomplete-container',
item: '.-autocomplete-item',
...settings.selector
};
const rules = this.rules;
Object.keys(rules).forEach(key => {
@ -178,7 +183,7 @@ this.AutoComplete = class {
const startpos = this.element.selectionStart;
const val = this.getText().substring(0, startpos);
/*
/*
Matching on multiple expressions.
We always go from a matched state to an unmatched one
before going to a different matched one.
@ -258,8 +263,8 @@ this.AutoComplete = class {
}
onItemHover(doc, e) {
this.tmplInst.$('.-autocomplete-item').removeClass('selected');
$(e.target).closest('.-autocomplete-item').addClass('selected');
this.tmplInst.$(this.selector.item).removeClass('selected');
$(e.target).closest(this.selector.item).addClass('selected');
}
filteredList() {
@ -305,7 +310,7 @@ this.AutoComplete = class {
// Replace text with currently selected item
select() {
const node = this.tmplInst.find('.-autocomplete-item.selected');
const node = this.tmplInst.find(`${ this.selector.item }.selected`);
if (node == null) {
return false;
}
@ -370,13 +375,13 @@ this.AutoComplete = class {
}
/*
/*
Rendering functions
*/
positionContainer() {
// First render; Pick the first item and set css whenever list gets shown
let pos;
let pos = {};
const position = this.$element.position();
const rule = this.matchedRule();
const offset = getCaretCoordinates(this.element, this.element.selectionStart);
@ -384,10 +389,11 @@ this.AutoComplete = class {
// In whole-field positioning, we don't move the container and make it the
// full width of the field.
if (rule && isWholeField(rule)) {
pos = {
left: position.left,
width: this.$element.outerWidth() //position.offsetWidth
};
pos.left = position.left;
if (rule.doNotChangeWidth !== false) {
pos.width = this.$element.outerWidth(); //position.offsetWidth
}
} else { //Normal positioning, at token word
pos = { left: position.left + offset.left };
}
@ -398,36 +404,36 @@ this.AutoComplete = class {
} else {
pos.top = position.top + offset.top + parseInt(this.$element.css('font-size'));
}
this.tmplInst.$('.-autocomplete-container').css(pos);
this.tmplInst.$(this.selector.container).css(pos);
}
ensureSelection() {
// Re-render; make sure selected item is something in the list or none if list empty
const selectedItem = this.tmplInst.$('.-autocomplete-item.selected');
const selectedItem = this.tmplInst.$(`${ this.selector.item }.selected`);
if (!selectedItem.length) {
// Select anything
this.tmplInst.$('.-autocomplete-item:first-child').addClass('selected');
this.tmplInst.$(`${ this.selector.item }:first-child`).addClass('selected');
}
}
// Select next item in list
next() {
const currentItem = this.tmplInst.$('.-autocomplete-item.selected');
const currentItem = this.tmplInst.$(`${ this.selector.item }.selected`);
if (!currentItem.length) {
return;
return this.tmplInst.$(`${ this.selector.item }:first-child`).addClass('selected');
}
currentItem.removeClass('selected');
const next = currentItem.next();
if (next.length) {
next.addClass('selected');
} else { //End of list or lost selection; Go back to first item
this.tmplInst.$('.-autocomplete-item:first-child').addClass('selected');
this.tmplInst.$(`${ this.selector.item }:first-child`).addClass('selected');
}
}
//Select previous item in list
prev() {
const currentItem = this.tmplInst.$('.-autocomplete-item.selected');
const currentItem = this.tmplInst.$(`${ this.selector.item }.selected`);
if (!currentItem.length) {
return; //Don't try to iterate an empty list
}
@ -436,7 +442,7 @@ this.AutoComplete = class {
if (prev.length) {
prev.addClass('selected');
} else { //Beginning of list or lost selection; Go to end of list
this.tmplInst.$('.-autocomplete-item:last-child').addClass('selected');
this.tmplInst.$(`${ this.selector.item }:last-child`).addClass('selected');
}
}

@ -0,0 +1 @@
export default new Mongo.Collection('autocompleteRecords');

@ -62,7 +62,7 @@ Template._autocompleteContainer.destroyed = function() {
Template._autocompleteContainer.events({
// t.data is the AutoComplete instance; `this` is the data item
'click .-autocomplete-item'(e, t) {
'click .-autocomplete-item, click [data-autocomplete]'(e, t) {
t.data.onItemClick(this, e);
},
'mouseenter .-autocomplete-item'(e, t) {
@ -78,3 +78,4 @@ Template._autocompleteContainer.helpers({
return this.matchedRule().noMatchTemplate || Template._noMatch;
}
});
export { acEvents, attributes, autocompleteHelpers };

@ -25,17 +25,4 @@ Package.onUse(function(api) {
], 'server');
api.export('Autocomplete', 'server');
api.export('AutocompleteTest', {testOnly: true});
});
Package.onTest(function(api) {
api.use('mizzao:autocomplete');
api.use('mongo');
api.use('tinytest');
api.addFiles('tests/rule_tests.coffee', 'client');
api.addFiles('tests/regex_tests.coffee', 'client');
api.addFiles('tests/param_tests.coffee', 'client');
api.addFiles('tests/security_tests.coffee');
});

@ -14,7 +14,7 @@
<div class="section-content border-component-color">
<div class="alert pending-background pending-color pending-border">
<strong>
WARNING: Once you enable this, you will not be able to login on the native mobile apps (Rocket.Chat+) using your password until they implement the 2FA.
{{_ "Two-factor_authentication_native_mobile_app_warning"}}
</strong>
</div>
{{#if isEnabled}}

@ -1,25 +1,31 @@
.message {
.actionLinks {
padding: 0;
& .actionLinks {
margin-top: 4px;
margin-bottom: 4px;
padding: 0;
text-align: center;
li {
cursor: pointer;
& li {
position: relative;
display: inline;
padding-right: 2px;
list-style: none;
display: inline;
.action-link {
cursor: pointer;
& .action-link {
margin: 0 2px;
padding: 5px;
border-radius: 7px;
margin: 0 2px;
}
}
li:last-child::after {
& li:last-child::after {
content: none;
}
}

@ -11,14 +11,13 @@ Package.onUse(function(api) {
api.use('rocketchat:lib');
api.use('rocketchat:theme');
api.use('rocketchat:ui');
api.use('less');
api.addFiles('both/lib/actionLinks.js');
api.addFiles('client/lib/actionLinks.js', 'client');
api.addFiles('client/init.js', 'client');
api.addFiles('client/stylesheets/actionLinks.less', 'client');
api.addFiles('client/stylesheets/actionLinks.css', 'client');
api.addFiles('server/actionLinkHandler.js', 'server');
});

@ -2,6 +2,10 @@ Template.body.onRendered(() => {
Tracker.autorun((c) => {
const piwikUrl = RocketChat.settings.get('PiwikAnalytics_enabled') && RocketChat.settings.get('PiwikAnalytics_url');
const piwikSiteId = piwikUrl && RocketChat.settings.get('PiwikAnalytics_siteId');
const piwikPrependDomain = piwikUrl && RocketChat.settings.get('PiwikAnalytics_prependDomain');
const piwikCookieDomain = piwikUrl && RocketChat.settings.get('PiwikAnalytics_cookieDomain');
const piwikDomains = piwikUrl && RocketChat.settings.get('PiwikAnalytics_domains');
const piwikAdditionalTracker = piwikUrl && RocketChat.settings.get('PiwikAdditionalTrackers');
const googleId = RocketChat.settings.get('GoogleAnalytics_enabled') && RocketChat.settings.get('GoogleAnalytics_ID');
if (piwikSiteId || googleId) {
c.stop();
@ -14,7 +18,31 @@ Template.body.onRendered(() => {
window._paq.push(['trackPageView']);
window._paq.push(['enableLinkTracking']);
if (piwikPrependDomain) {
window._paq.push(['setDocumentTitle', `${ window.location.hostname }/${ document.title }`]);
}
const upperLevelDomain = `*.${ window.location.hostname.split('.').slice(1).join('.') }`;
if (piwikCookieDomain) {
window._paq.push(['setCookieDomain', upperLevelDomain]);
}
if (piwikDomains) {
// array
const domainsArray = piwikDomains.split(/\n/);
const domains = [];
for (let i = 0; i < domainsArray.length; i++) {
// only push domain if it contains a non whitespace character.
if (/\S/.test(domainsArray[i])) {
domains.push(`*.${ domainsArray[i].trim() }`);
}
}
window._paq.push(['setDomains', domains]);
}
(() => {
const addTrackers = JSON.parse(piwikAdditionalTracker);
for (let i = 0; i < addTrackers.length; i++) {
const tracker = addTrackers[i];
window._paq.push(['addTracker', `${ tracker['trackerURL'] }piwik.php`, tracker['siteId']]);
}
window._paq.push(['setTrackerUrl', `${ piwikUrl }piwik.php`]);
window._paq.push(['setSiteId', Number.parseInt(piwikSiteId)]);
const d = document;

@ -8,7 +8,7 @@ function trackEvent(category, action, label) {
}
if (!window._paq || window.ga) {
//Trigger the trackPageView manually as the page views don't seem to be tracked
//Trigger the trackPageView manually as the page views are only loaded when the loadScript.js code is executed
FlowRouter.triggers.enter([(route) => {
if (window._paq) {
const http = location.protocol;

@ -18,6 +18,32 @@ RocketChat.settings.addGroup('Analytics', function addSettings() {
i18nLabel: 'Client_ID',
enableQuery
});
this.add('PiwikAdditionalTrackers', '', {
type: 'string',
multiline: true,
public: true,
i18nLabel: 'PiwikAdditionalTrackers',
enableQuery
});
this.add('PiwikAnalytics_prependDomain', false, {
type: 'boolean',
public: true,
i18nLabel: 'PiwikAnalytics_prependDomain',
enableQuery
});
this.add('PiwikAnalytics_cookieDomain', false, {
type: 'boolean',
public: true,
i18nLabel: 'PiwikAnalytics_cookieDomain',
enableQuery
});
this.add('PiwikAnalytics_domains', '', {
type: 'string',
multiline: true,
public: true,
i18nLabel: 'PiwikAnalytics_domains',
enableQuery
});
});
this.section('Analytics_Google', function() {

@ -8,7 +8,8 @@ class API extends Restivus {
this.defaultFieldsToExclude = {
joinCode: 0,
$loki: 0,
meta: 0
meta: 0,
members: 0
};
this._config.defaultOptionsEndpoint = function() {
@ -96,7 +97,7 @@ class API extends Restivus {
endpoints[method] = { action: endpoints[method] };
}
//Add a try/catch for each much
//Add a try/catch for each endpoint
const originalAction = endpoints[method].action;
endpoints[method].action = function() {
this.logger.debug(`${ this.request.method.toUpperCase() }: ${ this.request.url }`);

@ -164,8 +164,6 @@ RocketChat.API.v1.addRoute('channels.delete', { authRequired: true }, {
post() {
const findResult = findChannelByIdOrName({ params: this.requestParams(), checkedArchived: false });
//The find method returns either with the group or the failur
Meteor.runAsUser(this.userId, () => {
Meteor.call('eraseRoom', findResult._id);
});
@ -176,6 +174,35 @@ RocketChat.API.v1.addRoute('channels.delete', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('channels.files', { authRequired: true }, {
get() {
const findResult = findChannelByIdOrName({ params: this.requestParams(), checkedArchived: false });
Meteor.runAsUser(this.userId, () => {
Meteor.call('canAccessRoom', findResult._id, this.userId);
});
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { rid: findResult._id });
const files = RocketChat.models.Uploads.find(ourQuery, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
}).fetch();
return RocketChat.API.v1.success({
files,
count: files.length,
offset,
total: RocketChat.models.Uploads.find(ourQuery).count()
});
}
});
RocketChat.API.v1.addRoute('channels.getIntegrations', { authRequired: true }, {
get() {
if (!RocketChat.authz.hasPermission(this.userId, 'manage-integrations')) {
@ -254,9 +281,11 @@ RocketChat.API.v1.addRoute('channels.history', { authRequired: true }, {
result = Meteor.call('getChannelHistory', { rid: findResult._id, latest: latestDate, oldest: oldestDate, inclusive, count, unreads });
});
return RocketChat.API.v1.success({
messages: result && result.messages ? result.messages : []
});
if (!result) {
return RocketChat.API.v1.unauthorized();
}
return RocketChat.API.v1.success(result);
}
});
@ -332,13 +361,22 @@ RocketChat.API.v1.addRoute('channels.leave', { authRequired: true }, {
RocketChat.API.v1.addRoute('channels.list', { authRequired: true }, {
get: {
//This is like this only to provide an example of how we routes can be defined :X
//This is defined as such only to provide an example of how the routes can be defined :X
action() {
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { t: 'c' });
//Special check for the permissions
if (RocketChat.authz.hasPermission(this.userId, 'view-joined-room')) {
ourQuery.usernames = {
$in: [ this.user.username ]
};
} else if (!RocketChat.authz.hasPermission(this.userId, 'view-c-room')) {
return RocketChat.API.v1.unauthorized();
}
const rooms = RocketChat.models.Rooms.find(ourQuery, {
sort: sort ? sort : { name: 1 },
skip: offset,
@ -379,6 +417,59 @@ RocketChat.API.v1.addRoute('channels.list.joined', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('channels.members', { authRequired: true }, {
get() {
const findResult = findChannelByIdOrName({ params: this.requestParams(), checkedArchived: false });
const { offset, count } = this.getPaginationItems();
const { sort } = this.parseJsonQuery();
const members = RocketChat.models.Rooms.processQueryOptionsOnResult(Array.from(findResult.usernames), {
sort: sort ? sort : -1,
skip: offset,
limit: count
});
return RocketChat.API.v1.success({
members,
count: members.length,
offset,
total: findResult.usernames.length
});
}
});
RocketChat.API.v1.addRoute('channels.messages', { authRequired: true }, {
get() {
const findResult = findChannelByIdOrName({ params: this.requestParams(), checkedArchived: false });
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { rid: findResult._id });
//Special check for the permissions
if (RocketChat.authz.hasPermission(this.userId, 'view-joined-room') && !findResult.usernames.includes(this.user.username)) {
return RocketChat.API.v1.unauthorized();
} else if (!RocketChat.authz.hasPermission(this.userId, 'view-c-room')) {
return RocketChat.API.v1.unauthorized();
}
const messages = RocketChat.models.Messages.find(ourQuery, {
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
}).fetch();
return RocketChat.API.v1.success({
messages,
count: messages.length,
offset,
total: RocketChat.models.Messages.find(ourQuery).count()
});
}
});
RocketChat.API.v1.addRoute('channels.online', { authRequired: true }, {
get() {
const { query } = this.parseJsonQuery();

@ -50,9 +50,30 @@ RocketChat.API.v1.addRoute('chat.getMessage', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('chat.pinMessage', { authRequired: true }, {
post() {
if (!this.bodyParams.messageId || !this.bodyParams.messageId.trim()) {
throw new Meteor.Error('error-messageid-param-not-provided', 'The required "messageId" param is required.');
}
const msg = RocketChat.models.Messages.findOneById(this.bodyParams.messageId);
if (!msg) {
throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.');
}
let pinnedMessage;
Meteor.runAsUser(this.userId, () => pinnedMessage = Meteor.call('pinMessage', msg));
return RocketChat.API.v1.success({
message: pinnedMessage
});
}
});
RocketChat.API.v1.addRoute('chat.postMessage', { authRequired: true }, {
post() {
const messageReturn = processWebhookMessage(this.bodyParams, this.user)[0];
const messageReturn = processWebhookMessage(this.bodyParams, this.user, undefined, true)[0];
if (!messageReturn) {
return RocketChat.API.v1.failure('unknown-error');
@ -66,6 +87,68 @@ RocketChat.API.v1.addRoute('chat.postMessage', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('chat.starMessage', { authRequired: true }, {
post() {
if (!this.bodyParams.messageId || !this.bodyParams.messageId.trim()) {
throw new Meteor.Error('error-messageid-param-not-provided', 'The required "messageId" param is required.');
}
const msg = RocketChat.models.Messages.findOneById(this.bodyParams.messageId);
if (!msg) {
throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.');
}
Meteor.runAsUser(this.userId, () => Meteor.call('starMessage', {
_id: msg._id,
rid: msg.rid,
starred: true
}));
return RocketChat.API.v1.success();
}
});
RocketChat.API.v1.addRoute('chat.unPinMessage', { authRequired: true }, {
post() {
if (!this.bodyParams.messageId || !this.bodyParams.messageId.trim()) {
throw new Meteor.Error('error-messageid-param-not-provided', 'The required "messageId" param is required.');
}
const msg = RocketChat.models.Messages.findOneById(this.bodyParams.messageId);
if (!msg) {
throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.');
}
Meteor.runAsUser(this.userId, () => Meteor.call('unpinMessage', msg));
return RocketChat.API.v1.success();
}
});
RocketChat.API.v1.addRoute('chat.unStarMessage', { authRequired: true }, {
post() {
if (!this.bodyParams.messageId || !this.bodyParams.messageId.trim()) {
throw new Meteor.Error('error-messageid-param-not-provided', 'The required "messageId" param is required.');
}
const msg = RocketChat.models.Messages.findOneById(this.bodyParams.messageId);
if (!msg) {
throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.');
}
Meteor.runAsUser(this.userId, () => Meteor.call('starMessage', {
_id: msg._id,
rid: msg.rid,
starred: false
}));
return RocketChat.API.v1.success();
}
});
RocketChat.API.v1.addRoute('chat.update', { authRequired: true }, {
post() {
check(this.bodyParams, Match.ObjectIncluding({

@ -1,7 +1,7 @@
//Returns the private group subscription IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
function findPrivateGroupByIdOrName({ params, userId, checkedArchived = true }) {
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');
throw new Meteor.Error('error-room-param-not-provided', 'The parameter "roomId" or "roomName" is required');
}
let roomSub;
@ -64,6 +64,18 @@ RocketChat.API.v1.addRoute('groups.addOwner', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('groups.addLeader', { authRequired: true }, {
post() {
const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId });
const user = this.getUserFromParams();
Meteor.runAsUser(this.userId, () => {
Meteor.call('addRoomLeader', findResult.rid, user._id);
});
return RocketChat.API.v1.success();
}
});
//Archives a private group only if it wasn't
RocketChat.API.v1.addRoute('groups.archive', { authRequired: true }, {
post() {
@ -142,6 +154,31 @@ RocketChat.API.v1.addRoute('groups.delete', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('groups.files', { authRequired: true }, {
get() {
const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId, checkedArchived: false });
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { rid: findResult._id });
const files = RocketChat.models.Uploads.find(ourQuery, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
}).fetch();
return RocketChat.API.v1.success({
files,
count: files.length,
offset,
total: RocketChat.models.Uploads.find(ourQuery).count()
});
}
});
RocketChat.API.v1.addRoute('groups.getIntegrations', { authRequired: true }, {
get() {
if (!RocketChat.authz.hasPermission(this.userId, 'manage-integrations')) {
@ -214,9 +251,11 @@ RocketChat.API.v1.addRoute('groups.history', { authRequired: true }, {
result = Meteor.call('getChannelHistory', { rid: findResult.rid, latest: latestDate, oldest: oldestDate, inclusive, count, unreads });
});
return RocketChat.API.v1.success({
messages: result && result.messages ? result.messages : []
});
if (!result) {
return RocketChat.API.v1.unauthorized();
}
return RocketChat.API.v1.success(result);
}
});
@ -296,6 +335,51 @@ RocketChat.API.v1.addRoute('groups.list', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('groups.members', { authRequired: true }, {
get() {
const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId });
const { offset, count } = this.getPaginationItems();
const { sort } = this.parseJsonQuery();
const members = RocketChat.models.Rooms.processQueryOptionsOnResult(Array.from(findResult._room.usernames), {
sort: sort ? sort : -1,
skip: offset,
limit: count
});
return RocketChat.API.v1.success({
members,
count: members.length,
offset,
total: findResult._room.usernames
});
}
});
RocketChat.API.v1.addRoute('groups.messages', { authRequired: true }, {
get() {
const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId });
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { rid: findResult.rid });
const messages = RocketChat.models.Messages.find(ourQuery, {
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
}).fetch();
return RocketChat.API.v1.success({
messages,
count: messages.length,
offset,
total: RocketChat.models.Messages.find(ourQuery).count()
});
}
});
RocketChat.API.v1.addRoute('groups.online', { authRequired: true }, {
get() {
const { query } = this.parseJsonQuery();
@ -373,6 +457,20 @@ RocketChat.API.v1.addRoute('groups.removeOwner', { authRequired: true }, {
}
});
RocketChat.API.v1.addRoute('groups.removeLeader', { authRequired: true }, {
post() {
const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId });
const user = this.getUserFromParams();
Meteor.runAsUser(this.userId, () => {
Meteor.call('removeRoomLeader', findResult.rid, user._id);
});
return RocketChat.API.v1.success();
}
});
RocketChat.API.v1.addRoute('groups.rename', { authRequired: true }, {
post() {
if (!this.bodyParams.name || !this.bodyParams.name.trim()) {

@ -1,46 +1,80 @@
function findDirectMessageRoomById(roomId, userId) {
if (!roomId || !roomId.trim()) {
return RocketChat.API.v1.failure('Body param "roomId" is required');
function findDirectMessageRoom(params, user) {
if ((!params.roomId || !params.roomId.trim()) && (!params.username || !params.username.trim())) {
throw new Meteor.Error('error-room-param-not-provided', 'Body param "roomId" or "username" is required');
}
const roomSub = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(roomId, userId);
const room = RocketChat.getRoomByNameOrIdWithOptionToJoin({
currentUserId: user._id,
nameOrId: params.username || params.roomId,
type: 'd'
});
if (!roomSub || roomSub.t !== 'd') {
return RocketChat.API.v1.failure(`No direct message room found by the id of: ${ roomId }`);
if (!room || room.t !== 'd') {
throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "username" param provided does not match any dirct message');
}
return roomSub;
const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(room._id, user._id);
return {
room,
subscription
};
}
RocketChat.API.v1.addRoute(['dm.close', 'im.close'], { authRequired: true }, {
RocketChat.API.v1.addRoute(['dm.create', 'im.create'], { authRequired: true }, {
post() {
const findResult = findDirectMessageRoomById(this.bodyParams.roomId, this.userId);
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
//The find method returns either with the dm or the failure
if (findResult.statusCode) {
return findResult;
}
return RocketChat.API.v1.success({
room: findResult.room
});
}
});
if (!findResult.open) {
RocketChat.API.v1.addRoute(['dm.close', 'im.close'], { authRequired: true }, {
post() {
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
if (!findResult.subscription.open) {
return RocketChat.API.v1.failure(`The direct message room, ${ this.bodyParams.name }, is already closed to the sender`);
}
Meteor.runAsUser(this.userId, () => {
Meteor.call('hideRoom', findResult.rid);
Meteor.call('hideRoom', findResult.room._id);
});
return RocketChat.API.v1.success();
}
});
RocketChat.API.v1.addRoute(['dm.history', 'im.history'], { authRequired: true }, {
RocketChat.API.v1.addRoute(['dm.files', 'im.files'], { authRequired: true }, {
get() {
const findResult = findDirectMessageRoomById(this.queryParams.roomId, this.userId);
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
//The find method returns either with the group or the failure
if (findResult.statusCode) {
return findResult;
}
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { rid: findResult.room._id });
const files = RocketChat.models.Uploads.find(ourQuery, {
sort: sort ? sort : { name: 1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
}).fetch();
return RocketChat.API.v1.success({
files,
count: files.length,
offset,
total: RocketChat.models.Uploads.find(ourQuery).count()
});
}
});
RocketChat.API.v1.addRoute(['dm.history', 'im.history'], { authRequired: true }, {
get() {
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
let latestDate = new Date();
if (this.queryParams.latest) {
@ -69,11 +103,68 @@ RocketChat.API.v1.addRoute(['dm.history', 'im.history'], { authRequired: true },
let result;
Meteor.runAsUser(this.userId, () => {
result = Meteor.call('getChannelHistory', { rid: findResult.rid, latest: latestDate, oldest: oldestDate, inclusive, count, unreads });
result = Meteor.call('getChannelHistory', {
rid: findResult.room._id,
latest: latestDate,
oldest: oldestDate,
inclusive,
count,
unreads
});
});
if (!result) {
return RocketChat.API.v1.unauthorized();
}
return RocketChat.API.v1.success(result);
}
});
RocketChat.API.v1.addRoute(['dm.members', 'im.members'], { authRequired: true }, {
get() {
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
const { offset, count } = this.getPaginationItems();
const { sort } = this.parseJsonQuery();
const members = RocketChat.models.Rooms.processQueryOptionsOnResult(Array.from(findResult.room.usernames), {
sort: sort ? sort : -1,
skip: offset,
limit: count
});
return RocketChat.API.v1.success({
messages: result && result.messages ? result.messages : []
members,
count: members.length,
offset,
total: findResult.room.usernames
});
}
});
RocketChat.API.v1.addRoute(['dm.messages', 'im.messages'], { authRequired: true }, {
get() {
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
console.log(findResult);
const ourQuery = Object.assign({}, query, { rid: findResult.room._id });
const messages = RocketChat.models.Messages.find(ourQuery, {
sort: sort ? sort : { ts: -1 },
skip: offset,
limit: count,
fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude)
}).fetch();
return RocketChat.API.v1.success({
messages,
count: messages.length,
offset,
total: RocketChat.models.Messages.find(ourQuery).count()
});
}
});
@ -170,19 +261,14 @@ RocketChat.API.v1.addRoute(['dm.list.everyone', 'im.list.everyone'], { authRequi
RocketChat.API.v1.addRoute(['dm.open', 'im.open'], { authRequired: true }, {
post() {
const findResult = findDirectMessageRoomById(this.bodyParams.roomId, this.userId);
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
//The find method returns either with the group or the failure
if (findResult.statusCode) {
return findResult;
}
if (findResult.open) {
if (findResult.subscription.open) {
return RocketChat.API.v1.failure(`The direct message room, ${ this.bodyParams.name }, is already open for the sender`);
}
Meteor.runAsUser(this.userId, () => {
Meteor.call('openRoom', findResult.rid);
Meteor.call('openRoom', findResult.room._id);
});
return RocketChat.API.v1.success();
@ -195,15 +281,10 @@ RocketChat.API.v1.addRoute(['dm.setTopic', 'im.setTopic'], { authRequired: true
return RocketChat.API.v1.failure('The bodyParam "topic" is required');
}
const findResult = findDirectMessageRoomById(this.bodyParams.roomId, this.userId);
//The find method returns either with the group or the failure
if (findResult.statusCode) {
return findResult;
}
const findResult = findDirectMessageRoom(this.requestParams(), this.user);
Meteor.runAsUser(this.userId, () => {
Meteor.call('saveRoomSettings', findResult.rid, 'roomTopic', this.bodyParams.topic);
Meteor.call('saveRoomSettings', findResult.room._id, 'roomTopic', this.bodyParams.topic);
});
return RocketChat.API.v1.success({

@ -19,12 +19,17 @@ RocketChat.API.v1.addRoute('users.create', { authRequired: true }, {
this.bodyParams.joinDefaultChannels = true;
}
if (this.bodyParams.customFields) {
RocketChat.validateCustomFields(this.bodyParams.customFields);
}
const newUserId = RocketChat.saveUser(this.userId, this.bodyParams);
if (this.bodyParams.customFields) {
RocketChat.saveCustomFields(newUserId, this.bodyParams.customFields);
RocketChat.saveCustomFieldsWithoutValidation(newUserId, this.bodyParams.customFields);
}
if (typeof this.bodyParams.active !== 'undefined') {
Meteor.runAsUser(this.userId, () => {
Meteor.call('setUserActiveStatus', newUserId, this.bodyParams.active);
@ -105,6 +110,10 @@ RocketChat.API.v1.addRoute('users.info', { authRequired: true }, {
RocketChat.API.v1.addRoute('users.list', { authRequired: true }, {
get() {
if (!RocketChat.authz.hasPermission(this.userId, 'view-d-room')) {
return RocketChat.API.v1.unauthorized();
}
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
@ -186,7 +195,11 @@ RocketChat.API.v1.addRoute('users.resetAvatar', { authRequired: true }, {
RocketChat.API.v1.addRoute('users.setAvatar', { authRequired: true }, {
post() {
check(this.bodyParams, { avatarUrl: Match.Maybe(String), userId: Match.Maybe(String) });
check(this.bodyParams, Match.ObjectIncluding({
avatarUrl: Match.Maybe(String),
userId: Match.Maybe(String),
username: Match.Maybe(String)
}));
let user;
if (this.isUserFromParams()) {
@ -197,32 +210,34 @@ RocketChat.API.v1.addRoute('users.setAvatar', { authRequired: true }, {
return RocketChat.API.v1.unauthorized();
}
if (this.bodyParams.avatarUrl) {
RocketChat.setUserAvatar(user, this.bodyParams.avatarUrl, '', 'url');
} else {
const Busboy = Npm.require('busboy');
const busboy = new Busboy({ headers: this.request.headers });
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);
}));
Meteor.runAsUser(user._id, () => {
if (this.bodyParams.avatarUrl) {
RocketChat.setUserAvatar(user, this.bodyParams.avatarUrl, '', 'url');
} else {
const Busboy = Npm.require('busboy');
const busboy = new Busboy({ headers: this.request.headers });
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(() => {
RocketChat.setUserAvatar(user, Buffer.concat(imageData), mimetype, 'rest');
callback();
}));
file.on('end', Meteor.bindEnvironment(() => {
RocketChat.setUserAvatar(user, Buffer.concat(imageData), mimetype, 'rest');
callback();
}));
}));
this.request.pipe(busboy);
})();
}
this.request.pipe(busboy);
})();
}
});
return RocketChat.API.v1.success();
}

@ -1,47 +1,61 @@
.permissions-manager {
h2 {
font-weight: bold !important;
font-size: 16px;
& h2 {
margin-top: 1em !important;
margin-bottom: 1em !important;
border-bottom-width: 1px;
font-size: 16px;
font-weight: bold !important;
}
.permission-grid {
th {
white-space: normal;
text-align: center;
& .permission-grid {
& th {
position: relative;
padding-top: 20px;
}
td {
text-align: center;
white-space: normal;
}
& td {
width: 10%;
text-align: center;
}
.icon-edit {
font-size: 80%;
& .icon-edit {
position: absolute;
padding-left: 2px;
top: 0;
left: 50%;
padding-left: 2px;
transform: translateX(-50%);
font-size: 80%;
}
& .permission-name {
cursor: default;
}
}
.empty-role {
& .empty-role {
padding: 0.5em !important;
}
.form-role {
label {
width: 150px;
& .form-role {
& label {
display: inline-block;
width: 150px;
text-align: right;
}
.form-buttons {
& .form-buttons {
padding-left: 150px;
}
}

@ -0,0 +1,14 @@
/* globals RoomRoles */
Meteor.startup(function() {
RocketChat.Notifications.onLogged('Users:NameChanged', function({_id, name}) {
RoomRoles.update({
'u._id': _id
}, {
$set: {
'u.name': name
}
}, {
multi: true
});
});
});

@ -19,7 +19,7 @@
<tbody>
{{#each permission}}
<tr class="admin-table-row">
<td class="border-component-color">{{_id}}</td>
<td class="permission-name border-component-color" title="{{_ permissionDescription}}">{{_ permissionName}}<br>[{{_id}}]</td>
{{#each role}}
<td class="border-component-color">
<input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles}}" data-role="{{_id}}" data-permission="{{../_id}}">

@ -21,6 +21,14 @@ Template.permissions.helpers({
}
},
permissionName() {
return `${ this._id }`;
},
permissionDescription() {
return `${ this._id }_description`;
},
hasPermission() {
return RocketChat.authz.hasAllPermission('access-permissions');
}

@ -10,13 +10,11 @@ Package.onUse(function(api) {
api.use([
'ecmascript',
'underscore',
'rocketchat:lib',
'less'
'rocketchat:lib'
]);
api.use('mongo', ['client', 'server']);
api.use('kadira:flow-router', 'client');
api.use('less', 'client');
api.use('tracker', 'client');
api.use('templating', 'client');
@ -34,6 +32,7 @@ Package.onUse(function(api) {
api.addFiles('client/requiresPermission.html', ['client']);
api.addFiles('client/route.js', ['client']);
api.addFiles('client/usersNameChanged.js', ['client']);
// views
api.addFiles('client/views/permissions.html', ['client']);
@ -42,7 +41,7 @@ Package.onUse(function(api) {
api.addFiles('client/views/permissionsRole.js', ['client']);
// stylesheets
api.addFiles('client/stylesheets/permissions.less', 'client');
api.addFiles('client/stylesheets/permissions.css', 'client');
api.addFiles('server/models/Permissions.js', ['server']);
api.addFiles('server/models/Roles.js', ['server']);

@ -46,6 +46,8 @@ Meteor.startup(function() {
{ _id: 'run-migration', roles : ['admin'] },
{ _id: 'set-moderator', roles : ['admin', 'owner'] },
{ _id: 'set-owner', roles : ['admin', 'owner'] },
{ _id: 'send-many-messages', roles : ['admin', 'bot'] },
{ _id: 'set-leader', roles : ['admin', 'owner'] },
{ _id: 'unarchive-room', roles : ['admin'] },
{ _id: 'view-c-room', roles : ['admin', 'user', 'bot', 'anonymous'] },
{ _id: 'user-generate-access-token', roles : ['admin'] },
@ -73,6 +75,7 @@ Meteor.startup(function() {
const defaultRoles = [
{ name: 'admin', scope: 'Users', description: 'Admin' },
{ name: 'moderator', scope: 'Subscriptions', description: 'Moderator' },
{ name: 'leader', scope: 'Subscriptions', description: 'Leader' },
{ name: 'owner', scope: 'Subscriptions', description: 'Owner' },
{ name: 'user', scope: 'Users', description: '' },
{ name: 'bot', scope: 'Users', description: '' },

@ -23,8 +23,10 @@ function AutoLinker(message) {
if (match.getType() === 'url') {
if (regUrls.test(match.matchedText)) {
if (match.matchedText.indexOf(Meteor.absoluteUrl()) === 0) {
const tag = match.buildTag(); // returns an `Autolinker.HtmlTag` instance for an <a> tag
tag.setAttr('target', ''); // sets target to empty, instead of _blank
// returns an `Autolinker.HtmlTag` instance for an <a> tag
const tag = match.buildTag();
// sets target to empty, instead of _blank
tag.setAttr('target', '');
return tag;
}

@ -13,7 +13,7 @@ Package.onUse(function(api) {
api.use('ecmascript');
api.use('rocketchat:lib');
api.addFiles('client.js', 'client');
api.addFiles('client/client.js', 'client');
api.addFiles('settings.js', 'server');
api.addFiles('server/settings.js', 'server');
});

@ -5,7 +5,7 @@ Meteor.startup(function() {
groups: ['channel', 'group', 'direct'],
id: 'autotranslate',
i18nTitle: 'Auto_Translate',
icon: 'icon-language',
icon: 'language',
template: 'autoTranslateFlexTab',
order: 20
});

@ -1,56 +1,63 @@
.flex-tab {
.autotranslate {
ul {
li {
& .autotranslate {
& ul {
& li {
margin-bottom: 20px;
}
}
form {
label {
& form {
& label {
display: block;
font-weight: bold;
margin-bottom: 5px;
font-weight: bold;
}
div span {
& div span {
font-size: 14px;
i.icon-pencil {
font-size: 12px;
& i.icon-pencil {
margin-left: 3px;
font-size: 12px;
}
}
}
.submit {
& .submit {
margin-top: 30px;
text-align: center;
}
[data-edit] {
& [data-edit] {
cursor: pointer;
}
}
}
.message {
.translated {
border-left: 1px dotted;
padding-left: 3px;
& .translated {
margin-left: 3px;
padding-left: 3px;
border-left: 1px dotted;
i.icon-language.loading {
& i.icon-language.loading {
display: inline-block;
animation: spinh 2000ms infinite linear;
}
}
&.sequential {
.translated {
border-left: 0;
& .translated {
position: absolute;
left: 5px;
border-left: 0;
}
}
}

@ -9,14 +9,13 @@ Package.onUse(function(api) {
api.use([
'ecmascript',
'ddp-rate-limiter',
'less',
'rocketchat:lib'
]);
api.use('templating', 'client');
api.addFiles([
'client/stylesheets/autotranslate.less',
'client/stylesheets/autotranslate.css',
'client/lib/autotranslate.js',
'client/lib/actionButton.js',
'client/lib/tabBar.js',

@ -33,7 +33,9 @@ Meteor.loginWithCas = function(options, callback) {
}
const appUrl = Meteor.absoluteUrl().replace(/\/$/, '') + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX;
const loginUrl = `${ login_url }?service=${ appUrl }/_cas/${ credentialToken }`;
// check if the provided CAS URL already has some parameters
const delim = (login_url.split('?').length > 1) ? '&' : '?';
const loginUrl = `${ login_url }${ delim }service=${ appUrl }/_cas/${ credentialToken }`;
const popup = openCenteredPopup(
loginUrl,

@ -18,12 +18,11 @@ Package.onUse(function(api) {
api.use('ecmascript');
// Server files
api.add_files('cas_rocketchat.js', 'server');
api.add_files('cas_server.js', 'server');
api.add_files('server/cas_rocketchat.js', 'server');
api.add_files('server/cas_server.js', 'server');
// Client files
api.add_files('cas_client.js', 'client');
api.add_files('client/cas_client.js', 'client');
});
Npm.depends({

@ -127,7 +127,7 @@ Accounts.registerLoginHandler(function(options) {
if (!_hasCredential(options.cas.credentialToken)) {
throw new Meteor.Error(Accounts.LoginCancelledError.numericError,
'no matching login attempt found');
'no matching login attempt found');
}
const result = _retrieveCredential(options.cas.credentialToken);
@ -249,7 +249,9 @@ Accounts.registerLoginHandler(function(options) {
ts: new Date(),
open: true,
alert: true,
unread: 1
unread: 1,
userMentions: 1,
groupMentions: 0
});
}
});

@ -3,7 +3,7 @@ RocketChat.ChannelSettings = new class {
this.options = new ReactiveVar({});
}
/*
/*
* Adds an option in Channel Settings
* @config (object)
* id: option id (required)
@ -21,12 +21,13 @@ RocketChat.ChannelSettings = new class {
});
}
getOptions(currentData, group) {
getOptions(currentData = {}, group) {
const allOptions = _.toArray(this.options.get());
const allowedOptions = _.compact(_.map(allOptions, function(option) {
const ret = {...option};
if (option.validation == null || option.validation()) {
option.data = Object.assign({}, typeof option.data === 'function' ? option.data() : option.data, currentData);
return option;
ret.data = Object.assign({}, typeof option.data === 'function' ? option.data() : option.data, currentData);
return ret;
}
})).filter(function(option) {
return !group || !option.group || option.group.includes(group);

@ -4,7 +4,7 @@ Meteor.startup(() => {
id: 'channel-settings',
anonymous: true,
i18nTitle: 'Room_Info',
icon: 'icon-info-circled',
icon: 'info-circled',
template: 'channelSettings',
order: 0
});

@ -22,9 +22,11 @@ Meteor.startup(function() {
Tracker.nonreactive(() => {
if (msg.t === 'r') {
if (Session.get('openedRoom') === msg.rid) {
const type = FlowRouter.current().route.name === 'channel' ? 'c' : 'p';
RoomManager.close(type + FlowRouter.getParam('name'));
FlowRouter.go(FlowRouter.current().route.name, { name: msg.msg }, FlowRouter.current().queryParams);
const room = ChatRoom.findOne(msg.rid);
if (room.name !== FlowRouter.getParam('name')) {
RoomManager.close(room.t + FlowRouter.getParam('name'));
RocketChat.roomTypes.openRouteLink(room.t, room, FlowRouter.current().queryParams);
}
}
}
});

@ -1,97 +1,113 @@
.flex-tab {
.channel-settings {
ul {
li {
& .channel-settings {
& ul {
& li {
margin-bottom: 20px;
}
}
label {
& label {
display: block;
font-weight: bold;
margin-bottom: 5px;
font-size: 14px;
font-weight: bold;
}
.current-setting {
font-size: 14px;
width: calc(~"100% - 38px");
& .current-setting {
display: inline-block;
vertical-align: middle;
width: calc(100% - 38px);
min-height: 20px;
cursor: pointer;
margin-top: 3px;
cursor: pointer;
vertical-align: middle;
font-size: 14px;
&[data-edit="false"] {
cursor: inherit;
user-select: initial;
}
}
.editing {
& .editing {
margin: -2px 0 -1px -9px;
padding-right: 80px;
font-size: 14px;
margin: -2px 0 -1px -9px;
}
.buttons {
& .buttons {
position: absolute;
top: -1px;
bottom: 0;
right: 10px;
bottom: 0;
border-radius: 0 4px 4px 0;
.button {
& .button {
padding: 8px;
}
}
.button.edit {
padding: 8px;
font-size: 12px;
vertical-align: middle;
& .button.edit {
display: inline-block;
visibility: hidden;
padding: 8px;
vertical-align: middle;
font-size: 12px;
}
.submit {
& .submit {
margin-top: 30px;
text-align: center;
}
.boolean {
& .boolean {
font-size: 0;
> label {
width: calc(~"100% - 45px");
& > label {
display: inline-block;
width: calc(100% - 45px);
vertical-align: middle;
}
.setting-block {
width: 40px;
& .setting-block {
display: inline-block;
vertical-align: middle;
width: 40px;
margin-left: -5px;
vertical-align: middle;
}
}
.setting-block {
& .setting-block {
position: relative;
font-size: 0;
.loading-animation {
& .loading-animation {
top: 30px;
}
&:hover {
.button.edit {
& .button.edit {
visibility: visible;
}
}
}
nav {
& nav {
text-align: right;
}
}

@ -1,106 +1,104 @@
<template name="channelSettings">
<div class="content">
<div class="list-view channel-settings">
<div class="title">
<h2>{{_ "Room_Info"}}</h2>
</div>
<form>
<ul class="list clearfix">
{{#let room=getRoom}}
{{#each toArray settings}}
<div class="list-view channel-settings">
<div class="title">
<h2>{{_ "Room_Info"}}</h2>
</div>
<form>
<ul class="list clearfix">
{{#let room=getRoom}}
{{#each toArray settings}}
{{#if $value.canView room}}
{{#let value=(valueOf room $key)}}
<li class="{{$value.type}}">
<label>{{_ $value.label}}</label>
<div class="setting-block">
{{#if $eq $value.type 'text'}}
{{#if editing $key}}
{{#if $value.canEdit room}}
<input type="text" name="{{$key}}" value="{{value}}" class="content-background-color editing" />
{{/if}}
{{else}}
<span class='current-setting' data-edit="{{#if $value.canEdit room}}{{$key}}{{else}}false{{/if}}">{{value}}</span>
{{#if $value.canView room}}
{{#let value=(valueOf room $key)}}
<li class="{{$value.type}}">
<label>{{_ $value.label}}</label>
<div class="setting-block">
{{#if $eq $value.type 'text'}}
{{#if editing $key}}
{{#if $value.canEdit room}}
<input type="text" name="{{$key}}" value="{{value}}" class="content-background-color editing" />
{{/if}}
{{else}}
<span class='current-setting' data-edit="{{#if $value.canEdit room}}{{$key}}{{else}}false{{/if}}">{{value}}</span>
{{/if}}
{{/if}}
{{#if $eq $value.type 'markdown'}}
{{#if editing $key}}
{{#if $value.canEdit room}}
<input type="text" name="{{$key}}" value="{{unscape value}}" class="content-background-color editing" />
{{/if}}
{{else}}
<span class='current-setting' data-edit="{{#if $value.canEdit room}}{{$key}}{{else}}false{{/if}}">{{{RocketChatMarkdown value}}}</span>
{{#if $eq $value.type 'markdown'}}
{{#if editing $key}}
{{#if $value.canEdit room}}
<input type="text" name="{{$key}}" value="{{unscape value}}" class="content-background-color editing" />
{{/if}}
{{else}}
<span class='current-setting' data-edit="{{#if $value.canEdit room}}{{$key}}{{else}}false{{/if}}">{{{RocketChatMarkdown value}}}</span>
{{/if}}
{{/if}}
{{#if $eq $value.type 'select'}}
{{#each toArray $value.options}}
<div class="input radio">
<input type="radio" id="{{$key}}" name="{{../$key}}" value="{{$key}}" checked="{{$eq value $key}}" disabled="{{isDisabled $key room}}" />
<label for="{{$key}}">{{_ $value}}</label>
</div>
{{/each}}
{{/if}}
{{#if $eq $value.type 'boolean'}}
<div class="input checkbox toggle">
<input type="checkbox" id="{{$key}}" name="{{$key}}" value="{{value}}" checked="{{$eq value true}}" disabled="{{isDisabled $key room}}" />
<label for="{{$key}}"></label>
{{#if $eq $value.type 'select'}}
{{#each toArray $value.options}}
<div class="input radio">
<input type="radio" id="{{$key}}" name="{{../$key}}" value="{{$key}}" checked="{{$eq value $key}}" disabled="{{isDisabled $key room}}" />
<label for="{{$key}}">{{_ $value}}</label>
</div>
{{#if $value.canEdit room}}
{{#if $value.processing.get}}
{{> loading}}
{{/if}}
{{/each}}
{{/if}}
{{#if $eq $value.type 'boolean'}}
<div class="input checkbox toggle">
<input type="checkbox" id="{{$key}}" name="{{$key}}" value="{{value}}" checked="{{$eq value true}}" disabled="{{isDisabled $key room}}" />
<label for="{{$key}}"></label>
</div>
{{#if $value.canEdit room}}
{{#if $value.processing.get}}
{{> loading}}
{{/if}}
{{/if}}
{{/if}}
{{#unless $value.isToggle}}
{{#if $value.canEdit room}}
{{#if editing $key}}
<div class="buttons secondary-background-color">
<button type="button" class="button cancel">
<i class="icon-cancel"></i>
</button>
<button type="button" class="button primary save">
<i class="icon-ok success-color"></i>
</button>
</div>
{{else}}
<button type="button" class="button edit">
<i class="icon-pencil" data-edit="{{$key}}"></i>
{{#unless $value.isToggle}}
{{#if $value.canEdit room}}
{{#if editing $key}}
<div class="buttons secondary-background-color">
<button type="button" class="button cancel">
<i class="icon-cancel"></i>
</button>
<button type="button" class="button primary save">
<i class="icon-ok success-color"></i>
</button>
{{/if}}
{{/if}}
{{/unless}}
</div>
</li>
{{# if has $value 'message' }}
{{#let message=($value.message room)}}
{{#if message}}
<li>
<div class="alert alert-warning pending-background pending-border">
{{_ message}}
</div>
</li>
{{else}}
<button type="button" class="button edit">
<i class="icon-pencil" data-edit="{{$key}}"></i>
</button>
{{/if}}
{{/if}}
{{/let}}
{{/if}}
{{/let}}
{{/if}}
{{/each}}
{{/let}}
{{#each channelSettings}}
{{> Template.dynamic template=template data=data}}
{{/unless}}
</div>
</li>
{{# if has $value 'message' }}
{{#let message=($value.message room)}}
{{#if message}}
<li>
<div class="alert alert-warning pending-background pending-border">
{{_ message}}
</div>
</li>
{{/if}}
{{/let}}
{{/if}}
{{/let}}
{{/if}}
{{/each}}
</ul>
</form>
{{#if canDeleteRoom}}
<nav>
<button class="button danger delete" title="{{_ 'Delete'}}"><i class="icon-trash"></i></button>
</nav>
{{/if}}
</div>
{{/let}}
{{#each channelSettings}}
{{> Template.dynamic template=template data=data}}
{{/each}}
</ul>
</form>
{{#if canDeleteRoom}}
<nav>
<button class="button danger delete" title="{{_ 'Delete'}}"><i class="icon-trash"></i></button>
</nav>
{{/if}}
</div>
</template>

@ -16,6 +16,9 @@ Template.channelSettings.helpers({
}
return true;
}
if (this.$value.getValue) {
return this.$value.getValue(obj, key);
}
return obj && obj[key];
},
showSetting(setting, room) {
@ -152,22 +155,30 @@ Template.channelSettings.onCreated(function() {
canEdit(room) {
return RocketChat.authz.hasAllPermission('edit-room', room._id);
},
getValue(room) {
if (RocketChat.settings.get('UI_Allow_room_names_with_special_chars')) {
return room.fname || room.name;
}
return room.name;
},
save(value, room) {
let nameValidation;
if (!RocketChat.authz.hasAllPermission('edit-room', room._id) || (room.t !== 'c' && room.t !== 'p')) {
return toastr.error(t('error-not-allowed'));
}
try {
nameValidation = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
} catch (error1) {
nameValidation = new RegExp('^[0-9a-zA-Z-_.]+$');
}
if (!nameValidation.test(value)) {
return toastr.error(t('error-invalid-room-name', {
room_name: {
name: value
}
}));
if (!RocketChat.settings.get('UI_Allow_room_names_with_special_chars')) {
try {
nameValidation = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
} catch (error1) {
nameValidation = new RegExp('^[0-9a-zA-Z-_.]+$');
}
if (!nameValidation.test(value)) {
return toastr.error(t('error-invalid-room-name', {
room_name: {
name: value
}
}));
}
}
Meteor.call('saveRoomSettings', room._id, 'roomName', value, function(err) {
if (err) {

@ -11,7 +11,6 @@ Package.onUse(function(api) {
'reactive-var',
'tracker',
'templating',
'less',
'rocketchat:lib'
]);
@ -22,7 +21,7 @@ Package.onUse(function(api) {
'client/startup/trackSettingsChange.js',
'client/views/channelSettings.html',
'client/views/channelSettings.js',
'client/stylesheets/channel-settings.less'
'client/stylesheets/channel-settings.css'
], 'client');
api.addFiles([

@ -1,35 +1,21 @@
RocketChat.saveRoomName = function(rid, name, user, sendMessage = true) {
RocketChat.saveRoomName = function(rid, displayName, user, sendMessage = true) {
const room = RocketChat.models.Rooms.findOneById(rid);
if (room.t !== 'c' && room.t !== 'p') {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
'function': 'RocketChat.saveRoomName'
'function': 'RocketChat.saveRoomdisplayName'
});
}
let nameValidation;
try {
nameValidation = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
} catch (error) {
nameValidation = new RegExp('^[0-9a-zA-Z-_.]+$');
}
if (!nameValidation.test(name)) {
throw new Meteor.Error('error-invalid-room-name', `${ name } is not a valid room name. Use only letters, numbers, hyphens and underscores`, {
'function': 'RocketChat.saveRoomName',
room_name: name
});
}
if (name === room.name) {
if (displayName === room.name) {
return;
}
if (RocketChat.models.Rooms.findOneByName(name)) {
throw new Meteor.Error('error-duplicate-channel-name', `A channel with name '${ name }' exists`, {
'function': 'RocketChat.saveRoomName',
channel_name: name
});
}
const update = RocketChat.models.Rooms.setNameById(rid, name) && RocketChat.models.Subscriptions.updateNameAndAlertByRoomId(rid, name);
const slugifiedRoomName = RocketChat.getValidRoomName(displayName, rid);
const update = RocketChat.models.Rooms.setNameById(rid, slugifiedRoomName, displayName) && RocketChat.models.Subscriptions.updateNameAndAlertByRoomId(rid, slugifiedRoomName, displayName);
if (update && sendMessage) {
RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser(rid, name, user);
RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser(rid, displayName, user);
}
return name;
return displayName;
};

@ -2,29 +2,27 @@ Meteor.startup(() =>
Tracker.autorun(function() {
if (RocketChat.TabBar) {
if (RocketChat.settings && RocketChat.settings.get('Chatops_Enabled')) {
console.log('Adding chatops to tabbar');
RocketChat.TabBar.addButton({
groups: ['channel', 'group', 'direct'],
id: 'chatops-button2',
i18nTitle: 'rocketchat-chatops:Chatops_Title',
icon: 'icon-hubot',
icon: 'hubot',
template: 'chatops-dynamicUI',
order: 4
});
console.log('Adding chatops to tabbar');
return RocketChat.TabBar.addButton({
RocketChat.TabBar.addButton({
groups: ['channel', 'group', 'direct'],
id: 'chatops-button3',
i18nTitle: 'rocketchat-chatops:Chatops_Title',
icon: 'icon-inbox',
icon: 'inbox',
template: 'chatops_droneflight',
width: 675,
order: 5
});
} else {
RocketChat.TabBar.removeButton('chatops-button2');
return RocketChat.TabBar.removeButton('chatops-button3');
RocketChat.TabBar.removeButton('chatops-button3');
}
}
})

@ -1,16 +1,20 @@
.message-color {
display: inline-block;
font-weight: 100;
}
.message-color-sample {
position: relative;
top: 2px;
display: inline-block;
width: 14px;
height: 14px;
display: inline-block;
border-radius: 3px;
margin-right: 3px;
margin-left: 2px;
border: 1px solid rgba(0, 0, 0, 0.2);
position: relative;
top: 2px;
border-radius: 3px;
}

@ -9,7 +9,7 @@ Package.onUse(function(api) {
api.use('rocketchat:lib');
api.use('ecmascript');
api.addFiles('client.js', ['client']);
api.addFiles('style.css', ['client']);
api.addFiles('settings.js', ['server']);
api.addFiles('client/client.js', 'client');
api.addFiles('client/style.css', 'client');
api.addFiles('server/settings.js', 'server');
});

@ -2,7 +2,7 @@
import url from 'url';
WebApp.rawConnectHandlers.use(function(req, res, next) {
WebApp.rawConnectHandlers.use(Meteor.bindEnvironment(function(req, res, next) {
if (req._body) {
return next();
}
@ -12,7 +12,7 @@ WebApp.rawConnectHandlers.use(function(req, res, next) {
if (req.headers['content-type'] !== '' && req.headers['content-type'] !== undefined) {
return next();
}
if (req.url.indexOf('/ufs/') === 0) {
if (req.url.indexOf(`${ __meteor_runtime_config__.ROOT_URL_PATH_PREFIX }/ufs/`) === 0) {
return next();
}
@ -36,7 +36,7 @@ WebApp.rawConnectHandlers.use(function(req, res, next) {
return next();
});
});
}));
WebApp.rawConnectHandlers.use(function(req, res, next) {
if (/^\/(api|_timesync|sockjs|tap-i18n|__cordova)(\/|$)/.test(req.url)) {

@ -81,9 +81,9 @@ export class CustomOAuth {
const separator = this.authorizePath.indexOf('?') !== -1 ? '&' : '?';
const loginUrl = `${ this.authorizePath
}${ separator }client_id=${ config.clientId
}&redirect_uri=${ OAuth._redirectUri(this.name, config)
}&response_type=code` +
}${ separator }client_id=${ config.clientId
}&redirect_uri=${ OAuth._redirectUri(this.name, config)
}&response_type=code` +
`&state=${ OAuth._stateParam(loginStyle, credentialToken, options.redirectUrl)
}&scope=${ this.scope }`;

@ -20,9 +20,9 @@ Package.onUse(function(api) {
api.use('http', 'server');
api.mainModule('custom_oauth_client.js', 'client');
api.mainModule('client/custom_oauth_client.js', 'client');
api.mainModule('custom_oauth_server.js', 'server');
api.mainModule('server/custom_oauth_server.js', 'server');
api.export('CustomOAuth');
});

@ -1,83 +1,91 @@
.sound-info {
.icon-play-circled {
& .icon-play-circled {
cursor: pointer;
}
}
.sound-view {
z-index: 15;
overflow-y: auto;
overflow-x: hidden;
overflow-y: auto;
.thumb {
& .thumb {
width: 100%;
height: 350px;
padding: 20px;
}
nav {
& nav {
padding: 0 20px;
}
.info {
white-space: normal;
& .info {
padding: 0 20px;
h3 {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
white-space: normal;
& h3 {
overflow: hidden;
width: 100%;
margin: 8px 0;
user-select: text;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 24px;
margin: 8px 0;
line-height: 27px;
text-overflow: ellipsis;
width: 100%;
overflow: hidden;
white-space: nowrap;
i::after {
content: " ";
& i::after {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 4px;
content: " ";
vertical-align: middle;
border-radius: 4px;
}
}
p {
& p {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
line-height: 18px;
font-size: 12px;
font-weight: 300;
line-height: 18px;
}
}
.edit-form {
& .edit-form {
padding: 20px 20px 0;
white-space: normal;
h3 {
font-size: 24px;
& h3 {
margin-bottom: 8px;
font-size: 24px;
line-height: 22px;
}
p {
line-height: 18px;
& p {
font-size: 12px;
font-weight: 300;
line-height: 18px;
}
> .input-line {
& > .input-line {
margin-top: 20px;
}
nav {
& nav {
padding: 0;
&.buttons {
@ -85,18 +93,19 @@
}
}
.form-divisor {
text-align: center;
margin: 2em 0;
& .form-divisor {
height: 9px;
margin: 2em 0;
text-align: center;
> span {
& > span {
padding: 0 1em;
}
}
}
.room-info-content > div {
& .room-info-content > div {
margin: 0 0 20px;
}
}

@ -46,7 +46,7 @@ Template.adminSounds.onCreated(function() {
groups: ['custom-sounds', 'custom-sounds-selected'],
id: 'add-sound',
i18nTitle: 'Custom_Sound_Add',
icon: 'icon-plus',
icon: 'plus',
template: 'adminSoundEdit',
openClick(/*e, t*/) {
instance.tabBarData.set();
@ -59,7 +59,7 @@ Template.adminSounds.onCreated(function() {
groups: ['custom-sounds-selected'],
id: 'admin-sound-info',
i18nTitle: 'Custom_Sound_Info',
icon: 'icon-cog',
icon: 'customize',
template: 'adminSoundInfo',
order: 2
});

@ -13,7 +13,7 @@
</div>
<div class="input-line">
<label for="image">{{_ "Sound_File_mp3"}}</label>
<input id="image" type="file" accept="audio/mp3"/>
<input id="image" type="file" accept="audio/mp3,audio/mpeg"/>
</div>
<nav>
<button class='button button-block cancel' type="button"><span>{{_ "Cancel"}}</span></button>

@ -8,7 +8,6 @@ Package.describe({
Package.onUse(function(api) {
api.use([
'ecmascript',
'less',
'rocketchat:file',
'rocketchat:lib',
'templating',
@ -33,18 +32,18 @@ Package.onUse(function(api) {
'server/methods/uploadCustomSound.js'
], 'server');
api.addFiles('assets/stylesheets/customSoundsAdmin.less', 'client');
api.addFiles('admin/startup.js', 'client');
api.addFiles('admin/adminSounds.html', 'client');
api.addFiles('admin/adminSounds.js', 'client');
api.addFiles('admin/adminSoundEdit.html', 'client');
api.addFiles('admin/adminSoundInfo.html', 'client');
api.addFiles('admin/soundEdit.html', 'client');
api.addFiles('admin/soundEdit.js', 'client');
api.addFiles('admin/soundInfo.html', 'client');
api.addFiles('admin/soundInfo.js', 'client');
api.addFiles('admin/route.js', 'client');
api.addFiles('assets/stylesheets/customSoundsAdmin.css', 'client');
api.addFiles('client/admin/startup.js', 'client');
api.addFiles('client/admin/adminSounds.html', 'client');
api.addFiles('client/admin/adminSounds.js', 'client');
api.addFiles('client/admin/adminSoundEdit.html', 'client');
api.addFiles('client/admin/adminSoundInfo.html', 'client');
api.addFiles('client/admin/soundEdit.html', 'client');
api.addFiles('client/admin/soundEdit.js', 'client');
api.addFiles('client/admin/soundInfo.html', 'client');
api.addFiles('client/admin/soundInfo.js', 'client');
api.addFiles('client/admin/route.js', 'client');
api.addFiles('client/lib/CustomSounds.js', 'client');
api.addFiles('client/models/CustomSounds.js', 'client');

@ -11,8 +11,7 @@ Meteor.methods({
RocketChatFileCustomSoundsInstance.deleteFile(`${ soundData._id }.${ soundData.extension }`);
const ws = RocketChatFileCustomSoundsInstance.createWriteStream(`${ soundData._id }.${ soundData.extension }`, contentType);
ws.on('end', Meteor.bindEnvironment(() =>
Meteor.setTimeout(() => RocketChat.Notifications.notifyAll('updateCustomSound', {soundData})
, 500)
Meteor.setTimeout(() => RocketChat.Notifications.notifyAll('updateCustomSound', {soundData}), 500)
));
rs.pipe(ws);

@ -1,10 +1,13 @@
.icon-dolphin {
display: inline-block;
width: 30px;
height: 20px;
vertical-align: middle;
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDMwIDQzMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxnIGlkPSJzaWduLWluIiB0cmFuc2Zvcm09Im1hdHJpeCgwLjUgMCAwIDAuNSAwIDApIj4NCjxwYXRoIGZpbGw9IiNmZmZmZmYiIGQ9Ik02NjAuNjcyIDUwMC4wMzJxMCAxNC41MDggLTEwLjYwMiAyNS4xMWwtMzAzLjU1MiAzMDMuNTUycS0xMC42MDIgMTAuNjAyIC0yNS4xMSAxMC42MDJ0LTI1LjExIC0xMC42MDIgLTEwLjYwMiAtMjUuMTF2LTE2MC43MDRoLTI0OS45ODRxLTE0LjUwOCAwIC0yNS4xMSAtMTAuNjAydC0xMC42MDIgLTI1LjExdi0yMTQuMjcycTAgLTE0LjUwOCAxMC42MDIgLTI1LjExdDI1LjExIC0xMC42MDJoMjQ5Ljk4NHYtMTYwLjcwNHEwIC0xNC41MDggMTAuNjAyIC0yNS4xMXQyNS4xMSAtMTAuNjAyIDI1LjExIDEwLjYwMmwzMDMuNTUyIDMwMy41NTJxMTAuNjAyIDEwLjYwMiAxMC42MDIgMjUuMTF6bTE5Ni40MTYgLTE5Ni40MTZ2MzkyLjgzMnEwIDY2LjQwMiAtNDcuMTUxIDExMy41NTN0LTExMy41NTMgNDcuMTUxaC0xNzguNTZxLTcuMjU0IDAgLTEyLjU1NSAtNS4zMDF0LTUuMzAxIC0xMi41NTVxMCAtMi4yMzIgLS41NTggLTExLjE2dC0uMjc5IC0xNC43ODcgMS42NzQgLTEzLjExMyA1LjU4IC0xMC44ODEgMTEuNDM5IC0zLjYyN2gxNzguNTZxMzYuODI4IDAgNjMuMDU0IC0yNi4yMjZ0MjYuMjI2IC02My4wNTR2LTM5Mi44MzJxMCAtMzYuODI4IC0yNi4yMjYgLTYzLjA1NHQtNjMuMDU0IC0yNi4yMjZoLTE3NC4wOTZ0LTYuNDE3IC0uNTU4IC02LjQxNyAtMS42NzQgLTQuNDY0IC0zLjA2OSAtMy45MDYgLTUuMDIyIC0xLjExNiAtNy41MzNxMCAtMi4yMzIgLS41NTggLTExLjE2dC0uMjc5IC0xNC43ODcgMS42NzQgLTEzLjExMyA1LjU4IC0xMC44ODEgMTEuNDM5IC0zLjYyN2gxNzguNTZxNjYuNDAyIDAgMTEzLjU1MyA0Ny4xNTF0NDcuMTUxIDExMy41NTN6Ii8+DQo8L2c+DQo8L3N2Zz4=);
background-repeat: no-repeat;
vertical-align: middle;
}
.icon-dolphin ~ .icon-spin,

@ -1,7 +1,9 @@
.icon-drupal.service-icon {
display: inline-block;
width: 21px;
height: 28px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAYAAACOGPReAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAcNJREFUSMetlbFrFFEQh7/dJnhpDHcx6SyiRLhLkUKDsRZB8S9IWi2Syj8iVooQ0FLBNlqJRpNO8Br7FLkoRDBooQHhNCr6WTjB48zd7d7uNI+d+c333pt9bx5kNPVGVm1WYF39rTbKhD7zr62XBVwI4MsYF4sCZ9S2uq6mMbbVmWGBx9WW+kGdCN+J+G6pY3mBo2pT/ape6IrNx2qb6mhW4Ii6qf5Ur/TQXI74pjoyCJioa3F8FgdoF0K3pib9hLfiDy9l3NVS6G/3EiyH4GbO+q9E3nJ3oKF+Vx/33Urvkj2K/EZn4JW6l/uY/MsfU9+rzUPHXCz/+jDADvC14Myhrqpf1EpB6LHgrCbqa+BzkiSXikAD/ByopcAUsFUUGLYFTKVABWiXBG0DlRTYB8ZLgo4D+ynQAuolQevAdgq8AM6rk0Vo0R7ngQ3UU+qvvNfzCOhKcE4fOu6r39TpIYHT0XsfdDon45puq7WcwFrk7f1XQvVsdPS3Wd+geMPeRN65XqJZdVf9od5Tz/TZ7t3Q7aqzg2avqnfUg2gQO+pT9WGMO+E/CF21m5H0gU8AV4GLwEmgCnwC3gEbwJMkST4elfsHJbIReGbv9uUAAAAASUVORK5CYII=);
background-repeat: no-repeat;
}

@ -46,7 +46,7 @@ Template.adminEmoji.onCreated(function() {
groups: ['emoji-custom'],
id: 'add-emoji',
i18nTitle: 'Custom_Emoji_Add',
icon: 'icon-plus',
icon: 'plus',
template: 'adminEmojiEdit',
order: 1
});
@ -55,7 +55,7 @@ Template.adminEmoji.onCreated(function() {
groups: ['emoji-custom'],
id: 'admin-emoji-info',
i18nTitle: 'Custom_Emoji_Info',
icon: 'icon-cog',
icon: 'customize',
template: 'adminEmojiInfo',
order: 2
});

@ -1,98 +1,112 @@
.emojiAdminPreview {
height: 100%;
width: 100%;
overflow: hidden;
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
border-radius: 4px;
.emojiAdminPreview-image {
height: 100%;
& .emojiAdminPreview-image {
position: relative;
display: block;
width: 100%;
min-height: 20px;
min-width: 20px;
display: block;
position: relative;
background-size: cover;
height: 100%;
min-height: 20px;
border-radius: 4px;
background-repeat: no-repeat;
background-position: center;
border-radius: 4px;
background-size: cover;
}
}
.emoji-view {
z-index: 15;
overflow-y: auto;
overflow-x: hidden;
overflow-y: auto;
.thumb {
& .thumb {
width: 100%;
height: 350px;
padding: 20px;
}
nav {
& nav {
padding: 0 20px;
}
.info {
white-space: normal;
& .info {
padding: 0 20px;
h3 {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
white-space: normal;
& h3 {
overflow: hidden;
width: 100%;
margin: 8px 0;
user-select: text;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 24px;
margin: 8px 0;
line-height: 27px;
text-overflow: ellipsis;
width: 100%;
overflow: hidden;
white-space: nowrap;
i::after {
content: " ";
& i::after {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 4px;
content: " ";
vertical-align: middle;
border-radius: 4px;
}
}
p {
& p {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
line-height: 18px;
font-size: 12px;
font-weight: 300;
line-height: 18px;
}
}
.edit-form {
& .edit-form {
padding: 20px 20px 0;
white-space: normal;
h3 {
font-size: 24px;
& h3 {
margin-bottom: 8px;
font-size: 24px;
line-height: 22px;
}
p {
line-height: 18px;
& p {
font-size: 12px;
font-weight: 300;
line-height: 18px;
}
> .input-line {
& > .input-line {
margin-top: 20px;
}
nav {
& nav {
padding: 0;
&.buttons {
@ -100,18 +114,19 @@
}
}
.form-divisor {
text-align: center;
margin: 2em 0;
& .form-divisor {
height: 9px;
margin: 2em 0;
text-align: center;
> span {
& > span {
padding: 0 1em;
}
}
}
.room-info-content > div {
& .room-info-content > div {
margin: 0 0 20px;
}
}

@ -1,6 +1,6 @@
/* globals getEmojiUrlFromName:true, updateEmojiCustom:true, deleteEmojiCustom:true, isSetNotNull */
RocketChat.emoji.packages.emojiCustom = {
emojiCategories: { rocket: TAPi18n.__('Custom') },
emojiCategories: { rocket: 'Custom' },
toneList: {},
list: [],

@ -8,7 +8,6 @@ Package.describe({
Package.onUse(function(api) {
api.use([
'ecmascript',
'less',
'rocketchat:emoji',
'rocketchat:file',
'rocketchat:lib',
@ -34,7 +33,7 @@ Package.onUse(function(api) {
'server/methods/uploadEmojiCustom.js'
], 'server');
api.addFiles('assets/stylesheets/emojiCustomAdmin.less', 'client');
api.addFiles('assets/stylesheets/emojiCustomAdmin.css', 'client');
api.addFiles([
'admin/startup.js',

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

Loading…
Cancel
Save