Merge branch 'develop' into ldap-sync-custom-fields

pull/7614/head
Bruno Godoy Martins Correa 9 years ago committed by GitHub
commit 5c781693b9
  1. 2
      .docker/Dockerfile
  2. 2
      .github/changelog.js
  3. 2
      .meteor/packages
  4. 15
      .meteor/versions
  5. 5
      .postcssrc
  6. 2
      .sandstorm/sandstorm-pkgdef.capnp
  7. 3
      .scripts/set-version.js
  8. 221
      .stylelintrc
  9. 2
      .travis/snap.sh
  10. 4
      README.md
  11. 13
      client/routes/router.js
  12. 5859
      package-lock.json
  13. 40
      package.json
  14. 2
      packages/meteor-accounts-saml/saml_client.js
  15. 9
      packages/meteor-accounts-saml/saml_utils.js
  16. 40
      packages/meteor-autocomplete/client/autocomplete-client.js
  17. 1
      packages/meteor-autocomplete/client/collection.js
  18. 3
      packages/meteor-autocomplete/client/templates.js
  19. 13
      packages/meteor-autocomplete/package.js
  20. 22
      packages/rocketchat-action-links/client/stylesheets/actionLinks.css
  21. 3
      packages/rocketchat-action-links/package.js
  22. 5
      packages/rocketchat-api/server/api.js
  23. 92
      packages/rocketchat-api/server/v1/channels.js
  24. 85
      packages/rocketchat-api/server/v1/chat.js
  25. 80
      packages/rocketchat-api/server/v1/groups.js
  26. 157
      packages/rocketchat-api/server/v1/im.js
  27. 6
      packages/rocketchat-api/server/v1/users.js
  28. 46
      packages/rocketchat-authorization/client/stylesheets/permissions.css
  29. 6
      packages/rocketchat-authorization/package.js
  30. 6
      packages/rocketchat-autolinker/client/client.js
  31. 4
      packages/rocketchat-autolinker/package.js
  32. 0
      packages/rocketchat-autolinker/server/settings.js
  33. 2
      packages/rocketchat-autotranslate/client/lib/tabBar.js
  34. 41
      packages/rocketchat-autotranslate/client/stylesheets/autotranslate.css
  35. 3
      packages/rocketchat-autotranslate/package.js
  36. 0
      packages/rocketchat-cas/client/cas_client.js
  37. 7
      packages/rocketchat-cas/package.js
  38. 0
      packages/rocketchat-cas/server/cas_rocketchat.js
  39. 0
      packages/rocketchat-cas/server/cas_server.js
  40. 2
      packages/rocketchat-channel-settings/client/startup/tabBar.js
  41. 76
      packages/rocketchat-channel-settings/client/stylesheets/channel-settings.css
  42. 3
      packages/rocketchat-channel-settings/package.js
  43. 10
      packages/rocketchat-chatops/client/tabBar.js
  44. 0
      packages/rocketchat-colors/client/client.js
  45. 12
      packages/rocketchat-colors/client/style.css
  46. 6
      packages/rocketchat-colors/package.js
  47. 0
      packages/rocketchat-colors/server/settings.js
  48. 0
      packages/rocketchat-custom-oauth/client/custom_oauth_client.js
  49. 4
      packages/rocketchat-custom-oauth/package.js
  50. 0
      packages/rocketchat-custom-oauth/server/custom_oauth_server.js
  51. 73
      packages/rocketchat-custom-sounds/assets/stylesheets/customSoundsAdmin.css
  52. 0
      packages/rocketchat-custom-sounds/client/admin/adminSoundEdit.html
  53. 0
      packages/rocketchat-custom-sounds/client/admin/adminSoundInfo.html
  54. 0
      packages/rocketchat-custom-sounds/client/admin/adminSounds.html
  55. 4
      packages/rocketchat-custom-sounds/client/admin/adminSounds.js
  56. 0
      packages/rocketchat-custom-sounds/client/admin/route.js
  57. 0
      packages/rocketchat-custom-sounds/client/admin/soundEdit.html
  58. 0
      packages/rocketchat-custom-sounds/client/admin/soundEdit.js
  59. 0
      packages/rocketchat-custom-sounds/client/admin/soundInfo.html
  60. 0
      packages/rocketchat-custom-sounds/client/admin/soundInfo.js
  61. 0
      packages/rocketchat-custom-sounds/client/admin/startup.js
  62. 25
      packages/rocketchat-custom-sounds/package.js
  63. 5
      packages/rocketchat-dolphin/login-button.css
  64. 2
      packages/rocketchat-drupal/login-button.css
  65. 4
      packages/rocketchat-emoji-custom/admin/adminEmoji.js
  66. 97
      packages/rocketchat-emoji-custom/assets/stylesheets/emojiCustomAdmin.css
  67. 3
      packages/rocketchat-emoji-custom/package.js
  68. 27
      packages/rocketchat-emoji-emojione/sprites.css
  69. 25
      packages/rocketchat-emoji/client/emoji.css
  70. 34
      packages/rocketchat-emoji/client/emojiButton.js
  71. 0
      packages/rocketchat-emoji/client/emojiParser.js
  72. 133
      packages/rocketchat-emoji/client/emojiPicker.css
  73. 0
      packages/rocketchat-emoji/client/emojiPicker.html
  74. 0
      packages/rocketchat-emoji/client/emojiPicker.js
  75. 0
      packages/rocketchat-emoji/client/function-isSet.js
  76. 0
      packages/rocketchat-emoji/client/keyboardFix.js
  77. 0
      packages/rocketchat-emoji/client/lib/EmojiPicker.js
  78. 0
      packages/rocketchat-emoji/client/lib/emojiRenderer.js
  79. 0
      packages/rocketchat-emoji/client/rocketchat.js
  80. 29
      packages/rocketchat-emoji/emojiButton.js
  81. 23
      packages/rocketchat-emoji/package.js
  82. 25
      packages/rocketchat-file-upload/server/config/GridFS.js
  83. 29
      packages/rocketchat-file-upload/server/lib/FileUpload.js
  84. 1
      packages/rocketchat-file-upload/server/methods/sendFileMessage.js
  85. 6
      packages/rocketchat-github-enterprise/github-enterprise-login-button.css
  86. 1
      packages/rocketchat-google-vision/.npm/package/.gitignore
  87. 7
      packages/rocketchat-google-vision/.npm/package/README
  88. 1550
      packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json
  89. 7
      packages/rocketchat-google-vision/README.md
  90. 84
      packages/rocketchat-google-vision/client/googlevision.js
  91. 21
      packages/rocketchat-google-vision/package.js
  92. 153
      packages/rocketchat-google-vision/server/googlevision.js
  93. 10
      packages/rocketchat-google-vision/server/models/Messages.js
  94. 88
      packages/rocketchat-google-vision/server/settings.js
  95. 0
      packages/rocketchat-highlight-words/client/client.js
  96. 2
      packages/rocketchat-highlight-words/package.js
  97. 4
      packages/rocketchat-i18n/i18n/ar.i18n.json
  98. 27
      packages/rocketchat-i18n/i18n/ca.i18n.json
  99. 51
      packages/rocketchat-i18n/i18n/cs.i18n.json
  100. 4
      packages/rocketchat-i18n/i18n/de-AT.i18n.json
  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.58.0-develop
ENV RC_VERSION 0.59.0-develop
MAINTAINER buildmaster@rocket.chat

@ -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)');

@ -62,6 +62,7 @@ rocketchat:file
rocketchat:file-upload
rocketchat:github-enterprise
rocketchat:gitlab
rocketchat:google-vision
rocketchat:highlight-words
rocketchat:iframe-login
rocketchat:importer
@ -72,6 +73,7 @@ rocketchat:importer-slack
rocketchat:integrations
rocketchat:internal-hubot
rocketchat:irc
rocketchat:issuelinks
rocketchat:katex
rocketchat:ldap
rocketchat:lib

