diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index cbb9a7bfe1246cccb971b2f421803afa17e99f09..14e23628e9916b26e23cc5ffd0035fd4856af245 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -1,30 +1,30 @@ FROM node:0.10 +# IMPORTANT - FOR TESTING ONLY - DO NOT USE THIS FOR DEVELOPMENT OR PRODUCTION! MAINTAINER buildmaster@rocket.chat -RUN apt-get update \ -&& apt-get install -y graphicsmagick \ -&& rm -rf /var/lib/apt/lists/* - RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat \ -&& mkdir /app \ -&& mkdir /app/uploads +&& useradd -r -g rocketchat rocketchat + +VOLUME /app/uploads # gpg: key 4FD08014: public key "Rocket.Chat Buildmaster <buildmaster@rocket.chat>" imported RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 +ENV RC_VERSION develop + WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-develop.tgz" -o rocket.chat.tgz \ -&& tar zxvf ./rocket.chat.tgz \ -&& rm ./rocket.chat.tgz \ -&& cd /app/bundle/programs/server \ +RUN curl -fSL "https://rocket.chat/releases/${RC_VERSION}/download" -o rocket.chat.tgz \ +&& curl -fSL "https://rocket.chat/releases/${RC_VERSION}/asc" -o rocket.chat.tgz.asc \ +&& gpg --verify rocket.chat.tgz.asc \ +&& tar zxvf rocket.chat.tgz \ +&& rm rocket.chat.tgz \ +&& cd bundle/programs/server \ && npm install USER rocketchat -VOLUME /app/uploads WORKDIR /app/bundle # needs a mongoinstance - defaults to container linking with alias 'mongo' @@ -34,4 +34,5 @@ ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ Accounts_AvatarStorePath=/app/uploads EXPOSE 3000 + CMD ["node", "main.js"] diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index 6e52e7fdf7f528327350fb75e00cff2827de207b..286962d174d6f4683e8b8e170a8d4e0539539299 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -1,33 +1,30 @@ FROM node:0.10 +# crafted and tuned by pierre@ozoux.net and sing.li@rocket.chat MAINTAINER buildmaster@rocket.chat -RUN apt-get update \ -&& apt-get install -y graphicsmagick \ -&& rm -rf /var/lib/apt/lists/* - RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat \ -&& mkdir /app \ -&& mkdir /app/uploads +&& useradd -r -g rocketchat rocketchat + +VOLUME /app/uploads # gpg: key 4FD08014: public key "Rocket.Chat Buildmaster <buildmaster@rocket.chat>" imported RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 +ENV RC_VERSION latest + WORKDIR /app -RUN URL="https://github.com/RocketChat/Rocket.Chat/releases/latest" \ -&& FILE="/rocket.chat.tgz" \ -&& HEADER=$(curl -I -s "$URL" | grep -Fi Location: | sed -En 's/.*(https?:\/\/[a-zA-Z0-9\/.-_]*).*$/\1/p') \ -&& curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ -&& tar zxvf ./rocket.chat.tgz \ -&& rm ./rocket.chat.tgz \ -&& cd /app/bundle/programs/server \ +RUN curl -fSL "https://rocket.chat/releases/${RC_VERSION}/download" -o rocket.chat.tgz \ +&& curl -fSL "https://rocket.chat/releases/${RC_VERSION}/asc" -o rocket.chat.tgz.asc \ +&& gpg --verify rocket.chat.tgz.asc \ +&& tar zxvf rocket.chat.tgz \ +&& rm rocket.chat.tgz \ +&& cd bundle/programs/server \ && npm install USER rocketchat -VOLUME /app/uploads WORKDIR /app/bundle # needs a mongoinstance - defaults to container linking with alias 'mongo' @@ -37,4 +34,5 @@ ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ Accounts_AvatarStorePath=/app/uploads EXPOSE 3000 + CMD ["node", "main.js"] diff --git a/.docker/dockerfiles/master/Dockerfile b/.docker/dockerfiles/master/Dockerfile deleted file mode 100644 index dd62d8cc71e23f6eb1f74ca660a2f4de1b54e664..0000000000000000000000000000000000000000 --- a/.docker/dockerfiles/master/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -FROM node:0.10 - -MAINTAINER buildmaster@rocket.chat - -RUN apt-get update \ -&& apt-get install -y graphicsmagick \ -&& rm -rf /var/lib/apt/lists/* - -RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat \ -&& mkdir /app \ -&& mkdir /app/uploads - -# gpg: key 4FD08014: public key "Rocket.Chat Buildmaster <buildmaster@rocket.chat>" imported -RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 - -WORKDIR /app - -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-master.tgz" -o rocket.chat.tgz \ -&& tar zxvf ./rocket.chat.tgz \ -&& rm ./rocket.chat.tgz \ -&& cd /app/bundle/programs/server \ -&& npm install - -USER rocketchat - -VOLUME /app/uploads -WORKDIR /app/bundle - -# needs a mongoinstance - defaults to container linking with alias 'mongo' -ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads - -EXPOSE 3000 -CMD ["node", "main.js"] diff --git a/.gitignore b/.gitignore index 2ae4ddd56cc016c35b9152208a8b4a890dcd55d9..fdec437e0c511fe7c8546584cc2139143273c897 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ tramp ecosystem.json pm2.json settings.json +build.sh diff --git a/.lgtm b/.lgtm new file mode 100644 index 0000000000000000000000000000000000000000..3db37707374a90cac9e0b8a309a3ceabbb534278 --- /dev/null +++ b/.lgtm @@ -0,0 +1,2 @@ +approvals = 2 +pattern = "(?i)LGTM" diff --git a/.meteor/packages b/.meteor/packages index b48661e4c0da6bd376d568a9ae6560d78588fca4..d75f1e099a6400eb8ab3697c328363177baba76c 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -34,6 +34,7 @@ session spacebars standard-minifiers tracker +rocketchat:oauth2-server-config arunoda:streams rocketchat:lib @@ -41,6 +42,7 @@ rocketchat:lib rocketchat:authorization rocketchat:autolinker rocketchat:channel-settings +rocketchat:channel-settings-mail-messages rocketchat:colors rocketchat:custom-oauth rocketchat:emojione @@ -50,17 +52,21 @@ rocketchat:github-enterprise rocketchat:gitlab rocketchat:highlight rocketchat:ldap +rocketchat:livechat rocketchat:logger rocketchat:mailer rocketchat:markdown rocketchat:me rocketchat:mentions +rocketchat:mentions-flextab rocketchat:message-pin rocketchat:message-star rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join +rocketchat:slashcommands-kick rocketchat:slashcommands-leave +rocketchat:slashcommands-mute rocketchat:spotify rocketchat:statistics rocketchat:theme @@ -79,7 +85,6 @@ rocketchat:wordpress #rocketchat:chatops #rocketchat:hubot #rocketchat:irc -#rocketchat:livechat konecty:change-case konecty:delayed-task @@ -98,7 +103,6 @@ kadira:blaze-layout kadira:flow-router kenton:accounts-sandstorm kevohagan:sweetalert -meteorhacks:kadira mizzao:autocomplete mizzao:timesync momentjs:moment @@ -107,6 +111,7 @@ mrt:reactive-store mystor:device-detection nimble:restivus nooitaf:colors +ostrio:cookies@2.0.1 pauli:accounts-linkedin perak:codemirror percolate:migrations @@ -127,3 +132,4 @@ yasinuslu:blaze-meta rocketchat:assets rocketchat:integrations rocketchat:message-attachments +rocketchat:api diff --git a/.meteor/versions b/.meteor/versions index 8aed6ee4dd1b8e2619240418cca63e98f1c82635..ff8301b12be4a23023887f392366928e4f2cd500 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,8 +6,7 @@ accounts-meteor-developer@1.0.6 accounts-oauth@1.1.8 accounts-password@1.1.4 accounts-twitter@1.0.6 -alanning:roles@1.2.14 -aldeed:simple-schema@1.5.0 +aldeed:simple-schema@1.5.3 arunoda:streams@0.1.17 autoupdate@1.2.4 babel-compiler@5.8.24_1 @@ -25,7 +24,7 @@ cfs:http-methods@0.0.30 check@1.1.0 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.11 -cosmos:browserify@0.9.2 +cosmos:browserify@0.9.3 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 @@ -39,7 +38,7 @@ ecmascript@0.1.6 ecmascript-runtime@0.2.6 ejson@1.0.7 email@1.0.8 -emojione:emojione@1.5.2 +emojione:emojione@2.0.1 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 @@ -52,7 +51,7 @@ htmljs@1.0.5 http@1.1.1 id-map@1.0.4 idorecall:email-normalize@1.0.0 -jalik:ufs@0.3.3 +jalik:ufs@0.3.5 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 @@ -75,12 +74,10 @@ livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 matb33:collection-hooks@0.8.1 -mdg:validation-error@0.1.0 +mdg:validation-error@0.3.0 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 -meteorhacks:kadira@2.26.3 -meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 minimongo@1.0.10 @@ -88,7 +85,7 @@ mizzao:autocomplete@0.5.1 mizzao:timesync@0.3.4 mobile-experience@1.0.1 mobile-status-bar@1.0.6 -momentjs:moment@2.10.6 +momentjs:moment@2.11.1 monbro:mongodb-mapreduce-aggregation@1.0.1 mongo@1.1.3 mongo-id@1.0.1 @@ -104,10 +101,11 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 +ostrio:cookies@2.0.1 pauli:accounts-linkedin@1.2.0 pauli:linkedin@1.2.0 perak:codemirror@1.2.8 -percolate:migrations@0.9.7 +percolate:migrations@0.9.8 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 @@ -122,10 +120,12 @@ reactive-dict@1.1.3 reactive-var@1.0.6 reload@1.1.4 retry@1.0.4 +rocketchat:api@0.0.1 rocketchat:assets@0.0.1 rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 rocketchat:channel-settings@0.0.1 +rocketchat:channel-settings-mail-messages@0.0.1 rocketchat:colors@0.0.1 rocketchat:cors@0.0.1 rocketchat:custom-oauth@1.0.0 @@ -138,18 +138,24 @@ rocketchat:highlight@0.0.1 rocketchat:integrations@0.0.1 rocketchat:ldap@0.0.1 rocketchat:lib@0.0.1 +rocketchat:livechat@0.0.1 rocketchat:logger@0.0.1 rocketchat:mailer@0.0.1 rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 +rocketchat:mentions-flextab@0.0.1 rocketchat:message-attachments@0.0.1 rocketchat:message-pin@0.0.1 rocketchat:message-star@0.0.1 +rocketchat:oauth2-server@1.4.0 +rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 +rocketchat:slashcommands-kick@0.0.1 rocketchat:slashcommands-leave@0.0.1 +rocketchat:slashcommands-mute@0.0.1 rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 rocketchat:theme@0.0.1 diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 908e6daf7f9d70d8f46b41f82eb12b716a4b9b4e..8efc4b1b3b2fe5711975778cfa49d225e8113f9d 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 5, # Increment this for every release. + appVersion = 10, # Increment this for every release. - appMarketingVersion = (defaultText = "0.9.0"), + appMarketingVersion = (defaultText = "0.14.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/.travis.yml b/.travis.yml index 6d5742f1429bfd65447025ee77e062400aa4d78a..9c514e8bd3eee082a0687e13f489b0060c51a14c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,14 @@ language: node_js branches: only: - develop - - master + - "/^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/" +git: + depth: 1 node_js: - '0.12' cache: directories: - - ~/.meteor + - "~/.meteor" before_install: - npm install -g npm@'>=2.13.5' - mkdir -p node_modules @@ -19,19 +21,25 @@ before_script: script: - meteor build /tmp/build before_deploy: -- mkdir /tmp/deploy -- .travis/namefiles.sh -- .travis/sandstorm.sh +- source ".travis/setartname.sh" +- source ".travis/setdeploydir.sh" +- ".travis/setupsig.sh" +- ".travis/namefiles.sh" +- ".travis/sandstorm.sh" deploy: - - provider: s3 - access_key_id: "AKIAIKIA7H7D47KUHYCA" - secret_access_key: $ACCESSKEY - bucket: "rocketchatbuild" - skip_cleanup: true - local_dir: /tmp/deploy - on: - branch: - - master - - develop + provider: s3 + access_key_id: "AKIAIKIA7H7D47KUHYCA" + secret_access_key: $ACCESSKEY + bucket: "rocketchat" + skip_cleanup: true + upload_dir: build + local_dir: $ROCKET_DEPLOY_DIR + on: + condition: "$TRAVIS_PULL_REQUEST=false" + all_branches: true after_deploy: -- .travis/docker.sh +- ".travis/docker.sh" +- ".travis/update-releases.sh" +env: + global: + secure: HrPOM5sBibYkMcf9aeQThYPCDiXeLkg0Xgv0HvH88/ku/gphDpNEjHNReHZM3cyfm9y3RhHpVdD+Zzy38S2goKyewRzpXJsuyerOYkjND0v3tivhs9CAX8PAUxj1U5zllTyH4bgW2ZwRtNnwnmtIM/JJlnySMpKVDqIZBpbhn3ph9bJ2J+BW3D3Jw8meQ1vCX8szIibyJK/5QX6HG2RBFXJGYoQ8DmR8jQv0aJQvT1Az5DO4yImk8tX4NP95qOc19Jywr1DsbaSBZeJ8lFJAmBpIGx7KAmUVCcxSxfbXGRhs2K4iEYb3rJ/dU6KiyPsKGUG4aYNGgbvcX0ZxX/BZ6ZU9ff0E4IIf43IxoN3ElrOqOFk5msJAXbrJEreINSzDqKOy8NFYtCQ49E2gwzfage4ZXkhFyx3wMPa5bzpr3ncsTceMjMVz03uL781X6NLuCkUmXv+n8K2MNhJU9Xinpdx1GRJm+0lXJspNNJ1ruHeJtls4epj4bmCwKmmZbFKPXqa5e8xVcMIkwt1LMiHduhE+WgKNHdOMhXrCcTxF62ybLlsHXmyLLJeNjTeKS8QG2XSoonClDAz/1R41I1DsMPblcgz9uvYCf7UtyftbhJ83bnJeEmOYQiwijLG0+QMq+B2+mmZan3Z7Hl7O53dnwuLxz7EO7EhQhY+CqHVgc6s= diff --git a/.travis/docker.sh b/.travis/docker.sh index 255601ef0f580d569e9d3ef57d6406b8c3c64d02..66a9189c50c2ecdd671daff24ea74da3dc01fec3 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -4,15 +4,11 @@ IFS=$'\n\t' CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" -if ["$TRAVIS_TAG" ]; then - CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'","docker_tag":"'"$TRAVIS_TAG"'"}'; +if [[ $TRAVIS_TAG ]] + then + CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; else - if [ "$TRAVIS_BRANCH" == "master" ]; then - CURL_DATA='{"source_type":"Branch","source_name":"master","docker_tag":"latest"}'; - else - CURL_DATA='{"source_type":"Branch","source_name":"'"$TRAVIS_BRANCH"'","docker_tag":"'"$TRAVIS_BRANCH"'"}'; - fi + CURL_DATA='{"source_type":"Branch","source_name":"develop"}'; fi curl -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "$CURL_URL" -echo -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "CURL_URL" diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 4848dea2b11da637db450d990744dd1d89ad1db6..6bc9fe1c0aa186d91693b83a8403390278fe4987 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,7 +1,11 @@ #!/bin/bash -set -euo pipefail +set -euvo pipefail IFS=$'\n\t' -#cd $TRAVIS_BUILD_DIR -#export TAG=$(git describe --abbrev=0 --tags) -ln -s /tmp/build/Rocket.Chat.tar.gz "/tmp/deploy/rocket.chat-$TRAVIS_BRANCH.tgz" +# ROCKET_DEPLOY_DIR="/tmp/deploy" +#TRAVIS_TAG=0.1.0 + +FILENAME="$ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.tgz"; + +ln -s /tmp/build/Rocket.Chat.tar.gz "$FILENAME" +gpg --armor --detach-sign "$FILENAME" diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 43250534b7ef70100fd331a32320b8a74d68f9fc..ae9b43854b64cc662f9c63b22212992224606686 100755 --- a/.travis/sandstorm.sh +++ b/.travis/sandstorm.sh @@ -35,4 +35,4 @@ sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp mkdir -p /home/vagrant/bundle/opt/app/.sandstorm/ cp /opt/app/.sandstorm/launcher.sh /home/vagrant/bundle/opt/app/.sandstorm/ sed -i "s/\spgp/#pgp/g" sandstorm-pkgdef.capnp -spk pack /tmp/deploy/rocket.chat-$TRAVIS_BRANCH.spk +spk pack $ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.spk diff --git a/.travis/setartname.sh b/.travis/setartname.sh new file mode 100755 index 0000000000000000000000000000000000000000..5d5839b6a5e0abb95ad3a18ab0660dc59e6b97d4 --- /dev/null +++ b/.travis/setartname.sh @@ -0,0 +1,6 @@ +if [[ $TRAVIS_TAG ]] + then + export ARTIFACT_NAME="$TRAVIS_TAG"; +else + export ARTIFACT_NAME="develop"; +fi diff --git a/.travis/setdeploydir.sh b/.travis/setdeploydir.sh new file mode 100755 index 0000000000000000000000000000000000000000..2c49e4a7027ae32d142e6c13f68d95d18b23ff81 --- /dev/null +++ b/.travis/setdeploydir.sh @@ -0,0 +1,2 @@ +export ROCKET_DEPLOY_DIR="/tmp/deploy" +mkdir -p $ROCKET_DEPLOY_DIR diff --git a/.travis/setupsig.sh b/.travis/setupsig.sh new file mode 100755 index 0000000000000000000000000000000000000000..72bcd8ade0468e8777dbce86c626d460a06bbbba --- /dev/null +++ b/.travis/setupsig.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -euo pipefail + +cp .travis/sign.key.gpg /tmp +gpg --yes --batch --passphrase=$mypass /tmp/sign.key.gpg +gpg --allow-secret-key-import --import /tmp/sign.key +rm /tmp/sign.key diff --git a/.travis/sign.key.gpg b/.travis/sign.key.gpg new file mode 100644 index 0000000000000000000000000000000000000000..488e275998d505474fd6a93c263b4931885d7d00 Binary files /dev/null and b/.travis/sign.key.gpg differ diff --git a/.travis/update-releases.sh b/.travis/update-releases.sh new file mode 100755 index 0000000000000000000000000000000000000000..2bb8f11c564c3d0a398e00d010e988928cd4b436 --- /dev/null +++ b/.travis/update-releases.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail +IFS=$'\n\t' + +CURL_URL="https://rocket.chat/releases/update" + +curl -X POST "$CURL_URL" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d43c1d2cd2cdd8c25bbe3b801c2886ca459c4ff0..0000000000000000000000000000000000000000 --- a/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -FROM node:0.10 - -MAINTAINER buildmaster@rocket.chat - -RUN apt-get update \ -&& apt-get install -y graphicsmagick \ -&& rm -rf /var/lib/apt/lists/* - -RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat \ -&& mkdir /app \ -&& mkdir /app/uploads - -# gpg: key 4FD08014: public key "Rocket.Chat Buildmaster <buildmaster@rocket.chat>" imported -RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 - -WORKDIR /app - -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/develop.rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ -&& tar zxvf ./rocket.chat.tgz \ -&& rm ./rocket.chat.tgz \ -&& cd /app/bundle/programs/server \ -&& npm install - -USER rocketchat - -VOLUME /app/uploads -WORKDIR /app/bundle - -# needs a mongoinstance - defaults to container linking with alias 'mongo' -ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads - -EXPOSE 3000 -CMD ["node", "main.js"] diff --git a/HISTORY.md b/HISTORY.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9264452677d5af0f4c515014d755fd3fcc1c3f30 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -0,0 +1,344 @@ +## NEXT + +- + +## 0.14.0, 2016-Jan-18 + +- Added admin setting to Force SSL +- Added connections status bar to login page +- Added options to enable TLS on LDAP +- Added package dependecy because of RoomModerators collection +- Added Raspberry Pi support announcement +- Added UI to Add/Remove Room Moderators and Owners +- Adds aria-label to button with icons only +- Allow multi-line title on oembed +- Allow SMTP server with no login +- Display burger icon on History page +- Display time based on locale instead of using fixed 24h format +- Do not close Desktop Notifications to keep them in notification center +- Escape dollar before message token replacement +- Fallback LDAP login to local account if LDAP fails +- Fixed audio-recorder not stoping +- Fixed confusing text labels on video/audio call buttons +- Fixed overlapping windows +- Fixed unset moderator test +- Fixed Warning: Site URL configuration for Sandstorm.io +- Fixes a bug with search results, where sometimes cog wasn't displayed. +- Fixes adding/removing owners and moderators +- Fixes Domain whitelist not restricting +- Get the correct language when senging messages via email +- Implement logging out of other logged-in clients +- Improved code execution on open room computation +- Improved processWebhookMessage return +- Improved room moderator subscription and tests +- Improved the layout and info of the oauth popup +- Make oembed parse title in ungreedy form +- Moved collection definition to a better place +- Moved logic to create a message from webhooks to a new file +- Moved response logic outside of processWebhookMessage +- Parse urls with fragments correctly +- Prevent browsers from trying to validate the input field +- Prevent erros update outgoing webhooks with empty channel +- Prevent multiple listeners on message stream per room +- Process outgoing webhook response as a new message +- Remove toUpperCase from emojione popup config +- Send correct content-type for livechat +- Set/Unset moderator via streams +- Sort room files by uploadedAt +- Update oembedVideoWidget removing static height +- Update strings with localized strings in en +- Use 'mim-types' ty check content type and compare to extension +- Using default values instead of integration data +- Using processWebhookMessage on V1 APIs + +## 0.13.0, 2016-Jan-11 + +- Add api `chat.messageExample` +- Add apis 'integrations.create' and 'integrations.remove' +- Add group to tabbar buttons +- Add helper methods to return data as success, failure, etc +- Add method to athenticate api via oauth +- Add more logs on integrations +- Add oauth2-server and oauth2-server-config +- Add option to disable oauth apps, default is enabled +- Add visitor info into tabbar +- Add visitor status colors +- Adding livechat package as default +- Adds a link in the unread bar to jump to first unread message +- Changed icon for visitor information tabbar +- Create package rocketchat:api +- Create routes `channels.setTopic` and `channels.create` +- Create template to show errors from oauth login +- Fix LDAP +- Fix livechat error message position +- Fix min-height on link oembed. +- Fix open links for Android +- Fix problem with middleware that tries to parse json body +- Fix the wrong language display in the view of accountProfile +- Gix pinned tabbar button not showing sometimes +- Highlight messages when jump-to is used Allow selecting user info text +- Implement an interface to manage oauth apps +- Implement api chat.postMessage +- Improved closeFlex logic when switching tabbars +- Insert the zapier default server +- Parse bodyParams.payload as json if it exists +- Permissions rework +- Remove docker dependency on graphicsmagick +- Remove restivus package version +- Removed byte array for debug statements for ufsWrite +- Save visitor's page navigation history +- Set current app language to user's language after user login +- Show the auth and token urls in oauth admin page +- Shows visitor's navigation history +- Update log.coffee +- Use different ids for members info and user info tabbars + +## 0.12.1, 2016-Jan-05 + +- Fix problem with middleware that tries to parse json body + +## 0.12.0, 2016-Jan-04 + +- Add a setting to disable form-based login +- Add request debug messages +- Button to test SMTP settings +- Fix guest users default role +- Fix livechat trigger by url +- Hide registration and forgot password links when hidding login form +- Improved clean button color +- Increase the delay to render color fields +- New password reset screen +- No need to reload server for SMTP settings to take effect +- Settings: unset section if none is given on update +- Support named color for message attachments +- Trim integration messages +- Try to parse all request bodies as JSON +- Upload build artifacts to GitHub and sign tgz for docker images + +## 0.11.0, 2015-Dec-28 + +- Add role bot to users of integrations in scope bot +- Add route to cadastre new integrations via API +- Add "Jump to" and infinite scroll to message search results +- Add infinite scroll to files list +- Add livechat branding +- Add new color variables to the theme editor +- Adjust tgz filename in Dockerfile +- Allow bot call deleteOutgoingIntegration +- Allow creation of outgoing integrations from bots +- Allow searching for logged in user in userAutocomplete +- Always use a department if there is only one active +- Better message positioning +- Change /invite to use addUserToRoom instead joinRoom +- Create direct rooms correctly in incoming hook +- Only join user in public channels via integrations +- Fix ungroup of messages after join message +- Do not load all settings to process.env +- Enable triggers in messages to users +- Enable/disable livechat pre registration form pick a department at livechat pre registration +- Enforce data in body params +- Execute outgoing triggers +- Fix error on roomExit callback +- Fix livechat agent subscription creation +- Fix livechat triggers not triggering +- Fix preview of images in mobile +- Fix triggers with defined channels +- Fix update of permissions +- Get integration name from body +- If no channel in trigger listen all public channels +- Make sample data into array +- Move set of integration type to server side +- Re order settings +- Remove integration if trigger response is 410 +- Remove unecessary logs +- Removed livechat duplicated route definition +- Rename integration api routes, add apis remove, info and sample +- Set user role in integration update too +- Tokenize message on message render to prevent re processing +- Turn channel and triggerWords optional in triggers +- Using branding image from main APP + +## 0.10.2, 2015-Dec-22 + +- Fixes image preview bugs with filenames containing spaces + +## 0.10.1, 2015-Dec-21 + +- Fix upload permissions introduced in raik:ufs 0.3.4 + +## 0.10.0, 2015-Dec-21 + +- Accept property *msg* as text in attachments +- Add "Room has been deleted" entry +- Add /kick command and button for kicking users from room +- Add an not-authorized exception instead of a console.log +- Add an option to show warning in a setting +- Add copy to clipboard button on installation +- Add examples of curl and json in integrations +- Add field to display the integration token +- Add hover background color for messages +- Add msg property as an alternative for text +- Add option to disable setting based in other setting and another impr… +- Add setting to turn on/off debug messages from methods and publishes +- Add some docs about Settings API +- Adding setting for protected uploads; updating jail:us to 0.3.3 +- Adjust layout direction based on user's language +- Allow cascade methods in settings creation +- Allow emoji as avatar for webhooks/integrations +- Allow OEmbed to bypass file protection +- Allow pass an array of roles to user in Acctouns.createUser +- Allow to set messages as ungroupable +- Appearance settings +- Attachments: Concerning the mobile settings to save badwidth and fix … +- Bump version to 0.10.0 +- Centralize message better +- Centralize messages +- Change order of loading variables +- Change the rate limit of method setAvatarFromService from 1m to 5s +- Changes to layout and add infinite scroll to mentions bar +- Check if file is empty before upload +- Closes #1691; Fiz a grouping error in messages from history +- Code cleanup +- Configure LGTM approvals +- Create method in settings to update options of one setting +- Detect file dimensions in uploads and set height of image in attachments +- Detect if system is runing GM or IM, add info to RocketChat.Info and … +- Disable ldap settings when ldap is disabled +- Explain the available docker images +- Fix a PT translation +- Fix avatar position on compact view +- Fix checking if message is command +- Fix crash when connection reset from LDAP server +- Fix deleting a message not deleting it's attachments +- Fix error "Cannot read property 'replace' of undefined" +- Fix guest permissions +- Fix language loading from cordova +- Fix merge mess =P +- Fix mute by setting mute on room instead of subscription +- Fix pin and star +- Fix some ldap problems and set reconnect to true +- Fix sort of settings +- Fix URL +- Fixed pin and star +- Fixed several english issues. +- Get next agent on queue +- Group message by time, default 5min +- Improve avatar resize function to use GM detection and allow change s… +- Improve error when closing window +- Improved triggers settings +- Initial trigger support +- Livechat appearance preview +- Livechat hooks +- Livechat manager fix and improvements +- Livechat sidenav active item +- Livechat widget preview +- LoadSurroundingMessages +- Mentions sidenav; +- Missing language entries +- More improvements in message grouping +- Mover rocketchat.info into rocketchat:lib +- Mute/Unmute commands and button +- New icon for unpin +- New MAINTERRS +- Pass role to user created via SAML integration +- Protecting uploaded files +- Removed all console.logs from publishes and methods +- Removed ES code +- Removed kadira package +- Removed logs +- Removed unused code +- Render a player for audio files +- Return the correct error for unauthorized upload access +- Revert "Allow OEmbed to bypass file protection" +- Saving livechat trigger config +- Set avatar resize enabled by default +- Setting only one, either emoji or avatar, but never both +- Show warning and allow admins to fix the Site URL +- Support calls from client / browsers +- Ui fix for livechat survey +- Undo wrongly commited file +- Unsubscribe e-mails from CSV +- Update aldeed:simple-schema to 1.5.1 +- Update Ansible link to beginners friendly deployment guide +- Update jalik:ufs to 0.3.4 +- Updated aldeed:simple-schema to 1.5.0 +- Updated muted usernames on setUsername +- Use attachments to render preview of uploads and use relative paths +- Using flow-router group routes + +## 0.9.0, 2015-Dec-14 + +- Fix broken image-link when og:image contains "&" (e.g. Google Maps) +- Error message when file upload media type it not accepted +- Add setting Accounts_LoginExpiration +- Fix 'create new' in private group list opening 'create channel' flex +- Moved RocketMailer to Mailer +- Move avatars on username change +- Livechat Survey +- Livechat popout support +- New integrations panel on the admin +- Many fixes on rtl.less +- Avatars for Unicode usernames +- Fix for mentioning RTL names +- Force file names to always be in LTR +- Add query operator for mailer +- Departments support +- Fixes issue #1619 persistent custom oauth. +- Add a new setting type "action" to call server methods +- Add lib clipboard.js +- Add new page container type, settings +- Add new role, manage-integrations +- Add settings/action to allow admins restart the server +- Allow arrays of keys in RocketChat.settings.onload +- Allow avatar and alias customization +- Allow packages to register files for theming +- Allow use Markdown to render a single stringn and register a helper +- Change layout of attachments +- Create a setting/action to test push notifications +- Create a user rocket.cat and set avatar on system initialization +- Do not alert admins about wrong url if accessing from cordova +- Encode url and token +- Implement package for message attachments +- Inform user to refresh page after extension install +- Pass success message to settings/actions +- Prepare code to reconfigure push plugin in runtime +- Prevent parse message urls if option parseUrls is false in message +- Prompt users to install extentions to enable screen sharing +- Shos if message is from bot and never render compact message version +- Fixed blockquote non-continous border +- Moved accountBox HTML to new separated template + +## 0.8.0, 2015-Dec-8 + +- Fixed error: when allow change username was set to false, registration +- Improve message rendering removing MessageAction from render time +- Textarea theme fix for RTL +- Update the flex-nav hidden element for RTL +- Refresh the count of unread messages on scroll +- Reset correctly all counters of unread marks +- Force deletion and stop computations of templates when closing room +- Close rooms when more than 10 is open instead of closing rooms +- Reset avatar before uploading to prevent caching +- Create page to manage assets and change favicons +- Add option to disable "Forgot Password" link on login page +- New RocketChat.RateLimiter +- Favico.js update +- Better RTL support +- Remove custom oAuth record when removed from settings +- Improve Settings layout +- Collapse sub groups of settings +- Change translations in PT for False and True +- Add Secret URL +- Fix push notification for android +- Enable push bay default and improve settings organization +- Alert admin if configured url is different from current +- Translate section of settings +- Add "Meiryo UI" to font-family +- Fix livechat visitor can't chat after refresh +- Fix can't send msgs to new livechat rooms +- Clear iOS app badge on app startup +- Fix for image swipebox to show in RTL interface + +## 0.1.0, 2015-May-19 + +- Initial public launch diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000000000000000000000000000000000000..2f212b17aa1f9586530393a8a1f558dc033650fa --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,10 @@ +engelgabriel +geekgonecrazy +gmsecrieru +graywolf336 +marceloschmidt +rcaferati +rodrigok +rwakida +sampaiodiego +Sing-Li diff --git a/README.md b/README.md index 6f5ff72f957de43f5325fa4b2b234a0c12b95efb..731063addc34b7434251d6a4db64bf025ab24c44 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ The Ultimate Open Source WebChat Platform * [Desktop apps](#desktop-apps) * [Deployment](#deployment) * [Heroku](#heroku) + * [Scalingo](#scalingo) * [Sandstorm.io](#sandstormio) * [Sloppy.io](#sloppyio) * [Docker](#docker) * [FreeBSD](#freebsd) * [Ansible](#ansible) + * [Raspberry Pi 2](#raspberry-pi-2) * [Ubuntu VPS](#ubuntu-vps) * [Ubuntu Software Center](#ubuntu-software-center) * [About Rocket.Chat](#about-rocketchat) @@ -23,7 +25,7 @@ The Ultimate Open Source WebChat Platform * [Documentation](#documentation) * [License](#license) * [Development](#development) - * [Installation](#installation) + * [Quick Start](#quick-start-for-code-developers) * [Branching Model](#branching-model) * [Translations](#translations) * [Community](#community) @@ -60,18 +62,17 @@ Now compatible with all Android devices as old as version 4.0.x - [download here ## Heroku Host your own Rocket.Chat server for **FREE** with [One-Click Deploy](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/master) -Branch **master** (Latest stable version): - -[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/master) +[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) -Branch **develop** (Newer but unstable): +## Scalingo +Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com) -[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) +[](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#develop) ## Sandstorm.io [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) -_*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat-develop.spk) for testing on your own server. +_*Grab*_ the [Sandstorm SPK for the latest Rocket.Chat release](https://rocket.chat/releases/latest/spk) for testing on your own server. ## Sloppy.io Host your docker container at [sloppy.io](http://sloppy.io). Get an account and use the [quickstarter](https://github.com/sloppyio/quickstarters/tree/master/rocketchat) @@ -81,12 +82,23 @@ Host your docker container at [sloppy.io](http://sloppy.io). Get an account and or -Use the automated build at our [Official Docker Registry](https://hub.docker.com/r/rocketchat/rocket.chat/) +Use the automated build image of our [most recent release](https://hub.docker.com/r/rocketchat/rocket.chat/) [](https://hub.docker.com/r/rocketchat/rocket.chat/) ``` -docker pull rocketchat/rocket.chat +docker pull rocketchat/rocket.chat:latest +``` + +OR select a specific release ([details of releases available](https://github.com/RocketChat/Rocket.Chat/releases)): +``` +docker pull rocketchat/rocket.chat:vX.X.X +``` + +OR our [official docker registry image](https://hub.docker.com/_/rocket.chat/), containing recent stable release build approved by Docker: + +``` +docker pull rocket.chat ``` ## FreeBSD @@ -97,7 +109,12 @@ Run solid five-nines deployment on industry workhorse FreeBSD server: ## Ansible Automated production-grade deployment in minutes, for RHEL / CentOS 7 or Ubuntu 14.04 LTS / 15.04: -[](https://galaxy.ansible.com/detail#/role/6478) +[](https://github.com/RocketChat/Rocket.Chat/wiki/Easy,-hands-off-deployment-with-Ansible) + +## Raspberry Pi 2 +Run Rocket.Chat on this world famous $30 quad core server: + +[](https://github.com/RocketChat/Rocket.Chat.RaspberryPi) ## Ubuntu VPS Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) @@ -241,7 +258,7 @@ Note that Rocket.Chat is distributed under the [MIT License](http://opensource.o # Development -## Installation +## Quick start for code developers Prerequisites: * [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) @@ -255,13 +272,7 @@ cd Rocket.Chat meteor ``` -or use docker: - -``` -git clone https://github.com/RocketChat/Rocket.Chat.git -cd Rocket.Chat -docker run -it -p 3000:3000 -v "$(pwd)":/app danieldent/meteor -``` +If you are not a developer and just want to run the server - see [deployment methods](https://github.com/RocketChat/Rocket.Chat/wiki#deployment). ## Branching Model diff --git a/client/helpers/log.coffee b/client/helpers/log.coffee index f00b503c8d363db42c15cc969e5c9efe4eca41ed..bc6666749306cd453967c769bdcc405499b14105 100644 --- a/client/helpers/log.coffee +++ b/client/helpers/log.coffee @@ -1,2 +1,2 @@ -Blaze.registerHelper 'log', -> - console.log.apply console, arguments \ No newline at end of file +Template.registerHelper 'log', -> + console.log.apply console, arguments diff --git a/client/methods/pinMessage.coffee b/client/methods/pinMessage.coffee deleted file mode 100644 index a46e6bdde718526144240141037d1b4c65306330..0000000000000000000000000000000000000000 --- a/client/methods/pinMessage.coffee +++ /dev/null @@ -1,21 +0,0 @@ -Meteor.methods - pinMessage: (message) -> - if not Meteor.userId() - throw new Meteor.Error 203, t('User_logged_out') - - if not RocketChat.settings.get 'Message_AllowPinning' - throw new Meteor.Error 'message-pinning-not-allowed', t('Message_pinning_not_allowed') - - Tracker.nonreactive -> - - message.pts = new Date(Date.now() + TimeSync.serverOffset()) - message.pinned = true - message = RocketChat.callbacks.run 'beforeSaveMessage', message - - ChatMessage.update - _id: message.id - 'u._id': Meteor.userId() - , - $set: - pinned: message.pinned - pts: message.pts diff --git a/client/methods/saveRoomName.coffee b/client/methods/saveRoomName.coffee deleted file mode 100644 index 0885fe433cebcb704f96b0316ba538333f559dc3..0000000000000000000000000000000000000000 --- a/client/methods/saveRoomName.coffee +++ /dev/null @@ -1,27 +0,0 @@ -Meteor.methods - saveRoomName: (rid, name) -> - if not Meteor.userId() - throw new Meteor.Error 203, t('User_logged_out') - - room = ChatRoom.findOne rid - - if room.u._id isnt Meteor.userId() or room.t not in ['c', 'p'] - throw new Meteor.Error 403, t('Not allowed') - - if RocketChat.settings.get 'UTF8_Names_Slugify' - name = _.slugify name - - if name is room.name - return - - ChatRoom.update rid, - $set: - name: name - - ChatSubscription.update - rid: rid - , - $set: - name: name - - return name diff --git a/client/methods/unpinMessage.coffee b/client/methods/unpinMessage.coffee deleted file mode 100644 index a60e28960e3b6f36793a57b9fe1213295c469888..0000000000000000000000000000000000000000 --- a/client/methods/unpinMessage.coffee +++ /dev/null @@ -1,21 +0,0 @@ -Meteor.methods - unpinMessage: (message) -> - if not Meteor.userId() - throw new Meteor.Error 203, t('User_logged_out') - - if not RocketChat.settings.get 'Message_AllowPinning' - throw new Meteor.Error 'message-pinning-not-allowed', t('Message_pinning_not_allowed') - - Tracker.nonreactive -> - - message.pts = new Date(Date.now() + TimeSync.serverOffset()) - message.pinned = false - message = RocketChat.callbacks.run 'beforeSaveMessage', message - - ChatMessage.update - _id: message.id - 'u._id': Meteor.userId() - , - $set: - pinned: message.pinned - pts: message.pts diff --git a/client/routes/adminRouter.coffee b/client/routes/adminRouter.coffee index ee8a4ed0e1e21f8a21bded8deff5534ded57d675..c226715e635bbfa28d5ed925973e749f31a506b1 100644 --- a/client/routes/adminRouter.coffee +++ b/client/routes/adminRouter.coffee @@ -1,33 +1,27 @@ -tabReset = -> - RocketChat.TabBar.reset() - FlowRouter.route '/admin/users', name: 'admin-users' - triggersEnter: [tabReset] - triggersExit: [tabReset] + triggersExit: [ -> + Session.set 'adminSelectedUser' + ] action: -> + Session.set 'adminSelectedUser' + RocketChat.TabBar.showGroup 'adminusers' BlazeLayout.render 'main', {center: 'adminUsers'} - FlowRouter.route '/admin/rooms', name: 'admin-rooms' - triggersEnter: [tabReset] - triggersExit: [tabReset] action: -> + RocketChat.TabBar.showGroup 'adminrooms' BlazeLayout.render 'main', {center: 'adminRooms'} - FlowRouter.route '/admin/statistics', name: 'admin-statistics' - triggersEnter: [tabReset] - triggersExit: [tabReset] action: -> + RocketChat.TabBar.showGroup 'adminstatistics' BlazeLayout.render 'main', {center: 'adminStatistics'} - FlowRouter.route '/admin/:group?', name: 'admin' - triggersEnter: [tabReset] - triggersExit: [tabReset] action: -> + RocketChat.TabBar.showGroup 'admin' BlazeLayout.render 'main', {center: 'admin'} diff --git a/client/routes/router.coffee b/client/routes/router.coffee index 74873c70a05da43cee2975de3037d0c17c6c917c..9757366bfa568cead9c054fbb511b8dae0a073c1 100644 --- a/client/routes/router.coffee +++ b/client/routes/router.coffee @@ -3,7 +3,6 @@ Blaze.registerHelper 'pathFor', (path, kw) -> BlazeLayout.setRoot 'body' - FlowRouter.subscriptions = -> Tracker.autorun => RoomManager.init() @@ -42,7 +41,7 @@ FlowRouter.route '/home', name: 'home' action: -> - RocketChat.TabBar.reset() + RocketChat.TabBar.showGroup 'home' BlazeLayout.render 'main', {center: 'home'} KonchatNotification.getDesktopPermission() @@ -51,18 +50,17 @@ FlowRouter.route '/changeavatar', name: 'changeAvatar' action: -> + RocketChat.TabBar.showGroup 'changeavatar' BlazeLayout.render 'main', {center: 'avatarPrompt'} FlowRouter.route '/account/:group?', name: 'account' action: (params) -> - RocketChat.TabBar.closeFlex() - RocketChat.TabBar.resetButtons() - unless params.group params.group = 'Preferences' params.group = _.capitalize params.group, true + RocketChat.TabBar.showGroup 'account' BlazeLayout.render 'main', { center: "account#{params.group}" } @@ -74,6 +72,7 @@ FlowRouter.route '/history/private', action: -> Session.setDefault('historyFilter', '') + RocketChat.TabBar.showGroup 'private-history' BlazeLayout.render 'main', {center: 'privateHistory'} diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 832cbd2f21cef3b3e95290b6ebd417426f404411..ee2f83261e49ac3d6bcdb1b6298f895b739b8ebb 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -11,9 +11,11 @@ RocketChat.roomTypes.add 'c', 10, action: (params, queryParams) -> Session.set 'showUserInfo' openRoom 'c', params.name + RocketChat.TabBar.showGroup 'channel' link: (sub) -> return { name: sub.name } - permissions: [ 'view-c-room' ] + condition: -> + return RocketChat.authz.hasAllPermission 'view-c-room' RocketChat.roomTypes.add 'd', 20, template: 'directMessages' @@ -24,9 +26,11 @@ RocketChat.roomTypes.add 'd', 20, action: (params, queryParams) -> Session.set 'showUserInfo', params.username openRoom 'd', params.username + RocketChat.TabBar.showGroup 'directmessage' link: (sub) -> return { username: sub.name } - permissions: [ 'view-d-room' ] + condition: -> + return RocketChat.authz.hasAllPermission 'view-d-room' RocketChat.roomTypes.add 'p', 30, template: 'privateGroups' @@ -37,6 +41,8 @@ RocketChat.roomTypes.add 'p', 30, action: (params, queryParams) -> Session.set 'showUserInfo' openRoom 'p', params.name + RocketChat.TabBar.showGroup 'privategroup' link: (sub) -> return { name: sub.name } - permissions: [ 'view-p-room' ] + condition: -> + return RocketChat.authz.hasAllPermission 'view-p-room' diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee index c42fb6200e01edf4347b8e774e9a7eacf2932447..ed209ee71b3bc758fac84fb479c923fe394c2a1e 100644 --- a/client/startup/startup.coffee +++ b/client/startup/startup.coffee @@ -10,7 +10,7 @@ Meteor.startup -> window.lastMessageWindow = {} window.lastMessageWindowHistory = {} - @defaultUserLanguage = -> + @defaultAppLanguage = -> lng = window.navigator.userLanguage || window.navigator.language || 'en' # Fix browsers having all-lowercase language settings eg. pt-br, en-us re = /([a-z]{2}-)([a-z]{2})/ @@ -18,14 +18,25 @@ Meteor.startup -> lng = lng.replace re, (match, parts...) -> return parts[0] + parts[1].toUpperCase() return lng + @defaultUserLanguage = -> + return RocketChat.settings.get('Language') || defaultAppLanguage() + loadedLaguages = [] - setLanguage = (language) -> + @setLanguage = (language) -> + if !language + return + if loadedLaguages.indexOf(language) > -1 return loadedLaguages.push language + if isRtl language + $('html').addClass "rtl" + else + $('html').removeClass "rtl" + language = language.split('-').shift() TAPi18n.setLanguage(language) @@ -35,14 +46,12 @@ Meteor.startup -> Function(localeFn)() moment.locale(language) - Tracker.autorun (c) -> - if Meteor.user()?.language? - c.stop() - - localStorage.setItem("userLanguage", Meteor.user().language) - setLanguage Meteor.user().language + Meteor.subscribe("userData", () -> + userLanguage = Meteor.user()?.language + userLanguage ?= defaultUserLanguage() - userLanguage = localStorage.getItem("userLanguage") - userLanguage ?= defaultUserLanguage() + if localStorage.getItem('userLanguage') isnt userLanguage + localStorage.setItem('userLanguage', userLanguage) - setLanguage userLanguage + setLanguage userLanguage + ) diff --git a/docker-compose.yml b/docker-compose.yml index 7fc1a9f81e0551979bb7691724b523b74f1a9049..2637c3c86a24cae08c2ba61cee9b63c0a86d2d5b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,15 +6,13 @@ mongo: command: mongod --smallfiles --oplogSize 128 rocketchat: - image: rocketchat/rocket.chat:develop + image: rocketchat/rocket.chat:latest # volumes: # - ./uploads:/app/uploads environment: - PORT=3000 - ROOT_URL=http://yourhost:3000 - MONGO_URL=mongodb://mongo:27017/rocketchat -# uncomment and set the line below if you need to support mobile apps -# - DDP_DEFAULT_CONNECTION_URL=http://yourhost:3000 links: - mongo:mongo ports: @@ -24,7 +22,7 @@ rocketchat: hubot: image: rocketchat/hubot-rocketchat environment: - - ROCKETCHAT_URL=yourhost:3000 + - ROCKETCHAT_URL=rocketchat:3000 - ROCKETCHAT_ROOM=GENERAL - ROCKETCHAT_USER=bot - ROCKETCHAT_PASSWORD=botpassword @@ -35,4 +33,4 @@ hubot: - rocketchat:rocketchat # this is used to expose the hubot port for notifications on the host on port 3001, e.g. for hubot-jenkins-notifier ports: - - 3001:8080 \ No newline at end of file + - 3001:8080 diff --git a/build.sh b/example-build.sh similarity index 85% rename from build.sh rename to example-build.sh index f60192ddad78c55bf611f69661a02061976dde35..579353a01a320a213e1ab3fa5babf412cd6e1081 100755 --- a/build.sh +++ b/example-build.sh @@ -1,6 +1,6 @@ #!/bin/bash export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat rocketchat:hubot +meteor add rocketchat:hubot meteorhacks:kadira meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat cd /var/www/rocket.chat/bundle/programs/server npm install diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index d2e04cbfc219366a5fe3caa7fe7568922e058a74..bc196b60c391b347e6f08a25cdd6dd186d32244f 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -3,16 +3,36 @@ "Access_Online_Demo" : "الدخول إلى العرض التجريبي", "Accounts" : "الØسابات", "Accounts_AllowPasswordChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± كلمة السر", + "Accounts_AllowUsernameChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± اسم المستخدم", "Accounts_AllowUserProfileChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ¹Ø¯ÙŠÙ„ المل٠الشخصي للعضو", + "Accounts_AvatarResize" : "تغيير Øجم الصور الرمزية", + "Accounts_AvatarSize" : "Øجم الصورة الرمزية", + "Accounts_AvatarStorePath" : "مسار تخزين الصورة الرمزية", + "Accounts_AvatarStoreType" : "نوع تخزين الصورة الرمزية", + "Accounts_EmailVerification" : "التØقق من البريد الإلكتروني", + "Accounts_ManuallyApproveNewUsers" : "المواÙقة على المستخدمين الجدد يدويا", + "Accounts_OAuth_Custom_Enable" : "تمكين", + "Accounts_OAuth_Custom_URL" : "الرابط", "Accounts_PasswordReset" : "إعادة تعيين كلمة السر", + "Accounts_RegistrationForm" : "استمارة التسجيل", + "Accounts_RegistrationForm_Disabled" : "معطل", + "Accounts_RegistrationForm_Public" : "عام", + "Accounts_RegistrationForm_Secret_URL" : "رابط سري", + "Accounts_RegistrationForm_SecretURL" : "رابط استمارة التسجيل السري", + "Accounts_RegistrationRequired" : "التسجيل مطلوب", + "Activate" : "تÙعيل", "Add_Members" : "إضاÙØ© الأعضاء", "Add_users" : "إضاÙØ© مستخدمين", "Administration" : "الإدارة", "All_channels" : "جميع القنوات", "and" : "Ùˆ", + "API_Analytics" : "التØليلات", + "Archive" : "الأرشيÙ", "are_also_typing" : "هم أيضا يكتبون", "are_typing" : "يكتبون", "Are_you_sure" : "هل أنت متأكد؟", + "Auto_Load_Images" : "تØميل تلقائي للصور", + "Avatar_changed_successfully" : "تم تغيير الصورة الرمزية بنجاØ", "away" : "بعيد", "Away" : "بعيد", "away_female" : "بعيدة", @@ -32,34 +52,60 @@ "Channels" : "القنوات", "Channels_list" : "قائمة القنوات العامة", "Chat_Rooms" : "غر٠المØادثة", - "close" : "أغلق", + "Clear_all_unreads_question" : "Ù…Ø³Ø ÙƒØ§ÙØ© الغير مقروءة؟", + "close" : "غلق", "coming_soon" : "قريبا", + "Commands" : "الأوامر", + "Compact_View" : "عرض متراص", "Confirm_password" : "تأكيد كلمة السر", "Conversation" : "Ù…Øادثة", + "Convert_Ascii_Emojis" : "Øول Ù…Øار٠الأسكي إلى اموجي", + "COPY_TO_CLIPBOARD" : "نسخ", "Create_new" : "إنشاء جديد", + "Create_new_direct_message_room" : "إنشاء غرÙØ© رسالة مباشرة جديدة", "Create_new_private_group" : "إنشاء مجموعة خاصة جديدة", "Create_new_public_channel" : "إنشاء قناة عامة جديدة", "Created_at" : "أنشئت ÙÙŠ", + "days" : "أيام", + "Deactivate" : "تعطيل", + "Delete_Room_Warning" : "Øذ٠الغرÙØ©ØŒ ÙŠØذ٠جميع الرسائل المرسلة داخل الغرÙØ©.ØŒ هذا لا يمكن التراجع عنه.", + "Deleted" : "تم الØØ°Ù!", "Desktop_Notifications" : "تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨", "Desktop_Notifications_Disabled" : "تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ معطلة. قم بتغيير إعدادات المتصÙØ Ø¥Ø°Ø§ أردت تÙعيلها.", "Desktop_Notifications_Enabled" : "تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ Ù…Ùعلة", "Direct_Messages" : "الرسائل المباشرة", "Disable_Favorite_Rooms" : "تعطيل المÙضلة", "Disable_New_Message_Notification" : "تعطيل التنبيه عن رسالة جديدة", - "Disable_New_Room_Notification" : "تعطيل التنبيه عن غرÙØ© جديدة", - "edited" : "عدلت", + "Disable_New_Room_Notification" : "تعطيل التنبيهات الجديدة ÙÙŠ الغرÙØ©", + "Drop_to_upload_file" : "إسقاط لتØميل الملÙ", + "E-mail" : "البريد اﻹلكتروني", + "edited" : "تم العديل", + "Email_already_exists" : "البريد الالكتروني موجود مسبقا", "Email_or_username" : "البريد الإلكتروني أو اسم المستخدم", "Email_verified" : "تم التØقق من البريد الإلكتروني", + "Emoji" : "رمز تعبيري (اموجي)", "Enable_Desktop_Notifications" : "تÙعيل تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨", "Enter_info" : "ادخل المعلومات الخاصة بك", + "Enter_to" : "ادخل الى", + "Error" : "خطأ", "Error_changing_password" : "خطأ ÙÙŠ تغيير كلمة السر", - "False" : "لا", + "Error_too_many_requests" : "خطأ، الكثير من الطلبات. من Ùضلك أبطء السرعة. عليك الانتظار٪ s ثانية قبل المØاولة مرة أخرى", + "False" : "خاطئة", "Favorites" : "المÙضلة", + "FileUpload" : "تØميل الملÙ", + "FileUpload_Enabled" : "تØميل الملÙات Ù…Ùعلة", + "FileUpload_MaxFileSize" : "الØد الأقصى لتØميل المل٠الØجم (بايت)", + "FileUpload_MediaTypeWhiteList" : "أنواع الوسائط المقبولة", + "FileUpload_ProtectFiles" : "Øماية الملÙات المØملة", "Forgot_password" : "نسيت كلمة السر", + "From_Email" : "من البريد الإلكتروني", + "General" : "العامة", "Get_to_know_the_team" : "تعر٠على Rocket.Team", "github_no_public_email" : "ليس لديك أي بريد الإلكتروني عام ÙÙŠ Øسابك على Github", + "Has_more" : "يوجد المزيد", "Hide_room" : "إخÙاء الغرÙØ©", "History" : "تاريخ", + "hours" : "ساعة", "Incorrect_Password" : "كلمة السر غير صØÙŠØØ©", "inline_code" : "نص_برمجي", "Invalid_confirm_pass" : "تأكيد كلمة السر لا تطابق كلمة السر", @@ -68,34 +114,73 @@ "Invalid_pass" : "لا يجب أن تكون كلمة السر Ùارغة", "invisible" : "Ø®ÙÙŠ", "Invisible" : "Ø®ÙÙŠ", + "Invitation_Subject" : "موضوع الدعوة", "Invite_Users" : "دعوة المستخدمين", "is_also_typing" : "هو أيضا يكتب", + "is_also_typing_female" : "هي أيضا تكتب", + "is_also_typing_male" : "هو أيضا يكتب", "is_typing" : "يكتب", + "is_typing_female" : "تكتب", + "is_typing_male" : "يكتب", "italics" : "مائل", "join" : "انضم", "Join_the_Community" : "إنظم للمجتمع", - "Language" : "لغة", + "Jump_to_message" : "القÙز إلى الرسالة", + "Jump_to_recent_messages" : "اذهب إلى الرسائل الأخيرة", + "Language" : "اللغة", "Language_Version" : "النسخة الإنجليزية", + "Last_login" : "آخر تسجيل دخول", "Last_message" : "آخر رسالة", + "Layout" : "التصميم", + "Layout_Home_Title" : "عنوان الصÙØØ© الرئيسية", + "Layout_Login_Terms" : "شروط الدخول", + "Layout_Privacy_Policy" : "سياسة الخصوصية", + "Layout_Terms_of_Service" : "شروط الخدمة", "Leave_room" : "مغادرة الغرÙØ©", "line" : "خط", "Load_more" : "اعرض أكثر", + "Loading..." : "تØميل ...", + "Loading_more_from_history" : "تØميل المزيد من التاريخ", "Loading_suggestion" : "تØميل الاقتراØات ...", "Login" : "تسجيل الدخول", "Login_with" : "تسجيل الدخول بـ %s", - "login_with" : "أو الدخول مباشرة مع", + "login_with" : "أو الدخول مباشرة بـ", "Logout" : "تسجيل خروج", + "Logout_Others" : "تسجيل الخروج من الأجهزة الأخرى", + "Make_Admin" : "جعل مدير", + "Mark_as_read" : "تعليم كمقروء", "Members" : "الأعضاء", "Members_List" : "قائمة الأعضاء", "Members_placeholder" : "الأعضاء", - "Message_removed" : "مسØت الرسالة", - "Messages" : "رسائل", + "Message" : "رسالة", + "Message_AllowDeleting" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨Øذ٠الرسائل", + "Message_AllowEditing" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ¹Ø¯ÙŠÙ„ الرسائل", + "Message_AllowEditing_BlockEditInMinutesDescription" : "أدخل 0 لتعطيل الØظر.", + "Message_deleting_not_allowed" : "Øذ٠الرسائل غير مسموØ", + "Message_editing_blocked" : "لا يمكن تعديل هذه الرسالة بعد الآن", + "Message_editing_not_allowed" : "تعديل الرسائل غير مسموØ", + "Message_KeepHistory" : "إبقاء Ù…ØÙوظات الرسائل", + "Message_pinned" : "تم تثبيث الرسالة", + "Message_pinning_not_allowed" : "تثبيث الرسائل غير مسموØ", + "Message_removed" : "تم Øذ٠الرسالة", + "Message_ShowDeletedStatus" : "عرض Øالة التعديل", + "Message_ShowEditedStatus" : "عرض Øالة الØØ°Ù", + "Message_ShowFormattingTips" : "اظهار Ù†ØµØ§Ø¦Ø Ø§Ù„ØªÙ†Ø³ÙŠÙ‚", + "Messages" : "الرسائل", + "Meta_fb_app_id" : "معر٠تطبيق الÙيسبوك", + "Meta_language" : "اللغة", + "Meta_robots" : "الروبوتات", + "minutes" : "دقيقة", "More_channels" : "المزيد من القنوات", + "More_groups" : "المزيد من المجموعات الخاصة", + "More_unreads" : "المزيد غير مقروءة", "Msgs" : "رسائل", "multi" : "متعدد", + "Mute_user" : "اسكات المستخدم", "My_Account" : "Øسابي", "n_messages" : "%s رسائل", - "Name" : "اسم", + "Name" : "الإسم", + "Name_cant_be_empty" : "اﻹسم لا يمكن أن يكون Ùارغا", "New_messages" : "رسائل جديدة", "New_password" : "كلمة سر جديدة", "No_channels_yet" : "لست جزء من أي قناة Øتى الآن.", @@ -103,58 +188,123 @@ "No_favorites_yet" : "لم تقم بإضاÙØ© Ù…Ùضلات بعد.", "No_groups_yet" : "لا يوجد لديك مجموعات خاصة Øتى الآن.", "No_permission_to_view_room" : "ليس لديك صلاØية لرؤية هذه الغرÙØ©", + "No_results_found" : "لا توجد نتائج", "Not_allowed" : "غير مسموØ", + "Not_authorized" : "غير مصرØ", "Not_found_or_not_allowed" : "غير موجود أو غير مسموØ", "Nothing_found" : "لا يوجد شيء", + "Notify_all_in_this_room" : "إخطار جميع من ÙÙŠ هذه الغرÙØ©", "Old_and_new_password_required" : "تØتاج إلى كتابة كلمة السر القديمة والجديدة لتغيير كلمة السر الخاصة بك.", "Old_Password" : "كلمة السر القديمة", "Online" : "متواجد", - "Oops!" : "عÙوا", + "Only_you_can_see_this_message" : "يمكنك أنت Ùقط رؤية هذه الرسالة", + "Oops!" : "عذرا", + "Opt_out_statistics" : "لا ترسل Ø¥Øصاءات الموقع Ù„Rocket.Chat", + "optional" : "اختياري", + "others" : "آخرون", "Password" : "كلمة السر", + "Password_Change_Disabled" : "مدير الموقع منع تغيير كلمة السر", "Password_changed_successfully" : "تم تغيير كلمة السر بنجاØ", + "People" : "الناس", + "Please_enter_your_new_password_below" : "الرجاء إدخال كلمة المرور الجديدة أدناه:", "Please_wait" : "يرجى الانتظار", + "Please_wait_activation" : "يرجى الانتظار، قد يستغرق بعض الوقت.", "Please_wait_statistics" : "يرجى الانتظار إلى أن يتم Øساب الإØصائيات", - "Preferences" : "الإعدادات", - "Preferences_saved" : "تم ØÙظ الإعدادات", - "Privacy" : "خصوصية", + "Preferences" : "التÙضيلات", + "Preferences_saved" : "تم ØÙظ التÙضيلات", + "Privacy" : "الخصوصية", "Private_Groups" : "مجموعات خاصة", + "Private_Groups_list" : "قائمة المجموعات الخاصة", "Profile" : "المل٠الشخصي", "Profile_saved_successfully" : "تم ØÙظ المل٠الشخصي بنجاØ", + "Push_enable" : "تمكين", + "Push_test_push" : "تجربة", "Quick_Search" : "بØØ« سريع", "quote" : "اقتباس", + "Record" : "سجل", "Register" : "تسجيل Øساب جديد", + "Registration_Succeeded" : "تم التسجيل بنجاØ", "Remember_me" : "تذكرني", "Remove" : "إزالة", "Remove_Admin" : "إزالة مدير", + "Remove_from_room" : "إزالة من الغرÙØ©", + "Removed" : "تمت اﻹزالة", + "Reset" : "إعادة التعيين", "Reset_password" : "إعادة تعيين كلمة السر", + "Restart" : "إعادة التشغيل", + "Restart_the_server" : "إعادة تشغيل السيرÙر", "Room" : "غرÙØ©", + "Room_has_been_deleted" : "تم Øذ٠الغرÙØ©", "Room_name_changed" : "تم تغيير اسم الغرÙØ© إلى: <em>__room_name__</em> بواسطة <em>__user_by__</em>", "Room_name_changed_successfully" : "تم تغيير اسم الغرÙØ© بنجاØ", + "Room_not_found" : "لم يتم العثور على الغرÙØ©", + "Room_uploaded_file_list" : "قائمة الملÙات", + "Room_uploaded_file_list_empty" : "لا يوجد ملÙات.", + "room_user_count" : "% مستخدم", "Rooms" : "الغرÙ", + "S_new_messages_since_s" : "% رسالة جديدة منذ %", + "Save_changes" : "ØÙظ التغيرات", + "Save_Mobile_Bandwidth" : "توÙير استهلاك الانترنت", "Search" : "بØØ«", "Search_Messages" : "بØØ« الرسائل", + "Search_settings" : "إعدادات البØØ«", + "seconds" : "ثواني", + "See_all" : "عرض الكل", + "See_only_online" : "المتصلون Ùقط", "Select_an_avatar" : "اختر صورة", "Select_file" : "اختر ملÙا", "Select_service_to_login" : "اختر خدمة للدخول إليها لتØميل صورتك أو قم بالتØميل مباشرة من جهازك", "Selected_users" : "أعضاء مختارين", + "Send" : "إرسال", "Send_confirmation_email" : "إرسال رسالة تأكيد", "Send_Message" : "أرسل رسالة", - "Settings" : "إعدادات", + "Settings" : "اﻹعدادات", + "Settings_updated" : "تم تØديث الإعدادات", + "Showing_online_users" : "عرض <b>__total_online__</b>من __total__ عضو", "Showing_results" : "<p>يعرض <b>%s</b> نتائج</p>", "Silence" : "الصمت", "since_creation" : "منذ %s", - "Sound" : "صوت", + "Site_Name" : "اسم الموقع", + "Site_Url" : "رابط الموقع", + "Site_Url_Description" : "مثال: https://chat.domain.com/", + "Sound" : "الصوت", "Start_of_conversation" : "بداية المØادثة", - "Statistics" : "Ø¥Øصائيات", + "Statistics" : "الإØصائيات", + "Stats_Active_Users" : "الأعضاء النشيطين", + "Stats_Avg_Channel_Users" : "متوسط مستخدمي القناة", + "Stats_Avg_Private_Group_Users" : "متوسط مستخدمي المجموعات الخاصة", "Stats_Away_Users" : "المستخدمين البعيدين", "Stats_Max_Room_Users" : "أقصى عدد للمستخدمين ÙÙŠ الغرÙ", + "Stats_Non_Active_Users" : "المستخدمين الغير نشطين", + "Stats_Offline_Users" : "المستخدمون الغير متصلون", + "Stats_Online_Users" : "المستخدمون المتصلون", + "Stats_OS_Arch" : "بنية النظام", + "Stats_OS_Cpus" : "عدد أنوية النظام", + "Stats_OS_Freemem" : "الذاكرة الØرة", + "Stats_OS_Loadavg" : "متوسط التØميل", + "Stats_OS_Platform" : "منصة النظام", + "Stats_OS_Release" : "إصدار النظام", + "Stats_OS_Type" : "نوع النظام", + "Stats_Total_Channels" : "مجموع القنوات", "Stats_Total_Direct_Messages" : "إجمالي عدد غر٠الرسالة المباشرة", "Stats_Total_Messages" : "مجموع الرسائل", - "Stats_Total_Rooms" : "إجمالي عدد الغرÙ", + "Stats_Total_Private_Groups" : "عدد المجموعات الخاصة", + "Stats_Total_Rooms" : "عدد الغرÙ", + "Stats_Total_Users" : "عدد الأعضاء", + "Stop_Recording" : "إيقا٠التسجيل", "strike" : "شطب", + "Submit" : "تقديم", + "The_channel_name_is_required" : "اسم القناة مطلوب", + "The_field_is_required" : "هذا الØقل %s مطلوب.", + "The_server_will_restart_in_s_seconds" : "سيتم إعادة تشغيل الخادم ÙÙŠ %s ثانية", "True" : "نعم", - "Unread_Rooms" : "غر٠غير مقروءة", + "Type_your_new_password" : "اكتب كلمة المرور الجديدة", + "Unmute_user" : "إلغاء اسكات المستخدم", + "Unread_Rooms" : "الغر٠غير مقروءة", "Unread_Rooms_Mode" : "وضع الغر٠الغير مقروءة", + "Upload_file_question" : "تØميل الملÙØŸ", + "Uploading_file" : "تØميل المل٠...", + "Use_Emojis" : "استخدم الرموز التعبيرية (ايموجي)", "Use_initials_avatar" : "استخدم الأØر٠الأولى من اسم المستخدم", "use_menu" : "استخدم القائمة الجانبية للوصول إلى الغر٠الخاصة بك والمØادثات", "Use_service_avatar" : "استخدام %s الرمزية", @@ -162,24 +312,50 @@ "Use_uploaded_avatar" : "استخدم الصورة المØملة", "Use_url_for_avatar" : "استخدم رابط للصورة الرمزية", "User_added_by" : "تم إضاÙØ© <em>__user_added__</em> بواسطة <em>__user_by__</em>.", + "User_Channels" : "قنوات المستخدم", + "User_has_been_activated" : "تم تÙعيل المستخدم", + "User_has_been_deactivated" : "تم إلغاء تنشيط المستخدم", + "User_has_been_deleted" : "تم Øذ٠العضو", + "User_Info" : "معلومات المستخدم", "User_is_no_longer_an_admin" : "المستخدم لم يعد مديرا", + "User_is_not_activated" : "العضو غير Ù…Ùعل", "User_is_now_an_admin" : "المستخدم الآن مدير", "User_joined_channel" : "انضم للقناة.", + "User_joined_channel_female" : "انضمت للقناة", + "User_joined_channel_male" : "انضم للقناة.", "User_left" : "غادر القناة.", + "User_left_female" : "غادرت القناة.", + "User_left_male" : "غادر القناة.", "User_logged_out" : "المستخدم سجل الخروج", - "User_not_found_or_incorrect_password" : "اسم المستخدم غير موجود أو كلمة السر غير صØÙŠØØ©", + "User_muted_by" : "تم اسكات <em>__user_muted__</em> بواسطة <em>__user_by__</em>.", + "User_not_found_or_incorrect_password" : "لم يتم العثور على المستخدم أو كلمة المرور غير صØÙŠØØ©", "User_removed_by" : "تم ØØ°Ù <em>__user_removed__</em> بواسطة <em>__user_by__</em>.", + "User_removed_from_room" : "تم إزالة المستخدم من الغرÙØ©", + "User_Settings" : "إعدادات المستخدم", + "User_unmuted_by" : "تم إلغاء اسكات <em>__user_unmuted__</em> بواسطة <em>__user_by__</em>.", + "User_updated_successfully" : "تم تØديث العضو بنجاØ", "Username" : "اسم المستخدم", "Username_cant_be_empty" : "اسم المستخدم لا يمكن أن يكون Ùارغا", + "Username_Change_Disabled" : "مدير الموقع منع تغيير اسم المستخدم", "Username_description" : "يتم استخدام اسم المستخدم Ù„Ù„Ø³Ù…Ø§Ø Ù„Ù„Ø¢Ø®Ø±ÙŠÙ† بذكرك ÙÙŠ الرسائل.", "Username_invalid" : "<strong>%s</strong> لا ÙŠØµÙ„Ø ÙƒØ¥Ø³Ù… مستخدم،<br/> استخدم Ùقط ØروÙا وأرقاما وشرطات", "Username_title" : "تسجيل اسم المستخدم", "Username_unavaliable" : "<strong>%s</strong> مستخدم مسبقا :(", + "Users" : "المستخدمين", + "UTF8_Names_Validation_Description" : "لا ØªØ³Ù…Ø Ø¨Ø§Ø³ØªØ®Ø¯Ø§Ù… رموز خاصة Ùˆ مساÙات. يمكنك استخدام العلامات التالية - _ . لكن لا ØªØ³Ù…Ø Ø¨Ù‡Ù† ÙÙŠ نهاية الاسم.", "View_All" : "مشاهدة الكل", "We_have_sent_password_email" : "لقد قمنا بإرسال رسالة بريد إلكتروني مع إرشادات إعادة تعيين كلمة السر. إذا لم يصلك البريد الإلكتروني قريبا، يرجى العودة والمØاولة مرة أخرى.", "We_have_sent_registration_email" : "لقد قمنا بإرسال رسالة بريد إلكتروني لتأكيد تسجيلك. إذا لم يصلك البريد الإلكتروني قريبا، يرجى العودة والمØاولة مرة أخرى.", "Welcome" : "مرØبا بك يا <em>%s</em>.", "Welcome_to_the" : "أهلا بك ÙÙŠ", + "With_whom" : "مع من", + "Yes" : "نعم", + "Yes_clear_all" : "نعم، Øذ٠الكل!", + "Yes_delete_it" : "نعم، Ø£ØØ°Ù!", + "You_can_use_an_emoji_as_avatar" : "تستطيع استخدام ايموجي كصورة رمزية", + "You_have_been_muted" : "لقد تم اسكاتك ولا يمكنك التØدث ÙÙŠ هذه الغرÙØ©", "You_need_confirm_email" : "تØتاج إلى تأكيد بريدك الإلكتروني لتسجيل الدخول!", + "You_will_not_be_able_to_recover" : "لن تستطيع استرداد هذه الرسالة!", + "Your_entry_has_been_deleted" : "لقد تم Øذ٠رسالتك", "Your_Open_Source_solution" : "تطبيق المØادثة الخاص بك المÙØªÙˆØ Ø§Ù„Ù…ØµØ¯Ø±" } \ No newline at end of file diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 22c80008b852fd18551099c3ea54ecb4bc27ea25..ebca809b478681c98b56a2d264214f3861b66a6d 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -1,73 +1,106 @@ { - "Access_online_demo" : "Öffne die online demo", + "Access_not_authorized" : "Der Zugriff ist nicht gestattet.", + "Access_online_demo" : "Öffne die Online-Demo", "Access_Online_Demo" : "Öffne die Online Demo", - "Accounts" : "Kontos", - "Accounts_AllowedDomainsList" : "Erlaubt Domains Liste", - "Accounts_AllowPasswordChange" : "Passwort ändern erlauben", - "Accounts_AllowUsernameChange" : "Änderung von Benutzernamen erlauben", - "Accounts_AvatarResize" : "Größe des Avatars anpassen", - "Accounts_AvatarSize" : "Avatar Größe", - "Accounts_AvatarStorePath" : "Avatar Speicherpfad", - "Accounts_AvatarStoreType" : "Avatar Speichertyp", - "Accounts_denyUnverifiedEmail" : "Nicht verifizierte E-Mails ablehnen", + "Access_Token_URL" : "URL des Access-Token", + "Accounts" : "Konten", + "Accounts_AllowedDomainsList" : "Liste von erlaubten Domains", + "Accounts_AllowedDomainsList_Description" : "Durch Kommata getrennte Liste von erlaubten Domains", + "Accounts_AllowPasswordChange" : "Ändern des Passworts zulassen", + "Accounts_AllowUserAvatarChange" : "Benutzern das Ändern des Profilbilds erlauben", + "Accounts_AllowUsernameChange" : "Ändern von Benutzernamen erlauben", + "Accounts_AllowUserProfileChange" : "Benutzern das Ändern des Profils erlauben", + "Accounts_AvatarResize" : "Größe des Profilbilds anpassen", + "Accounts_AvatarSize" : "Größe des Profilbilds", + "Accounts_AvatarStorePath" : "Speicherpfad des Profilbilds", + "Accounts_AvatarStoreType" : "Speichertyp des Profilbilds", + "Accounts_denyUnverifiedEmail" : "Nicht verifizierte E-Mail-Adressen ablehnen", "Accounts_EmailVerification" : "E-Mail-Verifizierung", + "Accounts_Enrollment_Email" : "Registrierungsmail", + "Accounts_Enrollment_Email_Description" : "Sie können [name] für den Vor- und Nachnamen, [fname] für den Vornamen oder [lname] für den Nachnamen des Benutzers verwenden. <br />Ebenfalls können Sie [email] verwenden, um die E-Mail-Adresse des Benutzers anzugeben.", + "Accounts_LoginExpiration" : "Ablauffrist der Anmeldung", "Accounts_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", "Accounts_OAuth_Custom_Authorize_Path" : "Autorisierungspfad", "Accounts_OAuth_Custom_Button_Color" : "Buttonfarbe", - "Accounts_OAuth_Custom_Button_Label_Color" : "Button-Text-Farbe", - "Accounts_OAuth_Custom_Button_Label_Text" : "Button-Text", + "Accounts_OAuth_Custom_Button_Label_Color" : "Farbe des Buttontexts", + "Accounts_OAuth_Custom_Button_Label_Text" : "Text des Buttons", "Accounts_OAuth_Custom_Enable" : "Aktivieren", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_Identity_Path" : "Identitäts Pfad", + "Accounts_OAuth_Custom_id" : "ID", + "Accounts_OAuth_Custom_Identity_Path" : "Identitätspfad", + "Accounts_OAuth_Custom_Login_Style" : "Anmeldungsart", "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Token_Path" : "Token Pfad", + "Accounts_OAuth_Custom_Token_Path" : "Pfad des Token", "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Facebook" : "Facebook Login", + "Accounts_OAuth_Facebook" : "Anmeldung über Facebook erlauben", "Accounts_OAuth_Facebook_id" : "Facebook-App-ID", - "Accounts_OAuth_Facebook_secret" : "Facebook Secret", - "Accounts_OAuth_Github" : "OAuth Enabled", - "Accounts_OAuth_Github_id" : "Client ID", - "Accounts_OAuth_Github_secret" : "Client Secret", - "Accounts_OAuth_Gitlab" : "OAuth aktiviert", - "Accounts_OAuth_Gitlab_id" : "Gitlab Id", - "Accounts_OAuth_Gitlab_secret" : "Client Secret", - "Accounts_OAuth_Google" : "Google Login", - "Accounts_OAuth_Google_id" : "Google Id", - "Accounts_OAuth_Google_secret" : "Google Secret", - "Accounts_OAuth_Linkedin" : "LinkedIn Login", - "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", - "Accounts_OAuth_Linkedin_secret" : "Linkeding Secret", - "Accounts_OAuth_Meteor" : "Meteor Login", - "Accounts_OAuth_Meteor_id" : "Meteor Id", - "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_Twitter" : "Twitter Login", - "Accounts_OAuth_Twitter_id" : "Twitter Id", - "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_OAuth_Facebook_secret" : "Facebook-Secret", + "Accounts_OAuth_Github" : "OAuth aktivieren", + "Accounts_OAuth_Github_id" : "Client-ID", + "Accounts_OAuth_Github_secret" : "Client-Secret", + "Accounts_OAuth_Gitlab" : "OAuth aktivieren", + "Accounts_OAuth_Gitlab_id" : "GitLab-ID", + "Accounts_OAuth_Gitlab_secret" : "Client-Secret", + "Accounts_OAuth_Google" : "Google-Anmeldung erlauben", + "Accounts_OAuth_Google_id" : "Google-ID", + "Accounts_OAuth_Google_secret" : "Google-Secret", + "Accounts_OAuth_Linkedin" : "Anmeldung über LinkedIn erlauben", + "Accounts_OAuth_Linkedin_id" : "LinkedIn-ID", + "Accounts_OAuth_Linkedin_secret" : "Linkeding-Secret", + "Accounts_OAuth_Meteor" : "Anmeldung über Meteor erlauben", + "Accounts_OAuth_Meteor_id" : "Meteor-ID", + "Accounts_OAuth_Meteor_secret" : "Meteor-Secret", + "Accounts_OAuth_Twitter" : "Anmeldung über Twitter erlauben", + "Accounts_OAuth_Twitter_id" : "Twitter-ID", + "Accounts_OAuth_Twitter_secret" : "Twitter-Secret", + "Accounts_PasswordReset" : "Passwort zurücksetzen", + "Accounts_Registration_AuthenticationServices_Enabled" : "Anmeldung mit Authentifizierungsdiensten", + "Accounts_RegistrationForm" : "Anmeldeformular", + "Accounts_RegistrationForm_Disabled" : "Deaktiviert", + "Accounts_RegistrationForm_LinkReplacementText" : "Ersatztext für den Registrierungsformularlink", + "Accounts_RegistrationForm_Public" : "Öffentlich", + "Accounts_RegistrationForm_Secret_URL" : "Geheime URL", + "Accounts_RegistrationForm_SecretURL" : "Geheime URL für die Registrierungsseite", + "Accounts_RegistrationForm_SecretURL_Description" : "Sie müssen eine zufällige Zeichenfolge, die der Registrierungs-URL hinzugefügt wird, verwenden. Beispiel: https://demo.rocket.chat/registrieren/[geheimer_schluessel]", "Accounts_RegistrationRequired" : "Anmeldung erforderlich", + "Accounts_RequireNameForSignUp" : "Ein Name ist für die Anmeldung erforderlich.", + "Accounts_ShowFormLogin" : "Anmeldeformular zeigen", "Activate" : "Aktivieren", - "Add_custom_oauth" : "Benutzerdefinierte oauth hinzufügen", + "Add_custom_oauth" : "Benutzerdefiniertes OAuth-Konto hinzufügen", "Add_Members" : "Mitglieder hinzufügen", "Add_users" : "Benutzer hinzufügen", "Administration" : "Administration", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "Nach der OAuth2-Authentifizierung werden die Benutzer auf diese URL weitergeleitet.", + "Alias" : "Alias", "All_channels" : "Alle Kanäle", - "Allow_Invalid_SelfSigned_Certs" : "Selbstsignierte SSL-Zertifikate für die Link-Validierung und die Vorschau zulassen", + "Allow_Invalid_SelfSigned_Certs" : "Ungültige und selbstsignierte SSL-Zertifikate erlauben", + "Allow_Invalid_SelfSigned_Certs_Description" : "Ungültige und selbstsignierte SSL-Zertifikate für die Link-Validierung und die Vorschau zulassen", "and" : "und", "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Einbetten", - "API_EmbedDisabledFor" : "Deaktiviere Embed für User", + "API_EmbedDisabledFor" : "Einbettungen für Benutzer deaktivieren", "API_EmbedDisabledFor_Description" : "Durch Kommata getrennte Liste von Benutzernamen", + "Application_added" : "Die Anwendung wurde hinzugefügt.", + "Application_Name" : "Name der Anwendung", + "Application_updated" : "Die Anwendung wurde aktualisiert.", + "Archive" : "Archivieren", "are_also_typing" : "schreiben auch", "are_typing" : "schreiben", "Are_you_sure" : "Sind Sie sicher?", + "Authorization_URL" : "Autorisierungs-URL", + "Authorize" : "Berechtigen", "Auto_Load_Images" : "Automatisches Laden der Bilder", - "Avatar_changed_successfully" : "Avatar erfolgreich geändert", + "Avatar_changed_successfully" : "Das Profilbild wurde erfolgreich geändert.", + "Avatar_URL" : "URL des Profilbilds", + "Avatar_url_invalid_or_error" : "Die angegebene Internetadresse ist ungültig oder nicht verfügbar. Bitte versuchen Sie es mit einer anderen Internetadresse erneut.", "away" : "abwesend", "Away" : "Abwesend", "away_female" : "abwesend", "Away_female" : "Abwesend", "away_male" : "abwesend", "Away_male" : "Abwesend", + "Back_to_applications" : "Zurück zu den Anwendungen", + "Back_to_integrations" : "Zurück zu Integrationen", "Back_to_login" : "Zurück zum Login", "bold" : "fett", "busy" : "beschäftigt", @@ -77,89 +110,119 @@ "busy_male" : "beschäftigt", "Busy_male" : "Beschäftigt", "Cancel" : "Abbrechen", - "CDN_PREFIX" : "CDN Präfix", - "Change_avatar" : "Ändere dein Avatar", + "CDN_PREFIX" : "CDN-Präfix", + "Certificates_and_Keys" : "Zertifikate und Schlüssel", + "Change_avatar" : "Profilbild", "Channels" : "Kanäle", - "Channels_list" : "Liste der öffentlichen Channels", + "Channels_list" : "Liste der öffentlichen Kanäle", "Chat_Rooms" : "Chaträume", - "Clear_all_unreads_question" : "Alle ungelesenen löschen?", - "close" : "schließen", + "Choose_the_alias_that_will_appear_before_the_username_in_messages" : "Wählen Sie den Alias, der vor dem Benutzernamen in den Nachrichten angezeigt wird.", + "Choose_the_username_that_this_integration_will_post_as" : "Wählen Sie den Benutzernamen, der die Integration veröffentlicht.", + "Clear_all_unreads_question" : "Möchten Sie alle ungelesenen Nachrichten löschen?", + "Client_ID" : "Client-ID", + "Client_Secret" : "Client-Secret", + "close" : "Schließen", "coming_soon" : "kommt bald", "Commands" : "Befehle", - "Compact_View" : "Kompakte Ansicht", - "Confirm_password" : "Bestätigen Sie Ihr Passwort", + "Compact_View" : "Kompaktansicht", + "Confirm_password" : "Bestätigen Sie Ihr Passwort.", "Contact" : "Kontakt", "Conversation" : "Konversation", - "Convert_Ascii_Emojis" : "Konvertiere ASCII zu Emoji", + "Convert_Ascii_Emojis" : "ASCII zu Emoji konvertieren", + "COPY_TO_CLIPBOARD" : "IN DIE ZWISCHENABLAGE KOPIEREN", "Create_new" : "Neu erstellen", - "Create_new_direct_message_room" : "Erstellen Sie einen neuen Direktnachrichten-Raum", - "Create_new_private_group" : "Erstellen Sie eine neue private Gruppe", - "Create_new_public_channel" : "Erstelle einen neuen öffentlichen Channel", + "Create_new_direct_message_room" : "Neuen privaten Nachrichtenraum erstellen", + "Create_new_private_group" : "Neue private Gruppe erstellen", + "Create_new_public_channel" : "Einen neuen öffentlichen Kanal erstellen", "Created_at" : "Erstellt am", - "Custom_oauth_helper" : "Bei der Einrichtung von OAuth, muss eine Callback-URL angegeben werden. Benutze <pre>%s</pre>", - "Custom_oauth_unique_name" : "Eindeutigen Namen von benutzerdefinierte oauth", + "Created_at_s_by_s" : "Erstellt am <strong>%s</strong> von <strong>%s</strong>", + "Custom_oauth_helper" : "Bei der Einrichtung muss eine Rückruf-URL angegeben werden. Benutze dafür folgende URL: <pre>%s</pre>", + "Custom_oauth_unique_name" : "Name des OAuth-Kontos", "days" : "Tage", "Deactivate" : "Deaktivieren", - "Delete_Room_Warning" : "Beim Löschen eines Raumes, werden seine Nachrichten ebenfalls gelöscht. Dies kann nicht rückgängig gemacht werden.", - "Delete_User_Warning" : "Beim Löschen eines Benutzers, werden alle seine Nachrichten ebenfalls gelöscht. Dies kann nicht rückgängig gemacht werden.", + "Delete_Room_Warning" : "Beim Löschen eines Raums werden alle Nachrichten in diesem Raum unwiderruflich gelöscht.", + "Delete_User_Warning" : "Beim Löschen eines Benutzers werden alle Nachrichten des Benutzers unwiderruflich gelöscht.", "Deleted" : "Gelöscht!", "Desktop_Notifications" : "Desktop-Benachrichtigungen", "Desktop_Notifications_Disabled" : "Desktop-Benachrichtigungen sind deaktiviert. Ändern Sie Ihre Browsereinstellungen, wenn Sie Benachrichtigungen erhalten wollen.", - "Desktop_Notifications_Enabled" : "Desktop-Benachrichtigungen sind aktiviert", + "Desktop_Notifications_Enabled" : "Desktop-Benachrichtigungen sind bereits aktiviert.", "Direct_Messages" : "Private Nachrichten", "Disable_Favorite_Rooms" : "Favoriten deaktivieren", - "Disable_New_Message_Notification" : "Deaktiviere Benachrichtigung bei neuen Nachrichten", - "Disable_New_Room_Notification" : "Deaktiviere Benachrichtigung bei neuen Raum Nachrichten", - "Drop_to_upload_file" : "Ablegen um Datei zu uploaden", - "Duplicate_channel_name" : "Ein Kanal mit dem Namen, '%s', existiert", - "Duplicate_private_group_name" : "Eine private Gruppe mit dem Namen, '%s', existiert", + "Disable_New_Message_Notification" : "Benachrichtigungen bei neuen Nachrichten deaktivieren", + "Disable_New_Room_Notification" : "Benachrichtigungen bei neuen Nachrichten in einem Raum deaktivieren", + "Do_you_want_to_change_to_s_question" : "Möchten Sie dies zu <strong>%s</strong> ändern?", + "Drop_to_upload_file" : "Ablegen, um Datei hochzuladen", + "Duplicate_archived_channel_name" : "Ein archivierter Kanal mit dem Namen '%s' existiert bereits.", + "Duplicate_archived_private_group_name" : "Eine archivierte private Gruppe mit dem Namen '%s' existiert bereits.", + "Duplicate_channel_name" : "Ein Kanal mit dem Namen '%s' existiert bereits.", + "Duplicate_private_group_name" : "Eine private Gruppe mit dem Namen '%s' existiert bereits.", "E-mail" : "E-Mail", "edited" : "bearbeitet", - "Email_already_exists" : "E-Mail existiert bereits", - "Email_or_username" : "Email oder Username", - "Email_verified" : "Email bestätigt", + "Email_already_exists" : "Die E-Mail-Adresse existiert bereits.", + "Email_or_username" : "E-Mail-Adresse oder Nutzername", + "Email_verified" : "Die E-Mail-Adresse wurde bestätigt.", "Emoji" : "Emoji", - "Enable_Desktop_Notifications" : "Aktiviere Desktop-Benachrichtigungen", - "Enter_info" : "Geben Sie Ihre Anmeldedaten an", - "Enter_to" : "Enter um", + "Enable_Desktop_Notifications" : "Aktivieren", + "Enter_info" : "Geben Sie Ihre Anmeldedaten an.", + "Enter_to" : "Betreten, um", + "Error" : "Fehler", "Error_changing_password" : "Fehler beim Ändern des Passwortes", - "Error_too_many_requests" : "Fehler, zu viele Anfragen. Slow down ;) Warte %s Sekunden vor einem erneuten Versuch", - "Esc_to" : "Esc um", - "False" : "Falsch", + "Error_too_many_requests" : "Fehler, zu viele Anfragen. Warte %s Sekunden, bevor du es erneut probierst.", + "Esc_to" : "Verlassen, um", + "Example_s" : "Beispiel: <code class=\"inline\">%s</code>", + "False" : "Nein", "Favorites" : "Favoriten", - "FileUpload" : "Datei-Upload", - "FileUpload_Enabled" : "Datei-Upload aktivieren", + "FileUpload" : "Dateien hochladen", + "FileUpload_Enabled" : "Hochladen von Dateien aktivieren", + "FileUpload_File_Empty" : "Datei ist leer", "FileUpload_MaxFileSize" : "Max. Größe für hochgeladene Dateien (in Bytes)", - "FileUpload_MediaTypeWhiteList" : "Durch Kommata getrennte Liste von Medientypen", + "FileUpload_MediaType_NotAccepted" : "Medientypen werden nicht akzeptiert", + "FileUpload_MediaTypeWhiteList" : "Erlaubte Medientypen", "FileUpload_MediaTypeWhiteListDescription" : "Durch Kommata getrennte Liste von Medientypen", - "Follow_social_profiles" : "Folge uns in sozialen Netzen, fork uns auf github und teile deine Gedanken über die rocket.chat app auf unserem trello board.", + "FileUpload_ProtectFiles" : "Hochgeladene Dateien schützen", + "FileUpload_ProtectFilesDescription" : "Nur bestätigte Benutzer dürfen Dateien hochladen.", + "Follow_social_profiles" : "Folge uns in sozialen Netzwerken, fork uns auf GitHub und teile deine Gedanken über die Rocket.Chat-App auf unserem Trello-Board.", "Forgot_password" : "Passwort vergessen?", "Fork_it_on_github" : "Fork es auf GitHub", - "From_Email" : "E-Mail von", - "General" : "Allgemein", - "Get_to_know_the_team" : "Lernen Sie das Rocket.Team kennen", - "github_no_public_email" : "Sie haben keine öffentliche Email-Adresse in Ihrem Github Account", - "Give_a_unique_name_for_the_custom_oauth" : "Geben Sie einen eindeutigen Namen für das benutzerdefinierte oauth", + "From_Email" : "Absender", + "General" : "Allgemeines", + "Get_to_know_the_team" : "Lernen Sie das Rocket.Team kennen.", + "github_no_public_email" : "Sie haben keine öffentliche E-Mail-Adresse in Ihrem GitHub-Account.", + "Give_a_unique_name_for_the_custom_oauth" : "Geben Sie dem benutzerdefinierten OAuth-Konto einen eindeutigen Namen.", + "Give_the_application_a_name_This_will_be_seen_by_your_users" : "Geben Sie der Anwendung einen Namen. Die Nutzer können den Namen sehen.", "Has_more" : "Mehr", - "Have_your_own_chat" : "Erstelle deinen eigenen web chat. Entwickelt mit Meteor.com, der Rocket.Chat ist eine tolle Lösung für Entwickler, die schnell und einfach einen eigene Chat Plattform aufbauen wollen.", + "Have_your_own_chat" : "Starte deinen eigenen Internet-Chat. Entwickelt mit Meteor.com. Rocket.Chat ist eine tolle Lösung für Entwickler, die schnell und einfach eine eigene Chat-Plattform aufbauen möchten.", "Hide_room" : "Raum verstecken", "History" : "Chronik", "hours" : "Stunden", - "Incorrect_Password" : "Falsches Passwort", - "inline_code" : "inline_code", - "Install_FxOs" : "Installiere Rocket.Chat auf deinem Firefox", + "Incorrect_Password" : "Das angegebene Passwort ist falsch.", + "inline_code" : "Code", + "Install_Extension" : "Erweiterung installieren", + "Install_FxOs" : "Rocket.Chat in deinem Firefox-Browser aktivieren", "Install_FxOs_done" : "Super! Du kannst Rocket.Chat nun über das Icon auf deinem Startbildschirm nutzen. Viel Spaß mit Rocket.Chat!", "Install_FxOs_error" : "Schade, das hat leider nicht geklappt! Der folgende Fehler ist aufgetreten:", - "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App (drücke \"Installieren\" in der Aufforderung).", - "Invalid_confirm_pass" : "Die Passwörter stimmen nicht überein", - "Invalid_email" : "Email-Adresse ungültigt", - "Invalid_name" : "Der Name darf nicht leer sein", - "Invalid_pass" : "Das Passwort darf nicht leer sein", + "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App, indem du auf \"Installieren\" klickst.", + "Integration_added" : "Die Integration wurde hinzugefügt.", + "Integration_Incoming_WebHook" : "Eingehende WebHook-Integration", + "Integration_New" : "Neue Integration", + "Integration_updated" : "Die Integration wurde aktualisiert.\n", + "Integrations" : "Integrationen", + "Invalid_asset" : "Ungültiger Wert", + "Invalid_confirm_pass" : "Die Passwörter stimmen nicht überein.", + "Invalid_email" : "Die eingegebenen E-Mail-Adresse ist ungültig.", + "Invalid_file_height" : "Ungültige Dateihöhe", + "Invalid_file_type" : "Ungültiges Dateiformat.", + "Invalid_file_width" : "Ungültige Dateibreite", + "Invalid_name" : "Es muss ein Name angegeben werden.", + "Invalid_pass" : "Es muss ein Passwort angegeben werden.", "Invalid_room_name" : "<strong>%s</strong> ist kein zulässiger Raumname.<br/> Benutze nur Buchstaben, Nummern und Bindestriche.", + "Invalid_room_type" : "<strong>%s</strong> ist kein gültiger Raumtyp.", + "Invalid_Secret_URL" : "Ungültige geheime URL", + "Invalid_secret_URL_message" : "Die angegebene URL ist ungültig.", "invisible" : "unsichtbar", "Invisible" : "Unsichtbar", - "Invitation_HTML" : "Einladungs HTML", - "Invitation_Subject" : "Einladungs Betreff", + "Invitation_HTML" : "Einladungstext (HTML)", + "Invitation_Subject" : "Einladungsbetreff", "Invite_Users" : "Benutzer einladen", "is_also_typing" : "schreibt auch", "is_also_typing_female" : "schreibt auch", @@ -169,265 +232,385 @@ "is_typing_male" : "schreibt", "italics" : "kursiv", "join" : "Beitreten", + "Join_audio_call" : "Anruf beitreiten", "Join_the_Community" : "Trete der Community bei", + "Join_video_call" : "Videoanruf beitreten", + "Jump_to_first_unread" : "Erste ungelesene Nachricht anzeigen", + "Jump_to_message" : "Diese Nachricht im Chat anzeigen", + "Jump_to_recent_messages" : "Neue Nachricht im Chat anzeigen", "Language" : "Sprache", "Language_Version" : "Deutsche Version", - "Last_login" : "Letztes login", + "Last_login" : "Letzte Anmeldung", "Last_message" : "Letzte Nachricht", "Layout" : "Layout", - "Layout_Home_Body" : "Home Body", - "Layout_Home_Title" : "Home Title", - "Layout_Login_Header" : "Login Header", - "Layout_Login_Terms" : "Nutzungsbedingungen zu Anmeldung", + "Layout_Home_Body" : "Inhalt der Startseite", + "Layout_Home_Title" : "Titel der Startseite", + "Layout_Login_Header" : "Kopfzeile der Anmeldeseite", + "Layout_Login_Terms" : "Anmeldebedingungen", "Layout_Privacy_Policy" : "Datenschutzbestimmungen", - "Layout_Sidenav_Footer" : "Seiten Navigations Footer", - "Layout_Sidenav_Footer_description" : "Die Footer Größe ist 260x70", + "Layout_Sidenav_Footer" : "Seitenfußzeile", + "Layout_Sidenav_Footer_description" : "Die Größe der Fußzeile beträgt 260 x 70 Pixel.", "Layout_Terms_of_Service" : "Nutzungsbedingungen", "LDAP" : "LDAP", - "LDAP_Bind_Search" : "Bind Suche", - "LDAP_DN" : "LDAP DN", + "LDAP_Bind_Search" : "Bind-Suche", + "LDAP_Bind_Search_Description" : "Ein Stück von JSON, welches Bind und Verbindungsinformationen regelt, und folgende Form hat: {\"filter\": \"(&(objectCategory=person)(objectclass=user)(memberOf=CN=ROCKET_ACCESS,CN=Users,DC=domain,DC=com)(sAMAccountName=#{username}))\", \"scope\": \"sub\", \"userDN\": \"rocket.service@domain.com\", \"password\": \"urpass\"}", + "LDAP_CA_Cert" : "CA-Cert", + "LDAP_Description" : "LDAP ist ein Frontend zu hierarchischen Datenbanken, die viele Unternehmen nutzen, um eine eine Einmalanmeldung (SSO) zu ermöglichen. Ãœber SSO kann \"ein Benutzer nach einer einmaligen Authentifizierung an einem Arbeitsplatz auf alle Rechner und Dienste, für die er lokal berechtigt ist, am selben Arbeitsplatz zugreifen kann, ohne sich jedes Mal neu anmelden zu müssen\". Genauere Informationen zur Konfiguration von LDAP mit Konfigurationsbeispielen erhalten Sie unter folgendem Link: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication", + "LDAP_DN" : "Distinguished Name (DN)", + "LDAP_DN_Description" : "Suche root. Beispiel: dc=domain, dc=com", "LDAP_Enable" : "LDAP aktivieren", - "LDAP_Port" : "LDAP Port", - "LDAP_Url" : "LDAP URL", + "LDAP_Enable_Description" : "LDAP für die Authentifizierung verwenden.", + "LDAP_Port" : "LDAP-Port", + "LDAP_Port_Description" : "Port für den Zugriff auf LDAP. Beispiel: Port 389", + "LDAP_Reject_Unauthorized" : "Unberechtigte ablehnen", + "LDAP_Sync_User_Data" : "Daten synchronisieren", + "LDAP_Sync_User_Data_Description" : "Bei der Anmeldung die Benutzerdaten mit dem Server synchronisieren (Beispiel: Name, E-Mail).", + "LDAP_Sync_User_Data_FieldMap" : "Nutzerdaten-Feldkarte", + "LDAP_Sync_User_Data_FieldMap_Description" : "Konfigurieren Sie, wie Benutzer-Account-Felder (wie die E-Mail-Adresse) aus einem Datensatz (sobald gefunden) in LDAP besiedelt werden. Beispiel: {\"cn\": \"Name\", \"Mail\": \"E-Mail\"} nimmt einen von Menschen lesbaren Namen von dem cn-Attribut und die E-Mail-Adresse vom Mail-Attribut. Verfügbare Felder beinhalten den Namen und die E-Mail-Adresse.", + "LDAP_TLS" : "TLS", + "LDAP_Url" : "LDAP-URL", + "LDAP_Url_Description" : "URL des LDAP-Servers. Beispiel: ldap://company.dns.com", "Leave_room" : "Raum verlassen", "line" : "Zeilen", "Load_more" : "Mehr laden", "Loading..." : "Wird geladen ...", - "Loading_more_from_history" : "Lade mehr aus der Historie", + "Loading_more_from_history" : "Mehr Nachrichten aus dem Verlauf anzeigen", "Loading_suggestion" : "Vorschläge werden geladen...", - "Login" : "Login", - "Login_with" : "Login mit %s", + "Logged_out_of_other_clients_successfully" : "Sie wurden erfolgreich von anderen Geräten abgemeldet.", + "Login" : "Anmelden", + "Login_with" : "Anmelden mit %s", "login_with" : "Oder melden Sie sich direkt mit folgenden Accounts an", "Logout" : "Abmelden", - "Make_Admin" : "zum Admin machen", + "Logout_Others" : "Von anderen Geräten abmelden", + "Make_Admin" : "Benutzer zum Admin ernennen", "Mark_as_read" : "Als gelesen markieren", - "Markdown_Headers" : "Markdown-Headers", + "Markdown_Headers" : "Markdown-Ãœberschriften", "Members" : "Mitglieder", - "Members_List" : "Mitgliederliste", + "Members_List" : "Mitglieder", "Members_placeholder" : "Mitglieder", "Message" : "Nachricht", - "Message_AllowDeleting" : "Erlaube Nachrichten zu löschen", - "Message_AllowEditing" : "Erlaube Bearbeitung von Nachrichten", - "Message_AllowEditing_BlockEditInMinutes" : "Bearbeiten von Nachrichten blockieren nach (in Minuten - 0 zum deaktivieren)", - "Message_AllowEditing_BlockEditInMinutesDescription" : "Geben Sie 0 ein, um das Blocken zu deaktivieren.", - "Message_AudioRecorderEnabled" : "Audio Recorder Aktiviert", - "Message_deleting_not_allowed" : "Nachrichten löschen nicht erlaubt", - "Message_editing_blocked" : "Diese Nachricht kann nicht mehr bearbeitet werden", - "Message_editing_not_allowed" : "Nachrichten bearbeiten nicht erlaubt", + "Message_AllowDeleting" : "Das Löschen von Nachrichten erlauben", + "Message_AllowEditing" : "Die Bearbeitung von Nachrichten erlauben", + "Message_AllowEditing_BlockEditInMinutes" : "Bearbeiten von Nachrichten nach (in Minuten - 0 zum deaktivieren) blockieren ", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Geben Sie eine 0 ein, um das Bearbeiten von Nachrichten jederzeit zu erlauben.", + "Message_AudioRecorderEnabled" : "Audioaufnahme aktivieren", + "Message_AudioRecorderEnabledDescription" : "'audio/wav'-Dateien sind erforderlich, damit der Medientyp in den \"Dateien-Upload\"-Einstellungen akzeptiert wird.", + "Message_deleting_not_allowed" : "Das Löschen von Nachrichten ist nicht erlaubt.", + "Message_editing_blocked" : "Diese Nachricht kann nicht mehr bearbeitet werden.", + "Message_editing_not_allowed" : "Das Bearbeiten von Nachrichten ist nicht erlaubt.", + "Message_GroupingPeriod" : "Gruppierungsdauer (in Sekunden)", + "Message_GroupingPeriodDescription" : "Nachrichten werden einer vorherigen Nachricht zugeordnet, wenn beide Nachrichten von dem gleichen Benutzer kommen und die abgelaufene Zeit kleiner als die mitgeteilte Zeit in Sekunden war.", "Message_KeepHistory" : "Nachrichtenverlauf behalten", - "Message_MaxAllowedSize" : "Maximale Größe der Nachricht", - "Message_pinned" : "Nachricht angeheftet", - "Message_pinning_not_allowed" : "Nachrichten anheften erlaubt", - "Message_removed" : "Nachricht entfernt", - "Message_ShowDeletedStatus" : "Zeige Löschstatus", - "Message_ShowEditedStatus" : "Zeige Bearbeitungsstatus", - "Message_ShowFormattingTips" : "Formatierungs-Tipps anzeigen", + "Message_MaxAllowedSize" : "Maximal zulässige Größe der Nachrichten\n", + "Message_pinned" : "Die Nachricht wurde fixiert.", + "Message_pinning_not_allowed" : "Das Fixieren von Nachrichten verbieten", + "Message_removed" : "Diese Nachricht wurde entfernt.", + "Message_ShowDeletedStatus" : "Löschstatus zeigen", + "Message_ShowEditedStatus" : "Bearbeitungsstatus zeigen", + "Message_ShowFormattingTips" : "Formatierungstipps anzeigen", "Messages" : "Nachrichten", - "Meta" : "Meta", - "Meta_fb_app_id" : "Facebook APP ID", - "Meta_google-site-verification" : "Google Seiten", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here" : "Nachrichten, die an den eingehenden Webhook gesendet werden, werden hier veröffentlicht.", + "Meta" : "Metadaten", + "Meta_fb_app_id" : "Facebook-App-ID", + "Meta_google-site-verification" : "Google-Seiten-Verifizierung", "Meta_language" : "Sprache", "Meta_msvalidate01" : "MSValidate.01", - "Meta_robots" : "Robots", + "Meta_robots" : "Roboter", "minutes" : "Minuten", - "More_channels" : "Mehr Channels", + "More_channels" : "Mehr Kanäle", "More_groups" : "Weitere private Gruppen", - "More_unreads" : "Mehr ungelesene", - "Msgs" : "Mttl", + "More_unreads" : "Mehr ungelesene Nachrichten", + "Msgs" : "Nachrichten", "multi" : "mehrere", + "Mute_user" : "Benutzern das Chatten verbieten", + "Muted" : "Stumm geschaltet", "My_Account" : "Mein Konto", "n_messages" : "%s Nachrichten", "Name" : "Name", - "Name_cant_be_empty" : "Name darf nicht leer sein", - "Name_optional" : "Name (freiwillig)", + "Name_cant_be_empty" : "Es muss ein Name angegeben werden.", + "Name_optional" : "Name (optional)", + "New_Application" : "Neue Anwendung", + "New_integration" : "Neue Integration", "New_messages" : "Neue Nachrichten", "New_password" : "Neues Passwort", - "No_channel_with_name_%s_was_found" : "Es wurde keine Kanal mit dem Namen <strong>\"%s\"</strong> gefunden!", - "No_channels_yet" : "Sie sind kein Mitglied eines Channels.", + "No_channel_with_name_%s_was_found" : "Es wurde kein Kanal mit dem Namen <strong>\"%s\"</strong> gefunden!", + "No_channels_yet" : "Sie sind kein Mitglied eines Kanals.", "No_direct_messages_yet" : "Sie haben keine Konversation gestartet.", - "No_favorites_yet" : "Sie haben keine Favoriten hinzugefügt.", + "No_favorites_yet" : "Sie haben noch keine Favoriten hinzugefügt.", "No_group_with_name_%s_was_found" : "Es wurde keine private Gruppe mit dem Namen <strong>\"%s\"</strong> gefunden!", "No_groups_yet" : "Sie sind kein Mitglied einer privaten Gruppe.", - "No_permission_to_view_room" : "Sie haben keine Berechtigung diesen Raum zu betreten", + "No_livechats" : "Kein LiveChat vorhanden.", + "No_permission_to_view_room" : "Sie haben keine Berechtigung, diesen Raum zu betreten.", + "No_results_found" : "Keine Ergebnisse gefunden.", + "no_tokens_for_this_user" : "Es liegen keine Token für diesen Benutzer vor.", "No_user_with_username_%s_was_found" : "Es wurde kein Benutzer mit dem Namen <strong>\"%s\"</strong> gefunden!", "Not_allowed" : "Nicht erlaubt", - "Not_found_or_not_allowed" : "Nicht gefunden oder erlaubt", - "Nothing_found" : "Nichts gefunden", - "Notify_all_in_this_room" : "Alle in diesem Raum benachrichtigen", - "Old_and_new_password_required" : "Das alte und neue Passwort müssen angegeben werden um das jetzige Passwort zu ändern.", + "Not_authorized" : "Nicht berechtigt", + "Not_found_or_not_allowed" : "Nicht gefunden oder nicht erlaubt.", + "Nothing_found" : "Es wurde nichts gefunden.", + "Notify_all_in_this_room" : "Alle Benutzer in diesem Raum benachrichtigen", + "OAuth_Application" : "OAuth-Anwendung", + "OAuth_Applications" : "OAuth-Anwendungen", + "Old_and_new_password_required" : "Das alte und neue Passwort muss angegeben werden, um das derzeitige Passwort zu ändern.", "Old_Password" : "Altes Passwort", "Online" : "Online", - "Only_you_can_see_this_message" : "Nur Sie können diese Nachricht sehen", - "Oops!" : "Oops", - "Opt_out_statistics" : "Meine anonymen Statitstiken nicht an Rocke.Chat senden", - "Opt_out_statistics_warning" : "Durch das Absenden Ihrer anonymen Statistiken, werden Sie uns helfen, festzustellen, wie viele Instanzen von Rocket.Chat eingesetzt werden, und wie gut das System verhält, so können wir es weiter verbessern. Wenn Sie weiterhin das Senden von anonymen Statistiken möchten, deaktivieren Sie das Kontrollkästchen oben. Danke.", + "Only_you_can_see_this_message" : "Nur Sie können diese Nachricht sehen.", + "Oops!" : "Hoppla", + "Opt_out_statistics" : "Meine anonymen Statistiken nicht an Rocket.Chat senden", + "Opt_out_statistics_warning" : "Indem Sie uns Ihre anonymen Statistiken zur Verfügung stellen, können wir feststellen, wie viele Personen Rocket.Chat installiert haben und wie gut Rocket.Chat funktioniert. Das hilft uns dabei, Rocket.Chat weiterzuentwickeln. Es werden keine Benutzerinformationen gesendet und die erhaltenen Daten werden vertraulich behandelt. Wenn Sie weiterhin anonyme Statistiken an uns senden möchten, deaktivieren Sie bitte das Kontrollkästchen oben. Vielen Dank.", + "optional" : "optional", "others" : "andere", "Password" : "Passwort", - "Password_Change_Disabled" : "Der Administrator hat das Ändern des Passwortes nicht erlaubt.", - "Password_changed_successfully" : "Passwort erfolgreich geändert", - "People" : "Leute", + "Password_Change_Disabled" : "Der Administrator hat das Ändern des Passworts deaktiviert.", + "Password_changed_successfully" : "Das Passwort wurde erfolgreich geändert.", + "People" : "Menschen", + "Please_enter_value_for_url" : "Bitte geben Sie eine URL für Ihr Profilbild ein.", + "Please_enter_your_new_password_below" : "Bitte geben Sie Ihr neues Passwort ein:", "Please_wait" : "Bitte warten", - "Please_wait_activation" : "Bitte warten. ", - "Please_wait_statistics" : "Bitte warten, Statistiken werden generiert.", + "Please_wait_activation" : "Bitte warten, der Vorgang kann einige Zeit in Anspruch nehmen.", + "Please_wait_statistics" : "Bitte warten, die Statistiken werden erstellt.", + "Post_as" : "Verschicken als", + "Post_to_Channel" : "Im Kanal veröffentlichen", + "Post_to_s_as_s" : "Versenden an <strong>%s</strong> als <strong>%s</strong>", "Powered_by" : "Powered by", "Preferences" : "Einstellungen", - "Preferences_saved" : "Einstellungen gespeichert", + "Preferences_saved" : "Die Einstellungen wurden gespeichert.", "Privacy" : "Datenschutz", "Private_Groups" : "Private Gruppen", - "Private_Groups_list" : "Liste der Private Gruppen", + "Private_Groups_list" : "Liste aller privaten Gruppen", "Profile" : "Profil", - "Profile_saved_successfully" : "Profil erfolgreich gespeichert", - "Proudly_developed" : "Stolz mit Meteor entwickelt", - "Push" : "Push", - "Push_apn_cert" : "APN Cert", - "Push_apn_dev_cert" : "APN Dev Cert", - "Push_apn_dev_key" : "APN Dev Key", - "Push_apn_dev_passphrase" : "APN Dev Passphrase", - "Push_apn_key" : "APN Key", - "Push_apn_passphrase" : "APN Passphrase", + "Profile_saved_successfully" : "Das Profil wurde erfolgreich gespeichert", + "Proudly_developed" : "Stolz mit Meteor entwickelt.", + "Push" : "Push-Nachrichten", + "Push_apn_cert" : "APN-Cert", + "Push_apn_dev_cert" : "APN-Dev-Cert", + "Push_apn_dev_key" : "APN-Dev-Key", + "Push_apn_dev_passphrase" : "APN-Dev-Passphrase", + "Push_apn_key" : "APN-Key", + "Push_apn_passphrase" : "APN-Passphrase", "Push_debug" : "Debuggen", + "push_disabled" : "Push-Nachrichten deaktiviert", "Push_enable" : "Aktivieren", - "Push_gcm_api_key" : "GCM API Key", - "Push_gcm_project_number" : "GCM Projektnummer", + "Push_enable_gateway" : "Gateway aktivieren", + "Push_gateway" : "Gateway", + "Push_gcm_api_key" : "GCM-API-Key", + "Push_gcm_project_number" : "GCM-Projektnummer", "Push_production" : "Produktion", + "Push_test_push" : "Test", "Quick_Search" : "Schnellsuche", "quote" : "Zitat", "Recents" : "Aktuell", "Record" : "Aufnehmen", - "Register" : "Registriere einen neuen Account", - "Registration_Succeeded" : "Registrierung erfolgreich", - "Remember_me" : "Erinnere dich an mich", + "Redirect_URI" : "Weiterleitungs-URL", + "Refresh_your_page_after_install_to_enable_screen_sharing" : "Aktualisieren Sie die Seite nach der Installation, um die Bildschirmübertragung zu aktivieren.", + "Register" : "Registrieren Sie ein neues Konto", + "Registration_Succeeded" : "Ihre Registrierung war erfolgreich.", + "Remember_me" : "Erinnere mich", "Remove" : "Entfernen", "Remove_Admin" : "Admin entfernen", - "Remove_custom_oauth" : "Entferne benutzerdefiniertes oauth", + "Remove_as_moderator" : "Moderatorenrechte entfernen", + "Remove_as_owner" : "als Besitzer entfernen", + "Remove_custom_oauth" : "OAuth-Konto entfernen", + "Remove_from_room" : "Aus dem Raum entfernen", + "Removed" : "Entfernt", + "Reset" : "Zurücksetzen", "Reset_password" : "Passwort zurücksetzen", + "Restart" : "Neustart", + "Restart_the_server" : "Server neustarten", "Room" : "Raum", - "Room_name_changed" : "Raumname geändert zu: <em>__room_name__</em> von <em>__user_by__</em>", - "Room_name_changed_successfully" : "Raumname erfolgreich umbenannt", - "Room_not_found" : "Raum nicht gefunden", - "Room_uploaded_file_list" : "Dateiliste", - "Room_uploaded_file_list_empty" : "Keine Dateien zur Verfügung.", + "Room_archived" : "Der Raum wurde archiviert.", + "Room_has_been_deleted" : "Der Raum wurde gelöscht.", + "Room_name_changed" : "Der Raumname wurde von <em>__user_by__</em> zu <em>__room_name__</em> geändert.", + "Room_name_changed_successfully" : "Der Raumname wurde erfolgreich geändert.", + "Room_not_found" : "Der Raum konnte nicht gefunden werden.", + "Room_unarchived" : "Der Raum wurde wiederhergestellt.", + "Room_uploaded_file_list" : "Dateien", + "Room_uploaded_file_list_empty" : "Es wurden noch keine Dateien hochgeladen.", "room_user_count" : "%s Benutzer", "Rooms" : "Räume", "S_new_messages_since_s" : "%s neue Nachrichten seit %s", "SAML" : "SAML", - "SAML_Custom_Cert" : "Benutzerdefinierte Zertifikat", - "SAML_Custom_Entry_point" : "Individueller Einstiegspunkt", + "SAML_Custom_Cert" : "Benutzerdefiniertes Zertifikat", + "SAML_Custom_Entry_point" : "Einsprungspunkt", "SAML_Custom_Generate_Username" : "Benutzernamen generieren", + "SAML_Custom_Issuer" : "Benutzerdefinierter Aussteller", "SAML_Custom_Provider" : "Benutzerdefinierter Provider", "Save_changes" : "Änderungen speichern", - "Save_Mobile_Bandwidth" : "Mobilfunkbandbreite verringern", + "Save_Mobile_Bandwidth" : "Mobiles Datenvolumen sparen", + "Screen_Share" : "Bildschirmübertragung", "Search" : "Suche", - "Search_Messages" : "Nachrichten suchen", + "Search_Messages" : "Nachrichten durchsuchen", "Search_settings" : "Sucheinstellungen", "seconds" : "Sekunden", "See_all" : "Alle anzeigen", "See_only_online" : "Nur online", - "Select_an_avatar" : "Wählen Sie ein Avatar", + "Select_an_avatar" : "Profilbild auswählen", "Select_file" : "Datei wählen", - "Select_service_to_login" : "Wählen Sie einen Service um sich einzuloggen, ein Bild auszuwählen oder eines direkt von Ihrem Computer hochzuladen", + "Select_service_to_login" : "Wählen Sie einen Dienst zum Anmelden aus, um ein Bild auszuwählen oder ein Bild direkt von Ihrem Computer hochzuladen.", "Selected_users" : "Ausgewählte Mitglieder", - "Send" : "Absenden", - "Send_confirmation_email" : "Bestätigungsmail versendet", - "Send_invitation_email" : "Einladungs E-Mail senden", - "Send_invitation_email_error" : "Sie haben kein gültige E-Mail-Adresse angegeben.", - "Send_invitation_email_info" : "Sie können mehrere E-Mail-Einladungen auf einmal absenden.", - "Send_invitation_email_success" : "Sie haben erfolgreich eine Einladung per E-Mail an folgende Adressen versendet:", - "Send_invitation_email_warning" : "Um Einladungs-E-Mails zu senden, müssen Sie zuerst die SMTP-Einstellungen konfigurieren.", + "Send" : "Senden", + "Send_a_test_mail_to_my_user" : "Eine Test-E-Mail an die Benutzer senden", + "Send_a_test_push_to_my_user" : "Eine Test-Push-Nachricht an die Benutzer senden", + "Send_confirmation_email" : "Bestätigungsmail versenden", + "Send_data_into_RocketChat_in_realtime" : "Daten in Rocket.Chat in Echtzeit senden.", + "Send_invitation_email" : "Einladung per E-Mail senden", + "Send_invitation_email_error" : "Sie haben keine gültige E-Mail-Adresse angegeben.", + "Send_invitation_email_info" : "Sie können mehrere Einladungen per E-Mail gleichzeitig absenden.", + "Send_invitation_email_success" : "Sie haben erfolgreich eine Einladung an folgende E-Mail-Adressen versendet:", + "Send_invitation_email_warning" : "Um Einladungen per E-Mail zu versenden, müssen Sie zuerst die SMTP-Einstellungen konfigurieren.", "Send_Message" : "Nachricht senden", + "Send_your_JSON_payloads_to_this_URL" : "Senden Sie Ihre JSON-Nutzlasten an diese URL.", + "Set_as_moderator" : "Zum Moderator ernennen", + "Set_as_owner" : "zum Besitzer machen", "Settings" : "Einstellungen", - "Settings_updated" : "Einstellungen aktualisiert", + "Settings_updated" : "Die Einstellungen wurden aktualisiert.", + "Should_be_a_URL_of_an_image" : "Dies soll die URL des Bildes sein.", + "Should_exists_a_user_with_this_username" : "Der Benutzer muss bereits vorhanden sein.", + "Showing_archived_results" : "<b>%s</b> archivierte Räume", "Showing_online_users" : "Zeige <b>__total_online__</b> von __total__ users", - "Showing_results" : "<p>Zeige <b>%s</b> Ergebnisse</p>", + "Showing_results" : "<p><b>%s</b> Ergebnisse</p>", "Silence" : "Ruhe", "since_creation" : "seit %s", - "Site_Name" : "Seitenname:", - "Site_Url" : "Website URL", + "Site_Name" : "Seitenname", + "Site_Url" : "Website-URL", "Site_Url_Description" : "Beispiel: https://chat.domain.com/", "SMTP" : "SMTP", - "SMTP_Host" : "SMTP Host", - "SMTP_Password" : "SMTP Passwort", - "SMTP_Port" : "SMTP Port", - "SMTP_Username" : "SMTP Benutzername", - "Sound" : "Sound", + "SMTP_Host" : "SMTP-Host", + "SMTP_Password" : "SMTP-Passwort", + "SMTP_Port" : "SMTP-Port", + "SMTP_Test_Button" : "SMTP-Einstellungen testen", + "SMTP_Username" : "SMTP-Benutzername", + "Sound" : "Ton", + "Start_audio_call" : "Anruf starten", "Start_of_conversation" : "Beginn der Konversation", + "Start_video_call" : "Videoanruf starten", + "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" : "Starten Sie mit <code class=\"inline\">%s</code> für Nutzer oder <code class=\"inline\">%s</code> für Kanäle. Beispiel: <code class=\"inline\">%s</code> oder <code class=\"inline\">%s</code>", "Statistics" : "Statistiken", "Stats_Active_Users" : "Aktive Benutzer", - "Stats_Avg_Channel_Users" : "Durchschnittliche Kanal Benutzer", - "Stats_Avg_Private_Group_Users" : "Durchschnittliche Benutzer in Privater Gruppe", - "Stats_Away_Users" : "Beschäftige Benutzer", - "Stats_Max_Room_Users" : "Maximale Raum Benutzer", - "Stats_Non_Active_Users" : "Ina", + "Stats_Avg_Channel_Users" : "Durchschnittliche Benutzeranzahl pro Kanal", + "Stats_Avg_Private_Group_Users" : "Durchschnittliche Benutzeranzahl in privaten Gruppen", + "Stats_Away_Users" : "Abwesende Benutzer", + "Stats_Max_Room_Users" : "Maximale Benutzeranzahl eines Raums", + "Stats_Non_Active_Users" : "Nicht aktive Benutzer", "Stats_Offline_Users" : "Benutzer offline", "Stats_Online_Users" : "Benutzer online", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS CPU Count", - "Stats_OS_Freemem" : "OS freier Speicher", - "Stats_OS_Loadavg" : "OS Auslastungsdurchschnitt", - "Stats_OS_Platform" : "OS Plattform", - "Stats_OS_Release" : "OS Release", - "Stats_OS_Totalmem" : "OS Gesamtspeicher", - "Stats_OS_Type" : "OS Typ", - "Stats_OS_Uptime" : "OS Uptime", - "Stats_Total_Channels" : "Anzahl Kanäle", - "Stats_Total_Direct_Messages" : "Anzahl der Direktnachrichtenräume", - "Stats_Total_Messages" : "Anzahl der Nachrichten", - "Stats_Total_Private_Groups" : "Anzahl der Privaten Gruppen", + "Stats_OS_Arch" : "Systemtyp", + "Stats_OS_Cpus" : "CPU-Zähler", + "Stats_OS_Freemem" : "Freier Speicherplatz", + "Stats_OS_Loadavg" : "Durchschnittliche Systemauslastung (\"Load\")", + "Stats_OS_Platform" : "Plattform", + "Stats_OS_Release" : "Version", + "Stats_OS_Totalmem" : "Gesamtspeicherplatz", + "Stats_OS_Type" : "Betriebssystem", + "Stats_OS_Uptime" : "Systemverfügbarkeit", + "Stats_Total_Channels" : "Anzahl der Kanäle", + "Stats_Total_Direct_Messages" : "Anzahl der privaten Nachrichtenräume", + "Stats_Total_Messages" : "Anzahl aller Nachrichten", + "Stats_Total_Private_Groups" : "Anzahl der privaten Gruppen", "Stats_Total_Rooms" : "Anzahl der Räume", "Stats_Total_Users" : "Anzahl der Benutzer", "Stop_Recording" : "Aufnahme stoppen", "strike" : "durchgestrichen", "Submit" : "Abschicken", + "Success" : "Dieser Vorgang war erfolgreich.", + "The_application_name_is_required" : "Es muss ein Name für diese Anwendung angegeben werden.", + "The_channel_name_is_required" : "Ein Name für den Kanal muss angegeben werden.", "The_field_is_required" : "Das Feld %s ist erforderlich.", - "True" : "Wahr", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "Die automatische Skalierung der Bilder funktioniert nicht, da ImageMagick oder GraphicsMagick nicht auf dem Server installiert sind.", + "The_redirectUri_is_required" : "Es muss eine Weiterleitung-URL angegeben werden.", + "The_server_will_restart_in_s_seconds" : "Der Server wird in %s Sekunden neu gestartet", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "Die Einstellung <strong>%s</strong> wurde zu <strong>%s</strong> konfiguriert und Sie greifen von <strong>%s</strong> zu!", + "The_user_will_be_removed_from_s" : "Der Benutzer wird von %s entfernt.", + "The_user_wont_be_able_to_type_in_s" : "Der Benutzer kann nicht mehr in %s schreiben.", + "There_are_no_integrations" : "Es sind keine Integrationen vorhanden.", + "This_is_a_push_test_messsage" : "Dies ist eine Test-Push-Nachricht.", + "True" : "Ja", + "Type_your_new_password" : "Geben Sie Ihr neues Passwort ein", + "Unarchive" : "Wiederherstellen", + "Unmute_user" : "Benutzern das Chatten erlauben ", "Unnamed" : "Unbenannt", - "Upload_file_question" : "Datei hochladen?", - "Use_Emojis" : "Verwende Emojis", - "Use_initials_avatar" : "Benutze deine Initialien", - "use_menu" : "Benutze das Seitenmenü um deine Chats zu öffnen", - "Use_service_avatar" : "Benutze %s avatar", + "Unread_Rooms" : "Ungelesene Räume", + "Unread_Rooms_Mode" : "Ungelesene Räume aufgelistet anzeigen ", + "Upload_file_question" : "Möchten Sie eine Datei hochladen?", + "Uploading_file" : "Datei wird hochgeladen...", + "Use_Emojis" : "Emojis verwenden", + "Use_initials_avatar" : "Anfangsbuchstaben deines Nutzernamens verwenden", + "use_menu" : "Benutze das Seitenmenü, um deine Chats zu öffnen.", + "Use_service_avatar" : "Benutze %s Profilbild", "Use_this_username" : "Benutzen Sie folgenden Benutzernamen", - "Use_uploaded_avatar" : "Benutze diesen Avatar", - "User_added_by" : "Benutzer <em>__user_added__</em> hinzugefügt von <em>__user_by__</em>.", - "User_Channels" : "Benutzer Kanäle", - "User_has_been_activated" : "Benutzer wurde aktiviert", - "User_has_been_deactivated" : "Benutzer wurde deaktiviert", - "User_has_been_deleted" : "Benutzer wurde gelöscht", - "User_Info" : "Benutzer-Info", - "User_is_no_longer_an_admin" : "Der Benutzer ist kein Admin mehr", - "User_is_not_activated" : "Benutzer ist nicht aktiviert", - "User_is_now_an_admin" : "Benutzer ist jetzt ein Admin", + "Use_uploaded_avatar" : "Das hochgeladene Profilbild verwenden", + "Use_url_for_avatar" : "URL für Profilbild verwenden", + "User__username__is_now_a_moderator_of__room_name_" : "Der Benuzer __username__ ist jetzt ein Moderator des Raums __room_name__.", + "User__username__is_now_a_owner_of__room_name_" : "Benutzer __username__ ist jetzt ein Besitzer von __room_name__", + "User__username__removed_from__room_name__moderators" : "Der Benutzer __username__ wurde von einem Moderator aus __room_name__ entfernt.", + "User__username__removed_from__room_name__owners" : "Benutzer __username__ wurde als Besitzer von __room_name__ entfernt.", + "User__username__was_added_as_a_moderator_by__user_by_" : "Der Benuzer <em>__username__</em> wurde von <em>__user_by__</em> als Moderator hinzugefügt.", + "User__username__was_added_as_a_owner_by__user_by_" : "Benutzer <em>__username__</em> wurde von <em>__user_by__</em> als Besitzer hinzugefügt.", + "User__username__was_removed_as_a_moderator_by__user_by_" : "Dem Benutzer <em>__username__</em> wurden die Moderatorenrechte von <em>__user_by__</em> entfernt.", + "User__username__was_removed_as_a_owner_by__user_by_" : "Benutzer <em>__username__</em> wurde von <em>__user_by__</em> als Besitzer entfernt.", + "User_added_by" : "Der Benutzer <em>__user_added__</em> wurde von <em>__user_by__</em> hinzugefügt.", + "User_Channels" : "Benutzerkanäle", + "User_has_been_activated" : "Der Benutzer wurde aktiviert.", + "User_has_been_deactivated" : "Der Benutzer wurde deaktiviert.", + "User_has_been_deleted" : "Der Benutzer wurde gelöscht.", + "User_has_been_muted_in_s" : "Dem Nutzer wurde das Schreiben in %s verboten.", + "User_has_been_removed_from_s" : "Der Benutzer wurde von %s entfernt.", + "User_Info" : "Benutzerinformationen", + "User_is_no_longer_an_admin" : "Der Benutzer ist kein Admin mehr.", + "User_is_not_activated" : "Der Benutzer ist nicht aktiviert.", + "User_is_now_an_admin" : "Der Benutzer ist jetzt ein Admin.", "User_joined_channel" : "Ist dem Kanal beigetreten.", "User_joined_channel_female" : "Ist dem Kanal beigetreten.", "User_joined_channel_male" : "Ist dem Kanal beigetreten.", - "User_left" : "Benutzer <em>__user_left__</em> ist gegangen.", - "User_left_female" : "Benutzer <em>__user_left__</em> ist gegangen.", - "User_left_male" : "Benutzer <em>__user_left__</em> ist gegangen.", - "User_logged_out" : "Benutzer ausgeloggt", - "User_not_found_or_incorrect_password" : "Benutzer nicht gefunden oder falsches Passwort", - "User_removed_by" : "Benutzer <em>__user_removed__</em> entfernt von <em>__user_by__</em>.", + "User_left" : "Der Benutzer <em>__user_left__</em> hat den Kanal verlassen.", + "User_left_female" : "Der Benutzer <em>__user_left__</em> hat den Kanal verlassen.", + "User_left_male" : "Der Benutzer <em>__user_left__</em> hat den Kanal verlassen.", + "User_logged_out" : "Der Benutzer wurde abgemeldet.", + "User_muted_by" : "Dem Benutzer <em>__user_muted__</em> wurde das Chatten von <em>__user_by__</em> verboten.", + "User_muted_in_room" : "Dem Benutzer wurde das Chatten verboten.", + "User_not_found_or_incorrect_password" : "Entweder konnte der Benutzer nicht gefunden werden oder Sie haben ein falsches Passwort angegeben.", + "User_or_channel_name" : "Benutzer- oder Kanalname", + "User_removed_by" : "Der Benutzer <em>__user_removed__</em> wurde von <em>__user_by__</em> entfernt.", + "User_removed_from_room" : "Der Benutzer wurde aus dem Raum entfernt.", "User_Settings" : "Benutzereinstellungen", - "User_updated_successfully" : "Benutzer erfolgreich aktualisiert", + "User_unmuted_by" : "Dem Benutzer <em>__user_unmuted__</em> wurde das Chatten von <em>__user_by__</em> wieder erlaubt. ", + "User_unmuted_in_room" : "Dem Benutzer wurde das Chatten wieder erlaubt.", + "User_updated_successfully" : "Der Benutzer wurde erfolgreich aktualisiert.", "Username" : "Benutzername", - "Username_cant_be_empty" : "Der Benutzername darf nicht leer sein", - "Username_Change_Disabled" : "Der Administrator hat das Ändern des Benutzernamens nicht erlaubt", - "Username_description" : "Der Benutzername wird dazu benutzt Sie in Nachtichten zu markieren.", - "Username_invalid" : "<strong>%s</strong> ist kein zulässiger Username.<br/> Benutze nur Buchstaben, Nummern, Punkte oder Bindestriche.", + "Username_cant_be_empty" : "Sie müssen einen Benutzernamen angeben.", + "Username_Change_Disabled" : "Der Administrator hat das Ändern von Benutzernamen deaktiviert.", + "Username_description" : "Der Benutzername wird dazu benutzt, Sie in Nachtichten zu erwähnen.", + "Username_invalid" : "<strong>%s</strong> ist kein zulässiger Benutzername.<br/> Benutzen Sie nur Buchstaben, Nummern, Punkte oder Bindestriche.", "Username_title" : "Benutzernamen festlegen", - "Username_unavaliable" : "<strong>%s</strong> wird schon verwendet :(", + "Username_unavaliable" : "<strong>%s</strong> wird leider schon verwendet. ", "Users" : "Benutzer", + "UTF8_Names_Slugify" : "UTF8-Namen-Slugify", + "UTF8_Names_Validation" : "UTF8-Namen-Verifizierung", + "UTF8_Names_Validation_Description" : "Erlauben Sie keine Sonderzeichen und Leerzeichen. Sie können - _ und . verwenden, aber nicht am Ende eines Namens.", "View_All" : "Alle ansehen", - "Wait_activation_warning" : "Bevor Sie sich einloggen können, muss das Konto von einem Administrator manuell aktiviert werden.", - "We_have_sent_password_email" : "Wir haben Ihnen eine Anleitung zum Zurücksetzen des Passworts an Ihre Email-Adresse gesendet. Wenn Sie keine Email erhalten haben versuchen Sie es bitte noch einmal.", - "We_have_sent_registration_email" : "Wir haben Ihnen eine Bestätigungs Email gesendet. Wenn Sie keine Email erhalten haben versuchen Sie es bitte noch einmal.", - "Welcome" : "Willkommen <em>%s</em>.", + "Wait_activation_warning" : "Bevor Sie sich anmelden können, muss das Konto von einem Administrator manuell aktiviert werden.", + "We_have_sent_password_email" : "Wir haben Ihnen eine Anleitung zum Zurücksetzen des Passworts an Ihre E-Mail-Adresse gesendet. Wenn Sie keine E-Mail erhalten haben, versuchen Sie es bitte noch einmal.", + "We_have_sent_registration_email" : "Wir haben Ihnen eine Bestätigungsmail gesendet. Wenn Sie keine E-Mail erhalten haben, versuchen Sie es bitte noch einmal.", + "Welcome" : "Willkommen, <em>%s</em>.", "Welcome_to_the" : "Willkommen bei", + "will_be_able_to" : "wird in der Lage sein,", "With_whom" : "Mit wem?", - "Yes_clear_all" : "Ja, alles!", - "Yes_delete_it" : "Ja, löschen!", - "you_are_in_preview_mode_of" : "Sie sind im Vorschau-Modus des Kanals #<strong>__room_name__</strong>", - "You_need_confirm_email" : "Sie müssen Ihre Email bestätigen!", - "You_will_not_be_able_to_recover" : "Sie können es nicht wieder rückgängig machen!", + "Yes" : "Ja", + "Yes_clear_all" : "Ja!", + "Yes_delete_it" : "Ja!", + "Yes_mute_user" : "Ja, Benutzer stumm schalten!\n", + "Yes_remove_user" : "Ja, Nutzer entfernen!", + "you_are_in_preview_mode_of" : "Sie befinden sich im Vorschaumodus des Kanals #<strong>__room_name__</strong>.", + "You_are_logged_in_as" : "Sie sind angemeldet als", + "You_can_change_a_different_avatar_too" : "Sie können das aktuell verwendete Profilbild überschreiben, um von dieser Integration zu veröffentlichen.", + "You_can_use_an_emoji_as_avatar" : "Sie können auch einen Emoji als Profilbild verwenden.", + "You_have_been_muted" : "Ihnen wurde das Chatten in diesem Raum verboten. ", + "You_need_confirm_email" : "Sie müssen Ihre E-Mail-Adresse bestätigen!", + "You_need_install_an_extension_to_allow_screen_sharing" : "Sie müssen eine Erweiterung installieren, um eine Bildschirmübertragung zu starten.", + "You_should_name_it_to_easily_manage_your_integrations" : "Zur einfachen Verwaltung der Integrationen empfehlen wir, der Integration einen Namen zuzuordnen.", + "You_will_not_be_able_to_recover" : "Die Nachricht kann anschließend nicht wiederhergestellt werden.", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", - "Your_Open_Source_solution" : "Deine eigene Open Source Chat Lösung" + "Your_mail_was_sent_to_s" : "Ihre E-Mail wurde an %s gesendet.", + "Your_Open_Source_solution" : "Deine eigene Open-Source-Chat-Lösung.", + "Your_push_was_sent_to_s_devices" : "Die Push-Nachricht wurde an %s Geräte gesendet." } \ No newline at end of file diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 56d73d095a80146eeabbbeed3154170abb4b22d6..7514464264779d7f643f02742bc3f8f6cfaf4153 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -2,6 +2,7 @@ "Access_not_authorized" : "Access not authorized", "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", + "Access_Token_URL" : "Access Token URL", "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Allowed Domains List", "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains", @@ -26,6 +27,7 @@ "Accounts_OAuth_Custom_Enable" : "Enable", "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Login_Style" : "Login Style", "Accounts_OAuth_Custom_Secret" : "Secret", "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_URL" : "URL", @@ -61,11 +63,13 @@ "Accounts_RegistrationForm_SecretURL_Description" : "You must provide a random string that will be added to your registration URL. Example: https://demo.rocket.chat/register/[secret_hash]", "Accounts_RegistrationRequired" : "Registration Required", "Accounts_RequireNameForSignUp" : "Require Name For Signup", + "Accounts_ShowFormLogin" : "Show form-based Login", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", "Add_users" : "Add users", "Administration" : "Administration", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "After OAuth2 authentication, users will be redirected to this URL", "Alias" : "Alias", "All_channels" : "All channels", "Allow_Invalid_SelfSigned_Certs" : "Allow Invalid Self-Signed Certs", @@ -76,9 +80,15 @@ "API_Embed" : "Embed", "API_EmbedDisabledFor" : "Disable Embed for Users", "API_EmbedDisabledFor_Description" : "Comma-separated list of usernames", + "Application_added" : "Application added", + "Application_Name" : "Application Name", + "Application_updated" : "Application updated", + "Archive" : "Archive", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", + "Authorization_URL" : "Authorization URL", + "Authorize" : "Authorize", "Auto_Load_Images" : "Auto Load Images", "Avatar_changed_successfully" : "Avatar changed successfully", "Avatar_URL" : "Avatar URL", @@ -89,6 +99,7 @@ "Away_female" : "Away", "away_male" : "away", "Away_male" : "Away", + "Back_to_applications" : "Back to applications", "Back_to_integrations" : "Back to integrations", "Back_to_login" : "Back to login", "bold" : "bold", @@ -108,6 +119,8 @@ "Choose_the_alias_that_will_appear_before_the_username_in_messages" : "Choose the alias that will appear before the username in messages.", "Choose_the_username_that_this_integration_will_post_as" : "Choose the username that this integration will post as.", "Clear_all_unreads_question" : "Clear all unreads?", + "Client_ID" : "Client ID", + "Client_Secret" : "Client Secret", "close" : "close", "coming_soon" : "coming soon", "Commands" : "Commands", @@ -137,7 +150,10 @@ "Disable_Favorite_Rooms" : "Disable Favorites", "Disable_New_Message_Notification" : "Disable New Message Notification", "Disable_New_Room_Notification" : "Disable New Room Notification", + "Do_you_want_to_change_to_s_question" : "Do you want to change to <strong>%s</strong>?", "Drop_to_upload_file" : "Drop to upload file", + "Duplicate_archived_channel_name" : "An archived Channel with name '%s' exists", + "Duplicate_archived_private_group_name" : "An archived Private Group with name '%s' exists", "Duplicate_channel_name" : "A Channel with name '%s' exists", "Duplicate_private_group_name" : "A Private Group with name '%s' exists", "E-mail" : "E-mail", @@ -153,15 +169,20 @@ "Error_changing_password" : "Error changing password", "Error_too_many_requests" : "Error, too many requests. Please slow down. You must wait %s seconds before trying again", "Esc_to" : "Esc to", + "Example_s" : "Example: <code class=\"inline\">%s</code>", "False" : "False", "Favorites" : "Favorites", "FileUpload" : "File Upload", "FileUpload_Enabled" : "File Uploads Enabled", + "FileUpload_File_Empty" : "File empty", "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", "FileUpload_MediaType_NotAccepted" : "Media Types Not Accepted", "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", + "FileUpload_ProtectFiles" : "Protect uploaded files", + "FileUpload_ProtectFilesDescription" : "Only authenticated users will have access", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", + "Force_SSL" : "Force SSL", "Forgot_password" : "Forgot your password", "Fork_it_on_github" : "Fork it on github", "From_Email" : "From Email", @@ -169,6 +190,7 @@ "Get_to_know_the_team" : "Get to know the Rocket.Team", "github_no_public_email" : "You don't have any email as public email in your GitHub account", "Give_a_unique_name_for_the_custom_oauth" : "Give a unique name for the custom oauth", + "Give_the_application_a_name_This_will_be_seen_by_your_users" : "Give the application a name. This will be seen by your users.", "Has_more" : "Has more", "Have_your_own_chat" : "Have your own web chat. Developed with Meteor.com, the Rocket.Chat is a great solution for developers looking forward to build and evolve their own chat platform.", "Hide_room" : "Hide room", @@ -181,8 +203,10 @@ "Install_FxOs_done" : "Great! You can now use Rocket.Chat via the icon on your homescreen. Have fun with Rocket.Chat!", "Install_FxOs_error" : "Sorry, that did not work as intended! The following error appeared:", "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", + "Integration_added" : "Integration has been added", "Integration_Incoming_WebHook" : "Incoming WebHook Integration", "Integration_New" : "New Integration", + "Integration_updated" : "Integration has been updated", "Integrations" : "Integrations", "Invalid_asset" : "Invalid asset", "Invalid_confirm_pass" : "The password confirmation does not match password", @@ -193,6 +217,7 @@ "Invalid_name" : "The name must not be empty", "Invalid_pass" : "The password must not be empty", "Invalid_room_name" : "<strong>%s</strong> is not a valid room name,<br/> use only letters, numbers and dashes", + "Invalid_room_type" : "<strong>%s</strong> is not a valid room type.", "Invalid_Secret_URL" : "Invalid Secret URL", "Invalid_secret_URL_message" : "The URL provided is invalid.", "invisible" : "invisible", @@ -208,7 +233,12 @@ "is_typing_male" : "is typing", "italics" : "italics", "join" : "Join", + "Join_audio_call" : "Join audio call", "Join_the_Community" : "Join the Community", + "Join_video_call" : "Join video call", + "Jump_to_first_unread" : "Jump to first unread", + "Jump_to_message" : "Jump to message", + "Jump_to_recent_messages" : "Jump to recent messages", "Language" : "Language", "Language_Version" : "English Version", "Last_login" : "Last login", @@ -225,6 +255,7 @@ "LDAP" : "LDAP", "LDAP_Bind_Search" : "Bind Search", "LDAP_Bind_Search_Description" : "A piece of JSON that governs bind and connection info and is of the form {\"filter\": \"(&(objectCategory=person)(objectclass=user)(memberOf=CN=ROCKET_ACCESS,CN=Users,DC=domain,DC=com)(sAMAccountName=#{username}))\", \"scope\": \"sub\", \"userDN\": \"rocket.service@domain.com\", \"password\": \"urpass\"}", + "LDAP_CA_Cert" : "CA Cert", "LDAP_Description" : "LDAP is a hierarchical database that many companies use to provide single sign on - a facility for sharing one password between multiple sites and services. For advanced configuration information and examples, please consult our wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", "LDAP_DN" : "Distinguished Name (DN)", "LDAP_DN_Description" : "Search root; example: dc=domain,dc=com", @@ -232,10 +263,12 @@ "LDAP_Enable_Description" : "Attempt to utilize LDAP for authentication.", "LDAP_Port" : "LDAP Port", "LDAP_Port_Description" : "Port to access LDAP on; eg: 389", + "LDAP_Reject_Unauthorized" : "Reject Unauthorized", "LDAP_Sync_User_Data" : "Sync Data", "LDAP_Sync_User_Data_Description" : "Keep user data in sync with server on login (eg: name, email).", "LDAP_Sync_User_Data_FieldMap" : "User Data Field Map", "LDAP_Sync_User_Data_FieldMap_Description" : "Configure how user account fields (like email) are populated from a record in LDAP (once found). As an example, {\"cn\":\"name\", \"mail\":\"email\"} will choose a person's human readable name from the cn attribute, and their email from the mail attribute. Available fields include name, and email.", + "LDAP_TLS" : "TLS", "LDAP_Url" : "LDAP URL", "LDAP_Url_Description" : "URL of the LDAP server; example: ldap://company.dns.com", "Leave_room" : "Leave room", @@ -244,10 +277,12 @@ "Loading..." : "Loading...", "Loading_more_from_history" : "Loading more from history", "Loading_suggestion" : "Loading suggestions...", + "Logged_out_of_other_clients_successfully" : "Logged out of other clients successfully", "Login" : "Login", "Login_with" : "Login with %s", "login_with" : "Or login directly with", "Logout" : "Logout", + "Logout_Others" : "Logout From Other Logged In Locations", "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", "Markdown_Headers" : "Markdown Headers", @@ -264,6 +299,8 @@ "Message_deleting_not_allowed" : "Message deleting not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", "Message_editing_not_allowed" : "Message editing not allowed", + "Message_GroupingPeriod" : "Grouping Period (in seconds)", + "Message_GroupingPeriodDescription" : "Messages will be grouped with previous message if both are from the same user and the elapsed time was less than the informed time in seconds.", "Message_KeepHistory" : "Keep Message History", "Message_MaxAllowedSize" : "Maximum Allowed Message Size", "Message_pinned" : "Message pinned", @@ -286,11 +323,14 @@ "More_unreads" : "More unreads", "Msgs" : "Msgs", "multi" : "multi", + "Mute_user" : "Mute user", + "Muted" : "Muted", "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", "Name_cant_be_empty" : "Name can't be empty", "Name_optional" : "Name (optional)", + "New_Application" : "New Application", "New_integration" : "New integration", "New_messages" : "New messages", "New_password" : "New password", @@ -302,6 +342,7 @@ "No_groups_yet" : "You have no private groups yet.", "No_livechats" : "You have no livechats.", "No_permission_to_view_room" : "You don't have permission to view this room", + "No_results_found" : "No results found", "no_tokens_for_this_user" : "There are no tokens for this user", "No_user_with_username_%s_was_found" : "No user with username <strong>\"%s\"</strong> was found!", "Not_allowed" : "Not allowed", @@ -309,6 +350,8 @@ "Not_found_or_not_allowed" : "Not Found or Not Allowed", "Nothing_found" : "Nothing found", "Notify_all_in_this_room" : "Notify all in this room", + "OAuth_Application" : "OAuth Application", + "OAuth_Applications" : "OAuth Applications", "Old_and_new_password_required" : "You need to provide both old and new password for changing your password.", "Old_Password" : "Old Password", "Online" : "Online", @@ -323,6 +366,7 @@ "Password_changed_successfully" : "Password changed successfully", "People" : "People", "Please_enter_value_for_url" : "Please enter a value for the url of your avatar.", + "Please_enter_your_new_password_below" : "Please enter your new password below:", "Please_wait" : "Please wait", "Please_wait_activation" : "Please wait, this can take some time.", "Please_wait_statistics" : "Please wait, statistics are being generated.", @@ -358,20 +402,29 @@ "quote" : "quote", "Recents" : "Recents", "Record" : "Record", + "Redirect_URI" : "Redirect URI", "Refresh_your_page_after_install_to_enable_screen_sharing" : "Refresh your page after install to enable screen sharing", "Register" : "Register a new account", "Registration_Succeeded" : "Registration Succeeded", "Remember_me" : "Remember me", "Remove" : "Remove", "Remove_Admin" : "Remove Admin", + "Remove_as_moderator" : "Remove as moderator", + "Remove_as_owner" : "Remove as owner", "Remove_custom_oauth" : "Remove custom oauth", + "Remove_from_room" : "Remove from room", + "Removed" : "Removed", + "Reset" : "Reset", "Reset_password" : "Reset password", "Restart" : "Restart", "Restart_the_server" : "Restart the server", "Room" : "Room", + "Room_archived" : "Room archived", + "Room_has_been_deleted" : "Room has been deleted", "Room_name_changed" : "Room name changed to: <em>__room_name__</em> by <em>__user_by__</em>", "Room_name_changed_successfully" : "Room name changed successfully", "Room_not_found" : "Room not found", + "Room_unarchived" : "Room unarchived", "Room_uploaded_file_list" : "Files List", "Room_uploaded_file_list_empty" : "No files available.", "room_user_count" : "%s users", @@ -397,6 +450,7 @@ "Select_service_to_login" : "Select a service to login to load your picture or upload one directly from your computer", "Selected_users" : "Selected members", "Send" : "Send", + "Send_a_test_mail_to_my_user" : "Send a test mail to my user", "Send_a_test_push_to_my_user" : "Send a test push to my user", "Send_confirmation_email" : "Send confirmation email", "Send_data_into_RocketChat_in_realtime" : "Send data into Rocket.Chat in real-time.", @@ -407,10 +461,13 @@ "Send_invitation_email_warning" : "In order to send invitation e-mails, you must first configure SMTP settings.", "Send_Message" : "Send Message", "Send_your_JSON_payloads_to_this_URL" : "Send your JSON payloads to this URL.", + "Set_as_moderator" : "Set as moderator", + "Set_as_owner" : "Set as owner", "Settings" : "Settings", "Settings_updated" : "Settings updated", "Should_be_a_URL_of_an_image" : "Should be a URL of an image.", - "Should_exists_a_user_with_this_username" : "Should exists a user with this username.", + "Should_exists_a_user_with_this_username" : "The user must already exist.", + "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", "Showing_online_users" : "Showing <b>__total_online__</b> of __total__ users", "Showing_results" : "<p>Showing <b>%s</b> results</p>", "Silence" : "Silence", @@ -422,9 +479,12 @@ "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP Password", "SMTP_Port" : "SMTP Port", + "SMTP_Test_Button" : "Test SMTP Settings", "SMTP_Username" : "SMTP Username", "Sound" : "Sound", + "Start_audio_call" : "Start audio call", "Start_of_conversation" : "Start of conversation", + "Start_video_call" : "Start video call", "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" : "Start with <code class=\"inline\">%s</code> for user or <code class=\"inline\">%s</code> for channel. Eg: <code class=\"inline\">%s</code> or <code class=\"inline\">%s</code>", "Statistics" : "Statistics", "Stats_Active_Users" : "Active Users", @@ -454,12 +514,21 @@ "strike" : "strike", "Submit" : "Submit", "Success" : "Success", - "The_configured_URL_is_different_from_the_URL_you_are_accessing" : "The configured URL is different from the URL you are accessing!", + "The_application_name_is_required" : "Th _application name is required", + "The_channel_name_is_required" : "The channel name is required", "The_field_is_required" : "The field %s is required.", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "The image resize will not work because we can not detect ImageMagick or GraphicsMagick installed on your server.", + "The_redirectUri_is_required" : "The redirectUri is required", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", - "There_is_no_integrations" : "There is no integrations", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "The setting <strong>%s</strong> is configured to <strong>%s</strong> and you are accessing from <strong>%s</strong>!", + "The_user_will_be_removed_from_s" : "The user will be removed from %s", + "The_user_wont_be_able_to_type_in_s" : "The user won't be able to type in %s", + "There_are_no_integrations" : "There are no integrations", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", + "Type_your_new_password" : "Type your new password", + "Unarchive" : "Unarchive", + "Unmute_user" : "Unmute user", "Unnamed" : "Unnamed", "Unread_Rooms" : "Unread Rooms", "Unread_Rooms_Mode" : "Unread Rooms Mode", @@ -472,11 +541,21 @@ "Use_this_username" : "Use this username", "Use_uploaded_avatar" : "Use uploaded avatar", "Use_url_for_avatar" : "Use url for avatar", + "User__username__is_now_a_moderator_of__room_name_" : "User __username__ is now a moderator of __room_name__", + "User__username__is_now_a_owner_of__room_name_" : "User __username__ is now a owner of __room_name__", + "User__username__removed_from__room_name__moderators" : "User __username__ removed from __room_name__ moderators", + "User__username__removed_from__room_name__owners" : "User __username__ removed from __room_name__ owners", + "User__username__was_added_as_a_moderator_by__user_by_" : "User <em>__username__</em> was added as a moderator by <em>__user_by__</em>", + "User__username__was_added_as_a_owner_by__user_by_" : "User <em>__username__</em> was added as a owner by <em>__user_by__</em>", + "User__username__was_removed_as_a_moderator_by__user_by_" : "User <em>__username__</em> was removed as a moderator by <em>__user_by__</em>", + "User__username__was_removed_as_a_owner_by__user_by_" : "User <em>__username__</em> was removed as a owner by <em>__user_by__</em>", "User_added_by" : "User <em>__user_added__</em> added by <em>__user_by__</em>.", "User_Channels" : "User Channels", "User_has_been_activated" : "User has been activated", "User_has_been_deactivated" : "User has been deactivated", "User_has_been_deleted" : "User has been deleted", + "User_has_been_muted_in_s" : "User has been muted in %s", + "User_has_been_removed_from_s" : "User has been removed from %s", "User_Info" : "User Info", "User_is_no_longer_an_admin" : "User is no longer an admin", "User_is_not_activated" : "User is not activated", @@ -488,10 +567,15 @@ "User_left_female" : "Has left the channel.", "User_left_male" : "Has left the channel.", "User_logged_out" : "User is logged out", + "User_muted_by" : "User <em>__user_muted__</em> muted by <em>__user_by__</em>.", + "User_muted_in_room" : "User muted in room", "User_not_found_or_incorrect_password" : "User not found or incorrect password", "User_or_channel_name" : "User or channel name", "User_removed_by" : "User <em>__user_removed__</em> removed by <em>__user_by__</em>.", + "User_removed_from_room" : "The user has been removed from the room", "User_Settings" : "User Settings", + "User_unmuted_by" : "User <em>__user_unmuted__</em> unmuted by <em>__user_by__</em>.", + "User_unmuted_in_room" : "User unmuted in room", "User_updated_successfully" : "User updated successfully", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", @@ -510,17 +594,24 @@ "We_have_sent_registration_email" : "We have sent you an e-mail to confirm your registration. If you do not receive an e-mail shortly, please come back and try again.", "Welcome" : "Welcome <em>%s</em>.", "Welcome_to_the" : "Welcome to the", + "will_be_able_to" : "will be able to", "With_whom" : "With whom", "Yes" : "Yes", "Yes_clear_all" : "Yes, clear all!", "Yes_delete_it" : "Yes, delete it!", + "Yes_mute_user" : "Yes, mute user!", + "Yes_remove_user" : "Yes, remove user!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", - "You_can_change_a_different_avatar_too" : "You can change a different avatar too", + "You_are_logged_in_as" : "You are logged in as", + "You_can_change_a_different_avatar_too" : "You can override the avatar used to post from this integration.", + "You_can_use_an_emoji_as_avatar" : "You can also use an emoji as an avatar.", + "You_have_been_muted" : "You have been muted and cannot speak in this room", "You_need_confirm_email" : "You need to confirm your email to login!", "You_need_install_an_extension_to_allow_screen_sharing" : "You need install an extension to allow screen sharing", "You_should_name_it_to_easily_manage_your_integrations" : "You should name it to easily manage your integrations.", "You_will_not_be_able_to_recover" : "You will not be able to recover this message!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", + "Your_mail_was_sent_to_s" : "Your mail was sent to %s", "Your_Open_Source_solution" : "Your own Open Source chat solution", "Your_push_was_sent_to_s_devices" : "Your push was sent to %s devices" } \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 01f48d5c754a8cc4a658adf85437fb89ffccdad6..83fdccc6647fb7e9146c4512e0fbc8573998d776 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -2,6 +2,7 @@ "Access_not_authorized" : "Pääsy estetty.", "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", + "Access_Token_URL" : "Access Token URL", "Accounts" : "Käyttäjätilit", "Accounts_AllowedDomainsList" : "Pilkkueroteltu lista sallituista domaineista", "Accounts_AllowedDomainsList_Description" : "Pilkuilla eroteltu luettelo sallituista verkkotunnuksia", @@ -17,6 +18,7 @@ "Accounts_EmailVerification" : "Sähköpostiosoitteen varmistaminen", "Accounts_Enrollment_Email" : "Kirjautumissähköposti", "Accounts_Enrollment_Email_Description" : "Voit käyttää [name], [fname], [lname] käyttäjän koko nimen, etunimen tai sukunimen paikalla.<br />Voit käyttää [email] käyttäjän sähköpostin paikalla.", + "Accounts_LoginExpiration" : "Kirjautumisen vanhentumisaika (päiviä)", "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", "Accounts_OAuth_Custom_Authorize_Path" : "Auktorisointipolku", "Accounts_OAuth_Custom_Button_Color" : "Painikkeen väri", @@ -25,6 +27,7 @@ "Accounts_OAuth_Custom_Enable" : "Kytke päälle", "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_Identity_Path" : "Identity polku", + "Accounts_OAuth_Custom_Login_Style" : "Kirjautumistyyli", "Accounts_OAuth_Custom_Secret" : "Secret", "Accounts_OAuth_Custom_Token_Path" : "Token polku", "Accounts_OAuth_Custom_URL" : "URL", @@ -60,11 +63,13 @@ "Accounts_RegistrationForm_SecretURL_Description" : "Sinun on annettava satunnainen merkkijono, joka lisätään rekisteröitymis-URLiin. Esimerkiksi: https://chat.example.com/register/[secret_hash]", "Accounts_RegistrationRequired" : "Rekisteröinti vaaditaan", "Accounts_RequireNameForSignUp" : "Vaadi nimi rekisteröityessä", + "Accounts_ShowFormLogin" : "Näytä lomakepohjainen kirjautuminen", "Activate" : "Aktivoi", "Add_custom_oauth" : "Lisää mukautettu oauth", "Add_Members" : "Lisää osallistujia", "Add_users" : "Lisää käyttäjiä", "Administration" : "Ylläpito", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "OAuth2-todennuksen jälkeen käyttäjät ohjataan tähän URL-osoitteeseen", "Alias" : "Alias", "All_channels" : "Kaikki kanavat", "Allow_Invalid_SelfSigned_Certs" : "Salli virheelliset ja itse allekirjoitetut SSL varmenteet linkin validointiin ja esikatseluihin", @@ -75,9 +80,15 @@ "API_Embed" : "Upota", "API_EmbedDisabledFor" : "Poista upotustoiminto käyttäjiltä", "API_EmbedDisabledFor_Description" : "Pilkkueroteltu lista käyttäjätunnuksista", + "Application_added" : "Sovellus lisätty", + "Application_Name" : "Sovelluksen nimi", + "Application_updated" : "Sovellus päivitetty", + "Archive" : "Arkistoi", "are_also_typing" : "kirjoittavat myös", "are_typing" : "kirjoittavat", "Are_you_sure" : "Oletko varma?", + "Authorization_URL" : "Valtuutus URL", + "Authorize" : "Valtuuta", "Auto_Load_Images" : "Lataa kuvat automaattisesti\n", "Avatar_changed_successfully" : "Avatar vaihdettu onnistuneesti", "Avatar_URL" : "Avatarin URL", @@ -88,6 +99,7 @@ "Away_female" : "Poissa", "away_male" : "poissa", "Away_male" : "Poissa", + "Back_to_applications" : "Takaisin sovelluksiin", "Back_to_integrations" : "Takaisin integraatioihin", "Back_to_login" : "Takaisin kirjautumiseen", "bold" : "lihavoitu", @@ -107,6 +119,8 @@ "Choose_the_alias_that_will_appear_before_the_username_in_messages" : "Valitse alias, joka näkyy viesteissä ennen käyttäjätunnustasi", "Choose_the_username_that_this_integration_will_post_as" : "Valitse käyttäjänimi, jolla integraatio postaa keskusteluun", "Clear_all_unreads_question" : "Tyhjennä kaikki lukemattomat?", + "Client_ID" : "Client ID", + "Client_Secret" : "Client Secret", "close" : "sulje", "coming_soon" : "tulossa", "Commands" : "Komennot", @@ -136,7 +150,10 @@ "Disable_Favorite_Rooms" : "Poista Suosikit käytöstä", "Disable_New_Message_Notification" : "Poista uuden viestin ilmoitus käytöstä", "Disable_New_Room_Notification" : "Poista uuden huoneen ilmoitus käytöstä", + "Do_you_want_to_change_to_s_question" : "Haluatko vaihtaa tämän arvoon <strong>%s</strong>?", "Drop_to_upload_file" : "Vedä ja pudota lähettääksesi tiedoston", + "Duplicate_archived_channel_name" : "Arkistoitu kanava nimellä '%s' on olemassa", + "Duplicate_archived_private_group_name" : "Arkistoitu privaattiryhmä '%s%' on olemassa", "Duplicate_channel_name" : "Kanava nimeltä '%s' on olemassa jo", "Duplicate_private_group_name" : "Privaattiryhmä '%s' on olemassa jo", "E-mail" : "Sähköpostiosoite", @@ -152,14 +169,18 @@ "Error_changing_password" : "Virhe vaihtaessa salasanaa", "Error_too_many_requests" : "Virhe, liikaa pyyntöjä. Rauhoitu hieman.\nOdota %s sekuntia ennen uudelleenyritystä.", "Esc_to" : "Poistu", + "Example_s" : "Esimerkiksi: <code class=\"inline\">%s</code>", "False" : "Ei", "Favorites" : "Suosikit", "FileUpload" : "Lähetä tiedosto", "FileUpload_Enabled" : "Tiedostojen lähetykset käytössä", + "FileUpload_File_Empty" : "Tiedosto tyhjä", "FileUpload_MaxFileSize" : "Suurin lähetettävän tiedoston koko (tavuina)", "FileUpload_MediaType_NotAccepted" : "Mediatyyppejä ei hyväksytä", "FileUpload_MediaTypeWhiteList" : "Hyväksytyt mediatyypit", "FileUpload_MediaTypeWhiteListDescription" : "Pilkkueroteltu lista mediatyypeistä", + "FileUpload_ProtectFiles" : "Suojaa ladatut tiedostot", + "FileUpload_ProtectFilesDescription" : "Vain kirjautuneilla käyttäjillä on pääsy tiedostoihin", "Follow_social_profiles" : "Seuraa someamme, forkkaa Githubissa ja jaa ajatuksiasi rocket.chatista trellossa.", "Forgot_password" : "Unohditko salasanasi?", "Fork_it_on_github" : "Forkkaa GitHubissa", @@ -168,6 +189,7 @@ "Get_to_know_the_team" : "Tutustu Rocket.Teamiin", "github_no_public_email" : "GitHub-tunnukseltasi ei löydy julkisia sähköpostiosoitetietoja", "Give_a_unique_name_for_the_custom_oauth" : "Anna yksilöllinen nimi mukautettua oauth varten", + "Give_the_application_a_name_This_will_be_seen_by_your_users" : "Anna sovelluksen nimi. Käyttäjät näkevät tämän.", "Has_more" : "Löytyy lisää", "Have_your_own_chat" : "Have your own web chat. Developed with Meteor.com, the Rocket.Chat is a great solution for developers looking forward to build and evolve their own chat platform.", "Hide_room" : "Piilota kanava", @@ -180,8 +202,10 @@ "Install_FxOs_done" : "Hienoa! Voit käyttää nyt Rocket.Chatiä etusivulla olevan kuvakkeen kautta. Pidä kivaa!", "Install_FxOs_error" : "Pahoittelut, asennus ei onnistunut, seuraava virhe ilmeni:", "Install_FxOs_follow_instructions" : "Vahvista sovelluksen asennus laitteellasi (paina \"Install\" käskettäessä)", + "Integration_added" : "Integraatio lisätty", "Integration_Incoming_WebHook" : "Sisääntuleva WebHook-integraatio", "Integration_New" : "Uusi integraatio", + "Integration_updated" : "Integraatio päivitetty", "Integrations" : "Integraatiot", "Invalid_asset" : "Virheellinen resurssi", "Invalid_confirm_pass" : "Salasanat eivät täsmää", @@ -192,6 +216,7 @@ "Invalid_name" : "Nimi ei voi olla tyhjä", "Invalid_pass" : "Salasana ei voi olla tyhjä", "Invalid_room_name" : "<strong>%s</strong> ei ole hyväksyttävä kanavan nimi,<br/> käytä vain kirjaimia, numeroita ja viivaa", + "Invalid_room_type" : "<strong>%s</strong> ei ole sallittu huoneen tyyppi.", "Invalid_Secret_URL" : "Virheellinen salainen URL", "Invalid_secret_URL_message" : "URL on virheellinen.", "invisible" : "näkymätön", @@ -207,7 +232,12 @@ "is_typing_male" : "kirjoittaa", "italics" : "kursivoitu", "join" : "Liity", + "Join_audio_call" : "Liity äänipuheluun", "Join_the_Community" : "Liity yhteisöön", + "Join_video_call" : "Liity videopuheluun", + "Jump_to_first_unread" : "Siirry ensimmäiseen lukemattomaan", + "Jump_to_message" : "Siirry viestiin", + "Jump_to_recent_messages" : "Siirry viimeisimpiin viestiin", "Language" : "Kieli", "Language_Version" : "Suomi", "Last_login" : "Viimeisin kirjautuminen", @@ -243,10 +273,12 @@ "Loading..." : "Ladataan...", "Loading_more_from_history" : "Ladataan lisää historiasta", "Loading_suggestion" : "Ladataan ehdotuksia...", + "Logged_out_of_other_clients_successfully" : "Muut sessiot kirjattu ulos onnistuneesti", "Login" : "Kirjaudu", "Login_with" : "Kirjaudu käyttäen %s", "login_with" : "tai kirjaudu suoraan", "Logout" : "Kirjaudu ulos", + "Logout_Others" : "Kirjaa ulos muut sessiot", "Make_Admin" : "Tee ylläpitäjäksi", "Mark_as_read" : "Merkitse luetuksi", "Markdown_Headers" : "Markdown otsikot", @@ -263,6 +295,8 @@ "Message_deleting_not_allowed" : "Viestin poisto ei sallittu", "Message_editing_blocked" : "Tätä viestiä ei voi muokata enää.", "Message_editing_not_allowed" : "Viestin muokkaus ei sallittu", + "Message_GroupingPeriod" : "Ryhmittelyaika (sekunneissa)", + "Message_GroupingPeriodDescription" : "Viestit ryhmitellään edellisen viestin kanssa jos molemmat viestit ovat samalta käyttäjältä ja viestien välinen aika on pienempi kuin määritelty aika.", "Message_KeepHistory" : "Säilytä viestihistoria", "Message_MaxAllowedSize" : "Viestin suurin sallittu koko", "Message_pinned" : "Viesti kiinnitetty", @@ -285,11 +319,14 @@ "More_unreads" : "Lisää lukemattomia", "Msgs" : "Viestit", "multi" : "monta", + "Mute_user" : "Mykistä käyttäjä", + "Muted" : "Mykistetty", "My_Account" : "Käyttäjätilini", "n_messages" : "%s viestiä", "Name" : "Nimi", "Name_cant_be_empty" : "Nimi ei voi olla tyhjä", "Name_optional" : "Nimi (valinnainen)", + "New_Application" : "Uusi sovellus", "New_integration" : "Uusi integraatio", "New_messages" : "Uusia viestejä", "New_password" : "Uusi salasana", @@ -301,6 +338,7 @@ "No_groups_yet" : "Sinulla ei ole vielä privaattiryhmiä.", "No_livechats" : "Sinulla ei ole livechatteja.", "No_permission_to_view_room" : "Sinulla ei ole oikeutta katsella tätä", + "No_results_found" : "Ei tuloksia", "no_tokens_for_this_user" : "Valtuutusta käyttäjälle ei löydy", "No_user_with_username_%s_was_found" : "Käyttäjää nimeltä <strong>\"%s\"</strong> ei löytynyt!", "Not_allowed" : "Ei sallittu", @@ -308,6 +346,8 @@ "Not_found_or_not_allowed" : "Ei löydy tai ei sallittu", "Nothing_found" : "Ei löytynyt", "Notify_all_in_this_room" : "Ilmoita kaikille kanavallaolijoille", + "OAuth_Application" : "OAuth sovellus", + "OAuth_Applications" : "OAuth sovellukset", "Old_and_new_password_required" : "Sinun täytyy antaa sekä vanha että uusi salasana, että saat vaihdettua salasanasi.", "Old_Password" : "Vanha salasana", "Online" : "Online", @@ -322,6 +362,7 @@ "Password_changed_successfully" : "Salasana vaihdettu", "People" : "Ihmiset", "Please_enter_value_for_url" : "Anna avatarisi URL", + "Please_enter_your_new_password_below" : "Anna uusi salasana:", "Please_wait" : "Odota hetki", "Please_wait_activation" : "Odota, tämä voi kestää jonkin aikaa.", "Please_wait_statistics" : "Odota, tilastoja generoidaan.", @@ -357,20 +398,29 @@ "quote" : "lainaus", "Recents" : "Viimeisimmät", "Record" : "Nauhoita", + "Redirect_URI" : "Ohjaus URI", "Refresh_your_page_after_install_to_enable_screen_sharing" : "Päivitä sivu asennuksen jälkeen ottaaksesi käyttöön näytön jakamisen", "Register" : "Rekisteröi uusi käyttäjätili", "Registration_Succeeded" : "Rekisteröinti onnistui", "Remember_me" : "Muista minut", "Remove" : "Poista", "Remove_Admin" : "Poista ylläpitäjyys", + "Remove_as_moderator" : "Poista moderaattoristatus", + "Remove_as_owner" : "Poista omistajuus", "Remove_custom_oauth" : "Poista mukautettu oauth", + "Remove_from_room" : "Poista huoneesta", + "Removed" : "Poistettu", + "Reset" : "Nollaa", "Reset_password" : "Nollaa salasana", "Restart" : "Käynnistä uudelleen", "Restart_the_server" : "Käynnistä palvelin uudelleen", "Room" : "Huone", + "Room_archived" : "Huone arkistoitu", + "Room_has_been_deleted" : "Huone poistettu", "Room_name_changed" : "Huoneen nimi vaihdettu <em>__room_name__</em> <em>__user_by__</em> toimesta", "Room_name_changed_successfully" : "Huoneen nimi vaihdettu", "Room_not_found" : "Huonetta ei löytynyt", + "Room_unarchived" : "Huone palautettu arkistosta", "Room_uploaded_file_list" : "Tiedostolista", "Room_uploaded_file_list_empty" : "Tiedostoja ei ole saatavilla.", "room_user_count" : "%s käyttäjää", @@ -396,6 +446,7 @@ "Select_service_to_login" : "Valitse kirjautumiseen käytettävä palvelu tai lataa kuvasi suoraan koneeltasi", "Selected_users" : "Valitut käyttäjät", "Send" : "Lähetä", + "Send_a_test_mail_to_my_user" : "Lähetä testisähköposti käyttäjälle", "Send_a_test_push_to_my_user" : "Lähetä testi-push käyttäjälle", "Send_confirmation_email" : "Lähetä vahvistussähköposti", "Send_data_into_RocketChat_in_realtime" : "Lähetä data Rocket.Chatiin reaaliajassa", @@ -406,10 +457,13 @@ "Send_invitation_email_warning" : "Lähettääksesi sähköpostikutsuja, sinun täytyy ensin tehdä SMTP asetukset.", "Send_Message" : "Lähetä viesti", "Send_your_JSON_payloads_to_this_URL" : "Lähetä JSON payload tähän URL-osoitteeseen", + "Set_as_moderator" : "Aseta moderaattoriksi", + "Set_as_owner" : "Aseta omistajaksi", "Settings" : "Asetukset", "Settings_updated" : "Asetukset päivitetty", "Should_be_a_URL_of_an_image" : "Kuvan URL-osoite", "Should_exists_a_user_with_this_username" : "Käyttäjä tällä käyttäjätunnuksella tulisi olla olemassa", + "Showing_archived_results" : "<p>Näytetään <b>%s</b> arkistoitua tulosta</p>", "Showing_online_users" : "Näytetään <b>__total_online__</b>/__total__ users", "Showing_results" : "<p>Näytetään <b>%s</b> tulosta</p>", "Silence" : "Hiljaisuus", @@ -421,9 +475,12 @@ "SMTP_Host" : "SMTP-palvelin", "SMTP_Password" : "SMTP Salasana", "SMTP_Port" : "SMTP-portti", + "SMTP_Test_Button" : "Testaa SMTP-asetukset", "SMTP_Username" : "SMTP Käyttäjätunnus", "Sound" : "Ääni", + "Start_audio_call" : "Aloita äänipuhelu", "Start_of_conversation" : "Keskustelun alku", + "Start_video_call" : "Aloita videopuhelu", "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" : "Aloita <code class=\"inline\">%s</code> käyttäjänä or <code class=\"inline\">%s</code> kanavana. Esim: <code class=\"inline\">%s</code> tai <code class=\"inline\">%s</code>", "Statistics" : "Tilastot", "Stats_Active_Users" : "Aktiivisia käyttäjiä", @@ -453,12 +510,21 @@ "strike" : "yliviivaa", "Submit" : "Lähetä", "Success" : "Onnistui", - "The_configured_URL_is_different_from_the_URL_you_are_accessing" : "Määritetty URL-osoite on eri kuin nyt käytettävä!", + "The_application_name_is_required" : "Sovelluksen nimi on pakollinen", + "The_channel_name_is_required" : "Kanavan nimi on määriteltävä", "The_field_is_required" : "Kenttä %s vaaditaan.", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "Kuvien koon muuttaminen ei toimi koska ImageMagickia tai GraphicsMagickia ei havaittu asennettuna palvelimelle.", + "The_redirectUri_is_required" : "Ohjaus URI on pakollinen", "The_server_will_restart_in_s_seconds" : "Palvelin käynnistyy %s sekunnin kuluttua", - "There_is_no_integrations" : "Integraatioita ei ole", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "Asetus <strong>%s</strong> on määritelty arvoon <strong>%s</strong> yrität käyttää tätä lähteenä <strong>%s</strong>!", + "The_user_will_be_removed_from_s" : "Käyttäjä poistetaan %s", + "The_user_wont_be_able_to_type_in_s" : "Käyttäjä ei pysty kirjoittamaan %s", + "There_are_no_integrations" : "Ei integraatioita", "This_is_a_push_test_messsage" : "Tämä on testi-pushviesti", "True" : "Kyllä", + "Type_your_new_password" : "Anna uusi salasana", + "Unarchive" : "Palauta arkistosta", + "Unmute_user" : "Poista mykistys käyttäjältä", "Unnamed" : "Nimetön", "Unread_Rooms" : "Lukemattomia", "Unread_Rooms_Mode" : "Lukemattomien tila", @@ -471,11 +537,21 @@ "Use_this_username" : "Käytä tätä käyttäjänimieä", "Use_uploaded_avatar" : "Käytä ladattua avataria", "Use_url_for_avatar" : "Käytä avatar-URLia", + "User__username__is_now_a_moderator_of__room_name_" : "Käyttäjä __username__ on nyt __room_name__ moderaattori", + "User__username__is_now_a_owner_of__room_name_" : "Käyttäjä __username__ on nyt __room_name__ omistaja", + "User__username__removed_from__room_name__moderators" : "Käyttäjän __username__ moderaattoristatus __room_name__  on poistettu", + "User__username__removed_from__room_name__owners" : "Käyttäjä __username__ poistettu __room_name__ omistajista", + "User__username__was_added_as_a_moderator_by__user_by_" : "Käyttäjä <em>__username__</em> on lisätty moderaattoriksi <em>__user_by__</em> toimesta", + "User__username__was_added_as_a_owner_by__user_by_" : "Käyttäjä <em>__username__</em> lisätty <em>__user_by__</em> omistajaksi", + "User__username__was_removed_as_a_moderator_by__user_by_" : "Käyttäjän <em>__username__</em> moderaattoristatus poistettu käyttäjän  <em>__user_by__</em> toimesta", + "User__username__was_removed_as_a_owner_by__user_by_" : "Käyttäjä <em>__username__</em> on poistettu <em>__user_by__</em> omistajista", "User_added_by" : "Käyttäjä <em>__user_added__</em> lisätty <em>__user_by__</em> toimesta.", "User_Channels" : "Käyttäjän kanavat", "User_has_been_activated" : "Käyttäjä on aktivoitu", "User_has_been_deactivated" : "Käyttäjä on deaktivoitu", "User_has_been_deleted" : "Käyttäjä on poistettu", + "User_has_been_muted_in_s" : "Käyttäjä on mykistetty %s", + "User_has_been_removed_from_s" : "Käyttäjä on poistettu %s", "User_Info" : "Käyttäjän tiedot", "User_is_no_longer_an_admin" : "Käyttäjä ei ole enää ylläpitäjä", "User_is_not_activated" : "Käyttäjää ei ole aktivoitu", @@ -487,10 +563,15 @@ "User_left_female" : "Käyttäjä poistui kanavalta.", "User_left_male" : "Käyttäjä poistui kanavalta.", "User_logged_out" : "Käyttäjä on kirjautunut ulos", + "User_muted_by" : "Käyttäjä <em>__user_muted__</em> mykistetty <em>__user_by__</em> toimesta.", + "User_muted_in_room" : "Käyttäjä mykistetty huoneessa", "User_not_found_or_incorrect_password" : "Käyttäjää ei löydy tai väärä salasana", "User_or_channel_name" : "Käyttäjän tai kanavan nimi", "User_removed_by" : "Käyttäjä <em>__user_removed__</em> poistettu <em>__user_by__</em> toimesta.", + "User_removed_from_room" : "Käyttäjä on poistettu huoneesta", "User_Settings" : "Käyttäjän asetukset", + "User_unmuted_by" : "Käyttäjän <em>__user_unmuted__</em> mykistys poistettu <em>__user_by__</em> toimesta.", + "User_unmuted_in_room" : "Käyttäjän mykistys poistettu huoneessa", "User_updated_successfully" : "Käyttäjän tiedot päivitetty", "Username" : "Käyttäjänimi", "Username_cant_be_empty" : "Käyttäjänimi ei voi olla tyhjä", @@ -509,17 +590,24 @@ "We_have_sent_registration_email" : "Lähetimme rekisteröitymisvahvistuksen sähköpostiisi. Mikäli et saanut sähköpostia, yritä uudelleen.", "Welcome" : "Tervetuloa <em>%s</em>.", "Welcome_to_the" : "Tervetuloa", + "will_be_able_to" : "mahdollistaa", "With_whom" : "kanssa", "Yes" : "Kyllä", "Yes_clear_all" : "Jep, tyhjennä kaikki!", "Yes_delete_it" : "Kyllä, poista!", + "Yes_mute_user" : "Kyllä, mykistä käyttäjä!", + "Yes_remove_user" : "Kyllä, poista käyttäjä!", "you_are_in_preview_mode_of" : "Tämä on kanavan #<strong>__room_name__</strong> esikatselutila", - "You_can_change_a_different_avatar_too" : "Voit vaihtaa myös toisen avatarin", + "You_are_logged_in_as" : "Olet kirjautunut sisään käyttäjänä", + "You_can_change_a_different_avatar_too" : "Voit vaihtaa tähän eri avatarin tätä integraatiota varten", + "You_can_use_an_emoji_as_avatar" : "Voit käyttää myös emojia avatarina.", + "You_have_been_muted" : "Olet mykistetty, et voi puhua tässä huoneessa.", "You_need_confirm_email" : "Sinun tulee vahvistaa sähköpostiosoitteesi!", "You_need_install_an_extension_to_allow_screen_sharing" : "Sinun tarvitsee asentaa laajennus mahdollistaaksesi näytön jakamisen", "You_should_name_it_to_easily_manage_your_integrations" : "Nimeä siten, että sinun on helppo hallita integraatioitasi", "You_will_not_be_able_to_recover" : "Viestin palauttaminen ei ole mahdollista!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", + "Your_mail_was_sent_to_s" : "Sähköpostisi lähetettiin, vastaanottaja %s", "Your_Open_Source_solution" : "Your own Open Source chat solution", "Your_push_was_sent_to_s_devices" : "Push-viesti lähetettiin %s laitteeseen" } \ No newline at end of file diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 31144e2a9c07a7e4bb07f947005c6ada4e50cfa9..a534eea244be4b2ecb07137fed1e3d01185533ea 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -1,16 +1,30 @@ { + "Access_not_authorized" : "Accès non autorisé", "Access_online_demo" : "Accédez à la démo en ligne", "Access_Online_Demo" : "Accédez à la démo en ligne", "Accounts" : "Comptes", + "Accounts_AllowedDomainsList" : "Liste des domaines autorisés", + "Accounts_AllowedDomainsList_Description" : "Liste des domaines autorisés (séparés par des virgules)", + "Accounts_AllowPasswordChange" : "Autoriser le changement de mot de passe", + "Accounts_AllowUserAvatarChange" : "Autoriser le changement d'avatar (utilisateurs)", + "Accounts_AllowUsernameChange" : "Autoriser le changement de nom d'utilisateur", + "Accounts_AllowUserProfileChange" : "Autoriser le changement de profil (utilisateurs)", + "Accounts_AvatarResize" : "Redimensionner les avatars", + "Accounts_AvatarSize" : "Taille des avatars", + "Accounts_AvatarStorePath" : "Chemin de stockage des avatars", + "Accounts_AvatarStoreType" : "Type de stockage des avatars", "Accounts_denyUnverifiedEmail" : "Refuser les emails non vérifiées", "Accounts_EmailVerification" : "Vérification de l'e-mail", + "Accounts_Enrollment_Email" : "E-mail d'inscription", + "Accounts_Enrollment_Email_Description" : "Vous pouvez utiliser [name], [fname], [lname] pour le nom complet de l'utilisateur, le prénom et le nom de famille respectivement.<br />Vous pouvez utiliser [email] pour le mail de l'utilisateur.", + "Accounts_LoginExpiration" : "Expiration de la connexion (jours)", "Accounts_ManuallyApproveNewUsers" : "Approuver manuellement les nouveaux utilisateurs", "Accounts_OAuth_Custom_Authorize_Path" : "URL d'autorisation", "Accounts_OAuth_Custom_Button_Color" : "Couleur du bouton", "Accounts_OAuth_Custom_Button_Label_Color" : "Couleur de texte du bouton", "Accounts_OAuth_Custom_Button_Label_Text" : "Texte du bouton", "Accounts_OAuth_Custom_Enable" : "Activer", - "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_id" : "ID", "Accounts_OAuth_Custom_Identity_Path" : "URL d'identification", "Accounts_OAuth_Custom_Secret" : "Secret", "Accounts_OAuth_Custom_Token_Path" : "URL de Token", @@ -19,8 +33,11 @@ "Accounts_OAuth_Facebook_id" : "App Id Facebook", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", "Accounts_OAuth_Github" : "Connexion avec GitHub", - "Accounts_OAuth_Github_id" : "GitHub Id", + "Accounts_OAuth_Github_id" : "ID client", "Accounts_OAuth_Github_secret" : "GitHub Secret", + "Accounts_OAuth_Gitlab" : "OAuth activé", + "Accounts_OAuth_Gitlab_id" : "ID GitLab", + "Accounts_OAuth_Gitlab_secret" : "Mot de passe client", "Accounts_OAuth_Google" : "Connexion avec Google", "Accounts_OAuth_Google_id" : "Google Id", "Accounts_OAuth_Google_secret" : "Google Secret", @@ -33,23 +50,36 @@ "Accounts_OAuth_Twitter" : "Connexion avec Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Mot de passe réinitialisé", + "Accounts_Registration_AuthenticationServices_Enabled" : "Enregistrement des comptes avec les services d'authentification", + "Accounts_RegistrationForm" : "Formulaire d'inscription", + "Accounts_RegistrationForm_Disabled" : "Désactivé", + "Accounts_RegistrationForm_Public" : "Publique", + "Accounts_RegistrationForm_Secret_URL" : "URL secrète", + "Accounts_RegistrationForm_SecretURL_Description" : "Vous devez fournir une chaîne de caractères aléatoire qui sera ajouté à votre URL d'inscription. Exemple: https://demo.rocket.chat/register/[secret_hash]", "Accounts_RegistrationRequired" : "Enregistrement nécessaire", + "Accounts_RequireNameForSignUp" : "Exiger un nom pour s'inscrire", "Activate" : "Activer", "Add_custom_oauth" : "Ajouter OAuth personnalisé", "Add_Members" : "Ajouter des membres", "Add_users" : "Ajouter des utilisateurs", "Administration" : "Administration", "All_channels" : "Tous les canaux", - "Allow_Invalid_SelfSigned_Certs" : "Autoriser les certificats SSL invalides et autosignés pour la validation des liens et prévisualisations", + "Allow_Invalid_SelfSigned_Certs" : "Autoriser les certificats auto-signés invalides", + "Allow_Invalid_SelfSigned_Certs_Description" : "Autoriser les certificats SSL invalides et auto-signés pour la validation des liens et extraits.", "and" : "et", "API" : "API", "API_Analytics" : "Analytique", "API_Embed" : "Embed", + "API_EmbedDisabledFor" : "Désactiver l'intégration externe pour les utilisateurs", + "API_EmbedDisabledFor_Description" : "Liste de noms d'utilisateurs séparés par des virgules", + "Archive" : "Archiver", "are_also_typing" : "sont également en train d'écrire", "are_typing" : "sont en train d'écrire", "Are_you_sure" : "Êtes-vous sûr(e) ?", "Auto_Load_Images" : "Charger automatiquement les images", "Avatar_changed_successfully" : "Avatar modifié avec succès", + "Avatar_url_invalid_or_error" : "L'URL est invalide ou non accessible. Essayez de nouveau, mais avec une URL différente.", "away" : "absent", "Away" : "Absent", "away_female" : "absente", @@ -65,13 +95,17 @@ "busy_male" : "occupé", "Busy_male" : "Occupé", "Cancel" : "Annuler", + "CDN_PREFIX" : "Préfixe CDN", + "Certificates_and_Keys" : "Certificats et clés", "Change_avatar" : "Changer l'avatar", "Channels" : "Canaux", "Channels_list" : "Liste des canaux publics", "Chat_Rooms" : "Salons de discussion", + "Clear_all_unreads_question" : "Marquer tout comme lu ?", "close" : "fermer", "coming_soon" : "prochainement", "Commands" : "Commandes", + "Compact_View" : "Vue compacte", "Confirm_password" : "Confirmez votre mot de passe", "Contact" : "Contact", "Conversation" : "Conversation", @@ -85,6 +119,7 @@ "Custom_oauth_unique_name" : "Nom unique OAuth personnalisé", "days" : "jours", "Deactivate" : "Désactiver", + "Delete_Room_Warning" : "Supprimer un salon supprimera également tous les messages postés dans le salon. Cela ne peut pas être annulé.", "Delete_User_Warning" : "Supprimer un utilisateur va également supprimer tous les messages de celui-ci. Cette action ne peut être annulée.", "Deleted" : "Supprimé !", "Desktop_Notifications" : "Notifications sur le bureau", @@ -94,22 +129,34 @@ "Disable_Favorite_Rooms" : "Désactiver les favoris", "Disable_New_Message_Notification" : "Désactiver la notification de nouveau message", "Disable_New_Room_Notification" : "Désactiver la notification de nouveau salon", + "Do_you_want_to_change_to_s_question" : "Voulez-vous changer pour <strong>%s</strong> ?", "Drop_to_upload_file" : "Glissez-déposez pour transférer un fichier", + "Duplicate_archived_channel_name" : "Un canal archivé avec le nom '% s' existe", "Duplicate_channel_name" : "Un canal avec le nom '% s' existe", "Duplicate_private_group_name" : "Un groupe privé avec le nom '% s' existe", "E-mail" : "Email", "edited" : "modifié", "Email_already_exists" : "L'adresse email existe déjà ", "Email_or_username" : "Adresse email ou nom d'utilisateur", - "Email_verified" : "Email vérifié", + "Email_verified" : "Courriel vérifié", "Emoji" : "Emoji", "Enable_Desktop_Notifications" : "Activer les notifications sur le bureau", "Enter_info" : "Entrez vos identifiants de connexion", "Enter_to" : "Entrée pour", - "Error_changing_password" : "Erreur lors du changement de mot de \npasse", + "Error_changing_password" : "Erreur lors du changement de mot de passe", + "Error_too_many_requests" : "Erreur, trop de requêtes. Veuillez ralentir. Vous devez attendre %s secondes avant de réessayer.", "Esc_to" : "Échap pour", + "Example_s" : "Exemple : <code class=\"inline\">%s</code>", "False" : "Non", "Favorites" : "Favoris", + "FileUpload" : "Envoi de fichiers", + "FileUpload_Enabled" : "Envois de fichiers activés", + "FileUpload_File_Empty" : "Fichier vide", + "FileUpload_MaxFileSize" : "Taille maximale d'envoi de fichier (en octets)", + "FileUpload_MediaTypeWhiteList" : "Types de média acceptés", + "FileUpload_MediaTypeWhiteListDescription" : "Liste des types de média (séparés par des virgules)", + "FileUpload_ProtectFiles" : "Protéger les fichiers uploadés", + "FileUpload_ProtectFilesDescription" : "Seuls les utilisateurs authentifiés auront accès", "Follow_social_profiles" : "Suivez-nous sur les réseaux sociaux, clonez le projet sur GitHub et partagez vos idées à propos de rocket.chat sur notre tableau Trello.", "Forgot_password" : "Mot de passe oublié", "Fork_it_on_github" : "Cloner sur GitHub", @@ -125,11 +172,24 @@ "hours" : "heures", "Incorrect_Password" : "Mot de passe incorrect", "inline_code" : "Ligne de code", + "Install_Extension" : "Installer l'extension", + "Install_FxOs" : "Installez Rocket.Chat dans votre Firefox", + "Install_FxOs_done" : "Formidable ! Vous pouvez maintenant utiliser Rocket.Chat via l'icône sur votre écran d'accueil. Amusez-vous avec Rocket.Chat !", + "Install_FxOs_error" : "Désolé, cela n'a pas fonctionné comme prévu! L'erreur suivante est apparue :", + "Install_FxOs_follow_instructions" : "Veuillez confirmer l'installation de l'application sur votre appareil (appuyez sur \"Installer\" lorsque c'est demandé).", + "Integration_added" : "L'intégration a été ajoutée", + "Integration_updated" : "L'intégration a été mise à jour", "Invalid_confirm_pass" : "Les mots de passe renseignés ne sont pas les mêmes", "Invalid_email" : "L'adresse email saisie est invalide", + "Invalid_file_height" : "Hauteur du fichier non valide", + "Invalid_file_type" : "Type de fichier invalide", + "Invalid_file_width" : "Largeur du fichier non valide", "Invalid_name" : "Le nom doit être renseigné", "Invalid_pass" : "Le mot de passe doit être renseigné", "Invalid_room_name" : "<strong>%s</strong> n'est pas un nom de canal valide,<br>/ utilisez des lettres, des chiffres et des tirets uniquement", + "Invalid_room_type" : "<strong>%s</strong> n'est pas un nom de canal valide.", + "Invalid_Secret_URL" : "URL secrète invalide", + "Invalid_secret_URL_message" : "L'URL fournie est invalide.", "invisible" : "invisible", "Invisible" : "Invisible", "Invitation_HTML" : "Contenu HTML de l'invitation", @@ -144,6 +204,8 @@ "italics" : "italique", "join" : "Rejoindre\n", "Join_the_Community" : "Rejoignez la communauté", + "Jump_to_message" : "Aller au message", + "Jump_to_recent_messages" : "Aller aux messages récents", "Language" : "Langue", "Language_Version" : "Version anglaise", "Last_login" : "Dernière connexion", @@ -155,12 +217,23 @@ "Layout_Login_Terms" : "Conditions de connexion", "Layout_Privacy_Policy" : "Politique de confidentialité", "Layout_Sidenav_Footer" : "Pied de page", - "Layout_Sidenav_Footer_description" : "La taille du pied de page est 260x70", + "Layout_Sidenav_Footer_description" : "La taille du pied de page est de 260 × 70 pixels", "Layout_Terms_of_Service" : "Conditions de service", "LDAP" : "LDAP", - "LDAP_DN" : "DN LDAP", + "LDAP_Bind_Search" : "Recherche liée (Bind Search)", + "LDAP_Bind_Search_Description" : "Un code JSON qui régit les informations de lien et de connexion et est sous la forme {\"filter\": \"(&(objectCategory=person)(objectclass=user)(memberOf=CN=ROCKET_ACCESS,CN=Users,DC=domain,DC=com)(sAMAccountName=#{username}))\", \"scope\": \"sub\", \"userDN\": \"rocket.service@domain.com\", \"password\": \"urpass\"}", + "LDAP_Description" : "LDAP est une base de données hiérarchique que de nombreuses entreprises utilisent pour fournir une authentification unique à travers leurs services - L'utilisateur ne devra s'authentifier qu'une seule fois pour accéder à tous les services. Pour plus d'informations et des exemples de configuration avancée, s'il vous plaît consulter notre wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication .", + "LDAP_DN" : "Nom distinctif (DN)", + "LDAP_DN_Description" : "Recherche racine; exemple: dc=domain,DC=com", + "LDAP_Enable" : "Activer LDAP", + "LDAP_Enable_Description" : "Essayer d'utiliser LDAP pour l'authentification.", "LDAP_Port" : "Port LDAP", + "LDAP_Port_Description" : "Port pour accéder à LDAP ; par exemple: 389", + "LDAP_Sync_User_Data" : "Synchronisation des données", + "LDAP_Sync_User_Data_Description" : "Garder les données de l'utilisateur en synchronisation celles du serveur lors de la connexion (par exemple: nom, e-mail).", + "LDAP_Sync_User_Data_FieldMap_Description" : "Configurer la façon dont les champs de compte d'utilisateur (comme le courrier électronique) sont remplis à partir d'un enregistrement dans l'annuaire LDAP (une fois trouvés). A titre d'exemple, {\"cn\": \"nom\", \"mail\": \"e-mail\"} choisira le nom d'une personne humainement lisible à partir de l'attribut cn, et leur e-mail à partir de l'attribut mail. Les champs disponibles comprennent le nom et le courrier électronique.", "LDAP_Url" : "Adresse LDAP", + "LDAP_Url_Description" : "URL du serveur LDAP ; exemple: ldap://company.dns.com", "Leave_room" : "Quitter le salon", "line" : "ligne", "Load_more" : "Charger plus", @@ -173,26 +246,33 @@ "Logout" : "Se déconnecter", "Make_Admin" : "Promouvoir administrateur", "Mark_as_read" : "Marquer comme lu", + "Markdown_Headers" : "Titres Markdown", "Members" : "Membres", "Members_List" : "Liste des membres", "Members_placeholder" : "Membres", "Message" : "Message", "Message_AllowDeleting" : "Autoriser la suppression de messages", "Message_AllowEditing" : "Autoriser la modification de messages", - "Message_AllowEditing_BlockEditInMinutes" : "Bloquer la modification de messages après (en minutes, 0 pour désactiver)", + "Message_AllowEditing_BlockEditInMinutes" : "Bloquer la modification des messages après (n) minutes", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Entrez 0 pour désactiver le blocage.", + "Message_AudioRecorderEnabled" : "Enregistrement audio activé", + "Message_AudioRecorderEnabledDescription" : "Nécessite que les fichiers de type « audio/wav » soient acceptés en tant que média dans les réglages d'envoi de fichiers.", "Message_deleting_not_allowed" : "Suppression d'un message non autorisée", "Message_editing_blocked" : "Ce message ne peut plus être modifié", "Message_editing_not_allowed" : "Modification d'un message non autorisée", + "Message_GroupingPeriod" : "Période de regroupement (en secondes)", + "Message_GroupingPeriodDescription" : "Les messages seront regroupés avec les messages précédents si ils sont du même utilisateur et si le temps écoulé est inférieur au temps indiqué en secondes.", "Message_KeepHistory" : "Conserver l'historique des messages", - "Message_MaxAllowedSize" : "Taille maximum de message autorisée", + "Message_MaxAllowedSize" : "Taille maximale d'un message autorisée", "Message_pinned" : "Message épinglé", "Message_pinning_not_allowed" : "L'épinglement de message n'est pas autorisé", "Message_removed" : "Message supprimé", "Message_ShowDeletedStatus" : "Afficher le statut de suppression", "Message_ShowEditedStatus" : "Afficher le statut de modification", + "Message_ShowFormattingTips" : "Afficher les astuces de mise en forme", "Messages" : "Messages", "Meta" : "Meta", - "Meta_fb_app_id" : "Facebook APP ID", + "Meta_fb_app_id" : "App ID Facebook", "Meta_google-site-verification" : "Google Site Verification", "Meta_language" : "Langue", "Meta_msvalidate01" : "MSValidate.01", @@ -203,6 +283,7 @@ "More_unreads" : "Davantage de messages non lus", "Msgs" : "Messages", "multi" : "multiple", + "Mute_user" : "Rendre muet", "My_Account" : "Mon compte", "n_messages" : "%s messages", "Name" : "Nom", @@ -216,9 +297,11 @@ "No_favorites_yet" : "Vous n'avez ajouté aucun favoris pour le moment.", "No_group_with_name_%s_was_found" : "Aucun groupe privé nommé <strong>\"%s\"</strong> n'a été trouvé !", "No_groups_yet" : "Vous n'avez pas encore de groupes privés.", + "No_livechats" : "Vous avez pas de chats instantanés.", "No_permission_to_view_room" : "Vous n'avez pas la permission de voir ce salon", "No_user_with_username_%s_was_found" : "Aucun utilisateur nommé <strong>\"%s\"</strong> n'a été trouvé !", "Not_allowed" : "Non autorisé", + "Not_authorized" : "Non autorisé", "Not_found_or_not_allowed" : "Introuvable ou non autorisé", "Nothing_found" : "Aucun résultat", "Notify_all_in_this_room" : "Notifiez tout le monde dans ce salon", @@ -231,8 +314,10 @@ "Opt_out_statistics_warning" : "En envoyant vos statistiques anonymes, vous allez nous aider à identifier le nombre d'instances de Rocket.Chat déployées, ainsi que le bon comportement du système, et donc que nous pourrions encore améliorer. Si vous souhaitez continuer à nous envoyer vos statistiques anonymes, décochez la case ci-dessus. Merci.", "others" : "autres", "Password" : "Mot de passe", + "Password_Change_Disabled" : "L'administrateur de votre Rocket.Chat a désactivé la possibilité de changer de mot de passe", "Password_changed_successfully" : "Mot de passe modifié avec succès", "People" : "Personnes", + "Please_enter_value_for_url" : "Veuillez entrer l'url de votre avatar.", "Please_wait" : "Veuillez patienter", "Please_wait_activation" : "Veuillez patienter, cela peut prendre un peu de temps.", "Please_wait_statistics" : "Veuillez patienter, les statistiques sont en cours de génération.", @@ -254,28 +339,41 @@ "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Débogage", "Push_enable" : "Activer", + "Push_enable_gateway" : "Activer la passerelle", + "Push_gateway" : "Passerelle", + "Push_gcm_api_key" : "Clé API GCM", + "Push_gcm_project_number" : "Numéro de projet GCM", "Push_production" : "Production", "Quick_Search" : "Recherche rapide", "quote" : "citation", "Recents" : "Récents", "Record" : "Enregistrer", + "Refresh_your_page_after_install_to_enable_screen_sharing" : "Actualisez votre page après l'installation pour permettre le partage d'écran", "Register" : "Créer un nouveau compte", "Registration_Succeeded" : "Enregistrement réussi", "Remember_me" : "Se souvenir de moi", "Remove" : "Supprimer", "Remove_Admin" : "Supprimer administrateur", "Remove_custom_oauth" : "Supprimer OAuth personnalisé ", + "Remove_from_room" : "Retirer du salon", "Reset_password" : "Réinitialiser le mot de passe", "Room" : "Salon", + "Room_archived" : "Salon archivé", + "Room_has_been_deleted" : "Le salon a été supprimé", "Room_name_changed" : "Nom du salon changé en : <em>__room_name__</em> par <em>__user_by__</em>", "Room_name_changed_successfully" : "Nom du salon changé avec succès", "Room_not_found" : "Salon introuvable", + "Room_unarchived" : "Salon désarchivé", "Room_uploaded_file_list" : "Liste des fichiers", "Room_uploaded_file_list_empty" : "Aucun fichier disponible.", "room_user_count" : "%s utilisateurs", "Rooms" : "Salons", "S_new_messages_since_s" : "%s nouveaux messages depuis %s", "SAML" : "SAML", + "SAML_Custom_Cert" : "Certificat personnalisé", + "SAML_Custom_Entry_point" : "Point d'entrée personnalisée", + "SAML_Custom_Generate_Username" : "Générer le nom d'utilisateur", + "SAML_Custom_Provider" : "Fournisseur personnalisé", "Save_changes" : "Sauvegarder les modifications", "Save_Mobile_Bandwidth" : "Préserver la bande passante sur mobile", "Search" : "Recherche", @@ -298,11 +396,14 @@ "Send_Message" : "Envoyer un message", "Settings" : "Paramètres", "Settings_updated" : "Paramètres mis à jour", + "Showing_archived_results" : "<p>Affichage de <b>%s</b> résultats archivés</p>", "Showing_online_users" : "<b>__total_online__</b> utilisateur(s) sur un total de __total__ affichés", "Showing_results" : "<p><b>%s</b> résultat(s)</p>", "Silence" : "Silence", "since_creation" : "depuis %s", - "Site_Name" : "Nom du site :", + "Site_Name" : "Nom du site", + "Site_Url" : "URL du site", + "Site_Url_Description" : "Exemple : https://chat.domain.com/", "SMTP" : "SMTP", "SMTP_Host" : "Hôte SMTP", "SMTP_Password" : "Mot de passe SMTP", @@ -337,16 +438,24 @@ "Stop_Recording" : "Arrêter l'enregistrement", "strike" : "barré", "Submit" : "Envoyer", + "The_channel_name_is_required" : "Le canal doit être nommé", "The_field_is_required" : "Le champ %s est requis.", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "Le réglage <strong>%s</strong> est configuré pour <strong>%s</strong> et vous accédez à partir de <strong>%s</strong> !", "True" : "Oui", + "Unarchive" : "Désarchiver", + "Unmute_user" : "Réactiver", "Unnamed" : "Sans nom", + "Unread_Rooms" : "Salons contenant des messages non-lus", + "Unread_Rooms_Mode" : "Mode des salons non-lus", "Upload_file_question" : "Transférer le fichier ?", + "Uploading_file" : "Envoi de fichier en cours...", "Use_Emojis" : "Utiliser les émoticônes", "Use_initials_avatar" : "Utiliser les initiales de votre nom d'utilisateur", "use_menu" : "Utilisez le menu latéral pour accéder à vos salons et discussions.", "Use_service_avatar" : "Utiliser l'avatar %s", "Use_this_username" : "Utilisez ce nom d'utilisateur", "Use_uploaded_avatar" : "Utiliser l'avatar transmis", + "Use_url_for_avatar" : "Utilisez l'URL pour l'avatar", "User_added_by" : "L'utilisateur <em>__user_added__</em> a été ajouté par <em>__user_by__</em>.", "User_Channels" : "Salons d'utilisateur", "User_has_been_activated" : "L'utilisateur a été activé", @@ -359,15 +468,20 @@ "User_joined_channel" : "A rejoint le canal.", "User_joined_channel_female" : "A rejoint le canal.", "User_joined_channel_male" : "A rejoint le canal.", - "User_left" : "L'utilisateur <em>__user_left__</em> est parti.", - "User_left_female" : "L'utilisateur <em>__user_left__</em> est parti.", - "User_left_male" : "L'utilisateur <em>__user_left__</em> est parti.", + "User_left" : "A quitté le canal.", + "User_left_female" : "A quitté le canal.", + "User_left_male" : "A quitté le canal.", "User_logged_out" : "L'utilisateur est déconnecté", + "User_muted_in_room" : "L'utilisateur à été bloqué dans ce salon", + "User_not_found_or_incorrect_password" : "Utilisateur introuvable ou mot de passe incorrect", "User_removed_by" : "L'utilisateur <em>__user_removed__</em> a été éjecté par <em>__user_by__</em>.", + "User_removed_from_room" : "L'utilisateur a été retiré du salon", "User_Settings" : "Paramètres utilisateur", + "User_unmuted_in_room" : "L'utilisateur à été réactivé dans ce salon", "User_updated_successfully" : "Utilisateur mis à jour avec succès", "Username" : "Nom d'utilisateur", "Username_cant_be_empty" : "Le nom d'utilisateur doit être renseigné", + "Username_Change_Disabled" : "L'administrateur de votre Rocket.Chat a désactivé la possibilité de changer de nom d'utilisateur", "Username_description" : "Le nom d'utilisateur est utilisé pour permettre à d'autres personnes de vous mentionner dans leurs messages.", "Username_invalid" : "<strong>%s</strong> n'est pas un nom d'utilisateur valide,<br/> utilisez des lettres, des chiffres, des points et des tirets uniquement", "Username_title" : "Enregistrer un nom d'utilisateur", @@ -380,10 +494,15 @@ "Welcome" : "Bienvenue <em>%s</em>.", "Welcome_to_the" : "Bienvenue sur", "With_whom" : "Avec qui", + "Yes" : "Oui", + "Yes_clear_all" : "Oui, marquez tout comme lu !", "Yes_delete_it" : "Oui, je confirme la suppression !", "you_are_in_preview_mode_of" : "Aperçu du salon #<strong>__room_name__</strong> ", + "You_can_use_an_emoji_as_avatar" : "Vous pouvez également utiliser un emoji comme avatar.", + "You_have_been_muted" : "Vous avez été bloqué et ne pouvez pas parler dans cette salle", "You_need_confirm_email" : "Vous devez confirmer votre adresse email pour vous connecter !", - "You_will_not_be_able_to_recover" : "Cette action n'est pas réversible !", + "You_need_install_an_extension_to_allow_screen_sharing" : "Vous devez installer une extension pour permettre le partage d'écran", + "You_will_not_be_able_to_recover" : "Vous ne serez pas en mesure de récupérer ce message !", "Your_entry_has_been_deleted" : "Ce message a été supprimé.", "Your_Open_Source_solution" : "Votre propre solution de chat Open Source" } \ No newline at end of file diff --git a/i18n/he.i18n.json b/i18n/he.i18n.json index 0a641b93d4d5215b42990fe914bf505094efa64c..fdd4e9b7b7ffd12593b01b5eba612bce39b4602c 100644 --- a/i18n/he.i18n.json +++ b/i18n/he.i18n.json @@ -1,147 +1,302 @@ { - "Access_online_demo" : "צפה בגרסת הדגמה", - "Access_Online_Demo" : "צפה בגרסת ההדגמה", - "Add_Members" : "הוסף חברי×", - "Add_users" : "הוסף משתמשי×", + "Access_not_authorized" : "הגישה ××™× ×” מורשית.", + "Access_online_demo" : "צפייה בגרסת הדגמה", + "Access_Online_Demo" : "צפייה בגרסת ההדגמה", + "Accounts" : "×—×©×‘×•× ×•×ª", + "Accounts_EmailVerification" : "×ימות דו×״ל", + "Accounts_OAuth_Custom_Authorize_Path" : "× ×ª×™×‘ ×ימות", + "Accounts_OAuth_Custom_Button_Color" : "צבע הכפתור", + "Accounts_OAuth_Custom_Button_Label_Color" : "צבע טקסט הכפתור", + "Accounts_OAuth_Custom_Button_Label_Text" : "טקסט הכפתור", + "Accounts_OAuth_Custom_Enable" : "הפעלה", + "Accounts_OAuth_Custom_Identity_Path" : "× ×ª×™×‘ הזהות", + "Accounts_OAuth_Custom_Secret" : "סוד", + "Accounts_OAuth_Custom_Token_Path" : "× ×ª×™×‘ ×”×סימון", + "Accounts_OAuth_Custom_URL" : "כתובת", + "Accounts_OAuth_Facebook" : "×›× ×™×¡×” לפייסבוק", + "Accounts_OAuth_Facebook_id" : "מזהה יישומון פייסבוק", + "Accounts_OAuth_Facebook_secret" : "סוד פייסבוק", + "Accounts_OAuth_Github_id" : "מזהה לקוח", + "Accounts_OAuth_Github_secret" : "סוד לקוח", + "Accounts_OAuth_Google" : "×›× ×™×¡×” לגוגל", + "Accounts_OAuth_Google_id" : "מזהה בגוגל", + "Accounts_OAuth_Google_secret" : "סוד גוגל", + "Accounts_OAuth_Linkedin" : "×›× ×™×¡×” ל־LinkedIn", + "Accounts_OAuth_Linkedin_id" : "מזהה LinkedIn", + "Accounts_OAuth_Linkedin_secret" : "סוד LinkedIn", + "Accounts_PasswordReset" : "×יפוס ססמה", + "Accounts_RegistrationForm" : "טופס הרשמה", + "Accounts_RegistrationForm_Secret_URL" : "כתובת סודית", + "Accounts_RegistrationRequired" : "× ×“×¨×©×ª הרשמה", + "Add_Members" : "הוספת חברי×", + "Add_users" : "הוספת משתמשי×", + "Administration" : "× ×™×”×•×œ", "All_channels" : "כל הערוצי×", "and" : "ו", + "API_Embed" : "הטמעה", "are_also_typing" : "×’× ×ž×§×œ×™×“×™×", "are_typing" : "מקלידי×", + "Are_you_sure" : "בווד×ות?", + "Auto_Load_Images" : "×˜×¢×™× ×ª ×ª×ž×•× ×•×ª ×וטומטית", + "Avatar_changed_successfully" : "×”×ª×ž×•× ×” הוחלפה בהצלחה", "away" : "×œ× × ×ž×¦×", "Away" : "×œ× × ×ž×¦×", - "Back_to_login" : "חזור להתחברות", + "away_female" : "×œ× × ×ž×¦×ת", + "Away_female" : "×œ× × ×ž×¦×ת", + "away_male" : "×œ× × ×ž×¦×", + "Away_male" : "×œ× × ×ž×¦×", + "Back_to_login" : "חזרה ×œ×›× ×™×¡×”", "bold" : "מודגש", "busy" : "עסוק", "Busy" : "עסוק", + "busy_female" : "עסוקה", + "Busy_female" : "עסוקה", + "busy_male" : "עסוק", + "Busy_male" : "עסוק", "Cancel" : "ביטול", - "Change_avatar" : "×©× ×” ×ת ×”×וו×טר", + "Certificates_and_Keys" : "תעודות ומפתחות", + "Change_avatar" : "החלפת ×ª×ž×•× ×ª המשתמש שלך", "Channels" : "ערוצי×", "Channels_list" : "רשימת ×¢×¨×•×¦×™× ×¦×™×‘×•×¨×™×™×", - "Chat_Rooms" : "חדרי צ'×ט", - "close" : "סגור", + "Chat_Rooms" : "חדרי צ׳×ט", + "close" : "סגירה", "coming_soon" : "בקרוב", - "Confirm_password" : "×מת ×ת הסיסמ×", - "Contact" : "צור קשר", + "Confirm_password" : "×ימות הססמה", + "Contact" : "יצירת קשר", "Conversation" : "שיחה", - "Create_new" : "צור חדש", - "Create_new_private_group" : "צור קבוצה פרטית חדשה", - "Create_new_public_channel" : "צור ערוץ ציבורי חדש", - "Created_at" : "× ×•×¦×¨ ב-", + "Convert_Ascii_Emojis" : "המרת ASCII ל×ימוג׳י", + "COPY_TO_CLIPBOARD" : "העתקה ללוח הגזירי×", + "Create_new" : "יצירת חדש", + "Create_new_direct_message_room" : "יצירת חדר הודעה ישירה חדש", + "Create_new_private_group" : "יצירת קבוצה פרטית חדשה", + "Create_new_public_channel" : "יצירת ערוץ ציבורי חדש", + "Created_at" : "× ×•×¦×¨ ב־", + "days" : "ימי×", + "Deleted" : "× ×ž×—×§!", "Direct_Messages" : "הודעות ישירות", + "Disable_New_Message_Notification" : "× ×˜×¨×•×œ התרעת הודעה חדשה", + "Disable_New_Room_Notification" : "× ×˜×¨×•×œ התרעת חדר חדש", + "Drop_to_upload_file" : "יש להשליך לכ×ן כדי להעלות קובץ", + "Duplicate_channel_name" : "כבר ×§×™×™× ×¢×¨×•×¥ ×‘×©× â€š%s‘", + "Duplicate_private_group_name" : "כבר קיימת קבוצה פרטית בש× ‚%s‘", + "E-mail" : "דו×״ל", "edited" : "× ×¢×¨×š", - "Email_or_username" : "כתובת ×ימייל ×ו ×©× ×ž×©×ª×ž×©", - "Email_verified" : "כתובת ×”×ימייל ×ומתה", - "Enter_info" : "הזן ×ת פרטי ההתחברות שלך", - "Error_changing_password" : "×”×¡×™×¡×ž× ×©×•× ×ª×”", + "Email_already_exists" : "כתובת הדו×״ל כבר קיימת", + "Email_or_username" : "כתובת דו×״ל ×ו ×©× ×ž×©×ª×ž×©", + "Email_verified" : "כתובת הדו×״ל ×ומתה", + "Enter_info" : "× × ×œ×”×–×™×Ÿ ×ת ×”×¤×¨×˜×™× ×©×œ×š", + "Error" : "שגי××”", + "Error_changing_password" : "הססמה הוחלפה", + "Example_s" : "לדוגמה: <code class=\"inline\">%s</code>", "Favorites" : "מועדפי×", - "Follow_social_profiles" : "עקוב ×חר ×”×¤×¨×•×¤×™×œ×™× ×©×œ× ×• ברשתות החברתיות, עשה fork לפרויקט ×©×œ× ×• ב-github ושתף ×ת המחשבות שלך על ×פליקציית rocket.chat בלוח trello ×©×œ× ×•.", - "Forgot_password" : "שכחת ×ת הסיסמ×?", - "Fork_it_on_github" : "עשה ×œ× ×• fork ב-github", - "Get_to_know_the_team" : "הכר ×ת הצוות שמ×חורי Rocket.Chat", - "github_no_public_email" : "×ין לך ××£ כתובת ×ימייל פומבית בחשבון ×”-GitHub שלך", - "Have_your_own_chat" : "תהיה בעל שרת צ'×ט. פותחה ×¢× meteor.com, ×”×פליקציה Rocket.Chat ×”×™× ×¤×ª×¨×•×Ÿ מעולה עבור ×ž×¤×ª×—×™× ×”×ž×—×¤×©×™× ×œ×‘× ×•×ª ולשפר ×ת פלפורמת הצ'×ט שלה×.", - "Hide_room" : "הסתר ×ת החדר", + "FileUpload_ProtectFiles" : "×”×’× ×” על ×§×‘×¦×™× ×©×”×•×¢×œ×•", + "Follow_social_profiles" : "× ×™×ª×Ÿ לעקוב ×חר ×”×¤×¨×•×¤×™×œ×™× ×©×œ× ×• ברשתות החברתיות, לעשות fork ×œ×ž×™×–× ×©×œ× ×• ב־github ושתף ×ת המחשבות שלך על ×פליקציית rocket.chat בלוח trello ×©×œ× ×•.", + "Forgot_password" : "שכחת ×ת הססמה?", + "Fork_it_on_github" : "fork ב־github", + "From_Email" : "כתובת מ×ת", + "General" : "כללי", + "Get_to_know_the_team" : "היכרות ×¢× ×”×¦×•×•×ª שמ×חורי Rocket.Chat", + "github_no_public_email" : "×ין לך ××£ כתובת דו×״ל פומבית בחשבון ×”Ö¾GitHub שלך", + "Has_more" : "יש עוד", + "Have_your_own_chat" : "קח ×ת ×”×¢× ×™×™× ×™× ×œ×™×“×™×™×. ×”×פליקציה Rocket.Chat, ש", + "Hide_room" : "להסתיר ×ת החדר", "History" : "היסטוריה", + "hours" : "שעות", "inline_code" : "קוד", - "Invalid_confirm_pass" : "×ימות ×”×¡×™×¡×ž× ××™× ×• ×–×”×” לסיסמ×", - "Invalid_email" : "כתובת ×”×ימייל ×©×”×•×–× ×” ××™× ×” ×ª×§×™× ×”", - "Invalid_name" : "×”×©× ×—×™×™×‘ להיות מוזן", - "Invalid_pass" : "×”×¡×™×¡×ž× ×—×™×™×‘×ª להיות ×ž×•×–× ×ª", - "Invalid_room_name" : "<strong>%s</strong> ×”×•× ×œ× ×©× ×ª×§×™×Ÿ לחדר,<br/> השתמש רק ב×ותיות, ×ž×¡×¤×¨×™× ×•×ž×§×¤×™×.", + "Install_Extension" : "×”×ª×§× ×ª הרחבה", + "Invalid_confirm_pass" : "×ימות הססמה ××™× ×• ×–×”×” לססמה", + "Invalid_email" : "כתובת הדו×״ל ×©×”×•×–× ×” ××™× ×” ×ª×§×™× ×”", + "Invalid_name" : "יש להזין ש×", + "Invalid_pass" : "יש להזין ססמה", + "Invalid_room_name" : "×”×©× <strong>%s</strong> ×”×•× ×œ× ×©× ×ª×§×™×Ÿ לחדר,<br/> יש להשתמש רק ב×ותיות, ×ž×¡×¤×¨×™× ×•×ž×§×¤×™×.", "invisible" : "בלתי × ×¨××”", "Invisible" : "בלתי × ×¨××”", "is_also_typing" : "×’× ×ž×§×œ×™×“/×”", + "is_also_typing_female" : "×’× ×ž×§×œ×™×“×”", + "is_also_typing_male" : "×’× ×ž×§×œ×™×“", "is_typing" : "מקליד/×”", + "is_typing_female" : "מקלידה", + "is_typing_male" : "מקליד", "italics" : "× ×•×˜×”", - "join" : "הצטרף", - "Join_the_Community" : "הצטרף לקהילה", + "join" : "הצטרפות", + "Join_the_Community" : "הצטרפות לקהילה", + "Jump_to_message" : "מעבר להודעה", + "Jump_to_recent_messages" : "מעבר להודעות ×”××—×¨×•× ×•×ª", "Language" : "שפה", "Language_Version" : "גרסה ×× ×’×œ×™×ª", + "Last_login" : "×›× ×™×¡×” ××—×¨×•× ×”", "Last_message" : "ההודעה ×”××—×¨×•× ×”", - "Leave_room" : "עזוב ×ת החדר", + "Layout" : "פריסה", + "Layout_Home_Body" : "גוף עמוד הבית", + "Layout_Home_Title" : "כותרת עמוד הבית", + "Layout_Login_Header" : "כותרת ×›× ×™×¡×”", + "Layout_Login_Terms" : "×ª× ××™ ×›× ×™×¡×”", + "Layout_Privacy_Policy" : "×ž×“×™× ×™×•×ª פרטיות", + "Layout_Terms_of_Service" : "×ª× ××™ השירות", + "LDAP" : "LDAP", + "LDAP_DN" : "×©× ×ž×‘×“×™×œ (DN)", + "LDAP_Port" : "פתחת LDAP", + "LDAP_Url" : "כתובת LDAP", + "Leave_room" : "לעזוב ×ת החדר", "line" : "שורה", - "Load_more" : "טען עוד", - "Loading_suggestion" : "טוען הצעות...", - "Login" : "התחבר", - "Login_with" : "התחבר ×¢× %s", - "login_with" : "×ו התחבר ישירות ×¢×", - "Logout" : "×”×ª× ×ª×§", + "Load_more" : "×˜×¢×™× ×ª × ×•×¡×¤×™×", + "Loading..." : "×‘×˜×¢×™× ×”â€¦", + "Loading_more_from_history" : "הודעות × ×•×¡×¤×•×ª × ×˜×¢× ×•×ª מההיסטוריה", + "Loading_suggestion" : "ההצעות × ×˜×¢× ×•×ªâ€¦", + "Login" : "התחברות", + "Login_with" : "×›× ×™×¡×” ×¢× %s", + "login_with" : "×ו ×œ×”×™×›× ×¡ ישירות ×¢×", + "Logout" : "יצי××”", + "Mark_as_read" : "סימון ×›× ×§×¨×", "Members" : "חברי×", "Members_List" : "רשימת חברי×", "Members_placeholder" : "חברי×", + "Message" : "הודעה", + "Message_AllowDeleting" : "ל×פשר מחיקת הודעות", + "Message_AllowEditing" : "ל×פשר עריכת הודעות", + "Message_KeepHistory" : "שמירה על היסטוריית הודעות", + "Message_MaxAllowedSize" : "גודל ההודעה המרבי המותר", + "Message_removed" : "ההודעה הוסרה", + "Message_ShowDeletedStatus" : "הצגת מצב מחיקה", + "Message_ShowEditedStatus" : "הצגת מצב ערוך", + "Meta_language" : "שפה", + "Meta_robots" : "רובוטי×", + "minutes" : "דקות", "More_channels" : "עוד ערוצי×", + "More_groups" : "קבוצות פרטיות × ×•×¡×¤×•×ª", "Msgs" : "הודעות", "multi" : "הרבה", + "Mute_user" : "השתקת משתמש", + "My_Account" : "החשבון שלי", "n_messages" : "%s הודעות", "Name" : "ש×", "New_messages" : "הודעות חדשות", - "New_password" : "×¡×™×¡×ž× ×—×“×©×”", + "New_password" : "ססמה חדשה", "No_channels_yet" : "××™× ×š חבר ב××£ ערוץ עד ×›×”.", "No_direct_messages_yet" : "×œ× ×”×ª×—×œ×ª ××£ שיחה עד ×›×”.", "No_favorites_yet" : "×ין לך מועדפי×.", "No_groups_yet" : "×œ× ×§×™×™×ž×•×ª לך קבוצות פרטיות.", "No_permission_to_view_room" : "×ין לך הרש×ות לצפות בחדר ×–×”", + "No_results_found" : "×œ× × ×ž×¦×ו תוצ×ות", + "no_tokens_for_this_user" : "×ין ××¡×™×ž×•× ×™× ×œ×ž×©×ª×ž×© ×–×”", "Not_allowed" : "×œ× ×ž×•×¨×©×”", - "Not_found_or_not_allowed" : "×œ× × ×ž×¦× ×ו ××™× ×š מורשה", + "Not_found_or_not_allowed" : "×œ× × ×ž×¦× ×ו ש×ין לך הרש××”", "Nothing_found" : "×ין תוצ×ות", + "Notify_all_in_this_room" : "להודיע לכל מי שבחדר", "Online" : "מחובר", "Oops!" : "×ופס", - "Password" : "סיסמ×", - "Please_wait" : "×× × ×”×ž×ª×Ÿ", - "Powered_by" : "מופעל על ידי", + "Opt_out_statistics" : "×œ× ×œ×©×œ×•×— ×ת הסטטיסטיקה שלי ל־Rocket.Chat", + "others" : "×חרי×", + "Password" : "ססמה", + "Password_changed_successfully" : "הססמה הוחלפה בהצלחה", + "Please_wait" : "× × ×œ×”×ž×ª×™×Ÿ", + "Post_to_Channel" : "×¤×¨×¡×•× ×œ×¢×¨×•×¥", + "Powered_by" : "מופעל על גבי", + "Preferences" : "העדפות", + "Preferences_saved" : "ההעדפות × ×©×ž×¨×•", "Privacy" : "פרטיות", "Private_Groups" : "קבוצות פרטיות", + "Private_Groups_list" : "הצגת הקבוצות הפרטיות", + "Profile" : "פרופיל", + "Profile_saved_successfully" : "הפרופיל × ×©×ž×¨ בהצלחה", "Proudly_developed" : "פותח בג×ווה ×¢× Meteor", + "Push" : "דחיפה", + "Push_debug" : "× ×™×¤×•×™ שגי×ות", + "Push_enable_gateway" : "הפעלת שער גישה", + "Push_gateway" : "שער גישה", + "Push_test_push" : "בדיקה", "Quick_Search" : "חיפוש מהיר", "quote" : "ציטוט", "Recents" : "××—×¨×•× ×™×/××—×¨×•× ×•×ª", - "Register" : "×”×™×¨×©× ×¢× ×—×©×‘×•×Ÿ חדש", - "Remember_me" : "זכור ×ותי", - "Remove" : "מחק", - "Reset_password" : "×פס סיסמ×", + "Register" : "הרשמה ×¢× ×—×©×‘×•×Ÿ חדש", + "Remember_me" : "שמירת ×”×¤×¨×˜×™× ×©×œ×™", + "Remove" : "מחיקה", + "Reset" : "×יפוס", + "Reset_password" : "×יפוס ססמה", + "Restart" : "הפעלה מחדש", + "Restart_the_server" : "×יפוס השרת", "Room" : "חדר", "Room_name_changed" : "×©× ×”×—×“×¨ ×©×•× ×” ל: <em>__room_name__</em> על ידי המשתמש <em>__user_by__</em>", "Room_name_changed_successfully" : "×©× ×”×—×“×¨ ×©×•× ×” בהצלחה", - "Search" : "חפש", - "See_all" : "צפה בהכל", - "See_only_online" : "רק מחובר", - "Select_an_avatar" : "בחר ×וו×טר", - "Select_file" : "בחר קובץ", - "Select_service_to_login" : "בחר שירות להתחבר דרכו כדי לטעון ×ת ×”×ª×ž×•× ×” שלך ×ו העלה ×חת ישירות מהמחשב שלך", + "room_user_count" : "משתמשי %s", + "Rooms" : "חדרי×", + "SAML" : "SAML", + "Save_changes" : "שמירת ×”×©×™× ×•×™×™×", + "Save_Mobile_Bandwidth" : "חסכון בתעבורה סלולרית", + "Screen_Share" : "שיתוף מסך", + "Search" : "חיפוש", + "Search_Messages" : "חיפוש בהודעות", + "Search_settings" : "הגדרות חיפוש", + "See_all" : "צפייה בהכול", + "See_only_online" : "רק מחוברי×", + "Select_an_avatar" : "בחירת ×ª×ž×•× ×”", + "Select_file" : "בחירת קובץ", + "Select_service_to_login" : "יש לבחור בשירות להתחבר דרכו ×œ×˜×¢×™× ×ª ×”×ª×ž×•× ×” שלך ×ו להעלות ×חת ישירות מהמחשב שלך", "Selected_users" : "×—×‘×¨×™× × ×‘×—×¨×™×", - "Send_confirmation_email" : "שלח מייל ×ימות", - "Send_Message" : "שלח הודעה", + "Send" : "שליחה", + "Send_confirmation_email" : "שליחת דו×״ל ×ימות", + "Send_Message" : "שליחת הודעה", "Settings" : "הגדרות", + "Settings_updated" : "ההגדרות ×¢×•×“×›× ×•", "Showing_online_users" : "מציג <b>__total_online__</b> מתוך __total__ משתמשי×", - "Showing_results" : "<p>מציג <b>%s</b> תוצ×ות</p>", - "Silence" : "השתק", + "Showing_results" : "<p>מוצגות <b>%s</b> תוצ×ות</p>", + "Silence" : "השתקה", "since_creation" : "מ××– %s", + "Site_Name" : "×©× ×”×תר", + "SMTP" : "SMTP", + "SMTP_Host" : "מ×רח ", + "SMTP_Password" : "ססמה ל־", + "SMTP_Port" : "פתחת SMTP", + "SMTP_Username" : "×©× ×ž×©×ª×ž×© ב־SMTP", + "Sound" : "שמע", "Start_of_conversation" : "התחלת השיחה", + "Statistics" : "סטטיסטיקה", + "Stats_Away_Users" : "×ž×©×ª×ž×©×™× ×©××™× × × ×ž×¦××™×", + "Stats_Total_Messages" : "סך כל ההודעות", "strike" : "מחוק", - "Submit" : "שלח", + "Submit" : "שליחה", + "Success" : "הצליח", + "The_channel_name_is_required" : "×©× ×”×¢×¨×•×¥ × ×“×¨×©", "The_field_is_required" : "השדה %s ×”×•× ×—×•×‘×”.", - "Use_initials_avatar" : "השתמש בתחיליות ×©× ×”×ž×©×ª×ž×© שלך", - "use_menu" : "השתמש בתפריט הצד כדי לגשת ×œ×—×“×¨×™× ×•×œ×©×™×—×•×ª הצ'×ט שלך.", - "Use_service_avatar" : "השתמש ב×וו×טר %s", - "Use_this_username" : "השתמש ×‘×©× ×”×ž×©×ª×ž×© ×”×–×”", - "Use_uploaded_avatar" : "השתמש ב×וו×טר שהועלה", + "The_server_will_restart_in_s_seconds" : "השרת יפעיל ×ת עצמו מחדש בעוד ", + "Upload_file_question" : "להעלות קובץ?", + "Use_Emojis" : "שימוש ב×ימוג׳י", + "Use_initials_avatar" : "שימוש בר×שי התיבות של ×©× ×”×ž×©×ª×ž×© שלך", + "use_menu" : "× ×™×ª×Ÿ להשתמש בתפריט הצד כדי לגשת ×œ×—×“×¨×™× ×•×œ×¦×³××˜×™× ×©×œ×š.", + "Use_service_avatar" : "שימוש ×‘×ª×ž×•× ×” מ־%s", + "Use_this_username" : "יש להשתמש ×‘×©× ×”×ž×©×ª×ž×© ×”×–×”", + "Use_uploaded_avatar" : "שימוש ×‘×ª×ž×•× ×” שהועלתה", "User_added_by" : "המשתמש <em>__user_added__</em> × ×•×¡×£ על ידי <em>__user_by__</em>", + "User_has_been_activated" : "המשתמש הופעל", + "User_has_been_deactivated" : "המשתמש × ×•×˜×¨×œ", "User_joined_channel" : "הצטרף לערוץ.", - "User_left" : "המשתמש <em>__user_left__</em> עזב ×ת השיחה.", + "User_joined_channel_female" : "הצטרפה לערוץ.", + "User_joined_channel_male" : "הצטרף לערוץ.", + "User_left" : "המשתמש עזב ×ת השיחה.", + "User_left_female" : "עזבה ×ת הערוץ.", + "User_left_male" : "עזב ×ת הערוץ.", "User_logged_out" : "המשתמש ×œ× ×ž×—×•×‘×¨", "User_removed_by" : "המשתמש <em>__user_removed__</em> הוסר על ידי <em>__user_by__</em>", + "User_Settings" : "הגדרות המשתמש", "Username" : "×©× ×ž×©×ª×ž×©", - "Username_cant_be_empty" : "×©× ×”×ž×©×ª×ž×© חייב להיות מוזן", + "Username_cant_be_empty" : "יש להזין ×©× ×ž×©×ª×ž×©", "Username_description" : "×©× ×”×ž×©×ª×ž×© שלך משמש עבור ××–×›×•×¨×™× ×©×œ×š בהודעות של ×ž×©×ª×ž×©×™× ×חרי×.", - "Username_invalid" : "<strong>%s</strong> ×”×•× ×œ× ×©× ×ž×©×ª×ž×© תקין,<br/> השתמש רק ב×ותיות, ×ž×¡×¤×¨×™× × ×§×•×“×•×ª ומקפי×.", - "Username_title" : "×¨×©×•× ×©× ×ž×©×ª×ž×©", - "Username_unavaliable" : "<strong>%s</strong> תפוס :(", - "View_All" : "הצג הכל", - "We_have_sent_password_email" : "×”×™× ×š צריך לקבל בדקות הקרובות מייל ×¢× ×”×•×¨×ות ל×יפוס הסיסמ×. ×× ××™× ×š רו××” ×ותו, ×× × × ×¡×” ×©× ×™×ª.", - "We_have_sent_registration_email" : "×©×œ×—× ×• לך מייל ל×ישור ההרשמה. ×× ××™× ×š מקבל ×ת המייל בדקות הקרובות, ×× × × ×¡×” ×©× ×™×ª.", - "Welcome" : "ברוך ×”×‘× <em>%s</em>.", - "Welcome_to_the" : "ברוך ×”×‘× ×œ-", - "you_are_in_preview_mode_of" : "×”× ×š בתצוגה מוקדמת של ערוץ #<strong>__rom_name__</strong>", - "You_need_confirm_email" : "×”×™× ×š צריך ל×מת ×ת כתובת ×”×ימייל על ×ž× ×ª להתחבר!", - "Your_Open_Source_solution" : "פתרון הקוד הפתוח שלך לצ'×ט" + "Username_invalid" : "×”×©× <strong>%s</strong> ××™× ×• ×©× ×ž×©×ª×ž×© תקין,<br/> יש להשתמש רק ב×ותיות, ×ž×¡×¤×¨×™× × ×§×•×“×•×ª ומקפי×.", + "Username_title" : "×¨×™×©×•× ×©× ×ž×©×ª×ž×©", + "Username_unavaliable" : "×”×©× <strong>%s</strong> תפוס :(", + "Users" : "משתמשי×", + "View_All" : "הצגת הכול", + "We_have_sent_password_email" : "בדקות הקרובות ×מורה להגיע ×ליך הודעה בדו×״ל ×¢× ×”×•×¨×ות ל×יפוס הססמה. ×× ×”×”×•×“×¢×” ×œ× ×ž×’×™×¢×” ×ליך, × × ×œ× ×¡×•×ª שוב.", + "We_have_sent_registration_email" : "×©×œ×—× ×• לך הודעת דו×״ל ל×ישור ההרשמה. ×× ×”×”×•×“×¢×” ×œ× ×ž×’×™×¢×” ×ליך בדקות הקרובות, × × ×œ×—×–×•×¨ לכ×ן ×•×œ× ×¡×•×ª שוב.", + "Welcome" : "ברוך בו×ך <em>%s</em>.", + "Welcome_to_the" : "ברוך בו×ך ל־", + "With_whom" : "×¢× ×ž×™", + "Yes" : "כן", + "Yes_delete_it" : "כן, למחוק ×ותה!", + "you_are_in_preview_mode_of" : "זוהי תצוגה מוקדמת של הערוץ #<strong>__rom_name__</strong>", + "You_need_confirm_email" : "עליך ל×מת ×ת כתובת הדו×״ל על ×ž× ×ª להתחבר!", + "You_need_install_an_extension_to_allow_screen_sharing" : "צריך להתקין הרחבה כדי ל×פשר שיתוף מסך", + "You_will_not_be_able_to_recover" : "×œ× ×ª×”×™×” לך ×פשרות לשחזר ×ת ההודעה הזו!", + "Your_entry_has_been_deleted" : "הרשומה שלך × ×ž×—×§×”", + "Your_Open_Source_solution" : "הפתרון " } \ No newline at end of file diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 1af3a9b6f9405ab35eea230a05e18098c68d03d9..c70aaf9488dc93195f8c2c4fe45bba179be2adef 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -4,6 +4,7 @@ "Accounts" : "RaÄuni", "Accounts_AllowPasswordChange" : "Dopusti promjenu lozinke", "Accounts_AllowUsernameChange" : "Dopusti promjenu korisniÄkog imena", + "Accounts_AvatarResize" : "Promjeni veliÄinu Avatara", "Accounts_AvatarSize" : "VeliÄina Avatara", "Accounts_denyUnverifiedEmail" : "Odbij neprovjereni e-mail", "Accounts_EmailVerification" : "E-mail Verifikacija", @@ -18,6 +19,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Prijava", "Accounts_OAuth_Meteor" : "Meteor Prijava", "Accounts_OAuth_Twitter" : "Twitter Prijava", + "Accounts_PasswordReset" : "Resetiraj lozinku", "Accounts_RegistrationRequired" : "Potrebna je registracija", "Activate" : "Aktiviraj", "Add_Members" : "Dodaj ÄŒlanove", @@ -26,6 +28,7 @@ "All_channels" : "Svi kanali", "and" : "i", "API_Analytics" : "Analitika", + "Archive" : "Arhiva", "are_also_typing" : "isto tipkaju", "are_typing" : "tipkaju", "Are_you_sure" : "Jesi li siguran?", @@ -46,12 +49,15 @@ "busy_male" : "zauzet", "Busy_male" : "Zauzet", "Cancel" : "Otkaži", + "CDN_PREFIX" : "CDN Prefiks", "Change_avatar" : "Promijeni avatar", "Channels" : "Kanali", "Channels_list" : "Lista javnih kanala", "Chat_Rooms" : "Chat Sobe", + "Clear_all_unreads_question" : "Makni sve neproÄitane?", "close" : "zatvori", "coming_soon" : "dolazi uskoro", + "Commands" : "Naredbe", "Confirm_password" : "Potvrdi svoju lozinku", "Contact" : "Kontakt", "Conversation" : "Razgovor", @@ -78,12 +84,15 @@ "Email_already_exists" : "Email već postoji", "Email_or_username" : "Email or username", "Email_verified" : "Email provjeren", + "Emoji" : "Emoji", "Enter_info" : "Unesi svoje informacije za prijavu", "Enter_to" : "UÄ‘i u ", + "Error" : "PogreÅ¡ka", "Error_changing_password" : "Lozinka je izmijenjena", "Esc_to" : "Pobjegni iz", "False" : "Ne", "Favorites" : "Omiljeni", + "FileUpload_ProtectFiles" : "ZaÅ¡titite uploadane datoteke", "Follow_social_profiles" : "Slijedi naÅ¡e socijalne profile, forkaj chat na githubu i podijeli svoje misli o rocket.chat aplikaciji na naÅ¡oj trello ploÄi.", "Forgot_password" : "Zaboravih lozinku", "Fork_it_on_github" : "Forkaj na githubu", @@ -98,6 +107,8 @@ "Incorrect_Password" : "NetoÄna lozinka", "inline_code" : "jednolinijski kôd", "Install_FxOs" : "Instalirajte Rocket.Chat na svoj Firefox", + "Install_FxOs_error" : "Nažalost, to nije uspjelo onako kako smo zamislili! Pojavila se sljedeća greÅ¡ka:", + "Integration_added" : "Integracija je dodana", "Invalid_confirm_pass" : "Potvrda lozinke se ne slaže sa lozinkom", "Invalid_email" : "Uneseni e-mail nije valjan", "Invalid_name" : "Ime ne smije biti prazno", @@ -115,6 +126,8 @@ "italics" : "ukosi", "join" : "Pridruži se", "Join_the_Community" : "Pridruži se zajednici", + "Jump_to_message" : "SkoÄi na poruku", + "Jump_to_recent_messages" : "SkoÄi na nedavne poruke", "Language" : "Jezik", "Language_Version" : "Engleska Verzija", "Last_login" : "Zadnja prijava", @@ -175,6 +188,7 @@ "No_group_with_name_%s_was_found" : "Privatna grupa s tim imenom nije naÄ‘ena", "No_groups_yet" : "JoÅ¡ nemaÅ¡ privatnih grupa.", "No_permission_to_view_room" : "NemaÅ¡ dopuÅ¡tenje da vidiÅ¡ ovu sobu", + "No_results_found" : "Rezultati nisu naÄ‘eni", "No_user_with_username_%s_was_found" : "Korisnik sa korisniÄkim imenom <strong>\"%s\"</strong> nije naÄ‘en!", "Not_allowed" : "Nije dozvoljeno", "Not_found_or_not_allowed" : "Nije NaÄ‘eno ili Nije Dozvoljeno", @@ -193,6 +207,7 @@ "Please_wait" : "PriÄekaj", "Please_wait_activation" : "Molimo priÄekajte, ovo bi moglo potrajati neko vrijeme.", "Please_wait_statistics" : "Molimo priÄekajte, statistike se generiraju.", + "Post_as" : "PoÅ¡alji kao", "Powered_by" : "Powered by", "Preferences" : "Postavke", "Preferences_saved" : "Postavke saÄuvane", @@ -208,13 +223,18 @@ "Quick_Search" : "Brza Pretraga", "quote" : "c", "Recents" : "Nedavni", + "Record" : "Snimaj", "Register" : "Registriraj novi raÄun", "Registration_Succeeded" : "Registracija je uspjela ", "Remember_me" : "Zapamti me", "Remove" : "Makni", "Remove_Admin" : "Makni Administratora", + "Remove_from_room" : "Uklonite iz sobe", + "Removed" : "Uklonjeno", "Reset_password" : "Resetiraj lozinku", "Room" : "Soba", + "Room_archived" : "Soba je arhivirana", + "Room_has_been_deleted" : "Soba je obrisana", "Room_name_changed" : "Ime sobe promijenjeno u: <em>__room_name__</em> od <em>__user_by__</em>", "Room_name_changed_successfully" : "Ime sobe je uspjeÅ¡no izmijenjeno", "Room_not_found" : "Soba nije naÄ‘ena", @@ -223,6 +243,7 @@ "room_user_count" : "% korisnika", "Rooms" : "Sobe", "S_new_messages_since_s" : "novih poruka od", + "SAML_Custom_Cert" : "PrilagoÄ‘eni Certifikat", "SAML_Custom_Generate_Username" : "Izradi korisniÄko ime", "Save_changes" : "Spremi promjene", "Search" : "Traži", @@ -244,11 +265,14 @@ "Send_Message" : "PoÅ¡alji Poruku", "Settings" : "Postavke", "Settings_updated" : "Postavke su ažurirane", + "Should_exists_a_user_with_this_username" : "Korisnik mora već postojati.", "Showing_online_users" : "Prikazujem <b>__total_online__</b> od __total__ korisnika", "Showing_results" : "<p>Prikazujem <b>%s</b> rezultata</p>", "Silence" : "TiÅ¡ina", "since_creation" : "%s", "Site_Name" : "Ime Stranice:", + "Site_Url" : "Link web stranice", + "Site_Url_Description" : "Primjer: https://chat.domain.com/", "SMTP_Password" : "SMTP lozinka", "SMTP_Port" : "SMTP port", "SMTP_Username" : "SMTP korisniÄko ime", @@ -272,8 +296,11 @@ "Stats_Total_Private_Groups" : "Ukupno Privatnih Grupa", "Stats_Total_Rooms" : "Ukupno soba", "Stats_Total_Users" : "Ukupno korisnika", + "Stop_Recording" : "Prestani sa snimanjem", "strike" : "precrtaj", "Submit" : "PoÅ¡alji", + "Success" : "Uspjeh", + "The_channel_name_is_required" : "Ime kanala je potrebno", "The_field_is_required" : "Polje% s je traženo.", "True" : "Da", "Unnamed" : "Neimenovan", @@ -302,6 +329,7 @@ "User_logged_out" : "Korisnik je odjavljen", "User_not_found_or_incorrect_password" : "Korisnik nije pronaÄ‘en ili pogreÅ¡na lozinka", "User_removed_by" : "Korisnik <em>__user_removed__</em> maknut od <em>__user_by__</em>.", + "User_removed_from_room" : "Korisnik je uklonjen iz sobe", "User_Settings" : "KorisniÄke postavke", "User_updated_successfully" : "Korisnik je uspjeÅ¡no ažuriran", "Username" : "KorisniÄko ime", @@ -319,6 +347,8 @@ "Welcome" : "Dobro doÅ¡ao/la<em>%s</em>.", "Welcome_to_the" : "Dobro doÅ¡li »", "With_whom" : "Sa kim", + "Yes" : "Da", + "Yes_clear_all" : "Da, makni sve!", "Yes_delete_it" : "Da, obriÅ¡i!", "you_are_in_preview_mode_of" : "Ti si u preglednom naÄinu kanala # <strong>__room_name__</strong>", "You_need_confirm_email" : "TrebaÅ¡ potvrditi svoj email kako bi se prijavio!", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 696cdec725e1aa06d2bbb41863d002c95de09609..1051095f4d3b76dc7ccc5d229ce6f75a47f2c442 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -44,6 +44,7 @@ "Accounts_OAuth_Twitter_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Twitter", "Accounts_OAuth_Twitter_secret" : "Twitter សម្ងាážáŸ‹", "Accounts_RegistrationRequired" : "ážáŸ’រូវ​ចុះ​ឈ្មោះ", + "Accounts_RequireNameForSignUp" : "ážáŸ’រូវការ Name សម្រាប់ការចុះឈ្មោះ", "Activate" : "ធ្វើ​ឱ្យ​សកម្ម", "Add_custom_oauth" : "បន្ážáŸ‚ម oauth ផ្ទាល់​ážáŸ’លួន", "Add_Members" : "ážáŸ‚ម​សមាជិក", @@ -62,6 +63,7 @@ "Are_you_sure" : "ážáž¾â€‹áž¢áŸ’នក​ច្បាស់​ហើយ​ឬ?", "Auto_Load_Images" : "ផ្ទុក​រូបភាព​ដោយ​ស្វáŸáž™áž”្រវážáŸ’ážáž·", "Avatar_changed_successfully" : "ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹ážšáž¼áž”​ážáŸ†â€‹áž“ាង​ដោយ​ជោគជáŸáž™", + "Avatar_url_invalid_or_error" : "ážáŸ†ážŽáž—្ជាប់ដែលបានមិនážáŸ’រឹមážáŸ’រូវ ដូចនáŸáŸ‡ážŸáž¼áž˜áž–្យាយាមម្ážáž„ទៀហប៉ុន្ážáŸ‚ជាមួយážáŸ†ážŽáž—្ជាប់ផ្សáŸáž„ទៀážáŸ”", "away" : "ឆ្ងាយ", "Away" : "ឆ្ងាយ", "away_female" : "ឆ្ងាយ", @@ -191,6 +193,7 @@ "LDAP_Port" : "ច្រក LDAP", "LDAP_Port_Description" : "ផែដើម្បីចូលទៅកាន់ LDAP ážáŸ’រង់លáŸáž; ឧទាហរណáŸáŸ– 389 ", "LDAP_Sync_User_Data" : "រក្សាទិន្ននáŸáž™ User ដោយ Sync ជាមួយ Server", + "LDAP_Sync_User_Data_Description" : "រក្សាទិន្ននáŸáž™áž¢áŸ’នកប្រើប្រាស់ក្នុងការ Sync ជាមួយម៉ាស៊ីនមáŸáž€áŸ’នុងការ Login (eg: name, email)។", "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", @@ -213,6 +216,7 @@ "Message_AllowEditing_BlockEditInMinutes" : "បិទការកែស្រួលសារបន្ទាប់ (ជាចំនួននាទី ឬ0ដើម្បីបិទចោល)", "Message_AllowEditing_BlockEditInMinutesDescription" : "បញ្ចូលលáŸáž 0 ដើម្បីបិទការ Block", "Message_AudioRecorderEnabled" : "ការážážážŸáž˜áŸ’áž›áŸáž„បានអនុញ្ញាážáž·", + "Message_AudioRecorderEnabledDescription" : "ážáŸ’រូវការឯកសារប្រភáŸáž‘ 'audio/wav' ក្នុងការកំណážáŸ‹ 'File Upload' ", "Message_deleting_not_allowed" : "ការ​លប់សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", "Message_editing_blocked" : "សារ​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ážáŸ’រូវ​បាន​កែប្រែ​ទៀážâ€‹áž‘áŸ", "Message_editing_not_allowed" : "ការ​កែ​សម្រួល​សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", @@ -241,6 +245,7 @@ "n_messages" : "%s សារ", "Name" : "Name", "Name_cant_be_empty" : "ឈ្មោះ​មិន​អាច​ទទáŸ", + "Name_optional" : "ឈ្មោះ (ស្រáŸáž…​ចិážáŸ’ážâ€‹)", "New_messages" : "សារ​ážáŸ’មី", "New_password" : "ពាក្យ​សម្ងាážáŸ‹â€‹ážáŸ’មី", "No_channel_with_name_%s_was_found" : "មិន​មាន​ប៉ុស្ážáž·áŸâ€‹ážˆáŸ’មោះ <strong>\"%s\"</strong> ឡើយ​", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index b066ea7f2afd42ec203fa256ef514e5022397add..3804dedd2f5d712f253fbd33b1a2f8d99f1e05a5 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -1,13 +1,21 @@ { + "Access_not_authorized" : "액세스 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤", "Access_online_demo" : "온ë¼ì¸ ë°ëª¨ ì ‘ì†", "Access_Online_Demo" : "온ë¼ì¸ ë°ëª¨ ì ‘ì†", "Accounts" : "ê³„ì •", + "Accounts_AllowedDomainsList" : "허용 가능한 ë„ë©”ì¸ ëª©ë¡", + "Accounts_AllowPasswordChange" : "암호 변경 허용", "Accounts_AllowUserAvatarChange" : "ì‚¬ìš©ìž ì•„ë°”íƒ€ ë³€ê²½ì„ í—ˆìš©", + "Accounts_AllowUsernameChange" : "ì‚¬ìš©ìž ì´ë¦„ 변경 허용", "Accounts_AllowUserProfileChange" : "ì‚¬ìš©ìž í”„ë¡œí•„ ë³€ê²½ì„ í—ˆìš©", + "Accounts_AvatarResize" : "아바타 í¬ê¸° ì¡°ì •", "Accounts_AvatarSize" : "아바타 í¬ê¸°", + "Accounts_AvatarStorePath" : "아바타 ì €ìž¥ 경로", + "Accounts_AvatarStoreType" : "아바파 ì €ìž¥ 타입", "Accounts_denyUnverifiedEmail" : "확ì¸ë˜ì§€ ì•Šì€ ì´ë©”ì¼ ê±°ë¶€", "Accounts_EmailVerification" : "ì´ë©”ì¼ í™•ì¸", - "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", + "Accounts_Enrollment_Email" : "등ë¡í•œ ì´ë©”ì¼", + "Accounts_ManuallyApproveNewUsers" : "수ë™ìœ¼ë¡œ 새로운 ì‚¬ìš©ìž ìŠ¹ì¸", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize 경로", "Accounts_OAuth_Custom_Button_Color" : "버튼 색", "Accounts_OAuth_Custom_Button_Label_Color" : "버튼 í…스트 색", @@ -25,6 +33,8 @@ "Accounts_OAuth_Github_id" : "Github ID", "Accounts_OAuth_Github_secret" : "Github 암호", "Accounts_OAuth_Gitlab" : "OAuth 활성화", + "Accounts_OAuth_Gitlab_id" : "Gitlab ID", + "Accounts_OAuth_Gitlab_secret" : "Client 암호", "Accounts_OAuth_Google" : "구글 로그ì¸", "Accounts_OAuth_Google_id" : "구글 ID", "Accounts_OAuth_Google_secret" : "구글 암호", @@ -37,6 +47,12 @@ "Accounts_OAuth_Twitter" : "트위터 로그ì¸", "Accounts_OAuth_Twitter_id" : "트위터 ID", "Accounts_OAuth_Twitter_secret" : "트위터 암호", + "Accounts_PasswordReset" : "암호 ìž¬ì„¤ì •", + "Accounts_RegistrationForm" : "ë“±ë¡ ì–‘ì‹", + "Accounts_RegistrationForm_Disabled" : "비활성화", + "Accounts_RegistrationForm_Public" : "공개", + "Accounts_RegistrationForm_Secret_URL" : "비밀 URL", + "Accounts_RegistrationForm_SecretURL" : "ë“±ë¡ ì–‘ì‹ ë¹„ë°€ URL", "Accounts_RegistrationRequired" : "등ë¡ì‹œ 필수", "Activate" : "활성화", "Add_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth 추가", @@ -44,15 +60,19 @@ "Add_users" : "ì‚¬ìš©ìž ì¶”ê°€", "Administration" : "관리", "All_channels" : "ëª¨ë“ ì±„ë„", + "Allow_Invalid_SelfSigned_Certs" : "ìž˜ëª»ëœ Self-Signed Certs 허용", "and" : "ê·¸ë¦¬ê³ ", "API" : "API", "API_Analytics" : "분ì„", "API_Embed" : "í¬í•¨", + "API_EmbedDisabledFor" : "사용ìžì—대한 Embed 비활성화", + "API_EmbedDisabledFor_Description" : "쉼표로 êµ¬ë¶„ëœ ì‚¬ìš©ìž ì´ë¦„ 목ë¡", "are_also_typing" : "ë˜í•œ ìž…ë ¥ì¤‘", "are_typing" : "ìž…ë ¥ 중", "Are_you_sure" : "괜찮아요?", "Auto_Load_Images" : "ì´ë¯¸ì§€ ìžë™ 로드", "Avatar_changed_successfully" : "아바타를 성공ì 으로 변경하였습니다", + "Avatar_url_invalid_or_error" : "ì§€ì •ëœ URLì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ ì ‘ê·¼í• ìˆ˜ 없습니다. 다른 URLë¡œ 다시 ì‹œë„하세요.", "away" : "ìžë¦¬ë¹„움", "Away" : "ìžë¦¬ë¹„움", "away_female" : "ìžë¦¬ë¹„움", @@ -68,26 +88,31 @@ "busy_male" : "ë°”ì¨", "Busy_male" : "ë°”ì¨", "Cancel" : "취소", + "CDN_PREFIX" : "CDN Prefix", + "Certificates_and_Keys" : "ì¸ì¦ì„œì™€ 키", "Change_avatar" : "아바타 변경", "Channels" : "채ë„", "Channels_list" : "공개 ì±„ë„ ë¦¬ìŠ¤íŠ¸", "Chat_Rooms" : "채팅방", + "Clear_all_unreads_question" : "ì½ì§€ ì•Šì€ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆê¹Œ?", "close" : "닫기", "coming_soon" : "곧", "Commands" : "ëª…ë ¹", + "Compact_View" : "축소해 보기", "Confirm_password" : "암호를 확ì¸í•˜ì„¸ìš”", "Contact" : "ì ‘ì†", "Conversation" : "대화", - "Convert_Ascii_Emojis" : "ASCII를 Emojisë¡œ 변환", + "Convert_Ascii_Emojis" : "ì´ëª¨ì§€ë¥¼ ASCIIë¡œ 변환", "Create_new" : "새로 만들기", "Create_new_direct_message_room" : "새 ê·“ì†ë§ ë°© 만들기 ", - "Create_new_private_group" : "새로운 ê°œì¸ ê·¸ë£¹ì„ ë§Œë“니다", - "Create_new_public_channel" : "새 공용 ì±„ë„ ìƒì„±", + "Create_new_private_group" : "새로운 ë¹„ë°€Â ê·¸ë£¹ì„ ë§Œë“니다", + "Create_new_public_channel" : "새 ê³µê°œÂ ì±„ë„ ìƒì„±", "Created_at" : "ì œìž‘", + "Custom_oauth_helper" : "OAuth Provider를 ì„¤ì •í• ë•Œ, 콜백 URLì„ ì•Œë ¤ì¤˜ì•¼í•©ë‹ˆë‹¤. <pre>%s</pre>를 사용.", "Custom_oauth_unique_name" : "ì‚¬ìš©ìž ì •ì˜ OAuth ê³ ìœ í•œ ì´ë¦„", "days" : "ì¼", "Deactivate" : "비활성화", - "Delete_Room_Warning" : "ë°©ì„ ì‚ì œí•˜ë©´ ë°©ì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì´ ìž‘ì—…ì€ ë˜ëŒë¦´ 수 없습니다.", + "Delete_Room_Warning" : "ë°©ì„ ì‚ì œí•˜ë©´ ëª¨ë“ ë©”ì‹œì§€ê°€ ì‚ì œë©ë‹ˆë‹¤. ì´ ìž‘ì—…ì€ ì·¨ì†Œí• ìˆ˜ 없습니다.", "Delete_User_Warning" : "ì‚¬ìš©ìž ì‚ì œì‹œ 사용ìžì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì·¨ì†Œí• ìˆ˜ 없습니다.", "Deleted" : "ì‚ì œ!", "Desktop_Notifications" : "바탕화면 알림", @@ -97,27 +122,34 @@ "Disable_Favorite_Rooms" : "ì¦ê²¨ì°¾ê¸° 사용안함", "Disable_New_Message_Notification" : "새 메시지 알림 비활성화", "Disable_New_Room_Notification" : "새 ë°© 알림 비활성화", + "Do_you_want_to_change_to_s_question" : "<strong>%s</strong>으로 변경합니까?", "Drop_to_upload_file" : "ì—…ë¡œë“œí• íŒŒì¼ ë“œë¡", "Duplicate_channel_name" : "'%s' ì±„ë„ ì´ë¦„ì€ ì´ë¯¸ 존재합니다.", - "Duplicate_private_group_name" : "'%s'는 ì´ë¯¸ 존재하는 ê°œì¸ ê·¸ë£¹ìž…ë‹ˆë‹¤.", + "Duplicate_private_group_name" : "'%s'는 ì´ë¯¸ 존재하는 비밀 그룹입니다.", "E-mail" : "ì´ë©”ì¼", "edited" : "ìˆ˜ì •ë¨", "Email_already_exists" : "ì´ë©”ì¼ì´ ì´ë¯¸ 존재합니다", "Email_or_username" : "ì´ë©”ì¼ ë˜ëŠ” ì‚¬ìš©ìž ì´ë¦„", "Email_verified" : "Email 확ì¸", "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "바탕화면 알림 활성화", "Enter_info" : "ë¡œê·¸ì¸ ì •ë³´ë¥¼ ìž…ë ¥í•˜ì„¸ìš”", "Enter_to" : "Enter to", - "Error_changing_password" : "암호 변경 중 오류 ë°œìƒ", + "Error" : "오류", + "Error_changing_password" : "암호 변경 중 오류 ë°œìƒ", + "Error_too_many_requests" : "너무 ë§Žì€ ìš”ì²ìœ¼ë¡œ ì—러발ìƒ. 천천히 하세요. %s ì´ˆ ì´í›„ ìž…ë ¥í• ìˆ˜ 있습니다", "Esc_to" : "Esc to", "False" : "False", "Favorites" : "ì¦ê²¨ì°¾ê¸°", "FileUpload" : "íŒŒì¼ ì—…ë¡œë“œ", + "FileUpload_Enabled" : "íŒŒì¼ ì—…ë¡œë“œ 활성화", "FileUpload_MaxFileSize" : "íŒŒì¼ ì—…ë¡œë“œ 최대 í¬ê¸° (ë°”ì´íŠ¸ 단위)", + "FileUpload_MediaTypeWhiteList" : "허용 가능한 미디어 타입", + "FileUpload_MediaTypeWhiteListDescription" : "쉼표로 êµ¬ë¶„ëœ ë¯¸ë””ì–´ 타입 목ë¡", "Follow_social_profiles" : "소셜 프로파ì¼ì— ë”°ë¼ì£¼ì‹ì‹œì˜¤. Githubì—ì„œ í¬í¬í•˜ê³ , ìš°ë¦¬ì˜ trello ë³´ë“œì—ì„œ rocket.chat appì—대한 ì˜ê²¬ì„ ê³µìœ í•©ë‹ˆë‹¤.", "Forgot_password" : "암호를 잊었습니다", "Fork_it_on_github" : "Githubì—ì„œ í¬í¬", - "From_Email" : "ì´ë©”ì¼ë¡œë¶€í„°", + "From_Email" : "ì´ë©”ì¼ì—ì„œ", "General" : "ì¼ë°˜", "Get_to_know_the_team" : "Rocket.Team 알아보기", "github_no_public_email" : "Github ê³„ì •ì— ê³µê°œëœ ì´ë©”ì¼ì´ 없습니다.", @@ -129,11 +161,19 @@ "hours" : "시간", "Incorrect_Password" : "ìž˜ëª»ëœ ì•”í˜¸", "inline_code" : "inline_code", + "Install_FxOs" : "파ì´ì–´íìŠ¤ì— Rocket.Chat 설치", + "Install_FxOs_done" : "좋습니다! 홈 스í¬ë¦°ì˜ ì•„ì´ì½˜ì„ 통해 Rock.Chatì„ ì‚¬ìš©í• ìˆ˜ 있습니다. Rock.Chatê³¼ ì¦ê±°ìš´ ì‹œê°„ì„ ë³´ë‚´ì‹ì‹œì˜¤.", + "Install_FxOs_error" : "미안, ì˜ë„한대로 ìž‘ë™í•˜ì§€ 않았습니다. ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤:", + "Install_FxOs_follow_instructions" : "ìž¥ì¹˜ì— ì‘ìš© 프로그램 설치를 확ì¸í•˜ì‹ì‹œì˜¤ ( \"설치\" 메시지가 뜨면).", "Invalid_confirm_pass" : "암호가 ì¼ì¹˜í•˜ì§€ 않습니다", "Invalid_email" : "ìž…ë ¥í•œ ì´ë©”ì¼ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤", + "Invalid_file_height" : "ìž˜ëª»ëœ íŒŒì¼ ë†’ì´", + "Invalid_file_type" : "ìž˜ëª»ëœ íŒŒì¼ í˜•ì‹", + "Invalid_file_width" : "ìž˜ëª»ëœ íŒŒì¼ ë„ˆë¹„", "Invalid_name" : "ì´ë¦„ì„ ë¹„ì›Œ 둘 수 없습니다", "Invalid_pass" : "암호를 비워 둘 수 없습니다", "Invalid_room_name" : "<strong>%s</strong>ì€ ì‚¬ìš© 가능한 ë°© ì´ë¦„ì´ ì•„ë‹™ë‹ˆë‹¤.<br/>소문ìž, 숫ìž, 대시만 ì‚¬ìš©í• ìˆ˜ 있습니다", + "Invalid_Secret_URL" : "ìž˜ëª»ëœ ë¹„ë°€ URL", "invisible" : "보지 ì•ŠìŒ", "Invisible" : "보지 ì•ŠìŒ", "Invitation_HTML" : "HTML 초대 페ì´ì§€", @@ -162,9 +202,14 @@ "Layout_Sidenav_Footer_description" : "바닥글 í¬ê¸°ëŠ” 260x70입니다.", "Layout_Terms_of_Service" : "ì´ìš©ì•½ê´€", "LDAP" : "LDAP", + "LDAP_Bind_Search" : "검색 ê°ì¶”기", "LDAP_Description" : "LDAP는 ë§Žì€ ê¸°ì—…ë“¤ì´ í†µí•© ì¸ì¦ì„ ì œê³µí•˜ê¸° 위해 사용하는 계층ì ì¸ ë°ì´í„°ë² ì´ìŠ¤ìž…니다. 여러 사ì´íŠ¸ì™€ 서비스 ê°„ì— í•˜ë‚˜ì˜ ì•”í˜¸ë¥¼ ê³µìœ í•˜ê¸° 위한 기능으로, ìžì„¸í•œ ì •ë³´ëŠ” 위키를 ì°¸ê³ í•˜ì„¸ìš”: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP", - "LDAP_DN" : "LDAP DN", + "LDAP_DN" : "ê³ ìœ ì´ë¦„ (DN)", + "LDAP_Enable" : "LDAP 사용", "LDAP_Port" : "LDAP í¬íŠ¸", + "LDAP_Sync_User_Data" : "ë°ì´í„° ë™ê¸°í™”", + "LDAP_Sync_User_Data_Description" : "ì„œë²„ì— ë¡œê·¸ì¸í• ë•Œ ì‚¬ìš©ìž ë°ì´í„°ì˜ ë™ê¸°í™”를 ìœ ì§€í•˜ì„¸ìš”(예: ì´ë¦„, ì´ë©”ì¼).", + "LDAP_Sync_User_Data_FieldMap" : "ì‚¬ìš©ìž ë°ì´í„° í•„ë“œ 맵", "LDAP_Url" : "LDAP URL", "Leave_room" : "ë°© 나가기", "line" : "밑줄", @@ -178,13 +223,17 @@ "Logout" : "로그아웃", "Make_Admin" : "ê´€ë¦¬ìž ê¶Œí•œ ìƒì„±", "Mark_as_read" : "ì½ì—ˆìŒ", + "Markdown_Headers" : "마í¬ë‹¤ìš´ í•´ë”", "Members" : "멤버", "Members_List" : "멤버 리스트", "Members_placeholder" : "멤버", "Message" : "메시지", "Message_AllowDeleting" : "메시지 ì‚ì œ 허용", "Message_AllowEditing" : "메시지 ìˆ˜ì • 허용", - "Message_AllowEditing_BlockEditInMinutes" : "ì´í›„ë¡œ 메시지 ìˆ˜ì • ì•ˆë¨ (분 - 0 ì€ ì‚¬ìš©ì•ˆí•¨)", + "Message_AllowEditing_BlockEditInMinutes" : "(n) 분 ì´í›„ë¡œ ìˆ˜ì •í• ìˆ˜ 없습니다", + "Message_AllowEditing_BlockEditInMinutesDescription" : "0ì„ ìž…ë ¥í•˜ë©´ 블로킹 비활성화", + "Message_AudioRecorderEnabled" : "ìŒì„± ë…¹ìŒ í™œì„±í™”", + "Message_AudioRecorderEnabledDescription" : "'audio/wav' 파ì¼ì€ 'íŒŒì¼ ì—…ë¡œë“œ' ì„¤ì •ì—ì„œ 허용한 미디어 타입ì´ì–´ì•¼ 합니다.", "Message_deleting_not_allowed" : "메시지 ì‚ì œë¥¼ í• ìˆ˜ 없습니다.", "Message_editing_blocked" : "메시지를 ë” ì´ìƒ ìˆ˜ì •í• ìˆ˜ 없습니다.", "Message_editing_not_allowed" : "메시지 ìˆ˜ì •ì„ í• ìˆ˜ 없습니다.", @@ -195,13 +244,14 @@ "Message_removed" : "메시지 ì œê±°", "Message_ShowDeletedStatus" : "ì‚ì œëœ ìƒíƒœ 확ì¸", "Message_ShowEditedStatus" : "ìˆ˜ì • ìƒíƒœ 확ì¸", + "Message_ShowFormattingTips" : "í¬ë©§ íŒ ë³´ê¸°", "Messages" : "메시지", "Meta" : "메타", "Meta_fb_app_id" : "페ì´ìŠ¤ë¶ APP ID", "Meta_google-site-verification" : "Google 사ì´íŠ¸ 확ì¸", "Meta_language" : "언어", "Meta_msvalidate01" : "MSValidate.01", - "Meta_robots" : "검색 로봇", + "Meta_robots" : "로봇", "minutes" : "분", "More_channels" : "추가 채ë„", "More_groups" : "비밀 그룹 ë”보기", @@ -218,12 +268,13 @@ "No_channel_with_name_%s_was_found" : "<strong>\"%s\"</strong> ì±„ë„ ì´ë¦„ì„ ì°¾ì„ ìˆ˜ 없습니다!", "No_channels_yet" : "ì–´ë– í•œ 채ë„ì—ë„ ê°€ìž…í•˜ì§€ 않았습니다.", "No_direct_messages_yet" : "ì–´ë–¤ ê·“ì†ë§ë„ 하지 않았습니다.", - "No_favorites_yet" : "ì¦ê²¨ì°¾ê¸°ê°€ 없습니다.", + "No_favorites_yet" : "ì•„ì§ ì¦ê²¨ì°¾ê¸°ë¥¼ 추가하지 않았습니다.", "No_group_with_name_%s_was_found" : "<strong>\"%s\"</strong> 비밀 그룹 ì´ë¦„ì„ ì°¾ì„ ìˆ˜ 없습니다!", - "No_groups_yet" : "ê°œì¸ ê·¸ë£¹ì„ ë§Œë“¤ì§€ 않았습니다.", + "No_groups_yet" : "비밀 ê·¸ë£¹ì„ ë§Œë“¤ì§€ 않았습니다.", "No_permission_to_view_room" : "ì´ ë°©ì„ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤", "No_user_with_username_%s_was_found" : "<strong>\"%s\"</strong> ì‚¬ìš©ìž ì´ë¦„ì„ ê°€ì§„ 사용ìžë¥¼ ì°¾ì„ ìˆ˜ 없습니다!", "Not_allowed" : "허용ë˜ì§€ ì•ŠìŒ", + "Not_authorized" : "ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤", "Not_found_or_not_allowed" : "ì°¾ì„ ìˆ˜ 없거나 허용ë˜ì§€ 않았습니다", "Nothing_found" : "ì°¾ì„ ìˆ˜ 없습니다", "Notify_all_in_this_room" : "ì´ ë°©ì— ìžˆëŠ” ëª¨ë“ ì´ì—게 알림", @@ -233,19 +284,21 @@ "Only_you_can_see_this_message" : "ì´ ë©”ì‹œì§€ëŠ” ë‹¹ì‹ ë§Œ ë³¼ 수 있습니다", "Oops!" : "ì•„ì°¨", "Opt_out_statistics" : "ë‚˜ì˜ ì–´ë–¤ 무기명 í†µê³„ë„ Rocket.chat으로 보내지 마ì‹ì‹œì˜¤.", - "Opt_out_statistics_warning" : "ë‹¹ì‹ ì˜ ë¬´ê¸°ëª… 통계 ìžë£Œë¥¼ ì „ì†¡í•˜ëŠ” 것으로 우리는 ëª‡ê°œì˜ Rocket.Chat 서비스를 설치하였는지 ì•Œ 수 있으며 얼마나 ì‹œìŠ¤í…œì´ ìž˜ ìž‘ë™í•˜ëŠ”지 ì•Œ ìˆ˜ë¡ ì„œë¹„ìŠ¤ë¥¼ ê°œì„ í•˜ëŠ”ë° ë„ì›€ì´ ë©ë‹ˆë‹¤. ë§Œì¼ ë¬´ê¸°ëª… 통계 ì •ë³´ë¥¼ ì „ì†¡í•˜ê¸¸ ì›í•˜ì‹œë©´ ìœ„ì˜ ì²´í¬ë°•ìŠ¤ë¥¼ ì„¤ì •ì„ í•´ì œí•´ì£¼ì‹ì‹œì˜¤. ê³ ë§™ìŠµë‹ˆë‹¤.", + "Opt_out_statistics_warning" : "ë°°í¬ëœ Rocket.Chatì—대한 여럿 ì¸ìŠ¤í„´ìŠ¤ë“¤ì„ 확ì¸í•˜ì—¬ 통계를 ì „ì†¡í•˜ê²Œë˜ë©´ 우리는 ë¬¸ì œì ì„ í™•ì¸í•˜ê³ ë” ì¢‹ì€ ì‹œìŠ¤í…œì„ ë§Œë“¤ 수 있습니다. ì‚¬ìš©ìž ì •ë³´ë¥¼ 보내지 않으며, 우리가 ë°›ì€ ì •ë³´ëŠ” ëª¨ë‘ ë¹„ë°€ìœ ì§€ê°€ ë©ë‹ˆë‹¤. 만약 계ì†í•´ì„œ 통계를 ë³´ë‚´ê³ ì‹¶ë‹¤ë©´ ì²´í¬ë°•ìŠ¤ë¥¼ í•´ì œí•˜ì‹œë©´ ë©ë‹ˆë‹¤. ê°ì‚¬í•©ë‹ˆë‹¤.", "others" : "다른 사람", "Password" : "암호", + "Password_Change_Disabled" : "Rock.Chat 관리ìžëŠ” 암호 ë³€ê²½ì„ í• ìˆ˜ 없습니다.", "Password_changed_successfully" : "암호를 성공ì 으로 변경하였습니다.", "People" : "사람들", + "Please_enter_value_for_url" : "아바타 URLì„ ìž…ë ¥í•˜ì‹ì‹œì˜¤.", "Please_wait" : "ìž ì‹œë§Œ ê¸°ë‹¤ë ¤ 주세요.", "Please_wait_activation" : "ì‹œê°„ì´ ì¢€ 걸릴 수 있습니다. ìž ì‹œë§Œ ê¸°ë‹¤ë ¤ì£¼ì‹ì‹œì˜¤.", "Please_wait_statistics" : "통계를 ìƒì„± 중입니다. ìž ì‹œë§Œ ê¸°ë‹¤ë ¤ì£¼ì‹ì‹œì˜¤.", "Powered_by" : "Powered by", "Preferences" : "ì„¤ì •", "Preferences_saved" : "ì„¤ì • ì €ìž¥í•¨.", - "Privacy" : "ê°œì¸ì •ë³´ë³´í˜¸", - "Private_Groups" : "ê°œì¸ ê·¸ë£¹", + "Privacy" : "프ë¼ì´ë²„ì‹œ", + "Private_Groups" : "비밀 그룹", "Private_Groups_list" : "비밀 그룹 목ë¡", "Profile" : "프로필", "Profile_saved_successfully" : "í”„ë¡œí•„ì„ ì„±ê³µì 으로 ì €ìž¥", @@ -257,9 +310,12 @@ "Push_apn_dev_passphrase" : "APN 개발 암호", "Push_apn_key" : "APN 키", "Push_apn_passphrase" : "APN 암호", - "Push_debug" : "디버그", - "Push_enable" : "사용", + "Push_debug" : "Debug", + "Push_enable" : "사용 가능", + "Push_gcm_api_key" : "GCM API Key", + "Push_gcm_project_number" : "GCM 프로ì 트 번호", "Push_production" : "Production", + "Push_test_push" : "테스트", "Quick_Search" : "ë¹ ë¥¸ 찾기", "quote" : "ì¸ìš©", "Recents" : "최근", @@ -270,15 +326,25 @@ "Remove" : "ì‚ì œ", "Remove_Admin" : "ê´€ë¦¬ìž ê¶Œí•œ ì œê±°", "Remove_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth ì œê±°", + "Removed" : "ì œê±°ë¨", "Reset_password" : "암호 ìž¬ì„¤ì •", + "Restart" : "재시작", "Room" : "ë°©", + "Room_has_been_deleted" : "ë°©ì´ ì‚ì œë˜ì—ˆìŠµë‹ˆë‹¤", "Room_name_changed" : "ë°© ì´ë¦„ 변경: <em>__user_by__</em>ì—ì„œ <em>__room_name__</em>ë¡œ.", "Room_name_changed_successfully" : "ë°© ì´ë¦„ 변경 완료", "Room_not_found" : "ë°©ì„ ì°¾ì„ ìˆ˜ 없습니다.", "Room_uploaded_file_list" : "íŒŒì¼ ëª©ë¡", + "Room_uploaded_file_list_empty" : "파ì¼ì„ ì‚¬ìš©í• ìˆ˜ 없습니다.", "room_user_count" : "%s 사용ìž", "Rooms" : "ë°©", + "S_new_messages_since_s" : "%s 새로운 메시지 %s ì´í›„ë¡œ", "SAML" : "SAML", + "SAML_Custom_Cert" : "커스텀 ì¸ì¦", + "SAML_Custom_Entry_point" : "커스텀 ì ‘ê·¼ í¬ì¸íŠ¸", + "SAML_Custom_Generate_Username" : "ì‚¬ìš©ìž ì´ë¦„ ìƒì„±", + "SAML_Custom_Issuer" : "커스텀 발급ìž", + "SAML_Custom_Provider" : "커스텀 ì œê³µìž", "Save_changes" : "ë³€ê²½ì‚¬í• ì €ìž¥", "Save_Mobile_Bandwidth" : "ëª¨ë°”ì¼ ëŒ€ì—í ì €ìž¥", "Search" : "검색", @@ -303,9 +369,9 @@ "Settings_updated" : "ì„¤ì • ì—…ë°ì´íŠ¸", "Showing_online_users" : "__total__ 사용ìžì˜ <b>__total_online__</b> 표시", "Showing_results" : "<p><b>%s</b> ê²°ê³¼ 확ì¸</p>", - "Silence" : "무언", + "Silence" : "소리ë„기", "since_creation" : "%s ì´í›„", - "Site_Name" : "사ì´íŠ¸ ì´ë¦„:", + "Site_Name" : "사ì´íŠ¸ ì´ë¦„", "Site_Url" : "사ì´íŠ¸ URL", "Site_Url_Description" : "예: https://chat.domain.com/", "SMTP" : "SMTP", @@ -319,11 +385,11 @@ "Stats_Active_Users" : "활성 사용ìž", "Stats_Avg_Channel_Users" : "ì±„ë„ ì‚¬ìš©ìž í‰ê· ", "Stats_Avg_Private_Group_Users" : "비밀 그룹 ì‚¬ìš©ìž í‰ê· ", - "Stats_Away_Users" : "ìžë¦¬ë¹„움 사용ìž", + "Stats_Away_Users" : "ì‚¬ìš©ìž ìžë¦¬ë¹„움", "Stats_Max_Room_Users" : "최대 ë°© 사용ìž", "Stats_Non_Active_Users" : "비활성 사용ìž", - "Stats_Offline_Users" : "현실 세계ì¸", - "Stats_Online_Users" : "ê°€ìƒ ì„¸ê³„ì¸", + "Stats_Offline_Users" : "오프ë¼ì¸ 사용ìž", + "Stats_Online_Users" : "온ë¼ì¸ 사용ìž", "Stats_OS_Arch" : "OS Arch", "Stats_OS_Cpus" : "OS CPU 갯수", "Stats_OS_Freemem" : "OS 빈 메모리", @@ -342,17 +408,23 @@ "Stop_Recording" : "ê¸°ë¡ ì¤‘ì§€", "strike" : "ì·¨ì†Œì„ ", "Submit" : "ì œì¶œ", + "Success" : "성공", + "The_channel_name_is_required" : "ì±„ë„ ì´ë¦„ì´ í•„ìš”í•©ë‹ˆë‹¤", "The_field_is_required" : "í•„ë“œ %s는 필요합니다.", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "ë‹¹ì‹ ì˜ ì„œë²„ì— ImageMagick ë˜ëŠ” GraphicMagickì´ ì„¤ì¹˜ë˜ì–´ 있지 ì•Šì•„ ì´ë¯¸ì§€ í¬ê¸°ë¥¼ ìž¬ì¡°ì •í• ìˆ˜ 없습니다.", + "The_server_will_restart_in_s_seconds" : "서버가 %s ì´ˆ 후 재시작합니다.", "True" : "True", "Unnamed" : "ì´ë¦„ì´ì—†ëŠ”", "Upload_file_question" : "파ì¼ì„ ì—…ë¡œë“œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?", - "Use_Emojis" : "Emojis 사용", + "Uploading_file" : "íŒŒì¼ ì—…ë¡œë“œ 중...", + "Use_Emojis" : "ì´ëª¨ì§€ 사용", "Use_initials_avatar" : "ì‚¬ìš©ìž ì´ë¦„ì„ ì´ë‹ˆì…œë¡œ 사용합니다", "use_menu" : "사ì´ë“œ 메뉴를 ì´ìš©í•˜ì—¬ ë°©ê³¼ ì±„íŒ…ì— ì°¸ì—¬í• ìˆ˜ 있습니다", "Use_service_avatar" : "아바타 %s 사용", "Use_this_username" : "ì´ ì‚¬ìš©ìž ì´ë¦„ 사용", "Use_uploaded_avatar" : "ì—…ë¡œë“œëœ ì•„ë°”íƒ€ 사용", - "User_added_by" : "ì‚¬ìš©ìž <em>__user_added__</em>ì„/를 <em>__user_by__</em>ì— ì¶”ê°€í•¨.", + "Use_url_for_avatar" : "아바타 URL 사용", + "User_added_by" : "ì‚¬ìš©ìž <em>__user_added__</em>ì„/를 <em>__user_by__</em>ì— ì¶”ê°€í•©ë‹ˆë‹¤.", "User_Channels" : "ì‚¬ìš©ìž ì±„ë„", "User_has_been_activated" : "사용ìžê°€ 활성화ë˜ì—ˆìŠµë‹ˆë‹¤", "User_has_been_deactivated" : "사용ìžê°€ 비활성화ë˜ì—ˆìŠµë‹ˆë‹¤", @@ -364,16 +436,17 @@ "User_joined_channel" : "채ë„ì— ì°¸ì—¬í–ˆìŠµë‹ˆë‹¤.", "User_joined_channel_female" : "채ë„ì— ì°¸ì—¬í–ˆìŠµë‹ˆë‹¤.", "User_joined_channel_male" : "채ë„ì— ì°¸ì—¬í–ˆìŠµë‹ˆë‹¤.", - "User_left" : "ì‚¬ìš©ìž <em>__user_left__</em> ë– ë‚¨.", - "User_left_female" : "ì‚¬ìš©ìž <em>__user_left__</em> ë– ë‚¨.", - "User_left_male" : "ì‚¬ìš©ìž <em>__user_left__</em> ë– ë‚¨.", + "User_left" : "채ë„ì„ ë– ë‚¬ìŠµë‹ˆë‹¤.", + "User_left_female" : "채ë„ì„ ë– ë‚¬ìŠµë‹ˆë‹¤.", + "User_left_male" : "채ë„ì„ ë– ë‚¬ìŠµë‹ˆë‹¤.", "User_logged_out" : "사용ìžë¥¼ 로그아웃합니다", "User_not_found_or_incorrect_password" : "사용ìžë¥¼ ì°¾ì„ ìˆ˜ 없거나 ìž˜ëª»ëœ ì•”í˜¸ìž…ë‹ˆë‹¤", - "User_removed_by" : "ì‚¬ìš©ìž <em>__user_removed__</em>ì„/를 <em>__user_by__</em>ì—ì„œ ì‚ì œë¨.", + "User_removed_by" : "ì‚¬ìš©ìž <em>__user_removed__</em>ì„/를 <em>__user_by__</em>ì—ì„œ ì‚ì œí•˜ì˜€ìŠµë‹ˆë‹¤.", "User_Settings" : "ì‚¬ìš©ìž ì„¤ì •", - "User_updated_successfully" : "사용ìžë¥¼ 성공ì 으로 ì—…ë°ì´íŠ¸í•˜ì˜€ìŠµë‹ˆë‹¤.", + "User_updated_successfully" : "사용ìžë¥¼ 성공ì 으로 ì—…ë°ì´íŠ¸ 하였습니다.", "Username" : "ì‚¬ìš©ìž ì´ë¦„", "Username_cant_be_empty" : "ì‚¬ìš©ìž ì´ë¦„ì„ ë¹„ì›Œë‘˜ 수 없습니다", + "Username_Change_Disabled" : "Rocket.Chat 관리ìžëŠ” ì‚¬ìš©ìž ì´ë¦„ ë³€ê²½ì„ í• ìˆ˜ 없습니다.", "Username_description" : "ì‚¬ìš©ìž ì´ë¦„ì€ ë‹¤ë¥¸ ì‚¬ëžŒì´ ë©”ì‹œì§€ì—ì„œ ì–¸ê¸‰í• ìˆ˜ 있ë„ë¡ í•˜ëŠ”ë° ì‚¬ìš©ë©ë‹ˆë‹¤.", "Username_invalid" : "<strong>&s</strong>는 ì•Œë§žì€ ì‚¬ìš©ìžëª…ì´ ì•„ë‹™ë‹ˆë‹¤,<br/> 문ìž, 숫ìž, 마침표와 ë°‘ì¤„ì„ ì‚¬ìš©í•˜ì‹ì‹œì˜¤.", "Username_title" : "ì‚¬ìš©ìž ì´ë¦„ 등ë¡", @@ -386,9 +459,11 @@ "Welcome" : "환ì˜í•©ë‹ˆë‹¤, <em>%s</em>.", "Welcome_to_the" : "ì˜¤ì‹ ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤", "With_whom" : "누구랑?", + "Yes" : "예", "Yes_clear_all" : "예, ì „ë¶€ 지ì›ë‹ˆë‹¤!", "Yes_delete_it" : "예, ì‚ì œí•©ë‹ˆë‹¤!", "you_are_in_preview_mode_of" : "#<strong>__room_name__</strong> ì±„ë„ ë¯¸ë¦¬ë³´ê¸° 모드", + "You_have_been_muted" : "ë‹¹ì‹ ì€ ì´ì œ ì´ ë°©ì—ì„œ ë“£ì§€ë„ ë§í•˜ì§€ë„ 못합니다", "You_need_confirm_email" : "로그ì¸í•˜ë ¤ë©´ ì´ë©”ì¼ í™•ì¸ì´ 필요합니다!", "You_will_not_be_able_to_recover" : "ì´ ë©”ì‹œì§€ëŠ” ë³µêµ¬í• ìˆ˜ 없습니다!", "Your_entry_has_been_deleted" : "í•ëª©ì´ ì‚ì œë˜ì—ˆìŠµë‹ˆë‹¤.", diff --git a/i18n/lo.i18n.json b/i18n/lo.i18n.json index 11c7f733bb6bedcb857e01efaff45cf099da5687..68943c27834d15acf71557cf5b710b7494b7ee4b 100644 --- a/i18n/lo.i18n.json +++ b/i18n/lo.i18n.json @@ -1,6 +1,6 @@ { "Channels" : "ຊ່àºàº‡â€‹àº—າງ​àºàº²àº™", "edited" : "à»àºà»‰â€‹à»„ຂ", - "User_left" : "ໄດ້​ປະ​ໄວ້​ຊ່àºàº‡â€‹àº—າງ​àºàº²àº™â€‹.", - "New_password" : "ລະ​ຫັດ​ຜ່ານ​ໃຫມ່" + "New_password" : "ລະ​ຫັດ​ຜ່ານ​ໃຫມ່", + "User_left" : "ໄດ້​ປະ​ໄວ້​ຊ່àºàº‡â€‹àº—າງ​àºàº²àº™â€‹." } \ No newline at end of file diff --git a/i18n/nl.i18n.json b/i18n/nl.i18n.json index 0e333939023179c68953bb185917bd5d7c27e3ed..6a04b1d6d65c6654bf5706448f104c3d60959f51 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -1,14 +1,35 @@ { + "Access_not_authorized" : "Toegang niet geautoriseerd", "Access_online_demo" : "Toegang tot de online demo", "Access_Online_Demo" : "Toegang tot de online demo", + "Accounts" : "Accounts", + "Accounts_AllowedDomainsList" : "Toegestaan ​​Domeinen Lijst", + "Accounts_AllowPasswordChange" : "Toestaan wachtwoord wijzigen", + "Accounts_AllowUsernameChange" : "Toestaan wijzigen gebruikersnaam", + "Accounts_AvatarResize" : "Wijzig Avatar grootte", + "Accounts_AvatarSize" : "Avatar grootte", "Accounts_denyUnverifiedEmail" : "Weiger ongeverifieerde e-mail", "Accounts_EmailVerification" : "Email verificatie", + "Accounts_LoginExpiration" : "Login Vervaltermijn in Dagen", + "Accounts_ManuallyApproveNewUsers" : "Handmatig goedkeuren Nieuwe Gebruikers", + "Accounts_OAuth_Custom_Authorize_Path" : "Machtigen Path", + "Accounts_OAuth_Custom_Button_Color" : "Knop Color", + "Accounts_OAuth_Custom_Button_Label_Color" : "Knop Tekst Kleur", + "Accounts_OAuth_Custom_Button_Label_Text" : "Knop Tekst", + "Accounts_OAuth_Custom_Enable" : "Inschakelen", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identiteit Path", + "Accounts_OAuth_Custom_Login_Style" : "Login Stijl", + "Accounts_OAuth_Custom_Secret" : "Geheim", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook Inloggen", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", "Accounts_OAuth_Github" : "OAuth Ingeschakeld", "Accounts_OAuth_Github_id" : "Client Id", "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Gitlab_id" : "Gitlab Id", "Accounts_OAuth_Google" : "Google Inloggen", "Accounts_OAuth_Google_id" : "Google Id", "Accounts_OAuth_Google_secret" : "Google Secret", @@ -21,24 +42,43 @@ "Accounts_OAuth_Twitter" : "Twitter Inloggen", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Wachtwoord reset", + "Accounts_RegistrationForm" : "Registratieformulier", + "Accounts_RegistrationForm_Disabled" : "Uitgeschakeld", + "Accounts_RegistrationForm_Public" : "Openbaar", + "Accounts_RegistrationForm_Secret_URL" : "Geheime URL", "Accounts_RegistrationRequired" : "Registratie vereist", + "Activate" : "Activeren", + "Add_custom_oauth" : "Voeg aangepaste OAuth toe", "Add_Members" : "Voeg leden toe", "Add_users" : "Gebruikers toevoegen", "Administration" : "Administratie", + "Alias" : "Alias", "All_channels" : "Alle kanalen", + "Allow_Invalid_SelfSigned_Certs" : "Sta Ongeldige Self-Signed Certs toe", "and" : "en", + "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Embed", + "API_EmbedDisabledFor" : "Embed voor gebruikers uitschakelen", + "API_EmbedDisabledFor_Description" : "Komma's gescheiden lijst van gebruikersnamen", + "Application_added" : "Applicatie toegevoegd", + "Application_Name" : "Naam van de toepassing", + "Application_updated" : "Applicatie bijgewerkt", + "Archive" : "Archiveren", "are_also_typing" : "zijn ook aan het typen", "are_typing" : "zijn aan het typen", "Are_you_sure" : "Weet u het zeker?", + "Auto_Load_Images" : "Automatisch afbeeldingen laden", "Avatar_changed_successfully" : "Afbeelding is gewijzigd", + "Avatar_URL" : "Afbeelding URL", "away" : "Afwezig", "Away" : "Afwezig", "away_female" : "afwezig", "Away_female" : "Afwezig", "away_male" : "afwezig", "Away_male" : "Afwezig", + "Back_to_applications" : "Terug naar toepassingen", "Back_to_login" : "Terug naar Inloggen", "bold" : "vetgedrukt", "busy" : "Bezet", @@ -52,21 +92,39 @@ "Channels" : "Kanalen", "Channels_list" : "Lijst van de openbare kanalen", "Chat_Rooms" : "Kanalen", + "Choose_the_alias_that_will_appear_before_the_username_in_messages" : "Kies de alias die zal verschijnen voor de gebruikersnaam in berichten.", + "Clear_all_unreads_question" : "Wis alle ongelezen?", + "Client_ID" : "Client ID", "close" : "Sluiten", "coming_soon" : "binnekort beschikbaar", + "Commands" : "Commando's", + "Compact_View" : "Compacte weergave", "Confirm_password" : "Bevestig uw wachtwoord", "Contact" : "Contact", "Conversation" : "Gesprek", + "Convert_Ascii_Emojis" : "ASCII naar Emoji Converteren ", "Create_new" : "Maak nieuw", "Create_new_direct_message_room" : "Maak een nieuw direct bericht kamer", "Create_new_private_group" : "Maak een nieuwe privé-groep", "Create_new_public_channel" : "Maak een nieuw publiek kanaal", "Created_at" : "Gemaakt op", + "Created_at_s_by_s" : "Gemaakt op <strong>%s</strong> door <strong>%s</strong>", + "Custom_oauth_unique_name" : "Aangepaste OAuth unieke naam", "days" : "dagen", + "Deactivate" : "Deactiveren", "Delete_User_Warning" : "Een gebruiker verwijderen betekent dat alle berichten van die gebruiker ook verwijderd worden. Dit kan niet ongedaan gemaakt worden.", "Deleted" : "Verwijderd!", + "Desktop_Notifications" : "Desktop Meldingen", + "Desktop_Notifications_Disabled" : "Desktop Meldingen zijn uitgeschakeld. Wijzig uw browser voorkeuren als u Meldingen ingeschakeld wil hebben.", + "Desktop_Notifications_Enabled" : "Desktop Meldingen zijn ingeschakeld", "Direct_Messages" : "Directe berichten", + "Disable_Favorite_Rooms" : "Favorieten Uitschakelen", + "Disable_New_Message_Notification" : "Notificatie voor nieuwe berichten uitzetten", + "Disable_New_Room_Notification" : "Notificatie voor nieuwe kamer/room uitzetten", + "Do_you_want_to_change_to_s_question" : "Wilt u <strong>%s</strong> veranderen?", "Drop_to_upload_file" : "Sleep hierheen om een bestand te uploaden", + "Duplicate_archived_channel_name" : "An gearchiveerd kanaal met naam '%s' bestaat al", + "Duplicate_archived_private_group_name" : "An gearchiveerde privé-group met naam '%s' bestaat al", "Duplicate_channel_name" : "Een kanaal met de naam '%s' bestaat reeds", "Duplicate_private_group_name" : "Een privé-groep met de naam '%s' bestaat reeds", "E-mail" : "E-mail", @@ -74,27 +132,59 @@ "Email_already_exists" : "Emailadres bestaat al", "Email_or_username" : "E-mail of gebruikersnaam", "Email_verified" : "E-mail geverifiëerd", + "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "Zet Desktop Meldingen aan", "Enter_info" : "Voer uw gegevens in", + "Enter_to" : "Ga binnen bij", + "Error" : "Fout", "Error_changing_password" : "Fout bij het veranderen van het wachtwoord", + "Error_too_many_requests" : "Fout, te veel verzoeken. Gelieve vertragen. U moet %s seconden wachten alvorens opnieuw te proberen", + "Esc_to" : "Esc om", + "Example_s" : "Voorbeeld: <code class=\"inline\">%s</code>", "False" : "False", "Favorites" : "Favorieten", + "FileUpload" : "Bestand uploaden", + "FileUpload_Enabled" : "File uploaden ingeschakeld", + "FileUpload_File_Empty" : "Bestand leeg", + "FileUpload_MaxFileSize" : "Maximale bestandgsgrootte voor uploads (in bytes)", + "FileUpload_MediaType_NotAccepted" : "Mediatypen niet geaccepteerd", + "FileUpload_MediaTypeWhiteList" : "Geaccepteerde Media Types", + "FileUpload_ProtectFiles" : "Bescherm geüploade bestanden", + "FileUpload_ProtectFilesDescription" : "Alleen geverifieerde gebruikers hebben toegang", "Follow_social_profiles" : "Volg ons via de sociale netwerken, kopieer ons op GitHub en deel uw mening over de rocket.chat app op onze Trello pagina.", "Forgot_password" : "Wachtwoord vergeten", "Fork_it_on_github" : "Kopieer ons op GitHub", + "From_Email" : "Afzender e-mail", + "General" : "Algemeen", "Get_to_know_the_team" : "Maak kennis met het Rocket.Team", "github_no_public_email" : "U heeft geen openbaar e-mail adres in uw GitHub toegang", - "Have_your_own_chat" : "Gebruik uw eigen webchat. Ontwikkeld met Meteor.com, Rocket.Chat is een goede oplossing voor ontwikkelaars omeenn eigen chat-platform in te richten en te ontwikkelen.", + "Give_a_unique_name_for_the_custom_oauth" : "Geef een unieke naam voor de aangepaste OAuth", + "Has_more" : "Heeft meer", + "Have_your_own_chat" : "Gebruik uw eigen webchat. Ontwikkeld met Meteor.com, Rocket.Chat is een goede oplossing voor ontwikkelaars om een eigen chat-platform in te richten en te verder te ontwikkelen.", "Hide_room" : "Kamer verbergen", "History" : "Geschiedenis", "hours" : "uur", + "Incorrect_Password" : "Verkeerd paswoord", "inline_code" : "inline_code", + "Install_Extension" : "Installeer Uitbreiding", + "Install_FxOs" : "Rocket.Chat installeren op uw Firefox-", + "Install_FxOs_error" : "Sorry, dat werkte niet zoals de bedoeling! De volgende fout is verschenen:", + "Integration_added" : "Integratie is toegevoegd", + "Integration_updated" : "Integratie is bijgewerkt", "Invalid_confirm_pass" : "De wachtwoorden zijn niet gelijk", "Invalid_email" : "Ongeldig e-mail adres", + "Invalid_file_height" : "Ongeldige hoogte", + "Invalid_file_type" : "Ongeldig bestandstype", + "Invalid_file_width" : "Ongeldige breedte", "Invalid_name" : "De naam mag niet leeg zijn", "Invalid_pass" : "Het wachtwoord mag niet leeg zijn", "Invalid_room_name" : "<strong>%s</strong> is geen geldige naam,<br/> gebruik alleen letters, cijfers en streepjes", + "Invalid_room_type" : "<strong>%s</strong> is geen geldig kamer type", "invisible" : "onzichtbaar", "Invisible" : "Onzichtbaar", + "Invitation_HTML" : "Uitnodiging HTML", + "Invitation_Subject" : "Uitnodiging Onderwerp", + "Invite_Users" : "Gebruikers Uitnodigen", "is_also_typing" : "is ook aan het typen", "is_also_typing_female" : "is ook aan het typen", "is_also_typing_male" : "is ook aan het typen", @@ -104,14 +194,23 @@ "italics" : "cursief", "join" : "Toetreden", "Join_the_Community" : "Word lid", + "Jump_to_first_unread" : "Naar eerste ongelezen", + "Jump_to_message" : "Ga naar bericht", + "Jump_to_recent_messages" : "Ga naar recente berichten", "Language" : "Taal", "Language_Version" : "Nederlndse versie", "Last_login" : "Laatste aanmelding", "Last_message" : "Laatste bericht", + "Layout" : "Lay-out", "Layout_Home_Body" : "Home Body", "Layout_Home_Title" : "Home Titel", + "Layout_Login_Header" : "Login Header", + "Layout_Login_Terms" : "Login voorwaarden", + "Layout_Privacy_Policy" : "Privacybeleid", "Layout_Sidenav_Footer" : "Side Navigation Footer", "Layout_Sidenav_Footer_description" : "Footer afmetingen is 260 x 70px", + "Layout_Terms_of_Service" : "Algemene Voorwaarden", + "LDAP" : "LDAP", "LDAP_DN" : "Distinguished Name (DN)", "LDAP_Port" : "LDAP Port", "LDAP_Url" : "LDAP URL", @@ -119,24 +218,37 @@ "line" : "lijn", "Load_more" : "Meer laden", "Loading..." : "Laden ...", + "Loading_more_from_history" : "Meer oude berichten laden", "Loading_suggestion" : "Suggesties laden...", "Login" : "Log In", "Login_with" : "Login met %s", "login_with" : "Of log in met", "Logout" : "Uitloggen", "Make_Admin" : "Maak Admin", + "Mark_as_read" : "Markeer als gelezen", "Members" : "Leden", "Members_List" : "Ledenlijst", "Members_placeholder" : "Leden", "Message" : "Bericht", "Message_AllowDeleting" : "Bericht verwijderen toestaan", "Message_AllowEditing" : "Bericht bewerken toestaan", + "Message_AllowEditing_BlockEditInMinutes" : "Blokkeer berichtbewerkingen na (n) minuten", + "Message_AudioRecorderEnabled" : "Audio Recorder Ingeschakeld", "Message_deleting_not_allowed" : "Bericht verwijderen niet toegestaan", + "Message_editing_blocked" : "Dit bericht kan niet meer worden bewerkt", "Message_editing_not_allowed" : "Bericht bewerken niet toegestaan", + "Message_GroupingPeriod" : "Groeperen periode (in seconden)", + "Message_GroupingPeriodDescription" : "Berichten worden gegroepeerd met het vorige bericht als beide van dezelfde gebruiker zijn.", "Message_KeepHistory" : "Bewaar berichten geschiedenis", + "Message_MaxAllowedSize" : "Maximaal toegestane berichtgrootte", + "Message_pinned" : "Bericht is vastgezet", + "Message_pinning_not_allowed" : "Bericht vastzetten niet toegestaan", "Message_removed" : "Bericht verwijderd", "Message_ShowDeletedStatus" : "Toon Verwijderde Status", "Message_ShowEditedStatus" : "Toon Gewijzigde Status", + "Message_ShowFormattingTips" : "Toon opmaaktips", + "Messages" : "Berichten", + "Meta" : "Meta", "Meta_fb_app_id" : "Facebook App Id", "Meta_google-site-verification" : "Google Site Verification", "Meta_language" : "Taal", @@ -144,11 +256,16 @@ "Meta_robots" : "Robots", "minutes" : "minuten", "More_channels" : "Meer kanalen", + "More_groups" : "Meer privé-berichten", + "More_unreads" : "Meer ongelezen", "Msgs" : "Berichten", "multi" : "multi", + "Mute_user" : "Maak gebruiker stil", "My_Account" : "Mijn account", "n_messages" : "%s berichten", "Name" : "Naam", + "Name_cant_be_empty" : "De naam mag niet leeg zijn", + "New_Application" : "Nieuwe toepassing", "New_messages" : "Nieuwe berichten", "New_password" : "Nieuw Wachtwoord", "No_channel_with_name_%s_was_found" : "Geen kanaal met de naam <strong>\"%s\"</strong> gevonden", @@ -158,25 +275,42 @@ "No_group_with_name_%s_was_found" : "Geen privé-groep met de naam <strong>\"%s\"</strong> gevonden", "No_groups_yet" : "U heeft nog geen privé-groepen.", "No_permission_to_view_room" : "U heeft geen toestemming dit kanaal te bekijken", + "No_results_found" : "Geen resultaten gevonden", + "no_tokens_for_this_user" : "Er zijn geen tokens voor deze gebruiker", "No_user_with_username_%s_was_found" : "Geen gebruiker met de naam <strong>\"%s\"</strong> gevonden", "Not_allowed" : "Niet toegestaan", + "Not_authorized" : "Geen bevoegdheid", "Not_found_or_not_allowed" : "Niet gevonden of niet toegestaan", "Nothing_found" : "Niets gevonden", "Notify_all_in_this_room" : "Meld aan iederen in deze kamer", + "Old_and_new_password_required" : "Je moet zowel je oude als nieuwe wachtwoord geven om uw wachtwoord te wijzigen.", + "Old_Password" : "Oud Wachtwoord", "Online" : "Online", + "Only_you_can_see_this_message" : "Alleen jij kunt dit bericht lezen", "Oops!" : "Oeps", + "Opt_out_statistics" : "Stuur mijn statistieken niet naar Rocket.Chat", + "Opt_out_statistics_warning" : "Door het verzenden van uw statistieken, zult u ons helpen om te bepalen hoe veel gevallen van Rocket.Chat worden ingezet, evenals hoe goed het systeem zich gedraagd, zodat we verder kunnen verbeteren. Maak je geen zorgen, omdat er geen informatie over de gebruiker wordt gestuurd en alle informatie die wij ontvangen wordt vertrouwelijk behandeld. Als u wilt doorgaan met het sturen van uw statistieken, schakelt de bovenstaande checkbox. Dank je.", "others" : "anderen", "Password" : "Wachtwoord", + "Password_Change_Disabled" : "Uw Rocket.Chat beheerder heeft het veranderen van wachtwoorden uitgeschakeld", "Password_changed_successfully" : "Wachtwoord succesvol gewijzigd", + "People" : "Mensen", + "Please_enter_your_new_password_below" : "Vul hieronder uw nieuwe wachtwoord in:", "Please_wait" : "Wacht alstublieft", "Please_wait_activation" : "Even geduld, dit kan enige tijd duren.", "Please_wait_statistics" : "Even geduld, er worden statistieken gegenereerd.", + "Post_to_Channel" : "Posten in kanaal", + "Post_to_s_as_s" : "Posten in <strong>%s</strong> als <strong>%s</strong>", "Powered_by" : "Mede mogelijk gemaakt door", + "Preferences" : "Voorkeuren", + "Preferences_saved" : "Voorkeuren opgeslagen", "Privacy" : "Privacy", "Private_Groups" : "Privé groepen", + "Private_Groups_list" : "Lijst van privé-groepen", "Profile" : "Profiel", "Profile_saved_successfully" : "Profiel succesvol opgeslagen", "Proudly_developed" : "Ontwikkeld met Meteor", + "Push" : "Push", "Push_apn_cert" : "APN Certificaat", "Push_apn_dev_cert" : "APN Ontwikkelaars Certificaat", "Push_apn_dev_key" : "APN Ontwikkelaars Sleutel", @@ -184,24 +318,45 @@ "Push_apn_key" : "APN Key", "Push_apn_passphrase" : "APN Wachtwoord", "Push_debug" : "Debug", + "push_disabled" : "Push notificaties uitgeschakeld", "Push_enable" : "Enable", "Push_production" : "Productie", + "Push_test_push" : "Test", "Quick_Search" : "Snelzoeken", "quote" : "citaat", "Recents" : "Recente", + "Record" : "Opnemen", + "Refresh_your_page_after_install_to_enable_screen_sharing" : "Ververs uw pagina na installeren om het delen van het scherm mogelijk te maken", "Register" : "Registreer een nieuwe gebruiker", "Registration_Succeeded" : "Registratie Geslaagd", "Remember_me" : "Onthou me", "Remove" : "Verwijderen", "Remove_Admin" : "Verwijder Admin", - "Reset_password" : "Nieuw Wachtwoord", + "Remove_custom_oauth" : "Verwijder aangepaste OAuth", + "Remove_from_room" : "Verwijderen uit de kamer", + "Removed" : "Verwijderd", + "Reset" : "Reset", + "Reset_password" : "Reset Wachtwoord", + "Restart" : "Herstart", + "Restart_the_server" : "Herstart de server", "Room" : "Kamer", + "Room_archived" : "Kamer gearchiveerd", + "Room_has_been_deleted" : "Kamer is verwijderd", "Room_name_changed" : "Naam van de kamer veranderd in: <em>__room_name__</em> door <em>__user_by__</em>", "Room_name_changed_successfully" : "Naam van het kanaal is aangepast", "Room_not_found" : "Kamer niet gevonden", + "Room_unarchived" : "Kamer uit meer gearchiveerd", + "Room_uploaded_file_list" : "Bestandslijst", + "Room_uploaded_file_list_empty" : "Geen bestanden beschikbaar.", "room_user_count" : "%s gebruikers", + "Rooms" : "Kamers", + "S_new_messages_since_s" : "%s nieuwe berichten sinds %s", + "SAML" : "SAML", "Save_changes" : "Wijzigingen opslaan", + "Save_Mobile_Bandwidth" : "Bespaar op mobile bandbreedte", + "Screen_Share" : "Scherm delen", "Search" : "Zoeken", + "Search_Messages" : "Berichten zoeken", "Search_settings" : "Zoekinstellingen", "seconds" : "secondes", "See_all" : "Alles zien", @@ -210,22 +365,40 @@ "Select_file" : "Selecteer bestand", "Select_service_to_login" : "Selecteer een dienst in te loggen om uw foto op te halen of upload er één van uw computer", "Selected_users" : "Geselecteerde leden", - "Send_confirmation_email" : "Bevestigings e-mail te sturen", + "Send" : "Verstuur", + "Send_a_test_mail_to_my_user" : "Stuur een test email naar mijn gebruiker", + "Send_a_test_push_to_my_user" : "Stuur een test push notificatie naar mijn gebruiker", + "Send_confirmation_email" : "Bevestigings e-mail sturen", + "Send_data_into_RocketChat_in_realtime" : "Stuur gegevens in Rocket.Chat in real-time.", + "Send_invitation_email" : "Stuur uitnodiging e-mail", + "Send_invitation_email_error" : "Je hebt geen geldig e-mailadres gegeven.", + "Send_invitation_email_info" : "Je kunt meerdere e-mail uitnodigingen verzenden per keer sturen.", + "Send_invitation_email_success" : "U hebt een uitnodiging e-mail gestuurd naar de volgende adressen:", + "Send_invitation_email_warning" : "Om de uitnodiging e-mails te versturen, moet u eerst de SMTP-instellingen configureren.", "Send_Message" : "Bericht verzenden", "Settings" : "Instellingen", "Settings_updated" : "Instellingen bijgewerkt", + "Should_be_a_URL_of_an_image" : "Dit moet een URL van een afbeelding zijn.", + "Should_exists_a_user_with_this_username" : "De gebruiker moet al bestaan.", "Showing_online_users" : "Toont <b>__total_online__</b> van de __total__ gebruikers", "Showing_results" : "<p>Toon <b>%s</b> resultaten</p>", "Silence" : "Stilte", "since_creation" : "sinds%s", + "Site_Name" : "Site naam", + "Site_Url" : "URL van de site", + "Site_Url_Description" : "Voorbeeld: https://chat.domain.com/", + "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP-wachtwoord", "SMTP_Port" : "SMTP Poort", "SMTP_Username" : "SMTP Gebruikersnaam", + "Sound" : "Geluid", "Start_of_conversation" : "Begin van het gesprek", + "Statistics" : "Statistieken", "Stats_Active_Users" : "Actieve gebruikers", "Stats_Avg_Channel_Users" : "Gemiddeld aantal Kanaal Gebruikers", "Stats_Avg_Private_Group_Users" : "Gemiddeld aantal Privé Groep Gebruikers", + "Stats_Away_Users" : "Afwezige gebruikers", "Stats_Max_Room_Users" : "Maximaal aantal Kamer Gebruikers", "Stats_Non_Active_Users" : "Inactieve Gebruikers", "Stats_Offline_Users" : "Offline Gebruikers", @@ -241,24 +414,42 @@ "Stats_OS_Uptime" : "OS Uptime", "Stats_Total_Channels" : "Totaal Kanalen", "Stats_Total_Direct_Messages" : "Totaal Directe Berichten Kamers", + "Stats_Total_Messages" : "Totaal aantal berichten", "Stats_Total_Private_Groups" : "Totaal Privé Groepen", "Stats_Total_Rooms" : "Totaal aantal Kamers", "Stats_Total_Users" : "Totaal aantal leden", + "Stop_Recording" : "Stop opname", "strike" : "doorhalen", "Submit" : "Verzenden", + "Success" : "Succes", + "The_channel_name_is_required" : "De naam van het kanaal is vereist", "The_field_is_required" : "Het veld %s is vereist.", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "Het beeld zal niet van grootte worden veranderd omdat we niet kunnen zien of Imagemagick of GraphicsMagick geïnstalleerd zijn op uw server.", + "The_server_will_restart_in_s_seconds" : "De server wordt herstart in %s seconden", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "De configuratie <strong>%s</strong> is ingesteld op <strong>%s</strong> en u gebruikt toegang vanaf <strong>%s</strong>!", + "This_is_a_push_test_messsage" : "Dit is een push-test messsage", "True" : "True", + "Type_your_new_password" : "Typ uw nieuwe wachtwoord", + "Unarchive" : "Uit archief halen", + "Unmute_user" : "Laat iemand weer praten", "Unnamed" : "Naamloos", + "Unread_Rooms" : "Ongelezen Kamers", + "Unread_Rooms_Mode" : "Ongelezen Kamers Mode", "Upload_file_question" : "Bestand uploaden?", + "Uploading_file" : "Bestand uploaden...", + "Use_Emojis" : "Gebruik Emojis", "Use_initials_avatar" : "Gebruik de initialen van uw gebruikersnaam", "use_menu" : "Gebruik het menu aan de zijkant om toegang te krijgen tot de kanalen en privé gesprekken", "Use_service_avatar" : "Gebruik %s afbeelding", "Use_this_username" : "Gebruik deze gebruikersnaam", "Use_uploaded_avatar" : "Gebruik geüploade afbeelding", + "Use_url_for_avatar" : "Gebruik url voor avatar", "User_added_by" : "Gebruiker <em>__user_added__</em> toegevoegd door <em>__user_by__</em>", + "User_Channels" : "Gebruikers Kanalen", "User_has_been_activated" : "Gebruiker is geactiveerd", "User_has_been_deactivated" : "Gebruiker is gedeactiveerd", "User_has_been_deleted" : "Gebruiker is verwijderd", + "User_Info" : "Gebruikers informatie", "User_is_no_longer_an_admin" : "Gebruiker is niet langer een admin", "User_is_not_activated" : "Gebruiker is niet geactiveerd", "User_is_now_an_admin" : "Gebruiker is nu een admin", @@ -269,15 +460,25 @@ "User_left_female" : "Heeft het kanaal verlaten.", "User_left_male" : "Heeft het kanaal verlaten.", "User_logged_out" : "Gebruiker is uitgelogd", + "User_muted_by" : "Gebruiker <em>__user_muted__</em> tot zwijgen gebracht door <em>__user_by__</em>.", + "User_muted_in_room" : "Gebruiker stil gemaakt in de kamer", + "User_not_found_or_incorrect_password" : "Gebruiker niet gevonden of onjuist wachtwoord", + "User_or_channel_name" : "Gebruiker of kanaal ", "User_removed_by" : "Gebruiker <em>__user_removed__</em> verwijderd door <em>__user_by__</em>.", + "User_removed_from_room" : "De gebruiker is verwijderd uit de kamer", "User_Settings" : "Gebruikersinstellingen", + "User_unmuted_by" : "Gebruiker <em>__user_muted__</em> weer tot spreken in staat gebracht door <em>__user_by__</em>.\n", + "User_unmuted_in_room" : "Gebruiker kan weer spreken in de kamer", "User_updated_successfully" : "Gebruiker succesvol bijgewerkt", "Username" : "Gebruikersnaam", "Username_cant_be_empty" : "De gebruikersnaam mag niet leeg zijn", + "Username_Change_Disabled" : "Uw Rocket.Chat beheerder heeft het wijzigen van gebruikersnamen uitgeschakeld", "Username_description" : "De gebruikersnaam kan door anderen gebruikt worden om aan u te refereren.", "Username_invalid" : "<strong>%s</strong> is geen geldige gebruikersnaam,<br/> gebruik uitsluitend letters, cijfers, punten en streepjes", "Username_title" : "Registreer Gebruikersnaam", "Username_unavaliable" : "<strong>%s</strong> is al in gebruik :(", + "Users" : "Gebruikers", + "UTF8_Names_Validation_Description" : "Geen speciale tekens en spaties toestaan. U kunt - _ en. gebruiken maar niet aan het einde van de naam", "View_All" : "Bekijk alles", "Wait_activation_warning" : "Voordat u kunt inloggen, moet uw account handmatig worden geactiveerd door een beheerder.", "We_have_sent_password_email" : "Wij hebben u een e-mail gestuurd met herstel instructies voor uw wachtwoord. Als u deze e-mail niet snel ontvangt, ook niet in uw spam-folder, kom dan terug en probeer het opnieuw.", @@ -285,10 +486,17 @@ "Welcome" : "Welkom <em>%s</em>.", "Welcome_to_the" : "Welkom bij de", "With_whom" : "Met wie", + "Yes_clear_all" : "Ja, alles wissen!", "Yes_delete_it" : "Ja, verwijder het!", "you_are_in_preview_mode_of" : "U kijkt naar de voorbeschouwing van kanaal #<strong>__room_name__</strong>", + "You_can_change_a_different_avatar_too" : "U kunt de afbeelding die bij berichten gebruikt wordt vervangen.", + "You_can_use_an_emoji_as_avatar" : "U kunt ook een emoji gebruiken als een afbeelding.", + "You_have_been_muted" : "Je bent tot zwijgen gebracht in deze kamer.", "You_need_confirm_email" : "U dient uw e-mail te bevestigen on in te kunnen loggen!", + "You_need_install_an_extension_to_allow_screen_sharing" : "U moet een uitbreiding op uw browser installeren om het delen van het scherm mogelijk te maken", "You_will_not_be_able_to_recover" : "Dit bericht zal niet meer te herstellen zijn!", "Your_entry_has_been_deleted" : "Uw bericht is verwijderd.", - "Your_Open_Source_solution" : "Uw eigen Open Source chat-oplossing" + "Your_mail_was_sent_to_s" : "Uw e-mail werd verzonden naar %s", + "Your_Open_Source_solution" : "Uw eigen Open Source chat-oplossing", + "Your_push_was_sent_to_s_devices" : "Je push werd verzonden naar %s apparaten" } \ No newline at end of file diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 040ad0cf694778a4cb60ed4baa7243a4b961e9d5..59a316acc479c6a01145a66f4f47486d396af67f 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -49,6 +49,7 @@ "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Zresetuj hasÅ‚o", "Accounts_Registration_AuthenticationServices_Enabled" : "Rejestracja przy użyciu serwisów zewnÄ™trznych", "Accounts_RegistrationForm" : "Formularz rejestracyjny", "Accounts_RegistrationForm_Disabled" : "WyÅ‚Ä…czony", @@ -58,6 +59,7 @@ "Accounts_RegistrationForm_SecretURL" : "Sekretny adres URL formularza rejestracyjnego", "Accounts_RegistrationRequired" : "Musisz siÄ™ zarejestrować", "Accounts_RequireNameForSignUp" : "Wymagaj podana nazwy podczas rejestracji", + "Accounts_ShowFormLogin" : "Pokaż formularz logowania", "Activate" : "Aktywuj", "Add_custom_oauth" : "Dodaj wÅ‚asne OAuth", "Add_Members" : "Dodaj czÅ‚onków", @@ -70,8 +72,9 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Osadź", - "API_EmbedDisabledFor" : "WyÅ‚Ä…dz osadzanie dla użytkowników", + "API_EmbedDisabledFor" : "WyÅ‚Ä…cz osadzanie dla użytkowników", "API_EmbedDisabledFor_Description" : "Lista użytkowników oddzielonych przecinkami", + "Archive" : "Archiwizuj", "are_also_typing" : "również piszÄ…", "are_typing" : "piszÄ…", "Are_you_sure" : "JesteÅ› pewny?", @@ -84,6 +87,7 @@ "Away_female" : "Zaraz wracam", "away_male" : "zaraz wracam", "Away_male" : "Zaraz wracam", + "Back_to_integrations" : "Powrót do integracji", "Back_to_login" : "Wróć do strony logowania", "bold" : "pogrubienie", "busy" : "zajÄ™ty", @@ -94,6 +98,7 @@ "Busy_male" : "ZajÄ™ty", "Cancel" : "Anuluj", "CDN_PREFIX" : "Prefiks CDN", + "Certificates_and_Keys" : "Certyfikaty i klucze", "Change_avatar" : "ZmieÅ„ avatar", "Channels" : "KanaÅ‚y", "Channels_list" : "Lista kanałów publicznych", @@ -107,6 +112,7 @@ "Contact" : "Kontakt", "Conversation" : "Rozmowa", "Convert_Ascii_Emojis" : "Konwertuj ASCII do Emoji", + "COPY_TO_CLIPBOARD" : "SKOPIUJ DO SCHOWKA", "Create_new" : "Utwórz", "Create_new_direct_message_room" : "Nowa prywatna rozmowa", "Create_new_private_group" : "Utwórz prywatnÄ… grupÄ™", @@ -138,6 +144,7 @@ "Enable_Desktop_Notifications" : "WÅ‚Ä…cz powiadomienia na pulpicie", "Enter_info" : "Podaj swoje dane", "Enter_to" : "NaciÅ›nij Enter: ", + "Error" : "BÅ‚Ä…d", "Error_changing_password" : "BÅ‚Ä…d zmiany hasÅ‚a", "Error_too_many_requests" : "BÅ‚Ä…d, zbyt wiele żądaÅ„. ProszÄ™ zwolnij. Musisz poczekać %s sekund zanim spróbujesz ponownie", "Esc_to" : "NaciÅ›nij Esc: ", @@ -163,15 +170,22 @@ "hours" : "godzin", "Incorrect_Password" : "HasÅ‚o jest nieprawidÅ‚owe", "inline_code" : "kod", + "Install_Extension" : "Zainstaluj rozszerzenie", "Install_FxOs" : "Zainstaluj Rocket.Chat w Firefoksie", "Install_FxOs_done" : "Åšwietnie! Możesz teraz wÅ‚Ä…czać Rocket.Chat poprzez ikonÄ™ na ekranie głównym. Å»yczymy miÅ‚ego korzystania z Rocket.Chat!", "Install_FxOs_error" : "Niestety, coÅ› nie zadziaÅ‚aÅ‚o! WystÄ…piÅ‚ nastÄ™pujÄ…cy bÅ‚Ä…d:", "Install_FxOs_follow_instructions" : "Potwierdź instalowanie aplikacji na twoim urzÄ…dzeniu (gdy wyskoczy pytanie naciÅ›nij przycisk \"Zainstaluj\").", + "Integration_New" : "Nowy Integracja", + "Integrations" : "Integracje", "Invalid_confirm_pass" : "Podane hasÅ‚a nie sÄ… jednakowe", "Invalid_email" : "E-mail jest nieprawidÅ‚owy", + "Invalid_file_height" : "NieprawidÅ‚owa wysokość pliku", + "Invalid_file_type" : "NieprawidÅ‚owy typ pliku", + "Invalid_file_width" : "NieprawidÅ‚owa szerokość pliku", "Invalid_name" : "Nazwa nie może być pusta", "Invalid_pass" : "HasÅ‚o nie może być puste", "Invalid_room_name" : "<strong>%s</strong> nie jest poprawnÄ… nazwÄ… pokoju, <br / >użyj tylko liter, cyfr i myÅ›lników", + "Invalid_secret_URL_message" : "Podany adres URL jest nieprawidÅ‚owy.", "invisible" : "niewidoczny", "Invisible" : "Niewidoczny", "Invitation_HTML" : "Kod HTML zaproszenia", @@ -186,6 +200,8 @@ "italics" : "kursywa", "join" : "DoÅ‚Ä…cz", "Join_the_Community" : "DoÅ‚Ä…cz do spoÅ‚ecznoÅ›ci", + "Jump_to_first_unread" : "Przejdź do pierwszej nieprzeczytanej", + "Jump_to_recent_messages" : "Przejdź do ostatnich wiadomoÅ›ci", "Language" : "JÄ™zyk", "Language_Version" : "Wersja angielska", "Last_login" : "Ostatnie logowanie", @@ -265,6 +281,7 @@ "Name" : "Nazwa", "Name_cant_be_empty" : "Nazwa nie może być pusta", "Name_optional" : "Nazwa (opcjonalnie)", + "New_integration" : "Nowa integracja", "New_messages" : "Nowe wiadomoÅ›ci", "New_password" : "Nowe hasÅ‚o", "No_channel_with_name_%s_was_found" : "Nie odnaleziono kanaÅ‚u o nazwie <strong>\"%s\"</strong>!", @@ -288,6 +305,7 @@ "Oops!" : "Ups", "Opt_out_statistics" : "Nie wysyÅ‚aj statystyk do autorów Rocket.Chat", "Opt_out_statistics_warning" : "PrzesyÅ‚ajÄ…c swoje statystyki pomagasz nam okreÅ›lić jak instalacji Rocket.Chat jest w użyciu i jak dobrze sprawuje siÄ™ nasza aplikacja, co pozwala nam jÄ… wciąż ulepszać. Nie przesyÅ‚amy żadnych informacji o użytkownikach, a wszystkie otrzymane informacje sÄ… traktowane jako poufne. JeÅ›li chcesz nadal przesyÅ‚ać nam statystyki, odznacz powyższe pole. DziÄ™kujemy.", + "optional" : "opcjonalne", "others" : "inni", "Password" : "HasÅ‚o", "Password_Change_Disabled" : "Administrator czatu wyÅ‚Ä…czyÅ‚ możliwość zmiany haseÅ‚", @@ -315,6 +333,8 @@ "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debugowanie", "Push_enable" : "WÅ‚Ä…cz", + "Push_enable_gateway" : "WÅ‚Ä…cz bramÄ™", + "Push_gateway" : "Brama", "Push_gcm_api_key" : "Klucz API GCM", "Push_gcm_project_number" : "Identyfikator projektu GCM", "Push_production" : "Serwer produkcyjny", @@ -322,14 +342,19 @@ "quote" : "cytat", "Recents" : "Najnowsze", "Record" : "Nagrywaj", + "Refresh_your_page_after_install_to_enable_screen_sharing" : "OdÅ›wież stronÄ™ po instalacji, aby umożliwić dzielenie ekranu", "Register" : "Zarejestruj nowe konto", "Registration_Succeeded" : "Rejestracja zakoÅ„czona", "Remember_me" : "ZapamiÄ™taj mnie", "Remove" : "UsuÅ„", "Remove_Admin" : "Zabierz Admina", "Remove_custom_oauth" : "UsuÅ„ wÅ‚asne OAuth", + "Removed" : "UsuniÄ™to", "Reset_password" : "Zresetuj hasÅ‚o", + "Restart" : "Uruchom ponownie", + "Restart_the_server" : "Uruchom serwer ponownie", "Room" : "Pokój", + "Room_archived" : "Pokój zarchiwizowany", "Room_name_changed" : "Nazwa pokoju zmieniona na: <em>__room_name__</em>przez <em>__user_by__</em>", "Room_name_changed_successfully" : "Nazwa pokoju zmieniona", "Room_not_found" : "Nie odnaleziono pokoju", @@ -346,6 +371,7 @@ "SAML_Custom_Provider" : "WÅ‚asny dostawca (provider)", "Save_changes" : "Zapisz zmiany", "Save_Mobile_Bandwidth" : "OszczÄ™dzaj przepustowość", + "Screen_Share" : "Współdzielenie ekranu", "Search" : "Szukaj", "Search_Messages" : "Przeszukaj wiadomoÅ›ci", "Search_settings" : "Przeszukaj ustawienia", @@ -407,12 +433,16 @@ "Stop_Recording" : "Zatrzymaj nagrywanie", "strike" : "przekreÅ›lenie", "Submit" : "PrzeÅ›lij", + "Success" : "Sukces", "The_field_is_required" : "Pole %s jest wymagane.", + "The_server_will_restart_in_s_seconds" : "Serwer zostanie ponownie uruchomiony za %s sekund", "True" : "Tak", + "Type_your_new_password" : "Wprowadź nowe hasÅ‚o", "Unnamed" : "Anonimowy", "Unread_Rooms" : "Nieprzeczytane pokoje", "Unread_Rooms_Mode" : "Tryb nieprzeczytanych pokoi", "Upload_file_question" : "PrzesÅ‚ać plik?", + "Uploading_file" : "PrzesyÅ‚anie pliku ...", "Use_Emojis" : "Użyj Emoji", "Use_initials_avatar" : "Użyj inicjałów", "use_menu" : "Otwórz menu boczne by uzyskać dostÄ™p do twoich pokoi i rozmów", @@ -460,6 +490,7 @@ "Yes_delete_it" : "Tak, usuÅ„ to!", "you_are_in_preview_mode_of" : "JesteÅ› w trybie podglÄ…du kanaÅ‚u # <strong>__room_name__</strong>", "You_need_confirm_email" : "Aby siÄ™ zalogować musisz potwierdzić swój adres e-mail!", + "You_need_install_an_extension_to_allow_screen_sharing" : "Musisz zainstalować rozszerzenie, aby umożliwić dzielenie ekranu", "You_will_not_be_able_to_recover" : "Nie bÄ™dziesz w stanie odzyskać tej wiadomoÅ›ci!", "Your_entry_has_been_deleted" : "Twój wpis zostaÅ‚ usuniÄ™ty.", "Your_Open_Source_solution" : "Twój wÅ‚asny czat Open Source" diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index eedf1d79fa655d55764040ff90e75e6b01c7c3b9..e4af9ea8aba180de6290e9cb2725a714a44ac081 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -49,6 +49,7 @@ "Accounts_RegistrationForm_Secret_URL" : "URL Secreta", "Accounts_RegistrationRequired" : "Registro Obrigatório", "Accounts_RequireNameForSignUp" : "Nome é obrigatório para cadastro", + "Accounts_ShowFormLogin" : "Mostrar formulário de login", "Activate" : "Ativar", "Add_custom_oauth" : "Adicionar oauth customizado", "Add_Members" : "Adicionar membros", @@ -65,6 +66,7 @@ "are_also_typing" : "também estão digitando", "are_typing" : "estão digitando", "Are_you_sure" : "Você tem certeza?", + "Authorize" : "Autorizar", "Auto_Load_Images" : "Auto Carregar Imagens", "Avatar_changed_successfully" : "Avatar alterado com sucesso", "Avatar_url_invalid_or_error" : "A URL fornecida é inválida ou não acessÃvel. Por favor tente novamente, mas com uma url diferente.", @@ -130,7 +132,7 @@ "Enter_to" : "Enter para", "Error" : "Erro", "Error_changing_password" : "Erro ao alterar senha", - "Error_too_many_requests" : "Erro, foram realizadas muitas solicitações. Por favor, diminua a velocidade. Você dev esperar %s segundos antes de tentar novamente", + "Error_too_many_requests" : "Erro, foram realizadas muitas solicitações. Por favor, diminua a velocidade. Você deve esperar %s segundos antes de tentar novamente", "Esc_to" : "Esc para", "False" : "Não", "Favorites" : "Favoritos", @@ -138,7 +140,9 @@ "FileUpload_Enabled" : "Habilitar upload de arquivos", "FileUpload_MaxFileSize" : "Tamanho máximo dos arquivos (em bytes)", "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia", - "FileUpload_MediaTypeWhiteListDescription" : "Lista de tipos de mÃdia separada por vÃrgula", + "FileUpload_MediaTypeWhiteListDescription" : "Separados por vÃrgula", + "FileUpload_ProtectFiles" : "Proteger arquivos enviados", + "FileUpload_ProtectFilesDescription" : "Somente usuários autenticados terão acesso", "Follow_social_profiles" : "Siga-nos nas redes sociais, faça fork no github e compartilhe suas ideias sobre o app rocket.chat em nosso trello.", "Forgot_password" : "Esqueceu sua senha", "Fork_it_on_github" : "Fork it on github", @@ -314,6 +318,7 @@ "Remove" : "Remover", "Remove_Admin" : "Remover Administrador", "Remove_custom_oauth" : "Remover oauth customizado", + "Removed" : "Removido", "Reset_password" : "Resetar senha", "Restart" : "Reiniciar", "Restart_the_server" : "Reiniciar o servidor", @@ -395,7 +400,6 @@ "strike" : "tachado", "Submit" : "Enviar", "Success" : "Sucesso", - "The_configured_URL_is_different_from_the_URL_you_are_accessing" : "A URL configurada é diferente da URL que você está acessando!", "The_field_is_required" : "O campo %s é obrigatório.", "The_server_will_restart_in_s_seconds" : "O servidor será reiniciado em %s segundos", "This_is_a_push_test_messsage" : "Este é uma mensagem de teste de push notification", @@ -446,11 +450,13 @@ "We_have_sent_registration_email" : "Nós lhe enviamos um e-mail para confirmar o seu registro. Se você não receber um e-mail em breve, por favor retorne e tente novamente.", "Welcome" : "Seja bem-vindo <em>%s</em>.", "Welcome_to_the" : "Bem-vindo ao", + "will_be_able_to" : "poderá", "With_whom" : "Com quem", "Yes" : "Sim", "Yes_clear_all" : "Sim, limpar tudo!", "Yes_delete_it" : "Sim, exclua!", "you_are_in_preview_mode_of" : "Esta é uma prévia do canal #<strong>__room_name__</strong>", + "You_are_logged_in_as" : "Vocês está logado como", "You_need_confirm_email" : "Você precisa confirmar seu email para logar!", "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..15571b9486efa4ff1ed9f880e191d8eba4afd49d --- /dev/null +++ b/i18n/ro.i18n.json @@ -0,0 +1,613 @@ +{ + "Access_not_authorized" : "Acces neautorizat", + "Access_online_demo" : "AccesaÈ›i demo on-line", + "Access_Online_Demo" : "Accesati Demo Online", + "Access_Token_URL" : "Acces Token URL", + "Accounts" : "Conturi", + "Accounts_AllowedDomainsList" : "Listă domenii permise", + "Accounts_AllowedDomainsList_Description" : "Lista separată cu virgule a domeniilor acceptate", + "Accounts_AllowPasswordChange" : "PermiteÈ›i schimbare parolă", + "Accounts_AllowUserAvatarChange" : "Permite schimbarea avatar-ului utilzatorilor", + "Accounts_AllowUsernameChange" : "PermiteÈ›i schimbarea numelui de utilizator", + "Accounts_AllowUserProfileChange" : "Permite schimbarea profilului utilzatorilor", + "Accounts_AvatarResize" : "Redimensionarea Avatare", + "Accounts_AvatarSize" : "Dimensiune Avatar", + "Accounts_AvatarStorePath" : "Calea de stocare Avatar", + "Accounts_AvatarStoreType" : "Tip stocare Avatar", + "Accounts_denyUnverifiedEmail" : "Nu accepta e-mail neverificat", + "Accounts_EmailVerification" : "Verificarea email-ului", + "Accounts_Enrollment_Email" : "E-mail de înscriere ", + "Accounts_Enrollment_Email_Description" : "PuteÈ›i utiliza [name], [fname], [lname] pentru numele complet al utilizatorului, prenumele respectiv numele de familie.<br/>PuteÈ›i folosi [email] pentru e-mailul utilizatorului.", + "Accounts_LoginExpiration" : "Autentificarea expiră (în zile)", + "Accounts_ManuallyApproveNewUsers" : "Aprobarea manuală a noilor utilizatori", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", + "Accounts_OAuth_Custom_Button_Color" : "Culoare buton", + "Accounts_OAuth_Custom_Button_Label_Color" : "Culoare buton text", + "Accounts_OAuth_Custom_Button_Label_Text" : "Text buton", + "Accounts_OAuth_Custom_Enable" : "Activează", + "Accounts_OAuth_Custom_id" : "Id-ul", + "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Login_Style" : "Stil Autentificare", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_URL" : "URL", + "Accounts_OAuth_Facebook" : "Logare cu Facebook", + "Accounts_OAuth_Facebook_id" : "Facebook App ID", + "Accounts_OAuth_Facebook_secret" : "Facebook Secret", + "Accounts_OAuth_Github" : "OAuth Activat", + "Accounts_OAuth_Github_id" : "Client Id", + "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Gitlab" : "OAuth Activat", + "Accounts_OAuth_Gitlab_id" : "Gitlab Id", + "Accounts_OAuth_Gitlab_secret" : "Client Secret", + "Accounts_OAuth_Google" : "Login cu Google", + "Accounts_OAuth_Google_id" : "Google Id", + "Accounts_OAuth_Google_secret" : "Google Secret", + "Accounts_OAuth_Linkedin" : "Logare cu LinkedIn", + "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", + "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", + "Accounts_OAuth_Meteor" : "Logare cu Meteor", + "Accounts_OAuth_Meteor_id" : "Meteor ID", + "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_OAuth_Twitter" : "Logare cu Twitter", + "Accounts_OAuth_Twitter_id" : "Twitter Id", + "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Resetează parola", + "Accounts_Registration_AuthenticationServices_Enabled" : "ÃŽnregistrare cu servicii de autentificare", + "Accounts_RegistrationForm" : "Formular de înregistrare", + "Accounts_RegistrationForm_Disabled" : "Dezactivat", + "Accounts_RegistrationForm_LinkReplacementText" : "ÃŽnlocuire link din formularul de înregistrare", + "Accounts_RegistrationForm_Public" : "Public", + "Accounts_RegistrationForm_Secret_URL" : "URL secret", + "Accounts_RegistrationForm_SecretURL" : "URL secret din formularul de înregistrare", + "Accounts_RegistrationForm_SecretURL_Description" : "Trebuie să furnizaÈ›i un È™ir aleatoriu care va fi adăugat la URL-ul dvs. de înregistrare. Exemplu: https://demo.rocket.chat/register/[secret_hash]", + "Accounts_RegistrationRequired" : "ÃŽnregistrare necesară", + "Accounts_RequireNameForSignUp" : "Cere nume pentru înregistrare", + "Accounts_ShowFormLogin" : "Arată formularul pentru autentificare", + "Activate" : "Activează", + "Add_custom_oauth" : "Adaugă OAuth personalizat", + "Add_Members" : "Adaugă membri", + "Add_users" : "Adaugă utilizatori", + "Administration" : "Administrare", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "După autentificare OAuth2, utilizatorii vor fi redirecÈ›ionat către această adresă URL", + "Alias" : "Alias", + "All_channels" : "Toate canalele", + "Allow_Invalid_SelfSigned_Certs" : "PermiteÈ›i Certificate Self-Signed Certs", + "Allow_Invalid_SelfSigned_Certs_Description" : "PermiteÈ›i certificat SSL invalid È™i auto-semnat pentru validarea link-urilor È™i previzualizări.", + "and" : "È™i", + "API" : "API", + "API_Analytics" : "Analytics", + "API_Embed" : "Embed", + "API_EmbedDisabledFor" : "DezactivaÈ›i Embed pentru utilizatori", + "API_EmbedDisabledFor_Description" : "Lista separată cu virgule a numelor de utilizator", + "Application_added" : "AplicaÈ›ie adăugată", + "Application_Name" : "Nume aplicaÈ›ie", + "Application_updated" : "AplicaÈ›ie actualizată", + "Archive" : "Arhivează", + "are_also_typing" : "tastează", + "are_typing" : "tastează", + "Are_you_sure" : "Sigur doriÈ›i asta?", + "Authorization_URL" : "URL de autorizare", + "Authorize" : "Autorizează", + "Auto_Load_Images" : "Auto-încarcă imagini", + "Avatar_changed_successfully" : "Avatar schimbat cu succes", + "Avatar_URL" : "URL Avatar ", + "Avatar_url_invalid_or_error" : "URL-ul furnizat este invalid sau nu este accesibil. Vă rugăm să încercaÈ›i din nou, dar cu o altă adresă URL.", + "away" : "departe", + "Away" : "Departe", + "away_female" : "departe", + "Away_female" : "Departe", + "away_male" : "departe", + "Away_male" : "Departe", + "Back_to_applications" : "ÃŽnapoi la aplicaÈ›ii", + "Back_to_integrations" : "ÃŽnapoi la integrări", + "Back_to_login" : "ÃŽnapoi la autentificare", + "bold" : "îngroÈ™at", + "busy" : "ocupat", + "Busy" : "Ocupat", + "busy_female" : "ocupat", + "Busy_female" : "Ocupat", + "busy_male" : "ocupat", + "Busy_male" : "Ocupat", + "Cancel" : "Anulează", + "CDN_PREFIX" : "CDN Prefix", + "Certificates_and_Keys" : "Certificate È™i chei", + "Change_avatar" : "Schimbare avatar", + "Channels" : "Canale", + "Channels_list" : "Listă de canale publice", + "Chat_Rooms" : "Camere de chat", + "Choose_the_alias_that_will_appear_before_the_username_in_messages" : "Alege alias care va apărea în faÈ›a numelui de utilizator în mesaje.", + "Choose_the_username_that_this_integration_will_post_as" : "Alege numele de utilizator cu care va posta această integrare.", + "Clear_all_unreads_question" : "ȘtergeÈ›i toate necitite?", + "Client_ID" : "ID Client", + "Client_Secret" : "Client Secret", + "close" : "închide", + "coming_soon" : "în curând", + "Commands" : "Comenzi", + "Compact_View" : "Vizualizare compactă", + "Confirm_password" : "ConfirmaÈ›i parola", + "Contact" : "Contact", + "Conversation" : "ConversaÅ£ie", + "Convert_Ascii_Emojis" : "Conversie ASCII în Emoji", + "COPY_TO_CLIPBOARD" : "COPIAÈšI ÃŽN CLIPBOARD", + "Create_new" : "Crează nou", + "Create_new_direct_message_room" : "CreaÈ›i o nouă cameră de mesaje directe", + "Create_new_private_group" : "CreaÈ›i un nou grup privat", + "Create_new_public_channel" : "Crează un nou canal public.", + "Created_at" : "Creat la", + "Created_at_s_by_s" : "Creat la <strong>%s</strong> by <strong>%s</strong>", + "Custom_oauth_helper" : "La configurarea furnizorul de OAuth, va trebui să apelaÈ›i un URL de apel invers. UtilizaÈ›i <pre>%s</pre>.", + "Custom_oauth_unique_name" : "Nume unic OAuth personalizat", + "days" : "zile", + "Deactivate" : "Dezactivează", + "Delete_Room_Warning" : "Ștergerea unei camere va È™terge toate mesajele postate în cameră. Acest lucru nu poate fi anulat.", + "Delete_User_Warning" : "Ștergerea unui utilizator va È™terge È™i toate mesajele acelui utilizator. Acest lucru nu poate fi anulat.", + "Deleted" : "Șters!", + "Desktop_Notifications" : "Notificări pe desktop", + "Desktop_Notifications_Disabled" : "Notificările desktop sunt dezactivate. SchimbaÈ›i preferinÈ›ele browser-ului dacă aveÈ›i nevoie de notificări activate.", + "Desktop_Notifications_Enabled" : "Notificări pe desktop sunt activate", + "Direct_Messages" : "Mesaje directe", + "Disable_Favorite_Rooms" : "DezactivaÈ›i Favorite", + "Disable_New_Message_Notification" : "Dezactivează notificările privind mesajele noi", + "Disable_New_Room_Notification" : "Dezactivează notificările privind camere noi", + "Do_you_want_to_change_to_s_question" : "DoriÈ›i să modificaÈ›i în <strong>%s</strong>?", + "Drop_to_upload_file" : "TrageÈ›i fiÈ™ierul aici pentru încărcare", + "Duplicate_archived_channel_name" : "Există în arhivă un canalul cu numele \"%s\"", + "Duplicate_archived_private_group_name" : "Există în arhivă un grup privat cu numele '% s' ", + "Duplicate_channel_name" : "Un canal cu numele \"% s\" există deja", + "Duplicate_private_group_name" : "Un grup privat cu numele '% s' există deja", + "E-mail" : "E-mail", + "edited" : "editat", + "Email_already_exists" : "Adresa de e-mail există deja", + "Email_or_username" : "Adresă de e-mail sau nume de utilizator", + "Email_verified" : "Email verificat", + "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "ActivaÈ›i notificări pe desktop", + "Enter_info" : "IntroduceÈ›i informaÈ›iile dumneavoastră", + "Enter_to" : "Enter pentru a", + "Error" : "Eroare", + "Error_changing_password" : "Eroare la schimbarea parolei", + "Error_too_many_requests" : "Eroare, prea multe cereri. Vă rugăm să încetinÈ›i. Trebuie să aÈ™teptaÈ›i % s secunde înainte de a încerca din nou", + "Esc_to" : "Esc pentru a", + "Example_s" : "Exemplu: <code class=\"inline\">%s</code>", + "False" : "Fals", + "Favorites" : "Favorite", + "FileUpload" : "ÃŽncărcare fiÈ™ier", + "FileUpload_Enabled" : "ÃŽncărcarea de fiÈ™iere activată", + "FileUpload_File_Empty" : "FiÈ™ier gol", + "FileUpload_MaxFileSize" : "Dimensiune maximă a fiÈ™ierului (în bytes)", + "FileUpload_MediaType_NotAccepted" : "Tipuri de media ne-acceptate", + "FileUpload_MediaTypeWhiteList" : "Tipuri de media acceptate", + "FileUpload_MediaTypeWhiteListDescription" : "Lista separată cu virgule a tipuri de media", + "FileUpload_ProtectFiles" : "Protejare fiÈ™iere încărcate", + "FileUpload_ProtectFilesDescription" : "Doar utilizatorii autentificaÈ›i vor avea acces", + "Follow_social_profiles" : "UrmăriÈ›i conturile noastre sociale, \"fork\" proiectul pe GitHub È™i împărtășiÈ›i părerile despre rocket.chat pe board-ul nostru de trello.", + "Forgot_password" : "Parolă uitată", + "Fork_it_on_github" : "\"Fork\" proiectul pe GitHub", + "From_Email" : "E-mail de la", + "General" : "General", + "Get_to_know_the_team" : "FaceÈ›i cunoÈ™tință cu Rocket.Team", + "github_no_public_email" : "Nu aveÈ›i nici un e-mail setat ca e-mail public în contul dumneavoastră GitHub", + "Give_a_unique_name_for_the_custom_oauth" : "AlegeÈ›i un nume unic pentru OAuth personalizat", + "Give_the_application_a_name_This_will_be_seen_by_your_users" : "Da aplicaÈ›iei un nume. Acest lucru va fi văzut de utilizatori.", + "Has_more" : "Are mai multe", + "Have_your_own_chat" : "Avea propriul dumneavoastră web chat. Scris folosind Meteor.com, Rocket.Chat este o soluÈ›ie excelentă pentru developerii care vor să construiască È™i să dezvolte platforma lor de chat.", + "Hide_room" : "Ascunde camera", + "History" : "Istoric", + "hours" : "ore", + "Incorrect_Password" : "Parolă incorectă", + "inline_code" : "inline_code", + "Install_Extension" : "InstalaÈ›i extensie", + "Install_FxOs" : "InstalaÈ›i Rocket.Chat pe Firefox", + "Install_FxOs_done" : "Grozav! Acum puteÈ›i folosi Rocket.Chat atingând pictograma de pe ecranul de start. Distrează-te cu Rocket.Chat!", + "Install_FxOs_error" : "Ne pare rău, lucrurile n-au mers bine! Următoarea eroare a apărut:", + "Install_FxOs_follow_instructions" : "Vă rugăm să confirmaÈ›i instalarea aplicaÈ›iei pe dispozitiv (apăsaÈ›i \"Install\" când vi se solicită).", + "Integration_added" : "Integrarea a fost adăugată", + "Integration_Incoming_WebHook" : "Integrare Intrare WebHook", + "Integration_New" : "Integrare nouă", + "Integration_updated" : "Integrarea a fost actualizată", + "Integrations" : "Integrări", + "Invalid_asset" : "Resursă invalidă", + "Invalid_confirm_pass" : "Confirmarea parolei nu se potriveÈ™te cu parola introdusă", + "Invalid_email" : "Adresa de email folosită este invalidă", + "Invalid_file_height" : "ÃŽnălÈ›ime fiÈ™ier invalidă.", + "Invalid_file_type" : "Tip de fiÈ™ier invalid", + "Invalid_file_width" : "Lățime fiÈ™ier invalidă", + "Invalid_name" : "Câmpul nume de utilizator nu poate fi gol", + "Invalid_pass" : "Câmpul de parolă nu poate fi gol", + "Invalid_room_name" : "<strong>%s</strong> nu este un nume de cameră valid,<br/> folosiÈ›i doar litere, cifre È™i cratimă", + "Invalid_room_type" : "<strong>%s</strong> nu e un nume de cameră valid.", + "Invalid_Secret_URL" : "URL secret invalid", + "Invalid_secret_URL_message" : "URL-ul furnizat este invalid.", + "invisible" : "invizibil", + "Invisible" : "Invizibil", + "Invitation_HTML" : " HTML InvitaÈ›ie", + "Invitation_Subject" : "Subiect InvitaÈ›ie ", + "Invite_Users" : "InvitaÈ›i utilizatori", + "is_also_typing" : "tastează", + "is_also_typing_female" : "tastează", + "is_also_typing_male" : "tastează", + "is_typing" : "tastează", + "is_typing_female" : "tastează", + "is_typing_male" : "tastează", + "italics" : "cursive", + "join" : "AlăturaÈ›i-vă", + "Join_audio_call" : "Intră în apel audio", + "Join_the_Community" : "IntraÈ›i în comunitate", + "Join_video_call" : "Intră în apel video", + "Jump_to_first_unread" : "Salt la primul mesaj necitit", + "Jump_to_message" : "Salt la mesaj", + "Jump_to_recent_messages" : "Salt la mesajele recente", + "Language" : "Limba", + "Language_Version" : "Versiunea în limba Română", + "Last_login" : "Ultima autentificare", + "Last_message" : "Ultimul mesaj", + "Layout" : "Layout", + "Layout_Home_Body" : "Corp pagină 'Acasă'", + "Layout_Home_Title" : "Titlu pagină 'Acasă'", + "Layout_Login_Header" : "Header Autentificare", + "Layout_Login_Terms" : "Termeni Autentificare", + "Layout_Privacy_Policy" : "Politica de confidenÈ›ialitate", + "Layout_Sidenav_Footer" : "Footer meniu lateral", + "Layout_Sidenav_Footer_description" : "Dimensiunea footer-ului este de 260 x 70px", + "Layout_Terms_of_Service" : "CondÈ›ii de utilizare", + "LDAP" : "LDAP", + "LDAP_Bind_Search" : "Bind Search", + "LDAP_Bind_Search_Description" : "O bucată de JSON care guvernează leagarea È™i conectarea de informaÈ›ii È™i este de forma {\"filter\": \"(&(objectCategory=person)(objectclass=user)(memberOf=CN=ROCKET_ACCESS,CN=Users,DC=domain,DC=com)(sAMAccountName=#{username}))\", \"scope\": \"sub\", \"userDN\": \"rocket.service@domain.com\", \"password\": \"urpass\"}", + "LDAP_Description" : "LDAP este o bază de date ierarhică pe care multe companii o folosesc pentru a oferi osingură  parolă pe mai multe site-uri È™i servicii. Pentru informaÈ›ii È™i exemple de configurare avansate, vă rugăm să consultaÈ›i wiki nostru: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", + "LDAP_DN" : "Distinguished Name (DN)", + "LDAP_DN_Description" : "Rădăcină de căutare; exemplu: dc = domeniu, DC = com", + "LDAP_Enable" : "ActivaÈ›i LDAP", + "LDAP_Enable_Description" : "ÃŽncearcă să utilizezi LDAP pentru autentificare.", + "LDAP_Port" : "LDAP Port", + "LDAP_Port_Description" : "Port pentru a accesa LDAP pe; de exemplu: 389", + "LDAP_Sync_User_Data" : "Sync Data", + "LDAP_Sync_User_Data_Description" : "PăstraÈ›i datele utilizatorului în sincron cu serverul de autentificare (de exemplu: nume, e-mail).", + "LDAP_Sync_User_Data_FieldMap" : "User Data Field Map", + "LDAP_Sync_User_Data_FieldMap_Description" : "ConfiguraÈ›i modul în care detalii ale contului de utilizator (cum ar fi e-mail) sunt populate de o înregistrare LDAP (odată găsită). De exemplu, {\"cn\": \"Numele\", \"e-mail\": \"e-mail\"} va alege numele unei persoane ce poate fi citit de la atributul cn, È™i e-mail lor de atributul e-mail. Detaliile disponibile includ numele È™i e-mail.", + "LDAP_Url" : "LDAP URL", + "LDAP_Url_Description" : "URL-ul serverului LDAP; exemplu: ldap: //company.dns.com", + "Leave_room" : "PărăseÈ™te camera", + "line" : "linie", + "Load_more" : "ÃŽncarcă mai multe", + "Loading..." : "Se încarcă...", + "Loading_more_from_history" : "Se încarcă mai multe din istoric", + "Loading_suggestion" : "Se încarcă sugestii...", + "Logged_out_of_other_clients_successfully" : "Delogat cu succes din alÈ›i clienÈ›i", + "Login" : "Autentificare", + "Login_with" : "Autentifică-te cu %s", + "login_with" : "Sau conectare direct cu", + "Logout" : "IeÈ™ire", + "Logout_Others" : "Delogare din celelalte locaÈ›ii", + "Make_Admin" : "Fă utilizator de tip Admin", + "Mark_as_read" : "Marchează ca citit", + "Markdown_Headers" : "Markdown Headers", + "Members" : "Membri", + "Members_List" : "Lista de membri", + "Members_placeholder" : "Membri", + "Message" : "Mesaj", + "Message_AllowDeleting" : "PermiteÈ›i È™tergerea mesajului", + "Message_AllowEditing" : "PermiteÈ›i editarea mesajului", + "Message_AllowEditing_BlockEditInMinutes" : "Blocare editare mesaje după (n) minute", + "Message_AllowEditing_BlockEditInMinutesDescription" : "IntroduceÈ›i 0 pentru a dezactiva blocarea.", + "Message_AudioRecorderEnabled" : "Audio Recorder Activat", + "Message_AudioRecorderEnabledDescription" : "Necesită \"/ WAV audio\" să fie un tip de media acceptat în setările \"upload\".", + "Message_deleting_not_allowed" : "Nu e permisă È™tergerea de mesaje", + "Message_editing_blocked" : "Acest mesaj nu mai poate fi editat", + "Message_editing_not_allowed" : "Nu e permisă editarea de mesaje", + "Message_GroupingPeriod" : "Perioadă pentru grupare (în secunde)", + "Message_GroupingPeriodDescription" : "Mesajele vor fi grupate cu mesajul anterior dacă sunt de la acelaÈ™i utilizator È™i timpul scurs a fost mai mic decât perioada pentru grupare în secunde.", + "Message_KeepHistory" : "Păstrează istoricul mesajelor", + "Message_MaxAllowedSize" : "Dimensiunea maximă admisă Mesaj", + "Message_pinned" : "Mesaj fixat", + "Message_pinning_not_allowed" : "Nu e permisă fixarea de mesaje", + "Message_removed" : "Mesaj eliminat", + "Message_ShowDeletedStatus" : "AfiÈ™are starea de È™tergere", + "Message_ShowEditedStatus" : "AfiÈ™ează starea de editare", + "Message_ShowFormattingTips" : "Arată sugestii de formatare", + "Messages" : "Mesaje", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here" : "Mesajele care sunt trimise prin WebHook vor fi postate aici.", + "Meta" : "Meta", + "Meta_fb_app_id" : "Facebook App ID", + "Meta_google-site-verification" : "Google Site Verification", + "Meta_language" : "Limba", + "Meta_msvalidate01" : "MSValidate.01", + "Meta_robots" : "RoboÈ›i", + "minutes" : "minute", + "More_channels" : "Mai multe canale", + "More_groups" : "Mai multe grupuri private", + "More_unreads" : "Mai multe necitite", + "Msgs" : "Mesaje", + "multi" : "multi", + "Mute_user" : "Blochează mesajele utilizatorului", + "Muted" : "SilenÈ›ios", + "My_Account" : "Contul meu", + "n_messages" : "%s mesaje", + "Name" : "Nume", + "Name_cant_be_empty" : "Numele nu poate fi gol", + "Name_optional" : "Nume (opÈ›ional)", + "New_Application" : "AplicaÈ›ie nouă", + "New_integration" : "Integrare nouă", + "New_messages" : "Mesaje noi", + "New_password" : "Parolă nouă", + "No_channel_with_name_%s_was_found" : "Niciun canal găsit cu numele <strong>\"%s\"</strong>!", + "No_channels_yet" : "ÃŽncă nu faceÈ›i parte din niciun canal.", + "No_direct_messages_yet" : "ÃŽncă nu aÈ›i iniÈ›iat nicio conversaÈ›ie.", + "No_favorites_yet" : "ÃŽncă nu aÈ›i adăugat niciun canal favorit.", + "No_group_with_name_%s_was_found" : "Niciun grup privat găsit cu numele <strong>\"%s\"</strong>!", + "No_groups_yet" : "ÃŽncă nu aveÈ›i niciun grup privat.", + "No_livechats" : "Nu aveÈ›i livechats.", + "No_permission_to_view_room" : "Nu aveÈ›i permisiunea de a vedea această cameră", + "No_results_found" : "Niciun rezultat găsit", + "no_tokens_for_this_user" : "Nu există tokens pentru acest utilizator.", + "No_user_with_username_%s_was_found" : "Niciun utilizator găsit cu numele de utilizator <strong>\"%s\"</strong>!", + "Not_allowed" : "Nepermis", + "Not_authorized" : "Neautorizat", + "Not_found_or_not_allowed" : "Nu a fost găsit sau nu e permis", + "Nothing_found" : "Nu s-a găsit nimic", + "Notify_all_in_this_room" : "Notifică toÈ›i utilizatorii din această cameră", + "OAuth_Application" : "AplicaÈ›ie OAuth", + "OAuth_Applications" : "AplicaÈ›ii OAuth", + "Old_and_new_password_required" : "Trebuie să introduceÈ›i È™i parola veche È™i cea nouă pentru a schimba parola.", + "Old_Password" : "Parola veche", + "Online" : "Activ", + "Only_you_can_see_this_message" : "Doar dumneavoastră puteÈ›i vedea acest mesaj", + "Oops!" : "Oops", + "Opt_out_statistics" : "Nu trimiteÈ›i statisticile mele la Rocket.Chat", + "Opt_out_statistics_warning" : "Prin trimiterea statisticilor, veÈ›i ajuta să identificăm modul în care e utilizat Rocket.Chat, precum È™i cât de bine se comportă sistemul, astfel încât să putem îmbunătăți în continuare aplicaÈ›ia. Nu vă faceÈ›i griji, nu se trimit informaÈ›ii despre utilizatori È™i toate informaÈ›iile pe care le primim sunt păstrate în mod confidenÈ›ial. Dacă doriÈ›i să continuaÈ›i a ne trimite statisticile, debifaÈ›i caseta de selectare de mai sus. MulÈ›umim.", + "optional" : "facultativ", + "others" : "alÈ›i", + "Password" : "Parolă", + "Password_Change_Disabled" : "Administratorul a dezactivat schimbarea de parole", + "Password_changed_successfully" : "Parola a fost schimbată cu succes", + "People" : "Oameni", + "Please_enter_value_for_url" : "Vă rugăm să introduceÈ›i o valoare pentru adresa URL a avatarului.", + "Please_enter_your_new_password_below" : "Vă rugăm să introduceÈ›i noua parolă mai jos:", + "Please_wait" : "Vă rugăm aÈ™teptaÈ›i", + "Please_wait_activation" : "Vă rugăm să aÈ™teptaÈ›i, acest lucru poate dura ceva timp.", + "Please_wait_statistics" : "Vă rugăm să aÈ™teptaÈ›i, statisticile sunt generate.", + "Post_as" : "Publică drept", + "Post_to_Channel" : "Publică pe canal", + "Post_to_s_as_s" : "Publică în <strong>%s</strong> as <strong>%s</strong>", + "Powered_by" : "Oferit de", + "Preferences" : "PreferinÈ›e", + "Preferences_saved" : "PreferinÈ›e salvate", + "Privacy" : "ConfidenÈ›ialitate", + "Private_Groups" : "Grupuri private", + "Private_Groups_list" : "Lista grupurilor private", + "Profile" : "Profil", + "Profile_saved_successfully" : "Profil salvat cu succes", + "Proudly_developed" : "Scris cu mândrie folosind Meteor", + "Push" : "Notificări Push", + "Push_apn_cert" : "APN Cert", + "Push_apn_dev_cert" : "APN Dev Cert", + "Push_apn_dev_key" : "APN Dev Key", + "Push_apn_dev_passphrase" : "APN Dev Passphrase", + "Push_apn_key" : "APN Key", + "Push_apn_passphrase" : "APN Passphrase", + "Push_debug" : "Depanare", + "push_disabled" : "Push dezactivat", + "Push_enable" : "Activează", + "Push_enable_gateway" : "ActivaÈ›i Gateway", + "Push_gateway" : "Gateway", + "Push_gcm_api_key" : "GCM API Key", + "Push_gcm_project_number" : "GCM Project Number", + "Push_production" : "ProducÈ›ie", + "Push_test_push" : "Test", + "Quick_Search" : "Cautare rapida", + "quote" : "citat", + "Recents" : "Recente", + "Record" : "ÃŽnregistrează", + "Redirect_URI" : "RedirecÈ›ionare URI", + "Refresh_your_page_after_install_to_enable_screen_sharing" : "Reîncarcă pagina după instalare pentru a permite partajarea de ecran", + "Register" : "ÃŽnregistrează un cont nou", + "Registration_Succeeded" : "ÃŽnregistrarea a reuÈ™it", + "Remember_me" : "Èšine-mă minte", + "Remove" : "Elimină", + "Remove_Admin" : "EliminaÈ›i utilizator de tip Admin", + "Remove_as_moderator" : "EliminaÈ›i ca moderator", + "Remove_as_owner" : "EliminaÈ›i ca proprietar", + "Remove_custom_oauth" : "EliminaÈ›i OAuth personalizat", + "Remove_from_room" : "EliminaÈ›i din cameră", + "Removed" : "Eliminat", + "Reset" : "Reset", + "Reset_password" : "Resetează parola", + "Restart" : "Repornire", + "Restart_the_server" : "ReporniÈ›i serverul", + "Room" : "Cameră", + "Room_archived" : "Cameră arhivată", + "Room_has_been_deleted" : "Camera a fost È™tearsă", + "Room_name_changed" : "Numele camerei a fost schimbat în: <em>__room_name__</em> de către <em>__user_by__</em>", + "Room_name_changed_successfully" : "Numele camerei a fost schimbat cu succes.", + "Room_not_found" : "Camera nu a fost găsită", + "Room_unarchived" : "Cameră dezarhivată", + "Room_uploaded_file_list" : "Lista de fiÈ™iere", + "Room_uploaded_file_list_empty" : "Niciun fiÈ™ier disponibil.", + "room_user_count" : "%s utilizatorii", + "Rooms" : "Camere", + "S_new_messages_since_s" : "%s mesaje noi de la %s", + "SAML" : "SAML", + "SAML_Custom_Cert" : "Custom Certificate", + "SAML_Custom_Entry_point" : "Custom Entry Point", + "SAML_Custom_Generate_Username" : "Generate Username", + "SAML_Custom_Issuer" : "Custom Issuer", + "SAML_Custom_Provider" : "Custom Provider", + "Save_changes" : "Salvează modificările", + "Save_Mobile_Bandwidth" : "EconomiseÈ™te lățime de bandă în modul Mobile", + "Screen_Share" : "Partajare ecran", + "Search" : "Căutare", + "Search_Messages" : "Căutare mesaje", + "Search_settings" : "Setări de căutare", + "seconds" : "secunde", + "See_all" : "VedeÈ›i tot", + "See_only_online" : "Doar online", + "Select_an_avatar" : "SelectaÈ›i un avatar", + "Select_file" : "SelectaÈ›i fiÈ™ierul", + "Select_service_to_login" : "SelectaÈ›i un serviciu pentru a vă conecta pentru a încărca fotografia dumneavoastră de profil sau încărcaÈ›i una direct de pe computer", + "Selected_users" : "Membri selectaÈ›i", + "Send" : "Trimite", + "Send_a_test_mail_to_my_user" : "Trimite un e-mail de test pentru utilizator meu", + "Send_a_test_push_to_my_user" : "Trimite Push de test pentru utilizator meu", + "Send_confirmation_email" : "Trimite email de confirmare", + "Send_data_into_RocketChat_in_realtime" : "Trimite datele înspre Rocket.Chat în timp real.", + "Send_invitation_email" : "Trimite e-mail de invitaÈ›ie", + "Send_invitation_email_error" : "Nu aÈ›i furnizat nici o adresă de e-mail validă.", + "Send_invitation_email_info" : "PuteÈ›i trimite mai multe invitaÈ›ii de e-mail odată.", + "Send_invitation_email_success" : "AÈ›i trimis cu succes o invitaÈ›ie de e-mail la următoarele adrese:", + "Send_invitation_email_warning" : "Pentru a trimite invitaÈ›ii e-mail, trebuie să configuraÈ›i mai întâi setările SMTP.", + "Send_Message" : "Trimite mesaj", + "Send_your_JSON_payloads_to_this_URL" : "TrimiteÈ›i JSON către această adresă URL.", + "Set_as_moderator" : "SetaÈ›i ca moderator", + "Set_as_owner" : "SetaÈ›i ca proprietar", + "Settings" : "Setări", + "Settings_updated" : "Setări actualizare", + "Should_be_a_URL_of_an_image" : "Ar trebui să fie o adresă URL a unei imagini.", + "Should_exists_a_user_with_this_username" : "Trebuie să existe deja un utilizator cu acest nume de utilizator.", + "Showing_archived_results" : "<p>Se arată <b>%s</b> rezultate arhivate</p>", + "Showing_online_users" : "Se afiÈ™ează <b>__total_online__</b> din __total__ users", + "Showing_results" : "<p>Se afiÈ™ează <b>%s</b> rezultate</p>", + "Silence" : "Tăcere", + "since_creation" : "de la %s", + "Site_Name" : "Numele site-ului", + "Site_Url" : "URL-ul site-ului", + "Site_Url_Description" : "Exemplu: https://chat.domain.com/", + "SMTP" : "SMTP", + "SMTP_Host" : "SMTP Host", + "SMTP_Password" : "SMTP Password", + "SMTP_Port" : "Port SMTP", + "SMTP_Test_Button" : "Setări SMTP de testare", + "SMTP_Username" : "Nume de utilizator SMTP ", + "Sound" : "Sunet", + "Start_audio_call" : "PorneÈ™te apel audio", + "Start_of_conversation" : "ÃŽnceputul conversaÈ›iei", + "Start_video_call" : "PorneÈ™te apel video", + "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" : "ÃŽncepe cu <code class=\"inline\">%s</code> pentru utilizator sau <code class=\"inline\">%s</code> pentru canal. Ex: <code class=\"inline\">%s</code> sau <code class=\"inline\">%s</code>", + "Statistics" : "Statistici", + "Stats_Active_Users" : "Utilizatori activi", + "Stats_Avg_Channel_Users" : "Medii utilizatori canal", + "Stats_Avg_Private_Group_Users" : "Medie utilizatori grup privat", + "Stats_Away_Users" : "Utilizatori Away", + "Stats_Max_Room_Users" : "Maximum număr de utilizatori în cameră", + "Stats_Non_Active_Users" : "Utilizatori inactivi", + "Stats_Offline_Users" : "Utilizatori offline", + "Stats_Online_Users" : "Utilizatori Activi", + "Stats_OS_Arch" : "OS Arch", + "Stats_OS_Cpus" : "OS număr CPU ", + "Stats_OS_Freemem" : "OS Free Memory", + "Stats_OS_Loadavg" : "OS Load Media", + "Stats_OS_Platform" : "OS Platform", + "Stats_OS_Release" : "OS Release", + "Stats_OS_Totalmem" : "OS Total Memory", + "Stats_OS_Type" : "Tip sistem de operare", + "Stats_OS_Uptime" : "OS Uptime", + "Stats_Total_Channels" : "Total Canale", + "Stats_Total_Direct_Messages" : "Total camere mesaje directe", + "Stats_Total_Messages" : "Numărul total de mesaje", + "Stats_Total_Private_Groups" : "Total grupuri private", + "Stats_Total_Rooms" : "Total camere", + "Stats_Total_Users" : "Utilizatori", + "Stop_Recording" : "OpreÈ™te înregistrare", + "strike" : "tăiat", + "Submit" : "Trimite", + "Success" : "Succes", + "The_application_name_is_required" : "Este nevoie de numele aplicaÈ›iei", + "The_channel_name_is_required" : "Este nevoie de numele canalului", + "The_field_is_required" : "Este nevoie de câmpul %s.", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server" : "Redimensionarea imaginii nu va funcÈ›iona, deoarece nu putem detecta ImageMagick sau GraphicsMagick instalat pe server.", + "The_redirectUri_is_required" : "URI de redirectare este necesar", + "The_server_will_restart_in_s_seconds" : "Serverul va reporni în %s secunde", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s" : "Setarea <strong>%s</strong> e configurată să <strong>%s</strong> iar dumneavoastră accesaÈ›i din <strong>%s</strong>!", + "The_user_will_be_removed_from_s" : "Utilizatorul va fi eliminat din %s", + "The_user_wont_be_able_to_type_in_s" : "Utilizatorul nu va putea să introducă text în %s", + "There_are_no_integrations" : "Nu sunt integrări", + "This_is_a_push_test_messsage" : "Acesta este un test de notificare Push", + "True" : "Adevărat", + "Type_your_new_password" : "IntroduceÈ›i noua parolă", + "Unarchive" : "DezarhivaÈ›i", + "Unmute_user" : "Deblochează mesajele utilizatorului", + "Unnamed" : "Anonim", + "Unread_Rooms" : "Camere necitite", + "Unread_Rooms_Mode" : "Mod camere necitite", + "Upload_file_question" : "ÃŽncarcă fiÈ™ier?", + "Uploading_file" : "ÃŽncărcare de fiÈ™iere ...", + "Use_Emojis" : "FolosiÈ›i Emoji", + "Use_initials_avatar" : "FolosiÈ›i iniÈ›ialele numelui de utilizator", + "use_menu" : "FolosiÈ›i meniul lateral pentru a vă accesa camerele È™i chat-urile", + "Use_service_avatar" : "UtilizaÈ›i avatarul %s", + "Use_this_username" : "FolosiÈ›i acest nume de utilizator", + "Use_uploaded_avatar" : "UtilizaÈ›i avatar încărcat", + "Use_url_for_avatar" : "UtilizaÈ›i URL pentru avatar", + "User__username__is_now_a_moderator_of__room_name_" : "Utilizator __username__  este acum un moderator al __room_name__", + "User__username__is_now_a_owner_of__room_name_" : "Utilizatorul __username__ este acum proprietar al  __room_name__", + "User__username__removed_from__room_name__moderators" : "Utilizatorul __username__ a fost eliminat din moderatorii  __room_name__", + "User__username__removed_from__room_name__owners" : "Utilizatorul __username__ scos din proprietarii __room_name__", + "User__username__was_added_as_a_moderator_by__user_by_" : "Utilizatorul <em>__username__</em> a fost adăugat ca moderator de către <em>__user_by__</em>", + "User__username__was_added_as_a_owner_by__user_by_" : "Utilizatorul <em>__username__</em> a fost adăugat ca proprietar de către <em>__user_by__</em>", + "User__username__was_removed_as_a_moderator_by__user_by_" : "Utilizatorul <em>__username__</em> a fost scos ca moderator de către <em>__user_by__</em>", + "User__username__was_removed_as_a_owner_by__user_by_" : "Utilizatorul <em>__username__</em> a fost eliminat ca proprietar de către <em>__user_by__</em>", + "User_added_by" : "Utilizator <em>__user_added__</em> adăugat de către <em>__user_by__</em>.", + "User_Channels" : "Canale utilizator", + "User_has_been_activated" : "Utilizatorul a fost activat", + "User_has_been_deactivated" : "Utilizator a fost dezactivat", + "User_has_been_deleted" : "Utilizatorul a fost È™ters", + "User_has_been_muted_in_s" : "Utilizator a fost oprit în %s", + "User_has_been_removed_from_s" : "Utilizator a fost eliminat din %s", + "User_Info" : "Info utilizator", + "User_is_no_longer_an_admin" : "Utilizatorul nu mai este Admin", + "User_is_not_activated" : "Utilizatorul nu este activat", + "User_is_now_an_admin" : "Utilizatorul este acum Admin", + "User_joined_channel" : "A intrat pe canal.", + "User_joined_channel_female" : "A intrat pe canal.", + "User_joined_channel_male" : "A intrat pe canal.", + "User_left" : "A părăsit canalul.", + "User_left_female" : "A părăsit canalul.", + "User_left_male" : "A părăsit canalul.", + "User_logged_out" : "Utilizatorul este deconectat", + "User_muted_by" : "Utilizatorul <em>__user_muted__</em> a fost blocat de către  <em>__user_by__</em>.", + "User_muted_in_room" : "Utilizator blocat în cameră", + "User_not_found_or_incorrect_password" : "Utilizator nu a fost găsit sau parolă incorectă", + "User_or_channel_name" : "Nume de utilizator sau de canal ", + "User_removed_by" : "Utilizator <em>__user_removed__</em> È™ters de către <em>__user_by__</em>.", + "User_removed_from_room" : "Utilizatorul a fost scos din cameră", + "User_Settings" : "Setări utilizator", + "User_unmuted_by" : "Utilizatorul <em>__user_muted__</em> a fost deblocat de către <em>__user_by__</em>.", + "User_unmuted_in_room" : "Utilizator deblocat în cameră", + "User_updated_successfully" : "Utilizator actualizat cu succes", + "Username" : "Nume de ultilizator", + "Username_cant_be_empty" : "Numele de utilizator nu poate fi gol", + "Username_Change_Disabled" : "Administratorul a dezactivat schimbarea de nume de utilizator", + "Username_description" : "Numele de utilizator este folosit pentru a permite altora să vă menÈ›ioneze în mesaje.", + "Username_invalid" : "<strong>%s</strong>nu e un nume de utilizator valid,<br/> folosiÈ›i doar litere, cifre È™i cratime", + "Username_title" : "ÃŽnregistrează nume de utilizator", + "Username_unavaliable" : "<strong>%s</strong> e deja folosit :(", + "Users" : "Utilizatori", + "UTF8_Names_Slugify" : "UTF8 Names Slugify", + "UTF8_Names_Validation" : "Validare UTF8 Names ", + "UTF8_Names_Validation_Description" : "Nu permite caractere È™i spaÈ›ii speciale. PuteÈ›i folosi '-',  '_' È™i '.' dar nu la sfârÈ™itul numelui", + "View_All" : "Vezi toÈ›i", + "Wait_activation_warning" : "Ca să vă puteÈ›i autentifica, contul dumneavoastră trebuie să fie activat manual de către un administrator.", + "We_have_sent_password_email" : "V-am trimis un e-mail cu instrucÈ›iuni de resetare a parolei. Dacă nu primiÈ›i un e-mail în scurt timp, va rugăm să reveniti È™i să încercaÈ›i din nou.", + "We_have_sent_registration_email" : "V-am trimis un e-mail pentru a confirma înregistrarea dumneavoastră. Dacă nu primiÈ›i un e-mail în scurt timp, vă rugăm să reveniÈ›i È™i să încercaÈ›i din nou.", + "Welcome" : "Bun venit <em>%s</em>.", + "Welcome_to_the" : "Bun venit în", + "will_be_able_to" : "va putea", + "With_whom" : "Cu cine", + "Yes" : "Da", + "Yes_clear_all" : "Da, È™terge toate!", + "Yes_delete_it" : "Da, È™terge-l!", + "Yes_mute_user" : "Da, blochează mesajele utilizatorului", + "Yes_remove_user" : "Da, eliminaÈ›i utilizatorul!", + "you_are_in_preview_mode_of" : "Vă aflaÈ›i în modul de previzualizare a canalului #", + "You_are_logged_in_as" : "SunteÈ›i autentificat ca ", + "You_can_change_a_different_avatar_too" : "PuteÈ›i înlocui avatarul folosit pentru a posta din această integrare.", + "You_can_use_an_emoji_as_avatar" : "PuteÈ›i utiliza un emoji ca avatar", + "You_have_been_muted" : "AÈ›i fost blocat È™i nu puteÈ›i vorbi în această cameră", + "You_need_confirm_email" : "ConfirmaÈ›i adresa de email pentru a vă înregistra!", + "You_need_install_an_extension_to_allow_screen_sharing" : "AveÈ›i nevoie de a instala o extensie pentru a permite partajarea ecranului", + "You_should_name_it_to_easily_manage_your_integrations" : "Ar trebui să o numiÈ›i pentru a vă gestiona cu uÈ™urință integrările.", + "You_will_not_be_able_to_recover" : "Nu veÈ›i putea recupera acest mesaj!", + "Your_entry_has_been_deleted" : "Mesajul dumneavoastră a fost È™ters.", + "Your_mail_was_sent_to_s" : "E-mail-ul a fost trimis la %s", + "Your_Open_Source_solution" : "Propria soluÈ›ie de chat Open Source", + "Your_push_was_sent_to_s_devices" : "Mesajul Push a fost trimis la %s dispozitive" +} \ No newline at end of file diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 4295b405854935a15a6e28ce79ccd4dc2e01fdf5..ee1c1597ec3519e87bdd3308d5b381f4173dd52c 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -1,26 +1,49 @@ { "Access_online_demo" : "Попробовать демо-верÑию", "Access_Online_Demo" : "Попробовать демо-верÑию", + "Accounts" : "Ðккаунты", + "Accounts_AllowedDomainsList" : "СпиÑок разрешенных доменов", + "Accounts_AllowedDomainsList_Description" : "Разделенный запÑтыми ÑпиÑок разрешенных доменов", + "Accounts_AllowPasswordChange" : "Разрешить Ñмену паролÑ", + "Accounts_AllowUserAvatarChange" : "Разрешить пользователю изменÑÑ‚ÑŒ Ðватар", + "Accounts_AllowUsernameChange" : "Разрешить изменÑÑ‚ÑŒ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ", + "Accounts_AllowUserProfileChange" : "Разрешить пользователю изменÑÑ‚ÑŒ наÑтройки профилÑ", + "Accounts_AvatarResize" : "Изменение размера аватара", + "Accounts_AvatarSize" : "Размер аватара", + "Accounts_AvatarStorePath" : "Путь к аватарам", + "Accounts_AvatarStoreType" : "Тип хранилища Ðватаров", + "Accounts_denyUnverifiedEmail" : "Запретить непроверенные e-mail", "Accounts_EmailVerification" : "Подтверждение e-mail", + "Accounts_ManuallyApproveNewUsers" : "Утверждать вручную новых пользователей", "Accounts_OAuth_Custom_Button_Color" : "Цвет кнопки", "Accounts_OAuth_Custom_Button_Label_Color" : "Цвет текÑта кнопки", "Accounts_OAuth_Custom_Button_Label_Text" : "ТекÑÑ‚ кнопки", "Accounts_OAuth_Custom_Enable" : "Включить", "Accounts_OAuth_Custom_Secret" : "Ключ", + "Accounts_OAuth_Custom_URL" : "URL", + "Accounts_OAuth_Gitlab" : "OAuth включен", "Accounts_OAuth_Google" : "Google логин", "Accounts_OAuth_Google_id" : "Google ID", "Accounts_OAuth_Google_secret" : "Google пароль", "Accounts_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", + "Activate" : "Ðктивировать", + "Add_custom_oauth" : "Добавить пользовательÑкий OAuth", "Add_Members" : "Добавить Пользователей", "Add_users" : "Добавить пользователей", + "Administration" : "ÐдминиÑтрирование", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "ПоÑле аутентификации OAuth2, пользователи будут перенаправлÑÑ‚ÑŒÑÑ Ð½Ð° Ñтот URL", "All_channels" : "Ð’Ñе Чаты", + "Allow_Invalid_SelfSigned_Certs" : "Разрешить невалидные ÑамоподпиÑанные Ñертификаты", + "Allow_Invalid_SelfSigned_Certs_Description" : "Разрешить некорректные и ÑамоподпиÑанные SSL Ñертификаты Ð´Ð»Ñ ÑвÑзи валидации и предпроÑмотра", "and" : "и", "API_Analytics" : "Ðналитика", + "API_EmbedDisabledFor_Description" : "Разделенный запÑтыми ÑпиÑок имен пользователей", + "Archive" : "Удалить", "are_also_typing" : "вÑе ещё печатают", "are_typing" : "печатает", "Are_you_sure" : "Ð’Ñ‹ уверены?", "Auto_Load_Images" : "Ðвтозагрузка изображений", - "Avatar_changed_successfully" : "Ðватар измененм уÑпешно", + "Avatar_changed_successfully" : "Ðватар уÑпешно изменен", "away" : "отошёл", "Away" : "Отошёл", "away_female" : "отошла", @@ -46,14 +69,25 @@ "Confirm_password" : "Подтвердить пароль", "Contact" : "Контакт", "Conversation" : "Диалог", + "Convert_Ascii_Emojis" : "Конвертировать ASCII в Emoji", "Create_new" : "Создать новый", + "Create_new_direct_message_room" : "Создать комнату Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… Ñообщений", "Create_new_private_group" : "Создать новый приватный чат", "Create_new_public_channel" : "Создать новый публичный чат", "Created_at" : "Создано в", + "Custom_oauth_unique_name" : "Уникальное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÑŒÑкого OAuth ", "days" : "дней", + "Deactivate" : "Деактивировать", + "Delete_Room_Warning" : "Удаление чата так же удалит вÑе ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² Ñтом чате. Ðто не может быть отменено.", + "Delete_User_Warning" : "Удаление Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ вÑе ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Ñтого пользователÑ. Ðто дейÑтвие невозможно отменить.", "Deleted" : "Удалено!", + "Desktop_Notifications" : "Desktop уведомлениÑ", + "Desktop_Notifications_Disabled" : "Desktop ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ñ‹. Измените наÑтройки браузера, еÑли вам нужно включить уведомлениÑ.", "Desktop_Notifications_Enabled" : "Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ Ñтола включены", "Direct_Messages" : "Личные ÑообщениÑ", + "Disable_Favorite_Rooms" : "Отключить избранное", + "Disable_New_Message_Notification" : "Отключить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ новых ÑообщениÑÑ…", + "Disable_New_Room_Notification" : "Отключить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ новых чатах", "Drop_to_upload_file" : "ПеремеÑтите Ñюда Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ файла", "Duplicate_channel_name" : "Канал Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%s' ÑущеÑтвует", "Duplicate_private_group_name" : "ЧаÑÑ‚Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð° Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%s' ÑущеÑтвует", @@ -61,25 +95,41 @@ "edited" : "отредактировано", "Email_already_exists" : "Ðл. Ð°Ð´Ñ€ÐµÑ ÑƒÐ¶Ðµ ÑущеÑтвует", "Email_or_username" : "Почтовый Ñщик или логин", - "Email_verified" : "Ðлектронный Ð°Ð´Ñ€ÐµÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐµÐ½", + "Email_verified" : "E-mail проверÑетÑÑ", "Enable_Desktop_Notifications" : "Включить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ Ñтола", "Enter_info" : "Введите Ñвои данные", + "Enter_to" : "Войти в", "Error_changing_password" : "Ошибка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ", + "Error_too_many_requests" : "Ошибка, Ñлишком много запроÑов. ПожалуйÑта, помедленнее. Ð’Ñ‹ должны подождать%s Ñекунд, прежде чем попробовать Ñнова", + "Esc_to" : "Выйти из", + "False" : "Ðет", "Favorites" : "Избранные чаты", + "FileUpload" : "Загрузка файла", + "FileUpload_Enabled" : "Загрузка файлов включена", + "FileUpload_MaxFileSize" : "МакÑимальный размер загружаемых файлов (в байтах)", + "FileUpload_ProtectFilesDescription" : "Только авторизованные пользователи будут иметь доÑтуп", "Follow_social_profiles" : "ДобавлÑйте Ð½Ð°Ñ Ð² Ð´Ñ€ÑƒÐ·ÑŒÑ Ð² Ñоциальных ÑетÑÑ…, форкайте на github и пишите Ñвои отзывы о нашем приложении у Ð½Ð°Ñ Ð² trello.", "Forgot_password" : "Забыли пароль?", "Fork_it_on_github" : "Форкайте на github", + "From_Email" : "От Email", + "General" : "Общий", "github_no_public_email" : "Ð’ наÑтройках GitHub отÑутÑтвует публично доÑтупный e-mail", + "Give_a_unique_name_for_the_custom_oauth" : "Задайте уникальное Ð¸Ð¼Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÑŒÑкого OAuth", + "Give_the_application_a_name_This_will_be_seen_by_your_users" : "Задайте приложению имÑ. Оно будет видно вÑем пользователÑм.", "Has_more" : "Еще", + "Have_your_own_chat" : "Создайте Ñвой веб чат. Разработанный на оÑнове Meteor.com Rocket.Chat Ñто отличное решение Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡ÐºÐ¸ÐºÐ¾Ð², которые хотÑÑ‚ Ñоздать Ñвою ÑобÑтвенную платформу Ð´Ð»Ñ Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ.", "Hide_room" : "Скрыть чат", "History" : "ИÑториÑ", "hours" : "чаÑ(Ñ‹)", + "Incorrect_Password" : "Ðеверный пароль", "inline_code" : "внутренний код", "Invalid_confirm_pass" : "Пароли не Ñовпадают", "Invalid_email" : "Ðеверный e-mail", + "Invalid_file_type" : "Ðеверный тип файла", "Invalid_name" : "Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым", "Invalid_pass" : "Пароль не может быть пуÑтым", "Invalid_room_name" : "<strong>%s</strong> недопуÑтимое Ð¸Ð¼Ñ ÐºÐ¾Ð¼Ð½Ð°Ñ‚Ñ‹, <br/> допуÑтимые Ñимволы: цифры, подчеркивание и буквы.", + "Invalid_room_type" : "<strong>%s</strong> недопуÑтимый тип комнаты.", "invisible" : "невидимый", "Invisible" : "Ðевидимый", "Invite_Users" : "ПриглаÑить пользователей", @@ -92,12 +142,19 @@ "italics" : "курÑив", "join" : "ПриÑоединитьÑÑ", "Join_the_Community" : "ПриÑоединитьÑÑ Ðº ÑообщеÑтву", + "Jump_to_first_unread" : "Перейти к первому непрочитанному", + "Jump_to_message" : "Перейти к Ñообщению", + "Jump_to_recent_messages" : "Перейти к поÑледнему Ñообщению", "Language" : "Язык", "Language_Version" : "РуÑÑÐºÐ°Ñ Ð²ÐµÑ€ÑиÑ", + "Last_login" : "ПоÑледний визит", "Last_message" : "ПоÑледнее Ñообщение", + "Layout_Home_Body" : "Контент главной", + "Layout_Home_Title" : "Ðазвание главной", "Layout_Privacy_Policy" : "Политика конфиденциальноÑти", "Layout_Terms_of_Service" : "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ÑпользованиÑ", "LDAP_DN" : "LDAP домен", + "LDAP_Enable" : "Включить LDAP", "LDAP_Port" : "LDAP Порт", "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Leave_room" : "Покинуть чат", @@ -118,40 +175,58 @@ "Message" : "Сообщение", "Message_AllowDeleting" : "Разрешить удаление Ñообщений", "Message_AllowEditing" : "Разрешить редактирование Ñообщений", + "Message_AllowEditing_BlockEditInMinutes" : "Запреить редактирование Ñообщений поÑле (n) минут", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Введите 0, чтобы отключить блокировку.", + "Message_deleting_not_allowed" : "Удаление Ñообщений запрещено", + "Message_editing_blocked" : "Ðто Ñообщение больше не может быть отредактировано", + "Message_editing_not_allowed" : "Редактирование Ñообщений запрещено", "Message_KeepHistory" : "Хранить иÑторию Ñообщений", + "Message_MaxAllowedSize" : "МакÑимально допуÑтимый размер ÑообщениÑ", + "Message_pinned" : "Сообщение прикреплено", + "Message_pinning_not_allowed" : "Прикрепление Ñообщений запрещено", "Message_removed" : "Сообщение удалено", "Message_ShowDeletedStatus" : "Отображать ÑÑ‚Ð°Ñ‚ÑƒÑ \"Удалено\"", "Message_ShowEditedStatus" : "Отображать ÑÑ‚Ð°Ñ‚ÑƒÑ \"Отредактировано\"", + "Message_ShowFormattingTips" : "Показывать Ñоветы по форматированию", "Messages" : "СообщениÑ", "Meta_language" : "Язык", + "Meta_robots" : "Боты", "minutes" : "минут(Ñ‹)", "More_channels" : "Другие чаты", + "More_groups" : "Больше приватных чатов", "More_unreads" : "Еще непрочитанные", "Msgs" : "СообщениÑ", "multi" : "много", "My_Account" : "Мой аккаунт", "n_messages" : "%s Ñообщений", "Name" : "ИмÑ", + "Name_cant_be_empty" : "Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым", "New_messages" : "Ðовые ÑообщениÑ", "New_password" : "Ðовый пароль", - "No_channel_with_name_%s_was_found" : "Канал Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼Â <strong>\"%s\"</strong> не найден!", + "No_channel_with_name_%s_was_found" : "Чат Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ <strong>\"%s\"</strong> не найден!", "No_channels_yet" : "Ð’Ñ‹ не ÑоÑтоите в публичных чатах.", "No_direct_messages_yet" : "Можно пиÑать пользователÑм приватные ÑообщениÑ.", "No_favorites_yet" : "Ð’ избранном пуÑто. Попробуй добавить Ñюда что-нибудь.", - "No_group_with_name_%s_was_found" : "ЧаÑÑ‚Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð° Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ <strong>\"%s\"</strong> не ÑущеÑтвует", + "No_group_with_name_%s_was_found" : "Приватный чат Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ <strong>\"%s\"</strong> не ÑущеÑтвует", "No_groups_yet" : "Ð’Ñ‹ не ÑоÑтоите ни в одном приватном чате.", "No_permission_to_view_room" : "У Ð²Ð°Ñ Ð½ÐµÑ‚ прав Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Ñтого чата.", - "No_user_with_username_%s_was_found" : "Ðет Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼  <strong>\"%s\"</strong>!", + "No_user_with_username_%s_was_found" : "Пользователь Ñ Ð»Ð¾Ð³Ð¸Ð½Ð¾Ð¼  <strong>\"%s\"</strong> не найден!", "Not_allowed" : "Ðе допуÑкаетÑÑ", "Not_found_or_not_allowed" : "Чат не ÑущеÑтвует или владелец ограничил доÑтуп ", "Nothing_found" : "Ðичего не найдено", "Notify_all_in_this_room" : "Уведомить вÑех в данном чате", + "Old_and_new_password_required" : "Ð’Ñ‹ должны предоÑтавить как Ñтарый, так и новый пароль Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ.", + "Old_Password" : "Старый пароль", "Online" : "Ð’ Ñети", + "Only_you_can_see_this_message" : "Только вы можете видеть Ñто Ñообщение", "Oops!" : "Ой", "Opt_out_statistics" : "Ðе отправлÑÑ‚ÑŒ мою ÑтатиÑтику в Rocket.Chat", + "Opt_out_statistics_warning" : "ОтправлÑÑ Ð²Ð°ÑˆÑƒ ÑтатиÑтику, вы помогаете нам идентифицировать количеÑтво уÑтановок Rocket.Chat, а также узнать наÑколько ÑиÑтема хорошо работает Ð´Ð»Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ¹ÑˆÐµÐ¹ ее модернизации и улучшениÑ. Ðе беÑпокойтеÑÑŒ, Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ вашем чате конфиденциальна и Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ пользователÑÑ… не отправлÑетÑÑ Ð½Ð°Ð¼. ЕÑли вы хотите отправлÑÑ‚ÑŒ нам Ñвою ÑтатиÑтику, уберите галочку выше. СпаÑибо.", "others" : "другие", "Password" : "Пароль", + "Password_Change_Disabled" : "ÐдминиÑтратор отключил возможноÑÑ‚ÑŒ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»ÐµÐ¹", "Password_changed_successfully" : "Пароль уÑпешно изменен", + "People" : "Люди", "Please_wait" : "Минуточку", "Please_wait_activation" : "ПожалуйÑта, подождите, Ñто может занÑÑ‚ÑŒ некоторое времÑ.", "Please_wait_statistics" : "ПожалуйÑта, подождите, ÑтатиÑтика генерируютÑÑ.", @@ -160,6 +235,7 @@ "Preferences_saved" : "ÐаÑтройки Ñохранены", "Privacy" : "ПриватноÑÑ‚ÑŒ", "Private_Groups" : "Приватные чаты", + "Private_Groups_list" : "СпиÑок приватных чатов", "Profile" : "Профиль", "Profile_saved_successfully" : "Профиль уÑпешно Ñохранен", "Proudly_developed" : "Разработано Ñ Meteor", @@ -168,16 +244,24 @@ "Quick_Search" : "БыÑтрый поиÑк", "quote" : "цитата", "Recents" : "Ðедавние", + "Record" : "ЗапиÑÑŒ", "Register" : "ЗарегиÑтрироватьÑÑ", "Registration_Succeeded" : "УÑÐ¿ÐµÑˆÐ½Ð°Ñ Ñ€ÐµÐ³Ð¸ÑтрациÑ", "Remember_me" : "Запомните менÑ", "Remove" : "Удалить", + "Remove_Admin" : "Разжаловать админиÑтратора", + "Remove_custom_oauth" : "Удалить пользовательÑкий OAuth", + "Remove_from_room" : "Удалить из чата", "Reset_password" : "СброÑить пароль", "Room" : "Чат", "Room_name_changed" : "Ðазвание чата изменено: <em>__room_name__</em> пользователем <em>__user_by__</em>", "Room_name_changed_successfully" : "Ðазвание чата уÑпешно изменено", "Room_not_found" : "Комната не найдена", + "Room_uploaded_file_list" : "СпиÑок файлов", + "Room_uploaded_file_list_empty" : "Ðет доÑтупных файлов", "room_user_count" : "%s пользователей", + "Rooms" : "Чаты", + "S_new_messages_since_s" : "%s новых Ñообщений Ñ %s", "Save_changes" : "Сохранить изменениÑ", "Search" : "ПоиÑк", "Search_Messages" : "ПоиÑк Ñообщений", @@ -188,9 +272,13 @@ "Select_an_avatar" : "Выбор автара", "Select_file" : "Выберите файл", "Selected_users" : "Выбранные учаÑтники", - "Send" : "ПоÑлать", + "Send" : "Отправить", "Send_confirmation_email" : "Отправить пиÑьмо Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸ÐµÐ¼", "Send_invitation_email" : "Отправить приглашение по Ñлектронной почте", + "Send_invitation_email_error" : "Ð’Ñ‹ не предоÑтавили корректный e-mail адреÑ.", + "Send_invitation_email_info" : "Ð’Ñ‹ можете отправить неÑколько e-mail приглашений за раз.", + "Send_invitation_email_success" : "Ð’Ñ‹ уÑпешно отправили Ð¿Ñ€Ð¸Ð³Ð»Ð°ÑˆÐµÐ½Ð¸Ñ Ð½Ð° Ñледующие адреÑа:", + "Send_invitation_email_warning" : "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы отправлÑÑ‚ÑŒ приглашение по Ñлектронной почте, вы должны Ñначала наÑтроить параметры SMTP.", "Send_Message" : "Отправить Ñообщение", "Settings" : "ÐаÑтройки", "Settings_updated" : "ÐаÑтройки обновлены", @@ -204,37 +292,52 @@ "SMTP_Username" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ SMTP-", "Sound" : "Звук", "Start_of_conversation" : "Ðачать диалог", + "Statistics" : "СтатиÑтика", "Stats_Active_Users" : "Ðктивные пользователи", + "Stats_Avg_Channel_Users" : "КоличеÑтво пользователей в публичных чатах", + "Stats_Avg_Private_Group_Users" : "КоличеÑтво пользователей в приватных чатах", + "Stats_Away_Users" : "Отошедших пользователей", + "Stats_Max_Room_Users" : "МакÑимальное количеÑтво пользователей в чате", "Stats_Non_Active_Users" : "Ðеактивные пользователи", "Stats_Offline_Users" : "Пользователи не в Ñети", "Stats_Online_Users" : "Пользователи в Ñети", "Stats_OS_Arch" : "Ðрхитектура ОС", "Stats_OS_Cpus" : "КоличеÑтво процеÑÑоров в ОС", "Stats_OS_Freemem" : "Свободное кол-во памÑти", + "Stats_OS_Loadavg" : "Загрузка ОС", "Stats_OS_Platform" : "Платформа ОС", "Stats_OS_Release" : "ВерÑÐ¸Ñ ÐžÐ¡", "Stats_OS_Totalmem" : "Общее кол-во памÑти в ОС", "Stats_OS_Type" : "Тип СиÑтемы", "Stats_OS_Uptime" : "Ðптайм ÑиÑтемы", - "Stats_Total_Channels" : "Общее кол-во каналов", + "Stats_Total_Channels" : "Ð’Ñего публичных чатов", + "Stats_Total_Direct_Messages" : "Общее количеÑтво Ñообщений в личных чатах", "Stats_Total_Messages" : "Ð’Ñего Ñообщений", + "Stats_Total_Private_Groups" : "Ð’Ñего приватных чатов", + "Stats_Total_Rooms" : "Ð’Ñего чатов", "Stats_Total_Users" : "Ð’Ñего пользователей", + "Stop_Recording" : "ОÑтановить запиÑÑŒ", + "strike" : "зачеркнутый", "Submit" : "Отправить", "The_field_is_required" : "Поле %s обÑзательно.", - "True" : "ИÑтина", + "True" : "Да", + "Type_your_new_password" : "Введите новый пароль", + "Unnamed" : "Без названиÑ", "Upload_file_question" : "Загрузить файл?", + "Use_Emojis" : "ИÑпользовать Emojis", "Use_initials_avatar" : "ИÑпользовать Ñтандартный аватар", "use_menu" : "ИÑпользуйте боковое меню Ð´Ð»Ñ Ð´Ð¾Ñтупа к вашим ÑообщениÑм и чатам", "Use_service_avatar" : "ИÑпользовать %s аватар", "Use_this_username" : "ИÑпользовать Ñто Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ", "Use_uploaded_avatar" : "ИÑпользовать загруженную аватарку", + "Use_url_for_avatar" : "ИÑпользовать аватар по URL", "User_added_by" : "Пользователь <em>__user_added__</em> добавлен <em>__user_by__</em>.", "User_Channels" : "Чаты пользователÑ", "User_has_been_activated" : "Пользователь активирован", "User_has_been_deactivated" : "Пользователь деактивирован", "User_has_been_deleted" : "Пользователь был удален", "User_Info" : "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ пользователе", - "User_is_no_longer_an_admin" : "Пользователь не больше не админиÑтратор", + "User_is_no_longer_an_admin" : "Пользователь больше не админиÑтратор", "User_is_not_activated" : "Пользователь не активирован", "User_is_now_an_admin" : "Пользователь теперь админиÑтратор", "User_joined_channel" : "ПриÑоединилÑÑ Ðº чату.", @@ -244,15 +347,23 @@ "User_left_female" : "Пользователь <em>__user_left__</em> покинула чат.", "User_left_male" : "Пользователь <em>__user_left__</em> покинул чат.", "User_logged_out" : "Пользователь не в Ñети", + "User_muted_by" : "Пользователь <em>__user_muted__</em> заблокирован пользователем <em>__user_by__</em>.", + "User_muted_in_room" : "Пользователь заблокирован в чате", + "User_not_found_or_incorrect_password" : "Пользователь не найден, или введен неправильный пароль ", "User_removed_by" : "Пользователь <em>__user_removed__</em> удален <em>__user_by__</em>.", "User_Settings" : "ПользовательÑкие наÑтройки", + "User_unmuted_by" : "Пользователь <em>__user_unmuted__</em> разблокирован пользователем <em>__user_by__</em>.", + "User_unmuted_in_room" : "Пользователь разблокирован в чате", "User_updated_successfully" : "Пользователь уÑпешно обновлен", "Username" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ", "Username_cant_be_empty" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ может быть пуÑтым", + "Username_Change_Disabled" : "ÐдминиÑтратор отключил возможноÑÑ‚ÑŒ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¸Ð¼ÐµÐ½ пользователей", "Username_description" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтников к вам.", "Username_invalid" : "<strong>%s</strong> неправильное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ, <br/> можно иÑпользовать только цифры, точки, Ð¿Ð¾Ð´Ñ‡ÐµÑ€ÐºÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¸ латинÑкие буквы", "Username_title" : "ЗарегиÑтрировать логин", "Username_unavaliable" : "<strong>%s</strong> уже иÑпользуетÑÑ :(", + "Users" : "Пользователи", + "UTF8_Names_Validation_Description" : "Специальные Ñимволы запрещены. Ð’Ñ‹ можете иÑпользовать - _ и . но только не в конце имени", "View_All" : "ПоÑмотреть вÑех", "Wait_activation_warning" : "Прежде чем вы Ñможете войти в ваш аккаунт, он должен быть активирован вручную админиÑтратором.", "We_have_sent_password_email" : "Ðа вашу почту было отправлено пиÑьмо Ñ Ð¸Ð½ÑтрукциÑми. ЕÑли по каким-то причинам пиÑьмо не пришло, попробуйте еще раз и/или напишите нам.", @@ -262,7 +373,9 @@ "With_whom" : "C кем", "Yes_delete_it" : "Да, удалить его!", "you_are_in_preview_mode_of" : "Ð’Ñ‹ находитеÑÑŒ в режиме предварительного проÑмотра канала # <strong>__room_name__</strong>", + "You_can_use_an_emoji_as_avatar" : "Ð’Ñ‹ также можете иÑпользовать emoji в качеÑтве аватара.", + "You_have_been_muted" : "Ð’Ñ‹ были заблокированы и не можете говорить в Ñтом чате", "You_need_confirm_email" : "Ðеобходимо подтвердить email Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°!", - "You_will_not_be_able_to_recover" : "Ð’Ñ‹ не Ñможете воÑÑтановить!", + "You_will_not_be_able_to_recover" : "Ð’Ñ‹ не Ñможете воÑÑтановить Ñто Ñообщение!", "Your_Open_Source_solution" : "Ваш ÑобÑтвенный чат на базе Open Source-технологий" } \ No newline at end of file diff --git a/i18n/sq.i18n.json b/i18n/sq.i18n.json index 364aaf1e358c618d91d582323503404ff128d156..a76109b0e15a3fc6c7563a423bbdcebecdfd6f2a 100644 --- a/i18n/sq.i18n.json +++ b/i18n/sq.i18n.json @@ -1,41 +1,111 @@ { + "Access_online_demo" : "Hyni demo internet", + "Access_Online_Demo" : "Qasja Online Demo", + "Accounts_EmailVerification" : "E-mail Verifikimi", + "Accounts_RegistrationRequired" : "Regjistrimi kërkuar", + "Add_Members" : "Shto Anëtarët", "Add_users" : "Shtoni përdoruesit", + "All_channels" : "Të gjitha kanalet", "and" : "dhe", + "API_Analytics" : "Analitikë", + "API_Embed" : "Mbjell", "are_also_typing" : "janë gjithashtu shtypja", "are_typing" : "janë shtypur", + "Are_you_sure" : "Jeni te sigurte qe?", + "Avatar_changed_successfully" : "Avatari i ndryshuar me sukses", + "away" : "larg", + "Away" : "Larg", + "away_female" : "larg", + "Away_female" : "Larg", + "away_male" : "larg", + "Away_male" : "Larg", + "Back_to_login" : "Kthehu tek login", + "bold" : "guximshme", + "busy" : "i zënë", + "Busy" : "I zënë", + "busy_female" : "i zënë", + "Busy_female" : "I zënë", + "busy_male" : "i zënë", + "Busy_male" : "I zënë", "Cancel" : "Anuloj", + "Change_avatar" : "Ndrysho avatarin", "Channels" : "Kanalet", "Channels_list" : "Lista e kanaleve publike", "Chat_Rooms" : "Chat dhoma", "close" : "Mbyll", + "coming_soon" : "se shpejti", "Confirm_password" : "Konfirmoni fjalëkalimin tuaj", "Contact" : "Kontakt", "Conversation" : "Bisedë", + "Create_new" : "Krijo  te ri", + "Create_new_direct_message_room" : "Krijo një dhomë të re mesazh të drejtpërdrejtë", + "Create_new_private_group" : "Krijo një grup të ri privat", "Create_new_public_channel" : "Krijo një kanal të ri publik", - "Direct_Messages" : "Mesazhe të drejtpërdrejta", + "Created_at" : "Krijuar në", + "Deleted" : "Fshihet!", + "Direct_Messages" : "Mesazhe Private", + "Drop_to_upload_file" : "Drop të ngarkoni fotografi", + "Duplicate_channel_name" : "Ekziston një Channel me emrin '% s'", + "Duplicate_private_group_name" : "Një grup privat me emrin ekziston '% s'", "edited" : "edited", + "Email_already_exists" : "Emaili ekziston", "Email_or_username" : "Email ose emrin e përdoruesit", "Email_verified" : "Email verifikuar", "Enter_info" : "Shkruani të dhënat tuaja", "Error_changing_password" : "Gabim ndryshuar fjalëkalimin", + "False" : "I rremë", "Favorites" : "Favoritet", "Follow_social_profiles" : "Ndiqni profilet tona sociale, na paguaj në Github dhe të ndajnë mendimet tuaja në lidhje me app rocket.chat në bord tonë Trello.", "Forgot_password" : "Keni harruar fjalëkalimin tuaj", "Fork_it_on_github" : "Paguaj atë në Github", + "github_no_public_email" : "Ju nuk keni ndonjë email si email publik në llogarinë tuaj GitHub", "Have_your_own_chat" : "Ketë web chat tuaj. Zhvilluar me Meteor.com, The Rocket.Chat është një zgjidhje e madhe për zhvilluesit në kërkim përpara për të ndërtuar dhe të zhvillohet vetë platformën e tyre chat.", "Hide_room" : "Dhomë Fshih", "History" : "Historiku", + "inline_code" : "inline_code", + "Invalid_confirm_pass" : "Konfirmimi Fjalëkalimi nuk përputhet me fjalëkalimin", + "Invalid_email" : "E-mail dhënë është i pavlefshëm", + "Invalid_name" : "Emri nuk duhet të jetë bosh", + "Invalid_pass" : "Fjalëkalimi nuk duhet të jetë bosh", + "invisible" : "i padukshëm", + "Invisible" : "I padukshëm", "is_also_typing" : "janë gjithashtu shtypja", + "is_also_typing_female" : "është shtypja", + "is_also_typing_male" : "është edhe shtypja", "is_typing" : "është shtypja", + "is_typing_female" : "është shtypja", + "is_typing_male" : "është shtypja", + "italics" : "italics", + "join" : "Bashkohuni", "Join_the_Community" : "Join Komuniteti", + "Language" : "Gjuhë", "Language_Version" : "Versioni anglisht", + "Last_message" : "Mesazhi i fundit", + "LDAP_DN" : "Të nderuar Emri (DN)", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Dhomë Leave", + "line" : "linjë", "Load_more" : "Lexo më shumë", + "Loading_suggestion" : "Sugjerimet Duke u ngarkuar ...", "Login" : "Hyrje", + "Login_with" : "Identifikohuni me% s", + "login_with" : "Ose login direkt me", + "Logout" : "Largohu", "Members" : "Anëtarët", "Members_List" : "Lista e Anëtarëve", "Members_placeholder" : "Anëtarët", + "Message" : "Mesazh", + "Message_AllowDeleting" : "Lejo Mesazh Fshirja", + "Message_AllowEditing" : "Lejo Mesazh Editing", + "Message_ShowDeletedStatus" : "Trego Statusi Deleted", + "Message_ShowEditedStatus" : "Trego Statusi Edited", + "Meta_language" : "Gjuhë", + "Meta_robots" : "Robots", "More_channels" : "Më shumë kanale", + "multi" : "multi", + "My_Account" : "Llogaria ime", + "n_messages" : "% s Mesazhet", "Name" : "Emër", "New_messages" : "Mesazhe të reja", "New_password" : "Fjalëkalimi i ri", @@ -43,35 +113,80 @@ "No_direct_messages_yet" : "Ju nuk kanë filluar asnjë biseda ende.", "No_favorites_yet" : "Ju nuk keni shtuar asnjë preferuarat ende.", "No_groups_yet" : "Nuk keni asnjë faqe grupe private ende.", + "No_permission_to_view_room" : "Ju nuk keni leje për të parë këtë dhomë", + "Not_allowed" : "Nuk lejohet", + "Not_found_or_not_allowed" : "Not Found ose jo Lejohet", + "Nothing_found" : "Asgjë për të gjetur", + "Notify_all_in_this_room" : "Të njoftojë të gjithë në këtë dhomë", + "Online" : "Online", + "Oops!" : "Oops", + "others" : "të tjerët", "Password" : "Fjalëkalim", - "Please_wait" : "Te lutem prit", + "Password_changed_successfully" : "Fjalëkalimi ndryshuar me sukses", + "Please_wait" : "Te lutem prisni", "Powered_by" : "Mundësuar nga", + "Privacy" : "Privacy", "Private_Groups" : "Grupet Private", + "Profile" : "Profil", + "Profile_saved_successfully" : "Profili ruajtur me sukses", "Proudly_developed" : "Zhvilluar me krenari me Meteor", "Quick_Search" : "Kërko Shpejt", + "quote" : "citoj", "Recents" : "Recents", "Register" : "Regjistrohu një llogari të re", - "Remember_me" : "Mua më kujtoni", + "Remember_me" : "Më kujton mua", "Remove" : "Hiq", "Reset_password" : "Fjalëkalimi i ri", + "Room" : "Dhomë", "Room_name_changed" : "Emri dhomë ndryshuar për:", - "Room_name_changed_successfully" : "Emri dhomë ndryshuar me sukses", + "Room_name_changed_successfully" : "Emri dhomës  është ndryshuar me sukses", + "Save_changes" : "Ruaj ndryshimet", "Search" : "Kërko", + "Search_settings" : "Cilësimet", "See_all" : "Shih të gjithë", "See_only_online" : "Vetëm online", + "Select_an_avatar" : "Zgjidh një avatar", + "Select_file" : "Zgjidh skedar", + "Select_service_to_login" : "Zgjidh një shërbim të identifikoheni për të ngarkuar foton tuaj ose ngarkoni një direkt nga kompjuteri juaj", "Selected_users" : "Anëtarë të zgjedhur", "Send_confirmation_email" : "Dërgo email konfirmimi", "Send_Message" : "Dërgoni mesazh", + "Settings" : "Cilësimet", "Showing_online_users" : "Duke treguar", + "Silence" : "Heshtje", + "since_creation" : "që nga% s", "Start_of_conversation" : "Fillimi i bisedës", + "strike" : "grevë", "Submit" : "Paraqes", + "The_field_is_required" : "Fusha% s është e nevojshme.", + "Use_initials_avatar" : "Përdorni inicialet tënd Emri i përdoruesit", "use_menu" : "Përdorni menynë anësore për të hyrë në dhomat tuaja dhe biseda", + "Use_service_avatar" : "Përdorni% s avatar", + "Use_this_username" : "Përdoreni këtë emrin e përdoruesit", + "Use_uploaded_avatar" : "Përdorni avatar ngarkuar", "User_added_by" : "Përdorues", - "User_left" : "Ka lënë kanal.", + "User_joined_channel" : "Është bashkuar kanalit.", + "User_joined_channel_female" : "Është bashkuar kanalit.", + "User_joined_channel_male" : "Është bashkuar kanalit.", + "User_left" : "Ka lënë kanalin.", + "User_left_female" : "Ka lënë kanalin.", + "User_left_male" : "Ka lënë kanalin.", "User_logged_out" : "Përdoruesi është regjistruar jashtë", "User_removed_by" : "Përdorues", + "User_Settings" : "Përdoruesi Cilësimet", + "Username" : "Emri i përdoruesit", + "Username_cant_be_empty" : "Emri i përdoruesit nuk mund të jetë bosh", + "Username_description" : "Emri i përdoruesit është përdorur për të lejuar të tjerët për të përmendur ju në mesazhe.", "View_All" : "Shiko të gjitha", + "We_have_sent_password_email" : "Ne të dërguam ty një e-mail me udhëzime të rivendosur fjalëkalimin. Nëse ju nuk merrni një e-mail shpejti, ju lutem të ktheheni dhe provoni përsëri.", + "We_have_sent_registration_email" : "Ne të dërguam ty një e-mail për të konfirmuar regjistrimin tuaj. Nëse ju nuk merrni një e-mail shpejti, ju lutem të ktheheni dhe provoni përsëri.", "Welcome" : "I mirëpritur", "Welcome_to_the" : "Mirë se vini në", - "You_need_confirm_email" : "Ju duhet për të konfirmuar email-it tuaj të identifikoheni!" + "With_whom" : "Me kë", + "Yes_delete_it" : "Po, fshini atë!", + "you_are_in_preview_mode_of" : "Ju jeni në mënyrë preview e kanalit #", + "You_need_confirm_email" : "Ju duhet për të konfirmuar email-it tuaj të identifikoheni!", + "You_will_not_be_able_to_recover" : "Ju nuk do të jetë në gjendje të mbulojë këtë mesazh!", + "Your_entry_has_been_deleted" : "Hyrja juaj është fshirë.", + "Your_Open_Source_solution" : "Vet Open Source chat zgjidhja juaj" } \ No newline at end of file diff --git a/i18n/sr.i18n.json b/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..39a02b9d8b427422a1302ff20784339e21178347 --- /dev/null +++ b/i18n/sr.i18n.json @@ -0,0 +1,67 @@ +{ + "Add_users" : "Додај кориÑнике", + "and" : "и", + "are_also_typing" : "такође куцају", + "are_typing" : "куцају", + "Cancel" : "Откажи", + "Channels" : "Канали", + "Channels_list" : "СпиÑак јавних канала", + "Chat_Rooms" : "Собе за ћаÑкање", + "close" : "затвори", + "Contact" : "Контакт", + "Conversation" : "Разговор", + "Create_new_public_channel" : "Ðаправи нови јавни канал", + "Direct_Messages" : "Директне поруке", + "edited" : "измењено", + "Email_verified" : "Е-адреÑа потврђена", + "Error_changing_password" : "Грешка приликом промене лозинке", + "Favorites" : "Омиљено", + "Follow_social_profiles" : "Пратите наше друштвене профиле, форкујте Ð½Ð°Ñ Ð½Ð° Гитхабу и поделите ваша мишљења о нашој rocket.chat апликацији на нашој Трело табли.", + "Fork_it_on_github" : "Форкуј на Гитхабу", + "Hide_room" : "Сакриј Ñобу", + "History" : "ИÑторијат", + "Invalid_room_name" : "<strong>%s</strong> није иÑправно име канала,<br/> кориÑтите Ñамо Ñлова, бројеве и цртице", + "is_also_typing" : "такође куца", + "is_typing" : "куца", + "Join_the_Community" : "Придружи Ñе заједници", + "Language_Version" : "ЕнглеÑка верзија", + "Leave_room" : "ÐапуÑти Ñобу", + "Load_more" : "Учитај још", + "Login" : "Пријава", + "Members" : "Чланови", + "Members_List" : "СпиÑак чланова", + "Members_placeholder" : "Чланови", + "More_channels" : "Више канала", + "Name" : "Име", + "New_messages" : "Ðове поруке", + "New_password" : "Ðова лозинка", + "No_channels_yet" : "ÐиÑте члан било ког канала још.", + "No_direct_messages_yet" : "ÐиÑте започели ниједан разговор још.", + "No_favorites_yet" : "ÐиÑте означили ништа омиљеним још.", + "No_groups_yet" : "Ðемате ниједну приватну групу за Ñада.", + "Please_wait" : "Сачекајте", + "Powered_by" : "Покреће", + "Private_Groups" : "Приватне групе", + "Proudly_developed" : "ПоноÑно развијено кориÑтећи Метеор", + "Quick_Search" : "Брза претрага", + "Recents" : "Скорашње", + "Remove" : "Уклони", + "Reset_password" : "Поново поÑтави лозинку", + "Room_name_changed" : "Ðазив Ñобе промењен у: <em>__room_name__</em> променио/ла <em>__user_by__</em>", + "Room_name_changed_successfully" : "Име Ñобе уÑпешно промењено", + "Search" : "Претрага", + "See_all" : "Погледај Ñве", + "See_only_online" : "Само на мрежи", + "Selected_users" : "Изабрани чланови", + "Send_confirmation_email" : "Пошаљи потврдну поруку", + "Send_Message" : "Пошаљи поруку", + "Showing_online_users" : "Приказујем <b>__total_online__</b> од __total__ кориÑника", + "Start_of_conversation" : "Почетак разговора", + "Submit" : "Пошаљи", + "User_added_by" : "КориÑник/ца <em>__user_added__</em> је додат(а) од Ñтране <em>__user_by__</em>.", + "User_left" : "је напуÑтио/ла канал.", + "User_logged_out" : "КориÑник је одјављен", + "User_removed_by" : "КориÑник/ца <em>__user_removed__</em> је уклоњен од Ñтране <em>__user_by__</em>.", + "View_All" : "Погледај Ñве", + "Welcome" : "Добродошли <em>%s</em>." +} \ No newline at end of file diff --git a/install.sh b/install.sh index 9980acc5751ca4d6154280c3c165963a9af4a3fc..361dbcb90f63eb0baf48ad1ae7868b08c33b6e66 100755 --- a/install.sh +++ b/install.sh @@ -8,7 +8,7 @@ if [ "$1" == "development" ]; then fi cd $ROOTPATH -curl -fSL "https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz +curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-develop.tgz" -o rocket.chat.tgz tar zxf rocket.chat.tgz && rm rocket.chat.tgz cd $ROOTPATH/bundle/programs/server npm install diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 62cf49677a5425a02a3c70a4031a3d7c9b107c27..3ee0e68c276d1b55afb19829e8d4644caeadff88 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -31,6 +31,12 @@ if UploadFS? return false; initFileStore = -> + cookie = new Cookies() + if Meteor.isClient + cookie.set 'rc_uid', Meteor.userId(); + cookie.set 'rc_token', Meteor._localStorage.getItem('Meteor.loginToken') + cookie.send() + Meteor.fileStore = new UploadFS.store.GridFS collection: fileCollection name: 'rocketchat_uploads' @@ -40,13 +46,49 @@ if UploadFS? contentTypes: fileUploadMediaWhiteList() onFinishUpload: -> console.log arguments + transformWrite: (readStream, writeStream, fileId, file) -> + if RocketChatFile.enabled is false or not /^image\/.+/.test(file.type) + return readStream.pipe writeStream + + stream = undefined + + identify = (err, data) -> + if err? + return stream.pipe writeStream + + file.identify = + format: data.format + size: data.size + + if data.Orientation? and data.Orientation not in ['', 'Unknown', 'Undefined'] + RocketChatFile.gm(stream).autoOrient().stream().pipe(writeStream) + else + stream.pipe writeStream + + stream = RocketChatFile.gm(readStream).identify(identify).stream() + onRead: (fileId, file, req, res) -> + if RocketChat.settings.get 'FileUpload_ProtectFiles' + rawCookies = req.headers.cookie if req?.headers?.cookie? + uid = cookie.get('rc_uid', rawCookies) if rawCookies? + token = cookie.get('rc_token', rawCookies) if rawCookies? + + if not uid? + uid = req.query.rc_uid + token = req.query.rc_token + + unless uid and token and RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) + res.writeHead 403 + return false + res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" + return true +Meteor.startup -> if Meteor.isServer initFileStore() else Tracker.autorun (c) -> - if RocketChat.settings.subscription.ready() + if Meteor.userId() and RocketChat.settings.subscription.ready() initFileStore() c.stop() diff --git a/packages/meteor-accounts-saml/saml_server.js b/packages/meteor-accounts-saml/saml_server.js index 030922b82b941a2289e6ed0ba42bc467bec52a96..1dd3f227201cd0151e9023022742ae6333f42b44 100644 --- a/packages/meteor-accounts-saml/saml_server.js +++ b/packages/meteor-accounts-saml/saml_server.js @@ -78,6 +78,13 @@ Accounts.registerLoginHandler(function (loginRequest) { console.log("RESULT :" + JSON.stringify(loginResult)); } + if (loginResult == undefined) { + return { + type: "saml", + error: new Meteor.Error(Accounts.LoginCancelledError.numericError, "No matching login attempt found") + } + } + if (loginResult && loginResult.profile && loginResult.profile.email) { var user = Meteor.users.findOne({ 'emails.address': loginResult.profile.email @@ -87,8 +94,10 @@ Accounts.registerLoginHandler(function (loginRequest) { var newUser = { name: loginResult.profile.cn || loginResult.profile.username, active: true, + globalRoles: ['user'], emails: [{ - address: loginResult.profile.email + address: loginResult.profile.email, + verified: true }] }; @@ -99,10 +108,8 @@ Accounts.registerLoginHandler(function (loginRequest) { } } - Meteor.users.insert(newUser); - user = Meteor.users.findOne({ - 'emails.address': loginResult.profile.email - }); + var userId = Accounts.insertUserDoc({}, newUser); + user = Meteor.users.findOne(userId); } //creating the token and adding to the user diff --git a/packages/rocketchat-api/package.js b/packages/rocketchat-api/package.js new file mode 100644 index 0000000000000000000000000000000000000000..bc639498450e578b149a13e7d2d62ac7f43105a3 --- /dev/null +++ b/packages/rocketchat-api/package.js @@ -0,0 +1,24 @@ +Package.describe({ + name: 'rocketchat:api', + version: '0.0.1', + summary: 'Rest API', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'underscore', + 'rocketchat:lib', + 'nimble:restivus' + ]); + + api.addFiles('server/api.coffee', 'server'); + api.addFiles('server/routes.coffee', 'server'); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-api/server/api.coffee b/packages/rocketchat-api/server/api.coffee new file mode 100644 index 0000000000000000000000000000000000000000..e15db14f1fa9741eafa6c13a2b71a58799f39a51 --- /dev/null +++ b/packages/rocketchat-api/server/api.coffee @@ -0,0 +1,61 @@ +class API extends Restivus + constructor: -> + @authMethods = [] + super + + addAuthMethod: (method) -> + @authMethods.push method + + success: (result={}) -> + if _.isObject(result) + result.success = true + + return {} = + statusCode: 200 + body: result + + failure: (result) -> + if _.isObject(result) + result.success = false + else + result = + success: false + error: result + + return {} = + statusCode: 400 + body: result + + unauthorized: (msg) -> + return {} = + statusCode: 401 + body: + success: false + error: msg or 'unauthorized' + + +RocketChat.API = {} + + +RocketChat.API.v1 = new API + version: 'v1' + useDefaultAuth: true + prettyJson: false + enableCors: false + auth: + token: 'services.resume.loginTokens.hashedToken' + user: -> + if @bodyParams?.payload? + @bodyParams = JSON.parse @bodyParams.payload + + for method in RocketChat.API.v1.authMethods + result = method.apply @, arguments + if result not in [undefined, null, false] + return result + + if @request.headers['x-auth-token'] + token = Accounts._hashLoginToken @request.headers['x-auth-token'] + + return {} = + userId: @request.headers['x-user-id'] + token: token diff --git a/packages/rocketchat-api/server/routes.coffee b/packages/rocketchat-api/server/routes.coffee new file mode 100644 index 0000000000000000000000000000000000000000..16a3efc14ae58bfbc82d7cd06382e9cc6567d5b8 --- /dev/null +++ b/packages/rocketchat-api/server/routes.coffee @@ -0,0 +1,109 @@ +RocketChat.API.v1.addRoute 'info', authRequired: false, + get: -> RocketChat.Info + + +RocketChat.API.v1.addRoute 'me', authRequired: true, + get: -> + return _.pick @user, [ + '_id' + 'name' + 'emails' + 'status' + 'statusConnection' + 'username' + 'utcOffset' + 'active' + 'language' + ] + + +# Send Channel Message +RocketChat.API.v1.addRoute 'chat.messageExamples', authRequired: true, + get: -> + return RocketChat.API.v1.success + body: [ + token: Random.id(24) + channel_id: Random.id() + channel_name: 'general' + timestamp: new Date + user_id: Random.id() + user_name: 'rocket.cat' + text: 'Sample text 1' + trigger_word: 'Sample' + , + token: Random.id(24) + channel_id: Random.id() + channel_name: 'general' + timestamp: new Date + user_id: Random.id() + user_name: 'rocket.cat' + text: 'Sample text 2' + trigger_word: 'Sample' + , + token: Random.id(24) + channel_id: Random.id() + channel_name: 'general' + timestamp: new Date + user_id: Random.id() + user_name: 'rocket.cat' + text: 'Sample text 3' + trigger_word: 'Sample' + ] + + +# Send Channel Message +RocketChat.API.v1.addRoute 'chat.postMessage', authRequired: true, + post: -> + try + @bodyParams.bot = + u: @userId + + messageReturn = processWebhookMessage @bodyParams, @user + + if not messageReturn? + return RocketChat.API.v1.failure 'unknown-error' + + return RocketChat.API.v1.success + ts: Date.now() + channel: messageReturn.channel + message: messageReturn.message + catch e + return RocketChat.API.v1.failure e.error + +# Set Channel Topic +RocketChat.API.v1.addRoute 'channels.setTopic', authRequired: true, + post: -> + if not @bodyParams.channel? + return RocketChat.API.v1.failure 'Body param "channel" is required' + + if not @bodyParams.topic? + return RocketChat.API.v1.failure 'Body param "topic" is required' + + unless RocketChat.authz.hasPermission(@userId, 'edit-room', @bodyParams.channel) + return RocketChat.API.v1.unauthorized() + + if not RocketChat.saveRoomTopic(@bodyParams.channel, @bodyParams.topic) + return RocketChat.API.v1.failure 'invalid_channel' + + return RocketChat.API.v1.success + topic: @bodyParams.topic + + +# Create Channel +RocketChat.API.v1.addRoute 'channels.create', authRequired: true, + post: -> + if not @bodyParams.name? + return RocketChat.API.v1.failure 'Body param "name" is required' + + if not RocketChat.authz.hasPermission(@userId, 'create-c') + return RocketChat.API.v1.unauthorized() + + id = undefined + try + Meteor.runAsUser this.userId, => + id = Meteor.call 'createChannel', @bodyParams.name, [] + catch e + return RocketChat.API.v1.failure e.name + ': ' + e.message + + return RocketChat.API.v1.success + channel: RocketChat.models.Rooms.findOne({_id: id.rid}) diff --git a/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json index f69e18d8fe1f4e8ece18f785cccb6f4acf9e5566..78afe4f3ae8144939a273a33a428d50ebe6beadc 100644 --- a/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json @@ -2,6 +2,14 @@ "dependencies": { "image-size": { "version": "0.4.0" + }, + "mime-types": { + "version": "2.1.9", + "dependencies": { + "mime-db": { + "version": "1.21.0" + } + } } } } diff --git a/packages/rocketchat-assets/package.js b/packages/rocketchat-assets/package.js index e5f75eaf3d27f5f47f50790894c19bdc0b1b7bc3..7f299bb33aa5121657480bf3091da94519857e72 100644 --- a/packages/rocketchat-assets/package.js +++ b/packages/rocketchat-assets/package.js @@ -13,14 +13,15 @@ Package.onUse(function(api) { 'underscore', 'webapp', 'rocketchat:file', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('server/assets.coffee', 'server'); }); Npm.depends({ - "image-size": "0.4.0" + "image-size": "0.4.0", + "mime-types": "2.1.9" }); Package.onTest(function(api) { diff --git a/packages/rocketchat-assets/server/assets.coffee b/packages/rocketchat-assets/server/assets.coffee index acf9d258456c1a69c3082201375ecacfcdf74e38..4c99b703d1d0cec937f52f0e46bf8818ab2b9e0b 100644 --- a/packages/rocketchat-assets/server/assets.coffee +++ b/packages/rocketchat-assets/server/assets.coffee @@ -1,5 +1,5 @@ sizeOf = Npm.require 'image-size' - +mime = Npm.require 'mime-types' @RocketChatAssetsInstance = new RocketChatFile.GridFS name: 'assets' @@ -11,8 +11,7 @@ assets = defaultUrl: 'favicon.ico?v=3' constraints: type: 'image' - contentType: 'image/vnd.microsoft.icon' - extention: 'ico' + extension: 'ico' width: undefined height: undefined 'favicon.svg': @@ -20,8 +19,7 @@ assets = defaultUrl: '/images/logo/icon.svg?v=3' constraints: type: 'image' - contentType: 'image/svg+xml' - extention: 'svg' + extension: 'svg' width: undefined height: undefined 'favicon_64.png': @@ -29,8 +27,7 @@ assets = defaultUrl: 'images/logo/favicon-64x64.png?v=3' constraints: type: 'image' - contentType: 'image/png' - extention: 'png' + extension: 'png' width: 64 height: 64 'favicon_96.png': @@ -38,8 +35,7 @@ assets = defaultUrl: 'images/logo/favicon-96x96.png?v=3' constraints: type: 'image' - contentType: 'image/png' - extention: 'png' + extension: 'png' width: 96 height: 96 'favicon_128.png': @@ -47,8 +43,7 @@ assets = defaultUrl: 'images/logo/favicon-128x128.png?v=3' constraints: type: 'image' - contentType: 'image/png' - extention: 'png' + extension: 'png' width: 128 height: 128 'favicon_192.png': @@ -56,8 +51,7 @@ assets = defaultUrl: 'images/logo/android-chrome-192x192.png?v=3' constraints: type: 'image' - contentType: 'image/png' - extention: 'png' + extension: 'png' width: 192 height: 192 'favicon_256.png': @@ -65,8 +59,7 @@ assets = defaultUrl: 'images/logo/favicon-256x256.png?v=3' constraints: type: 'image' - contentType: 'image/png' - extention: 'png' + extension: 'png' width: 256 height: 256 @@ -104,8 +97,8 @@ Meteor.methods if not assets[asset]? throw new Meteor.Error "Invalid_asset" - if contentType isnt assets[asset].constraints.contentType - throw new Meteor.Error "Invalid_file_type" + if mime.extension(contentType) isnt assets[asset].constraints.extension + throw new Meteor.Error "Invalid_file_type", contentType file = new Buffer(binaryContent, 'binary') diff --git a/packages/rocketchat-authorization/README.md b/packages/rocketchat-authorization/README.md index 239b085c856dc0d1280af7d604b5f5a40c2d2eb7..c2365d83f6986f4c0c0b0889aa1f4c9b147942c3 100644 --- a/packages/rocketchat-authorization/README.md +++ b/packages/rocketchat-authorization/README.md @@ -1,6 +1,6 @@ -Supports role or permission based authorization, and defines the association between them. +Supports role or permission based authorization, and defines the association between them. -A user is associated with role(s), and a role is associated with permission(s). This package depends on alanning:roles for the role/user association, while the role/permission association is handled internally. Thus, the underlying alanning:roles has no concept of a permission or the association between a role and permission. +A user is associated with role(s), and a role is associated with permission(s). This package depends on alanning:roles for the role/user association, while the role/permission association is handled internally. Thus, the underlying alanning:roles has no concept of a permission or the association between a role and permission. Authorization checks can be done based on a role or permission. However, permission based checks are preferred because they loosely associate an action with a role. For example: @@ -19,13 +19,12 @@ if hasRole(userId, ['admin','site-moderator','moderator']) Usage: ``` -# assign user to moderator role. Permissions scoped globally -# user can moderate (e.g. edit channel name, delete private group message) for all rooms -RocketChat.authz.addUsersToRoles(userId, 'moderator') +# assign user to admin role. Permissions scoped globally +RocketChat.authz.addUserRoles(userId, 'admin') # assign user to moderator role. Permissions scoped to the specified room # user can moderate (e.g. edit channel name, delete private group message) for only one room specified by the roomId -RocketChat.authz.addUsersToRoles(userId, 'moderator', roomId ) +RocketChat.authz.addUserRoles(userId, 'moderator', roomId ) # check if user can modify message for any room RocketChat.authz.hasPermission(userId, 'edit-message') @@ -37,5 +36,5 @@ RocketChat.authz.hasPermission(userId, 'edit-message', roomId) Notes: 1. Roles are statically defined. UI needs to be implemented to dynamically assign permission(s) to a Role -2. 'admin', 'moderator', 'user' role identifiers should NOT be changed (unless you update the associated code) because they are referenced when creating users and creating rooms. -3. edit, delete message permissions are at either the global or room scope. i.e. role with edit-message with GLOBAL scope can edit ANY message regardless of the room type. However, role with edit-message with room scope can only edit messages for the room. The global scope is associated with the admin role while the "room-scoped" permission is assigned to the room "moderator" (room creator). If we want a middle ground that allows for edit-message for only channel/group/direct, then we need to create individual edit-c-message, edit-p-message, edit-d-message permissions. +2. 'admin', 'moderator', 'user' role identifiers should NOT be changed (unless you update the associated code) because they are referenced when creating users and creating rooms. +3. edit, delete message permissions are at either the global or room scope. i.e. role with edit-message with GLOBAL scope can edit ANY message regardless of the room type. However, role with edit-message with room scope can only edit messages for the room. The global scope is associated with the admin role while the "room-scoped" permission is assigned to the room "moderator" (room creator). If we want a middle ground that allows for edit-message for only channel/group/direct, then we need to create individual edit-c-message, edit-p-message, edit-d-message permissions. diff --git a/packages/rocketchat-authorization/client/hasPermission.coffee b/packages/rocketchat-authorization/client/hasPermission.coffee index 9d636b9552e7bc47ebb78e80fbb66b60af6a75c1..015ec854ee72935b6bc854010e417cc3f31b1973 100644 --- a/packages/rocketchat-authorization/client/hasPermission.coffee +++ b/packages/rocketchat-authorization/client/hasPermission.coffee @@ -1,25 +1,29 @@ -atLeastOne = (toFind, toSearch) -> - console.log 'toFind: ', toFind if window.rocketDebug - console.log 'toSearch: ', toSearch if window.rocketDebug - return not _.isEmpty(_.intersection(toFind, toSearch)) - -all = (toFind, toSearch) -> - toFind = _.uniq(toFind) - toSearch = _.uniq(toSearch) - return _.isEmpty( _.difference( toFind, toSearch)) +atLeastOne = (permissions, scope) -> + return _.some permissions, (permissionId) -> + permission = ChatPermissions.findOne permissionId + return _.some permission.roles, (roleName) -> + role = RocketChat.models.Roles.findOne roleName + roleScope = role?.scope + return RocketChat.models[roleScope]?.isUserInRole?(Meteor.userId(), roleName, scope) + +all = (permissions, scope) -> + return _.every permissions, (permissionId) -> + permission = ChatPermissions.findOne permissionId + return _.some permission.roles, (roleName) -> + role = RocketChat.models.Roles.findOne roleName + roleScope = role?.scope + return RocketChat.models[roleScope]?.isUserInRole?(Meteor.userId(), roleName, scope) Template.registerHelper 'hasPermission', (permission, scope) -> - unless _.isString( scope ) - scope = Roles.GLOBAL_GROUP - return hasPermission( permission, scope, atLeastOne) + return hasPermission(permission, scope, atLeastOne) -RocketChat.authz.hasAllPermission = (permissions, scope=Roles.GLOBAL_GROUP) -> - return hasPermission( permissions, scope, all ) +RocketChat.authz.hasAllPermission = (permissions, scope) -> + return hasPermission(permissions, scope, all) -RocketChat.authz.hasAtLeastOnePermission = (permissions, scope=Roles.GLOBAL_GROUP) -> +RocketChat.authz.hasAtLeastOnePermission = (permissions, scope) -> return hasPermission(permissions, scope, atLeastOne) -hasPermission = (permissions, scope=Roles.GLOBAL_GROUP, strategy) -> +hasPermission = (permissions, scope, strategy) -> userId = Meteor.userId() unless userId @@ -30,10 +34,4 @@ hasPermission = (permissions, scope=Roles.GLOBAL_GROUP, strategy) -> permissions = [].concat permissions - roleNames = Roles.getRolesForUser(userId, scope) - - userPermissions = [] - for roleName in roleNames - userPermissions = userPermissions.concat(_.pluck(ChatPermissions.find({roles : roleName }).fetch(), '_id')) - - return strategy( permissions, userPermissions) + return strategy(permissions, scope) diff --git a/packages/rocketchat-authorization/client/hasRole.coffee b/packages/rocketchat-authorization/client/hasRole.coffee index 3140a74bfe635cfc05d6ec20b8c59f4eb84f67bd..aff335e48b2fd0f7ae37fce3f2d00bb98796124c 100644 --- a/packages/rocketchat-authorization/client/hasRole.coffee +++ b/packages/rocketchat-authorization/client/hasRole.coffee @@ -1,8 +1,3 @@ -RocketChat.authz.hasRole = (userId, roleName, scope=Roles.GLOBAL_GROUP) -> - unless Meteor.userId() - return false - - roleName = [].concat roleName - - # per alanning:roles, returns true if user is in ANY roles - return Roles.userIsInRole(userId, roleName, scope) +RocketChat.authz.hasRole = (userId, roleNames, scope) -> + roleNames = [].concat roleNames + return RocketChat.models.Roles.isUserInRoles(userId, roleNames, scope) # true if user is in ANY role diff --git a/packages/rocketchat-authorization/client/collection.coffee b/packages/rocketchat-authorization/client/lib/ChatPermissions.coffee similarity index 96% rename from packages/rocketchat-authorization/client/collection.coffee rename to packages/rocketchat-authorization/client/lib/ChatPermissions.coffee index b719f7f9ed648c4d5df0d16de2fd541787017d97..e9adaae10f2f65de5c9d31f3283895af25ec4649 100644 --- a/packages/rocketchat-authorization/client/collection.coffee +++ b/packages/rocketchat-authorization/client/lib/ChatPermissions.coffee @@ -1 +1 @@ -@ChatPermissions = new Meteor.Collection 'rocketchat_permissions' \ No newline at end of file +@ChatPermissions = new Meteor.Collection 'rocketchat_permissions' diff --git a/packages/rocketchat-authorization/client/lib/models/Roles.coffee b/packages/rocketchat-authorization/client/lib/models/Roles.coffee new file mode 100644 index 0000000000000000000000000000000000000000..5d94d584c613bbc6d950efde4d3c28314197c5e9 --- /dev/null +++ b/packages/rocketchat-authorization/client/lib/models/Roles.coffee @@ -0,0 +1,14 @@ +RocketChat.models.Roles = new Meteor.Collection 'rocketchat_roles' + +RocketChat.models.Roles.findUsersInRole = (name, scope, options) -> + role = @findOne name + roleScope = role?.scope or 'Users' + RocketChat.models[roleScope]?.findUsersInRoles?(name, scope, options) + +RocketChat.models.Roles.isUserInRoles = (userId, roles, scope) -> + roles = [].concat roles + _.some roles, (roleName) => + role = @findOne roleName + roleScope = role?.scope or 'Users' + return RocketChat.models[roleScope]?.isUserInRole?(userId, roleName, scope) + diff --git a/packages/rocketchat-authorization/client/lib/models/Subscriptions.js b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js new file mode 100644 index 0000000000000000000000000000000000000000..7ff02a801037048cd704df777f0a559dce497751 --- /dev/null +++ b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js @@ -0,0 +1,35 @@ +Meteor.subscribe('scopedRoles', 'Subscriptions'); + +if (_.isUndefined(RocketChat.models.Subscriptions)) { + RocketChat.models.Subscriptions = {} +} + +RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId) { + query = { + rid: roomId, + roles: roleName + }; + + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models.Subscriptions.findUsersInRoles = function(roles, scope, options) { + roles = [].concat(roles); + + var query = { + roles: { $in: roles } + } + + if (scope) { + query.rid = scope; + } + + subscriptions = this.find(query).fetch(); + + users = _.compact(_.map(subscriptions, function(subscription) { + if ('undefined' !== typeof subscription.u && 'undefined' !== typeof subscription.u._id) + return subscription.u._id + })); + + return RocketChat.models.Users.find({ _id: { $in: users } }, options); +} diff --git a/packages/rocketchat-authorization/client/lib/models/Users.js b/packages/rocketchat-authorization/client/lib/models/Users.js new file mode 100644 index 0000000000000000000000000000000000000000..e7f61495105807867555a801164b9265caf04dcc --- /dev/null +++ b/packages/rocketchat-authorization/client/lib/models/Users.js @@ -0,0 +1,24 @@ +Meteor.subscribe('scopedRoles', 'Users'); + +if (_.isUndefined(RocketChat.models.Users)) { + RocketChat.models.Users = {} +} + +RocketChat.models.Users.isUserInRole = function(userId, roleName) { + query = { + _id: userId, + roles: roleName + }; + + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models.Users.findUsersInRoles = function(roles, scope, options) { + roles = [].concat(roles); + + var query = { + roles: { $in: roles } + } + + return this.find(query, options); +} diff --git a/packages/rocketchat-authorization/client/route.coffee b/packages/rocketchat-authorization/client/route.coffee index fe115fedcff8994742bb5ebcf9d73c7a88c44ae1..fce94d5ad7d8122e5eaab6275d8195f744308fd9 100644 --- a/packages/rocketchat-authorization/client/route.coffee +++ b/packages/rocketchat-authorization/client/route.coffee @@ -1,6 +1,7 @@ FlowRouter.route '/admin/permissions', name: 'admin-permissions' action: (params) -> + RocketChat.TabBar.showGroup 'admin-permissions' BlazeLayout.render 'main', center: 'pageContainer' pageTitle: t('Permissions') @@ -9,6 +10,7 @@ FlowRouter.route '/admin/permissions', FlowRouter.route '/admin/permissions/:name?/edit', name: 'admin-permissions-edit' action: (params) -> + RocketChat.TabBar.showGroup 'admin-permissions' BlazeLayout.render 'main', center: 'pageContainer' pageTitle: t('Role_Editing') @@ -17,6 +19,7 @@ FlowRouter.route '/admin/permissions/:name?/edit', FlowRouter.route '/admin/permissions/new', name: 'admin-permissions-new' action: (params) -> + RocketChat.TabBar.showGroup 'admin-permissions' BlazeLayout.render 'main', center: 'pageContainer' pageTitle: t('Role_Editing') diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 144f7ea88f9ae3f0735cec28551a19b7085bcc5e..61f0527598d0fe448a263d6f5c9d82ca8d390b88 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -1,3 +1,5 @@ +Meteor.subscribe 'roles' + RocketChat.authz.subscription = Meteor.subscribe 'permissions' RocketChat.AdminBox.addOption diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee index 0e134582401e8e84e1224610ec2572324770ec6c..af92f2c126605ba8bacee8042285ef1fd42c6d01 100644 --- a/packages/rocketchat-authorization/client/views/permissions.coffee +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -8,7 +8,7 @@ Template.permissions.helpers granted: (roles) -> if roles? - return 'checked' if roles.indexOf(@name) isnt -1 + return 'checked' if roles.indexOf(@_id) isnt -1 hasPermission: -> return RocketChat.authz.hasAllPermission 'access-permissions' @@ -31,18 +31,14 @@ Template.permissions.onCreated -> added: {} removed: {} - subs = @subscribe 'roles' - Tracker.autorun => - if subs.ready() - @roles.set Roles.getAllRoles().fetch() + @roles.set RocketChat.models.Roles.find().fetch() Tracker.autorun => - if subs.ready() - ChatPermissions.find().observeChanges - added: (id, fields) => - @permissionByRole[id] = fields.roles - changed: (id, fields) => - @permissionByRole[id] = fields.roles - removed: (id) => - delete @permissionByRole[id] + ChatPermissions.find().observeChanges + added: (id, fields) => + @permissionByRole[id] = fields.roles + changed: (id, fields) => + @permissionByRole[id] = fields.roles + removed: (id) => + delete @permissionByRole[id] diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index f95b309f24a35ed785388c21c8971469c6462fa3..c895fea4c2de67b038350d2e55c73b41b3e1c2b8 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -9,8 +9,8 @@ <td> </td> {{#each role}} <td title="{{description}}"> - <a href="{{pathFor "admin-permissions-edit" name=name}}"> - {{name}} + <a href="{{pathFor "admin-permissions-edit" name=_id}}"> + {{_id}} <i class="icon-edit"></i> </a> </td> @@ -23,7 +23,7 @@ <td>{{_id}}</td> {{#each role}} <td> - <input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles ../_id}}" data-role="{{name}}" data-permission="{{../_id}}"> + <input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles}}" data-role="{{_id}}" data-permission="{{../_id}}"> </td> {{/each}} </tr> diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index bb754ced89c9a40911c5882ca11318aa6b5dbda2..739fa26afada48c8d0a1c6b219db572a6e36e3ba 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -1,6 +1,6 @@ Template.permissionsRole.helpers role: -> - return Meteor.roles.findOne({ name: FlowRouter.getParam('name') }) or {} + return RocketChat.models.Roles.findOne({ _id: FlowRouter.getParam('name') }) or {} userInRole: -> return Template.instance().usersInRole @@ -108,4 +108,4 @@ Template.permissionsRole.onCreated -> @subscribe 'roles', FlowRouter.getParam('name') @subscribe 'usersInRole', FlowRouter.getParam('name') - @usersInRole = Roles.getUsersInRole(FlowRouter.getParam('name'), Roles.GLOBAL_GROUP, { sort: { username: 1 } }) + @usersInRole = RocketChat.models.Roles.findUsersInRole(FlowRouter.getParam('name'), null, { sort: { username: 1 } }) diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index a824390e886680a18e37f6fc3df8c3021b91c77f..18382fdb3c6a805a096fbfc4c7eec6e780c0b20c 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -7,7 +7,7 @@ <form id="form-role" class="inline form-role"> <label>{{_ "Role"}} :</label> {{#if editing}} - <span>{{name}}</span> + <span>{{_id}}</span> {{else}} <input type="text" name="name" value=""> {{/if}} diff --git a/packages/rocketchat-authorization/i18n/ar.i18n.json b/packages/rocketchat-authorization/i18n/ar.i18n.json index 6983bb7d0fe6b96f79c382ca414d36096ea9fa28..2c88e2e3004ffb2d106dce330f6ca296ec6c380e 100644 --- a/packages/rocketchat-authorization/i18n/ar.i18n.json +++ b/packages/rocketchat-authorization/i18n/ar.i18n.json @@ -1,6 +1,9 @@ { "Add_user" : "إضاÙØ© مستخدم", - "Save" : "ØÙظ", + "Back_to_permissions" : "العودة إلى التصريØات", + "Permissions" : "التصريØات", + "Saving" : "جاري الØÙظ", "User_added" : "وأضا٠العضو <em>__user_added__</em>.", - "User_removed" : "ازيل المستخدم" + "User_not_found" : "لم يتم العثور على المستخدم", + "User_removed" : "تم إزالة المستخدم" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/cs.i18n.json b/packages/rocketchat-authorization/i18n/cs.i18n.json index 84eb3ce32fd3bf86f83bacec57592ef2c02834a6..6f31cf5a2e622e523ae008338072897b8e56c993 100644 --- a/packages/rocketchat-authorization/i18n/cs.i18n.json +++ b/packages/rocketchat-authorization/i18n/cs.i18n.json @@ -1,3 +1 @@ -{ - "Save" : "Uložit" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/de.i18n.json b/packages/rocketchat-authorization/i18n/de.i18n.json index e13943efa3ec9db703c2ce789ae03adfde2ee8ee..18f0ee3d48151fad65d81b01595626e11459bd2e 100644 --- a/packages/rocketchat-authorization/i18n/de.i18n.json +++ b/packages/rocketchat-authorization/i18n/de.i18n.json @@ -1,4 +1,17 @@ { - "Save" : "Speichern", - "User_added" : "Benutzer <em>__user_added__</em> wurde hinzugefügt." + "Add_user" : "Benutzer hinzufügen", + "Back_to_permissions" : "Zurück zu den Berechtigungen", + "Cannot_delete_a_protected_role" : "Eine geschützte Rolle kann nicht gelöscht werden.", + "Cannot_delete_role_because_its_in_use" : "Die Rolle kann nicht gelöscht werden, da sie gerade verwendet wird.", + "New_role" : "Neue Rolle", + "Permissions" : "Berechtigungen", + "Role" : "Rolle", + "Role_Editing" : "Rolle bearbeiten", + "Role_removed" : "Die Rolle wurde entfernt.", + "Saving" : "Speichern", + "There_are_no_users_in_this_role" : "Es sind dieser Rolle keine Benutzer zugeordnet.", + "User_added" : "Der Benutzer <em>__user_added__</em> wurde hinzugefügt.", + "User_not_found" : "Der Benutzer konnte nicht gefunden werden.", + "User_removed" : "Der Benutzer wurde gelöscht.", + "Users_in_role" : "Zugeordnete Nutzer" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/el.i18n.json b/packages/rocketchat-authorization/i18n/el.i18n.json index c0b916f189e931069994ed8e3ff4a6b2747c1591..8743d1a9706733366823026e3578d4aa5f18ccbe 100644 --- a/packages/rocketchat-authorization/i18n/el.i18n.json +++ b/packages/rocketchat-authorization/i18n/el.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Αποθήκευση", "User_added" : "Ο χÏήστης <em>__user_added__</em> Ï€ÏστÎθηκε." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/en.i18n.json b/packages/rocketchat-authorization/i18n/en.i18n.json index 46367ea01760d684267a330592b5e7a5db6562be..1a2b7b7080a40e46b23aa9d96d3140d2253082bf 100644 --- a/packages/rocketchat-authorization/i18n/en.i18n.json +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -5,11 +5,9 @@ "Cannot_delete_role_because_its_in_use" : "Cannot delete role because it's in use", "New_role" : "New role", "Permissions" : "Permissions", - "Removed" : "Removed", "Role" : "Role", "Role_Editing" : "Role Editing", "Role_removed" : "Role removed", - "Save" : "Save", "Saving" : "Saving", "There_are_no_users_in_this_role" : "There are no users in this role.", "User_added" : "User added", diff --git a/packages/rocketchat-authorization/i18n/es.i18n.json b/packages/rocketchat-authorization/i18n/es.i18n.json index 9ace70c0a3c24d88767a4a4db23afc81d4456558..1c2eaf558856daec42aeeab8da7ed71cb31b1bd6 100644 --- a/packages/rocketchat-authorization/i18n/es.i18n.json +++ b/packages/rocketchat-authorization/i18n/es.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Guardar", "User_added" : "Usuario <em>__user_added__</em> añadido." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/fi.i18n.json b/packages/rocketchat-authorization/i18n/fi.i18n.json index 041ed788cf19116c74c25ac5ed863e2063c915be..989d23b26efa529528cade8803c79e5dd2ea6ff4 100644 --- a/packages/rocketchat-authorization/i18n/fi.i18n.json +++ b/packages/rocketchat-authorization/i18n/fi.i18n.json @@ -5,11 +5,9 @@ "Cannot_delete_role_because_its_in_use" : "Et voi poistaa roolia, koska se on käytössä", "New_role" : "Uusi rooli", "Permissions" : "Oikeudet", - "Removed" : "Poistettu", "Role" : "Rooli", "Role_Editing" : "Roolin muokkaaminen", "Role_removed" : "Rooli poistettu", - "Save" : "Tallenna", "Saving" : "Tallennetaan", "There_are_no_users_in_this_role" : "Roolissa ei ole käyttäjiä", "User_added" : "Käyttäjä <em>__user_added__</em> lisätty.", diff --git a/packages/rocketchat-authorization/i18n/fr.i18n.json b/packages/rocketchat-authorization/i18n/fr.i18n.json index ee7fabae8a33b2c7f4d2d4ce4f64acb0a99ae003..adcc0c34d11babd5196f78dcf70d8c8432d65792 100644 --- a/packages/rocketchat-authorization/i18n/fr.i18n.json +++ b/packages/rocketchat-authorization/i18n/fr.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Enregistrer", "User_added" : "L'utilisateur <em>__user_added__</em> a été ajouté." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/he.i18n.json b/packages/rocketchat-authorization/i18n/he.i18n.json index ed313b293643423fffd0a9707c0ea69f31b30c77..e8843caf9e5cedb512349c220bd3437c2a8fe8a5 100644 --- a/packages/rocketchat-authorization/i18n/he.i18n.json +++ b/packages/rocketchat-authorization/i18n/he.i18n.json @@ -1,4 +1,16 @@ { - "Save" : "שמור", - "User_added" : "המשתמש <em>__user_added__</em> × ×•×¡×£." + "Add_user" : "הוספת משתמש", + "Back_to_permissions" : "חזרה להרש×ות", + "Cannot_delete_a_protected_role" : "×œ× × ×™×ª×Ÿ למחוק תפקיד מוגן.", + "New_role" : "תפקיד חדש", + "Permissions" : "הרש×ות", + "Role" : "תפקיד", + "Role_Editing" : "עריכת תפקידי×", + "Role_removed" : "התפקיד הוסר", + "Saving" : "בשמירה", + "There_are_no_users_in_this_role" : "×ין ×ž×©×ª×ž×©×™× ×‘×ª×¤×§×™×“ ×–×”.", + "User_added" : "המשתמש × ×•×¡×£.", + "User_not_found" : "המשתמש ×œ× × ×ž×¦×", + "User_removed" : "המשתמש הוסר", + "Users_in_role" : "×ž×©×ª×ž×©×™× ×‘×ª×¤×§×™×“" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/hr.i18n.json b/packages/rocketchat-authorization/i18n/hr.i18n.json index 6b72824ca23dddd03050c4809b61a3e9f91ba347..4bf37f94d0c0c95b23a2bffc5d4cf9be52f329f4 100644 --- a/packages/rocketchat-authorization/i18n/hr.i18n.json +++ b/packages/rocketchat-authorization/i18n/hr.i18n.json @@ -1,4 +1,12 @@ { - "Save" : "SaÄuvaj", - "User_added" : "Korisnik <em>__user_added__</em> je dodan." + "Add_user" : "Dodaj korisnika", + "Back_to_permissions" : "Povratak na dozvole", + "Permissions" : "DopuÅ¡tenja", + "Role" : "Uloga", + "Saving" : "Spremanje", + "There_are_no_users_in_this_role" : "Nema korisnika u toj ulozi.", + "User_added" : "Korisnik <em>__user_added__</em> je dodan.", + "User_not_found" : "Korisnik nije pronaÄ‘en", + "User_removed" : "Korisnik je uklonjen", + "Users_in_role" : "Korisnici u ulozi" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/hu.i18n.json b/packages/rocketchat-authorization/i18n/hu.i18n.json index 9f88a36530aa4e058b431eae3d2f153539d5e016..cd097103a5a5d7ecbd442a46666a61c022d02752 100644 --- a/packages/rocketchat-authorization/i18n/hu.i18n.json +++ b/packages/rocketchat-authorization/i18n/hu.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Mentés", "User_added" : "<em>__user_added__</em> hozzáadva." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/it.i18n.json b/packages/rocketchat-authorization/i18n/it.i18n.json index 73b11372f508b416d763bb1d488d65eb0295e3f6..d95b3cf085c7e2dd2059a1240b7ffbd789ee2d1f 100644 --- a/packages/rocketchat-authorization/i18n/it.i18n.json +++ b/packages/rocketchat-authorization/i18n/it.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Salva", "User_added" : "Utente <em>__user_added__</em> aggiunto." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ja.i18n.json b/packages/rocketchat-authorization/i18n/ja.i18n.json index 846240cce4b7e32e8acb22f221141c4bd68fe83f..63994876ab03cf777c34854ae723c4bd1710302f 100644 --- a/packages/rocketchat-authorization/i18n/ja.i18n.json +++ b/packages/rocketchat-authorization/i18n/ja.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "ä¿å˜", "User_added" : "ユーザ <em>%s</em> è¿½åŠ ã—ã¾ã—ãŸã€‚" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/km.i18n.json b/packages/rocketchat-authorization/i18n/km.i18n.json index d3ce4c6f879897f08abb7b90eb81c4fdfb1bee4e..f252b47a08b7e90c65acbd805fa368227ca1d422 100644 --- a/packages/rocketchat-authorization/i18n/km.i18n.json +++ b/packages/rocketchat-authorization/i18n/km.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "រក្សាទុក", "User_added" : "អ្នក​ប្រើ <em>__user_added__</em> បាន​បន្ážáŸ‚ម" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ko.i18n.json b/packages/rocketchat-authorization/i18n/ko.i18n.json index a7ed67a8ddfe3ca48e3f757a65b0ea272c63845d..d55848ec9451d7fd6f8aa6ad566c78fa6ddde8c1 100644 --- a/packages/rocketchat-authorization/i18n/ko.i18n.json +++ b/packages/rocketchat-authorization/i18n/ko.i18n.json @@ -1,4 +1,9 @@ { - "Save" : "ì €ìž¥", - "User_added" : "ì‚¬ìš©ìž <em>__user_added__</em> 추가함." + "Add_user" : "ì‚¬ìš©ìž ì¶”ê°€", + "New_role" : "새로운 ì—í• ", + "Permissions" : "권한", + "Saving" : "ì €ìž¥ 중", + "User_added" : "ì‚¬ìš©ìž ì¶”ê°€í•¨.", + "User_not_found" : "사용ìžë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ", + "User_removed" : "ì‚¬ìš©ìž ì œê±°ë¨" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ku.i18n.json b/packages/rocketchat-authorization/i18n/ku.i18n.json index 1e7dd6a08761b8632da8fa06be4dceeeb7d76f97..1b1b8096a8ed607d0917f6bdbe2b5866802b9c8d 100644 --- a/packages/rocketchat-authorization/i18n/ku.i18n.json +++ b/packages/rocketchat-authorization/i18n/ku.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "پاشەکەوت", "User_added" : "بەکارهێنەر زیادکرا" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ms-MY.i18n.json b/packages/rocketchat-authorization/i18n/ms-MY.i18n.json index 07811f70be04c1889430ed918fe26cb187b5ecec..e34b443be0e01d2f39f5a0e8784204d572d458c9 100644 --- a/packages/rocketchat-authorization/i18n/ms-MY.i18n.json +++ b/packages/rocketchat-authorization/i18n/ms-MY.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Simpan", "User_added" : "Pengguna <em>__user_added__</em> ditambah." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/nl.i18n.json b/packages/rocketchat-authorization/i18n/nl.i18n.json index 039425c06c54f54afa4372f2df33ec3a7603a134..5b85b6b098437eef4f38719c42424a55ee658f13 100644 --- a/packages/rocketchat-authorization/i18n/nl.i18n.json +++ b/packages/rocketchat-authorization/i18n/nl.i18n.json @@ -1,4 +1,17 @@ { - "Save" : "Bewaren", - "User_added" : "Gebruiker toegevoegd" + "Add_user" : "Gebruikers toevoegen", + "Back_to_permissions" : "Terug naar machtigingen", + "Cannot_delete_a_protected_role" : "Kan een beschermde rol niet verwijderen", + "Cannot_delete_role_because_its_in_use" : "Kan rol niet verwijderen omdat het in gebruik is", + "New_role" : "Nieuwe rol", + "Permissions" : "Machtigingen", + "Role" : "Rol", + "Role_Editing" : "Rol bewerken", + "Role_removed" : "Rol verwijderd", + "Saving" : "Opslaan", + "There_are_no_users_in_this_role" : "Er zijn geen gebruikers met deze rol.", + "User_added" : "Gebruiker toegevoegd", + "User_not_found" : "Gebruiker niet gevonden", + "User_removed" : "Gebruiker verwijderd", + "Users_in_role" : "Gebruikers met rol" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/pl.i18n.json b/packages/rocketchat-authorization/i18n/pl.i18n.json index 14ea715b8ec344eb2c36abfbe1308d98e0163d6b..a022338c789a63ed9cac7a61b4387c206c0c906e 100644 --- a/packages/rocketchat-authorization/i18n/pl.i18n.json +++ b/packages/rocketchat-authorization/i18n/pl.i18n.json @@ -1,4 +1,14 @@ { - "Save" : "Zapisz", - "User_added" : "Użytkownik <em>__user_added__</em> dodany." + "Add_user" : "Dodaj użytkownika", + "Back_to_permissions" : "Powrót do uprawnieÅ„", + "New_role" : "Nowa rola", + "Permissions" : "Uprawnienia", + "Role" : "Rola", + "Role_Editing" : "Edycja ról", + "Role_removed" : "Rola usuniÄ™ta", + "Saving" : "Zapisywanie", + "There_are_no_users_in_this_role" : "Ta rola nie ma przypisanych użytkowników.", + "User_added" : "Użytkownik <em>__user_added__</em> dodany.", + "User_not_found" : "Użytkownik nie znaleziony", + "User_removed" : "Użytkownik usuniÄ™ty" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/pt.i18n.json b/packages/rocketchat-authorization/i18n/pt.i18n.json index 8664e27746f77f8e8839dc0f90f657faa55874e0..b0bb242a6c7940a34c9e1248426cce8ee73f9f11 100644 --- a/packages/rocketchat-authorization/i18n/pt.i18n.json +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -5,11 +5,9 @@ "Cannot_delete_role_because_its_in_use" : "Não é possÃvel remover o papel pois ele está em uso", "New_role" : "Novo papel", "Permissions" : "Permissões", - "Removed" : "Removido", "Role" : "Papel", "Role_Editing" : "Edição de Papel", "Role_removed" : "Papel Removido", - "Save" : "Salvar", "Saving" : "Salvando", "There_are_no_users_in_this_role" : "Não há usuários neste papel.", "User_added" : "Usuário adicionado", diff --git a/packages/rocketchat-authorization/i18n/ro.i18n.json b/packages/rocketchat-authorization/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..30f9bb1036b9134561dc413fdc4bc710893fff14 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ro.i18n.json @@ -0,0 +1,17 @@ +{ + "Add_user" : "Adaugă utilizator", + "Back_to_permissions" : "ÃŽnapoi la permisiuni", + "Cannot_delete_a_protected_role" : "Nu se poate È™terge un rol protejat", + "Cannot_delete_role_because_its_in_use" : "Nu se poate È™terge rol, deoarece este în uz", + "New_role" : "Rol nou", + "Permissions" : "Permisiuni", + "Role" : "Rol", + "Role_Editing" : "Editare rol", + "Role_removed" : "Rol eliminat", + "Saving" : "Salvare...", + "There_are_no_users_in_this_role" : "Nu există utilizatori în acest rol.", + "User_added" : "Utilizator adăugat", + "User_not_found" : "Utilizatorul nu a fost găsit", + "User_removed" : "Utilizator eliminat", + "Users_in_role" : "Utilizatorii în rol" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ru.i18n.json b/packages/rocketchat-authorization/i18n/ru.i18n.json index a1e844169a3c83204f292adf5b73e6f0e95700fa..60691f938cd8b5d987939b8a11063ac222961448 100644 --- a/packages/rocketchat-authorization/i18n/ru.i18n.json +++ b/packages/rocketchat-authorization/i18n/ru.i18n.json @@ -1,4 +1,6 @@ { - "Save" : "Сохранить", - "User_added" : "Пользователь <em>__user_added__</em> добавлен." + "Back_to_permissions" : "Ðазад к наÑтройкам прав", + "Permissions" : "ÐаÑтройка прав", + "User_added" : "Пользователь <em>__user_added__</em> добавлен.", + "Users_in_role" : "Пользователи Ñ Ñ€Ð¾Ð»ÑŒÑŽ" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/sq.i18n.json b/packages/rocketchat-authorization/i18n/sq.i18n.json index b01a59cc8c1c69ffbcff4e8cc7847288eac34f22..6f31cf5a2e622e523ae008338072897b8e56c993 100644 --- a/packages/rocketchat-authorization/i18n/sq.i18n.json +++ b/packages/rocketchat-authorization/i18n/sq.i18n.json @@ -1,3 +1 @@ -{ - "Save" : "Ruaj" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/sr.i18n.json b/packages/rocketchat-authorization/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..e50b8a1469c67ec05d1aae09406761858e436fd7 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/sr.i18n.json @@ -0,0 +1,3 @@ +{ + "User_added" : "КориÑник/ца додат(а)" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/sv.i18n.json b/packages/rocketchat-authorization/i18n/sv.i18n.json index 7bc9d5f5301627b9b75bf2caa789874a33ed6ec6..6f31cf5a2e622e523ae008338072897b8e56c993 100644 --- a/packages/rocketchat-authorization/i18n/sv.i18n.json +++ b/packages/rocketchat-authorization/i18n/sv.i18n.json @@ -1,3 +1 @@ -{ - "Save" : "Spara" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ta-IN.i18n.json b/packages/rocketchat-authorization/i18n/ta-IN.i18n.json index 24a652c5f05464348f2d514454ff580d9cbe18c8..6feacff35ebcd68a7eff867c68e3fc6d4fc4069f 100644 --- a/packages/rocketchat-authorization/i18n/ta-IN.i18n.json +++ b/packages/rocketchat-authorization/i18n/ta-IN.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "சேமி", "User_added" : "பயனர௠<em>__user_added__</em>சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®°à¯." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/tr.i18n.json b/packages/rocketchat-authorization/i18n/tr.i18n.json index 87c7ba45b61ec480889819f621606f03d370a515..c8fe5872ecd52eda415482f7e4ce815b7f645965 100644 --- a/packages/rocketchat-authorization/i18n/tr.i18n.json +++ b/packages/rocketchat-authorization/i18n/tr.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Kaydet", "User_added" : "<em>__user_added__</em> eklendi." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ug.i18n.json b/packages/rocketchat-authorization/i18n/ug.i18n.json index 64384b7a94a0c1c27eac392feabd7dff4b0ffe99..e2d8791b127d5760237c1c95288369ee92339bf1 100644 --- a/packages/rocketchat-authorization/i18n/ug.i18n.json +++ b/packages/rocketchat-authorization/i18n/ug.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "ساقلاش", "User_added" : "<em>__user_added__</em> ئەزا قوشۇلدى." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/uk.i18n.json b/packages/rocketchat-authorization/i18n/uk.i18n.json index c1ac4e32dd601f0d27952ea909d8688f3de22a7b..0bfea7a4c0c90967bc4a888146ee10bdf8eeeb0f 100644 --- a/packages/rocketchat-authorization/i18n/uk.i18n.json +++ b/packages/rocketchat-authorization/i18n/uk.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Зберегти", "User_added" : "КориÑтувач <em>__user_added__</em> доданий." } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/zh.i18n.json b/packages/rocketchat-authorization/i18n/zh.i18n.json index 5b7a5b62c1e6572b97337da89338e7bf6fc3a12e..0504f9957b455f5b4e0dec9f11f06ebc21028402 100644 --- a/packages/rocketchat-authorization/i18n/zh.i18n.json +++ b/packages/rocketchat-authorization/i18n/zh.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "ä¿å˜", "User_added" : "å·²æ·»åŠ ç”¨æˆ· <em>__user_added__</em> 。" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 90a13112d928751706bd7e62d8e7cc3cfacdb660..69682e47db333201648a31e4c0ff64e69936b27d 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -11,18 +11,22 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1', - 'alanning:roles@1.2.12' + 'rocketchat:lib' ]); - api.use('mongo', 'client'); + api.use('mongo', ['client', 'server']); api.use('kadira:flow-router', 'client'); api.use('less@2.5.1', 'client'); + api.use('tracker', 'client'); api.use('templating', 'client'); api.addFiles('lib/rocketchat.coffee', ['server','client']); - api.addFiles('client/collection.coffee', ['client']); + api.addFiles('client/lib/ChatPermissions.coffee', ['client']); + api.addFiles('client/lib/models/Roles.coffee', ['client']); + api.addFiles('client/lib/models/Users.js', ['client']); + api.addFiles('client/lib/models/Subscriptions.js', ['client']); + api.addFiles('client/startup.coffee', ['client']); api.addFiles('client/hasPermission.coffee', ['client']); api.addFiles('client/hasRole.coffee', ['client']); @@ -39,19 +43,22 @@ Package.onUse(function(api) { api.addFiles('client/stylesheets/permissions.less', 'client'); api.addFiles('server/models/Permissions.coffee', ['server']); + api.addFiles('server/models/Roles.coffee', ['server']); + api.addFiles('server/models/Base.js', ['server']); + api.addFiles('server/models/Users.js', ['server']); + api.addFiles('server/models/Subscriptions.js', ['server']); - api.addFiles('server/functions/addUsersToRoles.coffee', ['server']); - api.addFiles('server/functions/getPermissionsForRole.coffee', ['server']); + api.addFiles('server/functions/addUserRoles.coffee', ['server']); api.addFiles('server/functions/getRoles.coffee', ['server']); - api.addFiles('server/functions/getRolesForUser.coffee', ['server']); api.addFiles('server/functions/getUsersInRole.coffee', ['server']); api.addFiles('server/functions/hasPermission.coffee', ['server']); api.addFiles('server/functions/hasRole.coffee', ['server']); - api.addFiles('server/functions/removeUsersFromRoles.coffee', ['server']); + api.addFiles('server/functions/removeUserFromRoles.coffee', ['server']); // publications - api.addFiles('server/publication.coffee', ['server']); + api.addFiles('server/publications/permissions.js', 'server'); api.addFiles('server/publications/roles.coffee', 'server'); + api.addFiles('server/publications/scopedRoles.js', 'server'); api.addFiles('server/publications/usersInRole.coffee', 'server'); // methods @@ -71,6 +78,6 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n', ['client', 'server']); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); diff --git a/packages/rocketchat-authorization/server/functions/addUserRoles.coffee b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee new file mode 100644 index 0000000000000000000000000000000000000000..c715153ce326174249ddba7290f2051551558997 --- /dev/null +++ b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee @@ -0,0 +1,19 @@ +RocketChat.authz.addUserRoles = (userId, roleNames, scope) -> + if not userId or not roleNames + return false + + user = RocketChat.models.Users.findOneById(userId) + if not user + throw new Meteor.Error 'invalid-user' + + roleNames = [].concat roleNames + + existingRoleNames = _.pluck(RocketChat.authz.getRoles(), '_id') + invalidRoleNames = _.difference(roleNames, existingRoleNames) + unless _.isEmpty(invalidRoleNames) + for role in invalidRoleNames + RocketChat.models.Roles.createOrUpdate role + + RocketChat.models.Roles.addUserRoles(userId, roleNames, scope) + + return true diff --git a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee b/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee deleted file mode 100644 index 3af878e6814adf10ef689e91cabe3eb8508bb1c3..0000000000000000000000000000000000000000 --- a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee +++ /dev/null @@ -1,28 +0,0 @@ -RocketChat.authz.addUsersToRoles = (userIds, roleNames, scope ) -> - console.log '[methods] addUserToRoles -> '.green, 'arguments:', arguments - if not userIds or not roleNames - return false - - unless _.isArray(userIds) - userIds = [userIds] - - users = Meteor.users.find({_id: {$in : userIds}}).fetch() - unless userIds.length is users.length - throw new Meteor.Error 'invalid-user' - - unless _.isArray(roleNames) - roleNames = [roleNames] - - existingRoleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name') - invalidRoleNames = _.difference( roleNames, existingRoleNames) - unless _.isEmpty(invalidRoleNames) - # throw new Meteor.Error 'invalid-role' - for role in invalidRoleNames - Roles.createRole role - - unless _.isString(scope) - scope = Roles.GLOBAL_GROUP - - Roles.addUsersToRoles( userIds, roleNames, scope) - - return true diff --git a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee b/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee deleted file mode 100644 index 7023d120265bdf8e1e41d5062538f4ae116d90ea..0000000000000000000000000000000000000000 --- a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee +++ /dev/null @@ -1,9 +0,0 @@ -RocketChat.authz.getPermissionsForRole = (roleName) -> - unless roleName - throw new Meteor.Error 'invalid-role' - - roleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name') - unless roleName in roleNames - throw new Meteor.Error 'invalid-role', "Role #{roleName} not found" - - return _.pluck(RocketChat.models.Permissions.findByRole( roleName ).fetch(), '_id') diff --git a/packages/rocketchat-authorization/server/functions/getRoles.coffee b/packages/rocketchat-authorization/server/functions/getRoles.coffee index 37c3d2537fdb438dcc9afc654e5eb1d941ef69af..895dcc532c1913c7fdb53e8800c8d079ecc4f8e8 100644 --- a/packages/rocketchat-authorization/server/functions/getRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/getRoles.coffee @@ -1,2 +1,2 @@ RocketChat.authz.getRoles = -> - return Roles.getAllRoles() \ No newline at end of file + return RocketChat.models.Roles.find().fetch() diff --git a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee b/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee deleted file mode 100644 index 40f8564a28eaf39aa1bc64178b7e0be4fa02b1cd..0000000000000000000000000000000000000000 --- a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee +++ /dev/null @@ -1,7 +0,0 @@ -RocketChat.authz.getRolesForUser = (userId, scope) -> - console.log '[methods] getRolesForUser -> '.green, 'arguments:', arguments - # returns roles for the given scope as well as the global scope - unless scope - scope = Roles.GLOBAL_GROUP - - return Roles.getRolesForUser(userId, scope) \ No newline at end of file diff --git a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee index ee416c3e90255a1dddb77cb42ec78b055676126e..b8fc11a51fbae3c0462bab59d41e59392782e547 100644 --- a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee +++ b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee @@ -1,6 +1,2 @@ RocketChat.authz.getUsersInRole = (roleName, scope, options) -> - # alanning:roles doc says this is an expensive operation - unless _.isString(scope) - scope = Roles.GLOBAL_GROUP - - return Roles.getUsersInRole(roleName, scope, options) + return RocketChat.models.Roles.findUsersInRole(roleName, scope, options) diff --git a/packages/rocketchat-authorization/server/functions/hasPermission.coffee b/packages/rocketchat-authorization/server/functions/hasPermission.coffee index f0d2d3ca2e92327ddd41a49cf760d4a3806f9a56..7ae014453d0e994254bfa534be5054163f970e60 100644 --- a/packages/rocketchat-authorization/server/functions/hasPermission.coffee +++ b/packages/rocketchat-authorization/server/functions/hasPermission.coffee @@ -1,12 +1,3 @@ RocketChat.authz.hasPermission = (userId, permissionId, scope) -> - console.log '[methods] hasPermission -> '.green, 'arguments:', arguments - - # get user's roles - roles = RocketChat.authz.getRolesForUser(userId, scope) - - # get permissions for user's roles - permissions = [] - for role in roles - permissions = permissions.concat( RocketChat.authz.getPermissionsForRole( role )) - # may contain duplicate, but doesn't matter - return permissionId in permissions \ No newline at end of file + permission = RocketChat.models.Permissions.findOne permissionId + return RocketChat.models.Roles.isUserInRoles(userId, permission.roles, scope) diff --git a/packages/rocketchat-authorization/server/functions/hasRole.coffee b/packages/rocketchat-authorization/server/functions/hasRole.coffee index 83d32ea862a3000591167a5cefe5f1d1bcaf198c..aff335e48b2fd0f7ae37fce3f2d00bb98796124c 100644 --- a/packages/rocketchat-authorization/server/functions/hasRole.coffee +++ b/packages/rocketchat-authorization/server/functions/hasRole.coffee @@ -1,4 +1,3 @@ -RocketChat.authz.hasRole = (userId, roleName, scope) -> - console.log '[methods] hasRoles -> '.green, 'arguments:', arguments - # per alanning:roles, returns true if user is in ANY roles - return Roles.userIsInRole(userId, [roleName], scope) \ No newline at end of file +RocketChat.authz.hasRole = (userId, roleNames, scope) -> + roleNames = [].concat roleNames + return RocketChat.models.Roles.isUserInRoles(userId, roleNames, scope) # true if user is in ANY role diff --git a/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee new file mode 100644 index 0000000000000000000000000000000000000000..64df765f67fc7711960861e2f4b8543287b8afce --- /dev/null +++ b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee @@ -0,0 +1,18 @@ +RocketChat.authz.removeUserFromRoles = (userId, roleNames, scope) -> + if not userId or not roleNames + return false + + user = RocketChat.models.Users.findOneById(userId) + if not user? + throw new Meteor.Error 'invalid-user' + + roleNames = [].concat roleNames + + existingRoleNames = _.pluck(RocketChat.authz.getRoles(), 'name') + invalidRoleNames = _.difference(roleNames, existingRoleNames) + unless _.isEmpty(invalidRoleNames) + throw new Meteor.Error 'invalid-role' + + RocketChat.models.Roles.removeUserRoles(userId, roleNames, scope) + + return true diff --git a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee deleted file mode 100644 index a3f7c794d898a711815f3488eafae4f30b135248..0000000000000000000000000000000000000000 --- a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee +++ /dev/null @@ -1,26 +0,0 @@ -RocketChat.authz.removeUsersFromRoles = (userIds, roleNames, scope ) -> - console.log '[methods] removeUsersFromRoles -> '.green, 'arguments:', arguments - if not userIds or not roleNames - return false - - unless _.isArray(userIds) - userIds = [userIds] - - users = Meteor.users.find({_id: {$in : userIds}}).fetch() - unless userIds.length is users.length - throw new Meteor.Error 'invalid-user' - - unless _.isArray(roleNames) - roleNames = [roleNames] - - existingRoleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name') - invalidRoleNames = _.difference( roleNames, existingRoleNames) - unless _.isEmpty(invalidRoleNames) - throw new Meteor.Error 'invalid-role' - - unless _.isString(scope) - scope = Roles.GLOBAL_GROUP - - Roles.removeUsersFromRoles( userIds, roleNames, scope) - - return true \ No newline at end of file diff --git a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee index a6d52621a7dbcdde74464f1f130a7f8518201ff3..6924414101c3ff901e644bc3f8d8a6160d8befb5 100644 --- a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee @@ -3,6 +3,4 @@ Meteor.methods if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - console.log '[methods] authorization:addPermissionToRole -> '.green, 'arguments:', arguments - RocketChat.models.Permissions.addRole permission, role diff --git a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee index 98583682d75c41acd69d1ea279b6a6ffba1c63c6..74ba6bbea53017285a33b185a525663ef2bd96ba 100644 --- a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee @@ -1,17 +1,14 @@ Meteor.methods - 'authorization:addUserToRole': (roleName, username) -> + 'authorization:addUserToRole': (roleName, username, scope) -> if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - console.log('[methods] authorization:addUserToRole -> '.green, 'arguments:', arguments); - if not roleName or not _.isString(roleName) or not username or not _.isString(username) throw new Meteor.Error 'invalid-arguments' - user = Meteor.users.findOne { username: username }, { fields: { _id: 1 } } + user = RocketChat.models.Users.findOneByUsername username, { fields: { _id: 1 } } if not user?._id? throw new Meteor.Error 'user-not-found', 'User_not_found' - # return Roles.addUsersToRoles user._id, roleName - return Roles.addUsersToRoles user._id, roleName, Roles.GLOBAL_GROUP + return RocketChat.models.Roles.addUserRoles user._id, roleName, scope diff --git a/packages/rocketchat-authorization/server/methods/deleteRole.coffee b/packages/rocketchat-authorization/server/methods/deleteRole.coffee index ab6e554c11234c0bf6e5e1f8df51596e2a63aa65..39ca53a350289761cca1c9725c2ebe8d70cf6dd4 100644 --- a/packages/rocketchat-authorization/server/methods/deleteRole.coffee +++ b/packages/rocketchat-authorization/server/methods/deleteRole.coffee @@ -1,18 +1,19 @@ Meteor.methods - 'authorization:deleteRole': (_id) -> + 'authorization:deleteRole': (roleName) -> if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - console.log '[methods] authorization:deleteRole -> '.green, 'arguments:', arguments - - role = Meteor.roles.findOne _id + role = RocketChat.models.Roles.findOne roleName + if not role? + throw new Meteor.Error 'invalid-role' if role.protected throw new Meteor.Error 'protected-role', 'Cannot_delete_a_protected_role' - someone = Meteor.users.findOne { "roles.#{Roles.GLOBAL_GROUP}": role.name } + roleScope = role.scope or 'Users' + existingUsers = RocketChat.models[roleScope]?.findUsersInRoles?(roleName) - if someone? + if existingUsers?.count() > 0 throw new Meteor.Error 'role-in-use', 'Cannot_delete_role_because_its_in_use' - return Roles.deleteRole role.name + return RocketChat.models.Roles.remove role.name diff --git a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee index 9efde6b9d17d8ce9f74f4aec942f0cb69e0d163c..ff5def0ad66c35f17b1f4c4a6df0598b159a9245 100644 --- a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee +++ b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee @@ -3,6 +3,4 @@ Meteor.methods if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - console.log '[methods] authorization:removeRoleFromPermission -> '.green, 'arguments:', arguments - RocketChat.models.Permissions.removeRole permission, role diff --git a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee index 26d47a63b1a80ff61edfc2de22668c105c4f2881..26da340af6f32bfd70bab9179e3aebff25a58734 100644 --- a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee +++ b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - console.log('[methods] authorization:removeUserFromRole -> '.green, 'arguments:', arguments); - if not roleName or not _.isString(roleName) or not username or not _.isString(username) throw new Meteor.Error 'invalid-arguments' @@ -13,4 +11,4 @@ Meteor.methods if not user?._id? throw new Meteor.Error 'user-not-found' - return Roles.removeUsersFromRoles user._id, roleName, Roles.GLOBAL_GROUP + return RocketChat.models.Roles.removeUserRoles user._id, roleName diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee index 8df33ff81a556c2daee3dcc5a5d23b68de0ff809..874fe0eaa6d0bc3de8ba8c3d1e178e857b42069a 100644 --- a/packages/rocketchat-authorization/server/methods/saveRole.coffee +++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee @@ -3,15 +3,7 @@ Meteor.methods if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - console.log '[methods] authorization:saveRole -> '.green, 'arguments:', arguments + if not roleData.name? + throw new Meteor.Error 'invalid-data', 'Role name is required' - saveData = - description: roleData.description - - if not _id? and roleData.name? - saveData.name = roleData.name - - if _id? - return Meteor.roles.update _id, { $set: saveData } - else - return Meteor.roles.insert saveData + return RocketChat.models.Roles.createOrUpdate roleData.name, 'Users', roleData.description diff --git a/packages/rocketchat-authorization/server/models/Base.js b/packages/rocketchat-authorization/server/models/Base.js new file mode 100644 index 0000000000000000000000000000000000000000..5977c6446677641d03f7e66ada585774895224d0 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Base.js @@ -0,0 +1,38 @@ +RocketChat.models._Base.prototype.roleBaseQuery = function(userId, scope) { return {} } + +RocketChat.models._Base.prototype.findRolesByUserId = function(userId, options) { + var query = this.roleBaseQuery(userId); + return this.find(query, { fields: { roles: 1 } }); +} + +RocketChat.models._Base.prototype.isUserInRole = function(userId, roleName, scope) { + var query = this.roleBaseQuery(userId, scope); + query.roles = roleName; + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models._Base.prototype.addRolesByUserId = function(userId, roles, scope) { + var roles = [].concat(roles); + var query = this.roleBaseQuery(userId, scope); + var update = { + $addToSet: { + roles: { $each: roles } + } + } + return this.update(query, update); +} + +RocketChat.models._Base.prototype.removeRolesByUserId = function(userId, roles, scope) { + var roles = [].concat(roles); + var query = this.roleBaseQuery(userId, scope); + var update = { + $pullAll: { + roles: roles + } + } + return this.update(query, update); +} + +RocketChat.models._Base.prototype.findUsersInRoles = function() { + throw new Meteor.Error('overwrite-function', 'You must overwrite this function in the extended classes'); +} diff --git a/packages/rocketchat-authorization/server/models/Permissions.coffee b/packages/rocketchat-authorization/server/models/Permissions.coffee index 3e1c6eef96a5e025b65cbbad6fe3929ea2e7a8fc..ec763d94b7122a1d14dcde4db00e4f26b850b792 100644 --- a/packages/rocketchat-authorization/server/models/Permissions.coffee +++ b/packages/rocketchat-authorization/server/models/Permissions.coffee @@ -2,7 +2,6 @@ RocketChat.models.Permissions = new class extends RocketChat.models._Base constructor: -> @_initModel 'permissions' - # FIND findByRole: (role, options) -> query = diff --git a/packages/rocketchat-authorization/server/models/Roles.coffee b/packages/rocketchat-authorization/server/models/Roles.coffee new file mode 100644 index 0000000000000000000000000000000000000000..8489afa1d47ac77c94b8acc537d88bab2faa09d8 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Roles.coffee @@ -0,0 +1,43 @@ +RocketChat.models.Roles = new class extends RocketChat.models._Base + constructor: -> + @_initModel 'roles' + @tryEnsureIndex { 'name': 1 } + @tryEnsureIndex { 'scope': 1 } + + findUsersInRole: (name, scope, options) -> + role = @findOne name + roleScope = role?.scope or 'Users' + RocketChat.models[roleScope]?.findUsersInRoles?(name, scope, options) + + isUserInRoles: (userId, roles, scope) -> + roles = [].concat roles + _.some roles, (roleName) => + role = @findOne roleName + roleScope = role?.scope or 'Users' + return RocketChat.models[roleScope]?.isUserInRole?(userId, roleName, scope) + + createOrUpdate: (name, scope, description, protectedRole) -> + scope ?= 'Users' + updateData = {} + updateData.name = name + updateData.scope = scope + if description? + updateData.description = description + if protectedRole? + updateData.protected = protectedRole + + @upsert { _id: name }, { $set: updateData } + + addUserRoles: (userId, roles, scope) -> + roles = [].concat roles + for roleName in roles + role = @findOne roleName + roleScope = role?.scope or 'Users' + RocketChat.models[roleScope]?.addRolesByUserId?(userId, roleName, scope) + + removeUserRoles: (userId, roles, scope) -> + roles = [].concat roles + for roleName in roles + role = @findOne roleName + roleScope = role?.scope or 'Users' + RocketChat.models[roleScope]?.removeRolesByUserId?(userId, roleName, scope) diff --git a/packages/rocketchat-authorization/server/models/Subscriptions.js b/packages/rocketchat-authorization/server/models/Subscriptions.js new file mode 100644 index 0000000000000000000000000000000000000000..9c7d4a16fc760f753d6109bc14d64932d245aa05 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Subscriptions.js @@ -0,0 +1,28 @@ +RocketChat.models.Subscriptions.roleBaseQuery = function(userId, scope) { + var query = { "u._id": userId } + if (!_.isUndefined(scope)) { + query.rid = scope; + } + return query; +} + +RocketChat.models.Subscriptions.findUsersInRoles = function(roles, scope, options) { + roles = [].concat(roles); + + var query = { + roles: { $in: roles } + } + + if (scope) { + query.rid = scope; + } + + subscriptions = this.find(query).fetch(); + + users = _.compact(_.map(subscriptions, function(subscription) { + if ('undefined' !== typeof subscription.u && 'undefined' !== typeof subscription.u._id) + return subscription.u._id + })); + + return RocketChat.models.Users.find({ _id: { $in: users } }, options); +} diff --git a/packages/rocketchat-authorization/server/models/Users.js b/packages/rocketchat-authorization/server/models/Users.js new file mode 100644 index 0000000000000000000000000000000000000000..315ab7e9acf9500536ff5c9ca491bc380d1f3970 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Users.js @@ -0,0 +1,13 @@ +RocketChat.models.Users.roleBaseQuery = function(userId, scope) { + return { _id: userId } +} + +RocketChat.models.Users.findUsersInRoles = function(roles, scope, options) { + roles = [].concat(roles); + + var query = { + roles: { $in: roles } + } + + return this.find(query, options); +} diff --git a/packages/rocketchat-authorization/server/publication.coffee b/packages/rocketchat-authorization/server/publication.coffee deleted file mode 100644 index 8f6e008e14c17c2c5da24bd2c4b52071452e8fd6..0000000000000000000000000000000000000000 --- a/packages/rocketchat-authorization/server/publication.coffee +++ /dev/null @@ -1,3 +0,0 @@ -Meteor.publish 'permissions', -> - console.log '[publish] permissions'.green - return RocketChat.models.Permissions.find {} diff --git a/packages/rocketchat-authorization/server/publications/permissions.js b/packages/rocketchat-authorization/server/publications/permissions.js new file mode 100644 index 0000000000000000000000000000000000000000..0872d3b4db046cc84791c55c1e576b7399bd4218 --- /dev/null +++ b/packages/rocketchat-authorization/server/publications/permissions.js @@ -0,0 +1,3 @@ +Meteor.publish('permissions', function () { + return RocketChat.models.Permissions.find({}); +}); diff --git a/packages/rocketchat-authorization/server/publications/roles.coffee b/packages/rocketchat-authorization/server/publications/roles.coffee index 6357a62510e7c6a4635d19a169531248d04a0145..b3eafb56d3e50b2a485ab95413f4a4064755d776 100644 --- a/packages/rocketchat-authorization/server/publications/roles.coffee +++ b/packages/rocketchat-authorization/server/publications/roles.coffee @@ -2,7 +2,5 @@ Meteor.publish 'roles', -> unless @userId return @ready() - if not RocketChat.authz.hasPermission @userId, 'access-permissions' - throw new Meteor.Error "not-authorized" + return RocketChat.models.Roles.find() - return RocketChat.authz.getRoles() diff --git a/packages/rocketchat-authorization/server/publications/scopedRoles.js b/packages/rocketchat-authorization/server/publications/scopedRoles.js new file mode 100644 index 0000000000000000000000000000000000000000..bd6247697b0abb90c100593ea93c9aa097bdaf58 --- /dev/null +++ b/packages/rocketchat-authorization/server/publications/scopedRoles.js @@ -0,0 +1,11 @@ +/** + * Publish logged-in user's roles so client-side checks can work. + */ +Meteor.publish('scopedRoles', function (scope) { + if (!this.userId || _.isUndefined(RocketChat.models[scope]) || !_.isFunction(RocketChat.models[scope].findRolesByUserId)) { + this.ready() + return + } + + return RocketChat.models[scope].findRolesByUserId(this.userId); +}); diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 905a43410e67a7471e24aeceb5a5a5a5bf0c36c7..7febc408c37ea789fcf0026dc4491a4d7a747545 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -7,7 +7,7 @@ Meteor.startup -> permissions = [ { _id: 'view-statistics', - roles : ['admin', 'temp-role']} + roles : ['admin']} { _id: 'view-privileged-setting', roles : ['admin']} @@ -27,11 +27,14 @@ Meteor.startup -> { _id: 'edit-other-user-info', roles : ['admin']} + { _id: 'edit-other-user-password', + roles : ['admin']} + { _id: 'assign-admin-role', roles : ['admin']} { _id: 'edit-other-user-active-status', - roles : ['admin', 'site-moderator']} + roles : ['admin']} { _id: 'delete-user', roles : ['admin']} @@ -46,31 +49,43 @@ Meteor.startup -> roles : ['admin']} { _id: 'create-c', - roles : ['admin', 'site-moderator', 'user']} + roles : ['admin', 'user']} { _id: 'delete-c', - roles : ['admin', 'site-moderator']} + roles : ['admin']} { _id: 'edit-room', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'edit-message', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'delete-message', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator', 'owner']} + + { _id: 'remove-user', + roles : ['admin', 'moderator', 'owner']} + + { _id: 'mute-user', + roles : ['admin', 'moderator', 'owner']} { _id: 'ban-user', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator', 'owner']} + + { _id: 'set-moderator', + roles : ['admin', 'owner']} + + { _id: 'set-owner', + roles : ['admin']} { _id: 'create-p', - roles : ['admin', 'site-moderator', 'user']} + roles : ['admin', 'user']} { _id: 'delete-p', - roles : ['admin', 'site-moderator']} + roles : ['admin']} { _id: 'delete-d', - roles : ['admin', 'site-moderator']} + roles : ['admin']} { _id: 'bulk-register-user', roles : ['admin']} @@ -79,13 +94,13 @@ Meteor.startup -> roles : ['admin']} { _id: 'view-c-room', - roles : ['admin', 'site-moderator', 'user']} + roles : ['admin', 'user']} { _id: 'view-p-room', - roles : ['admin', 'site-moderator', 'user']} + roles : ['admin', 'user']} { _id: 'view-d-room', - roles : ['admin', 'site-moderator', 'user']} + roles : ['admin', 'user']} { _id: 'access-permissions', roles : ['admin']} @@ -94,17 +109,22 @@ Meteor.startup -> roles : ['admin']} { _id: 'manage-integrations', + roles : ['admin', 'bot']} + + { _id: 'manage-oauth-apps', roles : ['admin']} ] - #alanning:roles - roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); - for permission in permissions - RocketChat.models.Permissions.upsert( permission._id, {$setOnInsert : permission }) - for role in permission.roles - unless role in roles - Roles.createRole role - roles.push(role) - + RocketChat.models.Permissions.upsert( permission._id, {$set: permission }) + + defaultRoles = [ + { name: 'admin', scope: 'Users' } + { name: 'moderator', scope: 'Subscriptions' } + { name: 'owner', scope: 'Subscriptions' } + { name: 'user', scope: 'Users' } + { name: 'bot', scope: 'Users' } + ] + for role in defaultRoles + RocketChat.models.Roles.createOrUpdate role.name, role.scope diff --git a/packages/rocketchat-autolinker/package.js b/packages/rocketchat-autolinker/package.js index af2c141991583727bce93cf9f1195b00d03bf955..26e5d0a3f02adaa5fc72b759d10bc76ed8b5fc40 100644 --- a/packages/rocketchat-autolinker/package.js +++ b/packages/rocketchat-autolinker/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'konecty:autolinker', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('autolinker.coffee', ['server','client']); diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee new file mode 100644 index 0000000000000000000000000000000000000000..c55e6956b7b2068df6f4cacb5a4448c7f21aba33 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee @@ -0,0 +1,13 @@ +Meteor.startup -> + RocketChat.ChannelSettings.addOption + id: 'mail-messages' + template: 'channelSettingsMailMessages' + validation: -> + return RocketChat.authz.hasAllPermission('mail-messages') + + RocketChat.callbacks.add 'roomExit', (mainNode) -> + messagesBox = $('.messages-box') + if messagesBox.get(0)? + instance = Blaze.getView(messagesBox.get(0))?.templateInstance() + instance?.resetSelection(false) + , RocketChat.callbacks.priority.MEDIUM, 'room-exit-mail-messages' diff --git a/packages/rocketchat-channel-settings-mail-messages/client/stylesheets/mail-messages.less b/packages/rocketchat-channel-settings-mail-messages/client/stylesheets/mail-messages.less new file mode 100644 index 0000000000000000000000000000000000000000..6b5e9dd4a5b695c7fb866492494ac21dbd808a9f --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/stylesheets/mail-messages.less @@ -0,0 +1,24 @@ +.flex-tab { + .mail-message { + form { + margin-top: 20px; + + .input-line.double-col { + margin-bottom: 20px; + + label { + line-height: 15px; + } + + div { + line-height: 15px; + i.octicon { + font-size: 13px; + opacity: 0.4; + vertical-align: top; + } + } + } + } + } +} diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee new file mode 100644 index 0000000000000000000000000000000000000000..855a105f0f4c96ff6889df49149839c42f1054de --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee @@ -0,0 +1,10 @@ +Template.channelSettingsMailMessages.events + 'click button.mail-messages': (e, t) -> + Session.set 'channelSettingsMailMessages', Session.get('openedRoom') + RocketChat.TabBar.setTemplate('mailMessagesInstructions') + view = Blaze.getView($('.messages-box')[0]) + view?.templateInstance?().resetSelection?(true) + +Template.channelSettingsMailMessages.onCreated -> + view = Blaze.getView($('.messages-box')[0]) + view?.templateInstance?().resetSelection?(false) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html new file mode 100644 index 0000000000000000000000000000000000000000..10b1cce82fe7934fea31b5bed1a2866b29dc3578 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html @@ -0,0 +1,8 @@ +<template name="channelSettingsMailMessages"> + <li> + <label>{{_ "Mail_Messages"}}</label> + <div> + <button type="button" class="button primary mail-messages">{{_ "Choose_messages"}}</button> + </div> + </li> +</template> diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d78a9c41f42654c68c5ee85bcd94586f0701d5cd --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -0,0 +1,123 @@ +Template.mailMessagesInstructions.helpers + name: -> + return Meteor.user().name + email: -> + return Meteor.user().emails?[0]?.address + roomName: -> + return ChatRoom.findOne(Session.get('openedRoom'))?.name + erroredEmails: -> + return Template.instance()?.erroredEmails.get().join(', ') + autocompleteSettings: -> + return { + limit: 10 + # inputDelay: 300 + rules: [ + { + # @TODO maybe change this 'collection' and/or template + collection: 'CachedChannelList' + subscription: 'userAutocomplete' + field: 'username' + template: Template.userSearch + noMatchTemplate: Template.userSearchEmpty + matchAll: true + filter: + exceptions: Template.instance().selectedUsers.get() + selector: (match) -> + return { username: match } + sort: 'username' + } + ] + } + selectedUsers: -> + return Template.instance().selectedUsers.get() + +Template.mailMessagesInstructions.events + 'click .cancel': (e, t) -> + t.reset() + + 'click .send': (e, t) -> + t.$('.error').hide() + $btn = t.$('button.send') + oldBtnValue = $btn.html() + $btn.html(TAPi18n.__('Sending')) + + selectedMessages = $('.messages-box .message.selected') + + error = false + if selectedMessages.length is 0 + t.$('.error-select').show() + error = true + + if t.$('input[name=to_emails]').val().trim() + rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/ + emails = t.$('input[name=to_emails]').val().trim().split(',') + erroredEmails = [] + for email in emails + unless rfcMailPatternWithName.test email.trim() + erroredEmails.push email.trim() + + t.erroredEmails.set erroredEmails + if erroredEmails.length > 0 + t.$('.error-invalid-emails').show() + error = true + else if not t.selectedUsers.get().length + t.$('.error-missing-to').show() + error = true + + if error + $btn.html(oldBtnValue) + else + data = + rid: Session.get('openedRoom') + to_users: t.selectedUsers.get() + to_emails: t.$('input[name=to_emails]').val().trim() + subject: t.$('input[name=subject]').val().trim() + messages: selectedMessages.map((i, message) -> return message.id).toArray() + language: localStorage.getItem('userLanguage') + + Meteor.call 'mailMessages', data, (err, result) -> + $btn.html(oldBtnValue) + if err? + return toastr.error(err.reason or err.message) + + console.log(result) + toastr.success(TAPi18n.__('Your_email_has_been_queued_for_sending')) + t.reset() + + 'click .select-all': (e, t) -> + t.$('.error-select').hide() + + view = Blaze.getView($('.messages-box')[0]) + view?.templateInstance?().selectedMessages = _.pluck(ChatMessage.find({rid: Session.get('openedRoom')})?.fetch(), '_id') + $(".messages-box .message").addClass('selected') + + 'autocompleteselect #to_users': (event, instance, doc) -> + instance.selectedUsers.set instance.selectedUsers.get().concat doc.username + event.currentTarget.value = '' + event.currentTarget.focus() + + 'click .remove-to-user': (e, instance) -> + self = @ + + users = Template.instance().selectedUsers.get() + users = _.reject Template.instance().selectedUsers.get(), (_id) -> + return _id is self.valueOf() + + Template.instance().selectedUsers.set(users) + + $('#to_users').focus() + +Template.mailMessagesInstructions.onCreated -> + @autoCompleteCollection = new Mongo.Collection null + @selectedUsers = new ReactiveVar [] + @erroredEmails = new ReactiveVar [] + + @reset = => + @selectedUsers.set [] + RocketChat.TabBar.setTemplate('channelSettings') + view = Blaze.getView($('.messages-box')[0]) + view?.templateInstance?().resetSelection?(false) + + @autorun => + if Session.get('channelSettingsMailMessages') isnt Session.get('openedRoom') + this.reset() diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html new file mode 100644 index 0000000000000000000000000000000000000000..c2a8dd37da01142ca3b30e91802a0ebec590b519 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html @@ -0,0 +1,55 @@ +<template name="mailMessagesInstructions"> + <div class="content"> + <div class="list-view mail-message"> + <div class="status"> + <h2>{{_ "Mail_Messages"}}</h2> + </div> + <p>{{_ "Mail_Messages_Instructions"}}</p> + <form> + <fieldset> + <div class="input-line double-col"> + <label>{{_ "From"}}</label> + <div>{{name}}</div> + <div>{{email}}</div> + </div> + <div class="input-line double-col"> + <label>{{_ "To_users"}}</label> + <div> + {{> inputAutocomplete settings=autocompleteSettings id="to_users" name="to_users" class="search" autocomplete="off"}} + <ul class="selected-users"> + {{#each selectedUsers}} + <li>{{.}} <i class="icon-cancel remove-to-user"></i></li> + {{/each}} + </ul> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Additional_emails"}}</label> + <div> + <input type="text" name="to_emails" value="" /> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Subject"}}</label> + <div> + <input type="text" name="subject" value="{{_ "Mail_Messages_Subject" roomName}}" /> + </div> + </div> + </fieldset> + </form> + <div class="error error-missing-to alert alert-danger" style="display: none"> + {{_ "Mail_Message_Missing_to"}} + </div> + <div class="error error-invalid-emails alert alert-danger" style="display: none"> + {{_ "Mail_Message_Invalid_emails" erroredEmails}} + </div> + <div class="error error-select alert alert-danger" style="display: none"> + {{{_ "Mail_Message_No_messages_selected_select_all"}}} + </div> + <p style="margin-top: 30px"> + <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> + <button type="button" class="button primary send">{{_ "Send"}}</button> + </p> + </div> + </div> +</template> diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..ad10bc3dc16ab6b133aaa18e8c5cb787782522ac --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json @@ -0,0 +1,6 @@ +{ + "Choose_messages" : "اختر الرسائل", + "From" : "من", + "Sending" : "جار الإرسال...", + "Subject" : "الموضوع" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/cs.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/cs.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..5e5f1ba3fb4b86c58741e9d04639c4ef333e924c --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json @@ -0,0 +1,16 @@ +{ + "Additional_emails" : "Zusätzliche E-Mails", + "Body" : "Body", + "Choose_messages" : "Nachrichten auswählen", + "From" : "Absender", + "Mail_Message_Invalid_emails" : "Sie haben eine oder mehrere ungültige E-Mail-Adressen angegeben: %s", + "Mail_Message_Missing_to" : "Sie müssen einen/mehrere Benutzer auswählen oder einen/mehrere E-Mail-Adressen durch Kommata getrennt angeben.", + "Mail_Message_No_messages_selected_select_all" : "Sie haben keine Nachrichten ausgewählt. Möchten Sie <a href='#' class='select-all'>alle</a> sichtbaren Nachrichten auswählen?", + "Mail_Messages" : "Nachrichten per E-Mail senden", + "Mail_Messages_Instructions" : "Wählen Sie aus, welche Nachrichten Sie per E-Mail senden möchten, indem Sie die Nachrichten anklicken. ", + "Mail_Messages_Subject" : "Hier ist ein ausgewählter Teil aus %s Nachrichten", + "Sending" : "Senden...", + "Subject" : "Betreff", + "To_users" : "An die Benutzer", + "Your_email_has_been_queued_for_sending" : "Ihre E-Mail wird in Kürze gesendet werden." +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/el.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/el.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..9383ba9a910b3124ff149e4b4bb289c4092a5338 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json @@ -0,0 +1,16 @@ +{ + "Additional_emails" : "Additional E-mails", + "Body" : "Body", + "Choose_messages" : "Choose messages", + "From" : "From", + "Mail_Message_Invalid_emails" : "You have provided one or more invalid e-mails: %s", + "Mail_Message_Missing_to" : "You must select one or more users or provide one or more e-mail addresses, separated by commas.", + "Mail_Message_No_messages_selected_select_all" : "You haven't selected any messages. Would you like to <a href='#' class='select-all'>select all</a> visible messages?", + "Mail_Messages" : "Mail Messages", + "Mail_Messages_Instructions" : "Choose which messages you want to send via e-mail by clicking the messages", + "Mail_Messages_Subject" : "Here's a selected portion of %s messages", + "Sending" : "Sending...", + "Subject" : "Subject", + "To_users" : "To Users", + "Your_email_has_been_queued_for_sending" : "Your email has been queued for sending" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/es.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/es.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/fa.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/fa.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..062abf850411e79abafad617ecb6c74ad8e11e19 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json @@ -0,0 +1,16 @@ +{ + "Additional_emails" : "Lisäsähköpostit", + "Body" : "Runko", + "Choose_messages" : "Valitse viestit", + "From" : "Lähettäjä", + "Mail_Message_Invalid_emails" : "Olet antanut virheellisiä sähköposteja: %s", + "Mail_Message_Missing_to" : "Sinun tulee valita yksi tai useampi käyttäjä tai yksi tai useampi sähköpostiosoite, pilkuilla eroteltuna.", + "Mail_Message_No_messages_selected_select_all" : "Et ole valinnut yhtään viestiä. Haluaisitko <a href='#' class='select-all'>valita kaikki</a> näkyvät viestit?", + "Mail_Messages" : "Lähetä viestit sähköpostitse", + "Mail_Messages_Instructions" : "Valitse, mitkä viestit haluat lähettää sähköpostitse klikkaamalla viestejä", + "Mail_Messages_Subject" : "Tässä muutama viesti (%s viestiä)", + "Sending" : "Lähetetään...", + "Subject" : "Aihe", + "To_users" : "Käyttäjille", + "Your_email_has_been_queued_for_sending" : "Sähköpostisi on lähetysjonossa" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/fr.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/fr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..3092354611af32f7fc2388898cc9fbadc16424ea --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/fr.i18n.json @@ -0,0 +1,14 @@ +{ + "Body" : "Corps", + "Choose_messages" : "Choisissez des messages", + "From" : "De", + "Mail_Message_Invalid_emails" : "Vous avez fourni un ou plusieurs e-mails invalides : %s", + "Mail_Message_Missing_to" : "Vous devez sélectionner un ou plusieurs utilisateurs ou fournir une ou plusieurs adresses e-mail, séparées par des virgules.", + "Mail_Message_No_messages_selected_select_all" : "Vous n'avez sélectionné aucun message. Voudriez-vous <a href='#' class='select-all'>sélectionner tous</a> les messages visibles ?", + "Mail_Messages" : "Messages électroniques", + "Mail_Messages_Instructions" : "Choisissez les messages que vous souhaitez envoyer par e-mail en cliquant dessus", + "Mail_Messages_Subject" : "Voici une sélection des messages \"%s\"", + "Sending" : "Envoi...", + "Subject" : "Sujet", + "Your_email_has_been_queued_for_sending" : "Votre email a été mis en boite d'envoi" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..0ee4017b43ee20d0b34a6bf8e68d5151965ef4f8 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json @@ -0,0 +1,4 @@ +{ + "Choose_messages" : "בחירת הודעות", + "To_users" : "למשתמשי×" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/hr.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/hr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6bbb424d86f3fcdfd0de9426c0a1ab642384ec10 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/hr.i18n.json @@ -0,0 +1,8 @@ +{ + "Additional_emails" : "Dodatni E-mailovi", + "Choose_messages" : "Odaberite poruke", + "From" : "Od", + "Sending" : "Slanje ...", + "Subject" : "Naslov", + "To_users" : "Za korisnike" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/hu.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/hu.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/it.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/it.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ja.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ja.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/km.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/km.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ko.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ko.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ku.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ku.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/lo.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/lo.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ms-MY.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ms-MY.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..ab0b7fd7daac13b4b7c14b4d18eeca711394c64e --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json @@ -0,0 +1,13 @@ +{ + "Additional_emails" : "Extra e-mails", + "Body" : "Body", + "Choose_messages" : "Kies berichten", + "From" : "Afzender", + "Mail_Message_Missing_to" : "U moet een of meer gebruikers selecteren of één of meer e-mailadressen invullen, gescheiden door komma's.", + "Mail_Message_No_messages_selected_select_all" : "Je hebt geen bericten geslecteerd. Zou je <a href='#' class='select-all'>alle zichtbare berichten</a> willen selecteren?", + "Mail_Messages" : "Mailberichten", + "Sending" : "Verzenden ...", + "Subject" : "Onderwerp", + "To_users" : "Aan Gebruikers", + "Your_email_has_been_queued_for_sending" : "Uw e-mail staat in de wachtrij voor het verzenden" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..ba59cee84fe5cdfc13b736527ef1125f7ae8811d --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json @@ -0,0 +1,4 @@ +{ + "Choose_messages" : "Wybierz wiadomoÅ›ci", + "Mail_Messages" : "WysyÅ‚anie wiadomoÅ›ci przez email" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/pt.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/pt.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ro.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..a51eb8444692ecfe7d72a9f72aeaccace8df4e97 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ro.i18n.json @@ -0,0 +1,16 @@ +{ + "Additional_emails" : "E-mail-uri suplimentare", + "Body" : "Corp", + "Choose_messages" : "Alege mesaje", + "From" : "De la", + "Mail_Message_Invalid_emails" : "AÈ›i furnizat unul sau mai multe e-mailuri invalide: %s", + "Mail_Message_Missing_to" : "Trebuie să furnizaÈ›i una sau mai multe adrese de e-mail pentru 'Către', separate prin virgulă.", + "Mail_Message_No_messages_selected_select_all" : "Nu aÈ›i selectat niciun mesaj. AÅ£i dori să <a href='#' class='select-all'>selctaÈ›i toate</a> mesajele vizibile?", + "Mail_Messages" : "Mesaje Email", + "Mail_Messages_Instructions" : "AlegeÈ›i ce mesaje doriÈ›i să trimiteÈ›i prin e-mail făcând clic pe ele", + "Mail_Messages_Subject" : "Iată o parte din %s mesaje", + "Sending" : "Se trimite ...", + "Subject" : "Subiect", + "To_users" : "Către utilizatori", + "Your_email_has_been_queued_for_sending" : "Emailul dumneavoastră a fost pus pe lista de trimis" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..3cb700b27ab69f66d6cac571cbfd81679864541e --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json @@ -0,0 +1,4 @@ +{ + "Mail_Message_Missing_to" : "Ð’Ñ‹ должны выбрать одного или неÑкольких пользователей или указать один или неÑколько адреÑов Ñлектронной почты, разделенных запÑтыми.", + "To_users" : "ПользователÑм" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/sq.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/sq.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/sr.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/sv.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/sv.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ta-IN.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ta-IN.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/tr.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/tr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ug.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ug.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/uk.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/uk.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/zh.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/zh.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/package.js b/packages/rocketchat-channel-settings-mail-messages/package.js new file mode 100644 index 0000000000000000000000000000000000000000..76b23988382597a520d55b8e1b96bd5c653fab16 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -0,0 +1,50 @@ +Package.describe({ + name: 'rocketchat:channel-settings-mail-messages', + version: '0.0.1', + summary: 'Channel Settings - Mail Messages', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'templating', + 'reactive-var', + 'less@2.5.0', + 'rocketchat:lib', + 'rocketchat:channel-settings', + 'momentjs:moment' + ]); + + api.addFiles([ + 'client/lib/startup.coffee', + 'client/stylesheets/mail-messages.less', + 'client/views/channelSettingsMailMessages.html', + 'client/views/channelSettingsMailMessages.coffee', + 'client/views/mailMessagesInstructions.html', + 'client/views/mailMessagesInstructions.coffee' + ], 'client'); + + + api.addFiles([ + 'server/lib/startup.coffee', + 'server/methods/mailMessages.coffee' + ], 'server'); + + // TAPi18n + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-channel-settings-mail-messages/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-channel-settings-mail-messages/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-channel-settings-mail-messages/server/lib/startup.coffee b/packages/rocketchat-channel-settings-mail-messages/server/lib/startup.coffee new file mode 100644 index 0000000000000000000000000000000000000000..0a30dd195e4989f195fef4b0592e907b3bf0fda7 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/server/lib/startup.coffee @@ -0,0 +1,3 @@ +Meteor.startup -> + permission = { _id: 'mail-messages', roles : [ 'admin' ] } + RocketChat.models.Permissions.upsert( permission._id, { $setOnInsert : permission }) diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee new file mode 100644 index 0000000000000000000000000000000000000000..f1c07f4bb78ea7f1a2aa7b7d6ef6a8bed332aad4 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -0,0 +1,57 @@ +Meteor.methods + 'mailMessages': (data) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] mailMessages -> Invalid user") + + check(data, Match.ObjectIncluding({ rid: String, to_users: [ String ], to_emails: String, subject: String, messages: [ String ], language: String })) + + room = Meteor.call 'canAccessRoom', data.rid, Meteor.userId() + unless room + throw new Meteor.Error('invalid-room', "[methods] mailMessages -> Invalid room") + + unless RocketChat.authz.hasPermission(Meteor.userId(), 'mail-messages') + throw new Meteor.Error 'not-authorized' + + rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/ + + emails = _.compact(data.to_emails.trim().split(',')) + missing = [] + if data.to_users.length > 0 + for username in data.to_users + user = RocketChat.models.Users.findOneByUsername(username) + if user?.emails?[0]?.address + emails.push user.emails[0].address + else + missing.push username + console.log emails + for email in emails + unless rfcMailPatternWithName.test email.trim() + throw new Meteor.Error('invalid-email', "[methods] mailMessages -> Invalid e-mail #{email}") + + user = Meteor.user() + name = user.name + email = user.emails?[0]?.address + + data.language = data.language.split('-').shift().toLowerCase() + + if data.language isnt 'en' + localeFn = Meteor.call 'loadLocale', data.language + if localeFn + Function(localeFn)() + + html = "" + RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) -> + dateTime = moment(message.ts).locale(data.language).format('L LT') + html += "<p style='margin-bottom: 5px'><b>#{message.u.username}</b> <span style='color: #aaa; font-size: 12px'>#{dateTime}</span><br />" + RocketChat.Message.parse(message, data.language) + "</p>" + + Meteor.defer -> + Email.send + to: emails + from: RocketChat.settings.get('From_Email') + replyTo: email + subject: data.subject + html: html + + console.log 'Sending email to ' + emails.join(', ') + + return { success: true, missing: missing } diff --git a/packages/rocketchat-channel-settings/client/lib/ChannelSettings.coffee b/packages/rocketchat-channel-settings/client/lib/ChannelSettings.coffee new file mode 100644 index 0000000000000000000000000000000000000000..f9322fbb446e609e226c5cb24962ee35d1bccf81 --- /dev/null +++ b/packages/rocketchat-channel-settings/client/lib/ChannelSettings.coffee @@ -0,0 +1,29 @@ +RocketChat.ChannelSettings = new class + options = new ReactiveVar {} + + ### + # Adds an option in Channel Settings + # @config (object) + # id: option id (required) + # template (string): template name to render (required) + # validation (function): if option should be displayed + ### + addOption = (config) -> + unless config?.id + throw new Meteor.Error "ChannelSettings-addOption-error", "Option id was not informed." + + Tracker.nonreactive -> + opts = options.get() + opts[config.id] = config + options.set opts + + getOptions = -> + allOptions = _.toArray options.get() + allowedOptions = _.compact _.map allOptions, (option) -> + if not option.validation? or option.validation() + return option + + return _.sortBy allowedOptions, 'order' + + addOption: addOption + getOptions: getOptions diff --git a/packages/rocketchat-channel-settings/client/startup/tabBar.coffee b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee index 17d1680317e5f51238544bf6c4a08cc9e7a6cc61..0381dcf755f790744300c330195adc650d9a7c25 100644 --- a/packages/rocketchat-channel-settings/client/startup/tabBar.coffee +++ b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee @@ -1,12 +1,8 @@ Meteor.startup -> - - RocketChat.callbacks.add 'enter-room', (subscription) -> - - if RocketChat.authz.hasAtLeastOnePermission('edit-room', subscription?.rid) - RocketChat.TabBar.addButton - id: 'channel-settings' - i18nTitle: 'Channel_Settings' - icon: 'octicon octicon-gear' - template: 'channelSettings' - order: 0 - , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-channel-settings' + RocketChat.TabBar.addButton + groups: ['channel', 'privategroup', 'directmessage'] + id: 'channel-settings' + i18nTitle: 'Room_Info' + icon: 'octicon octicon-info' + template: 'channelSettings' + order: 0 diff --git a/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee b/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee index b3618dd7232e96c9c775de28896c58df47feef05..4594215267d1c7eb2488293012ac53e6ae23b7f5 100644 --- a/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee +++ b/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee @@ -13,3 +13,15 @@ Meteor.startup -> return msg RocketChat.callbacks.add 'streamMessage', roomSettingsChangedCallback, RocketChat.callbacks.priority.HIGH + + roomNameChangedCallback = (msg) -> + Tracker.nonreactive -> + if msg.t is 'r' + if Session.get('openedRoom') is msg.rid + type = if FlowRouter.current().route.name is 'channel' then 'c' else 'p' + RoomManager.close type + FlowRouter.getParam('name') + FlowRouter.go FlowRouter.current().route.name, name: msg.msg + + return msg + + RocketChat.callbacks.add 'streamMessage', roomNameChangedCallback, RocketChat.callbacks.priority.HIGH diff --git a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less index 0227c11170d8da36077c2baffa8c113f2edd2ce1..872c1a7331835eeff8df795a9fd45e08f4bbb968 100644 --- a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less +++ b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less @@ -1,11 +1,25 @@ .flex-tab { .channel-settings { - margin-top: 60px; - padding: 20px; + ul { + li { + margin-bottom: 20px; + } + } form { label { + display: block; + font-weight: bold; + margin-bottom: 5px; + } + div span { + font-size: 14px; + i.octicon { + font-size: 12px; + vertical-align: middle; + margin-left: 3px; + } } } @@ -13,5 +27,9 @@ margin-top: 30px; text-align: center; } + + [data-edit] { + cursor: pointer; + } } } diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 4f9f5d344c5d991fad19f382913407cb7ea7e37b..30529f9a8091ef7ff082cd6366ad5b25e14989ea 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -1,23 +1,109 @@ Template.channelSettings.helpers + canEdit: -> + return RocketChat.authz.hasAllPermission('edit-room', @rid) + editing: (field) -> + return Template.instance().editing.get() is field notDirect: -> return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> return ChatRoom.findOne(@rid)?.t + channelSettings: -> + return RocketChat.ChannelSettings.getOptions() + roomTypeDescription: -> + roomType = ChatRoom.findOne(@rid)?.t + if roomType is 'c' + return t('Channel') + else if roomType is 'p' + return t('Private_Group') + roomName: -> + return ChatRoom.findOne(@rid)?.name + roomTopic: -> + return ChatRoom.findOne(@rid)?.topic + archived: -> + return ChatRoom.findOne(@rid)?.archived Template.channelSettings.events + 'keydown input[type=text]': (e, t) -> + if e.keyCode is 13 + e.preventDefault() + t.saveSetting() + + 'click [data-edit]': (e, t) -> + e.preventDefault() + t.editing.set($(e.currentTarget).data('edit')) + setTimeout (-> t.$('input.editing').focus().select()), 100 + + 'click .cancel': (e, t) -> + e.preventDefault() + t.editing.set() + 'click .save': (e, t) -> e.preventDefault() + t.saveSetting() + + 'click .archive': (e, t) -> + e.preventDefault() + + Meteor.call 'archiveRoom', t.data.rid, true, (err, results) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__ 'Room_archived' - settings = - roomType: t.$('input[name=roomType]:checked').val() + 'click .unarchive': (e, t) -> + e.preventDefault() - Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> + Meteor.call 'unarchiveRoom', t.data.rid, true, (err, results) -> return toastr.error err.reason if err - toastr.success TAPi18n.__ 'Settings_updated' + toastr.success TAPi18n.__ 'Room_unarchived' + +Template.channelSettings.onCreated -> + @editing = new ReactiveVar + + @validateRoomType = => + type = @$('input[name=roomType]:checked').val() + if type not in ['c', 'p'] + toastr.error t('Invalid_room_type', type) + return true + + @validateRoomName = => + rid = Template.currentData()?.rid + room = ChatRoom.findOne rid + + if not RocketChat.authz.hasAllPermission('edit-room', @rid) or room.t not in ['c', 'p'] + toastr.error t('Not_allowed') + return false + + name = $('input[name=roomName]').val() + if not /^[0-9a-z-_]+$/.test name + toastr.error t('Invalid_room_name', name) + return false + + return true + @validateRoomTopic = => + return true - # switch room.t - # when 'c' - # FlowRouter.go 'channel', name: name - # when 'p' - # FlowRouter.go 'group', name: name + @saveSetting = => + switch @editing.get() + when 'roomName' + if @validateRoomName() + Meteor.call 'saveRoomSettings', @data?.rid, 'roomName', @$('input[name=roomName]').val(), (err, result) -> + if err + if err.error in [ 'duplicate-name', 'name-invalid' ] + return toastr.error TAPi18n.__(err.reason, err.details.channelName) + return toastr.error TAPi18n.__(err.reason) + toastr.success TAPi18n.__ 'Room_name_changed_successfully' + when 'roomTopic' + if @validateRoomTopic() + Meteor.call 'saveRoomSettings', @data?.rid, 'roomTopic', @$('input[name=roomTopic]').val(), (err, result) -> + if err + return toastr.error TAPi18n.__(err.reason) + toastr.success TAPi18n.__ 'Room_topic_changed_successfully' + when 'roomType' + if @validateRoomType() + Meteor.call 'saveRoomSettings', @data?.rid, 'roomType', @$('input[name=roomType]:checked').val(), (err, result) -> + if err + if err.error is 'invalid-room-type' + return toastr.error TAPi18n.__(err.reason, err.details.roomType) + return toastr.error TAPi18n.__(err.reason) + toastr.success TAPi18n.__ 'Room_type_changed_successfully' + @editing.set() diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index c72ecae4ad66d4f22d6ecb136fc607766b3e11ab..8a326bd49117b25d98d02235dbe8fc83efd3ea35 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -1,25 +1,63 @@ <template name="channelSettings"> - <div class="control"> - <div class="header"> - <h2>{{_ "Room_Settings"}}</h2> - </div> - </div> - <div class="channel-settings scrollable"> - <form> - <fieldset> - {{#if notDirect}} - <div class="input-line double-col"> - <label>{{_ "Room_Type"}}</label> + <div class="content"> + <div class="list-view channel-settings"> + <div class="status"> + <h2>{{_ "Room_Info"}}</h2> + </div> + <form> + <ul class="list clearfix"> + {{#if notDirect}} + <li> + <label>{{_ "Name"}}</label> + <div> + {{#if editing 'roomName'}} + <input type="text" name="roomName" value="{{roomName}}" class="editing" /> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button> + {{else}} + <span>{{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomName"></i>{{/if}}</span> + {{/if}} + </div> + </li> + {{/if}} + <li> + <label>{{_ "Topic"}}</label> <div> - <label><input type="radio" name="roomType" value="c" checked="{{$eq roomType 'c'}}" /> {{_ "Channel"}}</label> - <label><input type="radio" name="roomType" value="p" checked="{{$eq roomType 'p'}}" /> {{_ "Private_Group"}}</label> + {{#if editing 'roomTopic'}} + <input type="text" name="roomTopic" value="{{roomTopic}}" class="editing" /> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button> + {{else}} + <span>{{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomTopic"></i>{{/if}}</span> + {{/if}} </div> - </div> - {{/if}} - </fieldset> - <div class="submit"> - <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> - </div> - </form> + </li> + {{#if notDirect}} + <li> + <label>{{_ "Type"}}</label> + <div> + {{#if editing 'roomType'}} + <label><input type="radio" name="roomType" class="editing" value="c" checked="{{$eq roomType 'c'}}" /> {{_ "Channel"}}</label> + <label><input type="radio" name="roomType" value="p" checked="{{$eq roomType 'p'}}" /> {{_ "Private_Group"}}</label> + <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> + <button type="button" class="button primary save">{{_ "Save"}}</button> + {{else}} + <span>{{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomType"></i>{{/if}}</span> + {{/if}} + </div> + </li> + {{/if}} + {{#if notDirect}} + <li> + <label>{{_ "Archive_Unarchive"}}</label> + {{#if archived}} + <button class="button unarchive"><span>{{_ "Unarchive"}}</span></button> + {{else}} + <button class="button archive"><span>{{_ "Archive"}}</span></button> + {{/if}} + </li> + {{/if}} + {{#each channelSettings}} + {{> Template.dynamic template=template data=data}} + {{/each}} + </ul> + </form> + </div> </div> </template> diff --git a/packages/rocketchat-channel-settings/i18n/ar.i18n.json b/packages/rocketchat-channel-settings/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..5f097c9f5662c2a8c494b36aba45d2682910f13b 100644 --- a/packages/rocketchat-channel-settings/i18n/ar.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ar.i18n.json @@ -1 +1,13 @@ -{ } \ No newline at end of file +{ + "Archive_Unarchive" : "أرشÙØ©/إلغاء الأرشÙØ©", + "Channel" : "قناة", + "Private_Group" : "مجموعة خاصة", + "Save" : "ØÙظ", + "Topic" : "الموضوع", + "Type" : "النوع", + "Room_Info" : "معلومات الغرÙØ©", + "room_changed_privacy" : "تم تغيير نوع الغرÙØ© إلى: <em>__room_type__</em> بواسطة <em>__user_by__</em>", + "room_changed_topic" : "تم تغيير موضوع الغرÙØ© إلى: <em>__room_topic__</em> بواسطة <em>__user_by__</em>", + "Room_topic_changed_successfully" : "تغيير موضوع الغرÙØ© بنجاØ", + "Room_type_changed_successfully" : "تم تغيير نوع الغرÙØ© بنجاØ" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/cs.i18n.json b/packages/rocketchat-channel-settings/i18n/cs.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..84eb3ce32fd3bf86f83bacec57592ef2c02834a6 100644 --- a/packages/rocketchat-channel-settings/i18n/cs.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/cs.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Uložit" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/de.i18n.json b/packages/rocketchat-channel-settings/i18n/de.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..05456b08e2c3027f8d7092fdd6e7fce4605b4579 100644 --- a/packages/rocketchat-channel-settings/i18n/de.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/de.i18n.json @@ -1 +1,13 @@ -{ } \ No newline at end of file +{ + "Archive_Unarchive" : "Archivieren / Wiederherstellen", + "Channel" : "Kanal", + "Private_Group" : "Private Gruppe", + "Save" : "Speichern", + "Topic" : "Thema", + "Type" : "Typ", + "Room_Info" : "Raum", + "room_changed_privacy" : "Der Raum wurde von <em>__user_by__</em> zum/r <em>__room_type__</em> geändert.", + "room_changed_topic" : "Das Thema des Raums wurde von <em>__user_by__</em> zu <em>__room_topic__</em> geändert.", + "Room_topic_changed_successfully" : "Das Thema des Raums wurde erfolgreich geändert.", + "Room_type_changed_successfully" : "Der Raumtyp wurde erfolgreich geändert." +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/el.i18n.json b/packages/rocketchat-channel-settings/i18n/el.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..8fe65b233818b01708c5b9c246d5ae5e3e7802f3 100644 --- a/packages/rocketchat-channel-settings/i18n/el.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/el.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Αποθήκευση" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index 3d4dda12e16da9238fc1f18adf40e503e6355d7a..7fa82c45dcbbfa018c5c71972d23202fc3bdd7c5 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,8 +1,13 @@ { + "Archive_Unarchive" : "Archive / Unarchive", "Channel" : "Channel", "Private_Group" : "Private Group", - "Room_Type" : "Room Type", - "Room_Settings" : "Room Settings", + "Save" : "Save", + "Topic" : "Topic", + "Type" : "Type", + "Room_Info" : "Room Info", "room_changed_privacy" : "Room type changed to: <em>__room_type__</em> by <em>__user_by__</em>", - "room_changed_topic" : "Room topic changed to: <em>__room_topic__</em> by <em>__user_by__</em>" + "room_changed_topic" : "Room topic changed to: <em>__room_topic__</em> by <em>__user_by__</em>", + "Room_topic_changed_successfully" : "Room topic changed successfully", + "Room_type_changed_successfully" : "Room type changed successfully" } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/es.i18n.json b/packages/rocketchat-channel-settings/i18n/es.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..05a125952ddf75c6d3713c92e893b4f71702c53c 100644 --- a/packages/rocketchat-channel-settings/i18n/es.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/es.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Guardar" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/fi.i18n.json b/packages/rocketchat-channel-settings/i18n/fi.i18n.json index ba9ae6c0008e97ce45f36604c628821967fd3187..578c094a27a4fa584c3934f44a2b94e1d1a732de 100644 --- a/packages/rocketchat-channel-settings/i18n/fi.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/fi.i18n.json @@ -1,8 +1,13 @@ { + "Archive_Unarchive" : "Arkistoi / palauta arkistosta", "Channel" : "Kanava", "Private_Group" : "Privaattiryhmä", - "Room_Type" : "Huoneen tyyppi", - "Room_Settings" : "Huoneen asetukset", + "Save" : "Tallenna", + "Topic" : "Aihe", + "Type" : "Tyyppi", + "Room_Info" : "Huoneen info", "room_changed_privacy" : "Huoneen tyyppi vaihdettu <em>__room_type__</em> käyttäjän <em>__user_by__</em> toimesta", - "room_changed_topic" : "Huoneen aihe vaihdettu <em>__room_topic__</em> käyttäjän <em>__user_by__</em> toimesta" + "room_changed_topic" : "Huoneen aihe vaihdettu <em>__room_topic__</em> käyttäjän <em>__user_by__</em> toimesta", + "Room_topic_changed_successfully" : "Huoneen aihe vaihdettu", + "Room_type_changed_successfully" : "Huoneen tyyppi vaihdettu" } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/fr.i18n.json b/packages/rocketchat-channel-settings/i18n/fr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..0e4908b96a1840117e148840bcfbe949719bc9e6 100644 --- a/packages/rocketchat-channel-settings/i18n/fr.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/fr.i18n.json @@ -1 +1,13 @@ -{ } \ No newline at end of file +{ + "Archive_Unarchive" : "Archiver / Désarchiver", + "Channel" : "Canal", + "Private_Group" : "Groupe privé", + "Save" : "Enregistrer", + "Topic" : "Sujet", + "Type" : "Type", + "Room_Info" : "Infos sur le salon", + "room_changed_privacy" : "Type du salon changé pour : <em>__room_type__</em> par <em>__user_by__</em>", + "room_changed_topic" : "Sujet du salon changé pour : <em>__room_topic__</em> by <em>__user_by__</em>", + "Room_topic_changed_successfully" : "Sujet du salon changé avec succès", + "Room_type_changed_successfully" : "Type de salon modifié avec succès" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/he.i18n.json b/packages/rocketchat-channel-settings/i18n/he.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..68f6f6ea7b8ffeb93add18059c6408310d136299 100644 --- a/packages/rocketchat-channel-settings/i18n/he.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/he.i18n.json @@ -1 +1,10 @@ -{ } \ No newline at end of file +{ + "Channel" : "ערוץ", + "Private_Group" : "קבוצה פרטית", + "Save" : "שמירה", + "Topic" : "× ×•×©×", + "Type" : "סוג", + "Room_Info" : "פרטי החדר", + "Room_topic_changed_successfully" : "× ×•×©× ×”×—×“×¨ ×©×•× ×” בהצלחה", + "Room_type_changed_successfully" : "סוג החדר ×©×•× ×” בהצלחה" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/hr.i18n.json b/packages/rocketchat-channel-settings/i18n/hr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..3ee66adf8f1d484d9204bf61fd6f5e6c35161388 100644 --- a/packages/rocketchat-channel-settings/i18n/hr.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/hr.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Archive_Unarchive" : "Arhiviraj / Dearhiviraj", + "Private_Group" : "Privatna Grupa", + "Save" : "SaÄuvaj", + "Type" : "Vrsta" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/hu.i18n.json b/packages/rocketchat-channel-settings/i18n/hu.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..f9fac2321e01af9b6198ace4523c6726294586ab 100644 --- a/packages/rocketchat-channel-settings/i18n/hu.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/hu.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Mentés" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/it.i18n.json b/packages/rocketchat-channel-settings/i18n/it.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..48008e60a7dd308345a23013d476c2e7a8d9623e 100644 --- a/packages/rocketchat-channel-settings/i18n/it.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/it.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Salva" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ja.i18n.json b/packages/rocketchat-channel-settings/i18n/ja.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..70cdb7bff67d54f64c0a9c94c0fd863c34d25608 100644 --- a/packages/rocketchat-channel-settings/i18n/ja.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ja.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "ä¿å˜" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/km.i18n.json b/packages/rocketchat-channel-settings/i18n/km.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..598c01accce2c59cbb52ceedadc9e63a1bcf04e8 100644 --- a/packages/rocketchat-channel-settings/i18n/km.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/km.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Channel" : "ប៉ុស្ážáž·áŸ", + "Private_Group" : "ក្រុម​ឯកជន", + "Save" : "រក្សាទុក" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ko.i18n.json b/packages/rocketchat-channel-settings/i18n/ko.i18n.json index dc45aca964f9600eddad3957b45132488d8299a4..3c26cdb50935b8bf2cbde763085319d4edbd4e6d 100644 --- a/packages/rocketchat-channel-settings/i18n/ko.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ko.i18n.json @@ -1,8 +1,7 @@ { "Channel" : "채ë„", - "Private_Group" : "ê°œì¸ ê·¸ë£¹", - "Room_Type" : "ë°© 종류", - "Room_Settings" : "ë°© ì„¤ì •", + "Private_Group" : "비밀 그룹", + "Save" : "ì €ìž¥", "room_changed_privacy" : "ë°© 종류가 <em>__user_by__</em>ì—서 <em>__room_type__</em>ë¡œ 변경ë˜ì—ˆìŠµë‹ˆë‹¤.", "room_changed_topic" : "ë°© ì£¼ì œê°€Â <em>__user_by__</em>ì—서 <em>__room_topic__</em>ë¡œ 변경ë˜ì—ˆìŠµë‹ˆë‹¤." } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ku.i18n.json b/packages/rocketchat-channel-settings/i18n/ku.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..5647eb663afa42df873882847dbb3d06dee2a4da 100644 --- a/packages/rocketchat-channel-settings/i18n/ku.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ku.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "پاشەکەوت" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json b/packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..c672c3727d8c51951e6e1e77048bbca1510c703d 100644 --- a/packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Simpan" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/nl.i18n.json b/packages/rocketchat-channel-settings/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..80b675a4377832ac8ff97b91e91d416a4f6c2006 100644 --- a/packages/rocketchat-channel-settings/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/nl.i18n.json @@ -1 +1,11 @@ -{ } \ No newline at end of file +{ + "Archive_Unarchive" : "Archief / Uit archief", + "Channel" : "Kanaal", + "Private_Group" : "Privé-groep", + "Save" : "Bewaren", + "Topic" : "Onderwerp", + "Type" : "Type", + "Room_Info" : "Kamer info", + "Room_topic_changed_successfully" : "Kamer onderwerp succesvol gewijzigd", + "Room_type_changed_successfully" : "Kamertype met succes gewijzigd" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/pl.i18n.json b/packages/rocketchat-channel-settings/i18n/pl.i18n.json index f93465d0f99a65709e2769fca20a31ac0348626b..8200c8c1f595a08debf524a53d30ba7a668c4b3f 100644 --- a/packages/rocketchat-channel-settings/i18n/pl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/pl.i18n.json @@ -1,8 +1,12 @@ { + "Archive_Unarchive" : "Przeniesienie do archiwum", "Channel" : "KanaÅ‚", "Private_Group" : "Grupa Prywatna", - "Room_Type" : "Rodzaj pokoju", - "Room_Settings" : "Ustawienia pokoju", + "Save" : "Zapisz", + "Topic" : "Temat", + "Type" : "Rodzaj", + "Room_Info" : "Ustawienia pokoju", "room_changed_privacy" : "<em>__user_by__</em> zmieniÅ‚(a) rodzaj pokoju na: <em>__room_type__</em>", - "room_changed_topic" : "<em>__user_by__</em> zmieniÅ‚(a) temat pokoju na: <em>__room_topic__</em>" + "room_changed_topic" : "<em>__user_by__</em> zmieniÅ‚(a) temat pokoju na: <em>__room_topic__</em>", + "Room_topic_changed_successfully" : "Temat pokoju zostaÅ‚ zmieniony" } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/pt.i18n.json b/packages/rocketchat-channel-settings/i18n/pt.i18n.json index f9d1b2c38ccf01f824d5f21b433ec0b805cba3ac..e41c8a68b54079d32238da76ab2e144095a48f52 100644 --- a/packages/rocketchat-channel-settings/i18n/pt.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/pt.i18n.json @@ -1,6 +1,5 @@ { "Channel" : "Canal", "Private_Group" : "Grupo Privado", - "Room_Type" : "Tipo de sala", - "Room_Settings" : "Configurações da Sala" + "Save" : "Salvar" } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ro.i18n.json b/packages/rocketchat-channel-settings/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..f730f467410be933be53c7a85c360ef985b0264f --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ro.i18n.json @@ -0,0 +1,13 @@ +{ + "Archive_Unarchive" : "Arhivează / Dezarhivează", + "Channel" : "Canal", + "Private_Group" : "Grup privat", + "Save" : "Salvează", + "Topic" : "Subiect", + "Type" : "Tip", + "Room_Info" : "Info cameră", + "room_changed_privacy" : "Tipul camerei schimbat în: <em>__room_type__</em> de către <em>__user_by__</em>", + "room_changed_topic" : "Subiectul camerei schimbat în: <em>__room_topic__</em> de către <em>__user_by__</em>", + "Room_topic_changed_successfully" : "Subiectul camerei a fost schimbat cu succes.", + "Room_type_changed_successfully" : "Tipul de cameră a fost schimbat cu succes" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ru.i18n.json b/packages/rocketchat-channel-settings/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..99a76b5c0d7db6d52b44433ae2d27962d2f12b43 100644 --- a/packages/rocketchat-channel-settings/i18n/ru.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ru.i18n.json @@ -1 +1,9 @@ -{ } \ No newline at end of file +{ + "Archive_Unarchive" : "Удалить / ВоÑÑтановить", + "Save" : "Сохранить", + "Topic" : "Тема", + "Type" : "Тип", + "room_changed_privacy" : "Тип чата изменен на: <em>__room_type__</em> by <em>__user_by__</em>", + "Room_topic_changed_successfully" : "Тема чата уÑпешно изменена", + "Room_type_changed_successfully" : "Тип чата уÑпешно изменен" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/sq.i18n.json b/packages/rocketchat-channel-settings/i18n/sq.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..b01a59cc8c1c69ffbcff4e8cc7847288eac34f22 100644 --- a/packages/rocketchat-channel-settings/i18n/sq.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/sq.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Ruaj" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/sr.i18n.json b/packages/rocketchat-channel-settings/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..dabebdbb00a1a9747ffd90bffe5a9d083edfadf9 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/sr.i18n.json @@ -0,0 +1,3 @@ +{ + "Save" : "Сачувај" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/sv.i18n.json b/packages/rocketchat-channel-settings/i18n/sv.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..7bc9d5f5301627b9b75bf2caa789874a33ed6ec6 100644 --- a/packages/rocketchat-channel-settings/i18n/sv.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/sv.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Spara" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ta-IN.i18n.json b/packages/rocketchat-channel-settings/i18n/ta-IN.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..9a9ac953658e09a14c6ceaa86e434da65066c643 100644 --- a/packages/rocketchat-channel-settings/i18n/ta-IN.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ta-IN.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "சேமி" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/tr.i18n.json b/packages/rocketchat-channel-settings/i18n/tr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..17b9fac70d281ea1fa9090c4ce67a72bc1f7ec7f 100644 --- a/packages/rocketchat-channel-settings/i18n/tr.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/tr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Kaydet" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/ug.i18n.json b/packages/rocketchat-channel-settings/i18n/ug.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..54117dbd0a54a794770392fe7a6150d54a5ccbf7 100644 --- a/packages/rocketchat-channel-settings/i18n/ug.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ug.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "ساقلاش" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/uk.i18n.json b/packages/rocketchat-channel-settings/i18n/uk.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..73f4e68da7668356f36d635b8dc2bfd042497323 100644 --- a/packages/rocketchat-channel-settings/i18n/uk.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/uk.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "Зберегти" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/zh.i18n.json b/packages/rocketchat-channel-settings/i18n/zh.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..70cdb7bff67d54f64c0a9c94c0fd863c34d25608 100644 --- a/packages/rocketchat-channel-settings/i18n/zh.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/zh.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Save" : "ä¿å˜" +} \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 06b8f3fe128ac6140841c36bb2827c5a803c48f6..a551aa5cde919f05b295b32b0f6db009a83c8bb1 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -10,12 +10,15 @@ Package.onUse(function(api) { api.use([ 'coffeescript', + 'reactive-var', + 'tracker', 'templating', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ + 'client/lib/ChannelSettings.coffee', 'client/startup/messageTypes.coffee', 'client/startup/tabBar.coffee', 'client/startup/trackSettingsChange.coffee', @@ -25,7 +28,9 @@ Package.onUse(function(api) { ], 'client'); api.addFiles([ - 'server/functions/changeRoomType.coffee', + 'server/functions/saveRoomType.coffee', + 'server/functions/saveRoomTopic.coffee', + 'server/functions/saveRoomName.coffee', 'server/methods/saveRoomSettings.coffee', 'server/models/Messages.coffee' ], 'server'); @@ -38,8 +43,7 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1'); - api.imply('tap:i18n'); + api.use('tap:i18n'); api.addFiles(tapi18nFiles); }); diff --git a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee b/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee deleted file mode 100644 index e9c89567302e183d11b51dec04818c0dacdde7c5..0000000000000000000000000000000000000000 --- a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee +++ /dev/null @@ -1,47 +0,0 @@ -RocketChat.changeRoomType = (rid, roomType) -> - console.log '[function] RocketChat.changeRoomType'.green, rid, roomType - - unless Match.test rid, String - throw new Meteor.Error 'invalid-rid' - - if roomType not in ['c', 'p'] - throw new Meteor.Error 'invalid-room-type' - - return RocketChat.models.Rooms.setTypeById(rid, roomType) and RocketChat.models.Subscriptions.updateTypeByRoomId(rid, roomType) - - - # username = s.trim username - # if not user or not username - # return false - - # if not /^[0-9a-zA-Z-_.]+$/.test username - # return false - - # # User already has desired username, return - # if user.username is username - # return user - - # # Check username availability - # unless RocketChat.checkUsernameAvailability username - # return false - - # previousUsername = user.username - - # # Username is available; if coming from old username, update all references - # if previousUsername - # RocketChat.models.Messages.updateAllUsernamesByUserId user._id, username - - # RocketChat.models.Messages.findByMention(previousUsername).forEach (msg) -> - # updatedMsg = msg.msg.replace(new RegExp("@#{previousUsername}", "ig"), "@#{username}") - # RocketChat.models.Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername msg._id, previousUsername, username, updatedMsg - - # RocketChat.models.Rooms.replaceUsername previousUsername, username - # RocketChat.models.Rooms.replaceUsernameOfUserByUserId user._id, username - - # RocketChat.models.Subscriptions.setUserUsernameByUserId user._id, username - # RocketChat.models.Subscriptions.setNameForDirectRoomsWithOldName previousUsername, username - - # # Set new username - # Meteor.users.update { _id: user._id }, { $set: { username: username } } - # user.username = username - # return user diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomName.coffee b/packages/rocketchat-channel-settings/server/functions/saveRoomName.coffee new file mode 100644 index 0000000000000000000000000000000000000000..9833b88764b271b3dadbae28f68b7ddce0041ec6 --- /dev/null +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomName.coffee @@ -0,0 +1,29 @@ +RocketChat.saveRoomName = (rid, name) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] sendMessage -> Invalid user") + + room = RocketChat.models.Rooms.findOneById rid + + if room.t not in ['c', 'p'] + throw new Meteor.Error 403, 'Not allowed' + + unless RocketChat.authz.hasPermission(Meteor.userId(), 'edit-room', rid) + #if room.u._id isnt Meteor.userId() and not hasPermission + throw new Meteor.Error 403, 'Not allowed' + + if not /^[0-9a-z-_]+$/.test name + throw new Meteor.Error 'name-invalid', 'Invalid_room_name', { channelName: name } + + name = _.slugify name + + if name is room.name + return + + # avoid duplicate names + if RocketChat.models.Rooms.findOneByName name + throw new Meteor.Error 'duplicate-name', 'Duplicate_channel_name', { channelName: name } + + RocketChat.models.Rooms.setNameById rid, name + RocketChat.models.Subscriptions.updateNameByRoomId rid, name + + return name diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee b/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee new file mode 100644 index 0000000000000000000000000000000000000000..6f3a7f24020e4c8335184157a1ec0135be872cac --- /dev/null +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee @@ -0,0 +1,5 @@ +RocketChat.saveRoomTopic = (rid, roomTopic) -> + unless Match.test rid, String + throw new Meteor.Error 'invalid-rid' + + return RocketChat.models.Rooms.setTopicById(rid, roomTopic) diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee b/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d990a4b3aeeb2ccd84f219f8573eccd8278175c9 --- /dev/null +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee @@ -0,0 +1,8 @@ +RocketChat.saveRoomType = (rid, roomType) -> + unless Match.test rid, String + throw new Meteor.Error 'invalid-rid' + + if roomType not in ['c', 'p'] + throw new Meteor.Error 'invalid-room-type', 'Invalid_room_type', { roomType: roomType } + + return RocketChat.models.Rooms.setTypeById(rid, roomType) and RocketChat.models.Subscriptions.updateTypeByRoomId(rid, roomType) diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee index 6375bf5f289180ce9e3732a313febb8522c65e56..2b4d8f95e7873e0de8bd02eccbcc18bd4add98e0 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -1,26 +1,31 @@ Meteor.methods - saveRoomSettings: (rid, settings) -> - console.log '[method] saveRoomSettings'.green, rid, settings - + saveRoomSettings: (rid, setting, value) -> unless Match.test rid, String - throw new Meteor.Error 'invalid-rid' + throw new Meteor.Error 'invalid-rid', 'Invalid room' - unless Match.test settings, Match.ObjectIncluding { roomType: String } - throw new Meteor.Error 'invalid-settings' + if setting not in ['roomName', 'roomTopic', 'roomType'] + throw new Meteor.Error 'invalid-settings', 'Invalid settings provided' unless RocketChat.authz.hasPermission(Meteor.userId(), 'edit-room', rid) throw new Meteor.Error 503, 'Not authorized' room = RocketChat.models.Rooms.findOneById rid if room? - if settings.roomType isnt room.t - RocketChat.changeRoomType(rid, settings.roomType) - - if settings.roomType is 'c' - message = TAPi18n.__('Channel') - else - message = TAPi18n.__('Private_Group') - - RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_privacy', rid, message, Meteor.user() + switch setting + when 'roomName' + name = RocketChat.saveRoomName rid, value + RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser rid, name, Meteor.user() + when 'roomTopic' + if value isnt room.topic + RocketChat.saveRoomTopic(rid, value) + RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', rid, value, Meteor.user() + when 'roomType' + if value isnt room.t + RocketChat.saveRoomType(rid, value) + if value is 'c' + message = TAPi18n.__('Channel') + else + message = TAPi18n.__('Private_Group') + RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_privacy', rid, message, Meteor.user() return true diff --git a/packages/rocketchat-channel-settings/server/models/Messages.coffee b/packages/rocketchat-channel-settings/server/models/Messages.coffee index 0a8e900e45d40835d506b73c468240b2d9208a8c..9a72fcd32bb0dbabffc7287513ba36505240a9fa 100644 --- a/packages/rocketchat-channel-settings/server/models/Messages.coffee +++ b/packages/rocketchat-channel-settings/server/models/Messages.coffee @@ -1,2 +1,5 @@ RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser = (type, roomId, message, user, extraData) -> return @createWithTypeRoomIdMessageAndUser type, roomId, message, user, extraData + +RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser = (roomId, roomName, user, extraData) -> + return @createWithTypeRoomIdMessageAndUser 'r', roomId, roomName, user, extraData diff --git a/packages/rocketchat-chatops/client/tabBar.coffee b/packages/rocketchat-chatops/client/tabBar.coffee index 5daff0a8915cdbaf5a5ad42b1e2ef07df2d92794..c6e65f4895a7a7324019b30f03e47d2d9b7539b8 100644 --- a/packages/rocketchat-chatops/client/tabBar.coffee +++ b/packages/rocketchat-chatops/client/tabBar.coffee @@ -1,18 +1,9 @@ Meteor.startup -> - - RocketChat.callbacks.add 'enter-room', -> - #if Meteor.user()?.services?.github?.id or Meteor.user()?.services?.gitlab?.id - # console.log 'Adding chatops to tabbar' - # RocketChat.TabBar.addButton - # id: 'chatops-button' - # i18nTitle: 'rocketchat-chatops:Chatops_Title' - # icon: 'icon-code' - # template: 'chatops' - # order: 4 - + Tracker.autorun -> if RocketChat.settings.get('Chatops_Enabled') console.log 'Adding chatops to tabbar' RocketChat.TabBar.addButton + groups: ['channel', 'privategroup', 'directmessage'] id: 'chatops-button2' i18nTitle: 'rocketchat-chatops:Chatops_Title' icon: 'octicon octicon-hubot' @@ -21,10 +12,13 @@ Meteor.startup -> console.log 'Adding chatops to tabbar' RocketChat.TabBar.addButton + groups: ['channel', 'privategroup', 'directmessage'] id: 'chatops-button3' i18nTitle: 'rocketchat-chatops:Chatops_Title' icon: 'octicon octicon-inbox' template: 'chatops_droneflight' width: 675 order: 5 - , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-chatops' + else + RocketChat.TabBar.removeButton 'chatops-button2' + RocketChat.TabBar.removeButton 'chatops-button3' diff --git a/packages/rocketchat-chatops/i18n/de.i18n.json b/packages/rocketchat-chatops/i18n/de.i18n.json index 92a7ee53ca898e035c2156f30738da47bb329274..0bb37873b18de0c319cfcd3ea1c5399359385822 100644 --- a/packages/rocketchat-chatops/i18n/de.i18n.json +++ b/packages/rocketchat-chatops/i18n/de.i18n.json @@ -1,4 +1,5 @@ { - "Chatops_Enabled" : "Chatops aktivieren", - "Chatops_Username" : "Chatops Benutzername" + "Chatops_Enabled" : "ChatOps aktivieren", + "Chatops_Title" : "ChatOps-Panel", + "Chatops_Username" : "ChatOps-Benutzername" } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/fr.i18n.json b/packages/rocketchat-chatops/i18n/fr.i18n.json index 36d9014b31a06258d4c0d4e00eb925a754ef3644..c504b432ac9b0092462b82e5054abbd6433179d8 100644 --- a/packages/rocketchat-chatops/i18n/fr.i18n.json +++ b/packages/rocketchat-chatops/i18n/fr.i18n.json @@ -1,4 +1,5 @@ { "Chatops_Enabled" : "Activer Chatops", - "Chatops_Title" : "Panneau de contrôle des Chatops" + "Chatops_Title" : "Panneau de contrôle des Chatops", + "Chatops_Username" : "Nom d'utilisateur Chatops" } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ko.i18n.json b/packages/rocketchat-chatops/i18n/ko.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..8d0449b61f8563070a47a52da0d6f45dd3ebb24c 100644 --- a/packages/rocketchat-chatops/i18n/ko.i18n.json +++ b/packages/rocketchat-chatops/i18n/ko.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Chatops_Enabled" : "Cahtops 사용", + "Chatops_Title" : "Chatops 패ë„", + "Chatops_Username" : "Chatops ì‚¬ìš©ìž ì´ë¦„" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/nl.i18n.json b/packages/rocketchat-chatops/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..c4049dda949957b2d3f2c23f6145115aa762c3d9 100644 --- a/packages/rocketchat-chatops/i18n/nl.i18n.json +++ b/packages/rocketchat-chatops/i18n/nl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Chatops_Enabled" : "Chatops Inschakelen", + "Chatops_Title" : "Chatops Panel", + "Chatops_Username" : "Chatops Gebruikersnaam" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ro.i18n.json b/packages/rocketchat-chatops/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..62627119a9f934a79a984925609d4aa1c3338b7a --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ro.i18n.json @@ -0,0 +1,5 @@ +{ + "Chatops_Enabled" : "ActivaÈ›i Chatops", + "Chatops_Title" : "Chatops Panel", + "Chatops_Username" : "Nume de ultilizator Chatops" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/sr.i18n.json b/packages/rocketchat-chatops/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/package.js b/packages/rocketchat-chatops/package.js index 2b8585bce635164996c91a9f81b676c173c766c2..17a2828094504fcc5e3cf832122c2bc5296ac83e 100644 --- a/packages/rocketchat-chatops/package.js +++ b/packages/rocketchat-chatops/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'dburles:google-maps@1.1.5' ]); @@ -23,8 +23,7 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use(["tap:i18n@1.5.1"], ["client", "server"]); - api.imply('tap:i18n'); + api.use('tap:i18n'); api.addFiles("package-tap.i18n", ["client", "server"]); api.addFiles([ @@ -45,7 +44,7 @@ Package.onUse(function(api) { ], 'server'); // TAPi18n -- needs to be added last - api.addFiles(tapi18nFiles, ["client", "server"]); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-colors/package.js b/packages/rocketchat-colors/package.js index 45899a9b7da18f0b359d07cab32aec230b4500ca..48b47b04ffea9b7c6f7f4ee96ab3055f10bbc4e1 100644 --- a/packages/rocketchat-colors/package.js +++ b/packages/rocketchat-colors/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client.coffee', 'client'); diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index f360cd6501482360d7e914168c4f9f7b05721cd0..b7b557fbb82f5df5e639ee72987bcb3b3cc4fda1 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -1,9 +1,44 @@ # Adding CORS headers so we can use CDNs for static content +# Try to parse all request bodies as JSON +WebApp.rawConnectHandlers.use (req, res, next) -> + if req._body + return next() + + if req.headers['transfer-encoding'] is undefined and isNaN(req.headers['content-length']) + return next() + + if req.headers['content-type'] not in ['', undefined] + return next() + + buf = '' + req.setEncoding('utf8') + req.on 'data', (chunk) -> buf += chunk + req.on 'end', -> + if RocketChat?.debugLevel? and RocketChat.debugLevel is 'debug' + console.log '[request]'.green, req.method, req.url, '\nheaders ->', req.headers, '\nbody ->', buf + + try + req.body = JSON.parse(buf) + catch err + req.body = buf + + req._body = true + next() + + WebApp.rawConnectHandlers.use (req, res, next) -> res.setHeader("Access-Control-Allow-Origin", "*") res.setHeader("X-Rocket-Chat-Version", VERSION) res.setHeader("Access-Control-Expose-Headers", "X-Rocket-Chat-Version") + + # Block next handlers to override CORS with value http://meteor.local + setHeader = res.setHeader + res.setHeader = (key, val) -> + if key.toLowerCase() is 'access-control-allow-origin' and val is 'http://meteor.local' + return + return setHeader.apply @, arguments + return next() _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware @@ -12,3 +47,42 @@ WebAppInternals._staticFilesMiddleware = (staticFiles, req, res, next) -> res.setHeader("X-Rocket-Chat-Version", VERSION) res.setHeader("Access-Control-Expose-Headers", "X-Rocket-Chat-Version") _staticFilesMiddleware(staticFiles, req, res, next) + + +url = Npm.require("url") + +httpServer = WebApp.httpServer +oldHttpServerListeners = httpServer.listeners('request').slice(0) +httpServer.removeAllListeners('request') + +httpServer.addListener 'request', (req, res) -> + args = arguments + next = -> + for oldListener in oldHttpServerListeners + oldListener.apply(httpServer, args) + + if RocketChat.settings.get('Force_SSL') isnt true + next() + return + + remoteAddress = req.connection.remoteAddress or req.socket.remoteAddress + + localhostRegexp = /^\s*(127\.0\.0\.1|::1)\s*$/ + localhostTest = (x) -> + return localhostRegexp.test(x) + + isLocal = localhostRegexp.test(remoteAddress) and (not req.headers['x-forwarded-for'] or _.all(req.headers['x-forwarded-for'].split(','), localhostTest)) + + isSsl = req.connection.pair or (req.headers['x-forwarded-proto'] and req.headers['x-forwarded-proto'].indexOf('https') isnt -1) + + if not isLocal and not isSsl + host = req.headers['host'] or url.parse(Meteor.absoluteUrl()).hostname + + host = host.replace(/:\d+$/, '') + + res.writeHead 302, + 'Location': 'https://' + host + req.url + res.end() + return + + next() diff --git a/packages/rocketchat-emojione/package.js b/packages/rocketchat-emojione/package.js index 761d9d0ff8753afae6e5f894bc2e8dee6ceb5d00..a89c2d31b66a7724901cdb9ff1527ff0d7026084 100644 --- a/packages/rocketchat-emojione/package.js +++ b/packages/rocketchat-emojione/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'emojione:emojione', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('emojione.coffee', ['server','client']); diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 00aa21319db99271c07db37013a2836cf57b02d1..b974aff0ba499b0a3a8e62db2ec684a593628aaa 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -4,12 +4,58 @@ fs = Npm.require('fs') path = Npm.require('path') mkdirp = Npm.require('mkdirp') gm = Npm.require('gm') +exec = Npm.require('child_process').exec # Fix problem with usernames being converted to object id Grid.prototype.tryParseObjectId = -> false RocketChatFile = gm: gm + enabled: undefined + enable: -> + RocketChatFile.enabled = true + RocketChat.settings.updateOptionsById 'Accounts_AvatarResize', {alert: undefined} + disable: -> + RocketChatFile.enabled = false + RocketChat.settings.updateOptionsById 'Accounts_AvatarResize', {alert: 'The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server'} + + +detectGM = -> + exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> + if not error? and stdout.indexOf('GraphicsMagick') > -1 + RocketChatFile.enable() + + RocketChat.Info.GraphicsMagick = + enabled: true + version: stdout + else + RocketChat.Info.GraphicsMagick = + enabled: false + + exec 'convert -version', Meteor.bindEnvironment (error, stdout, stderr) -> + if not error? and stdout.indexOf('ImageMagick') > -1 + if RocketChatFile.enabled isnt true + # Enable GM to work with ImageMagick if no GraphicsMagick + RocketChatFile.gm = RocketChatFile.gm.subClass({imageMagick: true}) + RocketChatFile.enable() + + RocketChat.Info.ImageMagick = + enabled: true + version: stdout + else + if RocketChatFile.enabled isnt true + RocketChatFile.disable() + + RocketChat.Info.ImageMagick = + enabled: false + +detectGM() + +Meteor.methods + 'detectGM': -> + detectGM() + return + RocketChatFile.bufferToStream = (buffer) -> bufferStream = new stream.PassThrough() diff --git a/packages/rocketchat-file/package.js b/packages/rocketchat-file/package.js index 7ed4a9d40ff39550d4d451c9ac218b5ca5e93012..4efed24a52bd07e1f774fe234307931e42dc5c51 100644 --- a/packages/rocketchat-file/package.js +++ b/packages/rocketchat-file/package.js @@ -8,11 +8,13 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use(['coffeescript']); + api.use('rocketchat:lib'); + api.use('rocketchat:version'); + api.use('coffeescript'); - api.addFiles('file.server.coffee', ['server']); + api.addFiles('file.server.coffee', 'server'); - api.export(['RocketChatFile'], ['server']); + api.export('RocketChatFile', 'server'); }); Npm.depends({ diff --git a/packages/rocketchat-github-enterprise/i18n/ar.i18n.json b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..16216ec3e867f35f1f5c4938426f50a7d6a57d06 100644 --- a/packages/rocketchat-github-enterprise/i18n/ar.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Github_Enterprise_Url_No_Trail" : "مثال: http://domain.com (باستثناء زائدة مائل)" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/de.i18n.json b/packages/rocketchat-github-enterprise/i18n/de.i18n.json index 22bde54918df56bffe2a74ba84e20aaa15543b54..aecb8bb77fc6c7a00ae49695ac963903b4975f6e 100644 --- a/packages/rocketchat-github-enterprise/i18n/de.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/de.i18n.json @@ -1,7 +1,7 @@ { - "Accounts_OAuth_GitHub_Enterprise" : "OAuth aktiviert", - "API_GitHub_Enterprise_URL" : "GitHub Enterprise", + "Accounts_OAuth_GitHub_Enterprise" : "OAuth aktivieren", + "API_GitHub_Enterprise_URL" : "Server-URL", "Accounts_OAuth_GitHub_Enterprise_id" : "Client-ID", - "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", - "Github_Enterprise_Url_No_Trail" : "Beispiel: http://domain.com (ohne Schrägstrich)" + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client-Secret", + "Github_Enterprise_Url_No_Trail" : "Beispiel: http://domain.com (ohne Schrägstrich am Ende)" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/fr.i18n.json b/packages/rocketchat-github-enterprise/i18n/fr.i18n.json index 06dd996c99c061aa3c02f3520b909ab4d0619fe2..dfaef650cc119f54b0f8ea74b933ca0f0d7c858f 100644 --- a/packages/rocketchat-github-enterprise/i18n/fr.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/fr.i18n.json @@ -1,3 +1,6 @@ { - "API_GitHub_Enterprise_URL" : "GitHub Enterprise" + "Accounts_OAuth_GitHub_Enterprise" : "OAuth activé", + "API_GitHub_Enterprise_URL" : "URL du serveur", + "Accounts_OAuth_GitHub_Enterprise_id" : "ID client", + "Github_Enterprise_Url_No_Trail" : "Exemple: http://domain.com (sans slash final)" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ko.i18n.json b/packages/rocketchat-github-enterprise/i18n/ko.i18n.json index bf2ee2cce6ab419414cf43f438b6af95061eecf4..29d25e822d56b469a7fa5e2cdb994eebe5dea4cf 100644 --- a/packages/rocketchat-github-enterprise/i18n/ko.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ko.i18n.json @@ -1,4 +1,7 @@ { - "API_GitHub_Enterprise_URL" : "GitHub Enterprise", + "Accounts_OAuth_GitHub_Enterprise" : "OAuth 활성화", + "API_GitHub_Enterprise_URL" : "Server URL", + "Accounts_OAuth_GitHub_Enterprise_id" : "Client ID", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client 암호", "Github_Enterprise_Url_No_Trail" : "예: http://domain.com (마지막 슬래시 ì œì™¸)" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/nl.i18n.json b/packages/rocketchat-github-enterprise/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..1163d7a6d0b518013569b6bda53af05061743756 100644 --- a/packages/rocketchat-github-enterprise/i18n/nl.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/nl.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Accounts_OAuth_GitHub_Enterprise" : "OAuth Ingeschakeld", + "API_GitHub_Enterprise_URL" : "Server URL", + "Accounts_OAuth_GitHub_Enterprise_id" : "Client Id", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", + "Github_Enterprise_Url_No_Trail" : "Voorbeeld: http://domain.com (exclusief slash)" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ro.i18n.json b/packages/rocketchat-github-enterprise/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..f685667cfd40ce637679005fb697571dda29d4bb --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/ro.i18n.json @@ -0,0 +1,7 @@ +{ + "Accounts_OAuth_GitHub_Enterprise" : "OAuth Activat", + "API_GitHub_Enterprise_URL" : "URL-ul serverului", + "Accounts_OAuth_GitHub_Enterprise_id" : "Client ID", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", + "Github_Enterprise_Url_No_Trail" : "Exemplu: http://domain.com (fără '/' la final)" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ru.i18n.json b/packages/rocketchat-github-enterprise/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..d3a57474db49292f4f4a9608b770f401d6cd2413 100644 --- a/packages/rocketchat-github-enterprise/i18n/ru.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ru.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Accounts_OAuth_GitHub_Enterprise" : "OAuth включен" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/sr.i18n.json b/packages/rocketchat-github-enterprise/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/package.js b/packages/rocketchat-github-enterprise/package.js index cca18ff40e338f42fad8a6cc3b8feab427283fa6..cbb6321723bb063387b2cc0f5d5be5c073ef37a4 100644 --- a/packages/rocketchat-github-enterprise/package.js +++ b/packages/rocketchat-github-enterprise/package.js @@ -8,14 +8,14 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use('coffeescript'); - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.use('rocketchat:custom-oauth'); api.addFiles('startup.coffee', 'server'); api.addFiles('github-enterprise-login-button.css', 'client'); api.addFiles('common.coffee'); - // TAPi18n + // TAPi18n api.use('templating', 'client'); var _ = Npm.require('underscore'); var fs = Npm.require('fs'); @@ -24,9 +24,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); diff --git a/packages/rocketchat-gitlab/i18n/de.i18n.json b/packages/rocketchat-gitlab/i18n/de.i18n.json index ce7e0675b85ead87704432aa7c33ef23e85d788a..3e6c591d6961e9c73b7401bcf1999efc2e5a5aaf 100644 --- a/packages/rocketchat-gitlab/i18n/de.i18n.json +++ b/packages/rocketchat-gitlab/i18n/de.i18n.json @@ -1,3 +1,3 @@ { - "API_Gitlab_URL" : "Git" + "API_Gitlab_URL" : "GitLab-URL" } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/ro.i18n.json b/packages/rocketchat-gitlab/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..aa29615cd108029974531adf38285605c00aeacb --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/ro.i18n.json @@ -0,0 +1,3 @@ +{ + "API_Gitlab_URL" : "GitLab URL" +} \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/sr.i18n.json b/packages/rocketchat-gitlab/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/package.js b/packages/rocketchat-gitlab/package.js index c8a0e62d3a8da2d1b7faf49d77b275c251f96c4d..8e1b7250e60e7377ae994fd90fd1a144fe78739c 100644 --- a/packages/rocketchat-gitlab/package.js +++ b/packages/rocketchat-gitlab/package.js @@ -8,7 +8,7 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use('coffeescript'); - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.use('rocketchat:custom-oauth'); api.addFiles("common.coffee"); @@ -24,9 +24,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-highlight/highlight.coffee b/packages/rocketchat-highlight/highlight.coffee index c98270151ae158ae6bed9c622e2eb7c684b33e58..57944340bcdd13626f59043605de4047084eb5f6 100644 --- a/packages/rocketchat-highlight/highlight.coffee +++ b/packages/rocketchat-highlight/highlight.coffee @@ -8,6 +8,7 @@ class Highlight constructor: (message) -> if s.trim message.html + message.tokens ?= [] # Count occurencies of ``` count = (message.html.match(/```/g) || []).length @@ -40,7 +41,15 @@ class Highlight result = hljs.highlightAuto code else result = hljs.highlight lang, code - msgParts[index] = "<pre><code class='hljs " + result.language + "'><span class='copyonly'>```<br></span>" + result.value + "<span class='copyonly'><br>```</span></code></pre>" + + token = "$#{Random.id()}$" + + message.tokens.push + highlight: true + token: token + text: "<pre><code class='hljs " + result.language + "'><span class='copyonly'>```<br></span>" + result.value + "<span class='copyonly'><br>```</span></code></pre>" + + msgParts[index] = token else msgParts[index] = part diff --git a/packages/rocketchat-highlight/package.js b/packages/rocketchat-highlight/package.js index a8587bff10e4d8c2ea192cbf807d5f445f8ab894..40c87c3567127f8d31ec7c8f0b289495538005a6 100644 --- a/packages/rocketchat-highlight/package.js +++ b/packages/rocketchat-highlight/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'simple:highlight.js', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('highlight.coffee', ['server','client']); diff --git a/packages/rocketchat-hubot/i18n/de.i18n.json b/packages/rocketchat-hubot/i18n/de.i18n.json index e077ae8144f46dd433d8ac9da10cbae0e3d51bf5..a840ae5c5dbda7844ee08ee03de522581a9db4e3 100644 --- a/packages/rocketchat-hubot/i18n/de.i18n.json +++ b/packages/rocketchat-hubot/i18n/de.i18n.json @@ -1,5 +1,5 @@ { - "RocketBot_Enabled" : "RocketBot aktivieren", - "RocketBot_Name" : "RocketBot Name", - "RocketBot_Name_Description" : "RocketBot Name muss einen registrierten Benutzernamen auf dem Server haben." + "RocketBot_Enabled" : "RocketBot aktiviert", + "RocketBot_Name" : "Name des RocketBots", + "RocketBot_Name_Description" : "Der Name des RocketBots muss den Namen eines registrierten Benutzers auf dem Server besitzen." } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/nl.i18n.json b/packages/rocketchat-hubot/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..4c365fdd09d5b8c8aa2e26229e151eda2bfc2a13 100644 --- a/packages/rocketchat-hubot/i18n/nl.i18n.json +++ b/packages/rocketchat-hubot/i18n/nl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "RocketBot_Enabled" : "RocketBot Ingeschakeld", + "RocketBot_Name" : "RocketBot Naam", + "RocketBot_Name_Description" : "RocketBot naam moet een geldige gebruikersnaam zijn op uw server." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ro.i18n.json b/packages/rocketchat-hubot/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..473424bfab99513383223c60c11d5e100c93ddf8 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ro.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RocketBot Activat", + "RocketBot_Name" : "Nume RocketBot", + "RocketBot_Name_Description" : "Numele RocketBot trebuie să fie un nume de utilizator valid înregistrat pe server." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ru.i18n.json b/packages/rocketchat-hubot/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..48f9516bddb851eb1549359f481911735f9f0aff 100644 --- a/packages/rocketchat-hubot/i18n/ru.i18n.json +++ b/packages/rocketchat-hubot/i18n/ru.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "RocketBot_Enabled" : "RocketBot включен", + "RocketBot_Name" : "Ð˜Ð¼Ñ RocketBot-а", + "RocketBot_Name_Description" : "Ð˜Ð¼Ñ RocketBot должно быть дейÑтвительным именем Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрированным на вашем Ñервере." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/sr.i18n.json b/packages/rocketchat-hubot/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/package.js b/packages/rocketchat-hubot/package.js index 62d91694a3fd877f3ca269e2eaae2ee6fff1c8c6..55074e51a4848746345befe54e7e9044db779dc3 100644 --- a/packages/rocketchat-hubot/package.js +++ b/packages/rocketchat-hubot/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'tracker', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ @@ -28,9 +28,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); api.export('Hubot', ['server']); api.export('HubotScripts', ['server']); diff --git a/packages/rocketchat-integrations/client/route.coffee b/packages/rocketchat-integrations/client/route.coffee index 4a87624ca342cf6c04ad4ca88d3d1d33c291f9ad..c5c6311d662191fb29693c9936d14b776df89d2f 100644 --- a/packages/rocketchat-integrations/client/route.coffee +++ b/packages/rocketchat-integrations/client/route.coffee @@ -1,26 +1,37 @@ FlowRouter.route '/admin/integrations', name: 'admin-integrations' action: (params) -> + RocketChat.TabBar.showGroup 'admin-integrations' BlazeLayout.render 'main', center: 'pageSettingsContainer' pageTitle: t('Integrations') pageTemplate: 'integrations' - FlowRouter.route '/admin/integrations/new', name: 'admin-integrations-new' action: (params) -> + RocketChat.TabBar.showGroup 'admin-integrations' BlazeLayout.render 'main', center: 'pageSettingsContainer' pageTitle: t('Integration_New') pageTemplate: 'integrationsNew' - FlowRouter.route '/admin/integrations/incoming/:id?', name: 'admin-integrations-incoming' action: (params) -> + RocketChat.TabBar.showGroup 'admin-integrations' BlazeLayout.render 'main', center: 'pageSettingsContainer' pageTitle: t('Integration_Incoming_WebHook') pageTemplate: 'integrationsIncoming' params: params + +FlowRouter.route '/admin/integrations/outgoing/:id?', + name: 'admin-integrations-outgoing' + action: (params) -> + RocketChat.TabBar.showGroup 'admin-integrations' + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('Integration_Outgoing_WebHook') + pageTemplate: 'integrationsOutgoing' + params: params diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index d1075af7756bea42043c72e9c7769fcfca3a82c3..52f196b1c8b25055769d996bdac25db78a90f03b 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -7,25 +7,45 @@ <div class="section"> <div class="admin-integrations-new-panel"> {{#each integrations}} - <a href="{{pathFor "admin-integrations-incoming" id=_id}}"> - <div class="admin-integrations-new-item"> - <i class="icon-login"></i> - <div class="admin-integrations-new-item-body"> - <div class="admin-integrations-new-item-title"> - Incoming WebHook {{#if name}}- {{name}}{{/if}} - </div> - <div class="admin-integrations-new-item-description"> - {{{_ "Post_to_s_as_s" channel username}}} - </div> - <div class="admin-integrations-new-item-description"> - {{{_ "Created_at_s_by_s" (dateFormated _createdAt) _createdBy.username}}} + {{#if $eq type 'webhook-incoming'}} + <a href="{{pathFor "admin-integrations-incoming" id=_id}}"> + <div class="admin-integrations-new-item"> + <i class="icon-login"></i> + <div class="admin-integrations-new-item-body"> + <div class="admin-integrations-new-item-title"> + Incoming WebHook {{#if name}}- {{name}}{{/if}} + </div> + <div class="admin-integrations-new-item-description"> + {{{_ "Post_to_s_as_s" channel username}}} + </div> + <div class="admin-integrations-new-item-description"> + {{{_ "Created_at_s_by_s" (dateFormated _createdAt) _createdBy.username}}} + </div> </div> + <i class="icon-angle-right"></i> </div> - <i class="icon-angle-right"></i> - </div> - </a> + </a> + {{/if}} {{else}} - <h1>{{_ "There_is_no_integrations"}}</h1> + <h1>{{_ "There_are_no_integrations"}}</h1> + {{/each}} + {{#each integrations}} + {{#if $eq type 'webhook-outgoing'}} + <a href="{{pathFor "admin-integrations-outgoing" id=_id}}"> + <div class="admin-integrations-new-item"> + <i class="icon-login"></i> + <div class="admin-integrations-new-item-body"> + <div class="admin-integrations-new-item-title"> + Outgoing WebHook {{#if name}}- {{name}}{{/if}} + </div> + <div class="admin-integrations-new-item-description"> + {{{_ "Created_at_s_by_s" (dateFormated _createdAt) _createdBy.username}}} + </div> + </div> + <i class="icon-angle-right"></i> + </div> + </a> + {{/if}} {{/each}} </div> </div> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index 28f19b530c6fc814be9e694497cf604ce77b791c..8e8f09dd0e121955c49edac78546f7a2a3653984 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -15,6 +15,7 @@ Template.integrationsIncoming.helpers data = ChatIntegrations.findOne({_id: params.id}) if data? data.url = Meteor.absoluteUrl("hooks/#{encodeURIComponent(data._id)}/#{encodeURIComponent(data.userId)}/#{encodeURIComponent(data.token)}") + data.completeToken = "#{encodeURIComponent(data._id)}/#{encodeURIComponent(data.userId)}/#{encodeURIComponent(data.token)}" Template.instance().record.set data return data @@ -25,10 +26,12 @@ Template.integrationsIncoming.helpers return {} = _id: Random.id() alias: record.alias + emoji: record.emoji avatar: record.avatar msg: 'Example message' bot: i: Random.id() + groupable: false attachments: [{ title: "Rocket.Chat" title_link: "https://rocket.chat" @@ -41,12 +44,52 @@ Template.integrationsIncoming.helpers _id: Random.id() username: record.username + exampleJson: -> + record = Template.instance().record.get() + data = + username: record.alias + icon_emoji: record.emoji + icon_url: record.avatar + text: 'Example message' + attachments: [{ + title: "Rocket.Chat" + title_link: "https://rocket.chat" + text: "Rocket.Chat, the best open source chat" + image_url: "https://rocket.chat/images/mockup.png" + color: "#764FA5" + }] + + for key, value of data + delete data[key] if value in [null, ""] + + return hljs.highlight('json', JSON.stringify(data, null, 2)).value + + curl: -> + record = Template.instance().record.get() + data = + username: record.alias + icon_emoji: record.emoji + icon_url: record.avatar + text: 'Example message' + attachments: [{ + title: "Rocket.Chat" + title_link: "https://rocket.chat" + text: "Rocket.Chat, the best open source chat" + image_url: "https://rocket.chat/images/mockup.png" + color: "#764FA5" + }] + + for key, value of data + delete data[key] if value in [null, ""] + + return "curl -X POST --data-urlencode 'payload=#{JSON.stringify(data)}' #{record.url}" Template.integrationsIncoming.events "blur input": (e, t) -> t.record.set name: $('[name=name]').val().trim() alias: $('[name=alias]').val().trim() + emoji: $('[name=emoji]').val().trim() avatar: $('[name=avatar]').val().trim() channel: $('[name=channel]').val().trim() username: $('[name=username]').val().trim() @@ -65,7 +108,7 @@ Template.integrationsIncoming.events closeOnConfirm: false html: false , -> - Meteor.call "deleteIntegration", params.id, (err, data) -> + Meteor.call "deleteIncomingIntegration", params.id, (err, data) -> swal title: t('Deleted') text: t('Your_entry_has_been_deleted') @@ -78,6 +121,7 @@ Template.integrationsIncoming.events "click .submit > .save": -> name = $('[name=name]').val().trim() alias = $('[name=alias]').val().trim() + emoji = $('[name=emoji]').val().trim() avatar = $('[name=avatar]').val().trim() channel = $('[name=channel]').val().trim() username = $('[name=username]').val().trim() @@ -91,21 +135,21 @@ Template.integrationsIncoming.events integration = channel: channel alias: alias if alias isnt '' + emoji: emoji if emoji isnt '' avatar: avatar if avatar isnt '' name: name if name isnt '' params = Template.instance().data.params?() if params?.id? - Meteor.call "updateIntegration", params.id, integration, (err, data) -> + Meteor.call "updateIncomingIntegration", params.id, integration, (err, data) -> if err? return toastr.error TAPi18n.__(err.error) toastr.success TAPi18n.__("Integration_updated") else - integration.type = 'webhook-incoming' integration.username = username - Meteor.call "addIntegration", integration, (err, data) -> + Meteor.call "addIncomingIntegration", integration, (err, data) -> if err? return toastr.error TAPi18n.__(err.error) diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index d17db30e5c5921f2f48fd17d4504ed0aca5b3aad..42ffe785ae739ea077dda73bb99564824b706449 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -47,16 +47,39 @@ <div class="settings-description">{{_ "Should_be_a_URL_of_an_image"}}</div> </div> </div> + <div class="input-line double-col"> + <label>{{_ "Emoji"}} ({{_ "optional"}})</label> + <div> + <input type="text" name="emoji" value="{{data.emoji}}" placeholder="{{_ 'Optional'}}" /> + <div class="settings-description">{{_ "You_can_use_an_emoji_as_avatar"}}</div> + <div class="settings-description">{{{_ "Example_s" ":ghost:"}}}</div> + </div> + </div> {{#if data.token}} <div class="input-line double-col"> <label>Webhook URL</label> <div> - <input type="text" name="token" value="{{data.url}}" disabled="disabled" /> + <input type="text" name="webhookurl" value="{{data.url}}" disabled="disabled" /> <div class="settings-description">{{_ "Send_your_JSON_payloads_to_this_URL"}}</div> - <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=token]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=webhookurl]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + </div> + </div> + <div class="input-line double-col"> + <label>Token</label> + <div> + <input type="text" name="completeToken" value="{{data.completeToken}}" disabled="disabled" /> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=completeToken]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> </div> </div> {{/if}} + <div class="input-line double-col"> + <label>{{_ "Example"}}</label> + <div> + <pre><code class="hljs json json-example">{{{exampleJson}}}</code></pre> + <input type="text" name="curl" value="{{curl}}" disabled="disabled" /> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=curl]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + </div> + </div> <div class="input-line message-example"> {{#nrr nrrargs 'message' example}}{{/nrr}} </div> diff --git a/packages/rocketchat-integrations/client/views/integrationsNew.html b/packages/rocketchat-integrations/client/views/integrationsNew.html index 496cf5112bbcaeb74bf75d498a73b9659e74b2cb..f4425ff8c3d2bb50dcb29ec6bd4b60c61fd542fd 100644 --- a/packages/rocketchat-integrations/client/views/integrationsNew.html +++ b/packages/rocketchat-integrations/client/views/integrationsNew.html @@ -20,7 +20,7 @@ <i class="icon-angle-right"></i> </div> </a> - <!-- <a href="{{pathFor "admin-integrations-incoming"}}"> + <a href="{{pathFor "admin-integrations-outgoing"}}"> <div class="admin-integrations-new-item"> <i class="icon-logout"></i> <div class="admin-integrations-new-item-body"> @@ -33,7 +33,7 @@ </div> <i class="icon-angle-right"></i> </div> - </a> --> + </a> </div> </div> </div> diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee new file mode 100644 index 0000000000000000000000000000000000000000..2fdde6709199b5cab118591cce283062ec1ee518 --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee @@ -0,0 +1,167 @@ +Template.integrationsOutgoing.onCreated -> + @record = new ReactiveVar + username: 'rocket.cat' + token: Random.id(24) + + +Template.integrationsOutgoing.helpers + + join: (arr, sep) -> + if not arr?.join? + return arr + + return arr.join sep + + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-integrations' + + data: -> + params = Template.instance().data.params?() + + if params?.id? + data = ChatIntegrations.findOne({_id: params.id}) + if data? + if not data.token? + data.token = Random.id(24) + return data + + return Template.instance().record.curValue + + example: -> + record = Template.instance().record.get() + return {} = + _id: Random.id() + alias: record.alias + emoji: record.emoji + avatar: record.avatar + msg: 'Response text' + bot: + i: Random.id() + groupable: false + attachments: [{ + title: "Rocket.Chat" + title_link: "https://rocket.chat" + text: "Rocket.Chat, the best open source chat" + image_url: "https://rocket.chat/images/mockup.png" + color: "#764FA5" + }] + ts: new Date + u: + _id: Random.id() + username: record.username + + exampleJson: -> + record = Template.instance().record.get() + data = + username: record.alias + icon_emoji: record.emoji + icon_url: record.avatar + text: 'Response text' + attachments: [{ + title: "Rocket.Chat" + title_link: "https://rocket.chat" + text: "Rocket.Chat, the best open source chat" + image_url: "https://rocket.chat/images/mockup.png" + color: "#764FA5" + }] + + for key, value of data + delete data[key] if value in [null, ""] + + return hljs.highlight('json', JSON.stringify(data, null, 2)).value + + +Template.integrationsOutgoing.events + "blur input": (e, t) -> + t.record.set + name: $('[name=name]').val().trim() + alias: $('[name=alias]').val().trim() + emoji: $('[name=emoji]').val().trim() + avatar: $('[name=avatar]').val().trim() + channel: $('[name=channel]').val().trim() + username: $('[name=username]').val().trim() + triggerWords: $('[name=triggerWords]').val().trim() + urls: $('[name=urls]').val().trim() + token: $('[name=token]').val().trim() + + + "click .submit > .delete": -> + params = Template.instance().data.params() + + swal + title: t('Are_you_sure') + text: t('You_will_not_be_able_to_recover') + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_delete_it') + cancelButtonText: t('Cancel') + closeOnConfirm: false + html: false + , -> + Meteor.call "deleteOutgoingIntegration", params.id, (err, data) -> + swal + title: t('Deleted') + text: t('Your_entry_has_been_deleted') + type: 'success' + timer: 1000 + showConfirmButton: false + + FlowRouter.go "admin-integrations" + + "click .submit > .save": -> + name = $('[name=name]').val().trim() + alias = $('[name=alias]').val().trim() + emoji = $('[name=emoji]').val().trim() + avatar = $('[name=avatar]').val().trim() + channel = $('[name=channel]').val().trim() + username = $('[name=username]').val().trim() + triggerWords = $('[name=triggerWords]').val().trim() + urls = $('[name=urls]').val().trim() + token = $('[name=token]').val().trim() + + if username is '' + return toastr.error TAPi18n.__("The_username_is_required") + + triggerWords = triggerWords.split(',') + for triggerWord, index in triggerWords + triggerWords[index] = triggerWord.trim() + delete triggerWords[index] if triggerWord.trim() is '' + + triggerWords = _.without triggerWords, [undefined] + + urls = urls.split('\n') + for url, index in urls + urls[index] = url.trim() + delete urls[index] if url.trim() is '' + + urls = _.without urls, [undefined] + + if urls.length is 0 + return toastr.error TAPi18n.__("You_should_inform_one_url_at_least") + + integration = + username: username + channel: channel if channel isnt '' + alias: alias if alias isnt '' + emoji: emoji if emoji isnt '' + avatar: avatar if avatar isnt '' + name: name if name isnt '' + triggerWords: triggerWords if triggerWords isnt '' + urls: urls if urls isnt '' + token: token if token isnt '' + + params = Template.instance().data.params?() + if params?.id? + Meteor.call "updateOutgoingIntegration", params.id, integration, (err, data) -> + if err? + return toastr.error TAPi18n.__(err.error) + + toastr.success TAPi18n.__("Integration_updated") + else + Meteor.call "addOutgoingIntegration", integration, (err, data) -> + if err? + return toastr.error TAPi18n.__(err.error) + + toastr.success TAPi18n.__("Integration_added") + FlowRouter.go "admin-integrations-outgoing", {id: data._id} diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html new file mode 100644 index 0000000000000000000000000000000000000000..afadc8b7bbe2c06a26b212578da673dc14370bc7 --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html @@ -0,0 +1,100 @@ +<template name="integrationsOutgoing"> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-integrations"}}"><i class="icon-angle-left"></i> {{_ "Back_to_integrations"}}</a><br><br> + <div class="rocket-form"> + <div class="section"> + <div class="section-content"> + <div class="input-line double-col"> + <label>{{_ "Name"}} ({{_ "optional"}})</label> + <div> + <input type="text" name="name" value="{{data.name}}" placeholder="{{_ 'Optional'}}" /> + <div class="settings-description">{{_ "You_should_name_it_to_easily_manage_your_integrations"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Channel"}} ({{_ "optional"}})</label> + <div> + <input type="text" name="channel" value="{{data.channel}}" placeholder="{{_ 'User_or_channel_name'}}" /> + <div class="settings-description">{{_ "Optional channel to listen on"}}</div> + <div class="settings-description">{{{_ "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" "@" "#" "@john" "#general"}}}</div> + <div class="settings-description">{{{_ "Leave empty to listen <strong>any public channel</strong>"}}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Trigger_Words"}} ({{_ "optional"}})</label> + <div> + <input type="text" name="triggerWords" value="{{join data.triggerWords ','}}" /> + <div class="settings-description">{{_ "When a line starts with one of these words, post to the URL(s) below"}}</div> + <div class="settings-description">{{_ "Separate multiple words with commas"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "URLs"}}</label> + <div> + <textarea name="urls" style="height: 100px;">{{join data.urls "\n"}}</textarea> + <div class="settings-description">{{_ "Enter as many URLs as you like, one per line, please"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Post_as"}}</label> + <div> + <input type="text" name="username" value="{{data.username}}" /> + <div class="settings-description">{{_ "Choose_the_username_that_this_integration_will_post_as"}}</div> + <div class="settings-description">{{_ "Should_exists_a_user_with_this_username"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Alias"}} ({{_ "optional"}})</label> + <div> + <input type="text" name="alias" value="{{data.alias}}" placeholder="{{_ 'Optional'}}" /> + <div class="settings-description">{{_ "Choose_the_alias_that_will_appear_before_the_username_in_messages"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Avatar_URL"}} ({{_ "optional"}})</label> + <div> + <input type="url" name="avatar" value="{{data.avatar}}" placeholder="{{_ 'Optional'}}" /> + <div class="settings-description">{{_ "You_can_change_a_different_avatar_too"}}</div> + <div class="settings-description">{{_ "Should_be_a_URL_of_an_image"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Emoji"}} ({{_ "optional"}})</label> + <div> + <input type="text" name="emoji" value="{{data.emoji}}" placeholder="{{_ 'Optional'}}" /> + <div class="settings-description">{{_ "You_can_use_an_emoji_as_avatar"}}</div> + <div class="settings-description">{{{_ "Example_s" ":ghost:"}}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>Token ({{_ "optional"}})</label> + <div> + <input type="text" name="token" value="{{data.token}}" /> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Responding"}}</label> + <div> + <div class="settings-description">{{{_ "If the handler wishes to post a response back into the Slack channel, the following JSON should be returned as the body of the response:"}}}</div> + <pre><code class="hljs json json-example">{{{exampleJson}}}</code></pre> + <div class="settings-description">{{{_ "Empty bodies or bodies with an empty text property will simply be ignored. Non-200 responses will be retried a reasonable number of times. A response will be posted using the alias and avatar specified above. You can override these informations as in the example above."}}}</div> + </div> + </div> + <div class="input-line message-example"> + {{#nrr nrrargs 'message' example}}{{/nrr}} + </div> + </div> + </div> + <div class="submit"> + {{#if data.token}} + <button class="button red delete"><i class="icon-trash"></i><span>{{_ "Delete"}}</span></button> + {{/if}} + <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> + </div> + </div> + {{else}} + {{_ "Not_authorized"}} + {{/if}} + </div> +</template> diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index ae298211d7288758f4087124a7b929e3ec1dcabf..f5ce2880e3efb0e618ea48cf4d6771662e59a9f8 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -11,7 +11,10 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); - api.use('rocketchat:lib@0.0.1'); + api.use('simple:highlight.js'); + api.use('rocketchat:lib'); + api.use('rocketchat:authorization'); + api.use('rocketchat:api'); api.use('kadira:flow-router', 'client'); api.use('templating', 'client'); @@ -28,6 +31,8 @@ Package.onUse(function(api) { api.addFiles('client/views/integrationsNew.coffee', 'client'); api.addFiles('client/views/integrationsIncoming.html', 'client'); api.addFiles('client/views/integrationsIncoming.coffee', 'client'); + api.addFiles('client/views/integrationsOutgoing.html', 'client'); + api.addFiles('client/views/integrationsOutgoing.coffee', 'client'); // stylesheets api.addAssets('client/stylesheets/integrations.less', 'server'); @@ -39,13 +44,21 @@ Package.onUse(function(api) { api.addFiles('server/publications/integrations.coffee', 'server'); // methods - api.addFiles('server/methods/addIntegration.coffee', 'server'); - api.addFiles('server/methods/updateIntegration.coffee', 'server'); - api.addFiles('server/methods/deleteIntegration.coffee', 'server'); + api.addFiles('server/methods/incoming/addIncomingIntegration.coffee', 'server'); + api.addFiles('server/methods/incoming/updateIncomingIntegration.coffee', 'server'); + api.addFiles('server/methods/incoming/deleteIncomingIntegration.coffee', 'server'); + api.addFiles('server/methods/outgoing/addOutgoingIntegration.coffee', 'server'); + api.addFiles('server/methods/outgoing/updateOutgoingIntegration.coffee', 'server'); + api.addFiles('server/methods/outgoing/deleteOutgoingIntegration.coffee', 'server'); // api api.addFiles('server/api/api.coffee', 'server'); + + api.addFiles('server/triggers.coffee', 'server'); + + api.addFiles('server/processWebhookMessage.js', 'server'); + var _ = Npm.require('underscore'); var fs = Npm.require('fs'); tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-integrations/i18n'), function(filename) { @@ -53,6 +66,6 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n', ['client', 'server']); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 4001e3c09a790b0702ca3e3bb6fd0f2b4578753c..98e926b07de6cc23d0c22261d4de521fa73fa6cb 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -1,8 +1,11 @@ Api = new Restivus - enableCors: false + enableCors: true apiPath: 'hooks/' auth: user: -> + if @bodyParams?.payload? + @bodyParams = JSON.parse @bodyParams.payload + user = RocketChat.models.Users.findOne _id: @request.params.userId 'services.resume.loginTokens.hashedToken': decodeURIComponent @request.params.token @@ -12,76 +15,153 @@ Api = new Restivus Api.addRoute ':integrationId/:userId/:token', authRequired: true, post: -> - if @bodyParams?.payload? - @bodyParams = JSON.parse @bodyParams.payload + console.log 'Post integration' + console.log '@urlParams', @urlParams + console.log '@bodyParams', @bodyParams integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) user = RocketChat.models.Users.findOne(@userId) - channel = @bodyParams.channel or integration.channel - channelType = channel[0] - channel = channel.substr(1) - - switch channelType - when '#' - room = RocketChat.models.Rooms.findOne - $or: [ - {_id: channel} - {name: channel} - ] - - if not room? - return {} = - statusCode: 400 - body: - success: false - error: 'invalid-channel' - - rid = room._id - Meteor.runAsUser user._id, -> - Meteor.call 'joinRoom', room._id - - when '@' - roomUser = RocketChat.models.Users.findOne - $or: [ - {_id: channel} - {username: channel} - ] - - if not roomUser? - return {} = - statusCode: 400 - body: - success: false - error: 'invalid-channel' - - rid = [user._id, roomUser._id].sort().join('') - room = RocketChat.models.Rooms.findOne(rid) - - if not room - Meteor.runAsUser user._id, -> - Meteor.call 'createDirectMessage', roomUser._id - room = RocketChat.models.Rooms.findOne(rid) - - else - return {} = - statusCode: 400 - body: - success: false - error: 'invalid-channel-type' - - message = - avatar: integration.avatar + @bodyParams.bot = + i: integration._id + + defaultValues = + channel: integration.channel alias: integration.alias - msg: @bodyParams.text or '' - attachments: @bodyParams.attachments - parseUrls: false - bot: - i: integration._id + avatar: integration.avatar + emoji: integration.emoji + + try + message = processWebhookMessage @bodyParams, user, defaultValues + + if not message? + return RocketChat.API.v1.failure 'unknown-error' + + return RocketChat.API.v1.success() + catch e + return RocketChat.API.v1.failure e.error + + +createIntegration = (options, user) -> + console.log 'Add integration' + console.log options + + Meteor.runAsUser user._id, => + switch options['event'] + when 'newMessageOnChannel' + options.data ?= {} + + if options.data.channel_name? and options.data.channel_name.indexOf('#') is -1 + options.data.channel_name = '#' + options.data.channel_name + + Meteor.call 'addOutgoingIntegration', + username: 'rocket.cat' + urls: [options.target_url] + name: options.name + channel: options.data.channel_name + triggerWords: options.data.trigger_words + + when 'newMessageToUser' + if options.data.username.indexOf('@') is -1 + options.data.username = '@' + options.data.username + + Meteor.call 'addOutgoingIntegration', + username: 'rocket.cat' + urls: [options.target_url] + name: options.name + channel: options.data.username + triggerWords: options.data.trigger_words + + return RocketChat.API.v1.success() + + +removeIntegration = (options, user) -> + console.log 'Remove integration' + console.log options + + integrationToRemove = RocketChat.models.Integrations.findOne urls: options.target_url + Meteor.runAsUser user._id, => + Meteor.call 'deleteOutgoingIntegration', integrationToRemove._id + + return RocketChat.API.v1.success() + + +Api.addRoute 'add/:integrationId/:userId/:token', authRequired: true, + post: -> + integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) - RocketChat.sendMessage user, message, room, {} + if not integration? + return RocketChat.API.v1.failure 'Invalid integraiton id' + + user = RocketChat.models.Users.findOne(@userId) + + return createIntegration @bodyParams, user + + +Api.addRoute 'remove/:integrationId/:userId/:token', authRequired: true, + post: -> + integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) + + if not integration? + return RocketChat.API.v1.failure 'Invalid integraiton id' + + user = RocketChat.models.Users.findOne(@userId) + + return removeIntegration @bodyParams, user + + +RocketChat.API.v1.addRoute 'integrations.create', authRequired: true, + post: -> + return createIntegration @bodyParams, @user + + +RocketChat.API.v1.addRoute 'integrations.remove', authRequired: true, + post: -> + return removeIntegration @bodyParams, @user + + +Api.addRoute 'sample/:integrationId/:userId/:token', authRequired: true, + get: -> + console.log 'Sample Integration' + + return {} = + statusCode: 200 + body: [ + token: Random.id(24) + channel_id: Random.id() + channel_name: 'general' + timestamp: new Date + user_id: Random.id() + user_name: 'rocket.cat' + text: 'Sample text 1' + trigger_word: 'Sample' + , + token: Random.id(24) + channel_id: Random.id() + channel_name: 'general' + timestamp: new Date + user_id: Random.id() + user_name: 'rocket.cat' + text: 'Sample text 2' + trigger_word: 'Sample' + , + token: Random.id(24) + channel_id: Random.id() + channel_name: 'general' + timestamp: new Date + user_id: Random.id() + user_name: 'rocket.cat' + text: 'Sample text 3' + trigger_word: 'Sample' + ] + + +Api.addRoute 'info/:integrationId/:userId/:token', authRequired: true, + get: -> + console.log 'Info integration' return {} = statusCode: 200 body: success: true + diff --git a/packages/rocketchat-integrations/server/methods/addIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee similarity index 66% rename from packages/rocketchat-integrations/server/methods/addIntegration.coffee rename to packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee index 454b87d6bd236932a6a0a2750aff7a8c475fe0bf..54efaf760064dd44e6fc5c07c564f2fc0bca3733 100644 --- a/packages/rocketchat-integrations/server/methods/addIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee @@ -1,22 +1,22 @@ Meteor.methods - addIntegration: (integration) -> + addIncomingIntegration: (integration) -> if not RocketChat.authz.hasPermission @userId, 'manage-integrations' throw new Meteor.Error 'not_authorized' if not _.isString(integration.channel) - throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel must be string' + throw new Meteor.Error 'invalid_channel', '[methods] addIncomingIntegration -> channel must be string' if integration.channel.trim() is '' - throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel can\'t be empty' + throw new Meteor.Error 'invalid_channel', '[methods] addIncomingIntegration -> channel can\'t be empty' if integration.channel[0] not in ['@', '#'] - throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel should start with # or @' + throw new Meteor.Error 'invalid_channel', '[methods] addIncomingIntegration -> channel should start with # or @' if not _.isString(integration.username) - throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username must be string' + throw new Meteor.Error 'invalid_username', '[methods] addIncomingIntegration -> username must be string' if integration.username.trim() is '' - throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username can\'t be empty' + throw new Meteor.Error 'invalid_username', '[methods] addIncomingIntegration -> username can\'t be empty' record = undefined channelType = integration.channel[0] @@ -37,12 +37,12 @@ Meteor.methods ] if record is undefined - throw new Meteor.Error 'channel_does_not_exists', "[methods] addIntegration -> The channel does not exists" + throw new Meteor.Error 'channel_does_not_exists', "[methods] addIncomingIntegration -> The channel does not exists" user = RocketChat.models.Users.findOne({username: integration.username}) if not user? - throw new Meteor.Error 'user_does_not_exists', "[methods] addIntegration -> The username does not exists" + throw new Meteor.Error 'user_does_not_exists', "[methods] addIncomingIntegration -> The username does not exists" stampedToken = Accounts._generateStampedLoginToken() hashStampedToken = Accounts._hashStampedToken(stampedToken) @@ -53,6 +53,7 @@ Meteor.methods hashedToken: hashStampedToken.hashedToken integration: true + integration.type = 'webhook-incoming' integration.token = hashStampedToken.hashedToken integration.userId = user._id integration._createdAt = new Date @@ -60,6 +61,8 @@ Meteor.methods RocketChat.models.Users.update {_id: user._id}, updateObj + RocketChat.models.Roles.addUserRoles user._id, 'bot' + integration._id = RocketChat.models.Integrations.insert integration return integration diff --git a/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/deleteIncomingIntegration.coffee similarity index 75% rename from packages/rocketchat-integrations/server/methods/deleteIntegration.coffee rename to packages/rocketchat-integrations/server/methods/incoming/deleteIncomingIntegration.coffee index d6f22c27701d26daa5f4605fb1b10315e07bfd5b..692bb014d273bbd73c344a5dbaf341aad12ee545 100644 --- a/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/deleteIncomingIntegration.coffee @@ -1,12 +1,12 @@ Meteor.methods - deleteIntegration: (integrationId) -> + deleteIncomingIntegration: (integrationId) -> if not RocketChat.authz.hasPermission @userId, 'manage-integrations' throw new Meteor.Error 'not_authorized' integration = RocketChat.models.Integrations.findOne(integrationId) if not integration? - throw new Meteor.Error 'invalid_integration', '[methods] addIntegration -> integration not found' + throw new Meteor.Error 'invalid_integration', '[methods] deleteIncomingIntegration -> integration not found' updateObj = $pull: diff --git a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee similarity index 55% rename from packages/rocketchat-integrations/server/methods/updateIntegration.coffee rename to packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee index d41d0e3d145a455cc6a0b96130792f5d79788e4b..59a93bdbbafae5e788a0cee499d1aa0fd23ece1e 100644 --- a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee @@ -1,19 +1,20 @@ Meteor.methods - updateIntegration: (integrationId, integration) -> + updateIncomingIntegration: (integrationId, integration) -> if not RocketChat.authz.hasPermission @userId, 'manage-integrations' throw new Meteor.Error 'not_authorized' if not _.isString(integration.channel) - throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel must be string' + throw new Meteor.Error 'invalid_channel', '[methods] updateIncomingIntegration -> channel must be string' if integration.channel.trim() is '' - throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel can\'t be empty' + throw new Meteor.Error 'invalid_channel', '[methods] updateIncomingIntegration -> channel can\'t be empty' if integration.channel[0] not in ['@', '#'] - throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel should start with # or @' + throw new Meteor.Error 'invalid_channel', '[methods] updateIncomingIntegration -> channel should start with # or @' - if not RocketChat.models.Integrations.findOne(integrationId)? - throw new Meteor.Error 'invalid_integration', '[methods] addIntegration -> integration not found' + currentIntegration = RocketChat.models.Integrations.findOne(integrationId) + if not currentIntegration? + throw new Meteor.Error 'invalid_integration', '[methods] updateIncomingIntegration -> integration not found' record = undefined channelType = integration.channel[0] @@ -34,12 +35,16 @@ Meteor.methods ] if record is undefined - throw new Meteor.Error 'channel_does_not_exists', "[methods] addIntegration -> The channel does not exists" + throw new Meteor.Error 'channel_does_not_exists', "[methods] updateIncomingIntegration -> The channel does not exists" + + user = RocketChat.models.Users.findOne({username: currentIntegration.username}) + RocketChat.models.Roles.addUserRoles user._id, 'bot' RocketChat.models.Integrations.update integrationId, $set: name: integration.name avatar: integration.avatar + emoji: integration.emoji alias: integration.alias channel: integration.channel _updatedAt: new Date diff --git a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee new file mode 100644 index 0000000000000000000000000000000000000000..6aab25ee634ae44e80c105f6911ad414e25a73fb --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -0,0 +1,69 @@ +Meteor.methods + addOutgoingIntegration: (integration) -> + if integration.channel?.trim? and integration.channel.trim() is '' + delete integration.channel + + if not RocketChat.authz.hasPermission(@userId, 'manage-integrations') and not RocketChat.authz.hasPermission(@userId, 'manage-integrations', 'bot') + throw new Meteor.Error 'not_authorized' + + if integration.username.trim() is '' + throw new Meteor.Error 'invalid_username', '[methods] addOutgoingIntegration -> username can\'t be empty' + + if not Match.test integration.urls, [String] + throw new Meteor.Error 'invalid_urls', '[methods] addOutgoingIntegration -> urls must be an array' + + for url, index in integration.urls + delete integration.urls[index] if url.trim() is '' + + integration.urls = _.without integration.urls, [undefined] + + if integration.urls.length is 0 + throw new Meteor.Error 'invalid_urls', '[methods] addOutgoingIntegration -> urls is required' + + if integration.channel? and integration.channel[0] not in ['@', '#'] + throw new Meteor.Error 'invalid_channel', '[methods] addOutgoingIntegration -> channel should start with # or @' + + if integration.triggerWords? + if not Match.test integration.triggerWords, [String] + throw new Meteor.Error 'invalid_triggerWords', '[methods] addOutgoingIntegration -> triggerWords must be an array' + + for triggerWord, index in integration.triggerWords + delete integration.triggerWords[index] if triggerWord.trim() is '' + + integration.triggerWords = _.without integration.triggerWords, [undefined] + + if integration.channel? + record = undefined + channelType = integration.channel[0] + channel = integration.channel.substr(1) + + switch channelType + when '#' + record = RocketChat.models.Rooms.findOne + $or: [ + {_id: channel} + {name: channel} + ] + when '@' + record = RocketChat.models.Users.findOne + $or: [ + {_id: channel} + {username: channel} + ] + + if record is undefined + throw new Meteor.Error 'channel_does_not_exists', "[methods] addOutgoingIntegration -> The channel does not exists" + + user = RocketChat.models.Users.findOne({username: integration.username}) + + if not user? + throw new Meteor.Error 'user_does_not_exists', "[methods] addOutgoingIntegration -> The username does not exists" + + integration.type = 'webhook-outgoing' + integration.userId = user._id + integration._createdAt = new Date + integration._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}} + + integration._id = RocketChat.models.Integrations.insert integration + + return integration diff --git a/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee new file mode 100644 index 0000000000000000000000000000000000000000..1808b05c2100b002ead280f7afd164ee44299e0c --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee @@ -0,0 +1,13 @@ +Meteor.methods + deleteOutgoingIntegration: (integrationId) -> + if not RocketChat.authz.hasPermission(@userId, 'manage-integrations') and not RocketChat.authz.hasPermission(@userId, 'manage-integrations', 'bot') + throw new Meteor.Error 'not_authorized' + + integration = RocketChat.models.Integrations.findOne(integrationId) + + if not integration? + throw new Meteor.Error 'invalid_integration', '[methods] deleteOutgoingIntegration -> integration not found' + + RocketChat.models.Integrations.remove _id: integrationId + + return true diff --git a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee new file mode 100644 index 0000000000000000000000000000000000000000..2e2d7afb2d1aa95dd1c5ce10d4bd047b544c51ce --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee @@ -0,0 +1,86 @@ +Meteor.methods + updateOutgoingIntegration: (integrationId, integration) -> + if not RocketChat.authz.hasPermission @userId, 'manage-integrations' + throw new Meteor.Error 'not_authorized' + + if integration.username.trim() is '' + throw new Meteor.Error 'invalid_username', '[methods] updateOutgoingIntegration -> username can\'t be empty' + + if not Match.test integration.urls, [String] + throw new Meteor.Error 'invalid_urls', '[methods] updateOutgoingIntegration -> urls must be an array' + + for url, index in integration.urls + delete integration.urls[index] if url.trim() is '' + + integration.urls = _.without integration.urls, [undefined] + + if integration.urls.length is 0 + throw new Meteor.Error 'invalid_urls', '[methods] updateOutgoingIntegration -> urls is required' + + if _.isString(integration.channel) + integration.channel = integration.channel.trim() + else + integration.channel = undefined + + if integration.channel? and integration.channel[0] not in ['@', '#'] + throw new Meteor.Error 'invalid_channel', '[methods] updateOutgoingIntegration -> channel should start with # or @' + + if not integration.token? or integration.token?.trim() is '' + throw new Meteor.Error 'invalid_token', '[methods] updateOutgoingIntegration -> token is required' + + if integration.triggerWords? + if not Match.test integration.triggerWords, [String] + throw new Meteor.Error 'invalid_triggerWords', '[methods] updateOutgoingIntegration -> triggerWords must be an array' + + for triggerWord, index in integration.triggerWords + delete integration.triggerWords[index] if triggerWord.trim() is '' + + integration.triggerWords = _.without integration.triggerWords, [undefined] + + if not RocketChat.models.Integrations.findOne(integrationId)? + throw new Meteor.Error 'invalid_integration', '[methods] updateOutgoingIntegration -> integration not found' + + + if integration.channel? + record = undefined + channelType = integration.channel[0] + channel = integration.channel.substr(1) + + switch channelType + when '#' + record = RocketChat.models.Rooms.findOne + $or: [ + {_id: channel} + {name: channel} + ] + when '@' + record = RocketChat.models.Users.findOne + $or: [ + {_id: channel} + {username: channel} + ] + + if record is undefined + throw new Meteor.Error 'channel_does_not_exists', "[methods] updateOutgoingIntegration -> The channel does not exists" + + user = RocketChat.models.Users.findOne({username: integration.username}) + + if not user? + throw new Meteor.Error 'user_does_not_exists', "[methods] updateOutgoingIntegration -> The username does not exists" + + RocketChat.models.Integrations.update integrationId, + $set: + name: integration.name + avatar: integration.avatar + emoji: integration.emoji + alias: integration.alias + channel: integration.channel + username: integration.username + userId: user._id + urls: integration.urls + token: integration.token + triggerWords: integration.triggerWords + _updatedAt: new Date + _updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}} + + return RocketChat.models.Integrations.findOne(integrationId) diff --git a/packages/rocketchat-integrations/server/processWebhookMessage.js b/packages/rocketchat-integrations/server/processWebhookMessage.js new file mode 100644 index 0000000000000000000000000000000000000000..ee684f4d59a0360818d48018184d2533c9098d4f --- /dev/null +++ b/packages/rocketchat-integrations/server/processWebhookMessage.js @@ -0,0 +1,102 @@ +this.processWebhookMessage = function(messageObj, user, defaultValues) { + var attachment, channel, channelType, i, len, message, ref, rid, room, roomUser; + + if (!defaultValues) { + defaultValues = { + channel: '', + alias: '', + avatar: '', + emoji: '' + }; + } + + channel = messageObj.channel || defaultValues.channel; + + channelType = channel[0]; + + channel = channel.substr(1); + + switch (channelType) { + case '#': + room = RocketChat.models.Rooms.findOne({ + $or: [ + { + _id: channel + }, { + name: channel + } + ] + }); + if (room == null) { + throw new Meteor.Error('invalid-channel'); + } + rid = room._id; + if (room.t === 'c') { + Meteor.runAsUser(user._id, function() { + return Meteor.call('joinRoom', room._id); + }); + } + break; + case '@': + roomUser = RocketChat.models.Users.findOne({ + $or: [ + { + _id: channel + }, { + username: channel + } + ] + }); + if (roomUser == null) { + throw new Meteor.Error('invalid-channel'); + } + rid = [user._id, roomUser._id].sort().join(''); + room = RocketChat.models.Rooms.findOne(rid); + if (!room) { + Meteor.runAsUser(user._id, function() { + Meteor.call('createDirectMessage', roomUser.username); + return room = RocketChat.models.Rooms.findOne(rid); + }); + } + break; + default: + throw new Meteor.Error('invalid-channel-type'); + } + + message = { + alias: messageObj.username || messageObj.alias || defaultValues.alias, + msg: _.trim(messageObj.text || messageObj.msg || ''), + attachments: messageObj.attachments, + parseUrls: false, + bot: messageObj.bot, + groupable: false + }; + + if ((messageObj.icon_url != null) || (messageObj.avatar != null)) { + message.avatar = messageObj.icon_url || messageObj.avatar; + } else if ((messageObj.icon_emoji != null) || (messageObj.emoji != null)) { + message.emoji = messageObj.icon_emoji || messageObj.emoji; + } else if (defaultValues.avatar != null) { + message.avatar = defaultValues.avatar; + } else if (defaultValues.emoji != null) { + message.emoji = defaultValues.emoji; + } + + if (_.isArray(message.attachments)) { + ref = message.attachments; + for (i = 0, len = ref.length; i < len; i++) { + attachment = ref[i]; + if (attachment.msg) { + attachment.text = _.trim(attachment.msg); + delete attachment.msg; + } + } + } + + var messageReturn = RocketChat.sendMessage(user, message, room, {}); + + return { + channel: channel, + message: messageReturn + } +}; diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee new file mode 100644 index 0000000000000000000000000000000000000000..72fae25524a98baef82bb60f1004dc9ace50286a --- /dev/null +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -0,0 +1,129 @@ +triggers = {} + +RocketChat.models.Integrations.find({type: 'webhook-outgoing'}).observe + added: (record) -> + channel = record.channel or '__any' + triggers[channel] ?= {} + triggers[channel][record._id] = record + + changed: (record) -> + channel = record.channel or '__any' + triggers[channel] ?= {} + triggers[channel][record._id] = record + + removed: (record) -> + channel = record.channel or '__any' + delete triggers[channel][record._id] + + +ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> + word = undefined + if trigger.triggerWords?.length > 0 + for triggerWord in trigger.triggerWords + if message.msg.indexOf(triggerWord) is 0 + word = triggerWord + break + + # Stop if there are triggerWords but none match + if not word? + return + + data = + token: trigger.token + channel_id: room._id + channel_name: room.name + timestamp: message.ts + user_id: message.u._id + user_name: message.u.username + text: message.msg + + if word? + data.trigger_word = word + + opts = + data: data + npmRequestOptions: + rejectUnauthorized: !RocketChat.settings.get 'Allow_Invalid_SelfSigned_Certs' + strictSSL: !RocketChat.settings.get 'Allow_Invalid_SelfSigned_Certs' + headers: + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36' + + HTTP.call 'POST', url, opts, (error, result) -> + if not result? or result.statusCode isnt 200 + if result.statusCode is 410 + RocketChat.models.Integrations.remove _id: trigger._id + return + + if tries <= 6 + # Try again in 0.1s, 1s, 10s, 1m40s, 16m40s, 2h46m40s and 27h46m40s + Meteor.setTimeout -> + ExecuteTriggerUrl url, trigger, message, room, tries+1 + , Math.pow(10, tries+2) + return + + # process outgoing webhook response as a new message + else if result?.statusCode is 200 and (result.data?.text? or result.data?.attachments?) + user = RocketChat.models.Users.findOneByUsername(trigger.username) + + result.data.bot = + i: trigger._id + + defaultValues = + channel: trigger.channel + alias: trigger.alias + avatar: trigger.avatar + emoji: trigger.emoji + + try + message = processWebhookMessage result.data, user, defaultValues + + if not message? + return RocketChat.API.v1.failure 'unknown-error' + + return RocketChat.API.v1.success() + catch e + return RocketChat.API.v1.failure e.error + +ExecuteTrigger = (trigger, message, room) -> + for url in trigger.urls + ExecuteTriggerUrl url, trigger, message, room + + +ExecuteTriggers = (message, room) -> + if not room? + return + + triggersToExecute = [] + + switch room.t + when 'd' + id = room._id.replace(message.u._id, '') + + username = _.without room.usernames, message.u.username + username = username[0] + + if triggers['@'+id]? + triggersToExecute.push trigger for key, trigger of triggers['@'+id] + + if id isnt username and triggers['@'+username]? + triggersToExecute.push trigger for key, trigger of triggers['@'+username] + + when 'c' + if triggers.__any? + triggersToExecute.push trigger for key, trigger of triggers.__any + + else + if triggers['#'+room._id]? + triggersToExecute.push trigger for key, trigger of triggers['#'+room._id] + + if room._id isnt room.name and triggers['#'+room.name]? + triggersToExecute.push trigger for key, trigger of triggers['#'+room.name] + + + for triggerToExecute in triggersToExecute + ExecuteTrigger triggerToExecute, message, room + + return message + + +RocketChat.callbacks.add 'afterSaveMessage', ExecuteTriggers, RocketChat.callbacks.priority.LOW diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index fd4f3f5f133ebb3ab71d08b8116a841a79c9da15..66e79c078540a68c939ad57ace51074675eef70a 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -1,14 +1,23 @@ MeteorWrapperLdapjs = Npm.require 'ldapjs' Meteor.startup -> - RocketChat.settings.addGroup 'LDAP' - RocketChat.settings.add 'LDAP_Enable', false, { type: 'boolean', group: 'LDAP', public: true } - RocketChat.settings.add 'LDAP_Url', 'ldap://', { type: 'string' , group: 'LDAP' } - RocketChat.settings.add 'LDAP_Port', '389', { type: 'string' , group: 'LDAP' } - RocketChat.settings.add 'LDAP_DN', '', { type: 'string' , group: 'LDAP', public: true } - RocketChat.settings.add 'LDAP_Bind_Search', '', { type: 'string' , group: 'LDAP' } - RocketChat.settings.add 'LDAP_Sync_User_Data', false, { type: 'boolean' , group: 'LDAP' } - RocketChat.settings.add 'LDAP_Sync_User_Data_FieldMap', '{"cn":"name", "mail":"email"}', { type: 'string' , group: 'LDAP' } + RocketChat.settings.addGroup 'LDAP', -> + enableQuery = {_id: 'LDAP_Enable', value: true} + enableTLSQuery = [ + {_id: 'LDAP_Enable', value: true} + {_id: 'LDAP_TLS', value: true} + ] + + @add 'LDAP_Enable', false, { type: 'boolean', public: true } + @add 'LDAP_TLS', false, { type: 'boolean', enableQuery: enableQuery } + @add 'LDAP_CA_Cert', '', { type: 'string', multiline: true, enableQuery: enableTLSQuery } + @add 'LDAP_Reject_Unauthorized', true, { type: 'boolean', enableQuery: enableTLSQuery } + @add 'LDAP_Url', 'ldap://', { type: 'string' , enableQuery: enableQuery } + @add 'LDAP_Port', '389', { type: 'string' , enableQuery: enableQuery } + @add 'LDAP_DN', '', { type: 'string' , public: true, enableQuery: enableQuery } + @add 'LDAP_Bind_Search', '', { type: 'string' , enableQuery: enableQuery } + @add 'LDAP_Sync_User_Data', false, { type: 'boolean' , enableQuery: enableQuery } + @add 'LDAP_Sync_User_Data_FieldMap', '{"cn":"name", "mail":"email"}', { type: 'string', enableQuery: enableQuery } timer = undefined @@ -20,11 +29,17 @@ updateServices = -> if enable? console.log "Enabling LDAP".blue + LDAP_DEFAULTS.TLS = RocketChat.settings.get 'LDAP_TLS' + LDAP_DEFAULTS.CACert = RocketChat.settings.get 'LDAP_CA_Cert' + LDAP_DEFAULTS.rejectUnauthorized = RocketChat.settings.get 'LDAP_Reject_Unauthorized' LDAP_DEFAULTS.url = RocketChat.settings.get 'LDAP_Url' LDAP_DEFAULTS.port = RocketChat.settings.get 'LDAP_Port' if RocketChat.settings.get 'LDAP_Port' LDAP_DEFAULTS.dn = RocketChat.settings.get 'LDAP_DN' or false LDAP_DEFAULTS.bindSearch = RocketChat.settings.get 'LDAP_Bind_Search' or '' else + LDAP_DEFAULTS.TLS = undefined + LDAP_DEFAULTS.CACert = undefined + LDAP_DEFAULTS.rejectUnauthorized = undefined LDAP_DEFAULTS.url = undefined LDAP_DEFAULTS.port = undefined LDAP_DEFAULTS.dn = undefined diff --git a/packages/rocketchat-ldap/i18n/de.i18n.json b/packages/rocketchat-ldap/i18n/de.i18n.json index 22e1aec0e1553993b912be11b53e78c0a31c39c5..77df8c918f8c8eff2ef9c2e360a949a020e062b9 100644 --- a/packages/rocketchat-ldap/i18n/de.i18n.json +++ b/packages/rocketchat-ldap/i18n/de.i18n.json @@ -1,3 +1,3 @@ { - "LDAP_Dn" : "LDAP DN" + "LDAP_Dn" : "LDAP-DN" } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ro.i18n.json b/packages/rocketchat-ldap/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..22e1aec0e1553993b912be11b53e78c0a31c39c5 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/ro.i18n.json @@ -0,0 +1,3 @@ +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/sr.i18n.json b/packages/rocketchat-ldap/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index d12d9346940cb7676ba75d221cc6da7d45fa8ad5..7cf5ff8c44fad5d8ebc239bfbb383e5d0690a0f9 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -11,6 +11,7 @@ var slug = function (text) { // e.g. "uid=someuser,cn=users,dc=somevalue" LDAP_DEFAULTS = { url: false, + TLS: false, port: '389', dn: false, createNewUser: true, @@ -42,6 +43,25 @@ var LDAP = function(options) { this.ldapjs = MeteorWrapperLdapjs; }; + +function startTLS(client) { + var opts = { + rejectUnauthorized: LDAP_DEFAULTS.rejectUnauthorized + }; + + if ( LDAP_DEFAULTS.CACert && LDAP_DEFAULTS.CACert != '' ){ + opts.ca = [LDAP_DEFAULTS.CACert]; + } + + var starttlsSync = Meteor.wrapAsync(client.starttls); + + var res = starttlsSync(opts , null); + if (res) { + console.log("StartTLS Result: " + res); + } +} + + /** * Attempt to bind (authenticate) ldap * and perform a dn search if specified @@ -56,17 +76,29 @@ LDAP.prototype.ldapCheck = function(options) { options = options || {}; - if (options.hasOwnProperty('username') && options.hasOwnProperty('ldapPass')) { + if (!options.hasOwnProperty('username') || !options.hasOwnProperty('ldapPass')) { + throw new Meteor.Error(403, "Missing LDAP Auth Parameter"); + } - var ldapAsyncFut = new Future(); + var ldapAsyncFut = new Future(); - // Create ldap client - var fullUrl = self.options.url + ':' + self.options.port; - var client = self.ldapjs.createClient({ - url: fullUrl - }); + // Create ldap client + var fullUrl = self.options.url + ':' + self.options.port; + var client = self.ldapjs.createClient({ + url: fullUrl, + reconnect: false + }); + + if (LDAP_DEFAULTS.TLS == true) { + startTLS(client); + } + + client.on('error', function(e) { + ldapAsyncFut.return({error: e}); + }); + client.on('connect', function(e) { var bindSync = Meteor.wrapAsync(client.bind.bind(client)); // Slide @xyz.whatever from username if it was passed in @@ -142,7 +174,7 @@ LDAP.prototype.ldapCheck = function(options) { delete opts.password; } catch(e) { console.log('LDAP: Error', e); - ldapAsyncFut.return({ + return ldapAsyncFut.return({ error: e }); } @@ -153,12 +185,14 @@ LDAP.prototype.ldapCheck = function(options) { client.search(options.ldapOptions.dn, opts, function(err, res) { if (err) { console.log('LDAP: Search Error', err); - ldapAsyncFut.return({ + return ldapAsyncFut.return({ error: err }); } + var entryCount = 0; var dn = self.options.dn; res.on('searchEntry', function(entry) { + entryCount++; dn = entry.object.dn; }); res.on('error', function(err) { @@ -168,7 +202,15 @@ LDAP.prototype.ldapCheck = function(options) { }); }); res.on('end', function(result) { - bind(dn); + if (entryCount === 1) { + bind(dn); + } else { + console.log('LDAP: Search returned', entryCount, 'record(s)'); + var err = new Error('User not Found'); + ldapAsyncFut.return({ + error: err + }); + } }); }); } catch (e) { @@ -180,13 +222,9 @@ LDAP.prototype.ldapCheck = function(options) { } else { bind(self.options.dn); } + }); - return ldapAsyncFut.wait(); - - } else { - throw new Meteor.Error(403, "Missing LDAP Auth Parameter"); - } - + return ldapAsyncFut.wait(); }; @@ -195,6 +233,7 @@ LDAP.prototype.ldapCheck = function(options) { // Meteor.loginWithLDAP on client side // @param {Object} loginRequest will consist of username, ldapPass, ldap, and ldapOptions Accounts.registerLoginHandler("ldap", function(loginRequest) { + var self = this; // If "ldap" isn't set in loginRequest object, // then this isn't the proper handler (return undefined) if (!loginRequest.ldap) { @@ -217,7 +256,24 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { var ldapResponse = ldapObj.ldapCheck(loginRequest); if (ldapResponse.error) { - throw new Meteor.Error("LDAP-login-error", ldapResponse.error); + console.log(ldapResponse.error); + console.log('[LDAP] Falling back to standard account base'); + if (typeof loginRequest.username === 'string') + if (loginRequest.username.indexOf('@') === -1) + loginRequest.username = {username: loginRequest.username}; + else + loginRequest.username = {email: loginRequest.username}; + + loginRequest = { + user: loginRequest.username, + password: { + digest: SHA256(loginRequest.ldapPass), + algorithm: "sha-256" + } + } + + return Accounts._runLoginHandlers(self, loginRequest); + // throw new Meteor.Error("LDAP-login-error", ldapResponse.error); } else { // Set initial userId and token vals var userId = null; diff --git a/packages/rocketchat-ldap/package.js b/packages/rocketchat-ldap/package.js index f832514eb3db1b35f1f12303ef1200bd60fd7910..38720bb37dd012f383c2cf913b29377c2576de4c 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -22,10 +22,11 @@ Package.onUse(function(api) { api.versionsFrom('1.0.3.1'); // Commom - api.use('rocketchat:lib@0.0.1'); - api.use('tap:i18n@1.5.1'); + api.use('rocketchat:lib'); + api.use('tap:i18n'); api.use('yasaricli:slugify'); api.use('coffeescript'); + api.use('sha'); // Client api.use('templating', 'client'); // Server diff --git a/packages/rocketchat-lib/README.md b/packages/rocketchat-lib/README.md index b00630727af688bf729b3c51b0ec9cd14d5e9ab5..68ab59d17c7927deec6a4124fd96996fc0e5862b 100644 --- a/packages/rocketchat-lib/README.md +++ b/packages/rocketchat-lib/README.md @@ -4,6 +4,49 @@ This package contains the main libraries of Rocket.Chat. ### APIs +#### Settings + +This is an example to create settings: +```javascript +RocketChat.settings.addGroup('Settings_Group', function() { + this.add('SettingInGroup', 'default_value', { type: 'boolean', public: true }); + + this.section('Group_Section', function() { + this.add('Setting_Inside_Section', 'default_value', { + type: 'boolean', + public: true, + enableQuery: { + _id: 'SettingInGroup', + value: true + } + }); + }); +}); +``` + +`RocketChat.settings.add` type: + +* `string` - Stores a string value + * Additional options: + * `multiline`: boolean +* `int` - Stores an integer value +* `boolean` - Stores a boolean value +* `select` - Creates an `<select>` element + * Additional options: + * `values`: Array of: { key: 'value', i18nLabel: 'Option_Label' } +* `color` - Creates a color pick element +* `action` - Executes a `Method.call` to `value` + * Additional options: + * `actionText`: Translatable value of the button +* `asset` - Creates an upload field + +`RocketChat.settings.add` options: + +* `description` - Description of the setting +* `public` - Boolean to set if the setting should be sent to client or not +* `enableQuery` - Only enable this setting if the correspondent setting has the value specified +* `alert` - Shows an alert message with the given text + #### roomTypes You can create your own room type using (on the client): @@ -23,7 +66,9 @@ RocketChat.roomTypes.add('l', 5, { return { name: sub.name } } }, - permissions: [ 'view-l-room' ] + condition: () => { + return RocketChat.authz.hasAllPermission('view-l-room'); + } }); ``` @@ -52,19 +97,9 @@ AccountBox.addItem({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', - route: { - name: 'livechat-manager', - path: '/livechat-manager', - action(params, queryParams) { - Session.set('openedRoom'); - BlazeLayout.render('main', { - center: 'page-container', - pageTitle: 'Live Chat Manager', - pageTemplate: 'livechat-manager' - }); - } - }, - permissions: ['view-livechat-manager'] + condition: () => { + return RocketChat.authz.hasAllPermission('view-livechat-manager'); + } }); ``` diff --git a/packages/rocketchat-lib/client/TabBar.coffee b/packages/rocketchat-lib/client/TabBar.coffee index 237024dbdd7c4738f931733b5c03aab1e90faff1..5228f2e55020c4ff1d961c21fd78a6e14069dcba 100644 --- a/packages/rocketchat-lib/client/TabBar.coffee +++ b/packages/rocketchat-lib/client/TabBar.coffee @@ -4,11 +4,15 @@ RocketChat.TabBar = new class buttons = new ReactiveVar {} + extraGroups = {} + animating = false open = new ReactiveVar false template = new ReactiveVar '' data = new ReactiveVar {} + visibleGroup = new ReactiveVar '' + setTemplate = (t, callback) -> return if animating is true template.set t @@ -65,6 +69,12 @@ RocketChat.TabBar = new class Tracker.nonreactive -> btns = buttons.get() btns[config.id] = config + + if extraGroups[config.id]? + btns[config.id].groups ?= [] + btns[config.id].groups = _.union btns[config.id].groups, extraGroups[config.id] + delete extraGroups[config.id] + buttons.set btns removeButton = (id) -> @@ -93,6 +103,23 @@ RocketChat.TabBar = new class resetButtons = -> buttons.set {} + showGroup = (group) -> + visibleGroup.set group + + getVisibleGroup = -> + visibleGroup.get() + + addGroup = (id, groups) -> + Tracker.nonreactive -> + btns = buttons.get() + if btns[id] + btns[id].groups ?= [] + btns[id].groups = _.union btns[id].groups, groups + buttons.set btns + else + extraGroups[id] ?= [] + extraGroups[id] = _.union extraGroups[id], groups + setTemplate: setTemplate setData: setData getTemplate: getTemplate @@ -108,3 +135,7 @@ RocketChat.TabBar = new class getButtons: getButtons reset: reset resetButtons: resetButtons + + showGroup: showGroup + getVisibleGroup: getVisibleGroup + addGroup: addGroup diff --git a/packages/rocketchat-lib/client/defaultTabBars.js b/packages/rocketchat-lib/client/defaultTabBars.js new file mode 100644 index 0000000000000000000000000000000000000000..6737d36c587d0f4d495a4bdf10a8876bea0a0969 --- /dev/null +++ b/packages/rocketchat-lib/client/defaultTabBars.js @@ -0,0 +1,35 @@ +RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'message-search', + i18nTitle: 'Search', + icon: 'octicon octicon-search', + template: 'messageSearch', + order: 1 +}); + +RocketChat.TabBar.addButton({ + groups: ['directmessage'], + id: 'user-info', + i18nTitle: 'User_Info', + icon: 'octicon octicon-person', + template: 'membersList', + order: 2 +}); + +RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup'], + id: 'members-list', + i18nTitle: 'Members_List', + icon: 'octicon octicon-organization', + template: 'membersList', + order: 2 +}); + +RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'uploaded-files-list', + i18nTitle: 'Room_uploaded_file_list', + icon: 'octicon octicon-file-symlink-directory', + template: 'uploadedFilesList', + order: 3 +}); diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 545dce131b85cd960539bb4b3580f566491542bb..7e74d9fd94959246dd10b8815094edd50835dd21 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -27,6 +27,7 @@ currentTracker = undefined BlazeLayout.render 'main', {center: 'roomNotFound'} return + $('.rocket-loader').remove(); mainNode = document.querySelector('.main-content') if mainNode? for child in mainNode.children @@ -50,16 +51,9 @@ currentTracker = undefined $('.message-form .input-message').focus() , 100 - RocketChat.TabBar.resetButtons() - RocketChat.TabBar.addButton({ id: 'message-search', i18nTitle: t('Search'), icon: 'octicon octicon-search', template: 'messageSearch', order: 1 }) - if type is 'd' - RocketChat.TabBar.addButton({ id: 'members-list', i18nTitle: t('User_Info'), icon: 'octicon octicon-person', template: 'membersList', order: 2 }) - else - RocketChat.TabBar.addButton({ id: 'members-list', i18nTitle: t('Members_List'), icon: 'octicon octicon-organization', template: 'membersList', order: 2 }) - RocketChat.TabBar.addButton({ id: 'uploaded-files-list', i18nTitle: t('Room_uploaded_file_list'), icon: 'octicon octicon-file-symlink-directory', template: 'uploadedFilesList', order: 3 }) - # update user's room subscription - if ChatSubscription.findOne({rid: room._id})?.open is false + sub = ChatSubscription.findOne({rid: room._id}) + if sub?.open is false Meteor.call 'openRoom', room._id - RocketChat.callbacks.run 'enter-room', ChatSubscription.findOne({rid: room._id}) + RocketChat.callbacks.run 'enter-room', sub diff --git a/packages/rocketchat-lib/client/lib/roomExit.coffee b/packages/rocketchat-lib/client/lib/roomExit.coffee index d8a44ae00a37fc9a8ad39caeffa568b27ed2b748..d7da9ed4a8718746e4b3c507e468a6411e9d59b6 100644 --- a/packages/rocketchat-lib/client/lib/roomExit.coffee +++ b/packages/rocketchat-lib/client/lib/roomExit.coffee @@ -1,4 +1,6 @@ @roomExit = -> + RocketChat.callbacks.run 'roomExit' + BlazeLayout.render 'main', {center: 'none'} if currentTracker? @@ -10,8 +12,9 @@ if child? if child.classList.contains('room-container') wrapper = child.querySelector('.messages-box > .wrapper') - if wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight - child.oldScrollTop = 10e10 - else - child.oldScrollTop = wrapper.scrollTop + if wrapper + if wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight + child.oldScrollTop = 10e10 + else + child.oldScrollTop = wrapper.scrollTop mainNode.removeChild child diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index 2e3773a8122eb20cde8049a5a13d1f456ce4b9cb..02843ea4702eb591530e7e6cc7f2c58bab0e18e4 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -3,23 +3,11 @@ RocketChat.roomTypes = new class roomTypes = {} mainOrder = 1 - protectedAction = (item) -> - # if not item.permissions? or RocketChat.authz.hasAtLeastOnePermission item.permissions - return item.route.action - - # return -> - # BlazeLayout.render 'main', - # center: 'pageContainer' - # # @TODO text Not_authorized don't get the correct language - # pageTitle: t('Not_authorized') - # pageTemplate: 'notAuthorized' - ### Adds a room type to app @param identifier An identifier to the room type. If a real room, MUST BE the same of `db.rocketchat_room.t` field, if not, can be null @param order Order number of the type @param config template: template name to render on sideNav - permissions: list of permissions to see the sideNav template icon: icon class route: name: route name @@ -45,7 +33,7 @@ RocketChat.roomTypes = new class if config.route?.path? and config.route?.name? and config.route?.action? FlowRouter.route config.route.path, name: config.route.name - action: protectedAction config + action: config.route.action triggersExit: [roomExit] ### @@ -58,14 +46,16 @@ RocketChat.roomTypes = new class return FlowRouter.path roomTypes[roomType].route.name, roomTypes[roomType].route.link(subData) + checkCondition = (roomType) -> + return not roomType.condition? or roomType.condition() + getAllTypes = -> - typesPermitted = [] + orderedTypes = [] _.sortBy(roomTypesOrder, 'order').forEach (type) -> - if not roomTypes[type.identifier].permissions? or RocketChat.authz.hasAtLeastOnePermission roomTypes[type.identifier].permissions - typesPermitted.push roomTypes[type.identifier] + orderedTypes.push roomTypes[type.identifier] - return typesPermitted + return orderedTypes getIcon = (roomType) -> return roomTypes[roomType]?.icon @@ -85,4 +75,6 @@ RocketChat.roomTypes = new class # setRoute: setRoute getRouteLink: getRouteLink + checkCondition: checkCondition + add: add diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee index 16ce89cf20f2c233761c06468f168851af0fc209..7a19eb1d3fb35ec970236196f47043f85b235000 100644 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ b/packages/rocketchat-lib/client/lib/settings.coffee @@ -38,11 +38,26 @@ Meteor.startup -> if not siteUrl or not Meteor.userId()? return - if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false + if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false or Meteor.settings.public.sandstorm return c.stop() siteUrl = siteUrl.replace /\/$/, '' if siteUrl isnt location.origin - toastr.warning TAPi18n.__('The_configured_URL_is_different_from_the_URL_you_are_accessing'), TAPi18n.__('Warning') + swal + type: 'warning' + title: t('Warning') + text: t("The_setting_s_is_configured_to_s_and_you_are_accessing_from_s", t('Site_Url'), siteUrl, location.origin) + '<br/><br/>' + t("Do_you_want_to_change_to_s_question", location.origin) + showCancelButton: true + confirmButtonText: t('Yes') + cancelButtonText: t('Cancel') + closeOnConfirm: false + html: true + , -> + Meteor.call 'saveSetting', 'Site_Url', location.origin, -> + swal + title: t('Saved') + type: 'success' + timer: 1000 + showConfirmButton: false return c.stop() diff --git a/packages/rocketchat-lib/i18n/ar.i18n.json b/packages/rocketchat-lib/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..b2b4bbb310607e261b0c8df1201622ca7e7fd039 100644 --- a/packages/rocketchat-lib/i18n/ar.i18n.json +++ b/packages/rocketchat-lib/i18n/ar.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "All_logs" : "كل السجلات", + "Delete" : "ØØ°Ù", + "Edit" : "تعديل" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/de.i18n.json b/packages/rocketchat-lib/i18n/de.i18n.json index b0d162a99b648c9d7236d8d3f27abb581bca66dc..061db4135c9217af7ddc78058d835a2c10db05ac 100644 --- a/packages/rocketchat-lib/i18n/de.i18n.json +++ b/packages/rocketchat-lib/i18n/de.i18n.json @@ -1,4 +1,7 @@ { + "All_logs" : "Alle Protokolle", + "Debug_Level" : "Debug-Level", + "Delete" : "Löschen", "Edit" : "Bearbeiten", - "Delete" : "Löschen" + "Only_errors" : "Nur Fehler" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/en.i18n.json b/packages/rocketchat-lib/i18n/en.i18n.json index b0e165dc996194714898a880cb80f9b81b423e09..f8de802dbcd68c19c65f4b7604913c8e0a6e2625 100644 --- a/packages/rocketchat-lib/i18n/en.i18n.json +++ b/packages/rocketchat-lib/i18n/en.i18n.json @@ -1,4 +1,7 @@ { + "All_logs" : "All logs", + "Debug_Level" : "Debug Level", + "Delete" : "Delete", "Edit" : "Edit", - "Delete" : "Delete" + "Only_errors" : "Only errors" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/fi.i18n.json b/packages/rocketchat-lib/i18n/fi.i18n.json index f283462d8f20c210b14553b1c3c17da4acea4428..22892d14afcdedca05a6c16cb143e4290d6618d6 100644 --- a/packages/rocketchat-lib/i18n/fi.i18n.json +++ b/packages/rocketchat-lib/i18n/fi.i18n.json @@ -1,4 +1,7 @@ { + "All_logs" : "Kaikki lokit", + "Debug_Level" : "Debug-taso", + "Delete" : "Poista", "Edit" : "Muokkaa", - "Delete" : "Poista" + "Only_errors" : "Vain virheet" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/fr.i18n.json b/packages/rocketchat-lib/i18n/fr.i18n.json index 6fcd2330c33793ab254abbc95a87d661e29a92c0..af1d286560d4732bce2a156e606deefccace2a73 100644 --- a/packages/rocketchat-lib/i18n/fr.i18n.json +++ b/packages/rocketchat-lib/i18n/fr.i18n.json @@ -1,4 +1,6 @@ { + "All_logs" : "Tous les journaux", + "Delete" : "Supprimer", "Edit" : "Modifier", - "Delete" : "Supprimer" + "Only_errors" : "Seules les erreurs" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/he.i18n.json b/packages/rocketchat-lib/i18n/he.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..53b1d1e98eb64a0709a0846c46c29e5298a07cdd 100644 --- a/packages/rocketchat-lib/i18n/he.i18n.json +++ b/packages/rocketchat-lib/i18n/he.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "All_logs" : "כל ×”×™×•×ž× ×™×", + "Debug_Level" : "רמת פירוט", + "Delete" : "מחיקה", + "Only_errors" : "שגי×ות בלבד" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/hr.i18n.json b/packages/rocketchat-lib/i18n/hr.i18n.json index 247eb268a3c435b68b8f098edd085331410e5c0a..487e25187be3df3fb4c76dccf60b0c5ae69fabed 100644 --- a/packages/rocketchat-lib/i18n/hr.i18n.json +++ b/packages/rocketchat-lib/i18n/hr.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Uredi", - "Delete" : "ObriÅ¡i" + "Delete" : "ObriÅ¡i", + "Edit" : "Uredi" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/km.i18n.json b/packages/rocketchat-lib/i18n/km.i18n.json index 0db86550f900f25f327791234b252eb0e194d2ef..6e4efda1491e155c327edb2d3bf275603eba5be7 100644 --- a/packages/rocketchat-lib/i18n/km.i18n.json +++ b/packages/rocketchat-lib/i18n/km.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "កែ​សម្រួល", - "Delete" : "លុប" + "Delete" : "លុប", + "Edit" : "កែ​សម្រួល" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ko.i18n.json b/packages/rocketchat-lib/i18n/ko.i18n.json index b454f6fb4a396dac50ac6a5e0ab65e71d1a355f4..fc308db9155bae2c107a60030de485b5842ae2d4 100644 --- a/packages/rocketchat-lib/i18n/ko.i18n.json +++ b/packages/rocketchat-lib/i18n/ko.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "ìˆ˜ì •", - "Delete" : "ì‚ì œ" + "Delete" : "ì‚ì œ", + "Edit" : "ìˆ˜ì •" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ms-MY.i18n.json b/packages/rocketchat-lib/i18n/ms-MY.i18n.json index 1c06d12d0c6e020f77830dce783473288ff64d59..bfe97c78cb240d185e5d58586ac8840ed3a291cb 100644 --- a/packages/rocketchat-lib/i18n/ms-MY.i18n.json +++ b/packages/rocketchat-lib/i18n/ms-MY.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Sunting", - "Delete" : "Padam" + "Delete" : "Padam", + "Edit" : "Sunting" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/nl.i18n.json b/packages/rocketchat-lib/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..39d4c63986ee7caf430a3e4e142e378af51d8bcd 100644 --- a/packages/rocketchat-lib/i18n/nl.i18n.json +++ b/packages/rocketchat-lib/i18n/nl.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "All_logs" : "Alle logs", + "Debug_Level" : "Debug Level", + "Delete" : "Verwijder", + "Edit" : "Wijzig", + "Only_errors" : "Alleen fouten" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/pl.i18n.json b/packages/rocketchat-lib/i18n/pl.i18n.json index f0a5a7f12d23523abf20979ebe37c7ea9f5901b4..9b98eea9a2a7c85060a76bc95b25091114cde216 100644 --- a/packages/rocketchat-lib/i18n/pl.i18n.json +++ b/packages/rocketchat-lib/i18n/pl.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Edycja", - "Delete" : "UsuÅ„" + "Delete" : "UsuÅ„", + "Edit" : "Edycja" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/pt.i18n.json b/packages/rocketchat-lib/i18n/pt.i18n.json index 7c1bc08766f41b0d8e6f48cf824fc5a4cba307ed..94accdb5b74bb98183cc32641f769b285c69f2b2 100644 --- a/packages/rocketchat-lib/i18n/pt.i18n.json +++ b/packages/rocketchat-lib/i18n/pt.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Editar", - "Delete" : "Deletar" + "Delete" : "Deletar", + "Edit" : "Editar" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ro.i18n.json b/packages/rocketchat-lib/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..974ae6298ae9636855175b0a64ad425db7f73def --- /dev/null +++ b/packages/rocketchat-lib/i18n/ro.i18n.json @@ -0,0 +1,7 @@ +{ + "All_logs" : "Toate înregistrările", + "Debug_Level" : "Debug Level", + "Delete" : "Șterge", + "Edit" : "Editează", + "Only_errors" : "Doar erori" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ru.i18n.json b/packages/rocketchat-lib/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..1a0f7a2f5aaa5780c1832be101282d6da5961d30 100644 --- a/packages/rocketchat-lib/i18n/ru.i18n.json +++ b/packages/rocketchat-lib/i18n/ru.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Delete" : "Удалить", + "Edit" : "Редактировать" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/sr.i18n.json b/packages/rocketchat-lib/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-lib/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/tr.i18n.json b/packages/rocketchat-lib/i18n/tr.i18n.json index 230736a85351678f1c3d3f2b7d48473b6bb3e3e6..fe60600ba2d3f8f7d3a4693526e0d87c5467482d 100644 --- a/packages/rocketchat-lib/i18n/tr.i18n.json +++ b/packages/rocketchat-lib/i18n/tr.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Düzenle", - "Delete" : "Sil" + "Delete" : "Sil", + "Edit" : "Düzenle" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/zh.i18n.json b/packages/rocketchat-lib/i18n/zh.i18n.json index 4a3796cadc9228cb35cdd5374a75d9d3d32e7296..297bc71c15ea96488a72d04d40a30823fa36fd5b 100644 --- a/packages/rocketchat-lib/i18n/zh.i18n.json +++ b/packages/rocketchat-lib/i18n/zh.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "编辑", - "Delete" : "åˆ é™¤" + "Delete" : "åˆ é™¤", + "Edit" : "编辑" } \ No newline at end of file diff --git a/packages/rocketchat-lib/lib/Message.coffee b/packages/rocketchat-lib/lib/Message.coffee new file mode 100644 index 0000000000000000000000000000000000000000..cbf6e92a89ff0e80376e19e12bfa538ea6abdeb2 --- /dev/null +++ b/packages/rocketchat-lib/lib/Message.coffee @@ -0,0 +1,26 @@ +RocketChat.Message = + parse: (msg, language) -> + messageType = RocketChat.MessageTypes.getType(msg) + if messageType?.render? + return messageType.render(msg) + else if messageType?.template? + # render template + else if messageType?.message? + if not language and localStorage?.getItem('userLanguage') + language = localStorage.getItem('userLanguage') + if messageType.data?(msg)? + return TAPi18n.__(messageType.message, messageType.data(msg), language) + else + return TAPi18n.__(messageType.message, {}, language) + else + if msg.u?.username is RocketChat.settings.get('Chatops_Username') + msg.html = msg.msg + return msg.html + + msg.html = msg.msg + if _.trim(msg.html) isnt '' + msg.html = _.escapeHTML msg.html + + # message = RocketChat.callbacks.run 'renderMessage', msg + msg.html = msg.html.replace /\n/gm, '<br/>' + return msg.html diff --git a/packages/rocketchat-lib/client/MessageTypes.coffee b/packages/rocketchat-lib/lib/MessageTypes.coffee similarity index 55% rename from packages/rocketchat-lib/client/MessageTypes.coffee rename to packages/rocketchat-lib/lib/MessageTypes.coffee index 3e374f4d7cace7513e86cf03b9d796585a742a02..58f651d4586d4a5f121de0149d4f8f1520a7f6bc 100644 --- a/packages/rocketchat-lib/client/MessageTypes.coffee +++ b/packages/rocketchat-lib/lib/MessageTypes.coffee @@ -68,3 +68,45 @@ Meteor.startup -> id: 'rtc' render: (message) -> RocketChat.callbacks.run 'renderRtcMessage', message + + RocketChat.MessageTypes.registerType + id: 'user-muted' + system: true + message: 'User_muted_by' + data: (message) -> + return { user_muted: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'user-unmuted' + system: true + message: 'User_unmuted_by' + data: (message) -> + return { user_unmuted: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'new-moderator' + system: true + message: 'User__username__was_added_as_a_moderator_by__user_by_' + data: (message) -> + return { username: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'moderator-removed' + system: true + message: 'User__username__was_removed_as_a_moderator_by__user_by_' + data: (message) -> + return { username: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'new-owner' + system: true + message: 'User__username__was_added_as_a_owner_by__user_by_' + data: (message) -> + return { username: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'owner-removed' + system: true + message: 'User__username__was_removed_as_a_owner_by__user_by_' + data: (message) -> + return { username: message.msg, user_by: message.u.username } diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 897bd0bab52cb71c4c7c823acebc60bdd9b579a8..5f2639f86fdc741d73f86ff96c95705f8f6dfcf7 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -22,13 +22,20 @@ Package.onUse(function(api) { api.use('service-configuration'); api.use('check'); api.use('arunoda:streams'); + api.use('rocketchat:version'); api.use('kadira:flow-router', 'client'); - // COMMON LIB api.addFiles('lib/core.coffee'); + + // DEBUGGER + api.addFiles('server/lib/debug.js', 'server'); + + // COMMON LIB api.addFiles('lib/settings.coffee'); api.addFiles('lib/callbacks.coffee'); api.addFiles('lib/slashCommand.coffee'); + api.addFiles('lib/Message.coffee'); + api.addFiles('lib/MessageTypes.coffee'); // SERVER LIB api.addFiles('server/lib/RateLimiter.coffee', 'server'); @@ -62,6 +69,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/saveSetting.coffee', 'server'); api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); api.addFiles('server/methods/sendMessage.coffee', 'server'); + api.addFiles('server/methods/sendSMTPTestEmail.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); @@ -70,6 +78,7 @@ Package.onUse(function(api) { // SERVER STARTUP api.addFiles('server/startup/settingsOnLoadCdnPrefix.coffee', 'server'); + api.addFiles('server/startup/settingsOnLoadSMTP.coffee', 'server'); api.addFiles('server/startup/oAuthServicesUpdate.coffee', 'server'); api.addFiles('server/startup/settings.coffee', 'server'); @@ -88,7 +97,11 @@ Package.onUse(function(api) { api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); api.addFiles('client/MessageAction.coffee', 'client'); - api.addFiles('client/MessageTypes.coffee', 'client'); + + api.addFiles('client/defaultTabBars.js', 'client'); + + // VERSION + api.addFiles('rocketchat.info'); // TAPi18n api.use('templating', 'client'); @@ -99,9 +112,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); // EXPORT api.export('RocketChat'); diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info new file mode 100644 index 0000000000000000000000000000000000000000..37f939dff5bfb57635a8edd8cd3df2cd23141af7 --- /dev/null +++ b/packages/rocketchat-lib/rocketchat.info @@ -0,0 +1,3 @@ +{ + "version": "0.14.0" +} diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index 20620d1c9dc55f6d3fc8701ce8374664fb5f6ccb..fa30388ff35ff8b4d127e89b120adb80f5ac74cf 100644 --- a/packages/rocketchat-lib/server/functions/sendMessage.coffee +++ b/packages/rocketchat-lib/server/functions/sendMessage.coffee @@ -11,7 +11,7 @@ RocketChat.sendMessage = (user, message, room, options) -> message.rid = room._id if message.parseUrls isnt false - if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g + if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([^\s]+)?)?/g message.urls = urls.map (url) -> url: url message = RocketChat.callbacks.run 'beforeSaveMessage', message @@ -30,7 +30,7 @@ RocketChat.sendMessage = (user, message, room, options) -> ### Meteor.defer -> - RocketChat.callbacks.run 'afterSaveMessage', message + RocketChat.callbacks.run 'afterSaveMessage', message, room ### Update all the room activity tracker fields diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index da23f4970b57347ea426a766bfc6c8eacbc3e254..cee48c9cad45dc8ec19b6def09f73be144f5c1fa 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -40,6 +40,7 @@ RocketChat._setUsername = (userId, username) -> RocketChat.models.Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername msg._id, previousUsername, username, updatedMsg RocketChat.models.Rooms.replaceUsername previousUsername, username + RocketChat.models.Rooms.replaceMutedUsername previousUsername, username RocketChat.models.Rooms.replaceUsernameOfUserByUserId user._id, username RocketChat.models.Subscriptions.setUserUsernameByUserId user._id, username diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 34f829a6d9d0a305bcc389fe8a1db56f4eb28e81..81b4099fe66a59c554efd676451a9d90bdcfd985 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -1,3 +1,5 @@ +RocketChat.settings._sorter = 0 + ### # Add a setting # @param {String} _id @@ -14,6 +16,10 @@ RocketChat.settings.add = (_id, value, options = {}) -> options.valueSource = 'packageValue' options.ts = new Date options.hidden = false + options.sorter ?= RocketChat.settings._sorter++ + + if options.enableQuery? + options.enableQuery = JSON.stringify options.enableQuery if process?.env?[_id]? value = process.env[_id] @@ -32,23 +38,33 @@ RocketChat.settings.add = (_id, value, options = {}) -> if not options.i18nDescription? options.i18nDescription = "#{_id}_Description" - return RocketChat.models.Settings.upsert { _id: _id }, + updateOperations = $set: options $setOnInsert: value: value createdAt: new Date + if not options.section? + updateOperations.$unset = { section: 1 } + + return RocketChat.models.Settings.upsert { _id: _id }, updateOperations + + ### # Add a setting group # @param {String} _id ### -RocketChat.settings.addGroup = (_id, options = {}) -> +RocketChat.settings.addGroup = (_id, options = {}, cb) -> # console.log '[functions] RocketChat.settings.addGroup -> '.green, 'arguments:', arguments if not _id return false + if _.isFunction(options) + cb = options + options = {} + if not options.i18nLabel? options.i18nLabel = _id @@ -58,12 +74,27 @@ RocketChat.settings.addGroup = (_id, options = {}) -> options.ts = new Date options.hidden = false - return RocketChat.models.Settings.upsert { _id: _id }, + RocketChat.models.Settings.upsert { _id: _id }, $set: options $setOnInsert: type: 'group' createdAt: new Date + if cb? + cb.call + add: (id, value, options = {}) -> + options.group = _id + RocketChat.settings.add id, value, options + + section: (section, cb) -> + cb.call + add: (id, value, options = {}) -> + options.group = _id + options.section = section + RocketChat.settings.add id, value, options + + return + ### # Remove a setting by id @@ -91,6 +122,19 @@ RocketChat.settings.updateById = (_id, value) -> return RocketChat.models.Settings.updateValueById _id, value +### +# Update options of a setting by id +# @param {String} _id +### +RocketChat.settings.updateOptionsById = (_id, options) -> + # console.log '[functions] RocketChat.settings.updateOptionsById -> '.green, 'arguments:', arguments + + if not _id or not options? + return false + + return RocketChat.models.Settings.updateOptionsById _id, options + + ### # Update a setting by id # @param {String} _id @@ -112,14 +156,17 @@ RocketChat.settings.init = -> RocketChat.models.Settings.find().observe added: (record) -> Meteor.settings[record._id] = record.value - process.env[record._id] = record.value + if record.env is true + process.env[record._id] = record.value RocketChat.settings.load record._id, record.value, initialLoad changed: (record) -> Meteor.settings[record._id] = record.value - process.env[record._id] = record.value + if record.env is true + process.env[record._id] = record.value RocketChat.settings.load record._id, record.value, initialLoad removed: (record) -> delete Meteor.settings[record._id] - delete process.env[record._id] + if record.env is true + delete process.env[record._id] RocketChat.settings.load record._id, undefined, initialLoad initialLoad = false diff --git a/packages/rocketchat-lib/server/lib/debug.js b/packages/rocketchat-lib/server/lib/debug.js new file mode 100644 index 0000000000000000000000000000000000000000..1ccc9791d31b8f4d6441be9227caab3cf66e4a3e --- /dev/null +++ b/packages/rocketchat-lib/server/lib/debug.js @@ -0,0 +1,46 @@ +RocketChat.debugLevel = 'debug'; + +Meteor.startup(function() { + RocketChat.settings.onload('Debug_Level', function(key, value, initialLoad) { + if (value) { + RocketChat.debugLevel = value; + } + }); + + var value = RocketChat.settings.get('Debug_Level'); + if (value) { + RocketChat.debugLevel = value; + } +}); + +var wrapMethods = function(name, originalHandler, methodsMap) { + methodsMap[name] = function() { + if (RocketChat.debugLevel === 'debug') { + var args = name === "ufsWrite" ? Array.prototype.slice.call(arguments, 1) : arguments; + console.log('[methods]'.green, name, '-> userId:', Meteor.userId(), ', arguments: ', args); + } + + return originalHandler.apply(this, arguments); + }; +}; + +var originalMeteorMethods = Meteor.methods; + +Meteor.methods = function(methodMap) { + _.each(methodMap, function(handler, name) { + wrapMethods(name, handler, methodMap); + }); + originalMeteorMethods(methodMap); +}; + +var originalMeteorPublish = Meteor.publish; + +Meteor.publish = function(name, func) { + return originalMeteorPublish(name, function() { + if (RocketChat.debugLevel === 'debug') { + console.log('[publish]'.green, name, '-> userId:', this.userId, ', arguments: ', arguments); + } + + return func.apply(this, arguments); + }) +}; diff --git a/packages/rocketchat-lib/server/methods/addOAuthService.coffee b/packages/rocketchat-lib/server/methods/addOAuthService.coffee index 4545add58416ea93414ac1ac01edadeeace8d9c6..b115a6d4bb3e5223bb5f3b70fd39f576fb55e8a6 100644 --- a/packages/rocketchat-lib/server/methods/addOAuthService.coffee +++ b/packages/rocketchat-lib/server/methods/addOAuthService.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] addOAuthService -> Invalid user") - console.log '[methods] addOAuthService -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - unless RocketChat.authz.hasPermission( Meteor.userId(), 'add-oauth-service') is true throw new Meteor.Error 'not-authorized', '[methods] addOAuthService -> Not authorized' @@ -17,6 +15,7 @@ Meteor.methods RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_authorize_path" , '/oauth/authorize', { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Authorize_Path', persistent: true } RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_id" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_id', persistent: true } RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_secret" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Secret', persistent: true } + RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_login_style" , 'popup' , { type: 'select' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Login_Style', persistent: true, values: [ { key: 'redirect', i18nLabel: 'Redirect' }, { key: 'popup', i18nLabel: 'Popup' }, { key: '', i18nLabel: 'Default' } ] } RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_label_text" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Text', persistent: true } RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_label_color", '#FFFFFF' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Color', persistent: true } RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_color" , '#13679A' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Color', persistent: true } diff --git a/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee b/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee index a69c22fffe43e99f3a946a5c6dcd334023358194..592b85470995143fba4caaf3ba22e11de7ec55f9 100644 --- a/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee +++ b/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee @@ -1,4 +1,3 @@ Meteor.methods checkRegistrationSecretURL: (hash) -> - console.log '[method] checkRegistrationSecretURL'.green, hash return hash is RocketChat.settings.get 'Accounts_RegistrationForm_SecretURL' diff --git a/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee b/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee index 97218c2df15e04ef6bb2823626a0cb0565216f7a..3087fb387f430b9699110fd83fcf3cd2e9d979c3 100644 --- a/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee +++ b/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] joinDefaultChannels -> Invalid user") - console.log '[methods] joinDefaultChannels -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - user = Meteor.user() RocketChat.callbacks.run 'beforeJoinDefaultChannels', user diff --git a/packages/rocketchat-lib/server/methods/removeOAuthService.coffee b/packages/rocketchat-lib/server/methods/removeOAuthService.coffee index 60d94fef7eeb8a9618bc972e090324d6b018d2f0..221b2495df2f5bd20f140f82c16a2aadd716bddc 100644 --- a/packages/rocketchat-lib/server/methods/removeOAuthService.coffee +++ b/packages/rocketchat-lib/server/methods/removeOAuthService.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] addOAuthService -> Invalid user") - console.log '[methods] addOAuthService -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - unless RocketChat.authz.hasPermission( Meteor.userId(), 'add-oauth-service') is true throw new Meteor.Error 'not-authorized', '[methods] addOAuthService -> Not authorized' diff --git a/packages/rocketchat-lib/server/methods/robotMethods.coffee b/packages/rocketchat-lib/server/methods/robotMethods.coffee index 664cb049bda7d24e22d156cbae5a576e3faff77b..4a101fdacf1ce680349c1572c598f4f092b1123f 100644 --- a/packages/rocketchat-lib/server/methods/robotMethods.coffee +++ b/packages/rocketchat-lib/server/methods/robotMethods.coffee @@ -6,8 +6,6 @@ Meteor.methods unless RocketChat.authz.hasRole Meteor.userId(), 'robot' throw new Meteor.Error 'unauthorized', '[methods] robot.modelCall -> Unauthorized' - console.log '[method] robot.modelCall'.green, arguments - unless _.isFunction RocketChat.models[model]?[method] throw new Meteor.Error 'invalid-method', '[methods] robot.modelCall -> Invalid method' diff --git a/packages/rocketchat-lib/server/methods/saveSetting.coffee b/packages/rocketchat-lib/server/methods/saveSetting.coffee index b2775cb055c1b2c5f963df3b0e01c1ef0d618ae6..0b6c1cad55a2c403ca121f74c9aba2110afc6a80 100644 --- a/packages/rocketchat-lib/server/methods/saveSetting.coffee +++ b/packages/rocketchat-lib/server/methods/saveSetting.coffee @@ -1,6 +1,5 @@ Meteor.methods saveSetting: (_id, value) -> - console.log '[method] saveSetting', _id, value if Meteor.userId()? user = Meteor.users.findOne Meteor.userId() diff --git a/packages/rocketchat-lib/server/methods/sendMessage.coffee b/packages/rocketchat-lib/server/methods/sendMessage.coffee index 527470eeb9e75fab4d555cee7b6b1e36193b6148..bec44f79f1a79520abb1ea2f3ed2d650c81499de 100644 --- a/packages/rocketchat-lib/server/methods/sendMessage.coffee +++ b/packages/rocketchat-lib/server/methods/sendMessage.coffee @@ -6,8 +6,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] sendMessage -> Invalid user") - console.log '[methods] sendMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - user = RocketChat.models.Users.findOneById Meteor.userId(), fields: username: 1 room = Meteor.call 'canAccessRoom', message.rid, user._id @@ -15,6 +13,15 @@ Meteor.methods if not room return false + if user.username in (room.muted or []) + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: room._id + ts: new Date + msg: TAPi18n.__('You_have_been_muted', {}, user.language); + } + return false + RocketChat.sendMessage user, message, room, options # Limit a user to sending 5 msgs/second diff --git a/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee b/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d766f129c99482c7e3f68d3e9498e754a5b47f58 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee @@ -0,0 +1,29 @@ +Meteor.methods + sendSMTPTestEmail: -> + if not Meteor.userId() + throw new Meteor.Error 'invalid-user', "[methods] sendSMTPTestEmail -> Invalid user" + + user = Meteor.user() + unless user.emails?[0]?.address + throw new Meteor.Error 'invalid-email', "[methods] sendSMTPTestEmail -> Invalid e-mail" + + Email.send + to: user.emails[0].address + from: RocketChat.settings.get('From_Email') + subject: "SMTP Test E-mail" + html: "You have successfully sent an e-mail" + + console.log 'Sending email to ' + user.emails[0].address + + return { + message: "Your_mail_was_sent_to_s" + params: [user.emails[0].address] + } + +# Limit a user to sending 1 test mail/second +DDPRateLimiter.addRule + type: 'method' + name: 'sendSMTPTestEmail' + userId: (userId) -> + return true +, 1, 1000 diff --git a/packages/rocketchat-lib/server/methods/setAdminStatus.coffee b/packages/rocketchat-lib/server/methods/setAdminStatus.coffee index b81d6d9f04f62db1ee3817794d0afd9854d3f5c2..542c5853fd094f682c17af4225fdc2527cf22cb4 100644 --- a/packages/rocketchat-lib/server/methods/setAdminStatus.coffee +++ b/packages/rocketchat-lib/server/methods/setAdminStatus.coffee @@ -7,8 +7,8 @@ Meteor.methods throw new Meteor.Error 'not-authorized', '[methods] setAdminStatus -> Not authorized' if admin - RocketChat.authz.addUsersToRoles( userId, 'admin') + RocketChat.authz.addUserRoles( userId, 'admin') else - RocketChat.authz.removeUsersFromRoles( userId, 'admin') + RocketChat.authz.removeUserFromRoles( userId, 'admin') return true diff --git a/packages/rocketchat-lib/server/methods/setRealName.coffee b/packages/rocketchat-lib/server/methods/setRealName.coffee index 2a913c93f3eccb44f92c2bb4d63499330ba96f32..92a2c9b078e1e14edc185f1dec2afe639525a36f 100644 --- a/packages/rocketchat-lib/server/methods/setRealName.coffee +++ b/packages/rocketchat-lib/server/methods/setRealName.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] setRealName -> Invalid user") - console.log '[methods] setRealName -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - user = Meteor.user() if user.name is name diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index f9e62785daf2c0d1907d85b5b0a8075e9cc36fd4..c74ec4a6b21f39fdcc0da7bd61f505e24c96336e 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -8,8 +8,6 @@ Meteor.methods if user.username? and not RocketChat.settings.get("Accounts_AllowUsernameChange") throw new Meteor.Error(403, "[methods] setUsername -> Username change not allowed") - console.log '[methods] setUsername -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - if user.username is username return username @@ -22,7 +20,7 @@ Meteor.methods throw new Meteor.Error 'username-invalid', "#{username} is not a valid username, use only letters, numbers, dots and dashes" if user.username != undefined - if not username.toLowerCase() == user.username.toLowerCase() + if not username.toLowerCase() == user.username.toLowerCase() if not RocketChat.checkUsernameAvailability username throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" else diff --git a/packages/rocketchat-lib/server/methods/updateUser.coffee b/packages/rocketchat-lib/server/methods/updateUser.coffee index 9a20d41012221417c70dc3176a562077088f4b80..2416d3d11846058197b35372e529bc6bc88c2c1c 100644 --- a/packages/rocketchat-lib/server/methods/updateUser.coffee +++ b/packages/rocketchat-lib/server/methods/updateUser.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] updateUser -> Invalid user") - console.log '[methods] updateUser -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - user = Meteor.user() canEditUserPermission = RocketChat.authz.hasPermission( user._id, 'edit-other-user-info') @@ -25,4 +23,8 @@ Meteor.methods Meteor.runAsUser userData._id, -> Meteor.call 'setUsername', userData.username - return true \ No newline at end of file + canEditUserPassword = RocketChat.authz.hasPermission( user._id, 'edit-other-user-password') + if canEditUserPassword and userData.password.trim() + Accounts.setPassword userData._id, userData.password.trim() + + return true diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index b7449cddf4757cd9b6aa2a05183eae6672cfa6b3..c7e7bf5ba00811df1d543f3ac89af416065e67b1 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -24,6 +24,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find query, options + findVisibleByMentionAndRoomId: (username, rid, options) -> + query = + _hidden: { $ne: true } + "mentions.username": username + "rid": rid + + return @find query, options + findVisibleByRoomId: (roomId, options) -> query = _hidden: @@ -108,6 +116,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find(query, options)?.fetch?()?[0]?.ts + findByRoomIdAndMessageIds: (rid, messageIds, options) -> + query = + rid: rid + _id: + $in: messageIds + + return @find query, options + cloneAndSaveAsHistoryById: (_id) -> me = RocketChat.models.Users.findOneById Meteor.userId() record = @findOneById _id @@ -126,7 +142,6 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @insert record - # UPDATE setHiddenById: (_id, hidden=true) -> query = @@ -148,6 +163,8 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base msg: '' t: 'rm' urls: [] + mentions: [] + attachments: [] editedAt: new Date() editedBy: _id: Meteor.userId() @@ -266,12 +283,33 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base message = user.username return @createWithTypeRoomIdMessageAndUser 'au', roomId, message, user, extraData - createRoomRenamedWithRoomIdRoomNameAndUser: (roomId, roomName, user, extraData) -> - return @createWithTypeRoomIdMessageAndUser 'r', roomId, roomName, user, extraData - createCommandWithRoomIdAndUser: (command, roomId, user, extraData) -> return @createWithTypeRoomIdMessageAndUser 'command', roomId, command, user, extraData + createUserMutedWithRoomIdAndUser: (roomId, user, extraData) -> + message = user.username + return @createWithTypeRoomIdMessageAndUser 'user-muted', roomId, message, user, extraData + + createUserUnmutedWithRoomIdAndUser: (roomId, user, extraData) -> + message = user.username + return @createWithTypeRoomIdMessageAndUser 'user-unmuted', roomId, message, user, extraData + + createNewModeratorWithRoomIdAndUser: (roomId, user, extraData) -> + message = user.username + return @createWithTypeRoomIdMessageAndUser 'new-moderator', roomId, message, user, extraData + + createModeratorRemovedWithRoomIdAndUser: (roomId, user, extraData) -> + message = user.username + return @createWithTypeRoomIdMessageAndUser 'moderator-removed', roomId, message, user, extraData + + createNewOwnerWithRoomIdAndUser: (roomId, user, extraData) -> + message = user.username + return @createWithTypeRoomIdMessageAndUser 'new-owner', roomId, message, user, extraData + + createOwnerRemovedWithRoomIdAndUser: (roomId, user, extraData) -> + message = user.username + return @createWithTypeRoomIdMessageAndUser 'owner-removed', roomId, message, user, extraData + # REMOVE removeById: (_id) -> query = diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index e1588bc548419cc9003d11d04b401f48a17b91c0..4befae7bfe04eb56461e5ded048e15751f4760d4 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -147,6 +147,17 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @find query, options + findByTypeAndArchivationState: (type, archivationstate, options) -> + query = + t: type + + if archivationstate + query.archived = true + else + query.archived = { $ne: true } + + return @find query, options + findByVisitorToken: (visitorToken, options) -> query = "v.token": visitorToken @@ -278,6 +289,16 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @update query, update, { multi: true } + replaceMutedUsername: (previousUsername, username) -> + query = + muted: previousUsername + + update = + $set: + "muted.$": username + + return @update query, update, { multi: true } + replaceUsernameOfUserByUserId: (userId, username) -> query = "u._id": userId @@ -310,6 +331,36 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @update query, update + setTopicById: (_id, topic) -> + query = + _id: _id + + update = + $set: + topic: topic + + return @update query, update + + muteUsernameByRoomId: (_id, username) -> + query = + _id: _id + + update = + $addToSet: + muted: username + + return @update query, update + + unmuteUsernameByRoomId: (_id, username) -> + query = + _id: _id + + update = + $pull: + muted: username + + return @update query, update + # INSERT createWithTypeNameUserAndUsernames: (type, name, user, usernames, extraData) -> diff --git a/packages/rocketchat-lib/server/models/Settings.coffee b/packages/rocketchat-lib/server/models/Settings.coffee index 282c9262b6b84ce1760d023d325c86e77e0f534a..c16d51c83164c4e7fa6bd250e785d9625f6b12fb 100644 --- a/packages/rocketchat-lib/server/models/Settings.coffee +++ b/packages/rocketchat-lib/server/models/Settings.coffee @@ -37,6 +37,16 @@ RocketChat.models.Settings = new class extends RocketChat.models._Base return @update query, update + updateOptionsById: (_id, options) -> + query = + _id: _id + + update = + $set: options + + return @update query, update + + # REMOVE createWithIdAndValue: (_id, value) -> record = diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 20910f4e03d88a568d093e31c3b51fb26d31817c..5a3248071206e749829baa63dfaee4668cb9dbf3 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -25,6 +25,15 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @find query, options + # FIND + findByRoomIdAndRoles: (roomId, roles, options) -> + roles = [].concat roles + query = + "rid": roomId + "roles": { $in: roles } + + return @find query, options + getLastSeen: (options = {}) -> query = { ls: { $exists: 1 } } options.sort = { ls: -1 } @@ -54,7 +63,7 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base update = $set: alert: false - open: false + open: true archived: false return @update query, update @@ -210,6 +219,25 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @update query, update, { multi: true } + addRoleById: (_id, role) -> + query = + _id: _id + + update = + $addToSet: + roles: role + + return @update query, update + + removeRoleById: (_id, role) -> + query = + _id: _id + + update = + $pull: + roles: role + + return @update query, update # INSERT createWithRoomAndUser: (room, user, extraData) -> diff --git a/packages/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index f72dc4db3436451de00ad5e0e71fb58a1b1a3228..9e9aaf502b32de11d48ebaf9ba85b22d82944cc2 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -46,6 +46,13 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @findOne query, options + findOneByIdAndLoginToken: (_id, token, options) -> + query = + _id: _id + 'services.resume.loginTokens.hashedToken' : Accounts._hashLoginToken(token) + + return @findOne query, options + # FIND findUsersNotOffline: (options) -> @@ -64,6 +71,24 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @find query, options + findActiveByUsernameRegexWithExceptions: (username, exceptions = [], options = {}) -> + console.log 'findActiveByUsernameRegexWithExceptions', username, exceptions + if not _.isArray exceptions + exceptions = [ exceptions ] + + usernameRegex = new RegExp username, "i" + query = + $and: [ + { active: true } + { username: { $nin: exceptions } } + { username: usernameRegex } + ] + # username: { $regex: usernameRegex, $nin: exceptions } + # username: { $nin: exceptions } + + console.log 'findActiveByUsernameRegexWithExceptions query', JSON.stringify query, null, ' ' + return @find query, options + findByActiveUsersNameOrUsername: (nameOrUsername, options) -> query = username: diff --git a/packages/rocketchat-lib/server/publications/settings.coffee b/packages/rocketchat-lib/server/publications/settings.coffee index c3d5beb0a4f53965daaaf50ba273a9f58f457445..f5454f90107f514706575a3cc864cf7509427189 100644 --- a/packages/rocketchat-lib/server/publications/settings.coffee +++ b/packages/rocketchat-lib/server/publications/settings.coffee @@ -1,6 +1,4 @@ Meteor.publish 'settings', (ids = []) -> - console.log '[publish] settings'.green - filter = hidden: { $ne: true } public: true @@ -12,8 +10,6 @@ Meteor.publish 'settings', (ids = []) -> return RocketChat.models.Settings.find filter, { fields: _id: 1, value: 1 } Meteor.publish 'admin-settings', -> - console.log '[publish] admin-settings'.green - unless @userId return @ready() diff --git a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee index eb796abc309180597f2d308c3b52b665e3eef8cc..75b30d643e2ef305a26c8c376331fce28505d090 100644 --- a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee +++ b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee @@ -29,12 +29,14 @@ oAuthServicesUpdate = -> data.authorizePath = RocketChat.models.Settings.findOneById("#{service._id}_authorize_path")?.value data.buttonLabelText = RocketChat.models.Settings.findOneById("#{service._id}_button_label_text")?.value data.buttonLabelColor = RocketChat.models.Settings.findOneById("#{service._id}_button_label_color")?.value + data.loginStyle = RocketChat.models.Settings.findOneById("#{service._id}_login_style")?.value data.buttonColor = RocketChat.models.Settings.findOneById("#{service._id}_button_color")?.value new CustomOAuth serviceName.toLowerCase(), serverURL: data.serverURL tokenPath: data.tokenPath identityPath: data.identityPath authorizePath: data.authorizePath + loginStyle: data.loginStyle if serviceName is 'Facebook' data.appId = data.clientId diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 688e0cd49248ab5b4c72fac8815bf16d46b54a28..4f3bf96d8cb93e636a585e5cad7bf8172fdef116 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -2,141 +2,169 @@ if not RocketChat.models.Settings.findOneById 'uniqueID' RocketChat.models.Settings.createWithIdAndValue 'uniqueID', Random.id() -RocketChat.settings.addGroup 'Accounts' -RocketChat.settings.add 'Accounts_EmailVerification', false, { type: 'boolean', group: 'Accounts', public: true, section: 'Registration' } -RocketChat.settings.add 'Accounts_ManuallyApproveNewUsers', false, { type: 'boolean', group: 'Accounts', section: 'Registration' } -RocketChat.settings.add 'Accounts_AllowedDomainsList', '', { type: 'string', group: 'Accounts', public: true, section: 'Registration' } - -RocketChat.settings.add 'Accounts_RegistrationForm', 'Public', { type: 'select', group: 'Accounts', public: true, section: 'Registration', values: [ { key: 'Public', i18nLabel: 'Accounts_RegistrationForm_Public' }, { key: 'Disabled', i18nLabel: 'Accounts_RegistrationForm_Disabled' }, { key: 'Secret URL', i18nLabel: 'Accounts_RegistrationForm_Secret_URL' } ] } -RocketChat.settings.add 'Accounts_RegistrationForm_SecretURL', Random.id(), { type: 'string', group: 'Accounts', section: 'Registration' } -RocketChat.settings.add 'Accounts_RegistrationForm_LinkReplacementText', 'New user registration is currently disabled', { type: 'string', group: 'Accounts', section: 'Registration', public: true } -RocketChat.settings.add 'Accounts_Registration_AuthenticationServices_Enabled', true, { type: 'boolean', group: 'Accounts', section: 'Registration', public: true } - -RocketChat.settings.add 'Accounts_PasswordReset', true, { type: 'boolean', group: 'Accounts', public: true, section: 'Registration' } - -RocketChat.settings.add 'Accounts_AvatarStoreType', 'GridFS', { type: 'string', group: 'Accounts', section: 'Avatar' } -RocketChat.settings.add 'Accounts_AvatarStorePath', '', { type: 'string', group: 'Accounts', section: 'Avatar' } -RocketChat.settings.add 'Accounts_AvatarResize', false, { type: 'boolean', group: 'Accounts', section: 'Avatar' } -RocketChat.settings.add 'Accounts_AvatarSize', 200, { type: 'int', group: 'Accounts', section: 'Avatar' } - -RocketChat.settings.add 'Accounts_OAuth_Facebook', false, { type: 'boolean', group: 'Accounts', section: 'Facebook', public: true } -RocketChat.settings.add 'Accounts_OAuth_Facebook_id', '', { type: 'string', group: 'Accounts', section: 'Facebook' } -RocketChat.settings.add 'Accounts_OAuth_Facebook_secret', '', { type: 'string', group: 'Accounts', section: 'Facebook' } -RocketChat.settings.add 'Accounts_OAuth_Google', false, { type: 'boolean', group: 'Accounts', section: 'Google', public: true } -RocketChat.settings.add 'Accounts_OAuth_Google_id', '', { type: 'string', group: 'Accounts', section: 'Google' } -RocketChat.settings.add 'Accounts_OAuth_Google_secret', '', { type: 'string', group: 'Accounts', section: 'Google' } -RocketChat.settings.add 'Accounts_OAuth_Github', false, { type: 'boolean', group: 'Accounts', section: 'Github', public: true } -RocketChat.settings.add 'Accounts_OAuth_Github_id', '', { type: 'string', group: 'Accounts', section: 'Github' } -RocketChat.settings.add 'Accounts_OAuth_Github_secret', '', { type: 'string', group: 'Accounts', section: 'Github' } -RocketChat.settings.add 'Accounts_OAuth_Gitlab', false, { type: 'boolean', group: 'Accounts', section: 'Gitlab', public: true } -RocketChat.settings.add 'Accounts_OAuth_Gitlab_id', '', { type: 'string', group: 'Accounts', section: 'Gitlab' } -RocketChat.settings.add 'Accounts_OAuth_Gitlab_secret', '', { type: 'string', group: 'Accounts', section: 'Gitlab' } -RocketChat.settings.add 'Accounts_OAuth_Linkedin', false, { type: 'boolean', group: 'Accounts', section: 'Linkedin', public: true } -RocketChat.settings.add 'Accounts_OAuth_Linkedin_id', '', { type: 'string', group: 'Accounts', section: 'Linkedin' } -RocketChat.settings.add 'Accounts_OAuth_Linkedin_secret', '', { type: 'string', group: 'Accounts', section: 'Linkedin' } -RocketChat.settings.add 'Accounts_OAuth_Meteor', false, { type: 'boolean', group: 'Accounts', section: 'Meteor', public: true } -RocketChat.settings.add 'Accounts_OAuth_Meteor_id', '', { type: 'string', group: 'Accounts', section: 'Meteor' } -RocketChat.settings.add 'Accounts_OAuth_Meteor_secret', '', { type: 'string', group: 'Accounts', section: 'Meteor' } -RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', group: 'Accounts', section: 'Twitter', public: true } -RocketChat.settings.add 'Accounts_OAuth_Twitter_id', '', { type: 'string', group: 'Accounts', section: 'Twitter' } -RocketChat.settings.add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', group: 'Accounts', section: 'Twitter' } - -RocketChat.settings.add 'Accounts_AllowUserProfileChange', true, { type: 'boolean', group: 'Accounts', section: 'General', public: true } -RocketChat.settings.add 'Accounts_AllowUserAvatarChange', true, { type: 'boolean', group: 'Accounts', section: 'General', public: true } -RocketChat.settings.add 'Accounts_AllowUsernameChange', true, { type: 'boolean', group: 'Accounts', section: 'General', public: true } -RocketChat.settings.add 'Accounts_AllowPasswordChange', true, { type: 'boolean', group: 'Accounts', section: 'General', public: true } -RocketChat.settings.add 'Accounts_RequireNameForSignUp', true, { type: 'boolean', group: 'Accounts', section: 'General', public: true } - -RocketChat.settings.add 'Accounts_LoginExpiration', 90, { type: 'int', group: 'Accounts', section: 'General', public: true } - -RocketChat.settings.addGroup 'FileUpload' -RocketChat.settings.add 'FileUpload_Enabled', true, { type: 'boolean', group: 'FileUpload', public: true } -RocketChat.settings.add 'FileUpload_MaxFileSize', 2097152, { type: 'int', group: 'FileUpload', public: true } -RocketChat.settings.add 'FileUpload_MediaTypeWhiteList', 'image/*,audio/*,application/pdf,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document', { type: 'string', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } - - -RocketChat.settings.addGroup 'General' -RocketChat.settings.add 'Site_Url', __meteor_runtime_config__?.ROOT_URL, { type: 'string', group: 'General', i18nDescription: 'Site_Url_Description', public: true } -RocketChat.settings.add 'Site_Name', 'Rocket.Chat', { type: 'string', group: 'General', public: true } -RocketChat.settings.add 'Allow_Invalid_SelfSigned_Certs', false, { type: 'boolean', group: 'General' } -RocketChat.settings.add 'Disable_Favorite_Rooms', false, { type: 'boolean', group: 'General' } -RocketChat.settings.add 'CDN_PREFIX', '', { type: 'string', group: 'General' } -RocketChat.settings.add 'Restart', 'restart_server', { type: 'action', group: 'General', actionText: 'Restart_the_server' } - -RocketChat.settings.add 'UTF8_Names_Validation', '[0-9a-zA-Z-_.]+', { type: 'string', group: 'General', section: 'UTF8', public: true ,i18nDescription: 'UTF8_Names_Validation_Description'} -RocketChat.settings.add 'UTF8_Names_Slugify', true, { type: 'boolean', group: 'General', section: 'UTF8', public: true } - -RocketChat.settings.addGroup 'API' -RocketChat.settings.add 'API_Analytics', '', { type: 'string', group: 'API', public: true } -RocketChat.settings.add 'API_Embed', true, { type: 'boolean', group: 'API', public: true } -RocketChat.settings.add 'API_EmbedDisabledFor', '', { type: 'string', group: 'API', public: true, i18nDescription: 'API_EmbedDisabledFor_Description' } - -RocketChat.settings.addGroup 'SMTP' -RocketChat.settings.add 'SMTP_Host', '', { type: 'string', group: 'SMTP' } -RocketChat.settings.add 'SMTP_Port', '', { type: 'string', group: 'SMTP' } -RocketChat.settings.add 'SMTP_Username', '', { type: 'string', group: 'SMTP' } -RocketChat.settings.add 'SMTP_Password', '', { type: 'string', group: 'SMTP' } -RocketChat.settings.add 'From_Email', '', { type: 'string', group: 'SMTP', placeholder: 'email@domain' } - -RocketChat.settings.add 'Invitation_Subject', 'You have been invited to Rocket.Chat', { type: 'string', group: 'SMTP', section: 'Invitation' } -RocketChat.settings.add 'Invitation_HTML', '<h2>You have been invited to <h1>Rocket.Chat</h1></h2><p>Go to ' + __meteor_runtime_config__?.ROOT_URL + ' and try the best open source chat solution available today!</p>', { type: 'string', multiline: true, group: 'SMTP', section: 'Invitation' } -RocketChat.settings.add 'Accounts_Enrollment_Email', '', { type: 'string', multiline: true, group: 'SMTP', section: 'Invitation' } - -RocketChat.settings.addGroup 'Message' -RocketChat.settings.add 'Message_AllowEditing', true, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_AllowEditing_BlockEditInMinutes', 0, { type: 'int', group: 'Message', public: true, i18nDescription: 'Message_AllowEditing_BlockEditInMinutesDescription' } -RocketChat.settings.add 'Message_AllowDeleting', true, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_AllowPinning', true, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_ShowEditedStatus', true, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_ShowDeletedStatus', false, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_KeepHistory', false, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_MaxAllowedSize', 5000, { type: 'int', group: 'Message', public: true } -RocketChat.settings.add 'Message_ShowFormattingTips', true, { type: 'boolean', group: 'Message', public: true } -RocketChat.settings.add 'Message_AudioRecorderEnabled', true, { type: 'boolean', group: 'Message', public: true, i18nDescription: 'Message_AudioRecorderEnabledDescription' } - -RocketChat.settings.addGroup 'Meta' -RocketChat.settings.add 'Meta_language', '', { type: 'string', group: 'Meta' } -RocketChat.settings.add 'Meta_fb_app_id', '', { type: 'string', group: 'Meta' } -RocketChat.settings.add 'Meta_robots', '', { type: 'string', group: 'Meta' } -RocketChat.settings.add 'Meta_google-site-verification', '', { type: 'string', group: 'Meta' } -RocketChat.settings.add 'Meta_msvalidate01', '', { type: 'string', group: 'Meta' } - -RocketChat.settings.addGroup 'Push' -RocketChat.settings.add 'Push_debug', false, { type: 'boolean', group: 'Push', public: true } -RocketChat.settings.add 'Push_enable', true, { type: 'boolean', group: 'Push', public: true } -RocketChat.settings.add 'Push_enable_gateway', true, { type: 'boolean', group: 'Push' } -RocketChat.settings.add 'Push_gateway', 'https://rocket.chat', { type: 'string', group: 'Push' } -RocketChat.settings.add 'Push_production', true, { type: 'boolean', group: 'Push', public: true } -RocketChat.settings.add 'Push_test_push', 'push_test', { type: 'action', group: 'Push', actionText: 'Send_a_test_push_to_my_user' } -RocketChat.settings.add 'Push_apn_passphrase', '', { type: 'string', group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_apn_key', '', { type: 'string', multiline: true, group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_apn_cert', '', { type: 'string', multiline: true, group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_apn_dev_passphrase', '', { type: 'string', group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_apn_dev_key', '', { type: 'string', multiline: true, group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_apn_dev_cert', '', { type: 'string', multiline: true, group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_gcm_api_key', '', { type: 'string', group: 'Push', section: 'Certificates_and_Keys' } -RocketChat.settings.add 'Push_gcm_project_number', '', { type: 'string', group: 'Push', public: true, section: 'Certificates_and_Keys' } - -RocketChat.settings.addGroup 'Layout' -RocketChat.settings.add 'Layout_Home_Title', 'Home', { type: 'string', group: 'Layout', public: true, section: 'Content' } -RocketChat.settings.add 'Layout_Home_Body', 'Welcome to Rocket.Chat <br> Go to APP SETTINGS -> Layout to customize this intro.', { type: 'string', multiline: true, group: 'Layout', public: true, section: 'Content' } -RocketChat.settings.add 'Layout_Terms_of_Service', 'Terms of Service <br> Go to APP SETTINGS -> Layout to customize this page.', { type: 'string', multiline: true, group: 'Layout', public: true, section: 'Content' } -RocketChat.settings.add 'Layout_Privacy_Policy', 'Privacy Policy <br> Go to APP SETTINGS -> Layout to customize this page.', { type: 'string', multiline: true, group: 'Layout', public: true, section: 'Content' } -RocketChat.settings.add 'Layout_Sidenav_Footer', '<div><a href="https://github.com/RocketChat/Rocket.Chat" class="logo" target="_blank"> <img src="/images/logo/logo.svg?v=3" /></a><div class="github-tagline"><span class="octicon octicon-pencil" style="color: #994C00"></span> with <span class="octicon octicon-heart" style="color: red"></span> on <span class="octicon octicon-mark-github"></span></div></div>', { type: 'string', group: 'Layout', public: true, i18nDescription: 'Layout_Sidenav_Footer_description' } -RocketChat.settings.add 'Layout_Login_Header', '<a class="logo" href="/"><img src="/images/logo/logo.svg?v=3" /></a>', { type: 'string', multiline: true, group: 'Layout', public: true, section: 'Login' } -RocketChat.settings.add 'Layout_Login_Terms', 'By proceeding to create your account and use Rocket.Chat, you are agreeing to our <a href="/terms-of-service">Terms of Service</a> and <a href="/privacy-policy">Privacy Policy</a>. If you do not agree, you cannot use Rocket.Chat.', { type: 'string', multiline: true, group: 'Layout', public: true, section: 'Login' } +RocketChat.settings.addGroup 'Accounts', -> + @add 'Accounts_AllowUserProfileChange', true, { type: 'boolean', public: true } + @add 'Accounts_AllowUserAvatarChange', true, { type: 'boolean', public: true } + @add 'Accounts_AllowUsernameChange', true, { type: 'boolean', public: true } + @add 'Accounts_AllowPasswordChange', true, { type: 'boolean', public: true } + @add 'Accounts_RequireNameForSignUp', true, { type: 'boolean', public: true } + @add 'Accounts_LoginExpiration', 90, { type: 'int', public: true } + @add 'Accounts_ShowFormLogin', true, { type: 'boolean', public: true } + + @section 'Registration', -> + @add 'Accounts_EmailVerification', false, { type: 'boolean', public: true } + @add 'Accounts_ManuallyApproveNewUsers', false, { type: 'boolean' } + @add 'Accounts_AllowedDomainsList', '', { type: 'string', public: true } + @add 'Accounts_RegistrationForm', 'Public', { type: 'select', public: true, values: [ { key: 'Public', i18nLabel: 'Accounts_RegistrationForm_Public' }, { key: 'Disabled', i18nLabel: 'Accounts_RegistrationForm_Disabled' }, { key: 'Secret URL', i18nLabel: 'Accounts_RegistrationForm_Secret_URL' } ] } + @add 'Accounts_RegistrationForm_SecretURL', Random.id(), { type: 'string' } + @add 'Accounts_RegistrationForm_LinkReplacementText', 'New user registration is currently disabled', { type: 'string', public: true } + @add 'Accounts_Registration_AuthenticationServices_Enabled', true, { type: 'boolean', public: true } + @add 'Accounts_PasswordReset', true, { type: 'boolean', public: true } + + @section 'Avatar', -> + @add 'Accounts_AvatarResize', true, { type: 'boolean' } + @add 'Accounts_AvatarSize', 200, { type: 'int', enableQuery: {_id: 'Accounts_AvatarResize', value: true} } + @add 'Accounts_AvatarStoreType', 'GridFS', { type: 'select', values: [ { key: 'GridFS', i18nLabel: 'GridFS' }, { key: 'FileSystem', i18nLabel: 'FileSystem' } ] } + @add 'Accounts_AvatarStorePath', '', { type: 'string', enableQuery: {_id: 'Accounts_AvatarStoreType', value: 'FileSystem'} } + + @section 'Facebook', -> + @add 'Accounts_OAuth_Facebook', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Facebook_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Facebook', value: true} } + @add 'Accounts_OAuth_Facebook_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Facebook', value: true} } + + @section 'Google', -> + @add 'Accounts_OAuth_Google', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Google_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Google', value: true} } + @add 'Accounts_OAuth_Google_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Google', value: true} } + + @section 'Github', -> + @add 'Accounts_OAuth_Github', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Github_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Github', value: true} } + @add 'Accounts_OAuth_Github_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Github', value: true} } + + @section 'Gitlab', -> + @add 'Accounts_OAuth_Gitlab', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Gitlab_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Gitlab', value: true} } + @add 'Accounts_OAuth_Gitlab_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Gitlab', value: true} } + + @section 'Linkedin', -> + @add 'Accounts_OAuth_Linkedin', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Linkedin_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Linkedin', value: true} } + @add 'Accounts_OAuth_Linkedin_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Linkedin', value: true} } + + @section 'Meteor', -> + @add 'Accounts_OAuth_Meteor', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Meteor_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Meteor', value: true} } + @add 'Accounts_OAuth_Meteor_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Meteor', value: true} } + + @section 'Twitter', -> + @add 'Accounts_OAuth_Twitter', false, { type: 'boolean', public: true } + @add 'Accounts_OAuth_Twitter_id', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Twitter', value: true} } + @add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', enableQuery: {_id: 'Accounts_OAuth_Twitter', value: true} } + + +RocketChat.settings.addGroup 'FileUpload', -> + @add 'FileUpload_Enabled', true, { type: 'boolean', public: true } + @add 'FileUpload_MaxFileSize', 2097152, { type: 'int', public: true } + @add 'FileUpload_MediaTypeWhiteList', 'image/*,audio/*,application/pdf,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document', { type: 'string', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } + @add 'FileUpload_ProtectFiles', true, { type: 'boolean', public: true, i18nDescription: 'FileUpload_ProtectFilesDescription' } + + +RocketChat.settings.addGroup 'General', -> + @add 'Site_Url', __meteor_runtime_config__?.ROOT_URL, { type: 'string', i18nDescription: 'Site_Url_Description', public: true } + @add 'Site_Name', 'Rocket.Chat', { type: 'string', public: true } + @add 'Language', '', { type: 'language', public: true } + @add 'Allow_Invalid_SelfSigned_Certs', false, { type: 'boolean' } + @add 'Disable_Favorite_Rooms', false, { type: 'boolean' } + @add 'CDN_PREFIX', '', { type: 'string' } + @add 'Force_SSL', false, { type: 'boolean', public: true } + @add 'Debug_Level', 'error', { type: 'select', values: [ { key: 'error', i18nLabel: 'Only_errors' }, { key: 'debug', i18nLabel: 'All_logs' } ] } + @add 'Restart', 'restart_server', { type: 'action', actionText: 'Restart_the_server' } + + @section 'UTF8', -> + @add 'UTF8_Names_Validation', '[0-9a-zA-Z-_.]+', { type: 'string', public: true, i18nDescription: 'UTF8_Names_Validation_Description'} + @add 'UTF8_Names_Slugify', true, { type: 'boolean', public: true } + + +RocketChat.settings.addGroup 'API', -> + @add 'API_Analytics', '', { type: 'string', public: true } + @add 'API_Embed', true, { type: 'boolean', public: true } + @add 'API_EmbedDisabledFor', '', { type: 'string', public: true, i18nDescription: 'API_EmbedDisabledFor_Description' } + + +RocketChat.settings.addGroup 'SMTP', -> + @add 'SMTP_Host', '', { type: 'string', env: true } + @add 'SMTP_Port', '', { type: 'string', env: true } + @add 'SMTP_Username', '', { type: 'string', env: true } + @add 'SMTP_Password', '', { type: 'string', env: true } + @add 'From_Email', '', { type: 'string', placeholder: 'email@domain' } + @add 'SMTP_Test_Button', 'sendSMTPTestEmail', { type: 'action', actionText: 'Send_a_test_mail_to_my_user' } + + @section 'Invitation', -> + @add 'Invitation_Subject', 'You have been invited to Rocket.Chat', { type: 'string' } + @add 'Invitation_HTML', '<h2>You have been invited to <h1>Rocket.Chat</h1></h2><p>Go to ' + __meteor_runtime_config__?.ROOT_URL + ' and try the best open source chat solution available today!</p>', { type: 'string', multiline: true } + @add 'Accounts_Enrollment_Email', '', { type: 'string', multiline: true } + + +RocketChat.settings.addGroup 'Message', -> + @add 'Message_AllowEditing', true, { type: 'boolean', public: true } + @add 'Message_AllowEditing_BlockEditInMinutes', 0, { type: 'int', public: true, i18nDescription: 'Message_AllowEditing_BlockEditInMinutesDescription' } + @add 'Message_AllowDeleting', true, { type: 'boolean', public: true } + @add 'Message_AllowPinning', true, { type: 'boolean', public: true } + @add 'Message_ShowEditedStatus', true, { type: 'boolean', public: true } + @add 'Message_ShowDeletedStatus', false, { type: 'boolean', public: true } + @add 'Message_KeepHistory', false, { type: 'boolean', public: true } + @add 'Message_MaxAllowedSize', 5000, { type: 'int', public: true } + @add 'Message_ShowFormattingTips', true, { type: 'boolean', public: true } + @add 'Message_AudioRecorderEnabled', true, { type: 'boolean', public: true, i18nDescription: 'Message_AudioRecorderEnabledDescription' } + @add 'Message_GroupingPeriod', 300, { type: 'int', public: true, i18nDescription: 'Message_GroupingPeriodDescription' } + + +RocketChat.settings.addGroup 'Meta', -> + @add 'Meta_language', '', { type: 'string' } + @add 'Meta_fb_app_id', '', { type: 'string' } + @add 'Meta_robots', '', { type: 'string' } + @add 'Meta_google-site-verification', '', { type: 'string' } + @add 'Meta_msvalidate01', '', { type: 'string' } + + +RocketChat.settings.addGroup 'Push', -> + @add 'Push_debug', false, { type: 'boolean', public: true } + @add 'Push_enable', true, { type: 'boolean', public: true } + @add 'Push_enable_gateway', true, { type: 'boolean' } + @add 'Push_gateway', 'https://rocket.chat', { type: 'string' } + @add 'Push_production', true, { type: 'boolean', public: true } + @add 'Push_test_push', 'push_test', { type: 'action', actionText: 'Send_a_test_push_to_my_user' } + + @section 'Certificates_and_Keys', -> + @add 'Push_apn_passphrase', '', { type: 'string' } + @add 'Push_apn_key', '', { type: 'string', multiline: true } + @add 'Push_apn_cert', '', { type: 'string', multiline: true } + @add 'Push_apn_dev_passphrase', '', { type: 'string' } + @add 'Push_apn_dev_key', '', { type: 'string', multiline: true } + @add 'Push_apn_dev_cert', '', { type: 'string', multiline: true } + @add 'Push_gcm_api_key', '', { type: 'string' } + @add 'Push_gcm_project_number', '', { type: 'string', public: true } + + +RocketChat.settings.addGroup 'Layout', -> + @add 'Layout_Sidenav_Footer', '<div><a href="https://github.com/RocketChat/Rocket.Chat" class="logo" target="_blank"> <img src="/images/logo/logo.svg?v=3" /></a><div class="github-tagline"><span class="octicon octicon-pencil" style="color: #994C00"></span> with <span class="octicon octicon-heart" style="color: red"></span> on <span class="octicon octicon-mark-github"></span></div></div>', { type: 'string', public: true, i18nDescription: 'Layout_Sidenav_Footer_description' } + + @section 'Content', -> + @add 'Layout_Home_Title', 'Home', { type: 'string', public: true } + @add 'Layout_Home_Body', 'Welcome to Rocket.Chat <br> Go to APP SETTINGS -> Layout to customize this intro.', { type: 'string', multiline: true, public: true } + @add 'Layout_Terms_of_Service', 'Terms of Service <br> Go to APP SETTINGS -> Layout to customize this page.', { type: 'string', multiline: true, public: true } + @add 'Layout_Privacy_Policy', 'Privacy Policy <br> Go to APP SETTINGS -> Layout to customize this page.', { type: 'string', multiline: true, public: true } + + @section 'Login', -> + @add 'Layout_Login_Header', '<a class="logo" href="/"><img src="/images/logo/logo.svg?v=3" /></a>', { type: 'string', multiline: true, public: true } + @add 'Layout_Login_Terms', 'By proceeding to create your account and use Rocket.Chat, you are agreeing to our <a href="/terms-of-service">Terms of Service</a> and <a href="/privacy-policy">Privacy Policy</a>. If you do not agree, you cannot use Rocket.Chat.', { type: 'string', multiline: true, public: true } + RocketChat.settings.add 'Statistics_opt_out', false, { type: 'boolean', group: false } RocketChat.settings.init() -Meteor.startup -> - if process?.env? and not process.env['MAIL_URL']? and RocketChat.settings.get('SMTP_Host') and RocketChat.settings.get('SMTP_Username') and RocketChat.settings.get('SMTP_Password') - process.env['MAIL_URL'] = "smtp://" + encodeURIComponent(RocketChat.settings.get('SMTP_Username')) + ':' + encodeURIComponent(RocketChat.settings.get('SMTP_Password')) + '@' + encodeURIComponent(RocketChat.settings.get('SMTP_Host')) - if RocketChat.settings.get('SMTP_Port') - process.env['MAIL_URL'] += ':' + parseInt(RocketChat.settings.get('SMTP_Port')) - - # Remove runtime settings (non-persistent) Meteor.startup -> RocketChat.models.Settings.update({ ts: { $lt: RocketChat.settings.ts }, persistent: { $ne: true } }, { $set: { hidden: true } }, { multi: true }) diff --git a/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee new file mode 100644 index 0000000000000000000000000000000000000000..67dfa65a82d2cb2374fd0dceacea0adcd4c6409a --- /dev/null +++ b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee @@ -0,0 +1,28 @@ +buildMailURL = _.debounce -> + console.log 'Updating process.env.MAIL_URL' + if RocketChat.settings.get('SMTP_Host') + process.env.MAIL_URL = "smtp://" + if RocketChat.settings.get('SMTP_Username') and RocketChat.settings.get('SMTP_Password') + process.env.MAIL_URL += encodeURIComponent(RocketChat.settings.get('SMTP_Username')) + ':' + encodeURIComponent(RocketChat.settings.get('SMTP_Password')) + '@' + process.env.MAIL_URL += encodeURIComponent(RocketChat.settings.get('SMTP_Host')) + if RocketChat.settings.get('SMTP_Port') + process.env.MAIL_URL += ':' + parseInt(RocketChat.settings.get('SMTP_Port')) +, 500 + +RocketChat.settings.onload 'SMTP_Host', (key, value, initialLoad) -> + if _.isString value + buildMailURL() + +RocketChat.settings.onload 'SMTP_Port', (key, value, initialLoad) -> + buildMailURL() + +RocketChat.settings.onload 'SMTP_Username', (key, value, initialLoad) -> + if _.isString value + buildMailURL() + +RocketChat.settings.onload 'SMTP_Password', (key, value, initialLoad) -> + if _.isString value + buildMailURL() + +Meteor.startup -> + buildMailURL() diff --git a/packages/rocketchat-livechat/app/.meteor/packages b/packages/rocketchat-livechat/app/.meteor/packages index 2f093f9100633e0fd58a54206b268cc3a555239b..83352a667a8daa77adcac18c085970cd760072e1 100644 --- a/packages/rocketchat-livechat/app/.meteor/packages +++ b/packages/rocketchat-livechat/app/.meteor/packages @@ -36,3 +36,5 @@ accounts-password standard-minifiers tap:i18n kevohagan:sweetalert +ecmascript +es5-shim diff --git a/packages/rocketchat-livechat/app/.meteor/versions b/packages/rocketchat-livechat/app/.meteor/versions index 34a2055ee61dc848e2ce7ba89515432a142a3791..3105a3bc809018b69d429eb62a7e20ba24c33fd9 100644 --- a/packages/rocketchat-livechat/app/.meteor/versions +++ b/packages/rocketchat-livechat/app/.meteor/versions @@ -27,6 +27,7 @@ ecmascript@0.1.6 ecmascript-runtime@0.2.6 ejson@1.0.7 email@1.0.8 +es5-shim@4.1.14 geojson-utils@1.0.4 html-tools@1.0.5 htmljs@1.0.5 diff --git a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee index 2cee37e8e78ff79d5d921e54e590336b5743cabf..842976af3615e7e0d5311a866ea29e6217fbac4d 100644 --- a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee +++ b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee @@ -93,11 +93,11 @@ class @ChatMessages showError error.reason if not Meteor.userId() - Meteor.call 'registerGuest', visitor.getToken(), (error, result) -> + Meteor.call 'livechat:registerGuest', { token: visitor.getToken() }, (error, result) -> if error? return showError error.reason - Meteor.loginWithPassword result.user, result.pass, (error) -> + Meteor.loginWithToken result.token, (error) -> if error return showError error.reason diff --git a/packages/rocketchat-livechat/app/client/lib/collections.coffee b/packages/rocketchat-livechat/app/client/lib/collections.coffee index 48b9e6fcd371f79351bdcf63768bc4c9b9d07740..c86ad59f9dde87d990bf26b7e8aa5ef400b6fc53 100644 --- a/packages/rocketchat-livechat/app/client/lib/collections.coffee +++ b/packages/rocketchat-livechat/app/client/lib/collections.coffee @@ -1,3 +1,5 @@ @ChatMessage = new Meteor.Collection null @ChatRoom = new Meteor.Collection 'rocketchat_room' @Settings = new Meteor.Collection 'rocketchat_settings' +@Trigger = new Meteor.Collection 'rocketchat_livechat_trigger' +@Department = new Meteor.Collection 'rocketchat_livechat_department' diff --git a/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee b/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee index c12bd00df8d2a45e0b35ff3c4f915a223ef17e21..d21a2a296144c0c111377321e28972a2e5a63c67 100644 --- a/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee +++ b/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee @@ -30,6 +30,8 @@ ts = new Date Meteor.call 'loadHistory', rid, ts, limit, undefined, (err, result) -> + return if err? + for item in result?.messages or [] if item.t isnt 'command' ChatMessage.upsert {_id: item._id}, item diff --git a/packages/rocketchat-livechat/app/client/lib/hooks.js b/packages/rocketchat-livechat/app/client/lib/hooks.js new file mode 100644 index 0000000000000000000000000000000000000000..1342000e2ed72e039c070b290e15785e39aac62c --- /dev/null +++ b/packages/rocketchat-livechat/app/client/lib/hooks.js @@ -0,0 +1,21 @@ +var api = { + pageVisited: function(info) { + Triggers.processRequest(info); + + Meteor.call('livechat:pageVisited', visitor.getToken(), info); + } +}; + +window.addEventListener('message', function(msg) { + if (typeof msg.data === 'object' && msg.data.src !== undefined && msg.data.src === 'rocketchat') { + if (api[msg.data.fn] !== undefined && typeof api[msg.data.fn] === 'function') { + var args = [].concat(msg.data.args || []) + api[msg.data.fn].apply(null, args); + } + } +}, false); + +// tell parent window that we are ready +Meteor.startup(function() { + parentCall('ready'); +}); diff --git a/packages/rocketchat-livechat/app/client/lib/triggers.js b/packages/rocketchat-livechat/app/client/lib/triggers.js new file mode 100644 index 0000000000000000000000000000000000000000..354e55d986d50e2c553a95d5ba12d06234c6b042 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/lib/triggers.js @@ -0,0 +1,79 @@ +this.Triggers = (function() { + var triggers = []; + var initiated = false; + var requests = []; + + var init = function() { + initiated = true; + Tracker.autorun(function() { + triggers = Trigger.find().fetch(); + + if (requests.length > 0 && triggers.length > 0) { + requests.forEach(function(request) { + processRequest(request); + }); + + requests = []; + } + }); + }; + + var fire = function(actions) { + if (Meteor.userId()) { + console.log('already logged user - does nothing'); + return; + } + actions.forEach(function(action) { + if (action.name === 'send-message') { + var roomId = visitor.getRoom(); + + if (!roomId) { + roomId = Random.id(); + visitor.setRoom(roomId); + } + + Session.set('triggered', true); + ChatMessage.insert({ + msg: action.params.msg, + rid: roomId, + u: { + username: action.params.name + } + }); + + parentCall('openWidget'); + } + }); + }; + + var processRequest = function(request) { + if (!initiated) { + return requests.push(request); + } + triggers.forEach(function(trigger) { + trigger.conditions.forEach(function(condition) { + switch (condition.name) { + case 'page-url': + if (request.location.href.match(new RegExp(condition.value))) { + fire(trigger.actions); + } + break; + + case 'time-on-site': + if (trigger.timeout) { + clearTimeout(trigger.timeout); + } + trigger.timeout = setTimeout(function() { + fire(trigger.actions); + }, parseInt(condition.value) * 1000); + break; + } + }); + }); + }; + + return { + init: init, + processRequest: processRequest + }; +})(); diff --git a/packages/rocketchat-livechat/app/client/routes/router.coffee b/packages/rocketchat-livechat/app/client/routes/router.coffee index 1105938efd909a826cdff2c173366956960a41f9..6b1712849214f691f2ef3fc8c8c8f8c94955b1dd 100644 --- a/packages/rocketchat-livechat/app/client/routes/router.coffee +++ b/packages/rocketchat-livechat/app/client/routes/router.coffee @@ -9,4 +9,4 @@ FlowRouter.route '/livechat', ] action: -> - BlazeLayout.render 'main', {center: 'room'} + BlazeLayout.render 'main', {center: 'livechatWindow'} diff --git a/packages/rocketchat-livechat/app/client/startup/triggers.js b/packages/rocketchat-livechat/app/client/startup/triggers.js new file mode 100644 index 0000000000000000000000000000000000000000..71cfdb1d0d95d6f0fc2783c61a3925a12180bb52 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/startup/triggers.js @@ -0,0 +1,5 @@ +Meteor.startup(function() { + Meteor.subscribe('livechat:trigger', function() { + Triggers.init() + }); +}); diff --git a/packages/rocketchat-livechat/app/client/stylesheets/_variables.less b/packages/rocketchat-livechat/app/client/stylesheets/_variables.less index e746bcf8cad8bb6c265e9615ce822df0fe6abe1e..d054cb4339ebf5cb56dea163696ef83819bcc777 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/_variables.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/_variables.less @@ -1,5 +1,5 @@ @header-min-height: 30px; -@footer-min-height: 42px; +@footer-min-height: 55px; @rooms-box-width: 260px; @flex-tab-width: 400px; diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 1335a0114511bdc8c618d0986be524aa5358aeb3..afcc4fcf35a05107fa665c8b2582df9ec2fa036b 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -1,4 +1,3 @@ -@import url(//fonts.googleapis.com/css?family=Roboto:300,400,500,600,700&subset=latin,cyrillic-ext,greek-ext,greek,vietnamese,latin-ext,cyrillic); @import "_variables.less"; @import "utils/_lesshat.import.less"; @import "utils/_reset.import.less"; @@ -13,11 +12,9 @@ html, body { height: 100%; } body { - padding: 0; margin: 0; - font-size: 10pt; - font-family: "Roboto", "HelveticaNeue", sans-serif; - // font-size: 14px; + font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif, "Meiryo UI"; + font-size: 0.8rem; color: @primary-font-color; height: 100%; width: 100%; @@ -36,6 +33,11 @@ textarea { font-family: inherit; font-size: inherit; line-height: inherit; + padding: 5px; + margin: 5px; + border: 1px solid #E7E7E7; + border-radius: 5px; + outline: none; } input:focus { @@ -54,6 +56,7 @@ input:focus { word-spacing: 0; box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.125); border: none; + border-radius: 0; line-height: 16px; position: relative; cursor: pointer;background-color: #FFF; @@ -334,7 +337,7 @@ input:focus { } .error { - bottom: 40px; + bottom: @footer-min-height; position: fixed; width: 100%; background-color: #F7D799; @@ -360,16 +363,14 @@ input:focus { border-right: 1px solid #E7E7E7; .input-wrapper { - padding: 6px; + padding: 6px 6px 0 6px; textarea { display: block; padding: 6px 8px; padding-right: 38px; overflow-y: auto; resize: none; - border: 1px solid #E7E7E7; - // margin: 10px; - border-radius: 5px; + margin: 0; max-height: 200px; width: 100%; font-size: 12px; @@ -378,7 +379,6 @@ input:focus { line-height: normal; background-color: #fff; position: relative; - outline: none; } } } @@ -397,12 +397,12 @@ input:focus { background-color: #FFF; border-left: 1px solid #E7E7E7; border-right: 1px solid #E7E7E7; + padding: 5px; - input, button { + input, button, select { display: block; - padding: 5px; - margin: 5px; } + .error { display: none; // width: 100%; @@ -425,54 +425,85 @@ input:focus { position: fixed; height: 100%; width: 100%; + z-index: 9990; + top: 0; + left: 0; + } - .wrapper { - background: white; - position: fixed; - height: 60vh; - width: 60vw; - top: 20vh; - left: 20vw; - border-radius: 6px; - display: flex; - flex-direction: column; - - header { - flex: 1 0 40px; - padding: 0 15px; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - line-height: 40px; - } + .wrapper { + z-index: 9999; + background: white; + position: fixed; + height: 60vh; + width: 60vw; + top: 20vh; + left: 20vw; + border-radius: 6px; + display: flex; + flex-direction: column; + + header { + flex: 1 0 40px; + padding: 0 15px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + line-height: 40px; + } - .content { - overflow-y: scroll; - padding: 10px; - flex: 1 1 100%; + .content { + overflow-y: scroll; + padding: 10px; + flex: 1 1 100%; - .instructions { - margin-top: 5px; - } + .instructions { + margin-top: 5px; + } - .survey-item { - margin-top: 20px; + .survey-item { + margin-top: 20px; - .question { - display: block; - } + .question { + display: block; + } - .answer { - margin-right: 5px; - } + .answer { + margin-right: 5px; + display: inline-block; + text-align: center; } } + } - footer { - flex: 1 0 60px; - border-top: 1px solid rgba(0, 0, 0, 0.1); - line-height: 60px; - text-align: right; - padding-right: 20px; - } + footer { + flex: 1 0 60px; + border-top: 1px solid rgba(0, 0, 0, 0.1); + line-height: 60px; + text-align: right; + padding-right: 20px; + } + } +} + +.powered-by { + text-align: right; + font-size: 0.65rem; + height: 20px; + line-height: 20px; + color: #666; + padding: 0 1em; + opacity: 0.5; + + .transition(opacity .15s ease-out); + + &:hover { + opacity: 1; + } + + a { + text-decoration: none; + margin-left: 1px; + img { + height: 14px; + vertical-align: middle; } } } diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/livechatWindow.html similarity index 68% rename from packages/rocketchat-livechat/app/client/views/room.html rename to packages/rocketchat-livechat/app/client/views/livechatWindow.html index 0220ed9abfa61b5216c72c5ca2429ece0897f2f3..91618ab52262b837081e4cfad2622fe6754b9bd4 100644 --- a/packages/rocketchat-livechat/app/client/views/room.html +++ b/packages/rocketchat-livechat/app/client/views/livechatWindow.html @@ -1,4 +1,4 @@ -<template name="room"> +<template name="livechatWindow"> {{#if livechatStartedEnabled}} <div class="livechat-room"> <div class="title" style="background-color:{{color}}"> @@ -10,14 +10,15 @@ </div> <h1>{{title}}</h1> </div> - {{#if currentUser}} - {{> messages}} - {{else}} - {{#if livechatEnabled}} + + {{#if livechatEnabled}} + {{#if showRegisterForm}} {{> register}} {{else}} - <div class="offline">{{_ "We_are_offline_Sorry_for_the_inconvenience"}}</div> + {{> messages}} {{/if}} + {{else}} + <div class="offline">{{_ "We_are_offline_Sorry_for_the_inconvenience"}}</div> {{/if}} </div> {{/if}} diff --git a/packages/rocketchat-livechat/app/client/views/room.js b/packages/rocketchat-livechat/app/client/views/livechatWindow.js similarity index 56% rename from packages/rocketchat-livechat/app/client/views/room.js rename to packages/rocketchat-livechat/app/client/views/livechatWindow.js index a844293decb8b1d2f93df988525d8da7aa6b32b3..c566d31ddd55201e50a644bb2fa0a73aa86f2ccd 100644 --- a/packages/rocketchat-livechat/app/client/views/room.js +++ b/packages/rocketchat-livechat/app/client/views/livechatWindow.js @@ -1,57 +1,62 @@ -Template.room.helpers({ - title: function() { +Template.livechatWindow.helpers({ + title() { var ref; if (!Template.instance().subscriptionsReady()) { return ''; } return ((ref = Settings.findOne('Livechat_title')) != null ? ref.value : void 0) || 'Rocket.Chat'; }, - color: function() { + color() { var ref; if (!Template.instance().subscriptionsReady()) { return 'transparent'; } return ((ref = Settings.findOne('Livechat_title_color')) != null ? ref.value : void 0) || '#C1272D'; }, - popoutActive: function() { + popoutActive() { return FlowRouter.getQueryParam('mode') === 'popout'; }, - livechatStartedEnabled: function() { + showRegisterForm() { + if (Session.get('triggered') || Meteor.userId()) { + return false; + } + var form = Settings.findOne('Livechat_registration_form'); + return form.value; + }, + livechatStartedEnabled() { return Template.instance().startedEnabled.get() !== null; }, - livechatEnabled: function() { + livechatEnabled() { return Template.instance().startedEnabled.get(); } }); -Template.room.events({ - 'click .title': function() { +Template.livechatWindow.events({ + 'click .title'() { parentCall('toggleWindow'); }, - 'click .popout': function(event) { + 'click .popout'(event) { event.stopPropagation(); parentCall('openPopout'); } }); -Template.room.onCreated(function() { - self = this; - - self.startedEnabled = new ReactiveVar(null); +Template.livechatWindow.onCreated(function() { + this.startedEnabled = new ReactiveVar(null); - self.subscribe('settings', ['Livechat_title', 'Livechat_title_color', 'Livechat_enabled']); + this.subscribe('settings', ['Livechat_title', 'Livechat_title_color', 'Livechat_enabled', 'Livechat_registration_form']); var initialCheck = true; - self.autorun(function() { - if (self.subscriptionsReady()) { + this.autorun(() => { + if (this.subscriptionsReady()) { var enabled = Settings.findOne('Livechat_enabled'); if (enabled !== undefined) { if (!enabled.value && initialCheck) { parentCall('removeWidget'); } initialCheck = false; - self.startedEnabled.set(enabled.value); + this.startedEnabled.set(enabled.value); } } }); diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index 1b49884bd821812463129ca722f73cee1b784c45..87cc3d9164e9d2d7a4ae436ccbcc0412bc9ef666 100644 --- a/packages/rocketchat-livechat/app/client/views/message.coffee +++ b/packages/rocketchat-livechat/app/client/views/message.coffee @@ -4,7 +4,7 @@ Template.message.helpers return 'own' if this.u?._id is Meteor.userId() time: -> - return moment(this.ts).format('HH:mm') + return moment(this.ts).format('LT') date: -> return moment(this.ts).format('LL') diff --git a/packages/rocketchat-livechat/app/client/views/messages.html b/packages/rocketchat-livechat/app/client/views/messages.html index 8bfbfd49b62fc84b8eeddac63fc1065ea9621689..8e3fe168b7d5c414af50acd9e875fbf0562b8671 100644 --- a/packages/rocketchat-livechat/app/client/views/messages.html +++ b/packages/rocketchat-livechat/app/client/views/messages.html @@ -19,5 +19,11 @@ <div class="input-wrapper"> <textarea class="input-message" placeholder="Type your message"></textarea> </div> + <p class="powered-by"> + Powered by + <a href="https://rocket.chat" target="_blank"> + <img class="logo" src="/images/logo/logo-dark.svg?v=1"> + </a> + </p> </div> </template> diff --git a/packages/rocketchat-livechat/app/client/views/register.coffee b/packages/rocketchat-livechat/app/client/views/register.coffee deleted file mode 100644 index f815eab9013ff4e144e7f08f1cf275a9b16dd49a..0000000000000000000000000000000000000000 --- a/packages/rocketchat-livechat/app/client/views/register.coffee +++ /dev/null @@ -1,50 +0,0 @@ -Template.register.helpers - error: -> - return Template.instance().error.get() - - title: -> - return '' unless Template.instance().subscriptionsReady() - return Settings.findOne('Livechat_title')?.value or 'Rocket.Chat' - - color: -> - return 'transparent' unless Template.instance().subscriptionsReady() - return Settings.findOne('Livechat_title_color')?.value or '#C1272D' - - welcomeMessage: -> - return "" - -Template.register.events - 'submit #livechat-registration': (e, instance) -> - e.preventDefault() - - $name = instance.$('input[name=name]') - $email = instance.$('input[name=email]') - - unless $name.val().trim() and $email.val().trim() - return instance.showError TAPi18n.__('Please_fill_name_and_email') - else - Meteor.call 'registerGuest', visitor.getToken(), $name.val(), $email.val(), (error, result) -> - if error? - return instance.showError error.reason - - Meteor.loginWithPassword result.user, result.pass, (error) -> - if error - return instance.showError error.reason - - 'click .error': (e, instance) -> - instance.hideError() - -Template.register.onCreated -> - @subscribe 'settings', ['Livechat_title', 'Livechat_title_color'] - @error = new ReactiveVar - - @showError = (msg) => - $('.error').addClass('show') - @error.set msg - return - - @hideError = => - $('.error').removeClass('show') - @error.set() - return - diff --git a/packages/rocketchat-livechat/app/client/views/register.html b/packages/rocketchat-livechat/app/client/views/register.html index 39ef026bf5e35097ec69459fd972aff8a798c2c5..7dd5afb76a2fc223cb3eae74eae8c0c01b0bb68d 100644 --- a/packages/rocketchat-livechat/app/client/views/register.html +++ b/packages/rocketchat-livechat/app/client/views/register.html @@ -9,7 +9,16 @@ </label> <input type="text" name="name" id="guestName" placeholder="{{_ "Name"}}"> <input type="email" name="email" id="guestEmail" placeholder="{{_ "E-mail"}}"> - <button type="submit" id="btnEntrar" class="-btn"> {{_ "Start_Chat"}} </button> + + {{#if hasDepartments}} + <select name="department"> + <option value="">{{_ "Select_a_department"}}</option> + {{#each departments}} + <option value="{{_id}}">{{name}}</option> + {{/each}} + </select> + {{/if}} + <button type="submit" id="btnEntrar" class="button"> {{_ "Start_Chat"}} </button> </form> </template> diff --git a/packages/rocketchat-livechat/app/client/views/register.js b/packages/rocketchat-livechat/app/client/views/register.js new file mode 100644 index 0000000000000000000000000000000000000000..df91839e23a29673b2e3457efbbaffcd0e95d671 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/register.js @@ -0,0 +1,68 @@ +Template.register.helpers({ + error() { + return Template.instance().error.get(); + }, + welcomeMessage() { + return ""; + }, + hasDepartments() { + return Department.find().count() > 1; + }, + departments() { + return Department.find(); + } +}); + +Template.register.events({ + 'submit #livechat-registration' (e, instance) { + var $email, $name; + e.preventDefault(); + $name = instance.$('input[name=name]'); + $email = instance.$('input[name=email]'); + if (!($name.val().trim() && $email.val().trim())) { + return instance.showError(TAPi18n.__('Please_fill_name_and_email')); + } else { + var departmentId = instance.$('select[name=department]').val(); + if (!departmentId) { + var department = Department.findOne(); + if (department) { + departmentId = department._id; + } + } + + var guest = { + token: visitor.getToken(), + name: $name.val(), + email: $email.val(), + department: departmentId + }; + Meteor.call('livechat:registerGuest', guest, function(error, result) { + if (error != null) { + return instance.showError(error.reason); + } + Meteor.loginWithToken(result.token, function(error) { + if (error) { + return instance.showError(error.reason); + } + }); + }); + } + }, + 'click .error' (e, instance) { + return instance.hideError(); + } +}); + +Template.register.onCreated(function() { + this.subscribe('livechat:availableDepartments'); + + this.error = new ReactiveVar; + this.showError = (msg) => { + $('.error').addClass('show'); + this.error.set(msg); + }; + this.hideError = () => { + $('.error').removeClass('show'); + this.error.set(); + }; +}); diff --git a/packages/rocketchat-livechat/app/client/views/survey.html b/packages/rocketchat-livechat/app/client/views/survey.html index 07babef73d29cc86d8fa90f6ce917f9b9f094be8..9c4a9b08f399a83330a1c5c241f5fadaf4835bd3 100644 --- a/packages/rocketchat-livechat/app/client/views/survey.html +++ b/packages/rocketchat-livechat/app/client/views/survey.html @@ -1,66 +1,65 @@ <template name="survey"> <div id="survey"> - <div class="overlay"> - <div class="wrapper"> - <header> - <b>{{_ 'Please_answer_survey'}}</b> - </header> - <div class="content"> - <p class="instructions">{{_ 'Survey_instructions'}}</p> - <form id="survey" class="livechat-form"> - <div class="survey-item"> - <label class="question"> - {{_ "How_satisfied_were_you_with_this_chat"}} - </label> - <label class="answer"><input type="radio" name="satisfaction" value="1" />1</label> - <label class="answer"><input type="radio" name="satisfaction" value="2" />2</label> - <label class="answer"><input type="radio" name="satisfaction" value="3" />3</label> - <label class="answer"><input type="radio" name="satisfaction" value="4" />4</label> - <label class="answer"><input type="radio" name="satisfaction" value="5" />5</label> - </div> - <div class="survey-item"> - <label class="question"> - {{_ "How_knowledgeable_was_the_chat_agent"}} - </label> - <label class="answer"><input type="radio" name="agentKnowledge" value="1" />1</label> - <label class="answer"><input type="radio" name="agentKnowledge" value="2" />2</label> - <label class="answer"><input type="radio" name="agentKnowledge" value="3" />3</label> - <label class="answer"><input type="radio" name="agentKnowledge" value="4" />4</label> - <label class="answer"><input type="radio" name="agentKnowledge" value="5" />5</label> - </div> - <div class="survey-item"> - <label class="question"> - {{_ "How_responsive_was_the_chat_agent"}} - </label> - <label class="answer"><input type="radio" name="agentResposiveness" value="1" />1</label> - <label class="answer"><input type="radio" name="agentResposiveness" value="2" />2</label> - <label class="answer"><input type="radio" name="agentResposiveness" value="3" />3</label> - <label class="answer"><input type="radio" name="agentResposiveness" value="4" />4</label> - <label class="answer"><input type="radio" name="agentResposiveness" value="5" />5</label> - </div> - <div class="survey-item"> - <label class="question"> - {{_ "How_friendly_was_the_chat_agent"}} - </label> - <label class="answer"><input type="radio" name="agentFriendliness" value="1" />1</label> - <label class="answer"><input type="radio" name="agentFriendliness" value="2" />2</label> - <label class="answer"><input type="radio" name="agentFriendliness" value="3" />3</label> - <label class="answer"><input type="radio" name="agentFriendliness" value="4" />4</label> - <label class="answer"><input type="radio" name="agentFriendliness" value="5" />5</label> - </div> - <div class="survey-item"> - <label class="question"> - {{_ "Additional_Feedback"}} - </label> - <textarea name="additionalFeedback" rows="5"></textarea> - </div> - </form> - </div> - <footer> - <button type="button" class="button secondary skip"><span>{{_ "Skip"}}</span></button> - <button type="button" class="button send"><span>{{_ "Send"}}</span></button> - </footer> + <div class="overlay"></div> + <div class="wrapper"> + <header> + <b>{{_ 'Please_answer_survey'}}</b> + </header> + <div class="content"> + <p class="instructions">{{_ 'Survey_instructions'}}</p> + <form id="survey" class="livechat-form"> + <div class="survey-item"> + <label class="question"> + {{_ "How_satisfied_were_you_with_this_chat"}} + </label> + <label class="answer"><input type="radio" name="satisfaction" value="1" />1</label> + <label class="answer"><input type="radio" name="satisfaction" value="2" />2</label> + <label class="answer"><input type="radio" name="satisfaction" value="3" />3</label> + <label class="answer"><input type="radio" name="satisfaction" value="4" />4</label> + <label class="answer"><input type="radio" name="satisfaction" value="5" />5</label> + </div> + <div class="survey-item"> + <label class="question"> + {{_ "How_knowledgeable_was_the_chat_agent"}} + </label> + <label class="answer"><input type="radio" name="agentKnowledge" value="1" />1</label> + <label class="answer"><input type="radio" name="agentKnowledge" value="2" />2</label> + <label class="answer"><input type="radio" name="agentKnowledge" value="3" />3</label> + <label class="answer"><input type="radio" name="agentKnowledge" value="4" />4</label> + <label class="answer"><input type="radio" name="agentKnowledge" value="5" />5</label> + </div> + <div class="survey-item"> + <label class="question"> + {{_ "How_responsive_was_the_chat_agent"}} + </label> + <label class="answer"><input type="radio" name="agentResposiveness" value="1" />1</label> + <label class="answer"><input type="radio" name="agentResposiveness" value="2" />2</label> + <label class="answer"><input type="radio" name="agentResposiveness" value="3" />3</label> + <label class="answer"><input type="radio" name="agentResposiveness" value="4" />4</label> + <label class="answer"><input type="radio" name="agentResposiveness" value="5" />5</label> + </div> + <div class="survey-item"> + <label class="question"> + {{_ "How_friendly_was_the_chat_agent"}} + </label> + <label class="answer"><input type="radio" name="agentFriendliness" value="1" />1</label> + <label class="answer"><input type="radio" name="agentFriendliness" value="2" />2</label> + <label class="answer"><input type="radio" name="agentFriendliness" value="3" />3</label> + <label class="answer"><input type="radio" name="agentFriendliness" value="4" />4</label> + <label class="answer"><input type="radio" name="agentFriendliness" value="5" />5</label> + </div> + <div class="survey-item"> + <label class="question"> + {{_ "Additional_Feedback"}} + </label> + <textarea name="additionalFeedback" rows="5"></textarea> + </div> + </form> </div> + <footer> + <button type="button" class="button secondary skip"><span>{{_ "Skip"}}</span></button> + <button type="button" class="button send"><span>{{_ "Send"}}</span></button> + </footer> </div> </div> </template> diff --git a/packages/rocketchat-livechat/app/i18n/ar.i18n.json b/packages/rocketchat-livechat/app/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6f3586ed429589b001f86e18967c8e49966b230a 100644 --- a/packages/rocketchat-livechat/app/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ar.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Skip" : "تخطي", + "Start_Chat" : "بدأ الدردشة" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/cs.i18n.json b/packages/rocketchat-livechat/app/i18n/cs.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6aaa0ff01cc53dc8626f112e9c09508972d5797a 100644 --- a/packages/rocketchat-livechat/app/i18n/cs.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/cs.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Spustit chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/de.i18n.json b/packages/rocketchat-livechat/app/i18n/de.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..dffe62cd1756e9d0eb6f8b05366511739877d80a 100644 --- a/packages/rocketchat-livechat/app/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/de.i18n.json @@ -1 +1,18 @@ -{ } \ No newline at end of file +{ + "Additional_Feedback" : "Zusätzliches Feedback", + "Appearance" : "Erscheinungsbild", + "How_friendly_was_the_chat_agent" : "Wie freundlich war der Chat-Agent?", + "How_knowledgeable_was_the_chat_agent" : "Wie sachkundig war der Chat-Agent?", + "How_responsive_was_the_chat_agent" : "Wie reaktionsschnell war der Chat-Agent?", + "How_satisfied_were_you_with_this_chat" : "Wie zufrieden waren Sie mit diesem Chat?", + "Installation" : "Installation", + "Please_answer_survey" : "Bitte nehmen Sie sich einen Moment Zeit, um kurz einige Fragen zu dem Chat zu beantworten.", + "Please_fill_name_and_email" : "Bitte geben Sie einen Namen und eine E-Mail-Adresse ein.", + "Select_a_department" : "Wählen Sie eine Abteilung", + "Skip" : "Ãœberspringen", + "Start_Chat" : "Chat beginnen", + "Survey" : "Umfrage", + "Survey_instructions" : "Bewerten Sie jede Frage nach Ihrer Zufriedenheit. 1 bedeutet, dass Sie völlig unzufrieden sind und 5 bedeutet, dass Sie vollständig zufrieden sind.", + "Thank_you_for_your_feedback" : "Vielen Dank für Ihre Rückmeldung.", + "We_are_offline_Sorry_for_the_inconvenience" : "Wir sind offline. Entschuldigen Sie die Unannehmlichkeiten." +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/el.i18n.json b/packages/rocketchat-livechat/app/i18n/el.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..14415269c851881c06176c8edb2c1ff71798ba6c 100644 --- a/packages/rocketchat-livechat/app/i18n/el.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/el.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "ΈναÏξη συνομιλίας" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index b8a9e1d8a1b4886131a119f747ad48a6b9e23c6b..e31bf14dbe78719ee090591c3175ad28e827a04d 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -1,20 +1,18 @@ { "Additional_Feedback" : "Additional Feedback", - "Skip" : "Skip", - "E-mail" : "E-mail", + "Appearance" : "Appearance", "How_friendly_was_the_chat_agent" : "How friendly was the chat agent?", "How_knowledgeable_was_the_chat_agent" : "How knowledgeable was the chat agent?", "How_responsive_was_the_chat_agent" : "How responsive was the chat agent?", "How_satisfied_were_you_with_this_chat" : "How satisfied were you with this chat?", - "Message" : "Message", - "Name" : "Name", + "Installation" : "Installation", "Please_answer_survey" : "Please take a moment to answer a quick survey about this chat", "Please_fill_name_and_email" : "Please fill name and e-mail", - "Send" : "Send", + "Select_a_department" : "Select a department", + "Skip" : "Skip", "Start_Chat" : "Start Chat", "Survey" : "Survey", "Survey_instructions" : "Rate each question according to your satisfaction, 1 meaning you are completely unsatisfied and 5 meaning you are completely satisfied.", "Thank_you_for_your_feedback" : "Thank you for your feedback", - "User_left" : "Has left the channel.", "We_are_offline_Sorry_for_the_inconvenience" : "We are offline. Sorry for the inconvenience." -} +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/es.i18n.json b/packages/rocketchat-livechat/app/i18n/es.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..01ccecd14b5eaa236769cbd9e47523c2fbc5a79f 100644 --- a/packages/rocketchat-livechat/app/i18n/es.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/es.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Iniciar chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/fa.i18n.json b/packages/rocketchat-livechat/app/i18n/fa.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..81ee6d2f85ebe073ceb6d3213f93b8d24a20127c 100644 --- a/packages/rocketchat-livechat/app/i18n/fa.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fa.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "شروع چت" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/fi.i18n.json b/packages/rocketchat-livechat/app/i18n/fi.i18n.json index f279ec41b30d2b8c334a5e4cf2ab84366c9e4454..b5820e4af81a628cf80aeb417a36f6d23386243b 100644 --- a/packages/rocketchat-livechat/app/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fi.i18n.json @@ -1,14 +1,18 @@ { "Additional_Feedback" : "Lisäpalaute", - "Skip" : "Ohita", - "How_friendly_was_the_chat_agent" : "Kuinka ystävällinen oli chat agentti?", - "How_knowledgeable_was_the_chat_agent" : "Miten osaava oli chat agentti?", - "How_responsive_was_the_chat_agent" : "Miten reagoiva oli chat agentti?", - "How_satisfied_were_you_with_this_chat" : "Kuinka tyytyväinen olet tähän chattiin?", + "Appearance" : "Ulkoasu", + "How_friendly_was_the_chat_agent" : "Kuinka ystävällinen chat agentti oli?", + "How_knowledgeable_was_the_chat_agent" : "Miten osaava chat agentti oli?", + "How_responsive_was_the_chat_agent" : "Miten reagoiva chat agentti oli?", + "How_satisfied_were_you_with_this_chat" : "Kuinka tyytyväinen olit tähän chattiin?", + "Installation" : "Asennus", "Please_answer_survey" : "Käytä hetki vastataksesi pikakyselyyn tästä chatista", "Please_fill_name_and_email" : "Täytä nimi ja sähköpostiosoite", + "Select_a_department" : "Valitse osasto", + "Skip" : "Ohita", "Start_Chat" : "Aloita chat", "Survey" : "Tutkimus", "Survey_instructions" : "Arvioi jokainen kysymys sen mukaan miten tyytyväinen olet, 1 tarkoittaa että olet täysin tyytymätön ja 5 tarkoittaa että olet täysin tyytyväinen.", - "Thank_you_for_your_feedback" : "Kiitos palautteestasi" + "Thank_you_for_your_feedback" : "Kiitos palautteestasi", + "We_are_offline_Sorry_for_the_inconvenience" : "Palvelu on offline-tilassa. Pahoittelut häiriöstä." } \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/fr.i18n.json b/packages/rocketchat-livechat/app/i18n/fr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..80b42a8c814b609507f0a9d8c5b2f4e38e88a7ce 100644 --- a/packages/rocketchat-livechat/app/i18n/fr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fr.i18n.json @@ -1 +1,16 @@ -{ } \ No newline at end of file +{ + "Additional_Feedback" : "Commentaires supplémentaires", + "Appearance" : "Apparence", + "How_friendly_was_the_chat_agent" : "Le bot de chat était-il amical ?", + "How_knowledgeable_was_the_chat_agent" : "Le bot de chat était-il clair ?", + "How_responsive_was_the_chat_agent" : "Le bot de chat avait-il des réponses adaptées ?", + "How_satisfied_were_you_with_this_chat" : "Comment étiez-vous satisfait ce chat?", + "Installation" : "Installation", + "Please_answer_survey" : "Prenez un moment pour répondre à un court sondage à propos de ce chat si vous pouvez", + "Skip" : "Passer", + "Start_Chat" : "Démarrer un tchat", + "Survey" : "Enquête", + "Survey_instructions" : "Notez chaque question en fonction de votre satisfaction, 1 signifiant que vous êtes très insatisfait et 5 que vous êtes entièrement satisfait.", + "Thank_you_for_your_feedback" : "Merci pour votre réponse", + "We_are_offline_Sorry_for_the_inconvenience" : "Nous sommes hors ligne. Désolé pour le désagrément." +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/he.i18n.json b/packages/rocketchat-livechat/app/i18n/he.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..7aacaa2a49c77365959547bc3a479e2548d3f187 100644 --- a/packages/rocketchat-livechat/app/i18n/he.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/he.i18n.json @@ -1 +1,8 @@ -{ } \ No newline at end of file +{ + "Additional_Feedback" : "משוב × ×•×¡×£", + "Appearance" : "מר××”", + "Installation" : "×”×ª×§× ×”", + "Start_Chat" : "Start Chat", + "Survey" : "סקר", + "Thank_you_for_your_feedback" : "תודה לך על המשוב" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/hr.i18n.json b/packages/rocketchat-livechat/app/i18n/hr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..0f5f0fa415ba9f415d14cb19177ef92500fbc834 100644 --- a/packages/rocketchat-livechat/app/i18n/hr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/hr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Appearance" : "Izgled", + "Installation" : "Instalacija", + "Start_Chat" : "PoÄetak Chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/hu.i18n.json b/packages/rocketchat-livechat/app/i18n/hu.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..5e8b9b574e5f29d5ce4665477b08dc76e06691b4 100644 --- a/packages/rocketchat-livechat/app/i18n/hu.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/hu.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Start Chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/it.i18n.json b/packages/rocketchat-livechat/app/i18n/it.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..dc6a25746c54c76a3032601c31194e885496cee2 100644 --- a/packages/rocketchat-livechat/app/i18n/it.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/it.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Avvia chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ja.i18n.json b/packages/rocketchat-livechat/app/i18n/ja.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..70a58ee9e7cfdd0dfbf831a062c6558d033bf476 100644 --- a/packages/rocketchat-livechat/app/i18n/ja.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ja.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "ãƒãƒ£ãƒƒãƒˆã‚’開始" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/km.i18n.json b/packages/rocketchat-livechat/app/i18n/km.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..a5eb5069a36f7b0573dab9b3bd0d1270072822b3 100644 --- a/packages/rocketchat-livechat/app/i18n/km.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/km.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "ចាប់ផ្ដើម​ជជែក​កំសាន្áž" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ko.i18n.json b/packages/rocketchat-livechat/app/i18n/ko.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..4bfdf5366f3ceb53d5d407f7059270acc115b344 100644 --- a/packages/rocketchat-livechat/app/i18n/ko.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ko.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "채팅 시작" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ku.i18n.json b/packages/rocketchat-livechat/app/i18n/ku.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..5e8b9b574e5f29d5ce4665477b08dc76e06691b4 100644 --- a/packages/rocketchat-livechat/app/i18n/ku.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ku.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Start Chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/lo.i18n.json b/packages/rocketchat-livechat/app/i18n/lo.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..88505c1c64a83db653f7790c7446f8c871f775a9 100644 --- a/packages/rocketchat-livechat/app/i18n/lo.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/lo.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "àºàº²àº™â€‹à»€àº¥àºµà»ˆàº¡â€‹àº•àº»à»‰àº™â€‹àºªàº»àº™â€‹àº—ະ​ນາ" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json b/packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..8dbe1bb222ef63442b3a11b4adb7af6031b6dfdf 100644 --- a/packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Mula Chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/nl.i18n.json b/packages/rocketchat-livechat/app/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..2bf171f8b5d5a4d902a4ae23fd5e37726a502427 100644 --- a/packages/rocketchat-livechat/app/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/nl.i18n.json @@ -1 +1,18 @@ -{ } \ No newline at end of file +{ + "Additional_Feedback" : "Extra feedback", + "Appearance" : "Uiterlijk", + "How_friendly_was_the_chat_agent" : "Hoe vriendelijk was de chat-agent?", + "How_knowledgeable_was_the_chat_agent" : "Hoe deskundig was de chat-agent?", + "How_responsive_was_the_chat_agent" : "Hoe goed reageert de chat-agent?", + "How_satisfied_were_you_with_this_chat" : "Hoe tevreden bent u met deze chat?", + "Installation" : "Installatie", + "Please_answer_survey" : "Heeft u een moment om een korte enquête over deze chat te beantwoorden", + "Please_fill_name_and_email" : "Vul naam en e-mail in", + "Select_a_department" : "Selecteer een afdeling", + "Skip" : "Overslaan", + "Start_Chat" : "Start Chat", + "Survey" : "Enquête", + "Survey_instructions" : "Beoordeel elke vraag naar mate uw tevredenheid, 1 betekent dat u helemaal ontevreden bent en 5 betekent volledig tevreden.", + "Thank_you_for_your_feedback" : "Hartelijk dank voor uw feedback", + "We_are_offline_Sorry_for_the_inconvenience" : "We zijn offline. Excuses voor het ongemak." +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/pl.i18n.json b/packages/rocketchat-livechat/app/i18n/pl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..f3e5e78e6998716f0e1306a239a0c927f089c644 100644 --- a/packages/rocketchat-livechat/app/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/pl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Skip" : "PomiÅ„", + "Start_Chat" : "Rozpocznij czat", + "Survey" : "Ankieta" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/pt.i18n.json b/packages/rocketchat-livechat/app/i18n/pt.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..b7e65b0c74f15e72a798a69dd063712d3bf44446 100644 --- a/packages/rocketchat-livechat/app/i18n/pt.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/pt.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Iniciar bate-papo" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ro.i18n.json b/packages/rocketchat-livechat/app/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..ab72db26d5d82b94134436486801d0b25331082a --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ro.i18n.json @@ -0,0 +1,18 @@ +{ + "Additional_Feedback" : "Feedback suplimentar", + "Appearance" : "Aspect", + "How_friendly_was_the_chat_agent" : "Cât de prietenos a fost agentul de chat?", + "How_knowledgeable_was_the_chat_agent" : "Cât de informat a fost agentul de chat?", + "How_responsive_was_the_chat_agent" : "Cât de rapid a fost agentul de chat?", + "How_satisfied_were_you_with_this_chat" : "Cât de mulÈ›umit sunteÈ›i de acest chat?", + "Installation" : "Instalare", + "Please_answer_survey" : "Vă rugăm să acordaÈ›i un moment pentru a răspunde la un sondaj rapid despre acest chat", + "Please_fill_name_and_email" : "Vă rugăm să completaÈ›i numele È™i e-mail", + "Select_a_department" : "SelectaÈ›i un departament", + "Skip" : "Sari peste asta", + "Start_Chat" : "Start chat", + "Survey" : "Sondaj de opinie", + "Survey_instructions" : "Da o nota fiecărei întrebări în funcÈ›ie de gradul de satisfacÈ›ie, 1 înseamnă că sunt complet nemulÈ›umit È™i 5 înseamnă că sunt complet mulÈ›umiÈ›i.", + "Thank_you_for_your_feedback" : "Vă mulÈ›umim pentru feedback", + "We_are_offline_Sorry_for_the_inconvenience" : "Suntem offline. Scuze pentru neplăcerile provocate." +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ru.i18n.json b/packages/rocketchat-livechat/app/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..9a8fba30e6ada21d583a5f575b91cfdf718c499f 100644 --- a/packages/rocketchat-livechat/app/i18n/ru.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ru.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Ðачать Чат" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/sq.i18n.json b/packages/rocketchat-livechat/app/i18n/sq.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..91b65876930da28d10f88a3cf24d6a7636871276 100644 --- a/packages/rocketchat-livechat/app/i18n/sq.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/sq.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Fillo bisedën" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/sr.i18n.json b/packages/rocketchat-livechat/app/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..65656ff72264e736d19a158b8eb79ccdabc06f35 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/sr.i18n.json @@ -0,0 +1,3 @@ +{ + "Start_Chat" : "Почетак Чат" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/sv.i18n.json b/packages/rocketchat-livechat/app/i18n/sv.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..504f8b76303e142f22cac626621c1c6d4f75a799 100644 --- a/packages/rocketchat-livechat/app/i18n/sv.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/sv.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Starta chatt" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json b/packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..279a5141a32efd5cb9766e36645775fce76566d9 100644 --- a/packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "தொடகà¯à®• சேடà¯" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/tr.i18n.json b/packages/rocketchat-livechat/app/i18n/tr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..370bbedcd2a3485316d9cd950c9f952a62b88659 100644 --- a/packages/rocketchat-livechat/app/i18n/tr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/tr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Sohbete BaÅŸla" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ug.i18n.json b/packages/rocketchat-livechat/app/i18n/ug.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..5e8b9b574e5f29d5ce4665477b08dc76e06691b4 100644 --- a/packages/rocketchat-livechat/app/i18n/ug.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ug.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Start Chat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/uk.i18n.json b/packages/rocketchat-livechat/app/i18n/uk.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..530dc71418bd243c7dd1474b733457a47c439e41 100644 --- a/packages/rocketchat-livechat/app/i18n/uk.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/uk.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Почати Чат" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/zh.i18n.json b/packages/rocketchat-livechat/app/i18n/zh.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..20a41fc2f8b5a657e3cbc98727183d6f0ff08e7a 100644 --- a/packages/rocketchat-livechat/app/i18n/zh.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/zh.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "开始èŠå¤©" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/assets/demo.html b/packages/rocketchat-livechat/assets/demo.html index 8b3929901c4b27e06112db2ed447caae359a74a5..99cfead8c1eda84d781eabe1718cc21ae9646aec 100644 --- a/packages/rocketchat-livechat/assets/demo.html +++ b/packages/rocketchat-livechat/assets/demo.html @@ -19,6 +19,14 @@ <body style="background-color: #EFEFEF"> <h1 style="color:#000">test</h1> <p style="color:#000">Talk to us.</p> + + <a href="#page-0" onclick="document.title='page-0'">page 0</a><br> + <a href="#page-1" onclick="document.title='page-1'">page 1</a><br> + <a href="#page-2" onclick="document.title='page-2'">page 2</a><br> + <a href="#page-3" onclick="document.title='page-3'">page 3</a><br> + <a href="#page-4" onclick="document.title='page-4'">page 4</a><br> + <a href="#page-5" onclick="document.title='page-5'">page 5</a><br> + <a href="#page-6" onclick="document.title='page-6'">page 6</a><br> </body> </html> diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index c16c5a7bd9277313415f0c8c371b05032f56aff7..f27762a53e05d8e2aca288a0d7c8b8e8d6c45157 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -9,22 +9,33 @@ // })(window, document, 'script', 'initRocket', 'http://localhost:5000/livechat'); // </script> -;(function(w) { - var exports = {}; +;var RocketChat = (function(w) { var config = {}; var widget; + var iframe; + var hookQueue = []; + var ready = false; - var closeWidget = () => { + var closeWidget = function() { widget.dataset.state = 'closed'; widget.style.height = '30px'; }; - var openWidget = () => { + var openWidget = function() { widget.dataset.state = 'opened'; widget.style.height = '300px'; }; var api = { + ready: function() { + ready = true; + if (hookQueue.length > 0) { + hookQueue.forEach(function(hookParams) { + callHook.apply(this, hookParams); + }); + hookQueue = []; + } + }, toggleWindow: function(forceClose) { if (widget.dataset.state === 'closed') { openWidget(); @@ -37,11 +48,49 @@ var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no'); popup.focus(); }, + openWidget: function() { + openWidget(); + }, removeWidget: function() { document.getElementsByTagName('body')[0].removeChild(widget); } }; + // hooks + var callHook = function(action, params) { + if (!ready) { + return hookQueue.push(arguments); + } + var data = { + src: 'rocketchat', + fn: action, + args: params + }; + iframe.contentWindow.postMessage(data, '*'); + }; + + var pageVisited = function() { + callHook('pageVisited', { + location: JSON.parse(JSON.stringify(document.location)), + title: document.title + }); + }; + + var currentPage = { + href: null, + title: null + }; + var trackNavigation = function() { + setInterval(function() { + if (document.location.href !== currentPage.href) { + pageVisited(); + + currentPage.href = document.location.href; + currentPage.title = document.title; + } + }, 800); + }; + var initRocket = function(url) { if (!url) { return; @@ -53,7 +102,7 @@ chatWidget.dataset.state = 'closed'; chatWidget.className = 'rocketchat-widget'; chatWidget.innerHTML = '<div class="rocketchat-container" style="width:100%;height:100%">' + - '<iframe src="' + url + '" style="width:100%;height:100%;border:none;background-color:transparent" allowTransparency="true"></iframe> '+ + '<iframe id="rocketchat-iframe" src="' + url + '" style="width:100%;height:100%;border:none;background-color:transparent" allowTransparency="true"></iframe> '+ '</div><div class="rocketchat-overlay"></div>'; chatWidget.style.position = 'fixed'; @@ -68,11 +117,12 @@ document.getElementsByTagName('body')[0].appendChild(chatWidget); widget = document.querySelector('.rocketchat-widget'); + iframe = document.getElementById('rocketchat-iframe'); w.addEventListener('message', function(msg) { if (typeof msg.data === 'object' && msg.data.src !== undefined && msg.data.src === 'rocketchat') { if (api[msg.data.fn] !== undefined && typeof api[msg.data.fn] === 'function') { - var args = [].concat(msg.data.args || []) + var args = [].concat(msg.data.args || []); api[msg.data.fn].apply(null, args); } } @@ -93,6 +143,9 @@ var mql = window.matchMedia('screen and (max-device-width: 480px) and (orientation: portrait)'); mediaqueryresponse(mql); mql.addListener(mediaqueryresponse); + + // track user navigation + trackNavigation(); }; if (typeof w.initRocket !== 'undefined') { @@ -107,5 +160,8 @@ initRocket.apply(null, [url]); }; - return exports; + // exports + return { + pageVisited: pageVisited + }; })(window); diff --git a/packages/rocketchat-livechat/client/collections/AgentUsers.js b/packages/rocketchat-livechat/client/collections/AgentUsers.js new file mode 100644 index 0000000000000000000000000000000000000000..e571fad61d2b47890c451156e30a86abce926e07 --- /dev/null +++ b/packages/rocketchat-livechat/client/collections/AgentUsers.js @@ -0,0 +1 @@ +this.AgentUsers = new Mongo.Collection('agentUsers'); diff --git a/packages/rocketchat-livechat/client/lib/LivechatDepartment.js b/packages/rocketchat-livechat/client/collections/LivechatDepartment.js similarity index 100% rename from packages/rocketchat-livechat/client/lib/LivechatDepartment.js rename to packages/rocketchat-livechat/client/collections/LivechatDepartment.js diff --git a/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js new file mode 100644 index 0000000000000000000000000000000000000000..08ea1741134bb6e9997d804c392ef8898f4dffc3 --- /dev/null +++ b/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js @@ -0,0 +1 @@ +this.LivechatDepartmentAgents = new Mongo.Collection('rocketchat_livechat_department_agents'); diff --git a/packages/rocketchat-livechat/client/collections/LivechatPageVisited.js b/packages/rocketchat-livechat/client/collections/LivechatPageVisited.js new file mode 100644 index 0000000000000000000000000000000000000000..f2f4fc2a60d79e222f5546b3bfe824eaa6500a53 --- /dev/null +++ b/packages/rocketchat-livechat/client/collections/LivechatPageVisited.js @@ -0,0 +1 @@ +this.LivechatPageVisited = new Mongo.Collection('rocketchat_livechat_page_visited'); diff --git a/packages/rocketchat-livechat/client/collections/LivechatTrigger.js b/packages/rocketchat-livechat/client/collections/LivechatTrigger.js new file mode 100644 index 0000000000000000000000000000000000000000..8cca1caa586df3eea16cb87a42fa29d6d4a65e5e --- /dev/null +++ b/packages/rocketchat-livechat/client/collections/LivechatTrigger.js @@ -0,0 +1 @@ +this.LivechatTrigger = new Mongo.Collection('rocketchat_livechat_trigger'); diff --git a/packages/rocketchat-livechat/client/lib/ua-parser.js b/packages/rocketchat-livechat/client/lib/ua-parser.js new file mode 100644 index 0000000000000000000000000000000000000000..2f34b32f8f0fc3c85ab1bac53571127a87055f09 --- /dev/null +++ b/packages/rocketchat-livechat/client/lib/ua-parser.js @@ -0,0 +1,8 @@ +/** + * UAParser.js v0.7.10 + * Lightweight JavaScript-based User-Agent string parser + * https://github.com/faisalman/ua-parser-js + * + * Copyright © 2012-2015 Faisal Salman <fyzlman@gmail.com> + * Dual licensed under GPLv2 & MIT + */(function(e,t){"use strict";var n="0.7.10",r="",i="?",s="function",o="undefined",u="object",a="string",f="major",l="model",c="name",h="type",p="vendor",d="version",v="architecture",m="console",g="mobile",y="tablet",b="smarttv",w="wearable",E="embedded",S={extend:function(e,t){for(var n in t)"browser cpu device engine os".indexOf(n)!==-1&&t[n].length%2===0&&(e[n]=t[n].concat(e[n]));return e},has:function(e,t){return typeof e=="string"?t.toLowerCase().indexOf(e.toLowerCase())!==-1:!1},lowerize:function(e){return e.toLowerCase()},major:function(e){return typeof e===a?e.split(".")[0]:t}},x={rgx:function(){var e,n=0,r,i,a,f,l,c,h=arguments;while(n<h.length&&!l){var p=h[n],d=h[n+1];if(typeof e===o){e={};for(a in d)d.hasOwnProperty(a)&&(f=d[a],typeof f===u?e[f[0]]=t:e[f]=t)}r=i=0;while(r<p.length&&!l){l=p[r++].exec(this.getUA());if(!!l)for(a=0;a<d.length;a++)c=l[++i],f=d[a],typeof f===u&&f.length>0?f.length==2?typeof f[1]==s?e[f[0]]=f[1].call(this,c):e[f[0]]=f[1]:f.length==3?typeof f[1]===s&&(!f[1].exec||!f[1].test)?e[f[0]]=c?f[1].call(this,c,f[2]):t:e[f[0]]=c?c.replace(f[1],f[2]):t:f.length==4&&(e[f[0]]=c?f[3].call(this,c.replace(f[1],f[2])):t):e[f]=c?c:t}n+=2}return e},str:function(e,n){for(var r in n)if(typeof n[r]===u&&n[r].length>0){for(var s=0;s<n[r].length;s++)if(S.has(n[r][s],e))return r===i?t:r}else if(S.has(n[r],e))return r===i?t:r;return e}},T={browser:{oldsafari:{version:{"1.0":"/8",1.2:"/1",1.3:"/3","2.0":"/412","2.0.2":"/416","2.0.3":"/417","2.0.4":"/419","?":"/"}}},device:{amazon:{model:{"Fire Phone":["SD","KF"]}},sprint:{model:{"Evo Shift 4G":"7373KT"},vendor:{HTC:"APA",Sprint:"Sprint"}}},os:{windows:{version:{ME:"4.90","NT 3.11":"NT3.51","NT 4.0":"NT4.0",2e3:"NT 5.0",XP:["NT 5.1","NT 5.2"],Vista:"NT 6.0",7:"NT 6.1",8:"NT 6.2",8.1:"NT 6.3",10:["NT 6.4","NT 10.0"],RT:"ARM"}}}},N={browser:[[/(opera\smini)\/([\w\.-]+)/i,/(opera\s[mobiletab]+).+version\/([\w\.-]+)/i,/(opera).+version\/([\w\.]+)/i,/(opera)[\/\s]+([\w\.]+)/i],[c,d],[/\s(opr)\/([\w\.]+)/i],[[c,"Opera"],d],[/(kindle)\/([\w\.]+)/i,/(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,/(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,/(?:ms|\()(ie)\s([\w\.]+)/i,/(rekonq)\/([\w\.]+)*/i,/(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs)\/([\w\.-]+)/i],[c,d],[/(trident).+rv[:\s]([\w\.]+).+like\sgecko/i],[[c,"IE"],d],[/(edge)\/((\d+)?[\w\.]+)/i],[c,d],[/(yabrowser)\/([\w\.]+)/i],[[c,"Yandex"],d],[/(comodo_dragon)\/([\w\.]+)/i],[[c,/_/g," "],d],[/(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,/(qqbrowser)[\/\s]?([\w\.]+)/i],[c,d],[/(uc\s?browser)[\/\s]?([\w\.]+)/i,/ucweb.+(ucbrowser)[\/\s]?([\w\.]+)/i,/JUC.+(ucweb)[\/\s]?([\w\.]+)/i],[[c,"UCBrowser"],d],[/(dolfin)\/([\w\.]+)/i],[[c,"Dolphin"],d],[/((?:android.+)crmo|crios)\/([\w\.]+)/i],[[c,"Chrome"],d],[/XiaoMi\/MiuiBrowser\/([\w\.]+)/i],[d,[c,"MIUI Browser"]],[/android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i],[d,[c,"Android Browser"]],[/FBAV\/([\w\.]+);/i],[d,[c,"Facebook"]],[/fxios\/([\w\.-]+)/i],[d,[c,"Firefox"]],[/version\/([\w\.]+).+?mobile\/\w+\s(safari)/i],[d,[c,"Mobile Safari"]],[/version\/([\w\.]+).+?(mobile\s?safari|safari)/i],[d,c],[/webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i],[c,[d,x.str,T.browser.oldsafari.version]],[/(konqueror)\/([\w\.]+)/i,/(webkit|khtml)\/([\w\.]+)/i],[c,d],[/(navigator|netscape)\/([\w\.-]+)/i],[[c,"Netscape"],d],[/(swiftfox)/i,/(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,/(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,/(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i,/(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir)[\/\s]?([\w\.]+)/i,/(links)\s\(([\w\.]+)/i,/(gobrowser)\/?([\w\.]+)*/i,/(ice\s?browser)\/v?([\w\._]+)/i,/(mosaic)[\/\s]([\w\.]+)/i],[c,d]],cpu:[[/(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\)]/i],[[v,"amd64"]],[/(ia32(?=;))/i],[[v,S.lowerize]],[/((?:i[346]|x)86)[;\)]/i],[[v,"ia32"]],[/windows\s(ce|mobile);\sppc;/i],[[v,"arm"]],[/((?:ppc|powerpc)(?:64)?)(?:\smac|;|\))/i],[[v,/ower/,"",S.lowerize]],[/(sun4\w)[;\)]/i],[[v,"sparc"]],[/((?:avr32|ia64(?=;))|68k(?=\))|arm(?:64|(?=v\d+;))|(?=atmel\s)avr|(?:irix|mips|sparc)(?:64)?(?=;)|pa-risc)/i],[[v,S.lowerize]]],device:[[/\((ipad|playbook);[\w\s\);-]+(rim|apple)/i],[l,p,[h,y]],[/applecoremedia\/[\w\.]+ \((ipad)/],[l,[p,"Apple"],[h,y]],[/(apple\s{0,1}tv)/i],[[l,"Apple TV"],[p,"Apple"]],[/(archos)\s(gamepad2?)/i,/(hp).+(touchpad)/i,/(kindle)\/([\w\.]+)/i,/\s(nook)[\w\s]+build\/(\w+)/i,/(dell)\s(strea[kpr\s\d]*[\dko])/i],[p,l,[h,y]],[/(kf[A-z]+)\sbuild\/[\w\.]+.*silk\//i],[l,[p,"Amazon"],[h,y]],[/(sd|kf)[0349hijorstuw]+\sbuild\/[\w\.]+.*silk\//i],[[l,x.str,T.device.amazon.model],[p,"Amazon"],[h,g]],[/\((ip[honed|\s\w*]+);.+(apple)/i],[l,p,[h,g]],[/\((ip[honed|\s\w*]+);/i],[l,[p,"Apple"],[h,g]],[/(blackberry)[\s-]?(\w+)/i,/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola|polytron)[\s_-]?([\w-]+)*/i,/(hp)\s([\w\s]+\w)/i,/(asus)-?(\w+)/i],[p,l,[h,g]],[/\(bb10;\s(\w+)/i],[l,[p,"BlackBerry"],[h,g]],[/android.+(transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+|nexus 7)/i],[l,[p,"Asus"],[h,y]],[/(sony)\s(tablet\s[ps])\sbuild\//i,/(sony)?(?:sgp.+)\sbuild\//i],[[p,"Sony"],[l,"Xperia Tablet"],[h,y]],[/(?:sony)?(?:(?:(?:c|d)\d{4})|(?:so[-l].+))\sbuild\//i],[[p,"Sony"],[l,"Xperia Phone"],[h,g]],[/\s(ouya)\s/i,/(nintendo)\s([wids3u]+)/i],[p,l,[h,m]],[/android.+;\s(shield)\sbuild/i],[l,[p,"Nvidia"],[h,m]],[/(playstation\s[34portablevi]+)/i],[l,[p,"Sony"],[h,m]],[/(sprint\s(\w+))/i],[[p,x.str,T.device.sprint.vendor],[l,x.str,T.device.sprint.model],[h,g]],[/(lenovo)\s?(S(?:5000|6000)+(?:[-][\w+]))/i],[p,l,[h,y]],[/(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i,/(zte)-(\w+)*/i,/(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i],[p,[l,/_/g," "],[h,g]],[/(nexus\s9)/i],[l,[p,"HTC"],[h,y]],[/[\s\(;](xbox(?:\sone)?)[\s\);]/i],[l,[p,"Microsoft"],[h,m]],[/(kin\.[onetw]{3})/i],[[l,/\./g," "],[p,"Microsoft"],[h,g]],[/\s(milestone|droid(?:[2-4x]|\s(?:bionic|x2|pro|razr))?(:?\s4g)?)[\w\s]+build\//i,/mot[\s-]?(\w+)*/i,/(XT\d{3,4}) build\//i,/(nexus\s[6])/i],[l,[p,"Motorola"],[h,g]],[/android.+\s(mz60\d|xoom[\s2]{0,2})\sbuild\//i],[l,[p,"Motorola"],[h,y]],[/android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9|nexus 10))/i,/((SM-T\w+))/i],[[p,"Samsung"],l,[h,y]],[/((s[cgp]h-\w+|gt-\w+|galaxy\snexus|sm-n900))/i,/(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i,/sec-((sgh\w+))/i],[[p,"Samsung"],l,[h,g]],[/(samsung);smarttv/i],[p,l,[h,b]],[/\(dtv[\);].+(aquos)/i],[l,[p,"Sharp"],[h,b]],[/sie-(\w+)*/i],[l,[p,"Siemens"],[h,g]],[/(maemo|nokia).*(n900|lumia\s\d+)/i,/(nokia)[\s_-]?([\w-]+)*/i],[[p,"Nokia"],l,[h,g]],[/android\s3\.[\s\w;-]{10}(a\d{3})/i],[l,[p,"Acer"],[h,y]],[/android\s3\.[\s\w;-]{10}(lg?)-([06cv9]{3,4})/i],[[p,"LG"],l,[h,y]],[/(lg) netcast\.tv/i],[p,l,[h,b]],[/(nexus\s[45])/i,/lg[e;\s\/-]+(\w+)*/i],[l,[p,"LG"],[h,g]],[/android.+(ideatab[a-z0-9\-\s]+)/i],[l,[p,"Lenovo"],[h,y]],[/linux;.+((jolla));/i],[p,l,[h,g]],[/((pebble))app\/[\d\.]+\s/i],[p,l,[h,w]],[/android.+;\s(glass)\s\d/i],[l,[p,"Google"],[h,w]],[/android.+(\w+)\s+build\/hm\1/i,/android.+(hm[\s\-_]*note?[\s_]*(?:\d\w)?)\s+build/i,/android.+(mi[\s\-_]*(?:one|one[\s_]plus)?[\s_]*(?:\d\w)?)\s+build/i],[[l,/_/g," "],[p,"Xiaomi"],[h,g]],[/\s(tablet)[;\/\s]/i,/\s(mobile)[;\/\s]/i],[[h,S.lowerize],p,l]],engine:[[/windows.+\sedge\/([\w\.]+)/i],[d,[c,"EdgeHTML"]],[/(presto)\/([\w\.]+)/i,/(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,/(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,/(icab)[\/\s]([23]\.[\d\.]+)/i],[c,d],[/rv\:([\w\.]+).*(gecko)/i],[d,c]],os:[[/microsoft\s(windows)\s(vista|xp)/i],[c,d],[/(windows)\snt\s6\.2;\s(arm)/i,/(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i],[c,[d,x.str,T.os.windows.version]],[/(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i],[[c,"Windows"],[d,x.str,T.os.windows.version]],[/\((bb)(10);/i],[[c,"BlackBerry"],d],[/(blackberry)\w*\/?([\w\.]+)*/i,/(tizen)[\/\s]([\w\.]+)/i,/(android|webos|palm\sos|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,/linux;.+(sailfish);/i],[c,d],[/(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i],[[c,"Symbian"],d],[/\((series40);/i],[c],[/mozilla.+\(mobile;.+gecko.+firefox/i],[[c,"Firefox OS"],d],[/(nintendo|playstation)\s([wids34portablevu]+)/i,/(mint)[\/\s\(]?(\w+)*/i,/(mageia|vectorlinux)[;\s]/i,/(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|(?=\s)arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,/(hurd|linux)\s?([\w\.]+)*/i,/(gnu)\s?([\w\.]+)*/i],[c,d],[/(cros)\s[\w]+\s([\w\.]+\w)/i],[[c,"Chromium OS"],d],[/(sunos)\s?([\w\.]+\d)*/i],[[c,"Solaris"],d],[/\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i],[c,d],[/(ip[honead]+)(?:.*os\s([\w]+)*\slike\smac|;\sopera)/i],[[c,"iOS"],[d,/_/g,"."]],[/(mac\sos\sx)\s?([\w\s\.]+\w)*/i,/(macintosh|mac(?=_powerpc)\s)/i],[[c,"Mac OS"],[d,/_/g,"."]],[/((?:open)?solaris)[\/\s-]?([\w\.]+)*/i,/(haiku)\s(\w+)/i,/(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,/(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,/(unix)\s?([\w\.]+)*/i],[c,d]]},C=function(t,n){if(this instanceof C){var i=t||(e&&e.navigator&&e.navigator.userAgent?e.navigator.userAgent:r),s=n?S.extend(N,n):N;return this.getBrowser=function(){var e=x.rgx.apply(this,s.browser);return e.major=S.major(e.version),e},this.getCPU=function(){return x.rgx.apply(this,s.cpu)},this.getDevice=function(){return x.rgx.apply(this,s.device)},this.getEngine=function(){return x.rgx.apply(this,s.engine)},this.getOS=function(){return x.rgx.apply(this,s.os)},this.getResult=function(){return{ua:this.getUA(),browser:this.getBrowser(),engine:this.getEngine(),os:this.getOS(),device:this.getDevice(),cpu:this.getCPU()}},this.getUA=function(){return i},this.setUA=function(e){return i=e,this},this.setUA(i),this}return(new C(t,n)).getResult()};C.VERSION=n,C.BROWSER={NAME:c,MAJOR:f,VERSION:d},C.CPU={ARCHITECTURE:v},C.DEVICE={MODEL:l,VENDOR:p,TYPE:h,CONSOLE:m,MOBILE:g,SMARTTV:b,TABLET:y,WEARABLE:w,EMBEDDED:E},C.ENGINE={NAME:c,VERSION:d},C.OS={NAME:c,VERSION:d},typeof exports!==o?(typeof module!==o&&module.exports&&(exports=module.exports=C),exports.UAParser=C):typeof define===s&&define.amd?define(function(){return C}):e.UAParser=C;var k=e.jQuery||e.Zepto;if(typeof k!==o){var L=new C;k.ua=L.getResult(),k.ua.get=function(){return L.getUA()},k.ua.set=function(e){L.setUA(e);var t=L.getResult();for(var n in t)k.ua[n]=t[n]}}})(typeof window=="object"?window:this); diff --git a/packages/rocketchat-livechat/client/route.js b/packages/rocketchat-livechat/client/route.js index a2029900297fcea39a1fa5e9ed044b144769cb0a..c5b0eb72ae780b8925aec90ef0b0de42856710b9 100644 --- a/packages/rocketchat-livechat/client/route.js +++ b/packages/rocketchat-livechat/client/route.js @@ -1,32 +1,68 @@ -FlowRouter.route('/live/:name', { - name: 'live', +livechatManagerRoutes = FlowRouter.group({ + prefix: '/livechat-manager', + name: 'livechat-manager' +}); - action: function(params, queryParams) { - console.log('action route livechat'); - Session.set('showUserInfo'); - openRoom('l', params.name); - }, +AccountBox.addRoute({ + name: 'livechat-dashboard', + path: '/dashboard', + sideNav: 'livechatFlex', + i18nPageTitle: 'Livechat_Dashboard', + pageTemplate: 'livechatDashboard' +}, livechatManagerRoutes); - triggersExit: [roomExit] -}); +AccountBox.addRoute({ + name: 'livechat-users', + path: '/users', + sideNav: 'livechatFlex', + i18nPageTitle: 'Livechat_Users', + pageTemplate: 'livechatUsers' +}, livechatManagerRoutes); -FlowRouter.route('/livechat-manager/departments', { +AccountBox.addRoute({ name: 'livechat-departments', + path: '/departments', + sideNav: 'livechatFlex', + i18nPageTitle: 'Departments', + pageTemplate: 'livechatDepartments' +}, livechatManagerRoutes); - action: function(params, queryParams) { - BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatDepartments', pageTitle: t('Departments') }); - } -}); +AccountBox.addRoute({ + name: 'livechat-department-edit', + path: '/departments/:_id/edit', + sideNav: 'livechatFlex', + i18nPageTitle: 'Edit_Department', + pageTemplate: 'livechatDepartmentForm' +}, livechatManagerRoutes); -FlowRouter.route('/livechat-manager/department/:_id?', { - name: 'livechat-department', - - action: function(params, queryParams) { - if (params._id) { - pageTitle = t('Edit_Department'); - } else { - pageTitle = t('New_Department'); - } - BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatDepartmentForm', pageTitle: pageTitle}); - } -}); +AccountBox.addRoute({ + name: 'livechat-department-new', + path: '/departments/new', + sideNav: 'livechatFlex', + i18nPageTitle: 'New_Department', + pageTemplate: 'livechatDepartmentForm' +}, livechatManagerRoutes); + +AccountBox.addRoute({ + name: 'livechat-triggers', + path: '/triggers', + sideNav: 'livechatFlex', + i18nPageTitle: 'Triggers', + pageTemplate: 'livechatTriggers' +}, livechatManagerRoutes); + +AccountBox.addRoute({ + name: 'livechat-installation', + path: '/installation', + sideNav: 'livechatFlex', + i18nPageTitle: 'Installation', + pageTemplate: 'livechatInstallation' +}, livechatManagerRoutes); + +AccountBox.addRoute({ + name: 'livechat-appearance', + path: '/appearance', + sideNav: 'livechatFlex', + i18nPageTitle: 'Appearance', + pageTemplate: 'livechatAppearance' +}, livechatManagerRoutes); diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less new file mode 100644 index 0000000000000000000000000000000000000000..24c80d0d8087829373dd473650a51e6a4558e321 --- /dev/null +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -0,0 +1,492 @@ +.calc(...) { + @process: ~`(function(e){function t(t,r){var a=");\n",c=n.split(","),i=c[0]+":"+t+"("+(c[1].trim()||0)+a;"start"==r?e="0;\n"+i:e+=i}e=e||8121991;var r="@{state}",n=e;if(8121991==e)return e;switch(r){case"1":t("-webkit-calc","start"),t("-moz-calc"),t("calc");break;case"2":t("-webkit-calc","start"),t("-moz-calc");break;case"3":t("-webkit-calc","start"),t("calc");break;case"4":t("-webkit-calc","start");break;case"5":t("-moz-calc","start"),t("calc");break;case"6":t("-moz-calc","start");break;case"7":t("calc","start")}return e=e.replace(/;$/g,"")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @state: 1; -lh-property: @process; + +} + +.transition(...) { + @process_webkit: ~`(function(e){e=e||"all 0 ease 0";var r=["background-size","border-radius","border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","box-shadow","column","transform","filter"],t="-webkit-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){e=e||"all 0 ease 0";var r=["background-size","box-shadow","column","transform","filter"],t="-moz-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_opera: ~`(function(e){e=e||"all 0 ease 0";var r=["transform"],t="-o-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){e=e||"all 0 ease 0";var r=["-webkit-","-moz-","-o-",""],t=["column","transform","filter"],n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""));var c=e.split(/(?:,)(?![^(]*\))/g);return c.forEach(function(e,n){t.forEach(function(t){-1!==e.indexOf(t)&&(c[n]="",r.forEach(function(a,u){c[n]+=e.trim().replace(new RegExp(t,"g"),function(e){return a+e}),u<r.length-1&&(c[n]+=",")}))})}),e=c.join(","),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transition: @process_webkit; + -moz-transition: @process_moz; + -o-transition: @process_opera; + transition: @process; +} + +.transform(...) { + @process: ~`(function(e){e=e||"none";var r={translate:"px",rotate:"deg",rotate3d:"deg",skew:"deg"};/^\w*\(?[a-z0-9.]*\)?/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""));for(var t in r)e.indexOf(t)>=0&&(e=e.replace(new RegExp(t+"[\\w]?\\([a-z0-9, %]*\\)"),function(e){var n=/(\d+\.?\d*)(?!\w|%)/g;return"rotate3d"==t&&(n=/,\s*\d+$/),e.replace(n,function(e){return e+r[t]})}));return e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: @process; + -moz-transform: @process; + -o-transform: @process; + -ms-transform: @process; + transform: @process; +} + +.flex-list { + .active { + background-color: rgba(255,255,255,0.075); + } +} + +.trigger-option, .trigger-value { + float: left; + display: inline-block; +} + +.trigger-option { + width: 30%; + max-width: 300px; + padding-right: 4px; +} + +.trigger-value { + width: 70%; + + input { + display: inline-block !important; + width: auto !important; + } +} + +.livechat-code { + width: 90%; + max-width: 750px; + text-align: right; + + textarea { + text-align: left; + width: 100%; + height: 200px; + background-color: #EFEFEF; + font-family: courier; + font-size: 12px; + display: block; + } +} + +.preview-mode { + width: auto; + margin-bottom: 1em; +} + +.livechat-settings-div, .livechat-preview-div { + width: 50%; + float: left; + height: 95%; + margin-bottom: 0 !important; + padding: 1em; +} + +.livechat-settings-div { + border-right: 1px solid #CCC; +} + +.livechat-preview { + width: 340px; + height: 350px; + margin: 0 auto; + + border-bottom: 1px solid #CCC; + position: relative; + + .preview-wrapper { + position: absolute; + width: 100%; + padding: 0 20px; + height: 350px; + bottom: 0; + + @header-min-height: 30px; + @footer-min-height: 42px; + @link-font-color: #008CE3; + @primary-font-color: #444444; + @secondary-font-color: #7f7f7f; + @info-font-color: #AAAAAA; + + .livechat-room { + display: flex; + flex-direction: column; + height: 100%; + + .title { + flex: 1 0 @header-min-height; + + line-height: @header-min-height; + + border-top-right-radius: 5px; + border-top-left-radius: 5px; + color: #FFF; + z-index: 10; + cursor: pointer; + h1 { + margin: 0; + padding: 0 5px; + font-size: 9pt; + display: inline-block; + text-transform: none; + } + + .toolbar { + display: inline-block; + float: right; + padding-right: 5px; + } + } + .messages { + flex: 1 1 100%; + + background-color: #FFF; + border-left: 1px solid #E7E7E7; + border-right: 1px solid #E7E7E7; + overflow-y: auto; + .wrapper { + padding-bottom: 6px; + + ul { + list-style-type: none; + padding: 0; + li { + padding: 0; + } + } + + .message { + font-size: 12px; + padding-left: 40px; + position: relative; + line-height: 18px; + margin: 12px 10px 0; + min-height: 36px; + &:nth-child(1) { + margin-top: 0; + } + &.new-day { + margin-top: 60px; + } + &.new-day { + &:before { + content: attr(data-date); + display: block; + position: absolute; + top: -30px; + left: 0; + font-size: 10px; + font-weight: 600; + text-align: center; + .calc(left, ~'50% - 70px'); + color: @secondary-font-color; + z-index: 10; + padding: 0 10px; + background-color: #FFF; + min-width: 120px; + } + &:after { + content: " "; + display: block; + position: absolute; + top: -20px; + left: 0; + width: 100%; + border-top: 1px solid #ddd; + } + } + .edit-message { + display: none; + cursor: pointer; + } + &.own:hover:not(.system) .edit-message { + display: inline-block; + } + .delete-message { + display: none; + cursor: pointer; + } + &.own:hover:not(.system) .delete-message { + display: inline-block; + } + .user { + display: inline-block; + font-weight: 600; + color: #444444; + margin-right: 5px; + outline: none; + &:hover { + color: #333; + } + } + .thumb { + position: absolute; + left: 0; + top: 0; + display: block; + width: 30px; + height: 30px; + } + .info { + font-size: 10px; + color: @info-font-color; + } + &.sequential { + // margin-top: 5px; + padding-top: 5px; + margin-top: 0; + margin-bottom: 0; + min-height: 20px; + .user { + display: none; + } + .thumb { + display: none; + } + .info { + position: absolute; + text-align: right; + left: -20px; + width: 55px; + .time { + display: none; + } + .edited { + display: inline-block; + } + .edit-message { + float: left; + margin-left: 1px; + } + .delete-message { + float: left; + } + } + &:hover { + .time { + display: inline-block; + } + .edited { + display: none; + } + } + } + &.system { + .body { + color: @info-font-color; + font-style: italic; + text-transform: lowercase; + em { + font-weight: 600; + } + } + } + .avatar-initials { + line-height: 40px; + } + a { + color: @link-font-color; + font-weight: 400; + &:hover { + color: darken(@link-font-color, 10%); + text-decoration: underline; + } + } + .body { + opacity: 1; + .transition(opacity 1s linear); + } + &.temp .body { + opacity: .5; + } + &.msg-error .body { + text-decoration: line-through; + } + + .avatar .avatar-image { + height: 100%; + width: 100%; + min-height: 20px; + min-width: 20px; + display: block; + position: relative; + background-color: transparent; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + border-radius: 4px; + } + } + } + .new-message { + margin: 0 -65px; + position: absolute; + background: #428bca; + border-radius: 20px; + width: 130px; + height: 30px; + text-align: center; + color: #FFF; + line-height: 30px; + font-size: 0.8em; + cursor: pointer; + bottom: 8px; + left: 50%; + z-index: 5; + .transition(transform 0.3s ease-out); + .transform(translateY(-40px)); + &.not { + .transform(translateY(100%)); + } + } + + .error { + bottom: 40px; + position: fixed; + width: 100%; + background-color: #F7D799; + padding: 5px; + z-index: 8; + + .transition(transform 0.2s ease-out); + .transform(translateY(100%)); + + &.show { + .transform(translateY(0)); + } + } + } + .footer { + flex: 1 0 @footer-min-height; + + z-index: 10; + + background-color: #FCFCFC; + border-top: 1px solid #E7E7E7; + border-left: 1px solid #E7E7E7; + border-right: 1px solid #E7E7E7; + + .input-wrapper { + padding: 6px; + textarea { + display: block; + padding: 6px 8px; + padding-right: 38px; + overflow-y: auto; + resize: none; + border: 1px solid #E7E7E7; + // margin: 10px; + border-radius: 5px; + max-height: 200px; + width: 100%; + font-size: 12px; + -webkit-appearance: none; + height: 28px; + line-height: normal; + background-color: #fff; + position: relative; + outline: none; + } + } + } + .offline { + flex: 1 1 100%; + font-weight: bold; + background-color: white; + padding: 2em 0; + text-align: center; + } + } + } + + &.closed { + .preview-wrapper { + height: 32px; + .livechat-room .title .toolbar { + display: none; + } + .messages { + display: none; + } + .footer { + display: none; + } + } + } +} + +.department-agents { + list-style-type: none; + + li { + display: inline-block; + background-color: #DDD; + border-radius: 10px; + padding: 2px 8px 2px 2px; + margin: 1px 0; + cursor: pointer; + + .icon-plus-circled { + opacity: 0.5; + font-size: 0.8rem; + } + } +} + +.agent-info { + input[type='text'] { + width: auto; + line-height: 24px; + height: 24px; + } +} + +.user-view { + li { + color: @secondary-font-color; + line-height: 18px; + font-size: 12px; + font-weight: 300; + } +} + +.icon-chat-empty.status-offline { + color: @status-offline; +} + +.icon-chat-empty.status-online { + color: @status-online; +} + +.icon-chat-empty.status-busy { + color: @status-busy; +} + +.icon-chat-empty.status-away { + color: @status-away; +} + +.visitor-navigation { + height: 130px; + overflow-y: auto; + border: 1px solid #E7E7E7; + border-radius: 4px; + padding: 4px; + margin-top: 4px; + + ul { + li { + white-space: nowrap; + + a { + text-overflow: ellipsis; + display: block; + overflow: hidden; + + color: @secondary-font-color; + text-decoration: underline; + + &:hover { + text-decoration: none; + } + } + } + } +} diff --git a/packages/rocketchat-livechat/client/stylesheets/load.js b/packages/rocketchat-livechat/client/stylesheets/load.js new file mode 100644 index 0000000000000000000000000000000000000000..3376dd0f6fd87d5408e7d56a33fc30e95f7b8bc3 --- /dev/null +++ b/packages/rocketchat-livechat/client/stylesheets/load.js @@ -0,0 +1,3 @@ +RocketChat.theme.addPackageAsset(() => { + return Assets.getText('client/stylesheets/livechat.less'); +}); diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index ea863114c22fdbcfd6350ea8c71e743187d4d183..1041cfc75e6cad1157bb6eace4282008755e3791 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -7,6 +7,7 @@ RocketChat.roomTypes.add('l', 5, { action: (params, queryParams) => { Session.set('showUserInfo'); openRoom('l', params.name); + RocketChat.TabBar.showGroup('livechat', 'search'); }, link: (sub) => { return { @@ -14,21 +15,30 @@ RocketChat.roomTypes.add('l', 5, { } } }, - permissions: ['view-l-room'] + condition: () => { + return RocketChat.settings.get('Livechat_enabled') && RocketChat.authz.hasAllPermission('view-l-room'); + } }); AccountBox.addItem({ name: 'Livechat', icon: 'icon-chat-empty', - href: 'livechat-manager', + href: 'livechat-users', sideNav: 'livechatFlex', - permissions: ['view-livechat-manager'], + condition: () => { + return RocketChat.settings.get('Livechat_enabled') && RocketChat.authz.hasAllPermission('view-livechat-manager'); + }, }); -AccountBox.addRoute({ - name: 'livechat-manager', - path: '/livechat-manager', - sideNav: 'livechatFlex', - pageTitle: t('Livechat_Manager'), - pageTemplate: 'livechatManager' +RocketChat.TabBar.addButton({ + groups: ['livechat'], + id: 'visitor-info', + i18nTitle: 'Visitor_Info', + icon: 'octicon octicon-info', + template: 'visitorInfo', + order: 0 }); + +RocketChat.TabBar.addGroup('message-search', ['livechat']); +RocketChat.TabBar.addGroup('starred-messages', ['livechat']); +RocketChat.TabBar.addGroup('uploaded-files-list', ['livechat']); diff --git a/packages/rocketchat-livechat/client/views/app/livechatAppearance.html b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html new file mode 100644 index 0000000000000000000000000000000000000000..d6b03dd458d75b4dabdf1f55896de38fbbf599b1 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html @@ -0,0 +1,68 @@ +<template name="livechatAppearance"> + <div class="livechat-settings-div"> + <h2>{{_ "Settings"}}</h2> + + <form class="rocket-form"> + <div class="input-line"> + <label for="title">{{_ "Title"}}</label> + <input type="text" class="preview-settings" name="title" value="{{title}}"> + </div> + <div class="input-line"> + <label for="color">{{_ "Title_bar_color"}}</label> + <input type="text" class="preview-settings minicolors" name="color" value="{{color}}"> + </div> + <div class="submit"> + <button class="button secondary reset-settings"><i class="icon-ccw"></i>{{_ "Reset"}}</button> + <button class="button"><i class="icon-floppy"></i>{{_ "Save"}}</button> + </div> + </form> + </div> + + <div class="livechat-preview-div"> + <h2>{{_ "Preview"}}</h2> + + <select class="preview-mode"> + <option value="opened">{{_ "Opened"}}</option> + <option value="closed">{{_ "Closed"}}</option> + </select> + + <div class="livechat-preview {{previewState}}"> + <div class="preview-wrapper"> + {{#with sampleData}} + <div class="livechat-room"> + <div class="title" style="background-color:{{color}}"> + <div class="toolbar"> + + <i class="popout icon-link-ext" title="Open in a new window"></i> + </div> + <h1>{{title}}</h1> + </div> + <div class="messages"> + <div class="wrapper"> + <ul> + {{#each messages}} + <li id="{{_id}}" class="message {{sequential}}" data-username="{{u.username}}" data-date="{{date}}"> + <span class="thumb thumb-small" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</span> + <span class="user" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</span> + <span class="info"> + <span class="time">{{time}}</span> + </span> + <div class="body" dir="auto"> + {{{body}}} + </div> + </li> + {{/each}} + </ul> + </div> + </div> + <div class="footer"> + <div class="input-wrapper"> + <textarea class="input-message" placeholder="Type your message"></textarea> + </div> + </div> + </div> + {{/with}} + </div> + </div> + </div> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatAppearance.js b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js new file mode 100644 index 0000000000000000000000000000000000000000..94e56f6f9ca8750a9c6d02bb8bb76d91912bb030 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js @@ -0,0 +1,139 @@ +Template.livechatAppearance.helpers({ + previewState () { + return Template.instance().previewState.get(); + }, + color () { + return Template.instance().color.get(); + }, + title () { + return Template.instance().title.get(); + }, + sampleData () { + return { + color: RocketChat.settings.get('Livechat_title_color'), + title: RocketChat.settings.get('Livechat_title'), + messages: [ + { + _id: Random.id(), + u: { + username: 'guest' + }, + time: moment(this.ts).format('LT'), + date: moment(this.ts).format('LL'), + body: 'Hello', + sequential: null + }, + { + _id: Random.id(), + u: { + username: 'rocketchat-agent' + }, + time: moment(this.ts).format('LT'), + date: moment(this.ts).format('LL'), + body: 'Hey, what can I help you with?', + sequential: null + }, + { + _id: Random.id(), + u: { + username: 'guest' + }, + time: moment(this.ts).format('LT'), + date: moment(this.ts).format('LL'), + body: 'I\'m looking for informations about your product.', + sequential: null + }, + { + _id: Random.id(), + u: { + username: 'rocketchat-agent' + }, + time: moment(this.ts).format('LT'), + date: moment(this.ts).format('LL'), + body: 'Our product is open source, you can do what you want with it! =D', + sequential: null + }, + { + _id: Random.id(), + u: { + username: 'guest' + }, + time: moment(this.ts).format('LT'), + date: moment(this.ts).format('LL'), + body: 'Yay, thanks. That\'s awesome.', + sequential: null + }, + { + _id: Random.id(), + u: { + username: 'rocketchat-agent' + }, + time: moment(this.ts).format('LT'), + date: moment(this.ts).format('LL'), + body: 'You\'re welcome.', + sequential: null + } + ] + }; + } +}); + +Template.livechatAppearance.onCreated(function() { + this.previewState = new ReactiveVar('opened'); + + this.title = new ReactiveVar(null); + this.color = new ReactiveVar(null); + + this.autorun(() => { + this.title.set(RocketChat.settings.get('Livechat_title')); + }); + this.autorun(() => { + this.color.set(RocketChat.settings.get('Livechat_title_color')); + }); +}); + +Template.livechatAppearance.events({ + 'change .preview-mode' (e, instance) { + instance.previewState.set(e.currentTarget.value); + }, + 'change .preview-settings, keyup .preview-settings' (e, instance) { + instance[e.currentTarget.name].set(e.currentTarget.value); + }, + 'click .reset-settings' (e, instance) { + e.preventDefault(); + + instance.title.set(RocketChat.settings.get('Livechat_title')); + instance.color.set(RocketChat.settings.get('Livechat_title_color')); + + instance.$('input.preview-settings[name=color]').minicolors('value', instance.color.get()); + }, + 'submit .rocket-form' (e, instance) { + e.preventDefault(); + + var settings = [ + { + _id: 'Livechat_title', + value: instance.title.get() + }, + { + _id: 'Livechat_title_color', + value: instance.color.get() + } + ]; + RocketChat.settings.batchSet(settings, (err, success) => { + if (err) { + return toastr.error(t('Error_updating_settings')); + } + toastr.success(t('Settings_updated')); + }); + } +}) + +Template.livechatAppearance.onRendered(function() { + Meteor.setTimeout(() => { + $('input.minicolors').minicolors({ + theme: 'rocketchat', + letterCase: 'uppercase' + }); + }, 500); +}); diff --git a/packages/rocketchat-livechat/client/views/app/livechatDashboard.html b/packages/rocketchat-livechat/client/views/app/livechatDashboard.html new file mode 100644 index 0000000000000000000000000000000000000000..ae5a2b7df4fffcd938e5e53b0283ee761966c868 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatDashboard.html @@ -0,0 +1,3 @@ +<template name="livechatDashboard"> + <h1>Dashboard</h1> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html index 5a82ac77c719601b0ec0dbcb7df3d79463661222..fccbaa7f071818e87b02d36fd87981cd83680d6a 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -24,34 +24,51 @@ </div> <hr /> <h2>{{_ "Agents"}}</h2> - <div class="input-line double-col"> - <input type="text" name="agent" placeholder="{{_ "Enter_a_username"}}"> - <button name="addAgent" type="button" class="button add-agent">{{_ "Add_agent"}}</button> - </div> - <div class="list"> - <table> - <thead> - <tr> - <th width="25%">{{_ "Username"}}</th> - <th>{{_ "Delete"}}</th> - </tr> - </thead> - <tbody> - {{#if agents.length}} - {{#each agents}} - <tr class="agent-info" data-id="{{_id}}"> - <td>{{username}}</td> - <td><a href="#remove" class="remove-agent"><i class="icon-trash"></i></a></td> - </tr> - {{/each}} - {{else}} + + <fieldset> + <legend>{{_ "Available_agents"}}</legend> + + <ul class="department-agents available-agents"> + {{#each availableAgents}} + <li><i class="icon-plus-circled"></i>{{username}}</li> + {{/each}} + </ul> + </fieldset> + + <fieldset> + <legend>{{_ "Selected_agents"}}</legend> + + <div class="list"> + <table> + <thead> <tr> - <td colspan="2">{{_ "There_are_no_agents_added_to_this_department_yet"}}</td> + <th width="25%">{{_ "Username"}}</th> + <th>{{_ "Count"}}</th> + <th>{{_ "Order"}}</th> + <th> </th> </tr> - {{/if}} - </tbody> - </table> - </div> + </thead> + <tbody> + {{#if selectedAgents}} + {{#each selectedAgents}} + <tr class="agent-info"> + <td>{{username}}</td> + <td><input type="text" class="count-{{agentId}}" name="count" value="{{count}}" size="3"></td> + <td><input type="text" class="order-{{agentId}}" name="order" value="{{order}}" size="3"></td> + <td><a href="#remove" class="remove-agent"><i class="icon-trash"></i></a></td> + </tr> + {{/each}} + {{else}} + <tr> + <td colspan="4">{{_ "There_are_no_agents_added_to_this_department_yet"}}</td> + </tr> + {{/if}} + </tbody> + </table> + </div> + + </fieldset> + </fieldset> <div class="submit"> <button type="button" class="button secondary back"><i class="icon-left-big"></i><span>{{_ "Back"}}</span></button> diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js index d4ff6d0fcac65b7cd1ed2d59538d947dd2d37e8a..6f5017e0ca2efb8234d0696c6b4339f001cd23d4 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js @@ -1,10 +1,16 @@ Template.livechatDepartmentForm.helpers({ department() { - // return Template.instance().department && !_.isEmpty(Template.instance().department.get()) ? Template.instance().department.get() : { enabled: true }; return Template.instance().department.get(); }, agents() { return Template.instance().department && !_.isEmpty(Template.instance().department.get()) ? Template.instance().department.get().agents : [] + }, + selectedAgents() { + return _.sortBy(Template.instance().selectedAgents.get(), 'username'); + }, + availableAgents() { + var selected = _.pluck(Template.instance().selectedAgents.get(), 'username'); + return AgentUsers.find({ username: { $nin: selected }}, { sort: { username: 1 } }); } }); @@ -29,16 +35,22 @@ Template.livechatDepartmentForm.events({ var oldBtnValue = $btn.html(); $btn.html(t('Saving')); - agents = instance.department && !_.isEmpty(instance.department.get()) ? instance.department.get().agents : []; - - departmentData = { + var departmentData = { enabled: enabled === "1" ? true : false, name: name.trim(), - description: description.trim(), - agents: agents - } + description: description.trim() + }; + + var departmentAgents = []; + + instance.selectedAgents.get().forEach((agent) => { + agent.count = instance.$('.count-' + agent.agentId).val(); + agent.order = instance.$('.order-' + agent.agentId).val(); + + departmentAgents.push(agent); + }); - Meteor.call('livechat:saveDepartment', _id, departmentData, function(error, result) { + Meteor.call('livechat:saveDepartment', _id, departmentData, departmentAgents, function(error, result) { $btn.html(oldBtnValue); if (error) { return toastr.error(t(error.reason || error.error)); @@ -54,59 +66,44 @@ Template.livechatDepartmentForm.events({ FlowRouter.go('livechat-departments'); }, - 'click button.add-agent' (e, instance) { + 'click .remove-agent' (e, instance) { e.preventDefault(); - var $btn = $(e.currentTarget); - - var $agent = instance.$('input[name=agent]') - - if ($agent.val().trim() === '') { - return toastr.error(t('Please_fill_a_username')); - } - - var oldBtnValue = $btn.html(); - $btn.html(t('Saving')); - Meteor.call('livechat:searchAgent', $agent.val(), function(error, user) { - $btn.html(oldBtnValue); - if (error) { - return toastr.error(t(error.reason || error.error)); - } - department = instance.department.get() || {}; - if (department.agents === undefined || !_.isArray(department.agents)) { - department.agents = []; - } - if (!_.findWhere(department.agents, { _id: user._id })) { - department.agents.push(user); - } - instance.department.set(department); - $agent.val(''); - }); + var selectedAgents = instance.selectedAgents.get(); + selectedAgents = _.reject(selectedAgents, (agent) => { return agent._id === this._id }); + instance.selectedAgents.set(selectedAgents); }, - 'click a.remove-agent' (e, instance) { - e.preventDefault(); - department = instance.department.get(); - department.agents = _.reject(department.agents, (agent) => { return agent._id === this._id }); - instance.department.set(department); - }, - - 'keydown input[name=agent]' (e, instance) { - if (e.keyCode === 13) { - e.preventDefault(); - $("button.add-agent").click(); - } + 'click .available-agents li' (e, instance) { + var selectedAgents = instance.selectedAgents.get(); + var agent = _.clone(this); + agent.agentId = this._id; + delete agent._id; + selectedAgents.push(agent); + instance.selectedAgents.set(selectedAgents); } }); Template.livechatDepartmentForm.onCreated(function() { this.department = new ReactiveVar({ enabled: true }); + this.selectedAgents = new ReactiveVar([]); + + this.subscribe('livechat:agents'); + this.autorun(() => { var sub = this.subscribe('livechat:departments', FlowRouter.getParam('_id')); if (sub.ready()) { department = LivechatDepartment.findOne({ _id: FlowRouter.getParam('_id') }); if (department) { this.department.set(department); + + this.subscribe('livechat:departmentAgents', department._id, () => { + var newSelectedAgents = []; + LivechatDepartmentAgents.find({ departmentId: department._id }).forEach((agent) => { + newSelectedAgents.push(agent); + }); + this.selectedAgents.set(newSelectedAgents); + }); } } }); diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartments.html b/packages/rocketchat-livechat/client/views/app/livechatDepartments.html index a334421e88e34715b460b107269f72be9a1d9898..2c92e7b07cc6dc5d59372fde3560774963ab606f 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartments.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.html @@ -24,8 +24,5 @@ </table> </div> - <form id="form-manager" class="inline"> - <button name="newDepartment" class="button primary">{{_ "New_Department"}}</button> - </form> - + <a href="{{pathFor 'livechat-department-new'}}" class="button primary">{{_ "New_Department"}}</a> </template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js index 274f1d1876e597cf27e302f83ed81e2dcc2718dd..e5d0746485dc5ca44f2183e639372807151d4e8e 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js @@ -1,20 +1,10 @@ Template.livechatDepartments.helpers({ "departments": () => { return LivechatDepartment.find(); - }, - "numAgents"() { - if (Array.isArray(this.agents)) { - return this.agents.length; - } } }); Template.livechatDepartments.events({ - "click button[name=newDepartment]": (event, instance) => { - event.preventDefault(); - FlowRouter.go('livechat-department'); - }, - 'click .remove-department' (e, instance) { e.preventDefault(); e.stopPropagation(); @@ -46,7 +36,7 @@ Template.livechatDepartments.events({ 'click .department-info' (e, instance) { e.preventDefault(); - FlowRouter.go('livechat-department', { _id: this._id }); + FlowRouter.go('livechat-department-edit', { _id: this._id }); } }); diff --git a/packages/rocketchat-livechat/client/views/app/livechatInstallation.html b/packages/rocketchat-livechat/client/views/app/livechatInstallation.html new file mode 100644 index 0000000000000000000000000000000000000000..6d912bb3cca378198721177f7d2cefa6f1f5d4b3 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatInstallation.html @@ -0,0 +1,8 @@ +<template name="livechatInstallation"> + <p>{{{_ "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site"}}}</p> + + <div class="livechat-code"> + <textarea class="clipboard" data-clipboard-target=".livechat-code textarea">{{script}}</textarea> + <button class="button clipboard" data-clipboard-target=".livechat-code textarea"><i class="icon-docs"></i>{{_ "Copy_to_clipboard"}}</button> + </div> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatInstallation.js b/packages/rocketchat-livechat/client/views/app/livechatInstallation.js new file mode 100644 index 0000000000000000000000000000000000000000..339d894e6904f91ee620495bb7b850aecd790003 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatInstallation.js @@ -0,0 +1,17 @@ +Template.livechatInstallation.helpers({ + script () { + return `<!-- Start of Rocket.Chat Livechat Script --> +<script type="text/javascript"> +(function(w, d, s, f, u) { + w[f] = w[f] || []; + w[f].push(u); + var h = d.getElementsByTagName(s)[0], + j = d.createElement(s); + j.async = true; + j.src = '${RocketChat.settings.get('Site_Url')}/packages/rocketchat_livechat/assets/rocket-livechat.js'; + h.parentNode.insertBefore(j, h); +})(window, document, 'script', 'initRocket', '${RocketChat.settings.get('Site_Url')}/livechat'); +</script> +<!-- End of Rocket.Chat Livechat Script -->`; + } +}) diff --git a/packages/rocketchat-livechat/client/views/app/livechatTriggers.html b/packages/rocketchat-livechat/client/views/app/livechatTriggers.html new file mode 100644 index 0000000000000000000000000000000000000000..98e5bd9b9e50aeecbed1a2240d142aa0d825f435 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatTriggers.html @@ -0,0 +1,32 @@ +<template name="livechatTriggers"> + <form id="trigger-form"> + <div class="rocket-form"> + <fieldset> + <legend>{{_ "Condition"}}</legend> + <div class="conditions"> + {{#each conditions}} + {{> livechatTriggerCondition}} + {{/each}} + {{#unless conditions}} + {{> livechatTriggerCondition}} + {{/unless}} + </div> + </fieldset> + <fieldset> + <legend>{{_ "Action"}}</legend> + <div class="actions"> + {{#each actions}} + {{> livechatTriggerAction}} + {{/each}} + {{#unless actions}} + {{> livechatTriggerAction}} + {{/unless}} + </div> + </fieldset> + <div class="submit"> + <button type="button" class="button red delete-trigger">{{_ "Delete"}}</button> + <button class="button save"><i class="icon-floppy"></i><span>{{_ "Save"}}</span></button> + </div> + </div> + </form> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatTriggers.js b/packages/rocketchat-livechat/client/views/app/livechatTriggers.js new file mode 100644 index 0000000000000000000000000000000000000000..d36632f0f7f0d66b80b4d93d961aa134be77c97b --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatTriggers.js @@ -0,0 +1,98 @@ +Template.livechatTriggers.helpers({ + conditions() { + var trigger = Template.instance().trigger.get(); + if (!trigger) return []; + + return trigger.conditions; + }, + actions() { + var trigger = Template.instance().trigger.get(); + if (!trigger) return []; + + return trigger.actions; + } +}); + +Template.livechatTriggers.events({ + 'submit #trigger-form' (e, instance) { + e.preventDefault(); + var $btn = instance.$('button.save'); + + var oldBtnValue = $btn.html(); + $btn.html(t('Saving')); + + var data = { + conditions: [], + actions: [] + }; + + $('.each-condition').each(function() { + data.conditions.push({ + name: $('.trigger-condition', this).val(), + value: $('.' + $('.trigger-condition', this).val() + '-value').val() + }); + }); + + $('.each-action').each(function() { + if ($('.trigger-action', this).val() === 'send-message') { + data.actions.push({ + name: $('.trigger-action', this).val(), + params: { + name: $('[name=send-message-name]', this).val(), + msg: $('[name=send-message-msg]', this).val() + } + }); + } else { + data.actions.push({ + name: $('.trigger-action', this).val(), + value: $('.' + $('.trigger-action', this).val() + '-value').val() + }); + } + }); + + Meteor.call('livechat:saveTrigger', data, function(error, result) { + $btn.html(oldBtnValue); + if (error) { + return toastr.error(t(error.reason || error.error)); + } + + toastr.success(t('Saved')); + }); + }, + 'click .delete-trigger' (e, instance) { + e.preventDefault() + + swal({ + title: t('Are_you_sure'), + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#DD6B55', + confirmButtonText: t('Yes'), + cancelButtonText: t('Cancel'), + closeOnConfirm: false, + html: false, + }, () => { + Meteor.call('livechat:removeTrigger', function(error, result) { + if (error) { + return toastr.error(t(error.reason || error.error)); + } + + swal({ + title: t('Removed'), + text: t('Trigger_removed'), + type: 'success', + timer: 1000, + showConfirmButton: false, + }); + }); + }); + } +}); + +Template.livechatTriggers.onCreated(function() { + this.subscribe('livechat:trigger'); + this.trigger = new ReactiveVar(null); + this.autorun(() => { + this.trigger.set(LivechatTrigger.findOne()); + }); +}); diff --git a/packages/rocketchat-livechat/client/views/app/livechatManager.html b/packages/rocketchat-livechat/client/views/app/livechatUsers.html similarity index 95% rename from packages/rocketchat-livechat/client/views/app/livechatManager.html rename to packages/rocketchat-livechat/client/views/app/livechatUsers.html index fc90993a0c2a168bcdb928d1eb00b451ace573d6..9bdb3f99dbd31a6495adab4572de979f07942818 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatManager.html +++ b/packages/rocketchat-livechat/client/views/app/livechatUsers.html @@ -1,4 +1,4 @@ -<template name="livechatManager"> +<template name="livechatUsers"> <h2>{{_ "Livechat_managers"}}</h2> <form id="form-manager" class="inline"> <label>{{_ "Add_manager"}}</label> @@ -27,7 +27,7 @@ <td>{{name}}</td> <td>{{username}}</td> <td>{{emailAddress}}</td> - <td><a href="#remove" class="remove-manager"><i class="icon-block"></i></a></td> + <td><a href="#remove" class="remove-manager"><i class="icon-trash"></i></a></td> </tr> {{/each}} </tbody> @@ -61,7 +61,7 @@ <td>{{name}}</td> <td>{{username}}</td> <td>{{emailAddress}}</td> - <td><a href="#remove" class="remove-agent"><i class="icon-block"></i></a></td> + <td><a href="#remove" class="remove-agent"><i class="icon-trash"></i></a></td> </tr> {{/each}} </tbody> diff --git a/packages/rocketchat-livechat/client/views/app/livechatManager.js b/packages/rocketchat-livechat/client/views/app/livechatUsers.js similarity index 94% rename from packages/rocketchat-livechat/client/views/app/livechatManager.js rename to packages/rocketchat-livechat/client/views/app/livechatUsers.js index 173cb633a50cf64cd14ebcc420cbf195345f3b44..eeb2d1dfa783871db0ac7e895ea3ec79d40ff31a 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatManager.js +++ b/packages/rocketchat-livechat/client/views/app/livechatUsers.js @@ -1,12 +1,10 @@ -var AgentUsers; var ManagerUsers; Meteor.startup(function() { - AgentUsers = new Mongo.Collection('agentUsers'); ManagerUsers = new Mongo.Collection('managerUsers'); }); -Template.livechatManager.helpers({ +Template.livechatUsers.helpers({ managers() { return ManagerUsers.find({}, { sort: { name: 1 } }); }, @@ -20,7 +18,7 @@ Template.livechatManager.helpers({ } }); -Template.livechatManager.events({ +Template.livechatUsers.events({ 'click .remove-manager' (e, instance) { e.preventDefault(); @@ -119,7 +117,7 @@ Template.livechatManager.events({ } }); -Template.livechatManager.onCreated(function() { +Template.livechatUsers.onCreated(function() { this.subscribe('livechat:agents'); this.subscribe('livechat:managers'); }); diff --git a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html new file mode 100644 index 0000000000000000000000000000000000000000..77872c89773683fe1f7a6434e5caa91b277e945e --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html @@ -0,0 +1,46 @@ +<template name="visitorInfo"> + <div class="content"> + <div class="user-view"> + + {{#with user}} + <div class="about clearfix"> + <div class="thumb"> + {{> avatar username=username}} + </div> + <div class="info"> + <h3 title="{{username}}"><i class="status-{{status}}"></i> {{username}}</h3> + <p>{{name}}</p> + + <ul> + {{#if utc}}<li><i class="icon-clock"></i>{{userTime}} (UTC {{utc}})</li>{{/if}} + {{#each emails}} <li><i class="icon-mail"></i> {{address}}{{#if verified}} <i class="icon-ok"></i>{{/if}}</li> {{/each}} + {{#each phone}} <li><i class="icon-phone"></i> {{phoneNumber}}</li> {{/each}} + {{#if lastLogin}} <li><i class="icon-calendar"></i> {{_ "Created_at"}}: {{createdAt}}</li> {{/if}} + {{#if lastLogin}} <li><i class="icon-calendar"></i> {{_ "Last_login"}}: {{lastLogin}}</li> {{/if}} + {{#if ip}}<li><i class="icon-laptop"></i><span>{{ip}}</span></li>{{/if}} + {{#if os}}<li><i class="{{osIcon}}"></i><span>{{os}}</span></li>{{/if}} + {{#if browser}}<li><i class="{{browserIcon}}"></i><span>{{browser}}</span></li>{{/if}} + </ul> + </div> + </div> + {{/with}} + <nav> + <!-- <button class="button pvt-msg"><span><i class="icon-forward"></i> {{_ "Forward"}}</span></button> --> + </nav> + + <h4>{{_ "Navigation_History_20_last_pages"}}</h4> + + <div class="visitor-navigation"> + {{#if loadingNavigation}} + {{_ "Loading..."}} + {{else}} + <ul> + {{#each pageVisited}} + <li><a href="{{page.location.href}}" target="_blank" title="{{accessDateTime}}">{{pageTitle}}</a></li> + {{/each}} + </ul> + {{/if}} + </div> + </div> + </div> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..48feb1fdd129a9f164165ee5f68b3523fc9d3df7 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js @@ -0,0 +1,70 @@ +Template.visitorInfo.helpers({ + user() { + var user = Meteor.users.findOne({ "profile.token": Template.instance().visitorToken.get() }); + if (user && user.userAgent) { + var ua = new UAParser(); + ua.setUA(user.userAgent); + + user.os = ua.getOS().name + ' ' + ua.getOS().version; + if (['Mac OS', 'iOS'].indexOf(ua.getOS().name) !== -1) { + user.osIcon = 'icon-apple'; + } else { + user.osIcon = 'icon-' + ua.getOS().name.toLowerCase(); + } + user.browser = ua.getBrowser().name + ' ' + ua.getBrowser().version; + user.browserIcon = 'icon-' + ua.getBrowser().name.toLowerCase(); + } + + return user; + }, + + loadingNavigation() { + return !Template.instance().pageVisited.ready(); + }, + + pageVisited() { + return LivechatPageVisited.find({ token: Template.instance().visitorToken.get() }, { sort: { ts: -1 } }); + }, + + pageTitle() { + return this.page.title || t('Empty_title'); + }, + + accessDateTime() { + return moment(this.ts).format('L LTS'); + }, + + createdAt() { + if (!this.createdAt) { + return ''; + } + return moment(this.createdAt).format('L LTS'); + }, + + lastLogin() { + if (!this.lastLogin) { + return ''; + } + return moment(this.lastLogin).format('L LTS'); + } +}); + +Template.visitorInfo.onCreated(function() { + this.visitorToken = new ReactiveVar(null); + + var currentData = Template.currentData(); + + if (currentData && currentData.rid) { + this.autorun(() => { + var room = ChatRoom.findOne(currentData.rid); + if (room && room.v && room.v.token) { + this.visitorToken.set(room.v.token); + } else { + this.visitorToken.set(); + } + }); + + this.subscribe('livechat:visitorInfo', currentData.rid); + this.pageVisited = this.subscribe('livechat:visitorPageVisited', currentData.rid); + } +}) diff --git a/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.html b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.html new file mode 100644 index 0000000000000000000000000000000000000000..4a4328b7ae87f2f898e936d3886fd66ec7b550a4 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.html @@ -0,0 +1,15 @@ +<template name="livechatTriggerAction"> + <div class="input-line each-action"> + <div class="trigger-option"> + <select name="action" class="trigger-action"> + <option value="send-message">{{_ "Send_a_message"}}</option> + </select> + </div> + <div class="trigger-value"> + <div class="send-message {{hiddenValue 'send-message'}}"> + <input type="text" name="send-message-name" placeholder="{{_ "Name_of_agent"}}" value="{{params.name}}" size="15"> + <input type="text" name="send-message-msg" placeholder="{{_ "Message"}}" value="{{params.msg}}"> + </div> + </div> + </div> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.js b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.js new file mode 100644 index 0000000000000000000000000000000000000000..7ef854e593fe17fd1d77d5fc04537b2b5654284a --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.js @@ -0,0 +1,23 @@ +Template.livechatTriggerAction.helpers({ + hiddenValue (current) { + if (this.name === undefined && Template.instance().firstAction) { + Template.instance().firstAction = false; + return ''; + } else { + if (this.name !== current) { + return 'hidden'; + } + } + } +}); + +Template.livechatTriggerAction.events({ + 'change .trigger-action' (e, instance) { + instance.$('.trigger-action-value ').addClass('hidden'); + instance.$('.' + e.currentTarget.value).removeClass('hidden'); + } +}); + +Template.livechatTriggerAction.onCreated(function() { + this.firstAction = true; +}); diff --git a/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.html b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.html new file mode 100644 index 0000000000000000000000000000000000000000..3e61db95a66c5b0dec87ad8cd25f49705a8ac4d4 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.html @@ -0,0 +1,18 @@ +<template name="livechatTriggerCondition"> + <div class="input-line each-condition"> + <div class="trigger-option"> + <select name="condition" class="trigger-condition"> + <option value="page-url" selected="{{conditionSelected 'page-url'}}">{{_ "Visitor_page_URL"}}</option> + <option value="time-on-site" selected="{{conditionSelected 'time-on-site'}}">{{_ "Visitor_time_on_site"}}</option> + </select> + </div> + <div class="trigger-value"> + <div class="page-url trigger-condition-value {{hiddenValue 'page-url'}}"> + <input type="text" name="page-url-value" class="page-url-value" placeholder="{{_ "Enter_a_regex"}}" value="{{valueFor 'page-url'}}"> + </div> + <div class="time-on-site trigger-condition-value {{hiddenValue 'time-on-site'}}"> + <input type="number" name="time-on-site-value" class="time-on-site-value" placeholder="{{_ "Time_in_seconds"}}" value="{{valueFor 'time-on-site'}}"> + </div> + </div> + </div> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.js b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.js new file mode 100644 index 0000000000000000000000000000000000000000..a99fa0213e104280d543c906dad247297b01dd56 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.js @@ -0,0 +1,33 @@ +Template.livechatTriggerCondition.helpers({ + hiddenValue (current) { + if (this.name === undefined && Template.instance().firstCondition) { + Template.instance().firstCondition = false; + return ''; + } else { + if (this.name !== current) { + return 'hidden'; + } + } + }, + conditionSelected (current) { + if (this.name === current) { + return 'selected'; + } + }, + valueFor (condition) { + if (this.name === condition) { + return this.value; + } + } +}); + +Template.livechatTriggerCondition.events({ + 'change .trigger-condition' (e, instance) { + instance.$('.trigger-condition-value ').addClass('hidden'); + instance.$('.' + e.currentTarget.value).removeClass('hidden'); + } +}); + +Template.livechatTriggerCondition.onCreated(function() { + this.firstCondition = true; +}) diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index ae76e6746d9fd67fb5d2e9b9bc5701d572004270..15d3ed86810d5ea9900b2019a5a1e405bcaf0040 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -6,14 +6,14 @@ </header> <div class="content"> <div class="wrapper"> - <ul> + <ul class="flex-list"> <li> - <a href="#link" class="admin-link">{{_ "Dashboard"}}</a> - <a href="#link" class="admin-link">{{_ "User_management"}}</a> - <a href="{{pathFor 'livechat-departments'}}" class="admin-link">{{_ "Departments"}}</a> - <a href="#link" class="admin-link">{{_ "Theme"}}</a> - <a href="#link" class="admin-link">{{_ "Integrations"}}</a> - <a href="#link" class="admin-link">{{_ "Live_sessions"}}</a> + <!-- <a href="{{pathFor 'livechat-dashboard'}}" class="{{active 'livechat-dashboard'}}">{{_ "Dashboard"}}</a> --> + <a href="{{pathFor 'livechat-users'}}" class="{{active 'livechat-users'}}">{{_ "User_management"}}</a> + <a href="{{pathFor 'livechat-departments'}}" class="{{active 'livechat-departments' 'livechat-department-edit'}}">{{_ "Departments"}}</a> + <a href="{{pathFor 'livechat-triggers'}}" class="{{active 'livechat-triggers'}}">{{_ "Triggers"}}</a> + <a href="{{pathFor 'livechat-installation'}}" class="{{active 'livechat-installation'}}">{{_ "Installation"}}</a> + <a href="{{pathFor 'livechat-appearance'}}" class="{{active 'livechat-appearance'}}">{{_ "Appearance"}}</a> </li> </ul> </div> diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js index 2fa2ed15adfadd4849720b5c52705b8b69361848..f7a8f2f0accfa20b5f6c2ac43157e25744ef432b 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js @@ -1,3 +1,12 @@ +Template.livechatFlex.helpers({ + active (...routes) { + FlowRouter.watchPathChange(); + if (routes.indexOf(FlowRouter.current().route.name) !== -1) { + return 'active'; + } + } +}); + Template.livechatFlex.events({ 'mouseenter header' () { SideNav.overArrow() @@ -10,4 +19,4 @@ Template.livechatFlex.events({ 'click header' () { SideNav.closeFlex() } -}) +}); diff --git a/packages/rocketchat-livechat/config.js b/packages/rocketchat-livechat/config.js index 9ae62a8ecb133a1be17de7141630519ed4812c1e..424768e39a961145a991b1392d876437449bc6bd 100644 --- a/packages/rocketchat-livechat/config.js +++ b/packages/rocketchat-livechat/config.js @@ -2,5 +2,6 @@ Meteor.startup(function() { RocketChat.settings.addGroup('Livechat'); RocketChat.settings.add('Livechat_title' , 'Rocket.Chat', { type: 'string', group: 'Livechat', public: true }); RocketChat.settings.add('Livechat_title_color' , '#C1272D', { type: 'string', group: 'Livechat', public: true }); - RocketChat.settings.add('Livechat_enabled' , true, { type: 'boolean', group: 'Livechat', public: true }); + RocketChat.settings.add('Livechat_enabled' , false, { type: 'boolean', group: 'Livechat', public: true }); + RocketChat.settings.add('Livechat_registration_form' , true, { type: 'boolean', group: 'Livechat', public: true, i18nLabel: 'Show_preregistration_form' }); }); diff --git a/packages/rocketchat-livechat/i18n/ar.i18n.json b/packages/rocketchat-livechat/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..5d22fd60b4c8e95d9b5dc6c5ad4abaa43fd478ff 100644 --- a/packages/rocketchat-livechat/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/i18n/ar.i18n.json @@ -1 +1,17 @@ -{ } \ No newline at end of file +{ + "Add" : "إضاÙØ©", + "Back" : "العودة", + "Closed" : "مغلق", + "Copy_to_clipboard" : "نسخ إلى الØاÙظة", + "Description" : "الوصÙ", + "Enable" : "تمكين", + "Enter_a_username" : "أدخل اسم المستخدم", + "Livechat_enabled" : "مكنت LIVECHAT", + "Livechat_title" : "عنوان الدردشة الØية", + "Livechat_title_color" : "لون خلÙية عنوان الدردشة الØية", + "Please_fill_a_username" : "يرجى ملء اسم المستخدم", + "Saved" : "تم الØÙظ", + "Send_a_message" : "إرسال رسالة", + "Theme" : "سمات", + "Time_in_seconds" : "الوقت بالثواني" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/cs.i18n.json b/packages/rocketchat-livechat/i18n/cs.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6ad288846f91d3de48ed4fcb65fa96b547442e4c 100644 --- a/packages/rocketchat-livechat/i18n/cs.i18n.json +++ b/packages/rocketchat-livechat/i18n/cs.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat povoleno" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/de.i18n.json b/packages/rocketchat-livechat/i18n/de.i18n.json index 30411a053d4faec2a9b25e7d934391bdbf21d76c..cf1cb71ca41362ce6f12cd69b717cff91dcfefdc 100644 --- a/packages/rocketchat-livechat/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/i18n/de.i18n.json @@ -1,4 +1,58 @@ { - "Livechat_title" : "Livechat Titel", - "Livechat_title_color" : "Livechat Titel Hintergrundfarbe" + "Add" : "Hinzufügen", + "Add_agent" : "Agent hinzufügen", + "Add_manager" : "Manager hinzufügen", + "Agent_added" : "Der Agent wurde hinzugefügt.", + "Agent_removed" : "Der Agent wurde gelöscht.", + "Available_agents" : "Verfügbare Agenten", + "Back" : "Zurück", + "Closed" : "Geschlossen", + "Copy_to_clipboard" : "In die Zwischenablage kopieren", + "Count" : "Zähler", + "Dashboard" : "Dashboard", + "Department_not_found" : "Abteilung konnte nicht gefunden werden.", + "Department_removed" : "Die Abteilung wurde gelöscht.", + "Departments" : "Abteilungen", + "Description" : "Beschreibung", + "Edit_Department" : "Abteilung bearbeiten", + "Empty_title" : "Es wurde kein Titel angegeben.", + "Enable" : "Aktivieren", + "Enabled" : "Aktiviert", + "Enter_a_regex" : "Geben Sie einen regex ein.", + "Enter_a_username" : "Geben Sie einen Benutzernamen ein", + "Live_sessions" : "Live-Sitzungen", + "Livechat_agents" : "LiveChat-Agent", + "Livechat_Dashboard" : "LiveChat-Dashboard", + "Livechat_enabled" : "LiveChat aktiviert", + "Livechat_Manager" : "LiveChat-Manager", + "Livechat_managers" : "LiveChat-Manager", + "Livechat_title" : "LiveChat-Titel", + "Livechat_title_color" : "Hintergrundfarbe des LiveChat-Titels", + "Livechat_Users" : "LiveChat-Benutzer", + "Manager_added" : "Der Manager wurde hinzugefügt.\n", + "Manager_removed" : "Der Manager wurde gelöscht.", + "Name_of_agent" : "Name des Agents", + "Navigation_History_20_last_pages" : "Navigationsverlauf (die letzten 20 Seiten)", + "New_Department" : "Neue Abteilung", + "Num_Agents" : "# Agents", + "Opened" : "Geöffnet", + "Order" : "Auftrag", + "Please_fill_a_name" : "Bitte geben Sie einen Namen ein.", + "Please_fill_a_username" : "Bitte geben Sie einen Benutzernamen ein.", + "Please_select_enabled_yes_or_no" : "Bitte wählen Sie eine Option für \"aktiviert\".", + "Saved" : "Gespeichert", + "Selected_agents" : "Ausgewählte Agenten", + "Send_a_message" : "Eine Nachricht schicken", + "Show_preregistration_form" : "Vorregistrierungsformular zeigen", + "Theme" : "Theme", + "There_are_no_agents_added_to_this_department_yet" : "Es wurden bisher keine Agenten zu dieser Abteilung hinzugefügt.", + "Time_in_seconds" : "Zeit in Sekunden", + "Title_bar_color" : "Farbe der Titelleiste", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site" : "Um den Rocket.Chat-LiveChat auf Ihrer Webseite zu installieren, kopieren und fügen Sie den Code über den letzten <strong></body></strong>-Tag Ihrer Seite ein.", + "Trigger_removed" : "Auslöser entfernt", + "Triggers" : "Auslöser", + "User_management" : "Benutzerverwaltung", + "Username_not_found" : "Der Benutzername konnte nicht gefunden werden.", + "Visitor_page_URL" : "URL der Besucherseite", + "Visitor_time_on_site" : "Besucherzeit auf der Seite" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/el.i18n.json b/packages/rocketchat-livechat/i18n/el.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..53f32128d5635f649de4dabf01ab5f239e3c6a0e 100644 --- a/packages/rocketchat-livechat/i18n/el.i18n.json +++ b/packages/rocketchat-livechat/i18n/el.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat ενεÏγοποιημÎνη" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index a6db675dc4f139b15ae2d59d3d35e1355d3c41a1..58602f022d7fd485d15484f974d61b4ddada3d9c 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -4,33 +4,55 @@ "Add_manager" : "Add manager", "Agent_added" : "Agent added", "Agent_removed" : "Agent removed", + "Available_agents" : "Available agents", "Back" : "Back", + "Closed" : "Closed", + "Copy_to_clipboard" : "Copy to clipboard", + "Count" : "Count", "Dashboard" : "Dashboard", "Department_not_found" : "Department not found", "Department_removed" : "Department removed", "Departments" : "Departments", "Description" : "Description", "Edit_Department" : "Edit Department", + "Empty_title" : "Empty title", "Enable" : "Enable", "Enabled" : "Enabled", + "Enter_a_regex" : "Enter a regex", "Enter_a_username" : "Enter a username", "Live_sessions" : "Live sessions", "Livechat_agents" : "Livechat agents", + "Livechat_Dashboard" : "Livechat Dashboard", "Livechat_enabled" : "Livechat enabled", "Livechat_Manager" : "Livechat Manager", "Livechat_managers" : "Livechat managers", "Livechat_title" : "Livechat Title", "Livechat_title_color" : "Livechat Title Background Color", + "Livechat_Users" : "Livechat Users", "Manager_added" : "Manager added", "Manager_removed" : "Manager removed", + "Name_of_agent" : "Name of agent", + "Navigation_History_20_last_pages" : "Navigation History (20 last pages)", "New_Department" : "New Department", "Num_Agents" : "# Agents", + "Opened" : "Opened", + "Order" : "Order", "Please_fill_a_name" : "Please fill a name", "Please_fill_a_username" : "Please fill a username", "Please_select_enabled_yes_or_no" : "Please select an option for Enabled", "Saved" : "Saved", + "Selected_agents" : "Selected agents", + "Send_a_message" : "Send a message", + "Show_preregistration_form" : "Show pre-registration form", "Theme" : "Theme", "There_are_no_agents_added_to_this_department_yet" : "There are no agents added to this department yet.", + "Time_in_seconds" : "Time in seconds", + "Title_bar_color" : "Title bar color", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site" : "To install Rocket.Chat Livechat in your website, copy & paste this code above the last <strong></body></strong> tag on your site.", + "Trigger_removed" : "Trigger removed", + "Triggers" : "Triggers", "User_management" : "User Management", - "Username_not_found" : "Username not found" + "Username_not_found" : "Username not found", + "Visitor_page_URL" : "Visitor page URL", + "Visitor_time_on_site" : "Visitor time on site" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/es.i18n.json b/packages/rocketchat-livechat/i18n/es.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..b777b5b19e9af7733e166bfd8aa325ae4fea3f2a 100644 --- a/packages/rocketchat-livechat/i18n/es.i18n.json +++ b/packages/rocketchat-livechat/i18n/es.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat habilitado" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/fa.i18n.json b/packages/rocketchat-livechat/i18n/fa.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..f69ec3552e0a1fc8ca2be1a4ded9405fe8f36cb8 100644 --- a/packages/rocketchat-livechat/i18n/fa.i18n.json +++ b/packages/rocketchat-livechat/i18n/fa.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "livechat در Ùعال" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/fi.i18n.json b/packages/rocketchat-livechat/i18n/fi.i18n.json index c3913e2b43c34656dad0c713ef29aacbfd73aeaf..deac2b104c7a52dc4c2b5a7940879440fe9e207a 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -4,32 +4,55 @@ "Add_manager" : "Lisää manageri", "Agent_added" : "Agentti lisätty", "Agent_removed" : "Agentti poistettu", + "Available_agents" : "Vapaat agentit", "Back" : "Takaisin", - "Dashboard" : "Kojelauta", - "Department_not_found" : "Osasto ei löytynyt", + "Closed" : "Suljettu", + "Copy_to_clipboard" : "Kopioi leikepöydälle", + "Count" : "Lukumäärä", + "Dashboard" : "Ohjauspaneeli", + "Department_not_found" : "Osastoa ei löytynyt", "Department_removed" : "Osasto poistettu", "Departments" : "Osastot", "Description" : "Kuvaus", "Edit_Department" : "Muokkaa osastoa", + "Empty_title" : "Tyhjä otsikko", "Enable" : "Ota käyttöön", "Enabled" : "Käytössä", + "Enter_a_regex" : "Syötä säännöllinen lause (regex)", "Enter_a_username" : "Syötä käyttäjätunnus", "Live_sessions" : "Live-istunnot", "Livechat_agents" : "Livechat agentit", + "Livechat_Dashboard" : "Livechat ohjauspaneeli", + "Livechat_enabled" : "LiveChat käytössä", "Livechat_Manager" : "Livechat manageri", "Livechat_managers" : "Livechat managerit", "Livechat_title" : "Livechat otsikko", "Livechat_title_color" : "Livechat otsikon taustaväri", + "Livechat_Users" : "Livechat käyttäjät", "Manager_added" : "Manageri lisätty", "Manager_removed" : "Manageri poistettu", + "Name_of_agent" : "Agentin nimi", + "Navigation_History_20_last_pages" : "Navigointihistoria (viimeiset 20 sivua)", "New_Department" : "Uusi osasto", "Num_Agents" : "# Agenttia", + "Opened" : "Avattu", + "Order" : "Järjestys", "Please_fill_a_name" : "Täytä nimi", "Please_fill_a_username" : "Täytä käyttäjätunnus", "Please_select_enabled_yes_or_no" : "Valitse vaihtoehto Käytössä", "Saved" : "Tallennettu", - "Theme" : "Teema", + "Selected_agents" : "Valitut agentit", + "Send_a_message" : "Lähetä viesti", + "Show_preregistration_form" : "Näytä esirekisteröintilomake", + "Theme" : "Ulkoasu", "There_are_no_agents_added_to_this_department_yet" : "Yhtään agenttia ei ole vielä lisätty tähän osastoon.", - "User_management" : "Käyttäjien hallinta", - "Username_not_found" : "Käyttäjätunnusta ei löydy" + "Time_in_seconds" : "Aika sekunneissa", + "Title_bar_color" : "Otsikkorivin väri", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site" : "Asentaaksesi Rocket.Chat Livechatin sivustollesi, kopioi ja liitä seuraava sivusi <strong></body></strong> osion yläpuolelle.", + "Trigger_removed" : "Laukaisija poistettu", + "Triggers" : "Laukaisijat", + "User_management" : "Käyttäjähallinta", + "Username_not_found" : "Käyttäjätunnusta ei löydy", + "Visitor_page_URL" : "Vierailijan sivun URL", + "Visitor_time_on_site" : "Vierailijan aika sivustolla" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/fr.i18n.json b/packages/rocketchat-livechat/i18n/fr.i18n.json index 27798a2d83489847a49ce6d497078374b780013a..5a5f097e8ba8bd1a1397cd2d5c49514f6e96a0c0 100644 --- a/packages/rocketchat-livechat/i18n/fr.i18n.json +++ b/packages/rocketchat-livechat/i18n/fr.i18n.json @@ -1,4 +1,25 @@ { - "Livechat_title" : "Titre du chat en direct", - "Livechat_title_color" : "Couleur de fond du titre du chat en direct" + "Add" : "Ajouter", + "Available_agents" : "Agents disponibles", + "Closed" : "Fermé", + "Copy_to_clipboard" : "Copier dans le presse-papier", + "Count" : "Nombre", + "Enter_a_regex" : "Entrez une expression rationnelle", + "Livechat_Dashboard" : "Dashboard du chat", + "Livechat_enabled" : "Chat en direct activé", + "Livechat_title" : "Titre du tchat en direct", + "Livechat_title_color" : "Couleur de fond du titre du tchat en direct", + "Livechat_Users" : "Utilisateurs du chat", + "Name_of_agent" : "Nom de l'assistant de chat", + "Opened" : "Ouvert", + "Order" : "Ordre", + "Selected_agents" : "Agents sélectionnés", + "Send_a_message" : "Envoyez un message", + "Show_preregistration_form" : "Afficher le formulaire de pré-inscription", + "Time_in_seconds" : "Temps en secondes", + "Title_bar_color" : "Couleur de la barre de titre", + "Trigger_removed" : "Déclencheur retiré", + "Triggers" : "Déclencheurs", + "Visitor_page_URL" : "Page d'accueil visiteur (URL)", + "Visitor_time_on_site" : "Temps des visiteurs sur le site" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/he.i18n.json b/packages/rocketchat-livechat/i18n/he.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..3efd17b9562c66f30c3764fdd72578ea88af811a 100644 --- a/packages/rocketchat-livechat/i18n/he.i18n.json +++ b/packages/rocketchat-livechat/i18n/he.i18n.json @@ -1 +1,25 @@ -{ } \ No newline at end of file +{ + "Add" : "הוספה", + "Add_agent" : "הוספת סוכן", + "Add_manager" : "הוספת ×ž× ×”×œ", + "Agent_added" : "× ×•×¡×£ סוכן", + "Agent_removed" : "הוסר סוכן", + "Back" : "חזרה", + "Copy_to_clipboard" : "העתקה ללוח הגזירי×", + "Department_not_found" : "המחלקה ×œ× × ×ž×¦××”", + "Description" : "תי×ור", + "Empty_title" : "כותרת ריקה", + "Enter_a_regex" : "× × ×œ×”×–×™×Ÿ ביטוי רגולרי", + "Enter_a_username" : "× × ×œ×”×–×™×Ÿ ×©× ×ž×©×ª×ž×©", + "Livechat_enabled" : "Livechat enabled", + "Manager_added" : "× ×•×¡×£ ×ž× ×”×œ", + "Manager_removed" : "הוסר ×ž× ×”×œ", + "Name_of_agent" : "×©× ×”×¡×•×›×Ÿ", + "Please_fill_a_name" : "× × ×œ×ž×œ× ×©×", + "Please_fill_a_username" : "× × ×œ×ž×œ× ×©× ×ž×©×ª×ž×©", + "Saved" : "× ×©×ž×¨", + "Send_a_message" : "שליחת הודעה", + "Time_in_seconds" : "זמן ×‘×©× ×™×•×ª", + "User_management" : "× ×™×”×•×œ משתמשי×", + "Username_not_found" : "×©× ×”×ž×©×ª×ž×© ×œ× × ×ž×¦×" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/hr.i18n.json b/packages/rocketchat-livechat/i18n/hr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..99a14df1af08c9afbf3686d2bd910ef685abcb25 100644 --- a/packages/rocketchat-livechat/i18n/hr.i18n.json +++ b/packages/rocketchat-livechat/i18n/hr.i18n.json @@ -1 +1,16 @@ -{ } \ No newline at end of file +{ + "Add" : "Dodaj", + "Back" : "Natrag", + "Closed" : "Zatvoreno", + "Copy_to_clipboard" : "Kopiraj u meÄ‘uspremnik", + "Description" : "Opis", + "Enabled" : "Omogućeno", + "Enter_a_username" : "Unesite korisniÄko ime", + "Livechat_enabled" : "LiveChat omogućeno", + "Please_fill_a_name" : "Molimo ispunite ime", + "Saved" : "Spremljeno", + "Send_a_message" : "PoÅ¡alji Poruku", + "Time_in_seconds" : "Vrijeme u sekundama", + "Trigger_removed" : "OkidaÄ uklonjen", + "Triggers" : "OkidaÄi" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/hu.i18n.json b/packages/rocketchat-livechat/i18n/hu.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..049e289a6b8c02d66a30eb5c977211ebb0a31560 100644 --- a/packages/rocketchat-livechat/i18n/hu.i18n.json +++ b/packages/rocketchat-livechat/i18n/hu.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "LiveChat engedélyezve" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/it.i18n.json b/packages/rocketchat-livechat/i18n/it.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..af31f8b349913faca2c8e6f35b8c36c7677e7dcb 100644 --- a/packages/rocketchat-livechat/i18n/it.i18n.json +++ b/packages/rocketchat-livechat/i18n/it.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat abilitato" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ko.i18n.json b/packages/rocketchat-livechat/i18n/ko.i18n.json index 6a58a7a6ee1968166b84658a2fc044f5343bc085..27f11f7b38525f1de2c2284dae5a8d04fc8c4f7e 100644 --- a/packages/rocketchat-livechat/i18n/ko.i18n.json +++ b/packages/rocketchat-livechat/i18n/ko.i18n.json @@ -1,4 +1,8 @@ { + "Add" : "추가", + "Description" : "설명", + "Enter_a_username" : "ì‚¬ìš©ìž ì´ë¦„ ìž…ë ¥", "Livechat_title" : "Livechat ì œëª©", - "Livechat_title_color" : "Livechat ì œëª© 배경색" + "Livechat_title_color" : "Livechat ì œëª© 배경색", + "Saved" : "ì €ìž¥ë¨" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/lo.i18n.json b/packages/rocketchat-livechat/i18n/lo.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..a9acf8c81be41e8fedc7879cd1fe4a4fc03514ac 100644 --- a/packages/rocketchat-livechat/i18n/lo.i18n.json +++ b/packages/rocketchat-livechat/i18n/lo.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat ເປີດ​ໃຫ້​ໃຊ້​ງານ" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/nl.i18n.json b/packages/rocketchat-livechat/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..f185cf0c6c352fef230c4620c12a289adec4dd2a 100644 --- a/packages/rocketchat-livechat/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/i18n/nl.i18n.json @@ -1 +1,47 @@ -{ } \ No newline at end of file +{ + "Add" : "Toevoegen", + "Add_manager" : "Manager toevoegen", + "Back" : "Terug", + "Closed" : "Gesloten", + "Copy_to_clipboard" : "Kopieer naar klembord", + "Count" : "Aantal", + "Dashboard" : "Dashboard", + "Department_not_found" : "Afdeling niet gevonden", + "Department_removed" : "Afdeling verwijderd", + "Departments" : "Afdelingen", + "Description" : "Beschrijving", + "Edit_Department" : "Afdeling bewerken", + "Enable" : "Inschakelen", + "Enabled" : "Ingeschakeld", + "Enter_a_regex" : "Voer een reguliere expressie in", + "Enter_a_username" : "Voer een gebruikersnaam in", + "Live_sessions" : "Live sessies", + "Livechat_Dashboard" : "Livechat Dashboard", + "Livechat_enabled" : "Livechat beschikbaar", + "Livechat_Manager" : "Livechat Manager", + "Livechat_managers" : "Livechat managers", + "Livechat_title" : "Livechat Titel", + "Livechat_title_color" : "Livechat Titel Achtergrond Kleur", + "Livechat_Users" : "Livechat Gebruikers", + "Manager_added" : "Manager toegevoegd", + "Manager_removed" : "Manager verwijderd", + "Name_of_agent" : "Naam agent", + "New_Department" : "Nieuwe afdeling", + "Opened" : "Geopend", + "Please_fill_a_name" : "Vul een naam in", + "Please_fill_a_username" : "Vul een gebruikersnaam in", + "Please_select_enabled_yes_or_no" : "Selecteer een optie voor Ingeschakeld", + "Saved" : "Opgeslagen", + "Send_a_message" : "Stuur een bericht", + "Theme" : "Thema", + "There_are_no_agents_added_to_this_department_yet" : "Er zijn nog geen agenten aan deze afdeling toegevoegd.", + "Time_in_seconds" : "Tijd in seconden", + "Title_bar_color" : "Titelbalk kleur", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site" : "Om Rocket.Chat Livechat te installeren op uw website, kopiëert u de volgende code boven de laatste <strong></body></strong> html tag op uw web pagina's.", + "Trigger_removed" : "Trigger verwijderd", + "Triggers" : "Triggers", + "User_management" : "Gebruikersbeheer", + "Username_not_found" : "Gebruikersnaam niet gevonden", + "Visitor_page_URL" : "Bezoeker URL", + "Visitor_time_on_site" : "Bezoeker tijd aanwezig op de site" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/pl.i18n.json b/packages/rocketchat-livechat/i18n/pl.i18n.json index 743f3732748d19d6e6cb7694ccacef5014791ce4..9a1059cc5e70eaf3e9c52edd15dd3af7c99ddfe9 100644 --- a/packages/rocketchat-livechat/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/i18n/pl.i18n.json @@ -1,4 +1,13 @@ { + "Add" : "Dodaj", + "Description" : "Opis", + "Enable" : "WÅ‚Ä…cz", + "Enabled" : "WÅ‚Ä…czone", + "Enter_a_username" : "Nazwa użytkownika", "Livechat_title" : "TytuÅ‚ Livechatu", - "Livechat_title_color" : "Kolor tÅ‚a nagłówka Livechat" + "Livechat_title_color" : "Kolor tÅ‚a nagłówka Livechat", + "Please_fill_a_username" : "ProszÄ™ wypeÅ‚nić nazwÄ™ użytkownika", + "Saved" : "Zapisano", + "Send_a_message" : "WyÅ›lij wiadomość", + "Theme" : "Motyw" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ro.i18n.json b/packages/rocketchat-livechat/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..83a8cd26ccacf284836f802b7c3c5c1908ca162f --- /dev/null +++ b/packages/rocketchat-livechat/i18n/ro.i18n.json @@ -0,0 +1,58 @@ +{ + "Add" : "Adăugă", + "Add_agent" : "Adaugă agent", + "Add_manager" : "Adauga manager", + "Agent_added" : "Agent adăugat", + "Agent_removed" : "Agent eliminat", + "Available_agents" : "AgenÈ›i disponibili", + "Back" : "ÃŽnapoi", + "Closed" : "ÃŽnchis", + "Copy_to_clipboard" : "CopiaÈ›i în clipboard", + "Count" : "Număr", + "Dashboard" : "Tablou de comandă", + "Department_not_found" : "Departamentul nu a fost găsit", + "Department_removed" : "Departament eliminat", + "Departments" : "Departamente", + "Description" : "Descriere", + "Edit_Department" : "Editează departament", + "Empty_title" : "Titlu gol", + "Enable" : "Activează", + "Enabled" : "Activat", + "Enter_a_regex" : "IntroduceÈ›i un regex", + "Enter_a_username" : "IntroduceÈ›i un nume de utilizator", + "Live_sessions" : "Sesiuni live", + "Livechat_agents" : "AgenÈ›i Livechat", + "Livechat_Dashboard" : "Tabloul de bord Livechat", + "Livechat_enabled" : "Livechat activat", + "Livechat_Manager" : "Manager Livechat", + "Livechat_managers" : "Manageri Livechat", + "Livechat_title" : "Titlu Livechat", + "Livechat_title_color" : "Culoare de fundal titlu Livechat ", + "Livechat_Users" : "Utilizatorii Livechat", + "Manager_added" : "Manager adăugat", + "Manager_removed" : "Manager eliminat", + "Name_of_agent" : "Numele agentului", + "Navigation_History_20_last_pages" : "Istoria de navigare (ultimele 20 de pagini)", + "New_Department" : "Departament nou", + "Num_Agents" : "# AgenÈ›i", + "Opened" : "Deschis", + "Order" : "Sortare", + "Please_fill_a_name" : "Vă rugăm să completaÈ›i un nume", + "Please_fill_a_username" : "Vă rugăm să completaÈ›i un nume de utilizator", + "Please_select_enabled_yes_or_no" : "Vă rugăm să selectaÈ›i o opÈ›iune pentru Enabled", + "Saved" : "Salvat", + "Selected_agents" : "AgenÈ›i selectaÈ›i", + "Send_a_message" : "Trimite un mesaj", + "Show_preregistration_form" : "Arată formularul de pre-înregistrare", + "Theme" : "Temă", + "There_are_no_agents_added_to_this_department_yet" : "ÃŽncă există agenÈ›i adăugaÈ›i la acest departament.", + "Time_in_seconds" : "Timpul în secunde", + "Title_bar_color" : "Culoare bară de titlu", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site" : "Pentru a instala Rocket.Chat Livechat în site-ul dvs., copiaÈ›i & lipiÈ›i acest cod chiar înaintea ultimului tag <strong></body></strong> din pagină.", + "Trigger_removed" : "DeclanÈ™ator eliminat", + "Triggers" : "DeclanÈ™atori", + "User_management" : "Managementul utilizatorilor", + "Username_not_found" : "Numele de utilizator nu a fost găsit", + "Visitor_page_URL" : "Pagina URL a vizitatorului", + "Visitor_time_on_site" : "Timpul vizitatorului pe site" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ru.i18n.json b/packages/rocketchat-livechat/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..ea345d96bfec4d43cec8dc71f039b245e23e0410 100644 --- a/packages/rocketchat-livechat/i18n/ru.i18n.json +++ b/packages/rocketchat-livechat/i18n/ru.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Включен Livechat", + "Livechat_title" : "Ðазвание чата" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/sq.i18n.json b/packages/rocketchat-livechat/i18n/sq.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..4252cafab36f4526d3616adbdf4ef32ed5cdf3ab 100644 --- a/packages/rocketchat-livechat/i18n/sq.i18n.json +++ b/packages/rocketchat-livechat/i18n/sq.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "LiveChat aktivizuar" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/sr.i18n.json b/packages/rocketchat-livechat/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/sv.i18n.json b/packages/rocketchat-livechat/i18n/sv.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..2a24e6702158107a8808cae2b4d66696b647880d 100644 --- a/packages/rocketchat-livechat/i18n/sv.i18n.json +++ b/packages/rocketchat-livechat/i18n/sv.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat aktiverat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/tr.i18n.json b/packages/rocketchat-livechat/i18n/tr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..008b9ca305b2e61b3e8961357d7d6a53b1dcdc87 100644 --- a/packages/rocketchat-livechat/i18n/tr.i18n.json +++ b/packages/rocketchat-livechat/i18n/tr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Canlı etkin" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ug.i18n.json b/packages/rocketchat-livechat/i18n/ug.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..7e724987836b6afe91b6686a6830452987e682c6 100644 --- a/packages/rocketchat-livechat/i18n/ug.i18n.json +++ b/packages/rocketchat-livechat/i18n/ug.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Livechat Enabled" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/uk.i18n.json b/packages/rocketchat-livechat/i18n/uk.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..13a9ea9ca687d64fdf0128c1f5bd6d8cedcac80d 100644 --- a/packages/rocketchat-livechat/i18n/uk.i18n.json +++ b/packages/rocketchat-livechat/i18n/uk.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "Включений Livechat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/zh.i18n.json b/packages/rocketchat-livechat/i18n/zh.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..c83357d2db2f5bfc5cc6dc35a4e9624d0aaabaec 100644 --- a/packages/rocketchat-livechat/i18n/zh.i18n.json +++ b/packages/rocketchat-livechat/i18n/zh.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "在线咨询å¯ç”¨" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/livechat.js b/packages/rocketchat-livechat/livechat.js index b33e6eb59094273cca8dd1dd573c9d9d55cab518..1e854bd8f64b2b74a243b988a789f12446ea985f 100644 --- a/packages/rocketchat-livechat/livechat.js +++ b/packages/rocketchat-livechat/livechat.js @@ -2,7 +2,7 @@ WebApp = Package.webapp.WebApp; Autoupdate = Package.autoupdate.Autoupdate; WebApp.connectHandlers.use('/livechat/', (req, res, next) => { - res.setHeader('content-type', 'html'); + res.setHeader('content-type', 'text/html; charset=utf-8'); head = Assets.getText('public/head.html'); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index dc6d77ad8f184f666f5a2d4b3d4a0fb1b37aedeb..a43697f53401f55a0dc46d584a5511487b86c5b8 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -20,14 +20,15 @@ Package.onUse(function(api) { api.use(['webapp', 'autoupdate'], 'server'); api.use('ecmascript'); - api.use('alanning:roles@1.2.12'); api.use('rocketchat:lib'); + api.use('rocketchat:authorization'); + api.use('rocketchat:ui'); api.use('kadira:flow-router', 'client'); api.use('templating', 'client'); api.use('mongo'); + api.use('less@2.5.1'); api.addFiles('livechat.js', 'server'); - api.addFiles('server/methods.js', 'server'); api.addFiles('server/startup.js', 'server'); api.addFiles('permissions.js', 'server'); @@ -36,39 +37,80 @@ Package.onUse(function(api) { api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); + // add stylesheets to theme compiler + api.addAssets('client/stylesheets/livechat.less', 'server'); + api.addFiles('client/stylesheets/load.js', 'server'); + + // collections + api.addFiles('client/collections/AgentUsers.js', 'client'); + api.addFiles('client/collections/LivechatDepartment.js', 'client'); + api.addFiles('client/collections/LivechatDepartmentAgents.js', 'client'); + api.addFiles('client/collections/LivechatPageVisited.js', 'client'); + api.addFiles('client/collections/LivechatTrigger.js', 'client'); + // client views - api.addFiles('client/views/app/livechatManager.html', 'client'); - api.addFiles('client/views/app/livechatManager.js', 'client'); - api.addFiles('client/views/app/livechatDepartments.html', 'client'); - api.addFiles('client/views/app/livechatDepartments.js', 'client'); + api.addFiles('client/views/app/livechatAppearance.html', 'client'); + api.addFiles('client/views/app/livechatAppearance.js', 'client'); + api.addFiles('client/views/app/livechatDashboard.html', 'client'); api.addFiles('client/views/app/livechatDepartmentForm.html', 'client'); api.addFiles('client/views/app/livechatDepartmentForm.js', 'client'); + api.addFiles('client/views/app/livechatDepartments.html', 'client'); + api.addFiles('client/views/app/livechatDepartments.js', 'client'); + api.addFiles('client/views/app/livechatInstallation.html', 'client'); + api.addFiles('client/views/app/livechatInstallation.js', 'client'); + api.addFiles('client/views/app/livechatTriggers.html', 'client'); + api.addFiles('client/views/app/livechatTriggers.js', 'client'); + api.addFiles('client/views/app/livechatUsers.html', 'client'); + api.addFiles('client/views/app/livechatUsers.js', 'client'); + + api.addFiles('client/views/app/tabbar/visitorInfo.html', 'client'); + api.addFiles('client/views/app/tabbar/visitorInfo.js', 'client'); + api.addFiles('client/views/sideNav/livechat.html', 'client'); api.addFiles('client/views/sideNav/livechat.js', 'client'); api.addFiles('client/views/sideNav/livechatFlex.html', 'client'); api.addFiles('client/views/sideNav/livechatFlex.js', 'client'); + api.addFiles('client/views/app/triggers/livechatTriggerAction.html', 'client'); + api.addFiles('client/views/app/triggers/livechatTriggerAction.js', 'client'); + api.addFiles('client/views/app/triggers/livechatTriggerCondition.html', 'client'); + api.addFiles('client/views/app/triggers/livechatTriggerCondition.js', 'client'); + // methods api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); + api.addFiles('server/methods/pageVisited.js', 'server'); + api.addFiles('server/methods/registerGuest.js', 'server'); + api.addFiles('server/methods/removeAgent.js', 'server'); + api.addFiles('server/methods/removeDepartment.js', 'server'); + api.addFiles('server/methods/removeManager.js', 'server'); + api.addFiles('server/methods/removeTrigger.js', 'server'); api.addFiles('server/methods/saveDepartment.js', 'server'); api.addFiles('server/methods/saveSurveyFeedback.js', 'server'); + api.addFiles('server/methods/saveTrigger.js', 'server'); api.addFiles('server/methods/searchAgent.js', 'server'); - api.addFiles('server/methods/removeAgent.js', 'server'); - api.addFiles('server/methods/removeManager.js', 'server'); - api.addFiles('server/methods/removeDepartment.js', 'server'); + api.addFiles('server/methods/sendMessageLivechat.js', 'server'); + // models api.addFiles('server/models/Users.js', 'server'); api.addFiles('server/models/Rooms.js', 'server'); api.addFiles('server/models/LivechatDepartment.js', 'server'); + api.addFiles('server/models/LivechatDepartmentAgents.js', 'server'); + api.addFiles('server/models/LivechatPageVisited.js', 'server'); + api.addFiles('server/models/LivechatTrigger.js', 'server'); - // collections - api.addFiles('client/lib/LivechatDepartment.js', 'client'); + // server lib + api.addFiles('server/lib/getNextAgent.js', 'server'); // publications + api.addFiles('server/publications/availableDepartments.js', 'server'); + api.addFiles('server/publications/departmentAgents.js', 'server'); api.addFiles('server/publications/livechatAgents.js', 'server'); - api.addFiles('server/publications/livechatManagers.js', 'server'); api.addFiles('server/publications/livechatDepartments.js', 'server'); + api.addFiles('server/publications/livechatManagers.js', 'server'); + api.addFiles('server/publications/trigger.js', 'server'); + api.addFiles('server/publications/visitorInfo.js', 'server'); + api.addFiles('server/publications/visitorPageVisited.js', 'server'); api.addFiles('server/publications/visitorRoom.js', 'server'); // livechat app @@ -86,7 +128,6 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n', ['client', 'server']); - // api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index 98bf89e1be0e0da2e924b66c6aae3d53d92bb8c1..ad5a5a3c8432579935162307bdfcc041e42a4ae3 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -1,10 +1,13 @@ Meteor.startup(() => { - var roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); + var roles = _.pluck(RocketChat.models.Roles.find().fetch(), 'name'); if (roles.indexOf('livechat-agent') === -1) { - Roles.createRole('livechat-agent'); + RocketChat.models.Roles.createOrUpdate('livechat-agent'); } if (roles.indexOf('livechat-manager') === -1) { - Roles.createRole('livechat-manager'); + RocketChat.models.Roles.createOrUpdate('livechat-manager'); + } + if (roles.indexOf('livechat-guest') === -1) { + RocketChat.models.Roles.createOrUpdate('livechat-guest'); } if (RocketChat.models && RocketChat.models.Permissions) { RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager', 'admin']); diff --git a/packages/rocketchat-livechat/server/lib/getNextAgent.js b/packages/rocketchat-livechat/server/lib/getNextAgent.js new file mode 100644 index 0000000000000000000000000000000000000000..63a484b49b912bbd5643b74ca8b21e86dc163f41 --- /dev/null +++ b/packages/rocketchat-livechat/server/lib/getNextAgent.js @@ -0,0 +1,9 @@ +this.getNextAgent = function(department) { + var agentFilter = {}; + + if (department) { + return RocketChat.models.LivechatDepartmentAgents.getNextAgentForDepartment(department); + } else { + return RocketChat.models.Users.getNextAgent(); + } +}; diff --git a/packages/rocketchat-livechat/server/methods.js b/packages/rocketchat-livechat/server/methods.js deleted file mode 100644 index 8b7b0dd70e7233cd4e00b02c3254154dcc2eae3e..0000000000000000000000000000000000000000 --- a/packages/rocketchat-livechat/server/methods.js +++ /dev/null @@ -1,109 +0,0 @@ -Meteor.methods({ - registerGuest: function(token, name, email) { - console.log('registerGuest ->'.green, token); - var pass, qt, user, userData, userExists, userId, inc = 0; - check(token, String); - user = Meteor.users.findOne({ - "profile.token": token - }, { - fields: { - _id: 1 - } - }); - if (user != null) { - throw new Meteor.Error('token-already-exists', 'Token already exists'); - } - pass = Meteor.uuid(); - while (true) { - qt = Meteor.users.find({ - 'profile.guest': true - }).count() + 1; - user = 'guest-' + (qt + inc++); - userExists = Meteor.users.findOne({ - 'username': user - }, { - fields: { - _id: 1 - } - }); - console.log('userExists ->',userExists); - if (!userExists) { - break; - } - } - userData = { - username: user, - password: pass - }; - userId = Accounts.createUser(userData); - - updateUser = { - name: name || user, - "profile.guest": true, - "profile.token": token - } - - if (email && email.trim() !== "") { - updateUser.emails = [{ "address": email }]; - } - - Meteor.users.update(userId, { - $set: updateUser - }); - return { - user: user, - pass: pass - }; - }, - sendMessageLivechat: function(message) { - var guest, operator, room; - console.log('sendMessageLivechat ->', arguments); - check(message.rid, String); - check(message.token, String); - guest = Meteor.users.findOne(Meteor.userId(), { - fields: { - username: 1 - } - }); - room = RocketChat.models.Rooms.findOneById(message.rid); - if (room == null) { - operator = Meteor.users.findOne({ - operator: true, - status: 'online' - }); - if (!operator) { - throw new Meteor.Error('no-operators', 'Sorry, no online operators'); - } - RocketChat.models.Rooms.insert({ - _id: message.rid, - name: guest.username, - msgs: 1, - lm: new Date(), - usernames: [operator.username, guest.username], - t: 'l', - ts: new Date(), - v: { - token: message.token - } - }); - RocketChat.models.Subscriptions.insert({ - rid: message.rid, - name: guest.username, - alert: true, - open: true, - unread: 1, - answered: false, - u: { - _id: operator._id, - username: operator.username - }, - t: 'l' - }); - } - room = Meteor.call('canAccessRoom', message.rid, guest._id); - if (!room) { - throw new Meteor.Error('cannot-acess-room'); - } - return RocketChat.sendMessage(guest, message, room); - } -}); diff --git a/packages/rocketchat-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js index e94c5bee12fe8ec0021478cb47305874f4f00cca..e236bc2c41a2f70ef0436a0239434ce0822d8b48 100644 --- a/packages/rocketchat-livechat/server/methods/addAgent.js +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -8,15 +8,13 @@ Meteor.methods({ throw new Meteor.Error('invalid-arguments'); } - console.log('[methods] livechat:addAgent -> '.green, 'arguments:', arguments); - var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { throw new Meteor.Error('user-not-found', 'Username_not_found'); } - if (RocketChat.authz.addUsersToRoles(user._id, 'livechat-agent')) { + if (RocketChat.authz.addUserRoles(user._id, 'livechat-agent')) { return RocketChat.models.Users.setOperator(user._id, true); } diff --git a/packages/rocketchat-livechat/server/methods/addManager.js b/packages/rocketchat-livechat/server/methods/addManager.js index 6519a406bf3849ac5f96dbab1094b1fb86803807..9f4af3713a4647d0d0d2feb43197c93d89f6e753 100644 --- a/packages/rocketchat-livechat/server/methods/addManager.js +++ b/packages/rocketchat-livechat/server/methods/addManager.js @@ -8,14 +8,12 @@ Meteor.methods({ throw new Meteor.Error('invalid-arguments'); } - console.log('[methods] livechat:addManager -> '.green, 'arguments:', arguments); - var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { throw new Meteor.Error('user-not-found', 'Username_not_found'); } - return RocketChat.authz.addUsersToRoles(user._id, 'livechat-manager'); + return RocketChat.authz.addUserRoles(user._id, 'livechat-manager'); } }); diff --git a/packages/rocketchat-livechat/server/methods/pageVisited.js b/packages/rocketchat-livechat/server/methods/pageVisited.js new file mode 100644 index 0000000000000000000000000000000000000000..97729d57f5579f2960ddcf5fe6b1ff60286ebae8 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/pageVisited.js @@ -0,0 +1,5 @@ +Meteor.methods({ + 'livechat:pageVisited' (token, pageInfo) { + return RocketChat.models.LivechatPageVisitied.saveByToken(token, pageInfo); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js new file mode 100644 index 0000000000000000000000000000000000000000..ee258a8a345615cfb7a051363218ede2f99c0de9 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -0,0 +1,81 @@ +Meteor.methods({ + 'livechat:registerGuest': function({ token, name, email, department } = {}) { + var pass, qt, user, userData, userExists, userId, inc = 0; + + check(token, String); + + user = Meteor.users.findOne({ + "profile.token": token + }, { + fields: { + _id: 1 + } + }); + + if (user != null) { + throw new Meteor.Error('token-already-exists', 'Token already exists'); + } + + while (true) { + qt = Meteor.users.find({ + 'profile.guest': true + }).count() + 1; + + user = 'guest-' + (qt + inc++); + + userExists = Meteor.users.findOne({ + 'username': user + }, { + fields: { + _id: 1 + } + }); + + if (!userExists) { + break; + } + } + userData = { + username: user, + globalRoles: ['livechat-guest'], + department: department + }; + + userData.userAgent = this.connection.httpHeaders['user-agent']; + userData.ip = this.connection.httpHeaders['x-real-ip'] || this.connection.clientAddress; + userData.host = this.connection.httpHeaders['host']; + + userId = Accounts.insertUserDoc({}, userData); + + updateUser = { + name: name || user, + "profile.guest": true, + "profile.token": token + } + + if (email && email.trim() !== "") { + updateUser.emails = [{ "address": email }]; + } + + var stampedToken = Accounts._generateStampedLoginToken(); + var hashStampedToken = Accounts._hashStampedToken(stampedToken); + + updateUser.services = { + resume: { + loginTokens: [ hashStampedToken ] + } + }; + + Meteor.users.update(userId, { + $set: updateUser + }); + + // update visited page history to not expire + RocketChat.models.LivechatPageVisitied.keepHistoryForToken(token); + + return { + userId: userId, + token: stampedToken.token + }; + } +}); diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js index bc6dd5bd4c98c85845d49c5e39f534a2cdddf4ae..adbf4ae47739efcb49602609dade49d4e62c6fc0 100644 --- a/packages/rocketchat-livechat/server/methods/removeAgent.js +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -8,15 +8,13 @@ Meteor.methods({ throw new Meteor.Error('invalid-arguments'); } - console.log('[methods] livechat:removeAgent -> '.green, 'arguments:', arguments); - var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { throw new Meteor.Error('user-not-found', 'Username_not_found'); } - if (RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-agent')) { + if (RocketChat.authz.removeUserFromRoles(user._id, 'livechat-agent')) { return RocketChat.models.Users.setOperator(user._id, false); } diff --git a/packages/rocketchat-livechat/server/methods/removeDepartment.js b/packages/rocketchat-livechat/server/methods/removeDepartment.js index 8fb2b620dff4ecd50d97a3563c94cab37d49ca4a..5419602088c7c05b784e4847e992667476fb5457 100644 --- a/packages/rocketchat-livechat/server/methods/removeDepartment.js +++ b/packages/rocketchat-livechat/server/methods/removeDepartment.js @@ -6,8 +6,6 @@ Meteor.methods({ check(_id, String); - console.log('[methods] livechat:removeDepartment -> '.green, 'arguments:', arguments); - var department = RocketChat.models.LivechatDepartment.findOneById(_id, { fields: { _id: 1 } }); if (!department) { diff --git a/packages/rocketchat-livechat/server/methods/removeManager.js b/packages/rocketchat-livechat/server/methods/removeManager.js index 38e462d3f0e03ef8e8dd89ebd7dc9de82c60d5f9..31ad6cd337b8f01524536b12474e7ce0440cec7f 100644 --- a/packages/rocketchat-livechat/server/methods/removeManager.js +++ b/packages/rocketchat-livechat/server/methods/removeManager.js @@ -6,14 +6,12 @@ Meteor.methods({ check(username, String); - console.log('[methods] livechat:removeManager -> '.green, 'arguments:', arguments); - var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { throw new Meteor.Error('user-not-found', 'Username_not_found'); } - return RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-manager'); + return RocketChat.authz.removeUserFromRoles(user._id, 'livechat-manager'); } }); diff --git a/packages/rocketchat-livechat/server/methods/removeTrigger.js b/packages/rocketchat-livechat/server/methods/removeTrigger.js new file mode 100644 index 0000000000000000000000000000000000000000..a2249b1459416ef3507aae902e71efcc741b9bc1 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/removeTrigger.js @@ -0,0 +1,9 @@ +Meteor.methods({ + 'livechat:removeTrigger' (trigger) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + return RocketChat.models.LivechatTrigger.removeAll(); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/saveDepartment.js b/packages/rocketchat-livechat/server/methods/saveDepartment.js index 526b32134f28956e33201cf1fa2b156bf480a70a..2f626c395720add0dfd8b8e533a5363c955b21ea 100644 --- a/packages/rocketchat-livechat/server/methods/saveDepartment.js +++ b/packages/rocketchat-livechat/server/methods/saveDepartment.js @@ -1,7 +1,5 @@ Meteor.methods({ - 'livechat:saveDepartment' (_id, departmentData) { - console.log('[methods] livechat:saveDepartment -> '.green, 'arguments:', arguments); - + 'livechat:saveDepartment' (_id, departmentData, departmentAgents) { if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { throw new Meteor.Error("not-authorized"); } @@ -19,6 +17,6 @@ Meteor.methods({ } } - return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description, departmentData.agents); + return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description, departmentAgents); } }); diff --git a/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js b/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js index 44d8fd05767bd36b4423d22f0c00aca2b1c3d4f3..5d7421876166203de801a0cde6424f42b84182f0 100644 --- a/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js +++ b/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js @@ -4,8 +4,6 @@ Meteor.methods({ check(visitorRoom, String); check(formData, [Match.ObjectIncluding({ name: String, value: String })]); - console.log('[methods] livechat:saveSurveyFeedback -> '.green, 'arguments:', arguments); - visitor = RocketChat.models.Users.getVisitorByToken(visitorToken); room = RocketChat.models.Rooms.findOneById(visitorRoom); diff --git a/packages/rocketchat-livechat/server/methods/saveTrigger.js b/packages/rocketchat-livechat/server/methods/saveTrigger.js new file mode 100644 index 0000000000000000000000000000000000000000..4077fc46d5b3568e7b587486c86fa13be81de169 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/saveTrigger.js @@ -0,0 +1,9 @@ +Meteor.methods({ + 'livechat:saveTrigger' (trigger) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + return RocketChat.models.LivechatTrigger.save(trigger); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/searchAgent.js b/packages/rocketchat-livechat/server/methods/searchAgent.js index 72b9d3d9bb0830deb8aced3d1c9ac47375803448..80bf6159baea80d08eb2387596bb47aa3b37ff49 100644 --- a/packages/rocketchat-livechat/server/methods/searchAgent.js +++ b/packages/rocketchat-livechat/server/methods/searchAgent.js @@ -8,8 +8,6 @@ Meteor.methods({ throw new Meteor.Error('invalid-arguments'); } - console.log('[methods] livechat:searchAgent -> '.green, 'arguments:', arguments); - var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1, username: 1 } }); if (!user) { diff --git a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js new file mode 100644 index 0000000000000000000000000000000000000000..2f9983768dd2ce32d07e8d784a2db6ef02efcc74 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js @@ -0,0 +1,62 @@ +Meteor.methods({ + sendMessageLivechat: function(message) { + var guest, agent, room; + + check(message.rid, String); + check(message.token, String); + + guest = Meteor.users.findOne(Meteor.userId(), { + fields: { + username: 1, + department: 1 + } + }); + + room = RocketChat.models.Rooms.findOneById(message.rid); + if (room == null) { + + // if no department selected verify if there is only one active and use it + if (!guest.department) { + var departments = RocketChat.models.LivechatDepartment.findEnabledWithAgents(); + if (departments.count() === 1) { + guest.department = departments.fetch()[0]._id; + } + } + + agent = getNextAgent(guest.department); + if (!agent) { + throw new Meteor.Error('no-agent-online', 'Sorry, no online agents'); + } + RocketChat.models.Rooms.insert({ + _id: message.rid, + name: guest.username, + msgs: 1, + lm: new Date(), + usernames: [agent.username, guest.username], + t: 'l', + ts: new Date(), + v: { + token: message.token + } + }); + RocketChat.models.Subscriptions.insert({ + rid: message.rid, + name: guest.username, + alert: true, + open: true, + unread: 1, + answered: false, + u: { + _id: agent.agentId, + username: agent.username + }, + t: 'l' + }); + } + room = Meteor.call('canAccessRoom', message.rid, guest._id); + if (!room) { + throw new Meteor.Error('cannot-acess-room'); + } + return RocketChat.sendMessage(guest, message, room); + } +}); diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index 41141b8d68ef4943ed85dfe3b10ec25c8058b010..5cbd7f35bbd3e412e161350875bc55620d35a458 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -19,23 +19,42 @@ class LivechatDepartment extends RocketChat.models._Base { return this.find(query, options); } - // UPSERT createOrUpdateDepartment(_id, enabled, name, description, agents, extraData) { - record = { + var agents = [].concat(agents); + + var record = { enabled: enabled, name: name, description: description, - agents: [] - } + numAgents: agents.length + }; - if (!_.isEmpty(agents)) { - for (agent of agents) { - record.agents.push({ _id: agent._id, username: agent.username }); - } + _.extend(record, extraData); + + if (_id) { + this.update({ _id: _id }, { $set: record }); + } else { + _id = this.insert(record); } - _.extend(record, extraData); - this.upsert({ _id: _id }, { $set: record }); + var savedAgents = _.pluck(RocketChat.models.LivechatDepartmentAgents.findByDepartmentId(_id).fetch(), 'agentId'); + var agentsToSave = _.pluck(agents, 'agentId'); + + // remove other agents + _.difference(savedAgents, agentsToSave).forEach((agentId) => { + RocketChat.models.LivechatDepartmentAgents.removeByDepartmentIdAndAgentId(_id, agentId); + }); + + agents.forEach((agent) => { + RocketChat.models.LivechatDepartmentAgents.saveAgent({ + agentId: agent.agentId, + departmentId: _id, + username: agent.username, + count: parseInt(agent.count), + order: parseInt(agent.order) + }); + }); + return _.extend(record, { _id: _id }); } @@ -44,6 +63,14 @@ class LivechatDepartment extends RocketChat.models._Base { query = { _id: _id }; return this.remove(query); } + + findEnabledWithAgents() { + var query = { + numAgents: { $gt: 0 }, + enabled: true + }; + return this.find(query); + } } RocketChat.models.LivechatDepartment = new LivechatDepartment(); diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js new file mode 100644 index 0000000000000000000000000000000000000000..551a00e1aebdac4ddd9059015656d6072c4c6d2e --- /dev/null +++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js @@ -0,0 +1,79 @@ +/** + * Livechat Department model + */ +class LivechatDepartmentAgents extends RocketChat.models._Base { + constructor() { + super(); + this._initModel('livechat_department_agents'); + } + + findByDepartmentId(departmentId) { + return this.find({ departmentId: departmentId }); + } + + saveAgent(agent) { + if (agent._id) { + return this.update({ _id: _id }, { $set: agent }); + } else { + return this.upsert({ + agentId: agent.agentId, + departmentId: agent.departmentId + }, { + $set: { + username: agent.username, + count: parseInt(agent.count), + order: parseInt(agent.order) + } + }); + } + } + + removeByDepartmentIdAndAgentId(departmentId, agentId) { + this.remove({ departmentId: departmentId, agentId: agentId }); + } + + getNextAgentForDepartment(departmentId) { + var agents = this.findByDepartmentId(departmentId).fetch(); + + if (agents.length === 0) { + return; + } + + var onlineUsers = RocketChat.models.Users.findOnlineUserFromList(_.pluck(agents, 'username')); + + var onlineUsernames = _.pluck(onlineUsers.fetch(), 'username'); + + var query = { + departmentId: departmentId, + username: { + $in: onlineUsernames + } + }; + + var sort = { + count: 1, + sort: 1, + username: 1 + }; + var update = { + $inc: { + count: 1 + } + }; + + var collectionObj = this.model.rawCollection(); + var findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj); + + var agent = findAndModify(query, sort, update); + if (agent) { + return { + agentId: agent.agentId, + username: agent.username + } + } else { + return null; + } + } +} + +RocketChat.models.LivechatDepartmentAgents = new LivechatDepartmentAgents(); diff --git a/packages/rocketchat-livechat/server/models/LivechatPageVisited.js b/packages/rocketchat-livechat/server/models/LivechatPageVisited.js new file mode 100644 index 0000000000000000000000000000000000000000..36ecd8272657ccd6a7a693ff6a7e2fafd8d9b2d5 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/LivechatPageVisited.js @@ -0,0 +1,48 @@ +/** + * Livechat Page Visited model + */ +class LivechatPageVisitied extends RocketChat.models._Base { + constructor() { + super(); + this._initModel('livechat_page_visited'); + + this.tryEnsureIndex({ 'token': 1 }); + this.tryEnsureIndex({ 'ts': 1 }); + + // keep history for 1 month if the visitor does not register + this.tryEnsureIndex({ 'expireAt': 1 }, { sparse: 1, expireAfterSeconds: 0 }); + } + + saveByToken(token, pageInfo) { + // keep history of unregistered visitors for 1 month + var keepHistoryMiliseconds = 2592000000; + + return this.insert({ + token: token, + page: pageInfo, + ts: new Date(), + expireAt: new Date().getTime() + keepHistoryMiliseconds + }); + } + + findByToken(token) { + return this.find({ token: token }, { sort : { ts: -1 }, limit: 20 }); + } + + keepHistoryForToken(token) { + return this.update({ + token: token, + expireAt: { + $exists: true + } + }, { + $unset: { + expireAt: 1 + } + }, { + multi: true + }); + } +} + +RocketChat.models.LivechatPageVisitied = new LivechatPageVisitied(); diff --git a/packages/rocketchat-livechat/server/models/LivechatTrigger.js b/packages/rocketchat-livechat/server/models/LivechatTrigger.js new file mode 100644 index 0000000000000000000000000000000000000000..4873a44f1c25bc45fc762a94523fa4a5f0c19e21 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/LivechatTrigger.js @@ -0,0 +1,26 @@ +/** + * Livechat Trigger model + */ +class LivechatTrigger extends RocketChat.models._Base { + constructor() { + super(); + this._initModel('livechat_trigger'); + } + + // FIND + save(data) { + trigger = this.findOne(); + + if (trigger) { + return this.update({ _id: trigger._id }, { $set: data }); + } else { + return this.insert(data); + } + } + + removeAll() { + this.remove({}); + } +} + +RocketChat.models.LivechatTrigger = new LivechatTrigger(); diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index 1481564cf1d669ea0e33a147781265730bb09cf2..7a9d212867d8f84a6cd1861d63d5770642eb4f80 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -13,6 +13,70 @@ RocketChat.models.Users.setOperator = function(_id, operator) { return this.update(_id, update); }; +/** + * Gets all online agents + * @return + */ +RocketChat.models.Users.findOnlineAgents = function() { + var query = { + status: 'online', + roles: 'livechat-agent' + }; + + return this.find(query); +}; + +/** + * Find online users from a list + * @param {array} userList - array of usernames + * @return + */ +RocketChat.models.Users.findOnlineUserFromList = function(userList) { + var query = { + status: 'online', + username: { + $in: [].concat(userList) + } + }; + + return this.find(query); +}; + +/** + * Get next user agent in order + * @return {object} User from db + */ +RocketChat.models.Users.getNextAgent = function() { + var query = { + status: 'online', + roles: 'livechat-agent' + }; + + var collectionObj = this.model.rawCollection(); + var findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj); + + var sort = { + livechatCount: 1, + username: 1 + }; + + var update = { + $inc: { + livechatCount: 1 + } + }; + + var user = findAndModify(query, sort, update); + if (user) { + return { + agentId: user._id, + username: user.username + } + } else { + return null; + } +}; + /** * Gets visitor by token * @param {string} token - Visitor token @@ -25,3 +89,16 @@ RocketChat.models.Users.getVisitorByToken = function(token, options) { return this.findOne(query, options); }; + +/** + * Gets visitor by token + * @param {string} token - Visitor token + */ +RocketChat.models.Users.findVisitorByToken = function(token) { + var query = { + "profile.guest": true, + "profile.token": token + }; + + return this.find(query); +}; diff --git a/packages/rocketchat-livechat/server/publications/availableDepartments.js b/packages/rocketchat-livechat/server/publications/availableDepartments.js new file mode 100644 index 0000000000000000000000000000000000000000..6ab277d73cecdcf214c4a1dea6644738762bf3f4 --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/availableDepartments.js @@ -0,0 +1,3 @@ +Meteor.publish('livechat:availableDepartments', function() { + return RocketChat.models.LivechatDepartment.findEnabledWithAgents(); +}); diff --git a/packages/rocketchat-livechat/server/publications/departmentAgents.js b/packages/rocketchat-livechat/server/publications/departmentAgents.js new file mode 100644 index 0000000000000000000000000000000000000000..b09f4fe3dd9c7f604544f97b557308f78a727dbf --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/departmentAgents.js @@ -0,0 +1,11 @@ +Meteor.publish('livechat:departmentAgents', function(departmentId) { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { + throw new Meteor.Error('not-authorized'); + } + + return RocketChat.models.LivechatDepartmentAgents.find({ departmentId: departmentId }); +}); diff --git a/packages/rocketchat-livechat/server/publications/livechatAgents.js b/packages/rocketchat-livechat/server/publications/livechatAgents.js index b68dba1459c21601c902d9f2a67998d022093bce..77be3cde55ec2e3918215add18d8890df41cdaec 100644 --- a/packages/rocketchat-livechat/server/publications/livechatAgents.js +++ b/packages/rocketchat-livechat/server/publications/livechatAgents.js @@ -7,8 +7,6 @@ Meteor.publish('livechat:agents', function() { throw new Meteor.Error('not-authorized'); } - console.log('[publish] livechat:agents -> '.green, 'arguments:', arguments); - var self = this; var handle = RocketChat.authz.getUsersInRole('livechat-agent').observeChanges({ diff --git a/packages/rocketchat-livechat/server/publications/livechatDepartments.js b/packages/rocketchat-livechat/server/publications/livechatDepartments.js index ab35d5dd88c2c7b3acac8d85f893284cabcdece1..a7566722d58e09066b483cdc30b57ffbb5270c00 100644 --- a/packages/rocketchat-livechat/server/publications/livechatDepartments.js +++ b/packages/rocketchat-livechat/server/publications/livechatDepartments.js @@ -7,8 +7,6 @@ Meteor.publish('livechat:departments', function(_id) { throw new Meteor.Error('not-authorized'); } - console.log('[publish] livechat:departments -> '.green, 'arguments:', arguments); - if (_id !== undefined) { return RocketChat.models.LivechatDepartment.findByDepartmentId(_id); } else { diff --git a/packages/rocketchat-livechat/server/publications/livechatManagers.js b/packages/rocketchat-livechat/server/publications/livechatManagers.js index 639c1305c6df0970858dd410777ce2928fbd006f..042a2acb50ac579000ce5c73b1d655ac3a1119c5 100644 --- a/packages/rocketchat-livechat/server/publications/livechatManagers.js +++ b/packages/rocketchat-livechat/server/publications/livechatManagers.js @@ -7,8 +7,6 @@ Meteor.publish('livechat:managers', function() { throw new Meteor.Error('not-authorized'); } - console.log('[publish] livechat:managers -> '.green, 'arguments:', arguments); - var self = this; var handle = RocketChat.authz.getUsersInRole('livechat-manager').observeChanges({ diff --git a/packages/rocketchat-livechat/server/publications/trigger.js b/packages/rocketchat-livechat/server/publications/trigger.js new file mode 100644 index 0000000000000000000000000000000000000000..61d7d6831f41d0013ff2e1efc106b24d907eb86a --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/trigger.js @@ -0,0 +1,3 @@ +Meteor.publish('livechat:trigger', function() { + return RocketChat.models.LivechatTrigger.find(); +}); diff --git a/packages/rocketchat-livechat/server/publications/visitorInfo.js b/packages/rocketchat-livechat/server/publications/visitorInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..a4fe7a17761329df24b160391e37b35ea6b3040b --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/visitorInfo.js @@ -0,0 +1,17 @@ +Meteor.publish('livechat:visitorInfo', function(roomId) { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-l-room')) { + throw new Meteor.Error('not-authorized'); + } + + var room = RocketChat.models.Rooms.findOneById(roomId); + + if (room && room.v && room.v.token) { + return RocketChat.models.Users.findVisitorByToken(room.v.token); + } else { + return this.ready(); + } +}); diff --git a/packages/rocketchat-livechat/server/publications/visitorPageVisited.js b/packages/rocketchat-livechat/server/publications/visitorPageVisited.js new file mode 100644 index 0000000000000000000000000000000000000000..72aa424c6737f85caad54111e766d84b27bf4b2b --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/visitorPageVisited.js @@ -0,0 +1,17 @@ +Meteor.publish('livechat:visitorPageVisited', function(roomId) { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-l-room')) { + throw new Meteor.Error('not-authorized'); + } + + var room = RocketChat.models.Rooms.findOneById(roomId); + + if (room && room.v && room.v.token) { + return RocketChat.models.LivechatPageVisitied.findByToken(room.v.token); + } else { + return this.ready(); + } +}); diff --git a/packages/rocketchat-livechat/server/publications/visitorRoom.js b/packages/rocketchat-livechat/server/publications/visitorRoom.js index 52b4fab49f6c249cae1742b92a9d4e7a8f440bc0..cb0570f7a7e8a736605bd737100a00c0395b475f 100644 --- a/packages/rocketchat-livechat/server/publications/visitorRoom.js +++ b/packages/rocketchat-livechat/server/publications/visitorRoom.js @@ -1,6 +1,4 @@ Meteor.publish('livechat:visitorRoom', function(visitorToken) { - console.log('[publish] livechat:visitorRoom -> '.green, 'arguments:', arguments); - return RocketChat.models.Rooms.findByVisitorToken(visitorToken, { fields: { name: 1, diff --git a/packages/rocketchat-mailer/client/router.coffee b/packages/rocketchat-mailer/client/router.coffee index 5205c1f2a693efdc02359bcd2a9b30f2e8b3793d..4260c1719c3fa4e9b0bb5578d64f975b362f48af 100644 --- a/packages/rocketchat-mailer/client/router.coffee +++ b/packages/rocketchat-mailer/client/router.coffee @@ -1,11 +1,7 @@ -tabReset = -> - RocketChat.TabBar.reset() - FlowRouter.route '/mailer', name: 'mailer' - triggersEnter: [tabReset] - triggersExit: [tabReset] action: -> + RocketChat.TabBar.showGroup 'mailer' BlazeLayout.render 'main', {center: 'mailer'} FlowRouter.route '/mailer/unsubscribe/:_id/:createdAt', diff --git a/packages/rocketchat-mailer/i18n/ar.i18n.json b/packages/rocketchat-mailer/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..d93ff17e2eae5acb0ebf7285199c339714e20f56 100644 --- a/packages/rocketchat-mailer/i18n/ar.i18n.json +++ b/packages/rocketchat-mailer/i18n/ar.i18n.json @@ -1 +1,11 @@ -{ } \ No newline at end of file +{ + "Dry_run" : "تنÙيذ تجريبي", + "Dry_run_description" : "سيتم إرسال رسالة بريدية واØدة إلى Ù†Ùس العنوان الموجود ÙÙŠ خانة \"من\". تأكد من كون ذلك العنوان البريدي Ùعال", + "Email_from" : "من", + "Email_subject" : "الموضوع", + "Send_email" : "إرسال البريد الإلكتروني", + "The_emails_are_being_sent" : "يتم إرسال رسائل البريد الإلكتروني.", + "You_are_not_authorized_to_view_this_page" : "لا تملك الصلاØية لمشاهدة هذه الصÙØØ©.", + "You_have_successfully_unsubscribed" : "لقد تم إلغاء اشتراكك Ø¨Ù†Ø¬Ø§Ø Ù…Ù† القائمة البريدية لدينا.", + "You_must_provide_the_unsubscribe_link" : "يجب توÙير رابط [إلغاء الاشتراك]." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/de.i18n.json b/packages/rocketchat-mailer/i18n/de.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..d70199a35e43e80bfea6e20a7e86f73a689c1955 100644 --- a/packages/rocketchat-mailer/i18n/de.i18n.json +++ b/packages/rocketchat-mailer/i18n/de.i18n.json @@ -1 +1,19 @@ -{ } \ No newline at end of file +{ + "From_email_warning" : "<b>Warnung</b>: Der <b>Absender</b> ist Gegenstand deiner Mail-Server-Einstellungen.", + "From_email_is_required" : "Ein Absender muss angegeben werden.", + "Dry_run" : "Probelauf", + "Dry_run_description" : "Es wird nur eine E-Mail an den Empfänger gesendet. Die E-Mail muss einem gültigen Benutzer gehören.", + "Email_from" : "Absender", + "Email_subject" : "Betreff", + "Email_body" : "Nachricht", + "Mailer" : "Mailer", + "Mailer_body_tags" : "Sie <b>müssen</b> [unsubscribe] verwenden, um einen Link zum Abmelden aus dem Verteiler zur Verfügung zu stellen. <br /> Sie können [name] für den Vor- und Nachnamen, [fname] für den Vornamen oder [lname] für den Nachnamen des Benutzers verwenden. <br />Ebenfalls können Sie [email] verwenden, um die E-Mail-Adresse des Benutzers anzugeben.", + "Query" : "Abfrage", + "Query_description" : "Zusätzliche Bedingungen für die Bestimmung, an welche Benutzer die E-Mails gesendet werden sollen. Ausgetragene Benutzer werden automatisch aus der Abfrage entfernt. Es muss ein gültiger JSON sein. Beispiel: \"{\"createdAt\":{\"$gt\":{\"$date\": \"2015-01-01T00:00:00.000Z\"}}}\"", + "Send_email" : "E-Mail senden", + "The_emails_are_being_sent" : "Die E-Mails werden gesendet.", + "You_are_not_authorized_to_view_this_page" : "Sie sind nicht berechtigt, diese Seite zu sehen.", + "You_have_successfully_unsubscribed" : "Sie haben sich erfolgreich von unserem Verteiler abgemeldet.", + "You_informed_an_invalid_FROM_address" : "Sie haben eine ungültige E-Mail-Adresse als Empfänger angegeben.", + "You_must_provide_the_unsubscribe_link" : "Sie müssen einen Link zum Abmelden vom Verteiler angeben." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/fr.i18n.json b/packages/rocketchat-mailer/i18n/fr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..71edb96248f9bba001000e80e9e03d7f5d0fb219 100644 --- a/packages/rocketchat-mailer/i18n/fr.i18n.json +++ b/packages/rocketchat-mailer/i18n/fr.i18n.json @@ -1 +1,14 @@ -{ } \ No newline at end of file +{ + "From_email_warning" : "<b>Attention</b> : le champ <b>De</b> est forcé par vos paramètres de serveur mail", + "From_email_is_required" : "Le champ \"De\" est requis.", + "Email_from" : "De", + "Email_subject" : "Sujet", + "Email_body" : "Corps du mail", + "Mailer_body_tags" : "Vous <b>devez</b> utiliser [unsubscribe] pour le lien de désinscription.<br />Vous pouvez utiliser [name], [fname], [lname] pour le nom complet de l'utilisateur, le prénom et le nom de famille respectivement.<br />Vous pouvez utiliser [email] pour le mail de l'utilisateur.", + "Send_email" : "Envoyer le courriel", + "The_emails_are_being_sent" : "Les courriels sont en train d'être envoyés.", + "You_are_not_authorized_to_view_this_page" : "Vous n'avez pas l'autorisation de voir cette page.", + "You_have_successfully_unsubscribed" : "Vous êtes désabonné avec succès de notre Liste de diffusion.", + "You_informed_an_invalid_FROM_address" : "Vous avez entré un expéditeur invalide (champ FROM).", + "You_must_provide_the_unsubscribe_link" : "Vous devez fournir le lien de désinscription [unsubscribe]." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/hr.i18n.json b/packages/rocketchat-mailer/i18n/hr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6408a16fb887470db3fee31a2e2224f83cbfcf2e 100644 --- a/packages/rocketchat-mailer/i18n/hr.i18n.json +++ b/packages/rocketchat-mailer/i18n/hr.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Email_from" : "Od", + "Send_email" : "PoÅ¡alji e-mail", + "The_emails_are_being_sent" : "E-mailovi su poslani.", + "You_are_not_authorized_to_view_this_page" : "Nemate dopuÅ¡tenje za pregled ove stranice." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/km.i18n.json b/packages/rocketchat-mailer/i18n/km.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..a99a6eb6c8c273a8d2057197e6a4e038e6ce6a6f 100644 --- a/packages/rocketchat-mailer/i18n/km.i18n.json +++ b/packages/rocketchat-mailer/i18n/km.i18n.json @@ -1 +1,11 @@ -{ } \ No newline at end of file +{ + "From_email_is_required" : "From អ៊ីមែលគឺážáŸ’រូវបំពáŸáž‰", + "Email_from" : "ពី", + "Email_subject" : "ប្រធានបទ", + "Email_body" : "រាងកាយអ៊ីមែល", + "Send_email" : "ផ្ញើ​រ​អ៊ី​ម៉ែ​ល", + "The_emails_are_being_sent" : "áž“áŸáŸ‡â€‹áž¢áŸŠáž¸áž˜áŸ‚ល​ážáŸ’រូវ​បាន​បញ្ជូន​។", + "You_are_not_authorized_to_view_this_page" : "អ្នក​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážâ€‹áž±áŸ’យ​មើល​ទំពáŸážšâ€‹áž“áŸáŸ‡â€‹áŸ”", + "You_have_successfully_unsubscribed" : "អ្នក​បាន unsubscribed ដោយ​ជោគជáŸáž™â€‹áž–ី​បញ្ជី Mailling របស់​យើង​។", + "You_must_provide_the_unsubscribe_link" : "អ្នកážáŸ’រូវážáŸ‚ផ្ដល់ážáŸ†ážŽáž—្ជាប់ [unsubscribe] ។" +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ko.i18n.json b/packages/rocketchat-mailer/i18n/ko.i18n.json index 0b3dccd1255d7a416029a249cc733148d5f53d9e..ffc9e58b9aa7483860d392115df5bd6bf494f3d6 100644 --- a/packages/rocketchat-mailer/i18n/ko.i18n.json +++ b/packages/rocketchat-mailer/i18n/ko.i18n.json @@ -3,5 +3,7 @@ "Email_subject" : "ì œëª©", "Email_body" : "ì´ë©”ì¼ ë³¸ë¬¸", "Send_email" : "ì´ë©”ì¼ ë³´ë‚´ê¸°", - "You_are_not_authorized_to_view_this_page" : "ë‹¹ì‹ ì€ ì´ íŽ˜ì´ì§€ë¥¼ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤." + "The_emails_are_being_sent" : "ì´ë©”ì¼ì„ ì „ì†¡ 중입니다.", + "You_are_not_authorized_to_view_this_page" : "ë‹¹ì‹ ì€ ì´ íŽ˜ì´ì§€ë¥¼ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤.", + "You_have_successfully_unsubscribed" : "지금부터 ë‹¹ì‹ ì€ ë©”ì¼ë§ 리스트를 ìˆ˜ì‹ í•˜ì§€ 않습니다." } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/nl.i18n.json b/packages/rocketchat-mailer/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..3c6d8dec0b99c85c79296219872046884d6ad52e 100644 --- a/packages/rocketchat-mailer/i18n/nl.i18n.json +++ b/packages/rocketchat-mailer/i18n/nl.i18n.json @@ -1 +1,11 @@ -{ } \ No newline at end of file +{ + "From_email_is_required" : "Afzender e-mailadres is verplicht", + "Dry_run_description" : "Zal slechts één e-mail sturen naar hetzelfde adres als in afzenderveld. De e-mail moet horen bij een geldige gebruiker.", + "Email_from" : "Afzender", + "Email_subject" : "Onderwerp", + "Email_body" : "E-mail tekst", + "Send_email" : "Verstuur e-mail", + "The_emails_are_being_sent" : "De e-mails worden verzonden.", + "You_are_not_authorized_to_view_this_page" : "U bent niet bevoegd om deze pagina te bekijken.", + "You_have_successfully_unsubscribed" : "U bent uitgeschreven van onze mailinglijst." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/pl.i18n.json b/packages/rocketchat-mailer/i18n/pl.i18n.json index 292bea7592fb7b5349479bd1e7112a78681b196f..e44e595d29f1b7c8e9978619c9445648fcbd11d1 100644 --- a/packages/rocketchat-mailer/i18n/pl.i18n.json +++ b/packages/rocketchat-mailer/i18n/pl.i18n.json @@ -6,6 +6,7 @@ "Email_body" : "Treść wiadomoÅ›ci", "Mailer" : "WyÅ›lij email użytkownikom", "Mailer_body_tags" : "<b>Musisz</b> użyć znacznika [unsubscribe] aby zawrzeć w treÅ›ci odnoÅ›nik do rezygnacji z subskrypcji.<br />Możesz użyć znaczników [name], [fname], [lname] by wstawić odpowiednio peÅ‚nÄ… nazwÄ™ użytkownika, jego imiÄ™, nazwisko.<br />\nMożesz użyć znacznika [email] by wstawić adres email użytkownika.", + "Query" : "Zapytanie", "Send_email" : "WyÅ›lij wiadomość", "The_emails_are_being_sent" : "WiadomoÅ›ci e-mail sÄ… wysyÅ‚ane.", "You_are_not_authorized_to_view_this_page" : "Nie masz uprawnieÅ„, aby zobaczyć tÄ™ stronÄ™.", diff --git a/packages/rocketchat-mailer/i18n/ro.i18n.json b/packages/rocketchat-mailer/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..957380946206560f1bea7d650745bf8cfa81cdbe --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ro.i18n.json @@ -0,0 +1,19 @@ +{ + "From_email_warning" : "b>AtenÈ›ie</b>:Câmpul <b>De la</b> depinde de setările serverului dumneavoastră de email.", + "From_email_is_required" : "E nevoie de adresa de email \"De la\"", + "Dry_run" : "Dry run", + "Dry_run_description" : "Va trimite un singur e-mail, la adresa specificată în CÄ‚TRE. E-mail-ul trebuie să aparÈ›ină unui utilizator valid.", + "Email_from" : "De la", + "Email_subject" : "Subiect", + "Email_body" : "Corp E-mail", + "Mailer" : "Mailer", + "Mailer_body_tags" : "<b>Trebuie</b> să folosiÈ›i [unsubscribe] pentru link-ul de unsuscribe.<br />PuteÈ›i utiliza [name], [fname], [lname] pentru numele întreg, prenume respectiv nume.<br />PuteÈ›i folosi [email] pentru e-mailul utilizatorului.", + "Query" : "Interogare", + "Query_description" : "CondiÈ›ii suplimentare pentru a determina către ce utilizatori se trimite e-mail. Utilizatorii dezabonaÈ›i sunt eliminaÈ›i automat din interogare. Trebuie să fie un JSON valid. Exemplu: \"{\" createdAt \": {\" $ GT \": {\" $ data \":\" 2015-01-01T00: 00: 00.000Z \"}}}\"", + "Send_email" : "Trimite email", + "The_emails_are_being_sent" : "E-mail-urile sunt trimise.", + "You_are_not_authorized_to_view_this_page" : "Nu sunteÈ›i autorizat pentru a vizualiza această pagină.", + "You_have_successfully_unsubscribed" : "V-aÈ›i dezabonat cu succes din lista noastră de email.", + "You_informed_an_invalid_FROM_address" : "AÈ›i utilizat o adresă DE LA invalidă.", + "You_must_provide_the_unsubscribe_link" : "Trebuie să furnizaÈ›i link-ul de [unsubscribe]." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ru.i18n.json b/packages/rocketchat-mailer/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..980d68b0494d5b054981f8108cda65beaf4a6b24 100644 --- a/packages/rocketchat-mailer/i18n/ru.i18n.json +++ b/packages/rocketchat-mailer/i18n/ru.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Dry_run_description" : "Мы отправим только один e-mail на Ð°Ð´Ñ€ÐµÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¹ в поле \"От\". E-mail Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ принадлежать дейÑтвительному пользователю." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/sr.i18n.json b/packages/rocketchat-mailer/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/package.js b/packages/rocketchat-mailer/package.js index 7dd1c4cd5a8fe12f0a6a54e3daf76fcf5e554c0f..ab47e1a98efa82f25c0f6a1415665143357f02f3 100644 --- a/packages/rocketchat-mailer/package.js +++ b/packages/rocketchat-mailer/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { 'coffeescript', 'ddp-rate-limiter', 'kadira:flow-router', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'rocketchat:authorization@0.0.1' ]); @@ -43,9 +43,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); api.export('Mailer'); }); diff --git a/packages/rocketchat-mailer/server/methods/sendMail.coffee b/packages/rocketchat-mailer/server/methods/sendMail.coffee index a4b7fd4194b5ba030077e74bc8a577251485427f..d12e7b18dff7cce61a920f4fffabf9d9a5aeedd2 100644 --- a/packages/rocketchat-mailer/server/methods/sendMail.coffee +++ b/packages/rocketchat-mailer/server/methods/sendMail.coffee @@ -1,8 +1,6 @@ Meteor.methods 'Mailer.sendMail': (from, subject, body, dryrun, query) -> - console.log '[method] Mailer.sendMail', from, subject, body, dryrun, query - return Mailer.sendMail from, subject, body, dryrun, query # Limit setting username once per minute diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index c578fec716055746fe5ff6193ed875c47bcf7e01..f33c817e52735bdbf0cac761c6efd0efd12cb860 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -13,6 +13,20 @@ class Markdown else return message + # Support `text` + if _.isString message + msg = msg.replace(/(^|>|[ >_*~])\`([^`\r\n]+)\`([<_*~]|\B|\b|$)/gm, '$1<span class="copyonly">`</span><span><code class="inline">$2</code></span><span class="copyonly">`</span>$3') + else + message.tokens ?= [] + msg = msg.replace /(^|>|[ >_*~])\`([^`\r\n]+)\`([<_*~]|\B|\b|$)/gm, (match, p1, p2, p3, offset, text) -> + token = "$#{Random.id()}$" + + message.tokens.push + token: token + text: "#{p1}<span class=\"copyonly\">`</span><span><code class=\"inline\">#{p2}</code></span><span class=\"copyonly\">`</span>#{p3}" + + return token + # Support  msg = msg.replace(/!\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/gm, '<a href="$2" title="$1" class="swipebox" target="_blank"><div class="inline-image" style="background-image: url($2);"></div></a>') @@ -35,9 +49,6 @@ class Markdown # Support # Text for h4 msg = msg.replace(/^#### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h4>$1</h4>') - # Support `text` - msg = msg.replace(/(^|>|[ >_*~])\`([^`\r\n]+)\`([<_*~]|\B|\b|$)/gm, '$1<span class="copyonly">`</span><code class="inline">$2</code><span class="copyonly">`</span>$3') - # Support *text* to make bold msg = msg.replace(/(^|>|[ >_~`])\*{1,2}([^\*\r\n]+)\*{1,2}([<_~`]|\B|\b|$)/gm, '$1<span class="copyonly">*</span><strong>$2</strong><span class="copyonly">*</span>$3') diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index aca6f0d8415c476256b110b0b8d6eadaf7f1a2ac..ef87d1cc43ca7cc8ac0dc3f28496292a220613e1 100644 --- a/packages/rocketchat-markdown/package.js +++ b/packages/rocketchat-markdown/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { api.use('underscore'); api.use('templating'); api.use('underscorestring:underscore.string'); - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.addFiles('settings.coffee', 'server'); api.addFiles('markdown.coffee'); diff --git a/packages/rocketchat-me/package.js b/packages/rocketchat-me/package.js index c23a5d916f9c0a5292eca31bcf4c7a7dea5913bf..a123d4e98edf8109527e6a1758c65fd43450ab66 100644 --- a/packages/rocketchat-me/package.js +++ b/packages/rocketchat-me/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('me.coffee', ['server','client']); diff --git a/packages/rocketchat-mentions-flextab/client/actionButton.coffee b/packages/rocketchat-mentions-flextab/client/actionButton.coffee new file mode 100644 index 0000000000000000000000000000000000000000..6d18189d7cad96342e7dcc2ac50eda254532c261 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/actionButton.coffee @@ -0,0 +1,14 @@ +Meteor.startup -> + RocketChat.MessageAction.addButton + id: 'jump-to-message' + icon: 'icon-right-hand' + i18nLabel: 'Jump_to_message' + action: (event, instance) -> + message = @_arguments[1] + $('.message-dropdown:visible').hide() + RoomHistoryManager.getSurroundingMessages(message, 50) + + validation: (message) -> + return message.mentionedList is true + + order: 100 diff --git a/packages/rocketchat-mentions-flextab/client/lib/MentionedMessage.coffee b/packages/rocketchat-mentions-flextab/client/lib/MentionedMessage.coffee new file mode 100644 index 0000000000000000000000000000000000000000..26dc11807b8c297ccc9e93363caf2898e8edd4a8 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/lib/MentionedMessage.coffee @@ -0,0 +1 @@ +@MentionedMessage = new Meteor.Collection 'rocketchat_mentioned_message' diff --git a/packages/rocketchat-mentions-flextab/client/tabBar.coffee b/packages/rocketchat-mentions-flextab/client/tabBar.coffee new file mode 100644 index 0000000000000000000000000000000000000000..93da941b2ec168aca05d00ff748ac3c23a87b555 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/tabBar.coffee @@ -0,0 +1,9 @@ +Meteor.startup -> + RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup'], + id: 'mentions', + i18nTitle: 'Mentions', + icon: 'icon-at', + template: 'mentionsFlexTab', + order: 3 + }) diff --git a/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee new file mode 100644 index 0000000000000000000000000000000000000000..9d693cf3e5a031cb316700e6df367e4b50d2a6dd --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee @@ -0,0 +1,40 @@ +Template.mentionsFlexTab.helpers + hasMessages: -> + return MentionedMessage.find({ rid: @rid }, { sort: { ts: -1 } }).count() > 0 + + messages: -> + return MentionedMessage.find { rid: @rid }, { sort: { ts: -1 } } + + notReadySubscription: -> + return 'notready' unless Template.instance().subscriptionsReady() + + hasMore: -> + return Template.instance().hasMore.get() + +Template.mentionsFlexTab.onCreated -> + @hasMore = new ReactiveVar true + @limit = new ReactiveVar 50 + @autorun => + sub = @subscribe 'mentionedMessages', @data.rid, @limit.get() + if sub.ready() + if MentionedMessage.find({ rid: @data.rid }).count() < @limit.get() + @hasMore.set false + +Template.mentionsFlexTab.events + 'click .message-cog': (e) -> + e.stopPropagation() + e.preventDefault() + message_id = $(e.currentTarget).closest('.message').attr('id') + $('.message-dropdown:visible').hide() + $(".mentioned-messages-list \##{message_id} .message-dropdown").remove() + message = MentionedMessage.findOne message_id + actions = RocketChat.MessageAction.getButtons message + el = Blaze.toHTMLWithData Template.messageDropdown, { actions: actions } + $(".mentioned-messages-list \##{message_id} .message-cog-container").append el + dropDown = $(".mentioned-messages-list \##{message_id} .message-dropdown") + dropDown.show() + + 'scroll .content': _.throttle (e, instance) -> + if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + instance.limit.set(instance.limit.get() + 50) + , 200 diff --git a/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html new file mode 100644 index 0000000000000000000000000000000000000000..8675f5c251b5cd0ff590e10e0142217b830de9f5 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html @@ -0,0 +1,28 @@ +<template name="mentionsFlexTab"> + <div class="content"> + <div class="list-view mentioned-messages-list"> + <div class="status"> + <h2>{{_ "Mentions"}}</h2> + </div> + <ul class="mentioned-messages-list list clearfix"> + {{#each messages}} + {{#nrr nrrargs 'message' .}}{{/nrr}} + {{/each}} + {{#if hasMore}} + <li class="load-more"> + {{#if Template.subscriptionsReady}} + <a href="">{{_ "Has_more"}}...</a> + {{else}} + <div class="load-more-loading">{{_ "Loading..."}}</div> + {{/if}} + </li> + {{/if}} + </ul> + {{#if Template.subscriptionsReady}} + {{#unless hasMessages}} + <h2>{{_ "No_mentions_found"}}</h2> + {{/unless}} + {{/if}} + </div> + </div> +</template> diff --git a/packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less b/packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less new file mode 100644 index 0000000000000000000000000000000000000000..a8956d799c8e2d5580d59a4fb00180be1cd13fd9 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less @@ -0,0 +1,46 @@ +.mentioned-messages-list { + &.notready { + background-image: url(/images/logo/loading.gif); + background-repeat: no-repeat; + background-position: 50% 50%; + height: 100px; + + .message { + display: none; + } + } + + li.empty { + color: #7f7f7f; + text-align: center; + margin-top: 60px; + } + + .mention-link.mention-link-me { + background-color: transparent; + color: inherit; + &:hover { + color: inherit; + } + } + + .message-cog-container { + .message-action { + display: none !important; + &.jump-to-message { + display: block !important; + } + } + } + + .load-more { + text-transform: lowercase; + text-align: center; + line-height: 40px; + font-style: italic; + + .load-more-loading { + color: #aaa; + } + } +} diff --git a/packages/rocketchat-mentions-flextab/i18n/ar.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ar.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/cs.i18n.json b/packages/rocketchat-mentions-flextab/i18n/cs.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/de.i18n.json b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..cdf69c577fd629171525083f1a6c595be5d2bb02 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "Erwähnungen", + "No_mentions_found" : "Sie wurden bisher nirgendwo erwähnt." +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/el.i18n.json b/packages/rocketchat-mentions-flextab/i18n/el.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/en.i18n.json b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..e876e44ba9822df6a7de1447412f2cbba25b4e7b --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "Mentions", + "No_mentions_found" : "No mentions found" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/es.i18n.json b/packages/rocketchat-mentions-flextab/i18n/es.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/fa.i18n.json b/packages/rocketchat-mentions-flextab/i18n/fa.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/fi.i18n.json b/packages/rocketchat-mentions-flextab/i18n/fi.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..003f29ff22aaa5402520262a089b9ff75154ee7b --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/fi.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "Maininnat", + "No_mentions_found" : "Mainintoja ei löytynyt" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/fr.i18n.json b/packages/rocketchat-mentions-flextab/i18n/fr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..78d945fe3d72f1457cb6c42acb799e9310798945 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/fr.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "Mentions", + "No_mentions_found" : "Aucune mention trouvée" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/he.i18n.json b/packages/rocketchat-mentions-flextab/i18n/he.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..f76342a759c4a82f711dcb5772fe25d08c23bed2 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/he.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "×זכורי×", + "No_mentions_found" : "×œ× × ×ž×¦×ו ×זכורי×" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/hr.i18n.json b/packages/rocketchat-mentions-flextab/i18n/hr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/hu.i18n.json b/packages/rocketchat-mentions-flextab/i18n/hu.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/it.i18n.json b/packages/rocketchat-mentions-flextab/i18n/it.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ja.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ja.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/km.i18n.json b/packages/rocketchat-mentions-flextab/i18n/km.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ko.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ko.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ku.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ku.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/lo.i18n.json b/packages/rocketchat-mentions-flextab/i18n/lo.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ms-MY.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ms-MY.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/nl.i18n.json b/packages/rocketchat-mentions-flextab/i18n/nl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..52e805767b306df055b5d7b5df3b2acbcc97b943 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/nl.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "Vermeldingen", + "No_mentions_found" : "Geen vermeldingen gevonden" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json b/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..4668ec4afa75b1d65c342cd02502007702fdf15f --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "Wzmianki o tobie", + "No_mentions_found" : "Nie znaleziono wzmianek o tobie" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/pt.i18n.json b/packages/rocketchat-mentions-flextab/i18n/pt.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ro.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..1e3a994651563e044cc9c58a897ac05a8049eb39 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ro.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "MenÈ›iuni", + "No_mentions_found" : "Nicio menÈ›iune găsită" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ru.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ru.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..1a95e01b2d59ed40e06820f12e731ae1e697647e --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ru.i18n.json @@ -0,0 +1,4 @@ +{ + "Mentions" : "УпоминаниÑ", + "No_mentions_found" : "Ð£Ð¿Ð¾Ð¼Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½Ðµ найдены" +} \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/sq.i18n.json b/packages/rocketchat-mentions-flextab/i18n/sq.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/sr.i18n.json b/packages/rocketchat-mentions-flextab/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/sv.i18n.json b/packages/rocketchat-mentions-flextab/i18n/sv.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ta-IN.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ta-IN.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/tr.i18n.json b/packages/rocketchat-mentions-flextab/i18n/tr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/ug.i18n.json b/packages/rocketchat-mentions-flextab/i18n/ug.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/uk.i18n.json b/packages/rocketchat-mentions-flextab/i18n/uk.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mentions-flextab/i18n/zh.i18n.json b/packages/rocketchat-mentions-flextab/i18n/zh.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-authorization/server/publications/integrations.coffee b/packages/rocketchat-mentions-flextab/package-tap.i18n similarity index 100% rename from packages/rocketchat-authorization/server/publications/integrations.coffee rename to packages/rocketchat-mentions-flextab/package-tap.i18n diff --git a/packages/rocketchat-mentions-flextab/package.js b/packages/rocketchat-mentions-flextab/package.js new file mode 100644 index 0000000000000000000000000000000000000000..320ff8098d1b48ace45bab0a45363802097c3384 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/package.js @@ -0,0 +1,46 @@ +Package.describe({ + name: 'rocketchat:mentions-flextab', + version: '0.0.1', + summary: 'Mentions Flextab', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'underscore', + 'less@2.5.0', + 'rocketchat:lib' + ]); + + api.addFiles([ + 'client/lib/MentionedMessage.coffee', + 'client/views/stylesheets/mentionsFlexTab.less', + 'client/views/mentionsFlexTab.html', + 'client/views/mentionsFlexTab.coffee', + 'client/actionButton.coffee', + 'client/tabBar.coffee' + ], 'client'); + + api.addFiles([ + 'server/publications/mentionedMessages.coffee' + ], 'server'); + + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-mentions-flextab/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-mentions-flextab/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee new file mode 100644 index 0000000000000000000000000000000000000000..72a557e2df8547cc83ad88e5db2f1d8ed441f68e --- /dev/null +++ b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee @@ -0,0 +1,25 @@ +Meteor.publish 'mentionedMessages', (rid, limit=50) -> + unless this.userId + return this.ready() + + publication = @ + + user = RocketChat.models.Users.findOneById this.userId + unless user + return this.ready() + + cursorHandle = RocketChat.models.Messages.findVisibleByMentionAndRoomId(user.username, rid, { sort: { ts: -1 }, limit: limit }).observeChanges + added: (_id, record) -> + record.mentionedList = true + publication.added('rocketchat_mentioned_message', _id, record) + + changed: (_id, record) -> + record.mentionedList = true + publication.changed('rocketchat_mentioned_message', _id, record) + + removed: (_id) -> + publication.removed('rocketchat_mentioned_message', _id) + + @ready() + @onStop -> + cursorHandle.stop() diff --git a/packages/rocketchat-mentions/package.js b/packages/rocketchat-mentions/package.js index 51266c3fd9c04c0647801a77022f767c677a4e69..bc10d0e3e7cfb291e130b43714f5655b8b72d4ca 100644 --- a/packages/rocketchat-mentions/package.js +++ b/packages/rocketchat-mentions/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('server.coffee', 'server'); diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee new file mode 100644 index 0000000000000000000000000000000000000000..4bfee816da8991bdb5e53a9309833c739ed1bd16 --- /dev/null +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -0,0 +1,30 @@ +Template.messageAttachment.helpers + fixCordova: (url) -> + if Meteor.isCordova and url?[0] is '/' + url = Meteor.absoluteUrl().replace(/\/$/, '') + url + query = "rc_uid=#{Meteor.userId()}&rc_token=#{Meteor._localStorage.getItem('Meteor.loginToken')}" + if url.indexOf('?') is -1 + url = url + '?' + query + else + url = url + '&' + query + + return url + + showImage: -> + if Meteor.user()?.settings?.preferences?.autoImageLoad is false and this.downloadImages? is not true + return false + + if Meteor.Device.isPhone() and Meteor.user()?.settings?.preferences?.saveMobileBandwidth and this.downloadImages? is not true + return false + + return true + + getImageHeight: (height) -> + return height or 200 + + color: -> + switch @color + when 'good' then return '#35AC19' + when 'warning' then return '#FCB316' + when 'danger' then return '#D30230' + else return @color diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 7429edaedb10a11373d7c7c7189eb70364a8c409..06fc30ea37ce3f34a7c5ee23c92d8579a9d87e51 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -9,14 +9,14 @@ {{#if author_link}} <div class="attachment-author"> {{#if author_icon}} - <img src="{{author_icon}}"> + <img src="{{fixCordova author_icon}}"> {{/if}} - <a href="{{author_link}}" target="_blank">{{author_name}}</a> + <a href="{{fixCordova author_link}}" target="_blank">{{author_name}}</a> </div> {{else}} <div class="attachment-author"> {{#if author_icon}} - <img src="{{author_icon}}"> + <img src="{{fixCordova author_icon}}"> {{/if}} {{author_name}} </div> @@ -25,7 +25,7 @@ {{#if title}} {{#if title_link}} - <div class="attachment-title"><a href="{{title_link}}" target="_blank">{{title}}</a></div> + <div class="attachment-title"><a href="{{fixCordova title_link}}" target="_blank">{{title}}</a></div> {{else}} <div class="attachment-title">{{title}}</div> {{/if}} @@ -34,7 +34,7 @@ <div class="attachment-flex"> {{#if thumb_url}} <div class="attachment-thumb"> - <img src="{{thumb_url}}"> + <img src="{{fixCordova thumb_url}}"> </div> {{/if}} @@ -47,11 +47,36 @@ {{#if image_url}} <div class="attachment-image"> - <a href="{{image_url}}" class="swipebox" target="_blank"> - <div class="inline-image" style="background-image: url({{image_url}});"> - <img src="{{image_url}}"> + {{#if showImage}} + <a href="{{fixCordova image_url}}" class="swipebox" target="_blank"> + <div class="inline-image" style="background-image: url('{{fixCordova image_url}}');"> + <img src="{{fixCordova image_url}}" height="{{getImageHeight image_dimensions.height}}"> + </div> + </a> + {{else}} + <div class="image-to-download" data-url="{{image_url}}"> + <i class="icon-picture"></i> + <div>click to load</div> </div> - </a> + {{/if}} + </div> + {{/if}} + + {{#if audio_url}} + <div class="attachment-audio"> + <audio controls> + <source src="{{fixCordova audio_url}}" type="{{audio_type}}"> + Your browser does not support the audio element. + </audio> + </div> + {{/if}} + + {{#if video_url}} + <div class="attachment-video"> + <video controls class="inline-video"> + <source src="{{fixCordova video_url}}" type="{{video_type}}"> + Your browser does not support the video element. + </video> </div> {{/if}} diff --git a/packages/rocketchat-message-attachments/package.js b/packages/rocketchat-message-attachments/package.js index 928f83ea8dcb924f2c566a8319a1fceca813f858..9c9945e868af9a42f5f8cbd70cde281fee4a0b4f 100644 --- a/packages/rocketchat-message-attachments/package.js +++ b/packages/rocketchat-message-attachments/package.js @@ -12,10 +12,11 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client/messageAttachment.html', 'client'); + api.addFiles('client/messageAttachment.coffee', 'client'); // stylesheets api.addAssets('client/stylesheets/messageAttachments.less', 'server'); diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index 78527e098fdc338816d1bede7debb54ab9221a44..14f0129ceb8067cafbdd0c9aa5646f961deb29e0 100644 --- a/packages/rocketchat-message-pin/client/actionButton.coffee +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -21,7 +21,7 @@ Meteor.startup -> RocketChat.MessageAction.addButton id: 'unpin-message' - icon: 'icon-pin' + icon: 'icon-pin rotate-45' i18nLabel: 'Unpin_Message' action: (event, instance) -> message = @_arguments[1] @@ -38,3 +38,14 @@ Meteor.startup -> return ChatRoom.findOne(message.rid).u?._id is Meteor.userId() order: 21 + + RocketChat.MessageAction.addButton + id: 'jump-to-pin-message' + icon: 'icon-right-hand' + i18nLabel: 'Jump_to_message' + action: (event, instance) -> + message = @_arguments[1] + $('.message-dropdown:visible').hide() + RoomHistoryManager.getSurroundingMessages(message, 50) + order: 100 + diff --git a/packages/rocketchat-message-pin/client/pinMessage.coffee b/packages/rocketchat-message-pin/client/pinMessage.coffee new file mode 100644 index 0000000000000000000000000000000000000000..7b934880ac43f8fbe8213f7bd48a9c86ad8a745c --- /dev/null +++ b/packages/rocketchat-message-pin/client/pinMessage.coffee @@ -0,0 +1,26 @@ +Meteor.methods + pinMessage: (message) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] pinMessage -> Invalid user") + + if not RocketChat.settings.get 'Message_AllowPinning' + throw new Meteor.Error 'message-pinning-not-allowed', '[methods] pinMessage -> Message pinning not allowed' + + + ChatMessage.update + _id: message._id + , + $set: { pinned: true } + + unpinMessage: (message) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] pinMessage -> Invalid user") + + if not RocketChat.settings.get 'Message_AllowPinning' + throw new Meteor.Error 'message-pinning-not-allowed', '[methods] pinMessage -> Message pinning not allowed' + + + ChatMessage.update + _id: message._id + , + $set: { pinned: false } diff --git a/packages/rocketchat-message-pin/client/tabBar.coffee b/packages/rocketchat-message-pin/client/tabBar.coffee index f4b8d24a66b68211b85dc870ecaca04247dfef90..f434a26bf6edea1d32f92939130342fc2c1ee7e5 100644 --- a/packages/rocketchat-message-pin/client/tabBar.coffee +++ b/packages/rocketchat-message-pin/client/tabBar.coffee @@ -1,5 +1,13 @@ Meteor.startup -> - RocketChat.callbacks.add 'enter-room', -> + Tracker.autorun -> if RocketChat.settings.get 'Message_AllowPinning' - RocketChat.TabBar.addButton({ id: 'pinned-messages', i18nTitle: 'Pinned_Messages', icon: 'icon-pin', template: 'pinnedMessages', order: 10 }) - , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-pin' + RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'pinned-messages', + i18nTitle: 'Pinned_Messages', + icon: 'icon-pin', + template: 'pinnedMessages', + order: 10 + }) + else + RocketChat.TabBar.removeButton 'pinned-messages' diff --git a/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee index c60783c49ef7a7985d2bf5e0f0502e66a2b0544c..ba6df0cada88cff05c31a0f7286761df523761f2 100644 --- a/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee +++ b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee @@ -1,16 +1,24 @@ Template.pinnedMessages.helpers hasMessages: -> - return PinnedMessage.find({ rid: this.rid }, { sort: { ts: -1 } }).count() > 0 + return PinnedMessage.find({ rid: @rid }, { sort: { ts: -1 } }).count() > 0 messages: -> - return PinnedMessage.find { rid: this.rid }, { sort: { ts: -1 } } + return PinnedMessage.find { rid: @rid }, { sort: { ts: -1 } } - notReadySubscription: -> - return 'notready' unless Template.instance().subscriptionsReady() + hasMore: -> + return Template.instance().hasMore.get() Template.pinnedMessages.onCreated -> - this.autorun => - this.subscribe 'pinnedMessages', Template.currentData().rid + @hasMore = new ReactiveVar true + @limit = new ReactiveVar 50 + @autorun => + sub = @subscribe 'pinnedMessages', @data.rid, @limit.get() + if sub.ready() + if PinnedMessage.find({ rid: @data.rid }).count() < @limit.get() + @hasMore.set false + + @autorun => + @subscribe 'pinnedMessages', Template.currentData().rid Template.pinnedMessages.events 'click .message-cog': (e) -> @@ -18,4 +26,15 @@ Template.pinnedMessages.events e.preventDefault() message_id = $(e.currentTarget).closest('.message').attr('id') $('.message-dropdown:visible').hide() - $(".pinned-messages-list \##{message_id} .message-dropdown").show() + $(".pinned-messages-list \##{message_id} .message-dropdown").remove() + message = PinnedMessage.findOne message_id + actions = RocketChat.MessageAction.getButtons message + el = Blaze.toHTMLWithData Template.messageDropdown, { actions: actions } + $(".pinned-messages-list \##{message_id} .message-cog-container").append el + dropDown = $(".pinned-messages-list \##{message_id} .message-dropdown") + dropDown.show() + + 'scroll .content': _.throttle (e, instance) -> + if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + instance.limit.set(instance.limit.get() + 50) + , 200 diff --git a/packages/rocketchat-message-pin/client/views/pinnedMessages.html b/packages/rocketchat-message-pin/client/views/pinnedMessages.html index d1c470c7f41cfe8820a6e9e3a8df161a2dae65a7..8122f0c580b011a32a2df021e4ba7932673e5d4f 100644 --- a/packages/rocketchat-message-pin/client/views/pinnedMessages.html +++ b/packages/rocketchat-message-pin/client/views/pinnedMessages.html @@ -1,22 +1,28 @@ <template name="pinnedMessages"> - <div class="control"> - <div class="header"> - <h2>{{_ "Pinned_Messages"}}</h2> + <div class="content"> + <div class="list-view pinned-messages-list"> + <div class="status"> + <h2>{{_ "Pinned_Messages"}}</h2> + </div> + <ul class="list clearfix"> + {{#each messages}} + {{#nrr nrrargs 'message' .}}{{/nrr}} + {{/each}} + {{#if hasMore}} + <li class="load-more"> + {{#if Template.subscriptionsReady}} + <a href="">{{_ "Has_more"}}...</a> + {{else}} + <div class="load-more-loading">{{_ "Loading..."}}</div> + {{/if}} + </li> + {{/if}} + </ul> + {{#if Template.subscriptionsReady}} + {{#unless hasMessages}} + <h2>{{_ "No_pinned_messages"}}</h2> + {{/unless}} + {{/if}} </div> </div> - <ul class="pinned-messages-list scrollable"> - {{#if Template.subscriptionsReady}} - {{#if hasMessages}} - {{#each messages}} - {{#nrr nrrargs 'message' .}}{{/nrr}} - {{/each}} - {{else}} - <li class="empty"> - {{_ "No_pinned_messages"}} - </li> - {{/if}} - {{else}} - {{> loading}} - {{/if}} - </ul> </template> diff --git a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less index de3c15683ba13efdebdd51c390e7cb22505cdb50..94248d67b99a3248b177fa71e7f5f4328e7e1a9f 100644 --- a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less +++ b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less @@ -1,17 +1,20 @@ -.pinned-messages-list { - padding: 30px 0; - - &.notready { - background-image: url(/images/logo/loading.gif); - background-repeat: no-repeat; - background-position: 50% 50%; - height: 100px; +.icon-pin.rotate-45:before { + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} - .message { - display: none; +.messages-box { + .message-cog-container { + .message-action { + &.jump-to-pin-message { + display: none !important; + } } } +} +.pinned-messages-list { li.empty { color: #7f7f7f; text-align: center; @@ -19,8 +22,22 @@ } .message-cog-container { - .edit-message, .delete-message, .star-message, .unstar-message { + .message-action { display: none !important; + &.pin-message, &.unpin-message, &.jump-to-pin-message { + display: block !important; + } + } + } + + .load-more { + text-transform: lowercase; + text-align: center; + line-height: 40px; + font-style: italic; + + .load-more-loading { + color: #aaa; } } } diff --git a/packages/rocketchat-message-pin/i18n/ar.i18n.json b/packages/rocketchat-message-pin/i18n/ar.i18n.json index ab3b6e37c0846ca70eaad727b45556fc7bba1bba..3a3ddcfed5462aed1b7f66405c458ecb108155d6 100644 --- a/packages/rocketchat-message-pin/i18n/ar.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ar.i18n.json @@ -1,4 +1,7 @@ { + "Message_AllowPinning" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ«Ø¨ÙŠØ« الرسائل", + "Pin_Message" : "تثبيث الرسالة", + "Unpin_Message" : "إلغاء تثبيث الرسالة", "Pinned_Messages" : "رسائل مثبتة", "No_pinned_messages" : "لا توجد رسائل مثبتة" } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/de.i18n.json b/packages/rocketchat-message-pin/i18n/de.i18n.json index b8e3131562d0148aa479c3693495c909a673af0e..1f6aa825c53be2e6897a984cdeb055ef9760ea71 100644 --- a/packages/rocketchat-message-pin/i18n/de.i18n.json +++ b/packages/rocketchat-message-pin/i18n/de.i18n.json @@ -1,3 +1,10 @@ { - "Message_AllowPinning" : "Erlaube es Nachrichten anzuheften" + "Message_AllowPinning" : "Das Fixieren von Nachrichten erlauben", + "Message_AllowPinning_Description" : "Benutzern das Fixieren von Nachrichten in Kanälen erlauben", + "Message_AllowPinningByAnyone" : "Jedem Nutzer erlauben, Nachrichten zu fixieren", + "Message_AllowPinningByAnyone_Description" : "Allen Benutzern das Fixieren von Nachrichten in Kanälen erlauben", + "Pin_Message" : "Nachricht fixieren", + "Unpin_Message" : "Nachicht nicht mehr fixieren", + "Pinned_Messages" : "Fixierte Nachrichten", + "No_pinned_messages" : "Es wurden bisher keine Nachrichten fixiert." } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/fr.i18n.json b/packages/rocketchat-message-pin/i18n/fr.i18n.json index 19f10ea3b8aed970de214ba28f85219e3a133293..1b4a150a1f2b0c2994a63ae6ae1822b34429d53d 100644 --- a/packages/rocketchat-message-pin/i18n/fr.i18n.json +++ b/packages/rocketchat-message-pin/i18n/fr.i18n.json @@ -1,3 +1,10 @@ { - "Message_AllowPinning" : "Autoriser l'épinglement de messages" + "Message_AllowPinning" : "Autoriser l'épinglement de messages", + "Message_AllowPinning_Description" : "Autoriser les messages à être épinglés à tous des canaux.", + "Message_AllowPinningByAnyone" : "Permettre à quiconque d'épingler des messages", + "Message_AllowPinningByAnyone_Description" : "Permettre à quiconque d'épingler des messages, pas seulement les administrateurs.", + "Pin_Message" : "Épingler ce message", + "Unpin_Message" : "Détacher ce message", + "Pinned_Messages" : "Messages épinglés", + "No_pinned_messages" : "Aucun message épinglé" } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/he.i18n.json b/packages/rocketchat-message-pin/i18n/he.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..8523fea7c8df9324431fe6778f314acf5fde46e9 100644 --- a/packages/rocketchat-message-pin/i18n/he.i18n.json +++ b/packages/rocketchat-message-pin/i18n/he.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Pin_Message" : "הצמדת הודעה", + "Unpin_Message" : "שחרור הודעה", + "Pinned_Messages" : "הודעות מוצמדות", + "No_pinned_messages" : "×ין הודעות מוצמדות" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/km.i18n.json b/packages/rocketchat-message-pin/i18n/km.i18n.json index 4b0abbe97422cfbe12fc6da0329fce4ba5e09a11..a61185894bc25b7438d261109666520c2a55b51a 100644 --- a/packages/rocketchat-message-pin/i18n/km.i18n.json +++ b/packages/rocketchat-message-pin/i18n/km.i18n.json @@ -1,3 +1,9 @@ { - "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​" + "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​", + "Message_AllowPinning_Description" : "អនុញ្ញាážáž±áŸ’យសារážáŸ’រូវបានážáŸ’ទាស់ទៅច្រើនប៉ុស្ážáž·áŸáŸ”", + "Message_AllowPinningByAnyone" : "អនុញ្ញាážáž±áŸ’យគ្រាប់គ្នាážáŸ’ទាស់សារ", + "Message_AllowPinningByAnyone_Description" : "អនុញ្ញាážáž·áž²áŸ’យគ្រប់គ្នាអាចážáŸ’ទាស់សារទៅកាន់ប៉ុស្ážáž·áŸážŽáž¶áž˜áž½áž™ ដោយមិនចាំបាច់សិទ្ធជាអ្នកគ្រប់គ្រង។", + "Pin_Message" : "ážáŸ’ទាស់សារ", + "Pinned_Messages" : "មិនážáŸ’ទាស់សារ", + "No_pinned_messages" : "មិនមានសារបានážáŸ’ទាស់" } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ko.i18n.json b/packages/rocketchat-message-pin/i18n/ko.i18n.json index 4feeebeb4f06b5295d1b0bae16e8c5c7c4c239c0..fbd8a50499a8cbff4f9400fc4bc825bb1aef53b9 100644 --- a/packages/rocketchat-message-pin/i18n/ko.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ko.i18n.json @@ -1,5 +1,6 @@ { "Message_AllowPinning" : "허용 메시지 ê³ ì •", + "Message_AllowPinningByAnyone" : "누구나 메시지를 ë³´ê´€í• ìˆ˜ 있ë„ë¡ í—ˆìš©", "Pin_Message" : "메시지 보관하기", "Unpin_Message" : "메시지 보관하지 않기", "Pinned_Messages" : "ë³´ê´€ëœ ë©”ì‹œì§€", diff --git a/packages/rocketchat-message-pin/i18n/nl.i18n.json b/packages/rocketchat-message-pin/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..721e551b3217d9f658b247958726cab59b1091bb 100644 --- a/packages/rocketchat-message-pin/i18n/nl.i18n.json +++ b/packages/rocketchat-message-pin/i18n/nl.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Bericht vastzetten toestaan" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ro.i18n.json b/packages/rocketchat-message-pin/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..20534d184df0fd50afd6437ecb494fc3a39a9eb2 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ro.i18n.json @@ -0,0 +1,10 @@ +{ + "Message_AllowPinning" : "PermiteÈ›i fixarea mesajului", + "Message_AllowPinning_Description" : "Permite fixarea mesajelor în oricare canal.", + "Message_AllowPinningByAnyone" : "Permite oricui să fixeze mesaje.", + "Message_AllowPinningByAnyone_Description" : "Permite oricui să fixeze mesaje pe un canal, nu doar administratorilor.", + "Pin_Message" : "Fixează mesaj", + "Unpin_Message" : "AnulaÈ›i fixarea mesajului", + "Pinned_Messages" : "Mesaje fixate", + "No_pinned_messages" : "Nu sunt mesaje fixate" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ru.i18n.json b/packages/rocketchat-message-pin/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..a83261331d94ebaa9049dac4c7df7cfcbccf331a 100644 --- a/packages/rocketchat-message-pin/i18n/ru.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ru.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Разрешить прикреплÑÑ‚ÑŒ ÑообщениÑ", + "Message_AllowPinning_Description" : "Разрешить прикреплÑÑ‚ÑŒ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ðº любому из каналов", + "Pinned_Messages" : "Прикрепленные ÑообщениÑ", + "No_pinned_messages" : "Ðет прикрепленных Ñообщений" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/sr.i18n.json b/packages/rocketchat-message-pin/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/package.js b/packages/rocketchat-message-pin/package.js index 69f0358da29e6d86fb1bca4e98226ac0fc2f5c7b..b70908ef0bdce2e313147918eb6795e6d8de53d0 100644 --- a/packages/rocketchat-message-pin/package.js +++ b/packages/rocketchat-message-pin/package.js @@ -9,13 +9,15 @@ Package.onUse(function(api) { api.use([ 'coffeescript', + 'underscore', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ 'client/lib/PinnedMessage.coffee', 'client/actionButton.coffee', + 'client/pinMessage.coffee', 'client/tabBar.coffee', 'client/views/pinnedMessages.html', 'client/views/pinnedMessages.coffee', @@ -38,9 +40,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use(["tap:i18n@1.5.1"], ["client", "server"]); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ["client", "server"]); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-message-pin/server/pinMessage.coffee b/packages/rocketchat-message-pin/server/pinMessage.coffee index 7a62e55f3da45d6934df4dea17ee3c4e21a8c574..01e651611439a7bfb3a8ff389089a0981c2600de 100644 --- a/packages/rocketchat-message-pin/server/pinMessage.coffee +++ b/packages/rocketchat-message-pin/server/pinMessage.coffee @@ -6,8 +6,6 @@ Meteor.methods if not RocketChat.settings.get 'Message_AllowPinning' throw new Meteor.Error 'message-pinning-not-allowed', '[methods] pinMessage -> Message pinning not allowed' - console.log '[methods] pinMessage -> '.green, 'userId:', Meteor.userId() - # If we keep history of edits, insert a new message to store history information if RocketChat.settings.get 'Message_KeepHistory' RocketChat.models.Messages.cloneAndSaveAsHistoryById message._id @@ -31,8 +29,6 @@ Meteor.methods if not RocketChat.settings.get 'Message_AllowPinning' throw new Meteor.Error 'message-pinning-not-allowed', '[methods] pinMessage -> Message pinning not allowed' - console.log '[methods] unpinMessage -> '.green, 'userId:', Meteor.userId() - # If we keep history of edits, insert a new message to store history information if RocketChat.settings.get 'Message_KeepHistory' RocketChat.models.Messages.cloneAndSaveAsHistoryById message._id diff --git a/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee index 7daf7a32bd576bc82e502cff3987260fe1876617..efa77f81456c4f9e9bab4511f9ca6497ef5e414f 100644 --- a/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee +++ b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee @@ -1,12 +1,14 @@ -Meteor.publish 'pinnedMessages', (rid, options = {}) -> +Meteor.publish 'pinnedMessages', (rid, limit=50) -> unless this.userId return this.ready() - console.log '[publish] pinnedMessages -> '.green, 'rid:', rid, 'options:', options - publication = @ - cursorHandle = RocketChat.models.Messages.findPinnedByRoom(rid, { sort: { ts: -1 }, limit: 50 }).observeChanges + user = RocketChat.models.Users.findOneById this.userId + unless user + return this.ready() + + cursorHandle = RocketChat.models.Messages.findPinnedByRoom(rid, { sort: { ts: -1 }, limit: limit }).observeChanges added: (_id, record) -> publication.added('rocketchat_pinned_message', _id, record) diff --git a/packages/rocketchat-message-star/client/actionButton.coffee b/packages/rocketchat-message-star/client/actionButton.coffee index 02d25daf7e74d8b5678fa55f834e41b6262f2a38..42d0f7a017256a14f9f97d03b50db68b7df496c4 100644 --- a/packages/rocketchat-message-star/client/actionButton.coffee +++ b/packages/rocketchat-message-star/client/actionButton.coffee @@ -26,3 +26,13 @@ Meteor.startup -> validation: (message) -> return RocketChat.settings.get('Message_AllowStarring') and message.starred order: 10 + + RocketChat.MessageAction.addButton + id: 'jump-to-star-message' + icon: 'icon-right-hand' + i18nLabel: 'Jump_to_message' + action: (event, instance) -> + message = @_arguments[1] + $('.message-dropdown:visible').hide() + RoomHistoryManager.getSurroundingMessages(message, 50) + order: 100 diff --git a/packages/rocketchat-message-star/client/tabBar.coffee b/packages/rocketchat-message-star/client/tabBar.coffee index b2b2d969d1ad552e440b87acae9f4412cfa3facd..9e34add34ab923157eddb1f29d64762de8dea380 100644 --- a/packages/rocketchat-message-star/client/tabBar.coffee +++ b/packages/rocketchat-message-star/client/tabBar.coffee @@ -1,4 +1,9 @@ Meteor.startup -> - RocketChat.callbacks.add 'enter-room', -> - RocketChat.TabBar.addButton({ id: 'starred-messages', i18nTitle: 'Starred_Messages', icon: 'icon-star', template: 'starredMessages', order: 3 }) - , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-star' + RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'starred-messages', + i18nTitle: 'Starred_Messages', + icon: 'icon-star', + template: 'starredMessages', + order: 3 + }) diff --git a/packages/rocketchat-message-star/client/views/starredMessages.coffee b/packages/rocketchat-message-star/client/views/starredMessages.coffee index 24124e12f4f640d68a5b0950b87af3f1e0ea5ed0..f51eb088a1524a77398c36cca90f48c2745ca756 100644 --- a/packages/rocketchat-message-star/client/views/starredMessages.coffee +++ b/packages/rocketchat-message-star/client/views/starredMessages.coffee @@ -1,16 +1,21 @@ Template.starredMessages.helpers hasMessages: -> - return StarredMessage.find({ rid: this.rid }, { sort: { ts: -1 } }).count() > 0 + return StarredMessage.find({ rid: @rid }, { sort: { ts: -1 } }).count() > 0 messages: -> - return StarredMessage.find { rid: this.rid }, { sort: { ts: -1 } } + return StarredMessage.find { rid: @rid }, { sort: { ts: -1 } } - notReadySubscription: -> - return 'notready' unless Template.instance().subscriptionsReady() + hasMore: -> + return Template.instance().hasMore.get() Template.starredMessages.onCreated -> - this.autorun => - this.subscribe 'starredMessages', Template.currentData().rid + @hasMore = new ReactiveVar true + @limit = new ReactiveVar 50 + @autorun => + sub = @subscribe 'starredMessages', @data.rid, @limit.get() + if sub.ready() + if StarredMessage.find({ rid: @data.rid }).count() < @limit.get() + @hasMore.set false Template.starredMessages.events 'click .message-cog': (e) -> @@ -18,4 +23,15 @@ Template.starredMessages.events e.preventDefault() message_id = $(e.currentTarget).closest('.message').attr('id') $('.message-dropdown:visible').hide() - $(".starred-messages-list \##{message_id} .message-dropdown").show() + $(".starred-messages-list \##{message_id} .message-dropdown").remove() + message = StarredMessage.findOne message_id + actions = RocketChat.MessageAction.getButtons message + el = Blaze.toHTMLWithData Template.messageDropdown, { actions: actions } + $(".starred-messages-list \##{message_id} .message-cog-container").append el + dropDown = $(".starred-messages-list \##{message_id} .message-dropdown") + dropDown.show() + + 'scroll .content': _.throttle (e, instance) -> + if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + instance.limit.set(instance.limit.get() + 50) + , 200 diff --git a/packages/rocketchat-message-star/client/views/starredMessages.html b/packages/rocketchat-message-star/client/views/starredMessages.html index 38724f43a20e534bdafec0adc9c9cc350bc977e2..b1bdc184762adaa40e72b54478a95cc45ec39f5b 100644 --- a/packages/rocketchat-message-star/client/views/starredMessages.html +++ b/packages/rocketchat-message-star/client/views/starredMessages.html @@ -1,22 +1,28 @@ <template name="starredMessages"> - <div class="control"> - <div class="header"> - <h2>{{_ "Starred_Messages"}}</h2> + <div class="content"> + <div class="list-view starred-messages-list"> + <div class="status"> + <h2>{{_ "Starred_Messages"}}</h2> + </div> + <ul class="list clearfix"> + {{#each messages}} + {{#nrr nrrargs 'message' .}}{{/nrr}} + {{/each}} + {{#if hasMore}} + <li class="load-more"> + {{#if Template.subscriptionsReady}} + <a href="">{{_ "Has_more"}}...</a> + {{else}} + <div class="load-more-loading">{{_ "Loading..."}}</div> + {{/if}} + </li> + {{/if}} + </ul> + {{#if Template.subscriptionsReady}} + {{#unless hasMessages}} + <h2>{{_ "No_starred_messages"}}</h2> + {{/unless}} + {{/if}} </div> </div> - <ul class="starred-messages-list scrollable"> - {{#if Template.subscriptionsReady}} - {{#if hasMessages}} - {{#each messages}} - {{#nrr nrrargs 'message' .}}{{/nrr}} - {{/each}} - {{else}} - <li class="empty"> - {{_ "No_starred_messages"}} - </li> - {{/if}} - {{else}} - {{> loading}} - {{/if}} - </ul> </template> diff --git a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less index b31cb69553af5fbcaafa34da94d6d0d9dbd47820..83e74cbb29b467e4b3b4e5c753cf1bef777973e4 100644 --- a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less +++ b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less @@ -1,17 +1,14 @@ -.starred-messages-list { - padding: 30px 0; - - &.notready { - background-image: url(/images/logo/loading.gif); - background-repeat: no-repeat; - background-position: 50% 50%; - height: 100px; - - .message { - display: none; +.messages-box { + .message-cog-container { + .message-action { + &.jump-to-star-message { + display: none !important; + } } } +} +.starred-messages-list { li.empty { color: #7f7f7f; text-align: center; @@ -19,8 +16,22 @@ } .message-cog-container { - .edit-message, .delete-message, .pin-message, .unpin-message { + .message-action { display: none !important; + &.star-message, &.unstar-message, &.jump-to-star-message { + display: block !important; + } + } + } + + .load-more { + text-transform: lowercase; + text-align: center; + line-height: 40px; + font-style: italic; + + .load-more-loading { + color: #aaa; } } } diff --git a/packages/rocketchat-message-star/i18n/de.i18n.json b/packages/rocketchat-message-star/i18n/de.i18n.json index bb056d4d81b846e4ba8a2c637e2a81bb7523231a..e7a604c007692baa15e70375cab22f6b805344d3 100644 --- a/packages/rocketchat-message-star/i18n/de.i18n.json +++ b/packages/rocketchat-message-star/i18n/de.i18n.json @@ -1,7 +1,7 @@ { - "Message_AllowStarring" : "Erlaube Nachricht mit einem Stern zu makieren", - "Star_Message" : "Stern-Nachrichten", - "Unstar_Message" : "Stern entfernen", - "Starred_Messages" : "Nachrichten mit Stern", - "No_starred_messages" : "Keine Nachrichten mit einem Stern" + "Message_AllowStarring" : "Erlaube es, Nachrichten zu markieren", + "Star_Message" : "Nachricht markieren", + "Unstar_Message" : "Markierung entfernen", + "Starred_Messages" : "Markierte Nachrichten", + "No_starred_messages" : "Es wurden bisher keine Nachrichten markiert." } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/hr.i18n.json b/packages/rocketchat-message-star/i18n/hr.i18n.json index f57e88dc1e86b7b8cae22bb35abecc47ee0579b6..3a488fb06895cca9df3b6221dab4ce80736b2c41 100644 --- a/packages/rocketchat-message-star/i18n/hr.i18n.json +++ b/packages/rocketchat-message-star/i18n/hr.i18n.json @@ -1,4 +1,5 @@ { "Unstar_Message" : "Ukloni zvjezdicu", - "Starred_Messages" : "Poruke sa zvjezdicom" + "Starred_Messages" : "Poruke sa zvjezdicom", + "No_starred_messages" : "Nema poruka sa zvjezdicom" } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ko.i18n.json b/packages/rocketchat-message-star/i18n/ko.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..ab22552dc73bf8ab93033ec72c7c1509b8bda6f2 100644 --- a/packages/rocketchat-message-star/i18n/ko.i18n.json +++ b/packages/rocketchat-message-star/i18n/ko.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Message_AllowStarring" : "메시지 별표 허용", + "Star_Message" : "별표 메시지", + "Unstar_Message" : "별표 ì‚ì œ", + "Starred_Messages" : "ë³„í‘œëœ ë©”ì‹œì§€", + "No_starred_messages" : "ë³„í‘œëœ ë©”ì‹œì§€ê°€ 없습니다" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ro.i18n.json b/packages/rocketchat-message-star/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..a4e057d9f1da6e13751e5fdd8f5c5970ca457434 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ro.i18n.json @@ -0,0 +1,7 @@ +{ + "Message_AllowStarring" : "PermiteÈ›i însemnarea cu steluță a mesajelor", + "Star_Message" : "Marchează cu stea mesajul", + "Unstar_Message" : "EliminaÈ›i marcajul cu stea", + "Starred_Messages" : "Mesaje cu stea", + "No_starred_messages" : "Niciun mesaj cu stea" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ru.i18n.json b/packages/rocketchat-message-star/i18n/ru.i18n.json index 24843cb079a2e507a458e6560294c7723539d789..a34c4a5791a81c4f805fa38c4bd70b27ab5b51d2 100644 --- a/packages/rocketchat-message-star/i18n/ru.i18n.json +++ b/packages/rocketchat-message-star/i18n/ru.i18n.json @@ -1,4 +1,5 @@ { + "Message_AllowStarring" : "Разрешить отмечать ÑообщениÑ", "Star_Message" : "Оценить Ñообщение", "Unstar_Message" : "Убрать оценку", "Starred_Messages" : "Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ Ð¾Ñ†ÐµÐ½ÐºÐ¾Ð¹", diff --git a/packages/rocketchat-message-star/i18n/sr.i18n.json b/packages/rocketchat-message-star/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/package.js b/packages/rocketchat-message-star/package.js index 6073d2bad8199a610b5c4ba23d52a4de38022e8b..a05a6a1767a6dac0257315839720ebaa7efcfa74 100644 --- a/packages/rocketchat-message-star/package.js +++ b/packages/rocketchat-message-star/package.js @@ -10,8 +10,9 @@ Package.onUse(function(api) { api.use([ 'coffeescript', + 'underscore', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ @@ -40,9 +41,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use(["tap:i18n@1.5.1"], ["client", "server"]); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ["client", "server"]); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-message-star/server/publications/starredMessages.coffee b/packages/rocketchat-message-star/server/publications/starredMessages.coffee index badaa2b3bddb105cbc90bf1f8fe6e5ef94e9eb48..51d664d7653035ed39bf3d9dcee23267e501e0a5 100644 --- a/packages/rocketchat-message-star/server/publications/starredMessages.coffee +++ b/packages/rocketchat-message-star/server/publications/starredMessages.coffee @@ -1,12 +1,14 @@ -Meteor.publish 'starredMessages', (rid, options = {}) -> +Meteor.publish 'starredMessages', (rid, limit=50) -> unless this.userId return this.ready() - console.log '[publish] starredMessages -> '.green, 'rid:', rid, 'options:', options - publication = @ - cursorHandle = RocketChat.models.Messages.findStarredByUserAtRoom(this.userId, rid, { sort: { ts: -1 }, limit: 50 }).observeChanges + user = RocketChat.models.Users.findOneById this.userId + unless user + return this.ready() + + cursorHandle = RocketChat.models.Messages.findStarredByUserAtRoom(this.userId, rid, { sort: { ts: -1 }, limit: limit }).observeChanges added: (_id, record) -> publication.added('rocketchat_starred_message', _id, record) diff --git a/packages/rocketchat-message-star/server/starMessage.coffee b/packages/rocketchat-message-star/server/starMessage.coffee index 625f0539f910b0eda1deaab5dc90d93605126f86..6df1a37865afece40a3323aa0c9a906034d33e80 100644 --- a/packages/rocketchat-message-star/server/starMessage.coffee +++ b/packages/rocketchat-message-star/server/starMessage.coffee @@ -6,6 +6,4 @@ Meteor.methods if not RocketChat.settings.get 'Message_AllowStarring' throw new Meteor.Error 'message-starring-not-allowed', "[methods] starMessage -> Message starring not allowed" - console.log '[methods] starMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - RocketChat.models.Messages.updateUserStarById(message._id, Meteor.userId(), message.starred) diff --git a/packages/rocketchat-oauth2-server-config/.gitignore b/packages/rocketchat-oauth2-server-config/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..677a6fc26373dfaddcf7d4b8a52711f7257e1be5 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/.gitignore @@ -0,0 +1 @@ +.build* diff --git a/packages/rocketchat-oauth2-server-config/admin/client/collection.coffee b/packages/rocketchat-oauth2-server-config/admin/client/collection.coffee new file mode 100644 index 0000000000000000000000000000000000000000..4004f7cde99f74da229510eb9a0efb941ed29713 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/collection.coffee @@ -0,0 +1 @@ +@ChatOAuthApps = new Meteor.Collection 'rocketchat_oauth_apps' diff --git a/packages/rocketchat-oauth2-server-config/admin/client/route.coffee b/packages/rocketchat-oauth2-server-config/admin/client/route.coffee new file mode 100644 index 0000000000000000000000000000000000000000..f2fcc3b836596dea446f0a2906346fada821c5df --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/route.coffee @@ -0,0 +1,17 @@ +FlowRouter.route '/admin/oauth-apps', + name: 'admin-oauth-apps' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('OAuth_Applications') + pageTemplate: 'oauthApps' + + +FlowRouter.route '/admin/oauth-app/:id?', + name: 'admin-oauth-app' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('OAuth_Application') + pageTemplate: 'oauthApp' + params: params diff --git a/packages/rocketchat-oauth2-server-config/admin/client/startup.coffee b/packages/rocketchat-oauth2-server-config/admin/client/startup.coffee new file mode 100644 index 0000000000000000000000000000000000000000..1619a366a3dd4c85c3c7417e3c8f7e4bb9e947c1 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/startup.coffee @@ -0,0 +1,7 @@ +Meteor.subscribe 'oauthApps' + +RocketChat.AdminBox.addOption + href: 'admin-oauth-apps' + i18nLabel: 'OAuth Apps' + permissionGranted: -> + return RocketChat.authz.hasAllPermission('manage-oauth-apps') diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee new file mode 100644 index 0000000000000000000000000000000000000000..4ced37677bb6857a9cc90107dde8be905b78d1fc --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee @@ -0,0 +1,79 @@ +Template.oauthApp.onCreated -> + @record = new ReactiveVar + active: true + + +Template.oauthApp.helpers + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-oauth-apps' + + data: -> + params = Template.instance().data.params?() + + if params?.id? + data = ChatOAuthApps.findOne({_id: params.id}) + if data? + data.authorization_url = Meteor.absoluteUrl("oauth/authorize") + data.access_token_url = Meteor.absoluteUrl("oauth/token") + + Template.instance().record.set data + return data + + return Template.instance().record.curValue + + +Template.oauthApp.events + "click .submit > .delete": -> + params = Template.instance().data.params() + + swal + title: t('Are_you_sure') + text: t('You_will_not_be_able_to_recover') + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_delete_it') + cancelButtonText: t('Cancel') + closeOnConfirm: false + html: false + , -> + Meteor.call "deleteOAuthApp", params.id, (err, data) -> + swal + title: t('Deleted') + text: t('Your_entry_has_been_deleted') + type: 'success' + timer: 1000 + showConfirmButton: false + + FlowRouter.go "admin-oauth-apps" + + "click .submit > .save": -> + name = $('[name=name]').val().trim() + active = $('[name=active]:checked').val().trim() is "1" + redirectUri = $('[name=redirectUri]').val().trim() + + if name is '' + return toastr.error TAPi18n.__("The_application_name_is_required") + + if redirectUri is '' + return toastr.error TAPi18n.__("The_redirectUri_is_required") + + app = + name: name + active: active + redirectUri: redirectUri + + params = Template.instance().data.params?() + if params?.id? + Meteor.call "updateOAuthApp", params.id, app, (err, data) -> + if err? + return toastr.error TAPi18n.__(err.error) + + toastr.success TAPi18n.__("Application_updated") + else + Meteor.call "addOAuthApp", app, (err, data) -> + if err? + return toastr.error TAPi18n.__(err.error) + + toastr.success TAPi18n.__("Application_added") + FlowRouter.go "admin-oauth-app", {id: data._id} diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html new file mode 100644 index 0000000000000000000000000000000000000000..d9d722ddd4917d53feaf9ca48f42330c82c2174b --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html @@ -0,0 +1,72 @@ +<template name="oauthApp"> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-oauth-apps"}}"><i class="icon-angle-left"></i> {{_ "Back_to_applications"}}</a><br><br> + <div class="rocket-form"> + <div class="section"> + <div class="section-content"> + <div class="input-line double-col"> + <label>{{_ "Active"}}</label> + <div> + <label><input class="input-monitor" type="radio" name="active" value="1" checked="{{$eq data.active true}}" /> {{_ "True"}}</label> + <label><input class="input-monitor" type="radio" name="active" value="0" checked="{{$eq data.active false}}" /> {{_ "False"}}</label> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Application_Name"}}</label> + <div> + <input type="text" name="name" value="{{data.name}}" /> + <div class="settings-description">{{_ "Give_the_application_a_name_This_will_be_seen_by_your_users"}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Redirect_URI"}}</label> + <div> + <input type="text" name="redirectUri" value="{{data.redirectUri}}" /> + <div class="settings-description">{{_ "After_OAuth2_authentication_users_will_be_redirected_to_this_URL"}}</div> + </div> + </div> + {{#if data.clientId}} + <div class="input-line double-col"> + <label>{{_ "Client_ID"}}</label> + <div> + <input type="text" name="clientId" value="{{data.clientId}}" disabled="disabled" /> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=clientId]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Client_Secret"}}</label> + <div> + <input type="text" name="clientSecret" value="{{data.clientSecret}}" disabled="disabled" /> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=clientSecret]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Authorization_URL"}}</label> + <div> + <input type="text" name="authorization_url" value="{{data.authorization_url}}" disabled="disabled" /> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=authorization_url]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Access_Token_URL"}}</label> + <div> + <input type="text" name="access_token_url" value="{{data.access_token_url}}" disabled="disabled" /> + <div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=access_token_url]">{{_ "COPY_TO_CLIPBOARD"}}</a></div> + </div> + </div> + {{/if}} + </div> + </div> + <div class="submit"> + {{#if data.clientId}} + <button class="button red delete"><i class="icon-trash"></i><span>{{_ "Delete"}}</span></button> + {{/if}} + <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> + </div> + </div> + {{else}} + {{_ "Not_authorized"}} + {{/if}} + </div> +</template> diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.coffee b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.coffee new file mode 100644 index 0000000000000000000000000000000000000000..0dca6796b28d1a74743a4a7c2ee863278698dcbf --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.coffee @@ -0,0 +1,9 @@ +Template.oauthApps.helpers + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-oauth-apps' + + applications: -> + return ChatOAuthApps.find() + + dateFormated: (date) -> + return moment(date).format('L LT') diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.html b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.html new file mode 100644 index 0000000000000000000000000000000000000000..f0dc3df3364aa0a9291c95d78239ad40c1d08d25 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.html @@ -0,0 +1,33 @@ +<template name="oauthApps"> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-oauth-app"}}" class="button primary new-role">{{_ "New_Application"}}</a> + + <div class="rocket-form"> + <div class="section"> + <div class="admin-integrations-new-panel"> + {{#each applications}} + <a href="{{pathFor "admin-oauth-app" id=_id}}"> + <div class="admin-integrations-new-item"> + <div class="admin-integrations-new-item-body"> + <div class="admin-integrations-new-item-title"> + {{name}} + </div> + <div class="admin-integrations-new-item-description"> + {{{_ "Created_at_s_by_s" (dateFormated _createdAt) _createdBy.username}}} + </div> + </div> + <i class="icon-angle-right"></i> + </div> + </a> + {{else}} + <h1>{{_ "There_are_no_applications"}}</h1> + {{/each}} + </div> + </div> + </div> + {{else}} + {{_ "Not_authorized"}} + {{/if}} + </div> +</template> diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee new file mode 100644 index 0000000000000000000000000000000000000000..21e189664dc64073a013c4ba2f34a0bffe6a9c72 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee @@ -0,0 +1,28 @@ +Meteor.methods + addOAuthApp: (application) -> + if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps' + throw new Meteor.Error 'not_authorized' + + if not _.isString(application.name) + throw new Meteor.Error 'invalid_name', '[methods] addOAuthApp -> name must be string' + + if application.name.trim() is '' + throw new Meteor.Error 'invalid_name', '[methods] addOAuthApp -> name can\'t be empty' + + if not _.isString(application.redirectUri) + throw new Meteor.Error 'invalid_redirectUri', '[methods] addOAuthApp -> redirectUri must be string' + + if application.redirectUri.trim() is '' + throw new Meteor.Error 'invalid_redirectUri', '[methods] addOAuthApp -> redirectUri can\'t be empty' + + if not _.isBoolean(application.active) + throw new Meteor.Error 'invalid_active', '[methods] addOAuthApp -> active must be boolean' + + application.clientId = Random.id() + application.clientSecret = Random.secret() + application._createdAt = new Date + application._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}} + + application._id = RocketChat.models.OAuthApps.insert application + + return application diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/deleteOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/deleteOAuthApp.coffee new file mode 100644 index 0000000000000000000000000000000000000000..704dfed09c5ffd4a77df7febdc4db62c2bffabdd --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/deleteOAuthApp.coffee @@ -0,0 +1,13 @@ +Meteor.methods + deleteOAuthApp: (applicationId) -> + if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps' + throw new Meteor.Error 'not_authorized' + + application = RocketChat.models.OAuthApps.findOne(applicationId) + + if not application? + throw new Meteor.Error 'invalid_application', '[methods] deleteOAuthApp -> application not found' + + RocketChat.models.OAuthApps.remove _id: applicationId + + return true diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee new file mode 100644 index 0000000000000000000000000000000000000000..e50cbf1161104b80fefb23db0ed376b62c32e649 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee @@ -0,0 +1,33 @@ +Meteor.methods + updateOAuthApp: (applicationId, application) -> + if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps' + throw new Meteor.Error 'not_authorized' + + if not _.isString(application.name) + throw new Meteor.Error 'invalid_name', '[methods] updateOAuthApp -> name must be string' + + if application.name.trim() is '' + throw new Meteor.Error 'invalid_name', '[methods] updateOAuthApp -> name can\'t be empty' + + if not _.isString(application.redirectUri) + throw new Meteor.Error 'invalid_redirectUri', '[methods] updateOAuthApp -> redirectUri must be string' + + if application.redirectUri.trim() is '' + throw new Meteor.Error 'invalid_redirectUri', '[methods] updateOAuthApp -> redirectUri can\'t be empty' + + if not _.isBoolean(application.active) + throw new Meteor.Error 'invalid_active', '[methods] updateOAuthApp -> active must be boolean' + + currentApplication = RocketChat.models.OAuthApps.findOne(applicationId) + if not currentApplication? + throw new Meteor.Error 'invalid_application', '[methods] updateOAuthApp -> application not found' + + RocketChat.models.OAuthApps.update applicationId, + $set: + name: application.name + active: application.active + redirectUri: application.redirectUri + _updatedAt: new Date + _updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}} + + return RocketChat.models.OAuthApps.findOne(applicationId) diff --git a/packages/rocketchat-oauth2-server-config/admin/server/publications/oauthApps.coffee b/packages/rocketchat-oauth2-server-config/admin/server/publications/oauthApps.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d29a5cbdcdbe69884614bd6e177926525c9cceac --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/server/publications/oauthApps.coffee @@ -0,0 +1,8 @@ +Meteor.publish 'oauthApps', -> + unless @userId + return @ready() + + if not RocketChat.authz.hasPermission @userId, 'manage-oauth-apps' + throw new Meteor.Error "not-authorized" + + return RocketChat.models.OAuthApps.find() diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee new file mode 100644 index 0000000000000000000000000000000000000000..c2acdd899d11a13db46046ecadea9d11e61d588b --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee @@ -0,0 +1,47 @@ +# @ChatOAuthApps = new Meteor.Collection 'rocketchat_oauth_apps' + +FlowRouter.route '/oauth/authorize', + action: (params, queryParams) -> + BlazeLayout.render 'main', + center: 'authorize' + modal: true + client_id: queryParams.client_id + redirect_uri: queryParams.redirect_uri + response_type: queryParams.response_type + state: queryParams.state + + +FlowRouter.route '/oauth/error/:error', + action: (params, queryParams) -> + BlazeLayout.render 'main', + center: 'oauth404' + modal: true + error: params.error + + +Template.authorize.onCreated -> + @subscribe 'authorizedOAuth' + @subscribe 'oauthClient', @data.client_id() + + +Template.authorize.helpers + getToken: -> + return localStorage.getItem('Meteor.loginToken') + + getClient: -> + return ChatOAuthApps.findOne() + + +Template.authorize.events + 'click #logout-oauth': -> + return Meteor.logout() + + 'click #cancel-oauth': -> + return window.close() + + +Template.authorize.onRendered -> + @autorun (c) => + if Meteor.user()?.oauth?.athorizedClients?.indexOf(@data.client_id()) > -1 + c.stop() + $('button').click() diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html new file mode 100644 index 0000000000000000000000000000000000000000..ce886eca1ff9fd581d58375814076ac0bbd4fea7 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html @@ -0,0 +1,59 @@ +<template name="authorize"> + {{#if currentUser}} + <div class="oauth-panel"> + <form method="post" action="" role="form" class="{{#unless Template.subscriptionsReady}}hidden{{/unless}}"> + {{#if currentUser}} + <div class="user-info"> + <div class="thumb"> + {{> avatar username=currentUser.username}} + </div> + <div class="username"> + {{_ "You_are_logged_in_as"}} + <h1>{{currentUser.username}}</h1> + </div> + </div> + {{/if}} + + <div class="integration-info"> + <div> + <span><b>{{getClient.name}}</b> {{_ "will_be_able_to"}}</span> + <ul class="integration-permissions"> + <li>Post Messages</li> + <li>Create Channels</li> + <li>Change Chennel Topic</li> + </ul> + </div> + </div> + <input type="hidden" name="allow" value="yes"> + <input type="hidden" name="token" value="{{getToken}}"> + <input type="hidden" name="client_id" value="{{client_id}}"> + <input type="hidden" name="redirect_uri" value="{{redirect_uri}}"> + <input type="hidden" name="response_type" value="code"> + <div class="buttons"> + <a id="logout-oauth" href="" class="button secondary">{{_ "Logout"}}</a> + <div class="horizontal-space"></div> + <button id="cancel-oauth" type="button" class="button secondary">{{_ "Cancel"}}</button> + <button type="submit" class="button">{{_ "Authorize"}}</button> + </div> + </form> + {{#unless Template.subscriptionsReady}} + {{_ "loading"}}... + {{/unless}} + </div> + {{else}} + {{> loginButtons}} + {{/if}} +</template> + +<template name="oauth404"> + <div class="oauth-panel"> + <form> + {{#if $eq error '404'}} + <h2>Invalid OAuth client</h2> + {{/if}} + {{#if $eq error 'invalid_redirect_uri'}} + <h2>Redirect URL does not match</h2> + {{/if}} + </form> + </div> +</template> diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/load.coffee b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/load.coffee new file mode 100644 index 0000000000000000000000000000000000000000..631ef382a4e69a8a6ebda08537da49d86e9d3f1e --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/load.coffee @@ -0,0 +1,2 @@ +RocketChat.theme.addPackageAsset -> + return Assets.getText 'oauth/client/stylesheets/oauth2.less' diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less new file mode 100644 index 0000000000000000000000000000000000000000..e83fecf16ffdd0e13633cfebcc82631ffe68222a --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less @@ -0,0 +1,72 @@ +.oauth-panel { + position: absolute; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + left: 0px; + right: 0px; + top: 0px; + bottom: 0px; + + ul, li, ol { + list-style: initial; + } + + ul { + padding-left: 10px; + margin-left: 6px; + } + + form { + min-width: 400px; + padding: 40px; + } + + .user-info { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding-bottom: 20px; + margin-bottom: 20px; + border-bottom: 1px solid #eee; + + .thumb { + height: 40px; + width: 40px; + margin-right: 10px; + } + + .username { + text-align: left; + h1 { + font-size: 18px; + } + } + } + + .integration-info { + display: flex; + flex-direction: column; + align-items: center; + + .integration-permissions { + margin-left: 16px; + padding-top: 10px; + padding-bottom: 40px; + } + } + + .buttons { + display: flex; + align-items: center; + justify-content: center; + + .horizontal-space { + border-right: 1px solid #ddd; + height: 14px; + margin: 0 15px; + } + } +} diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee new file mode 100644 index 0000000000000000000000000000000000000000..41fee6a9a863d9a6a10a50f5f030d7ec8a011ecc --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee @@ -0,0 +1,12 @@ +if not RocketChat.models.OAuthApps.findOne('zapier') + RocketChat.models.OAuthApps.insert + _id: 'zapier' + name: 'Zapier' + active: false + clientId: 'zapier' + clientSecret: 'RTK6TlndaCIolhQhZ7_KHIGOKj41RnlaOq_o-7JKwLr' + redirectUri: 'https://zapier.com/dashboard/auth/oauth/return/AppIDAPI/' + _createdAt: new Date + _createdBy: + _id: 'system' + username: 'system' diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee new file mode 100644 index 0000000000000000000000000000000000000000..7fb13851d207d457ac81e855367766151d698c18 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee @@ -0,0 +1,58 @@ +oauth2server = new OAuth2Server + accessTokensCollectionName: 'rocketchat_oauth_access_tokens' + refreshTokensCollectionName: 'rocketchat_oauth_refresh_tokens' + authCodesCollectionName: 'rocketchat_oauth_auth_codes' + clientsCollection: RocketChat.models.OAuthApps.model + debug: true + + +WebApp.connectHandlers.use oauth2server.app + + +Meteor.publish 'oauthClient', (clientId) -> + unless @userId + return @ready() + + return RocketChat.models.OAuthApps.find {clientId: clientId, active: true}, + fields: + name: 1 + + +RocketChat.API.v1.addAuthMethod -> + console.log @request.method, @request.url + + headerToken = @request.headers['authorization'] + getToken = @request.query.access_token + + if headerToken? + if matches = headerToken.match(/Bearer\s(\S+)/) + headerToken = matches[1] + else + headerToken = undefined + + bearerToken = headerToken or getToken + + if not bearerToken? + # console.log 'token not found'.red + return + + # console.log 'bearerToken', bearerToken + + getAccessToken = Meteor.wrapAsync oauth2server.oauth.model.getAccessToken, oauth2server.oauth.model + accessToken = getAccessToken bearerToken + + if not accessToken? + # console.log 'accessToken not found'.red + return + + if accessToken.expires? and accessToken.expires isnt 0 and accessToken.expires < new Date() + # console.log 'accessToken expired'.red + return + + user = RocketChat.models.Users.findOne(accessToken.userId) + if not user? + # console.log 'user not found'.red + return + + return user: user + diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js new file mode 100644 index 0000000000000000000000000000000000000000..3d7b2f10c2a0dc41918547c3a5b3dbee4a473422 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -0,0 +1,52 @@ +Package.describe({ + name: 'rocketchat:oauth2-server-config', + summary: "Configure the OAuth2 Server", + version: "1.0.0" +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use('webapp'); + api.use('coffeescript'); + api.use('rocketchat:lib'); + api.use('rocketchat:api'); + api.use('rocketchat:theme'); + api.use('rocketchat:oauth2-server'); + + api.use('templating', 'client'); + api.use('kadira:flow-router', 'client'); + + //// General // + // Server + api.addFiles('server/models/OAuthApps.coffee', 'server'); + + //// OAuth // + // Server + api.addFiles('oauth/server/oauth2-server.coffee', 'server'); + api.addFiles('oauth/server/default-services.coffee', 'server'); + + api.addAssets('oauth/client/stylesheets/oauth2.less', 'server'); + api.addFiles('oauth/client/stylesheets/load.coffee', 'server'); + + // Client + api.addFiles('oauth/client/oauth2-client.html', 'client'); + api.addFiles('oauth/client/oauth2-client.coffee', 'client'); + + + //// Admin // + // Client + api.addFiles('admin/client/startup.coffee', 'client'); + api.addFiles('admin/client/collection.coffee', 'client'); + api.addFiles('admin/client/route.coffee', 'client'); + api.addFiles('admin/client/views/oauthApp.html', 'client'); + api.addFiles('admin/client/views/oauthApp.coffee', 'client'); + api.addFiles('admin/client/views/oauthApps.html', 'client'); + api.addFiles('admin/client/views/oauthApps.coffee', 'client'); + + // Server + api.addFiles('admin/server/publications/oauthApps.coffee', 'server'); + api.addFiles('admin/server/methods/addOAuthApp.coffee', 'server'); + api.addFiles('admin/server/methods/updateOAuthApp.coffee', 'server'); + api.addFiles('admin/server/methods/deleteOAuthApp.coffee', 'server'); +}); diff --git a/packages/rocketchat-oauth2-server-config/server/models/OAuthApps.coffee b/packages/rocketchat-oauth2-server-config/server/models/OAuthApps.coffee new file mode 100644 index 0000000000000000000000000000000000000000..5f95a6c2d32e08ac297fffb2c4ffec08b0f724e3 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/server/models/OAuthApps.coffee @@ -0,0 +1,13 @@ +RocketChat.models.OAuthApps = new class extends RocketChat.models._Base + constructor: -> + @_initModel 'oauth_apps' + + + # FIND + # findByRole: (role, options) -> + # query = + # roles: role + + # return @find query, options + + # CREATE diff --git a/packages/rocketchat-oembed/client/oembedImageWidget.html b/packages/rocketchat-oembed/client/oembedImageWidget.html index 8d277d965021b748772a69de89b8a9728eb3b1c1..144dd7665215be92aefe9b16c2d9d8c8584e22a8 100644 --- a/packages/rocketchat-oembed/client/oembedImageWidget.html +++ b/packages/rocketchat-oembed/client/oembedImageWidget.html @@ -3,8 +3,8 @@ {{#if parsedUrl}} <div> <a href="{{url}}" class="swipebox" target="_blank"> - <div class="inline-image" style="background-image: url({{url}});"> - <img src="{{url}}"> + <div class="inline-image" style="background-image: url('{{url}}');"> + <img src="{{url}}" height="200"> </div> </a> </div> diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee index 3193a2df5a940d87961ef2427cb0680eb39b7744..79e6127073a67dd71a58a5f09e3d1d584d2cde58 100644 --- a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee +++ b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee @@ -26,7 +26,7 @@ Template.oembedUrlWidget.helpers if not this.meta? return - decodedOgImage = @meta.ogImage.replace(/&/g, '&') + decodedOgImage = @meta.ogImage?.replace?(/&/g, '&') return decodedOgImage or this.meta.twitterImage diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.html b/packages/rocketchat-oembed/client/oembedUrlWidget.html index 56115decb6de4433bf5da104cd478cf152e3ceaf..9d749d7f6c8ef71b4ab661b4a3ed146d44d53dcb 100644 --- a/packages/rocketchat-oembed/client/oembedUrlWidget.html +++ b/packages/rocketchat-oembed/client/oembedUrlWidget.html @@ -1,7 +1,7 @@ <template name="oembedUrlWidget"> {{#if show}} <blockquote> - <div style="{{#if image}}min-height: 60px;{{/if}} padding: 10px 3px;"> + <div style="{{#if image}}min-height: 80px;{{/if}} padding: 10px 3px;"> {{#if image}} {{#if meta.ogImageUserGenerated}} <div> @@ -25,4 +25,4 @@ </div> </blockquote> {{/if}} -</template> \ No newline at end of file +</template> diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index ace7d0496be20df1c7ef2e5d2f55f0321ede8563..3bb4babd591ad8f0e05629ff44d33d64e9df5e64 100644 --- a/packages/rocketchat-oembed/package.js +++ b/packages/rocketchat-oembed/package.js @@ -13,7 +13,7 @@ Package.onUse(function(api) { 'coffeescript', 'underscore', 'konecty:change-case', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client/baseWidget.html', 'client'); diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 7696e42b7705aca64c89934999f8710ce13e573c..95266e478ab99cfea1bf8b1f514d73e4a918f72c 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -103,7 +103,7 @@ OEmbed.getUrlMeta = (url, withFragment) -> if content?.body? metas = {} - content.body.replace /<title>(.+)<\/title>/gmi, (meta, title) -> + content.body.replace /<title>((.|\n)+?)<\/title>/gmi, (meta, title) -> metas.pageTitle = title content.body.replace /<meta[^>]*(?:name|property)=[']([^']*)['][^>]*content=[']([^']*)['][^>]*>/gmi, (meta, name, value) -> diff --git a/packages/rocketchat-sharedsecret/package.js b/packages/rocketchat-sharedsecret/package.js index 4371ff0846a000412e12de5f5a74756f7ead1159..d0547036c7adf12f6339c755d59ece2acedf5cef 100644 --- a/packages/rocketchat-sharedsecret/package.js +++ b/packages/rocketchat-sharedsecret/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.use(['jparker:crypto-aes'], ['server','client']); diff --git a/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6912464b1a1168f158a9b4e5d05619bf27ae679d 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "User_doesnt_exist" : "لا يوجد مستخدم بالاسم `@%s`" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/de.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/de.i18n.json index 7ed315a21cd419d186de385f01172f6c80285b0d..03bf1dcfbe890b85cb18a8af8290a84047bc032b 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/de.i18n.json @@ -1,5 +1,5 @@ { - "Invite_user_to_join_channel" : "Lade einen Benutzer in diesen Kanal ein", - "User_doesnt_exist" : "Kein Benutzer vorhanden mit dem Namen `@% s`.", - "Username_is_already_in_here" : "`@% s` ist bereits da" + "Invite_user_to_join_channel" : "Benutzer in diesen Kanal einladen", + "User_doesnt_exist" : "Kein Benutzer mit dem Namen `@% s` vorhanden.", + "Username_is_already_in_here" : "`@%s` wurde bereits hinzugefügt." } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/hr.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/hr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6e8a0bf75bcb1c7d5236d51be12807440b283712 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/hr.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/hr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Invite_user_to_join_channel" : "Pozovi jednog korisnika da se pridruži ovom kanalu", + "User_doesnt_exist" : "Ne postoji korisnik pod imenom `@% s`.", + "Username_is_already_in_here" : "`@% s` je već ovdje." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json index 79dc107036c67bb7bd7b13201f3abd4dcd25f112..784fb685f16bf4e151e1bd4c1c387e93010e21fd 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json @@ -1,4 +1,5 @@ { + "Invite_user_to_join_channel" : "ì´ ì±„ë„ë¡œ 초대한 ì‚¬ìš©ìž ì°¸ì—¬", "User_doesnt_exist" : "`@%s` 사용ìžê°€ 존재하지 않습니다.", "Username_is_already_in_here" : "`@%s` 사용ìžê°€ ì´ë¯¸ 있습니다." } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..35a6d518000af37fb6f8a8da1c78e7b0e970c01b 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Invite_user_to_join_channel" : "Nodig een gebruiker uit voor om dit kanaal", + "User_doesnt_exist" : "Geen gebruiker bestaat met de naam `@%s`.", + "Username_is_already_in_here" : "`@%s` is al hier." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ro.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..ce218ea20e43320fc7885615bc8a90f810efe839 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ro.i18n.json @@ -0,0 +1,5 @@ +{ + "Invite_user_to_join_channel" : "InvitaÈ›i un utilizator să se alăture acestui canal", + "User_doesnt_exist" : "Nu există nici un utilizator cu numele de `@%s`.", + "Username_is_already_in_here" : "`@% s` este deja aici." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..dba0f28979984872e132710c157b46902d0466ba 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Invite_user_to_join_channel" : "ПриглаÑить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¿Ñ€Ð¸ÑоединитьÑÑ Ðº Ñтому публичному чату", + "User_doesnt_exist" : "ÐŸÐ¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ð»Ð¾Ð³Ð¸Ð½Ð¾Ð¼ `@%s` не ÑущеÑтвует.", + "Username_is_already_in_here" : "`@%s` уже здеÑÑŒ." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/sr.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/package.js b/packages/rocketchat-slashcommands-invite/package.js index a73b9e87f4ea07a78a1390bc96b405f843b3f944..1f78c040243a8c13a302add086dd770da5479743 100644 --- a/packages/rocketchat-slashcommands-invite/package.js +++ b/packages/rocketchat-slashcommands-invite/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'check', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client.coffee', 'client'); @@ -27,9 +27,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-slashcommands-invite/server.coffee b/packages/rocketchat-slashcommands-invite/server.coffee index 36ae07981e531db2820d57d26ab6ce1386dfbf03..4b619023139d4bff982f2de3e8cf20d23a9e6ffe 100644 --- a/packages/rocketchat-slashcommands-invite/server.coffee +++ b/packages/rocketchat-slashcommands-invite/server.coffee @@ -37,8 +37,9 @@ class Invite } return - Meteor.runAsUser user._id, -> - Meteor.call 'joinRoom', item.rid + Meteor.call 'addUserToRoom', + rid: item.rid + username: user.username RocketChat.slashCommands.add 'invite', Invite diff --git a/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..6f532cbd1fb22059e1d7da40fe400ae4a16addff 100644 --- a/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Channel_doesnt_exist" : "القناة '#%s' غير موجودة." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/de.i18n.json b/packages/rocketchat-slashcommands-join/i18n/de.i18n.json index ad6c15152faecf30e80538da4e5fd05b2562740c..af31e778a80815908adb9365ec32bdc3b06d4ecf 100644 --- a/packages/rocketchat-slashcommands-join/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/de.i18n.json @@ -1,4 +1,4 @@ { "Channel_doesnt_exist" : "Der Kanal `#% s` existiert nicht.", - "Join_the_given_channel" : "Trete dem vorgeschlagenen Kanal bei" + "Join_the_given_channel" : "Angegebenen Kanal beitreten" } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/fr.i18n.json b/packages/rocketchat-slashcommands-join/i18n/fr.i18n.json index 9565cca54e7dec08cabd9ccb6203684ea054419a..900f6a3c2c9b51d18a84eb5d6bddca6a8b412587 100644 --- a/packages/rocketchat-slashcommands-join/i18n/fr.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/fr.i18n.json @@ -1,3 +1,4 @@ { - "Channel_doesnt_exist" : "Le canal `#%s` n'existe pas." + "Channel_doesnt_exist" : "Le canal `#%s` n'existe pas.", + "Join_the_given_channel" : "Rejoindre le canal donné" } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/hr.i18n.json b/packages/rocketchat-slashcommands-join/i18n/hr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..709ab51b4ada2fb94ca6907995a950f1d5341d37 100644 --- a/packages/rocketchat-slashcommands-join/i18n/hr.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/hr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Channel_doesnt_exist" : "Kanal `#% s` ne postoji." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json index 061624dfd786bbb2cc72fa39cf43217d94449eaa..08976fe9f190d36731c5dac5afaa375ac495bbcf 100644 --- a/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json @@ -1,3 +1,4 @@ { - "Channel_doesnt_exist" : "`#%s` 채ë„ì´ ì¡´ìž¬í•˜ì§€ 않습니다." + "Channel_doesnt_exist" : "`#%s` 채ë„ì´ ì¡´ìž¬í•˜ì§€ 않습니다.", + "Join_the_given_channel" : "ì§€ì •í•œ 채ë„ì— ì°¸ì—¬" } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/nl.i18n.json b/packages/rocketchat-slashcommands-join/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..0c0dd584e3cf747d9025fec91082232474d3d402 100644 --- a/packages/rocketchat-slashcommands-join/i18n/nl.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/nl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Channel_doesnt_exist" : "Het kanaal `#%s` bestaat niet.", + "Join_the_given_channel" : "Word lid van de gegeven kanaal" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ro.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..e6d2e68d62859d536e62289e38b3d4818cf39391 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ro.i18n.json @@ -0,0 +1,4 @@ +{ + "Channel_doesnt_exist" : "Canalul `#%s` nu există.", + "Join_the_given_channel" : "IntraÈ›i pe canalul specificat" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ru.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..aaaaf72ef992a556ce4cc8e94b499c38ba5d5e67 100644 --- a/packages/rocketchat-slashcommands-join/i18n/ru.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/ru.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Channel_doesnt_exist" : "Чат `#%s` не ÑущеÑтвует.", + "Join_the_given_channel" : "ПриÑоединитьÑÑ Ðº заданному публичному чату" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/sr.i18n.json b/packages/rocketchat-slashcommands-join/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/package.js b/packages/rocketchat-slashcommands-join/package.js index 04690ded85c9a5189bc54e0e8c1aa53f9399fc95..08f72676382888131e64d05051850b97b64d4202 100644 --- a/packages/rocketchat-slashcommands-join/package.js +++ b/packages/rocketchat-slashcommands-join/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'check', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client.coffee', 'client'); @@ -27,9 +27,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-slashcommands-kick/client.coffee b/packages/rocketchat-slashcommands-kick/client.coffee new file mode 100644 index 0000000000000000000000000000000000000000..acc40d33db03fc7e81cac9cf9e55487c96e3159b --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/client.coffee @@ -0,0 +1,11 @@ +RocketChat.slashCommands.add 'kick', (command, params, item) -> + username = params.trim() + if username is '' + return + username = username.replace('@', '') + + if Session.get('showUserInfo') is username + Session.set('showUserInfo', null) +, + description: TAPi18n.__ 'Remove_someone_from_room' + params: '@username' diff --git a/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..8a0f48baf891f8baeefda509380d5659256aff1c --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json @@ -0,0 +1,4 @@ +{ + "Username_is_not_in_this_room" : "المستخدم `#%s` غير موجود ÙÙŠ الغرÙØ©", + "Remove_someone_from_room" : "إزالة شخص من الغرÙØ©" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/cs.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/cs.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..033f4cec499f12780fe0c13c54a8a3800dc8f934 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "Der Benutzername `#%s` existiert nicht.", + "Username_is_not_in_this_room" : "Der Benutzer `#%s` ist nicht in diesem Raum.", + "Remove_someone_from_room" : "Jemanden aus dem Raum entfernen" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/el.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/el.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..4074198404aaa037f05d6262bd7af9027c5672ae --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "The username `#%s` doesn't exist.", + "Username_is_not_in_this_room" : "The user `#%s` is not in this room.", + "Remove_someone_from_room" : "Remove someone from the room" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/es.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/es.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/fa.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/fa.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..63a5726744edfb8423f4bab35db21c1a43f4196b --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "Käyttäjätunnusta  `#% s` ei ole olemassa.", + "Username_is_not_in_this_room" : "Käyttäjä `#% s` ei ole tässä huoneessa.", + "Remove_someone_from_room" : "Poista joku huoneesta" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..f005e4a0b51327f9ff573512d663c9f6124d780b --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "L'utilisateur `#%s` n'existe pas.", + "Username_is_not_in_this_room" : "L'utilisateur `#%s` est pas dans ce salon.", + "Remove_someone_from_room" : "Retirer quelqu'un du salon." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/he.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/he.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..f4880e1c7ea2ad0db394cf4411903eacaf30a31b --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "KorisniÄko ime '#% s` ne postoji.", + "Username_is_not_in_this_room" : "Korisnik `#% s` nije u ovoj sobi.", + "Remove_someone_from_room" : "Uklonite nekoga iz sobe" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/hu.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/hu.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/it.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/it.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ja.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ja.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/km.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/km.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ko.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ku.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ku.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/lo.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/lo.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ms-MY.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ms-MY.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..a7e2c8e2068d08ea68d42562811550924903852d --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "De gebruikersnaam `#%s` bestaat niet.", + "Username_is_not_in_this_room" : "De gebruiker `#%s` is niet in deze kamer.", + "Remove_someone_from_room" : "Verwijder iemand uit de kamer" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/pl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/pt.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/pt.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ro.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..967a28c53f65d8f8f9e122d40a09e28dc7a9a951 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ro.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "Numele de utilizator `#% s` nu există.", + "Username_is_not_in_this_room" : "Utilizatorul `#% s` nu este în această cameră.", + "Remove_someone_from_room" : "ScoateÈ›i pe cineva din camera" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..56c56d4f03ea306d7a900c6cacf27fc32bfaa996 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json @@ -0,0 +1,4 @@ +{ + "Username_is_not_in_this_room" : "Пользователь `#%s` не в Ñтом чате.", + "Remove_someone_from_room" : "Удалить кого-то из чата" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/sq.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/sq.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/sr.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/sv.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/sv.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ta-IN.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ta-IN.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/tr.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/tr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/ug.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ug.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/uk.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/uk.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/i18n/zh.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/zh.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-kick/package.js b/packages/rocketchat-slashcommands-kick/package.js new file mode 100644 index 0000000000000000000000000000000000000000..a2878a1f7d4206188684fdf24ec3ebe2e5a92335 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/package.js @@ -0,0 +1,36 @@ +Package.describe({ + name: 'rocketchat:slashcommands-kick', + version: '0.0.1', + summary: 'Command handler for the /kick command', + git: '' +}); + +Package.onUse(function(api) { + + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'check', + 'rocketchat:lib' + ]); + + api.addFiles('client.coffee', 'client'); + api.addFiles('server.coffee', 'server'); + + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-slashcommands-kick/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-slashcommands-kick/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-slashcommands-kick/server.coffee b/packages/rocketchat-slashcommands-kick/server.coffee new file mode 100644 index 0000000000000000000000000000000000000000..112313be987440b5aef170589f1faf42842a1dcd --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/server.coffee @@ -0,0 +1,40 @@ +### +# Kick is a named function that will replace /kick commands +### + +class Kick + constructor: (command, params, item) -> + if command isnt 'kick' or not Match.test params, String + return + + username = params.trim() + if username is '' + return + + username = username.replace('@', '') + + user = Meteor.users.findOne Meteor.userId() + kickedUser = RocketChat.models.Users.findOneByUsername username + room = RocketChat.models.Rooms.findOneById item.rid + + if not kickedUser? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + if username not in (room.usernames or []) + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_is_not_in_this_room', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + Meteor.call 'removeUserFromRoom', { rid: item.rid, username: username } + +RocketChat.slashCommands.add 'kick', Kick diff --git a/packages/rocketchat-slashcommands-leave/package.js b/packages/rocketchat-slashcommands-leave/package.js index 678f15b5593681774e84969aa3b03a07a8fad381..ac66b78c4648af2e9d62b8e1ba3178e9c1ed8d3b 100644 --- a/packages/rocketchat-slashcommands-leave/package.js +++ b/packages/rocketchat-slashcommands-leave/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('leave.coffee'); }); diff --git a/packages/rocketchat-slashcommands-mute/client/mute.coffee b/packages/rocketchat-slashcommands-mute/client/mute.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d812e0cc179eff97753683ee5795c77549b84640 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/client/mute.coffee @@ -0,0 +1,3 @@ +RocketChat.slashCommands.add 'mute', null, + description: TAPi18n.__ 'Mute_someone_in_room' + params: '@username' diff --git a/packages/rocketchat-slashcommands-mute/client/unmute.coffee b/packages/rocketchat-slashcommands-mute/client/unmute.coffee new file mode 100644 index 0000000000000000000000000000000000000000..4d59ccb7de4bd97b7407520628aacd4aebb77bec --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/client/unmute.coffee @@ -0,0 +1,3 @@ +RocketChat.slashCommands.add 'unmute', null, + description: TAPi18n.__ 'Unmute_someone_in_room' + params: '@username' diff --git a/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..093fc95cd564f0791dc57cc18eeb6dfe3faaa793 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "إسكات شخص ÙÙŠ الغرÙØ©", + "Unmute_someone_in_room" : "إلغاء إسكات شخص ÙÙŠ هذه الغرÙØ©" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/cs.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/cs.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/de.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/de.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..d1a8bdcde1f6a9341c1c6f498f26c12feffaff7e --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "Jemanden das Chatten in einem Raum verbieten", + "Unmute_someone_in_room" : "Jemanden das Chatten in einem Raum wieder erlauben" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/el.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/el.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..a4c14cecd20881e5ef2199153c0b08b8a5cf2df2 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "Mute someone in the room", + "Unmute_someone_in_room" : "Unmute someone in the room" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/es.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/es.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/fa.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/fa.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..9058f3251335a95904e820c5b9b8152e090f8300 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "Mykistä joku huoneessa", + "Unmute_someone_in_room" : "Poista jonkun mykistys huoneessa" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..f11bb2e01a39ee820c732a2d2d0df4ce5007df44 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "Rendre quelqu'un muet dans ce salon", + "Unmute_someone_in_room" : "Réactiver le chat de quelqu'un" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/he.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/he.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/hr.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/hr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/hu.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/hu.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/it.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/it.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ja.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ja.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/km.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/km.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ko.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ku.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ku.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/lo.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/lo.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ms-MY.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ms-MY.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..0493e2a91aadb4cfdc8a6ee22de6c2f8bd1d01ae --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "Maak iemand in de kamer stil", + "Unmute_someone_in_room" : "Laat iemand weer in de kamer praten" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/pl.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/pt.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/pt.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ro.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..72303597425f503f3ca99eddc82380d03ab13008 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ro.i18n.json @@ -0,0 +1,4 @@ +{ + "Mute_someone_in_room" : "BlocaÈ›i noi mesaje ale cuiva în cameră", + "Unmute_someone_in_room" : "DeblocaÈ›i mesajele noi ale unui utilizator în cameră" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..55e8952a1a75995ca14a58ca657e5197dfc7f867 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json @@ -0,0 +1,3 @@ +{ + "Mute_someone_in_room" : "Заглу" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/sq.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/sq.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/sr.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/sv.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/sv.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ta-IN.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ta-IN.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/tr.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/tr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/ug.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ug.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/uk.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/uk.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/i18n/zh.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/zh.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-mute/package.js b/packages/rocketchat-slashcommands-mute/package.js new file mode 100644 index 0000000000000000000000000000000000000000..3d776dd74e1787f97c047df4ed087b224ae1443a --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/package.js @@ -0,0 +1,38 @@ +Package.describe({ + name: 'rocketchat:slashcommands-mute', + version: '0.0.1', + summary: 'Command handler for the /mute command', + git: '' +}); + +Package.onUse(function(api) { + + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'check', + 'rocketchat:lib' + ]); + + api.addFiles('client/mute.coffee', 'client'); + api.addFiles('client/unmute.coffee', 'client'); + api.addFiles('server/mute.coffee', 'server'); + api.addFiles('server/unmute.coffee', 'server'); + + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-slashcommands-mute/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-slashcommands-mute/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-slashcommands-mute/server/mute.coffee b/packages/rocketchat-slashcommands-mute/server/mute.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d8bc3d3bc513d90e75e237da4fc23c63fedbd19a --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/server/mute.coffee @@ -0,0 +1,40 @@ +### +# Mute is a named function that will replace /mute commands +### + +class Mute + constructor: (command, params, item) -> + if command isnt 'mute' or not Match.test params, String + return + + username = params.trim() + if username is '' + return + + username = username.replace('@', '') + + user = Meteor.users.findOne Meteor.userId() + mutedUser = RocketChat.models.Users.findOneByUsername username + room = RocketChat.models.Rooms.findOneById item.rid + + if not mutedUser? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + if username not in (room.usernames or []) + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_is_not_in_this_room', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + Meteor.call 'muteUserInRoom', { rid: item.rid, username: username } + +RocketChat.slashCommands.add 'mute', Mute diff --git a/packages/rocketchat-slashcommands-mute/server/unmute.coffee b/packages/rocketchat-slashcommands-mute/server/unmute.coffee new file mode 100644 index 0000000000000000000000000000000000000000..e3b6ee25d82dba48c51f2c98d43557652520e3b5 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/server/unmute.coffee @@ -0,0 +1,40 @@ +### +# Unmute is a named function that will replace /unmute commands +### + +class Unmute + constructor: (command, params, item) -> + if command isnt 'unmute' or not Match.test params, String + return + + username = params.trim() + if username is '' + return + + username = username.replace('@', '') + + user = Meteor.users.findOne Meteor.userId() + unmutedUser = RocketChat.models.Users.findOneByUsername username + room = RocketChat.models.Rooms.findOneById item.rid + + if not unmutedUser? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + if username not in (room.usernames or []) + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_is_not_in_this_room', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + Meteor.call 'unmuteUserInRoom', { rid: item.rid, username: username } + +RocketChat.slashCommands.add 'unmute', Unmute diff --git a/packages/rocketchat-spotify/package.js b/packages/rocketchat-spotify/package.js index 4940ac69ed8a07ab7d59b461c0a84a3b9354b8b4..c4829d6eb67ba807dc2e9ae385b87705911b62a3 100644 --- a/packages/rocketchat-spotify/package.js +++ b/packages/rocketchat-spotify/package.js @@ -13,7 +13,7 @@ Package.onUse(function(api) { 'templating', 'underscore', 'rocketchat:oembed@0.0.1', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('lib/client/widget.coffee', 'client'); diff --git a/packages/rocketchat-statistics/package.js b/packages/rocketchat-statistics/package.js index 47133065781539a8e2e208e101e369d72865374a..31216ca161258852ee760ca43acf39d045c6c875 100644 --- a/packages/rocketchat-statistics/package.js +++ b/packages/rocketchat-statistics/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); // Statistics @@ -32,9 +32,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); diff --git a/packages/rocketchat-statistics/server/methods/getStatistics.coffee b/packages/rocketchat-statistics/server/methods/getStatistics.coffee index 8bf3e8cb1d915b244f6eab3f68d2be6f6361b66a..dfe10d205e7015211627c2e13af5cd3f9295bde7 100644 --- a/packages/rocketchat-statistics/server/methods/getStatistics.coffee +++ b/packages/rocketchat-statistics/server/methods/getStatistics.coffee @@ -3,9 +3,7 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] getStatistics -> Invalid user") - console.log '[methods] getStatistics -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - unless RocketChat.authz.hasPermission(Meteor.userId(), 'view-statistics') is true throw new Meteor.Error 'not-authorized', '[methods] getStatistics -> Not authorized' - return RocketChat.statistics.get() \ No newline at end of file + return RocketChat.statistics.get() diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 55ecffa41af830b6779f5968c163d328d02a3719..cd4541029362520318ff2aae15cfa5474bde1e90 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -475,7 +475,8 @@ form.inline { } } -input[disabled] { +input[disabled], +textarea[disabled] { background-color: #f4f4f4 !important; } @@ -867,6 +868,10 @@ a.github-fork { overflow: hidden; position: relative; border-radius: 4px; + .emojione { + height: 100%; + margin: 0px; + } .avatar-image { height: 100%; width: 100%; @@ -1579,7 +1584,7 @@ a.github-fork { } } h2 { - max-width: 90%; + width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; @@ -1722,6 +1727,10 @@ a.github-fork { .transform(translateX(0)); } } + &.main-modal { + left: 0px; + margin-right: 0px; + } .container-fluid { padding-top: 0; } @@ -1793,6 +1802,18 @@ a.github-fork { padding-top: 0; } + &.setting-changed { + > label { + color: #627CFF + } + } + + &[disabled] { + label { + color: #888; + } + } + input { color: #444; } @@ -1809,6 +1830,14 @@ a.github-fork { color: #888; padding: 5px; } + + .settings-alert { + background-color: rgb(255, 255, 230); + border: 1px solid rgb(255, 242, 196); + color: orange; + font-weight: bold; + padding: 5px; + } } } } @@ -2112,13 +2141,21 @@ a.github-fork { text-transform: uppercase; text-align: center; - > a { + > a.mark-read { float: right; &:hover { cursor: pointer; } } + + > a.jump-to { + float: left; + + &:hover { + cursor: pointer; + } + } } } @@ -2129,7 +2166,11 @@ a.github-fork { height: 100%; top: 0; left: 0; - + .room-topic { + font-size: 14px; + opacity: 0.4; + margin-left: 10px; + } .edit-room-title { margin-left: 4px; font-size: 16px; @@ -2385,6 +2426,9 @@ a.github-fork { width: 100%; .calc(height, ~'100% - 120px'); + .wrapper.has-more-next { + padding-bottom: 24px; + } ul { padding: 21px 0 10px; } @@ -2421,11 +2465,41 @@ a.github-fork { .transform(translateY(150%)); } } + .jump-recent { + z-index: 15; + background-color: #E7E7E7; + position: absolute; + text-align: right; + height: 24px; + line-height: 24px; + font-size: 0.8em; + padding-right: 20px; + bottom: 0; + left: 20px; + right: 20px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + + span { + cursor: pointer; + } + .transition(transform 0.3s ease-out); + .transform(translateY(0)); + &.not { + .transform(translateY(150%)); + } + } .editing { .body { border-radius: 4px; } } + &.selectable .message { + cursor: pointer; + &.selected { + background-color: #FFD; + } + } } .ticks-bar { @@ -2444,11 +2518,18 @@ a.github-fork { } .message { - padding: 18px 20px 4px 70px; + padding: 8px 20px 4px 70px; position: relative; line-height: 20px; min-height: 40px; + &.highlight { + -webkit-animation: highlight 3s; + -moz-animation: highlight 3s; + -o-animation: highlight 3s; + animation: highlight 3s; + } + .body, .user.user-card-message, .time { -webkit-user-select: text; -moz-user-select: text; @@ -2465,6 +2546,9 @@ a.github-fork { &:nth-child(1) { margin-top: 0; } + &:hover { + background-color: @message-hover-background-color; + } &.new-day { margin-top: 60px; } @@ -2583,7 +2667,6 @@ a.github-fork { .thumb { position: absolute; left: 20px; - top: 20px; display: block; width: 40px; height: 40px; @@ -2619,6 +2702,7 @@ a.github-fork { min-height: 20px; padding-top: 4px; padding-bottom: 4px; + margin-top: 0px; .user { display: none; } @@ -2647,6 +2731,9 @@ a.github-fork { margin-left: 1px; } } + .body { + margin-top: 0px; + } // .message-dropdown { // top: 100%; @@ -2683,6 +2770,7 @@ a.github-fork { .body { opacity: 1; .transition(opacity 1s linear); + margin-top: 2px; .inline-image { background-size: contain; @@ -2713,9 +2801,9 @@ a.github-fork { .compact { .message { - padding: 5px 20px 5px 70px; - .thumb:not(.thumb-small) .avatar { - margin-top: -15px; + padding: 4px 20px 4px 70px; + .body { + margin-top: 0px; } } } @@ -2999,7 +3087,12 @@ a.github-fork { margin-left: 120px; white-space: normal; .calc(width, ~'100% - 120px'); + h3 { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; font-size: 24px; margin-bottom: 8px; line-height: 27px; @@ -3035,6 +3128,10 @@ a.github-fork { } } 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; @@ -4195,7 +4292,10 @@ a.github-fork { } .inline-video { - max-height: 200px; + height: auto; + width: 100%; + max-width: 480px; + max-height: 270px; } .attention-message { @@ -4209,3 +4309,52 @@ a.github-fork { font-size: 40px; } } + +.search-messages-list { + .message-cog-container { + .message-action { + display: none !important; + &.jump-to-star-message { + display: block !important; + } + } + } + + .load-more { + text-transform: lowercase; + text-align: center; + line-height: 40px; + font-style: italic; + + .load-more-loading { + color: #aaa; + } + } + + .no-results { + text-align: center; + } +} + +.uploaded-files-list { + .load-more { + text-transform: lowercase; + text-align: center; + line-height: 40px; + font-style: italic; + + .load-more-loading { + color: #aaa; + } + } +} + +.messages-box { + .message-cog-container { + .message-action { + &.jump-to-search-message { + display: none !important; + } + } + } +} diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 9f4d66fcd297e795c2343024855f88efe793687c..b67ceb3652f68580e7bb7014ced551ec3845c300 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -109,6 +109,7 @@ ul .opt { .left(0px); .padding-left(10px); + text-align: left; } .flex-nav { .right(0px); @@ -195,9 +196,12 @@ } } .unread-bar { - > a { + > a.mark-read { float: left; } + > a.jump-to { + float: right; + } } } @@ -296,7 +300,7 @@ } } } - + .flex-opened { .flex-tab { .control { @@ -386,7 +390,7 @@ } } } - + @media all and(max-width: 1100px) { #rocket-chat { .flex-opened { @@ -628,7 +632,7 @@ #swipebox-overlay{ direction: ltr; } - + /* Override toastr messages to show on hte left side */ .toast-top-right { .left(12px); diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less old mode 100644 new mode 100755 index 7bdb7b45f75cb0552fa15a1342325e971f54c156..13141a7836e5bc0e0954dcbdac03ab2fcf6ed964 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -123,7 +123,7 @@ blockquote { } html { - .custom-scroll(transparent, rgba(255, 255, 255, 0.05), 3px); + .custom-scroll(transparent, @custom-scrollbar-color, 3px); } body { @@ -212,9 +212,8 @@ label.required:after { // new layout buttons .button { - background-color: #FFF; color: rgba(255, 255, 255, 0.85); - background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); + background-color: @action-buttons-color; &:before { background-color: rgba(0, 0, 0, 0.1); } @@ -237,7 +236,7 @@ label.required:after { background-color: #02acec; } &.clean { - background-color: rgba(0, 0, 0, 0.025); + background-color: @clean-buttons-color; } &.facebook { background-color: #325c99; @@ -328,7 +327,7 @@ a.github-fork { .info { background-color:@primary-background-color; h4 { - color: rgba(255, 255, 255, 0.65); + color: fade( @quaternary-font-color, 65% ); } &.status-offline { .thumb:after { @@ -384,29 +383,29 @@ a.github-fork { border-color: #9f0030; background-color: #D30230; } - } + } } span.soon { color: #aaa; } a { - color: rgba(255, 255, 255, 0.5); + color: fade( @quaternary-font-color, 50% ); border-bottom-color: darken(@primary-background-color, 2%); &:hover { background-color: darken(@primary-background-color, 2%); - color: rgba(255, 255, 255, 0.75); + color: fade( @quaternary-font-color, 75% ); } } } &.active .info, .info:hover { h4 { - color: rgba(255, 255, 255, 0.85); + color: fade(@quaternary-font-color, 85% ); } } .hover & { .info h4 { - color: rgba(255, 255, 255, 0.85); + color: fade(@quaternary-font-color, 85% ); } } } @@ -416,7 +415,7 @@ a.github-fork { //background-color: @primary-background-color; background-color: transparent; color: @tertiary-font-color; - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + .custom-scroll(transparent, @custom-scrollbar-color); header { background-color: @primary-background-color; } @@ -424,7 +423,7 @@ a.github-fork { background-color: @primary-background-color; } .content { - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + .custom-scroll(transparent, @custom-scrollbar-color); background-color: @primary-background-color; } .input-line { @@ -455,7 +454,7 @@ a.github-fork { } .rooms-list { background-color: lighten(@primary-background-color, 2%); - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + .custom-scroll(transparent, @custom-scrollbar-color); } .more { color: @tertiary-font-color; @@ -478,7 +477,7 @@ a.github-fork { &:hover { &:before, &:after { - background-color: rgba(255, 255, 255, 0.85); + background-color: fade( @quaternary-font-color, 85% ); } } } @@ -499,7 +498,7 @@ a.github-fork { } } .unread { - background-color: #1dce73; + background-color: @unread-notification-color; color: #FFF; } ul { @@ -515,8 +514,8 @@ a.github-fork { } &.active { a { - background-color: rgba(255, 255, 255, 0.075); - color: rgba(255, 255, 255, 0.75); + background-color: @active-channel-background-color; + color: @active-channel-font-color; } .opt { background-color: transparent; @@ -524,7 +523,7 @@ a.github-fork { } &.has-alert { .name { - color: #ffffff; + color: @quaternary-font-color; } } &.away { @@ -542,14 +541,14 @@ a.github-fork { .opt { background-color: transparent; i { - color: rgba(255, 255, 255, 0.5); + color: fade(@quaternary-font-color, 50% ); &:hover { - color: rgba(255, 255, 255, 0.75); + color: fade(@quaternary-font-color, 75% ); } } } i { - color: rgba(255, 255, 255, 0.35); + color: fade(@quaternary-font-color, 35% ); } input[type=text] { color: #000; diff --git a/packages/rocketchat-theme/i18n/ar.i18n.json b/packages/rocketchat-theme/i18n/ar.i18n.json index 7275473661d29fae4f82ae144af9dc753b8b05df..bdfad243ecf26910dda5a9cde9571a6c909e9018 100644 --- a/packages/rocketchat-theme/i18n/ar.i18n.json +++ b/packages/rocketchat-theme/i18n/ar.i18n.json @@ -1,3 +1,4 @@ { - "theme-color-status-away" : "لون Øالة بعيد" + "theme-color-status-away" : "لون Øالة بعيد", + "theme-color-status-busy" : "لون Øالة مشغول" } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/de.i18n.json b/packages/rocketchat-theme/i18n/de.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..93f6faa9c45986af74f33fa7837765b927c4351c 100644 --- a/packages/rocketchat-theme/i18n/de.i18n.json +++ b/packages/rocketchat-theme/i18n/de.i18n.json @@ -1 +1,31 @@ -{ } \ No newline at end of file +{ + "theme-color-action-buttons-color" : "Farbe des Aktionsbuttons", + "theme-color-active-channel-background-color" : "Hintergrundfarbe von aktiven Kanälen", + "theme-color-active-channel-font-color" : "Schriftfarbe von aktiven Kanälen", + "theme-color-blockquote-background" : "Hintergrundfarbe der Blockquotes ", + "theme-color-clean-buttons-color" : "Farbe des Säuberungsknopfs", + "theme-color-code-background" : "Hintergrundfarbe des Codes", + "theme-color-code-border" : "Randfarbe des Codes", + "theme-color-code-color" : "Farbe des Codes", + "theme-color-content-background-color" : "Hintergrundfarbe des Inhalts", + "theme-color-custom-scrollbar-color" : "Benutzerdefinierte Farbe der Scrollbar", + "theme-color-info-active-font-color" : "Schriftfarbe von aktiven Informationen", + "theme-color-info-font-color" : "Schriftfarbe von Informationen", + "theme-color-input-font-color" : "Schriftfarbe der Eingabe", + "theme-color-link-font-color" : "Schriftfarbe des Links", + "theme-color-message-hover-background-color" : "Hintergrundfarbe beim Mauskontakt mit einer Nachricht", + "theme-color-primary-background-color" : "Primäre Hintergrundfarbe ", + "theme-color-primary-font-color" : "Primäre Schriftfarbe", + "theme-color-quaternary-font-color" : "Quartäre Schriftfarbe", + "theme-color-secondary-background-color" : "Sekundäre Hintergrundfarbe", + "theme-color-secondary-font-color" : "Sekundäre Schriftfarbe", + "theme-color-smallprint-font-color" : "Schriftfarbe des Kleingedrucktem", + "theme-color-smallprint-hover-color" : "Farbe bei Mauskontakt mit Kleingedrucktem", + "theme-color-status-away" : "Farbe des Status \"abwesend\"", + "theme-color-status-busy" : "Farbe des Status \"beschäftigt\"", + "theme-color-status-offline" : "Farbe des Status \"offline\"\n", + "theme-color-status-online" : "Farbe des Status \"online\"", + "theme-color-tertiary-background-color" : "Tertiäre Hintergrundfarbe ", + "theme-color-tertiary-font-color" : "Tertiäre Schriftfarbe", + "theme-color-unread-notification-color" : "Farbe von ungelesenen Benachrichtigungen" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json index 1cac00320b14f0da11f7ecc9aac62f1d86b56b38..5535a7a7ecbdca1687c2a9fe9890fef589d15e85 100644 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -1,15 +1,22 @@ { + "theme-color-action-buttons-color" : "Actions Buttons Color", + "theme-color-active-channel-background-color" : "Active Channel Background Color", + "theme-color-active-channel-font-color" : "Active Channel Font Color", "theme-color-blockquote-background" : "Blockquote Background Color", + "theme-color-clean-buttons-color" : "Clean Buttons Color", "theme-color-code-background" : "Code Background Color", "theme-color-code-border" : "Code Border Color", "theme-color-code-color" : "Code Color", "theme-color-content-background-color" : "Content Background Color", + "theme-color-custom-scrollbar-color" : "Custom Scrollbar Color", "theme-color-info-active-font-color" : "Active Info Font Color", "theme-color-info-font-color" : "Info Font Color", "theme-color-input-font-color" : "Input Font Color", "theme-color-link-font-color" : "Link Font Color", + "theme-color-message-hover-background-color" : "Message Hover BG Color", "theme-color-primary-background-color" : "Primary Background Color", "theme-color-primary-font-color" : "Primary Font Color", + "theme-color-quaternary-font-color" : "Quaternary Font Color", "theme-color-secondary-background-color" : "Secondary Background Color", "theme-color-secondary-font-color" : "Secondary Font Color", "theme-color-smallprint-font-color" : "Small Print Font Color", @@ -19,5 +26,6 @@ "theme-color-status-offline" : "Offline Status Color", "theme-color-status-online" : "Online Status Color", "theme-color-tertiary-background-color" : "Tertiary Background Color", - "theme-color-tertiary-font-color" : "Tertiary Font Color" + "theme-color-tertiary-font-color" : "Tertiary Font Color", + "theme-color-unread-notification-color" : "Unread Notifications Color" } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/fi.i18n.json b/packages/rocketchat-theme/i18n/fi.i18n.json index 83ead2db3d3b175b2bb2f21ae85350c50c3bc67f..2ed1a051ebce49a24d46756952c4c13c29b35ee1 100644 --- a/packages/rocketchat-theme/i18n/fi.i18n.json +++ b/packages/rocketchat-theme/i18n/fi.i18n.json @@ -1,15 +1,21 @@ { + "theme-color-action-buttons-color" : "Toimintapainikkeiden väri", + "theme-color-active-channel-background-color" : "Aktiivisen kanavan taustaväri", + "theme-color-active-channel-font-color" : "Aktiivisen kanavan tekstin väri", "theme-color-blockquote-background" : "Lainauksen taustaväri", "theme-color-code-background" : "Koodin taustaväri", "theme-color-code-border" : "Koodin reunusväri", "theme-color-code-color" : "Koodin väri", "theme-color-content-background-color" : "Sisällön taustaväri", + "theme-color-custom-scrollbar-color" : "Vierityspalkin väri (custom)", "theme-color-info-active-font-color" : "Aktiivisen infon fontin väri", "theme-color-info-font-color" : "Infon fontin väri", "theme-color-input-font-color" : "Syötteen fontin väri", "theme-color-link-font-color" : "Linkin fontin väri", + "theme-color-message-hover-background-color" : "Message Hover BG Color", "theme-color-primary-background-color" : "Ensisijainen taustaväri", "theme-color-primary-font-color" : "Ensisijainen fontin väri", + "theme-color-quaternary-font-color" : "Neljäs tekstin väri", "theme-color-secondary-background-color" : "Toissijainen taustaväri", "theme-color-secondary-font-color" : "Toissijainen fontin väri", "theme-color-smallprint-font-color" : "Pienen tekstin fontin väri", diff --git a/packages/rocketchat-theme/i18n/fr.i18n.json b/packages/rocketchat-theme/i18n/fr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..e9164f9d59b2b7f538f96367d44a7df39b7cc156 100644 --- a/packages/rocketchat-theme/i18n/fr.i18n.json +++ b/packages/rocketchat-theme/i18n/fr.i18n.json @@ -1 +1,23 @@ -{ } \ No newline at end of file +{ + "theme-color-blockquote-background" : "Couleur de fond des blocs de citation", + "theme-color-code-background" : "Couleur de fond des blocs de code", + "theme-color-code-border" : "Couleur des bordures du code", + "theme-color-code-color" : "Couleur du code", + "theme-color-content-background-color" : "Couleur de fond du contenu", + "theme-color-info-active-font-color" : "Couleur de la police des informations actives", + "theme-color-info-font-color" : "Couleur de la police des informations", + "theme-color-input-font-color" : "Couleur de la police du champ de message", + "theme-color-link-font-color" : "Couleur de la police des liens", + "theme-color-primary-background-color" : "Couleur de fond principale", + "theme-color-primary-font-color" : "Couleur de la police principale", + "theme-color-secondary-background-color" : "Couleur de fond secondaire", + "theme-color-secondary-font-color" : "Couleur de police secondaire", + "theme-color-smallprint-font-color" : "Couleur de la police des petits messages", + "theme-color-smallprint-hover-color" : "Couleur de survol des petits messages", + "theme-color-status-away" : "Couleur du statut \"Parti\" (AFK)", + "theme-color-status-busy" : "Couleur du statut \"occupé\"", + "theme-color-status-offline" : "Couleur du statut \"hors-ligne\"", + "theme-color-status-online" : "Couleur du statut \"en ligne\"", + "theme-color-tertiary-background-color" : "Couleur de fond tertiaire (contenu)", + "theme-color-tertiary-font-color" : "Couleur de police tertiaire (contenu)" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/km.i18n.json b/packages/rocketchat-theme/i18n/km.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..c1235a4596e35f89514c8b91c4efe6e55bc2710f 100644 --- a/packages/rocketchat-theme/i18n/km.i18n.json +++ b/packages/rocketchat-theme/i18n/km.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "theme-color-code-background" : "កូដពណ៌ផ្ទៃážáž¶áž„ក្រោម", + "theme-color-code-border" : "កូដពណ៌ជាយ", + "theme-color-code-color" : "កូដពណ៌", + "theme-color-content-background-color" : "ពណ៌ផ្ទៃážáž¶áž„ក្រោយអážáŸ’ážáž”áž‘" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ko.i18n.json b/packages/rocketchat-theme/i18n/ko.i18n.json index eae4ba0da589a295cbc5087e78af34444ed9dca7..fa6ce4e77c669ab4241b0e8cc60156c5eb9419e0 100644 --- a/packages/rocketchat-theme/i18n/ko.i18n.json +++ b/packages/rocketchat-theme/i18n/ko.i18n.json @@ -4,6 +4,11 @@ "theme-color-code-border" : "코드 í…Œë‘리 색ìƒ", "theme-color-code-color" : "코드 색ìƒ", "theme-color-content-background-color" : "콘í…ì¸ ë°°ê²½ìƒ‰", + "theme-color-info-font-color" : "ê¸€ìž ìƒ‰ìƒ ì •ë³´", + "theme-color-primary-background-color" : "기본 배경색", + "theme-color-primary-font-color" : "기본 ê¸€ìž ìƒ‰ìƒ", + "theme-color-secondary-background-color" : "ë³´ì¡° 배경색", + "theme-color-secondary-font-color" : "ë³´ì¡° ê¸€ìž ìƒ‰ìƒ", "theme-color-status-away" : "ìžë¦¬ë¹„움 ìƒíƒœ 색ìƒ", "theme-color-status-busy" : "ë°”ì¨ ìƒíƒœ 색ìƒ", "theme-color-status-offline" : "ë³´ì§€ì•ŠìŒ ìƒíƒœ 색ìƒ", diff --git a/packages/rocketchat-theme/i18n/nl.i18n.json b/packages/rocketchat-theme/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..70a0eeb7d0be7f969469de0ffcd36d8e8b9e54e7 100644 --- a/packages/rocketchat-theme/i18n/nl.i18n.json +++ b/packages/rocketchat-theme/i18n/nl.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "theme-color-active-channel-background-color" : "Actieve Kanaal Achtergrondkleur", + "theme-color-active-channel-font-color" : "Actieve Kanaal Tekstkleur", + "theme-color-message-hover-background-color" : "Achtergrondkleur als muis er boven is", + "theme-color-unread-notification-color" : "Ongelezen Notificaties Kleur" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ro.i18n.json b/packages/rocketchat-theme/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..48d9bc9c49231accbc06d01ffeb2581623bdc945 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ro.i18n.json @@ -0,0 +1,31 @@ +{ + "theme-color-action-buttons-color" : "Culoare butoane acÈ›iuni", + "theme-color-active-channel-background-color" : "Culoare de fundal canal activ", + "theme-color-active-channel-font-color" : "Culoare text canal activ", + "theme-color-blockquote-background" : "Culoare de fundal Blockquote ", + "theme-color-clean-buttons-color" : "Culoare butoane curate", + "theme-color-code-background" : "Culoare de fundal cod", + "theme-color-code-border" : "Culoare chenar cod", + "theme-color-code-color" : "Culoare cod", + "theme-color-content-background-color" : "Culoare de fundal conÈ›inut", + "theme-color-custom-scrollbar-color" : "Culoare Scrollbar personalizat", + "theme-color-info-active-font-color" : "Culoare text informaÈ›ii activ", + "theme-color-info-font-color" : "Culoare text info", + "theme-color-input-font-color" : "Culoare text input", + "theme-color-link-font-color" : "Culoare text link", + "theme-color-message-hover-background-color" : "Culoare fundal mesaj la 'hover'", + "theme-color-primary-background-color" : "Culoare de fundal primară", + "theme-color-primary-font-color" : "Culoare text primară", + "theme-color-quaternary-font-color" : "Culoare font cuaternar", + "theme-color-secondary-background-color" : "Culoare de fundal secundară", + "theme-color-secondary-font-color" : "Culoare text secundară", + "theme-color-smallprint-font-color" : "Culoare text mic", + "theme-color-smallprint-hover-color" : "Culoare text mic la 'hover'", + "theme-color-status-away" : "Culoare status 'Away'", + "theme-color-status-busy" : "Culoare status 'Ocupat'", + "theme-color-status-offline" : "Culoare status 'Offline'", + "theme-color-status-online" : "Culoare status 'Activ'", + "theme-color-tertiary-background-color" : "Culoare de fundal terÈ›iară", + "theme-color-tertiary-font-color" : "Culoare text terÈ›iară", + "theme-color-unread-notification-color" : "Culoare notificări mesaje necitite" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/sr.i18n.json b/packages/rocketchat-theme/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-theme/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 0cfa009d7cec513722b36fc7eeae12cc40a3fb6b..027f9d264f3f55d31f4f5ade6f4caff5cea80aa6 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -46,9 +46,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Npm.depends({ diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee old mode 100644 new mode 100755 index 9830698b0e872f2eda6fd872adff964ed2325ea1..3a0557a4e66ea266a9d58bf37d6be00e8b98c75d --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -1,21 +1,30 @@ -RocketChat.theme.addPublicColor "content-background-color", "#FFF" -RocketChat.theme.addPublicColor "primary-background-color", "#04436A" -RocketChat.theme.addPublicColor "secondary-background-color", "#F4F4F4" -RocketChat.theme.addPublicColor "tertiary-background-color", "#EAEAEA" +RocketChat.theme.addPublicColor "primary-background-color", "#04436a" RocketChat.theme.addPublicColor "primary-font-color", "#444444" -RocketChat.theme.addPublicColor "secondary-font-color", "#7F7F7F" +RocketChat.theme.addPublicColor "secondary-background-color", "#f4f4f4" +RocketChat.theme.addPublicColor "secondary-font-color", "#7f7f7f" +RocketChat.theme.addPublicColor "tertiary-background-color", "#eaeaea" RocketChat.theme.addPublicColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" +RocketChat.theme.addPublicColor "quaternary-font-color", "#ffffff" + +RocketChat.theme.addPublicColor "action-buttons-color", "#13679a" +RocketChat.theme.addPublicColor "active-channel-background-color", "rgba(255, 255, 255, 0.075)" +RocketChat.theme.addPublicColor "active-channel-font-color", "rgba(255, 255, 255, 0.75)" +RocketChat.theme.addPublicColor "blockquote-background", "#cccccc" +RocketChat.theme.addPublicColor "clean-buttons-color", "rgba(0, 0, 0, 0.25)" +RocketChat.theme.addPublicColor "code-background", "#f8f8f8" +RocketChat.theme.addPublicColor "code-border", "#cccccc" +RocketChat.theme.addPublicColor "code-color", "#333333" +RocketChat.theme.addPublicColor "content-background-color", "#ffffff" +RocketChat.theme.addPublicColor "custom-scrollbar-color", "rgba(255, 255, 255, 0.05)" +RocketChat.theme.addPublicColor "info-active-font-color", "#ff0000" +RocketChat.theme.addPublicColor "info-font-color", "#aaaaaa" RocketChat.theme.addPublicColor "input-font-color", "rgba(255, 255, 255, 0.85)" -RocketChat.theme.addPublicColor "link-font-color", "#008CE3" -RocketChat.theme.addPublicColor "info-font-color", "#AAAAAA" -RocketChat.theme.addPublicColor "info-active-font-color", "#FF0000" -RocketChat.theme.addPublicColor "smallprint-font-color", "#C2E7FF" -RocketChat.theme.addPublicColor "smallprint-hover-color", "#FFFFFF" -RocketChat.theme.addPublicColor "status-online", "#35AC19" +RocketChat.theme.addPublicColor "link-font-color", "#008ce3" +RocketChat.theme.addPublicColor "message-hover-background-color", "#f9f9f9" +RocketChat.theme.addPublicColor "smallprint-font-color", "#c2e7ff" +RocketChat.theme.addPublicColor "smallprint-hover-color", "#ffffff" +RocketChat.theme.addPublicColor "status-away", "#fcb316" +RocketChat.theme.addPublicColor "status-busy", "#d30230" RocketChat.theme.addPublicColor "status-offline", "rgba(150, 150, 150, 0.50)" -RocketChat.theme.addPublicColor "status-busy", "#D30230" -RocketChat.theme.addPublicColor "status-away", "#FCB316" -RocketChat.theme.addPublicColor "code-background", "#F8F8F8" -RocketChat.theme.addPublicColor "code-border", "#CCC" -RocketChat.theme.addPublicColor "code-color", "#333" -RocketChat.theme.addPublicColor "blockquote-background", "#CCC" +RocketChat.theme.addPublicColor "status-online", "#35ac19" +RocketChat.theme.addPublicColor "unread-notification-color", "#1dce73" diff --git a/packages/rocketchat-ui-account/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee index 78c1828d504c84c7ada2aef2bddd4d27bd7c23b0..8895b85c3445634548329a6f189631e9ab316ecb 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.coffee +++ b/packages/rocketchat-ui-account/account/accountProfile.coffee @@ -7,7 +7,7 @@ Template.accountProfile.helpers return _.sortBy(result, 'key') userLanguage: (key) -> - return (localStorage.getItem('userLanguage') or defaultUserLanguage())?.split('-').shift().toLowerCase() is key + return (Meteor.user().language or defaultUserLanguage())?.split('-').shift().toLowerCase() is key realname: -> return Meteor.user().name @@ -106,3 +106,9 @@ Template.accountProfile.onRendered -> Template.accountProfile.events 'click .submit button': (e, t) -> t.save() + 'click .logoutOthers button': (event, templateInstance) -> + Meteor.logoutOtherClients (error) -> + if error + toastr.error error.reason + else + toastr.success t('Logged_out_of_other_clients_successfully') diff --git a/packages/rocketchat-ui-account/account/accountProfile.html b/packages/rocketchat-ui-account/account/accountProfile.html index 8a6dbfab5d4c037d88e78c0c75c1953d7d553435..b407102a772b906578e90b25e278db53f7cbc0ec 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.html +++ b/packages/rocketchat-ui-account/account/accountProfile.html @@ -59,6 +59,9 @@ <div class="submit"> <button class="button"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> </div> + <div class="logoutOthers"> + <button class="button">{{_ "Logout_Others"}}</button> + </div> </div> </div> </section> diff --git a/packages/rocketchat-ui-account/package.js b/packages/rocketchat-ui-account/package.js index 77b86dc6268700c6db01d19bc64cd4980fade8e7..5e818f1b6b8e320b9a2926903ec3d343474ba5fe 100644 --- a/packages/rocketchat-ui-account/package.js +++ b/packages/rocketchat-ui-account/package.js @@ -18,7 +18,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('account/account.html', 'client'); @@ -36,4 +36,4 @@ Package.onUse(function(api) { api.addFiles('account/avatar/prompt.coffee', 'client'); // api.addAssets('styles/side-nav.less', 'client'); -}); \ No newline at end of file +}); diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 4e215e45f5e737885357f9887e83873c79436094..b637991cd3278ef4aa07ebb40cbb27213766e008 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -1,12 +1,42 @@ +@TempSettings = new Meteor.Collection null +@Settings.find().observe + added: (data) -> + TempSettings.insert data + changed: (data) -> + TempSettings.update data._id, data + removed: (data) -> + TempSettings.remove data._id + + Template.admin.helpers + languages: -> + languages = TAPi18n.getLanguages() + result = [] + for key, language of languages + result.push _.extend(language, { key: key }) + result = _.sortBy(result, 'key') + result.unshift { + "name": "Default", + "en": "Default", + "key": "" + } + return result; + + appLanguage: (key) -> + if !key + return !RocketChat.settings.get('Language') + selected = (RocketChat.settings.get('Language'))?.split('-').shift().toLowerCase() is key + return selected + group: -> group = FlowRouter.getParam('group') - group ?= Settings.findOne({ type: 'group' })?._id - return Settings.findOne { _id: group, type: 'group' } + group ?= TempSettings.findOne({ type: 'group' })?._id + return TempSettings.findOne { _id: group, type: 'group' } sections: -> group = FlowRouter.getParam('group') - group ?= Settings.findOne({ type: 'group' })?._id - settings = Settings.find({ group: group }, {sort: {section: 1, i18nLabel: 1}}).fetch() + group ?= TempSettings.findOne({ type: 'group' })?._id + settings = TempSettings.find({ group: group }, {sort: {section: 1, sorter: 1, i18nLabel: 1}}).fetch() + sections = {} for setting in settings sections[setting.section or ''] ?= [] @@ -20,6 +50,49 @@ Template.admin.helpers return sectionsArray + isDisabled: -> + if not @enableQuery? + return {} + + if _.isString(@enableQuery) + enableQuery = JSON.parse(@enableQuery) + else + enableQuery = @enableQuery + + if not _.isArray(enableQuery) + enableQuery = [enableQuery] + + found = 0 + for item in enableQuery + if TempSettings.findOne(item)? + found++ + + return if found is enableQuery.length then {} else {disabled: 'disabled'} + + hasChanges: (section) -> + group = FlowRouter.getParam('group') + + query = + group: group + changed: true + + if section? + if section is '' + query.$or = [ + {section: ''} + {section: {$exists: false}} + ] + else + query.section = section + + return TempSettings.find(query).count() > 0 + + translateSection: (section) -> + if section.indexOf(':') > -1 + return section + + return t(section) + flexOpened: -> return 'opened' if RocketChat.TabBar.isFlexOpen() arrowPosition: -> @@ -44,28 +117,39 @@ Template.admin.helpers return Random.id() Template.admin.events + "change .input-monitor": (e, t) -> + value = _.trim $(e.target).val() + + switch @type + when 'int' + value = parseInt(value) + when 'boolean' + value = value is "1" + + TempSettings.update {_id: @_id}, + $set: + value: value + changed: Settings.findOne(@_id).value isnt value + "click .submit .save": (e, t) -> group = FlowRouter.getParam('group') - settings = Settings.find({ group: group }).fetch() - updateSettings = [] - for setting in settings - value = null - if setting.type is 'string' - value = _.trim(t.$("[name=#{setting._id}]").val()) - else if setting.type is 'int' - value = parseInt(_.trim(t.$("[name=#{setting._id}]").val())) - else if setting.type is 'boolean' and t.$("[name=#{setting._id}]:checked").length - value = if t.$("[name=#{setting._id}]:checked").val() is "1" then true else false - else if setting.type is 'color' - value = _.trim(t.$("[name=#{setting._id}]").val()) - else if setting.type is 'select' - value = t.$("[name=#{setting._id}]").val() - - if value? - updateSettings.push { _id: setting._id, value: value } - - if not _.isEmpty updateSettings - RocketChat.settings.batchSet updateSettings, (err, success) -> + + query = + group: group + changed: true + + if @section is '' + query.$or = [ + {section: ''} + {section: {$exists: false}} + ] + else + query.section = @section + + settings = TempSettings.find(query, {fields: {_id: 1, value: 1}}).fetch() + + if not _.isEmpty settings + RocketChat.settings.batchSet settings, (err, success) -> return toastr.error TAPi18n.__ 'Error_updating_settings' if err toastr.success TAPi18n.__ 'Settings_updated' @@ -115,17 +199,17 @@ Template.admin.events for blob in files toastr.info TAPi18n.__ 'Uploading_file' - if @fileConstraints.contentType isnt blob.type - toastr.error TAPi18n.__ 'Invalid_file_type' - return + # if @fileConstraints.contentType isnt blob.type + # toastr.error blob.type, TAPi18n.__ 'Invalid_file_type' + # return reader = new FileReader() reader.readAsBinaryString(blob) reader.onloadend = => Meteor.call 'setAsset', reader.result, blob.type, @asset, (err, data) -> if err? - toastr.error TAPi18n.__ err.error - console.log err.error + toastr.error err.reason, TAPi18n.__ err.error + console.log err return toastr.success TAPi18n.__ 'File_uploaded' @@ -159,10 +243,10 @@ Template.admin.onRendered -> Meteor.setTimeout -> $('input.minicolors').minicolors({theme: 'rocketchat'}) - , 500 + , 1000 Tracker.autorun -> FlowRouter.watchPathChange() Meteor.setTimeout -> $('input.minicolors').minicolors({theme: 'rocketchat'}) - , 200 + , 400 diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 492d539321b126e8c1e50d1cc0e4c516d71362f8..195d38f296b7d9fcb2301c38f17815d49adbf818 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -24,7 +24,7 @@ {{#if section}} <div class="section-title"> <div class="section-title-text"> - {{_ section}} + {{translateSection section}} </div> <div class="section-title-right"> <button class="button secondary expand"><span>{{_ "Expand"}}</span></button> @@ -42,40 +42,48 @@ {{/if}} {{/if}} {{#each settings}} - <div class="input-line double-col"> + <div class="input-line double-col {{#if changed}}setting-changed{{/if}}" {{isDisabled}}> <label>{{label}}</label> <div> {{#if $eq type 'string'}} {{#if multiline}} - <textarea name="{{_id}}" rows="4" style="height: auto">{{value}}</textarea> + <textarea class="input-monitor" name="{{_id}}" rows="4" style="height: auto" {{isDisabled}}>{{value}}</textarea> {{else}} - <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> + <input class="input-monitor" type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" {{isDisabled}}/> {{/if}} {{/if}} {{#if $eq type 'int'}} - <input type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> + <input class="input-monitor" type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" {{isDisabled}}/> {{/if}} {{#if $eq type 'boolean'}} - <label><input type="radio" name="{{_id}}" value="1" checked="{{$eq value true}}" /> {{_ "True"}}</label> - <label><input type="radio" name="{{_id}}" value="0" checked="{{$eq value false}}" /> {{_ "False"}}</label> + <label><input class="input-monitor" type="radio" name="{{_id}}" value="1" checked="{{$eq value true}}" {{isDisabled}}/> {{_ "True"}}</label> + <label><input class="input-monitor" type="radio" name="{{_id}}" value="0" checked="{{$eq value false}}" {{isDisabled}}/> {{_ "False"}}</label> {{/if}} {{#if $eq type 'select'}} - <select name="{{_id}}"> + <select class="input-monitor" name="{{_id}}" {{isDisabled}}> {{#each values}} <option value="{{key}}" selected="{{selectedOption ../_id key}}">{{_ i18nLabel}}</option> {{/each}} </select> {{/if}} + {{#if $eq type 'language'}} + <select class="input-monitor" name="{{_id}}" {{isDisabled}}> + {{#each languages}} + <option value="{{key}}" selected="{{appLanguage key}}" dir="auto">{{name}}</option> + {{/each}} + </select> + {{/if}} + {{#if $eq type 'color'}} - <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> + <input class="input-monitor minicolors" type="text" name="{{_id}}" value="{{value}}" {{isDisabled}}/> {{/if}} {{#if $eq type 'action'}} - <button type="button" class="button primary action" data-setting="{{_id}}" data-action="{{value}}">{{_ actionText}}</button> + <button type="button" class="button primary action" data-setting="{{_id}}" data-action="{{value}}" {{isDisabled}}>{{_ actionText}}</button> {{/if}} {{#if $eq type 'asset'}} @@ -101,6 +109,9 @@ {{#if description}} <div class="settings-description">{{{description}}}</div> {{/if}} + {{#if alert}} + <div class="settings-alert"><i class="icon-attention"></i>{{{_ alert}}}</div> + {{/if}} </div> </div> {{/each}} @@ -112,6 +123,12 @@ </div> {{/if}} {{/if}} + + {{#if hasChanges section}} + <div class="submit"> + <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> + </div> + {{/if}} </div> </div> {{/each}} @@ -120,7 +137,6 @@ {{#if $eq group._id 'Accounts'}} <button class="button secondary add-custom-oauth"><span>{{_ "Add_custom_oauth"}}</span></button> {{/if}} - <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> </div> </div> {{/unless}} diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee index f089dff3bed1190176132eeb2e9bea31b5b9da2a..aeb9352b1558b88b9733e57184d6fcfdcc410f76 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee @@ -23,6 +23,7 @@ Template.adminUserEdit.onCreated -> userData = { _id: Template.currentData()._id } userData.name = $("#name", ".edit-form").val() userData.username = $("#username", ".edit-form").val() + userData.password = $("#password", ".edit-form").val() unless userData._id and userData.name toastr.error TAPi18n.__('The_field_is_required'), TAPi18n.__('Name') @@ -32,4 +33,4 @@ Template.adminUserEdit.onCreated -> toastr.success t('User_updated_successfully') instance.cancel() if error - toastr.error error.reason \ No newline at end of file + toastr.error error.reason diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html index 686f999ffdba88b0c4db402a401fba8d0247fbf8..f1e620f95f96097c3dc9e0066633a6be064e5e37 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -13,6 +13,12 @@ <label for="username">{{_ "Username"}}</label> <input type="text" id="username" autocomplete="off" value="{{username}}"> </div> + {{#if hasPermission 'edit-other-user-password'}} + <div class="input-line"> + <label for="password">{{_ "Password"}}</label> + <input type="password" id="password" autocomplete="off" value=""> + </div> + {{/if}} </form> </div> <nav> @@ -20,4 +26,4 @@ <button class='button button-block blue save'><span>{{_ "Save"}}</span></button> </nav> {{/unless}} -</template> \ No newline at end of file +</template> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee index 098901fb5b2a58ce5841cf2e03d072f40cbb8288..e09e66e2a09394293e03edf38fbbce508c348542 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee @@ -37,7 +37,23 @@ Template.adminUsers.onCreated -> @filter = new ReactiveVar '' @ready = new ReactiveVar true - RocketChat.TabBar.addButton({ id: 'invite-user', i18nTitle: t('Invite_Users'), icon: 'icon-plus', template: 'adminInviteUser', order: 1 }) + RocketChat.TabBar.addButton({ + groups: ['adminusers', 'adminusers-selected'], + id: 'invite-user', + i18nTitle: 'Invite_Users', + icon: 'icon-plus', + template: 'adminInviteUser', + order: 1 + }) + + RocketChat.TabBar.addButton({ + groups: ['adminusers-selected'] + id: 'admin-user-info', + i18nTitle: 'User_Info', + icon: 'icon-user', + template: 'adminUserInfo', + order: 2 + }) @autorun -> filter = instance.filter.get() @@ -49,11 +65,10 @@ Template.adminUsers.onCreated -> if Session.get 'adminSelectedUser' channelSubscription = instance.subscribe 'userChannels', Session.get 'adminSelectedUser' RocketChat.TabBar.setData Meteor.users.findOne Session.get 'adminSelectedUser' - RocketChat.TabBar.addButton({ id: 'user-info', i18nTitle: t('User_Info'), icon: 'icon-user', template: 'adminUserInfo', order: 2 }) - # RocketChat.TabBar.addButton({ id: 'user-channel', i18nTitle: t('User_Channels'), icon: 'icon-hash', template: 'adminUserChannels', order: 3 }) + + RocketChat.TabBar.showGroup 'adminusers-selected' else - RocketChat.TabBar.reset() - RocketChat.TabBar.addButton({ id: 'invite-user', i18nTitle: t('Invite_Users'), icon: 'icon-plus', template: 'adminInviteUser', order: 1 }) + RocketChat.TabBar.showGroup 'adminusers' @users = -> filter = _.trim instance.filter?.get() @@ -89,8 +104,8 @@ Template.adminUsers.events 'click .user-info': (e) -> e.preventDefault() - Session.set 'adminSelectedUser', $(e.currentTarget).data('id') - Session.set 'showUserInfo', Meteor.users.findOne($(e.currentTarget).data('id'))?.username or true + Session.set 'adminSelectedUser', @_id + Session.set 'showUserInfo', Meteor.users.findOne(@_id)?.username or true RocketChat.TabBar.setTemplate 'adminUserInfo' RocketChat.TabBar.openFlex() diff --git a/packages/rocketchat-ui-admin/admin/users/adminUsers.html b/packages/rocketchat-ui-admin/admin/users/adminUsers.html index 828ca152200bcf67a18da83f9da51fe2d8a42ee6..aa410e3c9876abec3c1e96930894b7f5398d2db3 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUsers.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUsers.html @@ -32,7 +32,7 @@ </thead> <tbody> {{#each users}} - <tr class="user-info" data-id="{{_id}}"> + <tr class="user-info"> <td> <div class="user-image status-{{status}}"> {{> avatar username=username}} diff --git a/packages/rocketchat-ui-admin/package.js b/packages/rocketchat-ui-admin/package.js index bebed82fd631dcbe5bf009830b426ab110f8d8c9..6fc80872456d68c7c0a8cfe2dc00290c20e22c8d 100644 --- a/packages/rocketchat-ui-admin/package.js +++ b/packages/rocketchat-ui-admin/package.js @@ -18,7 +18,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); // template files diff --git a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee index 0177eb907c6625b535c8debaf023b59c00065d17..f308646ffbbbcdf3563cbdfc8c0696ab979e1c8f 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee @@ -2,26 +2,41 @@ Template.flexTabBar.helpers active: -> return 'active' if @template is RocketChat.TabBar.getTemplate() and RocketChat.TabBar.isFlexOpen() buttons: -> - RocketChat.TabBar.getButtons() return RocketChat.TabBar.getButtons() title: -> return t(@i18nTitle) or @title + visible: -> + if @groups.indexOf(RocketChat.TabBar.getVisibleGroup()) is -1 + return 'hidden' Template.flexTabBar.events 'click .tab-button': (e, t) -> e.preventDefault() - if RocketChat.TabBar.isFlexOpen() and RocketChat.TabBar.getTemplate() is $(e.currentTarget).data('template') + if RocketChat.TabBar.isFlexOpen() and RocketChat.TabBar.getTemplate() is @template RocketChat.TabBar.closeFlex() $('.flex-tab').css('max-width', '') else - width = $(e.currentTarget).data('width') - - if width? - $('.flex-tab').css('max-width', "#{width}px") + if @width? + $('.flex-tab').css('max-width', "#{@width}px") else $('.flex-tab').css('max-width', '') - RocketChat.TabBar.setTemplate $(e.currentTarget).data('template'), -> + RocketChat.TabBar.setTemplate @template, -> $('.flex-tab')?.find("input[type='text']:first")?.focus() $('.flex-tab .content')?.scrollTop(0) + +Template.flexTabBar.onCreated -> + # close flex if the visible group changed and the opened template is not in the new visible group + @autorun => + visibleGroup = RocketChat.TabBar.getVisibleGroup() + + Tracker.nonreactive => + openedTemplate = RocketChat.TabBar.getTemplate() + exists = false + RocketChat.TabBar.getButtons().forEach (button) -> + if button.groups.indexOf(visibleGroup) isnt -1 and openedTemplate is button.template + exists = true + + unless exists + RocketChat.TabBar.closeFlex() diff --git a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html index 8a971f49990e49f7ce8a19fc3c12ec862a4cde7c..10baeed54dbef01f0e924bb208c791ea127766a2 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html +++ b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html @@ -1,6 +1,6 @@ <template name="flexTabBar"> {{#each buttons}} - <div class="tab-button {{active}}" data-template="{{template}}" data-width="{{width}}" title="{{title}}"> + <div class="tab-button {{active}} {{visible}}" title="{{title}}"> <i class="{{icon}}" aria-label="{{title}}" role="button" tabindex="0"></i> </div> {{/each}} diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee index 59d128eec8e2d0bbcd1374316d1226a0cf06d34d..0d3113623d8b2de24d109b906c8cc6c0ddfedc83 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee @@ -1,3 +1,16 @@ +Meteor.startup -> + RocketChat.MessageAction.addButton + id: 'jump-to-search-message' + icon: 'icon-right-hand' + i18nLabel: 'Jump_to_message' + action: (event, instance) -> + message = @_arguments[1] + $('.message-dropdown:visible').hide() + RoomHistoryManager.getSurroundingMessages(message, 50) + + order: 100 + + Template.messageSearch.helpers tSearchMessages: -> return t('Search_Messages') @@ -5,6 +18,15 @@ Template.messageSearch.helpers searchResultMessages: -> return Template.instance().searchResult.get()?.messages + hasMore: -> + return Template.instance().hasMore.get() + + currentSearchTerm: -> + return Template.instance().currentSearchTerm.get() + + ready: -> + return Template.instance().ready.get() + Template.messageSearch.events "keydown #message-search": (e) -> if e.keyCode is 13 @@ -12,20 +34,56 @@ Template.messageSearch.events "keyup #message-search": _.debounce (e, t) -> value = e.target.value.trim() - if value is '' and t.currentSearchTerm - t.currentSearchTerm = '' + if value is '' and t.currentSearchTerm.get() + t.currentSearchTerm.set '' t.searchResult.set undefined + t.hasMore.set false return - else if value is t.currentSearchTerm + else if value is t.currentSearchTerm.get() return - Tracker.nonreactive -> - Meteor.call 'messageSearch', value, Session.get('openedRoom'), (error, result) -> - if result? and (result.messages?.length > 0 or result.users?.length > 0 or result.channels?.length > 0) - t.searchResult.set result - t.currentSearchTerm = value + t.hasMore.set true + t.limit.set 20 + t.search() , 500 + 'click .message-cog': (e, t) -> + e.stopPropagation() + e.preventDefault() + message_id = $(e.currentTarget).closest('.message').attr('id') + $('.message-dropdown:visible').hide() + $(".search-messages-list \##{message_id} .message-dropdown").remove() + message = _.findWhere(t.searchResult.get()?.messages, (message) -> return message._id is message_id) + actions = RocketChat.MessageAction.getButtons message + el = Blaze.toHTMLWithData Template.messageDropdown, { actions: actions } + $(".search-messages-list \##{message_id} .message-cog-container").append el + dropDown = $(".search-messages-list \##{message_id} .message-dropdown") + dropDown.show() + + 'scroll .content': _.throttle (e, t) -> + if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + t.limit.set(t.limit.get() + 20) + t.search() + , 200 + Template.messageSearch.onCreated -> - this.currentSearchTerm = '' - this.searchResult = new ReactiveVar + @currentSearchTerm = new ReactiveVar '' + @searchResult = new ReactiveVar + + @hasMore = new ReactiveVar true + @limit = new ReactiveVar 20 + @ready = new ReactiveVar true + + @search = => + @ready.set false + value = @$('#message-search').val() + Tracker.nonreactive => + Meteor.call 'messageSearch', value, Session.get('openedRoom'), @limit.get(), (error, result) => + @currentSearchTerm.set value + @ready.set true + if result? and (result.messages?.length > 0 or result.users?.length > 0 or result.channels?.length > 0) + @searchResult.set result + if result.messages?.length + result.users?.length + result.channels?.length < @limit.get() + @hasMore.set false + else + @searchResult.set() diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html index 25931d649876b62087e70689c6027153ed79c340..3b31486a97ab9a8cd4768b1b81fabfaad2d2b07c 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html @@ -1,17 +1,34 @@ <template name="messageSearch"> <div class="content"> - <div class="control"> - <form class="search-form" role="form"> - <div class="input-line search"> - <input type="text" id="message-search" class="search" placeholder="{{tSearchMessages}}" autocomplete="off" /> - <i class="icon-right-open-small"></i> - </div> - </form> + <div class="list-view search-messages-list"> + <div class="control"> + <form class="search-form" role="form"> + <div class="input-line search"> + <input type="text" id="message-search" class="search" placeholder="{{tSearchMessages}}" autocomplete="off" /> + <i class="icon-right-open-small"></i> + </div> + </form> + </div> + <ul class="list clearfix"> + {{#if currentSearchTerm}} + {{#if searchResultMessages}} + {{#each searchResultMessages}} + {{#nrr nrrargs 'message' .}}{{/nrr}} + {{/each}} + {{#if hasMore}} + <li class="load-more"> + {{#if ready}} + <a href="">{{_ "Has_more"}}...</a> + {{else}} + <div class="load-more-loading">{{_ "Loading..."}}</div> + {{/if}} + </li> + {{/if}} + {{else}} + <h2 class="no-results">{{_ "No_results_found"}}</h2> + {{/if}} + {{/if}} + </ul> </div> - <ul> - {{#each searchResultMessages}} - {{#nrr nrrargs 'message' .}}{{/nrr}} - {{/each}} - </ul> </div> </template> diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index d46b484db5d044525abc90a2954d89a73e71b51f..1f8b59a0cbf003f6c94bbfa5ebeb2dec848752d8 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -1,32 +1,46 @@ roomFiles = new Mongo.Collection 'room_files' Template.uploadedFilesList.helpers - files: -> - return roomFiles.find({ rid: this.rid }).fetch() + files: -> + return roomFiles.find({ rid: @rid }, { sort: {uploadedAt : -1} }).fetch() - hasFiles: -> - return roomFiles.find({ rid: this.rid }).count() > 0 + hasFiles: -> + return roomFiles.find({ rid: @rid }).count() > 0 - getFileIcon: (type) -> - if type.match(/^image\/.+$/) - return 'icon-picture' + hasMore: -> + return Template.instance().hasMore.get() - return 'icon-docs' + getFileIcon: (type) -> + if type.match(/^image\/.+$/) + return 'icon-picture' - customClassForFileType: -> - if this.type.match(/^image\/.+$/) - return 'room-files-swipebox' + return 'icon-docs' - escapedName: -> - return s.escapeHTML @name + customClassForFileType: -> + if @type.match(/^image\/.+$/) + return 'room-files-swipebox' + + escapedName: -> + return s.escapeHTML @name Template.uploadedFilesList.events - 'click .room-file-item': (e, t) -> - if $(e.currentTarget).siblings('.icon-picture').length - e.preventDefault() + 'click .room-file-item': (e, t) -> + if $(e.currentTarget).siblings('.icon-picture').length + e.preventDefault() + + 'scroll .content': _.throttle (e, t) -> + if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + t.limit.set(t.limit.get() + 50) + , 200 Template.uploadedFilesList.onCreated -> - this.subscribe 'roomFiles', Template.currentData().rid + rid = Template.currentData().rid + @hasMore = new ReactiveVar true + @limit = new ReactiveVar 50 + @autorun => + @subscribe 'roomFiles', rid, @limit.get(), => + if roomFiles.find({ rid: rid }).fetch().length < @limit.get() + @hasMore.set false Template.uploadedFilesList.onRendered -> - $('.room-files-swipebox').swipebox() + $('.room-files-swipebox').swipebox() diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html index f50af8c5ad994150fafe53cc86205d511b28188b..2ac193623080ad8255ebe1c3769357e06f3db615 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html @@ -1,27 +1,33 @@ <template name="uploadedFilesList"> - <div class="content"> - <div class="list-view uploaded-files-list"> - <div class="status"> - <h2>{{_ "Room_uploaded_file_list"}}</h2> - </div> - {{#if Template.subscriptionsReady}} - {{#if hasFiles }} - <ul class='list clearfix lines'> - {{#each files}} - <li> - <a title="{{escapedName}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> - <i class="{{getFileIcon type}}"></i> - <p>{{name}}</p> - </a> - </li> - {{/each}} - </ul> - {{else}} - <h2>{{_ "Room_uploaded_file_list_empty"}}</h2> - {{/if}} - {{else}} - <span>{{_ "Loading..."}}</span> - {{/if}} - </div> - </div> + <div class="content"> + <div class="list-view uploaded-files-list"> + <div class="status"> + <h2>{{_ "Room_uploaded_file_list"}}</h2> + </div> + <ul class="list clearfix lines"> + {{#each files}} + <li> + <a title="{{escapedName}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> + <i class="{{getFileIcon type}}"></i> + <p>{{name}}</p> + </a> + </li> + {{/each}} + {{#if hasMore}} + <li class="load-more"> + {{#if Template.subscriptionsReady}} + <a href="">{{_ "Has_more"}}...</a> + {{else}} + <div class="load-more-loading">{{_ "Loading..."}}</div> + {{/if}} + </li> + {{/if}} + </ul> + {{#if Template.subscriptionsReady}} + {{#unless hasFiles}} + <h2>{{_ "Room_uploaded_file_list_empty"}}</h2> + {{/unless}} + {{/if}} + </div> + </div> </template> diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 341af443b10324f82be702fb82bd022b591c22cf..3c3dc4c6da3a3dd3ac099f8c729043d1f18de2c3 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -31,7 +31,31 @@ Template.userInfo.helpers userTime: -> if @utcOffset? - return Template.instance().now.get().utcOffset(@utcOffset).format('HH:mm') + return Template.instance().now.get().utcOffset(@utcOffset).format('LT') + + canRemoveUser: -> + return RocketChat.authz.hasAllPermission('remove-user', Session.get('openedRoom')) + + canMuteUser: -> + return RocketChat.authz.hasAllPermission('mute-user', Session.get('openedRoom')) + + userMuted: -> + room = ChatRoom.findOne(Session.get('openedRoom')) + if _.isArray(room?.muted) and room.muted.indexOf(Session.get('showUserInfo')) isnt -1 + return true + return false + + canSetModerator: -> + return RocketChat.authz.hasAllPermission('set-moderator', Session.get('openedRoom')) + + isModerator: -> + return !!RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user?._id, roles: 'moderator' }) + + canSetOwner: -> + return RocketChat.authz.hasAllPermission('set-owner', Session.get('openedRoom')) + + isOwner: -> + return !!RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user?._id, roles: 'owner' }) Template.userInfo.events 'click .pvt-msg': (e) -> @@ -72,6 +96,120 @@ Template.userInfo.events 'click .back': (e) -> Session.set('showUserInfo', null) + 'click .remove-user': (e) -> + e.preventDefault() + rid = Session.get('openedRoom') + room = ChatRoom.findOne rid + if RocketChat.authz.hasAllPermission('remove-user', rid) + swal { + title: t('Are_you_sure') + text: t('The_user_will_be_removed_from_s', room.name) + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_remove_user') + cancelButtonText: t('Cancel') + closeOnConfirm: false + html: false + }, => + Meteor.call 'removeUserFromRoom', { rid: rid, username: @user.username }, (err, result) -> + if err + return toastr.error(err.reason or err.message) + swal + title: t('Removed') + text: t('User_has_been_removed_from_s', room.name) + type: 'success' + timer: 2000 + showConfirmButton: false + Session.set('showUserInfo', null) + else + toastr.error(TAPi18n.__ 'Not_allowed') + + 'click .mute-user': (e) -> + e.preventDefault() + rid = Session.get('openedRoom') + room = ChatRoom.findOne rid + if RocketChat.authz.hasAllPermission('mute-user', rid) + swal { + title: t('Are_you_sure') + text: t('The_user_wont_be_able_to_type_in_s', room.name) + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_mute_user') + cancelButtonText: t('Cancel') + closeOnConfirm: false + html: false + }, => + Meteor.call 'muteUserInRoom', { rid: rid, username: @user.username }, (err, result) -> + if err + return toastr.error(err.reason or err.message) + swal + title: t('Muted') + text: t('User_has_been_muted_in_s', room.name) + type: 'success' + timer: 2000 + showConfirmButton: false + + 'click .unmute-user': (e, t) -> + e.preventDefault() + rid = Session.get('openedRoom') + room = ChatRoom.findOne rid + if RocketChat.authz.hasAllPermission('mute-user', rid) + Meteor.call 'unmuteUserInRoom', { rid: rid, username: @user.username }, (err, result) -> + if err + return toastr.error(err.reason or err.message) + toastr.success TAPi18n.__ 'User_unmuted_in_room' + else + toastr.error(TAPi18n.__ 'Not_allowed') + + 'click .set-moderator': (e, t) -> + e.preventDefault() + + userModerator = RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id, roles: 'moderator' }, { fields: { _id: 1 } }) + unless userModerator? + Meteor.call 'addRoomModerator', Session.get('openedRoom'), @user._id, (err, results) => + if err + return toastr.error(err.reason or err.message) + + room = ChatRoom.findOne(Session.get('openedRoom')) + toastr.success TAPi18n.__ 'User__username__is_now_a_moderator_of__room_name_', { username: @user.username, room_name: room.name } + + 'click .unset-moderator': (e, t) -> + e.preventDefault() + + userModerator = RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id, roles: 'moderator' }, { fields: { _id: 1 } }) + if userModerator? + Meteor.call 'removeRoomModerator', Session.get('openedRoom'), @user._id, (err, results) => + if err + return toastr.error(err.reason or err.message) + + room = ChatRoom.findOne(Session.get('openedRoom')) + toastr.success TAPi18n.__ 'User__username__removed_from__room_name__moderators', { username: @user.username, room_name: room.name } + + 'click .set-owner': (e, t) -> + e.preventDefault() + + userOwner = RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id, roles: 'owner' }, { fields: { _id: 1 } }) + unless userOwner? + Meteor.call 'addRoomOwner', Session.get('openedRoom'), @user._id, (err, results) => + if err + return toastr.error(err.reason or err.message) + + room = ChatRoom.findOne(Session.get('openedRoom')) + toastr.success TAPi18n.__ 'User__username__is_now_a_owner_of__room_name_', { username: @user.username, room_name: room.name } + + 'click .unset-owner': (e, t) -> + e.preventDefault() + + userOwner = RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id, roles: 'owner' }, { fields: { _id: 1 } }) + if userOwner? + Meteor.call 'removeRoomOwner', Session.get('openedRoom'), @user._id, (err, results) => + if err + return toastr.error(err.reason or err.message) + + room = ChatRoom.findOne(Session.get('openedRoom')) + toastr.success TAPi18n.__ 'User__username__removed_from__room_name__owners', { username: @user.username, room_name: room.name } Template.userInfo.onCreated -> @now = new ReactiveVar moment() diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html index 844f5126c3ea39c4fa4691d7687b16cd8056ff47..bad3b31f4786ebbccbd7a98714f4ca2b2d080b01 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html @@ -30,10 +30,34 @@ {{> videoButtons}} {{#if showAll}} - <button class='button secondary back'><span>{{_ "View_All"}} <i class='icon-angle-right'></i></span></button> {{#if canDirectMessage user.username}} - <button class='button pvt-msg'><span><i class='icon-chat'></i> {{_ "Conversation"}}</span></button> + <button class='button button-block pvt-msg'><span><i class='icon-chat'></i> {{_ "Conversation"}}</span></button> + {{/if}} + {{#if canSetOwner}} + {{#if isOwner}} + <button class="button button-block unset-owner lightblue"><span>{{_ "Remove_as_owner"}}</span></button> + {{else}} + <button class="button button-block set-owner lightblue"><span>{{_ "Set_as_owner"}}</span></button> + {{/if}} + {{/if}} + {{#if canSetModerator}} + {{#if isModerator}} + <button class="button button-block unset-moderator lightblue"><span>{{_ "Remove_as_moderator"}}</span></button> + {{else}} + <button class="button button-block set-moderator lightblue"><span>{{_ "Set_as_moderator"}}</span></button> + {{/if}} {{/if}} + {{#if canRemoveUser}} + <button class="button button-block remove-user red"><span>{{_ "Remove_from_room"}}</span></button> + {{/if}} + {{#if canMuteUser}} + {{#if userMuted}} + <button class="button button-block unmute-user primary"><span>{{_ "Unmute_user"}}</span></button> + {{else}} + <button class="button button-block mute-user red"><span>{{_ "Mute_user"}}</span></button> + {{/if}} + {{/if}} + <button class='button secondary back'><span>{{_ "View_All"}} <i class='icon-angle-right'></i></span></button> {{/if}} </nav> {{/if}} diff --git a/packages/rocketchat-ui-flextab/package.js b/packages/rocketchat-ui-flextab/package.js index e508f10d508e852834862fd3156a6068a28d9e21..98a1b68a2c00b806c1169b386104c89524ab0ffa 100644 --- a/packages/rocketchat-ui-flextab/package.js +++ b/packages/rocketchat-ui-flextab/package.js @@ -22,6 +22,8 @@ Package.onUse(function(api) { 'rocketchat:lib' ]); + api.use('rocketchat:ui'); + api.addFiles('flex-tab/flexTabBar.html', 'client'); api.addFiles('flex-tab/tabs/membersList.html', 'client'); api.addFiles('flex-tab/tabs/messageSearch.html', 'client'); diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 52ef48d4bcb98ecf285293196cf6e8eb6d71f4fe..5d9946acac25f9fa7376035bec2f3ba886c2f88e 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -5,6 +5,9 @@ Template.loginForm.helpers namePlaceholder: -> return if RocketChat.settings.get 'Accounts_RequireNameForSignUp' then t('Name') else t('Name_optional') + showFormLogin: -> + return RocketChat.settings.get 'Accounts_ShowFormLogin' + showName: -> return 'hidden' unless Template.instance().state.get() is 'register' @@ -115,6 +118,8 @@ Template.loginForm.events else toastr.error t 'User_not_found_or_incorrect_password' return + localStorage.setItem('userLanguage', Meteor.user()?.language) + setLanguage(Meteor.user()?.language) 'click .register': -> Template.instance().state.set 'register' diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index 575459711cf5f23df907b37520143fa09b198c29..d84200d39144326a64006bc2fb88ea86f0c20254 100644 --- a/packages/rocketchat-ui-login/login/form.html +++ b/packages/rocketchat-ui-login/login/form.html @@ -4,7 +4,7 @@ You must login to Sandstorm (on the top right) in order to access this chat. </div> {{else}} - <form id="login-card" method='/'> + <form id="login-card" method='/' novalidate> {{#if waitActivation}} <header> <h2>{{{_ "Registration_Succeeded"}}}</h2> @@ -18,37 +18,41 @@ {{_ "You_need_confirm_email"}} </div> {{/if}} - <div class="fields"> - <div class='input-text active {{showName}}'> - <input type="text" name='name' placeholder='{{namePlaceholder}}' dir="auto" /> + {{#if showFormLogin}} + <div class="fields"> + <div class='input-text active {{showName}}'> + <input type="text" name='name' placeholder='{{namePlaceholder}}' dir="auto" /> + </div> + <div class='input-text active {{showEmailOrUsername}}'> + <input type="text" name='emailOrUsername' placeholder='{{_ "Email_or_username"}}' autocapitalize="off" autocorrect="off" /> + </div> + <div class='input-text active {{showEmail}}'> + <input type="email" name='email' placeholder='{{_ "Email"}}' /> + </div> + <div class='input-text active {{showPassword}}'> + <input type="password" name='pass' placeholder='{{_ "Password"}}' /> + </div> + <div class='input-text active {{showConfirmPassword}}'> + <input type="password" name='confirm-pass' placeholder='{{_ "Confirm_password"}}' /> + </div> </div> - <div class='input-text active {{showEmailOrUsername}}'> - <input type="text" name='emailOrUsername' placeholder='{{_ "Email_or_username"}}' autocapitalize="off" autocorrect="off" /> + <div class="submit"> + <button data-loading-text="{{_ "Please_wait"}}..." class='button primary login'><span>{{btnLoginSave}}</span></button> </div> - <div class='input-text active {{showEmail}}'> - <input type="email" name='email' placeholder='{{_ "Email"}}' /> + {{#if registrationAllowed}} + <div class="register {{showRegisterLink}}"> + <a href="">{{_ 'Register'}}</a> </div> - <div class='input-text active {{showPassword}}'> - <input type="password" name='pass' placeholder='{{_ "Password"}}' /> + {{else}} + {{#if linkReplacementText}} + {{{linkReplacementText}}} + {{/if}} + {{/if}} + {{#if passwordresetAllowed}} + <div class="forgot-password {{showForgotPasswordLink}}"> + <a href="">{{_ 'Forgot_password'}}</a> </div> - <div class='input-text active {{showConfirmPassword}}'> - <input type="password" name='confirm-pass' placeholder='{{_ "Confirm_password"}}' /> - </div> - </div> - <div class="submit"> - <button data-loading-text="{{_ "Please_wait"}}..." class='button primary login'><span>{{btnLoginSave}}</span></button> - </div> - {{#if registrationAllowed}} - <div class="register {{showRegisterLink}}"> - <a href="">{{_ 'Register'}}</a> - </div> - {{else}}{{#if linkReplacementText}} - {{{linkReplacementText}}} - {{/if}}{{/if}} - {{#if passwordresetAllowed}} - <div class="forgot-password {{showForgotPasswordLink}}"> - <a href="">{{_ 'Forgot_password'}}</a> - </div> + {{/if}} {{/if}} {{/if}} <div class="back-to-login {{showBackToLoginLink}}"> diff --git a/packages/rocketchat-ui-login/login/layout.html b/packages/rocketchat-ui-login/login/layout.html index 3cf9cd1bb298c9f036f1b5209e8f2835e6176a31..a097d5834bb2a9f91fd6892e1a06221dd2e17524 100644 --- a/packages/rocketchat-ui-login/login/layout.html +++ b/packages/rocketchat-ui-login/login/layout.html @@ -2,7 +2,7 @@ <section class="full-page"> <div class="wrapper"> {{ > loginHeader }} - {{ > loginForm }} + {{> Template.dynamic template=center}} {{ > loginFooter }} </div> </section> diff --git a/packages/rocketchat-ui-login/package.js b/packages/rocketchat-ui-login/package.js index 5b2c11042cbc43f79ad3d0a646a1b166440571df..750c1a7736d2b553336625c7d4ac7831534fa597 100644 --- a/packages/rocketchat-ui-login/package.js +++ b/packages/rocketchat-ui-login/package.js @@ -17,9 +17,16 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); + api.use('kadira:flow-router', 'client'); + + api.addFiles('routes.js', 'client'); + + api.addFiles('reset-password/resetPassword.html', 'client'); + api.addFiles('reset-password/resetPassword.js', 'client'); + api.addFiles('login/footer.html', 'client'); api.addFiles('login/form.html', 'client'); api.addFiles('login/header.html', 'client'); @@ -37,4 +44,4 @@ Package.onUse(function(api) { api.addFiles('login/services.coffee', 'client'); api.addFiles('login/social.coffee', 'client'); api.addFiles('username/username.coffee', 'client'); -}); \ No newline at end of file +}); diff --git a/packages/rocketchat-ui-login/reset-password/resetPassword.html b/packages/rocketchat-ui-login/reset-password/resetPassword.html new file mode 100644 index 0000000000000000000000000000000000000000..56d2468673008c30a6f730ea9594785b596825b1 --- /dev/null +++ b/packages/rocketchat-ui-login/reset-password/resetPassword.html @@ -0,0 +1,15 @@ +<template name="resetPassword"> + <form id="login-card" action="/"> + <div class="fields"> + <header> + <p>{{_ "Please_enter_your_new_password_below"}}</p> + </header> + <div class="input-text active"> + <input type="password" name="newPassword" placeholder="{{_ "Type_your_new_password"}}" dir="auto" /> + </div> + <div class="submit"> + <button data-loading-text="{{_ "Please_wait"}}..." class="button primary resetpass"><span>{{_ "Reset"}}</span></button> + </div> + </div> + </form> +</template> diff --git a/packages/rocketchat-ui-login/reset-password/resetPassword.js b/packages/rocketchat-ui-login/reset-password/resetPassword.js new file mode 100644 index 0000000000000000000000000000000000000000..ae91df0718059ed8f6c97a6bba12a915b0702fd6 --- /dev/null +++ b/packages/rocketchat-ui-login/reset-password/resetPassword.js @@ -0,0 +1,26 @@ +Template.resetPassword.events({ + 'submit #login-card': function(event, instance) { + event.preventDefault(); + + var button = instance.$('button.resetpass'); + RocketChat.Button.loading(button); + + Accounts.resetPassword(FlowRouter.getParam('token'), instance.find('[name=newPassword]').value, function(error) { + RocketChat.Button.reset(button); + if (error) { + console.log(error); + swal({ + title: t('Error_changing_password'), + type: 'error' + }); + } else { + FlowRouter.go('home'); + toastr.success(t('Password_changed_successfully')); + } + }); + } +}); + +Template.resetPassword.onRendered(function() { + this.find('[name=newPassword]').focus(); +}); diff --git a/packages/rocketchat-ui-login/routes.js b/packages/rocketchat-ui-login/routes.js new file mode 100644 index 0000000000000000000000000000000000000000..a6ac9f5b22f443156e96e13a774763b5cec4546c --- /dev/null +++ b/packages/rocketchat-ui-login/routes.js @@ -0,0 +1,6 @@ +FlowRouter.route('/reset-password/:token', { + name: 'resetPassword', + action: function() { + BlazeLayout.render('loginLayout', {center: 'resetPassword'}); + } +}); diff --git a/packages/rocketchat-ui-master/master/main.coffee b/packages/rocketchat-ui-master/master/main.coffee index 14ec9d986b25fe20dc93d0d4697fc24e092ceec1..a5896523f8a207399d5ed61a7a0632d2904a74e7 100644 --- a/packages/rocketchat-ui-master/master/main.coffee +++ b/packages/rocketchat-ui-master/master/main.coffee @@ -216,3 +216,5 @@ Template.main.onRendered -> # RTL Support - Need config option on the UI if isRtl localStorage.getItem "userLanguage" $('html').addClass "rtl" + else + $('html').removeClass "rtl" diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index abf74f660a8810a9a84504e3287566719981adae..68d5ba17aef520fd861b3dc80e1055fde5a7856c 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -43,7 +43,10 @@ <template name="main"> {{#if subsReady}} {{#unless logged}} - {{> loginLayout}} + <div class="connection-status"> + {{> status}} + </div> + {{> loginLayout center="loginForm"}} {{else}} {{#unless hasUsername}} {{> username}} @@ -56,13 +59,17 @@ <div class="connection-status"> {{> status}} </div> - <div class="flex-tab-bar" role="toolbar"> - {{> flexTabBar}} - </div> - <div class="main-content {{flexOpened}} {{flexOpenedRTC1}} {{flexOpenedRTC2}}"> + {{#unless modal}} + <div class="flex-tab-bar" role="toolbar"> + {{> flexTabBar}} + </div> + {{/unless}} + <div class="main-content {{flexOpened}} {{flexOpenedRTC1}} {{flexOpenedRTC2}} {{#if modal}}main-modal{{/if}}"> {{> Template.dynamic template=center}} </div> - {{> sideNav }} + {{#unless modal}} + {{> sideNav }} + {{/unless}} </div> {{> audioNotification }} {{/unless}} diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index c596d6e36af72a8bf0fc35847bd7c248ccfeeb73..6295dd6b95783ff0082fbbad1e12983974166910 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -1,12 +1,20 @@ Template.message.helpers isBot: -> return 'bot' if this.bot? + isGroupable: -> + return 'false' if this.groupable is false + isSequential: -> + return 'sequential' if this.groupable isnt false + getEmoji: (emoji) -> + return emojione.toImage emoji own: -> return 'own' if this.u?._id is Meteor.userId() + timestamp: -> + return +this.ts chatops: -> return 'chatops-message' if this.u?.username is RocketChat.settings.get('Chatops_Username') time: -> - return moment(this.ts).format('HH:mm') + return moment(this.ts).format('LT') date: -> return moment(this.ts).format('LL') isTemp: -> @@ -24,15 +32,13 @@ Template.message.helpers editTime: -> if Template.instance().wasEdited - return moment(@editedAt).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? + return moment(@editedAt).format('LL LT') #TODO profile pref for 12hr/24hr clock? editedBy: -> return "" unless Template.instance().wasEdited # try to return the username of the editor, # otherwise a special "?" character that will be # rendered as a special avatar return @editedBy?.username or "?" - pinned: -> - return this.pinned canEdit: -> hasPermission = RocketChat.authz.hasAtLeastOnePermission('edit-message', this.rid) isEditAllowed = RocketChat.settings.get 'Message_AllowEditing' @@ -53,10 +59,6 @@ Template.message.helpers return true return RocketChat.settings.get('Message_AllowDeleting') and this.u?._id is Meteor.userId() - canPin: -> - return RocketChat.settings.get 'Message_AllowPinning' - canStar: -> - return RocketChat.settings.get 'Message_AllowStarring' showEditedStatus: -> return RocketChat.settings.get 'Message_ShowEditedStatus' label: -> @@ -100,6 +102,11 @@ Template.message.onCreated -> msg.html = _.escapeHTML msg.html message = RocketChat.callbacks.run 'renderMessage', msg + if message.tokens?.length > 0 + for token in message.tokens + token.text = token.text.replace(/([^\$])(\$[^\$])/gm, '$1$$$2') + message.html = message.html.replace token.token, token.text + # console.log JSON.stringify message msg.html = message.html.replace /\n/gm, '<br/>' return msg.html @@ -107,27 +114,53 @@ Template.message.onCreated -> Template.message.onViewRendered = (context) -> view = this this._domrange.onAttached (domRange) -> - lastNode = domRange.lastNode() - if lastNode.previousElementSibling?.dataset?.date isnt lastNode.dataset.date - $(lastNode).addClass('new-day') - $(lastNode).removeClass('sequential') - else if lastNode.previousElementSibling?.dataset?.bot is 'bot' or lastNode.previousElementSibling?.dataset?.username isnt lastNode.dataset.username - $(lastNode).removeClass('sequential') - - if lastNode.nextElementSibling?.dataset?.date is lastNode.dataset.date - $(lastNode.nextElementSibling).removeClass('new-day') - $(lastNode.nextElementSibling).addClass('sequential') - else - $(lastNode.nextElementSibling).addClass('new-day') - $(lastNode.nextElementSibling).removeClass('sequential') + currentNode = domRange.lastNode() + currentDataset = currentNode.dataset + previousNode = currentNode.previousElementSibling + nextNode = currentNode.nextElementSibling + $currentNode = $(currentNode) + $previousNode = $(previousNode) + $nextNode = $(nextNode) + + unless previousNode? + $currentNode.addClass('new-day').removeClass('sequential') + + else if previousNode?.dataset? + previousDataset = previousNode.dataset + + if previousDataset.date isnt currentDataset.date + $currentNode.addClass('new-day').removeClass('sequential') + else + $currentNode.removeClass('new-day') + + if previousDataset.groupable is 'false' or currentDataset.groupable is 'false' + $currentNode.removeClass('sequential') + else + if previousDataset.username isnt currentDataset.username or parseInt(currentDataset.timestamp) - parseInt(previousDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 + $currentNode.removeClass('sequential') + else if not $currentNode.hasClass 'new-day' + $currentNode.addClass('sequential') + + if nextNode?.dataset? + nextDataset = nextNode.dataset + + if nextDataset.date isnt currentDataset.date + $nextNode.addClass('new-day').removeClass('sequential') + else + $nextNode.removeClass('new-day') + + if nextDataset.groupable isnt 'false' + if nextDataset.username isnt currentDataset.username or parseInt(nextDataset.timestamp) - parseInt(currentDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 + $nextNode.removeClass('sequential') + else if not $nextNode.hasClass 'new-day' + $nextNode.addClass('sequential') - if lastNode.nextElementSibling?.dataset?.bot is 'bot' or lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username - $(lastNode.nextElementSibling).removeClass('sequential') + if not nextNode? + templateInstance = view.parentView.parentView.parentView.parentView.parentView.templateInstance?() - if not lastNode.nextElementSibling? - if lastNode.classList.contains('own') is true - view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom = true + if currentNode.classList.contains('own') is true + templateInstance?.atBottom = true else - if view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom isnt true - newMessage = view.parentView.parentView.parentView.parentView.parentView.templateInstance?()?.find(".new-message") + if templateInstance?.atBottom isnt true + newMessage = templateInstance?.find(".new-message") newMessage?.className = "new-message" diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 0ae084bfc99cbd4c7bceff388288b2193fbdab3a..a2d6fd53f55ecdfecdb2953fb85818a3423e168d 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -1,5 +1,5 @@ <template name="message"> - <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-bot="{{isBot}}" data-date="{{date}}"> + <li id="{{_id}}" class="message {{isSequential}} {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-groupable="{{isGroupable}}" data-date="{{date}}" data-timestamp="{{timestamp}}"> {{#if avatar}} <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1"> <div class="avatar"> @@ -7,7 +7,15 @@ </div> </a> {{else}} - <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> + {{#if emoji}} + <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1"> + <div class="avatar"> + {{{getEmoji emoji}}} + </div> + </a> + {{else}} + <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> + {{/if}} {{/if}} {{#if alias}} <a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{alias}} <span class="message-alias">@{{u.username}}</span></a> diff --git a/packages/rocketchat-ui-message/message/messageBox.coffee b/packages/rocketchat-ui-message/message/messageBox.coffee index dd9ae3c8d74f6d2f341ac44636436a1be1425eba..00f3cad3a06c64475d419a8dc94e6f5619f9cafe 100644 --- a/packages/rocketchat-ui-message/message/messageBox.coffee +++ b/packages/rocketchat-ui-message/message/messageBox.coffee @@ -116,7 +116,6 @@ Template.messageBox.events fileUpload filesToUpload 'click .message-form .mic': (e, t) -> - console.log window.AudioRecorder AudioRecorder.start -> t.$('.stop-mic').removeClass('hidden') t.$('.mic').addClass('hidden') diff --git a/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee index e8a085eebeab3e3929ce4d3d31eaecdc57128a58..022ff911f7894cddf5271bd6ec347e69690d34bd 100644 --- a/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee +++ b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee @@ -88,7 +88,7 @@ Template.messagePopupConfig.helpers commands.push _id: command params: item.params - description: item.description + description: TAPi18n.__ item.description if commands.length > 10 break diff --git a/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee index 4f47569fd26de8ce0cffa8bc7e74163d4dec45bf..d50a31f2c236aa0a71d4bc5144f84d2101e4a68d 100644 --- a/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee +++ b/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee @@ -1,4 +1,4 @@ Template.messagePopupEmoji.helpers value: -> length = this.data.length - return this.data[length - 1].toUpperCase() + return this.data[length - 1] diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index f0c3872b1463b0308f3235c6f1e37f2334acc312..6136ef7e0873cb7991520d842b43275f1dd4e91a 100644 --- a/packages/rocketchat-ui-sidenav/package.js +++ b/packages/rocketchat-ui-sidenav/package.js @@ -18,7 +18,8 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib', + 'rocketchat:ui' ]); api.addFiles('side-nav/accountBox.html', 'client'); diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee index 6b0aa396d44eac80d5ef3d708ce64e62323d4895..4db2d7e04942c8fb2bb43d35d4165d4a33e12a80 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee @@ -9,8 +9,7 @@ Template.chatRoomItem.helpers return this.unread userStatus: -> - return 'status-' + (Session.get('user_' + this.name + '_status') or 'offline') if this.t is 'd' - return '' + return 'status-' + (Session.get('user_' + this.name + '_status') or 'offline') name: -> return this.name diff --git a/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee index 7d5448acdb925e9d3ef806ce7acb198e5dbf9919..a6abfa19958ea9006224cad14569b3b2c0ecb2a3 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee @@ -90,6 +90,9 @@ Template.createChannelFlex.events if err.error is 'duplicate-name' instance.error.set({ duplicate: true }) return + if err.error is 'archived-duplicate-name' + instance.error.set({ archivedduplicate: true }) + return else return toastr.error err.reason diff --git a/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.html b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.html index 2f5e30431261b80a07e7c46c10ffa6f4489419b3..32f223608d24a7db70f8057a24cd895393877b1c 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.html +++ b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.html @@ -40,6 +40,12 @@ {{{_ "Duplicate_channel_name" roomName}}} </div> {{/if}} + {{#if error.archivedduplicate}} + <div class="input-error"> + <strong>{{_ "Oops!"}}</strong> + {{{_ "Duplicate_archived_channel_name" roomName}}} + </div> + {{/if}} <div class="input-submit"> <button class="button clean primary save-channel">{{_ "Save" }}</button> <button class="button clean cancel-channel">{{_ "Cancel" }}</button> diff --git a/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee index 6b15e8505425b34915df3dbfc4069c6c66f02c80..b542942819e06e1307a21719e8dac2415e925ce1 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee @@ -1,6 +1,6 @@ Template.listPrivateGroupsFlex.helpers groups: -> - return ChatSubscription.find { t: { $in: ['p']}, f: { $ne: true } }, { sort: 't': 1, 'name': 1 } + return ChatSubscription.find { t: { $in: ['p']}, f: { $ne: true }, archived: { $ne: true } }, { sort: 't': 1, 'name': 1 } Template.listPrivateGroupsFlex.events 'click header': -> diff --git a/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee index 2b8db2c1bd674a2a20d6cccd869cce013d9e0b55..260dec67a5caac176621354b0a0fcc7a4e0f5ec7 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee @@ -85,6 +85,9 @@ Template.privateGroupsFlex.events if err.error is 'duplicate-name' instance.error.set({ duplicate: true }) return + if err.error is 'archived-duplicate-name' + instance.error.set({ archivedduplicate: true }) + return return toastr.error err.reason SideNav.closeFlex() instance.clearForm() diff --git a/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html index 24e9050283e27813df21f4a69c9df52371dcb6d1..821a4361efa441be9540cea27067762e3d33c850 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html +++ b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html @@ -40,6 +40,12 @@ {{{_ "Duplicate_private_group_name" groupName}}} </div> {{/if}} + {{#if error.archivedduplicate}} + <div class="input-error"> + <strong>{{_ "Oops!"}}</strong> + {{{_ "Duplicate_archived_private_group_name" groupName}}} + </div> + {{/if}} <div class="input-submit"> <button class="button clean primary save-pvt-group">{{_ "Save" }}</button> <button class="button clean cancel-pvt-group">{{_ "Cancel" }}</button> diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 1f6f5958a07b356f0d0273d6c8aba0510307e606..8b1bfb25b6c90e1b91c54faeb544a6e376f85a2b 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -14,6 +14,15 @@ Template.sideNav.helpers return true if favoritesEnabled and hasFavoriteRoomOpened + roomType: -> + return RocketChat.roomTypes.getTypes() + + canShowRoomType: -> + return RocketChat.roomTypes.checkCondition(@) + + templateName: -> + return @template + Template.sideNav.events 'click .close-flex': -> SideNav.closeFlex() @@ -36,10 +45,3 @@ Template.sideNav.onRendered -> Meteor.defer -> menu.updateUnreadBars() - - wrapper = $('.rooms-list .wrapper').get(0) - lastLink = $('.rooms-list h3.history-div').get(0) - - RocketChat.roomTypes.getTypes().forEach (roomType) -> - if Template[roomType.template]? - Blaze.render Template[roomType.template], wrapper, lastLink diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html index 80b0454af9cc1c988f451ea352c07c60783549c3..20446d87f20ec95731a23dada6a6ea36d921a636 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html @@ -11,6 +11,12 @@ <div class="wrapper"> {{ > unreadRooms }} + {{#each roomType}} + {{#if canShowRoomType}} + {{> Template.dynamic template=templateName }} + {{/if}} + {{/each}} + <h3 class="history-div"> <a href="{{pathFor 'privateHistory'}}">{{_ "History"}}</a> </h3> diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index aac7ca39f1f61f854ea51d23ebb7ae45b77f526a..cb79f341e3c8ca7eddd8db37ea21efa9c993d683 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -7,8 +7,10 @@ if not histories[rid]? histories[rid] = hasMore: ReactiveVar true + hasMoreNext: ReactiveVar false isLoading: ReactiveVar false unreadNotLoaded: ReactiveVar 0 + firstUnread: ReactiveVar {} loaded: 0 return histories[rid] @@ -42,6 +44,7 @@ Meteor.call 'loadHistory', rid, ts, limit, ls, (err, result) -> room.unreadNotLoaded.set result?.unreadNotLoaded + room.firstUnread.set result?.firstUnread wrapper = $('.messages-box .wrapper').get(0) if wrapper? @@ -62,20 +65,130 @@ if result?.messages?.length < limit room.hasMore.set false + getMoreNext = (rid, limit=defaultLimit) -> + room = getRoom rid + if room.hasMoreNext.curValue isnt true + return + + instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() + instance.atBottom = false + + room.isLoading.set true + + lastMessage = ChatMessage.findOne({rid: rid}, {sort: {ts: -1}}) + + typeName = undefined + + subscription = ChatSubscription.findOne rid: rid + if subscription? + ls = subscription.ls + typeName = subscription.t + subscription.name + else + curRoomDoc = ChatRoom.findOne(_id: rid) + typeName = curRoomDoc?.t + curRoomDoc?.name + + ts = lastMessage.ts + + if ts + Meteor.call 'loadNextMessages', rid, ts, limit, (err, result) -> + for item in result?.messages or [] + if item.t isnt 'command' + ChatMessage.upsert {_id: item._id}, item + + Meteor.defer -> + RoomManager.updateMentionsMarksOfRoom typeName + + room.isLoading.set false + room.loaded += result.messages.length + if result.messages.length < limit + room.hasMoreNext.set false + + getSurroundingMessages = (message, limit=defaultLimit) -> + unless message?.rid + return + + instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() + + if ChatMessage.findOne message._id + wrapper = $('.messages-box .wrapper') + msgElement = $("##{message._id}", wrapper) + pos = wrapper.scrollTop() + msgElement.offset().top - wrapper.height()/2 + wrapper.animate({ + scrollTop: pos + }, 500) + msgElement.addClass('highlight') + + setTimeout -> + messages = wrapper[0] + instance.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight; + + setTimeout -> + msgElement.removeClass('highlight') + , 3000 + else + room = getRoom message.rid + room.isLoading.set true + ChatMessage.remove { rid: message.rid } + + typeName = undefined + + subscription = ChatSubscription.findOne rid: message.rid + if subscription? + ls = subscription.ls + typeName = subscription.t + subscription.name + else + curRoomDoc = ChatRoom.findOne(_id: message.rid) + typeName = curRoomDoc?.t + curRoomDoc?.name + + Meteor.call 'loadSurroundingMessages', message, limit, (err, result) -> + for item in result?.messages or [] + if item.t isnt 'command' + ChatMessage.upsert {_id: item._id}, item + + Meteor.defer -> + readMessage.refreshUnreadMark(message.rid, true) + RoomManager.updateMentionsMarksOfRoom typeName + wrapper = $('.messages-box .wrapper') + msgElement = $("##{message._id}", wrapper) + pos = wrapper.scrollTop() + msgElement.offset().top - wrapper.height()/2 + wrapper.animate({ + scrollTop: pos + }, 500) + + msgElement.addClass('highlight') + + setTimeout -> + room.isLoading.set false + messages = wrapper[0] + instance.atBottom = !result.moreAfter && messages.scrollTop >= messages.scrollHeight - messages.clientHeight; + , 500 + + setTimeout -> + msgElement.removeClass('highlight') + , 3000 + room.loaded += result.messages.length + room.hasMore.set result.moreBefore + room.hasMoreNext.set result.moreAfter + hasMore = (rid) -> room = getRoom rid return room.hasMore.get() + hasMoreNext = (rid) -> + room = getRoom rid + return room.hasMoreNext.get() + + getMoreIfIsEmpty = (rid) -> room = getRoom rid if room.loaded is 0 getMore rid + isLoading = (rid) -> room = getRoom rid - return room.isLoading.get() clear = (rid) -> @@ -87,7 +200,10 @@ getRoom: getRoom getMore: getMore + getMoreNext: getMoreNext getMoreIfIsEmpty: getMoreIfIsEmpty hasMore: hasMore + hasMoreNext: hasMoreNext isLoading: isLoading clear: clear + getSurroundingMessages: getSurroundingMessages diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 0a70060a78eba4a5a4516183bec6e6e56e565661..d5b15660788e7eb0928ac210dc4466622cf2f355 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -62,7 +62,7 @@ RocketChat.Notifications.onUser 'message', (msg) -> sub.stop() if openedRooms[typeName].rid? - msgStream.removeListener openedRooms[typeName].rid + msgStream.removeAllListeners openedRooms[typeName].rid RocketChat.Notifications.unRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream openedRooms[typeName].ready = false @@ -85,6 +85,9 @@ RocketChat.Notifications.onUser 'message', (msg) -> Meteor.subscribe 'room', typeName ] + if record.ready is true + return + ready = record.sub[0].ready() and subscription.ready() if ready is true @@ -108,16 +111,23 @@ RocketChat.Notifications.onUser 'message', (msg) -> record.ready = RoomHistoryManager.isLoading(room._id) is false Dep.changed() - msgStream.on openedRooms[typeName].rid, (msg) -> - if msg.t isnt 'command' - ChatMessage.upsert { _id: msg._id }, msg - else - Meteor.defer -> - RoomManager.updateMentionsMarksOfRoom typeName + if openedRooms[typeName].streamActive isnt true + openedRooms[typeName].streamActive = true + msgStream.on openedRooms[typeName].rid, (msg) -> + + # Should not send message to room if room has not loaded all the current messages + if RoomHistoryManager.hasMoreNext(openedRooms[typeName].rid) is false + + # Do not load command messages into channel + if msg.t isnt 'command' + ChatMessage.upsert { _id: msg._id }, msg + + Meteor.defer -> + RoomManager.updateMentionsMarksOfRoom typeName - RocketChat.callbacks.run 'streamMessage', msg + RocketChat.callbacks.run 'streamMessage', msg - RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream + RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream Dep.changed() @@ -207,7 +217,7 @@ RocketChat.Notifications.onUser 'message', (msg) -> scrollTop = $(dom).find('.messages-box > .wrapper').scrollTop() - 50 totalHeight = $(dom).find('.messages-box > .wrapper > ul').height() + 40 - $('.mention-link-me').each (index, item) -> + $('.messages-box .mention-link-me').each (index, item) -> topOffset = $(item).offset().top + scrollTop percent = 100 / totalHeight * topOffset ticksBar.append('<div class="tick" style="top: '+percent+'%;"></div>') diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index 49c6a3c13d288b6c1af3f4a304e37479aa4e6c34..d75d66a2a32596550b3458648a94816d460013fa 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -41,30 +41,39 @@ actual.push newItem items.set actual + checkCondition = (item) -> + return not item.condition? or item.condition() + getItems = -> return _.filter items.get(), (item) -> - if not item.permissions? or RocketChat.authz.hasAllPermission item.permissions + if checkCondition(item) return true - addRoute = (newRoute) -> + addRoute = (newRoute, router = FlowRouter) -> # @TODO check for mandatory fields + routeConfig = + center: 'pageContainer' + pageTemplate: newRoute.pageTemplate + + if newRoute.i18nPageTitle? + routeConfig.i18nPageTitle = newRoute.i18nPageTitle - FlowRouter.route newRoute.path, + if newRoute.pageTitle? + routeConfig.pageTitle = newRoute.pageTitle + + router.route newRoute.path, name: newRoute.name action: -> Session.set 'openedRoom' - BlazeLayout.render 'main', - center: 'pageContainer' - pageTitle: newRoute.pageTitle - pageTemplate: newRoute.pageTemplate + RocketChat.TabBar.showGroup newRoute.name + BlazeLayout.render 'main', routeConfig triggersEnter: [ -> if newRoute.sideNav? SideNav.setFlex newRoute.sideNav SideNav.openFlex() ] - setStatus: setStatus toggle: toggle open: open diff --git a/packages/rocketchat-ui/lib/accounts.coffee b/packages/rocketchat-ui/lib/accounts.coffee index d81d0e7c5a4121d5d189267b1b3ddeb7d53f60e4..17f3828de2fb548355d16062f1dfdf5821ffa2fb 100644 --- a/packages/rocketchat-ui/lib/accounts.coffee +++ b/packages/rocketchat-ui/lib/accounts.coffee @@ -1,17 +1,6 @@ -Meteor.startup -> - Accounts.onEmailVerificationLink (token, done) -> - Accounts.verifyEmail token, (error) -> - if not error? - alert(t('Email_verified')) +Accounts.onEmailVerificationLink (token, done) -> + Accounts.verifyEmail token, (error) -> + if not error? + alert(t('Email_verified')) - done() - - Accounts.onResetPasswordLink (token, done) -> - newPassword = prompt(t('New_password')) - Accounts.resetPassword token, newPassword, (error) -> - if error? - console.log error - alert(t('Error_changing_password')) - else - alert('Password_changed') - done() \ No newline at end of file + done() diff --git a/packages/rocketchat-ui/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee index 4c77cee3d1a9b58dff58e25c4a97866c291d0773..f02353c55014e6621cf1b3361468d328c5df55b7 100644 --- a/packages/rocketchat-ui/lib/collections.coffee +++ b/packages/rocketchat-ui/lib/collections.coffee @@ -1,5 +1,11 @@ @ChatMessage = new Meteor.Collection null @ChatRoom = new Meteor.Collection 'rocketchat_room' @ChatSubscription = new Meteor.Collection 'rocketchat_subscription' +@RoomModeratorsAndOwners = new Mongo.Collection null @UserAndRoom = new Meteor.Collection null @CachedChannelList = new Meteor.Collection null + +RocketChat.models.Users = _.extend {}, RocketChat.models.Users, Meteor.users +RocketChat.models.Subscriptions = _.extend {}, RocketChat.models.Subscriptions, @ChatSubscription +RocketChat.models.Rooms = _.extend {}, RocketChat.models.Rooms, @ChatRoom +RocketChat.models.Messages = _.extend {}, RocketChat.models.Messages, @ChatMessage diff --git a/packages/rocketchat-ui/lib/cordova/urls.coffee b/packages/rocketchat-ui/lib/cordova/urls.coffee index 59bcf5d22f656359f1206d99bb80862877673395..aeed6e9604b962466353cd216164951322a4389e 100644 --- a/packages/rocketchat-ui/lib/cordova/urls.coffee +++ b/packages/rocketchat-ui/lib/cordova/urls.coffee @@ -10,9 +10,5 @@ Meteor.startup -> url = $link.attr('href') if /^https?:\/\/.+/.test(url) is true - switch platform - when 'ios' - window.open url, '_system' - when 'android' - navigator.app.loadUrl url, {openExternal: true} - e.preventDefault() \ No newline at end of file + window.open url, '_system' + e.preventDefault() diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index 48db0ca7dbe23551efec61ef00fd267a93a5aba2..548cc76437fa7c461844cda20e004c31cce18436 100644 --- a/packages/rocketchat-ui/lib/fileUpload.coffee +++ b/packages/rocketchat-ui/lib/fileUpload.coffee @@ -31,6 +31,13 @@ readAsArrayBuffer = (file, callback) -> timer: 1000 return + if file.file.size is 0 + swal + title: t('FileUpload_File_Empty') + type: 'error' + timer: 1000 + return + text = '' if file.type is 'audio' @@ -86,16 +93,38 @@ readAsArrayBuffer = (file, callback) -> onComplete: (file) -> self = this - Meteor.call 'sendMessage', { + url = file.url.replace(Meteor.absoluteUrl(), '/') + + attachment = + title: "File Uploaded: #{file.name}" + title_link: url + + if /^image\/.+/.test file.type + attachment.image_url = url + attachment.image_type = file.type + attachment.image_size = file.size + attachment.image_dimensions = file.identify?.size + + if /^audio\/.+/.test file.type + attachment.audio_url = url + attachment.audio_type = file.type + attachment.audio_size = file.size + + if /^video\/.+/.test file.type + attachment.video_url = url + attachment.video_type = file.type + attachment.video_size = file.size + + msg = _id: Random.id() rid: roomId - msg: """ - File Uploaded: *#{file.name}* - #{file.url} - """ + msg: "" file: _id: file._id - }, -> + groupable: false + attachments: [attachment] + + Meteor.call 'sendMessage', msg, -> Meteor.setTimeout -> uploading = Session.get 'uploading' if uploading? diff --git a/packages/rocketchat-ui/lib/notification.coffee b/packages/rocketchat-ui/lib/notification.coffee index c6822dd846b4ae80857e63a64ef6839848828846..0785236f5dec6445433de97f522c5e10b5d981d0 100644 --- a/packages/rocketchat-ui/lib/notification.coffee +++ b/packages/rocketchat-ui/lib/notification.coffee @@ -30,10 +30,6 @@ when 'p' FlowRouter.go 'group', {name: notification.payload.name} - setTimeout -> - n.close() - , 10000 - newMessage: -> unless Session.equals('user_' + Meteor.userId() + '_status', 'busy') or Meteor.user()?.settings?.preferences?.disableNewMessageNotification $('#chatAudioNotification')[0].play() diff --git a/packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee b/packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee index c2cad9187967992f5373ca8872348a5521ded8a9..013af2a24e52a488fc445c298c93d3d63b4840ec 100644 --- a/packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee +++ b/packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee @@ -1,4 +1,4 @@ -@AudioRecorder = new class +@AudioRecorder = new class start: (cb) -> window.AudioContext = window.AudioContext or window.webkitAudioContext navigator.getUserMedia = navigator.getUserMedia or navigator.webkitGetUserMedia @@ -28,7 +28,7 @@ if cb? @getBlob cb - @stream.stop() + @stream.getAudioTracks()[0].stop() @recorder.clear() diff --git a/packages/rocketchat-ui/lib/trackRoomNameChanged.coffee b/packages/rocketchat-ui/lib/trackRoomNameChanged.coffee deleted file mode 100644 index 8b3a0769febae4f4b9f11b9e85d6e2753536a69d..0000000000000000000000000000000000000000 --- a/packages/rocketchat-ui/lib/trackRoomNameChanged.coffee +++ /dev/null @@ -1,12 +0,0 @@ -Meteor.startup -> - roomNameChangedCallback = (msg) -> - Tracker.nonreactive -> - if msg.t is 'r' - if Session.get('openedRoom') is msg.rid - type = if FlowRouter.current().route.name is 'channel' then 'c' else 'p' - RoomManager.close type + FlowRouter.getParam('name') - FlowRouter.go FlowRouter.current().route.name, name: msg.msg - - return msg - - RocketChat.callbacks.add 'streamMessage', roomNameChangedCallback, RocketChat.callbacks.priority.HIGH diff --git a/packages/rocketchat-ui/lib/updateModeratorsAndOwners.js b/packages/rocketchat-ui/lib/updateModeratorsAndOwners.js new file mode 100644 index 0000000000000000000000000000000000000000..da6e309b9759b312308d5e6ba90a549b82096298 --- /dev/null +++ b/packages/rocketchat-ui/lib/updateModeratorsAndOwners.js @@ -0,0 +1,33 @@ +Meteor.startup(function() { + RocketChat.callbacks.add('streamMessage', function(msg) { + if (msg.t === 'new-moderator') { + user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }); + RoomModeratorsAndOwners.upsert({ rid: msg.rid, "u._id": user._id }, { $setOnInsert: { u: user }, $addToSet: { roles: 'moderator' } }); + } else if (msg.t === 'moderator-removed') { + user = Meteor.users.findOne({ username: msg.msg }); + moderator = RoomModeratorsAndOwners.findOne({ rid: msg.rid, "u._id": user._id, roles: 'moderator' }); + if (moderator && moderator.roles && moderator.roles.length === 1 && moderator.roles[0] === 'moderator') { + RoomModeratorsAndOwners.remove({ rid: msg.rid, "u._id": user._id, roles: 'moderator' }); + } else if (moderator) { + RoomModeratorsAndOwners.update({ rid: msg.rid, "u._id": user._id }, { $pull: { roles: 'moderator' } }); + } + } + return msg; + }, RocketChat.callbacks.priority.LOW, 'addOrRemoveModerator'); + + RocketChat.callbacks.add('streamMessage', function(msg) { + if (msg.t === 'new-owner') { + user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }); + RoomModeratorsAndOwners.upsert({ rid: msg.rid, "u._id": user._id }, { $setOnInsert: { u: user }, $addToSet: { roles: 'owner' } }); + } else if (msg.t === 'owner-removed') { + user = Meteor.users.findOne({ username: msg.msg }); + owner = RoomModeratorsAndOwners.findOne({ rid: msg.rid, "u._id": user._id, roles: 'owner' }); + if (owner && owner.roles && owner.roles.length === 1 && owner.roles[0] === 'owner') { + RoomModeratorsAndOwners.remove({ rid: msg.rid, "u._id": user._id, roles: 'owner' }); + } else if (owner) { + RoomModeratorsAndOwners.update({ rid: msg.rid, "u._id": user._id }, { $pull: { roles: 'owner' } }); + } + } + return msg; + }, RocketChat.callbacks.priority.LOW, 'addOrRemoveOwner'); +}) diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index e7822568ede7d0bad00df719272d3faa83181f85..6badab973672c064ea512e78d490f61c06a39530 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -14,6 +14,7 @@ Package.onUse(function(api) { api.versionsFrom('1.2.1'); api.use([ + 'accounts-base', 'mongo', 'session', 'jquery', @@ -23,7 +24,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'raix:push', 'raix:ui-dropped-event' ]); @@ -55,7 +56,7 @@ Package.onUse(function(api) { api.addFiles('lib/sideNav.coffee', 'client'); api.addFiles('lib/tapi18n.coffee', 'client'); api.addFiles('lib/textarea-autogrow.js', 'client'); - api.addFiles('lib/trackRoomNameChanged.coffee', 'client'); + api.addFiles('lib/updateModeratorsAndOwners.js', 'client'); // LIB CORDOVA api.addFiles('lib/cordova/facebook-login.coffee', 'client'); diff --git a/packages/rocketchat-ui/views/app/pageContainer.html b/packages/rocketchat-ui/views/app/pageContainer.html index 7c8af10e1c4d5591304bed5eebb3510595f50aa0..fdd8ce1e788bd59a6ad524da9ed1799e4778d7e2 100644 --- a/packages/rocketchat-ui/views/app/pageContainer.html +++ b/packages/rocketchat-ui/views/app/pageContainer.html @@ -3,7 +3,13 @@ <head class="fixed-title"> {{> burger}} <h2> - <span class="page-title">{{pageTitle}}</span> + <span class="page-title"> + {{#if i18nPageTitle}} + {{_ i18nPageTitle}} + {{else}} + {{pageTitle}} + {{/if}} + </span> </h2> </head> <div class="content"> diff --git a/packages/rocketchat-ui/views/app/privateHistory.coffee b/packages/rocketchat-ui/views/app/privateHistory.coffee index b04ecd4f8037f91a75c05d9bb8c0e097e9a363a3..b59fdc7c23e6883de1c34b57261daed16c24ae83 100644 --- a/packages/rocketchat-ui/views/app/privateHistory.coffee +++ b/packages/rocketchat-ui/views/app/privateHistory.coffee @@ -1,6 +1,13 @@ Template.privateHistory.helpers history: -> - items = ChatSubscription.find { name: { $regex: Session.get('historyFilter'), $options: 'i' }, t: { $in: ['d', 'c', 'p'] } }, {'sort': { 'ts': -1 } } + items = ChatSubscription.find { name: { $regex: Session.get('historyFilter'), $options: 'i' }, t: { $in: ['d', 'c', 'p'] }, archived: { $ne: true } }, {'sort': { 'ts': -1 } } + return { + items: items + length: items.count() + } + + archivedHistory: -> + items = ChatSubscription.find { name: { $regex: Session.get('historyFilter'), $options: 'i' }, t: { $in: ['d', 'c', 'p'] }, archived: true }, {'sort': { 'ts': -1 } } return { items: items length: items.count() @@ -30,9 +37,6 @@ Template.privateHistory.helpers when 'd' return FlowRouter.path 'direct', { username: this.name } -Template.privateHistory.onRendered -> - RocketChat.TabBar.reset() - Template.privateHistory.events 'keydown #history-filter': (event) -> if event.which is 13 diff --git a/packages/rocketchat-ui/views/app/privateHistory.html b/packages/rocketchat-ui/views/app/privateHistory.html index 7b51de5161cd0af6e14acd06109220772742101b..0d0acc27482ba98017a449637fc64e710e345911 100644 --- a/packages/rocketchat-ui/views/app/privateHistory.html +++ b/packages/rocketchat-ui/views/app/privateHistory.html @@ -1,6 +1,7 @@ <template name="privateHistory"> <section class="page-container page-list"> <header class="fixed-title"> + {{> burger}} <h2> <span class="room-title">{{_ "History"}}</span> </h2> @@ -35,6 +36,29 @@ </a> {{/each}} </div> + <div class="results"> + {{{_ "Showing_archived_results" archivedHistory.length}}} + </div> + <div class="list"> + {{#each archivedHistory.items}} + <a href="{{path}}"> + <div class="info"> + <h3><i class="{{type}}"></i><span class="enter-room">{{name}}</span></h3> + <ul> + {{#with roomOf rid}} + <li>{{_ "n_messages" msgs}}</li> + <li>{{_ "since_creation" creation}}</li> + {{/with}} + </ul> + </div> + <div class="status"> + {{#with roomOf rid}} + <strong>{{lastMessage}}</strong> + {{/with}} + </div> + </a> + {{/each}} + </div> </div> </section> </template> diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index d77154139d66e5886a1df1808f82b72a80d613b6..a50f595194f0e746e901ee852f3a36a939f13fac 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -32,6 +32,9 @@ Template.room.helpers hasMore: -> return RoomHistoryManager.hasMore this._id + hasMoreNext: -> + return RoomHistoryManager.hasMoreNext this._id + isLoading: -> return RoomHistoryManager.isLoading this._id @@ -75,6 +78,11 @@ Template.room.helpers else return roomData.name + roomTopic: -> + roomData = Session.get('roomData' + this._id) + return '' unless roomData + return roomData.topic + roomIcon: -> roomData = Session.get('roomData' + this._id) return '' unless roomData?.t @@ -101,26 +109,9 @@ Template.room.helpers return '' unless roomData return roomData.t is 'c' - canEditName: -> - roomData = Session.get('roomData' + this._id) - return '' unless roomData - if roomData.t in ['c', 'p'] - return RocketChat.authz.hasAtLeastOnePermission('edit-room', this._id) - else - return '' - canDirectMessage: -> return Meteor.user()?.username isnt this.username - roomNameEdit: -> - return Session.get('roomData' + this._id)?.name - - editingTitle: -> - return 'hidden' if Session.get('editRoomTitle') - - showEditingTitle: -> - return 'hidden' if not Session.get('editRoomTitle') - flexOpened: -> return 'opened' if RocketChat.TabBar.isFlexOpen() @@ -189,7 +180,7 @@ Template.room.helpers formatUnreadSince: -> room = ChatRoom.findOne(this._id, { reactive: false }) - room = RoomManager.openedRooms[room.t + room.name] + room = RoomManager.openedRooms[room?.t + room?.name] date = room?.unreadSince.get() if not date? then return @@ -210,6 +201,8 @@ Template.room.helpers compactView: -> return 'compact' if Meteor.user()?.settings?.preferences?.compactView + selectable: -> + return Template.instance().selectable.get() Template.room.events "click, touchend": (e, t) -> @@ -236,9 +229,18 @@ Template.room.events "click .upload-progress > a": -> Session.set "uploading-cancel-#{this.id}", true - "click .unread-bar > a": -> + "click .unread-bar > a.mark-read": -> readMessage.readNow(true) + "click .unread-bar > a.jump-to": -> + message = RoomHistoryManager.getRoom(@_id)?.firstUnread.get() + if message? + RoomHistoryManager.getSurroundingMessages(message, 50) + else + subscription = ChatSubscription.findOne({ rid: @_id }) + message = ChatMessage.find({ rid: @_id, ts: { $gt: subscription?.ls } }, { sort: { ts: 1 }, limit: 1 }).fetch()[0] + RoomHistoryManager.getSurroundingMessages(message, 50) + "click .flex-tab .more": (event, t) -> if RocketChat.TabBar.isFlexOpen() Session.set('rtcLayoutmode', 0) @@ -287,21 +289,9 @@ Template.room.events $('#room-title-field').focus().select() , 10 - 'keydown #room-title-field': (event) -> - if event.keyCode is 27 # esc - Session.set('editRoomTitle', false) - else if event.keyCode is 13 # enter - renameRoom @_id, $(event.currentTarget).val() - - 'blur #room-title-field': (event) -> - # TUDO: create a configuration to select the desired behaviour - # renameRoom this._id, $(event.currentTarget).val() - Session.set('editRoomTitle', false) - $(".fixed-title").removeClass "visible" - "click .flex-tab .user-image > a" : (e) -> RocketChat.TabBar.openFlex() - Session.set('showUserInfo', $(e.currentTarget).data('username')) + Session.set('showUserInfo', @username) 'click .user-card-message': (e) -> roomData = Session.get('roomData' + this._arguments[1].rid) @@ -313,9 +303,11 @@ Template.room.events RocketChat.TabBar.setTemplate 'membersList' 'scroll .wrapper': _.throttle (e, instance) -> - if RoomHistoryManager.hasMore(@_id) is true and RoomHistoryManager.isLoading(@_id) is false - if e.target.scrollTop is 0 + if RoomHistoryManager.isLoading(@_id) is false and (RoomHistoryManager.hasMore(@_id) is true or RoomHistoryManager.hasMoreNext(@_id) is true) + if RoomHistoryManager.hasMore(@_id) is true and e.target.scrollTop is 0 RoomHistoryManager.getMore(@_id) + else if RoomHistoryManager.hasMoreNext(@_id) is true and e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + RoomHistoryManager.getMoreNext(@_id) , 200 'click .load-more > a': -> @@ -347,6 +339,8 @@ Template.room.events dropDown.show() 'click .message-dropdown .message-action': (e, t) -> + e.preventDefault() + e.stopPropagation() el = $(e.currentTarget) button = RocketChat.MessageAction.getButtonById el.data('id') @@ -368,14 +362,7 @@ Template.room.events 'click .image-to-download': (event) -> ChatMessage.update {_id: this._arguments[1]._id, 'urls.url': $(event.currentTarget).data('url')}, {$set: {'urls.$.downloadImages': true}} - - 'click .pin-message': (event) -> - message = @_arguments[1] - instance = Template.instance() - if message.pinned - chatMessages[Session.get('openedRoom')].unpinMsg(message) - else - chatMessages[Session.get('openedRoom')].pinMsg(message) + ChatMessage.update {_id: this._arguments[1]._id, 'attachments.image_url': $(event.currentTarget).data('url')}, {$set: {'attachments.$.downloadImages': true}} 'dragenter .dropzone': (e) -> e.currentTarget.classList.add 'over' @@ -427,6 +414,35 @@ Template.room.events 'load img': (e, template) -> template.sendToBottomIfNecessary?() + 'click .jump-recent .jump-link': (e, template) -> + e.preventDefault() + template.atBottom = true + RoomHistoryManager.clear(template?.data?._id) + + 'click .message': (e, template) -> + if template.selectable.get() + document.selection?.empty() or window.getSelection?().removeAllRanges() + data = Blaze.getData(e.currentTarget) + _id = data?._arguments?[1]?._id + + if !template.selectablePointer + template.selectablePointer = _id + + if !e.shiftKey + template.selectedMessages = template.getSelectedMessages() + template.selectedRange = [] + template.selectablePointer = _id + + template.selectMessages _id + + selectedMessages = $('.messages-box .message.selected').map((i, message) -> message.id) + removeClass = _.difference selectedMessages, template.getSelectedMessages() + addClass = _.difference template.getSelectedMessages(), selectedMessages + for message in removeClass + $(".messages-box ##{message}").removeClass('selected') + for message in addClass + $(".messages-box ##{message}").addClass('selected') + Template.room.onCreated -> # this.scrollOnBottom = true @@ -435,17 +451,58 @@ Template.room.onCreated -> this.atBottom = true this.unreadCount = new ReactiveVar 0 - self = @ + this.selectable = new ReactiveVar false + this.selectedMessages = [] + this.selectedRange = [] + this.selectablePointer = null + + this.resetSelection = (enabled) => + this.selectable.set(enabled) + $('.messages-box .message.selected').removeClass 'selected' + this.selectedMessages = [] + this.selectedRange = [] + this.selectablePointer = null + + this.selectMessages = (to) => + if this.selectablePointer is to and this.selectedRange.length > 0 + this.selectedRange = [] + else + message1 = ChatMessage.findOne this.selectablePointer + message2 = ChatMessage.findOne to - @autorun -> - self.subscribe 'fullUserData', Session.get('showUserInfo'), 1 + minTs = _.min([message1.ts, message2.ts]) + maxTs = _.max([message1.ts, message2.ts]) + this.selectedRange = _.pluck(ChatMessage.find({ rid: message1.rid, ts: { $gte: minTs, $lte: maxTs } }).fetch(), '_id') -Template.room.onDestroyed -> - RocketChat.TabBar.resetButtons() + this.getSelectedMessages = => + messages = this.selectedMessages + addMessages = false + for message in this.selectedRange + if messages.indexOf(message) is -1 + addMessages = true + break - window.removeEventListener 'resize', this.onWindowResize + if addMessages + previewMessages = _.compact(_.uniq(this.selectedMessages.concat(this.selectedRange))) + else + previewMessages = _.compact(_.difference(this.selectedMessages, this.selectedRange)) + + return previewMessages + @autorun => + @subscribe 'fullUserData', Session.get('showUserInfo'), 1 + + Meteor.call 'getRoomModeratorsAndOwners', @data._id, (error, results) -> + if error + return toastr.error error.reason + + for record in results + delete record._id + RoomModeratorsAndOwners.upsert { rid: record.rid, "u._id": record.u._id }, record + +Template.room.onDestroyed -> + window.removeEventListener 'resize', this.onWindowResize Template.room.onRendered -> unless window.chatMessages @@ -539,7 +596,7 @@ Template.room.onRendered -> firstMessage = ChatMessage.findOne firstMessageOnScreen.id if firstMessage? subscription = ChatSubscription.findOne rid: template.data._id - template.unreadCount.set ChatMessage.find({rid: template.data._id, ts: {$lt: firstMessage.ts, $gt: subscription.ls}}).count() + template.unreadCount.set ChatMessage.find({rid: template.data._id, ts: {$lt: firstMessage.ts, $gt: subscription?.ls}}).count() else template.unreadCount.set 0 , 300 @@ -564,36 +621,3 @@ Template.room.onRendered -> if webrtc.localUrl.get()? RocketChat.TabBar.setTemplate 'membersList' RocketChat.TabBar.openFlex() - - -renameRoom = (rid, name) -> - name = name?.toLowerCase().trim() - console.log 'room renameRoom' if window.rocketDebug - room = Session.get('roomData' + rid) - if room.name is name - Session.set('editRoomTitle', false) - return false - - Meteor.call 'saveRoomName', rid, name, (error, result) -> - if result - Session.set('editRoomTitle', false) - # If room was renamed then close current room and send user to the new one - RoomManager.close room.t + room.name - switch room.t - when 'c' - FlowRouter.go 'channel', name: name - when 'p' - FlowRouter.go 'group', name: name - - toastr.success t('Room_name_changed_successfully') - if error - if error.error is 'name-invalid' - toastr.error t('Invalid_room_name', name) - return - if error.error is 'duplicate-name' - if room.t is 'c' - toastr.error t('Duplicate_channel_name', name) - else - toastr.error t('Duplicate_private_group_name', name) - return - toastr.error error.reason diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index 010ab8427bf99b2df4a97133967ce3face4de03a..483ef9d45651a00f0495917a096560d8f60b5140 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -13,11 +13,8 @@ <a href="#favorite" class="toggle-favorite"><i class="{{favorite}}" aria-label="{{_ favoriteLabel}}"></i></a> {{/if}} <i class="{{roomIcon}} status-{{userStatus}}"></i> - <span class="room-title {{editingTitle}}">{{roomName}}</span> - {{#if canEditName}} - <input type="text" id="room-title-field" class="{{showEditingTitle}}" value="{{roomNameEdit}}" dir="auto"> - <a href="#edit" class="edit-room-title"><i class="icon-pencil" aria-label="{{_ "Edit"}}"></i></a> - {{/if}} + <span class="room-title">{{roomName}}</span> + <span class="room-topic">{{roomTopic}}</span> </h2> </header> <div class="container-bars"> @@ -42,17 +39,20 @@ {{#if unreadCount}} {{#if unreadSince}} <div class="unread-bar"> + <a class="jump-to"> + {{_ "Jump_to_first_unread"}} + </a> {{_ "S_new_messages_since_s" unreadCount formatUnreadSince}} - <a> + <a class="mark-read"> {{_ "Mark_as_read"}} </a> </div> {{/if}} {{/if}} </div> - <div class="messages-box {{compactView}}"> + <div class="messages-box {{#if selectable}}selectable{{/if}} {{compactView}}"> <div class="ticks-bar"></div> - <div class="wrapper"> + <div class="wrapper {{#if hasMoreNext}}has-more-next{{/if}}"> <ul aria-live="polite"> {{#if hasMore}} <li class="load-more"> @@ -70,12 +70,24 @@ {{#each messagesHistory}} {{#nrr nrrargs 'message' .}}{{/nrr}} {{/each}} + {{#if hasMoreNext}} + <li class="load-more"> + {{#if isLoading}} + <div class="load-more-loading">{{_ "Loading_more_from_history"}}...</div> + {{else}} + <a href="">{{_ "Has_more"}}...</a> + {{/if}} + </li> + {{/if}} </ul> </div> <div class="new-message not"> <i class="icon-down-big"></i> <span>{{_ "New_messages"}}</span> </div> + <div class="jump-recent {{#unless hasMoreNext}}not{{/unless}}"> + <span class="jump-link">{{_ "Jump_to_recent_messages"}} <i class="icon-level-down"></i></span> + </div> </div> <footer class="footer"> {{> messageBox}} @@ -85,4 +97,4 @@ {{> Template.dynamic template=flexTemplate data=flexData}} </section> </div> -</template> \ No newline at end of file +</template> diff --git a/packages/rocketchat-ui/views/app/videoCall/videoButtons.html b/packages/rocketchat-ui/views/app/videoCall/videoButtons.html index fac8fced5888c9c5a85f4eb91ddc92bd02923f37..d8f442d60ff704ea11351d6485286b55d59f520e 100644 --- a/packages/rocketchat-ui/views/app/videoCall/videoButtons.html +++ b/packages/rocketchat-ui/views/app/videoCall/videoButtons.html @@ -3,11 +3,11 @@ {{#if videoAvaliable}} {{#unless videoActive}} {{#if callInProgress}} - <button class="join-video-call button secondary"><i class="icon-videocam"></i>{{_ "Join"}}</button> - <button class="join-audio-call button secondary"><i class="icon-phone"></i>{{_ "Join"}}</button> + <button class="join-video-call button secondary" aria-label="{{_ "Join_video_call"}}"><i class="icon-videocam"></i></button> + <button class="join-audio-call button secondary" aria-label="{{_ "Join_audio_call"}}"><i class="icon-phone"></i></button> {{else}} - <button class="start-video-call button"><i class="icon-videocam"></i>{{_ "Start"}}</button> - <button class="start-audio-call button"><i class="icon-phone"></i></button> + <button class="start-video-call button" aria-label="{{_ "Start_video_call"}}"><i class="icon-videocam"></i></button> + <button class="start-audio-call button" aria-label="{{_ "Start_audio_call"}}"><i class="icon-phone"></i></button> {{/if}} {{/unless}} {{/if}} diff --git a/packages/rocketchat-webrtc/i18n/ar.i18n.json b/packages/rocketchat-webrtc/i18n/ar.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..0e117a1ef1efa2c2143aabfe3e2fe9ea82bf4bd5 100644 --- a/packages/rocketchat-webrtc/i18n/ar.i18n.json +++ b/packages/rocketchat-webrtc/i18n/ar.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "تمكين للقنوات العامة", + "WebRTC_Enable_Direct" : "تمكين للرسائل المباشرة", + "WebRTC_Enable_Private" : "تمكين للقنوات الخاصة" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/de.i18n.json b/packages/rocketchat-webrtc/i18n/de.i18n.json index 4f6f648650c1927a007156851661ce52a758db0e..7376b712967a42f4fa7776549f3c78741cc21516 100644 --- a/packages/rocketchat-webrtc/i18n/de.i18n.json +++ b/packages/rocketchat-webrtc/i18n/de.i18n.json @@ -1,5 +1,5 @@ { - "WebRTC_Enable_Channel" : "Aktivieren für öffentliche Kanäle", - "WebRTC_Enable_Direct" : "Aktivieren für Direktnachrichten", - "WebRTC_Enable_Private" : "Aktivieren für private Kanäle" + "WebRTC_Enable_Channel" : "Für öffentliche Kanäle aktivieren", + "WebRTC_Enable_Direct" : "Für private Nachrichten aktivieren", + "WebRTC_Enable_Private" : "Für private Kanäle aktivieren" } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/fr.i18n.json b/packages/rocketchat-webrtc/i18n/fr.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..588bdc0b4b23ac0f3cf08706a100691305ab7690 100644 --- a/packages/rocketchat-webrtc/i18n/fr.i18n.json +++ b/packages/rocketchat-webrtc/i18n/fr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "Activer pour les canaux publics", + "WebRTC_Enable_Direct" : "Activer pour les messages directs", + "WebRTC_Enable_Private" : "Activer pour les canaux privés" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ko.i18n.json b/packages/rocketchat-webrtc/i18n/ko.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..122c0f35f3a99d300178a5845deb86cc6abd69fc 100644 --- a/packages/rocketchat-webrtc/i18n/ko.i18n.json +++ b/packages/rocketchat-webrtc/i18n/ko.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "공개 ì±„ë„ ì‚¬ìš©", + "WebRTC_Enable_Direct" : "ê·“ì†ë§ 사용", + "WebRTC_Enable_Private" : "비밀 그룹 사용" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/nl.i18n.json b/packages/rocketchat-webrtc/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..4df60fc80b8c5cb74fe0aaf5c65ef00ee257d0f5 100644 --- a/packages/rocketchat-webrtc/i18n/nl.i18n.json +++ b/packages/rocketchat-webrtc/i18n/nl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "Toestaan voor openbare kanalen", + "WebRTC_Enable_Direct" : "Toestaan directe-berichten", + "WebRTC_Enable_Private" : "Toestaan voor privé-berichten" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ro.i18n.json b/packages/rocketchat-webrtc/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..c4481eb992373156babf2a2aff7ae75d05897cbb --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ro.i18n.json @@ -0,0 +1,5 @@ +{ + "WebRTC_Enable_Channel" : "ActivaÈ›i pentru canale publice", + "WebRTC_Enable_Direct" : "ActivaÈ›i pentru mesaje directe", + "WebRTC_Enable_Private" : "ActivaÈ›i pentru canale private" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ru.i18n.json b/packages/rocketchat-webrtc/i18n/ru.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..4fa803614951bdb558ea8550118f74dbe715c666 100644 --- a/packages/rocketchat-webrtc/i18n/ru.i18n.json +++ b/packages/rocketchat-webrtc/i18n/ru.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "Включить Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… чатов", + "WebRTC_Enable_Direct" : "Включить Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… Ñообщений", + "WebRTC_Enable_Private" : "Включить Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ñ‹Ñ… чатов" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/sr.i18n.json b/packages/rocketchat-webrtc/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/package.js b/packages/rocketchat-webrtc/package.js index 5ed915027e3395829ab308aa4e8a7c66c611bc54..555b1db1f24e3d43213cb38a6eac3e3796b7587c 100644 --- a/packages/rocketchat-webrtc/package.js +++ b/packages/rocketchat-webrtc/package.js @@ -8,7 +8,7 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.use('coffeescript'); api.addFiles('adapter.js', 'client'); @@ -26,9 +26,8 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); api.export('WebRTC'); }); diff --git a/packages/rocketchat-wordpress/i18n/de.i18n.json b/packages/rocketchat-wordpress/i18n/de.i18n.json index f269571244df1451a940dd96e71b0bb9cddcb336..a95a71ed381fa63f85db1a94ec543d4fc0aafcc5 100644 --- a/packages/rocketchat-wordpress/i18n/de.i18n.json +++ b/packages/rocketchat-wordpress/i18n/de.i18n.json @@ -1,6 +1,6 @@ { - "API_Wordpress_URL" : "Wordpress URL", - "Accounts_OAuth_Wordpress" : "WordPress Login", - "Accounts_OAuth_Wordpress_id" : "Wordpress-ID", - "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" + "API_Wordpress_URL" : "Wordpress-URL", + "Accounts_OAuth_Wordpress" : "Anmeldung über Wordpress", + "Accounts_OAuth_Wordpress_id" : "WordPress-ID", + "Accounts_OAuth_Wordpress_secret" : "Wordpress-Secret" } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/fr.i18n.json b/packages/rocketchat-wordpress/i18n/fr.i18n.json index 315cdb25a08636af5fdb05ab0450f5c6d0b7e2b5..abda39cd1254929eabc5e416ae21479ef4dac1e7 100644 --- a/packages/rocketchat-wordpress/i18n/fr.i18n.json +++ b/packages/rocketchat-wordpress/i18n/fr.i18n.json @@ -1,6 +1,6 @@ { "API_Wordpress_URL" : "WordPress URL", "Accounts_OAuth_Wordpress" : "WordPress Login", - "Accounts_OAuth_Wordpress_id" : "WordPress ID", + "Accounts_OAuth_Wordpress_id" : "ID WordPress", "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/nl.i18n.json b/packages/rocketchat-wordpress/i18n/nl.i18n.json index 6f31cf5a2e622e523ae008338072897b8e56c993..1de9bd9e80c19d058704b87b764e036db82b7dbc 100644 --- a/packages/rocketchat-wordpress/i18n/nl.i18n.json +++ b/packages/rocketchat-wordpress/i18n/nl.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "WordPress URL", + "Accounts_OAuth_Wordpress" : "WordPress Inloggen", + "Accounts_OAuth_Wordpress_id" : "WordPress Id", + "Accounts_OAuth_Wordpress_secret" : "WordPress Geheim (secret)" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/ro.i18n.json b/packages/rocketchat-wordpress/i18n/ro.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..18fe2bdf9468caecd50e8c0c3b7d5691d514b178 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/ro.i18n.json @@ -0,0 +1,6 @@ +{ + "API_Wordpress_URL" : "URL WordPress", + "Accounts_OAuth_Wordpress" : "Autentificare WordPress", + "Accounts_OAuth_Wordpress_id" : " Id WordPress", + "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/sr.i18n.json b/packages/rocketchat-wordpress/i18n/sr.i18n.json new file mode 100644 index 0000000000000000000000000000000000000000..6f31cf5a2e622e523ae008338072897b8e56c993 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/package.js b/packages/rocketchat-wordpress/package.js index 6bd7e5d6bf208b792eee05be480017489ec51eb0..a219fc6b77a7db2ba3eebff603692a96eedbe513 100644 --- a/packages/rocketchat-wordpress/package.js +++ b/packages/rocketchat-wordpress/package.js @@ -1,30 +1,29 @@ Package.describe({ - name: 'rocketchat:wordpress', - version: '0.0.1', - summary: 'RocketChat settings for WordPress Oauth Flow' + name: 'rocketchat:wordpress', + version: '0.0.1', + summary: 'RocketChat settings for WordPress Oauth Flow' }); Package.onUse(function(api) { - api.versionsFrom('1.0'); - api.use('coffeescript'); - api.use('rocketchat:lib@0.0.1'); - api.use('rocketchat:custom-oauth'); - api.addFiles("common.coffee"); - api.addFiles('wordpress-login-button.css', 'client'); - api.addFiles('startup.coffee', 'server'); - - // TAPi18n - api.use('templating', 'client'); - var _ = Npm.require('underscore'); - var fs = Npm.require('fs'); - tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-wordpress/i18n'), function(filename) { - if (fs.statSync('packages/rocketchat-wordpress/i18n/' + filename).size > 16) { - return 'i18n/' + filename; - } - })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, ['client', 'server']); + api.versionsFrom('1.0'); + api.use('coffeescript'); + api.use('rocketchat:lib'); + api.use('rocketchat:custom-oauth'); + api.addFiles("common.coffee"); + api.addFiles('wordpress-login-button.css', 'client'); + api.addFiles('startup.coffee', 'server'); + + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-wordpress/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-wordpress/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { diff --git a/private/node_scripts/unsubscribe_csv/package.json b/private/node_scripts/unsubscribe_csv/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1efe93181ce21f7a771b053c5cb2b78832af3d30 --- /dev/null +++ b/private/node_scripts/unsubscribe_csv/package.json @@ -0,0 +1,20 @@ +{ + "name": "unsubscribe_csv", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "coffee unsubscribe.coffee", + "test": "mocha --compilers coffee:coffee-script --timeout 5s -R spec" + }, + "dependencies": { + "coffee-script": "~1.6.3", + "commander": "^2.9.0", + "ddp": "^0.11.0", + "line-by-line": "^0.1.3", + "line-reader": "^0.2.4", + "moment": "^2.10.2", + "mongodb": "^2.1.0", + "underscore": "^1.6.0", + "wait.for": "^0.6.6" + } +} diff --git a/private/node_scripts/unsubscribe_csv/unsubscribe.coffee b/private/node_scripts/unsubscribe_csv/unsubscribe.coffee new file mode 100644 index 0000000000000000000000000000000000000000..450d03329f8c8f51b0b1c1643e3071d4d60329a6 --- /dev/null +++ b/private/node_scripts/unsubscribe_csv/unsubscribe.coffee @@ -0,0 +1,33 @@ +_ = require 'underscore' + +fs = require('fs') +lineReader = require('line-reader') +moment = require('moment') +path = require('path') +program = require('commander') +wait = require('wait.for') + +MongoClient = require('mongodb').MongoClient + +program + .usage '[options]' + .option '-v, --verbose', 'Verbose', ((v, total) -> total + 1), 0 + .option '-M, --mongo-db [mongo db]', 'Mongo DB', 'localhost:27017' + .option '-N, --db-name [db name]', 'DB Name', 'meteor' + .on '--help', -> + console.log ' Example:' + console.log '' + console.log ' $ coffee unsubscribe.coffee' + console.log '' + .parse process.argv + +wait.launchFiber -> + db = wait.forMethod MongoClient, 'connect', "mongodb://#{program.mongoDb}/#{program.dbName}", { replSet: { socketOptions: { connectTimeoutMS: 300000 } } } + User = db.collection 'users' + lineReader.eachLine './unsubscribe.csv', (line, last) -> + row = line.split ',' + console.log row[0] if program.verbose + wait.launchFiber -> + updated = wait.forMethod User, 'update', { "emails.address": row[0] }, { $set: { "mailer.unsubscribed": true } } + if last + process.exit() diff --git a/rocketchat.info b/rocketchat.info deleted file mode 100644 index 49886ade63fb2c01118ec35a597fccb332138612..0000000000000000000000000000000000000000 --- a/rocketchat.info +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "0.9.0" -} diff --git a/scalingo.json b/scalingo.json new file mode 100644 index 0000000000000000000000000000000000000000..92ee06f04f6769510963a39856ab3d6e2565a9b8 --- /dev/null +++ b/scalingo.json @@ -0,0 +1,8 @@ +{ + "name": "Rocket.Chat", + "repository": "https://github.com/RocketChat/Rocket.Chat", + "description": "Have your own open-source Slack-like online chat, built with Meteor.", + "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/512x512.png?v=3", + "website": "https://rocket.chat", + "addons": ["scalingo-mongodb"] +} diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index b9531f2ea1a66a3b2e9ad3d86cd30195acb67e5c..061af1ad93515680b31ac12ae8eb5043322faadf 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -1,8 +1,8 @@ # Deny Account.createUser in client and set Meteor.loginTokenExpires accountsConfig = { forbidClientAccountCreation: true, loginExpirationInDays: RocketChat.settings.get 'Accounts_LoginExpiration' } -if RocketChat.settings.get('Account_AllowedDomainsList') - domainWhiteList = _.map RocketChat.settings.get('Account_AllowedDomainsList').split(','), (domain) -> domain.trim() +if RocketChat.settings.get('Accounts_AllowedDomainsList') + domainWhiteList = _.map RocketChat.settings.get('Accounts_AllowedDomainsList').split(','), (domain) -> domain.trim() accountsConfig.restrictCreationByEmailDomain = (email) -> ret = false for domain in domainWhiteList @@ -24,8 +24,8 @@ Accounts.emailTemplates.verifyEmail.text = (user, url) -> resetPasswordText = Accounts.emailTemplates.resetPassword.text Accounts.emailTemplates.resetPassword.text = (user, url) -> - url = url.replace Meteor.absoluteUrl(), Meteor.absoluteUrl() + 'login/' - verifyEmailText user, url + url = url.replace /\/#\//, '/' + resetPasswordText user, url if RocketChat.settings.get 'Accounts_Enrollment_Email' Accounts.emailTemplates.enrollAccount.text = (user, url) -> @@ -69,16 +69,25 @@ Accounts.onCreateUser (options, user) -> return user # Wrap insertUserDoc to allow executing code after Accounts.insertUserDoc is run -Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc) -> - options = arguments[1] - user = arguments[2] +Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc, options, user) -> + roles = [] + if Match.test(user.globalRoles, [String]) and user.globalRoles.length > 0 + roles = roles.concat user.globalRoles + + delete user.globalRoles + _id = insertUserDoc.call(Accounts, options, user) - # when inserting first user give them admin privileges otherwise make a regular user - firstUser = RocketChat.models.Users.findOne({ _id: { $ne: 'rocket.cat' }}, { sort: { createdAt: 1 }}) - roleName = if firstUser?._id is _id then 'admin' else 'user' + if roles.length is 0 + # when inserting first user give them admin privileges otherwise make a regular user + firstUser = RocketChat.models.Users.findOne({ _id: { $ne: 'rocket.cat' }}, { sort: { createdAt: 1 }}) + if firstUser?._id is _id + roles.push 'admin' + else + roles.push 'user' + + RocketChat.authz.addUserRoles(_id, roles) - RocketChat.authz.addUsersToRoles(_id, roleName) RocketChat.callbacks.run 'afterCreateUser', options, user return _id diff --git a/server/methods/addRoomModerator.coffee b/server/methods/addRoomModerator.coffee new file mode 100644 index 0000000000000000000000000000000000000000..eca8b3af439138094da44280fd74f6a36b72d90f --- /dev/null +++ b/server/methods/addRoomModerator.coffee @@ -0,0 +1,25 @@ +Meteor.methods + addRoomModerator: (rid, userId) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] addRoomModerator -> Invalid user' + + check rid, String + check userId, String + + unless RocketChat.authz.hasPermission Meteor.userId(), 'set-moderator', rid + throw new Meteor.Error 403, 'Not allowed' + + subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId rid, userId + unless subscription? + throw new Meteor.Error 'invalid-subscription', '[methods] addRoomModerator -> Invalid Subscription' + + RocketChat.models.Subscriptions.addRoleById(subscription._id, 'moderator') + + user = RocketChat.models.Users.findOneById userId + fromUser = RocketChat.models.Users.findOneById Meteor.userId() + RocketChat.models.Messages.createNewModeratorWithRoomIdAndUser rid, user, + u: + _id: fromUser._id + username: fromUser.username + + return true diff --git a/server/methods/addRoomOwner.coffee b/server/methods/addRoomOwner.coffee new file mode 100644 index 0000000000000000000000000000000000000000..d3838be0b0355221ff471b05021ec55f32cda053 --- /dev/null +++ b/server/methods/addRoomOwner.coffee @@ -0,0 +1,25 @@ +Meteor.methods + addRoomOwner: (rid, userId) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] addRoomOwner -> Invalid user' + + check rid, String + check userId, String + + unless RocketChat.authz.hasPermission Meteor.userId(), 'set-owner', rid + throw new Meteor.Error 403, 'Not allowed' + + subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId rid, userId + unless subscription? + throw new Meteor.Error 'invalid-subscription', '[methods] addRoomOwner -> Invalid Subscription' + + RocketChat.models.Subscriptions.addRoleById(subscription._id, 'owner') + + user = RocketChat.models.Users.findOneById userId + fromUser = RocketChat.models.Users.findOneById Meteor.userId() + RocketChat.models.Messages.createNewOwnerWithRoomIdAndUser rid, user, + u: + _id: fromUser._id + username: fromUser.username + + return true diff --git a/server/methods/addUserToRoom.coffee b/server/methods/addUserToRoom.coffee index cf1dd53963521cf98b32c9028b6ac8d069e52812..3cfd91d7346d9c36e1d7dbd40a9a3dc851f8b17a 100644 --- a/server/methods/addUserToRoom.coffee +++ b/server/methods/addUserToRoom.coffee @@ -1,8 +1,6 @@ Meteor.methods addUserToRoom: (data) -> fromId = Meteor.userId() - console.log '[methods] addUserToRoom -> '.green, 'data:', data - unless Match.test data?.rid, String throw new Meteor.Error 'invalid-rid' diff --git a/server/methods/archiveRoom.coffee b/server/methods/archiveRoom.coffee index abfcef70b12c8d3fd36e04f3e12911a13fd152eb..e1d86612d1d6241e8c52eca265dd7a0d2dccbd5f 100644 --- a/server/methods/archiveRoom.coffee +++ b/server/methods/archiveRoom.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', '[methods] archiveRoom -> Invalid user' - console.log '[methods] archiveRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - room = RocketChat.models.Rooms.findOneById rid if room.u? and room.u._id is Meteor.userId() or RocketChat.authz.hasRole(Meteor.userId(), 'admin') diff --git a/server/methods/canAccessRoom.coffee b/server/methods/canAccessRoom.coffee index 2d5cd6ff3303082c13fdf8211a7b5ec6e78334e1..4d84b6a8d7621582edb48132d0a90069189792c3 100644 --- a/server/methods/canAccessRoom.coffee +++ b/server/methods/canAccessRoom.coffee @@ -1,7 +1,5 @@ Meteor.methods canAccessRoom: (rid, userId) -> - console.log '[methods] canAccessRoom -> '.green, 'userId:', userId, 'rid:', rid - user = RocketChat.models.Users.findOneById userId, fields: username: 1 unless user?.username @@ -10,7 +8,7 @@ Meteor.methods unless rid throw new Meteor.Error 'invalid-room', '[methods] canAccessRoom -> Cannot access empty room' - room = RocketChat.models.Rooms.findOneById rid, { fields: { usernames: 1, t: 1, name: 1 } } + room = RocketChat.models.Rooms.findOneById rid, { fields: { usernames: 1, t: 1, name: 1, muted: 1 } } if room if room.t is 'c' @@ -21,6 +19,6 @@ Meteor.methods if canAccess isnt true return false else - return _.pick room, ['_id', 't', 'name', 'usernames'] + return _.pick room, ['_id', 't', 'name', 'usernames', 'muted'] else throw new Meteor.Error 'invalid-room', '[methods] canAccessRoom -> Room ID is invalid' diff --git a/server/methods/channelsList.coffee b/server/methods/channelsList.coffee index 7aa42ff6351877a870f922e7286bfd9481a32fba..c57d66e3a5474f281e819d7d0c7535559ba27811 100644 --- a/server/methods/channelsList.coffee +++ b/server/methods/channelsList.coffee @@ -1,3 +1,3 @@ Meteor.methods channelsList: -> - return { channels: RocketChat.models.Rooms.findByType('c', { sort: { msgs:-1 } }).fetch() } + return { channels: RocketChat.models.Rooms.findByTypeAndArchivationState('c', false, { sort: { msgs:-1 } }).fetch() } diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index 3c8319079d3791ea17e6b1d4ca1eaa5c29b8528a..3edf800ec94e6e9c9c29e3f38cccc0a5a9d2353a 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -14,8 +14,6 @@ Meteor.methods if RocketChat.authz.hasPermission(Meteor.userId(), 'create-c') isnt true throw new Meteor.Error 'not-authorized', '[methods] createChannel -> Not authorized' - console.log '[methods] createChannel -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - now = new Date() user = Meteor.user() @@ -23,7 +21,10 @@ Meteor.methods # avoid duplicate names if RocketChat.models.Rooms.findOneByName name - throw new Meteor.Error 'duplicate-name' + if RocketChat.models.Rooms.findOneByName(name).archived + throw new Meteor.Error 'archived-duplicate-name' + else + throw new Meteor.Error 'duplicate-name' # name = s.slugify name @@ -40,9 +41,6 @@ Meteor.methods room = RocketChat.models.Rooms.createWithTypeNameUserAndUsernames 'c', name, user, members, ts: now - # set creator as channel moderator. permission limited to channel by scoping to rid - RocketChat.authz.addUsersToRoles(Meteor.userId(), 'moderator', room._id) - for username in members member = RocketChat.models.Users.findOneByUsername username if not member? @@ -56,6 +54,9 @@ Meteor.methods RocketChat.models.Subscriptions.createWithRoomAndUser room, member, extra + # set creator as channel moderator. permission limited to channel by scoping to rid + RocketChat.authz.addUserRoles(Meteor.userId(), ['moderator','owner'], room._id) + Meteor.defer -> RocketChat.callbacks.run 'afterCreateChannel', user, room diff --git a/server/methods/createDirectMessage.coffee b/server/methods/createDirectMessage.coffee index 5fa5934680c0a5389acd593b2143e48f296b7bc7..48dc97b1e5f313e8641644f2f7f6b98e9b7e2445 100644 --- a/server/methods/createDirectMessage.coffee +++ b/server/methods/createDirectMessage.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', "[methods] createDirectMessage -> Invalid user" - console.log '[methods] createDirectMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - me = Meteor.user() if me.username is username diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 22080081372ebf7cf1f4b94c8ccb4a32e5a33dae..657fa879463b8d4cff8c1f08e0f0ebf22d4b2d41 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -6,8 +6,6 @@ Meteor.methods unless RocketChat.authz.hasPermission(Meteor.userId(), 'create-p') throw new Meteor.Error 'not-authorized', '[methods] createPrivateGroup -> Not authorized' - console.log '[methods] createPrivateGroup -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - try nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$' catch @@ -26,14 +24,17 @@ Meteor.methods # avoid duplicate names if RocketChat.models.Rooms.findOneByName name - throw new Meteor.Error 'duplicate-name' + if RocketChat.models.Rooms.findOneByName(name).archived + throw new Meteor.Error 'archived-duplicate-name' + else + throw new Meteor.Error 'duplicate-name' # create new room room = RocketChat.models.Rooms.createWithTypeNameUserAndUsernames 'p', name, me, members, ts: now # set creator as group moderator. permission limited to group by scoping to rid - RocketChat.authz.addUsersToRoles(Meteor.userId(), 'moderator', room._id) + RocketChat.authz.addUserRoles(Meteor.userId(), ['moderator','owner'], room._id) for username in members member = RocketChat.models.Users.findOneByUsername(username, { fields: { username: 1 }}) diff --git a/server/methods/deleteMessage.coffee b/server/methods/deleteMessage.coffee index fbf66bb76b2545a3cdf63e1b89434ad6626fe2ff..5e96a7cc4abeb8b3eda5a8ba90173364862e81a5 100644 --- a/server/methods/deleteMessage.coffee +++ b/server/methods/deleteMessage.coffee @@ -15,8 +15,6 @@ Meteor.methods unless hasPermission or (deleteAllowed and deleteOwn) throw new Meteor.Error 'message-deleting-not-allowed', "[methods] deleteMessage -> Message deleting not allowed" - console.log '[methods] deleteMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - keepHistory = RocketChat.settings.get 'Message_KeepHistory' showDeletedStatus = RocketChat.settings.get 'Message_ShowDeletedStatus' diff --git a/server/methods/eraseRoom.coffee b/server/methods/eraseRoom.coffee index a8c6f8248b7acba6ebbbee73c64f3bb07dbbef4e..5c82b18cb4c9e922fccf4566ccefef080c5cab05 100644 --- a/server/methods/eraseRoom.coffee +++ b/server/methods/eraseRoom.coffee @@ -5,8 +5,6 @@ Meteor.methods roomType = RocketChat.models.Rooms.findOneById(rid)?.t if RocketChat.authz.hasPermission( fromId, "delete-#{roomType}", rid ) - # console.log '[methods] eraseRoom -> '.green, 'fromId:', fromId, 'rid:', rid - # ChatRoom.update({ _id: rid}, {'$pull': { userWatching: Meteor.userId(), userIn: Meteor.userId() }}) RocketChat.models.Messages.removeByRoomId rid diff --git a/server/methods/getRoomIdByNameOrId.coffee b/server/methods/getRoomIdByNameOrId.coffee index 50d6a4a0c64ba06ddba90699d7cdc12eb87c44a0..4634081feb0e4b7528d8872e4f363fb02626268b 100644 --- a/server/methods/getRoomIdByNameOrId.coffee +++ b/server/methods/getRoomIdByNameOrId.coffee @@ -1,8 +1,6 @@ Meteor.methods getRoomIdByNameOrId: (rid) -> - console.log '[methods] getRoomIdByNameOrId-> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - room = RocketChat.models.Rooms.findOneById rid if not room? diff --git a/server/methods/getRoomModeratorsAndOwners.coffee b/server/methods/getRoomModeratorsAndOwners.coffee new file mode 100644 index 0000000000000000000000000000000000000000..37adf0601566e9d76ac1481a58837144ab540559 --- /dev/null +++ b/server/methods/getRoomModeratorsAndOwners.coffee @@ -0,0 +1,16 @@ +Meteor.methods + getRoomModeratorsAndOwners: (rid) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] getRoomModeratorsAndOwners -> Invalid user' + + check rid, String + + options = + sort: + "u.username": 1 + fields: + rid: 1 + u: 1 + roles: 1 + + return RocketChat.models.Subscriptions.findByRoomIdAndRoles(rid, ['moderator', 'owner'], options).fetch() diff --git a/server/methods/getTotalChannels.coffee b/server/methods/getTotalChannels.coffee index f791683e8c2486cd03f3a4ecc1605bfa0f095350..8c318d78a158ac6582264065c1ce547e1a40964d 100644 --- a/server/methods/getTotalChannels.coffee +++ b/server/methods/getTotalChannels.coffee @@ -3,5 +3,4 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', '[methods] getTotalChannels -> Invalid user' - console.log '[methods] getTotalChannels -> '.green, 'userId:', Meteor.userId() return RocketChat.models.Rooms.find({ t: 'c' }).count() diff --git a/server/methods/hideRoom.coffee b/server/methods/hideRoom.coffee index 3537394aef40fbd515a4daeb771e751e80fa2739..cbb2d6023c0d393943f2300b95a14a80d500ff64 100644 --- a/server/methods/hideRoom.coffee +++ b/server/methods/hideRoom.coffee @@ -3,6 +3,4 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', '[methods] hideRoom -> Invalid user' - console.log '[methods] hideRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - RocketChat.models.Subscriptions.hideByRoomIdAndUserId rid, Meteor.userId() diff --git a/server/methods/joinRoom.coffee b/server/methods/joinRoom.coffee index 81666400b1463dfa6013ad410d5c7f9aa5862ca5..42e9630474dbfd1796ce0001408aa79fd05f119d 100644 --- a/server/methods/joinRoom.coffee +++ b/server/methods/joinRoom.coffee @@ -3,8 +3,6 @@ Meteor.methods room = RocketChat.models.Rooms.findOneById rid - console.log '[methods] joinRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - if not room? throw new Meteor.Error 500, 'No channel with this id' diff --git a/server/methods/leaveRoom.coffee b/server/methods/leaveRoom.coffee index 4ff40c087fb97c4b32a5e931adbc13ca61c6b066..d54faba3fb162daa63eb23d20524759f47ebe0f6 100644 --- a/server/methods/leaveRoom.coffee +++ b/server/methods/leaveRoom.coffee @@ -1,8 +1,6 @@ Meteor.methods leaveRoom: (rid) -> fromId = Meteor.userId() - # console.log '[methods] leaveRoom -> '.green, 'fromId:', fromId, 'rid:', rid - unless Meteor.userId()? throw new Meteor.Error 300, 'Usuário não logado' diff --git a/server/methods/loadHistory.coffee b/server/methods/loadHistory.coffee index 921bfae150a9a21e46346007b69a7f1badc27e1f..3c3fea2213240a18fe28c2757947911de343c134 100644 --- a/server/methods/loadHistory.coffee +++ b/server/methods/loadHistory.coffee @@ -1,8 +1,6 @@ Meteor.methods loadHistory: (rid, end, limit=20, ls) -> fromId = Meteor.userId() - # console.log '[methods] loadHistory -> '.green, 'fromId:', fromId, 'rid:', rid, 'end:', end, 'limit:', limit, 'skip:', skip - unless Meteor.call 'canAccessRoom', rid, fromId return false @@ -29,9 +27,12 @@ Meteor.methods firstMessage = messages[messages.length - 1] if firstMessage?.ts > ls delete options.limit - unreadNotLoaded = RocketChat.models.Messages.findVisibleByRoomIdBetweenTimestamps(rid, ls, firstMessage.ts).count() + unreadMessages = RocketChat.models.Messages.findVisibleByRoomIdBetweenTimestamps(rid, ls, firstMessage.ts, { limit: 1, sort: { ts: 1 } }) + firstUnread = unreadMessages.fetch()[0] + unreadNotLoaded = unreadMessages.count() return { messages: messages + firstUnread: firstUnread unreadNotLoaded: unreadNotLoaded } diff --git a/server/methods/loadLocale.coffee b/server/methods/loadLocale.coffee index f4ed82c228ab664c9e125380ed58dc8c057d6683..17f4c2d87586b94a344b30ef063629f9c3eae40b 100644 --- a/server/methods/loadLocale.coffee +++ b/server/methods/loadLocale.coffee @@ -1,6 +1,5 @@ Meteor.methods loadLocale: (locale) -> - console.log "[method] loadLocale: #{locale}".green try return Assets.getText "moment-locales/#{locale.toLowerCase()}.js" catch e diff --git a/server/methods/loadMissedMessages.coffee b/server/methods/loadMissedMessages.coffee index e6c201aa77b229b7685c53bdc84114fcf201814e..7d22fe1fd452d4156892cdc4448fef34b5e0cdcc 100644 --- a/server/methods/loadMissedMessages.coffee +++ b/server/methods/loadMissedMessages.coffee @@ -1,8 +1,6 @@ Meteor.methods loadMissedMessages: (rid, start) -> fromId = Meteor.userId() - # console.log '[methods] loadMissedMessages -> '.green, 'fromId:', fromId, 'rid:', rid, 'start:', start - unless Meteor.call 'canAccessRoom', rid, fromId return false diff --git a/server/methods/loadNextMessages.coffee b/server/methods/loadNextMessages.coffee new file mode 100644 index 0000000000000000000000000000000000000000..91a600bfc43bd3722cb7c108b8aa9b59580042da --- /dev/null +++ b/server/methods/loadNextMessages.coffee @@ -0,0 +1,27 @@ +Meteor.methods + loadNextMessages: (rid, end, limit=20) -> + fromId = Meteor.userId() + + unless Meteor.call 'canAccessRoom', rid, fromId + return false + + options = + sort: + ts: 1 + limit: limit + + if not RocketChat.settings.get 'Message_ShowEditedStatus' + options.fields = { 'editedAt': 0 } + + if end? + records = RocketChat.models.Messages.findVisibleByRoomIdAfterTimestamp(rid, end, options).fetch() + else + records = RocketChat.models.Messages.findVisibleByRoomId(rid, options).fetch() + + messages = _.map records, (message) -> + message.starred = _.findWhere message.starred, { _id: fromId } + return message + + return { + messages: messages + } diff --git a/server/methods/loadSurroundingMessages.coffee b/server/methods/loadSurroundingMessages.coffee new file mode 100644 index 0000000000000000000000000000000000000000..0d63b37531c0fb9554f4eee93d8b99922063dbb4 --- /dev/null +++ b/server/methods/loadSurroundingMessages.coffee @@ -0,0 +1,46 @@ +Meteor.methods + loadSurroundingMessages: (message, limit=50) -> + fromId = Meteor.userId() + + unless message?.rid + return false + + unless Meteor.call 'canAccessRoom', message.rid, fromId + return false + + if not RocketChat.settings.get 'Message_ShowEditedStatus' + options.fields = { 'editedAt': 0 } + + limit = limit - 1 + + options = + sort: + ts: -1 + limit: Math.ceil(limit/2) + records = RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestamp(message.rid, message.ts, options).fetch() + messages = _.map records, (message) -> + message.starred = _.findWhere message.starred, { _id: fromId } + return message + + moreBefore = messages.length is options.limit + + messages.push message + + options = + sort: + ts: 1 + limit: Math.floor(limit/2) + records = RocketChat.models.Messages.findVisibleByRoomIdAfterTimestamp(message.rid, message.ts, options).fetch() + afterMessages = _.map records, (message) -> + message.starred = _.findWhere message.starred, { _id: fromId } + return message + + moreAfter = afterMessages.length is options.limit + + messages = messages.concat afterMessages + + return { + messages: messages + moreBefore: moreBefore + moreAfter: moreAfter + } diff --git a/server/methods/logoutCleanUp.coffee b/server/methods/logoutCleanUp.coffee index 4bf8d65487eb9d10fc17352f82dd578116368672..7d5615c3cb8f9cb4f2a60998ef05af27715c9aa6 100644 --- a/server/methods/logoutCleanUp.coffee +++ b/server/methods/logoutCleanUp.coffee @@ -1,7 +1,5 @@ Meteor.methods logoutCleanUp: (user) -> - console.log '[methods] logoutCleanUp -> '.green, 'userId:', user._id - Meteor.defer -> - RocketChat.callbacks.run 'afterLogoutCleanUp', user \ No newline at end of file + RocketChat.callbacks.run 'afterLogoutCleanUp', user diff --git a/server/methods/messageSearch.coffee b/server/methods/messageSearch.coffee index 0f1a714d39257666a34153074f08559bf414af16..4c5d99a6151c0075d38d1b7131916f805ca8fb5a 100644 --- a/server/methods/messageSearch.coffee +++ b/server/methods/messageSearch.coffee @@ -1,11 +1,9 @@ Meteor.methods - messageSearch: (text, rid) -> + messageSearch: (text, rid, limit) -> ### text = 'from:rodrigo mention:gabriel chat' ### - # console.log '[method] -> messageSearch', text - result = messages: [] users: [] @@ -15,7 +13,7 @@ Meteor.methods options = sort: ts: -1 - limit: 20 + limit: limit or 20 # Query for senders from = [] @@ -56,14 +54,21 @@ Meteor.methods # $meta: 'textScore' if Object.keys(query).length > 0 + query.t = { $ne: 'rm' } # hide removed messages (userful when searching for user messages) + query._hidden = { $ne: true } # don't return _hidden messages + # Filter by room if rid? query.rid = rid try if Meteor.call('canAccessRoom', rid, this.userId) isnt false + console.log query result.messages = RocketChat.models.Messages.find(query, options).fetch() + # make sure we don't return more than limit results + # limit -= result.messages?.length + # ### # # USERS # ### diff --git a/server/methods/migrate.coffee b/server/methods/migrate.coffee index 915b4582f37ac9de86dd7a76f8c332ef4ef56917..3b01619a1c8b6f13010558481160048a68503054 100644 --- a/server/methods/migrate.coffee +++ b/server/methods/migrate.coffee @@ -3,12 +3,11 @@ Meteor.methods user = Meteor.user() if not user? or RocketChat.authz.hasPermission(user._id, 'run-migration') isnt true - console.log '[methods] createChannel -> Not authorized' - return + throw new Meteor.Error "not-authorized", '[methods] migrateTo' this.unblock() Migrations.migrateTo version return version getMigrationVersion: -> - return Migrations.getVersion() \ No newline at end of file + return Migrations.getVersion() diff --git a/server/methods/muteUserInRoom.coffee b/server/methods/muteUserInRoom.coffee new file mode 100644 index 0000000000000000000000000000000000000000..1cff2d7de019844ba684fbae04b6b89633396282 --- /dev/null +++ b/server/methods/muteUserInRoom.coffee @@ -0,0 +1,29 @@ +Meteor.methods + muteUserInRoom: (data) -> + fromId = Meteor.userId() + check(data, Match.ObjectIncluding({ rid: String, username: String })) + + unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) + throw new Meteor.Error 'not-allowed', '[methods] muteUserInRoom -> Not allowed' + + room = RocketChat.models.Rooms.findOneById data.rid + if not room + throw new Meteor.Error 'invalid-room', '[methods] muteUserInRoom -> Room ID is invalid' + + if room.t not in ['c', 'p'] + throw new Meteor.Error 'invalid-room-type', '[methods] muteUserInRoom -> Invalid room type' + + if data.username not in (room?.usernames or []) + throw new Meteor.Error 'not-in-room', '[methods] muteUserInRoom -> User is not in this room' + + mutedUser = RocketChat.models.Users.findOneByUsername data.username + + RocketChat.models.Rooms.muteUsernameByRoomId data.rid, mutedUser.username + + fromUser = RocketChat.models.Users.findOneById fromId + RocketChat.models.Messages.createUserMutedWithRoomIdAndUser data.rid, mutedUser, + u: + _id: fromUser._id + username: fromUser.username + + return true diff --git a/server/methods/openRoom.coffee b/server/methods/openRoom.coffee index 9dcb5d818d2b672bb536588fa1cf509a83ce5060..2b2536c87f4fa3bd4fb049441568fc7d08cdf8e9 100644 --- a/server/methods/openRoom.coffee +++ b/server/methods/openRoom.coffee @@ -3,6 +3,4 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', '[methods] openRoom -> Invalid user' - console.log '[methods] openRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - RocketChat.models.Subscriptions.openByRoomIdAndUserId rid, Meteor.userId() diff --git a/server/methods/readMessages.coffee b/server/methods/readMessages.coffee index 35dc63a998dcf0afb813f014869daab2d1616318..985d6050505d2dda1c6015e198f6b151be3d4eca 100644 --- a/server/methods/readMessages.coffee +++ b/server/methods/readMessages.coffee @@ -3,6 +3,4 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', '[methods] readMessages -> Invalid user' - console.log '[methods] readMessages -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - RocketChat.models.Subscriptions.setAsReadByRoomIdAndUserId rid, Meteor.userId() diff --git a/server/methods/removeRoomModerator.coffee b/server/methods/removeRoomModerator.coffee new file mode 100644 index 0000000000000000000000000000000000000000..50ee2aa570e39513389a893b4b9dd185722055ea --- /dev/null +++ b/server/methods/removeRoomModerator.coffee @@ -0,0 +1,25 @@ +Meteor.methods + removeRoomModerator: (rid, userId) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] removeRoomModerator -> Invalid user' + + check rid, String + check userId, String + + unless RocketChat.authz.hasPermission Meteor.userId(), 'set-moderator', rid + throw new Meteor.Error 403, 'Not allowed' + + subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId rid, userId + unless subscription? + throw new Meteor.Error 'invalid-subscription', '[methods] removeRoomModerator -> Invalid Subscription' + + RocketChat.models.Subscriptions.removeRoleById(subscription._id, 'moderator') + + user = RocketChat.models.Users.findOneById userId + fromUser = RocketChat.models.Users.findOneById Meteor.userId() + RocketChat.models.Messages.createModeratorRemovedWithRoomIdAndUser rid, user, + u: + _id: fromUser._id + username: fromUser.username + + return true diff --git a/server/methods/removeRoomOwner.coffee b/server/methods/removeRoomOwner.coffee new file mode 100644 index 0000000000000000000000000000000000000000..b29a5f431ec81f7e503a514ffb8c7eeff85ac584 --- /dev/null +++ b/server/methods/removeRoomOwner.coffee @@ -0,0 +1,25 @@ +Meteor.methods + removeRoomOwner: (rid, userId) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] removeRoomOwner -> Invalid user' + + check rid, String + check userId, String + + unless RocketChat.authz.hasPermission Meteor.userId(), 'set-owner', rid + throw new Meteor.Error 403, 'Not allowed' + + subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId rid, userId + unless subscription? + throw new Meteor.Error 'invalid-subscription', '[methods] removeRoomOwner -> Invalid Subscription' + + RocketChat.models.Subscriptions.removeRoleById(subscription._id, 'owner') + + user = RocketChat.models.Users.findOneById userId + fromUser = RocketChat.models.Users.findOneById Meteor.userId() + RocketChat.models.Messages.createOwnerRemovedWithRoomIdAndUser rid, user, + u: + _id: fromUser._id + username: fromUser.username + + return true diff --git a/server/methods/removeUserFromRoom.coffee b/server/methods/removeUserFromRoom.coffee index d600b6d991ce7a3b2a538bbc8cac8d4fdff2d68b..2c737d9e83d2cad82dfe0869a56d000d6f521d17 100644 --- a/server/methods/removeUserFromRoom.coffee +++ b/server/methods/removeUserFromRoom.coffee @@ -1,25 +1,29 @@ Meteor.methods removeUserFromRoom: (data) -> fromId = Meteor.userId() - # console.log '[methods] removeUserFromRoom -> '.green, 'fromId:', fromId, 'data:', data + check(data, Match.ObjectIncluding({ rid: String, username: String })) + + unless RocketChat.authz.hasPermission(fromId, 'remove-user', data.rid) + throw new Meteor.Error 'not-allowed', 'Not allowed' room = RocketChat.models.Rooms.findOneById data.rid - if room.u?._id isnt Meteor.userId() and room.t is 'c' - throw new Meteor.Error 403, 'Not allowed' + if data.username not in (room?.usernames or []) + throw new Meteor.Error 'not-in-room', 'User is not in this room' removedUser = RocketChat.models.Users.findOneByUsername data.username RocketChat.models.Rooms.removeUsernameById data.rid, data.username - RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, data.username + RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, removedUser._id - switch room.t - when 'c' - RocketChat.authz.removeUsersFromRole(removedUser._id; 'channel-moderator', data.rid) - when 'p' - RocketChat.authz.removeUsersFromRole(removedUser._id; 'group-moderator', data.rid) + if room.t in [ 'c', 'p' ] + RocketChat.authz.removeUserFromRoles(removedUser._id, ['moderator', 'owner'], data.rid) - RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser + fromUser = RocketChat.models.Users.findOneById fromId + RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser, + u: + _id: fromUser._id + username: fromUser.username return true diff --git a/server/methods/resetAvatar.coffee b/server/methods/resetAvatar.coffee index 0bb66f0d14023e2cc76900285df917a8e6bb21a9..e6ff5278eca16c6dfe81a6c2652438bab38e6dd8 100644 --- a/server/methods/resetAvatar.coffee +++ b/server/methods/resetAvatar.coffee @@ -6,8 +6,6 @@ Meteor.methods unless RocketChat.settings.get("Accounts_AllowUserAvatarChange") throw new Meteor.Error(403, "[methods] resetAvatar -> Invalid access") - console.log '[methods] resetAvatar -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - user = Meteor.user() RocketChatFileAvatarInstance.deleteFile "#{user.username}.jpg" diff --git a/server/methods/saveRoomName.coffee b/server/methods/saveRoomName.coffee deleted file mode 100644 index 888d0c74b51766547dad7e04de19c72da7b5fa55..0000000000000000000000000000000000000000 --- a/server/methods/saveRoomName.coffee +++ /dev/null @@ -1,39 +0,0 @@ -Meteor.methods - saveRoomName: (rid, name) -> - if not Meteor.userId() - throw new Meteor.Error('invalid-user', "[methods] sendMessage -> Invalid user") - - room = RocketChat.models.Rooms.findOneById rid - - if room.t not in ['c', 'p'] - throw new Meteor.Error 403, 'Not allowed' - - unless RocketChat.authz.hasPermission(Meteor.userId(), 'edit-room', rid) - #if room.u._id isnt Meteor.userId() and not hasPermission - throw new Meteor.Error 403, 'Not allowed' - - try - nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$' - catch - nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$' - - if not nameValidation.test name - throw new Meteor.Error 'name-invalid' - - if RocketChat.settings.get 'UTF8_Names_Slugify' - name = _.slugify name - - if name is room.name - return - - # avoid duplicate names - if RocketChat.models.Rooms.findOneByName name - throw new Meteor.Error 'duplicate-name' - - RocketChat.models.Rooms.setNameById rid, name - - RocketChat.models.Subscriptions.updateNameByRoomId rid, name - - RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser rid, name, Meteor.user() - - return name diff --git a/server/methods/saveUserPreferences.coffee b/server/methods/saveUserPreferences.coffee index 5cf457a2315b861da789c1a0fff7a71b3e7f15db..39da131efdbf58e2f71470af26eee20108d2c45a 100644 --- a/server/methods/saveUserPreferences.coffee +++ b/server/methods/saveUserPreferences.coffee @@ -1,7 +1,5 @@ Meteor.methods saveUserPreferences: (settings) -> - console.log '[method] saveUserPreferences', settings - if Meteor.userId() preferences = {} diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index 0df26725a6bd97062776759430fa6a51aa7657b1..045d17ab62eba83481bcecfccf469a913da6d4ba 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -6,8 +6,6 @@ Meteor.methods unless RocketChat.settings.get("Accounts_AllowUserAvatarChange") throw new Meteor.Error(403, "[methods] resetAvatar -> Invalid access") - console.log '[methods] setAvatarFromService -> '.green, 'userId:', Meteor.userId(), 'contentType:', contentType, 'service:', service - user = Meteor.user() if service is 'initials' @@ -62,4 +60,4 @@ DDPRateLimiter.addRule type: 'method' name: 'setAvatarFromService' userId: -> return true -, 1, 60000 +, 1, 5000 diff --git a/server/methods/toogleFavorite.coffee b/server/methods/toogleFavorite.coffee index 853bfe00c771cfc28e06313dff18b38b83739537..58c4faa75359c182bea83cc8c04689df91904df5 100644 --- a/server/methods/toogleFavorite.coffee +++ b/server/methods/toogleFavorite.coffee @@ -3,6 +3,4 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] toogleFavorite -> Invalid user") - console.log '[methods] toogleFavorite -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - RocketChat.models.Subscriptions.setFavoriteByRoomIdAndUserId rid, Meteor.userId(), f diff --git a/server/methods/unarchiveRoom.coffee b/server/methods/unarchiveRoom.coffee index eed9cbfdc2d048c87babee2d981d30270d4b57b4..b78a843b8e598437042609c128a7d7f586494407 100644 --- a/server/methods/unarchiveRoom.coffee +++ b/server/methods/unarchiveRoom.coffee @@ -1,9 +1,7 @@ Meteor.methods - unArchiveRoom: (rid) -> + unarchiveRoom: (rid) -> if not Meteor.userId() - throw new Meteor.Error 'invalid-user', '[methods] unArchiveRoom -> Invalid user' - - console.log '[methods] unArchiveRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments + throw new Meteor.Error 'invalid-user', '[methods] unarchiveRoom -> Invalid user' room = RocketChat.models.Rooms.findOneById rid diff --git a/server/methods/unmuteUserInRoom.coffee b/server/methods/unmuteUserInRoom.coffee new file mode 100644 index 0000000000000000000000000000000000000000..cec5d061c342c87cbca3165e88e4be0d09df0758 --- /dev/null +++ b/server/methods/unmuteUserInRoom.coffee @@ -0,0 +1,29 @@ +Meteor.methods + unmuteUserInRoom: (data) -> + fromId = Meteor.userId() + check(data, Match.ObjectIncluding({ rid: String, username: String })) + + unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) + throw new Meteor.Error 'not-allowed', '[methods] unmuteUserInRoom -> Not allowed' + + room = RocketChat.models.Rooms.findOneById data.rid + if not room + throw new Meteor.Error 'invalid-room', '[methods] unmuteUserInRoom -> Room ID is invalid' + + if room.t not in ['c', 'p'] + throw new Meteor.Error 'invalid-room-type', '[methods] unmuteUserInRoom -> Invalid room type' + + if data.username not in (room?.usernames or []) + throw new Meteor.Error 'not-in-room', '[methods] unmuteUserInRoom -> User is not in this room' + + unmutedUser = RocketChat.models.Users.findOneByUsername data.username + + RocketChat.models.Rooms.unmuteUsernameByRoomId data.rid, unmutedUser.username + + fromUser = RocketChat.models.Users.findOneById fromId + RocketChat.models.Messages.createUserUnmutedWithRoomIdAndUser data.rid, unmutedUser, + u: + _id: fromUser._id + username: fromUser.username + + return true diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 09ce1aa2d6f58b05aac92e1e35985dddd3079e81..966c52399d5b877794094f8074bc2733dc047689 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -24,8 +24,6 @@ Meteor.methods if currentTsDiff > blockEditInMinutes throw new Meteor.Error 'message-editing-blocked' - console.log '[methods] updateMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - # If we keep history of edits, insert a new message to store history information if RocketChat.settings.get 'Message_KeepHistory' RocketChat.models.Messages.cloneAndSaveAsHistoryById originalMessage._id @@ -35,7 +33,7 @@ Meteor.methods _id: Meteor.userId() username: me.username - if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g + if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([^\s]+)?)?/g message.urls = urls.map (url) -> url: url message = RocketChat.callbacks.run 'beforeSaveMessage', message diff --git a/server/publications/activeUsers.coffee b/server/publications/activeUsers.coffee index ba420634b09432f4c04b9032fa4384234e17c7b0..65e3675b6a07b4ae6e9b6a6d35389ce3424724e8 100644 --- a/server/publications/activeUsers.coffee +++ b/server/publications/activeUsers.coffee @@ -2,8 +2,6 @@ Meteor.publish 'activeUsers', -> unless this.userId return this.ready() - console.log '[publish] activeUsers'.green - RocketChat.models.Users.findUsersNotOffline fields: username: 1 diff --git a/server/publications/adminRooms.coffee b/server/publications/adminRooms.coffee index bceec2d8c51ac8f2cbdfddc8d1df7f223211d6cb..638077d5ee54be91879d0d941ee5517a099cfd95 100644 --- a/server/publications/adminRooms.coffee +++ b/server/publications/adminRooms.coffee @@ -15,14 +15,13 @@ Meteor.publish 'adminRooms', (filter, types, limit) -> cl: 1 u: 1 usernames: 1 + muted: 1 limit: limit sort: name: 1 filter = _.trim filter - console.log '[publish] adminRooms'.green, filter, types, limit - if filter and types.length return RocketChat.models.Rooms.findByNameContainingAndTypes filter, types, options diff --git a/server/publications/channelAutocomplete.coffee b/server/publications/channelAutocomplete.coffee index eebbea4bc8f060b0313b12df539bb50cf4600f50..7586b0242ef676b1ed4fd7ff221ab482e2d7ed42 100644 --- a/server/publications/channelAutocomplete.coffee +++ b/server/publications/channelAutocomplete.coffee @@ -2,8 +2,6 @@ Meteor.publish 'channelAutocomplete', (name) -> unless this.userId return this.ready() - console.log '[publish] channelAutocomplete -> '.green, name - pub = this options = diff --git a/server/publications/filteredUsers.coffee b/server/publications/filteredUsers.coffee index fd93452f85c12b144437e437639dfd8585ec14b8..d1316d71ea3bb97f05c7d6aee0207d03d5ae95f2 100644 --- a/server/publications/filteredUsers.coffee +++ b/server/publications/filteredUsers.coffee @@ -2,8 +2,6 @@ Meteor.publish 'filteredUsers', (name) -> unless this.userId return this.ready() - console.log '[publish] filteredUsers'.green, name - exp = new RegExp(name, 'i') options = diff --git a/server/publications/fullUserData.coffee b/server/publications/fullUserData.coffee index 255a87542cf33bca2633ae11191100f541da4b2e..95173f5edb82d5b5b146bccfbe8f2630f4915f2e 100644 --- a/server/publications/fullUserData.coffee +++ b/server/publications/fullUserData.coffee @@ -31,8 +31,6 @@ Meteor.publish 'fullUserData', (filter, limit) -> limit: limit sort: { username: 1 } - console.log '[publish] fullUserData'.green, filter, limit - if filter if limit is 1 return RocketChat.models.Users.findByUsername filter, options diff --git a/server/publications/messages.coffee b/server/publications/messages.coffee index b2ee7f04918743ce521be74707912ae02e439c00..6e0feba1ccd2acd2f2a6cd1269876ad3bfc43974 100644 --- a/server/publications/messages.coffee +++ b/server/publications/messages.coffee @@ -4,8 +4,6 @@ Meteor.publish 'messages', (rid, start) -> publication = this - console.log '[publish] messages ->'.green, 'rid:', rid, 'start:', start - if typeof rid isnt 'string' return this.ready() diff --git a/server/publications/privateHistory.coffee b/server/publications/privateHistory.coffee index 9f8eb31f87142cf87100ee0f40721bbd04690cc7..115796f52c8fdeea347acec3447d2df5f083481f 100644 --- a/server/publications/privateHistory.coffee +++ b/server/publications/privateHistory.coffee @@ -2,8 +2,6 @@ Meteor.publish 'privateHistory', -> unless this.userId return this.ready() - console.log '[publish] privateHistory'.green - RocketChat.models.Rooms.findByContainigUsername RocketChat.models.Users.findOneById(this.userId).username, fields: t: 1 diff --git a/server/publications/room.coffee b/server/publications/room.coffee index 960f1c40de942e3305d9be872128fe3561d794da..711ba33bc7beb668441de639a521796f2246b3bd 100644 --- a/server/publications/room.coffee +++ b/server/publications/room.coffee @@ -2,8 +2,6 @@ Meteor.publish 'room', (typeName) -> unless this.userId return this.ready() - console.log '[publish] room ->'.green, 'arguments:', arguments - if typeof typeName isnt 'string' return this.ready() diff --git a/server/publications/roomFiles.coffee b/server/publications/roomFiles.coffee index 38fce2de1f8c694f2dd8355aa188a918efa78946..e905e740d22f3bf844eb6254f85b37152b97c2e0 100644 --- a/server/publications/roomFiles.coffee +++ b/server/publications/roomFiles.coffee @@ -1,34 +1,35 @@ -Meteor.publish 'roomFiles', (rid) -> - unless this.userId - return this.ready() - - console.log '[publish] roomFiles '.green, rid - - pub = this - - fileQuery = - rid: rid - complete: true - uploading: false - - fileOptions = - fields: - _id: 1 - rid: 1 - name: 1 - type: 1 - url: 1 - - cursorFileListHandle = fileCollection.find(fileQuery, fileOptions).observeChanges - added: (_id, record) -> - pub.added('room_files', _id, record) - - changed: (_id, record) -> - pub.changed('room_files', _id, record) - - removed: (_id, record) -> - pub.removed('room_files', _id, record) - - this.ready() - this.onStop -> - cursorFileListHandle.stop() +Meteor.publish 'roomFiles', (rid, limit = 50) -> + unless this.userId + return this.ready() + + pub = this + + fileQuery = + rid: rid + complete: true + uploading: false + + fileOptions = + limit: limit + sort: + uploadedAt: -1 + fields: + _id: 1 + rid: 1 + name: 1 + type: 1 + url: 1 + + cursorFileListHandle = fileCollection.find(fileQuery, fileOptions).observeChanges + added: (_id, record) -> + pub.added('room_files', _id, record) + + changed: (_id, record) -> + pub.changed('room_files', _id, record) + + removed: (_id, record) -> + pub.removed('room_files', _id, record) + + this.ready() + this.onStop -> + cursorFileListHandle.stop() diff --git a/server/publications/roomSearch.coffee b/server/publications/roomSearch.coffee index c499c1a89f7771e4d3f6a807e15cf389c35858de..f3357511223732ff78a673bbdddf9a0402e98fdf 100644 --- a/server/publications/roomSearch.coffee +++ b/server/publications/roomSearch.coffee @@ -2,8 +2,6 @@ Meteor.publish 'roomSearch', (selector, options, collName) -> unless this.userId return this.ready() - console.log '[publish] roomSearch -> '.green, 'selector:', selector, 'options:', options, 'collName:', collName - self = this searchType = null subHandleUsers = null diff --git a/server/publications/spotlight.coffee b/server/publications/spotlight.coffee index 9921d4987e40efab110209e0712d6644d562d07f..feec1ce6f654c85a39dad9b86e730485f2e7f2c3 100644 --- a/server/publications/spotlight.coffee +++ b/server/publications/spotlight.coffee @@ -2,8 +2,6 @@ Meteor.publish 'spotlight', (selector, options, collName) -> if not this.userId? or not selector?.name?.$regex? return this.ready() - console.log '[publish] spotlight -> '.green, 'selector:', selector, 'options:', options, 'collName:', collName - self = this subHandleUsers = null subHandleRooms = null diff --git a/server/publications/subscription.coffee b/server/publications/subscription.coffee index f188e99522e3e6e992eec9813ec4819f354692fe..2aca0e8f1579cfcabc1dd58be47b601abe3e2ca6 100644 --- a/server/publications/subscription.coffee +++ b/server/publications/subscription.coffee @@ -2,8 +2,6 @@ Meteor.publish 'subscription', -> unless this.userId return this.ready() - console.log '[publish] subscription'.green - RocketChat.models.Subscriptions.findByUserId this.userId, fields: t: 1 @@ -15,3 +13,4 @@ Meteor.publish 'subscription', -> open: 1 alert: 1 unread: 1 + archived: 1 diff --git a/server/publications/userAutocomplete.coffee b/server/publications/userAutocomplete.coffee new file mode 100644 index 0000000000000000000000000000000000000000..0f20eb20524cc1b47ce0124680924df57feb7617 --- /dev/null +++ b/server/publications/userAutocomplete.coffee @@ -0,0 +1,26 @@ +Meteor.publish 'userAutocomplete', (selector) -> + unless this.userId + return this.ready() + + pub = this + + options = + fields: + name: 1 + username: 1 + status: 1 + limit: 10 + + exceptions = selector.exceptions or [] + + cursorHandle = RocketChat.models.Users.findActiveByUsernameRegexWithExceptions(selector.username, exceptions, options).observeChanges + added: (_id, record) -> + pub.added("autocompleteRecords", _id, record) + changed: (_id, record) -> + pub.changed("autocompleteRecords", _id, record) + removed: (_id, record) -> + pub.removed("autocompleteRecords", _id, record) + @ready() + @onStop -> + cursorHandle.stop() + return diff --git a/server/publications/userChannels.coffee b/server/publications/userChannels.coffee index dbacf03b444d152705d891c88411b3ef492b430a..9192dcc635d74892f168466e2dd3dd134745d1d2 100644 --- a/server/publications/userChannels.coffee +++ b/server/publications/userChannels.coffee @@ -5,8 +5,6 @@ Meteor.publish 'userChannels', (userId) -> if RocketChat.authz.hasPermission( @userId, 'view-other-user-channels') isnt true return this.ready() - console.log '[publish] userChannels'.green, userId - RocketChat.models.Subscriptions.findByUserId userId, fields: rid: 1, diff --git a/server/publications/userData.coffee b/server/publications/userData.coffee index f6e5eac51670a043ef7387f33fef2aecc18ecfbb..6f49343368144d518f9daf1a140fe1edcda38161 100644 --- a/server/publications/userData.coffee +++ b/server/publications/userData.coffee @@ -2,8 +2,6 @@ Meteor.publish 'userData', -> unless this.userId return this.ready() - console.log '[publish] userData'.green - RocketChat.models.Users.find this.userId, fields: name: 1 diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 45e9f590c99acbb6189c0eb721a6851938a08fe1..4951142cb4f13894e81883095aff6f7cdda9e0e6 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -11,12 +11,14 @@ Meteor.startup -> console.log "Using #{storeType} for Avatar storage".green - transformWrite = undefined - if RocketChat.settings.get('Accounts_AvatarResize') is true + transformWrite = (file, readStream, writeStream) -> + if RocketChatFile.enabled is false or RocketChat.settings.get('Accounts_AvatarResize') isnt true + return readStream.pipe writeStream + height = RocketChat.settings.get 'Accounts_AvatarSize' width = height - transformWrite = (file, readStream, writeStream) -> - RocketChatFile.gm(readStream, file.fileName).background('#ffffff').resize(width, height+'^>').gravity('Center').extent(width, height).stream('jpeg').pipe(writeStream) + + RocketChatFile.gm(readStream, file.fileName).background('#ffffff').resize(width, height+'^>').gravity('Center').extent(width, height).stream('jpeg').pipe(writeStream) path = "~/uploads" diff --git a/server/startup/cron.coffee b/server/startup/cron.coffee index be643bcf42edb3edb7f25a3983a8853a2c58fedb..9bd2f8dd958b685a8766a117639742b3af73f768 100644 --- a/server/startup/cron.coffee +++ b/server/startup/cron.coffee @@ -2,22 +2,23 @@ SyncedCron.config collectionName: 'rocketchat_cron_history' +generateStatistics = -> + statistics = RocketChat.statistics.save() + statistics.host = Meteor.absoluteUrl() + unless RocketChat.settings.get 'Statistics_opt_out' + HTTP.post 'https://rocket.chat/stats', + data: statistics + return + Meteor.startup -> Meteor.defer -> + generateStatistics() # Generate and save statistics every hour SyncedCron.add name: 'Generate and save statistics', schedule: (parser) -># parser is a later.parse object return parser.text 'every 1 hour' - job: -> - statistics = RocketChat.statistics.save() - statistics.host = Meteor.absoluteUrl() - unless RocketChat.settings.get 'Statistics_opt_out' - console.log 'Sending statistics data to Rocket.Chat' - HTTP.post 'https://rocket.chat/stats', - data: statistics - - return + job: generateStatistics SyncedCron.start() diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index 47ba296a93f53a23843ae99c2b7a8f3aa9ee0b25..045b6d0673a8f0ed61df01526010d774b2f8470d 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -41,7 +41,7 @@ Meteor.startup -> name: 'Admin' Accounts.setPassword id, process.env.ADMIN_PASS - RocketChat.authz.addUsersToRoles( id, 'admin') + RocketChat.authz.addUserRoles( id, 'admin') else console.log 'E-mail exists; ignoring environment variables ADMIN_EMAIL and ADMIN_PASS'.red @@ -55,5 +55,5 @@ Meteor.startup -> # get oldest user oldestUser = RocketChat.models.Users.findOne({ _id: { $ne: 'rocket.cat' }}, { fields: { username: 1 }, sort: {createdAt: 1}}) if oldestUser - RocketChat.authz.addUsersToRoles( oldestUser._id, 'admin') + RocketChat.authz.addUserRoles( oldestUser._id, 'admin') console.log "No admins are found. Set #{oldestUser.username} as admin for being the oldest user" diff --git a/server/startup/migrations/v26.coffee b/server/startup/migrations/v26.coffee new file mode 100644 index 0000000000000000000000000000000000000000..2e45ece8dcf84e57aa92b139eac2172f43fc5862 --- /dev/null +++ b/server/startup/migrations/v26.coffee @@ -0,0 +1,5 @@ +Meteor.startup -> + Migrations.add + version: 26 + up: -> + RocketChat.models.Messages.update({ t: 'rm' }, { $set: { mentions: [] } }, { multi: true }) diff --git a/server/startup/migrations/v27.coffee b/server/startup/migrations/v27.coffee new file mode 100644 index 0000000000000000000000000000000000000000..b3f6f7d7716b880f49b67110bb1557bd8ddf8021 --- /dev/null +++ b/server/startup/migrations/v27.coffee @@ -0,0 +1,11 @@ +Meteor.startup -> + Migrations.add + version: 27 + up: -> + RocketChat.models.Users.update({}, { $rename: { roles: '_roles' } }, { multi: true }) + + RocketChat.models.Users.find({ _roles: { $exists: 1 } }).forEach (user) -> + for scope, roles of user._roles + RocketChat.models.Roles.addUserRoles(user._id, roles, scope) + + RocketChat.models.Users.update({}, { $unset: { _roles: 1 } }, { multi: true }) diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index 409131cc9b475f652eb67ce24a4306dd2a9d525f..85abbe2d8ccb891f66c209f5cc00ccbe94c80b74 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -7,6 +7,10 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + topic: 1 + muted: 1 + archived: 1 + return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options RocketChat.roomTypes.setPublish 'p', (identifier) -> @@ -17,6 +21,10 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + topic: 1 + muted: 1 + archived: 1 + user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options @@ -28,5 +36,6 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + topic: 1 user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeContainigUsernames 'd', [user.username, identifier], options