@ -22,7 +22,8 @@ caching-html-compiler@1.1.2
callback-hook@1.0.10
cfs:http-methods@0.0.32
check@1.2.5
coffeescript@1.12.6_1
coffeescript@1.12.7_1
coffeescript-compiler@1.12.7_1
dandv:caret-position@2.1.1
ddp@1.3.0
ddp-client@2.0.0
@ -75,7 +76,7 @@ localstorage@1.1.1
logging@1.1.17
matb33:collection-hooks@0.8.4
mdg:validation-error@0.5.1
meteor@1.7.0
meteor@1.7.1
meteor-base@1.1.0
meteor-developer-oauth@1.2.0
meteorhacks:inject-initial@1.0.4
@ -88,9 +89,9 @@ mizzao:autocomplete@0.5.1
mizzao:timesync@0.3.4
mobile-experience@1.0.4
mobile-status-bar@1.0.14
modules@0.9.2
modules@0.9.4
modules-runtime@0.8.0
mongo@1.1.19
mongo@1.1.22
mongo-id@1.0.6
mongo-livedata@1.0.12
mrt:reactive-store@0.0.1
@ -98,7 +99,7 @@ mystor:device-detection@0.2.0
nimble:restivus@0.8.12
nooitaf:colors@1.1.2_1
npm-bcrypt@0.9.3
npm-mongo@2.2.24
npm-mongo@2.2.30
oauth@1.1.13
oauth1@1.1.11
oauth2@1.1.11
@ -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
@ -232,7 +235,7 @@ 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.1.1
steffo:meteor-accounts-saml@0.0.1

@ -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.58.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.

@ -56,6 +56,9 @@ git.status()
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([{

@ -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" }
]
}
}

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

@ -85,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.
@ -119,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:

@ -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', {

5859
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,7 +1,7 @@
{
"name": "Rocket.Chat",
"description": "The Ultimate Open Source WebChat Platform",
"version": "0.58.0-develop",
"version": "0.59.0-develop",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
@ -23,6 +23,14 @@
"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"
@ -54,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",
@ -81,29 +89,35 @@
"babel-plugin-array-includes": "^2.0.3",
"chimp": "^0.49.1",
"conventional-changelog-cli": "^1.3.2",
"eslint": "^4.2.0",
"eslint": "^4.5.0",
"postcss-cssnext": "^2.11.0",
"postcss-smart-import": "^0.7.5",
"simple-git": "^1.73.0",
"stylelint": "^7.13.0",
"simple-git": "^1.75.0",
"stylelint": "^8.0.0",
"stylelint-order": "^0.6.0",
"supertest": "^3.0.0"
},
"dependencies": {
"@google-cloud/storage": "^1.2.0",
"aws-sdk": "^2.86.0",
"babel-runtime": "^6.23.0",
"@google-cloud/storage": "^1.2.1",
"aws-sdk": "^2.102.0",
"babel-runtime": "^6.26.0",
"bcrypt": "^1.0.2",
"codemirror": "^5.27.4",
"file-type": "^5.2.0",
"codemirror": "^5.28.0",
"emailreplyparser": "0.0.5",
"file-type": "^6.1.0",
"highlight.js": "^9.12.0",
"imap": "^0.8.19",
"jquery": "^3.2.1",
"mailparser-node4": "^2.0.2-2",
"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": "^10.0.2",
"semver": "^5.3.0",
"toastr": "^2.1.2"
"poplib": "^0.1.7",
"prom-client": "^10.0.4",
"semver": "^5.4.1",
"toastr": "^2.1.2",
"wolfy87-eventemitter": "^5.2.2"
}
}

@ -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*/) {

@ -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);
}
@ -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 => {
@ -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;
}
@ -376,7 +381,7 @@ this.AutoComplete = class {
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');
});

@ -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');
});

@ -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);
}
});
@ -388,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;
@ -154,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')) {
@ -226,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);
}
});
@ -308,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();

@ -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({

@ -195,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()) {

@ -1,51 +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 {
& .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;
}
}

@ -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');
@ -43,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']);

@ -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',

@ -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({

@ -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
});

@ -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;
}
}

@ -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([

@ -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');
});

@ -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
});

@ -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');

@ -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;
}
}

@ -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',

@ -1,25 +1,30 @@
.emojione {
image-rendering: -webkit-optimize-contrast;
image-rendering: optimizeQuality;
font-size: inherit;
height: 22px;
width: 22px;
position: relative;
display: inline-block;
overflow: hidden;
width: 22px;
height: 22px;
margin: 0 0.15em;
line-height: normal;
vertical-align: middle;
white-space: nowrap;
text-indent: 100%;
background-image: url("../../packages/emojione_emojione/assets/sprites/emojione.sprites.png");
background-size: 4365.625% 4365.625%;
background-repeat: no-repeat;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
background-size: 4365.625% 4365.625%;
font-size: inherit;
line-height: normal;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimizeQuality;
}
.emojione.big {
height: 44px !important;
width: 44px !important;
height: 44px !important;
}
.emojione-0023-20e3 {

@ -1,22 +1,27 @@
.emoji {
image-rendering: auto;
font-size: inherit;
height: 22px;
width: 22px;
position: relative;
display: inline-block;
overflow: hidden;
width: 22px;
height: 22px;
margin: 0 0.15em;
line-height: normal;
vertical-align: middle;
background-position: center;
white-space: nowrap;
text-indent: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
font-size: inherit;
line-height: normal;
image-rendering: auto;
}
.emoji.big {
height: 44px !important;
width: 44px !important;
height: 44px !important;
}

@ -0,0 +1,34 @@
/* globals Template chatMessages*/
Template.messageBox.events({
'click .emoji-picker-icon'(event) {
event.stopPropagation();
event.preventDefault();
if (RocketChat.EmojiPicker.isOpened()) {
RocketChat.EmojiPicker.close();
} else {
RocketChat.EmojiPicker.open(event.currentTarget, (emoji) => {
const {input} = chatMessages[RocketChat.openedRoom];
const emojiValue = `:${ emoji }:`;
const caretPos = input.selectionStart;
const textAreaTxt = input.value;
input.focus();
if (document.execCommand) {
document.execCommand('insertText', false, emojiValue);
} else {
input.value = textAreaTxt.substring(0, caretPos) + emojiValue + textAreaTxt.substring(caretPos);
}
input.focus();
input.selectionStart = caretPos + emojiValue.length;
input.selectionEnd = caretPos + emojiValue.length;
});
}
}
});
Template.messageBox.onCreated(function() {
RocketChat.EmojiPicker.init();
});

@ -1,5 +1,6 @@
.emoji-picker-icon {
cursor: pointer;
font-size: 18px;
&::before {
@ -14,64 +15,75 @@
}
.emoji-picker {
position: absolute;
display: none;
width: 100%;
max-width: 365px;
border-radius: 5px;
box-shadow:
0 1px 1px 0 rgba(0, 0, 0, 0.2),
0 2px 10px 0 rgba(0, 0, 0, 0.16);
position: absolute;
display: none;
&.show {
display: block;
}
.filter {
& .filter {
box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.2);
}
.filter-list {
& .filter-list {
display: flex;
width: 100%;
padding: 0 5px;
}
.filter-item {
& .filter-item {
display: flex;
padding: 6px 0;
border-style: solid;
border-width: 0 0 2px;
display: flex;
justify-content: center;
border-style: solid;
flex-grow: 1;
justify-content: center;
.category-icon {
& .category-icon {
font-size: 20px;
}
}
.current-category-header {
& .current-category-header {
padding: 3px 5px;
}
.emojis {
height: 160px;
& .emojis {
overflow-y: auto;
height: 160px;
padding: 3px 0 0 2px;
.emoji-list {
& .emoji-list {
display: none;
li {
& li {
display: inline-block;
margin: 2px;
padding: 4px 2px 2px;
border-radius: 4px;
cursor: pointer;
transition: transform 0.2s ease;
border-radius: 4px;
&:hover {
transform: scale(1.2);
background-color: #dddddd;
}
}
@ -85,88 +97,127 @@
.emoji-top {
display: flex;
align-items: center;
padding: 5px;
align-items: center;
& .emoji-filter {
position: relative;
.emoji-filter {
width: 90%;
margin-bottom: 0;
& .search {
position: relative;
width: 100%;
height: 35px;
padding: 2px 8px;
border-width: 1px;
border-style: solid;
border-radius: 5px;
outline: none;
line-height: normal;
appearance: none;
}
& .icon-search {
position: absolute;
top: 10px;
left: 7px;
}
}
.change-tone {
width: 10%;
& .change-tone {
position: relative;
display: flex;
width: 10%;
justify-content: center;
position: relative;
a {
& a {
position: relative;
z-index: 10;
}
.current-tone {
& .current-tone {
display: block;
width: 20px;
height: 20px;
border-radius: 10px;
}
.tone-selector {
& .tone-selector {
position: absolute;
border-radius: 4px;
box-shadow:
0 1px 1px 0 rgba(0, 0, 0, 0.2),
0 2px 10px 0 rgba(0, 0, 0, 0.16);
padding: 4px 2px;
top: 25px;
z-index: 1;
top: 25px;
visibility: hidden;
padding: 4px 2px;
transition: transform 0.2s ease, visibility 0.2s ease, opacity 0.2s ease;
transform: translateY(-20px);
opacity: 0;
visibility: hidden;
border-radius: 4px;
box-shadow:
0 1px 1px 0 rgba(0, 0, 0, 0.2),
0 2px 10px 0 rgba(0, 0, 0, 0.16);
&.show {
transform: translateY(0);
opacity: 1;
display: block;
visibility: visible;
transform: translateY(0);
opacity: 1;
}
li {
& li {
display: block;
padding: 0 4px;
}
span {
& span {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 10px;
transition: transform 0.2s ease;
border-radius: 10px;
}
}
.tone-0 {
& .tone-0 {
background-color: #ffcf11;
}
.tone-1 {
& .tone-1 {
background-color: #fae3c3;
}
.tone-2 {
& .tone-2 {
background-color: #e2cfa1;
}
.tone-3 {
& .tone-3 {
background-color: #dba373;
}
.tone-4 {
& .tone-4 {
background-color: #a88054;
}
.tone-5 {
& .tone-5 {
background-color: #5f4e43;
}
}

@ -1,29 +0,0 @@
/* globals Template */
Template.messageBox.events({
'click .emoji-picker-icon'(event) {
event.stopPropagation();
if (RocketChat.EmojiPicker.isOpened()) {
RocketChat.EmojiPicker.close();
} else {
RocketChat.EmojiPicker.open(event.currentTarget, (emoji) => {
const input = $(event.currentTarget).parent().parent().find('.input-message');
const emojiValue = `:${ emoji }:`;
const caretPos = input.prop('selectionStart');
const textAreaTxt = input.val();
input.val(textAreaTxt.substring(0, caretPos) + emojiValue + textAreaTxt.substring(caretPos));
input.focus();
input.prop('selectionStart', caretPos + emojiValue.length);
input.prop('selectionEnd', caretPos + emojiValue.length);
});
}
}
});
Template.messageBox.onCreated(function() {
RocketChat.EmojiPicker.init();
});

@ -10,26 +10,25 @@ Package.onUse(function(api) {
'ecmascript',
'underscore',
'templating',
'less',
'rocketchat:lib',
'rocketchat:ui-message'
]);
api.addFiles('function-isSet.js', 'client');
api.addFiles('rocketchat.js');
api.addFiles('client/function-isSet.js', 'client');
api.addFiles('client/rocketchat.js');
api.addFiles('emojiParser.js', 'client');
api.addFiles('client/emojiParser.js', 'client');
api.addFiles('emojiPicker.html', 'client');
api.addFiles('emojiPicker.js', 'client');
api.addFiles('emojiPicker.less', 'client');
api.addFiles('client/emojiPicker.html', 'client');
api.addFiles('client/emojiPicker.js', 'client');
api.addFiles('client/emojiPicker.css', 'client');
api.addFiles('emoji.css', 'client');
api.addFiles('client/emoji.css', 'client');
api.addFiles('lib/emojiRenderer.js', 'client');
api.addFiles('lib/EmojiPicker.js', 'client');
api.addFiles('emojiButton.js', 'client');
api.addFiles('keyboardFix.js', 'client');
api.addFiles('client/lib/emojiRenderer.js', 'client');
api.addFiles('client/lib/EmojiPicker.js', 'client');
api.addFiles('client/emojiButton.js', 'client');
api.addFiles('client/keyboardFix.js', 'client');
api.export('renderEmoji');
});

@ -66,20 +66,17 @@ const getByteRange = function(header) {
};
// code from: https://github.com/jalik/jalik-ufs/blob/master/ufs-server.js#L91
// code from: https://github.com/jalik/jalik-ufs/blob/master/ufs-server.js#L310
const readFromGridFS = function(storeName, fileId, file, headers, req, res) {
const store = UploadFS.getStore(storeName);
const rs = store.getReadStream(fileId, file);
const ws = new stream.PassThrough();
rs.on('error', function(err) {
[rs, ws].forEach(stream => stream.on('error', function(err) {
store.onReadError.call(store, err, fileId, file);
res.end();
});
ws.on('error', function(err) {
store.onReadError.call(store, err, fileId, file);
res.end();
});
}));
ws.on('close', function() {
// Close output stream at the end
ws.emit('end');
@ -89,7 +86,6 @@ const readFromGridFS = function(storeName, fileId, file, headers, req, res) {
// Transform stream
store.transformRead(rs, ws, fileId, file, req, headers);
const range = getByteRange(req.headers.range);
let out_of_range = false;
if (range) {
@ -193,15 +189,12 @@ new FileUploadClass({
get(file, req, res) {
const reqModifiedHeader = req.headers['if-modified-since'];
if (reqModifiedHeader) {
if (reqModifiedHeader === (file.uploadedAt && file.uploadedAt.toUTCString())) {
res.setHeader('Last-Modified', reqModifiedHeader);
res.writeHead(304);
res.end();
return;
}
if (reqModifiedHeader && reqModifiedHeader === (file.uploadedAt && file.uploadedAt.toUTCString())) {
res.setHeader('Last-Modified', reqModifiedHeader);
res.writeHead(304);
res.end();
return;
}
file = FileUpload.addExtensionTo(file);
const headers = {
'Cache-Control': 'public, max-age=0',

@ -53,7 +53,7 @@ Object.assign(FileUpload, {
}
const height = RocketChat.settings.get('Accounts_AvatarSize');
const width = height;
return RocketChatFile.gm(readStream).background('#ffffff').resize(width, `${ height }^`).gravity('Center').crop(width, height).extent(width, height).stream('jpeg').pipe(writeStream);
return (file => RocketChat.Info.GraphicsMagick.enabled ? file: file.alpha('remove'))(RocketChatFile.gm(readStream).background('#FFFFFF')).resize(width, `${ height }^`).gravity('Center').crop(width, height).extent(width, height).stream('jpeg').pipe(writeStream);
},
avatarsOnValidate(file) {
@ -61,24 +61,21 @@ Object.assign(FileUpload, {
return;
}
const tmpFile = UploadFS.getTempFilePath(file._id);
const fut = new Future();
const tempFilePath = UploadFS.getTempFilePath(file._id);
const height = RocketChat.settings.get('Accounts_AvatarSize');
const width = height;
const future = new Future();
RocketChatFile.gm(tmpFile).background('#ffffff').resize(width, `${ height }^`).gravity('Center').crop(width, height).extent(width, height).setFormat('jpeg').write(tmpFile, Meteor.bindEnvironment((err) => {
(file => RocketChat.Info.GraphicsMagick.enabled ? file: file.alpha('remove'))(RocketChatFile.gm(tempFilePath).background('#FFFFFF')).resize(width, `${ height }^`).gravity('Center').crop(width, height).extent(width, height).setFormat('jpeg').write(tempFilePath, Meteor.bindEnvironment(err => {
if (err != null) {
console.error(err);
}
const size = fs.lstatSync(tmpFile).size;
const size = fs.lstatSync(tempFilePath).size;
this.getCollection().direct.update({_id: file._id}, {$set: {size}});
fut.return();
future.return();
}));
return fut.wait();
return future.wait();
},
uploadsTransformWrite(readStream, writeStream, fileId, file) {
@ -183,18 +180,16 @@ Object.assign(FileUpload, {
if (this.handlers[handlerName] == null) {
console.error(`Upload handler "${ handlerName }" does not exists`);
}
return this.handlers[handlerName];
},
get(file, req, res, next) {
if (file.store && this.handlers && this.handlers[file.store] && this.handlers[file.store].get) {
this.handlers[file.store].get(file, req, res, next);
} else {
res.writeHead(404);
res.end();
return;
const store = this.getStoreByName(file.store);
if (store && store.get) {
return store.get(file, req, res, next);
}
res.writeHead(404);
res.end();
}
});

@ -24,6 +24,7 @@ Meteor.methods({
const attachment = {
title: file.name,
type: 'file',
description: file.description,
title_link: fileUrl,
title_link_download: true

@ -1,7 +1,9 @@
.icon-github_enterprise::before {
height: 1em;
content: "";
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wJGBYxHYxl31wAAAHpSURBVDjLpZI/aFNRFMZ/973bJqGRPopV4qNq/+SpTYnWRhCKilShg9BGcHOM+GfQoZuLk4iLgw4qZNBaHLuIdBNHl7Ta1qdNFI3SihnaNG1MpH3vuiQYQnwZvHCG893zffc751z4z6PX5T5gA1DAKnAaOAQEgAfAVeCpl+CeCrlRuEC6maO4h0A1wl4tPAHMqNUthvrDdHYY7A3t4rDVjeO6rBU2FaABM1WCrBNoi48Mi+nH9yj+KtPibAKwJXfQ5vcRG7soUnYmWEuQgAEIYBv4cGpoILI0Z4tyYYPegS6UguyijZQ6J45GSNmZHzUcJYD2ii2Ajv7efZ8WZ6ZwXFj79hXpayW4O0SL1Nl/8jzZlZ9dQLFS70pgvZKIyGD0yvu5eRmMnrk1PjI81ir1qBACTdPevXj95mVuNX8XKDQc/+T334bZZ104cvzYw2s3J3qAL5WXSsDbf61NNMBu+wOBs+VSyQ84Nfhg028ZGx3/qyy0lC7lgi7lghBitoon03lvB8l0/k7Wnk+8mny0cyXzEcfZxgwfZPTyRMHsOzAFXE9YhtNQIJnOx4FpJXT1eSkn2g0frqMoFrfoCXcqlCOAGwnLuO/l4JymcWl5uRxzXUKghBAiZ5r+WaV4lrCM555zqO+x2d0ftGmpiA/0k70AAAAASUVORK5CYII=);
height: 1em;
background-position: center center;
background-repeat: no-repeat;
background-position: center center;
}

@ -0,0 +1,7 @@
This directory and the files immediately inside it are automatically generated
when you change this package's NPM dependencies. Commit the files in this
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
so that others run the same versions of sub-dependencies.
You should NOT check in the node_modules directory that Meteor automatically
creates; if you are using git, the .gitignore file tells git to ignore it.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,7 @@
For this to properly work, you need to have a Google Service Account;
https://console.cloud.google.com/apis/credentials
Then you have to authorize that service account access to your buckets;
https://console.cloud.google.com/storage/browser
To do that, click on the ellipsis by your bucket's row and Edit object default permissions
Add user and paste the service account e-mail with owner privileges

@ -0,0 +1,84 @@
RocketChat.GoogleVision = {
getVisionAttributes(attachment) {
const attributes = {};
const labels = [];
if (attachment.labels && attachment.labels.length > 0) {
attachment.labels.forEach(label => {
labels.push({ label });
});
}
if (attachment.safeSearch && attachment.safeSearch && attachment.safeSearch.adult === true) {
labels.push({ label: 'NSFW', bgColor: 'red', fontColor: 'white' });
}
if (attachment.safeSearch && attachment.safeSearch.violence === true) {
labels.push({ label: 'Violence', bgColor: 'red', fontColor: 'white' });
}
if (attachment.colors && attachment.colors.length > 0) {
attributes.color = `#${ attachment.colors[0] }`;
}
if (attachment.logos && attachment.logos.length > 0) {
labels.push({ label: `Logo: ${ attachment.logos[0] }` });
}
if (attachment.faces && attachment.faces.length > 0) {
let faceCount = 0;
attachment.faces.forEach(face => {
const faceAttributes = [];
if (face.joy) {
faceAttributes.push('Joy');
}
if (face.sorrow) {
faceAttributes.push('Sorrow');
}
if (face.anger) {
faceAttributes.push('Anger');
}
if (face.surprise) {
faceAttributes.push('Surprise');
}
if (faceAttributes.length > 0) {
labels.push({ label: `Face ${ ++faceCount }: ${ faceAttributes.join(', ') }` });
}
});
}
if (labels.length > 0) {
attributes.labels = labels;
}
return attributes;
},
init() {
Tracker.autorun(() => {
if (RocketChat.settings.get('GoogleVision_Enable')) {
RocketChat.callbacks.add('renderMessage', (message) => {
if (message.attachments && message.attachments.length > 0) {
for (const index in message.attachments) {
if (message.attachments.hasOwnProperty(index)) {
const attachment = message.attachments[index];
message.attachments[index] = Object.assign(message.attachments[index], this.getVisionAttributes(attachment));
}
}
}
return message;
}, RocketChat.callbacks.priority.HIGH - 3, 'googlevision');
RocketChat.callbacks.add('streamMessage', (message) => {
if (message.attachments && message.attachments.length > 0) {
for (const index in message.attachments) {
if (message.attachments.hasOwnProperty(index)) {
const attachment = message.attachments[index];
message.attachments[index] = Object.assign(message.attachments[index], this.getVisionAttributes(attachment));
}
}
}
}, RocketChat.callbacks.priority.HIGH - 3, 'googlevision-stream');
} else {
RocketChat.callbacks.remove('renderMessage', 'googlevision');
RocketChat.callbacks.remove('streamMessage', 'googlevision-stream');
}
});
}
};
Meteor.startup(function() {
RocketChat.GoogleVision.init();
});

@ -0,0 +1,21 @@
Package.describe({
name: 'rocketchat:google-vision',
version: '0.0.1',
summary: 'Rocket.Chat Google Vision Integration',
git: ''
});
Npm.depends({
'@google-cloud/storage': '1.2.1',
'@google-cloud/vision': '0.11.5'
});
Package.onUse(function(api) {
api.use([
'ecmascript',
'rocketchat:lib'
]);
api.addFiles('client/googlevision.js', 'client');
api.addFiles(['server/settings.js', 'server/googlevision.js', 'server/models/Messages.js'], 'server');
});

@ -0,0 +1,153 @@
class GoogleVision {
constructor() {
this.storage = Npm.require('@google-cloud/storage');
this.vision = Npm.require('@google-cloud/vision');
this.storageClient = {};
this.visionClient = {};
this.enabled = RocketChat.settings.get('GoogleVision_Enable');
this.serviceAccount = {};
RocketChat.settings.get('GoogleVision_Enable', (key, value) => {
this.enabled = value;
});
RocketChat.settings.get('GoogleVision_ServiceAccount', (key, value) => {
try {
this.serviceAccount = JSON.parse(value);
this.storageClient = this.storage({ credentials: this.serviceAccount });
this.visionClient = this.vision({ credentials: this.serviceAccount });
} catch (e) {
this.serviceAccount = {};
}
});
RocketChat.settings.get('GoogleVision_Block_Adult_Images', (key, value) => {
if (value) {
RocketChat.callbacks.add('beforeSaveMessage', this.blockUnsafeImages.bind(this), RocketChat.callbacks.priority.MEDIUM, 'googlevision-blockunsafe');
} else {
RocketChat.callbacks.remove('beforeSaveMessage', 'googlevision-blockunsafe');
}
});
RocketChat.callbacks.add('afterFileUpload', this.annotate.bind(this));
}
incCallCount(count) {
const currentMonth = new Date().getMonth();
const maxMonthlyCalls = RocketChat.settings.get('GoogleVision_Max_Monthly_Calls') || 0;
if (maxMonthlyCalls > 0) {
if (RocketChat.settings.get('GoogleVision_Current_Month') !== currentMonth) {
RocketChat.settings.set('GoogleVision_Current_Month', currentMonth);
if (count > maxMonthlyCalls) {
return false;
}
} else if (count + (RocketChat.settings.get('GoogleVision_Current_Month_Calls') || 0) > maxMonthlyCalls) {
return false;
}
}
RocketChat.models.Settings.update({ _id: 'GoogleVision_Current_Month_Calls' }, { $inc: { value: count } });
return true;
}
blockUnsafeImages(message) {
if (this.enabled && this.serviceAccount && message && message.file && message.file._id) {
const file = RocketChat.models.Uploads.findOne({ _id: message.file._id });
if (file && file.type && file.type.indexOf('image') !== -1 && file.store === 'GoogleCloudStorage:Uploads' && file.GoogleStorage) {
if (this.incCallCount(1)) {
const bucket = this.storageClient.bucket(RocketChat.settings.get('FileUpload_GoogleStorage_Bucket'));
const bucketFile = bucket.file(file.GoogleStorage.path);
const results = Meteor.wrapAsync(this.visionClient.detectSafeSearch, this.visionClient)(bucketFile);
if (results && results.adult === true) {
FileUpload.getStore('Uploads').deleteById(file._id);
const user = RocketChat.models.Users.findOneById(message.u && message.u._id);
if (user) {
RocketChat.Notifications.notifyUser(user._id, 'message', {
_id: Random.id(),
rid: message.rid,
ts: new Date,
msg: TAPi18n.__('Adult_images_are_not_allowed', {}, user.language)
});
}
throw new Meteor.Error('GoogleVisionError: Image blocked');
}
} else {
console.error('Google Vision: Usage limit exceeded');
}
return message;
}
}
}
annotate({ message }) {
const visionTypes = [];
if (RocketChat.settings.get('GoogleVision_Type_Document')) {
visionTypes.push('document');
}
if (RocketChat.settings.get('GoogleVision_Type_Faces')) {
visionTypes.push('faces');
}
if (RocketChat.settings.get('GoogleVision_Type_Landmarks')) {
visionTypes.push('landmarks');
}
if (RocketChat.settings.get('GoogleVision_Type_Labels')) {
visionTypes.push('labels');
}
if (RocketChat.settings.get('GoogleVision_Type_Logos')) {
visionTypes.push('logos');
}
if (RocketChat.settings.get('GoogleVision_Type_Properties')) {
visionTypes.push('properties');
}
if (RocketChat.settings.get('GoogleVision_Type_SafeSearch')) {
visionTypes.push('safeSearch');
}
if (RocketChat.settings.get('GoogleVision_Type_Similar')) {
visionTypes.push('similar');
}
if (this.enabled && this.serviceAccount && visionTypes.length > 0 && message.file && message.file._id) {
const file = RocketChat.models.Uploads.findOne({ _id: message.file._id });
if (file && file.type && file.type.indexOf('image') !== -1 && file.store === 'GoogleCloudStorage:Uploads' && file.GoogleStorage) {
if (this.incCallCount(visionTypes.length)) {
const bucket = this.storageClient.bucket(RocketChat.settings.get('FileUpload_GoogleStorage_Bucket'));
const bucketFile = bucket.file(file.GoogleStorage.path);
this.visionClient.detect(bucketFile, visionTypes, Meteor.bindEnvironment((error, results) => {
if (!error) {
RocketChat.models.Messages.setGoogleVisionData(message._id, this.getAnnotations(visionTypes, results));
} else {
console.trace('GoogleVision error: ', error.stack);
}
}));
} else {
console.error('Google Vision: Usage limit exceeded');
}
}
}
}
getAnnotations(visionTypes, visionData) {
if (visionTypes.length === 1) {
const _visionData = {};
_visionData[`${ visionTypes[0] }`] = visionData;
visionData = _visionData;
}
const results = {};
for (const index in visionData) {
if (visionData.hasOwnProperty(index)) {
switch (index) {
case 'faces':
case 'landmarks':
case 'labels':
case 'similar':
case 'logos':
results[index] = (results[index] || []).concat(visionData[index] || []);
break;
case 'safeSearch':
results['safeSearch'] = visionData['safeSearch'];
break;
case 'properties':
results['colors'] = visionData[index]['colors'];
break;
}
}
}
return results;
}
}
RocketChat.GoogleVision = new GoogleVision;

@ -0,0 +1,10 @@
RocketChat.models.Messages.setGoogleVisionData = function(messageId, visionData) {
const updateObj = {};
for (const index in visionData) {
if (visionData.hasOwnProperty(index)) {
updateObj[`attachments.0.${ index }`] = visionData[index];
}
}
return this.update({ _id: messageId }, { $set: updateObj });
};

@ -0,0 +1,88 @@
Meteor.startup(function() {
RocketChat.settings.add('GoogleVision_Enable', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
public: true,
enableQuery: { _id: 'FileUpload_Storage_Type', value: 'GoogleCloudStorage' }
});
RocketChat.settings.add('GoogleVision_ServiceAccount', '', {
type: 'string',
group: 'FileUpload',
section: 'Google Vision',
multiline: true,
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Max_Monthly_Calls', 0, {
type: 'int',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Current_Month', 0, {
type: 'int',
group: 'FileUpload',
section: 'Google Vision',
hidden: true
});
RocketChat.settings.add('GoogleVision_Current_Month_Calls', 0, {
type: 'int',
group: 'FileUpload',
section: 'Google Vision',
blocked: true
});
RocketChat.settings.add('GoogleVision_Type_Document', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Type_Faces', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Type_Landmarks', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Type_Labels', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Type_Logos', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Type_Properties', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Type_SafeSearch', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
RocketChat.settings.add('GoogleVision_Block_Adult_Images', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: [{ _id: 'GoogleVision_Enable', value: true }, { _id: 'GoogleVision_Type_SafeSearch', value: true }]
});
RocketChat.settings.add('GoogleVision_Type_Similar', false, {
type: 'boolean',
group: 'FileUpload',
section: 'Google Vision',
enableQuery: { _id: 'GoogleVision_Enable', value: true }
});
});

@ -16,5 +16,5 @@ Package.onUse(function(api) {
'rocketchat:lib'
]);
api.addFiles('client.js', 'client');
api.addFiles('client/client.js', 'client');
});

@ -990,11 +990,9 @@
"Office_hours_enabled": "تم تفعيل ساعات الدوام في المكتب",
"Office_hours_updated": "تم تحديث ساعات الدوام في المكتب",
"Offline": "غير متصل",
"Offline_DM_Email": "لقد تم بعث برسالة مباشرة من قبل __user__",
"Offline_form": "شكل متواجد حاليا",
"Offline_form_unavailable_message": "شكل متواجد حاليا رسالة غير متوفرة",
"Offline_Link_Message": "الذهاب إلى الرسالة",
"Offline_Mention_Email": "تم التنويه باسمك بواسطة __user__ في #__room__",
"Offline_message": "رسالة متواجد حاليا",
"Offline_success_message": "رسالة نجاح متواجد حاليا",
"Offline_unavailable": "غير متوفر حاليا",
@ -1685,4 +1683,4 @@
"your_message_optional": "رسالتك (اختياري)",
"Your_password_is_wrong": "كلمة السر خاطئة",
"Your_push_was_sent_to_s_devices": "وقد أرسلت دفعك إلى أجهزة٪ الصورة"
}
}

@ -133,6 +133,7 @@
"Add_custom_oauth": "Afegeix OAuth personalitzat",
"Add_Domain": "Afegir domini",
"Add_manager": "Afegeix supervisor",
"Add_Role": "Afegeix rol",
"Add_user": "Afegeix usuari",
"Add_User": "Afegeix usuari",
"Add_users": "Afegeix usuaris",
@ -178,6 +179,7 @@
"API_Drupal_URL": "Adreça URL del servidor de Drupal",
"API_Drupal_URL_Description": "Exemple: https://domini.com (sense la barra final)",
"API_Embed": "Incrusta (embed)",
"API_Embed_UserAgent": "Incrusta user agent de la consulta",
"API_Embed_Description": "Activa o no les previsualitzacions d'enllaços quan un usuari publica l'enllaç a un web.",
"API_EmbedCacheExpirationDays": "Caducitat de la memòria cau de les incrustacions (en dies)",
"API_EmbedDisabledFor": "Deshabilitar la incrustació per als usuaris",
@ -316,6 +318,7 @@
"Chat_button": "botó de xat",
"Chat_closed": "Xat tancat",
"Chat_closed_successfully": "Xat tancat correctament",
"Chat_Now": "Xateja ara",
"Chat_window": "finestra de xat",
"Chatops_Enabled": "Activa Chatops",
"Chatops_Title": "Tauler de Chatops",
@ -416,10 +419,12 @@
"Desktop": "Escriptori",
"Desktop_Notification_Test": "Prova de notificació d'escriptori",
"Desktop_Notifications": "Notificacions d'escriptori",
"Desktop_Notifications_Default_Alert": "Alerta per defecte per a les notificacions d'escriptori",
"Desktop_Notifications_Disabled": "Les notificacions d'escriptori han estat desactivades. Canvia les preferències del navegador si vols tornar a activar-les.",
"Desktop_Notifications_Duration": "Durada de les notificacions d'escriptori",
"Desktop_Notifications_Duration_Description": "Segons de mostra de les notificacions d'escriptori. Això pot afectar al centre de notificacions del macOS. Introduïu 0 per utilitzar la configuració del navegador per defecte i no afectar al centre de notificacions.",
"Desktop_Notifications_Enabled": "Les notificacions d'escriptori estan activades",
"Different_Style_For_User_Mentions": "Estil diferent per les mencions d'usuari",
"Direct_message_someone": "Envia un missatge directe a algú",
"Direct_Messages": "Missatges directes",
"Disable_Notifications": "Desactiva notificacions",
@ -527,7 +532,7 @@
"error-invalid-redirectUri": "Redirecció URI invàlida",
"error-invalid-role": "Rol no vàlid",
"error-invalid-room": "Sala no vàlida",
"error-invalid-room-name": "<strong>__room_name__</strong> no és un nom de sala vàlid,<br/> utilitzeu només lletres, números, guions i guions baixos",
"error-invalid-room-name": "<strong>__room_name__</strong> no és un nom de sala vàlid",
"error-invalid-room-type": "<strong>__type__</strong> no és un tipus vàlid de sala.",
"error-invalid-settings": "La configuració proporcionada no és vàlida",
"error-invalid-subscription": "Subscripció no vàlida",
@ -768,7 +773,7 @@
"Invalid_name": "El nom no ha d'estar buit",
"Invalid_notification_setting_s": "Configuració de notificació invàlida: %s",
"Invalid_pass": "La contrasenya no ha d'estar buida",
"Invalid_room_name": "<strong>%s</strong> no és un nom de sala vàlid,<br/> utilitza només lletres, números, guions i guions baixos",
"Invalid_room_name": "<strong>%s</strong> no és un nom de sala vàlid",
"Invalid_secret_URL_message": "L'adreça URL proporcionada no és vàlida.",
"Invalid_setting_s": "Opció invàlida: %s",
"Invalid_two_factor_code": "Codi de dos factors invàlid",
@ -1045,6 +1050,7 @@
"Min_length_is": "La llargada mínima és %s",
"minutes": "minuts",
"Mobile": "Mòbil",
"Mobile_Notifications_Default_Alert": "Alerta per defecte notificacions mòbil",
"Monday": "dilluns",
"Monitor_history_for_changes_on": "Monitoritza l'historial per canvis a ",
"More_channels": "Més canals",
@ -1101,9 +1107,12 @@
"Not_found_or_not_allowed": "No trobat o no permès",
"Nothing": "Res",
"Nothing_found": "No s'ha trobat res",
"Notification_Desktop_Default_For": "Mostra notificacions d'escriptori per",
"Notification_Mobile_Default_For": "Notificacions push mòbil per",
"Notification_Duration": "Duració de la notificació",
"Notifications": "Notificacions",
"Notifications_Muted_Description": "Si esculls silenciar-ho tot, no veuràs la sala destacada a la llista quan hi hagi nous missatges, excepte si són mencions. Silenciar les notificacions sobreescriurà les opcions de notificació.",
"Notifications_Sound_Volume": "Volum del so de notificacions",
"Notify_all_in_this_room": "Notifica a tothom d'aquest canal",
"Notify_active_in_this_room": "Notifica als usuaris actius d'aquesta sala",
"Num_Agents": "# d'agents",
@ -1118,11 +1127,9 @@
"Office_hours_enabled": "Horari d'obertura actiu",
"Office_hours_updated": "Horari actualitzat",
"Offline": "Fora de línia",
"Offline_DM_Email": "__user__ us ha enviat un missatge directe",
"Offline_form": "formulari en línia",
"Offline_form_unavailable_message": "Missatge de formulari fora de línia no disponible",
"Offline_Link_Message": "VÉS AL MISSATGE",
"Offline_Mention_Email": "__user__ us ha mencionat a la sala #__room__",
"Offline_message": "missatge fora de línia",
"Offline_success_message": "Fora de línia correcte",
"Offline_unavailable": "Fora de línia no disponible",
@ -1316,6 +1323,12 @@
"Pinned_a_message": "S'ha fixat un missatge:",
"Pinned_Messages": "Missatges fixats",
"PiwikAnalytics_siteId_Description": "L'ID de lloc a utilitzar per a la identificació d'aquest lloc. Exemple: 17",
"PiwikAdditionalTrackers": "Llocs piwik addicionals",
"PiwikAnalytics_prependDomain": "Prefixa domini",
"PiwikAnalytics_prependDomain_Description": "Prefixa el domini del lloc al títol de la pàgina",
"PiwikAnalytics_cookieDomain": "Tots els subdominis",
"PiwikAnalytics_cookieDomain_Description": "Segueix visitants per tots els subdominis",
"PiwikAnalytics_domains": "Amaga enllaços de sortida",
"PiwikAnalytics_url_Description": "L'adreça URL on es troba el Piwik, assegureu-vos d'incloure la barra del final. Exemple: //piwik.rocket.chat/",
"Placeholder_for_email_or_username_login_field": "Indicatiu per al camp d'inici de sessió (correu electrònic o nom d'usuari)",
"Placeholder_for_password_login_field": "Indicatiu per al camp de contrasenya (inici de sessió)",
@ -1454,6 +1467,7 @@
"Rooms": "Sales",
"Running_Instances": "Instàncies executant-se",
"S_new_messages_since_s": "%s nous des de: %s",
"Same_Style_For_Mentions": "Mateix estil per a mencions",
"SAML": "SAML",
"SAML_Custom_Cert": "Certificat personalitzat",
"SAML_Custom_Entry_point": "Punt d'entrada (Entry Point) personalitzat",
@ -1487,6 +1501,7 @@
"Select_an_avatar": "Selecciona un avatar",
"Select_file": "Selecciona un arxiu",
"Select_service_to_login": "Selecciona un servei per iniciar sessió i carregar la teva imatge o puja una foto del teu ordinador",
"Select_role": "Selecciona un rol",
"Select_user": "Selecciona usuari",
"Select_users": "Selecciona els usuaris",
"Selected_agents": "Agents seleccionats",
@ -1710,8 +1725,10 @@
"Type_your_message": "Introduïu el missatge",
"Type_your_name": "Escriu el teu nom",
"Type_your_new_password": "Escriu la nova contrasenya",
"UI_Allow_room_names_with_special_chars": "Permet caràcters especials als noms de sala",
"UI_DisplayRoles": "Mostra rols",
"UI_Merge_Channels_Groups": "Uneix grups privats amb canals",
"UI_Unread_Counter_Style": "Estil de comptador de no-llegits",
"UI_Use_Name_Avatar": "Utilitza les inicials del nom complet per generar l'avatar per defecte",
"UI_Use_Real_Name": "Utilitza el nom real",
"Unarchive": "Desarxiva",
@ -1892,4 +1909,4 @@
"your_message_optional": "el teu missatge (opcional)",
"Your_password_is_wrong": "La contrasenya és incorrecta!",
"Your_push_was_sent_to_s_devices": "La notificació push s'ha enviat a %s dispositius"
}
}

@ -133,6 +133,7 @@
"Add_custom_oauth": "Přidat vlastní OAuth",
"Add_Domain": "Přidat Doménu",
"Add_manager": "Přidat správce",
"Add_Role": "Přidat roli",
"Add_user": "Přidat uživatele",
"Add_User": "Přidat uživatele",
"Add_users": "Přidat uživatele",
@ -154,11 +155,11 @@
"All_channels": "Všechny místnosti",
"All_logs": "Všechny logy",
"All_messages": "Všechny zprávy",
"Allow_Invalid_SelfSigned_Certs": "Umožnit nevalidní či self-signed certifikáty",
"Allow_Invalid_SelfSigned_Certs": "Umožnit neplatné či self-signed certifikáty",
"Allow_Invalid_SelfSigned_Certs_Description": "Umožňují použít neplatné/self-signed SSL certifikáty pro ověření odkazů a náhledů.",
"Allow_switching_departments": "Povolit uživateli změnit oddělení",
"Always_open_in_new_window": "Vždy otevírat v novém okně",
"Analytics_features_enabled": "Funkce Povoleny",
"Analytics_features_enabled": "Povolené funkce",
"Analytics_features_messages_Description": "Sleduje vlastní události spojené s uživatelskými akcemi u zpráv.",
"Analytics_features_rooms_Description": "Sleduje vlastní události spojené s uživatelskými akcemi na místnosti nebo skupině (vytvoření, odchod, smazání).",
"Analytics_features_users_Description": "Sleduje vlastní události spojené s úpravou uživatele (počet obnovení hesla, úprava profilovu či obrázku, atd).",
@ -178,6 +179,7 @@
"API_Drupal_URL": "Drupal URL Serveru",
"API_Drupal_URL_Description": "Například: https://domain.com (bez lomítka na konci)",
"API_Embed": "Náhled vložených odkazů",
"API_Embed_UserAgent": "User agent requestu na embed zdroj",
"API_Embed_Description": "Zda zobrazit náhled stránky když uživatel pošle odkaz",
"API_EmbedCacheExpirationDays": "Počet dní expirace cache embed",
"API_EmbedDisabledFor": "Zakázat vložený obsah pro uživatele",
@ -316,6 +318,7 @@
"Chat_button": "Chat Tlačítko",
"Chat_closed": "Místnost uzavřena",
"Chat_closed_successfully": "Místnost úspěšně uzavřena",
"Chat_Now": "Chatovat nyní",
"Chat_window": "Chat okno",
"Chatops_Enabled": "Aktivovat Chatops",
"Chatops_Title": "Chatops Panel",
@ -330,6 +333,8 @@
"Clear_all_unreads_question": "Označit vše jako přečtené?",
"Click_here": "Klikněte zde",
"Click_here_for_more_info": "Klikněte pro více infomací",
"UI_Click_Direct_Message": "Kliknutím vytvořit přímou zprávu",
"UI_Click_Direct_Message_Description": "Přeskočit záložku profilu a přejít přímo do konverzace",
"Client_ID": "ID klienta",
"Client_Secret": "Secret klienta",
"Clients_will_refresh_in_a_few_seconds": "Klienti se obnoví během několika sekund",
@ -414,10 +419,12 @@
"Desktop": "Plocha",
"Desktop_Notification_Test": "Test oznámení na ploše",
"Desktop_Notifications": "Oznámení na ploše",
"Desktop_Notifications_Default_Alert": "Výchozí upozornění oznámení na ploše",
"Desktop_Notifications_Disabled": "Oznámení na ploše jsou vypnuta. Změňte nastavení svého prohlížeče, pokud chcete oznámení povolit.",
"Desktop_Notifications_Duration": "Délka zobrazení notifikace",
"Desktop_Notifications_Duration_Description": "Délka zobrazení oznámení (v sekundách). Toto může ovlivnit nastevení OS X Oznamovacího centra. Zadejte 0 pro použítí výchozí nastavení prohlížeče/notifikačního centra OS X",
"Desktop_Notifications_Enabled": "Oznámení na ploše jsou povolena",
"Different_Style_For_User_Mentions": "Odlišný styl pro zmínky",
"Direct_message_someone": "Přímá zpráva někomu",
"Direct_Messages": "Přímé zprávy",
"Disable_Notifications": "Zakázat notifikace",
@ -525,7 +532,7 @@
"error-invalid-redirectUri": "Neplatná URL přesměrování",
"error-invalid-role": "Neplatná role",
"error-invalid-room": "Neplatná místnost",
"error-invalid-room-name": "<strong>__room_name__</strong> není platný název místnosti, <br/> použijte pouze písmena, číslice, pomlčky a podtržítka",
"error-invalid-room-name": "<strong>__room_name__</strong> není platný název místnosti",
"error-invalid-room-type": "<strong>__type__</strong> není platný typ místnosti.",
"error-invalid-settings": "Neplatné nastavení",
"error-invalid-subscription": "Neplatné přihlášení",
@ -567,7 +574,7 @@
"False": "Ne",
"Favorite_Rooms": "Aktivovat oblíbené místnosti",
"Favorites": "Oblíbené",
"Features_Enabled": "Funkce Povoleny",
"Features_Enabled": "Povolené funkce",
"Field": "Pole",
"Field_removed": "Pole odebráno",
"Field_required": "Pole vyžadováno",
@ -576,7 +583,7 @@
"File_type_is_not_accepted": "Neplatný typ souboru",
"File_uploaded": "Soubor nahrán",
"FileUpload": "Nahrání souboru",
"FileUpload_Enabled": "Nahrávání souborů povoleno",
"FileUpload_Enabled": "Povolit nahrávání souborů",
"FileUpload_Disabled": "Nahrávání souborů je zakázáno.",
"FileUpload_Enabled_Direct": "Nahrávání souborů povoleno v přímé konverzaci",
"FileUpload_File_Empty": "Soubor je prázdný",
@ -766,7 +773,7 @@
"Invalid_name": "Název nesmí být prázdný",
"Invalid_notification_setting_s": "Neplatné nastavení upozornění: %s",
"Invalid_pass": "Heslo nesmí být prázdné",
"Invalid_room_name": "<strong>%s</strong> není platné jméno místnosti,<br/> použijte pouze písmena, číslice a pomlčky",
"Invalid_room_name": "<strong>%s</strong> není platné jméno místnosti.",
"Invalid_secret_URL_message": "Adresa URL je neplatná.",
"Invalid_setting_s": "Neplatné nastavení: %s",
"Invalid_two_factor_code": "Neplatný dvoufázový kód",
@ -957,7 +964,7 @@
"Mail_Messages": "Odeslat zprávy",
"Mail_Messages_Instructions": "Kliknutím na zprávy vyberte ty, které chcete poslat e-mailem.",
"Mail_Messages_Subject": "Zde je vybraná část %s zpráv",
"Mailer": "Odesílač",
"Mailer": "Odesílač mailů",
"Mailer_body_tags": "Je <b>nutné</b> použít [unsubscribe] pro vložení odkazu na odhlášení. <br/> Můžete také použít [name], [fname], [lname] pro uživatelské jméno, křestí jméno a příjmen nebo [email] pro e-mail uživatele.",
"Mailing": "Mailing",
"Make_Admin": "Změnit na Správce",
@ -979,6 +986,7 @@
"Members_List": "Seznam členů",
"Mentions": "Zmínky",
"Mentions_default": "Zmínky (výchozí)",
"Mentions_only": "Pouze zmínky",
"Message": "Zpráva",
"Message_AllowBadWordsFilter": "Povolit filtrování sprostých slov",
"Message_AllowDeleting": "Povolit mazání zpráv",
@ -1033,7 +1041,7 @@
"Message_VideoRecorderEnabledDescription": "Vyžaduje přidání 'video/webm' mezi povolené typy souborů v nastavení",
"Messages": "Zprávy",
"Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here": "Zprávy, které jsou odesílány do příchozí WebHook integrace budou zveřejněny zde.",
"Meta": "Meta",
"Meta": "Meta informace",
"Meta_fb_app_id": "Facebook App Id",
"Meta_custom": "Vlastní meta tagy",
"Meta_google-site-verification": "Ověření stránek Google",
@ -1043,6 +1051,7 @@
"Min_length_is": "Minimální délka je %s",
"minutes": "minuty",
"Mobile": "Mobilní",
"Mobile_Notifications_Default_Alert": "Výchozí upozornění mobilní notifikace",
"Monday": "Pondělí",
"Monitor_history_for_changes_on": "Sledovat historii na změny:",
"More_channels": "Více místností",
@ -1099,9 +1108,14 @@
"Not_found_or_not_allowed": "Nenalezeno nebo není povoleno",
"Nothing": "Nic",
"Nothing_found": "Nic nalezeno",
"Notification_Desktop_Default_For": "Zobrazit oznámení na ploše",
"Notification_Mobile_Default_For": "Zasílat mobilní notifikace",
"Notification_Duration": "Délka zobrazení oznámení",
"Notifications": "Oznámení",
"Notifications_Muted_Description": "Pokud ztišíte všechno, neuvidíte zvýrazněné místnosti s novými zprávami, krom zmínek. Ztišení notifikací přetěží nastavení notifikací v jednotlivých místnostech.",
"Notifications_Max_Room_Members": "Maximální počet uživatelů v místnosti pro zakázání zmínky všech",
"Notifications_Max_Room_Members_Description": "Pokud počet uživatelů v místnosti překročí zadané číslo, notifikace všech (@all) nebude povolena. Uživatelé si toto nastavení mohou individuálně změnit. (0 možnost zakáže)",
"Notifications_Sound_Volume": "Hlasitost zvuku notifikace",
"Notify_all_in_this_room": "Oznámit všem v této místnosti",
"Notify_active_in_this_room": "Notifikovat aktivní uživatele v místnosti",
"Num_Agents": "# Operátorů",
@ -1116,11 +1130,11 @@
"Office_hours_enabled": "Otevírací doba povolena",
"Office_hours_updated": "Otevírací doba aktualizována",
"Offline": "Offline",
"Offline_DM_Email": "Přímá zpráva od __user__",
"Offline_form": "Offline formulář",
"Offline_form_unavailable_message": "Zpráva nedostupného offline formuláře",
"Offline_Link_Message": "PŘEJÍT NA ZPRÁVU",
"Offline_Mention_Email": "Zmínka od __user__ v #__room__",
"Offline_Mention_All_Email": "Zpráva od __user__ v místnosti #__room__",
"Offline_message": "Offline zprávy",
"Offline_success_message": "Zpráva pro offline úspěšnou akci",
"Offline_unavailable": "Offline nedostupný",
@ -1314,6 +1328,14 @@
"Pinned_a_message": "Připnuta zpráva:",
"Pinned_Messages": "Připnuté zprávy",
"PiwikAnalytics_siteId_Description": "ID webu k identifikaci těchto stránek (Např: 17)",
"PiwikAdditionalTrackers": "Dalši Piwik stránky",
"PiwikAdditionalTrackers_Description": "Zde vložte další Piwik stránky a jejich ID v následujícím formátu:\n [ { \"trackerURL\" : \"https://moje.piwik.domena2/\", \"siteId\" : 2 }, { \"trackerURL\" : \"https://moje.piwik.domena3/\", \"siteId\" : 3 } ]",
"PiwikAnalytics_prependDomain": "Přidat doménu",
"PiwikAnalytics_prependDomain_Description": "Přidat doménu do názvu stránky pro trackování",
"PiwikAnalytics_cookieDomain": "Všechny subdomény",
"PiwikAnalytics_cookieDomain_Description": "Sledovat uživatele napříč všemi subdoménami",
"PiwikAnalytics_domains": "Skrýt odchozí odkazy",
"PiwikAnalytics_domains_Description": "Pro report odchozích odkazů skrýt kliky na známé URL.\nDomény vkládejte na nový řádek bez oddělovacích znaků",
"PiwikAnalytics_url_Description": "Url Piwik vaší instance, nezapomeňte zahrnout koncové lomítko. Příklad: //piwik.rocket.chat/",
"Placeholder_for_email_or_username_login_field": "Zástupný text pro pole e-mailu nebo uživatelského jména v přihlášení",
"Placeholder_for_password_login_field": "Zástupný text pro pole hesla v přihlášení",
@ -1452,6 +1474,7 @@
"Rooms": "Místnosti",
"Running_Instances": "Spuštěných instancí",
"S_new_messages_since_s": "%s nových zprávy od %s",
"Same_Style_For_Mentions": "Stejný styl pro zmínky",
"SAML": "SAML",
"SAML_Custom_Cert": "Vlastní Certifikát",
"SAML_Custom_Entry_point": "Vlastní vstupní bod",
@ -1485,6 +1508,7 @@
"Select_an_avatar": "Vyberte avatar",
"Select_file": "Zvolte soubor",
"Select_service_to_login": "Vyberte službu pro přihlášení k načtení obrázků nebo nahrejte obrázek přímo z Vašeho počítače",
"Select_role": "Zvolit roli",
"Select_user": "Vybrat uživatele",
"Select_users": "Vybrat uživatele",
"Selected_agents": "Vybraní operátoři",
@ -1493,7 +1517,7 @@
"Send_a_test_mail_to_my_user": "Odeslat testovací zprávu na můj mail",
"Send_a_test_push_to_my_user": "Odeslat testovací notifikaci na má zařízení",
"Send_confirmation_email": "Zaslat potvrzovací e-mail",
"Send_data_into_RocketChat_in_realtime": "Posílat data do Rocket.Chat v reálném čase.",
"Send_data_into_RocketChat_in_realtime": "Posílejte data do Rocket.Chat v reálném čase.",
"Send_email": "Odelat e-mail",
"Send_invitation_email": "Poslat pozvánku e-mailem",
"Send_invitation_email_error": "Zadejte platnou e-mailovou adresu.",
@ -1708,8 +1732,10 @@
"Type_your_message": "Napište zprávu",
"Type_your_name": "Zadejte své jméno",
"Type_your_new_password": "Zadejte nové heslo",
"UI_Allow_room_names_with_special_chars": "Povolit speciální znaky v názvech místností",
"UI_DisplayRoles": "Zobrazit Role",
"UI_Merge_Channels_Groups": "Sloučit privátní skupiny s místnostmi",
"UI_Unread_Counter_Style": "Styl počítadla nepřečtených zpráv",
"UI_Use_Name_Avatar": "Použít iniciály celého jména uživatele pro výchozí avatar",
"UI_Use_Real_Name": "Použít skutečné jméno",
"Unarchive": "Zrušit archivaci",
@ -1719,6 +1745,7 @@
"Unnamed": "Nepojmenovaný",
"Unpin_Message": "Odepnout Zprávu",
"Unread_Count": "Počet nepřečtených",
"Unread_Count_DM": "Počet nepřečtených přímých zpráv",
"Unread_Tray_Icon_Alert": "Ikona v oznamovací oblasti upozorňuje na nepřečtené zprávy",
"Unread_Messages": "Nepřečtěné zprávy",
"Unread_Rooms": "Nepřečtené místnosti",
@ -1783,6 +1810,8 @@
"User_unmuted_by": "Uživatel <em>__user_by__</em> zrušil ztlumení <em>__user_unmuted__.</em>",
"User_unmuted_in_room": "Uživatel již není ztlumen",
"User_updated_successfully": "Uživatel úspěšně aktualizován",
"User_uploaded_file": "Nahrát soubor",
"User_uploaded_image": "Nahrát obrázek",
"Username": "Uživatelské jméno",
"Username_and_message_must_not_be_empty": "Uživatelské jméno a zpráva nesmí být prázdné.",
"Username_cant_be_empty": "Uživatelské jméno nemůže být prázdné",
@ -1888,4 +1917,4 @@
"your_message_optional": "vaše zpráva (nepovinná)",
"Your_password_is_wrong": "Vaše heslo je špatně!",
"Your_push_was_sent_to_s_devices": "Vaše notifikace byla odeslána do %s zařízení"
}
}

@ -807,10 +807,8 @@
"Off_the_record_conversation_is_not_available_for_your_browser_or_device": "Off-the-record-Gespräche sind für Ihren Browser oder Ihr Gerät nicht verfügbar.",
"Office_hours_enabled": "Bürozeiten aktiviert",
"Offline": "Offline",
"Offline_DM_Email": "Private Nachricht von __user__ erhalten.",
"Offline_form": "Offline-Formular",
"Offline_form_unavailable_message": "Nachricht, dass Offline Formular ungültig",
"Offline_Mention_Email": "Erwähnung durch __user__ in #__room__.",
"Offline_message": "Offline-Nachricht",
"Offline_success_message": "Nachricht, dass Offline Nachricht erfolgreich",
"Offline_unavailable": "offline - nicht verfügbar",
@ -1275,4 +1273,4 @@
"your_message_optional": "ihre optionale Nachricht",
"Your_password_is_wrong": "Falsches Passwort",
"Your_push_was_sent_to_s_devices": "Die Push-Nachricht wurde an %s Geräte gesendet."
}
}

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

Loading…
Cancel
Save