From 64979308ac3239e95d7323eb68bcd2ab4d38fed5 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Tue, 1 Sep 2015 00:05:26 -0400 Subject: [PATCH 0001/1338] initial sandstorm port --- .meteor/packages | 8 +- .meteor/platforms | 2 - .meteor/versions | 4 +- .../default/virtualbox/action_provision | 1 + .../default/virtualbox/action_set_name | 1 + .../machines/default/virtualbox/creator_uid | 1 + .../.vagrant/machines/default/virtualbox/id | 1 + .../machines/default/virtualbox/index_uuid | 1 + .../machines/default/virtualbox/private_key | 27 ++++++ .../default/virtualbox/synced_folders | 1 + .sandstorm/Vagrantfile | 83 +++++++++++++++++++ .sandstorm/build.sh | 15 ++++ .sandstorm/global-setup.sh | 30 +++++++ .sandstorm/launcher.sh | 16 ++++ .sandstorm/sandstorm-pkgdef.capnp | 66 +++++++++++++++ .sandstorm/setup.sh | 47 +++++++++++ .sandstorm/stack | 1 + client/lib/avatar.coffee | 3 +- client/views/account/avatar/prompt.html | 3 +- client/views/app/sideNav/userStatus.html | 3 + client/views/main.html | 12 ++- client/views/username/sandstormshare.html | 7 ++ packages/rocketchat-hubot/hubot.coffee | 4 +- .../settings/server/updateServices.coffee | 1 + .../client/oembedImageWidget.coffee | 3 +- server/configuration/accounts_meld.coffee | 3 +- server/lib/accounts.coffee | 12 +-- server/startup/avatar.coffee | 12 ++- server/startup/initialData.coffee | 1 + 29 files changed, 346 insertions(+), 23 deletions(-) create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/action_provision create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/action_set_name create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/creator_uid create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/id create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/index_uuid create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/private_key create mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/synced_folders create mode 100644 .sandstorm/Vagrantfile create mode 100755 .sandstorm/build.sh create mode 100755 .sandstorm/global-setup.sh create mode 100755 .sandstorm/launcher.sh create mode 100644 .sandstorm/sandstorm-pkgdef.capnp create mode 100755 .sandstorm/setup.sh create mode 100644 .sandstorm/stack create mode 100644 client/views/username/sandstormshare.html diff --git a/.meteor/packages b/.meteor/packages index a23bfb4c45a..f6ee307e1ed 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -34,10 +34,10 @@ rocketchat:markdown rocketchat:me #rocketchat:slashcommands-invite rocketchat:mentions -rocketchat:oembed -rocketchat:webrtc -#rocketchat:external #rocketchat:hubot +#rocketchat:oembed +rocketchat:webrtc-ib +#rocketchat:external #rocketchat:irc konecty:change-case @@ -82,3 +82,5 @@ monbro:mongodb-mapreduce-aggregation rocketchat:custom-oauth rocketchat:gitlab rocketchat:statistics +kenton:accounts-sandstorm + diff --git a/.meteor/platforms b/.meteor/platforms index 2d49a856332..8a3a35f9f62 100644 --- a/.meteor/platforms +++ b/.meteor/platforms @@ -1,4 +1,2 @@ -android browser -ios server diff --git a/.meteor/versions b/.meteor/versions index 6d51817b864..f0c9af8cfc7 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -46,6 +46,7 @@ jquery@1.11.3_2 json@1.0.3 kadira:blaze-layout@2.0.1 kadira:flow-router@2.4.0 +kenton:accounts-sandstorm@0.1.4 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.2 konecty:change-case@2.3.0 @@ -114,9 +115,8 @@ rocketchat:logger@0.0.1 rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 -rocketchat:oembed@0.0.1 rocketchat:statistics@0.0.1 -rocketchat:webrtc@0.0.1 +rocketchat:webrtc-ib@0.0.1 routepolicy@1.0.5 service-configuration@1.0.4 session@1.1.0 diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/action_provision b/.sandstorm/.vagrant/machines/default/virtualbox/action_provision new file mode 100644 index 00000000000..4f8991f5fe2 --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/action_provision @@ -0,0 +1 @@ +1.5:c17761bf-b2f4-49da-87b9-79a95da91252 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name b/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name new file mode 100644 index 00000000000..9a8930725a3 --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name @@ -0,0 +1 @@ +1440583526 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid b/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid new file mode 100644 index 00000000000..e37d32abba4 --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid @@ -0,0 +1 @@ +1000 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/id b/.sandstorm/.vagrant/machines/default/virtualbox/id new file mode 100644 index 00000000000..eb9637c6cf2 --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/id @@ -0,0 +1 @@ +c17761bf-b2f4-49da-87b9-79a95da91252 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid b/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid new file mode 100644 index 00000000000..fb8410bdfa9 --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid @@ -0,0 +1 @@ +0d8eab53d7a1444288ff01aef6a03573 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/private_key b/.sandstorm/.vagrant/machines/default/virtualbox/private_key new file mode 100644 index 00000000000..d30d91db6e7 --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAk1hkJc1e5h4yDnnOCJ29YUf0x1DhgSkGY0hcfWAubSEGS1HX +bxLIE+Al44jENNPrrdddtCKY+onxeefQo7FUFxVMEOM5JqFzpyq1Sliw9w7QmJef +DImS0z54ezqQ952W7BQc/XOndVpzvRPVREcRccOdGk5P60zoWZP/Oy4tviHcH7RM +faeBrs7ykD6RJKAjKwuMF3p/+FlPCPwql8cTifYZspFwFTja/XStk3PX4eLle5si +ZFN7SjsDa+FflUenmgkpW04E6TUaQHVhapHJCCbYRqwCrUX/5Yf2PakFPqfnRBaE +KKkGLRnVc7UrCDk21m/IZRmTHgSLAyDEGkFOIwIDAQABAoIBAHCJBAQzNJXA3i5c +LVY7U5bnJDbOuUyyjqRpcep3+T10CaChI088Iv+7JHUB0gkfClO9t12LRxejH4Eh +4iIDn9v5ch07zjyI9xHn9oqP7qji8cJ5mwoyUKdygQZtFqdn/wrT2chh+rYQnXD9 +otcBCHvBEU40HanzFUrFVBxZCqq5fP69ujsOVghykyzI5mWIRNGFXyvN8HxjXMr6 +mSiCvzEMscTZzdoCvy18lvDTWg5GyPLq9EM+4xQoEqlQv2RQEUmC2wC4JK09bJ8T +d19RGax1Nvbvw0ywWTgG/blGS0h7Q4aJziIL1Bv1IoIonn69wjL/qaWh+vqhL6QV +m87qh7ECgYEAwzy0kwO5Xo1mWZN4lJ8WrU7xh5TtsSJkfMlEQNsmhHAFN9B7p7MX +CrIAMd+U9z8ptxgFZwfoff4Qcb9QkHo8wZLj9vYWTAoJ0VyvVwUTwi4D5lHvFDe/ +IX2N4pJv5AB3+xValyg+z6ShGKmWJuLhCYtcYFxdr8tZ45RlHYzv0V0CgYEAwTP1 +F3dURItjPVQ7BSHXmPoSTSuhAjbQp+jWOIEa+wnM3K3OncfbICFqSwFsz1cjKDjz +fAMXw9is7s/T8CEm6u4DFKbZ2qlAcvq02oqZu1/6UZXxTXFdjfQaKpSQ4ZWMxVBE +nKIs/e/416zCH6zd1Xauus92xI+zse5iSn++JX8CgYBGu/ewS+kdGJ28VnGZZwoQ +QEnBlXOIea1uiHzyAnQyB2PclOw4FeqDNXpcl2ShL4EtlMZgTb0t6J6Ml4PY1HCu +sUlmcEIjyn9EGxBrtqsx7vn6uDSmXowg1hxRujxPntvZXCM2IJ6hHERBay+7Zveh +PZx6TPykdEhc66a2zhkVAQKBgAOwHTaUdYxVaNCL4hCIA9iMtXq5oXosV7FM1YIA +nOY72qg/vRjv7rPfT2sdHNmcXTRwWd19JZ/8a9inKPGFgHutjWuAf9oXrv5C4N7n +FGYqP9n81b1Xs6R5C2LSsS1NMIG3tYeT5O33/bUIPDBkmVtwx4cTXL4FzDVSSpgH +dja7AoGAMAXuTIrq1+L6sMQYgwx/9loN4KkdYAP7ZDlX+2uROzk2u/aCw9dGIJMs +R5JSS5+5oG2MRNTAnz/35qge5M9ucRdiNKdxO4jLK9e009m+wl4AxVFFRz0Bz8Nf +QYlzA2d5S3I1EJSUNjjDkEq9szaVeRmVKt40n3X/JKjTggX6Ibg= +-----END RSA PRIVATE KEY----- diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders b/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders new file mode 100644 index 00000000000..a01b299f5db --- /dev/null +++ b/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders @@ -0,0 +1 @@ +{"virtualbox":{"/opt/app":{"guestpath":"/opt/app","hostpath":"/home/sam/projects/Rocket.Chat/Rocket.Chat","disabled":false},"/host-dot-sandstorm":{"guestpath":"/host-dot-sandstorm","hostpath":"/home/sam/.sandstorm","disabled":false},"/vagrant":{"guestpath":"/vagrant","hostpath":"/home/sam/projects/Rocket.Chat/Rocket.Chat","disabled":false}}} \ No newline at end of file diff --git a/.sandstorm/Vagrantfile b/.sandstorm/Vagrantfile new file mode 100644 index 00000000000..c8421bb9861 --- /dev/null +++ b/.sandstorm/Vagrantfile @@ -0,0 +1,83 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # We base ourselves off Debian Jessie + config.vm.box = "debian/jessie64" + + if Vagrant.has_plugin?("vagrant-vbguest") then + # vagrant-vbguest is a Vagrant plugin that upgrades + # the version of VirtualBox Guest Additions within each + # guest. If you have the vagrant-vbguest plugin, then it + # needs to know how to compile kernel modules, etc., and so + # we give it this hint about operating system type. + config.vm.guest = "debian" + end + + # We forward port 6080, the Sandstorm web port, so that developers can + # visit their sandstorm app from their browser as local.sandstorm.io:6080 + # (aka 127.0.0.1:6080). + config.vm.network :forwarded_port, guest: 6080, host: 6080 + + # Use a shell script to "provision" the box. This installs Sandstorm using + # the bundled installer. + config.vm.provision "shell", inline: "sudo bash /opt/app/.sandstorm/global-setup.sh" + # Then, do stack-specific and app-specific setup. + config.vm.provision "shell", inline: "sudo bash /opt/app/.sandstorm/setup.sh" + + # Shared folders are configured per-provider since vboxsf can't handle >4096 open files, + # NFS requires privilege escalation every time you bring a VM up, + # and 9p is only available on libvirt. + + # Calculate the number of CPUs and the amount of RAM the system has, + # in a platform-dependent way; further logic below. + cpus = nil + total_kB_ram = nil + + host = RbConfig::CONFIG['host_os'] + if host =~ /darwin/ + cpus = `sysctl -n hw.ncpu`.to_i + total_kB_ram = `sysctl -n hw.memsize`.to_i / 1024 + elsif host =~ /linux/ + cpus = `nproc`.to_i + total_kB_ram = `grep MemTotal /proc/meminfo | awk '{print $2}'`.to_i + end + # Use the same number of CPUs within Vagrant as the system, with 1 + # as a default. + # + # Use at least 512MB of RAM, and if the system has more than 2GB of + # RAM, use 1/4 of the system RAM. This seems a reasonable compromise + # between having the Vagrant guest operating system not run out of + # RAM entirely (which it basically would if we went much lower than + # 512MB) and also allowing it to use up a healthily large amount of + # RAM so it can run faster on systems that can afford it. + if cpus.nil? + cpus = 1 + end + if total_kB_ram.nil? or total_kB_ram < 2048000 + assign_ram_mb = 512 + else + assign_ram_mb = (total_kB_ram / 1024 / 4) + end + # Actually apply these CPU/memory values to the providers. + config.vm.provider :virtualbox do |vb, override| + vb.cpus = cpus + vb.memory = assign_ram_mb + + override.vm.synced_folder "..", "/opt/app" + override.vm.synced_folder ENV["HOME"] + "/.sandstorm", "/host-dot-sandstorm" + override.vm.synced_folder "..", "/vagrant" + end + config.vm.provider :libvirt do |libvirt, override| + libvirt.cpus = cpus + libvirt.memory = assign_ram_mb + libvirt.random_hostname = true + + override.vm.synced_folder "..", "/opt/app", type: "9p", accessmode: "passthrough" + override.vm.synced_folder ENV["HOME"] + "/.sandstorm", "/host-dot-sandstorm", type: "9p", accessmode: "passthrough" + override.vm.synced_folder "..", "/vagrant", type: "9p", accessmode: "passthrough" + end +end diff --git a/.sandstorm/build.sh b/.sandstorm/build.sh new file mode 100755 index 00000000000..50a730f64f8 --- /dev/null +++ b/.sandstorm/build.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -euo pipefail + +# Make meteor bundle + +METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" +METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle + +cd /opt/app +meteor build --directory /home/vagrant/ +(cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install) + +# Copy our launcher script into the bundle so the grain can start up. +mkdir -p /home/vagrant/bundle/opt/app/.sandstorm/ +cp /opt/app/.sandstorm/launcher.sh /home/vagrant/bundle/opt/app/.sandstorm/ diff --git a/.sandstorm/global-setup.sh b/.sandstorm/global-setup.sh new file mode 100755 index 00000000000..303c9d22c1d --- /dev/null +++ b/.sandstorm/global-setup.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -euo pipefail +echo localhost > /etc/hostname +hostname localhost +curl https://install.sandstorm.io/ > /host-dot-sandstorm/caches/install.sh +SANDSTORM_CURRENT_VERSION=$(curl -fs "https://install.sandstorm.io/dev?from=0&type=install") +SANDSTORM_PACKAGE="sandstorm-$SANDSTORM_CURRENT_VERSION.tar.xz" +if [[ ! -f /host-dot-sandstorm/caches/$SANDSTORM_PACKAGE ]] ; then + curl --output "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE" "https://dl.sandstorm.io/$SANDSTORM_PACKAGE" +fi +bash /host-dot-sandstorm/caches/install.sh -d -e "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE" +modprobe ip_tables +# Make the vagrant user part of the sandstorm group so that commands like +# `spk dev` work. +usermod -a -G 'sandstorm' 'vagrant' +# Bind to all addresses, so the vagrant port-forward works. +sudo sed --in-place='' \ + --expression='s/^BIND_IP=.*/BIND_IP=0.0.0.0/' \ + /opt/sandstorm/sandstorm.conf +# TODO: update sandstorm installer script to ask about dev accounts, and +# specify a value for this option in the default config? +if ! grep --quiet --no-messages ALLOW_DEV_ACCOUNTS=true /opt/sandstorm/sandstorm.conf ; then + echo "ALLOW_DEV_ACCOUNTS=true" | sudo tee -a /opt/sandstorm/sandstorm.conf + sudo service sandstorm restart +fi +# Enable apt-cacher-ng proxy to make things faster if one appears to be running on the gateway IP +GATEWAY_IP=$(ip route | grep ^default | cut -d ' ' -f 3) +if nc -z "$GATEWAY_IP" 3142 ; then + echo "Acquire::http::Proxy \"http://$GATEWAY_IP:3142\";" > /etc/apt/apt.conf.d/80httpproxy +fi diff --git a/.sandstorm/launcher.sh b/.sandstorm/launcher.sh new file mode 100755 index 00000000000..4a7ab020aaa --- /dev/null +++ b/.sandstorm/launcher.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -euo pipefail + +echo '** Starting mongo...' +/bin/niscud \ + --fork --port 4002 --dbpath /var --noauth --bind_ip 127.0.0.1 \ + --nohttpinterface --noprealloc --logpath /var/mongo.log & + +# TODO: wait for niscu to be up +echo '** Starting Meteor...' + +export MONGO_URL="mongodb://127.0.0.1:4002/meteor"; +export ROOT_URL="http://127.0.0.1:8000"; +export PORT="8000"; + +node /main.js diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp new file mode 100644 index 00000000000..0921cfcd7d5 --- /dev/null +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -0,0 +1,66 @@ +@0xdb0b8a1059adf258; + +using Spk = import "/sandstorm/package.capnp"; +# This imports: +# $SANDSTORM_HOME/latest/usr/include/sandstorm/package.capnp +# Check out that file to see the full, documented package definition format. + +const pkgdef :Spk.PackageDefinition = ( + # The package definition. Note that the spk tool looks specifically for the + # "pkgdef" constant. + + id = "1yqjjc9yru8e577pm95peu7t32ccf1xf0mepkvxj9ezch9amj82h", + # Your app ID is actually its public key. The private key was placed in + # your keyring. All updates must be signed with the same key. + + manifest = ( + # This manifest is included in your app package to tell Sandstorm + # about your app. + + appTitle = (defaultText = "Rocket.Chat"), + + appVersion = 0, # Increment this for every release. + + appMarketingVersion = (defaultText = "0.6"), + # Human-readable representation of appVersion. Should match the way you + # identify versions of your app in documentation and marketing. + + actions = [ + # Define your "new document" handlers here. + ( title = (defaultText = "New Rocket.Chat"), + command = .myCommand + # The command to run when starting for the first time. (".myCommand" + # is just a constant defined at the bottom of the file.) + ) + ], + + continueCommand = .myCommand + # This is the command called to start your app back up after it has been + # shut down for inactivity. Here we're using the same command as for + # starting a new instance, but you could use different commands for each + # case. + ), + + sourceMap = ( + # The following directories will be copied into your package. + searchPath = [ + ( sourcePath = "/home/vagrant/bundle" ), + ( sourcePath = "/opt/meteor-spk/meteor-spk.deps" ) + ] + ), + + alwaysInclude = [ "." ] + # This says that we always want to include all files from the source map. + # (An alternative is to automatically detect dependencies by watching what + # the app opens while running in dev mode. To see what that looks like, + # run `spk init` without the -A option.) +); + +const myCommand :Spk.Manifest.Command = ( + # Here we define the command used to start up your server. + argv = ["/sandstorm-http-bridge", "8000", "--", "/opt/app/.sandstorm/launcher.sh"], + environ = [ + # Note that this defines the *entire* environment seen by your app. + (key = "PATH", value = "/usr/local/bin:/usr/bin:/bin") + ] +); diff --git a/.sandstorm/setup.sh b/.sandstorm/setup.sh new file mode 100755 index 00000000000..7f2b3609ddb --- /dev/null +++ b/.sandstorm/setup.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -euo pipefail + +cd /opt/ + +PACKAGE=meteor-spk-0.1.4 +PACKAGE_FILENAME="$PACKAGE.tar.xz" +CACHE_TARGET="/host-dot-sandstorm/caches/${PACKAGE_FILENAME}" + +# Fetch meteor-spk tarball if not cached +if [ ! -f "$CACHE_TARGET" ] ; then + curl https://dl.sandstorm.io/${PACKAGE_FILENAME} > "$CACHE_TARGET" +fi + +# Extract to /opt +tar xf "$CACHE_TARGET" + +# Create symlink so we can rely on the path /opt/meteor-spk +ln -s "${PACKAGE}" meteor-spk + +# Add bash, and its dependencies, so they get mapped into the image. +# Bash runs the launcher script. +cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ +cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ + +# Unfortunately, Meteor does not explicitly make it easy to cache packages, but +# we know experimentally that the package is mostly directly extractable to a +# user's $HOME/.meteor directory. +METEOR_RELEASE=1.1.0.2 +METEOR_PLATFORM=os.linux.x86_64 +METEOR_TARBALL_FILENAME="meteor-bootstrap-${METEOR_PLATFORM}.tar.gz" +METEOR_TARBALL_URL="https://d3sqy0vbqsdhku.cloudfront.net/packages-bootstrap/${METEOR_RELEASE}/${METEOR_TARBALL_FILENAME}" +METEOR_CACHE_TARGET="/host-dot-sandstorm/caches/${METEOR_TARBALL_FILENAME}" + +# Fetch meteor tarball if not cached +if [ ! -f "$METEOR_CACHE_TARGET" ] ; then + curl "$METEOR_TARBALL_URL" > "${METEOR_CACHE_TARGET}.partial" + mv "${METEOR_CACHE_TARGET}"{.partial,} +fi + +# Extract as unprivileged user, which is the usual meteor setup +cd /home/vagrant/ +su -c "tar xf '${METEOR_CACHE_TARGET}'" vagrant +# Link into global PATH +ln -s /home/vagrant/.meteor/meteor /usr/bin/meteor + diff --git a/.sandstorm/stack b/.sandstorm/stack new file mode 100644 index 00000000000..f148e1141a4 --- /dev/null +++ b/.sandstorm/stack @@ -0,0 +1 @@ +meteor diff --git a/client/lib/avatar.coffee b/client/lib/avatar.coffee index 8864fa52beb..e16a8559e19 100644 --- a/client/lib/avatar.coffee +++ b/client/lib/avatar.coffee @@ -4,7 +4,8 @@ if not username? return - return "#{Meteor.absoluteUrl()}avatar/#{username}.jpg?_dc=#{random}" + # return "#{Meteor.absoluteUrl()}avatar/#{username}.jpg?_dc=#{random}" + return "/avatar/#{username}.jpg?_dc=#{random}" Blaze.registerHelper 'avatarUrlFromUsername', getAvatarUrlFromUsername diff --git a/client/views/account/avatar/prompt.html b/client/views/account/avatar/prompt.html index e41996ffb02..f219f53c28b 100644 --- a/client/views/account/avatar/prompt.html +++ b/client/views/account/avatar/prompt.html @@ -58,7 +58,7 @@ {{/unless}} </div> </div> - + <!-- disable for sandstorm {{#if suggestions.ready}} {{> avatarSuggestion suggestions.avatars.gravatar}} {{> avatarSuggestion suggestions.avatars.facebook}} @@ -83,6 +83,7 @@ {{else}} {{_ "Loading_suggestion"}} {{/if}} + --> </div> </div> diff --git a/client/views/app/sideNav/userStatus.html b/client/views/app/sideNav/userStatus.html index 97e782c1e44..b0ea4b3488c 100644 --- a/client/views/app/sideNav/userStatus.html +++ b/client/views/app/sideNav/userStatus.html @@ -18,10 +18,13 @@ <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> + <!-- disable admin and logout for sandstorm {{#if isAdmin}} <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> {{/if}} + <a href="" id="logout"><i class="icon-logout"></i><span>{{_ "Logout"}}</span></a> + --> </div> </nav> {{/with}} diff --git a/client/views/main.html b/client/views/main.html index 02ebe6cce1c..4dd6fd5622a 100644 --- a/client/views/main.html +++ b/client/views/main.html @@ -44,11 +44,18 @@ <template name="main"> {{#if subsReady}} +<!-- {{#unless logged}} {{> loginLayout}} {{else}} +--> {{#unless hasUsername}} - {{> username}} + {{#if logged}} + {{> username}} + {{else}} + <!-- shared link cannot be disabled in sandstorm, so we show a blank page --> + {{> sandstormshare}} + {{/if}} {{else}} {{> spotlight}} {{> mobileMessageMenu}} @@ -63,7 +70,10 @@ {{> sideNav }} </div> {{> audioNotification }} + {{/unless}} +<!-- {{/unless}} +--> {{/if}} </template> diff --git a/client/views/username/sandstormshare.html b/client/views/username/sandstormshare.html new file mode 100644 index 00000000000..090a89d8a45 --- /dev/null +++ b/client/views/username/sandstormshare.html @@ -0,0 +1,7 @@ +<template name="sandstormshare"> + <section class="full-page"> + <div class="wrapper"> + + </div> + </section> +</template> diff --git a/packages/rocketchat-hubot/hubot.coffee b/packages/rocketchat-hubot/hubot.coffee index fa2ee105b7d..35d2cbb94d9 100644 --- a/packages/rocketchat-hubot/hubot.coffee +++ b/packages/rocketchat-hubot/hubot.coffee @@ -55,8 +55,8 @@ class RocketChatAdapter extends Hubot.Adapter console.log 'ROCKETCHATADAPTER -> send'.blue # console.log envelope, strings sendHelper @robot, envelope, strings, (string) => - console.log "send #{envelope.room}: #{string} (#{envelope.user.id})" if DEBUG - RocketChat.sendMessage RocketBot.user, { msg: string }, { _id: envelope.room } + # console.log "send #{envelope.room}: #{string} (#{envelope.user.id})" if DEBUG + RocketChat.sendMessage RocketBot.user, { msg: string }, { _id: envelope.room } # Public: Raw method for sending emote data back to the chat source. # diff --git a/packages/rocketchat-lib/settings/server/updateServices.coffee b/packages/rocketchat-lib/settings/server/updateServices.coffee index 42c0098b7aa..6d8af700197 100644 --- a/packages/rocketchat-lib/settings/server/updateServices.coffee +++ b/packages/rocketchat-lib/settings/server/updateServices.coffee @@ -10,6 +10,7 @@ updateServices = -> serviceName = service._id.replace('Accounts_OAuth_', '') + if serviceName is 'Meteor' serviceName = 'meteor-developer' diff --git a/packages/rocketchat-oembed/client/oembedImageWidget.coffee b/packages/rocketchat-oembed/client/oembedImageWidget.coffee index 4a4089af0fb..f801b22c6fe 100644 --- a/packages/rocketchat-oembed/client/oembedImageWidget.coffee +++ b/packages/rocketchat-oembed/client/oembedImageWidget.coffee @@ -1,3 +1,4 @@ Template.oembedImageWidget.helpers showImage: -> - return @downloadImages is true or not Meteor.Device.isPhone() \ No newline at end of file + return true + # @downloadImages is true or not Meteor.Device.isPhone() \ No newline at end of file diff --git a/server/configuration/accounts_meld.coffee b/server/configuration/accounts_meld.coffee index 11c5206caf4..e6e4a89fe00 100644 --- a/server/configuration/accounts_meld.coffee +++ b/server/configuration/accounts_meld.coffee @@ -1,6 +1,7 @@ orig_updateOrCreateUserFromExternalService = Accounts.updateOrCreateUserFromExternalService Accounts.updateOrCreateUserFromExternalService = (serviceName, serviceData, options) -> - if serviceName not in ['facebook', 'github', 'google', 'meteor-developer', 'linkedin', 'twitter'] and serviceData._oAuthCustom isnt true + + if serviceName not in ['facebook', 'github', 'gitlab', 'google', 'meteor-developer', 'linkedin', 'twitter', 'sandstorm'] and serviceData._oAuthCustom isnt true return if serviceName is 'meteor-developer' diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 5c565cb516c..e5fe2398cec 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -15,16 +15,18 @@ Accounts.emailTemplates.resetPassword.text = (user, url) -> verifyEmailText user, url Accounts.onCreateUser (options, user) -> - # console.log 'onCreateUser ->',JSON.stringify arguments, null, ' ' - # console.log 'options ->',JSON.stringify options, null, ' ' - # console.log 'user ->',JSON.stringify user, null, ' ' + console.log 'onCreateUser ->',JSON.stringify arguments, null, ' ' + console.log 'options ->',JSON.stringify options, null, ' ' + console.log 'user ->',JSON.stringify user, null, ' ' user.status = 'offline' user.active = not RocketChat.settings.get 'Accounts_ManuallyApproveNewUsers' + # disable admin for sandstorm # when inserting first user, set admin: true - unless Meteor.users.findOne() - user.admin = true + # unless Meteor.users.findOne() + # user.admin = true + if not user?.name? or user.name is '' if options.profile?.name? diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 770f371e92c..2a03c5be8a1 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -1,8 +1,11 @@ Meteor.startup -> - storeType = 'GridFS' + storeType = 'FileSystem' + + + # Sandstorm must store avatar in mongo + #if RocketChat.settings.get 'avatarStore_type' + # storeType = RocketChat.settings.get 'avatarStore_type' - if RocketChat.settings.get 'Accounts_AvatarStoreType' - storeType = RocketChat.settings.get 'Accounts_AvatarStoreType' RocketChatStore = RocketChatFile[storeType] @@ -18,7 +21,7 @@ Meteor.startup -> transformWrite = (file, readStream, writeStream) -> RocketChatFile.gm(readStream, file.fileName).background('#ffffff').resize(width, height+'^>').gravity('Center').extent(width, height).stream('jpeg').pipe(writeStream) - path = "~/uploads" + path = "/var" if RocketChat.settings.get('Accounts_AvatarStorePath')?.trim() isnt '' path = RocketChat.settings.get 'Accounts_AvatarStorePath' @@ -29,6 +32,7 @@ Meteor.startup -> transformWrite: transformWrite WebApp.connectHandlers.use '/avatar/', (req, res, next) -> + console.log 'avatar called!' this.params = username: req.url.replace(/^\//, '').replace(/\?.*$/, '') diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index 9af24b91b5b..d82f4eb7763 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -16,6 +16,7 @@ Meteor.startup -> name: 'general' msgs: 0 + if process.env.ADMIN_EMAIL? and process.env.ADMIN_PASS? re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i if re.test process.env.ADMIN_EMAIL -- GitLab From 1c58bf927b6e457b2c59ec2409f709e565e138f2 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Sep 2015 08:30:45 -0300 Subject: [PATCH 0002/1338] Init theme implementation --- .meteor/packages | 1 + .meteor/versions | 1 + client/views/main.html | 1 + .../.npm/package/.gitignore | 1 + .../.npm/package/README | 7 + .../.npm/package/npm-shrinkwrap.json | 242 ++++ .../assets/colors.less | 1198 +++++++++++++++++ .../assets/lesshat.import.less | 887 ++++++++++++ packages/rocketchat-theme-colors/package.js | 30 + .../rocketchat-theme-colors/server.coffee | 59 + 10 files changed, 2427 insertions(+) create mode 100644 packages/rocketchat-theme-colors/.npm/package/.gitignore create mode 100644 packages/rocketchat-theme-colors/.npm/package/README create mode 100644 packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json create mode 100644 packages/rocketchat-theme-colors/assets/colors.less create mode 100644 packages/rocketchat-theme-colors/assets/lesshat.import.less create mode 100644 packages/rocketchat-theme-colors/package.js create mode 100644 packages/rocketchat-theme-colors/server.coffee diff --git a/.meteor/packages b/.meteor/packages index 27e2304668a..d422fc0b3de 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -84,3 +84,4 @@ todda00:friendly-slugs underscorestring:underscore.string yasaricli:slugify yasinuslu:blaze-meta +rocketchat:theme-colors diff --git a/.meteor/versions b/.meteor/versions index 8c8bb9ce55b..000d093775b 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -118,6 +118,7 @@ rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-leave@0.0.1 rocketchat:statistics@0.0.1 +rocketchat:theme-colors@0.0.1 rocketchat:webrtc@0.0.1 routepolicy@1.0.5 service-configuration@1.0.4 diff --git a/client/views/main.html b/client/views/main.html index 590bf378267..b1a54c00c8a 100644 --- a/client/views/main.html +++ b/client/views/main.html @@ -34,6 +34,7 @@ <link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-touch-icon-144x144.png?v=3"> <link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-touch-icon-152x152.png?v=3"> <link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png?v=3"> + <link rel="stylesheet" type="text/css" href="/theme-colors.css"> </head> <body> diff --git a/packages/rocketchat-theme-colors/.npm/package/.gitignore b/packages/rocketchat-theme-colors/.npm/package/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/packages/rocketchat-theme-colors/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/rocketchat-theme-colors/.npm/package/README b/packages/rocketchat-theme-colors/.npm/package/README new file mode 100644 index 00000000000..3d492553a43 --- /dev/null +++ b/packages/rocketchat-theme-colors/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json new file mode 100644 index 00000000000..6493bf3d83a --- /dev/null +++ b/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,242 @@ +{ + "dependencies": { + "less": { + "version": "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6", + "dependencies": { + "errno": { + "version": "0.1.4", + "dependencies": { + "prr": { + "version": "0.0.0" + } + } + }, + "graceful-fs": { + "version": "3.0.8" + }, + "image-size": { + "version": "0.3.5" + }, + "mime": { + "version": "1.3.4" + }, + "mkdirp": { + "version": "0.5.1", + "dependencies": { + "minimist": { + "version": "0.0.8" + } + } + }, + "promise": { + "version": "6.1.0", + "dependencies": { + "asap": { + "version": "1.0.0" + } + } + }, + "request": { + "version": "2.61.0", + "dependencies": { + "bl": { + "version": "1.0.0", + "dependencies": { + "readable-stream": { + "version": "2.0.2", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "inherits": { + "version": "2.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "process-nextick-args": { + "version": "1.0.2" + }, + "string_decoder": { + "version": "0.10.31" + }, + "util-deprecate": { + "version": "1.0.1" + } + } + } + } + }, + "caseless": { + "version": "0.11.0" + }, + "extend": { + "version": "3.0.0" + }, + "forever-agent": { + "version": "0.6.1" + }, + "form-data": { + "version": "1.0.0-rc3", + "dependencies": { + "async": { + "version": "1.4.2" + } + } + }, + "json-stringify-safe": { + "version": "5.0.1" + }, + "mime-types": { + "version": "2.1.6", + "dependencies": { + "mime-db": { + "version": "1.18.0" + } + } + }, + "node-uuid": { + "version": "1.4.3" + }, + "qs": { + "version": "4.0.0" + }, + "tunnel-agent": { + "version": "0.4.1" + }, + "tough-cookie": { + "version": "2.0.0" + }, + "http-signature": { + "version": "0.11.0", + "dependencies": { + "assert-plus": { + "version": "0.1.5" + }, + "asn1": { + "version": "0.1.11" + }, + "ctype": { + "version": "0.5.3" + } + } + }, + "oauth-sign": { + "version": "0.8.0" + }, + "hawk": { + "version": "3.1.0", + "dependencies": { + "hoek": { + "version": "2.14.0" + }, + "boom": { + "version": "2.8.0" + }, + "cryptiles": { + "version": "2.0.4" + }, + "sntp": { + "version": "1.0.9" + } + } + }, + "aws-sign2": { + "version": "0.5.0" + }, + "stringstream": { + "version": "0.0.4" + }, + "combined-stream": { + "version": "1.0.5", + "dependencies": { + "delayed-stream": { + "version": "1.0.0" + } + } + }, + "isstream": { + "version": "0.1.2" + }, + "har-validator": { + "version": "1.8.0", + "dependencies": { + "bluebird": { + "version": "2.9.34" + }, + "chalk": { + "version": "1.1.1", + "dependencies": { + "ansi-styles": { + "version": "2.1.0" + }, + "escape-string-regexp": { + "version": "1.0.3" + }, + "has-ansi": { + "version": "2.0.0", + "dependencies": { + "ansi-regex": { + "version": "2.0.0" + } + } + }, + "strip-ansi": { + "version": "3.0.0", + "dependencies": { + "ansi-regex": { + "version": "2.0.0" + } + } + }, + "supports-color": { + "version": "2.0.0" + } + } + }, + "commander": { + "version": "2.8.1", + "dependencies": { + "graceful-readlink": { + "version": "1.0.1" + } + } + }, + "is-my-json-valid": { + "version": "2.12.2", + "dependencies": { + "generate-function": { + "version": "2.0.0" + }, + "generate-object-property": { + "version": "1.2.0", + "dependencies": { + "is-property": { + "version": "1.0.2" + } + } + }, + "jsonpointer": { + "version": "2.0.0" + }, + "xtend": { + "version": "4.0.0" + } + } + } + } + } + } + }, + "source-map": { + "version": "0.4.4", + "dependencies": { + "amdefine": { + "version": "1.0.0" + } + } + } + } + } + } +} diff --git a/packages/rocketchat-theme-colors/assets/colors.less b/packages/rocketchat-theme-colors/assets/colors.less new file mode 100644 index 00000000000..516091345e5 --- /dev/null +++ b/packages/rocketchat-theme-colors/assets/colors.less @@ -0,0 +1,1198 @@ +// Colors +// -------------- + +.custom-scroll(@background, @thumb, @width: 8px) { + &::-webkit-scrollbar { + width: @width; + background: @background; + } + &::-webkit-scrollbar-thumb { + background-color: @thumb; + -webkit-border-radius: 50px; + } + &::-webkit-scrollbar-corner { + background-color: @background; + } +} + +a { + &:hover, + &:active { + color: @primary-font-color; + } +} + +code { + background-color: @code-background; + border-color: @code-border; + color: @code-color; +} + +blockquote { + &:before { + background-color: @blockquote-background; + } +} + +.login-terms { + color: @smallprint-font-color; + a { + color: @smallprint-font-color; + &:hover { + color: @smallprint-hover-color; + } + } +} + +.upload-preview { + background-color: @secondary-background-color; +} + +.upload-preview-title { + background-color: @tertiary-background-color; +} + +.first-unread { + &.first-unread-opaque { + .body { + &::before { + background-color: lighten(@info-font-color, 25%); + } + + &::after { + color: @info-font-color; + } + } + } + .body { + &::before { + background-color: lighten(@info-active-font-color, 25%); + } + + &::after { + background-color: @content-background-color; + color: @info-active-font-color; + } + } +} + +.alert { + border-color: rgba(0, 0, 0, 0); +} + +.alert-warning { + color: #8A6D3B; + background-color: #FCF8E3; + border-color: #FAEBCC; +} + +.alert-danger { + color: #A94442; + background-color: #F2DEDE; + border-color: #EBCCD1; +} + +.scrollable { + .custom-scroll(transparent, #BFBFBF); +} + +.rocket-form { + legend { + &:after { + background-color: #DFDFDF; + } + } +} + +.input-line { + &.search { + .icon-search { + color: @secondary-font-color; + } + } + > label { + color: @primary-font-color; + } +} + +.rocket-h2 { + color: #EFEFEF; +} + +.rocket-h3 { + color: #EAEAEA; +} + +html { + .custom-scroll(transparent, rgba(255, 255, 255, 0.05), 3px); +} + +body { + color: @primary-font-color; + background-color: @primary-background-color; +} + +textarea, +select, +input[type='text'], +input[type='number'], +input[type='email'], +input[type='password'] { + border-color: #E7E7E7; + background-color: #fff; +} + +input.search { + &:before { + background-color: #000; + } +} + +.form-horizontal .control-label { + color: @primary-font-color; +} + +.-autocomplete-container { + p { + color: @secondary-font-color; + } +} + +.-autocomplete-item { + color: @secondary-font-color; + i { + color: @secondary-font-color; + } + &.selected { + background-color: @tertiary-background-color; + color: @primary-font-color; + } +} + +label.required:after { + color: red; +} + +.status-offline, +.icon-at.status-offline { + color: @status-offline; +} + +.status-online, +.icon-at.status-online { + color: @status-online; +} + +.status-busy, +.icon-at.status-busy { + color: @status-busy; +} + +.status-away, +.icon-at.status-away { + color: @status-away; +} + +// TODO -- Refactor favorite styles and logic; +.favorite-room { + color: #FECF09; +} + +.toggle-favorite { + color: #AAA; +} + +.btn-loading { + color: #444 !important; + background-color: transparent !important; + &:hover { + background-color: transparent !important; + } +} + +// new layout buttons +.button { + background-color: #FFF; + color: rgba(255, 255, 255, 0.85); + background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); + &:before { + background-color: rgba(0, 0, 0, 0.1); + } + &:hover { + color: #FFF; + } + &.secondary { + background-color: @tertiary-background-color; + color: @primary-font-color; + &:before { + background-color: rgba(0, 0, 0, 0.045); + } + } + &.delete, + &.remove, + &.red { + background-color: #bc2031; + } + &.lightblue { + background-color: #02acec; + } + &.clean { + background-color: rgba(0, 0, 0, 0.025); + } + &.facebook { + background-color: #325c99; + } + &.twitter { + background-color: #02acec; + } + &.google { + background-color: #dd4b39; + } + &.github { + background-color: #4c4c4c; + } + &.gitlab { + background-color: #373d47; + } + &.trello { + background-color: #026aa7; + } + &.meteor-developer { + background-color: #de4f4f; + } +} + +.burger { + i { + background-color: #333; + } + + .unread-burger-alert { + background-color: #F95555; + color: @content-background-color; + } +} + +.arrow { + &:before, + &:after { + background-color: #aaa; + } +} + +.a-plus { + &:before, + &:after { + background-color: #aaa; + } +} + +a.github-fork { + background-color: #5c5c5c; + color: #f0f0f0; + &:hover { + background-color: #4b4b4b; + color: #FFF; + } + &:before { + border-top-color: #f0f0f0; + } + &:after { + border-top-color: #f0f0f0; + } +} + +.mac-bar { + background-color: #ddd; + i { + background-color: #ff5f57; + &:nth-child(2) { + background-color: #ffbd2e; + } + &:nth-child(3) { + background-color: #28ca41; + } + } +} + +.avatar { + .avatar-image { + background-color: transparent; + } + &[initials]:before { + color: #FFF; + } +} + +#rocket-chat { + background-color: @content-background-color; +} + +.account-box { + .info { + h4 { + color: rgba(255, 255, 255, 0.65); + } + &.status-offline { + .thumb:after { + border-color: darken(@status-offline, 5%); + background-color: @status-offline; + } + } + &.status-online { + .thumb:after { + border-color: darken(@status-online, 5%); + background-color: @status-online; + } + } + &.status-away { + .thumb:after { + border-color: darken(@status-away, 5%); + background-color: @status-away; + } + } + &.status-busy { + .thumb:after { + border-color: darken(@status-busy, 5%); + background-color: @status-busy; + } + } + } + .options { + background-color: @primary-background-color; + .status { + &:after { + border-color: #6f6f6f; + } + &.offline { + &:after { + border-color: #666666; + background-color: #7b7b7b; + } + } + &.online { + &:after { + border-color: #2c9210; + background-color: #35AC19; + } + } + &.away { + &:after { + border-color: #e69200; + background-color: #fcb316; + } + } + &.busy { + &:after { + border-color: #9f0030; + background-color: #D30230; + } + } + } + span.soon { + color: #aaa; + } + a { + color: rgba(255, 255, 255, 0.5); + border-bottom-color: darken(@primary-background-color, 2%); + &:hover { + background-color: darken(@primary-background-color, 2%); + color: rgba(255, 255, 255, 0.75); + } + } + } + &.active .info, + .info:hover { + h4 { + color: rgba(255, 255, 255, 0.85); + } + } + .hover & { + .info h4 { + color: rgba(255, 255, 255, 0.85); + } + } +} + +// rooms-box +.flex-nav { + //background-color: @primary-background-color; + background-color: transparent; + color: @tertiary-font-color; + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + header { + background-color: @primary-background-color; + } + footer { + background-color: @primary-background-color; + } + .content { + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + background-color: @primary-background-color; + } + .input-line { + input[type='text'], + input[type='password'], + select { + border-color: @tertiary-font-color; + background-color: #04436a; + color: @input-font-color; + } + + & label { + color:@input-font-color; + } + } + .selected-users { + li { + background-color: rgba(0, 0, 0, 0.1); + } + } +} + +.side-nav { + background-color: #F4F4F4; + color: #000; + &:before { + background-color: #dfdfdf; + } + .rooms-list { + background-color: lighten(@primary-background-color, 2%); + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + } + .more { + color: @tertiary-font-color; + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + .input-error { + color: #f09286; + } + .empty { + color: @tertiary-font-color; + } + .header { + color: #fff; + background-color: @primary-background-color; + } + > .arrow { + &.hover, + &:hover { + &:before, + &:after { + background-color: rgba(255, 255, 255, 0.85); + } + } + } + .footer { + background: #fff; + background-color: @primary-background-color; + small { + color: @tertiary-font-color; + } + } + h3 { + color: @tertiary-font-color; + a { + color: inherit; + } + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + .unread { + background-color: #1dce73; + color: #FFF; + } + ul { + li { + .remove, + .erase { + color: #666; + } + &:hover { + .opt { + background-color: transparent; + } + } + &.active { + a { + background-color: rgba(255, 255, 255, 0.075); + color: rgba(255, 255, 255, 0.75); + } + .opt { + background-color: transparent; + } + } + &.has-alert { + .name { + color: #ffffff; + } + } + &.away { + a { + color: #666; + } + } + } + a { + color: @tertiary-font-color; + &:hover { + background-color: rgba(255, 255, 255, 0.05); + } + } + .opt { + background-color: transparent; + i { + color: rgba(255, 255, 255, 0.5); + &:hover { + color: rgba(255, 255, 255, 0.75); + } + } + } + i { + color: rgba(255, 255, 255, 0.35); + } + input[type=text] { + color: #000; + } + } +} + +.page-container { + .content { + .custom-scroll(transparent, #EAEAEA); + } +} + +.fixed-title { + background: #fff; + border-bottom-color: @tertiary-background-color; +} + +.cms-page { + color: #444; + background-color: @content-background-color; +} + +.spotlight { + background-color: rgba(0,0,0,.3); + > .spotlight-input { + color: #444; + > i { + color: #aaa; + } + } +} + +.mobile-message-menu { + background-color: rgba(0,0,0,.3); +} + +.page-static { + .content { + .section { + .section-content { + border-color: #ddd; + } + } + } +} + +.page-list { + .results { + border-bottom-color: #DFDFDF; + color: @secondary-font-color; + } + .list { + a { + color: @primary-font-color; + border-bottom-color: @secondary-background-color; + &:hover { + background-color: @secondary-background-color; + } + } + li { + color: @secondary-font-color; + &:after { + background-color: @secondary-font-color; + } + } + .info { + a { + color: @primary-font-color; + } + } + .status { + color: @secondary-font-color; + } + } +} + +.image-to-download { + background-color: #fafafa; + border-color: #ddd; + color: #aaa; +} + +.room-not-found { + color: orange; +} + +.upload-progress { + background-color: #b2d5c9; + color: @content-background-color; + .upload-progress-item { + border-bottom-color: #6a8179; + &:first-child { + border-top-color: #6a8179; + } + &.upload-error { + background-color: #FF6161; + border-color: #863737; + } + .upload-progress-progress { + background-color: #4c9789; + } + > a { + &:hover { + color: #eee; + } + } + } +} + +// change to page-messages +.messages-container { + .edit-room-title { + color: @secondary-font-color; + &:hover { + color: @primary-font-color; + } + } + .wrapper { + .custom-scroll(transparent, #EAEAEA); + } + .footer { + background: #FCFCFC; + border-top-color: @tertiary-background-color; + } + .message-popup { + background: #FAFAFA; + } + .message-popup-title { + background-color: @secondary-background-color; + border-bottom-color: #EEE; + } + .popup-item { + color: @secondary-font-color; + &.selected { + background-color: @tertiary-background-color; + color: @primary-font-color; + } + } + .popup-user-status { + border-color: rgba(0,0,0,.2); + } + .popup-user-status-system { + border-color: transparent; + } + .popup-user-status-offline { + background-color: @status-offline; + } + .popup-user-status-online { + background-color: @status-online; + } + .popup-user-status-away { + background-color: @status-away; + } + .popup-user-status-busy { + background-color: @status-busy; + } + .message-form { + > div { + > .file { + border-color: #E7E7E7; + color: #888; + background-color: #FCFCFC; + &:hover { + background-color: #F1F1F1; + color: #666; + } + } + > .mic, .stop-mic { + color: #888; + background-color: #FCFCFC; + &:hover { + background-color: #F1F1F1; + color: #666; + } + } + } + textarea { + &.editing { + background-color: #fff7d8; + } + } + .icon-paper-plane { + color: @secondary-font-color; + &:hover { + color: @primary-font-color; + } + } + .users-typing { + color: #888888; + background: #FCFCFC; + } + .formatting-tips { + color: #888888; + &:hover { + color: #444444; + } + q { + border-left-color: #ccc; + } + } + .editing-commands { + .editing-commands-cancel { + color: #888888; + } + .editing-commands-save { + color: #888888; + } + } + } +} + +.messages-box { + .load-more { + span { + border-color: #CCC; + background-color: #EEE; + } + } + .start { + color: @secondary-font-color; + } + .new-message { + background: #428bca; + color: #FFF; + } + .editing { + .body { + background-color: #fff7d8; + } + } +} + +.message { + &.new-day { + &:before { + color: @secondary-font-color; + background-color: @content-background-color; + } + &:after { + border-top-color: #ddd; + } + } + .user { + color: #444444; + &:hover { + color: #333; + } + } + .info { + color: @info-font-color; + } + &.system { + .body { + color: @info-font-color; + } + } + a { + color: @link-font-color; + &:hover { + color: darken(@link-font-color, 10%); + } + } +} + +// FLEX-TAB and FLEX-TAB views +.flex-tab { + background-color: @secondary-background-color; + border-left-color: @tertiary-background-color; + .control { + background-color: @secondary-background-color; + &:before { + background-color: @tertiary-background-color; + } + .more { + background-color: @tertiary-background-color; + border-bottom-color: @tertiary-background-color; + color: @secondary-font-color; + &:hover { + .arrow { + .arrow { + &:before, + &:after { + background-color: #4a4a4a; + } + } + } + } + .arrow { + &:before, + &:after { + background-color: #7a7a7a; + } + } + .flex-opened & { + background-color: @secondary-background-color; + &:hover { + .arrow { + &:before, + &:after { + background-color: #7a7a7a; + } + } + } + } + } + .search-form { + .icon-plus { + color: @secondary-font-color; + } + } + .info-tabs { + a { + color: inherit; + border-left-color: rgb(234, 234, 234); + &.active { + background-color: #F4F4F4; + } + &:last-child { + border-right-color: rgb(234, 234, 234); + } + } + } + } + .content { + .custom-scroll(transparent, #DADADA); + } +} + +.list-view { + > .status { + p { + color: @secondary-font-color; + } + .see-all { + color: @secondary-font-color; + background-color: transparent; + } + } +} + +.user-view { + .info { + h3 { + i.status-offline { + &:after { + border-color: darken(@status-offline, 5%); + background-color: @status-offline; + } + } + i.status-online { + &:after { + border-color: darken(@status-online, 5%); + background-color: @status-online; + } + } + i.status-away { + &:after { + border-color: darken(@status-away, 5%); + background-color: @status-away; + } + } + i.status-busy { + &:after { + border-color: darken(@status-busy, 5%); + background-color: @status-busy; + } + } + } + p { + color: @secondary-font-color; + } + } + .stats { + li { + background-color: #e9e9e9; + } + } + .box { + h4 { + } + &:after { + background-color: #CDCDCD; + } + } + .tags { + li { + background-color: #CDCDCD; + } + } + .links { + a { + color: #6f6f6f; + &:hover { + background-color: #e9e9e9; + color: #333; + } + } + } + .channels { + p { + color: @secondary-font-color; + } + a { + color: #6f6f6f; + } + } + .edit-form { + p { + color: @secondary-font-color; + } + } +} + +.user-image-status(@color) { + .avatar { + &:after { + background-color: darken(@color, 5%); + } + } +} + +.user-image { + background-color: @tertiary-background-color; + &:hover, + &.selected { + .avatar { + &:after { + } + .status-offline { + &:after { + background-color: @status-offline; + } + } + .status-online { + &:after { + background-color: @status-online; + } + } + .status-away { + &:after { + background-color: @status-away; + } + } + .status-busy { + &:after { + background-color: @status-busy; + } + } + p { + color: @primary-font-color; + } + } + } + .lines & { + background-color: transparent; + a { + background-color: transparent; + } + p { + color: @secondary-font-color; + } + } + &.status-offline { + .user-image-status(@status-offline); + } + &.status-online { + .user-image-status(@status-online); + } + &.status-away { + .user-image-status(@status-away); + } + &.status-busy { + .user-image-status(@status-busy); + } +} + +.user-profile { + .info { + a { + color: @primary-font-color; + &:hover { + color: @secondary-font-color; + } + } + } +} + +.rocket-modal { + background-color: rgba(0, 0, 0, 0.5); + &.fluid { + .modal { + main { + .custom-scroll(transparent, #CFCFCF); + } + } + } + legend { + color: @secondary-font-color; + &:before { + background-color: #dfdfdf; + } + } + .modal { + background-color: @content-background-color; + header { + background-color: #DADADA; + .close { + i { + color: @secondary-font-color; + } + &:hover { + i { + color: @primary-font-color; + } + } + } + } + main { + background-color: @content-background-color; + } + footer { + background-color: #eaeaea; + } + } +} + +#login-card { + background-color: #FAFAFA; + h2 { + color: @primary-font-color; + &.error { + color: #b40202; + } + } + h3 { + &.error { + color: #b40202; + } + } + a { + color: @primary-background-color; + &:active { + color: @primary-background-color; + } + &:hover { + color: darken(@primary-background-color, 10%); + } + } + .input-text { + input { + background-color: transparent; + border-bottom-color: #DFDFDF; + &.error { + border-bottom-color: #b40202; + &::-webkit-input-placeholder { + color: #b40202; + } + &:-moz-placeholder { + color: #b40202; + } + /* Firefox 18- */ + &::-moz-placeholder { + color: #b40202; + } + /* Firefox 19+ */ + &:-ms-input-placeholder { + color: #b40202; + } + } + } + input:-webkit-autofill { + color: @content-background-color !important; + } + input:-webkit-autofill { + background-color: transparent !important; + } + } +} + +.full-page { + background-color: darken(@primary-background-color, 10%); + .background-image(linear-gradient(darken(@primary-background-color,10%),@primary-background-color)); + .text { + color: #FFF; + .button { + background-color: #bc2031; + color: #FFF; + } + } + footer { + color: #fff; + div.switch-language { + a { + color: @secondary-font-color; + } + } + } +} + +.avatar-suggestion-item { + background-color: @secondary-background-color; + border-color: darken(@secondary-background-color, 10%); + .avatar { + background-size: cover; + background-color: @tertiary-background-color; + } + .question-mark { + &::before { + color: darken(@tertiary-background-color, 10%); + } + } +} + +.statistics-table { + border-color: #F9F9F9; +} + +@media all and(max-width: 780px) { + #rocket-chat { + .main-content { + background-color: @content-background-color; + } + } +} + +.dropzone { + &.over .dropzone-overlay { + background-color: rgba(0, 0, 0, 0.5); + color: @content-background-color; + > div { + background-color: rgba(0, 0, 0, 0.6); + } + } +} + +.is-cordova { + .flex-tab { + button.more { + background-color: #fff; + } + } +} diff --git a/packages/rocketchat-theme-colors/assets/lesshat.import.less b/packages/rocketchat-theme-colors/assets/lesshat.import.less new file mode 100644 index 00000000000..c08d552d280 --- /dev/null +++ b/packages/rocketchat-theme-colors/assets/lesshat.import.less @@ -0,0 +1,887 @@ +// * =========================================================== * +// < LESSHat > +// * =========================================================== * +// +// Made with Energy drinks in Prague, Czech Republic. +// Handcrafted by Petr Brzek, lesshat.com +// Works great with CSS Hat csshat.com + +// version: v3.0.2 (2014-06-17) + +// TABLE OF MIXINS: + // align-content + // align-items + // align-self + // animation + // animation-delay + // animation-direction + // animation-duration + // animation-fill-mode + // animation-iteration-count + // animation-name + // animation-play-state + // animation-timing-function + // appearance + // backface-visibility + // background-clip + // background-image + // background-origin + // background-size + // blur + // border-bottom-left-radius + // border-bottom-right-radius + // border-image + // border-radius + // border-top-left-radius + // border-top-right-radius + // box-shadow + // box-sizing + // brightness + // calc + // column-count + // column-gap + // column-rule + // column-width + // columns + // contrast + // display + // drop-shadow + // filter + // flex + // flex-basis + // flex-direction + // flex-grow + // flex-shrink + // flex-wrap + // font-face + // grayscale + // hue-rotate + // hyphens + // invert + // justify-content + // keyframes + // opacity + // order + // perspective + // perspective-origin + // placeholder + // rotate + // rotate3d + // rotateX + // rotateY + // rotateZ + // saturate + // scale + // scale3d + // scaleX + // scaleY + // scaleZ + // selection + // sepia + // size + // skew + // skewX + // skewY + // transform + // transform-origin + // transform-style + // transition + // transition-delay + // transition-duration + // transition-property + // transition-timing-function + // translate + // translate3d + // translateX + // translateY + // translateZ + // user-select + +.align-content(...) { + @process: ~`(function(r){return r=r||"stretch"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + @process_ms: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t?t="end":"space-between"==t?t="justify":"space-around"==t&&(t="distribute"),t})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-align-content: @process; + -ms-flex-line-pack: @process_ms; + align-content: @process; +} + +.align-items(...) { + @process_olderwebkit: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(t){return t=t||"stretch"})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + @process_ms: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + -webkit-box-align: @process_olderwebkit; + -moz-box-align: @process_moz; + -webkit-align-items: @process; + -ms-flex-align: @process_ms; + align-items: @process; +} + +.align-self(...) { + @process: ~`(function(t){return t=t||"auto"})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + @process_ms: ~`(function(t){return t=t||"auto","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + -webkit-align-self: @process; + -ms-flex-item-align: @process_ms; + align-self: @process; +} + +.animation(...) { + @process: ~`(function(t){return t=t||"none",/^[^, ]*,/.test(t)&&(t=t.replace(/(?:,)(?![^(]*\))/g,"")),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + -webkit-animation: @process; + -moz-animation: @process; + -o-animation: @process; + animation: @process; +} + +.animation-delay(...) { + @process: ~`(function(t){t=t||"0";var r=/(?:\d)(?:ms|s)/gi,e=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(t)||"0"===t||(t=t.replace(e,function(t){return t+=parseFloat(t,10)>10?"ms":"s"})),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-delay: @process; + -moz-animation-delay: @process; + -o-animation-delay: @process; + animation-delay: @process; +} + +.animation-direction(...) { + @process: ~`(function(r){return r||"normal"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-direction: @process; + -moz-animation-direction: @process; + -o-animation-direction: @process; + animation-direction: @process; +} + +.animation-duration(...) { + @process: ~`(function(r){r=r||"0";var t=/ms|s/gi,e=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(r)||"0"===r||(r=r.replace(e,function(r){return r+=parseFloat(r,10)>10?"ms":"s"})),r})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-duration: @process; + -moz-animation-duration: @process; + -o-animation-duration: @process; + animation-duration: @process; +} + +.animation-fill-mode(...) { + @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-fill-mode: @process; + -moz-animation-fill-mode: @process; + -o-animation-fill-mode: @process; + animation-fill-mode: @process; +} + +.animation-iteration-count(...) { + @process: ~`(function(r){return r||"0"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-iteration-count: @process; + -moz-animation-iteration-count: @process; + -o-animation-iteration-count: @process; + animation-iteration-count: @process; +} + +.animation-name(...) { + @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-name: @process; + -moz-animation-name: @process; + -o-animation-name: @process; + animation-name: @process; +} + +.animation-play-state(...) { + @process: ~`(function(r){return r||"running"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-play-state: @process; + -moz-animation-play-state: @process; + -o-animation-play-state: @process; + animation-play-state: @process; +} + +.animation-timing-function(...) { + @process: ~`(function(r){return r||"ease"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-animation-timing-function: @process; + -moz-animation-timing-function: @process; + -o-animation-timing-function: @process; + animation-timing-function: @process; +} + +.appearance(...) { + @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-appearance: @process; + -moz-appearance: @process; + appearance: @process; +} + +.backface-visibility(...) { + @process: ~`(function(r){return r||"visible"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-backface-visibility: @process; + -moz-backface-visibility: @process; + -o-backface-visibility: @process; + -ms-backface-visibility: @process; + backface-visibility: @process; +} + +.background-clip(...) { + @process: ~`(function(r){return r||"border-box"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + -webkit-background-clip: @process; + -moz-background-clip: @process; + background-clip: @process; +} + +.background-image(...) { + @process_ms: ~`(function(t){function e(t){var e,r,n,a,s,i,u,o,g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",c=0,l=0,f="",d=[];if(!t)return t;do e=t.charCodeAt(c++),r=t.charCodeAt(c++),n=t.charCodeAt(c++),o=e<<16|r<<8|n,a=63&o>>18,s=63&o>>12,i=63&o>>6,u=63&o,d[l++]=g.charAt(a)+g.charAt(s)+g.charAt(i)+g.charAt(u);while(c<t.length);f=d.join("");var p=t.length%3;return(p?f.slice(0,p-3):f)+"===".slice(p||3)}if(t=t||8121991,8121991==t)return t;var r=/linear|radial/g.test(t)&&t.split(/,(?=\s*(?:linear|radial|url))/g),n=[],a={"to bottom":'x1="0%" y1="0%" x2="0%" y2="100%"',"to left":'x1="100%" y1="0%" x2="0%" y2="0%"',"to top":'x1="0%" y1="100%" x2="0%" y2="0%"',"to right":'x1="0%" y1="0%" x2="100%" y2="0%"',get"top"(){return this["to bottom"]},get"180deg"(){return this["to bottom"]},get"right"(){return this["to left"]},get"270deg"(){return this["to left"]},get"bottom"(){return this["to top"]},get"90deg"(){return this["to right"]},get"0deg"(){return this["to top"]},get"left"(){return this["to right"]},"-45deg":'x1="0%" y1="0%" x2="100%" y2="100%"',"45deg":'x1="0%" y1="100%" x2="100%" y2="0%"',"ellipse at center":'cx="50%" cy="50%" r="75%"',get"135deg"(){return this["-45deg"]}},s={uri_data:"url(data:image/svg+xml;base64,",xml:'<?xml version="1.0" ?>',svg_start:'<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">',linear_gradient_start:'<linearGradient id="lesshat-generated" gradientUnits="userSpaceOnUse"',radial_gradient_start:'<radialGradient id="lesshat-generated" gradientUnits="userSpaceOnUse"',linear_gradient_end:"</linearGradient>",radial_gradient_end:"</radialGradient>",rect_linear:'<rect x="0" y="0" width="1" height="1" fill="url(#lesshat-generated)" />',rect_radial:'<rect x="-50" y="-50" width="101" height="101" fill="url(#lesshat-generated)" />',svg_end:"</svg>"};if(r.length){r.forEach(function(t){var e={};if(Object.keys(a).some(function(r){return t.indexOf(r)>=0?(e.svg_direction=a[r],!0):(e.svg_direction=!1,void 0)}),/linear/.test(t))e.svg_type="linear";else if(/radial/.test(t))e.svg_type="radial";else if(!/linear/.test(t)&&!/radial/.test(t))return e.url=t.trim(),e.svg_type="url",e.svg_direction=!0,n.push(e),!1;var r=t.match(/rgb|#[a-zA-Z0-9]|hsl/g).length;e.svg_stops=[],t=t.replace(/transparent/g,"rgba(0,0,0,0)"),t.match(/#[a-zA-Z0-9]/g)&&t.match(/(#[a-zA-Z0-9]+)\s*(\d+%)?/g).forEach(function(t){t=t.split(" "),e.svg_stops.push('<stop offset="'+(t[1]||!1)+'" stop-color="'+t[0]+'" stop-opacity="1"/>')}),t.match(/rgba?\(\d+,\s*\d+,\s*\d+(?:,\s*(0|1|\.\d+|0\.\d+))?\)/g)&&t.replace(/rgba?\((\d+,\s*\d+,\s*\d+)(?:,\s*(0|1|\.\d+|0\.\d+))?\)\s*(\d+%)?/g,function(t,r,n,a){e.svg_stops.push('<stop offset="'+(a||!1)+'" stop-color="rgb('+r+')" stop-opacity="'+(n||1)+'"/>')}),t.match(/hsla?\((\d+,\s*\d+%,\s*\d+%),\s*(0|1|\.\d+|0\.\d+)\)/g)&&t.replace(/hsla?\((\d+,\s*\d+%,\s*\d+%),\s*(0|1|\.\d+|0\.\d+)\)\s*(\d+%)?/g,function(t,r,n,a){e.svg_stops.push('<stop offset="'+(a||!1)+'" stop-color="hsl('+r+')" stop-opacity="'+(n||1)+'"/>')});var s=Math.floor(100/(r-1));e.svg_stops.forEach(function(t,r){/offset="false"/.test(t)&&(e.svg_stops[r]=t.replace(/offset="false"/,'offset="'+s*r+'%"'))}),e.svg_stops.sort(function(t,e){return t=t.match(/offset="(\d+)%"/),e=e.match(/offset="(\d+)%"/),2==t.length&&2==e.length?t[1]-e[1]:void 0}),n.push(e)});var i=[],u=n.every(function(t){for(var e in t)if(0==t[e]||0==t[e].length)return!1;return!0});if(!u)return 8121991;n.forEach(function(t,e){("linear"==t.svg_type||"radial"==t.svg_type)&&(i[e]=s.xml+s.svg_start),"linear"==t.svg_type?(i[e]+=s.linear_gradient_start+" "+t.svg_direction+">",t.svg_stops.forEach(function(t){i[e]+=t}),i[e]+=s.linear_gradient_end,i[e]+=s.rect_linear,i[e]+=s.svg_end):"radial"==t.svg_type?(i[e]+=s.radial_gradient_start+" "+t.svg_direction+">",t.svg_stops.forEach(function(t){i[e]+=t}),i[e]+=s.radial_gradient_end,i[e]+=s.rect_radial,i[e]+=s.svg_end):"url"==t.svg_type&&(i[e]=t.url)}),i.forEach(function(t,r){/<\?xml version="1.0" \?>/g.test(t)&&(i[r]=s.uri_data+e(t)+")")}),t=i.join(",")}return t})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; + @process_webkit: ~`(function(t){if(t=t||8121991,8121991==t)return t;var e={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(e);return n.some(function(n){return t.indexOf(n)>=0?(t=t.replace(new RegExp(n+"(?![ a-z0-9])","g"),e[n]),!0):(r.test(t)&&(t=t.replace(r,function(t,e,r,n,a){return e.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),t=t.replace(/(\d+)\s*deg/g,function(t,e){return 90-e+"deg"}).replace(/(linear|radial)-gradient/g,"-webkit-$1-gradient")})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(t);return n.some(function(n){return e.indexOf(n)>=0?(e=e.replace(new RegExp(n+"(?![ a-z0-9])","g"),t[n]),!0):(r.test(e)&&(e=e.replace(r,function(e,t,r,n,a){return t.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),e=e.replace(/(\d+)\s*deg/g,function(e,t){return 90-t+"deg"}).replace(/(linear|radial)-gradient/g,"-moz-$1-gradient")})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; + @process_opera: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(t);return n.some(function(n){return e.indexOf(n)>=0?(e=e.replace(new RegExp(n+"(?![ a-z0-9])","g"),t[n]),!0):(r.test(e)&&(e=e.replace(r,function(e,t,r,n,a){return t.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),e=e.replace(/(\d+)\s*deg/g,function(e,t){return 90-t+"deg"}).replace(/(linear|radial)-gradient/g,"-o-$1-gradient")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={top:"to bottom",right:"to left",bottom:"to top",left:"to right"},r=Object.keys(t);return r.some(function(r){return e.indexOf(r)>=0&&!new RegExp("to\\s+"+r+"|at\\s+"+r,"g").test(e)?(e=e.replace(new RegExp(r),t[r]),!0):void 0}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + background-image: @process_ms; + background-image: @process_webkit; + background-image: @process_moz; + background-image: @process_opera; + background-image: @process; +} + +.background-origin(...) { + @process: ~`(function(e){return e||"padding-box"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-background-origin: @process; + -moz-background-origin: @process; + background-origin: @process; +} + +.background-size(...) { + @process: ~`(function(e){e=e||"auto auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-background-size: @process; + -moz-background-size: @process; + background-size: @process; +} + +.blur(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: blur(@process); + -moz-filter: blur(@process); + -ms-filter: blur(@process); + filter: blur(@process); +} + +.border-bottom-left-radius(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-border-bottom-left-radius: @process; -webkit-background-clip: padding-box; + -moz-border-radius-bottomleft: @process; -moz-background-clip: padding; + border-bottom-left-radius: @process; background-clip: padding-box; +} + +.border-bottom-right-radius(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-border-bottom-right-radius: @process; -webkit-background-clip: padding-box; + -moz-border-radius-bottomright: @process; -moz-background-clip: padding; + border-bottom-right-radius: @process; background-clip: padding-box; +} + +.border-image(...) { + @process: ~`(function(e){return e=e||8121991,/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-border-image: @process; + -moz-border-image: @process; + -o-border-image: @process; + border-image: @process; +} + +.border-radius(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-border-radius: @process; -webkit-background-clip: padding-box; + -moz-border-radius: @process; -moz-background-clip: padding; + border-radius: @process; background-clip: padding-box; +} + +.border-top-left-radius(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-border-top-left-radius: @process; -webkit-background-clip: padding-box; + -moz-border-radius-topleft: @process; -moz-background-clip: padding; + border-top-left-radius: @process; background-clip: padding-box; +} + +.border-top-right-radius(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-border-top-right-radius: @process; -webkit-background-clip: padding-box; + -moz-border-radius-topright: @process; -moz-background-clip: padding; + border-top-right-radius: @process; background-clip: padding-box; +} + +.box-shadow(...) { + @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-box-shadow: @process; + -moz-box-shadow: @process; + box-shadow: @process; +} + +.box-sizing(...) { + @process: ~`(function(e){return e=e||"content-box"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-box-sizing: @process; + -moz-box-sizing: @process; + box-sizing: @process; +} + +.brightness(...) { + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: brightness(@process); + -moz-filter: brightness(@process); + -ms-filter: brightness(@process); + filter: brightness(@process); +} + +.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; + +} + +.column-count(...) { + @process: ~`(function(e){return e=e||"auto"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-column-count: @process; + -moz-column-count: @process; + column-count: @process; +} + +.column-gap(...) { + @process: ~`(function(e){e=e||"normal";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-column-gap: @process; + -moz-column-gap: @process; + column-gap: @process; +} + +.column-rule(...) { + @process: ~`(function(e){e=e||"medium none black";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-column-rule: @process; + -moz-column-rule: @process; + column-rule: @process; +} + +.column-width(...) { + @process: ~`(function(e){e=e||"auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-column-width: @process; + -moz-column-width: @process; + column-width: @process; +} + +.columns(...) { + @process: ~`(function(e){e=e||"auto auto";var t=/^\d+$/;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""),e=e.split(" ")),t.test(e[0])&&(e[0]=e[0]+"px"),e.join(" ")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-columns: @process; + -moz-columns: @process; + columns: @process; +} + +.contrast(...) { + @process: ~`(function(e){e=e||"100%";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: ~"contrast(@{process})"; + -moz-filter: ~"contrast(@{process})"; + -ms-filter: ~"contrast(@{process})"; + filter: ~"contrast(@{process})"; +} + +.display(...) { + @process_oldwebkit: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-webkit-box":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-moz-box":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_webkit: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-webkit-"+e:8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_ms: ~`(function(e){return e="flex"==e?"-ms-flexbox":"inline-flex"==e?"-ms-inline-flexbox":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){return"flex"!=e&&"inline-flex"!=e&&(e=8121991),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + display: @process_oldwebkit; + display: @process_moz; + display: @process_webkit; + display: @process_ms; + display: @process; +} + +.drop-shadow(...) { + @process: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: drop-shadow(@process); + -moz-filter: drop-shadow(@process); + -ms-filter: drop-shadow(@process); + filter: drop-shadow(@process); +} + +.filter(...) { + @process: ~`(function(e){return e=e||"none",/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: @process; + -moz-filter: @process; + -ms-filter: @process; + filter: @process; +} + +.flex(...) { + @process_olderwebkit: ~`(function(e){return/^\d+/.test(e)?e=e.match(/^\d+/)[0]:""==e&&(e="0"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){return/^\d+/.test(e)?e=e.match(/^\d+/)[0]:""==e&&(e="0"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){return e=e||"0 1 auto",/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-box-flex: @process_olderwebkit; + -moz-box-flex: @process_moz; + -webkit-flex: @process; + -ms-flex: @process; + flex: @process; +} + +.flex-basis(...) { + @process: ~`(function(e){e=e||"auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-flex-basis: @process; + flex-basis: @process; +} + +.flex-direction(...) { + @process_oldestwebkit: ~`(function(e){return e="row"==e||"column"==e?"normal":"row-reverse"==e||"column-reverse"==e?"reverse":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_oldermoz: ~`(function(e){return e="row"==e||"column"==e?"normal":"row-reverse"==e||"column-reverse"==e?"reverse":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_olderwebkit: ~`(function(e){return e="row"==e||"row-reverse"==e?"horizontal":"column"==e||"column-reverse"==e?"vertical":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){return e="row"==e||"row-reverse"==e?"horizontal":"column"==e||"column-reverse"==e?"vertical":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){return e=e||"row"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-box-direction: @process_oldestwebkit; + -moz-box-direction: @process_oldermoz; + -webkit-box-orient: @process_olderwebkit; + -moz-box-orient: @process_moz; + -webkit-flex-direction: @process; + -ms-flex-direction: @process; + flex-direction: @process; +} + +.flex-grow(...) { + @process: ~`(function(e){return e=e||"0"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-flex-grow: @process; + flex-grow: @process; +} + +.flex-shrink(...) { + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-flex-shrink: @process; + flex-shrink: @process; +} + +.flex-wrap(...) { + @process: ~`(function(e){return e=e||"nowrap"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-flex-wrap: @process; + -ms-flex-wrap: @process; + flex-wrap: @process; +} + +.font-face(@fontname, @fontfile, @fontweight:normal, @fontstyle:normal) { + font-family: "@{fontname}"; + src: url("@{fontfile}.eot"); + src: url("@{fontfile}.eot?#iefix") format("embedded-opentype"), + url("@{fontfile}.woff") format("woff"), + url("@{fontfile}.ttf") format("truetype"), + url("@{fontfile}.svg#@{fontname}") format("svg"); + font-weight: @fontweight; + font-style: @fontstyle; +} + +.grayscale(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: grayscale(@process); + -moz-filter: grayscale(@process); + -ms-filter: grayscale(@process); + filter: grayscale(@process); +} + +.hue-rotate(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: hue-rotate(@process); + -moz-filter: hue-rotate(@process); + -ms-filter: hue-rotate(@process); + filter: hue-rotate(@process); +} + +.hyphens(...) { + @process: ~`(function(e){return e=e||"manual"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-hyphens: @process; + -moz-hyphens: @process; + -ms-hyphens: @process; + hyphens: @process; +} + +.invert(...) { + @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: invert(@process); + -moz-filter: invert(@process); + -ms-filter: invert(@process); + filter: invert(@process); +} + +.justify-content(...) { + @process_oldestWebkit: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":("space-between"==e||"space-around"==e)&&(e="justify"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":("space-between"==e||"space-around"==e)&&(e="justify"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_ms: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":"space-between"==e?e="justify":"space-around"==e&&(e="distribute"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){return e=e||"flex-start"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-box-pack: @process_oldestWebkit; + -moz-box-pack: @process_moz; + -ms-flex-pack: @process_ms; + -webkit-justify-content: @process; + justify-content: @process; +} + +.keyframes(...) { + @process: ~`(function(e){function r(r,t,c){var i="}\n",u=n.split(/(^[a-zA-Z0-9-]+),/g),s=t+" "+u[1]+"{",o=["-webkit-","-moz-","-ms-",""];c?a.forEach(function(r){-1!==e.indexOf(r)&&(u[2]=u[2].replace(new RegExp(r,"g"),function(e){return c+e}))}):u[2]=u[2].replace(/{([^}]+)}/g,function(e,r){var t=r.split(";");t.forEach(function(e,r){a.forEach(function(n){-1!==e.indexOf(n)&&(t[r]="",o.forEach(function(a){t[r]+=e.trim().replace(new RegExp(n,"g"),function(e){return a+e})+";"}))})});var n=t.join(";").replace(/;;/g,";");return e.replace(r,n)}),s+=u[2]+i,"start"==r?e="0; } \n"+s:"startend"==r?e="0; } \n"+s.replace(i,""):e+="end"==r?s.replace(i,""):s}e=e||8121991;var t="@{state}",n=e;if(8121991==e)return e;var a=["animation","transform","filter"];switch(t){case"1":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"2":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r("end","@keyframes");break;case"3":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r("end","@-o-keyframes","-o-");break;case"4":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"5":r("start","@-webkit-keyframes","-webkit-"),r("end","@-moz-keyframes","-moz-");break;case"6":r("start","@-webkit-keyframes","-webkit-"),r("end","@-o-keyframes","-o-");break;case"7":r("start","@-webkit-keyframes","-webkit-"),r("end","@keyframes");break;case"8":r("startend","@-webkit-keyframes","-webkit-");break;case"9":r("start","@-moz-keyframes","-moz-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"10":r("start","@-moz-keyframes","-moz-"),r("end","@-o-keyframes","-o-");break;case"11":r("start","@-moz-keyframes","-moz-"),r("end","@keyframes");break;case"12":r("startend","@-moz-keyframes","-moz-");break;case"13":r("start","@-o-keyframes","-o-"),r("end","@keyframes");break;case"14":r("startend","@-o-keyframes","-o-");break;case"15":r("startend","@keyframes")}return e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @state: 1; lesshat-selector { -lh-property: @process; } +} + +.opacity(...) { + @process_ms: ~`(function(e){return e=e||"filter: alpha(opacity=100)","alpha(opacity="+Math.floor(100*e)+")"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + zoom: 1; filter: @process_ms; + -webkit-opacity: @process; + -moz-opacity: @process; + opacity: @process; +} + +.order(...) { + @process: ~`(function(e){return e=e||"0"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-box-ordinal-group: @process; + -moz-box-ordinal-group: @process; + -ms-flex-order: @process; + -webkit-order: @process; + order: @process; +} + +.perspective(...) { + @process: ~`(function(e){e=e||"none";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-perspective: @process; + -moz-perspective: @process; + perspective: @process; +} + +.perspective-origin(...) { + @process: ~`(function(e){e=e||"50% 50%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-perspective-origin: @process; + -moz-perspective-origin: @process; + perspective-origin: @process; +} + +.placeholder(@color:#aaa, @element: 08121991) { + .inception (@arguments) when not (@element = 08121991) { + @{element}::-webkit-input-placeholder { + color: @color; + } + @{element}:-moz-placeholder { + color: @color; + } + @{element}::-moz-placeholder { + color: @color; + } + @{element}:-ms-input-placeholder { + color: @color; + } + } + .inception (@arguments) when (@element = 08121991) { + &::-webkit-input-placeholder { + color: @color; + } + &:-moz-placeholder { + color: @color; + } + &::-moz-placeholder { + color: @color; + } + &:-ms-input-placeholder { + color: @color; + } + } + .inception(@arguments); +} + +.rotate(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: rotate(@process); + -moz-transform: rotate(@process); + -o-transform: rotate(@process); + -ms-transform: rotate(@process); + transform: rotate(@process); +} + +.rotate3d(...) { + @process: ~`(function(e){return e=e||"0, 0, 0, 0",e=e.replace(/,\s*\d+$/,function(e){return e+"deg"})})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: rotate3d(@process); + -moz-transform: rotate3d(@process); + -o-transform: rotate3d(@process); + -ms-transform: rotate3d(@process); + transform: rotate3d(@process); +} + +.rotateX(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: rotateX(@process); + -moz-transform: rotateX(@process); + -o-transform: rotateX(@process); + -ms-transform: rotateX(@process); + transform: rotateX(@process); +} + +.rotateY(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: rotateY(@process); + -moz-transform: rotateY(@process); + -o-transform: rotateY(@process); + -ms-transform: rotateY(@process); + transform: rotateY(@process); +} + +.rotateZ(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: rotateZ(@process); + -moz-transform: rotateZ(@process); + -o-transform: rotateZ(@process); + -ms-transform: rotateZ(@process); + transform: rotateZ(@process); +} + +.saturate(...) { + @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: ~"saturate(@{process})"; + -moz-filter: ~"saturate(@{process})"; + -ms-filter: ~"saturate(@{process})"; + filter: ~"saturate(@{process})"; +} + +.scale(...) { + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: scale(@process); + -moz-transform: scale(@process); + -o-transform: scale(@process); + -ms-transform: scale(@process); + transform: scale(@process); +} + +.scale3d(...) { + @process: ~`(function(e){return e=e||"1, 1, 1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: scale3d(@process); + -moz-transform: scale3d(@process); + -o-transform: scale3d(@process); + -ms-transform: scale3d(@process); + transform: scale3d(@process); +} + +.scaleX(...) { + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: scaleX(@process); + -moz-transform: scaleX(@process); + -o-transform: scaleX(@process); + -ms-transform: scaleX(@process); + transform: scaleX(@process); +} + +.scaleY(...) { + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: scaleY(@process); + -moz-transform: scaleY(@process); + -o-transform: scaleY(@process); + -ms-transform: scaleY(@process); + transform: scaleY(@process); +} + +.scaleZ(...) { + @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: scaleZ(@process); + -moz-transform: scaleZ(@process); + -o-transform: scaleZ(@process); + -ms-transform: scaleZ(@process); + transform: scaleZ(@process); +} + +.selection(...) { + @process: ~`(function(e){function r(r,t){var a="}\n",c=n.split(","),u=(c[1]||"")+t+"{"+c[0]+a;"start"==r?e="0; } \n"+u:"startend"==r?e="0; } \n"+u.replace(a,""):e+="end"==r?u.replace(a,""):u}e=e||8121991;var t="@{state}",n=e;if(8121991==e)return e;switch(t){case"1":r("start","::selection"),r("end","::-moz-selection");break;case"2":r("startend","::selection");break;case"3":r("startend","::-moz-selection")}return e=e.replace(/;$/g,"")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @state: 1; lesshat-selector { -lh-property: @process; } + +} + +.sepia(...) { + @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-filter: sepia(@process); + -moz-filter: sepia(@process); + -ms-filter: sepia(@process); + filter: sepia(@process); +} + +.size(@square) { + @unit: 'px'; + .process(@square) when (ispixel(@square)), (isem(@square)), (ispercentage(@square)), (iskeyword(@square)) { + width: @square; + height: @square; + } + + .process(@square) when not (ispixel(@square)) and not (isem(@square)) and not (ispercentage(@square)) and not (isstring(@square)) and not (iskeyword(@square)) { + width: ~`@{square} + @{unit}`; + height: ~`@{square} + @{unit}`; + } + + .process(@square); + +} + +.size(@width, @height) { + @unit: 'px'; + .process(@width, @height) when (ispixel(@width)), (isem(@width)), (ispercentage(@width)), (iskeyword(@width)) { + .kittens(@height) when (ispixel(@height)), (isem(@height)), (ispercentage(@height)), (iskeyword(@height)) { + width: @width; + height: @height; + } + .kittens(@height) when not (ispixel(@height)) and not (isem(@height)) and not (ispercentage(@height)) and not (iskeyword(@height)) { + width: @width; + height: ~`@{height} + @{unit}`; + } + .kittens(@height); + } + + .process(@width, @height) when (ispixel(@height)), (isem(@height)), (ispercentage(@height)), (iskeyword(@height)) { + .kittens(@width) when (ispixel(@width)), (isem(@width)), (ispercentage(@width)), (iskeyword(@width)) {} + .kittens(@width) when not (ispixel(@width)) and not (isem(@width)) and not (ispercentage(@width)) and not (iskeyword(@width)) { + width: ~`@{width} + @{unit}`; + height: @height; + } + .kittens(@width); + } + + .process(@width, @height) when not (ispixel(@width)) and not (isem(@width)) and not (ispercentage(@width)) and not (iskeyword(@width)) and not (ispixel(@height)) and not (isem(@height)) and not (ispercentage(@height)) and not (iskeyword(@height)) { + width: ~`@{width} + @{unit}`; + height: ~`@{height} + @{unit}`; + } + + .process(@width, @height); + +} + +.skew(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: skew(@process); + -moz-transform: skew(@process); + -o-transform: skew(@process); + -ms-transform: skew(@process); + transform: skew(@process); +} + +.skewX(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: skewX(@process); + -moz-transform: skewX(@process); + -o-transform: skewX(@process); + -ms-transform: skewX(@process); + transform: skewX(@process); +} + +.skewY(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: skewY(@process); + -moz-transform: skewY(@process); + -o-transform: skewY(@process); + -ms-transform: skewY(@process); + transform: skewY(@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; +} + +.transform-origin(...) { + @process: ~`(function(e){e=e||"50% 50% 0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform-origin: @process; + -moz-transform-origin: @process; + -o-transform-origin: @process; + -ms-transform-origin: @process; + transform-origin: @process; +} + +.transform-style(...) { + @process: ~`(function(e){return e=e||"flat"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform-style: @process; + -moz-transform-style: @process; + -o-transform-style: @process; + -ms-transform-style: @process; + transform-style: @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; +} + +.transition-delay(...) { + @process: ~`(function(e){e=e||"0";var r=/(?:\d)(?:ms|s)/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)||"0"===e||(e=e.replace(t,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transition-delay: @process; + -moz-transition-delay: @process; + -o-transition-delay: @process; + transition-delay: @process; +} + +.transition-duration(...) { + @process: ~`(function(e){e=e||"0";var r=/ms|s/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)||"0"===e||(e=e.replace(t,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transition-duration: @process; + -moz-transition-duration: @process; + -o-transition-duration: @process; + transition-duration: @process; +} + +.transition-property(...) { + @process_webkit: ~`(function(e){e=e||"all";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-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_moz: ~`(function(e){e=e||"all";var r=["background-size","box-shadow","column","transform","filter"],t="-moz-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process_opera: ~`(function(e){e=e||"all";var r=["transform"],t="-o-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + @process: ~`(function(e){e=e||"all";var r=["-webkit-","-moz-","-o-",""],t=["column","transform","filter"],n=e.split(/(?:,)(?![^(]*\))/g);return n.forEach(function(e,a){t.forEach(function(t){-1!==e.indexOf(t)&&(n[a]="",r.forEach(function(c,u){n[a]+=e.trim().replace(new RegExp(t,"g"),function(e){return c+e}),u<r.length-1&&(n[a]+=",")}))})}),e=n.join(",")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transition-property: @process_webkit; + -moz-transition-property: @process_moz; + -o-transition-property: @process_opera; + transition-property: @process; +} + +.transition-timing-function(...) { + @process: ~`(function(e){return e=e||"ease"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transition-timing-function: @process; + -moz-transition-timing-function: @process; + -o-transition-timing-function: @process; + transition-timing-function: @process; +} + +.translate(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: translate(@process); + -moz-transform: translate(@process); + -o-transform: translate(@process); + -ms-transform: translate(@process); + transform: translate(@process); +} + +.translate3d(...) { + @process: ~`(function(e){e=e||"0, 0, 0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: translate3d(@process); + -moz-transform: translate3d(@process); + -o-transform: translate3d(@process); + -ms-transform: translate3d(@process); + transform: translate3d(@process); +} + +.translateX(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: translateX(@process); + -moz-transform: translateX(@process); + -o-transform: translateX(@process); + -ms-transform: translateX(@process); + transform: translateX(@process); +} + +.translateY(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: translateY(@process); + -moz-transform: translateY(@process); + -o-transform: translateY(@process); + -ms-transform: translateY(@process); + transform: translateY(@process); +} + +.translateZ(...) { + @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-transform: translateZ(@process); + -moz-transform: translateZ(@process); + -o-transform: translateZ(@process); + -ms-transform: translateZ(@process); + transform: translateZ(@process); +} + +.user-select(...) { + @process: ~`(function(e){return e=e||"auto"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; + -webkit-user-select: @process; + -moz-user-select: @process; + -ms-user-select: @process; + user-select: @process; +} diff --git a/packages/rocketchat-theme-colors/package.js b/packages/rocketchat-theme-colors/package.js new file mode 100644 index 00000000000..62b4e326371 --- /dev/null +++ b/packages/rocketchat-theme-colors/package.js @@ -0,0 +1,30 @@ +Package.describe({ + name: 'rocketchat:theme-colors', + version: '0.0.1', + summary: '', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use('coffeescript'); + api.use('webapp'); + + api.addFiles('server.coffee', 'server'); + + api.addFiles('assets/lesshat.import.less', 'server', {isAsset: true}); + api.addFiles('assets/colors.less', 'server', {isAsset: true}); + + api.export('less', 'server'); + api.export('getText', 'server'); + api.export('getAndCompile', 'server'); +}); + +Npm.depends({ + 'less': 'https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6' +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-theme-colors/server.coffee b/packages/rocketchat-theme-colors/server.coffee new file mode 100644 index 00000000000..3b9fdd47a03 --- /dev/null +++ b/packages/rocketchat-theme-colors/server.coffee @@ -0,0 +1,59 @@ +less = Npm.require('less') + +getText = (file) -> + Assets.getText file + +getAndCompile = (cb) -> + variables = """ + @content-background-color: #FFF; + + @primary-background-color: #04436A; + @secondary-background-color: #F4F4F4; + @tertiary-background-color: #EAEAEA; + + @primary-font-color: #444444; + @secondary-font-color: #7F7F7F; + @tertiary-font-color: rgba(255, 255, 255, 0.6); + + @input-font-color: rgba(255, 255, 255, 0.85); + @link-font-color: #008CE3; + + @info-font-color: #AAAAAA; + @info-active-font-color: #FF0000; + + @smallprint-font-color: #C2E7FF; + @smallprint-hover-color: white; + + @status-online: #35AC19; + @status-offline: rgba(150, 150, 150, 0.50); + @status-busy: #D30230; + @status-away: #FCB316; + + @code-background: #F8F8F8; + @code-border: #CCC; + @code-color: #333; + @blockquote-background: #CCC; + """ + + lesshat = Assets.getText 'assets/lesshat.import.less' + colors = Assets.getText 'assets/colors.less' + + colors = [lesshat, variables, colors].join '\n' + + options = + compress: true + + less.render colors, options, cb + +WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> + getAndCompile (err, data) -> + + res.setHeader 'content-type', 'text/css; charset=UTF-8' + res.setHeader 'Content-Disposition', 'inline' + res.setHeader 'Cache-Control', 'no-cache' + res.setHeader 'Pragma', 'no-cache' + res.setHeader 'Expires', '0' + res.setHeader 'Content-Length', data.css.length * 8 + + res.end data.css + # less.render colors -- GitLab From 1cf330cb0efa4c2fd95b08617a615bd93534e08a Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 22 Sep 2015 21:12:45 -0300 Subject: [PATCH 0003/1338] Enable international characters --- .../rocketchat-lib/server/functions/setUsername.coffee | 2 +- packages/rocketchat-lib/server/methods/setUsername.coffee | 2 +- packages/rocketchat-mentions/client.coffee | 7 ++++--- packages/rocketchat-mentions/server.coffee | 4 ++-- server/methods/createChannel.coffee | 2 +- server/methods/createPrivateGroup.coffee | 2 +- server/methods/saveRoomName.coffee | 2 +- server/methods/setAvatarFromService.coffee | 2 +- server/restapi/restapi.coffee | 4 ++-- 9 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 664b48e9e85..de418b6486a 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -3,7 +3,7 @@ RocketChat.setUsername = (user, username) -> if not user or not username return false - if not /^[0-9a-zA-Z-_.]+$/.test username + if not /^[0-9a-zA-Z-_.\u00C0-\u017F]+$/.test username return false # User already has desired username, return diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 44bad046e86..a501a9a3cee 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -10,7 +10,7 @@ Meteor.methods if user.username is username return username - if not /^[0-9a-zA-Z-_.]+$/.test username + if not /^[0-9a-zA-Z-_.\u00C0-\u017F]+$/.test username throw new Meteor.Error 'username-invalid', "#{username} is not a valid username, use only letters, numbers, dots and dashes" if not RocketChat.checkUsernameAvailability username diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index 2e981a15121..083cd174b12 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -9,7 +9,8 @@ class MentionsClient msg = message.html mentions = [] - message.msg.replace /(?:^|\s|\n)(?:@)([A-Za-z0-9-_.]+)/g, (match, mention) -> + + message.msg.replace /(?:^|\s|\n)(?:@)([0-9a-zA-Z-_.\u00C0-\u017F]+)/g, (match, mention) -> mentions.push mention me = Meteor.user()?.username @@ -32,7 +33,7 @@ class MentionsClient return match.replace mention, "<a href=\"\" class=\"#{classes}\" data-username=\"#{username}\">#{mention}</a>" channels = [] - message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F]+)/g, (match, mention) -> channels.push mention if channels.length isnt 0 @@ -48,4 +49,4 @@ class MentionsClient message.html = msg return message -RocketChat.callbacks.add 'renderMessage', MentionsClient \ No newline at end of file +RocketChat.callbacks.add 'renderMessage', MentionsClient diff --git a/packages/rocketchat-mentions/server.coffee b/packages/rocketchat-mentions/server.coffee index e51e5bed70c..1a971366f3e 100644 --- a/packages/rocketchat-mentions/server.coffee +++ b/packages/rocketchat-mentions/server.coffee @@ -7,7 +7,7 @@ class MentionsServer constructor: (message) -> # If message starts with /me, replace it for text formatting mentions = [] - message.msg.replace /(?:^|\s|\n)(?:@)([A-Za-z0-9-_.]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:@)([A-Za-z0-9-_.\u00C0-\u017F]+)/g, (match, mention) -> mentions.push mention if mentions.length isnt 0 mentions = _.unique mentions @@ -25,7 +25,7 @@ class MentionsServer message.mentions = verifiedMentions channels = [] - message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F]+)/g, (match, mention) -> channels.push mention if channels.length isnt 0 diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index c3dff18c170..a5c6feaf868 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -3,7 +3,7 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', "[methods] createChannel -> Invalid user" - if not /^[0-9a-z-_]+$/.test name + if not /^[0-9a-zA-Z-_\u00C0-\u017F]+$/.test name throw new Meteor.Error 'name-invalid' if RocketChat.authz.hasPermission(Meteor.userId(), 'create-c') isnt true diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 81f20a0bd4d..f208d4562aa 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -8,7 +8,7 @@ Meteor.methods console.log '[methods] createPrivateGroup -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - if not /^[0-9a-z-_]+$/.test name + if not /^[0-9a-zA-Z-_\u00C0-\u017F]+$/.test name throw new Meteor.Error 'name-invalid' now = new Date() diff --git a/server/methods/saveRoomName.coffee b/server/methods/saveRoomName.coffee index 7dba0b2d710..621be3975ec 100644 --- a/server/methods/saveRoomName.coffee +++ b/server/methods/saveRoomName.coffee @@ -12,7 +12,7 @@ Meteor.methods #if room.u._id isnt Meteor.userId() and not hasPermission throw new Meteor.Error 403, 'Not allowed' - if not /^[0-9a-z-_]+$/.test name + if not /^[0-9a-zA-Z-_\u00C0-\u017F]+$/.test name throw new Meteor.Error 'name-invalid' name = _.slugify name diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index 90df44e2ad2..8ed563d6ccc 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -14,7 +14,7 @@ Meteor.methods {image, contentType} = RocketChatFile.dataURIParse dataURI rs = RocketChatFile.bufferToStream new Buffer(image, 'base64') - ws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", contentType + ws = RocketChatFileAvatarInstance.createWriteStream encodeURIComponent("#{user.username}.jpg"), contentType ws.on 'end', Meteor.bindEnvironment -> Meteor.setTimeout -> RocketChat.models.Users.setAvatarOrigin user._id, service diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 90ba65e19b1..4d04853ffab 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -61,7 +61,7 @@ Api.testapiValidateUsers = (users) -> if user.name? if user.email? if user.pass? - if /^[0-9a-z-_]+$/i.test user.name + if /^[0-9a-zA-Z-_\u00C0-\u017F]+$/i.test user.name if /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+\b/i.test user.email continue throw new Meteor.Error 'invalid-user-record', "[restapi] bulk/register -> record #" + i + " is invalid" @@ -125,7 +125,7 @@ Api.testapiValidateRooms = (rooms) -> if room.name? if room.members? if room.members.length > 1 - if /^[0-9a-z-_]+$/i.test room.name + if /^[0-9a-zA-Z-_\u00C0-\u017F]+$/i.test room.name continue throw new Meteor.Error 'invalid-room-record', "[restapi] bulk/createRoom -> record #" + i + " is invalid" return -- GitLab From 0aa955f459240047879ab78865c5b859da21aa69 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Thu, 24 Sep 2015 21:45:27 -0400 Subject: [PATCH 0004/1338] update for app store --- .../default/virtualbox/action_provision | 2 +- .../default/virtualbox/action_set_name | 2 +- .../.vagrant/machines/default/virtualbox/id | 2 +- .../machines/default/virtualbox/index_uuid | 2 +- .../machines/default/virtualbox/private_key | 50 +++++++++---------- .sandstorm/Vagrantfile | 17 ++++++- .sandstorm/global-setup.sh | 3 +- .sandstorm/launcher.sh | 14 +----- .sandstorm/sandstorm-pkgdef.capnp | 4 +- .sandstorm/setup.sh | 2 +- 10 files changed, 50 insertions(+), 48 deletions(-) diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/action_provision b/.sandstorm/.vagrant/machines/default/virtualbox/action_provision index 4f8991f5fe2..6aad4c25eaf 100644 --- a/.sandstorm/.vagrant/machines/default/virtualbox/action_provision +++ b/.sandstorm/.vagrant/machines/default/virtualbox/action_provision @@ -1 +1 @@ -1.5:c17761bf-b2f4-49da-87b9-79a95da91252 \ No newline at end of file +1.5:1345ca5b-3c86-44b9-98c3-6a6f3a6574c6 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name b/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name index 9a8930725a3..991fdfbedb0 100644 --- a/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name +++ b/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name @@ -1 +1 @@ -1440583526 \ No newline at end of file +1443070908 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/id b/.sandstorm/.vagrant/machines/default/virtualbox/id index eb9637c6cf2..fa709b2a089 100644 --- a/.sandstorm/.vagrant/machines/default/virtualbox/id +++ b/.sandstorm/.vagrant/machines/default/virtualbox/id @@ -1 +1 @@ -c17761bf-b2f4-49da-87b9-79a95da91252 \ No newline at end of file +1345ca5b-3c86-44b9-98c3-6a6f3a6574c6 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid b/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid index fb8410bdfa9..df17d5233f0 100644 --- a/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid +++ b/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid @@ -1 +1 @@ -0d8eab53d7a1444288ff01aef6a03573 \ No newline at end of file +7506910154f049b6bfaf858c95fbda9c \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/private_key b/.sandstorm/.vagrant/machines/default/virtualbox/private_key index d30d91db6e7..ef084242f4a 100644 --- a/.sandstorm/.vagrant/machines/default/virtualbox/private_key +++ b/.sandstorm/.vagrant/machines/default/virtualbox/private_key @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/.sandstorm/Vagrantfile b/.sandstorm/Vagrantfile index c8421bb9861..579a4395c10 100644 --- a/.sandstorm/Vagrantfile +++ b/.sandstorm/Vagrantfile @@ -1,6 +1,11 @@ # -*- mode: ruby -*- # vi: set ft=ruby : +# Guess at a reasonable name for the VM based on the folder vagrant-spk is +# run from. The timestamp is there to avoid conflicts if you have multiple +# folders with the same name. +VM_NAME = File.basename(File.dirname(File.dirname(__FILE__))) + "_sandstorm_#{Time.now.utc.to_i}" + # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" @@ -44,6 +49,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| elsif host =~ /linux/ cpus = `nproc`.to_i total_kB_ram = `grep MemTotal /proc/meminfo | awk '{print $2}'`.to_i + elsif host =~ /mingw/ + # powershell may not be available on Windows XP and Vista, so wrap this in a rescue block + begin + cpus = `powershell -Command "(Get-WmiObject Win32_Processor -Property NumberOfLogicalProcessors | Select-Object -Property NumberOfLogicalProcessors | Measure-Object NumberOfLogicalProcessors -Sum).Sum"`.to_i + total_kB_ram = `powershell -Command "Get-CimInstance -class cim_physicalmemory | % $_.Capacity}"`.to_i / 1024 + rescue + end end # Use the same number of CPUs within Vagrant as the system, with 1 # as a default. @@ -54,7 +66,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # RAM entirely (which it basically would if we went much lower than # 512MB) and also allowing it to use up a healthily large amount of # RAM so it can run faster on systems that can afford it. - if cpus.nil? + if cpus.nil? or cpus.zero? cpus = 1 end if total_kB_ram.nil? or total_kB_ram < 2048000 @@ -66,6 +78,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.provider :virtualbox do |vb, override| vb.cpus = cpus vb.memory = assign_ram_mb + vb.name = VM_NAME override.vm.synced_folder "..", "/opt/app" override.vm.synced_folder ENV["HOME"] + "/.sandstorm", "/host-dot-sandstorm" @@ -74,7 +87,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.provider :libvirt do |libvirt, override| libvirt.cpus = cpus libvirt.memory = assign_ram_mb - libvirt.random_hostname = true + libvirt.default_prefix = VM_NAME override.vm.synced_folder "..", "/opt/app", type: "9p", accessmode: "passthrough" override.vm.synced_folder ENV["HOME"] + "/.sandstorm", "/host-dot-sandstorm", type: "9p", accessmode: "passthrough" diff --git a/.sandstorm/global-setup.sh b/.sandstorm/global-setup.sh index 303c9d22c1d..3984f4445d2 100755 --- a/.sandstorm/global-setup.sh +++ b/.sandstorm/global-setup.sh @@ -6,7 +6,8 @@ curl https://install.sandstorm.io/ > /host-dot-sandstorm/caches/install.sh SANDSTORM_CURRENT_VERSION=$(curl -fs "https://install.sandstorm.io/dev?from=0&type=install") SANDSTORM_PACKAGE="sandstorm-$SANDSTORM_CURRENT_VERSION.tar.xz" if [[ ! -f /host-dot-sandstorm/caches/$SANDSTORM_PACKAGE ]] ; then - curl --output "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE" "https://dl.sandstorm.io/$SANDSTORM_PACKAGE" + curl --output "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE.partial" "https://dl.sandstorm.io/$SANDSTORM_PACKAGE" + mv "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE.partial" "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE" fi bash /host-dot-sandstorm/caches/install.sh -d -e "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE" modprobe ip_tables diff --git a/.sandstorm/launcher.sh b/.sandstorm/launcher.sh index 4a7ab020aaa..9f62691ffee 100755 --- a/.sandstorm/launcher.sh +++ b/.sandstorm/launcher.sh @@ -1,16 +1,4 @@ #!/bin/bash set -euo pipefail -echo '** Starting mongo...' -/bin/niscud \ - --fork --port 4002 --dbpath /var --noauth --bind_ip 127.0.0.1 \ - --nohttpinterface --noprealloc --logpath /var/mongo.log & - -# TODO: wait for niscu to be up -echo '** Starting Meteor...' - -export MONGO_URL="mongodb://127.0.0.1:4002/meteor"; -export ROOT_URL="http://127.0.0.1:8000"; -export PORT="8000"; - -node /main.js +exec node /start.js -p 8000 diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 0921cfcd7d5..d00edc85568 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -1,4 +1,4 @@ -@0xdb0b8a1059adf258; +@0xbbbe049af795122e; using Spk = import "/sandstorm/package.capnp"; # This imports: @@ -9,7 +9,7 @@ const pkgdef :Spk.PackageDefinition = ( # The package definition. Note that the spk tool looks specifically for the # "pkgdef" constant. - id = "1yqjjc9yru8e577pm95peu7t32ccf1xf0mepkvxj9ezch9amj82h", + id = "vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0", # Your app ID is actually its public key. The private key was placed in # your keyring. All updates must be signed with the same key. diff --git a/.sandstorm/setup.sh b/.sandstorm/setup.sh index 7f2b3609ddb..49d12a211ea 100755 --- a/.sandstorm/setup.sh +++ b/.sandstorm/setup.sh @@ -3,7 +3,7 @@ set -euo pipefail cd /opt/ -PACKAGE=meteor-spk-0.1.4 +PACKAGE=meteor-spk-0.1.7 PACKAGE_FILENAME="$PACKAGE.tar.xz" CACHE_TARGET="/host-dot-sandstorm/caches/${PACKAGE_FILENAME}" -- GitLab From 154226c06b21b455b39e7678cdcaed9934ee7c7f Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Fri, 25 Sep 2015 19:47:10 -0400 Subject: [PATCH 0005/1338] add market info --- .sandstorm/appGrid.svg | 52 ++++++++++++++++++++++++++++++ .sandstorm/grain.svg | 32 ++++++++++++++++++ .sandstorm/market.svg | 37 +++++++++++++++++++++ .sandstorm/sandstorm-pkgdef.capnp | 32 +++++++++++++++++- .sandstorm/screenshot.png | Bin 0 -> 47452 bytes 5 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 .sandstorm/appGrid.svg create mode 100644 .sandstorm/grain.svg create mode 100644 .sandstorm/market.svg create mode 100644 .sandstorm/screenshot.png diff --git a/.sandstorm/appGrid.svg b/.sandstorm/appGrid.svg new file mode 100644 index 00000000000..ed0ba57a158 --- /dev/null +++ b/.sandstorm/appGrid.svg @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="-241 333 128 128" style="enable-background:new -241 333 128 128;" xml:space="preserve"> +<style type="text/css"> + .st0{opacity:0.6;fill:#D1D1D1;enable-background:new ;} + .st1{clip-path:url(#SVGID_2_);} + .st2{fill:#02273E;} + .st3{fill:#C1272D;} + .st4{fill:#FFFFFF;} + .st5{fill:#CCCCCC;} +</style> +<path class="st0" d="M-120.3,461.2h-110c-4,0-7.3-3.2-7.3-7.3v-110c0-4,3.2-7.3,7.3-7.3h110c4,0,7.3,3.2,7.3,7.3v110 + C-113,457.9-116.2,461.2-120.3,461.2z"/> +<g> + <g> + <defs> + <path id="SVGID_1_" d="M-122.5,457.7h-112.3c-3.4,0-6.1-2.7-6.1-6.1V339.3c0-3.4,2.7-6.1,6.1-6.1h112.3c3.4,0,6.1,2.7,6.1,6.1 + v112.3C-116.4,455-119.1,457.7-122.5,457.7z"/> + </defs> + <clipPath id="SVGID_2_"> + <use xlink:href="#SVGID_1_" style="overflow:visible;"/> + </clipPath> + <g class="st1"> + <rect x="-243.5" y="331.2" class="st2" width="129.9" height="128"/> + </g> + </g> +</g> +<path class="st3" d="M-128.6,392.8c0-5.1-1.5-10.1-4.6-14.7c-2.7-4.1-6.6-7.8-11.4-10.8c-9.3-5.9-21.5-9.2-34.4-9.2 + c-4.3,0-8.5,0.4-12.7,1.1c-2.6-2.4-5.5-4.5-8.7-6.2c-16.9-8.2-30.9-0.2-30.9-0.2s13,10.7,10.9,20.1c-5.8,5.8-9,12.7-9,20 + c0,0,0,0,0,0.1c0,0,0,0,0,0.1c0,7.3,3.2,14.2,9,20c2.1,9.4-10.9,20.1-10.9,20.1s14,8,30.9-0.2c3.2-1.7,6.1-3.8,8.7-6.2 + c4.1,0.7,8.4,1.1,12.7,1.1c12.9,0,25.1-3.3,34.4-9.2c4.8-3.1,8.6-6.7,11.4-10.8c3-4.6,4.6-9.5,4.6-14.7 + C-128.6,392.9-128.6,392.9-128.6,392.8C-128.6,392.8-128.6,392.8-128.6,392.8z"/> +<path class="st4" d="M-178.9,365.4c23.8,0,43.2,12.3,43.2,27.6c0,15.2-19.3,27.6-43.2,27.6c-5.3,0-10.4-0.6-15.1-1.7 + c-4.8,5.7-15.3,13.7-25.5,11.1c3.3-3.6,8.2-9.6,7.2-19.5c-6.1-4.8-9.8-10.8-9.8-17.5C-222,377.7-202.7,365.4-178.9,365.4"/> +<g> + <g> + <circle class="st3" cx="-178.9" cy="393.8" r="5.7"/> + </g> + <g> + <circle class="st3" cx="-158.9" cy="393.8" r="5.7"/> + </g> + <g> + <circle class="st3" cx="-198.8" cy="393.8" r="5.7"/> + </g> +</g> +<g> + <path class="st5" d="M-178.9,416.9c-5.3,0-10.4-0.5-15.1-1.5c-4.2,4.4-12.9,10.3-21.9,10.1c-1.2,1.8-2.5,3.3-3.6,4.5 + c10.2,2.6,20.7-5.4,25.5-11.1c4.7,1.1,9.8,1.7,15.1,1.7c23.6,0,42.9-12.1,43.2-27.2C-136,406.3-155.2,416.9-178.9,416.9z"/> +</g> +</svg> diff --git a/.sandstorm/grain.svg b/.sandstorm/grain.svg new file mode 100644 index 00000000000..31c37372652 --- /dev/null +++ b/.sandstorm/grain.svg @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="-293 385 24 24" style="enable-background:new -293 385 24 24;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#C1272D;} + .st1{fill:#FFFFFF;} + .st2{fill:#CCCCCC;} +</style> +<path class="st0" d="M-269.9,397c0-1.1-0.3-2.2-1-3.2c-0.6-0.9-1.4-1.7-2.5-2.4c-2-1.3-4.7-2-7.6-2c-0.9,0-1.9,0.1-2.8,0.2 + c-0.6-0.5-1.2-1-1.9-1.4c-3.7-1.8-6.8,0-6.8,0s2.9,2.3,2.4,4.4c-1.3,1.3-2,2.8-2,4.4c0,0,0,0,0,0c0,0,0,0,0,0c0,1.6,0.7,3.1,2,4.4 + c0.5,2.1-2.4,4.4-2.4,4.4s3.1,1.8,6.8,0c0.7-0.4,1.4-0.8,1.9-1.4c0.9,0.2,1.8,0.2,2.8,0.2c2.8,0,5.5-0.7,7.6-2 + c1.1-0.7,1.9-1.5,2.5-2.4C-270.2,399.2-269.9,398.1-269.9,397C-269.9,397-269.9,397-269.9,397C-269.9,397-269.9,397-269.9,397z"/> +<path class="st1" d="M-280.9,391c5.2,0,9.5,2.7,9.5,6.1c0,3.3-4.2,6.1-9.5,6.1c-1.2,0-2.3-0.1-3.3-0.4c-1,1.3-3.4,3-5.6,2.4 + c0.7-0.8,1.8-2.1,1.6-4.3c-1.3-1-2.2-2.4-2.2-3.8C-290.4,393.7-286.2,391-280.9,391"/> +<g> + <g> + <circle class="st0" cx="-280.9" cy="397.2" r="1.3"/> + </g> + <g> + <circle class="st0" cx="-276.5" cy="397.2" r="1.3"/> + </g> + <g> + <circle class="st0" cx="-285.3" cy="397.2" r="1.3"/> + </g> +</g> +<g> + <path class="st2" d="M-280.9,402.3c-1.2,0-2.3-0.1-3.3-0.3c-0.9,1-2.8,2.3-4.8,2.2c-0.3,0.4-0.5,0.7-0.8,1c2.2,0.6,4.5-1.2,5.6-2.4 + c1,0.2,2.1,0.4,3.3,0.4c5.2,0,9.4-2.7,9.5-6C-271.5,400-275.7,402.3-280.9,402.3z"/> +</g> +</svg> diff --git a/.sandstorm/market.svg b/.sandstorm/market.svg new file mode 100644 index 00000000000..557c398ab35 --- /dev/null +++ b/.sandstorm/market.svg @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="-230 322 150 150" style="enable-background:new -230 322 150 150;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#02273E;} + .st1{fill:#C1272D;} + .st2{fill:#FFFFFF;} + .st3{fill:#CCCCCC;} +</style> +<g> + <rect x="-230" y="322" class="st0" width="150" height="150"/> +</g> +<path class="st1" d="M-90.2,395.1c0-6.5-2-12.8-5.8-18.6c-3.5-5.2-8.3-9.8-14.4-13.7c-11.8-7.5-27.2-11.7-43.5-11.7 + c-5.4,0-10.8,0.5-16,1.4c-3.2-3-7-5.7-11-7.9c-21.4-10.4-39.1-0.2-39.1-0.2s16.5,13.5,13.8,25.4c-7.4,7.3-11.4,16.1-11.4,25.3 + c0,0,0,0.1,0,0.1c0,0,0,0.1,0,0.1c0,9.2,4,18,11.4,25.3c2.7,11.9-13.8,25.4-13.8,25.4s17.7,10.1,39.1-0.2c4-2.2,7.8-4.9,11-7.9 + c5.2,0.9,10.6,1.4,16,1.4c16.3,0,31.8-4.1,43.5-11.6c6.1-3.9,10.9-8.5,14.4-13.7c3.8-5.8,5.8-12.1,5.8-18.6 + C-90.2,395.3-90.2,395.3-90.2,395.1C-90.2,395.2-90.2,395.2-90.2,395.1z"/> +<path class="st2" d="M-153.9,360.4c30.2,0,54.7,15.6,54.7,34.9c0,19.3-24.5,34.9-54.7,34.9c-6.7,0-13.2-0.8-19.1-2.2 + c-6,7.3-19.3,17.4-32.3,14.1c4.2-4.5,10.4-12.1,9.1-24.7c-7.7-6-12.4-13.7-12.4-22.1C-208.6,376-184.1,360.4-153.9,360.4"/> +<g> + <g> + <circle class="st1" cx="-153.9" cy="396.4" r="7.3"/> + </g> + <g> + <circle class="st1" cx="-128.7" cy="396.4" r="7.3"/> + </g> + <g> + <circle class="st1" cx="-179.2" cy="396.4" r="7.3"/> + </g> +</g> +<g> + <path class="st3" d="M-153.9,425.6c-6.7,0-13.2-0.7-19.1-1.9c-5.3,5.6-16.3,13-27.7,12.8c-1.5,2.3-3.1,4.1-4.5,5.6 + c12.9,3.3,26.2-6.8,32.3-14.1c5.9,1.4,12.4,2.2,19.1,2.2c30,0,54.3-15.4,54.7-34.5C-99.7,412.3-124,425.6-153.9,425.6z"/> +</g> +</svg> diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index d00edc85568..5e409d6a103 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,7 +19,7 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 0, # Increment this for every release. + appVersion = 1, # Increment this for every release. appMarketingVersion = (defaultText = "0.6"), # Human-readable representation of appVersion. Should match the way you @@ -39,6 +39,36 @@ const pkgdef :Spk.PackageDefinition = ( # shut down for inactivity. Here we're using the same command as for # starting a new instance, but you could use different commands for each # case. + + metadata = ( + icons = ( + appGrid = (svg = embed "rocket.chat-128.svg"), + grain = (svg = embed "rocket.chat-24.svg"), + market = (svg = embed "rocket.chat-150.svg"), + ), + + website = "https://rocket.chat", + codeUrl = "https://github.com/RocketChat/Rocket.Chat", + license = (openSource = MIT), + categories = [office, productivity], + + author = ( + contactEmail = "team@rocket.chat", + pgpSignature = embed "pgp-signature", + upstreamAuthor = "Rocket.Chat", + ), + pgpKeyring = embed "pgp-keyring", + + description = (defaultText = embed "README.md"), + shortDescription = (defaultText = "Messaging App"), + + screenshots = [ + (width = 448, height = 343, png = embed "screenshot.png") + ], + + changeLog = (defaultText = embed "CHANGELOG.md"), + ), + ), sourceMap = ( diff --git a/.sandstorm/screenshot.png b/.sandstorm/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..2a1c10943cc35f37c91548c0fa9f9593dfaee0b1 GIT binary patch literal 47452 zcmbsQRa{lw_Xi5ky*J%m(hbrn0<uW~X$hr~?natTNjFl`f`BxNG;A6L1eETSl9KM1 z=Xd_^&AB}{E9V?@<adrS)@Ma&s6EHUqQU|I;3_G~X#s%pa0y+&fIXbTzpVHI00SB- z+Vc1J_fWVkMBD`O%xYR%KvqWfu~z)a@d^02O=OtR#K;B_f3vl<2@%q9a&n4}j$U8e zn3|ftyuMkOn->=s$A9kh_wV0?vZg<OHkOx`=BB3>78fB;^rz>hH#Rr_?(C?mt9zxD zD=8_Rou1E4&l1R5Wn^R+85xCzh3V?*Qc_YZudHnS*?OOnvi@i7sa5Fu>Pk>x;PlLV zc6RpV<z+!Zfsc>RpS3@YgA)|bZ8_N4D=I1&UwW04lx%Hp@9*u4nj`4doqKzGo12@Z zq@)fH58K;X-<Z9rt*N1-rA|sp((+9i8X9VBY@A(~cTM_aXJ;25A1~_=!SUL+v$NCF z!^1DDij0^DSKNRA4`*imU}R*(+RAGD_jpW6lY(2knn$cvR9@7_`s&U>3KiGj+?x9O zdPXKDC=6$Qen!C9-_^x6w4lK>JO@|GjFXvKCop5@TkiM%0e(Kdq~!Mphi9!V9lwrm z6}UJ*eCbZC?1me;z7*g!49*Z17Us#N*cv;0ViO60KrfdUpRq9Tn1-BwDX@zzSX$pc z?CCt~tl8cE$N$n^-Ra$cs^*`}1PeV~+qe=L|Kb@p_v!A|{ZA=B)54GfqU#Jq!!e#) ztrfMAj}4_nS1ezzMugRPn6gunwg)@(Pb@DDjD+hbOn!{cb2QKsr`Q-;st$Czzu(V| z4rM@a9FL9`w~xh`tE#=L@HWyv65w9lJdSp-a#N$RQ<J3=(`rlbO$zc296Ka6le#%P zy!zF$P?s`jZk=VS@oVnSd`1wJ`Fj<of`-j2x0D*a$I`s@`%7B#+4HC9+zN?s;8ol^ z^eJz>=#zopXLhITd~f@~#)?pD&W7B003-_hIdER6WYO~38+(fIs`x93U6qpYhjyE% zH-ijtIrIBqFwUP*^kgyhb>BaKhp7JdnmKbGec<sz_9HtR5g`?|`?H~$I`_)maPTA= zWJ)UlV3Yw@ekT%JY&`wv$NeD^02lo)zlV?tLl>0-wdoWEUe4`>Z}R|SWv&ze-^i8Z zq_w?g|EAQco$wKaE!++(ci0w|P14}{k)i$~Q}m;eN!qgUi8;iR5c%?U9K&4|s1vcx zWL_rsZQPHKkLT%Jp6j#)uEx~|QQAyNiAocnlto9%6Wfo)iehN1Fb##N(H1bIl_+Hu zs#wWERXgTBg{yp6wGQ^Wbte{*{+M5=(JmhP^NGX-{p@>MqCEm(U8oVmqN<@LYEDtj z!MB3U(3o4k(W)S)5LO!!?Fw`#2BWy@cbsJ%HG;C0*rfRdRkuPcuX0N%biS)rH0fHd z7i)ws#A(TQroG+Z#bXy;!nf{;p(&IqFKu(XA69HZ>D?luT(VCOjrP>!D|bTcLWY;W zX3>6+YCY6as4I|oi;~YO%O#bIf)ld7eN|J1ZYSw5m-d!tuDMcddCNlp$uX6H%qsB6 zcyX<gk&ih`vvsA!*C^k2KD&{>T7Rq%vKBYuWM_=KFw>$_STAGL`Aj29-c!4A@eew6 zmaU~34hjA_uc)WpPWsNDjl0)q4Fea(E!5h}TYsqa7~iAMWWHHK6^>bKVO(k<#y#^> zXQrf|SNEoY)%TaT2ne74th(%OCy{r(p=xgHDI;r0nr{~>%(|Y>E^J#>$Gy|G(exmY zlk<>fG?ob*Bn~aIis^MWW#acprBI5*K>HYpkrMWuwf%hJcLbUx<H6keo%p8z$cdQk zue%2Q4@;w2gh?~6ul<--P?KYIT$mFoPq_++M8e*16tjr@c<HUhE-kwmEvP)d%rI!P z;+r`Wt1m8*#PK_b%elrvLC(s0?;tKr=Lr#Ep{%Y-w5u>z)MzM$UfrZ3<z{UyhD~=` zqQzLG102m#;iuI&6&GQqz-_<2fK5QcKyI&JVD!NLPXYR_puX9SOZ$&wTeCNDnfauB zO&O*(HA!FB?J#_Ja-u4z&$~XqB4mi4PE3`-PDj3rm_-TJQdXwm5bMS8+~543swn~l zZiDQE^thC95pGmTFVoYqVh+w{iqq9p%vDoZn>eTV@HWdTHvA@(tF-nuDl?&#xpXX9 z_o_CPf<%psIRmEhg;*qJQx+~dRXl3l!Kp=X-yS}O$CO4DslOCMXWav&HqRRxitIj5 z58!YI2q$NRcTOtv@h5L|S{=z>lAZ<z^b$U3rK7S-$=U2V^Q;8BIswP_i-UxJ&DXo* zW9R8Y>I6z(bW6h>bLd0roL|{%+v$|(7fTb{5P$3n9h1Yy;{R&PL<-NvS?xeW<^O86 zMTPN8L2wPyHa)sn!=sd9m7F%SnweQ|=FcaMX5UOJ%M*%&d-Pe@=hExd(1u&Di*rG{ zaa`OhfgpY?-(7M}oukldg?DVQ<$)jZ4KuqHL#*&mL588Z6ctLi2o@8<q^yKIF}%sX zYy3z8=cN`aPbRF73W1v|duSdEokgz<w)A#4)9RJyc6EX*p?f_THzg<ZsC(0jA|IoC zT~cjge7O^!^L+T~E{T&!O4y?RQP|#=>sPE<C3mLkf~pZdgIEvK%hnoh?dWzB`zim9 zjK@wowS=~n!_$hDk(^`E`LEv-Gue5jKx)2xX<a(tJ@`u!^(^oyZ=kGbo+QcY{-gC( z|J~e-*X(}&*Lo`|nSpxP4Hz?qsaI%;^j#7S9-<$3EB1_^ib^w^RnjOlvE$UfTQPPd zq$FA-o}>!&jM$8goz*;jWNVW%_MXt=bVsM5dCebdc3M%Psd`pl^XEXOJrfY?#(pyx z5hL7DqKuYSOk~d)5cP&P$;!uTFj&<{juNw!p({9~&EWPdzqL{ViBo#X6HOsP{794O zUwPoT2DarJltH(*A1KN*57wqfMCA*ocn^B6Td?t6FZlwf=zl4!@1@8e4LylWp7A^$ z!%mtk-`or$>bu=$eDD+x$7eG{Z#D|nn;kXO2sp;7P#+~6oi;T!G5P!6hZq?u6DYkh zAPtWy6xNQ$>=jISEv{9*UsELY#kro}G1c{kp_YiW_+<L8Yu)587sGhr=fOWqQ>U?5 znnid*Fw^?vzABlkkZe+!V3u6m5#_wI%kI--R49q5ws2C|2rV7!iHxG7PG&hCoW@oY z2^(IzZ)&0StZC%!%eWqUR(-$uwgJCm={9e(dC(|b*3hU<%QAX$e74;1Zthz_<AI|S z>_Llbas|pAaaN-FEBJp^iXR2%B+^OW|6rwC;HSi{lz*Y^qxaH`G7hHn1VR1|)hcVu z^i9r$GUH!^lFwtR$}(rp8uF{Mk&1GUc*@QOqry6x2lbe{M6>E~^4Wfyr+tH{WTEi| za>BfA@nseTW%2LD(OgFP0s7<oat^4*)zZTF=qO1U8%*&^B`W_($3wCt)%M9jwVAH+ zSbi)G!&Y_tvtff7jG&Rc_%XWmC|{Yh<-5trK|-R|UnQm9xzE>6KiQ~OIu@hf2Q>cq z))n*D%nd=#UHMwB9S^p5p`bKJ&p0O7Z6Vk5``BdhE7>O6$sDv=c@!>t+?SAWIJg@8 zbN^f8lq!x;)e4Rvkw$Z?g%B=}))krxaN;?SkeS(mLlH3Mwm!y*A3#?W(c82wo8pIF zf=+I&89TyrC-S5%jG3-YcHoEeEoEJvdj9mOckUk51g}jv<nO)8RL9VlnSun*+iPou z(*(YbAiwIn>9EeLX(T$j<VZ)p`hvf>`N&db&~0kO<D0eX4oix=D}%H7Uf<IOjQWy@ zhTWHb6s3Nr3H#L73R8pshJr&o7-oNKJsl-pM>ADMd82BiuPahv^yLqgV`IhNU(0S$ zr6)D-^^+j%Gb*~$Xrr8oa`^^Y^i#7wZfTKMM9LT;BR@7X3x(^?NKZy23>w;ojkz2w z6Of?2u3kazMg{+18{;O`*fTUzCWAftb5RJF2Wjql6ta!{k<Gt1V!B#opO36yjz+bw ztPR-M`6Ka{-;>H0$LKWIJS%7%_T<c{A5GgqWYZ4>?{EvP{E6K!givRGap@63*s=$1 zk1&P4csn$t${WY4qE2`3c&HI*<$Hw0{EMHPQm{AEFX`|%&Uq#_&}rAph>q^sYNzx3 z^ozvxN!f7q_LZkI&9f{z@d}emr2`T%u$sR?sp9lJv384G01<HYJGbqs>4Vg0!rqle z&|ft)l9E$*eW_8lsH^_5GQGu)`&~b3n2QV1tRI^4Rptk|S*V<9l+EX!mx#x`;^VvQ z5M(0@p)uxglpn(lS87u6J2(0FimQ`y1c{RtVzP1zbs^H+OoRXV8Uw@|krOP4*qlij zfPCwO$Qjtnk#LHk;F#eOuAotDl5g`A1Z`;_xuY18$o*wpovdd~Ir{0{`sItb2tdae z!_tq>NaPx1AhlV?RPc-R*1>Bab5FV>l*U_*4o)OnS$mNtD6=r1NA_nY8qEcVN+Ojv z7s3TU5o&g^Nsgn*v=9#%z4MYNmwL}e|5G9~y5HJU?&EZX@BNAipNKGjIg?FwJYLjQ zK6)n~Ozu!#iiYd{&qBZzZPD5DV~GyY24LR19qQvk^XM8)RL=b;8L~5aKuCCMrp-ZJ z^v6Go@l*_3l@`<=9lh*h4J@k)V$03A7#2PGX@69wfJFq~cmGk&XgN9M!URrDO|CH_ zLQ#atTQV<+){loZ*3UbS`EcN0>ibj+*9rK-2pMH?KC*X5Q{ljX#p|S9Sw>YQMrj%Z zq$kCdo-Bq1UFLHin~m{a3XDTji<|Kgh2hlxbFEP-N7ROn09Y4`k`5uYFmAs8J|ev7 zUm=8|>px8_5B8~XF$zEN@Gm^UNVGm8xV(6Fy9+lZ5thS(Ek`e)o4H%M!zip34sTXm zjenE;3c>t*!y~1i1~HxeEH*WbpBKCH(q|I~*~!W7>_jwV)ld4~_*v>nCQ*`5s*ddF z-NXf6c<~02=FzYr!!Ztky|!b{D%Z|h-(jo#uAJ2zJ+JCvE6+1QMSF)|Bh%UKMKW6S z5+V5D2IE{}C>2u|G_GR;$zl=u5cEXR`VZ)+&y;@4F(wkw>s<J^v)^%|ed}3$G?gTJ zG>0DEB8@2&(Ri~RhsJ4VP?41vkE$)I<8;-a1;`92;r$2bTsMnm9jLEn0DVuBZ4r7{ zdPfNp{KfA)nTwYR&ly#5iOU}$izr){gb-;@C3Zgej)X*|t`L-%xi5-<XO5HrXSHf~ z$>Tv*4uUVnK=)fc-yBe6ya<i`)omHJ63b19oy;oyn-Z?qJm{PYQDk<N-LN?yaFi=z zCcz|jbi+3>V15dVKA+cP_o%7H3b(FBWtT9s9cI*@TZ})MhmW^1jZH)Ix$Q6}sUDGt z5lBDbM$+RiUzMO;W@P>CI$kO#vo4Fhe2-LUFQ>#n5ujfsmH_*t$R?<<*WqVH=BP36 z981ta`KlBA<pxy8q5W3zDfnDIianS(!#CL_CkyjX4KJyC_cF-V*Tkpe^&!@$uEzHs zUqkaC)PiAcyMBJyrs~Ax$><es{|UJqml5|VR&%O1Kt3*ovncN5rh}nUshEhN60`7# z4B5K`)sEs&?Gox7)wf^e+*#%ZghuaegyrlB_js0B=*19y`*YvhWu40_h1KM$iMJN= z6r^C272+}&OaU+<IWdIR0+SXwojWxhgyr<Bg@LuepW^EchSH-WMpT!HDZ9?obUnQW zH(7oTAj(1KgQ26Jq^Nx#1sTHUF%J8AbOZf)cmIT6vWYL?CIJ>2lRMKB=8Do7k(3?5 zdqo(5IF2Y;^syo-Y``^zn!ml{`>d{i?T1pmeg8@-D{mq~fbLipUYhe0>!<(5=^}3; zi=p=(PCU+E+kHB}(}I(Pt8sCRwqvh9$WE*+JHbaYzP~}T=1ayRdZCxwFU-JgvNk87 z?2Ex5^qR~Ua_fvjUv=MWOnxjI!16s+mf`EMC6s(wL%l4>}Jx(>F=Q_A8AJs{4ka zq?cLNQ7EdC5N}!F{YV1_h)&%`(KnC~LwtGOsox!;vnPRiz*~Mq_IoLU5QO{SR{85} zJX`)2d030PEQ-xWiJVT_W*ND`q`u>(>D;H=e)f60SmN3+(E6G`5M=<d>0xxRn`4m> zyF<WXkPE3%kK-3WwB2mq`BYb#yfeBVd?l2+iM52iLEP_>JDjkiah;oN`xM0=lS{Jg zxn#>$TnOwTolttiMOnscO_PKr2#eGwTG9WBYn0axF+j``MZMDB?fy=8&qDtrtO@$Q zxSnUmgg2U$RC8;I_bp|p$e7bUFu*4BGAOK%{OZSR;)PL4*{v-gO@tavdXXdKq&0bL zj|GoLL+z~LkJe1Ocg`>7_?h+5ClDJKYw^*=t#a`vv!SoT4B?-wEC6FQ7bAgoMFylI zB%DS4MN@=6H_a=B!vgWM(lMvk_IO^0!CK?*)6e>6okhtDzKw;L5kFQv@E`B?dWs)} zUe5R%`D2%9<{esGz0n&-NHkG!YR{v=AN!544~R#_`P@l`liyApe;(drCzf?^s+IGx z%<89PS$51fYfeuq*V{x*GJd9<(F7WYc0FX3N=5H!p{wz+*e_I+i^H-9%Gmj4+wr)W z+*eFc7;!p<_MC9W1ZaWRS8szjr;3DZ@-lV3Qh7$rRSj4j5uA!pBNbsstkmA<qa|?O z@_@k;xX2k_@e60BIZhD=Cu{C>xi{O&3N}&C9i!kMpTJrLJZZEL`KB+5<m~JJIl8H8 zG9m>kqh`Wl(~lt?*#ptvY`6<g6g&GA-^m%sF#F75+WTw^SAT#Krns5*lZI^l)`&)H zbf!>Dq8uYB!6}U5d1|KgV~oV)-FRn%$SixVN>M#*z@t<volqwOO@sWZTc$L=GGs=+ zA5h;ktk~N`A1mlsz8n$&28_~WLAU|{!hy`XGu^SM+(2Q-u=6rX!rIjRt#9x$Z+^-H zGenQTao9=x{yw5`n2=B~bOl`u=bu6)eV9B)M7TdGPinU)3uS}-4D>D}n;atK>nk_L z&8-`~Xm&TjkB)aIWfOJH6$P}U0->#%`R>R-j>ZtVuE;W~fovK3<gHWR37z`0?){{s zFV7Xc?p^c?EmsU*VRSRuv6o|Xmvzag#t~FiqPjj|3k%ogBdtI+aO9Cck8@?viRq-y zE7WAr!~Xo6DcZ^PWPdpbHyctxpA=+bU&8u^9Z5=J*IjQ)tVKeKvpI?}h1EnIIZCKS zf&a%YjGl!yvYOCso!RW9GecJWiDY5)zQO|{+*1VAzU`~1?S>POl_j8Gqa>Kqy~yIO zruv2c#)VY7xW%L<2-zX^1*@vc%{B3bmjmUV;&GXNeY=0Qlm7Z*n-}$X*SoX*K6nP2 zN0DIug0~F8!t*czyN}PGKWX~hs;eFMf-G{(G1ff)_<C+*!@2B4_SDU%CD-}?CQ~~R zO|roTUdWN)5nCtQHY7T6_2w@WSiM^oBDrinmcSK5y9#Qm8mx2J{Z^IjvMx@iFO=pu zb5Stq`7wPz+f_iXiS2m4hNKj}gzq7_@O5CpZ|_NI)2>Sdp71libs1yc*LI`Zv@0}K zV>(+hvDWTH5Hk&CLv6f}tINx!oAlYc%#CMW5%}2g3t0!__OsQt|08wczaz@+c5W<= zXUE8zNrW6S8j@R9$qE)BDO{vkvB2>aP)$#jHTq8ZSwA02y0rpVjeDQeozKro<mA*e z=9z^xJ<ujb(GzANZ|TePIv7hkKLRHF1b6taia4NJHIdd)Ow*W=Z&wMXUt4DLLFLp4 zro|h-OI0p5DL>QpwJTQl+CiW_bhyn%t?ozB#KI7t89?(putf#Ux5q$K{r_*4|1Pvd z&-0O>nKJO%CTn7m8lb$PKEyS|Feeqr4bPdmfWpXPGf9-~Nkd51+&XzP(xWA3a^N>8 zk8|*i7MGuII<NEK&;vvZ9|C~=E`vM|UnRXtr_<DnB>q~Q!B1sxNWF9E%9?ds(oLqx zFo51l9Pgfq{;ty3LXkGJqQUaQm@Ofi0AW6n(ssHEC4hn`KfDjTnZ#yDtL$Z-4Xe%Y zFw1aN$KE-&GIbq7Grz$8h5|+Ec+2j3z5g`G@Jom>Y=8$lN@`eod}{Y##cnzK3#|bZ zvdr1)+Vmow!e%$Vr)ZZsA(>sdH2?Vys*;pTUo8s(sOoyOZS<J6!2Y9GtVQx^TeKBF zo#f6)uz-qy1Ll7`yt}i`Ld^*~)XpXkJ4ltfX4Qa+cI#sk{6BB|G+Ub{5Q9&z{2c^D zPLvW|cx0Q>Ld+J;UeE)>aM4_Czg>t)3FwFq$;^BF{etgAoK{ewtM!$|G|~T5fS)(~ z>)wcLmu0duk4#<6jGsxsifcdmGgtX%tp8(gBw>Wv@xb3X>+R-Cg*S{}Bt~ND9Qr<0 zU||5TDA{`C*>Rs{%WbSmd-}zGLW!fhkh1@it=dNzFXHj0)R=0g7!;}Iy=HcQc*LK* z=nLm(^KT`4J!R?R`IK5M;`p*g4zUN((7d8qpim~f=w7_t`{dXQp>7By`XSFc@A>?} zazw7{=ERtmY346XTf=dNQ9?o()I{FH1z70ArLulF;c1omzW=cI=3q>8I_59K8NoFT zjA8usL{T*BvOiBqt?EIbiGyrhO*Z}NOpJ4$<h8D|v%2lwU4g7^be3A?y#pf}y#)HJ zeRYT&2-5+CEhe<N0oSKys~&!gX0*BWTszm}y)O~EnH~3QHy;LXB>^EYBZY^Z_Ra>b z9HKg^qgH-Nw@kk(OSNrUVS(S>smDC^N3xW6($vr9SbAa7m3@UIoS;Cw&3bqLWri73 z_UU$>o#_3lBK7XuBx>-i@cYJu*~J))G3fF$kk26EdnnEnZ4sW-eQ?Ld+R%p#M527a z4C0;y6Zr>M<%Sos^_+~376HX9?wi{|*%(}lkbQPfyTWOoOwWZE>Fs6nYpw3!l{YE@ zP3(O7HR`i_GGUJttypmP-g6-k4klObagf5popSNUFn<e>ZC#*DfiRb8m4TGBQai<v zVvBU5FJQXtxcb5Wc@=cS7%*aBjU9_^KF9mc6z*qIQeOI1CW@<<_uFS9Jsjyq<?Pq( zhWv(KwvIo*E}EUD-C;{ymhR533`X1&eURzLIy#^}E6^ZB@|oA|?ytGK1+bpA`P$$6 z!?3Wcp7vv5-s;Q2BjKsH(8Ti3!!(91FK1szM2I(hLLJcDz4-{^3mr*eZhEZLf>{_g zr{Ac|)PvQ)ZbmnBXv6T01+%LQWAmXkss*Opg8X&7RH(kz0`$4)7iA7p!rY}(F=_Ii zMrx$4cbm{e8ZTa|1vKR8;rg4kF!cPnw&@F&Ve)q$YJ4F1UZPIZ@1J7B-#Z%f$11E@ ztXaYI{*eZWP)Q=Vc4=#4UW3Itr;lOwqJEFqcFeK)a_*m_n#SRa3t(Knb6(rL<&b&S zjh>Up9hH1@-Z;;=9?pz`4I6C{EqF^{N6Hlwv@lX9cryt{$C_{yFZ2AH|7Kvk@J0if z9(M_{4NnV#!XZy~AnUJic`k20%~UtKzzEQmG0rt-E*(Lg1N!n*0ajcU)^0be(>gEh zS$;<__Ed!z8_)ryQ>%GXhb~e_P?bOTYcP#PtX>~*hAEcTN4%JYhKPsJAA@Bz%%a1` z=pi+Hpe+-TX#ToNUUl%FIpw%+bn{r5M+p5QriESBc**$GCM>^>Xqiv6PyN@U;_t$U zkNXx7Sk2D}3MUa~n9Cx<m5Yj{eV6cWcuVeyO9C~IL-rCTkn+S3J*SXB<3&2$(FGC` zpa+@AL>xmd?5GgTnVgCb%N9ahjDCAy#mib2$KeSyn+OS28z<;-eye))3I@aGBS&zR zt3ngo%_=%SL7rHDd8ned(&qqm?dZ=ZK=k>j#VsFbB-j~7HLdfBC|*hG2mW_-j}U?~ z(J4%b>H}<eM9*Yy1he!j>amvqy{S^5xc6*Z<mstJN6KMqW9497?6Jwz&a)hRB+FbT z%JL2;I-evI3CTsJ@Bb{eF9Jjts7usfe3_0o@b?pL?2>c{&X+zfU5+%34JPfqJ;3C@ zo)ir@$#y#+!E|Ll$$T*FdTtD&N~!X;+pUT8>*YcxzC!a~pKsi|%}#GQvxttNQoVV| z%2Tt1gjX<aUDPf72b)~XJO6}^T1&RG&7<XqCHVI~Sk_FT`G&-lZC-#J@%_&*v3Jo@ zU}!%&{2!)ko>YJRRU71jM}dg9c!7>YmME;3@Rp+HZ{w%ye}nZSXSbT-p|e?4GYW>~ z=<mG+G7nD*4OQCCIpDU9=~Z=T$UdcSUOmQZ^Uj7P9~_*?0QH5|)0P<=SR(h)t`FPP zww<{b3Se9KyHVXr{2}hM@4~=8uw0b_keZ_9x--H&VI}072!62;bRT~(nH<*hCafoK z=@BS{yZGf2$Y#SZuu&LKQmaa`*YvKrrSdT2IE`7-`20KAcbiqX-Tg`V5Sgd6=4?SC z7jgo+&8yBg6KLkDjl|#yU7eY;Bo5rY6uPcPu{&u>h7hW1+<F7XvHPf0mm$k7YEa~q z@!qnGw})%z{dY;Ut!)_Mn@4zJQ7g*=9oQb~MzKkIFaZi9QIv1L+TKA!phpV&nn5VX z={i#Iq>yqE&*erQ{s`uxXR?8QqZrOXx|oh8bYJLWXJT1g!_FypRId)ddSw#85iqbX zy6T7Q3JH!>E`Eu><J-^Murp`Q#AKXgDRvVMe!w(R9|Bb9#qFu&WSF}97j(NQ%a!j@ z;!sQ(3`Pg>{a*1L3q!BCvsZnJGtEwO-xxlS39DxPTf&A{4Zf>D&)f2SVo`ymu7m<7 zct!zc8iYp_IYoFZ`eq+K108+!rGFVCsEUK2K^mpk3;8!2s)m=aLg_K+FhKp|Z@F}+ z@=XG`@V-QG(#pbPaVUx5VBu4=eAo*aqA(p)!trs>FDVR1sRh&y2|0ga>YN7CcAtia z*k`pnp$A{MYDmBGATTon{w&1UHhj|x=!SEj<bOM^3<HCBrGW0fauixFOeF$cQn|)Y z`~9TJe5G!qKUKb_kkxZFOmIFSyC0E0_3eFuOin~G(~%CdFOCi_(JoEOw0+E4EFjGN z>`vO~cqdE7ROunWKht-)s@P2jtJJGl5#UM9(q70fiFkBJ`el7$sYm&q@PC5}mtSe0 zFK83o$!v{FFYtw6{S0LM#GI^TDVHkof4rE2Ax6jTJ=l1=u(I9vX&bl#6HCFm677B0 z|HDU*eMHdj5=*OnyA<VE9JJ6ec6CKsrhMC3sT$@70MH>Q(9iy2GJ->3j7IUu@&f<e zzfCzMo7@ua;SvNR=-LTkKTTNTni6x`5DXndn80v&QL}TM66%F<H<zy4@CW~=+7Jw6 z$KP3g2vnK?iL~ZeQGPmm?!n0y%~1n?VI^0DWfTfVg)zYY>(o8Zu;X3bcCPG4r%`{l zD{*hVbG_hR3HyAud*r#-EQyM!3V7DeV>Cqwno-~YgBU>QRUUFoJ_rHm`v36YZ};Nm z*G4;eh+%b0k`op~sufdZInVr0c)oc92aa4~uuQD1m0$*AI2UKDJVwFyH`Fru!LKcn zZr6!X>ONR*K0e*DiFGgJ{gjolec5?Da%xBIy}8+>*Om+vLC-w}5x_)T(8)sSAq4m4 ziXan}&-+95!VD^(`_%C!c|843G9oxDq+;<C!Ii7k?@iL@1lE|C^r67GYpWkGUjp&u zg(A4dUfyOzJ&$9G{1S?i$N<YQDO!ma3wa`_2wq=-MINn8Efe5sl?dRViPBWT2-4#t z4IS`$<Z?v{(@+Ply3APc<I-*!`Eu`a8ro8O<4(R;lRI~<crnj%qR}pd#Wgl1;LrgJ zFeFqedgk-5WL$v$hjKFDjE_Kh5zzmxtm+tX`r{Zab(dg~XsFUDJnz*_&rxl}-O#%5 zciT>5YiV6b#e6m8vTb|(M8WfSk^hppfcW&`Y@Ijn-`zyCCjp1Soo_ubQ4aOXDAZsm z5Ak`0!ik?#(2?NeX&S*0gl9nv_%e*BW5r7x5bUJip*DxlJp1uC@OmVj#Yyk}7@<>P z0J4fGHUQ5<T2P?0Z8!=D-BCaAeD(zHHK`7Zr&pG#1I?$tG$KM=cN5tAdf)Niwoe2! zgzy5~Km3sC+rXvc?p+_lJA4ALY<%;4p6v%L(k*cjJzsisj$lNi;J`!38e>Btkxr3& z!HxBOBdEB(zQ*EeeX5%$g^fpmTwd)EEG~H$Dey37*<?KKow+yayM@meuaSP%2#Zrk zKByD)Vw^3n9v>`VDhB7$uqywYx&lLKRlD3YX{^<0d&BzD>G@MAqo+pDt=6*@VD0t@ zVA5BUnErV;DhrddRU(87?TULkuiDg9)HmzXJ%##1aB>0-L7&T$isR;q>bajjUm<na z;8lt7Y{~J_MJRutv-{g`A9t|Ng-Ol`Rg)A9V~fj5x#alweGRh**Z0x|jx|3DJZ4WO zr>?=6Bybz49wOp<B6px}kR;mj_$<#bjFRL-BYk|Q49Qo~zV*m%R06}D&~l&N4w{R_ z_6QvUglO$5^f2R)^vgyo)y->{M6j4#wY^)CnrJMkzA#jcUz0OE$6rx6o!ZDvrmt+M z$h9oMMOm9DUjbbe_``;BPKaJ6XY^(y9F=|O;}_YIp;~5=_<?)P<$%w5!@qmcF_$-% zr6Ib`yZC-_U$DWb2%3u*)|<zYiIfU2$PhHB>Q&I18N7-L=qslK6=?ojh#CW+e{o`t z-ng~0V)5(FzNBc2h@5Y>Z9#<y$&Phsh`L;p!*xy$p3;P(z@bl)fYp7axHDheDN2O^ zHhuIfrpj=<X$MgzW{?WjIS{$oiQg@V;5X;m4`G^*Ly2S%Jwf|Txr05#3YeNrOPHr5 z(-2W82qJ{U17#Gl85HEV?WBjmW+O)yh#sTa3&lSK@4$AjWzXyo1uiCF0X|qrD@?^q zl$yu}Iz_;YNWn0D9GX|%C`;MmM}c7Z^&(FF)cz>ufhO<={(B<7Zo*!^jZIbpWXTZ; z$`3F>eW?VWkI2iJ5Sjt(1VwMhy(5*!Dmz}7+I|EHbZ}L21kLgDijWh??gB+;*6oo* zXt^MsrU6vtk`FT7(tWMv`#kCvqh=X{2)+pQ9&{!^9yypJ!ej$lXHUl$I4&5;7@r_j z=jYy`60iU~B9Q*W@~;Fx&Z#gpGvF@E48EfZLD5JA#)r7A-99ryut`4*aLd*o{6z)Z z1+F~DQ-DJM77~W4>;+lo8AioKptv|dDn!WlME9i-&nbL=$b<AUsNxdsLb-c15yA}t z4yy-NZ2v>UeljFUZ_vZmlC2GnQ1Y{(80xIqbIgDUnS{!xaFq7}GRZ~?=Yp`8fmps% z{6AFx5x0OeYF<n68h0u5UZg@JSpW+u+?3tN{blff2Cf2qTSp7j-q`rQ$`A*(hnGm3 zmsVlcs{bic8a#n`ul%!!(?WEi(tq4zhp=k{FAY-*0t9htrl$1+GNZVtKycg~!E!el zH!yYG4mC!T!Gsq;5t5550vO2o>}7#*^oL;@t>BOwL7L9%?lIqml1L)(KuZ~9ctDnw zV^qx_d>|3TKeY3wP(TTAW+R3RIYnygLuwF}y@Z(gPartLxz&071A)(pkl+-o&tvmR zW`a~3=HNOk`Wsxw^1Eadjch;_O;6z%yp+%!m=-0+3Xw3m81kAk>!_2SjRWV}(8$DO zoZ9e($0|Sz{uSm+I=V<Jn2Ms20iHUlCeBT*wnIw;10h4i2B3T!r|Vp-3Y*-J->6u- zyQ%j(D*d?&YV6BIz=st`sxg}!ECXd%05sh;4Rd!=-Ajhs`ppg6q6TTWuI7}@JcqJn zpY2;C0`%&sZayI!oiq6kW*5>dJy<KJ>O@!sFimsDwSqFugjL33+DoZuEgbyqAd013 zJVh@t;Bj}UTjz=(90R^3L?@difUg)-_IaH2>A6Xj_ANH=*ZnFTX?qU6y|jiFdV3w6 zMG}fMPEikOJ_CHc;m@7{6YXn*O01AZrH0+Ntz*YwCMQP2F7*U&O(3PcSV*2q;9Hxd z@e29iqLH9yRy1MQxxFc{_4X61Ot5a-n~FdtinqdjRpm5C`^~IaK>=m8vjHg)vXOQV z3t@1Mr<HqlI(YB$UAF1}N<iIY02pV9Gx4sndA~ld$d=$^6xIp|JzxyN()%4hzCJU8 z5e1+n&f&*Oie$25)Xa`&()0BV@$#jYXL+B4NBd6A3;O{dUsvirKK(otfg18klvPw? z&><3<lEv55LUtkG775TeWW(Z)N??;0p)wZ)$6=GGFTx&|64z8f6W_2XWYi`CEJAq4 zl7lE|@onkJEzVM+Tn5&viO5j(=PbHWnfe0uAD%fAb}A?k2P}F`jq%4O0LrVZ8jNn{ zPYa3F6eB}E;dDzWUy;o-1a_}c33QX*Y!)YjXaaZ%&Dc@bdVzkhmaNUZEVYTAr3olR zp_HPBLNVys5uR<s(+Br-5C=<OmcB%9fR<<kyriL~KWU*gYV<%%qT>SpOc9`Bz+2mN zXq}zuXsey<3+Y&W8-8bItm+Kzdlc~&ZecH9RdKv!^`t$VMg0IBYu_Fp-s!d`hW|1` zG<019zQID2{QatY2SH91pbTcs2oKI4Io|OR!5MN86$=&o#kfsv%a2xeKF#jj@d)Tt z>*KOsKnXISqW80_ErL|s;#>sPL%QWY&i*2h{7s<Yc2DhRGtl2V;gWryeMb!x*06|x zHupvf;%5Yv+eIid;szB&s_Kwb)Agukk2~25Ya%WW_%?f~LJ?<Erk%2-w>((V!SufM z(zG}tSQ^U{_b5<r1qK>Ems+Yn(i`LwC|kepo~zwFdAkpd<Y_J@L0lHVF{hM3F9tGZ zP2Z8Yo?twX2MA_#bE<UJ^Vt&=4)aBLBIlOLQw8tb{m4!CjfW<Wu&)Pwy;gpj%Rla* zTD+a>_`QgVq+sH4h761$);<bg!LhOa;>#o|J*byHa=K1|dnBl?0n+ip?-7Byi{U=h zrEp|_+L8qMX?g8AT!9(*(p(IzL56e<t8NZQ0@om=ozcFHKw)P;;r{bnXvkSKIfD2m zqrL?2ye7i?57zz?2LE{&EHdXTNB_v^)a?=R=*+WL?RI_$OIn!Hf9M#Xf`p_qN!_(= zW*}a8Obnj3fRCk8`5sWdS496q-W$!}rkjiHgn;L$`?cUBfB<Em4xFMox&O8`ra*G~ za|Psi$Ns$$;C_{YO$bjlE43s>MzXm7M?U)?Jvi{jyzM?cScR;HT@H+Sdc78aaJ?2F z`;Wa4XV|mNU-$QOyt}s@xD>sao~5AT>)zOBtwgX6L#3~^z#)35B62$IXEmt%&0Cv( zqcMf=F$!8sdTUV7VE+9oZ6?FpD;CkFgo*E#QS*|rK7xa(7l|k7T^$shcn`<FlZ|;D zRK+WG?B6FOynim{P+2=da&_Cf-j;sO1d)*TG(Fd!$z-yM|MnS=`tBodg!TR``?5bD zcL8u9rC{R*fp=XZ7N`jSU`|x3hb;<D1%<0$jlA8v`@nkKXpM#ng-fp-FP5S<U443v zV#qt0_R6jZcuT!vf637I(6sKNEB`IfKH<-5=_w8=Eqs43@*s9%JXoITU{-*Zv;4Mz zeRa)%g9~-)_WrGqH7F#usY-tuZo&?*qp%s+z};8h-DmDH52`Gp2NF1Z(*@_}YtB4a z2)`0VOjGKs_7;X$lEP5f^LOfR{8E4&6q0X$mPRFQpbQo~4Zv*q2=l|H^os<s`j->2 z_K7a&kK>S3``H8oMK%FnFYa$^vUnV4oCP&S@J3U$2*uPj0s>q7uS_Z81eR=&*2lG$ zH`b`BL70%QGNSEqxa3=wuKunTINrq{VnGk100{>~=wh-<O73Bbg&c5>&lUU~!EGu4 z`G%870v8?kRFk8TU?zU4kR;6@kW36>b>B2=L2E8euyb}YP!gko@&5MY;x;z@zm=Si zYv;-+6X)+)1!2<;GY^#jrxtX%<<~d%*SJpnQVI=BOy=cqUL^=SZc<4P6gfyI^KUl^ zXmQ|O>F%!M#d$*`vrySHpV56NR^GTx{!Dc9R=Z4SWQf#38@Mq23YVrb{4SAOS9$Z1 zd?liE;8pos7EUl1O#w+I0MA|+zazt3CX5NSYQHi02W>RyAXx5ocV}`y6AW@2j5={y zis<jYa;$nQtS=ni&EwX88qx3Pt>s)Hm93OLpbCrc4)_|*wr`)-nNu>+ALC24g8hz6 z2+f+A3ia=83mbhhFJ6}DSKs~7NEXE9Y;VhipwyBI$zAUN_u-S5^07wOgP|1@&?|rI z$f?czHAC4_;hUrY?{598Qkr%jkEj0jYo{HbD#0Q2Ddz=;P42%uf7ekpP4WA}iG#tQ zKT=<Br}R7AGTG8VtLFzlIzg#bCo{gR1wN91Zy7!Wflen0^sC8suA|2(4Si9%5&!ZA zTY_)4Oa2~EMxqe7o8<4f3l2yvU&dN}$=rlhzjN8dlI~#}Ud@;KdSyQ`x}$OTQj&Y~ zY1Um37E<~x;N`^m$2*8vRhN+b)hj(RapQ)wJQHxKe)?Od-Lv?QfI1GuP=;-!H>l-C zd<siiLNd8mIshVpjRq;WDKTME;k|-|Wul`H1eqX3S*&=Pk`8VnUWU`3K`vMGbKpSZ zPOv)H|I$C{RvbYArI2CU4>FPrJS9}!k2!jmjwSsU^S@Q+oW=FpK|bx)mw%fF=q`|& zHo&uR?Q~P|T?ORslCI%7RhJ#GondaT=J%DIotEgDOu&Xs{2i&0sK`lZhRiR9+m-z# z%0*uob-?DC=<p?>Uq4x|H1CaDUirVgrd#gw%SI@I5)qDh`1qP;T0+RQ@g}10I<if^ z>Ir))WVrfA(7tQa$a7M#9(0m_UQ!mo_(j82gBfH(kPvg}3ugt`zH(mGzbFUkYls6A z!bdt%mdRhPj~;>m7S;C<{b_Y-zzlpKIJTC&t~L*VhnhbxrkQa1Wc->qGYkbhWCl;) z8fM=uc^s%)kPrb3c-CN3$FKg|me&4{8<KLL7$6r=`pA3I|MeCgKKOk7gxl{*eSbsb z7F{JAcd8LiC7q<{WfPXF5O!No{GlR8rO(2Bf75q{y5(fF3r{i?wJ73QxCBBXLgI_O zLgF}AQK#~6e-m$lu$y+wt7likd{_V#VL^e4fWif0p>PO2r2-@$B;tGo8bI-#CSV85 z-TNHiPx1F(!BBV|SD)J`O3%neQgR2;!!WLxFVrXdJ=GTq5c>7bmTtGvH_NISjHrl2 z?Wi_tj|;;6-jjE=Nx1es8G>!Kq=CH|+u7Um7Hwq#1voLAzq16306{XIYkFuF78iDD zH1XEE_$fwo2W&&GW|ubd-Ol5m2u-cj$5?=&jNq-94V^;Mkmh@Ci9wU@M6s(&$?<7t zip$oxLE6+^{4Sdl!4dvs4)EgWhM<A{l$vOE0iHTp68`0nESJtNzvx`~ge$|&Uk;P@ zwN*Lx6NH~eqZ?iP%Z>4N@;NbBwEMv(+9zl~uQcdmY0NgrI2q*_{Aax6GIDs9gqA-R zQWA*J5%UQ#u-l=(*n7Nne8gN<tJ`^RV<b1T_*|m})4>xe>rqTI)S4K-?586waCg(` z_YXh0DD-M_6()vvH!yiL^7}k%*89r^vh~s$i`V_T0=A}xc<}L@YS>u)!8L|^BQE`F zS8YY0SZSzK;T9?q<zk2n6yn5=thkMk^8x{Lk&7PhuMnI4t}nmgVWjA$FDr-o#r5g3 zZ5|C`!L5PNTrh*0j%x7cE2Gfrat6wvyBd&vXL)er^@y#I@2=A>6?^uHu&mO1UGZ3k zZ#p`kNyVX*Y>f4f%6k}tQ5aa7puWVN@+>^dsIM@Oh_1o>AxbNyU`lo)EB8Hf8qZ0K z4b9s>LvMdl-miWw_nfs+*{!=r2ZvUCKm45!=95>{I#YwV{SMD77J_nqU42q{Yx~2Y zwFgZ5JlRV3KL4IFGT{i1Oh`zO5@Q9e=Y+WjbU|l#<!B&p`NP_p^F2PucutOY<%*HL z=^N_#X;h!A`J5@Akc~S(X*d1F5c)@v*fh;-$W#f^29MfktxkAns6Z!%Cf^47k#JNc zIk){x?WrrSveow_G-PQcl}7X5SVT%>!zQU;Fg|@tJRYJI66TsWZwoBKbHfKe+FnEF zf(MefY;X~e_HLmrtFuZ;y>)&CD%A4nB44Y*3lu|J(tZ}FL{NBhIXT4-Ua-mg4+_2S zj=!GDNfMC6EvP?I7t<tp_#w@&)g$)KGrJPvLJ;vG>9Q*>uJ$n|lFW7clsyXH?B;{e zX=;h<3do;z^!Uw@HD&W>GpDavV|>2ut6I`Y>D%4ilU0<h-rZC6XoE}34|04vKQ2!H z`7<>YOt=Mm`q^G<kb5lGY4}*Hkrw#2(=1H0pT42Py9$om94P>YWL<fIby5Lw`(W`J z(&2wTC~86hBrYkJ0<rxs^U#s+Px>mze!M{Hchbfnd^D&IW#N50*WO8Fji!LiQKg7F z!iwhrYplx-+9+!(5W0)k^5K!an0#L~5bebMfNS|;_!#!5d%!&SpljvM?meC<um2$3 z8td{xOmy3e#pmic*4x6mX}%neZfw{>;Y%B2%h5;Ce)+)x46wXjjp(oCU*DC<tseNe zjdjXh1XDNx)5VbLK0$1oFYrb)3AMJA;iJlnu4c=u9|c2i`{#-6xMC;oIM||Pz*g~Z z$DTBgmWomEsxC}H&3`3xWsNdbzdA+lz1OHE(^}r5Av#y-7c}rWN3*B@F$2G9@0%tb z65+Q7v(G-D{>}2We$$jx_tR`r{l?(3iIuSUO=qj7k8z_|B`d1P-hu<&P6+>NvL73$ z8%<T4nTLjSMdY_Gqk2Jq*Jj*L7w>k?mynk?ZQQ^(;NEC?CZd`Ww4SZGOI(xX-RnV? zM^aDX@g^JkjmZg68O_YUC*(5|$Nu87ARJAq=LT|Um0~7cRSASG(<y&B<|+0auKDZ4 zrFs0vFUp3A@@Y$bge@HKwr;)fFg$DJkVCTN9}4>Mx1QCbAX3z7cc3)EG9dW*z7Xhp zyk~|d3b3qxBOliftxy5(T<M3h6W$~sMs>_~Q`W?@!66mS9rM0e<{QChrEnCQ^dmha z_it^yh)sCTscY5W)bp8CVtIbBb&B?w(20o$O8=G=7^m;KNnT;l6WhEu7Uv(wj|+k# zy`kQJSSHj46NYZPQ+cJs3;$@@it`ZojknAJM1vFU#`7rf$77>a_tTs&3w+PW`9XnL zh8(GSB@(KVvLfMvxgS51pSz5nCoIhby-PUFLtoUy$JALep6IVGiwF-qtADmA6<ApP z>FwG1#1gLYLeT46>Z^3X7xR9H2N5`SCOP!F(E?9*O=9FVgvCDiJC^$*pz@ak`3awB zAoS{E>#vE1R;dm;_W+X<%qn!`jgQc2?YdI#+uPGt*GI~ZbV#$MmE+-RhLJUq$6gSC z3amDK44g}vh85P;V2BMMH^;S8#6;DI@nZ=RIoKfoE8I^Ny!x;Vb2kzQpfOVPb6_Ci ztk|^$qpmD>|I;C_=${#RRKUs>{f2DS_Q%3A_QD)8L_k>7V`%E`9u(2~H1y|>YOt*0 zrDi5q|I*HeXyXbG<jZKfmwgQ#&q{A=!3L>xEHa=pTaRjcsww}>=^MVMG-{PfqZz}7 z?T(no8jiTHCO&$=+UBP7U5NF8#A_*P?I6L3otP`T`0einJMW*KCmY@e9W%j~4Wf3p z2RAr@e?z&@E9ZJy*SHV}#_vH+AT&NKQrg);VPZU0!XpAO3dT46xQ-bIWja0K&XT-a z(EK(vKQ8wOz3)cA=3hy`v&rA*1g~J4%_;IG>U~`TF)}?uqmJpIrsCU##jQ{aF(_-g zs`kK9-)Txh12lST>7UA|JMckt-D`}fieN@sr^On!dGdf!#b|s{gqCwc>*prv@k%Hl zHxhAxN7<DKsX9WD-yT5D(KbDoB-HW13!?Ey4;8-AIw_BZi%|U^tZ6U*2zwbQ=ac38 z^gAOiwf4y>E#B37x%Gv@!ez%lliy2Fcnn>|!Rc(U6woa<FqimaTK4G4>aet(9w6X< zWP@$`%Tg`Q$C?zFQgHFnG{c00Uf=ziOBmM1G!2CNaV0U(9{}Wg{2B}erj?u|altIl zle-_og}8yrFuhYE@N$X9%m&vLA2`gc;Bs+UvKMtg|IhOAOXxtJ0ZiW&#SReV>rN9- z(M}GYVt`ykvf?*mOSwBta7HidX!c6EUQjB77?l1`)Xhz#oYn!3%DX)*@Z*LPl;(<- za|?sgwyy!N<X9gQyGcLDdWH@U?L}fkk^7$iPVbHe-AwM)VflSTC5o_RcG9fB68P%Y z0XClA<j9)9aVlPdI*C@57l67>Nrb?0VVzQA^OzINO31Lk#%Mg%&5+9|N>}Uppkeok z#`^m=X93Y|0r9n_ON+?u#aUx<@y6sANFvcjOc421r#S_c^-k65dx^_Jci^%!I@u4a zpXN5<Dm%<icey3L1!9Bjqo+b3%i-5ZE1`m|Lciq=-q*(hsvD(%{wXB?mKd;OafdNF zIx+d~|2i^M?U9@*NU}?gD|u;}kR#S6Na@tZ6EdrXv6i<FZjfahWRErXzRq9SI+sE; zz9nUqSK9hGjkN1)9H>-$o0Bqh-8xmxWbfbvoSShs6F$!DrER-=vPPr9gP6JQ0w?V1 zFGnP4=WxZY8i1+O{(X!(_Pqgsb6vOyk8|h3Io_x!@Y($<yK7dQ;e;^?|Kx@slJb<X z5yNiuX{Aup?;qfA(ei7T9j1FMT9<9n6<#L&D4jQ_T?@_tx^~jc_I}ydi$sXEVwHK& z==S0*6(~smw6En1Cw0)k%P#WY=;zb7tvU)lC2O~GA_Y%7U%<e8WGX5H-#RMIOMe(h zO0?yCjtc%k5&z2rpkUtgQSIbL83zWR>ZVW~i}#ZD5mKjVDYb^G$<TX#?7?H4TgtL6 zH40~Kb1n>j;{4|`hUU1+GhCK2ET=zv?8YblQCr>il-zg$4YBIeZ~EK><BO+f1w32G zjWC`yr%=wiDr<%eexn`8eFQyk!ri_U>Q4>LJUl!L3~sg}SMlS!RBCI%XB8EioLuOC zfBf9{LT`B|?0NM**laKG(fQ*q9L>*o*7VXpxoLYM&j;?+<cQ>%W6moawaW_%9j1bY zt0sTSJ*UgPHfW%HUCxuU7gmDVa=DjV9sl<8-e;B3o|^B`w{!AzkVAUl($KY06BogY ziU>03C8Z6~-3ygt^)}T4$TnXTBn%Dy0*!&T-HM;qava<Lywm93<pwri{v1e{0*M_> z-gH{XAqL|4ZNllp@!?5O#lsQ0tatWvpDm6HXN@-zliWk|yS7l{_7f7cI(}smB3L9{ zC{cJRh6ORCe9ZWQbghlN&8BrW=C1!bSMV5*rlm%9&a<GkqlhM>(;YA6r!(cZ09vaM zGe`}{z<h^_gqpHakO8b^bgk2WI{2L~xfra2hxkKm*YEm=Eehyb#7Fb=yUm}NptQ=^ z)BL+}EP0B=LC0PuMOl{Aws$5?4DNKH&3t*EPtj6so3UJ&=~nlVlj?*iCAfW=fVTVc zBw;!D&OShJ;r!;i?CSsyv>}%opr8q8LsnX`=#8koHG6dfLx9A)W1UbbR)qGKgUghN zSS~(Ufv3<X+qdHzjY7e9D3A)r>Pbep0SBTF&y;W8usAzC3YP_E+P){-^vRE8;#zmX zwrMGGpP%vAv6jbzGJwRKE%|V(FpJwtuV)v~cR=P!WI!qp8;4$975wSYLJBm0Na{!K z$NwK?Zvhl#)P{kcUAh}dN$D=77f?!4>6S(TNoiO>K)ORZr9)DrmK15FQ@RC7Y3};} z|DAhh?wz@F=i8ax{Z72+jq{#*zvt7;VAnM=`{g9%n_Mg;$Gp@(64?;(62_U|-)_>C zWm4CDwVr2YqNKh3)PUr7&mXK-l3>1U&s&!<b&PkiiuKD(BYltV_r9SKivAQFFv)C` z1ztr=ju5I(@%%~jsLv4D*&abFY|qvDM$XLd_t!-^d1}hclCntQQJ)K#C1m7;1=5L0 zW}U(7WJd^_F~0tfm>1r)4-`EtHgSzH;R5$;J~8qRpB9`0{g9$e|0dM^M6E=9#bARy zmrT==?$N@E=R3U|2`%N13g6rqE5mWQGhez~yiUYh4xi@5!1I;Dxp+8Y1jU>%Bw+%$ z_QAF7%7&x}g$<%YFcIVXOckd~{E@mTo<>Thd+UR1h3~EcJWkbEp1#@0)?keiBXFON zVL3uHzGj-)C>OdsWs7q(%<6==!e{JUlOz=iRwI!uyY2dK%Zg5^hBy!R{|V0!D1Yge zBb{RP|GxFFSy8wL8q|R5-U5xF)moH|h_DoF5kO2C4KPnp`P!9a<gn>8I~_LrXAeS# zvGt&Q&OY^TA9>m_1J>vGu`TBJY+eUXa0xXz4-NsFVeCP9;_nC0TsP4xH>n~qyFjJk zOMLjx&Ha5*DzY%AZ)oQ@TjOsYj^oC@0DQDf>X6D0s4y%Ka|!G{CdgQL63KT4y56|Q zFA<*0WP>s|kw41Sn^FUVTL$M3dVeD=tgigvGMo@G>+si6qC=VH1rQ)%wtF%!DNOqg z2ch^C4W{pcH%@kK^Jr8b%2uwO3XqZ_f;|gh0LrN(Zl{~O31ZK64=0GQ5K0+!bz8Pt zG+ne0W_UBztG!eNRcs)6NC~-MEfa92rgdE@0yjn<Xh|)QIC;I1+duj0)gE62)D!<v zb`CKE1H5j&vPXuKutb4i>M?R>XstgE8h7ONJF0Fmqw51lDoB5YB>#WPNbRmux0VN@ zL7eTXS>#ePac6+E_^^J=yk9;!z)6Z2PLo=@m8t2BiM058C#kkg{$V~Yo~=c^Ytpd@ zBWQ`O%l|}V32Ei%P7U^tsp7q8%HPWiK8d@(LC_IGXAJ&c_cr=BESr{i`2A~)ZCbLY ziI-cWPq{#T87sh^VS;F+&^+|$z0*9-ya~=x)(vL&;&tqu(IkHOQzLa1uMMib;U`fl zHTO?{d+0aA3(;b#x`))R(w=2ofXyK$AIDCM|GhX*jp>sdlan-Sy_fG8z3MD;pa$_# zLvm~@_}>a@q?{F{ib*aj0pDKi5rQ*0c#4<r(E>Sa`v!4^Pp|dl+J!<AYtnEAr-rQU zG@3yU8$?8uYQvG8v!*)P2O0<Qd6k8_ybe~Kb@%BWjeeKD=&X6IrUdDykW%g<5jssO z-CPBfy+dit|5TdP^{KX6WP3LxJ*WveV@(oKm~|E6z+Z{M*?%xnJl*<<vTAkKvk<A( zgm^E|_FlYA{*~WxoTnP=u_0ucX2{H>j;7w9>^L4knc;Pj8<p<tKtk{049!f_#i8R- zEqSIk^+Ok6_czkA)$`_A<B~z#c|Z#;cFUe?KN-Gaf&YoY+ZA6cb(;{Kr#|c}Ri^3L zzCEo1NCla!ZP2oPK_h(a_viXh6a2(KJ7{~0%K*6%66<@{P}&>FpaBq3Y$k&;x4NSt zgS?FZKbzzQAP7qhIoWo{>_GLsZax!Ax##^;j027xDn$vRI9FmQHCt1HLmLf#M4}ji zi;EYSX1A^Lm8MxCyI~lM+n2X`cMkM-TZkd%wPu=$4yTS9%3dCg0GLGIyD<&=`afG; zP>!yS8hC8qC;T`x1fN`TFk{&CU)D$uh8$xE73>ec6d}R4FCrh%5Gn%MgEH#m1&hT; zH%X&Vvoty$j9!9Ei!1gVWI-eR0jL>;8mc*j4;KfHyuk&?f#8oCpa+IfyP;+fK9c|3 zSNU&3=l@5-nl^Z=?%Tm~UkZ-3x8+c|YCDW%?xM<%J*2RP*wz|o+*AYu?kyl(A=e(x z-;@P5zY=J*-5Wph{H!_hqtZ5*s{5A;ilDM5H^yRwcdPovY42klTz0tVblsW=eKXAs z%FZf1L@W3gE1>drqvV2Xk)&y^Hu-$L!$=MuPzJx~`x@CjpFmVLt}*FNI2}(T&Pum_ z={0bkZbf*`<fq@#!pKikBWJz1-=<#R7~NjH^N^mr%W*`3`3Hx7GVzOCoGcsv8JlTc z-lnwi)7HE*!<WWvlL_J0PSNe$W0{3Mq^+Y<ETi(o*tbVg|8q{GE1iw==RdY>8GmOL zd^TMkQIni}tN0tvTM`eH=}xQ|;I(Itn~|6LaOL@ag$go$rp~wiUrjJlf|VggjU#`M zqxW;!qm<=y*K!|^oo?F5A5&P41XYf7JbsmtJP$jk(f%|!o3TME%KT6@UZhiQFp=$v zOWw=Rm5l{xrTci}qWZ`y*BR6*r)Mj1dbRY>p_=|(n_s-ux>n!F6%snzWr~02&EdCR ze=4W^y$~;b!h}jS3U!zYCWtb>t4U3lGD%4|9E|t!jfZ7KhqacO(y*NYuI)Tuw2Hwf zh3E#wUpsatydbjQY(=aP+-~n2{j+WPCRD=lqh4X#68S!jpqg?U7iF@Taf8>xCPaeR zaR5E_A8RI(7bvWY1mSxJ0`K0_I6Bapt6nI1c-_kVtvt+gZ@Y8bcz!df{9dXay81l$ z^937U6nLktt#0V+hGRAf`o(*%PDQggPMMT{9CU`h6voVYXM|~Hiqln*P)r;Ebfu-- z|Gu=5#)ALT8FLC}cc_>g_igMhHhztTy7Kda@D1;0B+Kau$pufK8shYEB-yKpiWeUm zJ)Nim<f97pxq}pn;rqFcuf5+d+32e@R|n>1#anGZDXU+6ZQ^^A+F|=_hz$m%(8K3I ztC{@Tt%Bh7m_fOkAeQ}eomveI++tmD*8c1M_`%KJFvGj6e7ZMKoIrxGJ5x1q)cAGc zGg~uSje}YiRO7RhanXePv}R<oG7nzAc-yQVN(<{te+<~8yXAv##RvYodp_)7cQUnN zJyAK@;40BPf0kI4BUPT{`8%=->gdd}@r&0DbJwWLrx!D_WoaXgdCQG$s3nC0`;?ag zGj6pnUxzQ*XlH#o1dP^r0U3wFEPYM7Z})Y~jEHp6qOqCbfg8CmK&2y8u9G)~AM-|x z1C<cbUZb(R`sd)_U^kaOJM1P;!;h#1g?v;t^6ZEWn@S!K3SIeOj4AERiIDAe5F!jz zhZ#~HY$n(};zToJE&`dv0Un|(?tlN10HlFgS-kD|09CZ<xXT{SPD+s{VIpcvQIb)G z{2*_?j)f|Q$W$;Z8Y%!mHn`_!2kTY%{|4_v*KerA2(B0odI;&6iiiysT&E`r>AU~a z;L)(H8Pu`Go?l#$i$ai(F*rDw5hAO#z(&so=o&*z<Vh@!AZAY>u;yKF1FatST-xp( z>^WGm`E4q6yM(qTe5JtH-2`))g$oTSYF<>>;w>}0sL>Eil*f`f>(Im*T-Av=s@d4S zcw;B@xe~Jto0f)xH6yZo@-14NHsh1>P5TaVm>sp5!O~WL`r5Ba;<i!B2017w`p{nS zOc8jKPqU+$Rexv+P(UF@AY3%q;XPN+79SY+%0eW#u9UzRi_Tc){EUm*y65b0g!k#r z>>)LdBKXytnUKDu_riwW%Kqv3yjF#}<h|P~I8jU`S)I<M2L_e0zEQPsQLT>ViPq}9 zESOkShn8?0t|^_xhraVZi&v<7Y4U<|;-|DtRiF4kl_WcNGz)oV85P(M*|Jb@py4J9 zsBR-fRJa%|O(oR3V=YIg$Ep;_#1)-pG*i3JdFAY6Bu7gQCq(@SFUF;Z)C+dTd<yp< z&LgXwoPu8lAP2QKq9v_c9S7vH(+|#?SRZ6CD1eLyXFVIKLHBk?>%Tj>4_XlFxOZFI z$DRw2n>4V@Uzy(g67DjtHAl-aRh%8L)s^O0KCncCc~17oIR3sf)Z%5E(pG8DeF!LN z$wB?kh#&jUH9db3k^Up5w1|!>JzU!MKi&4xTvCnhyq4n_=6q<`Vk;rg8vi7<VQ&nD zr+-?u4|*}9bv_w-BK50SThaoHKJBGyW)`YOuhNUxH0J3BwYsE&&4Q=*VW@mxXtc2D zm!-cbU!?NpS6T%elEe1D+!A6hO1l???d8E%`L4b{nA?x}P7AP>Td-0}dwv;LsQcah zl43`ZktSjH*;z=H8<YFHA}pqrkJmQTAhfmN{Y|W0B=@pIW&ZA4oLS+o1UrL#mFgON z{sIWr@~;7z&p4z3-0v-w*c#Czwk{|F>fU__4ltO%)}Ysrrb`ruE8Tp9eb%C;u&x0m zG!w>T6g5;q?cQqQJyUaGqu38Z_%8upICLyV2mT5j2R<Ov5f*k3c69L^B(j50XRKu# z62%4HsKGPj2+l%9j8K2XC(qr*1*{V;9qgsb4Ql|!f0miZRVEJnl^);%q5l@2|BsuO z8Et~r&SW3*`2?FX4IC{JyTls!LZ--N$t^jf^HuperOo0Q_1ac%*F2&>Hf8AUUzy=} zZ21z#l7#Ktd_XyZ0YZTMAQACUk)av@0s{ySdVmQ$qeu`K8@bZdnBW5WQ(+@FN6<Hx ziVqXOg`u827`LQlVQ;VLArO$Gua945AMo3ATE|$rpO50&T7zf4-Tn%3?y@pPayA*$ zlEH~HdUY(pt3lRUm(Ub+!Y!$TBx9qK63j8U^<+_aYht9bqvOr@p-0cgDJTa6^9_}> z$VDofjR(3eDGtS*pG`f|)NZU*b5UAfwT1)uXazS$1I><;G+j(Ht~q5=Us08y<fw)l zN3@-qK}Sk5b`Tu@SxL8P(TfcewXcCeS}sj_+$cy!h6Y?TbkWPc(_p*W782HPZpR0f z3VQPbM#*RlYkd3=7K`SFOez6=$C9?}lg%$#|1C7<qA`tHsCckb_Pmf#s98ebN&#T8 z3r4@9c+K6Y;r0Ng67dx98qGcl17HS~b5JG+&1qE+XEPp|G+3Iy&Hy+#9p1NqvSZ>S zlXk8c>;7jrNTJW08H;Y$fhZo9@+#rxLi>oMC96PgYsk6-UlKoe23*&jQ@)^X^;4DV z>x8~Wg%NrrG#g^TWy}VW=4n1+=%QrTS?Tq?dC(dXMf;ew4KtVe;~q}@i1J8fioItA zD^gM1HSIK~mAFakCs$PIf4%fy%XK>~p(Z6->3{C^3w2q{dmc*7fggkv=#8mpiFn)_ zs5?799kU`TU$HkPj92hL_kQ!;K>*SihNqFosw@mxte~I~4;A?KVJ+|RT{$TI%(!pj zNB-a3LxVj%L^r%@Ab<e)gCH0{29^KMuzb;>NS%HA_x}$CCV+y6DF3X?;y+e~`_JlP zFT0m0ca^b&UkUx@Ezd}QBcEHYM3_sYN?*D^;y^AJN^N4+^WpohSE*lB7P(l)9!Hhg z&qKuvE>_acKtK;P`2HC%_CGqX&YN5y|9y!N6C@3d_R18!o_U<EevS?Uxt6tSxqH<{ zkV5wp@=h2sT}7TosP10B)Y`DH!839csS~!3txvX>?ptq-7qf&3Y_8*Q+6<d+{Fe-Q z8&frb;gzfDFW#P+#gd(rJ`823ECB1@WSZ`_a;q$QeNBZEKgoZr66E}`Q+Kd0D+7G4 zTn$GfX0}Hr_kUh|uz~)g=tv`UD&5QH=Tt^D;&mVPH4g13Nj%+?!%cd4(%r&T9r3AN z_Jb;sXa)fApIOr+^<GVz<-94IEB_cZ<C-UHYZGel6jFF<V}t?m<W?MtI6r~}5aB}L z3E!iF1?EucDH2nyDtwq;aDKQ*^?yQ(7WXqJ33b^3n+e+jX%7YQBpA0m@F_oM|2tmb zRetf!D*~#xGs+B{zY-Um^&qLnC?ctb+}V(VN#((*`Bac*YSln-M2g_NrJT|Pb#&|7 zhR8ne^i*Iim+Ms8$`@rhSbKBdWVC);ZGhLE@L#^^BhTEn+VnL{fRH{P$!*YNi|E3z zj_<|&G;IH30Ev9ZBuAg`{4y#okN-m;>9NjaWyb#T{R7vWQJX!?;PH^*xND*nink*p zu@snp8FyM}>gVp2d}OT3rhNP-_hctUZ>JQ(Om0g*O~Q>xuZkX8L->ZC{csg6L1rsq zE?6Qp$kElb5w85D;rie!3v$I|Bp6_d?;Y;Jh4iFOfdLqI(yt(V)Bjlp8S!($W3lKF z-!PY;-M&&>@BmW85=ITN>{AefgFM7?K9tF(4&^Uc6QP!4bc}08C(2)?z<wO1O}Ga7 zt@)W#n%`~|UBOS<rLd+ZEFa=pq{`EqhjDk+fKW1+9m<cOu0fI-)xcmclx3d}R1cnt zg!SkROlV-@%tTvJKn!CyRp=73^c#<}#*E*d?Y@()fJn43ffHifZYYHTAi*FmCP!4u znL@_c<D<+}WIWM~wT&<H?X9?h_AerkPwF|;$;SonMAL|3_;{}Y)$4dFi53StHk-_g zii;lSF4BFAbe!byvO{bzLMjhIjv=@_@GOFG<0&X+W)3anNn?-klpQwXNM0J1MoO-3 za+_htzuJv|5g}&hJ<TY{5v-VIljI<xl?fbiD5bbl1$vG_zj(2N4?Y4Y$qmTLs}3<i zSNOknte`pFtq}o5-L{92A<)B?_GFj|Vbpl}Xumf3P_69wv<Di(6d>!YfzIqhW{Au& zh;4pi(mOT!p*qdL`*Y%bQTRv8%D=OHMDQ5SrlZwvOiXy7!p8qeLjySD>m4w~U4a`i zDo8FLazRJ}aiSS#;990BYwoYfL(3IZBQgtV`IL?J=ii{{K>Yz)<3`216Sw*>ggOEJ zqcs~#JwFXm^aQbi#&h~!c{yZ&7;n|1R=S4*6ueCrbbp`KR+I01d_nEfc}Sh`{NPyx z{ap?8JWMMWWFL?(AM0LU{Dh=S&u4uqKm)CNX{b&&P`v~H!^|A_Dzl@@=PiEz2E$qH zmtTnCCgQrk>qaOQVRR4C;7Q2xDgfc`a71Sma50TSvm$*N_f6s@1Q$B};!iKEU#d<9 zFuu^NFHo4Ze6>e{M+$03)6fW&N|TbzSz~KGW1uj?Yd&n4l5;<SsP9}j5Wx9`PlyKJ zmt=upvOgj6k7wIS*=DwVD{<8KH}ceabN9S>J}u@tu>swdN&Q<JNg8IYn{Ont7IA(| z#LI{W#2QLxq-NY$VpL;pH*zX1UvGE5Msi_)J<371mBQ_PA7Wxb5y_XONeY5yJ}3c! z{CJi3T1N5&BzsC4%2y1mL3nQ0g7Cv*9c5j-G4wZ`^3tc?-C=>aXmENRa}Jbb=yHhG zQ}(oyM>589bjkc0i+8QRx4g3X1115U-c!jj)ZvyIXIEJbfN9Re0%3cGqp#`dD2as) z#gu%23QPSxn*SKru#)dI6+%y}m5#aNyA%{ngbidWdfag63)P7k@Nwc1@702)&|o^h zM~O&K$C~+a8aN<5a%!Lz4Mxbxj|Jys$K2}K+JGZ-q2|u#6p9lpT&u8xoqF*%JzRy1 z(HPN61pjF-A^bVXBkjUM(v9~2<<%OZY@xJ;cs}dX!+puTT`Tlg6WP*7ED+Bm91S=} z3C=`9uJ+@an;QFoloqVwuMq6W_c-KQD1U@Mp9?D(VlHc+OnBY@oW)Y`Zn%ugSz6*A zz45^3Nk6-+HoTFI4Y+e3pY88mykbbl7)demcO6QrR?7+46HKf2*~3}f96fmKV^g2; zmFWFSd>Pqec0!NjAX_)CmfprP#m_bI9D_2C-qkQ_$O!1Bog+_5D>+Q^s~7d>JDlkY z9nwE(ne)VSj~onj)GZzEXD71NotmNoOvGdOXh)FGy>8Gd!DLx$4*TKA(Y*RE-}}MQ z4*wL7Cp)GB7aqV2%ZlK_lU>1bXxn(mlX2z^gWuYxruvg1-gFy#XxY5E+S}SOhTUjS z-^AS%`O~tUv;9v-w<OFa-cP6CCW0j`wj}#!Hy>_N1!!_SeEqnH77lGc=mh*uIq$#+ z_Pb5L%MShTj|S=5#V0N9k=uL{jk7}mC}6zL6bj!UIdhCfp(mqi!vXS~jI789?wuZ0 z-wS~K4I~4MYnSq1D9R#y+5fRzy&T9qjzu{kgC7D`pZx$q@Ta!omVOC>peC@U5{4$) zPBEmbg=1FMQ;}#oDG*H8nY*Ud{lRxU<3DS;QJj0a$oHiTjCp;<xfPL4oR?|YcR=q_ zvu))7V_4ndJt*>_@_*3Qk$W?M2SxpnmcyRb+3}GFwvc1Xot#pP=C;T9L*vm^1jW(` zIj7NIiFKY_p|9AthA+_DvY7F;Y$Lpw!Jmc>t7aFmHTD`w+)std{J&kBSnm^#<tJ0z z7@D$5q8sJ&s{Ce6kIpmkk^7T=xx~8(L)i6Kt*bqU@dG)nd}6V_agdFty?c8v!7|5o zQd?i6hG}<XI3w>uNgR1p5<ZvRtKand?7BltdER|ivZb?=_)S{!oI-YMGT0!gPD~T5 z7l(~Yp5MO&3;lUje*tiC{9<mN5dVUUF1#XcW^8VbFg`P(Xs^;YIJ}56o1@8&vZ@n5 z=EUra96uU(@v1p=`vuj`?AQIpnu5!q0ZxPt7ppwM5q5@ESGKH)R05=iyg66Tr1m(< z)_nG>s(UofqRSZ;`<w01Jqk$3NQi?a$~)10j+lprN~P=B`3m-98S*J_!qKBA6p2XD zemV>?ycEk&6=LCbHNX$HeMRAVsFuT3V02g@=f>R<=fnGjd#^ylP*)&;%SM3oas4y~ zN1o%#cB5{_bfr{NwA9vgD#>NNv{-Cw4rIep4k@T^@S&2y8||cDr-HpLjqSKA8vC=4 z?RWi#!ht@Q>}P`S^j}*-9xhT2kSkYC7-DG>RZbMPbn!so`dMt?PWrqFjM3nxb#gYd zRElB%bopR&3s^VWqpxy!m)xK88lXV><Xt3N4d>tJHBDXLfi=`ieR2@za9jbAp4P5e z(1pTY&VSuuTsqjr_v-EMy}>C^7X~#gGJ8W6Z;ZD2-}b7D%ATV85o3d1q+tPgu&w@x z%=U&*bCtqFFKvJzVgGoN%zkU+@RnknmO$&Xt>AjR*k?ZmpNS@V4-B~KEq0BTtJpS5 zvc@-o-IK3xOM~mI2jchzr74Ev2?TO8?MpoU{C@Ul3JITfmC`J^<oDw|=CB-ipQFlU zr^z5a8W=yYNi7^ci4UZzKoN`Sv@LfF8sIAz1X9Ex#bI9N=#GU5#C3=qWD-ZF1pZK^ zeG#eyfXA@&guYr}=Z%U%XoiJ2#4fblG7_=MGa8d8(;Dgl?aXC4BMBjRzMd+bmG zDayf#g0Fq69NgaurSQTPe?gGU!g}{@deGav#&6;UnkY)`&C#5_gb&m|Y>RA1>JvS$ zPbeG>v8cPEA$Rcr6#KW-2(8!G|2l<d>MN5k1r6(LqtekTQT|w<AMTQW?6a3R@X3NW zxvi#qg_|{^)u}+X*@shti+x_X(JMF8yig#%MCnZPH8N_a=+m%-5-~p~fPc+`{5jGE zq0QcQRA?Y#s{I+07lZly+lCK#l^7tm!C`xC;CE8m)|0%ItL`m;d3qDR<PL_`<A&v1 zsQ`U7KyGyX5Cj^<hnO8zpYcKY{T5KfH4iocfGPRoEAr;a_79ccE%cyf%v;KT(LP_Q zDJ*Hbm_pzlW5odge$_hF=i<aveSAYZ+r6y|mh&=8ZkDbJe};d0x*bAm;wdAx9zsnv zu=s0$Cnd?@Q=#V%IXu90_Q<Mo4LETn`x!w&ofyh;H)I(nx}<sywMLUOzWFK1;{rEx zvKFGs$Fr`W!g12-i_7EG8{aQ4opE#6eDT5baL)Ga4QfqQZ#hy&PS7!y;bZQsO|V@l znzuhCGzF=#Z^wlz1z-RlMf))v;KT>adh+HN5%aWE5C8UIAy{Wv?QF!G*A&IE;cZeH z`WP@j6S+H2<7|+9>K$4DV4|9rZD&eWHznV+&b#o#nlk^>^EM8ieoNT=u*#w~@AVE! z!N$UDv}?f%SN$CT;VVDET3$msck&~>Llj__lomKcd{(5M%^>k2bgJ}XZhz3>%w&El z>pV^S;NzF+Ahy`V=IDkhT@VK;>Lc-3Kr2UqS6GkY`1Q2lLO?$!gs&LKLL*yuxcV$A zyC?kx(KM1TK9ca%ekeF0*RE<8{yL|q<8JXuUiKf0X3X;;xb=;iS#O(uh_%Nn5tSFc zwcC4<r|2GL6#Gs3sW|XttZdx!r&}+ZP(`|A$IQqP`9{@Q8e{c^U|gC@dXxbyuwO~g zWT&4v_J*o=VFUWFvz0HLVSoH7QqB4f>2O$v9p7ea(gGYC>ZT}lHeryPPnLdQwd&VG zLk18PBjCalj7@|`kwXA!grd4jg~xG+AGTaMC*$Ke2)&6sqv7EKia)uy&ugW{6c#{; z7eeEGQ-NeWH%p0shu*{t0^%@039rt;<IRhVsBKM5*3vf>C~)$4d!%t^zt?V_8&>>+ z3%X<0$CyR7(ZEE1G|76^N1oH(gWruIZfDPk2J4wRNk+KCSF?<c-9<kmHy3m!y3Q94 zk^W_Re4|99nkdpQsg(VJtikVKT#jRZ^du56V@T&{5qG6s9iAEgFvUcL)XUYQQuY(g zrdUnkfS5kB$dMrMd`GJPMz$0JmoUit{vb%06tLO2m)+xC+<$KJ<8)FPwSQXkz(DoH zt8N-jJ=#|C<U@M&8apAyk;u8GSJ?0o=PTiA=SSlYlD;M1SlBI#x_Mbk%59uH=H2U3 zI4pTrQZZT})t;AkTlC{Y)YhGSY$btr-qBcOYk{}a(!kudnUZSkx#}CUiS~rlx?a}n zXxKfI_#_>=GSii~$l+Ma%p8?^>Q^N?v*^$Kl77jDX1IWBXJ?iYuwuhYpWTO}eQe+V zsi2p8eUE}n{Nx(`NK#T9W%((@sj;rj%m!p4e@M@WTWFUCvf+xm5=P2A<Bu{=Cnc(^ z;0k(a57YcWIAd0$EW%)y(#F6`*hM~A$>kf{D&w8Q5WDtK$=bb#ELmGWE$6w&_2@^z zrrB7Zw+AatwcsKWT%3G9G*mbFRa5(w`Ia1HzQ1|!2%rCy7xG7Zt&+eQ7csD#a7qGH z*7%}^n_`y9W);?buNoZb3l!?PKt;tJ1ek66-0Ui#0DKx3dYkcTcZ-dI3T1-9zlmb^ z<Y3dcS#;~}qIb}T9Oyjwln5xUh`MFot_}Wxe!T9S5rrUT=m4liv8BI#3DQnBHZ!kV zGM=P6Ld@J>iJ`$i(;17YjSHPd3vk3vQ=`J%(8RElFi+20lx^ORC`atOs*OGOidwpQ z**;j6Syl0aw8d{&TK7x(w0=C{Wb``wUsTPx0LQvuWl{$$jxrAiVU*>UpP8e({J#yR z<<2D>GD`HX*}2#&RT)sK82AlH9ggAw*Y<@>*MJj~yZgIdiHyeDD@tT=-ohsZyzyfu z7;Pk93iuNG2wTgCY&%MWU19Mse7W2@<jtFQtVaDtEFGg<{rBOi#0iJ8(#kUKk-Nz` zHe@od+*2>K7tvnL5&ir$pIc4_sw7QWqk~MP{z4*e--k&(ypx!*9QkY&?+`5ft1?K{ z%kiHq`ZBL?G2Z_E1uA&di@_Ly{eJOhx&{9vGK_~`gw`RE*q;hu4aI`8+Qo5U6RN0B z7`#pJ_ef2vC0cu^F`LyF<5&sNldg<lTHw27ob6%|6!!Z?N-9qgCP6}_(OeG{;*@-~ zpC+VS$DKIIwZ3iQ;c|U7Q~P1vr&UNo^f4H^Jbt^iU@GltgH(o>STf#BEGF>S#h4?= zmHJ3(27$*wjZ^E8^tZB%-?`gTz#2Lt2JsAwao1VQo()>^j~$Eh#Ro)q39K<EksaZ} zNe#(qO?<O4^@rIktOlBFxs?hKwcLcHm<J?m7H)gnNYWG<Z;?p#E3JTUYp^57wF%UG zmB@l3_-aaXgolCIQxvmss6#!*bNP~8RL2@M4=8bVB)txxCp2EOLWg^oVR&6i;0ggK zA|mbkaM{(@-fI{Xp@0KVc25;UO)30=jHP7SiLe-Cgm$$y4Dd+_BAIk?9l719^JvPJ z@?<XVsjT3UX9d7Q`iC9O+t_YqPP0KyJh%m^Eu&=MQUcKcrm{qF6}87$A5W1qDy)kn z#gWZ{6l~IKDn52Xg=wwbMm&}>%}dp-SomrJsbP*z2Z-*XLASvUtpD0ohx=A%c?%}; z_^YY*D@7JA2JKb+*D7(ImE3xsr|y*?w*dB|g?y6r)J>jkR{ZH7$<kds!{q$AKifW_ zKIS6n#Z+H1+l9_M3r%nOYXMZ74nW^OS9UC>EY9nkpLN4Lo@=yMsM*zu7qkgmuf{?p zFu0y%%`?0c{%26$Ba1YqNV<GTx>=$A6rt^Oul(sgwcb2Ifhh!X@UC|9GfjNQN9YJw z7li&OSvPi8?LdJg9SI@upQTjp8NEY^FyUgO5wJlAz3nX@phC1&W(_Koi`M2!RA}d| z6%5LOHEeGtS6YTY7hwT$TuZC7u$A0`r-)NwntJEdG<90EvQ{!v#~Px7!L|sDtnsI% zIH-?Hk%6ST$%qL?D;F7^-9^31QS+zO@bVGMIgG13P4P~L(-rIIdOx3YBi+pi6}~cP z-@NOYXE~~xskPk<Nw>=%(1^tyo1{%M5PC<A&S1U1-Bg*{{`wbz0gw3plRpp64`$F| zgc13+NePgOtnW)i3y4L$qO7>IxK>whwzs*LbpD3;1~Go(hvi(R4S*|=2qZLsD2_Ki z?$a?iyJCx7W)S*WJz(-HC>!O38<z|ue8gl1sQ*x1(vXK1ov28N7Zw18{eyQ2!h!?B ze^@VOQ2PISmgQH6_9hvaU3^uG%=M^b?2M7v3?&U1@klI?y*z9KWHd}*|5SCvj?6Tp ziSlF5I5T<%LY4k!Gm`7sajtKlOKp=wznc=e^xv-t)`@2r&+qolrSD2?kBA=*aeO#@ zYh$fThYzam^|B$$i_E9P`zt7g41llwo7lRB8J&AS!>?bHd4V@RMRF*r`)&BqU;Lr) z8KZZOBR@Pc-XBz?I(JUqAN%j|*0_0U3CV)Ao97^nh8CzCpa7P?WFRq2-cTIHj3>U| znj}0;{Q8Z$)XEA;=VX8zhF_DlbktB^FbW(6!GI4wA@TKG$Hr|#Z({ubJhz-~;mQzI zVQW3`f9cOZquO_vZ|P)Plhlvm$~YuyT;jMKa|uF(9VA0|j}re%1EAJD`dl4#bK&xt z{C&LdY9trmOZ7A_f7+4tRAeo16tikSNbT%6Cl=fFgaPymo{U9j;@cHsUze1RaD&Ed zR_We{y%12mvQ_lOOx&aW4vG<9MDI*gt0EclNDmXQ?%^`{cg?s0=FK42@Z!%;&)v*p zhMcH_48Vu1dR3UJ;i$N?TMe2Ml|K~7Y%Wl?o+uHnzJ-AK3BfP#Q~uisy7fisI4FpO z@9T*~QbGk$tyuDK0X~TaE>{~J31KsyG%|m)>-pKr>@+7T7@9~-_j-8FgAb4wybS{; zLT#j!X21ZPsDi{G%OVittM@pJsViHL7R*IGur1V=mM#fN0kGZ`Z4_FdhWxMGFK7?( zR$q3Xxq^<l`ghzw%Ah%xyrbtVV1XsqIS~0Mp#K~v7;Jut*?x6usY4HHR3$~h6XezU zCI`Tl?xQ>H_Gkn#tU_}em9}pmzg^17bkBfyT^|nH-+V{>A$gZa3Q}B)!P@8r1sV`M zTL*t|;aBNAlRpkPfl%ebAf*(+907PQ3ewK!Xh;w5YhBmn=v^}@g9H*ac6%?eIYBDc z_Ke||_e)+~xYDJ@Y-sR}1$In5F0+Tg?4$Rc948!)g?Rk^Wp|~sf*>>CNGP1<CfE4U zPj$0UHGes3i*Y$xmFuW>f(=jF74%ML$}7_`D>=X=E}N}+`1E@xG&#BkN1z*+tqkN} zT&xQ1g_3_#6m%byK8t!ScFOg>=TtBt4ZZ0Tp>zw`IX+yuer^BVvChkk{=`74AhmBp zZpVbRUncxBPk8|_$>67_Zy^@C=8+p4$1HhJJdZljNa#+9)VjThl39`p&d=t4B+ytc zG*`X6_4C(uHJ@^==sOOvazzFNLCR7g-m$eu<|#FD7ht(g$n);`Q%zJ=rB_aI9DxWN zu`&DcmBuU&)C3h|hzKe?UI+wE<lYQ^x8zko|A{G-u*0B1L`s;1BW21Hj&JvYP0aSa zDN`c<#}_PhiDkUgdyfXoY=9A2>45?22bGA`Rqc*|yQ+XCn&x9QiHN|H`~c-Bdc8~; zu873J@rRJH_`<TfUkSF{9z|-Z91Io8m*KWn=8U|RucAr}nWmM$N$!{e_&m+TJ8ZY~ z_vpr033cLX-Rj3nIieos=vkZT0+zS2xIjcl=~hIM!Ep5WOgp`Ajh0NRy*YfhX<Wl1 z(P+omjkJ4D4&?GEz2j=D2`Z^dv{t>RvVD$RZ;oy=*kkM#y`azC{tYwKr3qxVAgxpY zry4(d8Q(#zJ2G|r42Yj)s8M5Lr)da9X^s9V{hsuSbPylRT!&hY*w}u#0YJDkkjbtZ zczW!127eqB)P1{zmlsBr^AX$F=OGKg4D0qtb)Llsd1K;7>C<GecCpVSfVmePR!mwM z&u^R0((roGw!WL?Rvgqk_fI7@>G>5i<k1m84C>DxUvFA0qJ#Q5I@7oGvfhT^)B(`1 z(E??(fDTf0<O{3v*c+5`aM|7f7#spLVE%Y*5u9;*-o4k9FdhdA%A{KT7PKS@7qlGZ zU=wUY1U>r(BUV)A0D$*F03p)}6ZnJD^x6c%$J<`;JL&>1l-g@oanAdT5x|iF>$S9? z%XUi=nmhH{U98fvxM;np3KX`Y!42vsK7T{be;K#u67Lwm4JFp+@q&|;`y6z5Q9BYn zY3A`&w3H5X9ty^`|EdD}WwlWdSE8rD?{QiC@PiH}M*B}8FlH};e7tEP#r@--Ku40@ zcX08~0)OzqgwU?m@TowFr@;Xs&I?I{;Uv^wgc`G83>$3{9UiZ8iwT0Wc)X#oi=mG- z4J2P=(l?$79-<>I6`5=Ip@_+H-I0f9?P&eFkCOQ3=pbWdPv4M&AJ|ov6^4~Msz7D? zO|TLTFvNYT(0u2C0(VD;<B7{uM;}c_pPk{kHKHM27X(Unv!rV?OQ67Xn3WvG?BK<% zRk>x-iL6p6uu`qET+^<lT!#(k1{9ZK6FMmHY<=K7Jky)?yvPN!!Z97+Qb0(t=tT$w z4D7fKpu)tGcakURAfWNI<}EVxp8bd)M=D|SNOj`w*rf*#z7-i6`OO%7xw{xz+gSl) zWhsSI<iIVC6(H!$l4Ft)P#loFZAOfN=={k85Gf!7g)yx-@V3vh1A>3!hBLNZ9Zb{V zgPyDR+^>lJx$21$L31OBu-vdJb;N)uz1`D11RBDXX)1Y-Xusa_+HT<D`FidqJ_8e+ zKVjnubMFk{Dr()Q+yGv0(#Hg3S1muF6FFxKO^<}$etY<#DWDAv)3igB1}M5KGy%}Y zg9dBLZ)pNw*kX`!#87U5z;d{O5tzv>zFt2r7lg~NH9_ddKjkYFXiC0zI4XF=3bunx ztMv>6#1UDhk7hYRJ!v3Zze4Ee&~FLoJM`S2^^_Et@1CI4Kw#=PeD=1#wuP!~K<wKE zJ<Myl__bBEpKbI!aO`;$aCu_+r`8LdPf(N#e0^cZ30`YvIYL;(ynFHBWfSfytKf;o z93Bu6!Kel_$xE>4@j?8z5E1%!=r!UXmmkMCB}pU&3SiV_iGpxzB~}X;S}$?FxB7{# z{umlOV*}dy(vzGe2E112rP<0cN7`i7s6+G$kX%_Ei!UJV6O*TDZi4nx27Rqb7bF|x zQt~NsB|b-vX>M|K)pW*RxE{`vgS(7TCLF<4=&A?KH<qmcYM_0bPS@a&b@oFJCa}=Z z$Cs-`27TYjj1NaCTFit9&6N9M0KMR|TjbMgP_Qj!rVC&@b+>S%1h?5UT9^_;@Nk0G zYji!t0atP>fJ@d#uhMIBu^z3C;<7#XgI|*>Fhs9EHG=`lW^H-E7-`D=2J`uy?f7?> zAJ-lr-sjuRUBPO8LqSfqG!M_x`CA--8?lPS%FOpXk=bs7z>;hlB=a-?eTgFNHxH0Z zPLA@ge_$wMY`t8Dfb*l5%jRE8?5d(x=G&rvU6Fe33ivPKd)@Fo5xOZx2tV6dCp+db zwYxpcf!;qBdjgyy?k(u=-a`Hj-v58DJ3?UHQRmUel>n8YC~E1#CMcajT$sOtvWgIr z;?g<@*=2T1n|)Dn>%3WeV?F&&)VdQ7egDiS@B?XmIDy0aznkjiinpZ5K#64%LPV<b z*o@mCoAB%bW6r;L2S_U)zJYMS4clYN-`vMo$e0R3#NKM|1o<9wM$|d^<$Gjg1m?24 z^H_^r--~C{&Y9l5pSUeOU-F#qwB+ojtE>8X`92U@E0l#G<0hma5Q*5}7eC3BWd9nb zFR_>lYHjIz*Vew17H1!S!8l3a>Rn|+hM9r3d~s$jQgvoA<=2%cj^%=<UIM+~#aCWf z68gdZV@{-p#r2iCD+6cywbCNf`DF%AA6bCFjy6Rc2>=RK7BpI#hBb_3$N4GmqaXcT z9MYLOut{w>x#(J~2q!MpqJV+re*1`EZ^(j$Ph*0F2&B2Cmh9K9FRA|%o-+sYqJ<Dx zBL;G!X4%*y(*_tt?Tq~};VOeVzJJGY=;;=GS+Gz6;$W5(!x$BDMylQL)IRj3w9)`F z-IWLw4^R9(8sb2Ll{;CA^difb$%ek*5D9q0uak%*ata;WGU$^?qeK0dp`8e$sOa|l zKK|h=byKX#iUw+@2fxB(y^v@Oh`iZ{7{>ECF%7rPZql@LFMGseAu<5iM+JwTFv|gO zV{sUR1%Mf0=%t4wfw&z9BkK$bfFon96v6+?7aI)#xlYKGE(ieF7y$fVH~b)Jmsn`< zm^N2^KdKL1o|~B=k)7UweAtj^V%`s=N6=2q#OMgk{8Bte6$eF;&sgm+OrFBMc7-K+ z-h^*QDzE259x&QI%c8r#=@|00krg@NFG@O*J_!cfEsei9&Mo*p)^<?Qg7o{3hv=YD zRW3mFn?I&{TgSEFdwei_KjeXu>mc?T-#g(c23-E6`nU~jr;h|x9bPw<rpeAR-hUaO zxVDV+lqZRNGHW>xX1EBXhH(r9&Yej#nKTpm>r9I1DD0Xe9<U^qqcz|sXE5VaWK@!F zd`nisaS=hM1ysX_hd5)6I+KJB_ZygTVLu6;h1OZ_wm(;y+Y<D!E5L>~{9axna2eHS zrj*ZrXH)u(jn=nRq^0fLujMIw7h|`Olcm(N&6X-wY}U&jCw(UBV0;k0*@OWbKd#zo z`P7iErtM2yh1TxmEO`o|`Hr}pLJ9$!McCSs`lo?=L_ubKl_vIs3cD_wLVCGVrDi4w zy&jWG$tohK_9^Sf9WZ7agGgI~t13Xu&Qx(!pOaA(!C#*o3vmq!5cqy(R>fAd&;$p5 z?7lG)m|mnPJLwASliVQ%eV7PsMLxGyu_3v$Wh>0g2ke|L#vr*rqLwKjV~wqE8&BoH zdS>2SD`T2kadr|T<B@>kiI@mMJI%QVp)9HEPhr#bY>o<Yk>YQ-44rAs95#-GKUI>x zYGK%EVq`|k{L{v@G}KL%z;8Nhf6hePj6vX2%*jF(H$BY?`-TKJmruCQFQS*06MSwD zfClCROcTt+&-S130B<SKs^kAix_czS_EJd<`cDT$>A{Vv7%5inQyTENYO6*h6u{5^ z?;^yz7bF?8ENI}1UHxB%+{@U~Q4eI?$8>_95o3>4ibD!=0?PU6Q)=JB(3@{Us${gH z+emr!Ilte`^_#DEm=~gT{N~T~6ZQpjT&rTq*#s^8L*$AfU?Xlm5gqeIqKShAV;myu z{zVODtKKjY@bok0uSXY3Y&sv}I@at-#eh(Hfe^-TE!5Mn&D`V-te9>*?$xQ>iz0>X zrQ*xS^P+{%x`#6!uX8qVZH$wIL86z}m56f(78FFVkzC<9?{DV5(j4ATIP?xUAa$N+ zI_12N%;OpPTV~mjMz8tUy5>IyXdAOgLu%8gxVwAZi*dj8{pr4oNQ^WM@bG^&sc(T= zFl8ztlx}fD<LMDZw{kDBZNT?#gAO^z;oUk^U!-r7VmOd240vFw#-je+TlH`1wwMKl z$JWVZFfWc;>8)6R{X+ZWsOq2YcT>Lpd-bn|M#q-}Ii4In_4><_xTnjSsN1(5MAhDA zjSSr)S#6*)VR++z-}6e+`R~$o<m1VgVL>*bGQ6<X+o?BxM<b<HCo7XYl5^Jmy$?b+ z1%0*>=R^p5S4<!DW$=}vaPzZF=vfsK<C0y~In&AnF<Mx11U5uWyuh4GONpbl{DHDA zBq@uZ5a}kL{zTb%_(=xpsZ>pT+TW$t;p;y$GmhL}p&Gn%9>&vEm06bw(CrNd4L<tD zKQNad;T-ypF_1zMz%lk<+P7YV=+#dQbR|rM&>9+q3!QMQFPHv|dPMBA_7%(6%QN{Z zcay`t*|NZ42jS`C^)`ElZI}Rc3cUf&E#nwIv>zMu=aLSDCM_=Q4P@pakP;5&kj1+k zl3779w#I{BHfMw7m<9LtIdk69GBts1?A#jV>erQy{B()H02d4P5)4z$alp;#i1!rH z3|b%lw$f3kki}H1-Q65A^oEh{V&{Ggu#`L2C+GNB&JFguK9r3sZDirhGePPph!J(D zW-gs8eM%Xk(fTo!&6iGZQW^8{UvO-9A5i1Uzb}TSxdvL5m(LminRJok2fl5GwIncs z)gVtf!)W2h(0$p)cl}^SG7NRhToJTjA<Uw(7)E$d7l)yL(xDVZ=UR*Jh6&WsmQ~|W z$`9<WVnIsnRgaFYLIY6g6MHFiJjhR)Ww|RSkQ7ecI$>n!BziN+L`~n{sRXz~QEP&M z%7dWrrZY^Z+jY#EAnM-N_3DC@@nM9%{qStl4>LQno>*;62+J6Gf8Ic55Q=`@d_V-B z&5TvxF@N5;o5T#)k%P|20G$d3IIIoJ6Xaq`@c%0N(P+)cXbjVEq3o^>Y)__0hr-+z z`lYw~Tj{I+s-}2DXCko!8%hi!zy5$=<xa+dcZ3LMQlMCDhz4&)K^#5&#m&W7kX>6P zniTW|6`w?(J+knT9ux^0TyEXI*6%p+4W1`DMhq7W%pEP8`V<w6I`&!-h+~3YjuR66 z9yykN5p^oh1Dn=MXPKRH_Lhf`i!{r2X?U(w^I_~gFZ?~$$P^UbVZRyc7my~kFU}|D zmR8tN#g9uj|Kg4Hg9KmoM(Zdf?AY&6RC=`B*dHP242|Yr#$c?{Kqd}s55iDokdR`8 zs7Smt7$Gk=e2{nY<Z$}#R~|FSAGRk#<g{F0x0sG*m6sc8UhK~69_cbl2P`P!8JR5l zcT|x7S~N0l_j(iu?rJ?mJ}U(~Qz%f$nrr7fGRTt<t-l;*ULN{7{5C`YkKR$y(wD*} z+Et*E0zan5(z?&s+FYWa*e0_tHdsG1gGF}L?lD1xKB2m~(HGCt{g+~y+hQ^VQxzR& zZ;C=_J+uGbxBtFU<g!M^gL9EaHXD6TyO%R&IJdy+lA4N7m2+sx@4pix+MS&&KVK34 zMd|TWC?wDl5JytVps<k^6XJ{Mvu)mwf&6vioGUIR`|aLw6uH#!Mtq68(de7%tFaaL zRZ6coT$njOlO?!Zoe=Yqk{12Q`LGfb<M&QmmArtNF59l50QIhZ0Qzt53o-mI^jetQ zkE;a8`=guXhc5_7=v$~R+zD{$e?DS;RuJ$VFp~?*HiM9buLaNIGPpK5yJQM>op6Yx z>I{EP$qa>h4`6hm{(u<%35g@!ceLBxVWWgU%%k@XV*WtlVC)U0?uXhkV0ySMUxac# ze;V{3UKmi=$oorI*R}YYs`M`SX_BHCDL*VM_E@1b#QByK-_&G0`9bDD&nU@U3)#TL zTYT09`d>T%u{Szl?-D&nr5e7<#Jpbi>^_ic(36KeLW$EG!n8smFE#^%C%u^xx+Rzx z(T(x8Lxx?`i?8YEcCn-}ce*Kdm=^Ic(fXW^@rXtMW={Gt^QT|5J7S%c8B}o()JmRT zb`r&(LhlAZQdncN5l3Rv+1O?B;J$E{*XLQwtDCzvZTHS_44jFsJDutuC3$SoqT7<q zraCCRZ!N8@tzVRW{K)(9^trxjMeY1=u`K*S?b`I3YKd((k$K$Vkv5F!87tyd*?!<6 z>QdXEc>j;<^VMlSsv{N(K(`w{!<#c-EWJefnz5UfdE}sk4>04pz5g8Io<XfIi}$3U z_^{(KT$o4Q>Dk!0gLX4+W#znm^pu04mG<Yg!q@%Vp!2UpXk_rDe@Ulpo+w+yD~gDG zno!}|GQFI@)0gA3_UHQV#KiHa`zxwVZpHco$ctVSmrtQKdJB`!9izxk8+?5Kfp8b9 zLUwZey|i@WQnsCuh7=tU7BDbc=GS9i!rGKDh~fRX|M@rWQr+uKT!bGbqiYjUTU!YY zBQ2^ZVK3#qA6iXmmN}b(k57Tp#+-Q#Wvg|Hx&CAf$9jiVzwP_G&g(;8N7@ScJN$bt z2u}CdBMR%@bdL4=M`)jNlD}KOTz;-iZnmY>VSRRWtJlG$4_BjX(p?i>gs9yKA+QC* zq`%0sFi@d(%eXoLB&tHJPH6Bk`q-Y-4`S^c7Hc`lyi=(JiHexGk~<88-D{D|TSxFz zUE#SOGUU=}Te+>8GpOyG-`UF8!TlUKFV{=Sw+s7T_`<6h<FCFjX*b7Ec3<MxUlVtg zF$_%pU(ThsohXE@FfM!*|F#e`#K5kY^qlm}`9qmPUnA=8A2$TBXqN^64Dd0v!{IjB zDDmFxt<Bc?Z)MsKoc!Hr`yJvx`t%SUD9fp7Y>B7pQTZ}_G^Eq_E@%hxxdTobOCUWz zZ)~N?NpvFdi4TqSSm9;_<Q6VQI+^H-?$pRzC{_1dZGh?9WS)qqX2gTvV%#a>kh^}6 zel%%qE4`)xsUB?TovbXGFXl&&ri%88wTFy|hmPI3?tc3`C#FSIF?F$od^cuRZO9W! z>XmhA;%<p8AQT<`DYF*sOFYM3$4|(om-KBl5o^kiSQZDk8#m=JlEqpQQUi=Ar`dJ6 zXKvo0__O)r+poo*TPVF87Qk|@fj!yQdSzD?ch63fl(dH0>RHb?k=P^BLErB}&PGQS zLF*gA*3lR9(=dEXEmxW!khS*;u}a43S_ycy@l=2BE}bi}D*fvBUFReH2m@R$7~dhG z7S;ASIPBpNqFREGALAPa*rWDbk=)ji6Gr~9qUfV1S?5N+-LN8Ie@JB~BuXXiV!ZQW zc{A&11nKoc`%EMnB@gQNE=*uFTpFm`QEc~KizgQ-cR#TOePtdc5~2x*1rt9N6(Q8U zK$^!Eqinzsl>4wsg=FJ#k1MOjZ}b{L+m%ywO`#3Dzo`6}HN955_})SCXuT|C5ry(4 zjJl31>#;}Du_^h@Q+(ie{^P@9z2U6{lqc@88v$#7oEV+iiS`aVgfc%w_h{fpoqij* ziq(u#D5+XXf3_xla`bX@<d$`|_9AB?!2i%d>?H>@dp_ih0Dam-vcsW*ho4_cN<@VJ z?&@IVCmZ<WX~b&p9+i`wC~cNt5XQQV`I@2%{f|!}4m3Y^%1PtLd+$3W)Md5VlNqs; zIo)ry?tSkPJ2z{)u!r0$e&q3CNOD$u^*Z~7e_Mb9N1?=BL*px;k|zR!xz;|A`TdiC z60axDJKeWi1c$LP{%I6EEwG>>PYR*3YgC$LTHU<>mEyOHVjet+%^p6dD{Vd>UAG(; zzb2~%s08loGTaj2<4d(&)z^9X`chocQTa&RncLr7?p3~P$6O|i;B6QoyR$u`)T!%o zKVH6MQox@bB0c{JiB*wBouI<!NY@w*um+rLp(yzli9*<rkRKEK^`%rTlGc@sw(fdA zm^8AIhUH3c!|oc~eiFm)xPAZ9GF{!h3@i*11c`6%3P%oBo`<t~9LO|Gk1RfYE+r=R ze{}ZML2)%foNt$1+=4p<cXwR~PH>k52`<4sz!EgUJp@~vV1WR^VTnM1;2K<ld+=bl z`L62fs;;i;>bCZeee-7L_4Kq%O~3xNWVka!;l?QYww{BO_(u}@&TK7Bhw&Ykt<Y67 z$vZo<S-|H+{&@Fxy&g+cK>9>M=++*05k7OYRKxqBfErzAZmZk1Wn#TK{bWL|cxrQ@ z!P9N4J^~}Dg@nb@s^qDjfX)l?iU0+fhYS!!%f)AiXsS+u@_fsT6Tir3{}(0%wBRh9 z_1DqE*EbKy!ctS#75X>2uJL6Rvtk#+e8R1QiR)|%9qjf(ah;t8MZS~z3T1sOu{@u% z!#wIz);;th7<>e_>wXR3%t!S*9xCvO%BM}vai7}!a1ku5Y05dg`0^A54Go3fwZHLQ zyp-s>^E4mjwSk5X2ZjVLyU_%$UIuoJ90lgjr2jzc8Ekz67`UT<)KlS3aW=e|$(rEe zDoGc69G+k!&B6w!==*V1O9DI3xeS}TmICb~2#(LGd`Uk~O(`wB$W#{X<v$V6H+B`? zJ-6>XG|gyvGHOW)&`qV10UeRq_~i{!mbj2;6}kW)aT@$?3dYY05FLHAm$^L;m_9O~ z01D(FzrfdY^GD`-2@<cA;}%~wuk`XU4SgEM;5~l`J};Q!4usavR?yLjQr9RKn>;Nn zq(A*LM<3QmVK}jg!6!FKtx<aMM+Q_~U9u%~t^Oe+wohqik)KVRH>>FHM2-8>18v6h zcip)6fBi8L5pO#q4-zeYTgUN|v5c%pq__y5<TngOI9Q@rg#M}QVgz(THMIfUa(PAU ztGm^k4E33>m&@1~Ap+xy8|7z{aB2qzxC<6+$8Pu$4rOLhE{9;R7Bx@HPi2H)gH}x6 zYTYwbZnKec;VPuQzO%inqa(MsTH1JCy|5Go<HG^6GVb|qAj2tG@6{3X9LTx39>`<{ zJXk@VXX85DSS!H>e{V@k>_9X+#*k|%b`QN(`p`WV+E<_v!m%J^hMNfM3G_|#NnBfG zJ~sDx(7k}$k2T!*DEf|#FZK!>cLb3Uk9bTOe#cm#p)E+Gfh;rtUe|9jOqElfR0+<m zx%r~%rGuZ?Lu0-QQF@B=DF!<50ghuQTw-l|dxWU%dREq!_ms`Ay{VtGJmXzO&`NqH z&h}jPjZ6P67ElS!DJ3INjU9W-0e0dt<Ann1L`Xv+_%k(N`3dlBpsWjZ8hcRy`O?8J zHRxdy93P=rZOAS87_Lvo7pzBXl1dHNh;D6l>I+zTld?7S4Y!zSb!C?1>l03I-gzq` zk9Ay#2M;JdF|xxVUCLUGd?Gs+2R|r?>NIqECnff25DiQ%Z#~ps8+c!WWW&EyyDPWL z?0F?*Xx~UCC9U^yqW1o-n+E(^hZzh513Nz207ohc`bwgsnJ?;Oi3Awg$p|@WR%r96 zi=#tMfpwNsdYEAXI88tQRD^NMGV5{h7XFylj(L!3nIhMZ$;ak|a6Gug*zY%PeTR7{ zCW#eK%iT|U%zk{E3gKTLCxHA%FD<AgKkVv4Ctd1=nzdkJQhg(VNnXmyNq>L;33(qI z)1#Odg<(*D5Gz*gxvL=qF!_L=j9b^$75vUdToGV|<8XoWi(<pO3@d;8O`uj_<cJtl z@=bi}peGrph0hNtVO_b|`Qmp6aA69zOBjSTv!s5&G)3Qko)4~8*MHRr7%iI<sdl|n zy6(dY*o~ZKy99!`pI3yb^ND~2K%*@&oAE}Cz-w)Jz`5x@eEzGvT)QF>{MkpkeQ1j( zI=Ceon7ot|5)_ms$w*-XDbIDUlsGkHXF~WB{ruq+$aN3S5mcrKRy?w=`46Qj(4vi7 z_lxrs9p@2%yCO*sD5?P}rP8KQ3sBVApTD79jaftzDH!Y_SbRxYIFFF_#dWwX?elAC z9h=7poeJw?Id0Jgj_2{@aS3ymgfI-SjwK<I!_o_vEwle~aR7Lu;7e!8izC%gll?J1 z+El5RPLxQe#mDVQzL3|e$FW1KSPc6FDn8N?5QH(;2hfZ?1Du)|&UO1!Xk-E3F_047 zaeugO`Rf-z7!L#|*L|?XU-60lpf6qKN+$L^ppa&HATI|Dx1+E+t>bp&$@FV~UQm1U zLC7)XNnTcxdWJd+1{5A)!CSy*xNcWbD0Y=aiCp(>>!x@NKb)~VB72Xm<SNRc_~K38 znbtE^))&7vt<US)^^n&qBI+Lx#o%~`H5QO6RbWY6RUYtMU?|kBi}SkUIw#t_hrp}l zUQ;=ULq%o&^0S#yblpi40d4RkxknbqD!9_b8$9agR@ncER33z%26MTMRMZ>SJGEV; zS5;hkrzB*;i-3VBo2DRrZ#js!pIXzDG7nWDV(`Gh7Q~$vOj+&lSzj7rg-X{e9QKG~ ze1z;ZYWm!)JGjsptTR8$nNc~VSHwM_ssi@RI>~>UH6F0lFoNy-JY9Q}xz(?JY7#p) zb~-eb{8P7E$X%04!ck`(#%R;FR}V;iV;4f4g`6#jW$XI8TeUWx`X~l+EFz-=4haLp z5ST7H>%^>SSk%SR;m3E5SJrp{x`)htq?`?#`*(Fbdq8Xi20T~*qTL6fNnh#dCIrXm zo~H@%?-%%(gvidhW=sRpkCHI13!2`Cl=~J6=V773e;FOzKpl5OSAIWfU`-w~Tol*C zNS9adfkU9FsVPR}D#2`(clY7A&a8&c=7kn`DoNuDm*pK-xP8=zJJ0&Pq0dhaKeX!1 zr*g9q*$A2wL`B<2?+bObo_jJ?QIB6XgZk+Zx>+QkGf7#xB<lsXl{0yRVtvQP5uVh) z4;}u@Rwu9Ss`_=@Hv;VYZAUpsBwZ6lZ&XeIlrZ{ot(??h%a2C)8(1fUYKLHe7z<qG z!1efZL?WbS0c(sB0{3jZHJw&xLNhTf$K4GxBP|Ph>df-gY$B2&J!k&<PSc6<xcdGv z9Q`AcK43`e23M&d&aDU)SW-9CpiWRMZXH{Ec_?CDlb}a>-rYP_b+>c?%|FFrpm1rH zXgq>?iwE3l#Mmuv466r44c7W5CP@v?)JR`DH`Eq#m_M+>eg~TZyUEBvs631q@pELD zHLc+`wdX81RCf*^7h}8d^@Jo{Mle9o5*Te9iQ9%1r9gb%t1!GGR6B+d-RG3SBCLd= z@Oq}u?-v6=F0z6G74gsq>!6nz=36O#Ps}c|ATYENUjf(y&7$<>8#ADF;RF~_eIMv> zw)dODI~R!}C#_jxCdBtT=dvt?Zd#-HK_CV&TwoWHfoYRq!(&-F<w3#TnZP99WQHXJ zH#&*SG={_i4r#!8t7O^F_kIm|l^-)qIsf$Wh0%mLCz5Z@OnjH9^u8VB>nlLN9<~OL zOt#%X>aLbvjC>?w0Orkg^Lr#2<dYNm1I={@Ra5~O!Qb})Qz}qV$2-6;*=%0!P4LT* ztfm+778j$sk|R&S<(<A#bcZsF7r4telFEY?Wd<cck@Ow3b&{;K${5tA;7?MSp`IY2 z(CK(e_=uo`y_ygq6=J9&422GQGB$_R<Rz$Em0lUsq?hm%!mN6?)olK{DCBj7q<jyt z8FiCI?Wa!D!BU|NO<|Cj*l9*_@vGM-&%b#*2Qp2XGp43+&YQI54(R9~)O_1cR}eR~ zw|(a4!}3L@((KMRU#{{lm!x#z8rSJr``~YZrJvYWGFFT6YIP@`;6r3u&puD2GyBus zQdK8EZCPYRy8z+Kt=GrcSFh7$d{>y@ygiL?XX|C3lp{h$Ou}7G3P^!#;nA#np@OS( zcTB6)ytA7=Cj9BG$v`zt{#UpOau~|NICK7)qquvvo+LkJs={zW)PUAvuTL${=H|rJ zt&E41o#=nbrI{`-{M=}cQ+QD`@#5eqpg^?#(&c07;7U7Z_Qv_E`@_Zd_MGc+WsZVB zsk#N)tZA<y%8uUyL9<Qsr$Yfki>BU{Ki%e5cLu1#+i1&)JJG$%8}w&{@!Rm+mep5w zPqpPPgdxY`xQLgh5NjjV?}0=poPZpj=_ys<4-dzR0pJBTSqb13wSLz??O`^6C^9XG zx(INb^Ngdy)0PBBb7Yx)WCjPMQ+c4>5`%944vH<`{`oCeSrqd;B;gg+cIU?qkCBH2 z7fgl~q~3$cw{>Cj@}lS924=fEiDppGG%aH}+>zA6>VonOQ1*e&MaGCzt|W5W&v%_& zNqjB>_!CSW+_b>@2zHZ}6qK6~M^z)UYiBlvEuHdfd4$_R_J{jYl-RNNb>#wJ1xaQm zkIf^8^R=hBy!o~GMZQz5g5HXJl=U;%cV2T;R+XIU#Kx`MZJQXm&6zw9=3}_1=?Q-G zV8@MSl~<qpw{lF&XUYpay61^j*~iZjMh!t)<&^Z;<d0MN2o#SU=J=sA8AUQ%TDktD zuWOinRbh}8Me2;i`*R5nSl>J93Vzr+3Z1?$77W@F`QwDR?ELfP;ibX}d9cIHgb`)* zNpaZ;T3JSI7h&$S(ar0gYO+eHrWX-l=-bZ?O^iyfN^L8ArBa2zP+3x0QebPj>bY`b zHVP}Y_nN5}nIw!6C>Pm%Q`CsJyalf00%W!tNAV?%iG|9xW-|S9ey@DGk-YSlyY#lS z!vxxHbT%jUZl1mcy_dn?PfgD0)~ci%wPM6f1iLh0pFxTXElXbGZ}XDCvkij$oJIL* z@44TdLnBgz*CZeU$5vT#RQr`-fwBY{<#A+IUx&$Y!o)?%Fd<7}c^%h%y<Pc<Lw{R| zVDrOo7?=(`NXS4#z0E}ZCo6*Q0XD3bYweg@wjSoeA3topr1M|7SQr?fwOnGNhbOZD zdf`2kBoF0q)cK4p6Mt*ExJW>BY4##svb+D8kG>5fut@Y&BYCdoM=V@3siWfbvvTKj zzpB#vzXLCyh|NXyf01`B3*cocg|2L!Yue!d?P)tpEvk6k1P=Nm#{;mRr<u`n-eIR? z*`F|u`zj2=pNTQhQ0O#qA%JN!w;I(F4kCCz7F_CP;H;XD2FBzrPLgQD73ONoOD%5z zt#8`$Y}{u7TIwTKP1yMp?82yqfQfCieEiZe$`zM&v+$NPdXu`L7UGA1fwi9B1IGhu zk+Oq(-aV~Fr|_zL(tTdl$~b4hvc5wNnS$^n=uNr$p^U&tT0MGwqPV%#6D<@mw4n8v z3=9P$n@|vJAC1fOw}<T0mZpErRy55e((unWa)zW$jd~-E0(tP!e*}VB_S1=goxhtr z#v09J&9burU9&WeXx&#A;y=I8b?x*Rui*VXz<GChw||!l(1cyqV_4s02@!M>u|EOc z<C;Z*q(TWnRqr=Pt(Ysyrkv_cBKHGeDe5J}b2Uw_=vF+{pr3@Gceo{<l^Acj<*4$a z3F8x9<>k}nQzhEI$mSTi6}{98>@W#M>vMhA2#$8>4`zU05tK(9(j?YOS3vodLSRA4 zqPfSmtXbM#PlMK!w!myN(i-x`ipC2#vv*^~mLX@P!)T$t+8dPhm|*ydLp%I2(8JIR zPJsez`FLR+N8F$m9OKH)=gJJ#B6*dSwZf=0DFy4w>cgJC-97iN+P1!FZ=Tv8d>~%A z(pR9+`<2WsvFUnj6N@ae_Yp=NWAgFxiC-VBY@e!FlLg(DO%N<%6~MHB{J`zwotTfU zZ&BP}{1om5fhFD3Jz?vea}x2v)5vOjHdUL(nLz<zpLD7ttiy@QoDMgOa`b;h2<BfU zD0u^{+%Bu>Jp|J$-R(F^()5=RC;pZm9Q>_YhXdd4!wIKnBqBV1Aq5nC{moBUSfc~L zQwDk#<MMhH#~UD^ACI2q=H_q_!Xw?KYsoCQcz2<RY`fi5u8kG#?WM}?=%+v6Ny<}T zJb6Xnkg!;@BD)&QPxH=EULFq)qxBJdZZ^&-*p%D$eCbslUX)(MFV~lu^le?)mF>S4 zeCiTWrD8VY;8|JY;5yGP8}ASo@4E<d(P8rJ2qI7g99Zzc#Sd$~{33*FUpNo;ILoXe zctYy6S!nzWl>Qh<2tvEKxsi0KIX7b!J0XJdx>Om=a!w|%b(3a4z|Cq%%uGQQd?bK} zvkfCDre_G8$@Y|9{n(cQd2t?Xqu+m>b&9JOSkgLi-><_ilA{?@WEnmF%L6b=_Sy3M ztq$LJmN#<U)h{P`IvbHT=xs~H{_bbw?chgZtzn)Kp6(6ZFq$lb$M!hw;ZrZ$>YuMv zrYxQm=`vPTza=2p;sg|d=yjP0haYPzKUNT}TR}z`6*N;MJBNjb9)d)Cl+a11z1C}0 zk)YC=zxn!~rFOps2-7&aR@y`1Yt0}&zS2(6V_-{+?w8qeOVIk3g7;_#fIPj)*rI#& z=j81=!8*Zb=!zorI#&#(BzkZ`2!gt`yJ+cE$cDUm+L!svJt*0SbTYj6&-h7nwhb!B zZptQ|=K5t3m1zT>j*QxzRE!_wxPTWRBVeg-OqS*_`@Gb_>*vV6iQkU%Y-`Z7eD=)y zqgN857puXRYx?YjbT8*SAwb)jw}g#4i$L29>(*@mBA6lLy~g7>IL%62m{&rInwk5P zGM#i#tRt)Je$Tgw6KJ-SICms~AlzoEql6zQ$?Q>BP4!Q<se6V47BRcB!Yi?=U-+Ll z4Uhh^sjc4c88wKi>2nnldy@9DTCiDok(*Tn*7a!nlfF72dxfy^42cMF-58R`fdaL1 zotN~XgkabL?9ti05)5^)5V#$t1-ukpjZEr!<?a2okSrx~)5=E@((&wr-!A&TLT;$% zTMxllbMTpK`|qcOKVuK3CWYC6mA#MMp|l!sfpM&DZMy~+A(|`goDb4wn83U@A&zFb z!qKbijbL^V0+V9Mh5}Xy{5FJHQat>&rSqL{de01jYl1g3vjnIY2uP1_>K}`91g2CL zeN#FiIHOxB4WU@t@|0RpO6CGz9V<f^mRKF7z1#~Dt>g82kTMQ_X5sFUzZs4Q{mmHw z!MHDzwnCQ_b#l(zPU4QTzN)<4Cx6irJ|EgM0yYB6*slUPIw7$8u=BOe&7%EVqk4($ zoh=hkMZjv0d2Lr)Bw$dtS@<9UN`66aUcxUdlK-VEGk()Uji*K-8(}#4l4Y^G4tt7G zTc?rf-hTn~%@qq?1FlvozpDnU*y#Pk&d%dgM(!O&g#_e;M!c-@=gLsAKg8gZN_Yu= zvbyFIz($^Cpg2wtIIIZ=M-jozy(0X>OMt--+hFAs*3p-_KNxTCm?)Xvh6OzLpsADa zAD}pmUX&M;ef$UXCoHoittU4u<9*7Hj_1YIP1;OLU5ph>nq5Im>)*ef1?fA)^}nu1 z{(X7vw#XXd`()}FhFijnycYvN5=OBts6R(@7J<hhfRXXc5kF|H|Hgg0b0^^Y7~4_U z-;*543o>{vYW<%A><K~0+7Isg_2<4+X3rXN8mC5&A;m1VnFL>!-l_u<SO{dgj&QrH zHyqL(7+v=TRgfilNb7}wHe_YbfW0%d>Y<RxgRcpV71P7^$?v74x^t%cuRZ(KE@LQU zlz@8G58!XttyUpt*hKIRM~kG>fp<pZ&5a6w!bzJGO7^e&@U_+~Ue|_c^RHQtJ{Ye* zzB*<UOm5UD6>pAjz|(q9ax?jbQApQsc1xb4mt}yPk>?XD&MwH=jSXKt7B>Tf;Qe{t z5D6b}6EVJtps)U_V;}O&%oRUq=#*A_>1^SkkE^!#W`}L5B}g0eBRl4P27(|a4Q(gx z+z-m>U&_qEUQ3?K(8F;K$Ig8qetbPsL=JaF+oi(E6>QGBJQW&4`IB4r-68uYFBEY+ zq^;IAXih6YhgL&Teh-tbv92_Ug>K>`IILeAYLA*1xGk={EtMukrNVj2g;Uj1Pd;*c zC}y2hwPGoMV_9ow)RmV~^_S0)T8q1)ke8PIiQXNff!1YCo%Oj_jWwko*NV5T9=40` zEJ6V;6XA&GeFH;$uBx8<YxcMUW}9i$-jDd=>6}xDVf^Ghk^s_rYw?Z7=X5I}p`e+U zAH!})ZWZUP|1<*${_7b+?@{bE^!JyT8$X|X#GOHSK~|J)pxcejl}gdFq-k<7FB;$a zaDLv7;f7V&K@oYj0JJ~g8SiZmt`h*$=leCR;n2`95gX=n5n0@Fy2Y_SP&I%9AI!qj zE{@H5Yrpoj--BJbJ(@x+JT4>=qrwKd(lxES%U}vgR<?paM*?e>Yl^qU&LihX<X%}h zQkE;JkO}Lbk1;pPLD#PoF{a7*anu+oR8&UC>5oO_^i~vA7l2t&HExitvu68n(b!%S zXSsgq!TzDao2R0kAHppX2_EiXzcvwpaSVsFzn{TQxUb^n+665l2B@$rV``cg6FI~< zm88~f3ZFG9%S+2gn$X4S?2i+v;vr$AIvH_c$ynBOa5-seO?i;b4*UF!R2~eR{Nf(h zFqY^*24O#VpwasUv(IEa;)<X&!o1TJdo+^^oGQj*7#kpkQ&E*h1XaEEw7z<spR2*c zH#nJ|OA2pW{LnJ0@$h%=<CE_AzV-EE#(jT+v~7%iMuz%cAM4+22LfMkGOo`FD&a<$ zfCGjqwViXy^R0|orMF#ljUYp@3n!)Xpr`~HOzuq~cnB<e6Jf0Q^dU|^+}gdWo?i=3 z65e^{M_KpG*1w4SN3Bf^m~wWNfit7S@rf+?14EiJ?P!wGl8>Y??b~RDP*iCuMR_oc z)DsYDb$M4a_7(T=iv<t<34KCYntOrF00}n;rup?H2w6)b6*d#63ve(4p%48Vt&_js z_GyIjBI%Y};q4_)%)5(vwGS_ShN|8%Mc&F0l)afg^Y=u+R-D;WB|il*m;%|Ttd`kE z4_;eaevEIAu&R@GHUIhvv23B{pb&_fL$BtY<r#F8VAfF2tkRi$r{het%`X=NCI&a` z!G{XL0E73em9fF5pm*6}ru2!AkMG!)2|6zAB=ex`yDH?aQYT^2oV`H-XW!n$XwkfQ zZ9$0cKx`ckQR508xxjZDQw07HA&TEVN+W-BXx=WuPpl*b<4nf3BKHs!*f_=3%<y6a z+x+POG&LWp?(V+*8hI8W0ZX)2;HUUa;`o+^;I}ZM`{8w5Wedl5TUv%>i5pi=4nN2k ziPa<3$f6+XVS|gh*G!wFR`fdg65C;X_k$!rpj!>PxfNBEvRX6fkR%^M4QCH|{1C(O z?oB*KJ3k0e1*v8)%jT*vrDzwjZJ`1f566STzZP*E?4K`LXQ_?685<jmiB=|$=(iFi zi|ga3Cjs-124C#|Dj1gSQfgoe_hSR#nvEZ1OC$Y!St36AeK*!l<Q_?Q%8P07QCYN| z-$fN6(I|B*A5mO@HVy`Dqrd@>c0d>Jg*F2yK!Uf$v4P7yS5X7v>{75)L`Jl(nBfiV z&Q2OH`$yu1ERkBtA+;f#BQ%Xf7Z>qFRiW{nn~rFH&=csyS0YR%`MqD*u#wtu8_WmF zs&AcyN`DIEK>!cZ1hA5x^${O4CVXh8J<XRCm26Yx;}s+XC?c5d<<|}x9D+~8{cB$g zPK{&$XTcJ_gBkeR9zr|w@hvlJ`OM0R-(~VklPE2xn*(JjeVQpR41gzc7y|@X<44rP zAeLhZuQ{YWDEgTb(N2oJF(_V9QpZIPt7JM;KPX|q_VZ(zN*NZiQw{hXm=Ca<i<pNH zVPVhJ_~dXAEV6zbmOH%9(|m^+kJV$8P#ZP(y|YTASG4a+on2Tej_~3}|FHo`XEN!# z5%yYG^4ySSaa>&OdnML)Pg!4J32Jkv2j1j(J78@gaf)ks8H)V$RhqQE4~Jc3kDQu* z6TAMdPV*=?J~5s<m;vbe;ZX2B6@NZ|{-pArrW)|sAO)sj^ZlUw;Af4rV5F=Q4d$om zy#r-R39eE{;U}~r(M(<f9MZ?rh#SyzfB~?xCRN3ltH*$muhg()gw@bdG&Y&wJARO< zd-26T=Owu6a^E$Yr>_*o8jS}ZhXRQcadFEpwltIDN4&s<Q@(X44|ovxsKD;7@nMZg z;w&oBM3D5BTd*k_1n`r82|$><;{5ZgP6|9sK>a~RHx0RLJ<zwt+7RAMYIPJRdHU<o z03ccO;X8uJ%ph;Gmo-hH#6ToA$CI!ku^Bo?a17R|1%5=SKT>`@7RAqacJDaXFRqh| zJ&xrYe82uObKECqv&jJSK(3yh1h^8a|J9U*!(M;Ke|C4N1AwL<*cq&(>nhi2Q1y!d zEwtwW!AGBi68OkK`Z)nLJ+a(0L(JsUOJ-33b2($=JI^EAj_|-HRd5^4H#jCsxHLP! zj~9I3LIjb^LT|C9QX1@eGL<o9Xt>!Glo91;Du4qUrj9ry2td8cogULMV#ZZWDUDgJ zW|cr#Bj<;=^U&PLnb9<piMbBKM7nXQf@Y&S=n)Kr1y}7ia*m<FkJJEK0yM|IxpmAy z(W@SuElj?CjaOS>H9-0$BY;y7cJkep^>q5E`=J%SviuFFS|sa_LKg#ul}o5nw~=W2 zm6ii96p3pct~2&)aZx`?fWfRiy>_SQpp0{g)Ug1G13(ZKKQl#j^x-7+?&Ol@0+{Bk zQ~E5rEk0ty+=M7dEFglugAKb6NZ;%qdl46>H;&m-XB7N*!JQc-o`oto;c-D+$?SsZ zr3a2}$)09uN%@i{E->7Za(nZN`ToOrMGF;-L(xEO&N~ApO}T@@{L7X+rz%AxT!Fs| zpW(lCu>6k(*QdO<?e?CYqk82Hh6#TWNXJH9@<Qzy4@X8c=<H(weUk^iA$=7UZEoJ0 zj;o7x+U48X`hfHjU_Z_gsWPc#@_k574FY>MQXMKF@#p*7pVfXUEsRJ`UjbZ4EM8O* z@vlk`iQ7~_9&;yz$Op<brTm_PLh87=tUTZXqXUH>IZ$r;Z8Yi!{9D{|8glNY=*NaX zy;*<c#EuVl^md=)NPx!JLAP*(7;Sgh_V?%e_nm@oQ<2u`pkGn2Bb)*Y3&}d%V>>k} z24aHv2U&?f!Jo8wAB#O8f(x_T#PR%8-W)fJ-46LzI%<IkPXiFFD+9imPE_pqAt>8G z2oL-6%&!e_;EE^$n8qx^ICf9w)Vc8(07X!*%dg|^^rG4Fk$mycS3W1fGnXZdbpdNM z0UH@v!#ZJug-}M|r+!}QRR3~TdciIwLFkLZw||528!yO{wJ|0Mbiy>68p`0JR8(+( z2a)d$?kmt0dTf9hwpZfaGN;O+V`{GSjH=+{@Fs+TjQY9W%;2N@tlk`L{MIg&D|#uv zeST)d<pM!LZtJ%|WtTUxH)Z9*ubYkR=w%F#62DF3>t^+WG8(%vv$u&NS}LC<AhtYO zlQAl4UR@n={S*4z7w<JWOATJ*1?2`$Wo66^uo>y;x`LvKaWEu5@*EXu%Xt6w=^HCf z^7oOR6*E~%a_Kr^+R|G%9t%k*v#+F~I+M(X?|20yj0-+!?^XWv(2nFXv5dP0EN_<G zkHG+FW%auI3l6{sNI$&bWdvf966mBpAKcx1%W$|I!~qCK<jCMJo;)coe)1&7`@Xw8 z@ZUd1boGFHo1=J7l9)n%?)~vOqE^p(k`MakMVKN`J;nq*J5>@Y$fHh??<B=;3pyk6 z7wEySGb&n;bulJvgcKzL>U)6?Y$w%hPqVd0<on$d{8kYI&vB96d%7SnkbZ&%qpo?E z_<rGi?MJbuL5!RqY~<Iiiw7H5)2?wt-kp5+9c`MX?Lx7t{Fnd`#tUz%6u{3ZP=T9G zOLN(Da`$%l6vCRzO!f?35_MK9+tjZ=i`Id`0JxwmYS-~D+k(34XS^lkcuz^7NnL5j z$kT1}U{{?<D5X~1lKU|LfP1p=X0c!*y@D=$C<|=UzF50?_@4Z>);eu6gL73kC1HcR zq8&;IAmX)w>9@VPPJgjr!|UQ&Wz`EOV>M1+71%y-O}%gD4aMH`dkg{C*QLOY#Pt?? z^a;bJa-gRRlOyj4Yk=CJJm6c9p)7_kDyau>>R3fgJC>2erO$gjg6Wm&b{6=7w{wC) z$7QLK6(9f%l$=CIY);Q+izv4r@u>i0#$FB5+CYdm8({pL%sLO{YGCg%RuOX?NKqRf zQW!bmz{2?bruWwjt|Bfws%fl$Lr_xS52RI&Kz-wG7R20E-P9`CtN$Atb;FG8$^GJ1 zl{4)u3R@T$#|@@=r;@OS_SuPamKK$;KWdKvA}K!ebX-|s0y^k?kZ=I7Mx`wQg#W-? z|37}(*8zf-!n0R3bWjwuEc+=cbg32dm1CFBd#C><kcZX17>;^`T?g3lo-XN#zAvdD z35q1wAYBqdqTp(ipdRA+7UJ7Sm+QZPl-$rxU3+=U2SVU#WQp>$3@_5U#eX?qH}>U; zj<L<5Yk!1Ha2*7t=7~JP@>caswgL$5ozd*>6`6?3``7Ars|3lnu}hTnJkCyYl@$!# z+KgdY>+Kd~`Byq$=3R!dR)!Ay*WB~z3&d{5F_FK+-&ay-+ld+yC<<B#WJWr3zWcBv ze4k#IgW_?>W<2U0=U&cBDPQb>h0Yy_)gM^)2W+q3wyL#f>e`#>v)>%^#~He)wbn@6 zp$x#N!!VZBgQ@gEet{pg%R@Fk>Le0T_Bo`~2a5Mf#F|a`6SSCtwCk)@#Ls=r5dgtu zy?Lp1uvSj*?@nKiTv|$k-bw4|&qp!$ePg#A`m(P@0gAPgHqUB4nFAoe-=7j7SJ5@k zW_P*#1fUJovm48bn|KB*3C!>*S6A5g7ten~9%3R6AFkIYCf4UiMmmUrqdzcB8Ep7w z;d>qMG4@y&`byV&CMmBc2CA-_w<wKIL)cfIy*qPS{8xnVel(Gc);%rY`R1m-AmNki zmvzH>s{^Eiai~|y;app;;@j)?&DWoP9V`*<{o_WGNbEKPKxgZfy@VscX)CS~b&PEa zVL_#XWt_%&jF$7=++{h8Vf7HP(ws4q8<-q?4{|r1E?hNnXJW?v$6&Fq@|2IV|IJ#0 zQOKG~(cGPt3G?5LQjbyUK&mGIuyTh|2h<m3AO67@1OFrx{(m&Vy2DXzqc8sTJNpms zSmr-q;-vqr`5g`>a_H9}ZtVuolgFsV3VjTB)1T4ozbAQ1bRk&0rhX{>-x^}WcPsS@ z48PtJeo{H}nqZf7GYh#D4FI875Ql@Pr6R@u+jjo~Eq0j%ew9u5b43~@!&&4oeGxME z&+~52GM=t#8Ammqmb@Fr*sV(PB;i+{V1645brv+1Q6mZaNdWek2#|E3nn+h1_d8z= z6HQ2!=YpU6xRNQEN<S0&Zq09^)gW;bN^efK=Sxz~i(=+?D9qO_Bco`E?j^`V!uyp} z&ULNqnnTYh&yv7fp^@@HVb9E{P|l>hNmd?shlylpqwU*T4)zXfA}-C@%P#kkMxeKz zZM#ktS5EQC_)ttwpTPm~t7h%rQVp|ycfu_Hb7qxF`ffRupDUGpleuCRg39^)ALBh6 z4)oAwJmr?JcQ_IBncr14#$o8^9+t@#Qkpr_!gxFE#7#TAsDp(}P|5wtDEldp3+}g~ zuHr@();tpFZCN=ePNx6>7Shyp&gnq4o8f8YH2ApmiEv8pH+Dv<pusxKb7KAED*8tj zSAvGwg(r$wuo8{h_rKq9w6R(yV=6SY;gJv)7uE6D)S8yOfQpo$3lB`%a$@v_ti8GS zlTG2nKrx@39QG{E&DUxk3(f(Gz1V2)@e%cVtrPo`Da3tL84|ytsuUg6N(6Kl;Plc+ zOfQ>@3AkY?JFD5meGX=ha8>-tElCQ~3kdRaych#JHoQ4Y0-?Z`Pncl(Zr7iko{ODl zJ}>}$yb|4ekQG&J9#t>H`JXyGaD<MFw1hC2A%jXazDP=TtozGpr1JMYwf$66MK<s| z)fldCZHpLSU<Ee|2cxDc+B|d0#O><`fQA&jYp2Tvux4Ha5I%jwS1dw3kA}kHT?@>g z*N}I~qJ0lOU*SB3CfNtx3rwkixY*H)%oWp~zLEEBMx$G7cg@giCO}CAM-~Cb;<Vwj z8N(^U8+qUrN&hi#*+r}7hG1qPQw0j5T~ieYev^`mp8F%;UsGB~lb3BZQZPS59Z)#t zCtYNuiuNjPKSvS|ccxow+0&zhK*)lZrg02=HWUZL?i&F)<5G0^TT#k0Lc9UB89l>K zR|2%@;^h-%U-b$H9-ExisU~SW4iFpFJmT?eOR7^04hI08+ZYcW@0~9&kr*R+w(LUt z*+k6=&rM;Ivli9lHGcm3NVXdv@>^N}`1t%W4GD@lR1dUQpWy(k;D6K9|BC|uKR5Go zz)x0eb1gOK*in2M1bf_KEIWh|e5Vt_Ezvklnh9tC{WHGLQCpvr<2n=ZefLM%D$6(w zEinMl!aIz;V!c}7p`(!z_84C1qm+#87XkwiBe}%z1`qB-+`&r%oQpIM9dojNA7rYI z49U-@Z_9VhR8F{O9wAPI$G|2kf)=z;t52|xm?&$MEd)lyU{qPK(=GAk(tnkY8}&cj zfD`3V4C(LcN%v<I9>sXuG<@;i9M>m)zSF;eiNGQ3EGtH$3h6C>cjAv<Uu~6l++kEj zM`L_%iV?#V%lt+25g5IMf$F2kpgjJL5kAJF`Y1gN=-4XyWllQ{jTSA0Hdno`_Wn_q zc4~RnXSJ~0^4y_IH2<TK4*$W^ot#U}Qw0F=<2Tj{l6M}XX;*$mylx90Bc#~)jcX@W z-d4lLzLwTWW9zC>ov+eX18fR+<!#OQ-hCz}gDlP&qZ<Z_8$W*M;Zb10G{J3?2g7vu zW}y_L(?;rmmzkr)j$z_3m_?R&|GH|lMvfTt!xTa8h>h}1jA?A}m(3kvgbi}Rq6{*) z2Jca)*K65ljIubwW{@+VhnG_!Mp_UChwy(k1M|;IP$dTIROQq_Xp^!xcy^+o4_r43 z;q%*Q9DM^^aqE!5uA^KC^RO8tP*feD|D(zv{*Mv5-O|JQS9#5dmM0{K8^6im?6V=E zER$7sq}!X%L$WHhuSrJsm^;}e`3;tfJO3_njrgeeHunEAJl~~(jfgb!;@hEtf$yby z0_-@&<1*WSB49Vl294(-f)_p!@#ZsJ8N0>hzU5u+23KdpS%tc-rQ;61Q-jQ3C-90t zSIrd2%n5O79iQ1<P0!A_t^ca6^xti(EQ^cK4F_PJ*GB#8<`2frH&t>RWuYe{&CZ== zdKtQMsan1(f)AO|CDotE<J_qLr6|A&ARz^#;PH7OD6oACOw{yR2vLgS`548@H3gI} z{2qnc7QDqlIVKYFfpR&Dq?ppx0O{=s<zkSI0eezUozH-WLGh3h8lpmn?oRJDJ6x0u z4_>6u8jH$0>eT`Z18=c6gg7;Y_LGz&-i;|Q5;>wCX@*2J!dEw|@tpr%z}!sCetHPe zAW%a(J}Ms9>!q#}M^ytgaC}@UOs|bEmB-{e<XL{Y9&%L7j?fkoW{qSOu%{sREwITo zGI%NR4YH6XL}nax0w^GY$_L3<X646w)>HdT&Fw5Q+DM3%!y?}qF+ovk$_b{(icF*L zo5NK(BF4aVe6La7=!QRaQBqCZAj9FV@<k^*+IDUN%_Aa*SHt6`+z`J#LdYnnu7CMN zH5!$!4;Vc{GF<P=Nly#zoT>k;6J-MmQ@)j0jrqXZKfG%yv4Mi#9i-d+d<yy@j@rs2 zvmF4U`)h1fY6h-Z`}O9O$CzsK_W6LH76zdyX6R?2da{~{4h#mYhLn&?DW8+SN}ws~ zZnYiyNrRdtoJ=!EHk8MgGX36|W&<S{R<9VfS%M}j_&FHk(R~*gDo4m*@7jirr%Eji zSF6-%QO0!xyq!gIl+?uH6To35%>=|Tv#&Fo6%d1%!w<`$48-s=;B|ZkXS?3Z-#7?g z4pu7t_jNb`(iu$Qb?Y)HVS|QChJy-sT9y9m>rH|*&S&-zfdDX34I?0Uj`I~ShjSP! zkPYM(0Q-);BSR?1=z;^Ec}Nto-jPIFxq$*YH2A`u)DGUGYAiBnl>x8v0mW_<-#(dk zfCDOOdh6S;C~A2Cb&Rs7z%&t@9|haJHYd&f?-6m$Kp?p84+-Ld4eY3~ag7D{4i(PC z0|9kqK=cPv`1)n%(kk=ilNX6vL7j;{+dpKGrcefgvmbz7Qzj7EYfB<UwSaODCi=h* z5B!oviR4mdSjqDt#rtC#{>KIgVJ!!oFFiTP-T@EvLqy6mJ-A*DoB=^iVGkRY2{7*m z=juCIgc%TVC_cqvNN6qsD8fSF4I@CVII$NP<*cVE;g~BZ6o7&aI%{P>>Vw4XF4*xW z-stl%bcXe9PGV+qlu5bmp+Z^@^C0_X0$qSV`<?Bn0OZIAK5Da{0cDtR)kyd5O`#@2 zEtT9XR6M=3d;RNDze7UcU6=oO%7wpBJ0O*IWoZbErTzVTeE@!^*Rvk|k3u<&V=eOp z7w-{JWM-se7qCAW0do`Db^pi%7~`#tU@?3kG(+_ZJ5WOoE(_&D8tqKozpI36@<O*R z*z0nZ$gWT`IBxF3@woQf^api$!9MZ=<0I$u@EQ%Lrzmo|Pu-At7{8X$f5VqDXHlni z$aR~5=U~TEOLzW-HPjwCcP9iGl)e8b8vN@B?N~x24LNNWF6*=$>S&ta1R`t>Q#%6l zFU14Wh7PO*l+etL-yMYCv_wf2AED@S2x8JvF-PWA4Haa&Lq4VY2FP*X^t?8Ht<<ys z(_-}9BUlcG<%N2kE%)2eR&<m;+-1GyB|&Zkiyet+e_F<JWGUDV;#^U}l#eE)VxI7$ zvtqLZY{(C}W>3MGWy`qJ(E#eS5wtMhn$~vG?SFG}cQd5@$7qEc1nEy-a?y@yxc1ds z5}gR&VKx3Ua7P46P758|?f}Hc^s|Eg(HF>dtoz3^?6hmGhj{ZOr0lvOD})y&g(a>n z8{{VQ9`ed9lEk_#L9|)KLVt6cw;u!s5%70L70|gzQRY@>4*XFl5OHcI-fLWY{OUT4 zNNjrnf)d=`ei(gIEOk;&L06cg==!L;Xm{9de?RQu?i&8j{E`WzK7$W7PYuZqqeHAv zu!5-*;g%{Icbxa0lKcQQ1`j+7=w9x+hH3r{3(dv3Ke1PoLs?_ojjv(=+a>9znVF*` zbb(^s1W}CtZ0=bgRA=ZeXE~U~zC%p_Rj{Q_2Pn>_e2Bg0@TWh_7A_3RV%?u_l$>(5 zmqitO!N%PXpwNm6OSoqlL3_5U;d%78CY@@Dm2##8%IhKh@|->udCiS-3|8y~_g2z$ zmEXI<y624XXfA8^q>0cX>Fh9(%-Bx{zH(Qgf>yWo<%xzYQ6PTouTCNGNe(@89FE4% znCvE6%45o`J>;tO8Rs1*ME0Yd_!bv_UPCGj$#UmvUEe7ezhl-d2{KCkNcGFWd$+Jd zdhjaOFiZ%lBi<U2*?UF`v$OE-+ijT}&B^YFoSLuukxIY;^hbFre_|SliguhL(J#%X z(hce~TEyi45CE9|o%=Lx+6BB5tfI9}tP-i*t;3V<2>I(gAg&Hl<&77j!X4ut-~sI5 zpOoR51Vh~*c2;)VTVZvW=IBe1<4WNY$PqC^QwlJX_fpCz;jlAR$^ari@j-t-w|oR8 zBcf%1MKO>EkIMffqGs=CTfW*Aq?5-ej5*46SKtq{fsqEkQ8=%*O2lY{GseJX)Y@jv z6V3c$68P^g;-$Zw(><ICfFWkIBcP%-2#OqdG@2&tOn{U=<0af|=>jA2?I}BaSFNv6 z)lDrZwhS7tQa=jHULVYnQi{q+JKXrD|7-8o=84d~ZT>grRn*%QdQ@DAci&ygR|i!T z0FeLD>J@rW(93}Hm;#J&!Gza72HK*5ZL0ruaVS3OGa>{BV%v_;jE;;8;J2Sy0MtiK MNlUR-!Rqz@0LOf80ssI2 literal 0 HcmV?d00001 -- GitLab From d0b156d0e70485da72e7c91d8e4c4d5d667a3313 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 25 Sep 2015 17:04:41 -0700 Subject: [PATCH 0006/1338] addd pgp-signature --- .sandstorm/pgp-signature | Bin 0 -> 688 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .sandstorm/pgp-signature diff --git a/.sandstorm/pgp-signature b/.sandstorm/pgp-signature new file mode 100644 index 0000000000000000000000000000000000000000..8d8e2bbe62f431cbfff59c76168afdd865332396 GIT binary patch literal 688 zcmV;h0#E&;0RgE3R{f9-0{{vEss9Ss-sA#U0n2$}09FOyP)Q(RZ6I`LWgua7bZBpK zAa7<MbZBKDQ(<mob98TVZ7ykVAYpKDAa`kWXdrZGWgup6Y;13LX>MmANklpzc4lsO zaCByFFfw#`GBI~IF*S2;d3j@ccQ9^ocx!euYIb3FV_|49Fk?1)H)v`xXl`{di2@u1 z009aB1_c6E1>jHs3JDOY{|eXM<N{bjUl0B{?Qmf=_z^Mbpin)8SP?UpfrF7079H(X z%@8CWYGSHF#tdJJu4xP}ny>jIZ4{SQhWpcq@>*A~cKt&7*dvU^OKPAsoC9PNOeQcG zk05~>KShhZ7*vUnqds44vZvVD<K(m;S_@{fTRgEc1+^ZvRDox4lH!-fnyGiY(jJ8s z)Iez`kqfZ;$v~N`LbRU8${Ph~3=3uQH_?$?`J`ha5ubX80P=H`&;v$MABa3Mylck3 zkH|3DE~OahD~Pd3a@mm|Ep;e17Mno`=&2_5SwUJ7Ap3038?5rx*jSvQ6vKCgO2$`C z_nVk3&?j3(N$Cqh>wqy3W7BEZUg(u|EAT99u~N^76f{nh`9{&iRwHA-Edjt7TTa>d zJL4Q!uKKX6>&qY%b_4trx8vYt(8sqKo7a2{SyjKVX8o|?RMiSDnz5yygs~QzPS2HC z93D^)^pL%T;y{+jjm7P>w$j3m>1&_vr$oeMydbYw(~BlZU%Bf-#Pz`=kO<HB7{jDi zOQ5&`Rve$I!V}Q>1t6A{$uqfi@vpqK+cUZ>wceNiJkRnvKMX_S2(hYCszBslx{%XZ zuQ%iHF+DL;&tmzrO^qRY1vB;ILLv^35S7xCV;l`DDkl{8NP&`eYMF@xmyv*WU!0~e WWdt-6h8J9bb7{6cta5wCYuC4+1~o?j literal 0 HcmV?d00001 -- GitLab From 8c8e73e0714cdd68e0c59814133de0d558827db0 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 25 Sep 2015 17:16:18 -0700 Subject: [PATCH 0007/1338] added pgp-keyring --- .sandstorm/pgp-keyring | Bin 0 -> 8435 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .sandstorm/pgp-keyring diff --git a/.sandstorm/pgp-keyring b/.sandstorm/pgp-keyring new file mode 100644 index 0000000000000000000000000000000000000000..ad9fabd672857d763016de2cb5db5a4c4a322507 GIT binary patch literal 8435 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 literal 0 HcmV?d00001 -- GitLab From 0c400713a5fb05caecfbda02ac179810f613116a Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Fri, 25 Sep 2015 20:17:24 -0400 Subject: [PATCH 0008/1338] fix capnp --- .sandstorm/CHANGELOG.md | 1 + .sandstorm/{grain.svg => rocet.chat-24.svg} | 0 .sandstorm/{appGrid.svg => rocket.chat-128.svg} | 0 .sandstorm/{market.svg => rocket.chat-150.svg} | 0 .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- 5 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .sandstorm/CHANGELOG.md rename .sandstorm/{grain.svg => rocet.chat-24.svg} (100%) rename .sandstorm/{appGrid.svg => rocket.chat-128.svg} (100%) rename .sandstorm/{market.svg => rocket.chat-150.svg} (100%) diff --git a/.sandstorm/CHANGELOG.md b/.sandstorm/CHANGELOG.md new file mode 100644 index 00000000000..8d14253d53f --- /dev/null +++ b/.sandstorm/CHANGELOG.md @@ -0,0 +1 @@ +### FIRST Sandstorm VERSION of Rocket.Chat diff --git a/.sandstorm/grain.svg b/.sandstorm/rocet.chat-24.svg similarity index 100% rename from .sandstorm/grain.svg rename to .sandstorm/rocet.chat-24.svg diff --git a/.sandstorm/appGrid.svg b/.sandstorm/rocket.chat-128.svg similarity index 100% rename from .sandstorm/appGrid.svg rename to .sandstorm/rocket.chat-128.svg diff --git a/.sandstorm/market.svg b/.sandstorm/rocket.chat-150.svg similarity index 100% rename from .sandstorm/market.svg rename to .sandstorm/rocket.chat-150.svg diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 5e409d6a103..50c67b607cf 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -59,11 +59,11 @@ const pkgdef :Spk.PackageDefinition = ( ), pgpKeyring = embed "pgp-keyring", - description = (defaultText = embed "README.md"), + description = (defaultText = embed "../README.md"), shortDescription = (defaultText = "Messaging App"), screenshots = [ - (width = 448, height = 343, png = embed "screenshot.png") + (width = 1024, height = 733, png = embed "screenshot.png") ], changeLog = (defaultText = embed "CHANGELOG.md"), -- GitLab From df18ffbd8434b2152cf14fd0c0fe936d9cf84066 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 25 Sep 2015 17:22:16 -0700 Subject: [PATCH 0009/1338] copied README.md into sandstorm-description.md --- .sandstorm/sandstorm-description.md | 213 ++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 .sandstorm/sandstorm-description.md diff --git a/.sandstorm/sandstorm-description.md b/.sandstorm/sandstorm-description.md new file mode 100644 index 00000000000..c7cccf624a5 --- /dev/null +++ b/.sandstorm/sandstorm-description.md @@ -0,0 +1,213 @@ + + +The Complete Open Source Chat Solution + +## Demo + +Checkout the latest version at [https://demo.rocket.chat](https://demo.rocket.chat) + +Get the app for your Android phone: + +[](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) + +Try it on Ubuntu: + +[Deploy on VPS or standalone server](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) + +Try it with docker: + +``` +docker-compose up +``` + +and check it out at http://localhost:80 + +Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron](https://github.com/RocketChat/Rocket.Chat.Electron/releases) + +[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) + +## About + +[](https://travis-ci.org/RocketChat/Rocket.Chat) +[](https://coveralls.io/r/RocketChat/Rocket.Chat) +[](https://codeclimate.com/github/RocketChat/Rocket.Chat) +[](https://github.com/RocketChat/Rocket.Chat/raw/master/LICENSE) + +Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](https://www.meteor.com/install) fullstack framework. + +It is a great solution for communities and companies wanting to privately host their own chat service or for developers looking forward to build and evolve their own chat platforms. + +### On the News + +##### [Hacker News](https://news.ycombinator.com/item?id=9624737) +> Yes, we made it to the #1 + +##### [Product Hunt](http://www.producthunt.com/posts/rocket-chat) +> Your own open source Slack-like chat + +##### [JavaScript Weekly](http://javascriptweekly.com/issues/234) +> An open source Web based, channel based chat system (a la Slack) built using Meteor, the full stack JavaScript development platform. + +##### [wwwhatsnew.com](http://wwwhatsnew.com/2015/05/30/rocket-chat-para-los-programadores-que-quieran-ofrecer-un-chat-en-su-web/) +> Para los programadores que quieran ofrecer un chat en su web + +##### [clasesdeperiodismo.com](http://www.clasesdeperiodismo.com/2015/05/30/un-chat-de-codigo-abierto-que-puedes-anadir-a-la-web/) +> Un chat de código abierto que puedes añadir a la web + +## Features + +- BYOS (bring your own server) +- Multiple Rooms +- Direct Messages +- Private Groups +- Public Channels +- Desktop Notifications +- Mentions +- Avatars +- Markdown +- Emojis +- Sent Message Edit and Deletion +- Transcripts / History +- File Upload / Sharing +- I18n - Supports 22 Languages [Internationalization with Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard) +- Hubot Friendly - [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) +- Media Embeds +- Link Previews +- LDAP Authentication - [LDAP Authentication on Rocket.Chat Wiki](https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication) +- Face to Face Video Conferencing aka WebRTC (Alpha) - [How to video chat](https://github.com/RocketChat/Rocket.Chat/wiki/Using-Face-to-face-video-conference-%28aka-webrtc%29) +- REST APIs - [Ready for testing ...](https://github.com/RocketChat/Rocket.Chat/wiki/REST-APIs) +- Remote Locations Video Monitoring - [Early access ...](https://github.com/RocketChat/Rocket.Chat/wiki/Remote-Video-Monitoring) +- Native Cross-Platform Desktop Application [Rocket.Chat.Electron - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.Electron/releases) +- Mobile app for iPhone, iPad, and iPod touch [Available now! - help us test](https://github.com/RocketChat/Rocket.Chat/wiki/Mobile-app-for-iPhones,-iPads,-iPod-Touch) +- Mobile app for Android phone, tablet, and TV stick [Available now on Google Play!](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) + +### Roadmap + +#### In Progress + +- Full text search +- Support for Okta SSO through SAML v2 [Issue #322](https://github.com/RocketChat/Rocket.Chat/issues/322) +- Native iOS Application [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) +- Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) +- External popout window for chat with website visitor, like Zopim, Olark, LiveChat, SnapEngage [Issue #519](https://github.com/RocketChat/Rocket.Chat/issues/519) + +#### Planned + +- Off-the-Record (OTR) Messaging [Issue #36 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/36) +- Kerberos Authentication +- XMPP Multi-user chat (MUC) + +### Issues + +[Github Issues](https://github.com/RocketChat/Rocket.Chat/issues) are used to track todos, bugs, feature requests, and more. + +### Integrations + +#### Hubot + +The docker image is ready. +Everyone can start hacking the adapter code, or launch his/her own bot within a few minutes now. +Please head over to the [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) for more information. + +#### Many, many, many more to come! + +We are developing the APIs based on the competition, so stay tunned and you will see a lot happening here. + +### Documentation + +Checkout [Github Wiki](https://github.com/RocketChat/Rocket.Chat/wiki) (coming soon) + +## Production Deployment + +### Unbuntu VPS or server + +Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker). + +### Docker + +Use the automated build at our [Official Docker Registry](https://registry.hub.docker.com/u/rocketchat/rocket.chat/) + +[](https://registry.hub.docker.com/u/rocketchat/rocket.chat/) + +``` +docker pull rocketchat/rocket.chat +``` + +### 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) + +### 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) + +[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/master) + + + +## Development Installation + +Prerequisites: + +* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [Meteor](https://www.meteor.com/install) + +Now just clone and start the app: + +```sh +git clone https://github.com/RocketChat/Rocket.Chat.git +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 +``` + +## Credits + +Thanks to +[Diego Sampaio](https://github.com/sampaiodiego), +[Gabriel Engel](https://github.com/engelgabriel), +[Marcelo Schmidt](https://github.com/marceloschmidt), +[Rafael Caferati](https://github.com/rcaferati), +[Rodrigo Nascimento](https://github.com/rodrigok), +[Sing Li](https://github.com/Sing-Li), +[Aaron Ogle](https://github.com/geekgonecrazy), +[Graywolf336](https://github.com/Graywolf336) + + +Emoji provided free by [Emoji One](http://emojione.com) + +Performance monitoring provided by [Kadira](https://kadira.io/) + +### Contributions + +#### We Need Your Help! + +A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it! + +So if you'd like to be part of the project, please check out the [roadmap](https://github.com/RocketChat/Rocket.Chat/milestones) and [issues](https://github.com/RocketChat/Rocket.Chat/issues) to see if there's anything you can help with. + +### Translations + +We are experimenting [Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard). +If you want to help, send an email to support at rocket.chat to be invited to the translation project. + +### Community + +Join the the conversation at [Twitter](http://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) + +### License + +Note that Rocket.Chat is distributed under the [MIT License](http://opensource.org/licenses/MIT). + +### Donate + +Rocket.Chat will be free forever, but you can help us speed-up the development! + +[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) -- GitLab From a0b138ef4b89be17875805a53c7ac341a980e0bb Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 25 Sep 2015 17:24:59 -0700 Subject: [PATCH 0010/1338] summarize --- .sandstorm/sandstorm-description.md | 214 +--------------------------- 1 file changed, 1 insertion(+), 213 deletions(-) diff --git a/.sandstorm/sandstorm-description.md b/.sandstorm/sandstorm-description.md index c7cccf624a5..7001f7c09a4 100644 --- a/.sandstorm/sandstorm-description.md +++ b/.sandstorm/sandstorm-description.md @@ -1,213 +1 @@ - - -The Complete Open Source Chat Solution - -## Demo - -Checkout the latest version at [https://demo.rocket.chat](https://demo.rocket.chat) - -Get the app for your Android phone: - -[](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) - -Try it on Ubuntu: - -[Deploy on VPS or standalone server](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) - -Try it with docker: - -``` -docker-compose up -``` - -and check it out at http://localhost:80 - -Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron](https://github.com/RocketChat/Rocket.Chat.Electron/releases) - -[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) - -## About - -[](https://travis-ci.org/RocketChat/Rocket.Chat) -[](https://coveralls.io/r/RocketChat/Rocket.Chat) -[](https://codeclimate.com/github/RocketChat/Rocket.Chat) -[](https://github.com/RocketChat/Rocket.Chat/raw/master/LICENSE) - -Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](https://www.meteor.com/install) fullstack framework. - -It is a great solution for communities and companies wanting to privately host their own chat service or for developers looking forward to build and evolve their own chat platforms. - -### On the News - -##### [Hacker News](https://news.ycombinator.com/item?id=9624737) -> Yes, we made it to the #1 - -##### [Product Hunt](http://www.producthunt.com/posts/rocket-chat) -> Your own open source Slack-like chat - -##### [JavaScript Weekly](http://javascriptweekly.com/issues/234) -> An open source Web based, channel based chat system (a la Slack) built using Meteor, the full stack JavaScript development platform. - -##### [wwwhatsnew.com](http://wwwhatsnew.com/2015/05/30/rocket-chat-para-los-programadores-que-quieran-ofrecer-un-chat-en-su-web/) -> Para los programadores que quieran ofrecer un chat en su web - -##### [clasesdeperiodismo.com](http://www.clasesdeperiodismo.com/2015/05/30/un-chat-de-codigo-abierto-que-puedes-anadir-a-la-web/) -> Un chat de código abierto que puedes añadir a la web - -## Features - -- BYOS (bring your own server) -- Multiple Rooms -- Direct Messages -- Private Groups -- Public Channels -- Desktop Notifications -- Mentions -- Avatars -- Markdown -- Emojis -- Sent Message Edit and Deletion -- Transcripts / History -- File Upload / Sharing -- I18n - Supports 22 Languages [Internationalization with Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard) -- Hubot Friendly - [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) -- Media Embeds -- Link Previews -- LDAP Authentication - [LDAP Authentication on Rocket.Chat Wiki](https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication) -- Face to Face Video Conferencing aka WebRTC (Alpha) - [How to video chat](https://github.com/RocketChat/Rocket.Chat/wiki/Using-Face-to-face-video-conference-%28aka-webrtc%29) -- REST APIs - [Ready for testing ...](https://github.com/RocketChat/Rocket.Chat/wiki/REST-APIs) -- Remote Locations Video Monitoring - [Early access ...](https://github.com/RocketChat/Rocket.Chat/wiki/Remote-Video-Monitoring) -- Native Cross-Platform Desktop Application [Rocket.Chat.Electron - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.Electron/releases) -- Mobile app for iPhone, iPad, and iPod touch [Available now! - help us test](https://github.com/RocketChat/Rocket.Chat/wiki/Mobile-app-for-iPhones,-iPads,-iPod-Touch) -- Mobile app for Android phone, tablet, and TV stick [Available now on Google Play!](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) - -### Roadmap - -#### In Progress - -- Full text search -- Support for Okta SSO through SAML v2 [Issue #322](https://github.com/RocketChat/Rocket.Chat/issues/322) -- Native iOS Application [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) -- Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) -- External popout window for chat with website visitor, like Zopim, Olark, LiveChat, SnapEngage [Issue #519](https://github.com/RocketChat/Rocket.Chat/issues/519) - -#### Planned - -- Off-the-Record (OTR) Messaging [Issue #36 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/36) -- Kerberos Authentication -- XMPP Multi-user chat (MUC) - -### Issues - -[Github Issues](https://github.com/RocketChat/Rocket.Chat/issues) are used to track todos, bugs, feature requests, and more. - -### Integrations - -#### Hubot - -The docker image is ready. -Everyone can start hacking the adapter code, or launch his/her own bot within a few minutes now. -Please head over to the [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) for more information. - -#### Many, many, many more to come! - -We are developing the APIs based on the competition, so stay tunned and you will see a lot happening here. - -### Documentation - -Checkout [Github Wiki](https://github.com/RocketChat/Rocket.Chat/wiki) (coming soon) - -## Production Deployment - -### Unbuntu VPS or server - -Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker). - -### Docker - -Use the automated build at our [Official Docker Registry](https://registry.hub.docker.com/u/rocketchat/rocket.chat/) - -[](https://registry.hub.docker.com/u/rocketchat/rocket.chat/) - -``` -docker pull rocketchat/rocket.chat -``` - -### 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) - -### 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) - -[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/master) - - - -## Development Installation - -Prerequisites: - -* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* [Meteor](https://www.meteor.com/install) - -Now just clone and start the app: - -```sh -git clone https://github.com/RocketChat/Rocket.Chat.git -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 -``` - -## Credits - -Thanks to -[Diego Sampaio](https://github.com/sampaiodiego), -[Gabriel Engel](https://github.com/engelgabriel), -[Marcelo Schmidt](https://github.com/marceloschmidt), -[Rafael Caferati](https://github.com/rcaferati), -[Rodrigo Nascimento](https://github.com/rodrigok), -[Sing Li](https://github.com/Sing-Li), -[Aaron Ogle](https://github.com/geekgonecrazy), -[Graywolf336](https://github.com/Graywolf336) - - -Emoji provided free by [Emoji One](http://emojione.com) - -Performance monitoring provided by [Kadira](https://kadira.io/) - -### Contributions - -#### We Need Your Help! - -A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it! - -So if you'd like to be part of the project, please check out the [roadmap](https://github.com/RocketChat/Rocket.Chat/milestones) and [issues](https://github.com/RocketChat/Rocket.Chat/issues) to see if there's anything you can help with. - -### Translations - -We are experimenting [Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard). -If you want to help, send an email to support at rocket.chat to be invited to the translation project. - -### Community - -Join the the conversation at [Twitter](http://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) - -### License - -Note that Rocket.Chat is distributed under the [MIT License](http://opensource.org/licenses/MIT). - -### Donate - -Rocket.Chat will be free forever, but you can help us speed-up the development! - -[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) +The Complete Open Source Chat Solution. Rocket.Chat is a Web Chat Server, developed in JavaScript. It is a great solution for communities and companies wanting to privately host their own chat service or for developers looking forward to build and evolve their own chat platforms. -- GitLab From 53536950adc691cf2c1b59c29ddad85e131558cc Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 25 Sep 2015 17:26:08 -0700 Subject: [PATCH 0011/1338] rename --- .sandstorm/{sandstorm-description.md => description.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .sandstorm/{sandstorm-description.md => description.md} (100%) diff --git a/.sandstorm/sandstorm-description.md b/.sandstorm/description.md similarity index 100% rename from .sandstorm/sandstorm-description.md rename to .sandstorm/description.md -- GitLab From 4a2fa1f13f4d9fcc616ea36438189b20ed3e2987 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Fri, 25 Sep 2015 20:28:49 -0400 Subject: [PATCH 0012/1338] smaller description --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 50c67b607cf..93e7d2b689b 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -59,7 +59,7 @@ const pkgdef :Spk.PackageDefinition = ( ), pgpKeyring = embed "pgp-keyring", - description = (defaultText = embed "../README.md"), + description = (defaultText = embed "description.md"), shortDescription = (defaultText = "Messaging App"), screenshots = [ -- GitLab From f0e78ea5b19a23584be801fd52c24b57381677a6 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Fri, 25 Sep 2015 23:00:02 -0400 Subject: [PATCH 0013/1338] sync with appstore version --- .../{rocet.chat-24.svg => rocket.chat-24.svg} | 0 .sandstorm/sandstorm-pkgdef.capnp | 10 +++++----- .sandstorm/screenshot.png | Bin 47452 -> 154050 bytes 3 files changed, 5 insertions(+), 5 deletions(-) rename .sandstorm/{rocet.chat-24.svg => rocket.chat-24.svg} (100%) diff --git a/.sandstorm/rocet.chat-24.svg b/.sandstorm/rocket.chat-24.svg similarity index 100% rename from .sandstorm/rocet.chat-24.svg rename to .sandstorm/rocket.chat-24.svg diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 93e7d2b689b..0041c47145b 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -34,7 +34,7 @@ const pkgdef :Spk.PackageDefinition = ( ) ], - continueCommand = .myCommand + continueCommand = .myCommand, # This is the command called to start your app back up after it has been # shut down for inactivity. Here we're using the same command as for # starting a new instance, but you could use different commands for each @@ -49,8 +49,8 @@ const pkgdef :Spk.PackageDefinition = ( website = "https://rocket.chat", codeUrl = "https://github.com/RocketChat/Rocket.Chat", - license = (openSource = MIT), - categories = [office, productivity], + license = (openSource = mit), + categories = [productivity], author = ( contactEmail = "team@rocket.chat", @@ -60,10 +60,10 @@ const pkgdef :Spk.PackageDefinition = ( pgpKeyring = embed "pgp-keyring", description = (defaultText = embed "description.md"), - shortDescription = (defaultText = "Messaging App"), + shortDescription = (defaultText = "Chat app"), screenshots = [ - (width = 1024, height = 733, png = embed "screenshot.png") + (width = 1203, height = 760, png = embed "screenshot.png") ], changeLog = (defaultText = embed "CHANGELOG.md"), diff --git a/.sandstorm/screenshot.png b/.sandstorm/screenshot.png index 2a1c10943cc35f37c91548c0fa9f9593dfaee0b1..49a876189745434222bee390e4456073ce054117 100644 GIT binary patch literal 154050 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 F{{x8PAQ=Dv literal 47452 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 MNlUR-!Rqz@0LOf80ssI2 -- GitLab From acd4a47a3912ea57e08a8a9ab1e14de5c9f9d12f Mon Sep 17 00:00:00 2001 From: erikmaarten <e.andersson@gmail.com> Date: Mon, 28 Sep 2015 20:28:16 +0200 Subject: [PATCH 0014/1338] Added category "communications" to metadata Communications seems to a better fit than productivity since this is primarily a chat app. (See specifications of categories here: https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/package.capnp) --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 0041c47145b..2c0b0f50c61 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -50,7 +50,7 @@ const pkgdef :Spk.PackageDefinition = ( website = "https://rocket.chat", codeUrl = "https://github.com/RocketChat/Rocket.Chat", license = (openSource = mit), - categories = [productivity], + categories = [communications, productivity], author = ( contactEmail = "team@rocket.chat", -- GitLab From f7cef1c2228956775ab2af19cd9edcbb67bd977f Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Wed, 30 Sep 2015 07:57:58 -0400 Subject: [PATCH 0015/1338] add travis build --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c518b60636b..9f24ff465cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ sudo: required language: node_js +branches: + only: + - travis-001 node_js: - "0.10" @@ -7,6 +10,9 @@ before_install: - "curl https://install.meteor.com | /bin/sh" script: + - meteor remove-platform ios + - meteor remove-platform android - meteor add rocketchat:livechat - meteor add rocketchat:hubot - - meteor build --server demo.rocket.chat ./ + - mkdir ./web + - meteor build ./web -- GitLab From 133f7850fffad59d384168d9464a28d53cd45ff4 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Wed, 30 Sep 2015 08:01:24 -0400 Subject: [PATCH 0016/1338] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9f24ff465cd..1886a908633 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: required language: node_js branches: only: - - travis-001 + - travis-001 node_js: - "0.10" -- GitLab From 0ecd158aacae2c08cab53c1b073ce46c41473d44 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Wed, 30 Sep 2015 08:11:23 -0400 Subject: [PATCH 0017/1338] try travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1886a908633..7b9912b6f63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,5 +14,5 @@ script: - meteor remove-platform android - meteor add rocketchat:livechat - meteor add rocketchat:hubot - - mkdir ./web - - meteor build ./web + - mkdir ../build + - meteor build ../build -- GitLab From fc610f7dbd35b7cffe2fe340ef40f6c04d39b5a5 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Wed, 30 Sep 2015 08:33:21 -0400 Subject: [PATCH 0018/1338] start from square one --- .meteor/versions | 3 +- .travis.yml | 2 - .../.npm/package/npm-shrinkwrap.json | 54 +++++++++---------- .../.npm/package/npm-shrinkwrap.json | 14 ++--- .../.npm/package/npm-shrinkwrap.json | 32 +++++------ 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 32d61434b64..e1541559ed8 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -137,13 +137,14 @@ rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 rocketchat:slashcommands-leave@0.0.1 +rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 rocketchat:webrtc@0.0.1 +rocketchat:wordpress@0.0.1 routepolicy@1.0.6 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 -rocketchat:wordpress@0.0.1 simple:highlight.js@1.0.9 simple:json-routes@1.0.4 spacebars@1.0.7 diff --git a/.travis.yml b/.travis.yml index 7b9912b6f63..cd4edb1e9ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,5 @@ before_install: script: - meteor remove-platform ios - meteor remove-platform android - - meteor add rocketchat:livechat - - meteor add rocketchat:hubot - mkdir ../build - meteor build ../build diff --git a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json index 4f676a0acb4..ad9fa4c8b9f 100644 --- a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json +++ b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json @@ -1,99 +1,99 @@ { "dependencies": { "connect": { - "version": "2.7.10", + "version": "http://registry.npmjs.org/connect/-/connect-2.7.10.tgz", "dependencies": { "qs": { - "version": "0.6.5" + "version": "http://registry.npmjs.org/qs/-/qs-0.6.5.tgz" }, "formidable": { - "version": "1.0.14" + "version": "http://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz" }, "cookie-signature": { - "version": "1.0.1" + "version": "http://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz" }, "buffer-crc32": { - "version": "0.2.1" + "version": "http://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz" }, "cookie": { - "version": "0.0.5" + "version": "http://registry.npmjs.org/cookie/-/cookie-0.0.5.tgz" }, "send": { - "version": "0.1.0", + "version": "http://registry.npmjs.org/send/-/send-0.1.0.tgz", "dependencies": { "mime": { - "version": "1.2.6" + "version": "http://registry.npmjs.org/mime/-/mime-1.2.6.tgz" }, "range-parser": { - "version": "0.0.4" + "version": "http://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz" } } }, "bytes": { - "version": "0.2.0" + "version": "http://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz" }, "fresh": { - "version": "0.1.0" + "version": "http://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz" }, "pause": { - "version": "0.0.1" + "version": "http://registry.npmjs.org/pause/-/pause-0.0.1.tgz" }, "debug": { - "version": "2.2.0", + "version": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "dependencies": { "ms": { - "version": "0.7.1" + "version": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz" } } } } }, "querystring": { - "version": "0.2.0" + "version": "http://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" }, "xml-crypto": { - "version": "0.6.0", + "version": "http://registry.npmjs.org/xml-crypto/-/xml-crypto-0.6.0.tgz", "dependencies": { "xpath.js": { - "version": "1.0.6" + "version": "http://registry.npmjs.org/xpath.js/-/xpath.js-1.0.6.tgz" } } }, "xml-encryption": { - "version": "0.7.2", + "version": "http://registry.npmjs.org/xml-encryption/-/xml-encryption-0.7.2.tgz", "dependencies": { "ejs": { - "version": "0.8.8" + "version": "http://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz" }, "async": { - "version": "0.2.10" + "version": "http://registry.npmjs.org/async/-/async-0.2.10.tgz" }, "xpath": { - "version": "0.0.5" + "version": "http://registry.npmjs.org/xpath/-/xpath-0.0.5.tgz" }, "node-forge": { - "version": "0.2.24" + "version": "http://registry.npmjs.org/node-forge/-/node-forge-0.2.24.tgz" } } }, "xml2js": { - "version": "0.2.0", + "version": "http://registry.npmjs.org/xml2js/-/xml2js-0.2.0.tgz", "dependencies": { "sax": { - "version": "1.1.2" + "version": "http://registry.npmjs.org/sax/-/sax-1.1.2.tgz" } } }, "xmlbuilder": { - "version": "2.6.4", + "version": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.4.tgz", "dependencies": { "lodash": { - "version": "3.10.1" + "version": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" } } }, "xmldom": { - "version": "0.1.19" + "version": "http://registry.npmjs.org/xmldom/-/xmldom-0.1.19.tgz" } } } diff --git a/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json index bf4b8acb16e..a8ecae95ec9 100644 --- a/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json @@ -1,29 +1,29 @@ { "dependencies": { "gm": { - "version": "1.18.1", + "version": "http://registry.npmjs.org/gm/-/gm-1.18.1.tgz", "dependencies": { "debug": { - "version": "2.2.0", + "version": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "dependencies": { "ms": { - "version": "0.7.1" + "version": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz" } } }, "array-series": { - "version": "0.1.5" + "version": "http://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz" }, "array-parallel": { - "version": "0.1.3" + "version": "http://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz" } } }, "gridfs-stream": { - "version": "0.5.3" + "version": "http://registry.npmjs.org/gridfs-stream/-/gridfs-stream-0.5.3.tgz" }, "mkdirp": { - "version": "0.3.5" + "version": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz" } } } diff --git a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json index 3dd543e2c5e..db1eb39703a 100644 --- a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json @@ -1,58 +1,58 @@ { "dependencies": { "ldapjs": { - "version": "0.7.1", + "version": "http://registry.npmjs.org/ldapjs/-/ldapjs-0.7.1.tgz", "dependencies": { "asn1": { - "version": "0.2.1" + "version": "http://registry.npmjs.org/asn1/-/asn1-0.2.1.tgz" }, "assert-plus": { - "version": "0.1.5" + "version": "http://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" }, "bunyan": { - "version": "0.22.1", + "version": "http://registry.npmjs.org/bunyan/-/bunyan-0.22.1.tgz", "dependencies": { "mv": { - "version": "0.0.5" + "version": "http://registry.npmjs.org/mv/-/mv-0.0.5.tgz" } } }, "nopt": { - "version": "2.1.1", + "version": "http://registry.npmjs.org/nopt/-/nopt-2.1.1.tgz", "dependencies": { "abbrev": { - "version": "1.0.7" + "version": "http://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" } } }, "pooling": { - "version": "0.4.6", + "version": "http://registry.npmjs.org/pooling/-/pooling-0.4.6.tgz", "dependencies": { "once": { - "version": "1.3.0" + "version": "http://registry.npmjs.org/once/-/once-1.3.0.tgz" }, "vasync": { - "version": "1.4.0", + "version": "http://registry.npmjs.org/vasync/-/vasync-1.4.0.tgz", "dependencies": { "jsprim": { - "version": "0.3.0", + "version": "http://registry.npmjs.org/jsprim/-/jsprim-0.3.0.tgz", "dependencies": { "extsprintf": { - "version": "1.0.0" + "version": "http://registry.npmjs.org/extsprintf/-/extsprintf-1.0.0.tgz" }, "json-schema": { - "version": "0.2.2" + "version": "http://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" }, "verror": { - "version": "1.3.3" + "version": "http://registry.npmjs.org/verror/-/verror-1.3.3.tgz" } } }, "verror": { - "version": "1.1.0", + "version": "http://registry.npmjs.org/verror/-/verror-1.1.0.tgz", "dependencies": { "extsprintf": { - "version": "1.0.0" + "version": "http://registry.npmjs.org/extsprintf/-/extsprintf-1.0.0.tgz" } } } -- GitLab From 363e59e5a41e16b0596cd7e186f5c5b89e59c153 Mon Sep 17 00:00:00 2001 From: westmakaha <westmakaha@makawave.com> Date: Wed, 30 Sep 2015 08:39:51 -0400 Subject: [PATCH 0019/1338] start from square one --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index cd4edb1e9ce..100ce646edd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,5 @@ before_install: - "curl https://install.meteor.com | /bin/sh" script: - - meteor remove-platform ios - - meteor remove-platform android - mkdir ../build - meteor build ../build -- GitLab From d2ddcb18a3c6924450426afb6f9fa423e0c165a1 Mon Sep 17 00:00:00 2001 From: Sing-Li <sli@makawave.com> Date: Sat, 3 Oct 2015 23:26:58 -0400 Subject: [PATCH 0020/1338] add buildinfo --- public/buildinfo/buildinfo.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 public/buildinfo/buildinfo.txt diff --git a/public/buildinfo/buildinfo.txt b/public/buildinfo/buildinfo.txt new file mode 100644 index 00000000000..b5efce9fb5f --- /dev/null +++ b/public/buildinfo/buildinfo.txt @@ -0,0 +1,2 @@ +v0.6.dev + -- GitLab From 7ead18666070b6400922882866cc603984b9a459 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 5 Oct 2015 14:46:10 -0300 Subject: [PATCH 0021/1338] Move all styles to inside the package --- client/stylesheets/global/_variables.less | 40 ----------- client/views/main.html | 2 +- .../.npm/package/npm-shrinkwrap.json | 20 +++--- .../assets}/stylesheets/animation.css | 0 .../assets}/stylesheets/base.less | 8 --- .../assets}/stylesheets/fontello.css | 0 .../assets/stylesheets/global/_variables.less | 7 ++ .../assets}/stylesheets/rtl.less | 0 .../assets}/stylesheets/swipebox.min.css | 0 .../stylesheets/utils/_colors.import.less | 0 .../stylesheets/utils/_emojione.import.less | 0 .../stylesheets/utils/_fonts.import.less | 0 .../stylesheets/utils/_keyframes.import.less | 0 .../stylesheets/utils/_lesshat.import.less | 0 .../stylesheets/utils/_preloader.import.less | 0 .../stylesheets/utils/_reset.import.less | 0 .../rocketchat-theme-colors/client.coffee | 9 +++ packages/rocketchat-theme-colors/package.js | 36 +++++++++- .../rocketchat-theme-colors/server.coffee | 66 +++++++++---------- .../rocketchat-theme-colors/variables.coffee | 44 +++++++++++++ 20 files changed, 134 insertions(+), 98 deletions(-) delete mode 100644 client/stylesheets/global/_variables.less rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/animation.css (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/base.less (99%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/fontello.css (100%) create mode 100644 packages/rocketchat-theme-colors/assets/stylesheets/global/_variables.less rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/rtl.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/swipebox.min.css (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_colors.import.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_emojione.import.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_fonts.import.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_keyframes.import.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_lesshat.import.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_preloader.import.less (100%) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_reset.import.less (100%) create mode 100644 packages/rocketchat-theme-colors/client.coffee create mode 100644 packages/rocketchat-theme-colors/variables.coffee diff --git a/client/stylesheets/global/_variables.less b/client/stylesheets/global/_variables.less deleted file mode 100644 index 891666d2189..00000000000 --- a/client/stylesheets/global/_variables.less +++ /dev/null @@ -1,40 +0,0 @@ -@header-min-height: 60px; -@footer-min-height: 70px; - -@rooms-box-width: 260px; -@flex-tab-width: 400px; -@flex-tab-webrtc-width: 400px; -@flex-tab-webrtc-2-width: 850px; - -// Colors -// -------------- - -@content-background-color: #FFF; - -@primary-background-color: #04436A; -@secondary-background-color: #F4F4F4; -@tertiary-background-color: #EAEAEA; - -@primary-font-color: #444444; -@secondary-font-color: #7F7F7F; -@tertiary-font-color: rgba(255, 255, 255, 0.6); - -@input-font-color: rgba(255, 255, 255, 0.85); -@link-font-color: #008CE3; - -@info-font-color: #AAAAAA; -@info-active-font-color: #FF0000; - -@smallprint-font-color: #C2E7FF; -@smallprint-hover-color: white; - -@status-online: #35AC19; -@status-offline: rgba(150, 150, 150, 0.50); -@status-busy: #D30230; -@status-away: #FCB316; - -@code-background: #F8F8F8; -@code-border: #CCC; -@code-color: #333; -@blockquote-background: #CCC; - diff --git a/client/views/main.html b/client/views/main.html index 365ad0c3647..8b898cd2ab3 100644 --- a/client/views/main.html +++ b/client/views/main.html @@ -34,7 +34,7 @@ <link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-touch-icon-144x144.png?v=3"> <link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-touch-icon-152x152.png?v=3"> <link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png?v=3"> - <link rel="stylesheet" type="text/css" href="/theme-colors.css"> + <link rel="stylesheet" type="text/css" href="/theme-colors.css" id="theme-colors"> </head> <body> diff --git a/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json index 6493bf3d83a..69c24b72239 100644 --- a/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json @@ -37,7 +37,7 @@ } }, "request": { - "version": "2.61.0", + "version": "2.64.0", "dependencies": { "bl": { "version": "1.0.0", @@ -55,7 +55,7 @@ "version": "0.0.1" }, "process-nextick-args": { - "version": "1.0.2" + "version": "1.0.3" }, "string_decoder": { "version": "0.10.31" @@ -88,10 +88,10 @@ "version": "5.0.1" }, "mime-types": { - "version": "2.1.6", + "version": "2.1.7", "dependencies": { "mime-db": { - "version": "1.18.0" + "version": "1.19.0" } } }, @@ -99,13 +99,13 @@ "version": "1.4.3" }, "qs": { - "version": "4.0.0" + "version": "5.1.0" }, "tunnel-agent": { "version": "0.4.1" }, "tough-cookie": { - "version": "2.0.0" + "version": "2.1.0" }, "http-signature": { "version": "0.11.0", @@ -128,13 +128,13 @@ "version": "3.1.0", "dependencies": { "hoek": { - "version": "2.14.0" + "version": "2.16.3" }, "boom": { - "version": "2.8.0" + "version": "2.9.0" }, "cryptiles": { - "version": "2.0.4" + "version": "2.0.5" }, "sntp": { "version": "1.0.9" @@ -162,7 +162,7 @@ "version": "1.8.0", "dependencies": { "bluebird": { - "version": "2.9.34" + "version": "2.10.2" }, "chalk": { "version": "1.1.1", diff --git a/client/stylesheets/animation.css b/packages/rocketchat-theme-colors/assets/stylesheets/animation.css similarity index 100% rename from client/stylesheets/animation.css rename to packages/rocketchat-theme-colors/assets/stylesheets/animation.css diff --git a/client/stylesheets/base.less b/packages/rocketchat-theme-colors/assets/stylesheets/base.less similarity index 99% rename from client/stylesheets/base.less rename to packages/rocketchat-theme-colors/assets/stylesheets/base.less index 78cab9c58af..de4ed45f409 100644 --- a/client/stylesheets/base.less +++ b/packages/rocketchat-theme-colors/assets/stylesheets/base.less @@ -1,10 +1,3 @@ -@import "global/_variables.less"; -@import "utils/_lesshat.import.less"; -@import "utils/_reset.import.less"; -@import "utils/_keyframes.import.less"; -@import "utils/_preloader.import.less"; -@import "utils/_emojione.import.less"; -@import "utils/_fonts.import.less"; .clearfix { clear: both; &::after { @@ -3865,4 +3858,3 @@ a.github-fork { } } -@import "utils/_colors.import.less"; diff --git a/client/stylesheets/fontello.css b/packages/rocketchat-theme-colors/assets/stylesheets/fontello.css similarity index 100% rename from client/stylesheets/fontello.css rename to packages/rocketchat-theme-colors/assets/stylesheets/fontello.css diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/global/_variables.less b/packages/rocketchat-theme-colors/assets/stylesheets/global/_variables.less new file mode 100644 index 00000000000..8eb4b9c9a76 --- /dev/null +++ b/packages/rocketchat-theme-colors/assets/stylesheets/global/_variables.less @@ -0,0 +1,7 @@ +@header-min-height: 60px; +@footer-min-height: 70px; + +@rooms-box-width: 260px; +@flex-tab-width: 400px; +@flex-tab-webrtc-width: 400px; +@flex-tab-webrtc-2-width: 850px; diff --git a/client/stylesheets/rtl.less b/packages/rocketchat-theme-colors/assets/stylesheets/rtl.less similarity index 100% rename from client/stylesheets/rtl.less rename to packages/rocketchat-theme-colors/assets/stylesheets/rtl.less diff --git a/client/stylesheets/swipebox.min.css b/packages/rocketchat-theme-colors/assets/stylesheets/swipebox.min.css similarity index 100% rename from client/stylesheets/swipebox.min.css rename to packages/rocketchat-theme-colors/assets/stylesheets/swipebox.min.css diff --git a/client/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_colors.import.less similarity index 100% rename from client/stylesheets/utils/_colors.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_colors.import.less diff --git a/client/stylesheets/utils/_emojione.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_emojione.import.less similarity index 100% rename from client/stylesheets/utils/_emojione.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_emojione.import.less diff --git a/client/stylesheets/utils/_fonts.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_fonts.import.less similarity index 100% rename from client/stylesheets/utils/_fonts.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_fonts.import.less diff --git a/client/stylesheets/utils/_keyframes.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_keyframes.import.less similarity index 100% rename from client/stylesheets/utils/_keyframes.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_keyframes.import.less diff --git a/client/stylesheets/utils/_lesshat.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_lesshat.import.less similarity index 100% rename from client/stylesheets/utils/_lesshat.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_lesshat.import.less diff --git a/client/stylesheets/utils/_preloader.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_preloader.import.less similarity index 100% rename from client/stylesheets/utils/_preloader.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_preloader.import.less diff --git a/client/stylesheets/utils/_reset.import.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_reset.import.less similarity index 100% rename from client/stylesheets/utils/_reset.import.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_reset.import.less diff --git a/packages/rocketchat-theme-colors/client.coffee b/packages/rocketchat-theme-colors/client.coffee new file mode 100644 index 00000000000..32a095eddc3 --- /dev/null +++ b/packages/rocketchat-theme-colors/client.coffee @@ -0,0 +1,9 @@ +Meteor.startup -> + el = $('#theme-colors')[0] + + connected = Meteor.status().connected + Tracker.autorun -> + if connected is false and Meteor.status().connected is true + el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() + console.log el.href + connected = Meteor.status().connected diff --git a/packages/rocketchat-theme-colors/package.js b/packages/rocketchat-theme-colors/package.js index 62b4e326371..7271849e8a9 100644 --- a/packages/rocketchat-theme-colors/package.js +++ b/packages/rocketchat-theme-colors/package.js @@ -10,11 +10,41 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('webapp'); + api.use('less@2.5.0_3'); + api.addFiles('variables.coffee', 'server'); api.addFiles('server.coffee', 'server'); - - api.addFiles('assets/lesshat.import.less', 'server', {isAsset: true}); - api.addFiles('assets/colors.less', 'server', {isAsset: true}); + api.addFiles('client.coffee', 'client'); + + // api.addFiles('assets/stylesheets/global/_variables.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_colors.import.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_emojione.import.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_fonts.import.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_keyframes.import.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_lesshat.import.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_preloader.import.less', 'client'); + // api.addFiles('assets/stylesheets/utils/_reset.import.less', 'client'); + // api.addFiles('assets/stylesheets/animation.css', 'client'); + // api.addFiles('assets/stylesheets/base.less', 'client'); + // api.addFiles('assets/stylesheets/fontello.css', 'client'); + // api.addFiles('assets/stylesheets/rtl.less', 'client'); + // api.addFiles('assets/stylesheets/swipebox.min.css', 'client'); + + api.addAssets('assets/stylesheets/global/_variables.less', 'server'); + api.addAssets('assets/stylesheets/utils/_colors.import.less', 'server'); + api.addAssets('assets/stylesheets/utils/_emojione.import.less', 'server'); + api.addAssets('assets/stylesheets/utils/_fonts.import.less', 'server'); + api.addAssets('assets/stylesheets/utils/_keyframes.import.less', 'server'); + api.addAssets('assets/stylesheets/utils/_lesshat.import.less', 'server'); + api.addAssets('assets/stylesheets/utils/_preloader.import.less', 'server'); + api.addAssets('assets/stylesheets/utils/_reset.import.less', 'server'); + api.addAssets('assets/stylesheets/animation.css', 'server'); + api.addAssets('assets/stylesheets/base.less', 'server'); + api.addAssets('assets/stylesheets/fontello.css', 'server'); + api.addAssets('assets/stylesheets/rtl.less', 'server'); + api.addAssets('assets/stylesheets/swipebox.min.css', 'server'); + + api.addAssets('assets/colors.less', 'server'); api.export('less', 'server'); api.export('getText', 'server'); diff --git a/packages/rocketchat-theme-colors/server.coffee b/packages/rocketchat-theme-colors/server.coffee index 3b9fdd47a03..7230087ad5b 100644 --- a/packages/rocketchat-theme-colors/server.coffee +++ b/packages/rocketchat-theme-colors/server.coffee @@ -1,44 +1,37 @@ + + less = Npm.require('less') getText = (file) -> Assets.getText file getAndCompile = (cb) -> - variables = """ - @content-background-color: #FFF; - - @primary-background-color: #04436A; - @secondary-background-color: #F4F4F4; - @tertiary-background-color: #EAEAEA; - - @primary-font-color: #444444; - @secondary-font-color: #7F7F7F; - @tertiary-font-color: rgba(255, 255, 255, 0.6); - - @input-font-color: rgba(255, 255, 255, 0.85); - @link-font-color: #008CE3; - - @info-font-color: #AAAAAA; - @info-active-font-color: #FF0000; - @smallprint-font-color: #C2E7FF; - @smallprint-hover-color: white; - - @status-online: #35AC19; - @status-offline: rgba(150, 150, 150, 0.50); - @status-busy: #D30230; - @status-away: #FCB316; - - @code-background: #F8F8F8; - @code-border: #CCC; - @code-color: #333; - @blockquote-background: #CCC; - """ - - lesshat = Assets.getText 'assets/lesshat.import.less' - colors = Assets.getText 'assets/colors.less' - - colors = [lesshat, variables, colors].join '\n' + # lesshat = Assets.getText 'assets/lesshat.import.less' + # colors = Assets.getText 'assets/colors.less' + + files = [ + variables.getAsLess() + Assets.getText 'assets/stylesheets/global/_variables.less' + # Assets.getText 'assets/stylesheets/utils/_colors.import.less' + Assets.getText 'assets/stylesheets/utils/_emojione.import.less' + Assets.getText 'assets/stylesheets/utils/_fonts.import.less' + Assets.getText 'assets/stylesheets/utils/_keyframes.import.less' + Assets.getText 'assets/stylesheets/utils/_lesshat.import.less' + Assets.getText 'assets/stylesheets/utils/_preloader.import.less' + Assets.getText 'assets/stylesheets/utils/_reset.import.less' + Assets.getText 'assets/stylesheets/animation.css' + Assets.getText 'assets/stylesheets/base.less' + Assets.getText 'assets/stylesheets/fontello.css' + Assets.getText 'assets/stylesheets/rtl.less' + Assets.getText 'assets/stylesheets/swipebox.min.css' + + # variables + Assets.getText 'assets/colors.less' + ] + + # colors = [lesshat, variables, colors].join '\n' + colors = files.join '\n' options = compress: true @@ -46,8 +39,10 @@ getAndCompile = (cb) -> less.render colors, options, cb WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> + console.log 'start rendering' + start = Date.now() getAndCompile (err, data) -> - + console.log 'stop rendering', Date.now() - start, err res.setHeader 'content-type', 'text/css; charset=UTF-8' res.setHeader 'Content-Disposition', 'inline' res.setHeader 'Cache-Control', 'no-cache' @@ -56,4 +51,3 @@ WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> res.setHeader 'Content-Length', data.css.length * 8 res.end data.css - # less.render colors diff --git a/packages/rocketchat-theme-colors/variables.coffee b/packages/rocketchat-theme-colors/variables.coffee new file mode 100644 index 00000000000..652650fa103 --- /dev/null +++ b/packages/rocketchat-theme-colors/variables.coffee @@ -0,0 +1,44 @@ +@variables = new class + data: {} + + addColor: (name, value) -> + @data[name] = + value: value + type: "color" + + getAsObject: -> + obj = {} + for name, item of @data + obj[name] = item.value + + return obj + + getAsLess: -> + items = [] + for name, item of @data + items.push "@#{name}: #{item.value};" + + return items.join '\n' + + +variables.addColor "content-background-color", "#FFF" +variables.addColor "primary-background-color", "#04436A" +variables.addColor "secondary-background-color", "#F4F4F4" +variables.addColor "tertiary-background-color", "#EAEAEA" +variables.addColor "primary-font-color", "#444444" +variables.addColor "secondary-font-color", "#7F7F7F" +variables.addColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" +variables.addColor "input-font-color", "rgba(255, 255, 255, 0.85)" +variables.addColor "link-font-color", "#008CE3" +variables.addColor "info-font-color", "#AAAAAA" +variables.addColor "info-active-font-color", "#FF0000" +variables.addColor "smallprint-font-color", "#C2E7FF" +variables.addColor "smallprint-hover-color", "white" +variables.addColor "status-online", "#35AC19" +variables.addColor "status-offline", "rgba(150, 150, 150, 0.50)" +variables.addColor "status-busy", "#D30230" +variables.addColor "status-away", "#FCB316" +variables.addColor "code-background", "#F8F8F8" +variables.addColor "code-border", "#CCC" +variables.addColor "code-color", "#333" +variables.addColor "blockquote-background", "#CCC" -- GitLab From 6abf7153d21daffa9b4798673c42242e7c52a579 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 5 Oct 2015 15:21:41 -0300 Subject: [PATCH 0022/1338] Use settings as cache --- .../settings/server/methods.coffee | 15 +++++-- packages/rocketchat-theme-colors/package.js | 1 + .../rocketchat-theme-colors/server.coffee | 44 ++++++++++--------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 35ee3c35c7a..729522f1642 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -4,7 +4,6 @@ # @param {Mixed} value # @param {Object} setting ### - RocketChat.settings.add = (_id, value, options = {}) -> if not _id or not value? return false @@ -33,11 +32,11 @@ RocketChat.settings.add = (_id, value, options = {}) -> return RocketChat.models.Settings.upsert { _id: _id }, upsertChanges + ### # Add a setting group # @param {String} _id ### - RocketChat.settings.addGroup = (_id, options = {}) -> if not _id return false @@ -58,11 +57,11 @@ RocketChat.settings.addGroup = (_id, options = {}) -> return RocketChat.models.Settings.upsert { _id: _id }, upsertChanges + ### # Remove a setting by id # @param {String} _id ### - RocketChat.settings.removeById = (_id) -> if not _id return false @@ -72,6 +71,14 @@ RocketChat.settings.removeById = (_id) -> return RocketChat.models.Settings.removeById _id +### +# Update a setting by id +# @param {String} _id +### +RocketChat.settings.updateById = (_id, value) -> + RocketChat.models.Settings.updateValueById _id, value + + Meteor.methods saveSetting: (_id, value) -> console.log '[method] saveSetting', _id, value @@ -82,5 +89,5 @@ Meteor.methods throw new Meteor.Error 503, 'Not authorized' # console.log "saveSetting -> ".green, _id, value - RocketChat.models.Settings.updateValueById _id, value + RocketChat.settings.updateById _id, value return true diff --git a/packages/rocketchat-theme-colors/package.js b/packages/rocketchat-theme-colors/package.js index 7271849e8a9..f19203fa7b6 100644 --- a/packages/rocketchat-theme-colors/package.js +++ b/packages/rocketchat-theme-colors/package.js @@ -8,6 +8,7 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); + api.use('rocketchat:lib'); api.use('coffeescript'); api.use('webapp'); api.use('less@2.5.0_3'); diff --git a/packages/rocketchat-theme-colors/server.coffee b/packages/rocketchat-theme-colors/server.coffee index 7230087ad5b..a1ba3d8c14a 100644 --- a/packages/rocketchat-theme-colors/server.coffee +++ b/packages/rocketchat-theme-colors/server.coffee @@ -1,4 +1,4 @@ - +RocketChat.settings.add 'css', '' less = Npm.require('less') @@ -7,13 +7,9 @@ getText = (file) -> getAndCompile = (cb) -> - # lesshat = Assets.getText 'assets/lesshat.import.less' - # colors = Assets.getText 'assets/colors.less' - files = [ variables.getAsLess() Assets.getText 'assets/stylesheets/global/_variables.less' - # Assets.getText 'assets/stylesheets/utils/_colors.import.less' Assets.getText 'assets/stylesheets/utils/_emojione.import.less' Assets.getText 'assets/stylesheets/utils/_fonts.import.less' Assets.getText 'assets/stylesheets/utils/_keyframes.import.less' @@ -25,29 +21,35 @@ getAndCompile = (cb) -> Assets.getText 'assets/stylesheets/fontello.css' Assets.getText 'assets/stylesheets/rtl.less' Assets.getText 'assets/stylesheets/swipebox.min.css' - - # variables Assets.getText 'assets/colors.less' ] - # colors = [lesshat, variables, colors].join '\n' colors = files.join '\n' options = compress: true - less.render colors, options, cb - -WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> console.log 'start rendering' start = Date.now() - getAndCompile (err, data) -> - console.log 'stop rendering', Date.now() - start, err - res.setHeader 'content-type', 'text/css; charset=UTF-8' - res.setHeader 'Content-Disposition', 'inline' - res.setHeader 'Cache-Control', 'no-cache' - res.setHeader 'Pragma', 'no-cache' - res.setHeader 'Expires', '0' - res.setHeader 'Content-Length', data.css.length * 8 - - res.end data.css + less.render colors, options, (err, data) -> + console.log 'stop rendering', Date.now() - start + if err? + return console.log err + + RocketChat.settings.updateById 'css', data.css + + +getAndCompile() + + +WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> + css = RocketChat.settings.get 'css' + + res.setHeader 'content-type', 'text/css; charset=UTF-8' + res.setHeader 'Content-Disposition', 'inline' + res.setHeader 'Cache-Control', 'no-cache' + res.setHeader 'Pragma', 'no-cache' + res.setHeader 'Expires', '0' + res.setHeader 'Content-Length', css.length * 8 + + res.end css -- GitLab From 800137026c55ecd7985f815a1ea0b0c5987ef655 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 5 Oct 2015 15:32:05 -0300 Subject: [PATCH 0023/1338] Improve code --- .../rocketchat-theme-colors/client.coffee | 2 +- packages/rocketchat-theme-colors/package.js | 2 +- .../rocketchat-theme-colors/server.coffee | 90 ++++++++++++------- .../rocketchat-theme-colors/variables.coffee | 65 +++++--------- 4 files changed, 80 insertions(+), 79 deletions(-) diff --git a/packages/rocketchat-theme-colors/client.coffee b/packages/rocketchat-theme-colors/client.coffee index 32a095eddc3..0ac4faa79b6 100644 --- a/packages/rocketchat-theme-colors/client.coffee +++ b/packages/rocketchat-theme-colors/client.coffee @@ -5,5 +5,5 @@ Meteor.startup -> Tracker.autorun -> if connected is false and Meteor.status().connected is true el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() - console.log el.href + connected = Meteor.status().connected diff --git a/packages/rocketchat-theme-colors/package.js b/packages/rocketchat-theme-colors/package.js index f19203fa7b6..1b9efa12315 100644 --- a/packages/rocketchat-theme-colors/package.js +++ b/packages/rocketchat-theme-colors/package.js @@ -13,8 +13,8 @@ Package.onUse(function(api) { api.use('webapp'); api.use('less@2.5.0_3'); - api.addFiles('variables.coffee', 'server'); api.addFiles('server.coffee', 'server'); + api.addFiles('variables.coffee', 'server'); api.addFiles('client.coffee', 'client'); // api.addFiles('assets/stylesheets/global/_variables.less', 'client'); diff --git a/packages/rocketchat-theme-colors/server.coffee b/packages/rocketchat-theme-colors/server.coffee index a1ba3d8c14a..dda42e38381 100644 --- a/packages/rocketchat-theme-colors/server.coffee +++ b/packages/rocketchat-theme-colors/server.coffee @@ -1,49 +1,71 @@ -RocketChat.settings.add 'css', '' - less = Npm.require('less') -getText = (file) -> - Assets.getText file - -getAndCompile = (cb) -> - - files = [ - variables.getAsLess() - Assets.getText 'assets/stylesheets/global/_variables.less' - Assets.getText 'assets/stylesheets/utils/_emojione.import.less' - Assets.getText 'assets/stylesheets/utils/_fonts.import.less' - Assets.getText 'assets/stylesheets/utils/_keyframes.import.less' - Assets.getText 'assets/stylesheets/utils/_lesshat.import.less' - Assets.getText 'assets/stylesheets/utils/_preloader.import.less' - Assets.getText 'assets/stylesheets/utils/_reset.import.less' - Assets.getText 'assets/stylesheets/animation.css' - Assets.getText 'assets/stylesheets/base.less' - Assets.getText 'assets/stylesheets/fontello.css' - Assets.getText 'assets/stylesheets/rtl.less' - Assets.getText 'assets/stylesheets/swipebox.min.css' - Assets.getText 'assets/colors.less' +RocketChat.theme = new class + variables: {} + files: [ + 'assets/stylesheets/global/_variables.less' + 'assets/stylesheets/utils/_emojione.import.less' + 'assets/stylesheets/utils/_fonts.import.less' + 'assets/stylesheets/utils/_keyframes.import.less' + 'assets/stylesheets/utils/_lesshat.import.less' + 'assets/stylesheets/utils/_preloader.import.less' + 'assets/stylesheets/utils/_reset.import.less' + 'assets/stylesheets/animation.css' + 'assets/stylesheets/base.less' + 'assets/stylesheets/fontello.css' + 'assets/stylesheets/rtl.less' + 'assets/stylesheets/swipebox.min.css' + 'assets/colors.less' ] - colors = files.join '\n' + constructor: -> + RocketChat.settings.add 'css', '' + + compile: -> + content = [ + @getVariablesAsLess() + ] + + content.push Assets.getText file for file in @files + + content = content.join '\n' + + options = + compress: true + + start = Date.now() + less.render content, options, (err, data) -> + console.log 'stop rendering', Date.now() - start + if err? + return console.log err + + RocketChat.settings.updateById 'css', data.css + + addColor: (name, value) -> + @variables[name] = + value: value + type: "color" - options = - compress: true + getVariablesAsObject: -> + obj = {} + for name, variable of @variables + obj[name] = variable.value - console.log 'start rendering' - start = Date.now() - less.render colors, options, (err, data) -> - console.log 'stop rendering', Date.now() - start - if err? - return console.log err + return obj - RocketChat.settings.updateById 'css', data.css + getVariablesAsLess: -> + items = [] + for name, variable of @variables + items.push "@#{name}: #{variable.value};" + return items.join '\n' -getAndCompile() + getCss: -> + return RocketChat.settings.get 'css' WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> - css = RocketChat.settings.get 'css' + css = RocketChat.theme.getCss() res.setHeader 'content-type', 'text/css; charset=UTF-8' res.setHeader 'Content-Disposition', 'inline' diff --git a/packages/rocketchat-theme-colors/variables.coffee b/packages/rocketchat-theme-colors/variables.coffee index 652650fa103..3e93d4b2692 100644 --- a/packages/rocketchat-theme-colors/variables.coffee +++ b/packages/rocketchat-theme-colors/variables.coffee @@ -1,44 +1,23 @@ -@variables = new class - data: {} +RocketChat.theme.addColor "content-background-color", "#FFF" +RocketChat.theme.addColor "primary-background-color", "#04436A" +RocketChat.theme.addColor "secondary-background-color", "#F4F4F4" +RocketChat.theme.addColor "tertiary-background-color", "#EAEAEA" +RocketChat.theme.addColor "primary-font-color", "#444444" +RocketChat.theme.addColor "secondary-font-color", "#7F7F7F" +RocketChat.theme.addColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" +RocketChat.theme.addColor "input-font-color", "rgba(255, 255, 255, 0.85)" +RocketChat.theme.addColor "link-font-color", "#008CE3" +RocketChat.theme.addColor "info-font-color", "#AAAAAA" +RocketChat.theme.addColor "info-active-font-color", "#FF0000" +RocketChat.theme.addColor "smallprint-font-color", "#C2E7FF" +RocketChat.theme.addColor "smallprint-hover-color", "white" +RocketChat.theme.addColor "status-online", "#35AC19" +RocketChat.theme.addColor "status-offline", "rgba(150, 150, 150, 0.50)" +RocketChat.theme.addColor "status-busy", "#D30230" +RocketChat.theme.addColor "status-away", "#FCB316" +RocketChat.theme.addColor "code-background", "#F8F8F8" +RocketChat.theme.addColor "code-border", "#CCC" +RocketChat.theme.addColor "code-color", "#333" +RocketChat.theme.addColor "blockquote-background", "#CCC" - addColor: (name, value) -> - @data[name] = - value: value - type: "color" - - getAsObject: -> - obj = {} - for name, item of @data - obj[name] = item.value - - return obj - - getAsLess: -> - items = [] - for name, item of @data - items.push "@#{name}: #{item.value};" - - return items.join '\n' - - -variables.addColor "content-background-color", "#FFF" -variables.addColor "primary-background-color", "#04436A" -variables.addColor "secondary-background-color", "#F4F4F4" -variables.addColor "tertiary-background-color", "#EAEAEA" -variables.addColor "primary-font-color", "#444444" -variables.addColor "secondary-font-color", "#7F7F7F" -variables.addColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" -variables.addColor "input-font-color", "rgba(255, 255, 255, 0.85)" -variables.addColor "link-font-color", "#008CE3" -variables.addColor "info-font-color", "#AAAAAA" -variables.addColor "info-active-font-color", "#FF0000" -variables.addColor "smallprint-font-color", "#C2E7FF" -variables.addColor "smallprint-hover-color", "white" -variables.addColor "status-online", "#35AC19" -variables.addColor "status-offline", "rgba(150, 150, 150, 0.50)" -variables.addColor "status-busy", "#D30230" -variables.addColor "status-away", "#FCB316" -variables.addColor "code-background", "#F8F8F8" -variables.addColor "code-border", "#CCC" -variables.addColor "code-color", "#333" -variables.addColor "blockquote-background", "#CCC" +RocketChat.theme.compile() -- GitLab From 0813a0a26bb9b56bdee9ab3f716b81ed4f27bf5e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 5 Oct 2015 17:18:43 -0300 Subject: [PATCH 0024/1338] Changing colors on the fly --- client/views/admin/admin.coffee | 12 + client/views/admin/admin.html | 11 + .../settings/lib/settings.coffee | 12 +- .../settings/server/methods.coffee | 16 + .../assets/stylesheets/base.less | 16 + .../{ => client}/client.coffee | 9 +- .../client/minicolors/jquery.minicolors.css | 278 +++++ .../client/minicolors/jquery.minicolors.js | 1027 +++++++++++++++++ packages/rocketchat-theme-colors/package.js | 34 +- .../{ => server}/server.coffee | 29 +- .../server/variables.coffee | 21 + .../rocketchat-theme-colors/variables.coffee | 23 - 12 files changed, 1431 insertions(+), 57 deletions(-) rename packages/rocketchat-theme-colors/{ => client}/client.coffee (55%) create mode 100644 packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.css create mode 100644 packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.js rename packages/rocketchat-theme-colors/{ => server}/server.coffee (71%) create mode 100644 packages/rocketchat-theme-colors/server/variables.coffee delete mode 100644 packages/rocketchat-theme-colors/variables.coffee diff --git a/client/views/admin/admin.coffee b/client/views/admin/admin.coffee index 6bad9f62865..9015fa20391 100644 --- a/client/views/admin/admin.coffee +++ b/client/views/admin/admin.coffee @@ -54,6 +54,8 @@ Template.admin.events 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()) if value? updateSettings.push { _id: setting._id, value: value } @@ -102,3 +104,13 @@ Template.admin.onRendered -> Tracker.afterFlush -> SideNav.setFlex "adminFlex" SideNav.openFlex() + + Meteor.setTimeout -> + $('input.minicolors').minicolors({theme: 'rocketchat'}) + , 500 + + Tracker.autorun -> + FlowRouter.watchPathChange() + Meteor.setTimeout -> + $('input.minicolors').minicolors({theme: 'rocketchat'}) + , 200 diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index 6c8c2dca111..2cffc76a600 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -71,6 +71,17 @@ {{/if}} </div> {{/if}} + {{#if $eq type 'color'}} + <div class="input-line double-col"> + <label>{{label}}</label> + <div> + <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> + {{#if description}} + <small>{{description}}</small> + {{/if}} + </div> + </div> + {{/if}} {{/each}} {{#if section}} diff --git a/packages/rocketchat-lib/settings/lib/settings.coffee b/packages/rocketchat-lib/settings/lib/settings.coffee index cc97e7623a2..ce9ea416307 100644 --- a/packages/rocketchat-lib/settings/lib/settings.coffee +++ b/packages/rocketchat-lib/settings/lib/settings.coffee @@ -3,13 +3,13 @@ if Meteor.isClient is true else Settings = RocketChat.models.Settings +initialLoad = true Settings.find().observe added: (record) -> Meteor.settings ?= {} Meteor.settings[record._id] = record.value - if Meteor.isClient is true - RocketChat.settings.load record._id, record.value + RocketChat.settings.load record._id, record.value, initialLoad if process? process.env ?= {} @@ -18,15 +18,15 @@ Settings.find().observe changed: (record) -> Meteor.settings?[record._id] = record.value - if Meteor.isClient is true - RocketChat.settings.load record._id, record.value + RocketChat.settings.load record._id, record.value, initialLoad if process? process.env[record._id] = record.value removed: (record) -> - if Meteor.isClient is true - RocketChat.settings.load record._id, undefined + RocketChat.settings.load record._id, undefined, initialLoad delete Meteor.settings?[record._id] delete process?.env?[record._id] + +initialLoad = false diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 729522f1642..20514c937dd 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -1,3 +1,5 @@ +RocketChat.settings.callbacks = {} + ### # Add a setting # @param {String} _id @@ -58,6 +60,20 @@ RocketChat.settings.addGroup = (_id, options = {}) -> return RocketChat.models.Settings.upsert { _id: _id }, upsertChanges +RocketChat.settings.load = (key, value, initialLoad) -> + if RocketChat.settings.callbacks[key]? + for callback in RocketChat.settings.callbacks[key] + callback key, value, initialLoad + + if RocketChat.settings.callbacks['*']? + for callback in RocketChat.settings.callbacks['*'] + callback key, value, initialLoad + + +RocketChat.settings.onload = (key, callback) -> + RocketChat.settings.callbacks[key] ?= [] + RocketChat.settings.callbacks[key].push callback + ### # Remove a setting by id # @param {String} _id diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/base.less b/packages/rocketchat-theme-colors/assets/stylesheets/base.less index de4ed45f409..2ee36a1448e 100644 --- a/packages/rocketchat-theme-colors/assets/stylesheets/base.less +++ b/packages/rocketchat-theme-colors/assets/stylesheets/base.less @@ -3858,3 +3858,19 @@ a.github-fork { } } +.minicolors-theme-rocketchat { + .minicolors-swatch { + height: 33px; + width: 33px; + top: 1px; + left: 1px; + border-radius: 5px 0 0 5px; + overflow: hidden; + border-width: 0 1px 0 0; + border-color: #e7e7e7; + } + + input { + text-indent: 34px; + } +} diff --git a/packages/rocketchat-theme-colors/client.coffee b/packages/rocketchat-theme-colors/client/client.coffee similarity index 55% rename from packages/rocketchat-theme-colors/client.coffee rename to packages/rocketchat-theme-colors/client/client.coffee index 0ac4faa79b6..3680ef5365e 100644 --- a/packages/rocketchat-theme-colors/client.coffee +++ b/packages/rocketchat-theme-colors/client/client.coffee @@ -1,9 +1,14 @@ -Meteor.startup -> +updateTheme = -> el = $('#theme-colors')[0] + el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() +Meteor.startup -> connected = Meteor.status().connected Tracker.autorun -> if connected is false and Meteor.status().connected is true - el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() + updateTheme() connected = Meteor.status().connected + + RocketChat.Notifications.onAll 'theme-updated', -> + updateTheme() diff --git a/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.css b/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.css new file mode 100644 index 00000000000..47dffa5ecfa --- /dev/null +++ b/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.css @@ -0,0 +1,278 @@ +.minicolors { + position: relative; +} + +.minicolors-sprite { + background-image: url(data:image/png;base64,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); +} + +.minicolors-no-data-uris .minicolors-sprite { + background-image: url(jquery.minicolors.png); +} + +.minicolors-swatch { + position: absolute; + vertical-align: middle; + background-position: -80px 0; + border: solid 1px #ccc; + cursor: text; + padding: 0; + margin: 0; + display: inline-block; +} + +.minicolors-swatch-color { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.minicolors input[type=hidden] + .minicolors-swatch { + width: 28px; + position: static; + cursor: pointer; +} + +.minicolors input[type=hidden][disabled] + .minicolors-swatch { + cursor: default; +} + +/* Panel */ +.minicolors-panel { + position: absolute; + width: 173px; + height: 152px; + background: white; + border: solid 1px #CCC; + box-shadow: 0 0 20px rgba(0, 0, 0, .2); + z-index: 99999; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; + display: none; +} + +.minicolors-panel.minicolors-visible { + display: block; +} + +/* Panel positioning */ +.minicolors-position-top .minicolors-panel { + top: -154px; +} + +.minicolors-position-right .minicolors-panel { + right: 0; +} + +.minicolors-position-bottom .minicolors-panel { + top: auto; +} + +.minicolors-position-left .minicolors-panel { + left: 0; +} + +.minicolors-with-opacity .minicolors-panel { + width: 194px; +} + +.minicolors .minicolors-grid { + position: absolute; + top: 1px; + left: 1px; + width: 150px; + height: 150px; + background-position: -120px 0; + cursor: crosshair; +} + +.minicolors .minicolors-grid-inner { + position: absolute; + top: 0; + left: 0; + width: 150px; + height: 150px; +} + +.minicolors-slider-saturation .minicolors-grid { + background-position: -420px 0; +} + +.minicolors-slider-saturation .minicolors-grid-inner { + background-position: -270px 0; + background-image: inherit; +} + +.minicolors-slider-brightness .minicolors-grid { + background-position: -570px 0; +} + +.minicolors-slider-brightness .minicolors-grid-inner { + background-color: black; +} + +.minicolors-slider-wheel .minicolors-grid { + background-position: -720px 0; +} + +.minicolors-slider, +.minicolors-opacity-slider { + position: absolute; + top: 1px; + left: 152px; + width: 20px; + height: 150px; + background-color: white; + background-position: 0 0; + cursor: row-resize; +} + +.minicolors-slider-saturation .minicolors-slider { + background-position: -60px 0; +} + +.minicolors-slider-brightness .minicolors-slider { + background-position: -20px 0; +} + +.minicolors-slider-wheel .minicolors-slider { + background-position: -20px 0; +} + +.minicolors-opacity-slider { + left: 173px; + background-position: -40px 0; + display: none; +} + +.minicolors-with-opacity .minicolors-opacity-slider { + display: block; +} + +/* Pickers */ +.minicolors-grid .minicolors-picker { + position: absolute; + top: 70px; + left: 70px; + width: 12px; + height: 12px; + border: solid 1px black; + border-radius: 10px; + margin-top: -6px; + margin-left: -6px; + background: none; +} + +.minicolors-grid .minicolors-picker > div { + position: absolute; + top: 0; + left: 0; + width: 8px; + height: 8px; + border-radius: 8px; + border: solid 2px white; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} + +.minicolors-picker { + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 2px; + background: white; + border: solid 1px black; + margin-top: -2px; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} + +/* Inline controls */ +.minicolors-inline { + display: inline-block; +} + +.minicolors-inline .minicolors-input { + display: none !important; +} + +.minicolors-inline .minicolors-panel { + position: relative; + top: auto; + left: auto; + box-shadow: none; + z-index: auto; + display: inline-block; +} + +/* Default theme */ +.minicolors-theme-default .minicolors-swatch { + top: 5px; + left: 5px; + width: 18px; + height: 18px; +} +.minicolors-theme-default.minicolors-position-right .minicolors-swatch { + left: auto; + right: 5px; +} +.minicolors-theme-default.minicolors { + width: auto; + display: inline-block; +} +.minicolors-theme-default .minicolors-input { + height: 20px; + width: auto; + display: inline-block; + padding-left: 26px; +} +.minicolors-theme-default.minicolors-position-right .minicolors-input { + padding-right: 26px; + padding-left: inherit; +} + +/* Bootstrap theme */ +.minicolors-theme-bootstrap .minicolors-swatch { + z-index: 2; + top: 3px; + left: 3px; + width: 28px; + height: 28px; + border-radius: 3px; +} +.minicolors-theme-bootstrap .minicolors-swatch-color { + border-radius: inherit; +} +.minicolors-theme-bootstrap.minicolors-position-right .minicolors-swatch { + left: auto; + right: 3px; +} +.minicolors-theme-bootstrap .minicolors-input { + float: none; + padding-left: 44px; +} +.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input { + padding-right: 44px; + padding-left: 12px; +} +.minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch { + top: 4px; + left: 4px; + width: 37px; + height: 37px; + border-radius: 5px; +} +.minicolors-theme-bootstrap .minicolors-input.input-sm + .minicolors-swatch { + width: 24px; + height: 24px; +} +.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} diff --git a/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.js b/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.js new file mode 100644 index 00000000000..1a68fe1151b --- /dev/null +++ b/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.js @@ -0,0 +1,1027 @@ +/* + * jQuery MiniColors: A tiny color picker built on jQuery + * + * Copyright: Cory LaViska for A Beautiful Site, LLC: http://www.abeautifulsite.net/ + * + * Contribute: https://github.com/claviska/jquery-minicolors + * + * @license: http://opensource.org/licenses/MIT + * + */ +(function (factory) { + /* jshint ignore:start */ + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } + /* jshint ignore:end */ +}(function ($) { + + // Defaults + $.minicolors = { + defaults: { + animationSpeed: 50, + animationEasing: 'swing', + change: null, + changeDelay: 0, + control: 'hue', + dataUris: true, + defaultValue: '', + format: 'hex', + hide: null, + hideSpeed: 100, + inline: false, + keywords: '', + letterCase: 'lowercase', + opacity: false, + position: 'bottom left', + show: null, + showSpeed: 100, + theme: 'default' + } + }; + + // Public methods + $.extend($.fn, { + minicolors: function(method, data) { + + switch(method) { + + // Destroy the control + case 'destroy': + $(this).each( function() { + destroy($(this)); + }); + return $(this); + + // Hide the color picker + case 'hide': + hide(); + return $(this); + + // Get/set opacity + case 'opacity': + // Getter + if( data === undefined ) { + // Getter + return $(this).attr('data-opacity'); + } else { + // Setter + $(this).each( function() { + updateFromInput($(this).attr('data-opacity', data)); + }); + } + return $(this); + + // Get an RGB(A) object based on the current color/opacity + case 'rgbObject': + return rgbObject($(this), method === 'rgbaObject'); + + // Get an RGB(A) string based on the current color/opacity + case 'rgbString': + case 'rgbaString': + return rgbString($(this), method === 'rgbaString'); + + // Get/set settings on the fly + case 'settings': + if( data === undefined ) { + return $(this).data('minicolors-settings'); + } else { + // Setter + $(this).each( function() { + var settings = $(this).data('minicolors-settings') || {}; + destroy($(this)); + $(this).minicolors($.extend(true, settings, data)); + }); + } + return $(this); + + // Show the color picker + case 'show': + show( $(this).eq(0) ); + return $(this); + + // Get/set the hex color value + case 'value': + if( data === undefined ) { + // Getter + return $(this).val(); + } else { + // Setter + $(this).each( function() { + updateFromInput($(this).val(data)); + }); + } + return $(this); + + // Initializes the control + default: + if( method !== 'create' ) data = method; + $(this).each( function() { + init($(this), data); + }); + return $(this); + + } + + } + }); + + // Initialize input elements + function init(input, settings) { + + var minicolors = $('<div class="minicolors" />'), + defaults = $.minicolors.defaults, + format = input.attr('data-format'), + keywords = input.attr('data-keywords'), + opacity = input.attr('data-opacity'); + + // Do nothing if already initialized + if( input.data('minicolors-initialized') ) return; + + // Handle settings + settings = $.extend(true, {}, defaults, settings); + + // The wrapper + minicolors + .addClass('minicolors-theme-' + settings.theme) + .toggleClass('minicolors-with-opacity', settings.opacity) + .toggleClass('minicolors-no-data-uris', settings.dataUris !== true); + + // Custom positioning + if( settings.position !== undefined ) { + $.each(settings.position.split(' '), function() { + minicolors.addClass('minicolors-position-' + this); + }); + } + + // Input size + if( format === 'rgb' ) { + $input_size = opacity ? '25' : '20'; + } else { + $input_size = keywords ? '11' : '7'; + } + + // The input + input + .addClass('minicolors-input') + .data('minicolors-initialized', false) + .data('minicolors-settings', settings) + .prop('size', $input_size) + .wrap(minicolors) + .after( + '<div class="minicolors-panel minicolors-slider-' + settings.control + '">' + + '<div class="minicolors-slider minicolors-sprite">' + + '<div class="minicolors-picker"></div>' + + '</div>' + + '<div class="minicolors-opacity-slider minicolors-sprite">' + + '<div class="minicolors-picker"></div>' + + '</div>' + + '<div class="minicolors-grid minicolors-sprite">' + + '<div class="minicolors-grid-inner"></div>' + + '<div class="minicolors-picker"><div></div></div>' + + '</div>' + + '</div>' + ); + + // The swatch + if( !settings.inline ) { + input.after('<span class="minicolors-swatch minicolors-sprite"><span class="minicolors-swatch-color"></span></span>'); + input.next('.minicolors-swatch').on('click', function(event) { + event.preventDefault(); + input.focus(); + }); + } + + // Prevent text selection in IE + input.parent().find('.minicolors-panel').on('selectstart', function() { return false; }).end(); + + // Inline controls + if( settings.inline ) input.parent().addClass('minicolors-inline'); + + updateFromInput(input, false); + + input.data('minicolors-initialized', true); + + } + + // Returns the input back to its original state + function destroy(input) { + + var minicolors = input.parent(); + + // Revert the input element + input + .removeData('minicolors-initialized') + .removeData('minicolors-settings') + .removeProp('size') + .removeClass('minicolors-input'); + + // Remove the wrap and destroy whatever remains + minicolors.before(input).remove(); + + } + + // Shows the specified dropdown panel + function show(input) { + + var minicolors = input.parent(), + panel = minicolors.find('.minicolors-panel'), + settings = input.data('minicolors-settings'); + + // Do nothing if uninitialized, disabled, inline, or already open + if( !input.data('minicolors-initialized') || + input.prop('disabled') || + minicolors.hasClass('minicolors-inline') || + minicolors.hasClass('minicolors-focus') + ) return; + + hide(); + + minicolors.addClass('minicolors-focus'); + panel + .stop(true, true) + .fadeIn(settings.showSpeed, function() { + if( settings.show ) settings.show.call(input.get(0)); + }); + + } + + // Hides all dropdown panels + function hide() { + + $('.minicolors-focus').each( function() { + + var minicolors = $(this), + input = minicolors.find('.minicolors-input'), + panel = minicolors.find('.minicolors-panel'), + settings = input.data('minicolors-settings'); + + panel.fadeOut(settings.hideSpeed, function() { + if( settings.hide ) settings.hide.call(input.get(0)); + minicolors.removeClass('minicolors-focus'); + }); + + }); + } + + // Moves the selected picker + function move(target, event, animate) { + + var input = target.parents('.minicolors').find('.minicolors-input'), + settings = input.data('minicolors-settings'), + picker = target.find('[class$=-picker]'), + offsetX = target.offset().left, + offsetY = target.offset().top, + x = Math.round(event.pageX - offsetX), + y = Math.round(event.pageY - offsetY), + duration = animate ? settings.animationSpeed : 0, + wx, wy, r, phi; + + // Touch support + if( event.originalEvent.changedTouches ) { + x = event.originalEvent.changedTouches[0].pageX - offsetX; + y = event.originalEvent.changedTouches[0].pageY - offsetY; + } + + // Constrain picker to its container + if( x < 0 ) x = 0; + if( y < 0 ) y = 0; + if( x > target.width() ) x = target.width(); + if( y > target.height() ) y = target.height(); + + // Constrain color wheel values to the wheel + if( target.parent().is('.minicolors-slider-wheel') && picker.parent().is('.minicolors-grid') ) { + wx = 75 - x; + wy = 75 - y; + r = Math.sqrt(wx * wx + wy * wy); + phi = Math.atan2(wy, wx); + if( phi < 0 ) phi += Math.PI * 2; + if( r > 75 ) { + r = 75; + x = 75 - (75 * Math.cos(phi)); + y = 75 - (75 * Math.sin(phi)); + } + x = Math.round(x); + y = Math.round(y); + } + + // Move the picker + if( target.is('.minicolors-grid') ) { + picker + .stop(true) + .animate({ + top: y + 'px', + left: x + 'px' + }, duration, settings.animationEasing, function() { + updateFromControl(input, target); + }); + } else { + picker + .stop(true) + .animate({ + top: y + 'px' + }, duration, settings.animationEasing, function() { + updateFromControl(input, target); + }); + } + + } + + // Sets the input based on the color picker values + function updateFromControl(input, target) { + + function getCoords(picker, container) { + + var left, top; + if( !picker.length || !container ) return null; + left = picker.offset().left; + top = picker.offset().top; + + return { + x: left - container.offset().left + (picker.outerWidth() / 2), + y: top - container.offset().top + (picker.outerHeight() / 2) + }; + + } + + var hue, saturation, brightness, x, y, r, phi, + + hex = input.val(), + format = input.attr('data-format'), + keywords = input.attr('data-keywords'), + opacity = input.attr('data-opacity'), + + // Helpful references + minicolors = input.parent(), + settings = input.data('minicolors-settings'), + swatch = minicolors.find('.minicolors-swatch'), + + // Panel objects + grid = minicolors.find('.minicolors-grid'), + slider = minicolors.find('.minicolors-slider'), + opacitySlider = minicolors.find('.minicolors-opacity-slider'), + + // Picker objects + gridPicker = grid.find('[class$=-picker]'), + sliderPicker = slider.find('[class$=-picker]'), + opacityPicker = opacitySlider.find('[class$=-picker]'), + + // Picker positions + gridPos = getCoords(gridPicker, grid), + sliderPos = getCoords(sliderPicker, slider), + opacityPos = getCoords(opacityPicker, opacitySlider); + + // Handle colors + if( target.is('.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider') ) { + + // Determine HSB values + switch(settings.control) { + + case 'wheel': + // Calculate hue, saturation, and brightness + x = (grid.width() / 2) - gridPos.x; + y = (grid.height() / 2) - gridPos.y; + r = Math.sqrt(x * x + y * y); + phi = Math.atan2(y, x); + if( phi < 0 ) phi += Math.PI * 2; + if( r > 75 ) { + r = 75; + gridPos.x = 69 - (75 * Math.cos(phi)); + gridPos.y = 69 - (75 * Math.sin(phi)); + } + saturation = keepWithin(r / 0.75, 0, 100); + hue = keepWithin(phi * 180 / Math.PI, 0, 360); + brightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100); + hex = hsb2hex({ + h: hue, + s: saturation, + b: brightness + }); + + // Update UI + slider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 })); + break; + + case 'saturation': + // Calculate hue, saturation, and brightness + hue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360); + saturation = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100); + brightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100); + hex = hsb2hex({ + h: hue, + s: saturation, + b: brightness + }); + + // Update UI + slider.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: brightness })); + minicolors.find('.minicolors-grid-inner').css('opacity', saturation / 100); + break; + + case 'brightness': + // Calculate hue, saturation, and brightness + hue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360); + saturation = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100); + brightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100); + hex = hsb2hex({ + h: hue, + s: saturation, + b: brightness + }); + + // Update UI + slider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 })); + minicolors.find('.minicolors-grid-inner').css('opacity', 1 - (brightness / 100)); + break; + + default: + // Calculate hue, saturation, and brightness + hue = keepWithin(360 - parseInt(sliderPos.y * (360 / slider.height()), 10), 0, 360); + saturation = keepWithin(Math.floor(gridPos.x * (100 / grid.width())), 0, 100); + brightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100); + hex = hsb2hex({ + h: hue, + s: saturation, + b: brightness + }); + + // Update UI + grid.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: 100 })); + break; + + } + + // Handle opacity + if( settings.opacity ) { + opacity = parseFloat(1 - (opacityPos.y / opacitySlider.height())).toFixed(2); + } else { + opacity = 1; + } + if( settings.opacity ) input.attr('data-opacity', opacity); + + // Set color string + if( format === 'rgb' ) { + // Returns RGB(A) string + var rgb = hex2rgb(hex), + opacity = input.attr('data-opacity') === '' ? 1 : keepWithin( parseFloat( input.attr('data-opacity') ).toFixed(2), 0, 1 ); + if( isNaN( opacity ) ) opacity = 1; + + if( input.minicolors('rgbObject').a < 1 && rgb ) { + // Set RGBA string if alpha + value = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat( opacity ) + ')'; + } else { + // Set RGB string (alpha = 1) + value = 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'; + } + } else { + // Returns hex color + value = convertCase( hex, settings.letterCase ); + } + + // Update value from picker + input.val( value ); + } + + // Set swatch color + swatch.find('span').css({ + backgroundColor: hex, + opacity: opacity + }); + + // Handle change event + doChange(input, value, opacity); + + } + + // Sets the color picker values from the input + function updateFromInput(input, preserveInputValue) { + + var hex, + hsb, + format = input.attr('data-format'), + keywords = input.attr('data-keywords'), + opacity, + x, y, r, phi, + + // Helpful references + minicolors = input.parent(), + settings = input.data('minicolors-settings'), + swatch = minicolors.find('.minicolors-swatch'), + + // Panel objects + grid = minicolors.find('.minicolors-grid'), + slider = minicolors.find('.minicolors-slider'), + opacitySlider = minicolors.find('.minicolors-opacity-slider'), + + // Picker objects + gridPicker = grid.find('[class$=-picker]'), + sliderPicker = slider.find('[class$=-picker]'), + opacityPicker = opacitySlider.find('[class$=-picker]'); + + // Determine hex/HSB values + if( isRgb(input.val()) ) { + // If input value is a rgb(a) string, convert it to hex color and update opacity + hex = rgbString2hex(input.val()); + alpha = keepWithin(parseFloat(getAlpha(input.val())).toFixed(2), 0, 1); + if( alpha ) { + input.attr('data-opacity', alpha); + } + } else { + hex = convertCase(parseHex(input.val(), true), settings.letterCase); + } + + if( !hex ){ + hex = convertCase(parseInput(settings.defaultValue, true), settings.letterCase); + } + hsb = hex2hsb(hex); + + // Get array of lowercase keywords + keywords = !keywords ? [] : $.map(keywords.split(','), function(a) { + return $.trim(a.toLowerCase()); + }); + + // Set color string + if( input.val() !== '' && $.inArray(input.val().toLowerCase(), keywords) > -1 ) { + value = convertCase(input.val()); + } else { + value = isRgb(input.val()) ? parseRgb(input.val()) : hex; + } + + // Update input value + if( !preserveInputValue ) input.val(value); + + // Determine opacity value + if( settings.opacity ) { + // Get from data-opacity attribute and keep within 0-1 range + opacity = input.attr('data-opacity') === '' ? 1 : keepWithin(parseFloat(input.attr('data-opacity')).toFixed(2), 0, 1); + if( isNaN(opacity) ) opacity = 1; + input.attr('data-opacity', opacity); + swatch.find('span').css('opacity', opacity); + + // Set opacity picker position + y = keepWithin(opacitySlider.height() - (opacitySlider.height() * opacity), 0, opacitySlider.height()); + opacityPicker.css('top', y + 'px'); + } + + // Set opacity to zero if input value is transparent + if( input.val().toLowerCase() === 'transparent' ) { + swatch.find('span').css('opacity', 0); + } + + // Update swatch + swatch.find('span').css('backgroundColor', hex); + + // Determine picker locations + switch(settings.control) { + + case 'wheel': + // Set grid position + r = keepWithin(Math.ceil(hsb.s * 0.75), 0, grid.height() / 2); + phi = hsb.h * Math.PI / 180; + x = keepWithin(75 - Math.cos(phi) * r, 0, grid.width()); + y = keepWithin(75 - Math.sin(phi) * r, 0, grid.height()); + gridPicker.css({ + top: y + 'px', + left: x + 'px' + }); + + // Set slider position + y = 150 - (hsb.b / (100 / grid.height())); + if( hex === '' ) y = 0; + sliderPicker.css('top', y + 'px'); + + // Update panel color + slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 })); + break; + + case 'saturation': + // Set grid position + x = keepWithin((5 * hsb.h) / 12, 0, 150); + y = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height()); + gridPicker.css({ + top: y + 'px', + left: x + 'px' + }); + + // Set slider position + y = keepWithin(slider.height() - (hsb.s * (slider.height() / 100)), 0, slider.height()); + sliderPicker.css('top', y + 'px'); + + // Update UI + slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: hsb.b })); + minicolors.find('.minicolors-grid-inner').css('opacity', hsb.s / 100); + break; + + case 'brightness': + // Set grid position + x = keepWithin((5 * hsb.h) / 12, 0, 150); + y = keepWithin(grid.height() - Math.ceil(hsb.s / (100 / grid.height())), 0, grid.height()); + gridPicker.css({ + top: y + 'px', + left: x + 'px' + }); + + // Set slider position + y = keepWithin(slider.height() - (hsb.b * (slider.height() / 100)), 0, slider.height()); + sliderPicker.css('top', y + 'px'); + + // Update UI + slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 })); + minicolors.find('.minicolors-grid-inner').css('opacity', 1 - (hsb.b / 100)); + break; + + default: + // Set grid position + x = keepWithin(Math.ceil(hsb.s / (100 / grid.width())), 0, grid.width()); + y = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height()); + gridPicker.css({ + top: y + 'px', + left: x + 'px' + }); + + // Set slider position + y = keepWithin(slider.height() - (hsb.h / (360 / slider.height())), 0, slider.height()); + sliderPicker.css('top', y + 'px'); + + // Update panel color + grid.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: 100 })); + break; + + } + + // Fire change event, but only if minicolors is fully initialized + if( input.data('minicolors-initialized') ) { + doChange(input, value, opacity); + } + + } + + // Runs the change and changeDelay callbacks + function doChange(input, value, opacity) { + + var settings = input.data('minicolors-settings'), + lastChange = input.data('minicolors-lastChange'); + + // Only run if it actually changed + if( !lastChange || lastChange.value !== value || lastChange.opacity !== opacity ) { + + // Remember last-changed value + input.data('minicolors-lastChange', { + value: value, + opacity: opacity + }); + + // Fire change event + if( settings.change ) { + if( settings.changeDelay ) { + // Call after a delay + clearTimeout(input.data('minicolors-changeTimeout')); + input.data('minicolors-changeTimeout', setTimeout( function() { + settings.change.call(input.get(0), value, opacity); + }, settings.changeDelay)); + } else { + // Call immediately + settings.change.call(input.get(0), value, opacity); + } + } + input.trigger('change').trigger('input'); + } + + } + + // Generates an RGB(A) object based on the input's value + function rgbObject(input) { + var hex = parseHex($(input).val(), true), + rgb = hex2rgb(hex), + opacity = $(input).attr('data-opacity'); + if( !rgb ) return null; + if( opacity !== undefined ) $.extend(rgb, { a: parseFloat(opacity) }); + return rgb; + } + + // Generates an RGB(A) string based on the input's value + function rgbString(input, alpha) { + var hex = parseHex($(input).val(), true), + rgb = hex2rgb(hex), + opacity = $(input).attr('data-opacity'); + if( !rgb ) return null; + if( opacity === undefined ) opacity = 1; + if( alpha ) { + return 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(opacity) + ')'; + } else { + return 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'; + } + } + + // Converts to the letter case specified in settings + function convertCase(string, letterCase) { + return letterCase === 'uppercase' ? string.toUpperCase() : string.toLowerCase(); + } + + // Parses a string and returns a valid hex string when possible + function parseHex(string, expand) { + string = string.replace(/^#/g, ''); + if( !string.match(/^[A-F0-9]{3,6}/ig) ) return ''; + if( string.length !== 3 && string.length !== 6 ) return ''; + if( string.length === 3 && expand ) { + string = string[0] + string[0] + string[1] + string[1] + string[2] + string[2]; + } + return '#' + string; + } + + // Parses a string and returns a valid RGB(A) string when possible + function parseRgb(string, obj) { + + var values = string.replace(/[^\d,.]/g, ''), + rgba = values.split(','), + output; + + rgba[0] = keepWithin(parseInt(rgba[0], 10), 0, 255); + rgba[1] = keepWithin(parseInt(rgba[1], 10), 0, 255); + rgba[2] = keepWithin(parseInt(rgba[2], 10), 0, 255); + if( rgba[3] ) { + rgba[3] = keepWithin(parseFloat(rgba[3], 10), 0, 1); + } + + // Return RGBA object + if( obj ) { + return { + r: rgba[0], + g: rgba[1], + b: rgba[2], + a: rgba[3] ? rgba[3] : null + }; + } + + // Return RGBA string + if( rgba[3] ) { + return 'rgba(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ', ' + rgba[3] + ')'; + } else { + return 'rgb(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ')'; + } + + } + + // Parses a string and returns a valid color string when possible + function parseInput(string, expand) { + if( isRgb(string) ) { + // Returns a valid rgb(a) string + return parseRgb(string); + } else { + return parseHex(string, expand); + } + } + + // Keeps value within min and max + function keepWithin(value, min, max) { + if( value < min ) value = min; + if( value > max ) value = max; + return value; + } + + // Checks if a string is a valid RGB(A) string + function isRgb(string) { + rgb = string.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); + return (rgb && rgb.length === 4) ? true : false; + } + + // Function to get alpha from a RGB(A) string + function getAlpha(rgba) { + rgba = rgba.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+(\.\d{1,2})?|\.\d{1,2})[\s+]?/i); + return (rgba && rgba.length === 6) ? rgba[4] : '1'; + } + + // Converts an HSB object to an RGB object + function hsb2rgb(hsb) { + var rgb = {}; + var h = Math.round(hsb.h); + var s = Math.round(hsb.s * 255 / 100); + var v = Math.round(hsb.b * 255 / 100); + if(s === 0) { + rgb.r = rgb.g = rgb.b = v; + } else { + var t1 = v; + var t2 = (255 - s) * v / 255; + var t3 = (t1 - t2) * (h % 60) / 60; + if( h === 360 ) h = 0; + if( h < 60 ) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3; } + else if( h < 120 ) {rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3; } + else if( h < 180 ) {rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3; } + else if( h < 240 ) {rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3; } + else if( h < 300 ) {rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3; } + else if( h < 360 ) {rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3; } + else { rgb.r = 0; rgb.g = 0; rgb.b = 0; } + } + return { + r: Math.round(rgb.r), + g: Math.round(rgb.g), + b: Math.round(rgb.b) + }; + } + + // Converts an RGB string to a hex string + function rgbString2hex(rgb){ + rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); + return (rgb && rgb.length === 4) ? '#' + + ('0' + parseInt(rgb[1],10).toString(16)).slice(-2) + + ('0' + parseInt(rgb[2],10).toString(16)).slice(-2) + + ('0' + parseInt(rgb[3],10).toString(16)).slice(-2) : ''; + } + + // Converts an RGB object to a hex string + function rgb2hex(rgb) { + var hex = [ + rgb.r.toString(16), + rgb.g.toString(16), + rgb.b.toString(16) + ]; + $.each(hex, function(nr, val) { + if (val.length === 1) hex[nr] = '0' + val; + }); + return '#' + hex.join(''); + } + + // Converts an HSB object to a hex string + function hsb2hex(hsb) { + return rgb2hex(hsb2rgb(hsb)); + } + + // Converts a hex string to an HSB object + function hex2hsb(hex) { + var hsb = rgb2hsb(hex2rgb(hex)); + if( hsb.s === 0 ) hsb.h = 360; + return hsb; + } + + // Converts an RGB object to an HSB object + function rgb2hsb(rgb) { + var hsb = { h: 0, s: 0, b: 0 }; + var min = Math.min(rgb.r, rgb.g, rgb.b); + var max = Math.max(rgb.r, rgb.g, rgb.b); + var delta = max - min; + hsb.b = max; + hsb.s = max !== 0 ? 255 * delta / max : 0; + if( hsb.s !== 0 ) { + if( rgb.r === max ) { + hsb.h = (rgb.g - rgb.b) / delta; + } else if( rgb.g === max ) { + hsb.h = 2 + (rgb.b - rgb.r) / delta; + } else { + hsb.h = 4 + (rgb.r - rgb.g) / delta; + } + } else { + hsb.h = -1; + } + hsb.h *= 60; + if( hsb.h < 0 ) { + hsb.h += 360; + } + hsb.s *= 100/255; + hsb.b *= 100/255; + return hsb; + } + + // Converts a hex string to an RGB object + function hex2rgb(hex) { + hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16); + return { + /* jshint ignore:start */ + r: hex >> 16, + g: (hex & 0x00FF00) >> 8, + b: (hex & 0x0000FF) + /* jshint ignore:end */ + }; + } + + // Handle events + $(document) + // Hide on clicks outside of the control + .on('mousedown.minicolors touchstart.minicolors', function(event) { + if( !$(event.target).parents().add(event.target).hasClass('minicolors') ) { + hide(); + } + }) + // Start moving + .on('mousedown.minicolors touchstart.minicolors', '.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider', function(event) { + var target = $(this); + event.preventDefault(); + $(document).data('minicolors-target', target); + move(target, event, true); + }) + // Move pickers + .on('mousemove.minicolors touchmove.minicolors', function(event) { + var target = $(document).data('minicolors-target'); + if( target ) move(target, event); + }) + // Stop moving + .on('mouseup.minicolors touchend.minicolors', function() { + $(this).removeData('minicolors-target'); + }) + // Show panel when swatch is clicked + .on('mousedown.minicolors touchstart.minicolors', '.minicolors-swatch', function(event) { + var input = $(this).parent().find('.minicolors-input'); + event.preventDefault(); + show(input); + }) + // Show on focus + .on('focus.minicolors', '.minicolors-input', function() { + var input = $(this); + if( !input.data('minicolors-initialized') ) return; + show(input); + }) + // Update value on blur + .on('blur.minicolors', '.minicolors-input', function() { + var input = $(this), + keywords = input.attr('data-keywords'), + settings = input.data('minicolors-settings'), + hex, + rgba, + swatchOpacity; + + if( !input.data('minicolors-initialized') ) return; + + // Get array of lowercase keywords + keywords = !keywords ? [] : $.map(keywords.split(','), function(a) { + return $.trim(a.toLowerCase()); + }); + + // Set color string + if( input.val() !== '' && $.inArray(input.val().toLowerCase(), keywords) > -1 ) { + value = input.val(); + } else { + // Get RGBA values for easy conversion + if( isRgb(input.val()) ) { + rgba = parseRgb(input.val(), true); + } else { + hex = parseHex(input.val(), true); + rgba = hex ? hex2rgb(hex) : null; + } + + // Convert to format + if( rgba === null ) { + value = settings.defaultValue; + } else if( settings.format === 'rgb' ) { + value = settings.opacity ? + parseRgb('rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + input.attr('data-opacity') + ')') : + parseRgb('rgb(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ')'); + } else { + value = rgb2hex(rgba); + } + } + + // Update swatch opacity + swatchOpacity = settings.opacity ? input.attr('data-opacity') : 1; + if( value.toLowerCase() === 'transparent' ) swatchOpacity = 0; + input + .closest('.minicolors') + .find('.minicolors-swatch > span') + .css('opacity', swatchOpacity); + + // Set input value + input.val(value); + + // Is it blank? + if( input.val() === '' ) input.val(parseInput(settings.defaultValue, true)); + + // Adjust case + input.val( convertCase(input.val(), settings.letterCase) ); + + }) + // Handle keypresses + .on('keydown.minicolors', '.minicolors-input', function(event) { + var input = $(this); + if( !input.data('minicolors-initialized') ) return; + switch(event.keyCode) { + case 9: // tab + hide(); + break; + case 13: // enter + case 27: // esc + hide(); + input.blur(); + break; + } + }) + // Update on keyup + .on('keyup.minicolors', '.minicolors-input', function() { + var input = $(this); + if( !input.data('minicolors-initialized') ) return; + updateFromInput(input, true); + }) + // Update on paste + .on('paste.minicolors', '.minicolors-input', function() { + var input = $(this); + if( !input.data('minicolors-initialized') ) return; + setTimeout( function() { + updateFromInput(input, true); + }, 1); + }); + +})); diff --git a/packages/rocketchat-theme-colors/package.js b/packages/rocketchat-theme-colors/package.js index 1b9efa12315..2db4f758d00 100644 --- a/packages/rocketchat-theme-colors/package.js +++ b/packages/rocketchat-theme-colors/package.js @@ -10,26 +10,17 @@ Package.onUse(function(api) { api.use('rocketchat:lib'); api.use('coffeescript'); + api.use('underscore'); api.use('webapp'); - api.use('less@2.5.0_3'); - - api.addFiles('server.coffee', 'server'); - api.addFiles('variables.coffee', 'server'); - api.addFiles('client.coffee', 'client'); - - // api.addFiles('assets/stylesheets/global/_variables.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_colors.import.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_emojione.import.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_fonts.import.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_keyframes.import.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_lesshat.import.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_preloader.import.less', 'client'); - // api.addFiles('assets/stylesheets/utils/_reset.import.less', 'client'); - // api.addFiles('assets/stylesheets/animation.css', 'client'); - // api.addFiles('assets/stylesheets/base.less', 'client'); - // api.addFiles('assets/stylesheets/fontello.css', 'client'); - // api.addFiles('assets/stylesheets/rtl.less', 'client'); - // api.addFiles('assets/stylesheets/swipebox.min.css', 'client'); + + + api.addFiles('server/server.coffee', 'server'); + api.addFiles('server/variables.coffee', 'server'); + + api.addFiles('client/client.coffee', 'client'); + api.addFiles('client/minicolors/jquery.minicolors.css', 'client'); + api.addFiles('client/minicolors/jquery.minicolors.js', 'client'); + api.addAssets('assets/stylesheets/global/_variables.less', 'server'); api.addAssets('assets/stylesheets/utils/_colors.import.less', 'server'); @@ -44,12 +35,7 @@ Package.onUse(function(api) { api.addAssets('assets/stylesheets/fontello.css', 'server'); api.addAssets('assets/stylesheets/rtl.less', 'server'); api.addAssets('assets/stylesheets/swipebox.min.css', 'server'); - api.addAssets('assets/colors.less', 'server'); - - api.export('less', 'server'); - api.export('getText', 'server'); - api.export('getAndCompile', 'server'); }); Npm.depends({ diff --git a/packages/rocketchat-theme-colors/server.coffee b/packages/rocketchat-theme-colors/server/server.coffee similarity index 71% rename from packages/rocketchat-theme-colors/server.coffee rename to packages/rocketchat-theme-colors/server/server.coffee index dda42e38381..67c54da4b47 100644 --- a/packages/rocketchat-theme-colors/server.coffee +++ b/packages/rocketchat-theme-colors/server/server.coffee @@ -20,6 +20,18 @@ RocketChat.theme = new class constructor: -> RocketChat.settings.add 'css', '' + RocketChat.settings.addGroup 'Theme' + + compile = _.debounce Meteor.bindEnvironment(@compile.bind(@)), 200 + + RocketChat.settings.onload '*', Meteor.bindEnvironment (key, value, initialLoad) => + if /^theme-.+/.test(key) is false then return + + name = key.replace /^theme-[a-z]+-/, '' + if @variables[name]? + @variables[name].value = value + + compile() compile: -> content = [ @@ -41,10 +53,23 @@ RocketChat.theme = new class RocketChat.settings.updateById 'css', data.css - addColor: (name, value) -> + RocketChat.Notifications.notifyAll 'theme-updated' + + addVariable: (type, name, value, isPublic=true) -> @variables[name] = + type: type value: value - type: "color" + + config = + group: 'Theme' + type: type + section: type + public: isPublic + + RocketChat.settings.add "theme-#{type}-#{name}", value, config + + addPublicColor: (name, value) -> + @addVariable 'color', name, value, true getVariablesAsObject: -> obj = {} diff --git a/packages/rocketchat-theme-colors/server/variables.coffee b/packages/rocketchat-theme-colors/server/variables.coffee new file mode 100644 index 00000000000..9830698b0e8 --- /dev/null +++ b/packages/rocketchat-theme-colors/server/variables.coffee @@ -0,0 +1,21 @@ +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-font-color", "#444444" +RocketChat.theme.addPublicColor "secondary-font-color", "#7F7F7F" +RocketChat.theme.addPublicColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" +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 "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" diff --git a/packages/rocketchat-theme-colors/variables.coffee b/packages/rocketchat-theme-colors/variables.coffee deleted file mode 100644 index 3e93d4b2692..00000000000 --- a/packages/rocketchat-theme-colors/variables.coffee +++ /dev/null @@ -1,23 +0,0 @@ -RocketChat.theme.addColor "content-background-color", "#FFF" -RocketChat.theme.addColor "primary-background-color", "#04436A" -RocketChat.theme.addColor "secondary-background-color", "#F4F4F4" -RocketChat.theme.addColor "tertiary-background-color", "#EAEAEA" -RocketChat.theme.addColor "primary-font-color", "#444444" -RocketChat.theme.addColor "secondary-font-color", "#7F7F7F" -RocketChat.theme.addColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" -RocketChat.theme.addColor "input-font-color", "rgba(255, 255, 255, 0.85)" -RocketChat.theme.addColor "link-font-color", "#008CE3" -RocketChat.theme.addColor "info-font-color", "#AAAAAA" -RocketChat.theme.addColor "info-active-font-color", "#FF0000" -RocketChat.theme.addColor "smallprint-font-color", "#C2E7FF" -RocketChat.theme.addColor "smallprint-hover-color", "white" -RocketChat.theme.addColor "status-online", "#35AC19" -RocketChat.theme.addColor "status-offline", "rgba(150, 150, 150, 0.50)" -RocketChat.theme.addColor "status-busy", "#D30230" -RocketChat.theme.addColor "status-away", "#FCB316" -RocketChat.theme.addColor "code-background", "#F8F8F8" -RocketChat.theme.addColor "code-border", "#CCC" -RocketChat.theme.addColor "code-color", "#333" -RocketChat.theme.addColor "blockquote-background", "#CCC" - -RocketChat.theme.compile() -- GitLab From 394dde0402024ab5334e7913acd563ed1aeaacf8 Mon Sep 17 00:00:00 2001 From: Asheesh Laroia <asheesh@asheesh.org> Date: Mon, 5 Oct 2015 17:15:39 -0700 Subject: [PATCH 0025/1338] Remove auto-generated directory This commit removes a directory that is automatically created as part of doing `vagrant-spk up`. --- .../default/virtualbox/action_provision | 1 - .../default/virtualbox/action_set_name | 1 - .../machines/default/virtualbox/creator_uid | 1 - .../.vagrant/machines/default/virtualbox/id | 1 - .../machines/default/virtualbox/index_uuid | 1 - .../machines/default/virtualbox/private_key | 27 ------------------- .../default/virtualbox/synced_folders | 1 - 7 files changed, 33 deletions(-) delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/action_provision delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/action_set_name delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/creator_uid delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/id delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/index_uuid delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/private_key delete mode 100644 .sandstorm/.vagrant/machines/default/virtualbox/synced_folders diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/action_provision b/.sandstorm/.vagrant/machines/default/virtualbox/action_provision deleted file mode 100644 index 6aad4c25eaf..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/action_provision +++ /dev/null @@ -1 +0,0 @@ -1.5:1345ca5b-3c86-44b9-98c3-6a6f3a6574c6 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name b/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name deleted file mode 100644 index 991fdfbedb0..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name +++ /dev/null @@ -1 +0,0 @@ -1443070908 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid b/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid deleted file mode 100644 index e37d32abba4..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid +++ /dev/null @@ -1 +0,0 @@ -1000 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/id b/.sandstorm/.vagrant/machines/default/virtualbox/id deleted file mode 100644 index fa709b2a089..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/id +++ /dev/null @@ -1 +0,0 @@ -1345ca5b-3c86-44b9-98c3-6a6f3a6574c6 \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid b/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid deleted file mode 100644 index df17d5233f0..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid +++ /dev/null @@ -1 +0,0 @@ -7506910154f049b6bfaf858c95fbda9c \ No newline at end of file diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/private_key b/.sandstorm/.vagrant/machines/default/virtualbox/private_key deleted file mode 100644 index ef084242f4a..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/private_key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAuN+C01kgL0/h0UXiUMJ2lDfTi4oMlBozHEvJxKI+o3Z9o+43 -+qxPpGLhCofYUBl5I6hQAjEbfS5Bq4gNoRga3A3YyAMYVWsZKqY3/57uxfwXlDCq -FhjC6qQpmAm4lXNF723L/oEQKOUuIVcHB5Lxnjza9c7PVnx8a/einpzqqc4VwqPt -Zy3FIp9gni9aUAqkMxK1GAtmaogj1bCMTaAx7nysKIYRKU+UpDsOcXrdCzr8pvCd -IJPX03dWYLaI2SVGMsTpBoC94AemvUESzEmNkjAD/AiPKvfHefFjFe8N8HXW1uxc -LEe0NDu0sNK7L8KNtRKUETnlJovxddvauqZXDQIDAQABAoIBAEF7QY50mhbH95c1 -ZpTuXCvhnjdlnVDz+riCC6RvRzqE5LmkzgUm9Uqnj0g4l6C/dQ3xNu2f0TnEoZQN -K66sqA7bhLZLilnvBkn5+Am9lJth0EQ3/Ha5LIkJvoXQo6Wj39iPjlrGAiBKFM3Q -UngXTyeaLIA2UXAzxapEW0BNGj0sXD9xnKJXkePVssy8KYwhXb4ZJgPxATgr7VIM -wSVPEJJQhEacDglu4fg+TC7BdvgRRvclURRuO57pDrSmTi1I1/NTrq2spv3/YuHw -2nvxNHRQmuCwgjLNvS7e75qnF6eR4qWjwIwH57zu6M8RJYbhFqvEvIZ57VctuKxn -jvPayS0CgYEA6Xl3YRt9qdwSmsYKwbfLs6ARpJ7VPbPAko4EG1Kthtl+SyVU6lg2 -mAts4FInjlVLLpdbWzzBqpKvpbFzEMto+j+czAcwnqdNa7NlI2GJbWRk6j5h5yuv -RSJdwbIjbUmMbWqM1cSM8g/mGYiuj2rCCil4v0aMujXyWu8cb5aNY68CgYEAyrWm -Y0r9qoG4pb9GSNAPoTWeINEB9damVXOhr8OBnlRARDz82Sk/anhyBeEm2CleBXwF -b06o5bMoepJsporfm1GS9JXvE5oD1bfHQ3R1da/FtKFN0xH/u8gkKYF0MRfpr2Ri -XkaNKKyBNv990EGjGRoJuJyu9NKip6bkhlqzlAMCgYBSV968xv9ZCx8cq0Bb9kDH -x2qxjrtSmbUPezsDj/NXnhmm0zHRvO70TQNHUnJVBswPUJ6N3S3IxRdh7uXQRI1v -xUO9ycNiEUuC8rB2/A2GIWReIUZSS9vzHB3JFNTd1JTMeknVkw7KyMS0uLooJtTs -1JebjnxPqHsjizWSPZz8TQKBgHXJYVp227j00Zc18qAijcJtxmlpKUtxI4upufzI -jIu0hvdfvMhuyFOUkyTJdGnMd76WFw5bVZbLKK04YfvP3CiDGPIYIShxqOLJe/a9 -N/dfYHEZ/X+1CLVTkXewqhRQwc/Rc7s2IZXNzvNnN/MIAL54O8fS+3J05mCmgEl1 -cL2DAoGAXK9cPG2UpT0vGoRPvBHkAunIQ6JNZL9F9O+8W4pp8Fgpy/lubw7Lu+UC -RLaEuxTEPXYFG5RWbOlDcvWQ6yrx/Xhnfi49F9r5A79RADlPAygK7xtqx0dY3y7S -39SyHDsDVUXokHp8tiyOxDfqcahAodbfcROdyhvklB1o7UYVXwA= ------END RSA PRIVATE KEY----- diff --git a/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders b/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders deleted file mode 100644 index a01b299f5db..00000000000 --- a/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders +++ /dev/null @@ -1 +0,0 @@ -{"virtualbox":{"/opt/app":{"guestpath":"/opt/app","hostpath":"/home/sam/projects/Rocket.Chat/Rocket.Chat","disabled":false},"/host-dot-sandstorm":{"guestpath":"/host-dot-sandstorm","hostpath":"/home/sam/.sandstorm","disabled":false},"/vagrant":{"guestpath":"/vagrant","hostpath":"/home/sam/projects/Rocket.Chat/Rocket.Chat","disabled":false}}} \ No newline at end of file -- GitLab From 5bfeeb4376d49bee07cd8d5cc3d419f50d7854a8 Mon Sep 17 00:00:00 2001 From: Asheesh Laroia <asheesh@asheesh.org> Date: Mon, 5 Oct 2015 17:20:22 -0700 Subject: [PATCH 0026/1338] Add VirtualBox/Vagrant state to gitignore --- .sandstorm/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .sandstorm/.gitignore diff --git a/.sandstorm/.gitignore b/.sandstorm/.gitignore new file mode 100644 index 00000000000..8000dd9db47 --- /dev/null +++ b/.sandstorm/.gitignore @@ -0,0 +1 @@ +.vagrant -- GitLab From ff094ec2e69dc40ef56c2c3ec6f152cc892a23fc Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 6 Oct 2015 13:40:55 -0300 Subject: [PATCH 0027/1338] Rate-limit username and avatar changes --- client/views/account/avatar/prompt.coffee | 14 ++++++--- i18n/en.i18n.json | 1 + .../rocketchat-lib/lib/rateLimiter.coffee | 31 ++++++++++++++++++- .../server/functions/setUsername.coffee | 2 +- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index dd9d88cecdd..a73f8da8f27 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -38,11 +38,17 @@ Template.avatarPrompt.helpers Template.avatarPrompt.events 'click .select-service': -> if @service is 'initials' - Meteor.call 'resetAvatar' - toastr.success t('Avatar_changed_successfully') + Meteor.call 'resetAvatar', (err) -> + if err?.details?.timeToReset? + toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) + else + toastr.success t('Avatar_changed_successfully') else - Meteor.call 'setAvatarFromService', @blob, @contentType, @service, -> - toastr.success t('Avatar_changed_successfully') + Meteor.call 'setAvatarFromService', @blob, @contentType, @service, (err) -> + if err?.details?.timeToReset? + toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) + else + toastr.success t('Avatar_changed_successfully') 'click .login-with-service': (event, template) -> loginWithService = "loginWith#{_.capitalize(this)}" diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 216df7f1a23..7fb818188d4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -105,6 +105,7 @@ "Enter_info" : "Enter your information", "Enter_to" : "Enter to", "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", "False" : "False", "Favorites" : "Favorites", diff --git a/packages/rocketchat-lib/lib/rateLimiter.coffee b/packages/rocketchat-lib/lib/rateLimiter.coffee index c566b671a71..7a6813446b1 100644 --- a/packages/rocketchat-lib/lib/rateLimiter.coffee +++ b/packages/rocketchat-lib/lib/rateLimiter.coffee @@ -1,7 +1,7 @@ # Limit sending messages to 5 messages per second per user DDPRateLimiter.addRule userId: (userId) -> - return Meteor.users.findOne(userId)?.username isnt RocketChat.settings.get('RocketBot_Name') + return RocketChat.models.Users.findOneById(userId)?.username isnt RocketChat.settings.get('RocketBot_Name') clientAddress: null type: 'method' name: 'sendMessage' @@ -9,3 +9,32 @@ DDPRateLimiter.addRule return true , 5, 1000 + +# Limit changing avatar once per minute +DDPRateLimiter.addRule + userId: -> return true + connectionId: -> return true + clientAddress: null + type: 'method' + name: 'setAvatarFromService' +, 1, 60000 + + +# Limit changing avatar once per minute +DDPRateLimiter.addRule + userId: -> return true + connectionId: -> return true + clientAddress: null + type: 'method' + name: 'resetAvatar' +, 1, 60000 + +# Limit setting username once per minute +DDPRateLimiter.addRule + userId: -> return not RocketChat.authz.hasPermission( user._id, 'edit-other-user-info') + connectionId: -> return true + clientAddress: null + type: 'method' + name: 'setUsername' +, 1, 60000 + diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 664b48e9e85..24cabea806f 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -31,6 +31,6 @@ RocketChat.setUsername = (user, username) -> RocketChat.models.Subscriptions.setNameForDirectRoomsWithOldName previousUsername, username # Set new username - Meteor.users.update { _id: user._id }, { $set: { username: username } } + RocketChat.models.Users.setUsername user._id, username user.username = username return user -- GitLab From 13ff6651b456917274d7c7f959ce4f61e9883cf7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 6 Oct 2015 16:41:56 -0300 Subject: [PATCH 0028/1338] Move _octicons --- .../assets}/stylesheets/utils/_octicons.less | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {client => packages/rocketchat-theme-colors/assets}/stylesheets/utils/_octicons.less (100%) diff --git a/client/stylesheets/utils/_octicons.less b/packages/rocketchat-theme-colors/assets/stylesheets/utils/_octicons.less similarity index 100% rename from client/stylesheets/utils/_octicons.less rename to packages/rocketchat-theme-colors/assets/stylesheets/utils/_octicons.less -- GitLab From 1ea487a0253da0d7591f17430ca77e792fbbd7ba Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 6 Oct 2015 16:56:26 -0300 Subject: [PATCH 0029/1338] Remove content length --- packages/rocketchat-theme-colors/server/server.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-theme-colors/server/server.coffee b/packages/rocketchat-theme-colors/server/server.coffee index 55b2a9945d9..55902c5ce73 100644 --- a/packages/rocketchat-theme-colors/server/server.coffee +++ b/packages/rocketchat-theme-colors/server/server.coffee @@ -98,6 +98,5 @@ WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> res.setHeader 'Cache-Control', 'no-cache' res.setHeader 'Pragma', 'no-cache' res.setHeader 'Expires', '0' - res.setHeader 'Content-Length', css.length * 8 res.end css -- GitLab From 55b00d815a4cc4840a574d552d0c74320c69456b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Wed, 7 Oct 2015 17:29:05 -0300 Subject: [PATCH 0030/1338] Add server side rate-limiter only; add on method declaration --- .meteor/packages | 1 + .meteor/versions | 16 -------- .../rocketchat-lib/lib/rateLimiter.coffee | 40 ------------------- packages/rocketchat-lib/package.js | 1 - .../server/methods/setUsername.coffee | 9 +++++ server/methods/resetAvatar.coffee | 7 ++++ server/methods/sendMessage.coffee | 8 ++++ server/methods/setAvatarFromService.coffee | 6 +++ 8 files changed, 31 insertions(+), 57 deletions(-) delete mode 100644 packages/rocketchat-lib/lib/rateLimiter.coffee diff --git a/.meteor/packages b/.meteor/packages index 7e27d2e2ab7..96ce4e513e0 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -107,3 +107,4 @@ rocketchat:github-enterprise rocketchat:chatops # sanjo:jasmine@0.20.2 # velocity:html-reporter +ddp-rate-limiter diff --git a/.meteor/versions b/.meteor/versions index 45238b76c83..8c8b864df5a 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -8,7 +8,6 @@ accounts-password@1.1.3 accounts-twitter@1.0.6 alanning:roles@1.2.13 aldeed:simple-schema@1.3.3 -amplify@1.0.0 arunoda:streams@0.1.17 autoupdate@1.2.3 babel-compiler@5.8.24_1 @@ -102,14 +101,11 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 -package-version-parser@3.0.4 pauli:accounts-linkedin@1.1.2 pauli:linkedin@1.1.2 perak:codemirror@1.2.7 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 -practicalmeteor:chai@2.1.0_1 -practicalmeteor:loglevel@1.2.0_2 promise@0.5.0 qnub:emojione@0.0.3 raix:eventemitter@0.1.3 @@ -150,11 +146,6 @@ rocketchat:statistics@0.0.1 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 -sanjo:jasmine@0.20.2 -sanjo:karma@3.0.2 -sanjo:long-running-child-process@1.1.3 -sanjo:meteor-files-helpers@1.2.0_1 -sanjo:meteor-version@1.0.0 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 @@ -178,13 +169,6 @@ ui@1.0.8 underscore@1.0.4 underscorestring:underscore.string@3.2.2 url@1.0.5 -velocity:chokidar@1.2.0_1 -velocity:core@0.10.4 -velocity:html-reporter@0.9.0 -velocity:meteor-internals@1.1.0_7 -velocity:meteor-stubs@1.1.0 -velocity:shim@0.1.0 -velocity:source-map-support@0.3.2_1 webapp@1.2.2 webapp-hashing@1.0.5 yasaricli:slugify@0.0.7 diff --git a/packages/rocketchat-lib/lib/rateLimiter.coffee b/packages/rocketchat-lib/lib/rateLimiter.coffee deleted file mode 100644 index 7a6813446b1..00000000000 --- a/packages/rocketchat-lib/lib/rateLimiter.coffee +++ /dev/null @@ -1,40 +0,0 @@ -# Limit sending messages to 5 messages per second per user -DDPRateLimiter.addRule - userId: (userId) -> - return RocketChat.models.Users.findOneById(userId)?.username isnt RocketChat.settings.get('RocketBot_Name') - clientAddress: null - type: 'method' - name: 'sendMessage' - connectionId: -> - return true -, 5, 1000 - - -# Limit changing avatar once per minute -DDPRateLimiter.addRule - userId: -> return true - connectionId: -> return true - clientAddress: null - type: 'method' - name: 'setAvatarFromService' -, 1, 60000 - - -# Limit changing avatar once per minute -DDPRateLimiter.addRule - userId: -> return true - connectionId: -> return true - clientAddress: null - type: 'method' - name: 'resetAvatar' -, 1, 60000 - -# Limit setting username once per minute -DDPRateLimiter.addRule - userId: -> return not RocketChat.authz.hasPermission( user._id, 'edit-other-user-info') - connectionId: -> return true - clientAddress: null - type: 'method' - name: 'setUsername' -, 1, 60000 - diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index e4ee3fd0d66..0001f455293 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -21,7 +21,6 @@ Package.onUse(function(api) { // COMMON api.addFiles('lib/core.coffee'); api.addFiles('lib/callbacks.coffee'); - api.addFiles('lib/rateLimiter.coffee'); api.addFiles('lib/slashCommand.coffee'); // MODELS SERVER diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 44bad046e86..1dfab8b8783 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -20,3 +20,12 @@ Meteor.methods throw new Meteor.Error 'could-not-change-username', "Could not change username" return username + +# Limit setting username once per minute +DDPRateLimiter.addRule + type: 'method' + name: 'setUsername' + userId: (userId) -> + # Administrators have permission to change others usernames, so don't limit those + return not RocketChat.authz.hasPermission( userId, 'edit-other-user-info') +, 1, 60000 diff --git a/server/methods/resetAvatar.coffee b/server/methods/resetAvatar.coffee index c3e31abe508..2e30ef85391 100644 --- a/server/methods/resetAvatar.coffee +++ b/server/methods/resetAvatar.coffee @@ -13,3 +13,10 @@ Meteor.methods RocketChat.Notifications.notifyAll 'updateAvatar', {username: user.username} return + +# Limit changing avatar once per minute +DDPRateLimiter.addRule + type: 'method' + name: 'resetAvatar' + userId: -> return true +, 1, 60000 diff --git a/server/methods/sendMessage.coffee b/server/methods/sendMessage.coffee index 2b5f84c89a9..527470eeb9e 100644 --- a/server/methods/sendMessage.coffee +++ b/server/methods/sendMessage.coffee @@ -16,3 +16,11 @@ Meteor.methods return false RocketChat.sendMessage user, message, room, options + +# Limit a user to sending 5 msgs/second +DDPRateLimiter.addRule + type: 'method' + name: 'sendMessage' + userId: (userId) -> + return RocketChat.models.Users.findOneById(userId)?.username isnt RocketChat.settings.get('RocketBot_Name') +, 5, 1000 diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index 90df44e2ad2..6083c8ecc21 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -23,3 +23,9 @@ Meteor.methods rs.pipe(ws) return + +DDPRateLimiter.addRule + type: 'method' + name: 'setAvatarFromService' + userId: -> return true +, 1, 60000 -- GitLab From 3f158ee0156012501cefa83a6368541ba05361d4 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 8 Oct 2015 10:31:42 -0300 Subject: [PATCH 0031/1338] Declaring dependencies explicitly for testing purposes. --- packages/meteor-streams/package.js | 2 ++ packages/rocketchat-lib/package.js | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/packages/meteor-streams/package.js b/packages/meteor-streams/package.js index 0b2b99d974d..1f4b367cc05 100755 --- a/packages/meteor-streams/package.js +++ b/packages/meteor-streams/package.js @@ -6,6 +6,8 @@ Package.describe({ Package.on_use(function (api, where) { api.use('underscore', ['client', 'server']); + api.use('check'); + api.use('random'); api.add_files(['lib/ev.js', 'lib/server.js', 'lib/stream_permission.js'], 'server'); api.add_files(['lib/ev.js', 'lib/client.js'], 'client'); }); diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index e4ee3fd0d66..3d8f3bbf4c7 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -17,6 +17,9 @@ Package.onUse(function(api) { api.use('underscore'); api.use('underscorestring:underscore.string'); api.use('monbro:mongodb-mapreduce-aggregation@1.0.1'); + api.use('service-configuration'); + api.use('check'); + api.use('arunoda:streams'); // COMMON api.addFiles('lib/core.coffee'); @@ -87,5 +90,9 @@ Package.onUse(function(api) { }); Package.onTest(function(api) { + api.use('coffeescript'); + api.use('sanjo:jasmine@0.20.2'); + api.use('rocketchat:lib'); + api.addFiles('tests/jasmine/server/unit/models/_Base.spec.coffee', 'server'); }); -- GitLab From 278fb1345abbd1cf9ec7aa5cfede06f8c6cc2704 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Thu, 8 Oct 2015 11:28:01 -0300 Subject: [PATCH 0032/1338] Create channel settings tab bar icon --- .meteor/packages | 1 + .meteor/versions | 1 + .../client/stylesheets/channel-settings.less | 17 ++++++++ .../client/tabBar.coffee | 11 +++++ .../client/views/channelSettings.coffee | 7 ++++ .../client/views/channelSettings.html | 25 ++++++++++++ .../i18n/en.i18n.json | 6 +++ .../rocketchat-channel-settings/package.js | 40 +++++++++++++++++++ 8 files changed, 108 insertions(+) create mode 100644 packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less create mode 100644 packages/rocketchat-channel-settings/client/tabBar.coffee create mode 100644 packages/rocketchat-channel-settings/client/views/channelSettings.coffee create mode 100644 packages/rocketchat-channel-settings/client/views/channelSettings.html create mode 100644 packages/rocketchat-channel-settings/i18n/en.i18n.json create mode 100644 packages/rocketchat-channel-settings/package.js diff --git a/.meteor/packages b/.meteor/packages index 7e27d2e2ab7..19e32dbe3cf 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -44,6 +44,7 @@ rocketchat:slashcommands-leave rocketchat:spotify rocketchat:statistics rocketchat:webrtc +rocketchat:channel-settings #rocketchat:chatops #rocketchat:livechat #rocketchat:hubot diff --git a/.meteor/versions b/.meteor/versions index 45238b76c83..4fcb93e66b1 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -125,6 +125,7 @@ reload@1.1.4 retry@1.0.4 rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 +rocketchat:channel-settings@0.0.1 rocketchat:chatops@0.0.1 rocketchat:colors@0.0.1 rocketchat:custom-oauth@1.0.0 diff --git a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less new file mode 100644 index 00000000000..0227c11170d --- /dev/null +++ b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less @@ -0,0 +1,17 @@ +.flex-tab { + .channel-settings { + margin-top: 60px; + padding: 20px; + + form { + label { + + } + } + + .submit { + margin-top: 30px; + text-align: center; + } + } +} diff --git a/packages/rocketchat-channel-settings/client/tabBar.coffee b/packages/rocketchat-channel-settings/client/tabBar.coffee new file mode 100644 index 00000000000..46bc83eacd8 --- /dev/null +++ b/packages/rocketchat-channel-settings/client/tabBar.coffee @@ -0,0 +1,11 @@ +Meteor.startup -> + + RocketChat.callbacks.add 'enter-room', -> + 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' diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee new file mode 100644 index 00000000000..5225bf4010b --- /dev/null +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -0,0 +1,7 @@ +Template.channelSettings.helpers + notDirect: -> + return ChatRoom.findOne(@rid).t isnt 'd' + roomType: -> + return ChatRoom.findOne(@rid).t + +Template.channelSettings.onCreated -> diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html new file mode 100644 index 00000000000..c72ecae4ad6 --- /dev/null +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -0,0 +1,25 @@ +<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> + <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> + </div> + </div> + {{/if}} + </fieldset> + <div class="submit"> + <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> + </div> + </form> + </div> +</template> diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json new file mode 100644 index 00000000000..3a052c3d63b --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -0,0 +1,6 @@ +{ + "Channel": "Channel", + "Private_Group": "Private Group", + "Room_Type": "Room Type", + "Room_Settings": "Room Settings" +} diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js new file mode 100644 index 00000000000..9cc6d0d9b7c --- /dev/null +++ b/packages/rocketchat-channel-settings/package.js @@ -0,0 +1,40 @@ +Package.describe({ + name: 'rocketchat:channel-settings', + version: '0.0.1', + summary: 'Channel Settings Panel', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'templating', + 'less@2.5.0', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles([ + 'client/tabBar.coffee', + 'client/views/channelSettings.html', + 'client/views/channelSettings.coffee', + 'client/stylesheets/channel-settings.less', + ], 'client'); + + // TAPi18n + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-channel-settings/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-channel-settings/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n@1.6.1'); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); -- GitLab From ef5435bcdd44384838f9b00e20379d027342df18 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 8 Oct 2015 12:22:36 -0300 Subject: [PATCH 0033/1338] Adding basic tests for RocketChat.models._Base --- .../server/unit/models/_Base.spec.coffee | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/rocketchat-lib/tests/jasmine/server/unit/models/_Base.spec.coffee diff --git a/packages/rocketchat-lib/tests/jasmine/server/unit/models/_Base.spec.coffee b/packages/rocketchat-lib/tests/jasmine/server/unit/models/_Base.spec.coffee new file mode 100644 index 00000000000..422fb80e1a0 --- /dev/null +++ b/packages/rocketchat-lib/tests/jasmine/server/unit/models/_Base.spec.coffee @@ -0,0 +1,24 @@ +describe 'rocketchat:lib Server | Models | Base', -> + + beforeEach -> + MeteorStubs.install() + this.obj = new RocketChat.models._Base + + afterEach -> + MeteorStubs.uninstall() + + it 'should exist', -> + expect(this.obj).toBeDefined() + + it 'should provide a basename for collections', -> + expect(typeof this.obj._baseName()).toBe('string') + + it 'should carry a Meteor.Collection object when initialized', -> + expect(this.obj.model).toBeFalsy() + expect(this.obj._initModel('carry')).toBeTruthy() + expect(typeof this.obj.model).toBe('object') + + it 'should apply a basename to the Meteor.Collection created', -> + name = 'apply' + expect(this.obj._initModel(name)).toBeTruthy() + expect(this.obj.model._name).toBe(this.obj._baseName() + name) -- GitLab From 2b16768ef5235b6ffd37ee40b365e71a62ad7b78 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 8 Oct 2015 12:43:10 -0300 Subject: [PATCH 0034/1338] Adding explicit dependencies and first tests for RocketChat.Markdown --- packages/rocketchat-markdown/package.js | 15 ++++++++++----- .../jasmine/client/unit/markdown.spec.coffee | 10 ++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index 2a7f3749f36..033fb957e09 100644 --- a/packages/rocketchat-markdown/package.js +++ b/packages/rocketchat-markdown/package.js @@ -8,14 +8,19 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use([ - 'coffeescript', - 'rocketchat:lib@0.0.1' - ]); + api.use('coffeescript'); + api.use('underscore'); + api.use('underscorestring:underscore.string'); + api.use('rocketchat:lib@0.0.1'); - api.addFiles('markdown.coffee', ['server','client']); + api.addFiles('markdown.coffee'); }); Package.onTest(function(api) { + api.use('coffeescript'); + api.use('sanjo:jasmine@0.20.2'); + api.use('rocketchat:lib'); + api.use('rocketchat:markdown'); + api.addFiles('tests/jasmine/client/unit/markdown.spec.coffee', 'client'); }); diff --git a/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee b/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee new file mode 100644 index 00000000000..dc78a38dfae --- /dev/null +++ b/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee @@ -0,0 +1,10 @@ +describe 'rocketchat:markdown Client + Server', -> + 'use strict' + + it 'should exist', -> + obj = RocketChat.Markdown { html: 'test' } + expect(obj).toBeDefined() + + it 'should highlight with bold when surrounded by *', -> + output = RocketChat.Markdown { 'msg': '', 'html':'*abc123*' } + expect(output.html).toEqual('<span class="copyonly">*</span><strong>abc123</strong><span class="copyonly">*</span>') -- GitLab From 00930088e09f8d3685d8a3ec162a1f873e791b57 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 8 Oct 2015 14:45:30 -0300 Subject: [PATCH 0035/1338] Rename package from theme-colors to theme --- .meteor/packages | 2 +- .meteor/versions | 2 +- client/views/main.html | 2 +- .../assets/lesshat.import.less | 887 ------------------ .../.npm/package/.gitignore | 0 .../.npm/package/README | 0 .../.npm/package/npm-shrinkwrap.json | 0 .../assets/colors.less | 0 .../assets/stylesheets/animation.css | 0 .../assets/stylesheets/base.less | 0 .../assets/stylesheets/fontello.css | 0 .../assets/stylesheets/global/_variables.less | 0 .../assets/stylesheets/rtl.less | 0 .../assets/stylesheets/swipebox.min.css | 0 .../stylesheets/utils/_colors.import.less | 0 .../stylesheets/utils/_emojione.import.less | 0 .../stylesheets/utils/_fonts.import.less | 0 .../stylesheets/utils/_keyframes.import.less | 0 .../stylesheets/utils/_lesshat.import.less | 0 .../assets/stylesheets/utils/_octicons.less | 0 .../stylesheets/utils/_preloader.import.less | 0 .../stylesheets/utils/_reset.import.less | 0 .../client/client.coffee | 5 +- .../client/minicolors/jquery.minicolors.css | 0 .../client/minicolors/jquery.minicolors.js | 0 .../package.js | 3 +- .../server/server.coffee | 4 +- .../server/variables.coffee | 0 28 files changed, 9 insertions(+), 896 deletions(-) delete mode 100644 packages/rocketchat-theme-colors/assets/lesshat.import.less rename packages/{rocketchat-theme-colors => rocketchat-theme}/.npm/package/.gitignore (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/.npm/package/README (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/.npm/package/npm-shrinkwrap.json (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/colors.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/animation.css (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/base.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/fontello.css (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/global/_variables.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/rtl.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/swipebox.min.css (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_colors.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_emojione.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_fonts.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_keyframes.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_lesshat.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_octicons.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_preloader.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/assets/stylesheets/utils/_reset.import.less (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/client/client.coffee (75%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/client/minicolors/jquery.minicolors.css (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/client/minicolors/jquery.minicolors.js (100%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/package.js (95%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/server/server.coffee (95%) rename packages/{rocketchat-theme-colors => rocketchat-theme}/server/variables.coffee (100%) diff --git a/.meteor/packages b/.meteor/packages index dee6f8eb2af..691b9f75ae2 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -87,7 +87,7 @@ todda00:friendly-slugs underscorestring:underscore.string yasaricli:slugify yasinuslu:blaze-meta -rocketchat:theme-colors +rocketchat:theme rocketchat:authorization perak:codemirror standard-minifiers diff --git a/.meteor/versions b/.meteor/versions index a0a31be562a..925c1136030 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -142,7 +142,7 @@ rocketchat:slashcommands-join@0.0.1 rocketchat:slashcommands-leave@0.0.1 rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 -rocketchat:theme-colors@0.0.1 +rocketchat:theme@0.0.1 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 diff --git a/client/views/main.html b/client/views/main.html index d48cdaa965d..330a506edc9 100644 --- a/client/views/main.html +++ b/client/views/main.html @@ -34,7 +34,7 @@ <link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-touch-icon-144x144.png?v=3"> <link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-touch-icon-152x152.png?v=3"> <link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png?v=3"> - <link rel="stylesheet" type="text/css" href="/theme-colors.css" id="theme-colors"> + <link rel="stylesheet" type="text/css" href="/theme.css" id="theme"> </head> <body> diff --git a/packages/rocketchat-theme-colors/assets/lesshat.import.less b/packages/rocketchat-theme-colors/assets/lesshat.import.less deleted file mode 100644 index c08d552d280..00000000000 --- a/packages/rocketchat-theme-colors/assets/lesshat.import.less +++ /dev/null @@ -1,887 +0,0 @@ -// * =========================================================== * -// < LESSHat > -// * =========================================================== * -// -// Made with Energy drinks in Prague, Czech Republic. -// Handcrafted by Petr Brzek, lesshat.com -// Works great with CSS Hat csshat.com - -// version: v3.0.2 (2014-06-17) - -// TABLE OF MIXINS: - // align-content - // align-items - // align-self - // animation - // animation-delay - // animation-direction - // animation-duration - // animation-fill-mode - // animation-iteration-count - // animation-name - // animation-play-state - // animation-timing-function - // appearance - // backface-visibility - // background-clip - // background-image - // background-origin - // background-size - // blur - // border-bottom-left-radius - // border-bottom-right-radius - // border-image - // border-radius - // border-top-left-radius - // border-top-right-radius - // box-shadow - // box-sizing - // brightness - // calc - // column-count - // column-gap - // column-rule - // column-width - // columns - // contrast - // display - // drop-shadow - // filter - // flex - // flex-basis - // flex-direction - // flex-grow - // flex-shrink - // flex-wrap - // font-face - // grayscale - // hue-rotate - // hyphens - // invert - // justify-content - // keyframes - // opacity - // order - // perspective - // perspective-origin - // placeholder - // rotate - // rotate3d - // rotateX - // rotateY - // rotateZ - // saturate - // scale - // scale3d - // scaleX - // scaleY - // scaleZ - // selection - // sepia - // size - // skew - // skewX - // skewY - // transform - // transform-origin - // transform-style - // transition - // transition-delay - // transition-duration - // transition-property - // transition-timing-function - // translate - // translate3d - // translateX - // translateY - // translateZ - // user-select - -.align-content(...) { - @process: ~`(function(r){return r=r||"stretch"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - @process_ms: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t?t="end":"space-between"==t?t="justify":"space-around"==t&&(t="distribute"),t})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-align-content: @process; - -ms-flex-line-pack: @process_ms; - align-content: @process; -} - -.align-items(...) { - @process_olderwebkit: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(t){return t=t||"stretch"})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - @process_ms: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - -webkit-box-align: @process_olderwebkit; - -moz-box-align: @process_moz; - -webkit-align-items: @process; - -ms-flex-align: @process_ms; - align-items: @process; -} - -.align-self(...) { - @process: ~`(function(t){return t=t||"auto"})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - @process_ms: ~`(function(t){return t=t||"auto","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - -webkit-align-self: @process; - -ms-flex-item-align: @process_ms; - align-self: @process; -} - -.animation(...) { - @process: ~`(function(t){return t=t||"none",/^[^, ]*,/.test(t)&&(t=t.replace(/(?:,)(?![^(]*\))/g,"")),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - -webkit-animation: @process; - -moz-animation: @process; - -o-animation: @process; - animation: @process; -} - -.animation-delay(...) { - @process: ~`(function(t){t=t||"0";var r=/(?:\d)(?:ms|s)/gi,e=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(t)||"0"===t||(t=t.replace(e,function(t){return t+=parseFloat(t,10)>10?"ms":"s"})),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-delay: @process; - -moz-animation-delay: @process; - -o-animation-delay: @process; - animation-delay: @process; -} - -.animation-direction(...) { - @process: ~`(function(r){return r||"normal"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-direction: @process; - -moz-animation-direction: @process; - -o-animation-direction: @process; - animation-direction: @process; -} - -.animation-duration(...) { - @process: ~`(function(r){r=r||"0";var t=/ms|s/gi,e=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(r)||"0"===r||(r=r.replace(e,function(r){return r+=parseFloat(r,10)>10?"ms":"s"})),r})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-duration: @process; - -moz-animation-duration: @process; - -o-animation-duration: @process; - animation-duration: @process; -} - -.animation-fill-mode(...) { - @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-fill-mode: @process; - -moz-animation-fill-mode: @process; - -o-animation-fill-mode: @process; - animation-fill-mode: @process; -} - -.animation-iteration-count(...) { - @process: ~`(function(r){return r||"0"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-iteration-count: @process; - -moz-animation-iteration-count: @process; - -o-animation-iteration-count: @process; - animation-iteration-count: @process; -} - -.animation-name(...) { - @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-name: @process; - -moz-animation-name: @process; - -o-animation-name: @process; - animation-name: @process; -} - -.animation-play-state(...) { - @process: ~`(function(r){return r||"running"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-play-state: @process; - -moz-animation-play-state: @process; - -o-animation-play-state: @process; - animation-play-state: @process; -} - -.animation-timing-function(...) { - @process: ~`(function(r){return r||"ease"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-animation-timing-function: @process; - -moz-animation-timing-function: @process; - -o-animation-timing-function: @process; - animation-timing-function: @process; -} - -.appearance(...) { - @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-appearance: @process; - -moz-appearance: @process; - appearance: @process; -} - -.backface-visibility(...) { - @process: ~`(function(r){return r||"visible"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-backface-visibility: @process; - -moz-backface-visibility: @process; - -o-backface-visibility: @process; - -ms-backface-visibility: @process; - backface-visibility: @process; -} - -.background-clip(...) { - @process: ~`(function(r){return r||"border-box"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - -webkit-background-clip: @process; - -moz-background-clip: @process; - background-clip: @process; -} - -.background-image(...) { - @process_ms: ~`(function(t){function e(t){var e,r,n,a,s,i,u,o,g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",c=0,l=0,f="",d=[];if(!t)return t;do e=t.charCodeAt(c++),r=t.charCodeAt(c++),n=t.charCodeAt(c++),o=e<<16|r<<8|n,a=63&o>>18,s=63&o>>12,i=63&o>>6,u=63&o,d[l++]=g.charAt(a)+g.charAt(s)+g.charAt(i)+g.charAt(u);while(c<t.length);f=d.join("");var p=t.length%3;return(p?f.slice(0,p-3):f)+"===".slice(p||3)}if(t=t||8121991,8121991==t)return t;var r=/linear|radial/g.test(t)&&t.split(/,(?=\s*(?:linear|radial|url))/g),n=[],a={"to bottom":'x1="0%" y1="0%" x2="0%" y2="100%"',"to left":'x1="100%" y1="0%" x2="0%" y2="0%"',"to top":'x1="0%" y1="100%" x2="0%" y2="0%"',"to right":'x1="0%" y1="0%" x2="100%" y2="0%"',get"top"(){return this["to bottom"]},get"180deg"(){return this["to bottom"]},get"right"(){return this["to left"]},get"270deg"(){return this["to left"]},get"bottom"(){return this["to top"]},get"90deg"(){return this["to right"]},get"0deg"(){return this["to top"]},get"left"(){return this["to right"]},"-45deg":'x1="0%" y1="0%" x2="100%" y2="100%"',"45deg":'x1="0%" y1="100%" x2="100%" y2="0%"',"ellipse at center":'cx="50%" cy="50%" r="75%"',get"135deg"(){return this["-45deg"]}},s={uri_data:"url(data:image/svg+xml;base64,",xml:'<?xml version="1.0" ?>',svg_start:'<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">',linear_gradient_start:'<linearGradient id="lesshat-generated" gradientUnits="userSpaceOnUse"',radial_gradient_start:'<radialGradient id="lesshat-generated" gradientUnits="userSpaceOnUse"',linear_gradient_end:"</linearGradient>",radial_gradient_end:"</radialGradient>",rect_linear:'<rect x="0" y="0" width="1" height="1" fill="url(#lesshat-generated)" />',rect_radial:'<rect x="-50" y="-50" width="101" height="101" fill="url(#lesshat-generated)" />',svg_end:"</svg>"};if(r.length){r.forEach(function(t){var e={};if(Object.keys(a).some(function(r){return t.indexOf(r)>=0?(e.svg_direction=a[r],!0):(e.svg_direction=!1,void 0)}),/linear/.test(t))e.svg_type="linear";else if(/radial/.test(t))e.svg_type="radial";else if(!/linear/.test(t)&&!/radial/.test(t))return e.url=t.trim(),e.svg_type="url",e.svg_direction=!0,n.push(e),!1;var r=t.match(/rgb|#[a-zA-Z0-9]|hsl/g).length;e.svg_stops=[],t=t.replace(/transparent/g,"rgba(0,0,0,0)"),t.match(/#[a-zA-Z0-9]/g)&&t.match(/(#[a-zA-Z0-9]+)\s*(\d+%)?/g).forEach(function(t){t=t.split(" "),e.svg_stops.push('<stop offset="'+(t[1]||!1)+'" stop-color="'+t[0]+'" stop-opacity="1"/>')}),t.match(/rgba?\(\d+,\s*\d+,\s*\d+(?:,\s*(0|1|\.\d+|0\.\d+))?\)/g)&&t.replace(/rgba?\((\d+,\s*\d+,\s*\d+)(?:,\s*(0|1|\.\d+|0\.\d+))?\)\s*(\d+%)?/g,function(t,r,n,a){e.svg_stops.push('<stop offset="'+(a||!1)+'" stop-color="rgb('+r+')" stop-opacity="'+(n||1)+'"/>')}),t.match(/hsla?\((\d+,\s*\d+%,\s*\d+%),\s*(0|1|\.\d+|0\.\d+)\)/g)&&t.replace(/hsla?\((\d+,\s*\d+%,\s*\d+%),\s*(0|1|\.\d+|0\.\d+)\)\s*(\d+%)?/g,function(t,r,n,a){e.svg_stops.push('<stop offset="'+(a||!1)+'" stop-color="hsl('+r+')" stop-opacity="'+(n||1)+'"/>')});var s=Math.floor(100/(r-1));e.svg_stops.forEach(function(t,r){/offset="false"/.test(t)&&(e.svg_stops[r]=t.replace(/offset="false"/,'offset="'+s*r+'%"'))}),e.svg_stops.sort(function(t,e){return t=t.match(/offset="(\d+)%"/),e=e.match(/offset="(\d+)%"/),2==t.length&&2==e.length?t[1]-e[1]:void 0}),n.push(e)});var i=[],u=n.every(function(t){for(var e in t)if(0==t[e]||0==t[e].length)return!1;return!0});if(!u)return 8121991;n.forEach(function(t,e){("linear"==t.svg_type||"radial"==t.svg_type)&&(i[e]=s.xml+s.svg_start),"linear"==t.svg_type?(i[e]+=s.linear_gradient_start+" "+t.svg_direction+">",t.svg_stops.forEach(function(t){i[e]+=t}),i[e]+=s.linear_gradient_end,i[e]+=s.rect_linear,i[e]+=s.svg_end):"radial"==t.svg_type?(i[e]+=s.radial_gradient_start+" "+t.svg_direction+">",t.svg_stops.forEach(function(t){i[e]+=t}),i[e]+=s.radial_gradient_end,i[e]+=s.rect_radial,i[e]+=s.svg_end):"url"==t.svg_type&&(i[e]=t.url)}),i.forEach(function(t,r){/<\?xml version="1.0" \?>/g.test(t)&&(i[r]=s.uri_data+e(t)+")")}),t=i.join(",")}return t})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`; - @process_webkit: ~`(function(t){if(t=t||8121991,8121991==t)return t;var e={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(e);return n.some(function(n){return t.indexOf(n)>=0?(t=t.replace(new RegExp(n+"(?![ a-z0-9])","g"),e[n]),!0):(r.test(t)&&(t=t.replace(r,function(t,e,r,n,a){return e.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),t=t.replace(/(\d+)\s*deg/g,function(t,e){return 90-e+"deg"}).replace(/(linear|radial)-gradient/g,"-webkit-$1-gradient")})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(t);return n.some(function(n){return e.indexOf(n)>=0?(e=e.replace(new RegExp(n+"(?![ a-z0-9])","g"),t[n]),!0):(r.test(e)&&(e=e.replace(r,function(e,t,r,n,a){return t.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),e=e.replace(/(\d+)\s*deg/g,function(e,t){return 90-t+"deg"}).replace(/(linear|radial)-gradient/g,"-moz-$1-gradient")})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`; - @process_opera: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(t);return n.some(function(n){return e.indexOf(n)>=0?(e=e.replace(new RegExp(n+"(?![ a-z0-9])","g"),t[n]),!0):(r.test(e)&&(e=e.replace(r,function(e,t,r,n,a){return t.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),e=e.replace(/(\d+)\s*deg/g,function(e,t){return 90-t+"deg"}).replace(/(linear|radial)-gradient/g,"-o-$1-gradient")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={top:"to bottom",right:"to left",bottom:"to top",left:"to right"},r=Object.keys(t);return r.some(function(r){return e.indexOf(r)>=0&&!new RegExp("to\\s+"+r+"|at\\s+"+r,"g").test(e)?(e=e.replace(new RegExp(r),t[r]),!0):void 0}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - background-image: @process_ms; - background-image: @process_webkit; - background-image: @process_moz; - background-image: @process_opera; - background-image: @process; -} - -.background-origin(...) { - @process: ~`(function(e){return e||"padding-box"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-background-origin: @process; - -moz-background-origin: @process; - background-origin: @process; -} - -.background-size(...) { - @process: ~`(function(e){e=e||"auto auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-background-size: @process; - -moz-background-size: @process; - background-size: @process; -} - -.blur(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: blur(@process); - -moz-filter: blur(@process); - -ms-filter: blur(@process); - filter: blur(@process); -} - -.border-bottom-left-radius(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-border-bottom-left-radius: @process; -webkit-background-clip: padding-box; - -moz-border-radius-bottomleft: @process; -moz-background-clip: padding; - border-bottom-left-radius: @process; background-clip: padding-box; -} - -.border-bottom-right-radius(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-border-bottom-right-radius: @process; -webkit-background-clip: padding-box; - -moz-border-radius-bottomright: @process; -moz-background-clip: padding; - border-bottom-right-radius: @process; background-clip: padding-box; -} - -.border-image(...) { - @process: ~`(function(e){return e=e||8121991,/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-border-image: @process; - -moz-border-image: @process; - -o-border-image: @process; - border-image: @process; -} - -.border-radius(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-border-radius: @process; -webkit-background-clip: padding-box; - -moz-border-radius: @process; -moz-background-clip: padding; - border-radius: @process; background-clip: padding-box; -} - -.border-top-left-radius(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-border-top-left-radius: @process; -webkit-background-clip: padding-box; - -moz-border-radius-topleft: @process; -moz-background-clip: padding; - border-top-left-radius: @process; background-clip: padding-box; -} - -.border-top-right-radius(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-border-top-right-radius: @process; -webkit-background-clip: padding-box; - -moz-border-radius-topright: @process; -moz-background-clip: padding; - border-top-right-radius: @process; background-clip: padding-box; -} - -.box-shadow(...) { - @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-box-shadow: @process; - -moz-box-shadow: @process; - box-shadow: @process; -} - -.box-sizing(...) { - @process: ~`(function(e){return e=e||"content-box"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-box-sizing: @process; - -moz-box-sizing: @process; - box-sizing: @process; -} - -.brightness(...) { - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: brightness(@process); - -moz-filter: brightness(@process); - -ms-filter: brightness(@process); - filter: brightness(@process); -} - -.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; - -} - -.column-count(...) { - @process: ~`(function(e){return e=e||"auto"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-column-count: @process; - -moz-column-count: @process; - column-count: @process; -} - -.column-gap(...) { - @process: ~`(function(e){e=e||"normal";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-column-gap: @process; - -moz-column-gap: @process; - column-gap: @process; -} - -.column-rule(...) { - @process: ~`(function(e){e=e||"medium none black";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-column-rule: @process; - -moz-column-rule: @process; - column-rule: @process; -} - -.column-width(...) { - @process: ~`(function(e){e=e||"auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-column-width: @process; - -moz-column-width: @process; - column-width: @process; -} - -.columns(...) { - @process: ~`(function(e){e=e||"auto auto";var t=/^\d+$/;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""),e=e.split(" ")),t.test(e[0])&&(e[0]=e[0]+"px"),e.join(" ")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-columns: @process; - -moz-columns: @process; - columns: @process; -} - -.contrast(...) { - @process: ~`(function(e){e=e||"100%";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: ~"contrast(@{process})"; - -moz-filter: ~"contrast(@{process})"; - -ms-filter: ~"contrast(@{process})"; - filter: ~"contrast(@{process})"; -} - -.display(...) { - @process_oldwebkit: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-webkit-box":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-moz-box":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_webkit: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-webkit-"+e:8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_ms: ~`(function(e){return e="flex"==e?"-ms-flexbox":"inline-flex"==e?"-ms-inline-flexbox":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){return"flex"!=e&&"inline-flex"!=e&&(e=8121991),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - display: @process_oldwebkit; - display: @process_moz; - display: @process_webkit; - display: @process_ms; - display: @process; -} - -.drop-shadow(...) { - @process: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: drop-shadow(@process); - -moz-filter: drop-shadow(@process); - -ms-filter: drop-shadow(@process); - filter: drop-shadow(@process); -} - -.filter(...) { - @process: ~`(function(e){return e=e||"none",/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: @process; - -moz-filter: @process; - -ms-filter: @process; - filter: @process; -} - -.flex(...) { - @process_olderwebkit: ~`(function(e){return/^\d+/.test(e)?e=e.match(/^\d+/)[0]:""==e&&(e="0"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){return/^\d+/.test(e)?e=e.match(/^\d+/)[0]:""==e&&(e="0"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){return e=e||"0 1 auto",/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-box-flex: @process_olderwebkit; - -moz-box-flex: @process_moz; - -webkit-flex: @process; - -ms-flex: @process; - flex: @process; -} - -.flex-basis(...) { - @process: ~`(function(e){e=e||"auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-flex-basis: @process; - flex-basis: @process; -} - -.flex-direction(...) { - @process_oldestwebkit: ~`(function(e){return e="row"==e||"column"==e?"normal":"row-reverse"==e||"column-reverse"==e?"reverse":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_oldermoz: ~`(function(e){return e="row"==e||"column"==e?"normal":"row-reverse"==e||"column-reverse"==e?"reverse":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_olderwebkit: ~`(function(e){return e="row"==e||"row-reverse"==e?"horizontal":"column"==e||"column-reverse"==e?"vertical":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){return e="row"==e||"row-reverse"==e?"horizontal":"column"==e||"column-reverse"==e?"vertical":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){return e=e||"row"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-box-direction: @process_oldestwebkit; - -moz-box-direction: @process_oldermoz; - -webkit-box-orient: @process_olderwebkit; - -moz-box-orient: @process_moz; - -webkit-flex-direction: @process; - -ms-flex-direction: @process; - flex-direction: @process; -} - -.flex-grow(...) { - @process: ~`(function(e){return e=e||"0"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-flex-grow: @process; - flex-grow: @process; -} - -.flex-shrink(...) { - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-flex-shrink: @process; - flex-shrink: @process; -} - -.flex-wrap(...) { - @process: ~`(function(e){return e=e||"nowrap"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-flex-wrap: @process; - -ms-flex-wrap: @process; - flex-wrap: @process; -} - -.font-face(@fontname, @fontfile, @fontweight:normal, @fontstyle:normal) { - font-family: "@{fontname}"; - src: url("@{fontfile}.eot"); - src: url("@{fontfile}.eot?#iefix") format("embedded-opentype"), - url("@{fontfile}.woff") format("woff"), - url("@{fontfile}.ttf") format("truetype"), - url("@{fontfile}.svg#@{fontname}") format("svg"); - font-weight: @fontweight; - font-style: @fontstyle; -} - -.grayscale(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: grayscale(@process); - -moz-filter: grayscale(@process); - -ms-filter: grayscale(@process); - filter: grayscale(@process); -} - -.hue-rotate(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: hue-rotate(@process); - -moz-filter: hue-rotate(@process); - -ms-filter: hue-rotate(@process); - filter: hue-rotate(@process); -} - -.hyphens(...) { - @process: ~`(function(e){return e=e||"manual"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-hyphens: @process; - -moz-hyphens: @process; - -ms-hyphens: @process; - hyphens: @process; -} - -.invert(...) { - @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: invert(@process); - -moz-filter: invert(@process); - -ms-filter: invert(@process); - filter: invert(@process); -} - -.justify-content(...) { - @process_oldestWebkit: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":("space-between"==e||"space-around"==e)&&(e="justify"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":("space-between"==e||"space-around"==e)&&(e="justify"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_ms: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":"space-between"==e?e="justify":"space-around"==e&&(e="distribute"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){return e=e||"flex-start"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-box-pack: @process_oldestWebkit; - -moz-box-pack: @process_moz; - -ms-flex-pack: @process_ms; - -webkit-justify-content: @process; - justify-content: @process; -} - -.keyframes(...) { - @process: ~`(function(e){function r(r,t,c){var i="}\n",u=n.split(/(^[a-zA-Z0-9-]+),/g),s=t+" "+u[1]+"{",o=["-webkit-","-moz-","-ms-",""];c?a.forEach(function(r){-1!==e.indexOf(r)&&(u[2]=u[2].replace(new RegExp(r,"g"),function(e){return c+e}))}):u[2]=u[2].replace(/{([^}]+)}/g,function(e,r){var t=r.split(";");t.forEach(function(e,r){a.forEach(function(n){-1!==e.indexOf(n)&&(t[r]="",o.forEach(function(a){t[r]+=e.trim().replace(new RegExp(n,"g"),function(e){return a+e})+";"}))})});var n=t.join(";").replace(/;;/g,";");return e.replace(r,n)}),s+=u[2]+i,"start"==r?e="0; } \n"+s:"startend"==r?e="0; } \n"+s.replace(i,""):e+="end"==r?s.replace(i,""):s}e=e||8121991;var t="@{state}",n=e;if(8121991==e)return e;var a=["animation","transform","filter"];switch(t){case"1":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"2":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r("end","@keyframes");break;case"3":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r("end","@-o-keyframes","-o-");break;case"4":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"5":r("start","@-webkit-keyframes","-webkit-"),r("end","@-moz-keyframes","-moz-");break;case"6":r("start","@-webkit-keyframes","-webkit-"),r("end","@-o-keyframes","-o-");break;case"7":r("start","@-webkit-keyframes","-webkit-"),r("end","@keyframes");break;case"8":r("startend","@-webkit-keyframes","-webkit-");break;case"9":r("start","@-moz-keyframes","-moz-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"10":r("start","@-moz-keyframes","-moz-"),r("end","@-o-keyframes","-o-");break;case"11":r("start","@-moz-keyframes","-moz-"),r("end","@keyframes");break;case"12":r("startend","@-moz-keyframes","-moz-");break;case"13":r("start","@-o-keyframes","-o-"),r("end","@keyframes");break;case"14":r("startend","@-o-keyframes","-o-");break;case"15":r("startend","@keyframes")}return e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @state: 1; lesshat-selector { -lh-property: @process; } -} - -.opacity(...) { - @process_ms: ~`(function(e){return e=e||"filter: alpha(opacity=100)","alpha(opacity="+Math.floor(100*e)+")"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - zoom: 1; filter: @process_ms; - -webkit-opacity: @process; - -moz-opacity: @process; - opacity: @process; -} - -.order(...) { - @process: ~`(function(e){return e=e||"0"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-box-ordinal-group: @process; - -moz-box-ordinal-group: @process; - -ms-flex-order: @process; - -webkit-order: @process; - order: @process; -} - -.perspective(...) { - @process: ~`(function(e){e=e||"none";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-perspective: @process; - -moz-perspective: @process; - perspective: @process; -} - -.perspective-origin(...) { - @process: ~`(function(e){e=e||"50% 50%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-perspective-origin: @process; - -moz-perspective-origin: @process; - perspective-origin: @process; -} - -.placeholder(@color:#aaa, @element: 08121991) { - .inception (@arguments) when not (@element = 08121991) { - @{element}::-webkit-input-placeholder { - color: @color; - } - @{element}:-moz-placeholder { - color: @color; - } - @{element}::-moz-placeholder { - color: @color; - } - @{element}:-ms-input-placeholder { - color: @color; - } - } - .inception (@arguments) when (@element = 08121991) { - &::-webkit-input-placeholder { - color: @color; - } - &:-moz-placeholder { - color: @color; - } - &::-moz-placeholder { - color: @color; - } - &:-ms-input-placeholder { - color: @color; - } - } - .inception(@arguments); -} - -.rotate(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: rotate(@process); - -moz-transform: rotate(@process); - -o-transform: rotate(@process); - -ms-transform: rotate(@process); - transform: rotate(@process); -} - -.rotate3d(...) { - @process: ~`(function(e){return e=e||"0, 0, 0, 0",e=e.replace(/,\s*\d+$/,function(e){return e+"deg"})})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: rotate3d(@process); - -moz-transform: rotate3d(@process); - -o-transform: rotate3d(@process); - -ms-transform: rotate3d(@process); - transform: rotate3d(@process); -} - -.rotateX(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: rotateX(@process); - -moz-transform: rotateX(@process); - -o-transform: rotateX(@process); - -ms-transform: rotateX(@process); - transform: rotateX(@process); -} - -.rotateY(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: rotateY(@process); - -moz-transform: rotateY(@process); - -o-transform: rotateY(@process); - -ms-transform: rotateY(@process); - transform: rotateY(@process); -} - -.rotateZ(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: rotateZ(@process); - -moz-transform: rotateZ(@process); - -o-transform: rotateZ(@process); - -ms-transform: rotateZ(@process); - transform: rotateZ(@process); -} - -.saturate(...) { - @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: ~"saturate(@{process})"; - -moz-filter: ~"saturate(@{process})"; - -ms-filter: ~"saturate(@{process})"; - filter: ~"saturate(@{process})"; -} - -.scale(...) { - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: scale(@process); - -moz-transform: scale(@process); - -o-transform: scale(@process); - -ms-transform: scale(@process); - transform: scale(@process); -} - -.scale3d(...) { - @process: ~`(function(e){return e=e||"1, 1, 1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: scale3d(@process); - -moz-transform: scale3d(@process); - -o-transform: scale3d(@process); - -ms-transform: scale3d(@process); - transform: scale3d(@process); -} - -.scaleX(...) { - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: scaleX(@process); - -moz-transform: scaleX(@process); - -o-transform: scaleX(@process); - -ms-transform: scaleX(@process); - transform: scaleX(@process); -} - -.scaleY(...) { - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: scaleY(@process); - -moz-transform: scaleY(@process); - -o-transform: scaleY(@process); - -ms-transform: scaleY(@process); - transform: scaleY(@process); -} - -.scaleZ(...) { - @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: scaleZ(@process); - -moz-transform: scaleZ(@process); - -o-transform: scaleZ(@process); - -ms-transform: scaleZ(@process); - transform: scaleZ(@process); -} - -.selection(...) { - @process: ~`(function(e){function r(r,t){var a="}\n",c=n.split(","),u=(c[1]||"")+t+"{"+c[0]+a;"start"==r?e="0; } \n"+u:"startend"==r?e="0; } \n"+u.replace(a,""):e+="end"==r?u.replace(a,""):u}e=e||8121991;var t="@{state}",n=e;if(8121991==e)return e;switch(t){case"1":r("start","::selection"),r("end","::-moz-selection");break;case"2":r("startend","::selection");break;case"3":r("startend","::-moz-selection")}return e=e.replace(/;$/g,"")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @state: 1; lesshat-selector { -lh-property: @process; } - -} - -.sepia(...) { - @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-filter: sepia(@process); - -moz-filter: sepia(@process); - -ms-filter: sepia(@process); - filter: sepia(@process); -} - -.size(@square) { - @unit: 'px'; - .process(@square) when (ispixel(@square)), (isem(@square)), (ispercentage(@square)), (iskeyword(@square)) { - width: @square; - height: @square; - } - - .process(@square) when not (ispixel(@square)) and not (isem(@square)) and not (ispercentage(@square)) and not (isstring(@square)) and not (iskeyword(@square)) { - width: ~`@{square} + @{unit}`; - height: ~`@{square} + @{unit}`; - } - - .process(@square); - -} - -.size(@width, @height) { - @unit: 'px'; - .process(@width, @height) when (ispixel(@width)), (isem(@width)), (ispercentage(@width)), (iskeyword(@width)) { - .kittens(@height) when (ispixel(@height)), (isem(@height)), (ispercentage(@height)), (iskeyword(@height)) { - width: @width; - height: @height; - } - .kittens(@height) when not (ispixel(@height)) and not (isem(@height)) and not (ispercentage(@height)) and not (iskeyword(@height)) { - width: @width; - height: ~`@{height} + @{unit}`; - } - .kittens(@height); - } - - .process(@width, @height) when (ispixel(@height)), (isem(@height)), (ispercentage(@height)), (iskeyword(@height)) { - .kittens(@width) when (ispixel(@width)), (isem(@width)), (ispercentage(@width)), (iskeyword(@width)) {} - .kittens(@width) when not (ispixel(@width)) and not (isem(@width)) and not (ispercentage(@width)) and not (iskeyword(@width)) { - width: ~`@{width} + @{unit}`; - height: @height; - } - .kittens(@width); - } - - .process(@width, @height) when not (ispixel(@width)) and not (isem(@width)) and not (ispercentage(@width)) and not (iskeyword(@width)) and not (ispixel(@height)) and not (isem(@height)) and not (ispercentage(@height)) and not (iskeyword(@height)) { - width: ~`@{width} + @{unit}`; - height: ~`@{height} + @{unit}`; - } - - .process(@width, @height); - -} - -.skew(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: skew(@process); - -moz-transform: skew(@process); - -o-transform: skew(@process); - -ms-transform: skew(@process); - transform: skew(@process); -} - -.skewX(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: skewX(@process); - -moz-transform: skewX(@process); - -o-transform: skewX(@process); - -ms-transform: skewX(@process); - transform: skewX(@process); -} - -.skewY(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: skewY(@process); - -moz-transform: skewY(@process); - -o-transform: skewY(@process); - -ms-transform: skewY(@process); - transform: skewY(@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; -} - -.transform-origin(...) { - @process: ~`(function(e){e=e||"50% 50% 0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform-origin: @process; - -moz-transform-origin: @process; - -o-transform-origin: @process; - -ms-transform-origin: @process; - transform-origin: @process; -} - -.transform-style(...) { - @process: ~`(function(e){return e=e||"flat"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform-style: @process; - -moz-transform-style: @process; - -o-transform-style: @process; - -ms-transform-style: @process; - transform-style: @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; -} - -.transition-delay(...) { - @process: ~`(function(e){e=e||"0";var r=/(?:\d)(?:ms|s)/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)||"0"===e||(e=e.replace(t,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transition-delay: @process; - -moz-transition-delay: @process; - -o-transition-delay: @process; - transition-delay: @process; -} - -.transition-duration(...) { - @process: ~`(function(e){e=e||"0";var r=/ms|s/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)||"0"===e||(e=e.replace(t,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transition-duration: @process; - -moz-transition-duration: @process; - -o-transition-duration: @process; - transition-duration: @process; -} - -.transition-property(...) { - @process_webkit: ~`(function(e){e=e||"all";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-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){e=e||"all";var r=["background-size","box-shadow","column","transform","filter"],t="-moz-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_opera: ~`(function(e){e=e||"all";var r=["transform"],t="-o-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){e=e||"all";var r=["-webkit-","-moz-","-o-",""],t=["column","transform","filter"],n=e.split(/(?:,)(?![^(]*\))/g);return n.forEach(function(e,a){t.forEach(function(t){-1!==e.indexOf(t)&&(n[a]="",r.forEach(function(c,u){n[a]+=e.trim().replace(new RegExp(t,"g"),function(e){return c+e}),u<r.length-1&&(n[a]+=",")}))})}),e=n.join(",")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transition-property: @process_webkit; - -moz-transition-property: @process_moz; - -o-transition-property: @process_opera; - transition-property: @process; -} - -.transition-timing-function(...) { - @process: ~`(function(e){return e=e||"ease"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transition-timing-function: @process; - -moz-transition-timing-function: @process; - -o-transition-timing-function: @process; - transition-timing-function: @process; -} - -.translate(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: translate(@process); - -moz-transform: translate(@process); - -o-transform: translate(@process); - -ms-transform: translate(@process); - transform: translate(@process); -} - -.translate3d(...) { - @process: ~`(function(e){e=e||"0, 0, 0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: translate3d(@process); - -moz-transform: translate3d(@process); - -o-transform: translate3d(@process); - -ms-transform: translate3d(@process); - transform: translate3d(@process); -} - -.translateX(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: translateX(@process); - -moz-transform: translateX(@process); - -o-transform: translateX(@process); - -ms-transform: translateX(@process); - transform: translateX(@process); -} - -.translateY(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: translateY(@process); - -moz-transform: translateY(@process); - -o-transform: translateY(@process); - -ms-transform: translateY(@process); - transform: translateY(@process); -} - -.translateZ(...) { - @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: translateZ(@process); - -moz-transform: translateZ(@process); - -o-transform: translateZ(@process); - -ms-transform: translateZ(@process); - transform: translateZ(@process); -} - -.user-select(...) { - @process: ~`(function(e){return e=e||"auto"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-user-select: @process; - -moz-user-select: @process; - -ms-user-select: @process; - user-select: @process; -} diff --git a/packages/rocketchat-theme-colors/.npm/package/.gitignore b/packages/rocketchat-theme/.npm/package/.gitignore similarity index 100% rename from packages/rocketchat-theme-colors/.npm/package/.gitignore rename to packages/rocketchat-theme/.npm/package/.gitignore diff --git a/packages/rocketchat-theme-colors/.npm/package/README b/packages/rocketchat-theme/.npm/package/README similarity index 100% rename from packages/rocketchat-theme-colors/.npm/package/README rename to packages/rocketchat-theme/.npm/package/README diff --git a/packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-theme/.npm/package/npm-shrinkwrap.json similarity index 100% rename from packages/rocketchat-theme-colors/.npm/package/npm-shrinkwrap.json rename to packages/rocketchat-theme/.npm/package/npm-shrinkwrap.json diff --git a/packages/rocketchat-theme-colors/assets/colors.less b/packages/rocketchat-theme/assets/colors.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/colors.less rename to packages/rocketchat-theme/assets/colors.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/animation.css b/packages/rocketchat-theme/assets/stylesheets/animation.css similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/animation.css rename to packages/rocketchat-theme/assets/stylesheets/animation.css diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/base.less rename to packages/rocketchat-theme/assets/stylesheets/base.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/fontello.css b/packages/rocketchat-theme/assets/stylesheets/fontello.css similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/fontello.css rename to packages/rocketchat-theme/assets/stylesheets/fontello.css diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/global/_variables.less b/packages/rocketchat-theme/assets/stylesheets/global/_variables.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/global/_variables.less rename to packages/rocketchat-theme/assets/stylesheets/global/_variables.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/rtl.less rename to packages/rocketchat-theme/assets/stylesheets/rtl.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/swipebox.min.css b/packages/rocketchat-theme/assets/stylesheets/swipebox.min.css similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/swipebox.min.css rename to packages/rocketchat-theme/assets/stylesheets/swipebox.min.css diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_colors.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_emojione.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_emojione.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_emojione.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_emojione.import.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_fonts.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_fonts.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_fonts.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_fonts.import.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_keyframes.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_keyframes.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_keyframes.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_keyframes.import.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_lesshat.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_lesshat.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_lesshat.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_lesshat.import.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_octicons.less b/packages/rocketchat-theme/assets/stylesheets/utils/_octicons.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_octicons.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_octicons.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_preloader.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_preloader.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_preloader.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_preloader.import.less diff --git a/packages/rocketchat-theme-colors/assets/stylesheets/utils/_reset.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_reset.import.less similarity index 100% rename from packages/rocketchat-theme-colors/assets/stylesheets/utils/_reset.import.less rename to packages/rocketchat-theme/assets/stylesheets/utils/_reset.import.less diff --git a/packages/rocketchat-theme-colors/client/client.coffee b/packages/rocketchat-theme/client/client.coffee similarity index 75% rename from packages/rocketchat-theme-colors/client/client.coffee rename to packages/rocketchat-theme/client/client.coffee index 3680ef5365e..4e888843ddb 100644 --- a/packages/rocketchat-theme-colors/client/client.coffee +++ b/packages/rocketchat-theme/client/client.coffee @@ -1,6 +1,7 @@ updateTheme = -> - el = $('#theme-colors')[0] - el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() + el = $('#theme')[0] + if el + el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() Meteor.startup -> connected = Meteor.status().connected diff --git a/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.css b/packages/rocketchat-theme/client/minicolors/jquery.minicolors.css similarity index 100% rename from packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.css rename to packages/rocketchat-theme/client/minicolors/jquery.minicolors.css diff --git a/packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.js b/packages/rocketchat-theme/client/minicolors/jquery.minicolors.js similarity index 100% rename from packages/rocketchat-theme-colors/client/minicolors/jquery.minicolors.js rename to packages/rocketchat-theme/client/minicolors/jquery.minicolors.js diff --git a/packages/rocketchat-theme-colors/package.js b/packages/rocketchat-theme/package.js similarity index 95% rename from packages/rocketchat-theme-colors/package.js rename to packages/rocketchat-theme/package.js index 9d90efff588..18ea8f34396 100644 --- a/packages/rocketchat-theme-colors/package.js +++ b/packages/rocketchat-theme/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:theme-colors', + name: 'rocketchat:theme', version: '0.0.1', summary: '', git: '' @@ -36,7 +36,6 @@ Package.onUse(function(api) { api.addAssets('assets/stylesheets/fontello.css', 'server'); api.addAssets('assets/stylesheets/rtl.less', 'server'); api.addAssets('assets/stylesheets/swipebox.min.css', 'server'); - api.addAssets('assets/colors.less', 'server'); }); Npm.depends({ diff --git a/packages/rocketchat-theme-colors/server/server.coffee b/packages/rocketchat-theme/server/server.coffee similarity index 95% rename from packages/rocketchat-theme-colors/server/server.coffee rename to packages/rocketchat-theme/server/server.coffee index 55902c5ce73..03e38c0aa54 100644 --- a/packages/rocketchat-theme-colors/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -16,7 +16,7 @@ RocketChat.theme = new class 'assets/stylesheets/fontello.css' 'assets/stylesheets/rtl.less' 'assets/stylesheets/swipebox.min.css' - 'assets/colors.less' + 'assets/stylesheets/utils/_colors.import.less' ] constructor: -> @@ -90,7 +90,7 @@ RocketChat.theme = new class return RocketChat.settings.get 'css' -WebApp.connectHandlers.use '/theme-colors.css', (req, res, next) -> +WebApp.connectHandlers.use '/theme.css', (req, res, next) -> css = RocketChat.theme.getCss() res.setHeader 'content-type', 'text/css; charset=UTF-8' diff --git a/packages/rocketchat-theme-colors/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee similarity index 100% rename from packages/rocketchat-theme-colors/server/variables.coffee rename to packages/rocketchat-theme/server/variables.coffee -- GitLab From 032d0581355fd723bc194c8c9599f9739f667d6d Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 8 Oct 2015 15:20:24 -0300 Subject: [PATCH 0036/1338] Supporting test execution on client and server. --- packages/rocketchat-markdown/markdown.coffee | 4 ++-- packages/rocketchat-markdown/package.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index 97bed19040b..33dcfa42715 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -6,7 +6,7 @@ class Markdown constructor: (message) -> - if _.trim message.html + if _s.trim message.html msg = message.html @@ -20,7 +20,7 @@ class Markdown message.html = msg - console.log 'Markdown', message if window.rocketDebug + console.log 'Markdown', message if window?.rocketDebug return message diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index 033fb957e09..17ce19f6999 100644 --- a/packages/rocketchat-markdown/package.js +++ b/packages/rocketchat-markdown/package.js @@ -22,5 +22,5 @@ Package.onTest(function(api) { api.use('rocketchat:lib'); api.use('rocketchat:markdown'); - api.addFiles('tests/jasmine/client/unit/markdown.spec.coffee', 'client'); + api.addFiles('tests/jasmine/client/unit/markdown.spec.coffee'); }); -- GitLab From d13bceebbeeab34fa091509680bcb49c0c978a11 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 8 Oct 2015 15:28:49 -0300 Subject: [PATCH 0037/1338] RocketChat.Markdown test was moved to the package's tests directory --- tests/jasmine/client/unit/markdowntest.js | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 tests/jasmine/client/unit/markdowntest.js diff --git a/tests/jasmine/client/unit/markdowntest.js b/tests/jasmine/client/unit/markdowntest.js deleted file mode 100644 index 0d5f214423c..00000000000 --- a/tests/jasmine/client/unit/markdowntest.js +++ /dev/null @@ -1,7 +0,0 @@ -describe('Testing rocketchat:markdown', function () { - 'use strict'; - it('should highlight with bold when surrounded by *', function () { - var output = RocketChat.Markdown({'msg': '', 'html':'*abc123*'}); - expect(output.html).toEqual('<span class="copyonly">*</span><strong>abc123</strong><span class="copyonly">*</span>') - }); - }); \ No newline at end of file -- GitLab From 89bea0c067521648635218d4c52288c5b27a5c89 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 8 Oct 2015 16:58:20 -0300 Subject: [PATCH 0038/1338] Adding application test --- tests/jasmine/client/unit/lib/sideNav.coffee | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/jasmine/client/unit/lib/sideNav.coffee diff --git a/tests/jasmine/client/unit/lib/sideNav.coffee b/tests/jasmine/client/unit/lib/sideNav.coffee new file mode 100644 index 00000000000..745cf2591ae --- /dev/null +++ b/tests/jasmine/client/unit/lib/sideNav.coffee @@ -0,0 +1,5 @@ +describe 'App | Client | Lib | SideNav', -> + 'use strict'; + + it 'should exist', -> + expect(SideNav).toBeDefined() -- GitLab From 4adbd03852b69fad35adb50a028a71ee4267589c Mon Sep 17 00:00:00 2001 From: Aaron Ogle <aaron@geekgonecrazy.com> Date: Fri, 9 Oct 2015 11:15:48 -0500 Subject: [PATCH 0039/1338] Changed Github Enterprise endpoints to be relative to the domain. If you put domain.com in the server url it would attempt to access domain.comapi/v3/user --- packages/rocketchat-github-enterprise/common.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-github-enterprise/common.coffee b/packages/rocketchat-github-enterprise/common.coffee index 36f171e822c..fe44a29b7f9 100644 --- a/packages/rocketchat-github-enterprise/common.coffee +++ b/packages/rocketchat-github-enterprise/common.coffee @@ -2,9 +2,9 @@ # In RocketChat -> Administration the URL needs to be http(s)://{github.enterprise.server}/ config = serverURL: '' - identityPath: 'api/v3/user' - authorizePath: 'login/oauth/authorize' - tokenPath: 'login/oauth/access_token' + identityPath: '/api/v3/user' + authorizePath: '/login/oauth/authorize' + tokenPath: '/login/oauth/access_token' addAutopublishFields: forLoggedInUser: ['services.github-enterprise'] forOtherUsers: ['services.github-enterprise.username'] -- GitLab From 7a8aef345876c7caf999deb863db7ba13f611a9e Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Fri, 9 Oct 2015 13:31:43 -0300 Subject: [PATCH 0040/1338] Updating packages and versions --- .meteor/packages | 4 ++-- .meteor/versions | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 7e27d2e2ab7..dd0a51febde 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -105,5 +105,5 @@ spacebars check rocketchat:github-enterprise rocketchat:chatops -# sanjo:jasmine@0.20.2 -# velocity:html-reporter +sanjo:jasmine@0.20.2 +velocity:console-reporter diff --git a/.meteor/versions b/.meteor/versions index 45238b76c83..7bb0c51348d 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -8,7 +8,6 @@ accounts-password@1.1.3 accounts-twitter@1.0.6 alanning:roles@1.2.13 aldeed:simple-schema@1.3.3 -amplify@1.0.0 arunoda:streams@0.1.17 autoupdate@1.2.3 babel-compiler@5.8.24_1 @@ -179,8 +178,8 @@ underscore@1.0.4 underscorestring:underscore.string@3.2.2 url@1.0.5 velocity:chokidar@1.2.0_1 +velocity:console-reporter@0.1.3 velocity:core@0.10.4 -velocity:html-reporter@0.9.0 velocity:meteor-internals@1.1.0_7 velocity:meteor-stubs@1.1.0 velocity:shim@0.1.0 -- GitLab From a42ca58a6fa001e1599f467adacb872d312becde Mon Sep 17 00:00:00 2001 From: Aaron Ogle <aaron@geekgonecrazy.com> Date: Fri, 9 Oct 2015 11:48:35 -0500 Subject: [PATCH 0041/1338] Enabled i18n and added note to exclude trailing slash on domain. --- .../i18n/en.i18n.json | 9 ++--- .../rocketchat-github-enterprise/package.js | 33 +++++++++---------- .../startup.coffee | 8 ++--- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index e8bdee76a8e..187124f550e 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -1,6 +1,7 @@ { - "Accounts_OAuth_GitHub_Enterprise" : "GitHub Enterprise OAuth", - "API_GitHub_Enterprise_URL" : "GitHub Enterprise Server URL", - "Accounts_OAuth_GitHub_Enterprise_id" : "GitHub OAuth Client Id", - "Accounts_OAuth_GitHub_Enterprise_secret" : "GitHub OAuth Client Secret" + "Accounts_OAuth_GitHub_Enterprise" : "OAuth Enabled", + "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" : "Note: Please exclude trailing slash" } diff --git a/packages/rocketchat-github-enterprise/package.js b/packages/rocketchat-github-enterprise/package.js index 5ac1751e7a9..ebcbaf8d9c4 100644 --- a/packages/rocketchat-github-enterprise/package.js +++ b/packages/rocketchat-github-enterprise/package.js @@ -4,33 +4,30 @@ Package.describe({ summary: 'RocketChat settings for GitHub Enterprise Oauth Flow' }); -// Loads all i18n.json files into tapi18nFiles -var _ = Npm.require('underscore'); -var fs = Npm.require('fs'); -tapi18nFiles = fs.readdirSync('packages/rocketchat-github-enterprise/i18n').forEach(function(filename) { - if (fs.statSync('packages/rocketchat-github-enterprise/i18n/' + filename).size > 16) { - return 'i18n/' + filename; - } -}); - Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use("tap:i18n@1.5.1"); api.use('coffeescript'); api.use('rocketchat:lib@0.0.1'); api.use('rocketchat:custom-oauth'); - api.use('templating', 'client'); - - - api.addFiles("package-tap.i18n"); - api.addFiles("common.coffee"); - api.addFiles(tapi18nFiles); - + api.addFiles("common.coffee"); api.addFiles('github-enterprise-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-github-enterprise/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-github-enterprise/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']); + }); Package.onTest(function(api) { diff --git a/packages/rocketchat-github-enterprise/startup.coffee b/packages/rocketchat-github-enterprise/startup.coffee index 6218ef61b3a..2ca75ae78c0 100644 --- a/packages/rocketchat-github-enterprise/startup.coffee +++ b/packages/rocketchat-github-enterprise/startup.coffee @@ -1,6 +1,6 @@ Meteor.startup -> - RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise', false, {type: 'boolean', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'OAuth Enabled'} - RocketChat.settings.add 'API_GitHub_Enterprise_URL', '', { type: 'string', group: 'Accounts', public: true, section: 'GitHub Enterprise', i18nLabel: 'Server URL' } - RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_id', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Client ID' } - RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_secret', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Client Secret' } + RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise', false, {type: 'boolean', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Accounts_OAuth_GitHub_Enterprise'} + RocketChat.settings.add 'API_GitHub_Enterprise_URL', '', { type: 'string', group: 'Accounts', public: true, section: 'GitHub Enterprise', i18nLabel: 'API_GitHub_Enterprise_URL', i18nDescription: 'Github_Enterprise_Url_No_Trail' } + RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_id', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Accounts_OAuth_GitHub_Enterprise_id' } + RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_secret', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Accounts_OAuth_GitHub_Enterprise_secret' } -- GitLab From 05461c7967c71ab4308ae58db6912f70fe48e168 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Fri, 9 Oct 2015 15:30:26 -0300 Subject: [PATCH 0042/1338] Updated versions --- .meteor/versions | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.meteor/versions b/.meteor/versions index 8c8b864df5a..7bb0c51348d 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -101,11 +101,14 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 +package-version-parser@3.0.4 pauli:accounts-linkedin@1.1.2 pauli:linkedin@1.1.2 perak:codemirror@1.2.7 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 +practicalmeteor:chai@2.1.0_1 +practicalmeteor:loglevel@1.2.0_2 promise@0.5.0 qnub:emojione@0.0.3 raix:eventemitter@0.1.3 @@ -146,6 +149,11 @@ rocketchat:statistics@0.0.1 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 +sanjo:jasmine@0.20.2 +sanjo:karma@3.0.2 +sanjo:long-running-child-process@1.1.3 +sanjo:meteor-files-helpers@1.2.0_1 +sanjo:meteor-version@1.0.0 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 @@ -169,6 +177,13 @@ ui@1.0.8 underscore@1.0.4 underscorestring:underscore.string@3.2.2 url@1.0.5 +velocity:chokidar@1.2.0_1 +velocity:console-reporter@0.1.3 +velocity:core@0.10.4 +velocity:meteor-internals@1.1.0_7 +velocity:meteor-stubs@1.1.0 +velocity:shim@0.1.0 +velocity:source-map-support@0.3.2_1 webapp@1.2.2 webapp-hashing@1.0.5 yasaricli:slugify@0.0.7 -- GitLab From 420ac769d9a5b9a3756c563269ee9d77b29b19c4 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Fri, 9 Oct 2015 15:52:37 -0300 Subject: [PATCH 0043/1338] Settings file should only be available on server. --- packages/rocketchat-markdown/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index 207cb99f99a..db177b363a0 100644 --- a/packages/rocketchat-markdown/package.js +++ b/packages/rocketchat-markdown/package.js @@ -13,8 +13,8 @@ Package.onUse(function(api) { api.use('underscorestring:underscore.string'); api.use('rocketchat:lib@0.0.1'); - api.addFiles('settings.coffee', ['server','client']); - api.addFiles('markdown.coffee', ['server','client']); + api.addFiles('settings.coffee', 'server'); + api.addFiles('markdown.coffee'); }); Package.onTest(function(api) { -- GitLab From f73c76b9b45cef7e4271bf525b5fcbcd1409eaa0 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 9 Oct 2015 22:51:35 -0500 Subject: [PATCH 0044/1338] update deploy --- .travis.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 100ce646edd..39a5c791159 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,21 @@ sudo: required language: node_js -branches: +branches: only: - travis-001 node_js: - - "0.10" - +- '0.10' before_install: - - "curl https://install.meteor.com | /bin/sh" - +- curl https://install.meteor.com | /bin/sh script: - - mkdir ../build - - meteor build ../build +- mkdir ../build +- meteor build ../build +deploy: + provider: s3 + access_key_id: AKIAIKIA7H7D47KUHYCA + bucket: rocketchatbuild + region: us-standard + skip_cleanup: true + local_dir: ../build + secret_access_key: + secure: LYA2XNdpHBTN/zs/71VWLr81b3Gb290PRIqQER72SZ3eQjDk0UpUUFkzK6mc6GkelXyqHRBRckmhBzVCEAO6KNIU9JHc9aUxyUbSt7OMTAZUZ8X36E7HL6mXN73YHtUCbEczD41aXMK+HQ9ol0EXfvbprp5gFwqT908dSVleNJCN6wZgW5ZJVzWTiC2/aaGqCrWhAWybG1XwCgl8ND8N3qFsNBZ6MDN3rpp9kVdDJ3vzp5Azkf6QrTFQTo2ai3DFFnRf7J84/8tpRL3tVcPwjik449KEkJlCPotxt7XxUTg9HrN5LQY4wYTKyKhoYxzADwse8VaU/oFhVef3A8AiLpfg8rR63ahs5ZOqJc926eiZWGumLfvcGkHD2kb+z+l9bIE8b2X7mct6gK4ub0E6Ul/NOoh1ZgppVzP3PuYZXGb2CNvZTrrSjH9dGWPWlRjZaErg4bs4BC6y6eGjgu1CqFa1eqLFO/oYdmX5c4kDskyNf0VSVVXmqLqQBWrkOGSr3Z8nR8XQ1PDQfmj8ZMmDRtvt58DuOVzOBkC71Mc/Kr/cKS0cXedwzzNg2BG4EHMsc1eTn6JWs95NFCbPbI5HzxYODumZwOwSJyXKiDgUhPmRc6I1MvgJqIIBGWFqIIGEfR715E4zaJzAYvTPWvL+8aBMfZxdQouRYH7d9kREc6U= -- GitLab From 8551ee5dde0dad5505803f0d44fcaf29f19a74d5 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 9 Oct 2015 23:12:10 -0500 Subject: [PATCH 0045/1338] modify travis --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 39a5c791159..404356827fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,12 @@ script: - meteor build ../build deploy: provider: s3 - access_key_id: AKIAIKIA7H7D47KUHYCA - bucket: rocketchatbuild - region: us-standard + access_key_id: "AKIAIKIA7H7D47KUHYCA" + bucket: "rocketchatbuild" + region: "us standard" skip_cleanup: true local_dir: ../build + on: + branch: travis-001 secret_access_key: secure: LYA2XNdpHBTN/zs/71VWLr81b3Gb290PRIqQER72SZ3eQjDk0UpUUFkzK6mc6GkelXyqHRBRckmhBzVCEAO6KNIU9JHc9aUxyUbSt7OMTAZUZ8X36E7HL6mXN73YHtUCbEczD41aXMK+HQ9ol0EXfvbprp5gFwqT908dSVleNJCN6wZgW5ZJVzWTiC2/aaGqCrWhAWybG1XwCgl8ND8N3qFsNBZ6MDN3rpp9kVdDJ3vzp5Azkf6QrTFQTo2ai3DFFnRf7J84/8tpRL3tVcPwjik449KEkJlCPotxt7XxUTg9HrN5LQY4wYTKyKhoYxzADwse8VaU/oFhVef3A8AiLpfg8rR63ahs5ZOqJc926eiZWGumLfvcGkHD2kb+z+l9bIE8b2X7mct6gK4ub0E6Ul/NOoh1ZgppVzP3PuYZXGb2CNvZTrrSjH9dGWPWlRjZaErg4bs4BC6y6eGjgu1CqFa1eqLFO/oYdmX5c4kDskyNf0VSVVXmqLqQBWrkOGSr3Z8nR8XQ1PDQfmj8ZMmDRtvt58DuOVzOBkC71Mc/Kr/cKS0cXedwzzNg2BG4EHMsc1eTn6JWs95NFCbPbI5HzxYODumZwOwSJyXKiDgUhPmRc6I1MvgJqIIBGWFqIIGEfR715E4zaJzAYvTPWvL+8aBMfZxdQouRYH7d9kREc6U= -- GitLab From 805bda945c41f566e0c81cff1408762e4343885a Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 9 Oct 2015 23:20:11 -0500 Subject: [PATCH 0046/1338] remove region --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 404356827fb..09ccda246ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" bucket: "rocketchatbuild" - region: "us standard" skip_cleanup: true local_dir: ../build on: -- GitLab From 8989361d6adfac14766ed5d9714962cb7d452490 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 10 Oct 2015 11:57:39 -0300 Subject: [PATCH 0047/1338] Updating to support ServiceConfiguration.configurations stub method (meteor-velocity/meteor-stubs/#11) --- .meteor/versions | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 7bb0c51348d..190f1934765 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,7 +6,7 @@ accounts-meteor-developer@1.0.6 accounts-oauth@1.1.7 accounts-password@1.1.3 accounts-twitter@1.0.6 -alanning:roles@1.2.13 +alanning:roles@1.2.14 aldeed:simple-schema@1.3.3 arunoda:streams@0.1.17 autoupdate@1.2.3 @@ -41,7 +41,7 @@ ejson@1.0.7 email@1.0.7 facebook@1.2.2 fastclick@1.0.7 -francocatena:status@1.3.4 +francocatena:status@1.5.0 geojson-utils@1.0.4 github@1.1.4 google@1.1.6 @@ -58,7 +58,7 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 kadira:blaze-layout@2.1.0 -kadira:flow-router@2.6.2 +kadira:flow-router@2.7.0 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 konecty:change-case@2.3.0 @@ -76,8 +76,8 @@ matb33:collection-hooks@0.7.15 meteor@1.1.9 meteor-base@1.0.1 meteor-developer@1.1.4 -meteorhacks:kadira@2.23.4 -meteorhacks:meteorx@1.3.1 +meteorhacks:kadira@2.23.6 +meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 minimongo@1.0.10 @@ -104,9 +104,10 @@ ordered-dict@1.0.4 package-version-parser@3.0.4 pauli:accounts-linkedin@1.1.2 pauli:linkedin@1.1.2 -perak:codemirror@1.2.7 +perak:codemirror@1.2.8 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 +pntbr:js-yaml-client@0.0.1 practicalmeteor:chai@2.1.0_1 practicalmeteor:loglevel@1.2.0_2 promise@0.5.0 @@ -164,7 +165,7 @@ spacebars-compiler@1.0.7 srp@1.0.4 standard-minifiers@1.0.1 steffo:meteor-accounts-saml@0.0.1 -tap:i18n@1.6.1 +tap:i18n@1.7.0 templating@1.1.4 templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 @@ -181,7 +182,7 @@ velocity:chokidar@1.2.0_1 velocity:console-reporter@0.1.3 velocity:core@0.10.4 velocity:meteor-internals@1.1.0_7 -velocity:meteor-stubs@1.1.0 +velocity:meteor-stubs@1.1.1 velocity:shim@0.1.0 velocity:source-map-support@0.3.2_1 webapp@1.2.2 -- GitLab From e9e9179da6493ce89db124be3b3c5b37ab41d8e7 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 01:53:42 -0500 Subject: [PATCH 0048/1338] add buildinfo and revision number support --- .travis.yml | 7 ++- public/buildinfo/buildinfo.txt | 110 ++++++++++++++++++++++++++++++++- travis/namefiles.sh | 4 ++ travis/package.json | 15 +++++ travis/setbuildinfo.js | 43 +++++++++++++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 travis/namefiles.sh create mode 100644 travis/package.json create mode 100644 travis/setbuildinfo.js diff --git a/.travis.yml b/.travis.yml index 09ccda246ff..bd75816da78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,13 @@ node_js: before_install: - curl https://install.meteor.com | /bin/sh script: -- mkdir ../build +- cd travis +- npm install +- npm start +- cd .. - meteor build ../build +- cd travis +- sh ./namefiles.sh deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" diff --git a/public/buildinfo/buildinfo.txt b/public/buildinfo/buildinfo.txt index b5efce9fb5f..0539d12125c 100644 --- a/public/buildinfo/buildinfo.txt +++ b/public/buildinfo/buildinfo.txt @@ -1,2 +1,110 @@ -v0.6.dev +v0.6.3222 +# Meteor packages used by this project, one per line. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. +accounts-facebook +accounts-github +accounts-google +accounts-meteor-developer +accounts-password +accounts-twitter +coffeescript +email +fastclick +http +jquery +less +reactive-dict +reactive-var +service-configuration + +arunoda:streams +rocketchat:lib + +rocketchat:autolinker +rocketchat:colors +rocketchat:custom-oauth +rocketchat:emojione +rocketchat:favico +rocketchat:file +rocketchat:gitlab +rocketchat:wordpress +rocketchat:highlight +rocketchat:ldap +rocketchat:logger +#rocketchat:markdown +rocketchat:me +rocketchat:mentions +rocketchat:message-star +rocketchat:oembed +rocketchat:slashcommands-invite +rocketchat:slashcommands-join +rocketchat:slashcommands-leave +rocketchat:spotify +rocketchat:statistics +rocketchat:webrtc +#rocketchat:chatops +#rocketchat:livechat +#rocketchat:hubot +#rocketchat:irc + +konecty:change-case +konecty:delayed-task +konecty:mongo-counter +konecty:multiple-instances-status +konecty:nrr +konecty:user-presence + +chrismbeckett:toastr +dispatch:run-as-user +francocatena:status +jalik:ufs +jalik:ufs-gridfs +jparker:gravatar +kadira:blaze-layout +kadira:flow-router +kevohagan:sweetalert +meteorhacks:kadira +mizzao:autocomplete +mizzao:timesync +momentjs:moment +monbro:mongodb-mapreduce-aggregation +mrt:reactive-store +mystor:device-detection +nimble:restivus +nooitaf:colors +pauli:accounts-linkedin +percolate:migrations +percolate:synced-cron +raix:handlebar-helpers +raix:push@2.6.13-rc.1 +raix:ui-dropped-event +steffo:meteor-accounts-saml +tap:i18n +tmeasday:crypto-md5 +tmeasday:errors +todda00:friendly-slugs +underscorestring:underscore.string +yasaricli:slugify +yasinuslu:blaze-meta +rocketchat:authorization +perak:codemirror +standard-minifiers +meteor-base +mobile-experience +mongo +blaze-html-templates +session +tracker +logging +reload +random +ejson +spacebars +check +rocketchat:github-enterprise +rocketchat:chatops +# sanjo:jasmine@0.20.2 +# velocity:html-reporter diff --git a/travis/namefiles.sh b/travis/namefiles.sh new file mode 100644 index 00000000000..e39d7e20be9 --- /dev/null +++ b/travis/namefiles.sh @@ -0,0 +1,4 @@ +cd ../../build +FILENAME=rocket.chat-`cat version.txt`.tgz +mv Rocket.Chat.tar.gz $FILENAME +ln -s $FILENAME rocket.chat-v.latest.tgz diff --git a/travis/package.json b/travis/package.json new file mode 100644 index 00000000000..7abc9ca86ae --- /dev/null +++ b/travis/package.json @@ -0,0 +1,15 @@ +{ + "name": "setbuildinfo", + "version": "1.0.0", + "description": "Set the buildinfo.txt resource", + "main": "setbuildinfo.js", + "scripts": { + "start": "node setbuildinfo.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "line-by-line": "^0.1.4", + "mkdirp": "^0.5.1" + } +} diff --git a/travis/setbuildinfo.js b/travis/setbuildinfo.js new file mode 100644 index 00000000000..89549e29b46 --- /dev/null +++ b/travis/setbuildinfo.js @@ -0,0 +1,43 @@ +var BUILD_INFO_PATH = '../public/buildinfo/buildinfo.txt'; +var PACKAGES_PATH = '../.meteor/packages'; +var BUILD_PATH = '../../build'; +var LineByLineReader = require('line-by-line'), + mkdirp = require('mkdirp'), + fs = require('fs'), + lr = new LineByLineReader(BUILD_INFO_PATH); + +var firstline = ""; + + +if (process.env.TRAVIS_JOB_ID) { + + var transformVersion = function (firstline) { + var versions = firstline.split("."); + + return versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_JOB_ID + '\n'; + }; + + + + lr.on('error', function (err) { + // 'err' contains error object + }); + + lr.on('line', function (line) { + if (firstline == "") + firstline = line; + + }); + + lr.on('end', function () { + + var packages = fs.readFileSync(PACKAGES_PATH); + var verinfo = transformVersion(firstline); + var content = verinfo + packages; + mkdirp.sync(BUILD_PATH); + fs.writeFileSync(BUILD_PATH + "/version.txt", verinfo); + fs.writeFileSync(BUILD_INFO_PATH, content); + + }); + +} \ No newline at end of file -- GitLab From 2cc54f6e35dc96fb54ffc17dcb98b621de5d85dd Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 02:11:33 -0500 Subject: [PATCH 0049/1338] fix buildinfo --- public/buildinfo/buildinfo.txt | 111 +-------------------------------- travis/setbuildinfo.js | 3 +- 2 files changed, 3 insertions(+), 111 deletions(-) diff --git a/public/buildinfo/buildinfo.txt b/public/buildinfo/buildinfo.txt index 0539d12125c..e33ae0d8524 100644 --- a/public/buildinfo/buildinfo.txt +++ b/public/buildinfo/buildinfo.txt @@ -1,110 +1 @@ -v0.6.3222 -# Meteor packages used by this project, one per line. -# -# 'meteor add' and 'meteor remove' will edit this file for you, -# but you can also edit it by hand. - -accounts-facebook -accounts-github -accounts-google -accounts-meteor-developer -accounts-password -accounts-twitter -coffeescript -email -fastclick -http -jquery -less -reactive-dict -reactive-var -service-configuration - -arunoda:streams -rocketchat:lib - -rocketchat:autolinker -rocketchat:colors -rocketchat:custom-oauth -rocketchat:emojione -rocketchat:favico -rocketchat:file -rocketchat:gitlab -rocketchat:wordpress -rocketchat:highlight -rocketchat:ldap -rocketchat:logger -#rocketchat:markdown -rocketchat:me -rocketchat:mentions -rocketchat:message-star -rocketchat:oembed -rocketchat:slashcommands-invite -rocketchat:slashcommands-join -rocketchat:slashcommands-leave -rocketchat:spotify -rocketchat:statistics -rocketchat:webrtc -#rocketchat:chatops -#rocketchat:livechat -#rocketchat:hubot -#rocketchat:irc - -konecty:change-case -konecty:delayed-task -konecty:mongo-counter -konecty:multiple-instances-status -konecty:nrr -konecty:user-presence - -chrismbeckett:toastr -dispatch:run-as-user -francocatena:status -jalik:ufs -jalik:ufs-gridfs -jparker:gravatar -kadira:blaze-layout -kadira:flow-router -kevohagan:sweetalert -meteorhacks:kadira -mizzao:autocomplete -mizzao:timesync -momentjs:moment -monbro:mongodb-mapreduce-aggregation -mrt:reactive-store -mystor:device-detection -nimble:restivus -nooitaf:colors -pauli:accounts-linkedin -percolate:migrations -percolate:synced-cron -raix:handlebar-helpers -raix:push@2.6.13-rc.1 -raix:ui-dropped-event -steffo:meteor-accounts-saml -tap:i18n -tmeasday:crypto-md5 -tmeasday:errors -todda00:friendly-slugs -underscorestring:underscore.string -yasaricli:slugify -yasinuslu:blaze-meta -rocketchat:authorization -perak:codemirror -standard-minifiers -meteor-base -mobile-experience -mongo -blaze-html-templates -session -tracker -logging -reload -random -ejson -spacebars -check -rocketchat:github-enterprise -rocketchat:chatops -# sanjo:jasmine@0.20.2 -# velocity:html-reporter +v0.6.dev diff --git a/travis/setbuildinfo.js b/travis/setbuildinfo.js index 89549e29b46..81568323430 100644 --- a/travis/setbuildinfo.js +++ b/travis/setbuildinfo.js @@ -37,7 +37,8 @@ if (process.env.TRAVIS_JOB_ID) { mkdirp.sync(BUILD_PATH); fs.writeFileSync(BUILD_PATH + "/version.txt", verinfo); fs.writeFileSync(BUILD_INFO_PATH, content); + console.log('Version is ' + verinfo); }); -} \ No newline at end of file +} -- GitLab From de6a5a71ef902d078a04239132a4cd6d2542c832 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 02:20:40 -0500 Subject: [PATCH 0050/1338] move travis to .travis --- .travis.yml | 4 ++-- {travis => .travis}/namefiles.sh | 0 {travis => .travis}/package.json | 0 {travis => .travis}/setbuildinfo.js | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename {travis => .travis}/namefiles.sh (100%) rename {travis => .travis}/package.json (100%) rename {travis => .travis}/setbuildinfo.js (100%) diff --git a/.travis.yml b/.travis.yml index bd75816da78..aac15c14859 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,12 @@ node_js: before_install: - curl https://install.meteor.com | /bin/sh script: -- cd travis +- cd .travis - npm install - npm start - cd .. - meteor build ../build -- cd travis +- cd .travis - sh ./namefiles.sh deploy: provider: s3 diff --git a/travis/namefiles.sh b/.travis/namefiles.sh similarity index 100% rename from travis/namefiles.sh rename to .travis/namefiles.sh diff --git a/travis/package.json b/.travis/package.json similarity index 100% rename from travis/package.json rename to .travis/package.json diff --git a/travis/setbuildinfo.js b/.travis/setbuildinfo.js similarity index 100% rename from travis/setbuildinfo.js rename to .travis/setbuildinfo.js -- GitLab From 4d46eacbd2e7c7197c0fb3d105370741b30d10ba Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 02:34:10 -0500 Subject: [PATCH 0051/1338] replace build id --- .travis/namefiles.sh | 2 ++ .travis/setbuildinfo.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index e39d7e20be9..bc62b12b4c0 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -2,3 +2,5 @@ cd ../../build FILENAME=rocket.chat-`cat version.txt`.tgz mv Rocket.Chat.tar.gz $FILENAME ln -s $FILENAME rocket.chat-v.latest.tgz +cd ../Rocket.Chat + diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index 81568323430..82ae86cfa98 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -9,12 +9,12 @@ var LineByLineReader = require('line-by-line'), var firstline = ""; -if (process.env.TRAVIS_JOB_ID) { +if (process.env.TRAVIS_BUILD_NUMBER)) { var transformVersion = function (firstline) { var versions = firstline.split("."); - return versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_JOB_ID + '\n'; + return versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BUILD_NUMBER + '\n'; }; -- GitLab From e7ac03184d33b785498f5080cf077bf5bb51f437 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 02:37:53 -0500 Subject: [PATCH 0052/1338] fix typo --- .travis/setbuildinfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index 82ae86cfa98..221e7a3b415 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -9,7 +9,7 @@ var LineByLineReader = require('line-by-line'), var firstline = ""; -if (process.env.TRAVIS_BUILD_NUMBER)) { +if (process.env.TRAVIS_BUILD_NUMBER) { var transformVersion = function (firstline) { var versions = firstline.split("."); -- GitLab From 7586600fe1f46cd6c11e283f0d970c76e65e7ab1 Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Sun, 11 Oct 2015 15:39:28 +0800 Subject: [PATCH 0053/1338] master run --- .meteor/versions | 1 - 1 file changed, 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index 8c8b864df5a..34cab543eb7 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -133,7 +133,6 @@ rocketchat:highlight@0.0.1 rocketchat:ldap@0.0.1 rocketchat:lib@0.0.1 rocketchat:logger@0.0.1 -rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 rocketchat:message-star@0.0.1 -- GitLab From 368791cf3d99dd50d0d64a888cfe24d117724d11 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 02:56:09 -0500 Subject: [PATCH 0054/1338] change to correct directory for deploy --- .travis.yml | 1 + .travis/namefiles.sh | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index aac15c14859..ab6bbc4b68e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ script: - meteor build ../build - cd .travis - sh ./namefiles.sh +- cd .. deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index bc62b12b4c0..6f56508c24e 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -2,5 +2,4 @@ cd ../../build FILENAME=rocket.chat-`cat version.txt`.tgz mv Rocket.Chat.tar.gz $FILENAME ln -s $FILENAME rocket.chat-v.latest.tgz -cd ../Rocket.Chat -- GitLab From 55015d9e0b79841e0f79d0b73ab8db466c6f93eb Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 03:07:51 -0500 Subject: [PATCH 0055/1338] add demo server build --- .travis.yml | 6 ++++++ .travis/namedemo.sh | 5 +++++ 2 files changed, 11 insertions(+) create mode 100644 .travis/namedemo.sh diff --git a/.travis.yml b/.travis.yml index ab6bbc4b68e..e169ba60ac0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,12 @@ script: - cd .travis - sh ./namefiles.sh - cd .. +- meteor add rocketchat:livechat +- meteor add rocketchat:hubot +- meteor build --server demo.rocket.chat ../build +- cd .travis +- sh ./namedemo.sh +- cd .. deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" diff --git a/.travis/namedemo.sh b/.travis/namedemo.sh new file mode 100644 index 00000000000..67663a3497f --- /dev/null +++ b/.travis/namedemo.sh @@ -0,0 +1,5 @@ +cd ../../build +FILENAME=demo.rocket.chat-`cat version.txt`.tgz +mv Rocket.Chat.tar.gz $FILENAME +ln -s $FILENAME demo.rocket.chat-v.latest.tgz + -- GitLab From a2b3bf472af9c8ebcf45eace9e0d5aa0eb5df5c4 Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Sun, 11 Oct 2015 16:33:35 +0800 Subject: [PATCH 0056/1338] Chinese Character supported --- packages/rocketchat-lib/server/functions/setUsername.coffee | 2 +- packages/rocketchat-lib/server/methods/setUsername.coffee | 2 +- packages/rocketchat-mentions/client.coffee | 4 ++-- packages/rocketchat-mentions/server.coffee | 4 ++-- server/methods/createChannel.coffee | 2 +- server/methods/createPrivateGroup.coffee | 2 +- server/methods/saveRoomName.coffee | 2 +- server/restapi/restapi.coffee | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index de418b6486a..c1180e463bb 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -3,7 +3,7 @@ RocketChat.setUsername = (user, username) -> if not user or not username return false - if not /^[0-9a-zA-Z-_.\u00C0-\u017F]+$/.test username + if not /^[0-9a-zA-Z-_.\u00C0-\u017F\u4e00-\u9fa5]+$/.test username return false # User already has desired username, return diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index a501a9a3cee..7f4f0305fe9 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -10,7 +10,7 @@ Meteor.methods if user.username is username return username - if not /^[0-9a-zA-Z-_.\u00C0-\u017F]+$/.test username + if not /^[0-9a-zA-Z-_.\u00C0-\u017F\u4e00-\u9fa5]+$/.test username throw new Meteor.Error 'username-invalid', "#{username} is not a valid username, use only letters, numbers, dots and dashes" if not RocketChat.checkUsernameAvailability username diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index 083cd174b12..ae6729ef0ad 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -10,7 +10,7 @@ class MentionsClient mentions = [] - message.msg.replace /(?:^|\s|\n)(?:@)([0-9a-zA-Z-_.\u00C0-\u017F]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:@)([0-9a-zA-Z-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> mentions.push mention me = Meteor.user()?.username @@ -33,7 +33,7 @@ class MentionsClient return match.replace mention, "<a href=\"\" class=\"#{classes}\" data-username=\"#{username}\">#{mention}</a>" channels = [] - message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> channels.push mention if channels.length isnt 0 diff --git a/packages/rocketchat-mentions/server.coffee b/packages/rocketchat-mentions/server.coffee index 1a971366f3e..04c42e511fc 100644 --- a/packages/rocketchat-mentions/server.coffee +++ b/packages/rocketchat-mentions/server.coffee @@ -7,7 +7,7 @@ class MentionsServer constructor: (message) -> # If message starts with /me, replace it for text formatting mentions = [] - message.msg.replace /(?:^|\s|\n)(?:@)([A-Za-z0-9-_.\u00C0-\u017F]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:@)([A-Za-z0-9-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> mentions.push mention if mentions.length isnt 0 mentions = _.unique mentions @@ -25,7 +25,7 @@ class MentionsServer message.mentions = verifiedMentions channels = [] - message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F]+)/g, (match, mention) -> + message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> channels.push mention if channels.length isnt 0 diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index a5c6feaf868..128fae22783 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -3,7 +3,7 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', "[methods] createChannel -> Invalid user" - if not /^[0-9a-zA-Z-_\u00C0-\u017F]+$/.test name + if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name throw new Meteor.Error 'name-invalid' if RocketChat.authz.hasPermission(Meteor.userId(), 'create-c') isnt true diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index f208d4562aa..9645a211fda 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -8,7 +8,7 @@ Meteor.methods console.log '[methods] createPrivateGroup -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - if not /^[0-9a-zA-Z-_\u00C0-\u017F]+$/.test name + if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name throw new Meteor.Error 'name-invalid' now = new Date() diff --git a/server/methods/saveRoomName.coffee b/server/methods/saveRoomName.coffee index 621be3975ec..aebfee0c480 100644 --- a/server/methods/saveRoomName.coffee +++ b/server/methods/saveRoomName.coffee @@ -12,7 +12,7 @@ Meteor.methods #if room.u._id isnt Meteor.userId() and not hasPermission throw new Meteor.Error 403, 'Not allowed' - if not /^[0-9a-zA-Z-_\u00C0-\u017F]+$/.test name + if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name throw new Meteor.Error 'name-invalid' name = _.slugify name diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 4d04853ffab..9a954dfcda7 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -61,7 +61,7 @@ Api.testapiValidateUsers = (users) -> if user.name? if user.email? if user.pass? - if /^[0-9a-zA-Z-_\u00C0-\u017F]+$/i.test user.name + if /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/i.test user.name if /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+\b/i.test user.email continue throw new Meteor.Error 'invalid-user-record', "[restapi] bulk/register -> record #" + i + " is invalid" @@ -125,7 +125,7 @@ Api.testapiValidateRooms = (rooms) -> if room.name? if room.members? if room.members.length > 1 - if /^[0-9a-zA-Z-_\u00C0-\u017F]+$/i.test room.name + if /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/i.test room.name continue throw new Meteor.Error 'invalid-room-record', "[restapi] bulk/createRoom -> record #" + i + " is invalid" return -- GitLab From 95c39ee87493954013f0c2b279b43671870196bd Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 11:22:30 -0500 Subject: [PATCH 0057/1338] update dockerfile to eliminate problematic meteor build --- Dockerfile | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9cebb0ea3ac..f100363dc81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1 +1,27 @@ -FROM meteorhacks/meteord:onbuild +FROM node:0.10 + +MAINTAINER buildmaster@rocket.chat + +RUN groupadd -r rocketchat \ +&& useradd -r -g rocketchat rocketchat + +# gpg: key 4FD08014: public key "Rocket.Chat Buildmaster <buildmaster@rocket.chat>" imported +RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 + + +RUN curl -fSL "http://http://rocketchatbuild.s3-website-us-east-1.amazonaws.com/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 + +WORKDIR /app/bundle +USER rocketchat + +# needs a mongoinstance - defaults to container linking with alias 'db' +ENV MONGO_URL=mongodb://db:27017/meteor \ + PORT=3000 \ + ROOT_URL=http://localhost:3000 + +EXPOSE 3000 +CMD ["node", "main.js"] \ No newline at end of file -- GitLab From 270eee4c25994072c8fc87ee7e0f8d4a81f9c5c8 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Sun, 11 Oct 2015 14:14:41 -0300 Subject: [PATCH 0058/1338] Change room type --- .../client/views/channelSettings.coffee | 15 ++++-- .../rocketchat-channel-settings/package.js | 5 ++ .../server/functions/changeRoomType.coffee | 47 +++++++++++++++++++ .../server/methods/saveRoomSettings.coffee | 19 ++++++++ .../rocketchat-lib/server/models/Rooms.coffee | 10 ++++ .../server/models/Subscriptions.coffee | 10 ++++ 6 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee create mode 100644 packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 5225bf4010b..c2e80b09d07 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -1,7 +1,16 @@ Template.channelSettings.helpers notDirect: -> - return ChatRoom.findOne(@rid).t isnt 'd' + return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> - return ChatRoom.findOne(@rid).t + return ChatRoom.findOne(@rid)?.t -Template.channelSettings.onCreated -> +Template.channelSettings.events + 'click .save': (e, t) -> + e.preventDefault() + + settings = + roomType: t.$('input[name=roomType]:checked').val() + + Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__ 'Settings_updated' \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 9cc6d0d9b7c..446e9b3e97e 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -22,6 +22,11 @@ Package.onUse(function(api) { 'client/stylesheets/channel-settings.less', ], 'client'); + api.addFiles([ + 'server/functions/changeRoomType.coffee', + 'server/methods/saveRoomSettings.coffee' + ], 'server'); + // TAPi18n var _ = Npm.require('underscore'); var fs = Npm.require('fs'); diff --git a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee b/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee new file mode 100644 index 00000000000..e9c89567302 --- /dev/null +++ b/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee @@ -0,0 +1,47 @@ +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/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee new file mode 100644 index 00000000000..e3e807ffb48 --- /dev/null +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -0,0 +1,19 @@ +Meteor.methods + saveRoomSettings: (rid, settings) -> + console.log '[method] saveRoomSettings'.green, rid, settings + + unless Match.test rid, String + throw new Meteor.Error 'invalid-rid' + + unless Match.test settings, Match.ObjectIncluding { roomType: String } + throw new Meteor.Error 'invalid-settings' + + 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) + + return true \ No newline at end of file diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index e31711c7f4c..adf06656245 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -290,6 +290,16 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @update query, update + setTypeById: (_id, type) -> + query = + _id: _id + + update = + $set: + t: type + + return @update query, update + # INSERT createWithTypeNameUserAndUsernames: (type, name, user, usernames, extraData) -> diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 7c98e495264..f698bea6735 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -194,6 +194,16 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @update query, update, { multi: true } + updateTypeByRoomId: (roomId, type) -> + query = + rid: roomId + + update = + $set: + t: type + + return @update query, update, { multi: true } + # INSERT createWithRoomAndUser: (room, user, extraData) -> -- GitLab From 1ffaf30148f4fca675b2bb3c03938baf1bfafb5b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 15:00:52 -0500 Subject: [PATCH 0059/1338] add SSL for image --- .travis.yml | 3 +++ Dockerfile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e169ba60ac0..9ed2910c130 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ node_js: - '0.10' before_install: - curl https://install.meteor.com | /bin/sh +- npm install -g npm@'>=2.13.5' script: - cd .travis - npm install @@ -22,6 +23,8 @@ script: - cd .travis - sh ./namedemo.sh - cd .. +after_deploy: +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/hubot-rocketchat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" diff --git a/Dockerfile b/Dockerfile index f100363dc81..56e3f0bc607 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN groupadd -r rocketchat \ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 -RUN curl -fSL "http://http://rocketchatbuild.s3-website-us-east-1.amazonaws.com/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ +RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ @@ -24,4 +24,4 @@ ENV MONGO_URL=mongodb://db:27017/meteor \ ROOT_URL=http://localhost:3000 EXPOSE 3000 -CMD ["node", "main.js"] \ No newline at end of file +CMD ["node", "main.js"] -- GitLab From cbac9b864566e0a1e945b69e4bd3dcbe470a35f1 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 15:13:19 -0500 Subject: [PATCH 0060/1338] set /app as root --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 56e3f0bc607..9686b4a1bcc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,9 +9,10 @@ RUN groupadd -r rocketchat \ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104 -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ +RUN mkdir /app \ +&& curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ -&& rm ./rocket.chat.tgz \ +&& rm ./rocket.chat.tgz /app \ && cd /app/bundle/programs/server \ && npm install -- GitLab From bd0afe49ecea770dc345b742c62310b2f669ddf7 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 15:16:18 -0500 Subject: [PATCH 0061/1338] set /app as root --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 9686b4a1bcc..73158e3d1c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB RUN mkdir /app \ +&& cd /app \ && curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz /app \ -- GitLab From 0a42db6a251e869a0238f860345e1bc3210d825f Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 15:18:42 -0500 Subject: [PATCH 0062/1338] set /app as root --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 73158e3d1c0..d6c63198280 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,8 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB RUN mkdir /app \ && cd /app \ && curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ -&& tar zxvf ./rocket.chat.tgz \ -&& rm ./rocket.chat.tgz /app \ +&& tar zxvf ./rocket.chat.tgz /app \ +&& rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ && npm install -- GitLab From 5ceeef8651c84334d2a8d81aaac32c6a246d0dcc Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 15:41:50 -0500 Subject: [PATCH 0063/1338] mod dockerfile --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index d6c63198280..be972ce9ac5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,16 +3,16 @@ FROM node:0.10 MAINTAINER buildmaster@rocket.chat RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat +&& useradd -r -g rocketchat rocketchat \ +&& mkdir /app # 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 mkdir /app \ -&& cd /app \ -&& curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ -&& tar zxvf ./rocket.chat.tgz /app \ +RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/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 -- GitLab From 414202403f5ef77b91a98642fd69b5bbdafcccc2 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 16:24:18 -0500 Subject: [PATCH 0064/1338] add docker trigger --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ed2910c130..a1856d8aec9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ script: - sh ./namedemo.sh - cd .. after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/hubot-rocketchat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST "https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" -- GitLab From 1e8a6576b43f87150e459d8e7c69886dd1c381d6 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 16:44:08 -0500 Subject: [PATCH 0065/1338] trigger change --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d493ce4ad6..f956bce96ba 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ Available from the AppStore: [](https://geo.itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) -Get the app for your Android phone: +Get the app for your Android phone: + [](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) -- GitLab From 8e93997d1fde2be96d3da383f6e820d278646f12 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 20:21:38 -0500 Subject: [PATCH 0066/1338] fix quote problem --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a1856d8aec9..5a05bc593c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ script: - sh ./namedemo.sh - cd .. after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST "https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" -- GitLab From 8f4f522b1faa8adfacaf590a69f10d678317b855 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 20:48:30 -0500 Subject: [PATCH 0067/1338] try version tag on docker --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a05bc593c8..8da2ae0776e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ script: - sh ./namedemo.sh - cd .. after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'docker_tag': '`cat ../build/version.txt`'}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" -- GitLab From beba7d10dd743b1bf9fed2fe1e005bedfe028b57 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 21:14:03 -0500 Subject: [PATCH 0068/1338] trying version number --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8da2ae0776e..ab4ca8c2cf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,9 @@ script: - cd .travis - sh ./namedemo.sh - cd .. +- export VERSION=`cat ../build/version.txt` after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'docker_tag': '`cat ../build/version.txt`'}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'docker_tag': '$VERSION'}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" -- GitLab From f784c24c816e789c1dc7589f6d51c29d114a96fb Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sun, 11 Oct 2015 21:39:59 -0500 Subject: [PATCH 0069/1338] fix build --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab4ca8c2cf3..5a05bc593c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,9 +23,8 @@ script: - cd .travis - sh ./namedemo.sh - cd .. -- export VERSION=`cat ../build/version.txt` after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'docker_tag': '$VERSION'}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" -- GitLab From 36560aa27fd1830b5b4dd1e95257407a8917909a Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 12 Oct 2015 09:09:41 -0500 Subject: [PATCH 0070/1338] update build script to eliminate need to install and build with meteor --- build.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 90b3c5b8eb8..f9bdc2f451e 100755 --- a/build.sh +++ b/build.sh @@ -1,9 +1,7 @@ #!/bin/bash -source ./build-info.sh -export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat -meteor add rocketchat:hubot -meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat +cd /var/www/rocket.chat +https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz +tar zxvf rocket.chat.tgz && rm rocket.chat.tgz cd /var/www/rocket.chat/bundle/programs/server npm install cd /var/www/rocket.chat/current -- GitLab From 231300dfb5a7cc94928216ccddadb473afd50f75 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 12 Oct 2015 18:15:34 -0500 Subject: [PATCH 0071/1338] update and correct docker-compose --- docker-compose.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 306491bdf6a..30a885fbf47 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,17 @@ +db: + image: mongo +# volumes: +# - ./data/runtime/db:/data/db +# - ./data/dump:/dump + command: mongod --smallfiles + rocketchat: - image: rocketchat/rocket.chat + image: singli/rocket.chat environment: - - MONGO_URL=mongodb://mongodb/rocketchat - - ROOT_URL=http://localhost:80 + - MONGO_URL=mongodb://db:27017/rocketchat + - ROOT_URL=http://yourhost:8818 links: - - mongodb + - db:db ports: - - 80:80 + - 8818:3000 -mongodb: - image: mongo - ports: - - 27017 -- GitLab From 3593ce5b4c6b23cb9a58469e726ea1bb658a008b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 12 Oct 2015 19:22:02 -0500 Subject: [PATCH 0072/1338] add PR special handling --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5a05bc593c8..db7974b4359 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' script: +- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit 0; fi - cd .travis - npm install - npm start -- GitLab From c6ef43b0a97c8f7f929fe81c4171de71099d144e Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 12 Oct 2015 19:44:25 -0500 Subject: [PATCH 0073/1338] PR fail indicator add PR fail indicator --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index db7974b4359..f041cb58d72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' script: -- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit 0; fi +- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - cd .travis - npm install - npm start -- GitLab From fdfc3b03d7de2cf40d40f2471e51126045994bc9 Mon Sep 17 00:00:00 2001 From: Lee Faus <leefaus@github.com> Date: Tue, 13 Oct 2015 09:03:32 -0400 Subject: [PATCH 0074/1338] Support for ChatOps Coloring --- client/stylesheets/base.less | 3 ++- client/stylesheets/utils/_chatops.less | 27 +++++++++++++++++++ client/views/app/message.coffee | 24 ++++++++++++----- client/views/app/message.html | 2 +- client/views/app/room.html | 9 +++++-- client/views/app/sideNav/chatRoomItem.html | 4 +-- .../rocketchat-chatops/server/settings.coffee | 1 + .../startup.coffee | 8 +++--- .../settings/server/startup.coffee | 2 +- packages/rocketchat-mentions/client.coffee | 3 ++- 10 files changed, 64 insertions(+), 19 deletions(-) create mode 100644 client/stylesheets/utils/_chatops.less diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 010ea4ac3d4..8fc3cdf0619 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -6,6 +6,7 @@ @import "utils/_emojione.import.less"; @import "utils/_fonts.import.less"; @import "utils/_octicons.less"; +@import "utils/_chatops.less"; .clearfix { clear: both; &::after { @@ -2346,7 +2347,7 @@ a.github-fork { .message { font-size: 14px; - padding: 18px 20px 4px 70px; + padding: 5px 20px 5px 70px; position: relative; line-height: 20px; min-height: 40px; diff --git a/client/stylesheets/utils/_chatops.less b/client/stylesheets/utils/_chatops.less new file mode 100644 index 00000000000..2e08b5e0b50 --- /dev/null +++ b/client/stylesheets/utils/_chatops.less @@ -0,0 +1,27 @@ +li.chatops-message { + background-color: #f8f8f8; +} + +.message .thumb .avatar { + margin-top: -15px !important; +} + +.chatops-message div.body { + font-size: 12px; + font-weight: bold; + color: #7a7a7a; +} + +li.chatops-message.sequential { + margin-top: -5px !important; +} + +.octicon.file { + font: normal normal normal 24px/1 octicons; +} + +.github-tagline { + padding-top: 3px; + font-weight: 200; + color: white; +} diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 78ad2871fe0..e2a46308f82 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -1,10 +1,13 @@ Template.message.helpers actions: -> return RocketChat.MessageAction.getButtons(this) - + own: -> return 'own' if this.u?._id is Meteor.userId() + chatops: -> + return 'chatops-message' if this.u?.username is RocketChat.settings.get('Chatops_Username') + time: -> return moment(this.ts).format('HH:mm') @@ -28,10 +31,16 @@ Template.message.helpers when 'rm' then t('Message_removed', { user: this.u.username }) when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this else + if this.u?.username is RocketChat.settings.get('Chatops_Username') + this.html = this.msg + message = RocketChat.callbacks.run 'renderMentions', this + # console.log JSON.stringify message + return this.html this.html = this.msg if _.trim(this.html) isnt '' this.html = _.escapeHTML this.html message = RocketChat.callbacks.run 'renderMessage', this + # console.log JSON.stringify message this.html = message.html.replace /\n/gm, '<br/>' return this.html @@ -89,12 +98,13 @@ Template.message.onViewRendered = (context) -> ul = lastNode.parentElement wrapper = ul.parentElement - if context.urls?.length > 0 and Template.oembedBaseWidget? and RocketChat.settings.get 'API_Embed' - for item in context.urls - do (item) -> - urlNode = lastNode.querySelector('.body a[href="'+item.url+'"]') - if urlNode? - $(lastNode.querySelector('.body')).append Blaze.toHTMLWithData Template.oembedBaseWidget, item + if this.u?.username is not "hubot" + if context.urls?.length > 0 and Template.oembedBaseWidget? and RocketChat.settings.get 'API_Embed' + for item in context.urls + do (item) -> + urlNode = lastNode.querySelector('.body a[href="'+item.url+'"]') + if urlNode? + $(lastNode.querySelector('.body')).append Blaze.toHTMLWithData Template.oembedBaseWidget, item if not lastNode.nextElementSibling? if lastNode.classList.contains('own') is true diff --git a/client/views/app/message.html b/client/views/app/message.html index 2ff13ac47cd..c82b73b256d 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -1,5 +1,5 @@ <template name="message"> - <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}}" data-username="{{u.username}}" data-date="{{date}}"> + <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-date="{{date}}"> <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> <a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</a> <span class="info"> diff --git a/client/views/app/room.html b/client/views/app/room.html index 08d9696b4a3..a403d7befd6 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -80,14 +80,15 @@ <form class="message-form" method="post" action="/"> <div style="display: flex"> <div class="file"> - <i class="icon-attach"></i> + <i class="octicon octicon-cloud-upload file"></i> <input type="file" accept="image/*"> </div> <div class="input-message-container"> {{> messagePopupConfig getPupupConfig}} <textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea> - <i class="icon-paper-plane" title="{{_ "Send_Message"}}" aria-label="{{_ "Send_Message"}}"></i> + <!--<i class="icon-paper-plane" title="{{_ "Send_Message"}}" aria-label="{{_ "Send_Message"}}"></i>--> </div> + <!-- {{#if canRecordAudio}} <div class="mic"> <i class="icon-mic" aria-label="{{_ "Record"}}"></i> @@ -96,6 +97,7 @@ <i class="icon-stop" aria-label="{{_ "Stop_Recording"}}"></i> </div> {{/if}} + --> </div> <div class="users-typing"> {{#with usersTyping}} @@ -115,6 +117,7 @@ {{/if}} {{/with}} </div> + <!-- {{#if showFormattingTips}} <div class="formatting-tips" aria-hidden="true" dir="auto"> {{#if showMarkdown}} @@ -129,8 +132,10 @@ {{#if showMarkdown}} <q><span class="hidden-br"><br></span>>{{_ "quote"}}</q> {{/if}} + </div> {{/if}} + --> <div class="editing-commands" aria-hidden="true" dir="auto"> <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="">{{_ 'Cancel'}}</a></div> <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="">{{_ 'Save_changes'}}</a></div> diff --git a/client/views/app/sideNav/chatRoomItem.html b/client/views/app/sideNav/chatRoomItem.html index 4fa16295a8f..a3ae1aa21f2 100644 --- a/client/views/app/sideNav/chatRoomItem.html +++ b/client/views/app/sideNav/chatRoomItem.html @@ -7,9 +7,9 @@ <i class="{{roomIcon}} {{userStatus}}"></i> <span class='name'>{{name}}</span> <span class='opt'> - <i class="icon-cancel-circled hide-room" title="{{_ "Hide_room"}}"></i> + <i class="octicon octicon-eye hide-room" title="{{_ "Hide_room"}}"></i> {{#if canLeave}} - <i class="icon-logout leave-room" title="{{_ "Leave_room"}}"></i> + <i class="octicon octicon-sign-out" title="{{_ "Leave_room"}}"></i> {{/if}} </span> </a> diff --git a/packages/rocketchat-chatops/server/settings.coffee b/packages/rocketchat-chatops/server/settings.coffee index 04c3944bc8f..d7787d1b067 100644 --- a/packages/rocketchat-chatops/server/settings.coffee +++ b/packages/rocketchat-chatops/server/settings.coffee @@ -1,2 +1,3 @@ Meteor.startup -> RocketChat.settings.add 'Chatops_Enabled', false, { type: 'boolean', group: 'General', public: true, i18nLabel: "ChatOps Enabled" } + RocketChat.settings.add 'Chatops_Username', false, { type: 'string', group: 'General', public: true, i18nLabel: "ChatOps User Name" } diff --git a/packages/rocketchat-github-enterprise/startup.coffee b/packages/rocketchat-github-enterprise/startup.coffee index 6218ef61b3a..aa56a2e660e 100644 --- a/packages/rocketchat-github-enterprise/startup.coffee +++ b/packages/rocketchat-github-enterprise/startup.coffee @@ -1,6 +1,6 @@ Meteor.startup -> - RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise', false, {type: 'boolean', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'OAuth Enabled'} - RocketChat.settings.add 'API_GitHub_Enterprise_URL', '', { type: 'string', group: 'Accounts', public: true, section: 'GitHub Enterprise', i18nLabel: 'Server URL' } - RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_id', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Client ID' } - RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_secret', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Client Secret' } + RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise', false, {type: 'boolean', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Accounts_OAuth_GitHub_Enterprise'} + RocketChat.settings.add 'API_GitHub_Enterprise_URL', '', { type: 'string', group: 'Accounts', public: true, section: 'GitHub Enterprise', i18nLabel: 'API_GitHub_Enterprise_URL' } + RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_id', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Accounts_OAuth_GitHub_Enterprise_id' } + RocketChat.settings.add 'Accounts_OAuth_GitHub_Enterprise_secret', '', { type: 'string', group: 'Accounts', section: 'GitHub Enterprise', i18nLabel: 'Accounts_OAuth_GitHub_Enterprise_secret' } diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 93d44b9c3bb..8c1235663d7 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -88,7 +88,7 @@ RocketChat.settings.add 'Layout_Home_Title', 'Home', { type: 'string', group: 'L 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', '<a href="https://github.com/RocketChat/Rocket.Chat" class="logo" target="_blank"> <img src="/images/logo/logo.svg?v=3" /> <small><i class="icon-github-circled"></i> Fork it on github</small> </a>', { type: 'string', group: 'Layout', public: true, i18nDescription: 'Layout_Sidenav_Footer_description' } +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' } diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index 2e981a15121..f1d159d9e03 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -48,4 +48,5 @@ class MentionsClient message.html = msg return message -RocketChat.callbacks.add 'renderMessage', MentionsClient \ No newline at end of file +RocketChat.callbacks.add 'renderMessage', MentionsClient +RocketChat.callbacks.add 'renderMentions', MentionsClient -- GitLab From f0a2f10f63b4925449535244449f9daf853530ea Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 13 Oct 2015 17:41:19 -0300 Subject: [PATCH 0075/1338] Back avatars to use absoluteUrl --- client/lib/avatar.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/lib/avatar.coffee b/client/lib/avatar.coffee index ba217f085a1..2947c0a7d41 100644 --- a/client/lib/avatar.coffee +++ b/client/lib/avatar.coffee @@ -4,7 +4,7 @@ if not username? return - return Meteor._relativeToSiteRootUrl "/avatar/#{username}.jpg?_dc=#{random}" + return Meteor.absoluteUrl "/avatar/#{username}.jpg?_dc=#{random}" Blaze.registerHelper 'avatarUrlFromUsername', getAvatarUrlFromUsername -- GitLab From 9c727fe0f2af0b69fed35c4d007b4d76fc783ad9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 13 Oct 2015 17:43:29 -0300 Subject: [PATCH 0076/1338] Remove duplicated slash --- client/lib/avatar.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/lib/avatar.coffee b/client/lib/avatar.coffee index 2947c0a7d41..1bb792256f5 100644 --- a/client/lib/avatar.coffee +++ b/client/lib/avatar.coffee @@ -4,7 +4,7 @@ if not username? return - return Meteor.absoluteUrl "/avatar/#{username}.jpg?_dc=#{random}" + return Meteor.absoluteUrl "avatar/#{username}.jpg?_dc=#{random}" Blaze.registerHelper 'avatarUrlFromUsername', getAvatarUrlFromUsername -- GitLab From 9b207763ffa6c384dc22c3af82ecce2eae7e66f9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 13 Oct 2015 18:20:15 -0300 Subject: [PATCH 0077/1338] Add setting to configure Site Url --- .meteor/versions | 1 + i18n/en.i18n.json | 4 +++- i18n/pt.i18n.json | 4 +++- packages/rocketchat-lib/settings/server/startup.coffee | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 34cab543eb7..8c8b864df5a 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -133,6 +133,7 @@ rocketchat:highlight@0.0.1 rocketchat:ldap@0.0.1 rocketchat:lib@0.0.1 rocketchat:logger@0.0.1 +rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 rocketchat:message-star@0.0.1 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 358f0fed8c8..4e70fab1b7e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -299,7 +299,9 @@ "Showing_results" : "<p>Showing <b>%s</b> results</p>", "Silence" : "Silence", "since_creation" : "since %s", - "Site_Name" : "Site Name:", + "Site_Name" : "Site Name", + "Site_Url" : "Site URL", + "Site_Url_Description" : "Example: https://chat.domain.com/", "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 44aaa3d27f9..fb0950dcbb8 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -286,7 +286,9 @@ "Showing_results" : "<p>Exibindo <b>%s</b> resultados</p>", "Silence" : "Silenciar", "since_creation" : "desde %s", - "Site_Name" : "Nome do Site:", + "Site_Name" : "Nome do Site", + "Site_Url" : "URL do Site", + "Site_Url_Description" : "Exemplo: https://chat.dominio.com.br/", "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "Host SMTP", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 93d44b9c3bb..d35d70fdcc8 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -35,6 +35,7 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter_id', '', { type: 'string', group RocketChat.settings.add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', group: 'Accounts', section: 'Twitter' } 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' } -- GitLab From 1aa0efeec6fbf0eea332589121a6c90115254830 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 13 Oct 2015 20:13:44 -0300 Subject: [PATCH 0078/1338] Fixed regex used for replacing links so it supports hash symbols. --- .meteor/versions | 1 + packages/rocketchat-markdown/markdown.coffee | 43 ++++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 34cab543eb7..8c8b864df5a 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -133,6 +133,7 @@ rocketchat:highlight@0.0.1 rocketchat:ldap@0.0.1 rocketchat:lib@0.0.1 rocketchat:logger@0.0.1 +rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 rocketchat:message-star@0.0.1 diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index 9adac3219ae..dd3b73a90c0 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -2,6 +2,8 @@ # Markdown is a named function that will parse markdown syntax # @param {Object} message - The message object ### +##if Meteor.isClient isnt true +## showdown = Npm.require('showdown') class Markdown constructor: (message) -> @@ -10,11 +12,38 @@ class Markdown msg = message.html - # Process MD like for strong, italic and strike - msg = msg.replace(/(^|>|[ >_*~])\`([^`]+)\`([<_*~]|\B|\b|$)/gm, '$1<span class="copyonly">`</span><code class="inline">$2</code><span class="copyonly">`</span>$3') - msg = msg.replace(/(^|>|[ >_~`])\*([^*]+)\*([<_~`]|\B|\b|$)/gm, '$1<span class="copyonly">*</span><strong>$2</strong><span class="copyonly">*</span>$3') - msg = msg.replace(/(^|>|[ >*~`])\_([^_]+)\_([<*~`]|\B|\b|$)/gm, '$1<span class="copyonly">_</span><em>$2</em><span class="copyonly">_</span>$3') - msg = msg.replace(/(^|>|[ >_*`])\~{1,2}([^~]+)\~{1,2}([<_*`]|\B|\b|$)/gm, '$1<span class="copyonly">~</span><strike>$2</strike><span class="copyonly">~</span>$3') + # Support  + msg = msg.replace(/!\[(.*)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$2" title="$1" class="swipebox" target="_blank"><div class="inline-image" style="background-image: url($2);"></div></a>') + + # Support [Text](http://link) + msg = msg.replace(/\[(([\d\w\.-_] ?)+)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$3">$1</a>') + + if RocketChat.settings.get('Markdown_Headers') + # Support # Text for h1 + msg = msg.replace(/^# (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h1>$1</h1>') + + # Support # Text for h2 + msg = msg.replace(/^## (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h2>$1</h2>') + + # Support # Text for h3 + msg = msg.replace(/^### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h3>$1</h4>') + + # 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') + + # Support _text_ to make italics + msg = msg.replace(/(^|>|[ >*~`])\_([^\_\r\n]+)\_([<*~`]|\B|\b|$)/gm, '$1<span class="copyonly">_</span><em>$2</em><span class="copyonly">_</span>$3') + + # Support ~text~ to strike through text + msg = msg.replace(/(^|>|[ >_*`])\~{1,2}([^~\r\n]+)\~{1,2}([<_*`]|\B|\b|$)/gm, '$1<span class="copyonly">~</span><strike>$2</strike><span class="copyonly">~</span>$3') + + # Support >Text for quote msg = msg.replace(/^>(.*)$/gm, '<blockquote><span class="copyonly">></span>$1</blockquote>') msg = msg.replace(/<\/blockquote>\n<blockquote>/gm, '</blockquote><blockquote>') @@ -24,5 +53,5 @@ class Markdown return message -RocketChat.callbacks.add 'renderMessage', Markdown, RocketChat.callbacks.priority.LOW -RocketChat.Markdown = true +RocketChat.callbacks.add 'renderMessage', Markdown, RocketChat.callbacks.priority.HIGH +RocketChat.Markdown = Markdown \ No newline at end of file -- GitLab From 790f31fd2abfdf3553013ba90672c807de9a1ff2 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 13 Oct 2015 20:15:08 -0300 Subject: [PATCH 0079/1338] Removing comments. --- packages/rocketchat-markdown/markdown.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index dd3b73a90c0..dc256b0a29b 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -2,8 +2,6 @@ # Markdown is a named function that will parse markdown syntax # @param {Object} message - The message object ### -##if Meteor.isClient isnt true -## showdown = Npm.require('showdown') class Markdown constructor: (message) -> -- GitLab From 96f1fb2aac581dc156b374c9d7626e3042668cd9 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 13 Oct 2015 20:17:22 -0300 Subject: [PATCH 0080/1338] New line at EOF --- packages/rocketchat-markdown/markdown.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index dc256b0a29b..e8822d3f421 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -52,4 +52,4 @@ class Markdown return message RocketChat.callbacks.add 'renderMessage', Markdown, RocketChat.callbacks.priority.HIGH -RocketChat.Markdown = Markdown \ No newline at end of file +RocketChat.Markdown = Markdown -- GitLab From 3c828049837b4b95eb893f334154c452019c5355 Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Wed, 14 Oct 2015 19:19:11 +0800 Subject: [PATCH 0081/1338] Chinese characters supported including rename room --- server/lib/accounts.coffee | 2 +- server/methods/createPrivateGroup.coffee | 2 +- server/methods/saveRoomName.coffee | 2 +- server/publications/channelAutocomplete.coffee | 11 ++++------- server/restapi/restapi.coffee | 1 - 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index b7902045707..561456113a2 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -64,7 +64,7 @@ Accounts.validateLoginAttempt (login) -> if login.allowed isnt true return login.allowed - if login.user?.active isnt true + if login.user?.active isnt true and login.user?.active != '1' throw new Meteor.Error 'inactive-user', TAPi18n.__ 'User_is_not_activated' return false diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 9645a211fda..6994f4b1b34 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -17,7 +17,7 @@ Meteor.methods members.push me.username - name = s.slugify name + # name = s.slugify name # avoid duplicate names if RocketChat.models.Rooms.findOneByName name diff --git a/server/methods/saveRoomName.coffee b/server/methods/saveRoomName.coffee index aebfee0c480..02425c803f0 100644 --- a/server/methods/saveRoomName.coffee +++ b/server/methods/saveRoomName.coffee @@ -15,7 +15,7 @@ Meteor.methods if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name throw new Meteor.Error 'name-invalid' - name = _.slugify name + ##remove name = _.slugify name if name is room.name return diff --git a/server/publications/channelAutocomplete.coffee b/server/publications/channelAutocomplete.coffee index 22a4368de7d..7cdd182e69b 100644 --- a/server/publications/channelAutocomplete.coffee +++ b/server/publications/channelAutocomplete.coffee @@ -13,15 +13,12 @@ Meteor.publish 'channelAutocomplete', (name) -> limit: 5 cursorHandle = RocketChat.models.Rooms.findByNameContainingAndTypes(name, ['c'], options).observeChanges - added: (_id, record) -> - pub.added('channel-autocomplete', _id, record) - + added: (_id, record) -> + pub.added('channel-autocomplete', _id, record) if _id? changed: (_id, record) -> - pub.changed('channel-autocomplete', _id, record) - + pub.changed('channel-autocomplete', _id, record) if _id? removed: (_id, record) -> - pub.removed('channel-autocomplete', _id, record) - + pub.removed('channel-autocomplete', _id, record) if _id? @ready() @onStop -> cursorHandle.stop() diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 9a954dfcda7..b5b9ec3a17f 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -21,7 +21,6 @@ Api.addRoute 'rooms/:id/join', authRequired: true, Meteor.call('joinRoom', @urlParams.id) status: 'success' # need to handle error - # leave a room Api.addRoute 'rooms/:id/leave', authRequired: true, post: -> -- GitLab From 4012af18df370dbfc0bbcc9ff4e84d85f9988573 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 12:30:53 -0300 Subject: [PATCH 0082/1338] Setting up Travis CI for test execution and removing test dependencies --- .meteor/packages | 2 -- .meteor/versions | 15 --------------- .travis.yml | 10 ++++++++-- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index dd0a51febde..ecb9bdf4c4b 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -105,5 +105,3 @@ spacebars check rocketchat:github-enterprise rocketchat:chatops -sanjo:jasmine@0.20.2 -velocity:console-reporter diff --git a/.meteor/versions b/.meteor/versions index 190f1934765..2bde4d97906 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -101,15 +101,12 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 -package-version-parser@3.0.4 pauli:accounts-linkedin@1.1.2 pauli:linkedin@1.1.2 perak:codemirror@1.2.8 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 -practicalmeteor:chai@2.1.0_1 -practicalmeteor:loglevel@1.2.0_2 promise@0.5.0 qnub:emojione@0.0.3 raix:eventemitter@0.1.3 @@ -150,11 +147,6 @@ rocketchat:statistics@0.0.1 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 -sanjo:jasmine@0.20.2 -sanjo:karma@3.0.2 -sanjo:long-running-child-process@1.1.3 -sanjo:meteor-files-helpers@1.2.0_1 -sanjo:meteor-version@1.0.0 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 @@ -178,13 +170,6 @@ ui@1.0.8 underscore@1.0.4 underscorestring:underscore.string@3.2.2 url@1.0.5 -velocity:chokidar@1.2.0_1 -velocity:console-reporter@0.1.3 -velocity:core@0.10.4 -velocity:meteor-internals@1.1.0_7 -velocity:meteor-stubs@1.1.1 -velocity:shim@0.1.0 -velocity:source-map-support@0.3.2_1 webapp@1.2.2 webapp-hashing@1.0.5 yasaricli:slugify@0.0.7 diff --git a/.travis.yml b/.travis.yml index c518b60636b..578bb0737d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,14 @@ node_js: before_install: - "curl https://install.meteor.com | /bin/sh" + - "mkdir -p node_modules &" + - "npm install phantomjs" + - "npm install velocity" + - "export PHANTOMJS_BIN=./node_modules/phantomjs/bin/phantomjs" + - "export JASMINE_BROWSER=PhantomJS" script: - - meteor add rocketchat:livechat - - meteor add rocketchat:hubot + - meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter + - ./node_modules/velocity/bin/velocity test-packages --ci + - ./node_modules/velocity/bin/velocity test-app --ci - meteor build --server demo.rocket.chat ./ -- GitLab From c690e9b1b926830ad0d680a6c7e297a3a726c880 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 12:49:48 -0300 Subject: [PATCH 0083/1338] Added correct velocity-cli package --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 578bb0737d7..7bc1c365f46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ before_install: - "curl https://install.meteor.com | /bin/sh" - "mkdir -p node_modules &" - "npm install phantomjs" - - "npm install velocity" + - "npm install velocity-cli" - "export PHANTOMJS_BIN=./node_modules/phantomjs/bin/phantomjs" - "export JASMINE_BROWSER=PhantomJS" -- GitLab From 4fa1812af42632891c64ba1b545762fff45704ce Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 12:58:03 -0300 Subject: [PATCH 0084/1338] Fixed path for velocity-cli execution --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7bc1c365f46..e3b9dfa13bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,6 @@ before_install: script: - meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter - - ./node_modules/velocity/bin/velocity test-packages --ci - - ./node_modules/velocity/bin/velocity test-app --ci + - ./node_modules/velocity-cli/bin/velocity test-packages --ci + - ./node_modules/velocity-cli/bin/velocity test-app --ci - meteor build --server demo.rocket.chat ./ -- GitLab From 350754b81863ef98d7a5628d5eeccd5cc1e9dc39 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 14 Oct 2015 13:27:26 -0300 Subject: [PATCH 0085/1338] make all new customizations configurable --- client/stylesheets/base.less | 11 ++++++++++- client/stylesheets/utils/_chatops.less | 4 ---- client/views/account/accountPreferences.coffee | 1 + client/views/account/accountPreferences.html | 17 +++++++++++++---- client/views/app/message.coffee | 4 ++-- client/views/app/room.coffee | 7 +++++-- client/views/app/room.html | 9 +++------ i18n/en.i18n.json | 5 +++++ i18n/pt.i18n.json | 5 +++++ packages/rocketchat-chatops/i18n/en.i18n.json | 3 ++- .../rocketchat-chatops/server/settings.coffee | 5 +++-- .../settings/server/startup.coffee | 3 +++ server/methods/saveUserPreferences.coffee | 3 +++ 13 files changed, 55 insertions(+), 22 deletions(-) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 0f0d145aa98..091ec24d4cf 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2351,7 +2351,7 @@ a.github-fork { .message { font-size: 14px; - padding: 5px 20px 5px 70px; + padding: 18px 20px 4px 70px; position: relative; line-height: 20px; min-height: 40px; @@ -2579,6 +2579,15 @@ a.github-fork { } } +.compact { + .message { + padding: 5px 20px 5px 70px; + .thumb .avatar { + margin-top: -15px; + } + } +} + .flex-tab-bar { position: absolute; width: 40px; diff --git a/client/stylesheets/utils/_chatops.less b/client/stylesheets/utils/_chatops.less index 2e08b5e0b50..2b56d8bb38a 100644 --- a/client/stylesheets/utils/_chatops.less +++ b/client/stylesheets/utils/_chatops.less @@ -2,10 +2,6 @@ li.chatops-message { background-color: #f8f8f8; } -.message .thumb .avatar { - margin-top: -15px !important; -} - .chatops-message div.body { font-size: 12px; font-weight: bold; diff --git a/client/views/account/accountPreferences.coffee b/client/views/account/accountPreferences.coffee index 4b17fba07bf..e948afe3858 100644 --- a/client/views/account/accountPreferences.coffee +++ b/client/views/account/accountPreferences.coffee @@ -39,6 +39,7 @@ Template.accountPreferences.onCreated -> data.useEmojis = $('input[name=useEmojis]:checked').val() data.convertAsciiEmoji = $('input[name=convertAsciiEmoji]:checked').val() data.saveMobileBandwidth = $('input[name=saveMobileBandwidth]:checked').val() + data.compactView = $('input[name=compactView]:checked').val() data.autoImageLoad = $('input[name=autoImageLoad]:checked').val() Meteor.call 'saveUserPreferences', data, (error, results) -> diff --git a/client/views/account/accountPreferences.html b/client/views/account/accountPreferences.html index 0b8cb69482b..2eabe151307 100644 --- a/client/views/account/accountPreferences.html +++ b/client/views/account/accountPreferences.html @@ -17,11 +17,13 @@ <div> {{#if desktopNotificationEnabled}} <label>{{_ "Desktop_Notifications_Enabled"}}</label> - {{else}} {{#if desktopNotificationDisabled}} - <label>{{_ "Desktop_Notifications_Disabled"}}</label> {{else}} - <label><button class="button enable-notifications"><i class="octicon octicon-comment"></i> <span>{{_ "Enable_Desktop_Notifications"}}</span></button></label> - {{/if}} {{/if}} + {{#if desktopNotificationDisabled}} + <label>{{_ "Desktop_Notifications_Disabled"}}</label> + {{else}} + <label><button class="button enable-notifications"><i class="octicon octicon-comment"></i> <span>{{_ "Enable_Desktop_Notifications"}}</span></button></label> + {{/if}} + {{/if}} </div> </div> <div class="input-line double-col"> @@ -52,6 +54,13 @@ <label><input type="radio" name="saveMobileBandwidth" value="0" checked="{{checked 'saveMobileBandwidth' false}}" /> {{_ "False"}}</label> </div> </div> + <div class="input-line double-col" id="compactView"> + <label>{{_ "Compact_View"}}</label> + <div> + <label><input type="radio" name="compactView" value="1" checked="{{checked 'compactView' true}}" /> {{_ "True"}}</label> + <label><input type="radio" name="compactView" value="0" checked="{{checked 'compactView' false true}}" /> {{_ "False"}}</label> + </div> + </div> </div> </div> <div class="section"> diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index f78799e162d..01e2b06a639 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -105,8 +105,8 @@ Template.message.onViewRendered = (context) -> ul = lastNode.parentElement wrapper = ul.parentElement - if this.u?.username is not "hubot" - if context.urls?.length > 0 and Template.oembedBaseWidget? and RocketChat.settings.get 'API_Embed' + if context.urls?.length > 0 and Template.oembedBaseWidget? and RocketChat.settings.get 'API_Embed' + if context.u?.username not in RocketChat.settings.get('API_EmbedDisabledFor')?.split(',') for item in context.urls do (item) -> urlNode = lastNode.querySelector('.body a[href="'+item.url+'"]') diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 37935ac9bb4..b1bef85f710 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -8,7 +8,7 @@ favoritesEnabled = -> # @TODO bug com o botão para "rolar até o fim" (novas mensagens) quando há uma mensagem com texto que gere rolagem horizontal Template.room.helpers showFormattingTips: -> - return RocketChat.Markdown or RocketChat.Highlight + return RocketChat.settings.get('Message_ShowFormattingTips') and (RocketChat.Markdown or RocketChat.Highlight) showMarkdown: -> return RocketChat.Markdown showHighlight: -> @@ -188,7 +188,7 @@ Template.room.helpers return !! ChatRoom.findOne { _id: @_id, t: 'c' } canRecordAudio: -> - return navigator.getUserMedia? or navigator.webkitGetUserMedia? + return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) roomManager: -> room = ChatRoom.findOne(this._id, { reactive: false }) @@ -217,6 +217,9 @@ Template.room.helpers showToggleFavorite: -> return true if isSubscribed(this._id) and favoritesEnabled() + compactView: -> + return 'compact' if Meteor.user()?.settings?.preferences?.compactView + Template.room.events "touchstart .message": (e, t) -> message = this._arguments[1] diff --git a/client/views/app/room.html b/client/views/app/room.html index a403d7befd6..e6a0b059a56 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -48,7 +48,7 @@ </div> {{/if}} {{/if}} - <div class="messages-box"> + <div class="messages-box {{compactView}}"> <div class="ticks-bar"></div> <div class="wrapper"> <ul aria-live="polite"> @@ -86,9 +86,8 @@ <div class="input-message-container"> {{> messagePopupConfig getPupupConfig}} <textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea> - <!--<i class="icon-paper-plane" title="{{_ "Send_Message"}}" aria-label="{{_ "Send_Message"}}"></i>--> </div> - <!-- + {{#if canRecordAudio}} <div class="mic"> <i class="icon-mic" aria-label="{{_ "Record"}}"></i> @@ -97,7 +96,6 @@ <i class="icon-stop" aria-label="{{_ "Stop_Recording"}}"></i> </div> {{/if}} - --> </div> <div class="users-typing"> {{#with usersTyping}} @@ -117,7 +115,7 @@ {{/if}} {{/with}} </div> - <!-- + {{#if showFormattingTips}} <div class="formatting-tips" aria-hidden="true" dir="auto"> {{#if showMarkdown}} @@ -135,7 +133,6 @@ </div> {{/if}} - --> <div class="editing-commands" aria-hidden="true" dir="auto"> <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="">{{_ 'Cancel'}}</a></div> <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="">{{_ 'Save_changes'}}</a></div> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 358f0fed8c8..3aa9107d2db 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -45,6 +45,8 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Embed", + "API_EmbedDisabledFor": "Disable Embed for Users", + "API_EmbedDisabledFor_Description": "Comma-separated usernames list", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", @@ -72,6 +74,7 @@ "close" : "close", "coming_soon" : "coming soon", "Commands" : "Commands", + "Compact_View": "Compact View", "Confirm_password" : "Confirm your password", "Contact" : "Contact", "Conversation" : "Conversation", @@ -179,6 +182,7 @@ "Message_AllowDeleting" : "Allow Message Deleting", "Message_AllowEditing" : "Allow Message Editing", "Message_AllowEditing_BlockEditInMinutes" : "Block message editing after (in minutes - 0 to disable)", + "Message_AudioRecorderEnabled": "Audio Recorder Enabled", "Message_deleting_not_allowed" : "Message deleting not allowed", "Message_editing_not_allowed" : "Message editing not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", @@ -189,6 +193,7 @@ "Message_pinned" : "Message pinned", "Message_ShowDeletedStatus" : "Show Deleted Status", "Message_ShowEditedStatus" : "Show Edited Status", + "Message_ShowFormattingTips": "Show Formatting Tips", "Messages": "Messages", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 44aaa3d27f9..fcdd5fb2ebe 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -44,6 +44,8 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Embed", + "API_EmbedDisabledFor": "Desabilitar embed para os usuários", + "API_EmbedDisabledFor_Description": "Lista de nomes de usuário separados por vÃrgula", "are_also_typing" : "também estão digitando", "are_typing" : "estão digitando", "Are_you_sure" : "Você tem certeza?", @@ -70,6 +72,7 @@ "Chat_Rooms" : "Salas de Chat", "close" : "fechar", "coming_soon" : "em breve", + "Compact_View": "Visão Compacta", "Confirm_password" : "Confirmar a senha", "Contact" : "Contato", "Conversation" : "Conversa", @@ -172,6 +175,7 @@ "Message_AllowDeleting" : "Permitir Exclusão de Mensagem", "Message_AllowEditing" : "Permitir Edição de Mensagem", "Message_AllowEditing_BlockEditInMinutes" : "Bloquear edição de mensagens após (em minutos - 0 para desabilitar)", + "Message_AudioRecorderEnabled": "Gravação de Ãudio Habilitada", "Message_deleting_not_allowed" : "Exclusão de mensagem não permitido", "Message_editing_not_allowed" : "Edição de mensagem não permitido", "Message_editing_blocked" : "Esta mensagem não pode mais ser editada", @@ -182,6 +186,7 @@ "Message_pinned" : "Mensagem fixada", "Message_ShowDeletedStatus" : "Mostrar Status ExcluÃdo", "Message_ShowEditedStatus" : "Mostrar Status Editado", + "Message_ShowFormattingTips": "Exibir dicas de formatação", "Messages": "Mensagens", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", diff --git a/packages/rocketchat-chatops/i18n/en.i18n.json b/packages/rocketchat-chatops/i18n/en.i18n.json index b6097d68e9b..818eea232e6 100644 --- a/packages/rocketchat-chatops/i18n/en.i18n.json +++ b/packages/rocketchat-chatops/i18n/en.i18n.json @@ -1,4 +1,5 @@ { "Chatops_Enabled" : "Enable Chatops", - "Chatops_Title": "Chatops panel" + "Chatops_Title": "Chatops panel", + "Chatops_Username": "Chatops username" } diff --git a/packages/rocketchat-chatops/server/settings.coffee b/packages/rocketchat-chatops/server/settings.coffee index d7787d1b067..2753900494d 100644 --- a/packages/rocketchat-chatops/server/settings.coffee +++ b/packages/rocketchat-chatops/server/settings.coffee @@ -1,3 +1,4 @@ Meteor.startup -> - RocketChat.settings.add 'Chatops_Enabled', false, { type: 'boolean', group: 'General', public: true, i18nLabel: "ChatOps Enabled" } - RocketChat.settings.add 'Chatops_Username', false, { type: 'string', group: 'General', public: true, i18nLabel: "ChatOps User Name" } + RocketChat.settings.addGroup 'Chatops' + RocketChat.settings.add 'Chatops_Enabled', false, { type: 'boolean', group: 'Chatops', public: true } + RocketChat.settings.add 'Chatops_Username', false, { type: 'string', group: 'Chatops', public: true } diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 8c1235663d7..274b0230b38 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -42,6 +42,7 @@ RocketChat.settings.add 'Disable_Favorite_Rooms', false, { type: 'boolean', grou 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' } @@ -62,6 +63,8 @@ RocketChat.settings.add 'Message_ShowEditedStatus', true, { type: 'boolean', gro 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 } RocketChat.settings.addGroup 'Meta' RocketChat.settings.add 'Meta_language', '', { type: 'string', group: 'Meta' } diff --git a/server/methods/saveUserPreferences.coffee b/server/methods/saveUserPreferences.coffee index 4a7e414a0b2..8d9c86442ef 100644 --- a/server/methods/saveUserPreferences.coffee +++ b/server/methods/saveUserPreferences.coffee @@ -20,6 +20,9 @@ Meteor.methods if settings.saveMobileBandwidth? preferences.saveMobileBandwidth = if settings.saveMobileBandwidth is "1" then true else false + if settings.compactView? + preferences.compactView = if settings.compactView is "1" then true else false + if settings.autoImageLoad? preferences.autoImageLoad = if settings.autoImageLoad is "1" then true else false -- GitLab From b627c954693bd33a4d367f784d739370db0a5f3e Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 13:31:04 -0300 Subject: [PATCH 0086/1338] Fixing call to underscore.string 'trim' method to avoid conflicts with Underscore test stubs. --- packages/rocketchat-markdown/markdown.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index 101b6108fd2..d0d2fb2a033 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -6,7 +6,7 @@ class Markdown constructor: (message) -> - if _s.trim message.html + if s.trim message.html msg = message.html -- GitLab From 610284452317c0d9e5eb23f4b32a592a2fd36094 Mon Sep 17 00:00:00 2001 From: Seth Shelnutt <Shelnutt2@gmail.com> Date: Wed, 14 Oct 2015 13:41:17 -0400 Subject: [PATCH 0087/1338] Add new server method getRoomIdByNameOrId This is used by hubot-rocketchat adapter to get room id's --- server/methods/getRoomIdByNameOrId.coffee | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 server/methods/getRoomIdByNameOrId.coffee diff --git a/server/methods/getRoomIdByNameOrId.coffee b/server/methods/getRoomIdByNameOrId.coffee new file mode 100644 index 00000000000..50d6a4a0c64 --- /dev/null +++ b/server/methods/getRoomIdByNameOrId.coffee @@ -0,0 +1,14 @@ +Meteor.methods + getRoomIdByNameOrId: (rid) -> + + console.log '[methods] getRoomIdByNameOrId-> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments + + room = RocketChat.models.Rooms.findOneById rid + + if not room? + room = RocketChat.models.Rooms.findOneByName rid + + if room? + rid = room._id + + return rid -- GitLab From 8b6085df514b848325bacdc2f44b016ef254da47 Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Thu, 15 Oct 2015 01:48:06 +0800 Subject: [PATCH 0088/1338] add findOrCreateRoom function --- server/methods/findOrCreateRoom.coffee | 13 +++++++++++++ server/restapi/restapi.coffee | 8 ++++++++ 2 files changed, 21 insertions(+) create mode 100644 server/methods/findOrCreateRoom.coffee diff --git a/server/methods/findOrCreateRoom.coffee b/server/methods/findOrCreateRoom.coffee new file mode 100644 index 00000000000..8d24f8ecc8e --- /dev/null +++ b/server/methods/findOrCreateRoom.coffee @@ -0,0 +1,13 @@ +Meteor.methods + findOrCreateClientRoomThenJoin: (clientId, usernames) -> + m = clientId.match(/^(?:CLT){0,1}([0-9]+)/i); + roomName = m[0]; + if not roomName? + throw new Meteor.Error 403, '[methods] findOrCreateClientRoom -> Mal-format' + + room = RocketChat.models.Rooms.findOneByName(roomName); + console.log '[methods] findOrCreateClientRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments + + if not room? + room = Meteor.call('createPrivateGroup', roomName, Meteor.userId(), usernames) + Meteor.call 'joinRoom', room._id diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index b5b9ec3a17f..67003b5357b 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -21,6 +21,14 @@ Api.addRoute 'rooms/:id/join', authRequired: true, Meteor.call('joinRoom', @urlParams.id) status: 'success' # need to handle error +# find or create a room +Api.addRoute 'rooms/findorcreatethenjoin/:clientId', authRequired: true, + post: -> + Meteor.runAsUser this.userId, () => + Meteor.call('findOrCreateClientRoomThenJoin', @urlParams.clientId) + status: 'success' # need to handle error + + # leave a room Api.addRoute 'rooms/:id/leave', authRequired: true, post: -> -- GitLab From 2a459f2db07cd23853b00257dcabc1c4d7214f8a Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 15:20:59 -0300 Subject: [PATCH 0089/1338] Simplifying rocketchat:markdown tests since its falling because of underscore.string --- packages/rocketchat-markdown/markdown.coffee | 2 +- packages/rocketchat-markdown/package.js | 2 +- .../tests/jasmine/client/unit/markdown.spec.coffee | 10 ++-------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index d0d2fb2a033..6e5a0b057fe 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -6,7 +6,7 @@ class Markdown constructor: (message) -> - if s.trim message.html + if _.trim message.html msg = message.html diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index db177b363a0..69740c6cd82 100644 --- a/packages/rocketchat-markdown/package.js +++ b/packages/rocketchat-markdown/package.js @@ -23,5 +23,5 @@ Package.onTest(function(api) { api.use('rocketchat:lib'); api.use('rocketchat:markdown'); - api.addFiles('tests/jasmine/client/unit/markdown.spec.coffee'); + api.addFiles('tests/jasmine/client/unit/markdown.spec.coffee', 'client'); }); diff --git a/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee b/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee index dc78a38dfae..f154266a873 100644 --- a/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee +++ b/packages/rocketchat-markdown/tests/jasmine/client/unit/markdown.spec.coffee @@ -1,10 +1,4 @@ -describe 'rocketchat:markdown Client + Server', -> - 'use strict' +describe 'rocketchat:markdown Client', -> it 'should exist', -> - obj = RocketChat.Markdown { html: 'test' } - expect(obj).toBeDefined() - - it 'should highlight with bold when surrounded by *', -> - output = RocketChat.Markdown { 'msg': '', 'html':'*abc123*' } - expect(output.html).toEqual('<span class="copyonly">*</span><strong>abc123</strong><span class="copyonly">*</span>') + expect(RocketChat.Markdown).toBeDefined() -- GitLab From 6e47717659398d542eda27abcff2405fd41fa3f1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 15:30:19 -0300 Subject: [PATCH 0090/1338] Move settings.onload to common --- .../settings/client/rocketchat.coffee | 4 +- .../settings/lib/rocketchat.coffee | 42 ++++++++++++------- .../settings/server/methods.coffee | 16 ------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/packages/rocketchat-lib/settings/client/rocketchat.coffee b/packages/rocketchat-lib/settings/client/rocketchat.coffee index 4640ce42413..3e30a004cb4 100644 --- a/packages/rocketchat-lib/settings/client/rocketchat.coffee +++ b/packages/rocketchat-lib/settings/client/rocketchat.coffee @@ -8,5 +8,5 @@ settingsDict = new ReactiveDict('settings') RocketChat.settings.get = (_id) -> return settingsDict.get(_id) -RocketChat.settings.load = (key, value) -> - return settingsDict.set key, value \ No newline at end of file +RocketChat.settings.onload '*', (key, value) -> + return settingsDict.set key, value diff --git a/packages/rocketchat-lib/settings/lib/rocketchat.coffee b/packages/rocketchat-lib/settings/lib/rocketchat.coffee index 3bde2ac5d7f..e43641e8c1d 100644 --- a/packages/rocketchat-lib/settings/lib/rocketchat.coffee +++ b/packages/rocketchat-lib/settings/lib/rocketchat.coffee @@ -2,24 +2,38 @@ # RocketChat.settings holds all packages settings # @namespace RocketChat.settings ### -RocketChat.settings = {} +RocketChat.settings = + callbacks: {} + ts: new Date -RocketChat.settings.ts = new Date + get: (_id) -> + return Meteor.settings?[_id] -RocketChat.settings.get = (_id) -> - return Meteor.settings?[_id] + set: (_id, value, callback) -> + Meteor.call 'saveSetting', _id, value, callback -RocketChat.settings.set = (_id, value, callback) -> - Meteor.call 'saveSetting', _id, value, callback + batchSet: (settings, callback) -> -RocketChat.settings.batchSet = (settings, callback) -> + # async -> sync + # http://daemon.co.za/2012/04/simple-async-with-only-underscore/ - # async -> sync - # http://daemon.co.za/2012/04/simple-async-with-only-underscore/ + save = (setting) -> + return (callback) -> + Meteor.call 'saveSetting', setting._id, setting.value, callback - save = (setting) -> - return (callback) -> - Meteor.call 'saveSetting', setting._id, setting.value, callback + actions = _.map settings, (setting) -> save(setting) + _(actions).reduceRight(_.wrap, (err, success) -> return callback err, success)() - actions = _.map settings, (setting) -> save(setting) - _(actions).reduceRight(_.wrap, (err, success) -> return callback err, success)() + load: (key, value, initialLoad) -> + if RocketChat.settings.callbacks[key]? + for callback in RocketChat.settings.callbacks[key] + callback key, value, initialLoad + + if RocketChat.settings.callbacks['*']? + for callback in RocketChat.settings.callbacks['*'] + callback key, value, initialLoad + + + onload: (key, callback) -> + RocketChat.settings.callbacks[key] ?= [] + RocketChat.settings.callbacks[key].push callback diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 20514c937dd..729522f1642 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -1,5 +1,3 @@ -RocketChat.settings.callbacks = {} - ### # Add a setting # @param {String} _id @@ -60,20 +58,6 @@ RocketChat.settings.addGroup = (_id, options = {}) -> return RocketChat.models.Settings.upsert { _id: _id }, upsertChanges -RocketChat.settings.load = (key, value, initialLoad) -> - if RocketChat.settings.callbacks[key]? - for callback in RocketChat.settings.callbacks[key] - callback key, value, initialLoad - - if RocketChat.settings.callbacks['*']? - for callback in RocketChat.settings.callbacks['*'] - callback key, value, initialLoad - - -RocketChat.settings.onload = (key, callback) -> - RocketChat.settings.callbacks[key] ?= [] - RocketChat.settings.callbacks[key].push callback - ### # Remove a setting by id # @param {String} _id -- GitLab From 84e92d271e23f44d38761cf3cf33af4eb76e9124 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Wed, 14 Oct 2015 15:30:34 -0300 Subject: [PATCH 0091/1338] Fix user is typing stream --- .../server/Notifications.coffee | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/rocketchat-lib/server/Notifications.coffee b/packages/rocketchat-lib/server/Notifications.coffee index 30f3da40253..3fb92a12935 100644 --- a/packages/rocketchat-lib/server/Notifications.coffee +++ b/packages/rocketchat-lib/server/Notifications.coffee @@ -46,25 +46,20 @@ RocketChat.Notifications = new class @streamUser.emit.apply @streamUser, args - ## Permissions for client # Enable emit for event typing for rooms and add username to event data func = (eventName, username, typing) -> - console.log arguments [room, e] = eventName.split('/') - if e isnt 'typing' - return false + if e is 'webrtc' + return true - user = Meteor.users.findOne(@userId, {fields: {username: 1}}) - if not user? or user.username isnt username - return false + if e is 'typing' + user = Meteor.users.findOne(@userId, {fields: {username: 1}}) + if user?.username is username + return true - return true + return false RocketChat.Notifications.streamRoom.permissions.write func, false # Prevent Cache - -RocketChat.Notifications.streamRoom.permissions.write (eventName) -> - [room, e] = eventName.split('/') - return e is 'webrtc' -- GitLab From 1d9611c59b4939d5bda6c2841d67f4f6c6c16878 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 15:30:40 -0300 Subject: [PATCH 0092/1338] Configure root_url on load of Site_Url setting --- packages/rocketchat-lib/package.js | 1 + packages/rocketchat-lib/settings/lib/onLoadSettings.coffee | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 packages/rocketchat-lib/settings/lib/onLoadSettings.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index e4ee3fd0d66..c8cc7d138d8 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -34,6 +34,7 @@ Package.onUse(function(api) { // Settings api.addFiles('settings/lib/rocketchat.coffee'); + api.addFiles('settings/lib/onLoadSettings.coffee'); api.addFiles('settings/server/models/Settings.coffee', 'server'); api.addFiles('settings/server/methods.coffee', 'server'); diff --git a/packages/rocketchat-lib/settings/lib/onLoadSettings.coffee b/packages/rocketchat-lib/settings/lib/onLoadSettings.coffee new file mode 100644 index 00000000000..d0efac3c71b --- /dev/null +++ b/packages/rocketchat-lib/settings/lib/onLoadSettings.coffee @@ -0,0 +1,5 @@ +RocketChat.settings.onload 'Site_Url', (key, value, initialLoad) -> + if value?.trim() isnt '' + __meteor_runtime_config__.ROOT_URL = value + if Meteor.absoluteUrl.defaultOptions?.rootUrl? + Meteor.absoluteUrl.defaultOptions.rootUrl = value -- GitLab From 612e590788524347a9e74046659099293e4c9c90 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 15:55:34 -0300 Subject: [PATCH 0093/1338] Explicitly declaring sanjo:jasmine version. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e3b9dfa13bc..c8a42978d51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ before_install: - "export JASMINE_BROWSER=PhantomJS" script: - - meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter + - meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine@0.20.2 velocity:console-reporter - ./node_modules/velocity-cli/bin/velocity test-packages --ci - ./node_modules/velocity-cli/bin/velocity test-app --ci - meteor build --server demo.rocket.chat ./ -- GitLab From 68b38c8427c48abd889034042c063ff2f6487121 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Wed, 14 Oct 2015 16:21:36 -0300 Subject: [PATCH 0094/1338] Fixes #1099 --- client/views/app/room.coffee | 5 +++-- client/views/app/room.html | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index b1bef85f710..db74d4a9b22 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -190,9 +190,10 @@ Template.room.helpers canRecordAudio: -> return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) - roomManager: -> + unreadSince: -> room = ChatRoom.findOne(this._id, { reactive: false }) - return RoomManager.openedRooms[room.t + room.name] + if room? + return RoomManager.openedRooms[room.t + room.name]?.unreadSince?.get() unreadCount: -> return RoomHistoryManager.getRoom(@_id).unreadNotLoaded.get() + Template.instance().unreadCount.get() diff --git a/client/views/app/room.html b/client/views/app/room.html index e6a0b059a56..ff971c070aa 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -39,7 +39,7 @@ {{/each}} </div> {{#if unreadCount}} - {{#if roomManager.unreadSince.get}} + {{#if unreadSince}} <div class="unread-bar"> {{_ "S_new_messages_since_s" unreadCount formatUnreadSince}} <a> -- GitLab From 9e62383a093a540d9ef7df977c42da79b749b7a9 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 16:21:36 -0300 Subject: [PATCH 0095/1338] Updating versions --- .meteor/versions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 2bde4d97906..6601e5f812c 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,7 @@ cfs:http-methods@0.0.30 check@1.0.6 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.10 -cosmos:browserify@0.5.1 +cosmos:browserify@0.8.1 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 @@ -72,7 +72,7 @@ less@2.5.0_3 livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 -matb33:collection-hooks@0.7.15 +matb33:collection-hooks@0.8.1 meteor@1.1.9 meteor-base@1.0.1 meteor-developer@1.1.4 @@ -150,7 +150,7 @@ routepolicy@1.0.6 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 -simple:highlight.js@1.0.9 +simple:highlight.js@1.2.0 simple:json-routes@1.0.4 spacebars@1.0.7 spacebars-compiler@1.0.7 -- GitLab From e729d85db36074f3e62c0fcb36d321234f99c8e4 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Wed, 14 Oct 2015 14:26:10 -0500 Subject: [PATCH 0096/1338] get ready for merge-down --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index db7974b4359..191d56d7817 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: required language: node_js branches: only: - - travis-001 + - master node_js: - '0.10' before_install: @@ -33,6 +33,6 @@ deploy: skip_cleanup: true local_dir: ../build on: - branch: travis-001 + branch: master secret_access_key: secure: LYA2XNdpHBTN/zs/71VWLr81b3Gb290PRIqQER72SZ3eQjDk0UpUUFkzK6mc6GkelXyqHRBRckmhBzVCEAO6KNIU9JHc9aUxyUbSt7OMTAZUZ8X36E7HL6mXN73YHtUCbEczD41aXMK+HQ9ol0EXfvbprp5gFwqT908dSVleNJCN6wZgW5ZJVzWTiC2/aaGqCrWhAWybG1XwCgl8ND8N3qFsNBZ6MDN3rpp9kVdDJ3vzp5Azkf6QrTFQTo2ai3DFFnRf7J84/8tpRL3tVcPwjik449KEkJlCPotxt7XxUTg9HrN5LQY4wYTKyKhoYxzADwse8VaU/oFhVef3A8AiLpfg8rR63ahs5ZOqJc926eiZWGumLfvcGkHD2kb+z+l9bIE8b2X7mct6gK4ub0E6Ul/NOoh1ZgppVzP3PuYZXGb2CNvZTrrSjH9dGWPWlRjZaErg4bs4BC6y6eGjgu1CqFa1eqLFO/oYdmX5c4kDskyNf0VSVVXmqLqQBWrkOGSr3Z8nR8XQ1PDQfmj8ZMmDRtvt58DuOVzOBkC71Mc/Kr/cKS0cXedwzzNg2BG4EHMsc1eTn6JWs95NFCbPbI5HzxYODumZwOwSJyXKiDgUhPmRc6I1MvgJqIIBGWFqIIGEfR715E4zaJzAYvTPWvL+8aBMfZxdQouRYH7d9kREc6U= -- GitLab From 0d42cd3954c0d46dd818d2db13511549008e8e8b Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 16:34:09 -0300 Subject: [PATCH 0097/1338] Final updated versions --- .meteor/packages | 2 +- .meteor/versions | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index ecb9bdf4c4b..30bc8e4d1a7 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -78,7 +78,7 @@ pauli:accounts-linkedin percolate:migrations percolate:synced-cron raix:handlebar-helpers -raix:push@2.6.13-rc.1 +raix:push raix:ui-dropped-event steffo:meteor-accounts-saml tap:i18n diff --git a/.meteor/versions b/.meteor/versions index 6601e5f812c..580e906fc44 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -34,7 +34,7 @@ ddp-rate-limiter@1.0.0 ddp-server@1.2.1 deps@1.0.9 diff-sequence@1.0.1 -dispatch:run-as-user@0.0.2 +dispatch:run-as-user@1.1.1 ecmascript@0.1.5 ecmascript-collections@0.1.6 ejson@1.0.7 @@ -112,7 +112,7 @@ qnub:emojione@0.0.3 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 -raix:push@2.6.13-rc.1 +raix:push@3.0.1 raix:ui-dropped-event@0.0.7 random@1.0.4 rate-limit@1.0.0 -- GitLab From a7916695ae486a3a5ef1a4f5223d3ac665e2fe9d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 17:15:54 -0300 Subject: [PATCH 0098/1338] Use flexbox to keep all bars stacked and improve unread pointer --- client/views/app/room.coffee | 7 +- client/views/app/room.html | 34 +- packages/rocketchat-theme/assets/colors.less | 1198 ----------------- .../assets/stylesheets/base.less | 78 +- .../stylesheets/utils/_colors.import.less | 22 +- 5 files changed, 80 insertions(+), 1259 deletions(-) delete mode 100644 packages/rocketchat-theme/assets/colors.less diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index b1bef85f710..9e7febbf9cb 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -237,7 +237,7 @@ Template.room.events "touchcancel .message": (e, t) -> Meteor.clearTimeout t.touchtime - "click .upload-progress-item > a": -> + "click .upload-progress > a": -> Session.set "uploading-cancel-#{this.id}", true "click .unread-bar > a": -> @@ -508,14 +508,15 @@ Template.room.onRendered -> template = this - wrapperOffset = $('.messages-box > .wrapper').offset() + containerBars = $('.messages-container > .container-bars') + containerBarsOffset = containerBars.offset() onscroll = _.throttle -> template.atBottom = wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight , 200 updateUnreadCount = _.throttle -> - firstMessageOnScreen = document.elementFromPoint(wrapperOffset.left+1, wrapperOffset.top+50) + firstMessageOnScreen = document.elementFromPoint(containerBarsOffset.left+1, containerBarsOffset.top+containerBars.height()+1) if firstMessageOnScreen?.id? firstMessage = ChatMessage.findOne firstMessageOnScreen.id if firstMessage? diff --git a/client/views/app/room.html b/client/views/app/room.html index e6a0b059a56..6095e07e5a4 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -20,9 +20,9 @@ {{/if}} </h2> </header> - <div class="upload-progress"> + <div class="container-bars"> {{#each uploading}} - <div class="upload-progress-item {{#if error}}upload-error{{/if}}"> + <div class="upload-progress {{#if error}}upload-error{{/if}}"> {{#if error}} {{error}} <a> @@ -30,24 +30,26 @@ </a> {{else}} <div class="upload-progress-progress" style="width: {{percentage}}%;"></div> - {{name}}... {{percentage}}% - <a> - cancel - </a> + <div class="upload-progress-text"> + {{name}}... {{percentage}}% + <a> + cancel + </a> + </div> {{/if}} </div> {{/each}} - </div> - {{#if unreadCount}} - {{#if roomManager.unreadSince.get}} - <div class="unread-bar"> - {{_ "S_new_messages_since_s" unreadCount formatUnreadSince}} - <a> - {{_ "Mark_as_read"}} - </a> - </div> + {{#if unreadCount}} + {{#if roomManager.unreadSince.get}} + <div class="unread-bar"> + {{_ "S_new_messages_since_s" unreadCount formatUnreadSince}} + <a> + {{_ "Mark_as_read"}} + </a> + </div> + {{/if}} {{/if}} - {{/if}} + </div> <div class="messages-box {{compactView}}"> <div class="ticks-bar"></div> <div class="wrapper"> diff --git a/packages/rocketchat-theme/assets/colors.less b/packages/rocketchat-theme/assets/colors.less deleted file mode 100644 index 516091345e5..00000000000 --- a/packages/rocketchat-theme/assets/colors.less +++ /dev/null @@ -1,1198 +0,0 @@ -// Colors -// -------------- - -.custom-scroll(@background, @thumb, @width: 8px) { - &::-webkit-scrollbar { - width: @width; - background: @background; - } - &::-webkit-scrollbar-thumb { - background-color: @thumb; - -webkit-border-radius: 50px; - } - &::-webkit-scrollbar-corner { - background-color: @background; - } -} - -a { - &:hover, - &:active { - color: @primary-font-color; - } -} - -code { - background-color: @code-background; - border-color: @code-border; - color: @code-color; -} - -blockquote { - &:before { - background-color: @blockquote-background; - } -} - -.login-terms { - color: @smallprint-font-color; - a { - color: @smallprint-font-color; - &:hover { - color: @smallprint-hover-color; - } - } -} - -.upload-preview { - background-color: @secondary-background-color; -} - -.upload-preview-title { - background-color: @tertiary-background-color; -} - -.first-unread { - &.first-unread-opaque { - .body { - &::before { - background-color: lighten(@info-font-color, 25%); - } - - &::after { - color: @info-font-color; - } - } - } - .body { - &::before { - background-color: lighten(@info-active-font-color, 25%); - } - - &::after { - background-color: @content-background-color; - color: @info-active-font-color; - } - } -} - -.alert { - border-color: rgba(0, 0, 0, 0); -} - -.alert-warning { - color: #8A6D3B; - background-color: #FCF8E3; - border-color: #FAEBCC; -} - -.alert-danger { - color: #A94442; - background-color: #F2DEDE; - border-color: #EBCCD1; -} - -.scrollable { - .custom-scroll(transparent, #BFBFBF); -} - -.rocket-form { - legend { - &:after { - background-color: #DFDFDF; - } - } -} - -.input-line { - &.search { - .icon-search { - color: @secondary-font-color; - } - } - > label { - color: @primary-font-color; - } -} - -.rocket-h2 { - color: #EFEFEF; -} - -.rocket-h3 { - color: #EAEAEA; -} - -html { - .custom-scroll(transparent, rgba(255, 255, 255, 0.05), 3px); -} - -body { - color: @primary-font-color; - background-color: @primary-background-color; -} - -textarea, -select, -input[type='text'], -input[type='number'], -input[type='email'], -input[type='password'] { - border-color: #E7E7E7; - background-color: #fff; -} - -input.search { - &:before { - background-color: #000; - } -} - -.form-horizontal .control-label { - color: @primary-font-color; -} - -.-autocomplete-container { - p { - color: @secondary-font-color; - } -} - -.-autocomplete-item { - color: @secondary-font-color; - i { - color: @secondary-font-color; - } - &.selected { - background-color: @tertiary-background-color; - color: @primary-font-color; - } -} - -label.required:after { - color: red; -} - -.status-offline, -.icon-at.status-offline { - color: @status-offline; -} - -.status-online, -.icon-at.status-online { - color: @status-online; -} - -.status-busy, -.icon-at.status-busy { - color: @status-busy; -} - -.status-away, -.icon-at.status-away { - color: @status-away; -} - -// TODO -- Refactor favorite styles and logic; -.favorite-room { - color: #FECF09; -} - -.toggle-favorite { - color: #AAA; -} - -.btn-loading { - color: #444 !important; - background-color: transparent !important; - &:hover { - background-color: transparent !important; - } -} - -// new layout buttons -.button { - background-color: #FFF; - color: rgba(255, 255, 255, 0.85); - background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); - &:before { - background-color: rgba(0, 0, 0, 0.1); - } - &:hover { - color: #FFF; - } - &.secondary { - background-color: @tertiary-background-color; - color: @primary-font-color; - &:before { - background-color: rgba(0, 0, 0, 0.045); - } - } - &.delete, - &.remove, - &.red { - background-color: #bc2031; - } - &.lightblue { - background-color: #02acec; - } - &.clean { - background-color: rgba(0, 0, 0, 0.025); - } - &.facebook { - background-color: #325c99; - } - &.twitter { - background-color: #02acec; - } - &.google { - background-color: #dd4b39; - } - &.github { - background-color: #4c4c4c; - } - &.gitlab { - background-color: #373d47; - } - &.trello { - background-color: #026aa7; - } - &.meteor-developer { - background-color: #de4f4f; - } -} - -.burger { - i { - background-color: #333; - } - - .unread-burger-alert { - background-color: #F95555; - color: @content-background-color; - } -} - -.arrow { - &:before, - &:after { - background-color: #aaa; - } -} - -.a-plus { - &:before, - &:after { - background-color: #aaa; - } -} - -a.github-fork { - background-color: #5c5c5c; - color: #f0f0f0; - &:hover { - background-color: #4b4b4b; - color: #FFF; - } - &:before { - border-top-color: #f0f0f0; - } - &:after { - border-top-color: #f0f0f0; - } -} - -.mac-bar { - background-color: #ddd; - i { - background-color: #ff5f57; - &:nth-child(2) { - background-color: #ffbd2e; - } - &:nth-child(3) { - background-color: #28ca41; - } - } -} - -.avatar { - .avatar-image { - background-color: transparent; - } - &[initials]:before { - color: #FFF; - } -} - -#rocket-chat { - background-color: @content-background-color; -} - -.account-box { - .info { - h4 { - color: rgba(255, 255, 255, 0.65); - } - &.status-offline { - .thumb:after { - border-color: darken(@status-offline, 5%); - background-color: @status-offline; - } - } - &.status-online { - .thumb:after { - border-color: darken(@status-online, 5%); - background-color: @status-online; - } - } - &.status-away { - .thumb:after { - border-color: darken(@status-away, 5%); - background-color: @status-away; - } - } - &.status-busy { - .thumb:after { - border-color: darken(@status-busy, 5%); - background-color: @status-busy; - } - } - } - .options { - background-color: @primary-background-color; - .status { - &:after { - border-color: #6f6f6f; - } - &.offline { - &:after { - border-color: #666666; - background-color: #7b7b7b; - } - } - &.online { - &:after { - border-color: #2c9210; - background-color: #35AC19; - } - } - &.away { - &:after { - border-color: #e69200; - background-color: #fcb316; - } - } - &.busy { - &:after { - border-color: #9f0030; - background-color: #D30230; - } - } - } - span.soon { - color: #aaa; - } - a { - color: rgba(255, 255, 255, 0.5); - border-bottom-color: darken(@primary-background-color, 2%); - &:hover { - background-color: darken(@primary-background-color, 2%); - color: rgba(255, 255, 255, 0.75); - } - } - } - &.active .info, - .info:hover { - h4 { - color: rgba(255, 255, 255, 0.85); - } - } - .hover & { - .info h4 { - color: rgba(255, 255, 255, 0.85); - } - } -} - -// rooms-box -.flex-nav { - //background-color: @primary-background-color; - background-color: transparent; - color: @tertiary-font-color; - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); - header { - background-color: @primary-background-color; - } - footer { - background-color: @primary-background-color; - } - .content { - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); - background-color: @primary-background-color; - } - .input-line { - input[type='text'], - input[type='password'], - select { - border-color: @tertiary-font-color; - background-color: #04436a; - color: @input-font-color; - } - - & label { - color:@input-font-color; - } - } - .selected-users { - li { - background-color: rgba(0, 0, 0, 0.1); - } - } -} - -.side-nav { - background-color: #F4F4F4; - color: #000; - &:before { - background-color: #dfdfdf; - } - .rooms-list { - background-color: lighten(@primary-background-color, 2%); - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); - } - .more { - color: @tertiary-font-color; - &:hover { - background-color: rgba(0, 0, 0, 0.1); - } - } - .input-error { - color: #f09286; - } - .empty { - color: @tertiary-font-color; - } - .header { - color: #fff; - background-color: @primary-background-color; - } - > .arrow { - &.hover, - &:hover { - &:before, - &:after { - background-color: rgba(255, 255, 255, 0.85); - } - } - } - .footer { - background: #fff; - background-color: @primary-background-color; - small { - color: @tertiary-font-color; - } - } - h3 { - color: @tertiary-font-color; - a { - color: inherit; - } - &:hover { - background-color: rgba(0, 0, 0, 0.1); - } - } - .unread { - background-color: #1dce73; - color: #FFF; - } - ul { - li { - .remove, - .erase { - color: #666; - } - &:hover { - .opt { - background-color: transparent; - } - } - &.active { - a { - background-color: rgba(255, 255, 255, 0.075); - color: rgba(255, 255, 255, 0.75); - } - .opt { - background-color: transparent; - } - } - &.has-alert { - .name { - color: #ffffff; - } - } - &.away { - a { - color: #666; - } - } - } - a { - color: @tertiary-font-color; - &:hover { - background-color: rgba(255, 255, 255, 0.05); - } - } - .opt { - background-color: transparent; - i { - color: rgba(255, 255, 255, 0.5); - &:hover { - color: rgba(255, 255, 255, 0.75); - } - } - } - i { - color: rgba(255, 255, 255, 0.35); - } - input[type=text] { - color: #000; - } - } -} - -.page-container { - .content { - .custom-scroll(transparent, #EAEAEA); - } -} - -.fixed-title { - background: #fff; - border-bottom-color: @tertiary-background-color; -} - -.cms-page { - color: #444; - background-color: @content-background-color; -} - -.spotlight { - background-color: rgba(0,0,0,.3); - > .spotlight-input { - color: #444; - > i { - color: #aaa; - } - } -} - -.mobile-message-menu { - background-color: rgba(0,0,0,.3); -} - -.page-static { - .content { - .section { - .section-content { - border-color: #ddd; - } - } - } -} - -.page-list { - .results { - border-bottom-color: #DFDFDF; - color: @secondary-font-color; - } - .list { - a { - color: @primary-font-color; - border-bottom-color: @secondary-background-color; - &:hover { - background-color: @secondary-background-color; - } - } - li { - color: @secondary-font-color; - &:after { - background-color: @secondary-font-color; - } - } - .info { - a { - color: @primary-font-color; - } - } - .status { - color: @secondary-font-color; - } - } -} - -.image-to-download { - background-color: #fafafa; - border-color: #ddd; - color: #aaa; -} - -.room-not-found { - color: orange; -} - -.upload-progress { - background-color: #b2d5c9; - color: @content-background-color; - .upload-progress-item { - border-bottom-color: #6a8179; - &:first-child { - border-top-color: #6a8179; - } - &.upload-error { - background-color: #FF6161; - border-color: #863737; - } - .upload-progress-progress { - background-color: #4c9789; - } - > a { - &:hover { - color: #eee; - } - } - } -} - -// change to page-messages -.messages-container { - .edit-room-title { - color: @secondary-font-color; - &:hover { - color: @primary-font-color; - } - } - .wrapper { - .custom-scroll(transparent, #EAEAEA); - } - .footer { - background: #FCFCFC; - border-top-color: @tertiary-background-color; - } - .message-popup { - background: #FAFAFA; - } - .message-popup-title { - background-color: @secondary-background-color; - border-bottom-color: #EEE; - } - .popup-item { - color: @secondary-font-color; - &.selected { - background-color: @tertiary-background-color; - color: @primary-font-color; - } - } - .popup-user-status { - border-color: rgba(0,0,0,.2); - } - .popup-user-status-system { - border-color: transparent; - } - .popup-user-status-offline { - background-color: @status-offline; - } - .popup-user-status-online { - background-color: @status-online; - } - .popup-user-status-away { - background-color: @status-away; - } - .popup-user-status-busy { - background-color: @status-busy; - } - .message-form { - > div { - > .file { - border-color: #E7E7E7; - color: #888; - background-color: #FCFCFC; - &:hover { - background-color: #F1F1F1; - color: #666; - } - } - > .mic, .stop-mic { - color: #888; - background-color: #FCFCFC; - &:hover { - background-color: #F1F1F1; - color: #666; - } - } - } - textarea { - &.editing { - background-color: #fff7d8; - } - } - .icon-paper-plane { - color: @secondary-font-color; - &:hover { - color: @primary-font-color; - } - } - .users-typing { - color: #888888; - background: #FCFCFC; - } - .formatting-tips { - color: #888888; - &:hover { - color: #444444; - } - q { - border-left-color: #ccc; - } - } - .editing-commands { - .editing-commands-cancel { - color: #888888; - } - .editing-commands-save { - color: #888888; - } - } - } -} - -.messages-box { - .load-more { - span { - border-color: #CCC; - background-color: #EEE; - } - } - .start { - color: @secondary-font-color; - } - .new-message { - background: #428bca; - color: #FFF; - } - .editing { - .body { - background-color: #fff7d8; - } - } -} - -.message { - &.new-day { - &:before { - color: @secondary-font-color; - background-color: @content-background-color; - } - &:after { - border-top-color: #ddd; - } - } - .user { - color: #444444; - &:hover { - color: #333; - } - } - .info { - color: @info-font-color; - } - &.system { - .body { - color: @info-font-color; - } - } - a { - color: @link-font-color; - &:hover { - color: darken(@link-font-color, 10%); - } - } -} - -// FLEX-TAB and FLEX-TAB views -.flex-tab { - background-color: @secondary-background-color; - border-left-color: @tertiary-background-color; - .control { - background-color: @secondary-background-color; - &:before { - background-color: @tertiary-background-color; - } - .more { - background-color: @tertiary-background-color; - border-bottom-color: @tertiary-background-color; - color: @secondary-font-color; - &:hover { - .arrow { - .arrow { - &:before, - &:after { - background-color: #4a4a4a; - } - } - } - } - .arrow { - &:before, - &:after { - background-color: #7a7a7a; - } - } - .flex-opened & { - background-color: @secondary-background-color; - &:hover { - .arrow { - &:before, - &:after { - background-color: #7a7a7a; - } - } - } - } - } - .search-form { - .icon-plus { - color: @secondary-font-color; - } - } - .info-tabs { - a { - color: inherit; - border-left-color: rgb(234, 234, 234); - &.active { - background-color: #F4F4F4; - } - &:last-child { - border-right-color: rgb(234, 234, 234); - } - } - } - } - .content { - .custom-scroll(transparent, #DADADA); - } -} - -.list-view { - > .status { - p { - color: @secondary-font-color; - } - .see-all { - color: @secondary-font-color; - background-color: transparent; - } - } -} - -.user-view { - .info { - h3 { - i.status-offline { - &:after { - border-color: darken(@status-offline, 5%); - background-color: @status-offline; - } - } - i.status-online { - &:after { - border-color: darken(@status-online, 5%); - background-color: @status-online; - } - } - i.status-away { - &:after { - border-color: darken(@status-away, 5%); - background-color: @status-away; - } - } - i.status-busy { - &:after { - border-color: darken(@status-busy, 5%); - background-color: @status-busy; - } - } - } - p { - color: @secondary-font-color; - } - } - .stats { - li { - background-color: #e9e9e9; - } - } - .box { - h4 { - } - &:after { - background-color: #CDCDCD; - } - } - .tags { - li { - background-color: #CDCDCD; - } - } - .links { - a { - color: #6f6f6f; - &:hover { - background-color: #e9e9e9; - color: #333; - } - } - } - .channels { - p { - color: @secondary-font-color; - } - a { - color: #6f6f6f; - } - } - .edit-form { - p { - color: @secondary-font-color; - } - } -} - -.user-image-status(@color) { - .avatar { - &:after { - background-color: darken(@color, 5%); - } - } -} - -.user-image { - background-color: @tertiary-background-color; - &:hover, - &.selected { - .avatar { - &:after { - } - .status-offline { - &:after { - background-color: @status-offline; - } - } - .status-online { - &:after { - background-color: @status-online; - } - } - .status-away { - &:after { - background-color: @status-away; - } - } - .status-busy { - &:after { - background-color: @status-busy; - } - } - p { - color: @primary-font-color; - } - } - } - .lines & { - background-color: transparent; - a { - background-color: transparent; - } - p { - color: @secondary-font-color; - } - } - &.status-offline { - .user-image-status(@status-offline); - } - &.status-online { - .user-image-status(@status-online); - } - &.status-away { - .user-image-status(@status-away); - } - &.status-busy { - .user-image-status(@status-busy); - } -} - -.user-profile { - .info { - a { - color: @primary-font-color; - &:hover { - color: @secondary-font-color; - } - } - } -} - -.rocket-modal { - background-color: rgba(0, 0, 0, 0.5); - &.fluid { - .modal { - main { - .custom-scroll(transparent, #CFCFCF); - } - } - } - legend { - color: @secondary-font-color; - &:before { - background-color: #dfdfdf; - } - } - .modal { - background-color: @content-background-color; - header { - background-color: #DADADA; - .close { - i { - color: @secondary-font-color; - } - &:hover { - i { - color: @primary-font-color; - } - } - } - } - main { - background-color: @content-background-color; - } - footer { - background-color: #eaeaea; - } - } -} - -#login-card { - background-color: #FAFAFA; - h2 { - color: @primary-font-color; - &.error { - color: #b40202; - } - } - h3 { - &.error { - color: #b40202; - } - } - a { - color: @primary-background-color; - &:active { - color: @primary-background-color; - } - &:hover { - color: darken(@primary-background-color, 10%); - } - } - .input-text { - input { - background-color: transparent; - border-bottom-color: #DFDFDF; - &.error { - border-bottom-color: #b40202; - &::-webkit-input-placeholder { - color: #b40202; - } - &:-moz-placeholder { - color: #b40202; - } - /* Firefox 18- */ - &::-moz-placeholder { - color: #b40202; - } - /* Firefox 19+ */ - &:-ms-input-placeholder { - color: #b40202; - } - } - } - input:-webkit-autofill { - color: @content-background-color !important; - } - input:-webkit-autofill { - background-color: transparent !important; - } - } -} - -.full-page { - background-color: darken(@primary-background-color, 10%); - .background-image(linear-gradient(darken(@primary-background-color,10%),@primary-background-color)); - .text { - color: #FFF; - .button { - background-color: #bc2031; - color: #FFF; - } - } - footer { - color: #fff; - div.switch-language { - a { - color: @secondary-font-color; - } - } - } -} - -.avatar-suggestion-item { - background-color: @secondary-background-color; - border-color: darken(@secondary-background-color, 10%); - .avatar { - background-size: cover; - background-color: @tertiary-background-color; - } - .question-mark { - &::before { - color: darken(@tertiary-background-color, 10%); - } - } -} - -.statistics-table { - border-color: #F9F9F9; -} - -@media all and(max-width: 780px) { - #rocket-chat { - .main-content { - background-color: @content-background-color; - } - } -} - -.dropzone { - &.over .dropzone-overlay { - background-color: rgba(0, 0, 0, 0.5); - color: @content-background-color; - > div { - background-color: rgba(0, 0, 0, 0.6); - } - } -} - -.is-cordova { - .flex-tab { - button.more { - background-color: #fff; - } - } -} diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index abc3707550c..f88cdc92056 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1954,47 +1954,29 @@ a.github-fork { } } -.unread-bar { +.container-bars { position: absolute; top: 60px; width: 100%; z-index: 11; font-weight: bold; - background-color: #E6F4FD; - line-height: 30px; - font-size: 12px; - padding: 0 10px; - box-shadow: 0px 1px 2px rgba(0,0,0,.2); - color: #068FE4; - text-transform: uppercase; - text-align: center; + display: flex; + flex-direction: column; - > a { - float: right; + > div { + height: 24px; + line-height: 24px; + padding: 0 10px; + border-top: 1px solid; - &:hover { - cursor: pointer; + &:last-child { + box-shadow: 0px 1px 2px rgba(0,0,0,.2); } } -} - -.upload-progress { - position: absolute; - top: 60px; - width: 100%; - z-index: 11; - font-weight: bold; - text-shadow: 1px 1px 0px rgba(0,0,0,.2); - .upload-progress-item { + .upload-progress { position: relative; - line-height: 24px; - padding: 0 10px; - border-bottom: 1px solid; - - &:first-child { - border-top: 1px solid; - } + text-shadow: 1px 1px 0px rgba(0,0,0,.2); &.upload-error { } @@ -2004,13 +1986,41 @@ a.github-fork { left: 0px; height: 100%; width: 0%; - z-index: -1; + z-index: 1; .transition(width, 1s, ease-out); } + .upload-progress-text { + padding: 0 10px; + position: absolute; + left: 0px; + right: 0px; + height: 100%; + z-index: 2; + + > a { + float: right; + text-transform: uppercase; + + &:hover { + cursor: pointer; + } + } + } + } + + .unread-bar { + background-color: #E6F4FD; + // line-height: 30px; + // font-size: 12px; + // padding: 0 10px; + // box-shadow: 0px 1px 2px rgba(0,0,0,.2); + color: #068FE4; + text-transform: uppercase; + text-align: center; + > a { float: right; - text-transform: uppercase; &:hover { cursor: pointer; @@ -2505,8 +2515,8 @@ a.github-fork { .info { position: absolute; text-align: right; - left: 0px; - width: 65px; + left: 5px; + width: 60px; .time { display: none; } diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index c66bdd76446..fd0c6738edc 100644 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -643,14 +643,15 @@ a.github-fork { color: orange; } -.upload-progress { - background-color: #b2d5c9; - color: @content-background-color; - .upload-progress-item { - border-bottom-color: #6a8179; - &:first-child { - border-top-color: #6a8179; - } +.container-bars { + >div { + border-color: #ffffff; + } + + .upload-progress { + background-color: #b2d5c9; + color: @content-background-color; + &.upload-error { background-color: #FF6161; border-color: #863737; @@ -664,6 +665,11 @@ a.github-fork { } } } + + .unread-bar { + background-color: #E6F4FD; + color: #068FE4; + } } // change to page-messages -- GitLab From 148ad7b4e69a85c86a34aaa4b2622041474e6be5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 17:16:04 -0300 Subject: [PATCH 0099/1338] Add auto prefixer --- .../.npm/package/npm-shrinkwrap.json | 38 +++++++++++++++++++ packages/rocketchat-theme/package.js | 3 +- .../rocketchat-theme/server/server.coffee | 4 ++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-theme/.npm/package/npm-shrinkwrap.json index 69c24b72239..643dd048cb6 100644 --- a/packages/rocketchat-theme/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-theme/.npm/package/npm-shrinkwrap.json @@ -237,6 +237,44 @@ } } } + }, + "less-plugin-autoprefix": { + "version": "1.4.2", + "dependencies": { + "autoprefixer-core": { + "version": "5.2.1", + "dependencies": { + "browserslist": { + "version": "0.4.0" + }, + "num2fraction": { + "version": "1.2.2" + }, + "caniuse-db": { + "version": "1.0.30000342" + } + } + }, + "postcss": { + "version": "4.1.16", + "dependencies": { + "es6-promise": { + "version": "2.3.0" + }, + "source-map": { + "version": "0.4.4", + "dependencies": { + "amdefine": { + "version": "1.0.0" + } + } + }, + "js-base64": { + "version": "2.1.9" + } + } + } + } } } } diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 2e58113125d..4ad9da6e4bf 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -40,7 +40,8 @@ Package.onUse(function(api) { }); Npm.depends({ - 'less': 'https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6' + 'less': 'https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6', + 'less-plugin-autoprefix': '1.4.2' }); Package.onTest(function(api) { diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 6d8ed70d8cb..8f185f6ed74 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -1,4 +1,5 @@ less = Npm.require('less') +autoprefixer = Npm.require('less-plugin-autoprefix') RocketChat.theme = new class variables: {} @@ -46,6 +47,9 @@ RocketChat.theme = new class options = compress: true + plugins: [ + new autoprefixer() + ] start = Date.now() less.render content, options, (err, data) -> -- GitLab From 99c2111dc7b4f3251bda2b6ac1558629bd948e46 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 14 Oct 2015 16:00:49 -0500 Subject: [PATCH 0100/1338] Move access key to env var Fix for easier update. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2aaa397bb99..86e96a11207 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,10 +29,10 @@ after_deploy: deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" + secret_access_key: $ACCESSKEY bucket: "rocketchatbuild" skip_cleanup: true local_dir: ../build on: branch: master - secret_access_key: - secure: LYA2XNdpHBTN/zs/71VWLr81b3Gb290PRIqQER72SZ3eQjDk0UpUUFkzK6mc6GkelXyqHRBRckmhBzVCEAO6KNIU9JHc9aUxyUbSt7OMTAZUZ8X36E7HL6mXN73YHtUCbEczD41aXMK+HQ9ol0EXfvbprp5gFwqT908dSVleNJCN6wZgW5ZJVzWTiC2/aaGqCrWhAWybG1XwCgl8ND8N3qFsNBZ6MDN3rpp9kVdDJ3vzp5Azkf6QrTFQTo2ai3DFFnRf7J84/8tpRL3tVcPwjik449KEkJlCPotxt7XxUTg9HrN5LQY4wYTKyKhoYxzADwse8VaU/oFhVef3A8AiLpfg8rR63ahs5ZOqJc926eiZWGumLfvcGkHD2kb+z+l9bIE8b2X7mct6gK4ub0E6Ul/NOoh1ZgppVzP3PuYZXGb2CNvZTrrSjH9dGWPWlRjZaErg4bs4BC6y6eGjgu1CqFa1eqLFO/oYdmX5c4kDskyNf0VSVVXmqLqQBWrkOGSr3Z8nR8XQ1PDQfmj8ZMmDRtvt58DuOVzOBkC71Mc/Kr/cKS0cXedwzzNg2BG4EHMsc1eTn6JWs95NFCbPbI5HzxYODumZwOwSJyXKiDgUhPmRc6I1MvgJqIIBGWFqIIGEfR715E4zaJzAYvTPWvL+8aBMfZxdQouRYH7d9kREc6U= + -- GitLab From a9d36f15b66570bda1a9550d03edcc6fe6483e7b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Wed, 14 Oct 2015 17:01:54 -0500 Subject: [PATCH 0101/1338] fix typo in build.sh --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f9bdc2f451e..873219ffc2e 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash cd /var/www/rocket.chat -https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz +curl -fSL "https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz tar zxvf rocket.chat.tgz && rm rocket.chat.tgz cd /var/www/rocket.chat/bundle/programs/server npm install -- GitLab From ccd35b936476c0d29c1f85d34e2cc1144dca5fd2 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 19:03:51 -0300 Subject: [PATCH 0102/1338] Fix indentations of setbuildinfo.js --- .travis/setbuildinfo.js | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index 221e7a3b415..7a2ab9d066f 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -2,43 +2,38 @@ var BUILD_INFO_PATH = '../public/buildinfo/buildinfo.txt'; var PACKAGES_PATH = '../.meteor/packages'; var BUILD_PATH = '../../build'; var LineByLineReader = require('line-by-line'), - mkdirp = require('mkdirp'), - fs = require('fs'), - lr = new LineByLineReader(BUILD_INFO_PATH); +var mkdirp = require('mkdirp'); +var fs = require('fs'); +var lr = new LineByLineReader(BUILD_INFO_PATH); var firstline = ""; - if (process.env.TRAVIS_BUILD_NUMBER) { - var transformVersion = function (firstline) { - var versions = firstline.split("."); + var versions = firstline.split("."); - return versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BUILD_NUMBER + '\n'; + return versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BUILD_NUMBER + '\n'; }; lr.on('error', function (err) { - // 'err' contains error object + // 'err' contains error object }); lr.on('line', function (line) { - if (firstline == "") - firstline = line; - + if (firstline == "") { + firstline = line; + } }); lr.on('end', function () { - - var packages = fs.readFileSync(PACKAGES_PATH); - var verinfo = transformVersion(firstline); - var content = verinfo + packages; - mkdirp.sync(BUILD_PATH); - fs.writeFileSync(BUILD_PATH + "/version.txt", verinfo); - fs.writeFileSync(BUILD_INFO_PATH, content); - console.log('Version is ' + verinfo); - + var packages = fs.readFileSync(PACKAGES_PATH); + var verinfo = transformVersion(firstline); + var content = verinfo + packages; + mkdirp.sync(BUILD_PATH); + fs.writeFileSync(BUILD_PATH + "/version.txt", verinfo); + fs.writeFileSync(BUILD_INFO_PATH, content); + console.log('Version is ' + verinfo); }); - } -- GitLab From 79c8e7a83d8e9e8c760b7ec8867ef1099423c017 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 14 Oct 2015 19:07:24 -0300 Subject: [PATCH 0103/1338] Added application tests --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 592be5d6f8d..b26209f6966 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,11 @@ before_install: - npm install velocity-cli - export PHANTOMJS_BIN=./node_modules/phantomjs/bin/phantomjs - export JASMINE_BROWSER=PhantomJS +- export DEBUG=1 +- export JASMINE_DEBUG=1 +- export VELOCITY_DEBUG=1 +- export VELOCITY_DEBUG_MIRROR=1 + script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - cd .travis @@ -28,7 +33,7 @@ script: - meteor add sanjo:jasmine@0.20.2 velocity:console-reporter - ./node_modules/velocity-cli/bin/velocity test-packages --ci - ./node_modules/velocity-cli/bin/velocity test-app --ci -- meteor build --server demo.rocket.chat ./ +- meteor --test --once - meteor build --server demo.rocket.chat ../build - cd .travis - sh ./namedemo.sh -- GitLab From 649bfb0a9fb3b1178266211f2f4f2f5bf3edda58 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 19:27:18 -0300 Subject: [PATCH 0104/1338] Update build.sh to allow build for development --- build.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index 873219ffc2e..49d2ef11d07 100755 --- a/build.sh +++ b/build.sh @@ -1,8 +1,14 @@ #!/bin/bash -cd /var/www/rocket.chat + +ROOTPATH=/var/www/rocket.chat +PM2FILE=pm2.json +if [ $1="development" ]; then + ROOTPATH=/var/www/rocket.chat.dev + PM2FILE=pm2.dev.json + +cd $ROOTPATH curl -fSL "https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz tar zxvf rocket.chat.tgz && rm rocket.chat.tgz -cd /var/www/rocket.chat/bundle/programs/server +cd $ROOTPATH/bundle/programs/server npm install -cd /var/www/rocket.chat/current -pm2 startOrRestart /var/www/rocket.chat/current/pm2.json +pm2 startOrRestart $ROOTPATH/current/$PM2JSON -- GitLab From 8ba8ddf12b7dbde3680e4fd3083f7dd8aeb569a3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 19:34:26 -0300 Subject: [PATCH 0105/1338] Fix buid.sh --- build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sh b/build.sh index 49d2ef11d07..fe9f39d9a8e 100755 --- a/build.sh +++ b/build.sh @@ -5,6 +5,7 @@ PM2FILE=pm2.json if [ $1="development" ]; then ROOTPATH=/var/www/rocket.chat.dev PM2FILE=pm2.dev.json +fi cd $ROOTPATH curl -fSL "https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz -- GitLab From 861c9a15e082bed58adf3362382ba8b568ee12fe Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 19:37:57 -0300 Subject: [PATCH 0106/1338] Fix typo --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index fe9f39d9a8e..8925f4c745c 100755 --- a/build.sh +++ b/build.sh @@ -12,4 +12,4 @@ curl -fSL "https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tg tar zxvf rocket.chat.tgz && rm rocket.chat.tgz cd $ROOTPATH/bundle/programs/server npm install -pm2 startOrRestart $ROOTPATH/current/$PM2JSON +pm2 startOrRestart $ROOTPATH/current/$PM2FILE -- GitLab From ed2d60c339c95bdc6a848980c4102916cb10a1da Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 14 Oct 2015 20:26:52 -0300 Subject: [PATCH 0107/1338] Fix build.sh again --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 8925f4c745c..ebaad4d327c 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ ROOTPATH=/var/www/rocket.chat PM2FILE=pm2.json -if [ $1="development" ]; then +if [ "$1" == "development" ]; then ROOTPATH=/var/www/rocket.chat.dev PM2FILE=pm2.dev.json fi -- GitLab From a56e7b85ba767d7cfc41509ee006125c53515421 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Wed, 14 Oct 2015 18:57:42 -0500 Subject: [PATCH 0108/1338] fix bug introduced during reformat --- .travis/setbuildinfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index 7a2ab9d066f..00229e2247b 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -1,7 +1,7 @@ var BUILD_INFO_PATH = '../public/buildinfo/buildinfo.txt'; var PACKAGES_PATH = '../.meteor/packages'; var BUILD_PATH = '../../build'; -var LineByLineReader = require('line-by-line'), +var LineByLineReader = require('line-by-line'); var mkdirp = require('mkdirp'); var fs = require('fs'); var lr = new LineByLineReader(BUILD_INFO_PATH); -- GitLab From 9e0634339b48f70990dc792539d989cec091579a Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Wed, 14 Oct 2015 22:48:40 -0500 Subject: [PATCH 0109/1338] add demo drones fleet management chat-ops panel --- .../rocketchat-chatops/client/startup.coffee | 3 +++ .../rocketchat-chatops/client/tabBar.coffee | 2 +- .../client/views/droneflight.coffee | 18 ++++++++++++++++++ .../client/views/droneflight.html | 19 +++++++++++++++++++ .../client/views/stylesheets/chatops.css | 15 +++++++++++++++ packages/rocketchat-chatops/package.js | 6 +++++- 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-chatops/client/startup.coffee create mode 100644 packages/rocketchat-chatops/client/views/droneflight.coffee create mode 100644 packages/rocketchat-chatops/client/views/droneflight.html diff --git a/packages/rocketchat-chatops/client/startup.coffee b/packages/rocketchat-chatops/client/startup.coffee new file mode 100644 index 00000000000..7cf93fd6620 --- /dev/null +++ b/packages/rocketchat-chatops/client/startup.coffee @@ -0,0 +1,3 @@ +Meteor.startup -> + console.log('startup hooked') + GoogleMaps.load() diff --git a/packages/rocketchat-chatops/client/tabBar.coffee b/packages/rocketchat-chatops/client/tabBar.coffee index bf60db99174..5daff0a8915 100644 --- a/packages/rocketchat-chatops/client/tabBar.coffee +++ b/packages/rocketchat-chatops/client/tabBar.coffee @@ -24,7 +24,7 @@ Meteor.startup -> id: 'chatops-button3' i18nTitle: 'rocketchat-chatops:Chatops_Title' icon: 'octicon octicon-inbox' - template: 'chatops_codemirror' + template: 'chatops_droneflight' width: 675 order: 5 , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-chatops' diff --git a/packages/rocketchat-chatops/client/views/droneflight.coffee b/packages/rocketchat-chatops/client/views/droneflight.coffee new file mode 100644 index 00000000000..de3c9feb04e --- /dev/null +++ b/packages/rocketchat-chatops/client/views/droneflight.coffee @@ -0,0 +1,18 @@ + +Template.chatops_droneflight.helpers + flightMapOptions: -> + if GoogleMaps.loaded() + console.log('helper run') + return {center: new google.maps.LatLng(35.6609285,-78.8456125), zoom: 17} + + +Template.chatops_droneflight.onCreated () -> + GoogleMaps.ready 'flightMap', (map) -> + console.log('ready') + redicon = { path: google.maps.SymbolPath.CIRCLE, fillColor: "red", fillOpacity: 0.8, strokeColor: "gold", strokeWeight: 2, scale: 10} + greenicon = {path: google.maps.SymbolPath.CIRCLE, fillColor: "green", fillOpacity: 0.8, strokeColor: "gold", strokeWeight: 2, scale: 10} + + marker = new google.maps.Marker({position: new google.maps.LatLng(35.661848,-78.843165), icon: redicon, map: map.instance}) + marker.setLabel('1') + marker2 = new google.maps.Marker({position: new google.maps.LatLng(35.660537,-78.846959), icon: greenicon, map: map.instance}) + marker2.setLabel('2') diff --git a/packages/rocketchat-chatops/client/views/droneflight.html b/packages/rocketchat-chatops/client/views/droneflight.html new file mode 100644 index 00000000000..9f6957ef90f --- /dev/null +++ b/packages/rocketchat-chatops/client/views/droneflight.html @@ -0,0 +1,19 @@ +<template name="chatops_droneflight"> + <div class="control"> + <div> <b>Drone 1:</b> mission <b>A3</b> waypoint <b>7</b> <span class="red">fuel 30%</span> </div> + <div> <b>Drone 2:</b> mission <b>A7</b> waypoint <b>2</b> <span class="green">fuel 100%</span> </div> + </div> + + <div class="content"> + <div class="map-container"> + {{> googleMap name="flightMap" options=flightMapOptions }} + </div> + + <div class="droneFlight"> + <button class='button'><span> {{_ "Return to base"}}</span></button> + <button class='button'><span> {{_ "Cancel"}}</span></button> + </div> + + </div> + +</template> diff --git a/packages/rocketchat-chatops/client/views/stylesheets/chatops.css b/packages/rocketchat-chatops/client/views/stylesheets/chatops.css index e69de29bb2d..5c439017ffa 100644 --- a/packages/rocketchat-chatops/client/views/stylesheets/chatops.css +++ b/packages/rocketchat-chatops/client/views/stylesheets/chatops.css @@ -0,0 +1,15 @@ + +.map-container { + width: 670px; + max-width: 100%; + height: 500px; + padding: 5px, 5px, 5px 5px; +} + +.red { + color: red; +} + +.green { + color: green; +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/package.js b/packages/rocketchat-chatops/package.js index 0afb8a9fc1e..2b8585bce63 100644 --- a/packages/rocketchat-chatops/package.js +++ b/packages/rocketchat-chatops/package.js @@ -10,7 +10,8 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib@0.0.1', + 'dburles:google-maps@1.1.5' ]); // TAPi18n @@ -27,11 +28,14 @@ Package.onUse(function(api) { api.addFiles("package-tap.i18n", ["client", "server"]); api.addFiles([ + 'client/startup.coffee', 'client/tabBar.coffee', 'client/views/chatops.html', 'client/views/chatops.coffee', 'client/views/codemirror.html', 'client/views/codemirror.coffee', + 'client/views/droneflight.html', + 'client/views/droneflight.coffee', 'client/views/dynamicUI.html', 'client/views/stylesheets/chatops.css', ], 'client'); -- GitLab From 48f6e32c23f75b43ae1c31a190f88e131c0aeed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= <theess@subshell.com> Date: Thu, 15 Oct 2015 17:42:44 +0200 Subject: [PATCH 0110/1338] Notifications are more consistent (#1068). - HTML notifications are shown when the user has selected the room of the message but the chat window does not have the focus. - HTML notification and new message sound use the same condition. - The unread count is always updated if the chat window does not have the focus. --- client/notifications/notification.coffee | 22 +++++++++++++++-- client/startup/unread.coffee | 31 ++++++++++++------------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/client/notifications/notification.coffee b/client/notifications/notification.coffee index 2bb8c584fc2..42b4bfce67a 100644 --- a/client/notifications/notification.coffee +++ b/client/notifications/notification.coffee @@ -1,3 +1,21 @@ +# Show notifications and play a sound for new messages. +# We trust the server to only send notifications for interesting messages, e.g. direct messages or +# group messages in which the user is mentioned. + Meteor.startup -> - RocketChat.Notifications.onUser 'notification', (data) -> - KonchatNotification.showDesktop data + RocketChat.Notifications.onUser 'notification', (notification) -> + + openedRoomId = undefined + if FlowRouter.getRouteName() in ['channel', 'group', 'direct'] + openedRoomId = Session.get 'openedRoom' + + # This logic is duplicated in /client/startup/unread.coffee. + hasFocus = readMessage.isEnable() + messageIsInOpenedRoom = openedRoomId is notification.payload.rid + + if !(hasFocus and messageIsInOpenedRoom) + # Play a sound. + KonchatNotification.newMessage() + + # Show a notification. + KonchatNotification.showDesktop notification diff --git a/client/startup/unread.coffee b/client/startup/unread.coffee index fd302b6e5ed..8b251305ab0 100644 --- a/client/startup/unread.coffee +++ b/client/startup/unread.coffee @@ -1,10 +1,3 @@ -Meteor.startup -> - - ChatSubscription.find({}, { fields: { unread: 1 } }).observeChanges - changed: (id, fields) -> - if fields.unread and fields.unread > 0 - KonchatNotification.newMessage() - Meteor.startup -> Tracker.autorun -> @@ -14,18 +7,26 @@ Meteor.startup -> subscriptions = ChatSubscription.find({open: true}, { fields: { unread: 1, alert: 1, rid: 1, t: 1, name: 1, ls: 1 } }) - rid = undefined + openedRoomId = undefined Tracker.nonreactive -> if FlowRouter.getRouteName() in ['channel', 'group', 'direct'] - rid = Session.get 'openedRoom' + openedRoomId = Session.get 'openedRoom' for subscription in subscriptions.fetch() - if subscription.rid is rid and (subscription.alert or subscription.unread > 0) - readMessage.readNow() - else - unreadCount += subscription.unread - if subscription.alert is true - unreadAlert = '•' + + if subscription.alert or subscription.unread > 0 + # This logic is duplicated in /client/notifications/notification.coffee. + hasFocus = readMessage.isEnable() + subscriptionIsTheOpenedRoom = openedRoomId is subscription.rid + if hasFocus and subscriptionIsTheOpenedRoom + # The user has probably read all messages in this room. + # TODO: readNow() should return whether it has actually marked the room as read. + readMessage.readNow() + else + # Increment the total unread count. + unreadCount += subscription.unread + if subscription.alert is true + unreadAlert = '•' readMessage.refreshUnreadMark(subscription.rid) -- GitLab From b9a06916480a651448e2f0176ada68fdb2527a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= <theess@subshell.com> Date: Thu, 15 Oct 2015 17:51:05 +0200 Subject: [PATCH 0111/1338] For @all, send notifications to all room users. --- .../rocketchat-lib/server/sendMessage.coffee | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-lib/server/sendMessage.coffee b/packages/rocketchat-lib/server/sendMessage.coffee index a60a2aab43f..ab2ed7d2fe4 100644 --- a/packages/rocketchat-lib/server/sendMessage.coffee +++ b/packages/rocketchat-lib/server/sendMessage.coffee @@ -82,10 +82,13 @@ RocketChat.sendMessage = (user, message, room, options) -> message.mentions?.forEach (mention) -> mentionIds.push mention._id + # @all? + toAll = mentionIds.indexOf('all') > -1 + if mentionIds.length > 0 usersOfMention = Meteor.users.find({_id: {$in: mentionIds}}, {fields: {_id: 1, username: 1}}).fetch() - if room.t is 'c' and mentionIds.indexOf('all') is -1 + if room.t is 'c' and !toAll for usersOfMentionItem in usersOfMention if room.usernames.indexOf(usersOfMentionItem.username) is -1 Meteor.runAsUser usersOfMentionItem._id, -> @@ -95,7 +98,7 @@ RocketChat.sendMessage = (user, message, room, options) -> Update all other subscriptions of mentioned users to alert their owners and incrementing the unread counter for mentions and direct messages ### - if mentionIds.indexOf('all') > -1 + if toAll # all users except sender if mention is for all RocketChat.models.Subscriptions.incUnreadForRoomIdExcludingUserId message.rid, user._id, 1 else @@ -105,7 +108,7 @@ RocketChat.sendMessage = (user, message, room, options) -> query = statusConnection: {$ne: 'online'} - if mentionIds.indexOf('all') > -1 + if toAll if room.usernames?.length > 0 query.username = $in: room.usernames @@ -116,9 +119,20 @@ RocketChat.sendMessage = (user, message, room, options) -> query._id = $in: mentionIds - usersOfMentionIds = _.pluck(usersOfMention, '_id'); - if usersOfMentionIds.length > 0 - for usersOfMentionId in usersOfMentionIds + userIdsToNotify = _.pluck(usersOfMention, '_id') + + # If the message is @all, send a notification to all online room users except for the sender. + if toAll and room.usernames?.length > 0 + onlineUsersOfRoom = Meteor.users.find({ + username: {$in: room.usernames}, + _id: {$ne: user._id} + status: {$in: ['online', 'away', 'busy']}}, + {fields: {_id: 1, username: 1}}) + .fetch() + userIdsToNotify = _.union userIdsToNotify, _.pluck(onlineUsersOfRoom, '_id') + + if userIdsToNotify.length > 0 + for usersOfMentionId in userIdsToNotify RocketChat.Notifications.notifyUser usersOfMentionId, 'notification', title: "@#{user.username} @ ##{room.name}" text: message.msg @@ -143,7 +157,7 @@ RocketChat.sendMessage = (user, message, room, options) -> type: room.t name: room.name query: - userId: $in: usersOfMentionIds + userId: $in: userIdsToNotify ### Update all other subscriptions to alert their owners but witout incrementing -- GitLab From d0f48c4ee14631470a7bda80761f571f53249363 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Thu, 15 Oct 2015 13:32:38 -0400 Subject: [PATCH 0112/1338] Switch docker build to rocketchat repository Switch docker automated build from singli/rocket.chat to rocketchat/rocket.chat --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 86e96a11207..67f3040ae2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ script: - sh ./namedemo.sh - cd .. after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/singli/rocket.chat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" -- GitLab From 453175925f0e93e4b58c96e3c2d8b196d283d8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= <jens@theess.de> Date: Thu, 15 Oct 2015 22:26:03 +0200 Subject: [PATCH 0113/1338] Use RocketChat.models.Users. --- packages/rocketchat-lib/server/sendMessage.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-lib/server/sendMessage.coffee b/packages/rocketchat-lib/server/sendMessage.coffee index ab2ed7d2fe4..a2e0bc5fad9 100644 --- a/packages/rocketchat-lib/server/sendMessage.coffee +++ b/packages/rocketchat-lib/server/sendMessage.coffee @@ -49,7 +49,7 @@ RocketChat.sendMessage = (user, message, room, options) -> ### RocketChat.models.Subscriptions.incUnreadOfDirectForRoomIdExcludingUserId message.rid, message.u._id, 1 - userOfMention = Meteor.users.findOne({_id: message.rid.replace(message.u._id, '')}, {fields: {username: 1, statusConnection: 1}}) + userOfMention = RocketChat.models.Users.findOne({_id: message.rid.replace(message.u._id, '')}, {fields: {username: 1, statusConnection: 1}}) if userOfMention? RocketChat.Notifications.notifyUser userOfMention._id, 'notification', title: "@#{user.username}" @@ -86,7 +86,7 @@ RocketChat.sendMessage = (user, message, room, options) -> toAll = mentionIds.indexOf('all') > -1 if mentionIds.length > 0 - usersOfMention = Meteor.users.find({_id: {$in: mentionIds}}, {fields: {_id: 1, username: 1}}).fetch() + usersOfMention = RocketChat.models.Users.find({_id: {$in: mentionIds}}, {fields: {_id: 1, username: 1}}).fetch() if room.t is 'c' and !toAll for usersOfMentionItem in usersOfMention @@ -123,7 +123,7 @@ RocketChat.sendMessage = (user, message, room, options) -> # If the message is @all, send a notification to all online room users except for the sender. if toAll and room.usernames?.length > 0 - onlineUsersOfRoom = Meteor.users.find({ + onlineUsersOfRoom = RocketChat.models.Users.find({ username: {$in: room.usernames}, _id: {$ne: user._id} status: {$in: ['online', 'away', 'busy']}}, -- GitLab From 47cba8b002262993d3f63f95832c7c009a3a3687 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 15 Oct 2015 19:25:25 -0300 Subject: [PATCH 0114/1338] Improve theme --- client/views/main.html | 1 - .../rocketchat-theme/client/client.coffee | 15 --- packages/rocketchat-theme/package.js | 1 - .../rocketchat-theme/server/server.coffee | 99 +++++++++++++++++-- public/theme.css | 1 + 5 files changed, 91 insertions(+), 26 deletions(-) delete mode 100644 packages/rocketchat-theme/client/client.coffee create mode 100644 public/theme.css diff --git a/client/views/main.html b/client/views/main.html index 330a506edc9..9eab99a5bec 100644 --- a/client/views/main.html +++ b/client/views/main.html @@ -34,7 +34,6 @@ <link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-touch-icon-144x144.png?v=3"> <link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-touch-icon-152x152.png?v=3"> <link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png?v=3"> - <link rel="stylesheet" type="text/css" href="/theme.css" id="theme"> </head> <body> diff --git a/packages/rocketchat-theme/client/client.coffee b/packages/rocketchat-theme/client/client.coffee deleted file mode 100644 index 4e888843ddb..00000000000 --- a/packages/rocketchat-theme/client/client.coffee +++ /dev/null @@ -1,15 +0,0 @@ -updateTheme = -> - el = $('#theme')[0] - if el - el.href = el.href.replace(/\?.*$/, '') + '?_dc=' + Random.id() - -Meteor.startup -> - connected = Meteor.status().connected - Tracker.autorun -> - if connected is false and Meteor.status().connected is true - updateTheme() - - connected = Meteor.status().connected - - RocketChat.Notifications.onAll 'theme-updated', -> - updateTheme() diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 2e58113125d..7bff8629a20 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -17,7 +17,6 @@ Package.onUse(function(api) { api.addFiles('server/server.coffee', 'server'); api.addFiles('server/variables.coffee', 'server'); - api.addFiles('client/client.coffee', 'client'); api.addFiles('client/minicolors/jquery.minicolors.css', 'client'); api.addFiles('client/minicolors/jquery.minicolors.js', 'client'); diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 6d8ed70d8cb..624931e0945 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -1,4 +1,18 @@ less = Npm.require('less') +crypto = Npm.require('crypto') + +# program = WebApp.clientPrograms['web.browser'] +# themeManifestItem = _.find program.manifest, (item) -> return item.url is '/theme.css' +# themeManifestItem.where = 'client' +# themeManifestItem.type = 'css' + +ClientVersions = undefined +_defineMutationMethods = Meteor.Collection.prototype._defineMutationMethods +Meteor.Collection.prototype._defineMutationMethods = -> + if this._name is 'meteor_autoupdate_clientVersions' + ClientVersions = this + + _defineMutationMethods.call this RocketChat.theme = new class variables: {} @@ -55,7 +69,74 @@ RocketChat.theme = new class RocketChat.settings.updateById 'css', data.css - RocketChat.Notifications.notifyAll 'theme-updated' + WebAppInternals.staticFiles['/__cordova/theme.css'] = WebAppInternals.staticFiles['/theme.css'] = + cacheable: true + sourceMapUrl: undefined + type: 'css' + content: data.css + + hash = crypto.createHash('sha1').update(data.css).digest('hex') + + program = WebApp.clientPrograms['web.cordova'] + themeManifestItem = _.find program.manifest, (item) -> return item.path is 'app/theme.css' + themeManifestItem.type = 'css' + themeManifestItem.where = 'client' + themeManifestItem.url = "/theme.css?#{hash}" + themeManifestItem.size = data.css.length + themeManifestItem.hash = hash + program.version = WebApp.calculateClientHashCordova() + + program = WebApp.clientPrograms['web.browser'] + themeManifestItem = _.find program.manifest, (item) -> return item.path is 'app/theme.css' + themeManifestItem.type = 'css' + themeManifestItem.where = 'client' + themeManifestItem.url = "/theme.css?#{hash}" + themeManifestItem.size = data.css.length + themeManifestItem.hash = hash + program.version = WebApp.calculateClientHashRefreshable() + + Autoupdate.autoupdateVersion = __meteor_runtime_config__.autoupdateVersion = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashNonRefreshable() + Autoupdate.autoupdateVersionRefreshable = __meteor_runtime_config__.autoupdateVersionRefreshable = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashRefreshable() + Autoupdate.autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashCordova() + + # reloadClientPrograms = WebAppInternals.reloadClientPrograms + # WebAppInternals.reloadClientPrograms = -> + + WebAppInternals.generateBoilerplate() + # process.emit('message', {refresh: 'client'}) + + if not ClientVersions.findOne("version")? + ClientVersions.insert + _id: "version" + version: Autoupdate.autoupdateVersion + else + ClientVersions.update "version", + $set: + version: Autoupdate.autoupdateVersion + + if not ClientVersions.findOne("version-cordova")? + ClientVersions.insert + _id: "version-cordova" + version: Autoupdate.autoupdateVersionCordova + refreshable: false + else + ClientVersions.update "version-cordova", + $set: + version: Autoupdate.autoupdateVersionCordova + + WebApp.onListening -> + if not ClientVersions.findOne("version-refreshable")? + ClientVersions.insert + _id: "version-refreshable" + version: Autoupdate.autoupdateVersionRefreshable + assets: WebAppInternals.refreshableAssets + else + ClientVersions.update "version-refreshable", + $set: + version: Autoupdate.autoupdateVersionRefreshable + assets: WebAppInternals.refreshableAssets + + # RocketChat.Notifications.notifyAll 'theme-updated' addVariable: (type, name, value, isPublic=true) -> @variables[name] = @@ -91,13 +172,13 @@ RocketChat.theme = new class return RocketChat.settings.get 'css' -WebApp.connectHandlers.use '/theme.css', (req, res, next) -> - css = RocketChat.theme.getCss() +# WebApp.rawConnectHandlers.use '/theme.css', (req, res, next) -> +# css = RocketChat.theme.getCss() - res.setHeader 'content-type', 'text/css; charset=UTF-8' - res.setHeader 'Content-Disposition', 'inline' - res.setHeader 'Cache-Control', 'no-cache' - res.setHeader 'Pragma', 'no-cache' - res.setHeader 'Expires', '0' +# res.setHeader 'content-type', 'text/css; charset=UTF-8' +# res.setHeader 'Content-Disposition', 'inline' +# res.setHeader 'Cache-Control', 'no-cache' +# res.setHeader 'Pragma', 'no-cache' +# res.setHeader 'Expires', '0' - res.end css +# res.end css diff --git a/public/theme.css b/public/theme.css new file mode 100644 index 00000000000..443f19f843f --- /dev/null +++ b/public/theme.css @@ -0,0 +1 @@ +/*OOOPS*/ -- GitLab From 0cd94e1b5be541b614046c128bdab875a4e9d5c2 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Thu, 15 Oct 2015 22:31:30 -0400 Subject: [PATCH 0115/1338] bump version to v0.7 closes #1123 --- public/buildinfo/buildinfo.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/buildinfo/buildinfo.txt b/public/buildinfo/buildinfo.txt index e33ae0d8524..23bd41cc4c8 100644 --- a/public/buildinfo/buildinfo.txt +++ b/public/buildinfo/buildinfo.txt @@ -1 +1,3 @@ -v0.6.dev +v0.7.dev +This is an unsupported non-production development release. + -- GitLab From 4500932b3a7757887c5502c6c2f5dbcf1208cf4a Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 16 Oct 2015 07:11:16 -0400 Subject: [PATCH 0116/1338] Use our official repository in docker-compose use official repository image instead of my test repository --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 30a885fbf47..b59ddd46332 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ db: command: mongod --smallfiles rocketchat: - image: singli/rocket.chat + image: rocketchat/rocket.chat environment: - MONGO_URL=mongodb://db:27017/rocketchat - ROOT_URL=http://yourhost:8818 -- GitLab From aa146d290ee20009f1e8e25ccbec4f3974151687 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 11:22:47 -0300 Subject: [PATCH 0117/1338] moved userStatus template to sideNav --- client/views/app/sideNav/sideNav.coffee | 56 +++++++++++++++++++++- client/views/app/sideNav/sideNav.html | 28 ++++++++++- client/views/app/sideNav/userStatus.coffee | 54 --------------------- client/views/app/sideNav/userStatus.html | 29 ----------- 4 files changed, 82 insertions(+), 85 deletions(-) delete mode 100644 client/views/app/sideNav/userStatus.coffee delete mode 100644 client/views/app/sideNav/userStatus.html diff --git a/client/views/app/sideNav/sideNav.coffee b/client/views/app/sideNav/sideNav.coffee index eda94286337..9c4c10294f2 100644 --- a/client/views/app/sideNav/sideNav.coffee +++ b/client/views/app/sideNav/sideNav.coffee @@ -1,17 +1,40 @@ Template.sideNav.helpers - flexTemplate: -> return SideNav.getFlex().template + flexData: -> return SideNav.getFlex().data + footer: -> return RocketChat.settings.get 'Layout_Sidenav_Footer' + showStarredRooms: -> favoritesEnabled = !RocketChat.settings.get 'Disable_Favorite_Rooms' hasFavoriteRoomOpened = ChatSubscription.findOne({ f: true, open: true }) return true if favoritesEnabled and hasFavoriteRoomOpened + myUserInfo: -> + visualStatus = "online" + username = Meteor.user()?.username + switch Session.get('user_' + username + '_status') + when "away" + visualStatus = t("away") + when "busy" + visualStatus = t("busy") + when "offline" + visualStatus = t("invisible") + return { + name: Session.get('user_' + username + '_name') + status: Session.get('user_' + username + '_status') + visualStatus: visualStatus + _id: Meteor.userId() + username: username + } + + showAdminOption: -> + return RocketChat.authz.hasAtLeastOnePermission( ['view-statistics', 'view-room-administration', 'view-user-administration', 'view-privileged-setting']) + Template.sideNav.events 'click .close-flex': -> SideNav.closeFlex() @@ -28,9 +51,40 @@ Template.sideNav.events 'scroll .rooms-list': -> menu.updateUnreadBars() + 'click .options .status': (event) -> + event.preventDefault() + AccountBox.setStatus(event.currentTarget.dataset.status) + + 'click .account-box': (event) -> + AccountBox.toggle() + + 'click #logout': (event) -> + event.preventDefault() + user = Meteor.user() + Meteor.logout -> + FlowRouter.go 'home' + Meteor.call('logoutCleanUp', user) + + 'click #avatar': (event) -> + FlowRouter.go 'changeAvatar' + + 'click #account': (event) -> + SideNav.setFlex "accountFlex" + SideNav.openFlex() + FlowRouter.go 'account' + + 'click #admin': -> + SideNav.setFlex "adminFlex" + SideNav.openFlex() + + 'click .account-link': -> + menu.close() + Template.sideNav.onRendered -> SideNav.init() menu.init() Meteor.defer -> menu.updateUnreadBars() + + AccountBox.init() diff --git a/client/views/app/sideNav/sideNav.html b/client/views/app/sideNav/sideNav.html index 89f7112635d..e88a90091e7 100644 --- a/client/views/app/sideNav/sideNav.html +++ b/client/views/app/sideNav/sideNav.html @@ -1,7 +1,33 @@ <template name="sideNav"> <aside class="side-nav" role="navigation"> <header class="header"> - {{> userStatus}} + <div class="account-box"> + {{#with myUserInfo}} + <div class="info status-{{status}}"> + {{#if username}} + <div class="thumb" data-status='{{visualStatus}}'> + {{> avatar username=username}} + </div> + <div class="data"> + <h4>{{username}}</h4> + </div> + {{/if}} + </div> + <nav class="options _hidden"> + <div class="wrapper"> + <a href="" data-status="online" class="status online"><span>{{_ "Online"}}</span></a> + <a href="" data-status="away" class="status away"><span>{{_ "Away" context="male"}}</span></a> + <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> + <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> + <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> + {{#if showAdminOption }} + <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> + {{/if}} + <a href="" id="logout"><i class="icon-logout"></i><span>{{_ "Logout"}}</span></a> + </div> + </nav> + {{/with}} + </div> </header> {{#if currentUser}} <div class="unread-rooms top-unread-rooms hidden"> diff --git a/client/views/app/sideNav/userStatus.coffee b/client/views/app/sideNav/userStatus.coffee deleted file mode 100644 index b722e4d2e27..00000000000 --- a/client/views/app/sideNav/userStatus.coffee +++ /dev/null @@ -1,54 +0,0 @@ -Template.userStatus.helpers - myUserInfo: -> - visualStatus = "online" - username = Meteor.user()?.username - switch Session.get('user_' + username + '_status') - when "away" - visualStatus = t("away") - when "busy" - visualStatus = t("busy") - when "offline" - visualStatus = t("invisible") - return { - name: Session.get('user_' + username + '_name') - status: Session.get('user_' + username + '_status') - visualStatus: visualStatus - _id: Meteor.userId() - username: username - } - - showAdminOption: -> - return RocketChat.authz.hasAtLeastOnePermission( ['view-statistics', 'view-room-administration', 'view-user-administration', 'view-privileged-setting']) - -Template.userStatus.events - 'click .options .status': (event) -> - event.preventDefault() - AccountBox.setStatus(event.currentTarget.dataset.status) - - 'click .account-box': (event) -> - AccountBox.toggle() - - 'click #logout': (event) -> - event.preventDefault() - user = Meteor.user() - Meteor.logout -> - FlowRouter.go 'home' - Meteor.call('logoutCleanUp', user) - - 'click #avatar': (event) -> - FlowRouter.go 'changeAvatar' - - 'click #account': (event) -> - SideNav.setFlex "accountFlex" - SideNav.openFlex() - FlowRouter.go 'account' - - 'click #admin': -> - SideNav.setFlex "adminFlex" - SideNav.openFlex() - - 'click .account-link': -> - menu.close() - -Template.userStatus.rendered = -> - AccountBox.init() diff --git a/client/views/app/sideNav/userStatus.html b/client/views/app/sideNav/userStatus.html deleted file mode 100644 index a2c749354c3..00000000000 --- a/client/views/app/sideNav/userStatus.html +++ /dev/null @@ -1,29 +0,0 @@ -<template name="userStatus"> - <div class="account-box"> - {{#with myUserInfo}} - <div class="info status-{{status}}"> - {{#if username}} - <div class="thumb" data-status='{{visualStatus}}'> - {{> avatar username=username}} - </div> - <div class="data"> - <h4>{{username}}</h4> - </div> - {{/if}} - </div> - <nav class="options _hidden"> - <div class="wrapper"> - <a href="" data-status="online" class="status online"><span>{{_ "Online"}}</span></a> - <a href="" data-status="away" class="status away"><span>{{_ "Away" context="male"}}</span></a> - <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> - <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> - <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> - {{#if showAdminOption }} - <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> - {{/if}} - <a href="" id="logout"><i class="icon-logout"></i><span>{{_ "Logout"}}</span></a> - </div> - </nav> - {{/with}} - </div> -</template> -- GitLab From 8cdf6808d4f5698f5b586ea9ac0524aa7e3a065c Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 11:36:06 -0300 Subject: [PATCH 0118/1338] improved admin users list --- client/views/admin/users/adminUsers.coffee | 6 ++++ client/views/admin/users/adminUsers.html | 38 +++++++++++++--------- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 1 + 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/client/views/admin/users/adminUsers.coffee b/client/views/admin/users/adminUsers.coffee index 63882d48097..3883baba47d 100644 --- a/client/views/admin/users/adminUsers.coffee +++ b/client/views/admin/users/adminUsers.coffee @@ -25,6 +25,12 @@ Template.adminUsers.helpers adminClass: -> return 'admin' if RocketChat.authz.hasRole(Meteor.userId(), 'admin') + username: -> + return '@' + @username if @username? + + emailAddress: -> + return _.map(@emails, (e) -> e.address).join(', ') + Template.adminUsers.onCreated -> instance = @ @limit = new ReactiveVar 50 diff --git a/client/views/admin/users/adminUsers.html b/client/views/admin/users/adminUsers.html index e85242b85f5..f806d9389fa 100644 --- a/client/views/admin/users/adminUsers.html +++ b/client/views/admin/users/adminUsers.html @@ -21,22 +21,30 @@ {{{_ "Showing_results" users.length}}} </div> <div class="list"> - {{#each users}} - <div class="user-info" data-id="{{_id}}"> - <li class='user-image status-{{status}}'> - {{> avatar username=username}} - <h3>{{name}}</h3> - </li> - <ul> - <li>@{{username}}</li> - {{#if email}}<li>{{email}}</li>{{/if}} - </ul> - </div> - {{/each}} + <table> + <thead> + <tr> + <td> </td> + <td> </td> + <td>{{_ "Name"}}</td> + <td>{{_ "Username"}}</td> + <td>{{_ "Email"}}</td> + </tr> + </thead> + <tbody> + {{#each users}} + <tr> + <td class='user-image status-{{status}}'></td> + <td>{{> avatar username=username}}</td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + </tr> + {{/each}} + </tbody> + </table> {{#if hasMore}} - <li class="load-more"> - <button class="button secondary load-more {{isLoading}}">{{_ "Load_more"}}</button> - </li> + <button class="button secondary load-more {{isLoading}}">{{_ "Load_more"}}</button> {{/if}} </div> {{/unless}} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 05fd9bcc314..72f19aa0f35 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -104,6 +104,7 @@ "E-mail" : "E-mail", "Edit" : "Edit", "edited" : "edited", + "Email" : "Email", "Email_already_exists" : "Email already exists", "Email_or_username" : "Email or username", "Email_verified" : "Email verified", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 68d9e6d23d6..f8d3046a818 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -100,6 +100,7 @@ "E-mail" : "E-mail", "Edit" : "Editar", "edited" : "editado", + "Email" : "Email", "Email_already_exists" : "Email já cadastrado", "Email_or_username" : "Email ou nome de usuário", "Email_verified" : "Email verificado", -- GitLab From b9693bd7c5fb8169114867424b48d4c0a44a3b6c Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 13:22:59 -0300 Subject: [PATCH 0119/1338] revert back sideNav animations --- client/lib/accountBox.coffee | 6 +++--- client/lib/sideNav.coffee | 4 ++-- client/views/app/sideNav/sideNav.html | 2 +- client/views/app/tabBar/membersList.html | 4 ++-- packages/rocketchat-theme/assets/stylesheets/base.less | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/lib/accountBox.coffee b/client/lib/accountBox.coffee index 86f1c483eb9..b546eb87e62 100644 --- a/client/lib/accountBox.coffee +++ b/client/lib/accountBox.coffee @@ -13,13 +13,13 @@ SideNav.closeFlex() return; status = 1 - self.options.removeClass("_hidden") + self.options.removeClass("animated-hidden") self.box.addClass("active") SideNav.toggleArrow 1 close = -> status = 0 - self.options.addClass("_hidden") + self.options.addClass("animated-hidden") self.box.removeClass("active") SideNav.toggleArrow -1 @@ -32,4 +32,4 @@ open: open close: close init: init -)() \ No newline at end of file +)() diff --git a/client/lib/sideNav.coffee b/client/lib/sideNav.coffee index 76334d22b0e..d55a61c6b6e 100644 --- a/client/lib/sideNav.coffee +++ b/client/lib/sideNav.coffee @@ -48,12 +48,12 @@ animating = true if status is -1 or (status isnt 1 and flexNav.opened) flexNav.opened = false - flexNav.addClass "hidden" + flexNav.addClass "animated-hidden" else flexNav.opened = true # added a delay to make sure the template is already rendered before animating it setTimeout -> - flexNav.removeClass "hidden" + flexNav.removeClass "animated-hidden" , 50 setTimeout -> animating = false diff --git a/client/views/app/sideNav/sideNav.html b/client/views/app/sideNav/sideNav.html index 89f7112635d..eaec5eb3c0d 100644 --- a/client/views/app/sideNav/sideNav.html +++ b/client/views/app/sideNav/sideNav.html @@ -23,7 +23,7 @@ <div class="unread-rooms bottom-unread-rooms hidden"> {{_ "More_unreads"}} <i class="icon-down-big"></i> </div> - <div class="flex-nav hidden"> + <div class="flex-nav animated-hidden"> <section> {{> Template.dynamic template=flexTemplate data=flexData}} </section> diff --git a/client/views/app/tabBar/membersList.html b/client/views/app/tabBar/membersList.html index 7180118f2e6..9ac9f2a9525 100644 --- a/client/views/app/tabBar/membersList.html +++ b/client/views/app/tabBar/membersList.html @@ -2,7 +2,7 @@ <div class="content"> {{> videoCall}} {{#if isGroupChat}} - <div class="list-view{{#if $.Session.get 'showUserInfo'}} -hidden{{/if}}"> + <div class="list-view{{#if $.Session.get 'showUserInfo'}} animated-hidden{{/if}}"> {{#with roomUsers}} <div class="status"> <h2>{{_ "Members_List"}}</h2> @@ -35,7 +35,7 @@ {{/with}} </div> {{/if}} - <div class="user-view animated{{#unless showUserInfo}} -hidden{{/unless}}"> + <div class="user-view animated{{#unless showUserInfo}} animated-hidden{{/unless}}"> {{> userInfo user=flexUserInfo showAll=isGroupChat video=isDirectChat}} </div> </div> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index abc3707550c..ea17855a3a3 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -916,7 +916,7 @@ a.github-fork { opacity: 1; visibility: visible; .transition(opacity .2s ease-out); - &.-hidden { + &.animated-hidden { visibility: hidden; opacity: 0; } @@ -1013,7 +1013,7 @@ a.github-fork { .transition(transform .3s cubic-bezier(.5, 0, .1, 1)); z-index:99; - &._hidden { + &.animated-hidden { .transform(translateY(-100%) translateY(-50px)); } > .wrapper { @@ -1114,7 +1114,7 @@ a.github-fork { overflow-x: hidden; width: @rooms-box-width; .transition(transform .3s cubic-bezier(.5, 0, .1, 1)); - &.hidden { + &.animated-hidden { .transform(translateX(-100%)); header, footer, @@ -1607,7 +1607,7 @@ a.github-fork { margin-right: -4px; } } - .hidden { + .animated-hidden { visibility: hidden; display: none; } @@ -2743,7 +2743,7 @@ a.github-fork { 1), opacity .125s ease-out .1s); } - > .-hidden { + > .animated-hidden { .transform(translateX(100%)); opacity: 0; } -- GitLab From 19cb6088cfa43035e1c635336d91771f9b9b6fe2 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 13:40:25 -0300 Subject: [PATCH 0120/1338] fix footer z-index --- packages/rocketchat-theme/assets/stylesheets/base.less | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index ea17855a3a3..196adf874ac 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1339,7 +1339,6 @@ a.github-fork { left: 0; width: 100%; padding: 10px 15px 0px 15px; - z-index: 1000; text-align: right; min-height: @footer-min-height; height: @footer-min-height; -- GitLab From e83ee600e0c51faf6b3761a5f8f36d7f28f5a35a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 16 Oct 2015 14:20:29 -0300 Subject: [PATCH 0121/1338] Meteor update --- .meteor/packages | 4 +-- .meteor/versions | 26 ++++++++------- .../.npm/package/npm-shrinkwrap.json | 10 +++--- .../.npm/package/npm-shrinkwrap.json | 14 ++++---- .../.npm/package/npm-shrinkwrap.json | 32 +++++++++---------- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index a6bf1f2988a..5e9dd90e782 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -78,7 +78,7 @@ pauli:accounts-linkedin percolate:migrations percolate:synced-cron raix:handlebar-helpers -raix:push@2.6.13-rc.1 +raix:push raix:ui-dropped-event steffo:meteor-accounts-saml tap:i18n @@ -106,6 +106,6 @@ spacebars check rocketchat:github-enterprise rocketchat:chatops -# sanjo:jasmine@0.20.2 +# sanjo:jasmine # velocity:html-reporter ddp-rate-limiter diff --git a/.meteor/versions b/.meteor/versions index c6b9a8b1038..2381327fbb3 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,7 +6,7 @@ accounts-meteor-developer@1.0.6 accounts-oauth@1.1.7 accounts-password@1.1.3 accounts-twitter@1.0.6 -alanning:roles@1.2.13 +alanning:roles@1.2.14 aldeed:simple-schema@1.3.3 arunoda:streams@0.1.17 autoupdate@1.2.3 @@ -25,8 +25,9 @@ cfs:http-methods@0.0.30 check@1.0.6 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.10 -cosmos:browserify@0.5.1 +cosmos:browserify@0.8.1 dandv:caret-position@2.1.1 +dburles:google-maps@1.1.5 ddp@1.2.2 ddp-client@1.2.1 ddp-common@1.2.1 @@ -34,14 +35,14 @@ ddp-rate-limiter@1.0.0 ddp-server@1.2.1 deps@1.0.9 diff-sequence@1.0.1 -dispatch:run-as-user@0.0.2 +dispatch:run-as-user@1.1.1 ecmascript@0.1.5 ecmascript-collections@0.1.6 ejson@1.0.7 email@1.0.7 facebook@1.2.2 fastclick@1.0.7 -francocatena:status@1.3.4 +francocatena:status@1.5.0 geojson-utils@1.0.4 github@1.1.4 google@1.1.6 @@ -58,7 +59,7 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 kadira:blaze-layout@2.1.0 -kadira:flow-router@2.6.2 +kadira:flow-router@2.7.0 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 konecty:change-case@2.3.0 @@ -72,12 +73,12 @@ less@2.5.0_3 livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 -matb33:collection-hooks@0.7.15 +matb33:collection-hooks@0.8.1 meteor@1.1.9 meteor-base@1.0.1 meteor-developer@1.1.4 -meteorhacks:kadira@2.23.4 -meteorhacks:meteorx@1.3.1 +meteorhacks:kadira@2.23.6 +meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 minimongo@1.0.10 @@ -103,15 +104,16 @@ observe-sequence@1.0.7 ordered-dict@1.0.4 pauli:accounts-linkedin@1.1.2 pauli:linkedin@1.1.2 -perak:codemirror@1.2.7 +perak:codemirror@1.2.8 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 +pntbr:js-yaml-client@0.0.1 promise@0.5.0 qnub:emojione@0.0.3 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 -raix:push@2.6.13-rc.1 +raix:push@3.0.1 raix:ui-dropped-event@0.0.7 random@1.0.4 rate-limit@1.0.0 @@ -150,14 +152,14 @@ routepolicy@1.0.6 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 -simple:highlight.js@1.0.9 +simple:highlight.js@1.2.0 simple:json-routes@1.0.4 spacebars@1.0.7 spacebars-compiler@1.0.7 srp@1.0.4 standard-minifiers@1.0.1 steffo:meteor-accounts-saml@0.0.1 -tap:i18n@1.6.1 +tap:i18n@1.7.0 templating@1.1.4 templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 diff --git a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json index ad9fa4c8b9f..6aaaf24c1aa 100644 --- a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json +++ b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json @@ -77,23 +77,23 @@ } }, "xml2js": { - "version": "http://registry.npmjs.org/xml2js/-/xml2js-0.2.0.tgz", + "version": "0.2.0", "dependencies": { "sax": { - "version": "http://registry.npmjs.org/sax/-/sax-1.1.2.tgz" + "version": "1.1.3" } } }, "xmlbuilder": { - "version": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.4.tgz", + "version": "2.6.4", "dependencies": { "lodash": { - "version": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + "version": "3.10.1" } } }, "xmldom": { - "version": "http://registry.npmjs.org/xmldom/-/xmldom-0.1.19.tgz" + "version": "0.1.19" } } } diff --git a/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json index a8ecae95ec9..bf4b8acb16e 100644 --- a/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-file/.npm/package/npm-shrinkwrap.json @@ -1,29 +1,29 @@ { "dependencies": { "gm": { - "version": "http://registry.npmjs.org/gm/-/gm-1.18.1.tgz", + "version": "1.18.1", "dependencies": { "debug": { - "version": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "version": "2.2.0", "dependencies": { "ms": { - "version": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "version": "0.7.1" } } }, "array-series": { - "version": "http://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz" + "version": "0.1.5" }, "array-parallel": { - "version": "http://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz" + "version": "0.1.3" } } }, "gridfs-stream": { - "version": "http://registry.npmjs.org/gridfs-stream/-/gridfs-stream-0.5.3.tgz" + "version": "0.5.3" }, "mkdirp": { - "version": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz" + "version": "0.3.5" } } } diff --git a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json index db1eb39703a..3dd543e2c5e 100644 --- a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json @@ -1,58 +1,58 @@ { "dependencies": { "ldapjs": { - "version": "http://registry.npmjs.org/ldapjs/-/ldapjs-0.7.1.tgz", + "version": "0.7.1", "dependencies": { "asn1": { - "version": "http://registry.npmjs.org/asn1/-/asn1-0.2.1.tgz" + "version": "0.2.1" }, "assert-plus": { - "version": "http://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" + "version": "0.1.5" }, "bunyan": { - "version": "http://registry.npmjs.org/bunyan/-/bunyan-0.22.1.tgz", + "version": "0.22.1", "dependencies": { "mv": { - "version": "http://registry.npmjs.org/mv/-/mv-0.0.5.tgz" + "version": "0.0.5" } } }, "nopt": { - "version": "http://registry.npmjs.org/nopt/-/nopt-2.1.1.tgz", + "version": "2.1.1", "dependencies": { "abbrev": { - "version": "http://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + "version": "1.0.7" } } }, "pooling": { - "version": "http://registry.npmjs.org/pooling/-/pooling-0.4.6.tgz", + "version": "0.4.6", "dependencies": { "once": { - "version": "http://registry.npmjs.org/once/-/once-1.3.0.tgz" + "version": "1.3.0" }, "vasync": { - "version": "http://registry.npmjs.org/vasync/-/vasync-1.4.0.tgz", + "version": "1.4.0", "dependencies": { "jsprim": { - "version": "http://registry.npmjs.org/jsprim/-/jsprim-0.3.0.tgz", + "version": "0.3.0", "dependencies": { "extsprintf": { - "version": "http://registry.npmjs.org/extsprintf/-/extsprintf-1.0.0.tgz" + "version": "1.0.0" }, "json-schema": { - "version": "http://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" + "version": "0.2.2" }, "verror": { - "version": "http://registry.npmjs.org/verror/-/verror-1.3.3.tgz" + "version": "1.3.3" } } }, "verror": { - "version": "http://registry.npmjs.org/verror/-/verror-1.1.0.tgz", + "version": "1.1.0", "dependencies": { "extsprintf": { - "version": "http://registry.npmjs.org/extsprintf/-/extsprintf-1.0.0.tgz" + "version": "1.0.0" } } } -- GitLab From 0f1b035b69387a5819cdff40f04bd6e04cf12707 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 16 Oct 2015 14:21:53 -0300 Subject: [PATCH 0122/1338] Meteor update --- .../.npm/package/npm-shrinkwrap.json | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json index 6aaaf24c1aa..16c8109f51a 100644 --- a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json +++ b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json @@ -1,78 +1,81 @@ { "dependencies": { "connect": { - "version": "http://registry.npmjs.org/connect/-/connect-2.7.10.tgz", + "version": "2.7.10", "dependencies": { "qs": { - "version": "http://registry.npmjs.org/qs/-/qs-0.6.5.tgz" + "version": "0.6.5" }, "formidable": { - "version": "http://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz" + "version": "1.0.14" }, "cookie-signature": { - "version": "http://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz" + "version": "1.0.1" }, "buffer-crc32": { - "version": "http://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz" + "version": "0.2.1" }, "cookie": { - "version": "http://registry.npmjs.org/cookie/-/cookie-0.0.5.tgz" + "version": "0.0.5" }, "send": { - "version": "http://registry.npmjs.org/send/-/send-0.1.0.tgz", + "version": "0.1.0", "dependencies": { "mime": { - "version": "http://registry.npmjs.org/mime/-/mime-1.2.6.tgz" + "version": "1.2.6" }, "range-parser": { - "version": "http://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz" + "version": "0.0.4" } } }, "bytes": { - "version": "http://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz" + "version": "0.2.0" }, "fresh": { - "version": "http://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz" + "version": "0.1.0" }, "pause": { - "version": "http://registry.npmjs.org/pause/-/pause-0.0.1.tgz" + "version": "0.0.1" }, "debug": { - "version": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "version": "2.2.0", "dependencies": { "ms": { - "version": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "version": "0.7.1" } } } } }, "querystring": { - "version": "http://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" + "version": "0.2.0" }, "xml-crypto": { - "version": "http://registry.npmjs.org/xml-crypto/-/xml-crypto-0.6.0.tgz", + "version": "0.6.0", "dependencies": { + "xmldom": { + "version": "0.1.19" + }, "xpath.js": { - "version": "http://registry.npmjs.org/xpath.js/-/xpath.js-1.0.6.tgz" + "version": "1.0.6" } } }, "xml-encryption": { - "version": "http://registry.npmjs.org/xml-encryption/-/xml-encryption-0.7.2.tgz", + "version": "0.7.2", "dependencies": { "ejs": { - "version": "http://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz" + "version": "0.8.8" }, "async": { - "version": "http://registry.npmjs.org/async/-/async-0.2.10.tgz" + "version": "0.2.10" }, "xpath": { - "version": "http://registry.npmjs.org/xpath/-/xpath-0.0.5.tgz" + "version": "0.0.5" }, "node-forge": { - "version": "http://registry.npmjs.org/node-forge/-/node-forge-0.2.24.tgz" + "version": "0.2.24" } } }, -- GitLab From e0519995993d1d1a3d7299ed86a5672a1cd01853 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 14:38:52 -0300 Subject: [PATCH 0123/1338] fix not showing any css --- .../rocketchat-theme/server/server.coffee | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 624931e0945..5c66d1e3a5b 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -77,23 +77,25 @@ RocketChat.theme = new class hash = crypto.createHash('sha1').update(data.css).digest('hex') - program = WebApp.clientPrograms['web.cordova'] - themeManifestItem = _.find program.manifest, (item) -> return item.path is 'app/theme.css' - themeManifestItem.type = 'css' - themeManifestItem.where = 'client' - themeManifestItem.url = "/theme.css?#{hash}" - themeManifestItem.size = data.css.length - themeManifestItem.hash = hash - program.version = WebApp.calculateClientHashCordova() - - program = WebApp.clientPrograms['web.browser'] - themeManifestItem = _.find program.manifest, (item) -> return item.path is 'app/theme.css' - themeManifestItem.type = 'css' - themeManifestItem.where = 'client' - themeManifestItem.url = "/theme.css?#{hash}" - themeManifestItem.size = data.css.length - themeManifestItem.hash = hash - program.version = WebApp.calculateClientHashRefreshable() + if WebApp.clientPrograms['web.cordova']? + program = WebApp.clientPrograms['web.cordova'] + themeManifestItem = (_.find program?.manifest, (item) -> return item.path is 'app/theme.css') or {} + themeManifestItem.type = 'css' + themeManifestItem.where = 'client' + themeManifestItem.url = "/theme.css?#{hash}" + themeManifestItem.size = data.css.length + themeManifestItem.hash = hash + program.version = WebApp.calculateClientHashCordova() + + if WebApp.clientPrograms['web.browser']? + program = WebApp.clientPrograms['web.browser'] + themeManifestItem = _.find program?.manifest, (item) -> return item.path is 'app/theme.css' + themeManifestItem.type = 'css' + themeManifestItem.where = 'client' + themeManifestItem.url = "/theme.css?#{hash}" + themeManifestItem.size = data.css.length + themeManifestItem.hash = hash + program.version = WebApp.calculateClientHashRefreshable() Autoupdate.autoupdateVersion = __meteor_runtime_config__.autoupdateVersion = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashNonRefreshable() Autoupdate.autoupdateVersionRefreshable = __meteor_runtime_config__.autoupdateVersionRefreshable = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashRefreshable() -- GitLab From d0c0facfc933469ed281b2d967c497bd49a94d36 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Fri, 16 Oct 2015 15:34:19 -0300 Subject: [PATCH 0124/1338] changed to single line --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 67f3040ae2d..c2767ccf28b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,8 +18,7 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- meteor add rocketchat:livechat -- meteor add rocketchat:hubot +- meteor add rocketchat:livechat rocketchat:hubot - meteor build --server demo.rocket.chat ../build - cd .travis - sh ./namedemo.sh -- GitLab From 2b2c90a99c1f3a8db445164f594e70479c6426c1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 16 Oct 2015 15:35:28 -0300 Subject: [PATCH 0125/1338] Add script to build in old style --- build-old.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 build-old.sh diff --git a/build-old.sh b/build-old.sh new file mode 100755 index 00000000000..90b3c5b8eb8 --- /dev/null +++ b/build-old.sh @@ -0,0 +1,10 @@ +#!/bin/bash +source ./build-info.sh +export METEOR_SETTINGS=$(cat settings.json) +meteor add rocketchat:livechat +meteor add rocketchat:hubot +meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat +cd /var/www/rocket.chat/bundle/programs/server +npm install +cd /var/www/rocket.chat/current +pm2 startOrRestart /var/www/rocket.chat/current/pm2.json -- GitLab From 55229476bc5d5b26f125962f152f0acd622a51a8 Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Sat, 17 Oct 2015 03:13:20 +0800 Subject: [PATCH 0126/1338] added api - findOrCreateRoomThenJoin --- .meteor/versions | 15 ++++++++------- client/views/app/tabBar/membersList.html | 2 +- server/methods/findOrCreateRoom.coffee | 13 ------------- server/restapi/restapi.coffee | 6 ++++-- 4 files changed, 13 insertions(+), 23 deletions(-) delete mode 100644 server/methods/findOrCreateRoom.coffee diff --git a/.meteor/versions b/.meteor/versions index c6b9a8b1038..01ee5655e69 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,7 +6,7 @@ accounts-meteor-developer@1.0.6 accounts-oauth@1.1.7 accounts-password@1.1.3 accounts-twitter@1.0.6 -alanning:roles@1.2.13 +alanning:roles@1.2.14 aldeed:simple-schema@1.3.3 arunoda:streams@0.1.17 autoupdate@1.2.3 @@ -41,7 +41,7 @@ ejson@1.0.7 email@1.0.7 facebook@1.2.2 fastclick@1.0.7 -francocatena:status@1.3.4 +francocatena:status@1.5.0 geojson-utils@1.0.4 github@1.1.4 google@1.1.6 @@ -58,7 +58,7 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 kadira:blaze-layout@2.1.0 -kadira:flow-router@2.6.2 +kadira:flow-router@2.7.0 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 konecty:change-case@2.3.0 @@ -76,8 +76,8 @@ matb33:collection-hooks@0.7.15 meteor@1.1.9 meteor-base@1.0.1 meteor-developer@1.1.4 -meteorhacks:kadira@2.23.4 -meteorhacks:meteorx@1.3.1 +meteorhacks:kadira@2.23.6 +meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 minimongo@1.0.10 @@ -103,9 +103,10 @@ observe-sequence@1.0.7 ordered-dict@1.0.4 pauli:accounts-linkedin@1.1.2 pauli:linkedin@1.1.2 -perak:codemirror@1.2.7 +perak:codemirror@1.2.8 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 +pntbr:js-yaml-client@0.0.1 promise@0.5.0 qnub:emojione@0.0.3 raix:eventemitter@0.1.3 @@ -157,7 +158,7 @@ spacebars-compiler@1.0.7 srp@1.0.4 standard-minifiers@1.0.1 steffo:meteor-accounts-saml@0.0.1 -tap:i18n@1.6.1 +tap:i18n@1.7.0 templating@1.1.4 templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 diff --git a/client/views/app/tabBar/membersList.html b/client/views/app/tabBar/membersList.html index 7180118f2e6..706cdc035e0 100644 --- a/client/views/app/tabBar/membersList.html +++ b/client/views/app/tabBar/membersList.html @@ -8,7 +8,7 @@ <h2>{{_ "Members_List"}}</h2> <p> {{{_ "Showing_online_users" total_online=totalOnline total=total}}} - {{!--<button class="see-all">{{seeAll}}</button>--}} + <button class="see-all">{{seeAll}}</button> </p> {{> videoButtons}} {{#if canAddUser}} diff --git a/server/methods/findOrCreateRoom.coffee b/server/methods/findOrCreateRoom.coffee deleted file mode 100644 index 8d24f8ecc8e..00000000000 --- a/server/methods/findOrCreateRoom.coffee +++ /dev/null @@ -1,13 +0,0 @@ -Meteor.methods - findOrCreateClientRoomThenJoin: (clientId, usernames) -> - m = clientId.match(/^(?:CLT){0,1}([0-9]+)/i); - roomName = m[0]; - if not roomName? - throw new Meteor.Error 403, '[methods] findOrCreateClientRoom -> Mal-format' - - room = RocketChat.models.Rooms.findOneByName(roomName); - console.log '[methods] findOrCreateClientRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - - if not room? - room = Meteor.call('createPrivateGroup', roomName, Meteor.userId(), usernames) - Meteor.call 'joinRoom', room._id diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 67003b5357b..023240c9d1a 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -22,10 +22,12 @@ Api.addRoute 'rooms/:id/join', authRequired: true, status: 'success' # need to handle error # find or create a room -Api.addRoute 'rooms/findorcreatethenjoin/:clientId', authRequired: true, +Api.addRoute 'rooms/findorcreatethenjoin', authRequired: true, post: -> + roomname = @bodyParams.roomname + usernames = @bodyParams.usernames Meteor.runAsUser this.userId, () => - Meteor.call('findOrCreateClientRoomThenJoin', @urlParams.clientId) + Meteor.call('findOrCreateRoomThenJoin', roomname , usernames) status: 'success' # need to handle error -- GitLab From df90606757fe6494dd9129d8b7d506e2bdb901c8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 16 Oct 2015 16:15:49 -0300 Subject: [PATCH 0127/1338] Remove the necessity of theme.css --- .../rocketchat-theme/server/server.coffee | 39 ++++++++++--------- public/theme.css | 1 - 2 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 public/theme.css diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 5c66d1e3a5b..1e6951397e8 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -77,25 +77,26 @@ RocketChat.theme = new class hash = crypto.createHash('sha1').update(data.css).digest('hex') - if WebApp.clientPrograms['web.cordova']? - program = WebApp.clientPrograms['web.cordova'] - themeManifestItem = (_.find program?.manifest, (item) -> return item.path is 'app/theme.css') or {} - themeManifestItem.type = 'css' - themeManifestItem.where = 'client' - themeManifestItem.url = "/theme.css?#{hash}" - themeManifestItem.size = data.css.length - themeManifestItem.hash = hash - program.version = WebApp.calculateClientHashCordova() - - if WebApp.clientPrograms['web.browser']? - program = WebApp.clientPrograms['web.browser'] - themeManifestItem = _.find program?.manifest, (item) -> return item.path is 'app/theme.css' - themeManifestItem.type = 'css' - themeManifestItem.where = 'client' - themeManifestItem.url = "/theme.css?#{hash}" - themeManifestItem.size = data.css.length - themeManifestItem.hash = hash - program.version = WebApp.calculateClientHashRefreshable() + for arch in ['web.cordova', 'web.browser'] + program = WebApp.clientPrograms[arch] + if program? and program.manifest? + themeManifestItem = _.find program.manifest, (item) -> return item.path is 'app/theme.css' + if not themeManifestItem? + themeManifestItem = {} + program.manifest.push themeManifestItem + + themeManifestItem.path = 'app/theme.css' + themeManifestItem.type = 'css' + themeManifestItem.cacheable = true + themeManifestItem.where = 'client' + themeManifestItem.url = "/theme.css?#{hash}" + themeManifestItem.size = data.css.length + themeManifestItem.hash = hash + + if arch is 'web.cordova' + program.version = WebApp.calculateClientHashCordova() + else + program.version = WebApp.calculateClientHashRefreshable() Autoupdate.autoupdateVersion = __meteor_runtime_config__.autoupdateVersion = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashNonRefreshable() Autoupdate.autoupdateVersionRefreshable = __meteor_runtime_config__.autoupdateVersionRefreshable = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashRefreshable() diff --git a/public/theme.css b/public/theme.css deleted file mode 100644 index 443f19f843f..00000000000 --- a/public/theme.css +++ /dev/null @@ -1 +0,0 @@ -/*OOOPS*/ -- GitLab From 358f6cd6d141210fb12780d4e70e2d2df812aa3d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 16:32:55 -0300 Subject: [PATCH 0128/1338] improved admin users list --- client/views/admin/users/adminUsers.html | 16 ++-- .../assets/stylesheets/base.less | 75 +++++-------------- .../stylesheets/utils/_colors.import.less | 8 ++ 3 files changed, 34 insertions(+), 65 deletions(-) diff --git a/client/views/admin/users/adminUsers.html b/client/views/admin/users/adminUsers.html index f806d9389fa..e3dbb018d3e 100644 --- a/client/views/admin/users/adminUsers.html +++ b/client/views/admin/users/adminUsers.html @@ -25,17 +25,19 @@ <thead> <tr> <td> </td> - <td> </td> - <td>{{_ "Name"}}</td> - <td>{{_ "Username"}}</td> - <td>{{_ "Email"}}</td> + <td width="34%">{{_ "Name"}}</td> + <td width="33%">{{_ "Username"}}</td> + <td width="33%">{{_ "Email"}}</td> </tr> </thead> <tbody> {{#each users}} - <tr> - <td class='user-image status-{{status}}'></td> - <td>{{> avatar username=username}}</td> + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> <td>{{name}}</td> <td>{{username}}</td> <td>{{emailAddress}}</td> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 196adf874ac..b7a323eda7d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -291,6 +291,11 @@ blockquote { animation-iteration-count: infinite; animation-timing-function: linear; } + .icon-search { + position: absolute; + left: 2px; + top: 10px; + } input { padding-left: 20px; } @@ -1842,66 +1847,20 @@ a.github-fork { } .list { - a { - .clearfix; - display: block; - padding: 10px 16px; - width: 100%; - border-bottom: 1px solid; - .transition(background .15s ease-out); - &:hover { - } - } - ul { - margin: 6px 0; + .user-image { + float: right; + margin-left: 12px; } - li { - display: inline-block; - margin-right: 14px; - font-size: 11px; - position: relative; - &:after { - content: " "; - width: 4px; - height: 4px; - border-radius: 50%; - position: absolute; - right: -12px; - .calc(top, - ~"50% - 2px"); - } - &:nth-last-child(1) { - &:after { - display: none; + table { + width: 100%; + tbody { + td { + vertical-align: middle; + padding: 0 2px; + } + tr { + cursor: pointer; } - } - } - .info { - display: block; - float: left; - .calc(width,~"100% - 150px"); - i { - margin-right: 5px; - width: 20px; - text-align: left; - } - h3 { - font-size: 18px; - font-weight: 500; - } - a { - text-decoration: none; - } - } - .status { - display: block; - float: right; - width: 150px; - min-height: 30px; - text-align: right; - strong { - font-size: 12px; - font-weight: 500; } } } diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index c66bdd76446..c65d61a4244 100644 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -630,6 +630,14 @@ a.github-fork { .status { color: @secondary-font-color; } + + table { + tbody { + tr:nth-child(odd) { + background-color: @secondary-background-color; + } + } + } } } -- GitLab From 85e2e91c81888dcfc416a954139402a1f85fb2a0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 16:44:36 -0300 Subject: [PATCH 0129/1338] uses e-mail translation --- client/views/admin/users/adminUsers.html | 2 +- i18n/en.i18n.json | 1 - i18n/pt.i18n.json | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/client/views/admin/users/adminUsers.html b/client/views/admin/users/adminUsers.html index e3dbb018d3e..b2eeb6c1d83 100644 --- a/client/views/admin/users/adminUsers.html +++ b/client/views/admin/users/adminUsers.html @@ -27,7 +27,7 @@ <td> </td> <td width="34%">{{_ "Name"}}</td> <td width="33%">{{_ "Username"}}</td> - <td width="33%">{{_ "Email"}}</td> + <td width="33%">{{_ "E-mail"}}</td> </tr> </thead> <tbody> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 72f19aa0f35..05fd9bcc314 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -104,7 +104,6 @@ "E-mail" : "E-mail", "Edit" : "Edit", "edited" : "edited", - "Email" : "Email", "Email_already_exists" : "Email already exists", "Email_or_username" : "Email or username", "Email_verified" : "Email verified", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index f8d3046a818..68d9e6d23d6 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -100,7 +100,6 @@ "E-mail" : "E-mail", "Edit" : "Editar", "edited" : "editado", - "Email" : "Email", "Email_already_exists" : "Email já cadastrado", "Email_or_username" : "Email ou nome de usuário", "Email_verified" : "Email verificado", -- GitLab From 29bfa3a8623c751995704d3c7430fae159079259 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 16 Oct 2015 16:45:04 -0300 Subject: [PATCH 0130/1338] Try a better way to refresh themes --- packages/rocketchat-theme/package.js | 1 + .../rocketchat-theme/server/server.coffee | 119 ++++-------------- 2 files changed, 27 insertions(+), 93 deletions(-) diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 7bff8629a20..c18f2ab85e5 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -12,6 +12,7 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); api.use('webapp'); + api.use('webapp-hashing'); api.addFiles('server/server.coffee', 'server'); diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 1e6951397e8..1740b1d3dd8 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -1,18 +1,33 @@ less = Npm.require('less') crypto = Npm.require('crypto') -# program = WebApp.clientPrograms['web.browser'] -# themeManifestItem = _.find program.manifest, (item) -> return item.url is '/theme.css' -# themeManifestItem.where = 'client' -# themeManifestItem.type = 'css' +calculateClientHash = WebAppHashing.calculateClientHash +WebAppHashing.calculateClientHash = (manifest, includeFilter, runtimeConfigOverride) -> + css = RocketChat.theme.getCss() -ClientVersions = undefined -_defineMutationMethods = Meteor.Collection.prototype._defineMutationMethods -Meteor.Collection.prototype._defineMutationMethods = -> - if this._name is 'meteor_autoupdate_clientVersions' - ClientVersions = this + WebAppInternals.staticFiles['/__cordova/theme.css'] = WebAppInternals.staticFiles['/theme.css'] = + cacheable: true + sourceMapUrl: undefined + type: 'css' + content: css + + hash = crypto.createHash('sha1').update(css).digest('hex') + + themeManifestItem = _.find manifest, (item) -> return item.path is 'app/theme.css' + if not themeManifestItem? + themeManifestItem = {} + manifest.push themeManifestItem + + themeManifestItem.path = 'app/theme.css' + themeManifestItem.type = 'css' + themeManifestItem.cacheable = true + themeManifestItem.where = 'client' + themeManifestItem.url = "/theme.css?#{hash}" + themeManifestItem.size = css.length + themeManifestItem.hash = hash + + calculateClientHash.call this, manifest, includeFilter, runtimeConfigOverride - _defineMutationMethods.call this RocketChat.theme = new class variables: {} @@ -69,77 +84,7 @@ RocketChat.theme = new class RocketChat.settings.updateById 'css', data.css - WebAppInternals.staticFiles['/__cordova/theme.css'] = WebAppInternals.staticFiles['/theme.css'] = - cacheable: true - sourceMapUrl: undefined - type: 'css' - content: data.css - - hash = crypto.createHash('sha1').update(data.css).digest('hex') - - for arch in ['web.cordova', 'web.browser'] - program = WebApp.clientPrograms[arch] - if program? and program.manifest? - themeManifestItem = _.find program.manifest, (item) -> return item.path is 'app/theme.css' - if not themeManifestItem? - themeManifestItem = {} - program.manifest.push themeManifestItem - - themeManifestItem.path = 'app/theme.css' - themeManifestItem.type = 'css' - themeManifestItem.cacheable = true - themeManifestItem.where = 'client' - themeManifestItem.url = "/theme.css?#{hash}" - themeManifestItem.size = data.css.length - themeManifestItem.hash = hash - - if arch is 'web.cordova' - program.version = WebApp.calculateClientHashCordova() - else - program.version = WebApp.calculateClientHashRefreshable() - - Autoupdate.autoupdateVersion = __meteor_runtime_config__.autoupdateVersion = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashNonRefreshable() - Autoupdate.autoupdateVersionRefreshable = __meteor_runtime_config__.autoupdateVersionRefreshable = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashRefreshable() - Autoupdate.autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova = process.env.AUTOUPDATE_VERSION or WebApp.calculateClientHashCordova() - - # reloadClientPrograms = WebAppInternals.reloadClientPrograms - # WebAppInternals.reloadClientPrograms = -> - - WebAppInternals.generateBoilerplate() - # process.emit('message', {refresh: 'client'}) - - if not ClientVersions.findOne("version")? - ClientVersions.insert - _id: "version" - version: Autoupdate.autoupdateVersion - else - ClientVersions.update "version", - $set: - version: Autoupdate.autoupdateVersion - - if not ClientVersions.findOne("version-cordova")? - ClientVersions.insert - _id: "version-cordova" - version: Autoupdate.autoupdateVersionCordova - refreshable: false - else - ClientVersions.update "version-cordova", - $set: - version: Autoupdate.autoupdateVersionCordova - - WebApp.onListening -> - if not ClientVersions.findOne("version-refreshable")? - ClientVersions.insert - _id: "version-refreshable" - version: Autoupdate.autoupdateVersionRefreshable - assets: WebAppInternals.refreshableAssets - else - ClientVersions.update "version-refreshable", - $set: - version: Autoupdate.autoupdateVersionRefreshable - assets: WebAppInternals.refreshableAssets - - # RocketChat.Notifications.notifyAll 'theme-updated' + process.emit('message', {refresh: 'client'}) addVariable: (type, name, value, isPublic=true) -> @variables[name] = @@ -173,15 +118,3 @@ RocketChat.theme = new class getCss: -> return RocketChat.settings.get 'css' - - -# WebApp.rawConnectHandlers.use '/theme.css', (req, res, next) -> -# css = RocketChat.theme.getCss() - -# res.setHeader 'content-type', 'text/css; charset=UTF-8' -# res.setHeader 'Content-Disposition', 'inline' -# res.setHeader 'Cache-Control', 'no-cache' -# res.setHeader 'Pragma', 'no-cache' -# res.setHeader 'Expires', '0' - -# res.end css -- GitLab From 19cc13588c8169105e4fa32bb0954295e310bad5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 16 Oct 2015 16:45:49 -0300 Subject: [PATCH 0131/1338] Closes #1125; Do not redirect users after login --- client/views/login/form.coffee | 4 +--- client/views/login/services.coffee | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/client/views/login/form.coffee b/client/views/login/form.coffee index 4016bb95d72..c1a78915ea1 100644 --- a/client/views/login/form.coffee +++ b/client/views/login/form.coffee @@ -85,8 +85,7 @@ Template.loginForm.events instance.state.set 'login' else if error?.error is 'inactive-user' instance.state.set 'wait-activation' - # else - # FlowRouter.go 'index' + else loginMethod = 'loginWithPassword' if RocketChat.settings.get('LDAP_Enable') @@ -100,7 +99,6 @@ Template.loginForm.events else toastr.error t 'User_not_found_or_incorrect_password' return - FlowRouter.go 'index' 'click .register': -> Template.instance().state.set 'register' diff --git a/client/views/login/services.coffee b/client/views/login/services.coffee index 7e2755a6ef0..fb491b8a994 100644 --- a/client/views/login/services.coffee +++ b/client/views/login/services.coffee @@ -57,7 +57,6 @@ Template.loginServices.events toastr.error error.message return - FlowRouter.go 'index' else loginWithService = "loginWith" + (if this.service.service is 'meteor-developer' then 'MeteorDeveloperAccount' else _.capitalize(this.service.service)) serviceConfig = this.service.clientConfig or {} @@ -68,4 +67,3 @@ Template.loginServices.events console.log JSON.stringify(error), error.message toastr.error error.message return - FlowRouter.go 'index' -- GitLab From a98c2104a4aee122c3388afc4bcd37071840ae61 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 16:48:11 -0300 Subject: [PATCH 0132/1338] remove the last _hidden class --- client/views/app/sideNav/userStatus.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/sideNav/userStatus.html b/client/views/app/sideNav/userStatus.html index a2c749354c3..5bac582d2c1 100644 --- a/client/views/app/sideNav/userStatus.html +++ b/client/views/app/sideNav/userStatus.html @@ -11,7 +11,7 @@ </div> {{/if}} </div> - <nav class="options _hidden"> + <nav class="options animated-hidden"> <div class="wrapper"> <a href="" data-status="online" class="status online"><span>{{_ "Online"}}</span></a> <a href="" data-status="away" class="status away"><span>{{_ "Away" context="male"}}</span></a> -- GitLab From e87b7959eb034255553331240cd1346a165fec1e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 16 Oct 2015 16:59:12 -0300 Subject: [PATCH 0133/1338] fix firefox min-height --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 196adf874ac..2952cc0f20d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1175,7 +1175,7 @@ a.github-fork { padding: 0 10px; z-index: 120; text-align: left; - min-height: @footer-min-height; + height: @footer-min-height; .transition-delay(.22s); > div { display: table-cell; -- GitLab From dd4d958510cd070b5ef5185f8342f51e75b80132 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 16 Oct 2015 17:01:55 -0300 Subject: [PATCH 0134/1338] meteor add-platform ios android to generate /__cordova/manifest.json --- .meteor/platforms | 2 ++ .travis.yml | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.meteor/platforms b/.meteor/platforms index 8a3a35f9f62..2d49a856332 100644 --- a/.meteor/platforms +++ b/.meteor/platforms @@ -1,2 +1,4 @@ +android browser +ios server diff --git a/.travis.yml b/.travis.yml index c2767ccf28b..0220b8d26c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,18 +13,19 @@ script: - cd .travis - npm install - npm start -- cd .. +- cd .. - meteor build ../build - cd .travis - sh ./namefiles.sh - cd .. +- meteor add-platform ios android - meteor add rocketchat:livechat rocketchat:hubot - meteor build --server demo.rocket.chat ../build - cd .travis - sh ./namedemo.sh - cd .. after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" @@ -34,4 +35,4 @@ deploy: local_dir: ../build on: branch: master - + -- GitLab From 4622aa5a524e76a8e0f35a7e18ee0c1e30df4af7 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 16 Oct 2015 17:04:24 -0300 Subject: [PATCH 0135/1338] remove platform by default --- .meteor/platforms | 2 -- 1 file changed, 2 deletions(-) diff --git a/.meteor/platforms b/.meteor/platforms index 2d49a856332..8a3a35f9f62 100644 --- a/.meteor/platforms +++ b/.meteor/platforms @@ -1,4 +1,2 @@ -android browser -ios server -- GitLab From 2a9c00b07bf16c2118302fda272de059b9d62e5c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 16 Oct 2015 18:04:44 -0300 Subject: [PATCH 0136/1338] remove android platform on build process --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0220b8d26c7..a0ba35fa764 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- meteor add-platform ios android +- meteor add-platform ios - meteor add rocketchat:livechat rocketchat:hubot - meteor build --server demo.rocket.chat ../build - cd .travis -- GitLab From 7b168fc2a862928567201b0ac35a845b216b18b1 Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Sat, 17 Oct 2015 07:27:06 +0800 Subject: [PATCH 0137/1338] to support Chinese characters slugify function should be disabled --- .meteor/packages | 1 + .meteor/versions | 1 + client/methods/saveRoomName.coffee | 2 +- .../.npm/package/npm-shrinkwrap.json | 3 --- server/methods/getUsernameSuggestion.coffee | 12 ++++++------ 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 5e9dd90e782..cbec033263d 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -109,3 +109,4 @@ rocketchat:chatops # sanjo:jasmine # velocity:html-reporter ddp-rate-limiter +rzymek:moment-locale-zh-cn diff --git a/.meteor/versions b/.meteor/versions index 2381327fbb3..70eb4294f12 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -149,6 +149,7 @@ rocketchat:theme@0.0.1 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 +rzymek:moment-locale-zh-cn@2.9.0 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 diff --git a/client/methods/saveRoomName.coffee b/client/methods/saveRoomName.coffee index 2072d68fa0b..659b8a35a8e 100644 --- a/client/methods/saveRoomName.coffee +++ b/client/methods/saveRoomName.coffee @@ -8,7 +8,7 @@ Meteor.methods if room.u._id isnt Meteor.userId() or room.t not in ['c', 'p'] throw new Meteor.Error 403, t('Not allowed') - name = _.slugify name + # name = _.slugify name if name is room.name return diff --git a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json index 16c8109f51a..69bde52fbee 100644 --- a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json +++ b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json @@ -54,9 +54,6 @@ "xml-crypto": { "version": "0.6.0", "dependencies": { - "xmldom": { - "version": "0.1.19" - }, "xpath.js": { "version": "1.0.6" } diff --git a/server/methods/getUsernameSuggestion.coffee b/server/methods/getUsernameSuggestion.coffee index afe5b6609d7..f9732af56db 100644 --- a/server/methods/getUsernameSuggestion.coffee +++ b/server/methods/getUsernameSuggestion.coffee @@ -15,25 +15,25 @@ usernameIsAvaliable = (username) -> usernames = [] username = undefined - usernames.push slug user.name + usernames.push user.name nameParts = user?.name?.split() if nameParts.length > 1 first = nameParts[0] last = nameParts[nameParts.length - 1] - usernames.push slug first[0] + last - usernames.push slug first + last[0] + usernames.push first[0] + last + usernames.push first + last[0] if user.profile?.name? - usernames.push slug user.profile.name + usernames.push user.profile.name if user.services? for serviceName, service of user.services if service.name? - usernames.push slug service.name + usernames.push service.name else if service.username? - usernames.push slug service.username + usernames.push service.username if user.emails?.length > 0 for email in user.emails when email.address? and email.verified is true -- GitLab From 448fae3e80e6efb745c26df27956cb0867fd3aef Mon Sep 17 00:00:00 2001 From: pauking <pauking@sinoqual.com> Date: Sat, 17 Oct 2015 07:49:33 +0800 Subject: [PATCH 0138/1338] roll back client/views/app/tabBar/membersList.html --- client/views/app/tabBar/membersList.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/tabBar/membersList.html b/client/views/app/tabBar/membersList.html index 4a491ca988b..9ac9f2a9525 100644 --- a/client/views/app/tabBar/membersList.html +++ b/client/views/app/tabBar/membersList.html @@ -8,7 +8,7 @@ <h2>{{_ "Members_List"}}</h2> <p> {{{_ "Showing_online_users" total_online=totalOnline total=total}}} - <button class="see-all">{{seeAll}}</button> + {{!--<button class="see-all">{{seeAll}}</button>--}} </p> {{> videoButtons}} {{#if canAddUser}} -- GitLab From cbff7498c6f8179ebe1734c6a0d11fa96b7b7fea Mon Sep 17 00:00:00 2001 From: sunnipaul <sunnipaul@gmail.com> Date: Sat, 17 Oct 2015 08:52:01 +0800 Subject: [PATCH 0139/1338] Update restapi.coffee --- server/restapi/restapi.coffee | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 023240c9d1a..4bc0eb29edb 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -20,16 +20,6 @@ Api.addRoute 'rooms/:id/join', authRequired: true, Meteor.runAsUser this.userId, () => Meteor.call('joinRoom', @urlParams.id) status: 'success' # need to handle error - -# find or create a room -Api.addRoute 'rooms/findorcreatethenjoin', authRequired: true, - post: -> - roomname = @bodyParams.roomname - usernames = @bodyParams.usernames - Meteor.runAsUser this.userId, () => - Meteor.call('findOrCreateRoomThenJoin', roomname , usernames) - status: 'success' # need to handle error - # leave a room Api.addRoute 'rooms/:id/leave', authRequired: true, -- GitLab From e485345f969723f8ba6f4951e01adc2e74699c78 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 17 Oct 2015 08:55:12 -0400 Subject: [PATCH 0140/1338] update readme for v0.7 --- README.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index f956bce96ba..f295189b859 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,8 @@ Try it on Ubuntu: Try it with docker: -``` -docker-compose up -``` +[Deploy with docker](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-with-Docker) -and check it out at http://localhost:80 Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron](https://github.com/RocketChat/Rocket.Chat.Electron/releases) @@ -81,23 +78,29 @@ It is a great solution for communities and companies wanting to privately host t - Avatars - Markdown - Emojis +- Media Embeds +- Link Previews - Sent Message Edit and Deletion - Transcripts / History - File Upload / Sharing - Full text search +- Live chat / Messaging call center +- LDAP Authentication - Support for Okta SSO through SAML v2 -- Live chat / Messaging call center - Alpha testing now! [Issue #519](https://github.com/RocketChat/Rocket.Chat/issues/519) -- I18n - Supports 22 Languages [Internationalization with Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard) -- Hubot Friendly - [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) -- Media Embeds -- Link Previews -- LDAP Authentication - [LDAP Authentication on Rocket.Chat Wiki](https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication) -- Face to Face Video Conferencing aka WebRTC (Alpha) - [How to video chat](https://github.com/RocketChat/Rocket.Chat/wiki/Using-Face-to-face-video-conference-%28aka-webrtc%29) -- REST APIs - [Ready for testing ...](https://github.com/RocketChat/Rocket.Chat/wiki/REST-APIs) -- Remote Locations Video Monitoring - [Early access ...](https://github.com/RocketChat/Rocket.Chat/wiki/Remote-Video-Monitoring) -- Native Cross-Platform Desktop Application [Rocket.Chat.Electron - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.Electron/releases) +- I18n - Supports 22 Languages +- Hubot Friendly +- Face to Face Video Conferencing (aka WebRTC) +- Multi-users Video Group Chat +- Audio calls +- Multi-users Audio Conference +- Screensharing +- Chat-ops powered by Hubot: scalable horizontal app integration (early access) +- REST APIs +- Remote Locations Video Monitoring +- Native Cross-Platform Desktop Application [Windows, Mac OSX, or Linux](https://rocket.chat/) - Mobile app for iPhone, iPad, and iPod touch [Download on AppStore!](https://geo.itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) - Mobile app for Android phone, tablet, and TV stick [Available now on Google Play!](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) +- Sandstorm.io instant Rocket.Chat server [Now on Sandstorm App Store](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) ### Roadmap @@ -108,8 +111,7 @@ It is a great solution for communities and companies wanting to privately host t - Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) - Off-the-Record (OTR) Messaging [Issue #36](https://github.com/RocketChat/Rocket.Chat/issues/36), [Issue #268 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/268) - API-enabled methods: [Issue #202](https://github.com/RocketChat/Rocket.Chat/issues/202), [Issue #454](https://github.com/RocketChat/Rocket.Chat/issues/454), [Issue #455](https://github.com/RocketChat/Rocket.Chat/issues/455), [Issue #759](https://github.com/RocketChat/Rocket.Chat/issues/759) -- Voice calls: [Issue #542](https://github.com/RocketChat/Rocket.Chat/issues/542) -- Screensharing: [Issue #418](https://github.com/RocketChat/Rocket.Chat/issues/418) + #### Planned - Kerberos Authentication: [Issue #839](https://github.com/RocketChat/Rocket.Chat/issues/839) -- GitLab From c5547be1192f5ee5556e8847d6bba98aa13798ab Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 17 Oct 2015 10:02:48 -0300 Subject: [PATCH 0141/1338] Added "FileUpload" settings group --- i18n/en.i18n.json | 4 ++++ i18n/pt.i18n.json | 6 +++++- packages/rocketchat-lib/settings/server/startup.coffee | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 05fd9bcc314..01d2fa52b40 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -116,6 +116,10 @@ "Esc_to" : "Esc to", "False" : "False", "Favorites" : "Favorites", + "FileUpload" : "File Upload", + "FileUpload_Enabled" : "Enable file upload", + "FileUpload_MaxFileSize" : "Max. size for uploaded files (in bytes)", + "FileUpload_MediaTypeWhiteList" : "Comma-separated Media Type list", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", "Fork_it_on_github" : "Fork it on github", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 68d9e6d23d6..e467246e160 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -110,6 +110,10 @@ "Esc_to" : "Esc para", "False" : "Falso", "Favorites" : "Favoritos", + "FileUpload" : "Upload de Arquivos", + "FileUpload_Enabled" : "Habilitar upload de arquivos", + "FileUpload_MaxFileSize" : "Tamanho máximo dos arquivos (em bytes)", + "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia (separados por vÃrgula)", "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", @@ -179,7 +183,7 @@ "Message_deleting_not_allowed" : "Exclusão de mensagem não permitido", "Message_editing_not_allowed" : "Edição de mensagem não permitido", "Message_editing_blocked" : "Esta mensagem não pode mais ser editada", - "Message_MaxAllowedSize" : "Tamanho máximo de mensagem permitido ", + "Message_MaxAllowedSize" : "Tamanho máximo de mensagem permitido ", "Message_pinning_not_allowed" : "Não Permitir Fixar Mensagem", "Message_KeepHistory" : "Manter Histórico de Mensagens", "Message_removed" : "Mensagem removida", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 2f755d2d045..e6c3fa4df82 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -34,6 +34,11 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', grou 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.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/*', { type: 'string', group: 'FileUpload', public: true } + 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 } -- GitLab From 7296eac602bce8d4a43d171df5e8ebb7f6510ed5 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 17 Oct 2015 09:04:09 -0400 Subject: [PATCH 0142/1338] update readme for v0.7 --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f295189b859..aa7b191be80 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@  -The Complete Open Source Chat Solution +The Complete Open Source Chat Platform ## Demo @@ -94,9 +94,9 @@ It is a great solution for communities and companies wanting to privately host t - Audio calls - Multi-users Audio Conference - Screensharing -- Chat-ops powered by Hubot: scalable horizontal app integration (early access) - REST APIs - Remote Locations Video Monitoring +- Chat-ops powered by Hubot: scalable horizontal app integration (early access) - Native Cross-Platform Desktop Application [Windows, Mac OSX, or Linux](https://rocket.chat/) - Mobile app for iPhone, iPad, and iPod touch [Download on AppStore!](https://geo.itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) - Mobile app for Android phone, tablet, and TV stick [Available now on Google Play!](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) @@ -106,22 +106,24 @@ It is a great solution for communities and companies wanting to privately host t ### Roadmap #### In Progress +- Support multiple teams on the same instance / same VPS infrastructure: [Issue #658](https://github.com/RocketChat/Rocket.Chat/issues/658), [Issue #630](https://github.com/RocketChat/Rocket.Chat/issues/630) - Support for PostgreSQL: [Issue #533](https://github.com/RocketChat/Rocket.Chat/issues/533), [Issue #822](https://github.com/RocketChat/Rocket.Chat/issues/822) - Native iOS Application [Issue #270](https://github.com/RocketChat/Rocket.Chat/issues/270), [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) - Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) - Off-the-Record (OTR) Messaging [Issue #36](https://github.com/RocketChat/Rocket.Chat/issues/36), [Issue #268 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/268) - API-enabled methods: [Issue #202](https://github.com/RocketChat/Rocket.Chat/issues/202), [Issue #454](https://github.com/RocketChat/Rocket.Chat/issues/454), [Issue #455](https://github.com/RocketChat/Rocket.Chat/issues/455), [Issue #759](https://github.com/RocketChat/Rocket.Chat/issues/759) +- Scalable WebRTC broadcaster / media-server integration, [Issue #1118 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/1118) #### Planned - Kerberos Authentication: [Issue #839](https://github.com/RocketChat/Rocket.Chat/issues/839) - XMPP Multi-user chat (MUC): [Issue #404](https://github.com/RocketChat/Rocket.Chat/issues/404) - More webhooks: GitLab, Confluence, Jira, Piwik, Wordpress: [Issue #233](https://github.com/RocketChat/Rocket.Chat/issues/233), [Issue #525](https://github.com/RocketChat/Rocket.Chat/issues/525), [Issue #637](https://github.com/RocketChat/Rocket.Chat/issues/637), [Issue #638](https://github.com/RocketChat/Rocket.Chat/issues/638), [Issue #747](https://github.com/RocketChat/Rocket.Chat/issues/747) -- Support multiple teams on the same instance / same VPS infrastructure: [Issue #658](https://github.com/RocketChat/Rocket.Chat/issues/658), [Issue #630](https://github.com/RocketChat/Rocket.Chat/issues/630) - Clusterize / Descentralize: [Issue #520](https://github.com/RocketChat/Rocket.Chat/issues/520), [Issue #601](https://github.com/RocketChat/Rocket.Chat/issues/601) - Anonymous use of Rocket.Chat: [Issue #604](https://github.com/RocketChat/Rocket.Chat/issues/604) - File Sharing via P2P and Scalable Multicast: [Issue #369](https://github.com/RocketChat/Rocket.Chat/issues/369), [Issue #370](https://github.com/RocketChat/Rocket.Chat/issues/370) - Anti-virus checking on file uploads: [Issue #757](https://github.com/RocketChat/Rocket.Chat/issues/757) +- Massively scalable hosting and provisioning ### Issues -- GitLab From 51ffb4f5da328ef4f65b705f6e9824bcbcdc6e80 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 17 Oct 2015 10:05:36 -0300 Subject: [PATCH 0143/1338] Providing access to settings subscription in order to setup client-side upload objects --- packages/rocketchat-lib/package.js | 2 -- packages/rocketchat-lib/settings/client/rocketchat.coffee | 3 ++- packages/rocketchat-lib/settings/client/startup.coffee | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 packages/rocketchat-lib/settings/client/startup.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index cd20abff3c4..6df34893079 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -44,13 +44,11 @@ Package.onUse(function(api) { api.addFiles('settings/lib/settings.coffee'); - // CLIENT api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); api.addFiles('client/MessageAction.coffee', 'client'); - api.addFiles('settings/client/startup.coffee', 'client'); api.addFiles('settings/client/rocketchat.coffee', 'client'); // SERVER diff --git a/packages/rocketchat-lib/settings/client/rocketchat.coffee b/packages/rocketchat-lib/settings/client/rocketchat.coffee index 3e30a004cb4..4fff6096b2d 100644 --- a/packages/rocketchat-lib/settings/client/rocketchat.coffee +++ b/packages/rocketchat-lib/settings/client/rocketchat.coffee @@ -5,8 +5,9 @@ settingsDict = new ReactiveDict('settings') +RocketChat.settings.subscription = Meteor.subscribe 'settings' RocketChat.settings.get = (_id) -> return settingsDict.get(_id) RocketChat.settings.onload '*', (key, value) -> - return settingsDict.set key, value + return settingsDict.set key, value \ No newline at end of file diff --git a/packages/rocketchat-lib/settings/client/startup.coffee b/packages/rocketchat-lib/settings/client/startup.coffee deleted file mode 100644 index 9e4f4b080ae..00000000000 --- a/packages/rocketchat-lib/settings/client/startup.coffee +++ /dev/null @@ -1,2 +0,0 @@ -Meteor.startup -> - Meteor.subscribe 'settings' -- GitLab From 208ae725abb231d425bad0126897ae827613f200 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 17 Oct 2015 10:07:48 -0300 Subject: [PATCH 0144/1338] Applying newly-added file upload settings. --- client/views/app/room.coffee | 3 +++ client/views/app/room.html | 4 ++-- lib/fileUpload.coffee | 32 ++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index db74d4a9b22..32c57de48d5 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -221,6 +221,9 @@ Template.room.helpers compactView: -> return 'compact' if Meteor.user()?.settings?.preferences?.compactView + fileUploadAllowedMediaTypes: -> + return RocketChat.settings.get('FileUpload_MediaTypeWhiteList') + Template.room.events "touchstart .message": (e, t) -> message = this._arguments[1] diff --git a/client/views/app/room.html b/client/views/app/room.html index ff971c070aa..fd3b053b498 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -81,7 +81,7 @@ <div style="display: flex"> <div class="file"> <i class="octicon octicon-cloud-upload file"></i> - <input type="file" accept="image/*"> + <input type="file" accept="{{fileUploadAllowedMediaTypes}}"> </div> <div class="input-message-container"> {{> messagePopupConfig getPupupConfig}} @@ -152,4 +152,4 @@ {{> Template.dynamic template=flexTemplate data=flexData}} </section> </div> -</template> +</template> \ No newline at end of file diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index d6a602ba922..67e71cc3460 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -1,6 +1,5 @@ if UploadFS? @fileCollection = new Mongo.Collection 'rocketchat_uploads' - fileCollection.allow insert: (userId, doc) -> return userId @@ -11,14 +10,23 @@ if UploadFS? remove: (userId, doc) -> return userId is doc.userId - Meteor.fileStore = new UploadFS.store.GridFS - collection: fileCollection - name: 'rocketchat_uploads' - collectionName: 'rocketchat_uploads' - filter: new UploadFS.Filter - maxSize: 2097152 - contentTypes: ['image/*', 'audio/*'] - onFinishUpload: -> - console.log arguments - onRead: (fileId, file, req, res) -> - res.setHeader 'content-disposition', 'download' + initFileStore = -> + Meteor.fileStore = new UploadFS.store.GridFS + collection: fileCollection + name: 'rocketchat_uploads' + collectionName: 'rocketchat_uploads' + filter: new UploadFS.Filter + maxSize: RocketChat.settings.get('FileUpload_MaxFileSize') + contentTypes: _.map(RocketChat.settings.get('FileUpload_MediaTypeWhiteList').split(','), (item) -> return item.trim() ) + onFinishUpload: -> + console.log arguments + onRead: (fileId, file, req, res) -> + res.setHeader 'content-disposition', 'download' + + if Meteor.isServer + initFileStore() + else + Tracker.autorun (c) -> + if RocketChat.settings.subscription.ready() + initFileStore() + c.stop() -- GitLab From 3001bd092ea1d61bbfe112c7b615d612f6d9576a Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 17 Oct 2015 10:08:56 -0300 Subject: [PATCH 0145/1338] Updating jalik:ufs and jalik:ufs-gridfs --- .meteor/versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 2381327fbb3..4b911104a02 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -52,8 +52,8 @@ htmljs@1.0.5 http@1.1.1 id-map@1.0.4 idorecall:email-normalize@1.0.0 -jalik:ufs@0.2.9 -jalik:ufs-gridfs@0.1.0 +jalik:ufs@0.3.0 +jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 -- GitLab From b72d302e253ef94c6c59227e22427d08ac4814bf Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 17 Oct 2015 10:10:40 -0300 Subject: [PATCH 0146/1338] Blocking drag and drop file uploads of any kind. --- client/lib/fileUpload.coffee | 2 ++ lib/fileUpload.coffee | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/client/lib/fileUpload.coffee b/client/lib/fileUpload.coffee index 533f20a70b3..1cfba202797 100644 --- a/client/lib/fileUpload.coffee +++ b/client/lib/fileUpload.coffee @@ -24,6 +24,8 @@ readAsArrayBuffer = (file, callback) -> return readAsDataURL file.file, (fileContent) -> + return unless fileUploadIsValidContentType file.file.type + text = '' if file.type is 'audio' diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 67e71cc3460..06797a05ad4 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -10,6 +10,24 @@ if UploadFS? remove: (userId, doc) -> return userId is doc.userId + + fileUploadMediaWhiteList = -> + return _.map(RocketChat.settings.get('FileUpload_MediaTypeWhiteList').split(','), (item) -> return item.trim() ) + + @fileUploadIsValidContentType = (type) -> + list = fileUploadMediaWhiteList() + + if _.contains list, type + return true + else + wildCardGlob = '/*' + wildcards = _.filter list, (item) -> return item.indexOf(wildCardGlob) > 0 + + if _.contains wildcards, type.replace(/(\/.*)$/, wildCardGlob) + return true; + + return false; + initFileStore = -> Meteor.fileStore = new UploadFS.store.GridFS collection: fileCollection @@ -17,7 +35,7 @@ if UploadFS? collectionName: 'rocketchat_uploads' filter: new UploadFS.Filter maxSize: RocketChat.settings.get('FileUpload_MaxFileSize') - contentTypes: _.map(RocketChat.settings.get('FileUpload_MediaTypeWhiteList').split(','), (item) -> return item.trim() ) + contentTypes: fileUploadMediaWhiteList() onFinishUpload: -> console.log arguments onRead: (fileId, file, req, res) -> -- GitLab From 24ab50a1ce266a4c992b3b8910a82af0743349b2 Mon Sep 17 00:00:00 2001 From: Liam Dawson <liam@liamdawson.me> Date: Sun, 18 Oct 2015 00:20:43 +1000 Subject: [PATCH 0147/1338] =?UTF-8?q?Add=20target=3D"=5Fblank"=20for=20mar?= =?UTF-8?q?kdown=20links=20=E2=80=94=20fixes=20#1113?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/rocketchat-markdown/markdown.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index e8822d3f421..2d1f1cfece7 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -14,7 +14,7 @@ class Markdown msg = msg.replace(/!\[(.*)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$2" title="$1" class="swipebox" target="_blank"><div class="inline-image" style="background-image: url($2);"></div></a>') # Support [Text](http://link) - msg = msg.replace(/\[(([\d\w\.-_] ?)+)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$3">$1</a>') + msg = msg.replace(/\[(([\d\w\.-_] ?)+)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$3" target="_blank">$1</a>') if RocketChat.settings.get('Markdown_Headers') # Support # Text for h1 -- GitLab From 132c1bb2ac7062c218267a679c20d462ed94b86f Mon Sep 17 00:00:00 2001 From: Liam Dawson <liam@liamdawson.me> Date: Sun, 18 Oct 2015 01:20:41 +1000 Subject: [PATCH 0148/1338] Change messagePopup regex to accept all non-whitespace Addresses #1141 --- client/views/app/messagePopup.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/views/app/messagePopup.coffee b/client/views/app/messagePopup.coffee index cbfa585796f..e154bd0c876 100644 --- a/client/views/app/messagePopup.coffee +++ b/client/views/app/messagePopup.coffee @@ -44,13 +44,13 @@ Template.messagePopup.onCreated -> template.suffix = val(template.data.suffix, ' ') if template.triggerAnywhere is true - template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^| )#{template.trigger}[A-Za-z0-9-_.]*$") + template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^| )#{template.trigger}[^\s]*$") else - template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^)#{template.trigger}[A-Za-z0-9-_.]*$") + template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^)#{template.trigger}[^\s]*$") - template.selectorRegex = val(template.data.selectorRegex, new RegExp "#{template.trigger}([A-Za-z0-9-_.]*)$") + template.selectorRegex = val(template.data.selectorRegex, new RegExp "#{template.trigger}([^\s]*)$") - template.replaceRegex = val(template.data.replaceRegex, new RegExp "#{template.trigger}[A-Za-z0-9-_.]*$") + template.replaceRegex = val(template.data.replaceRegex, new RegExp "#{template.trigger}[^\s]*$") template.getValue = val template.data.getValue, (_id) -> return _id -- GitLab From 111df9d25f1548a13b40ffe5fbab903ce984aae8 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sat, 17 Oct 2015 14:05:55 -0400 Subject: [PATCH 0149/1338] Remove unnecessary chatops pkg line remove unnecessary line --- .meteor/packages | 1 - 1 file changed, 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index 5e9dd90e782..e57d4decf1a 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -105,7 +105,6 @@ ejson spacebars check rocketchat:github-enterprise -rocketchat:chatops # sanjo:jasmine # velocity:html-reporter ddp-rate-limiter -- GitLab From a63d62095df57790c1c33b9f347c6eefc691b01e Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 17 Oct 2015 15:21:16 -0400 Subject: [PATCH 0150/1338] announce chatops early access --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa7b191be80..5c1ec83f1a3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@  -The Complete Open Source Chat Platform +The Ultimate Open Source WebChat Platform ## Demo @@ -137,6 +137,13 @@ The docker image is ready. Everyone can start hacking the adapter code, or launch his/her own bot within a few minutes now. Please head over to the [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) for more information. + +#### Chat-ops integrations powered by Hubot + +Integrate your application with fly-in panels today! Early access is available for developers. + +[Sample integration of a Drones Fleet Management System](https://raw.githubusercontent.com/Sing-Li/bbug/master/images/dronechatops.png) + #### Many, many, many more to come! We are developing the APIs based on the competition, so stay tuned and you will see a lot happening here. -- GitLab From ac0c3e6e41d095cdcb9dd19f20cffcc7e9d6878b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 17 Oct 2015 15:24:08 -0400 Subject: [PATCH 0151/1338] minor typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c1ec83f1a3..c3181d68fe8 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Please head over to the [Hubot Integration Project](https://github.com/RocketCha Integrate your application with fly-in panels today! Early access is available for developers. -[Sample integration of a Drones Fleet Management System](https://raw.githubusercontent.com/Sing-Li/bbug/master/images/dronechatops.png) + #### Many, many, many more to come! -- GitLab From 7900fdf66aa98054585575a47dc3ef63d156ecfd Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Sun, 18 Oct 2015 04:49:08 +0100 Subject: [PATCH 0152/1338] no message --- client/views/account/accountProfile.coffee | 12 +++++++++++- client/views/account/accountProfile.html | 6 +++++- i18n/en.i18n.json | 1 + .../rocketchat-lib/settings/server/startup.coffee | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 9bd7703bb67..e72e332e902 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -11,6 +11,14 @@ Template.accountProfile.helpers username: -> return Meteor.user().username + + allowUsernameChange: -> + return Settings.findOne("Accounts_AllowUsernameChange").value + + usernameChangeDisabled: -> + return t('Username_Change_Disabled') + + Template.accountProfile.onCreated -> settingsTemplate = this.parentTemplate(3) @@ -38,7 +46,9 @@ Template.accountProfile.onCreated -> @save = -> instance = @ - + if !Settings.findOne("Allow_Username_Change").value + toastr.error t('Username_Change_Disabled') + return callback() oldPassword = _.trim($('#oldPassword').val()) newPassword = _.trim($('#password').val()) diff --git a/client/views/account/accountProfile.html b/client/views/account/accountProfile.html index 9af06a11572..f8981c76aa8 100644 --- a/client/views/account/accountProfile.html +++ b/client/views/account/accountProfile.html @@ -12,7 +12,11 @@ <div class="input-line"> <label for="username">{{_ "Username"}}</label> <div> - <input type="text" name="username" id="username" placeholder="{{username}}" /> + {{#if allowUsernameChange}} + <input type="text" name="username" id="username" placeholder="{{username}}" /> + {{else}} + <input type="text" name="username" id="username" placeholder="{{username}}" disabled="disabled" title="{{usernameChangeDisabled}}" /> + {{/if}} </div> </div> <div class="input-line"> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 05fd9bcc314..3a4973d36b3 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -2,6 +2,7 @@ "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", + "Accounts_AllowUsernameChange" : "Allow Username Change", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", "Accounts_OAuth_Facebook" : "Facebook Login", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 2f755d2d045..45f48a07746 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -34,6 +34,8 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', grou 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_AllowUsernameChange', true, { type: 'boolean', group: 'Accounts', section: 'General' } + 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 } -- GitLab From 3a540a1aad64c371e4dc2e0a4fd98a8e1eb39dec Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Sun, 18 Oct 2015 04:58:09 +0100 Subject: [PATCH 0153/1338] no message --- i18n/en.i18n.json | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3a4973d36b3..6ca91ab55bd 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -359,6 +359,7 @@ "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", + "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "User_has_been_deactivated" : "User has been deactivated", "User_has_been_deleted" : "User has been deleted", "User_Info" : "User Info", -- GitLab From 9fef449fb676295d9a97fac6d6bc433a35207b56 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Sun, 18 Oct 2015 05:26:33 +0100 Subject: [PATCH 0154/1338] Make Account_AllowUsernameChange public --- packages/rocketchat-lib/settings/server/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 45f48a07746..3e97c978e4f 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -34,7 +34,7 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', grou 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_AllowUsernameChange', true, { type: 'boolean', group: 'Accounts', section: 'General' } +RocketChat.settings.add 'Accounts_AllowUsernameChange', true, { type: 'boolean', group: 'Accounts', section: 'General', public: true } RocketChat.settings.addGroup 'General' RocketChat.settings.add 'Site_Url', __meteor_runtime_config__?.ROOT_URL, { type: 'string', group: 'General', i18nDescription: 'Site_Url_Description', public: true } -- GitLab From bccadba58fdcf4228ac98591a74820a8303f7f95 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Sun, 18 Oct 2015 05:31:00 +0100 Subject: [PATCH 0155/1338] Use correct setting on form save --- client/views/account/accountProfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index e72e332e902..449c7e59161 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -46,7 +46,7 @@ Template.accountProfile.onCreated -> @save = -> instance = @ - if !Settings.findOne("Allow_Username_Change").value + if !Settings.findOne("Accounts_AllowUsernameChange").value toastr.error t('Username_Change_Disabled') return callback() oldPassword = _.trim($('#oldPassword').val()) -- GitLab From b3b8c3362ba5e74f5e7b23ab52e0919b63e0001f Mon Sep 17 00:00:00 2001 From: Junjie Huang <umcsdon@outlook.com> Date: Sun, 18 Oct 2015 05:57:39 -0500 Subject: [PATCH 0156/1338] Display Meteor package version information --- .travis/setbuildinfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index 00229e2247b..ffef83bd3bc 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -1,5 +1,5 @@ var BUILD_INFO_PATH = '../public/buildinfo/buildinfo.txt'; -var PACKAGES_PATH = '../.meteor/packages'; +var PACKAGES_PATH = '../.meteor/versions'; var BUILD_PATH = '../../build'; var LineByLineReader = require('line-by-line'); var mkdirp = require('mkdirp'); -- GitLab From d26356b1129d77e8c9a9ae8ead3d5616abcdcd01 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Sun, 18 Oct 2015 15:55:26 +0200 Subject: [PATCH 0157/1338] Create spotify integration client unit tests --- .../{ => lib}/client/oembedSpotifyWidget.html | 0 .../{ => lib}/client/widget.coffee | 0 .../{ => lib}/spotify.coffee | 3 +- packages/rocketchat-spotify/package.js | 6 +-- tests/jasmine/client/unit/spotifytest.coffee | 52 +++++++++++++++++++ 5 files changed, 57 insertions(+), 4 deletions(-) rename packages/rocketchat-spotify/{ => lib}/client/oembedSpotifyWidget.html (100%) rename packages/rocketchat-spotify/{ => lib}/client/widget.coffee (100%) rename packages/rocketchat-spotify/{ => lib}/spotify.coffee (94%) create mode 100644 tests/jasmine/client/unit/spotifytest.coffee diff --git a/packages/rocketchat-spotify/client/oembedSpotifyWidget.html b/packages/rocketchat-spotify/lib/client/oembedSpotifyWidget.html similarity index 100% rename from packages/rocketchat-spotify/client/oembedSpotifyWidget.html rename to packages/rocketchat-spotify/lib/client/oembedSpotifyWidget.html diff --git a/packages/rocketchat-spotify/client/widget.coffee b/packages/rocketchat-spotify/lib/client/widget.coffee similarity index 100% rename from packages/rocketchat-spotify/client/widget.coffee rename to packages/rocketchat-spotify/lib/client/widget.coffee diff --git a/packages/rocketchat-spotify/spotify.coffee b/packages/rocketchat-spotify/lib/spotify.coffee similarity index 94% rename from packages/rocketchat-spotify/spotify.coffee rename to packages/rocketchat-spotify/lib/spotify.coffee index e5997acf722..330c359e317 100644 --- a/packages/rocketchat-spotify/spotify.coffee +++ b/packages/rocketchat-spotify/lib/spotify.coffee @@ -24,7 +24,7 @@ class Spotify changed = false process message, message.msg, (message, msgParts, index, part) -> - re = /(?:^|\s)spotify:([^:]+):([^:]+)(?::([^:]+))?(?::(\S+))?(?:\s|$)/g + re = /(?:^|\s)spotify:([^:\s]+):([^:\s]+)(?::([^:\s]+))?(?::(\S+))?(?:\s|$)/g while match = re.exec(part) data = _.filter match.slice(1), (value) -> return value? @@ -55,3 +55,4 @@ class Spotify RocketChat.callbacks.add 'beforeSaveMessage', Spotify.transform, RocketChat.callbacks.priority.LOW RocketChat.callbacks.add 'renderMessage', Spotify.render +RocketChat.Spotify = Spotify diff --git a/packages/rocketchat-spotify/package.js b/packages/rocketchat-spotify/package.js index 3bf70a29597..4940ac69ed8 100644 --- a/packages/rocketchat-spotify/package.js +++ b/packages/rocketchat-spotify/package.js @@ -16,10 +16,10 @@ Package.onUse(function(api) { 'rocketchat:lib@0.0.1' ]); - api.addFiles('client/widget.coffee', 'client'); - api.addFiles('client/oembedSpotifyWidget.html', 'client'); + api.addFiles('lib/client/widget.coffee', 'client'); + api.addFiles('lib/client/oembedSpotifyWidget.html', 'client'); - api.addFiles('spotify.coffee', ['server','client']); + api.addFiles('lib/spotify.coffee', ['server','client']); }); Package.onTest(function(api) { diff --git a/tests/jasmine/client/unit/spotifytest.coffee b/tests/jasmine/client/unit/spotifytest.coffee new file mode 100644 index 00000000000..3810dec452e --- /dev/null +++ b/tests/jasmine/client/unit/spotifytest.coffee @@ -0,0 +1,52 @@ +describe 'Spotify integration', () -> + describe 'Spotify id transformer', () -> + it 'should transform track id to link and add it to message urls', () -> + message = {'urls': [], 'msg': 'spotify:track:34AWo71Ya5gq7wpNnatwr7'} + output = RocketChat.Spotify.transform message + expect(output).toEqual {'urls':[{'url': 'https://open.spotify.com/track/34AWo71Ya5gq7wpNnatwr7', 'source':'spotify:track:34AWo71Ya5gq7wpNnatwr7'}], 'msg': 'spotify:track:34AWo71Ya5gq7wpNnatwr7'} + + it 'should transform artist id to link and add it to message urls', () -> + message = {'urls': [], 'msg': 'spotify:artist:0OdUWJ0sBjDrqHygGUXeCF'} + output = RocketChat.Spotify.transform message + expect(output).toEqual {'urls':[{'url': 'https://open.spotify.com/artist/0OdUWJ0sBjDrqHygGUXeCF', 'source': 'spotify:artist:0OdUWJ0sBjDrqHygGUXeCF'}], 'msg': 'spotify:artist:0OdUWJ0sBjDrqHygGUXeCF'} + + it 'should transform album id to link and add it to message urls', () -> + message = {'urls': [], 'msg': 'spotify:album:0sNOF9WDwhWunNAHPD3Baj'} + output = RocketChat.Spotify.transform message + expect(output).toEqual {'urls':[{'url': 'https://open.spotify.com/album/0sNOF9WDwhWunNAHPD3Baj', 'source': 'spotify:album:0sNOF9WDwhWunNAHPD3Baj'}], 'msg': 'spotify:album:0sNOF9WDwhWunNAHPD3Baj'} + + it 'should transform user playlist id to link and add it to message urls', () -> + message = {'urls': [], 'msg': 'spotify:user:spotifybrazilian:playlist:4k7EZPI3uKMz4aRRrLVfen'} + output = RocketChat.Spotify.transform message + expect(output).toEqual {'urls':[{'url': 'https://open.spotify.com/user/spotifybrazilian/playlist/4k7EZPI3uKMz4aRRrLVfen', 'source': 'spotify:user:spotifybrazilian:playlist:4k7EZPI3uKMz4aRRrLVfen'}], 'msg': 'spotify:user:spotifybrazilian:playlist:4k7EZPI3uKMz4aRRrLVfen'} + + it 'should transform id to link even if wrapped around text', () -> + message = {'urls': [], 'msg': 'a text before spotify:track:34AWo71Ya5gq7wpNnatwr7 a text after'} + output = RocketChat.Spotify.transform message + expect(output).toEqual {'urls':[{'url': 'https://open.spotify.com/track/34AWo71Ya5gq7wpNnatwr7', 'source':'spotify:track:34AWo71Ya5gq7wpNnatwr7'}], 'msg': 'a text before spotify:track:34AWo71Ya5gq7wpNnatwr7 a text after'} + + it 'should transform id to link and add it to message urls without erasing previous urls', () -> + message = {'urls': [{'url': 'https://www.youtube.com/watch?v=_ze-sS61mCs'}], 'msg': 'https://www.youtube.com/watch?v=_ze-sS61mCs and spotify:track:34AWo71Ya5gq7wpNnatwr7'} + output = RocketChat.Spotify.transform message + expect(output).toEqual {'urls':[{'url': 'https://www.youtube.com/watch?v=_ze-sS61mCs'}, {'url': 'https://open.spotify.com/track/34AWo71Ya5gq7wpNnatwr7', 'source':'spotify:track:34AWo71Ya5gq7wpNnatwr7'}], 'msg': 'https://www.youtube.com/watch?v=_ze-sS61mCs and spotify:track:34AWo71Ya5gq7wpNnatwr7'} + + it 'should not apply transformation on links inside inline literal', () -> + message = {'urls': [], 'msg': '`spotify:track:34AWo71Ya5gq7wpNnatwr7`'} + output = RocketChat.Spotify.transform message + expect(output).toEqual message + + it 'should not apply transformation on links inside code block', () -> + message = {'urls': [], 'msg': '``` spotify:track:34AWo71Ya5gq7wpNnatwr7 ```'} + output = RocketChat.Spotify.transform message + expect(output).toEqual message + + describe 'Spotify id autolinker', () -> + it 'should autolink spotify id', () -> + message = RocketChat.Spotify.transform {'urls': [], 'msg': 'spotify:track:34AWo71Ya5gq7wpNnatwr7', 'html': 'spotify:track:34AWo71Ya5gq7wpNnatwr7'} + output = RocketChat.Spotify.render message + expect(output.html).toEqual '<a href="https://open.spotify.com/track/34AWo71Ya5gq7wpNnatwr7" target="_blank">spotify:track:34AWo71Ya5gq7wpNnatwr7</a>' + + it 'should autolink spotify id even if wrapped around text', () -> + message = RocketChat.Spotify.transform {'urls': [], 'msg': 'a text before spotify:track:34AWo71Ya5gq7wpNnatwr7 a text after', 'html': 'a text before spotify:track:34AWo71Ya5gq7wpNnatwr7 a text after'} + output = RocketChat.Spotify.render message + expect(output.html).toEqual 'a text before <a href="https://open.spotify.com/track/34AWo71Ya5gq7wpNnatwr7" target="_blank">spotify:track:34AWo71Ya5gq7wpNnatwr7</a> a text after' -- GitLab From f66ab732b8b122bda30afa854cec7de9695b3dd9 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Sun, 18 Oct 2015 18:51:01 +0200 Subject: [PATCH 0158/1338] SoundCloud embed widget integration Currently does not support *group* embed widget (like https://soundcloud.com/groups/made-with-ableton-live) --- .meteor/packages | 1 + .../rocketchat-oembed/server/server.coffee | 3 +++ .../lib/client/oembedSoundcloudWidget.html | 13 +++++++++++ .../lib/client/widget.coffee | 3 +++ packages/rocketchat-soundcloud/package.js | 23 +++++++++++++++++++ 5 files changed, 43 insertions(+) create mode 100644 packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html create mode 100644 packages/rocketchat-soundcloud/lib/client/widget.coffee create mode 100644 packages/rocketchat-soundcloud/package.js diff --git a/.meteor/packages b/.meteor/packages index e57d4decf1a..c4f22bcb778 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -41,6 +41,7 @@ rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join rocketchat:slashcommands-leave +#rocketchat:soundcloud rocketchat:spotify rocketchat:statistics rocketchat:webrtc diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index a998db74df8..38d596b59d5 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -15,6 +15,9 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> hostname: urlObj.hostname path: urlObj.path rejectUnauthorized: !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' + } httpOrHttps = if urlObj.protocol is 'https:' then https else http diff --git a/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html b/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html new file mode 100644 index 00000000000..7e4a1fa9a8b --- /dev/null +++ b/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html @@ -0,0 +1,13 @@ +<template name="oembedSoundcloudWidget"> + {{#if parsedUrl}} + <blockquote> + <a href="https://www.soundcloud.com" style="color: #9e9ea6">SoundCloud</a><br/> + {{#if meta.twitterAudioArtistName}} + <a href="https://www.soundcloud.com/{{meta.twitterAudioArtistName}}">{{meta.twitterAudioArtistName}}</a><br/> + {{/if}} + <a href="{{meta.ogUrl}}">{{meta.ogTitle}}</a><br/> + <p>{{meta.ogDescription}}</p> + <iframe width="100%" height="150" src="{{meta.twitterPlayer}}" frameborder="0"></iframe><br/> + </blockquote> + {{/if}} +</template> diff --git a/packages/rocketchat-soundcloud/lib/client/widget.coffee b/packages/rocketchat-soundcloud/lib/client/widget.coffee new file mode 100644 index 00000000000..4f921d64352 --- /dev/null +++ b/packages/rocketchat-soundcloud/lib/client/widget.coffee @@ -0,0 +1,3 @@ +Template.oembedBaseWidget.onCreated () -> + if this.data?.parsedUrl?.host is 'soundcloud.com' and this.data?.meta?.twitterPlayer? + this.data._overrideTemplate = 'oembedSoundcloudWidget' diff --git a/packages/rocketchat-soundcloud/package.js b/packages/rocketchat-soundcloud/package.js new file mode 100644 index 00000000000..6ce6ef8c864 --- /dev/null +++ b/packages/rocketchat-soundcloud/package.js @@ -0,0 +1,23 @@ +Package.describe({ + name: 'rocketchat:soundcloud', + version: '0.0.1', + summary: 'Soundcloud integration', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'templating', + 'rocketchat:oembed@0.0.1' + ]); + + api.addFiles('lib/client/widget.coffee', 'client'); + api.addFiles('lib/client/oembedSoundcloudWidget.html', 'client'); +}); + +Package.onTest(function(api) { + +}); -- GitLab From fd123a3d24818416da53e16f846410f97f378c17 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 19 Oct 2015 10:53:27 +0200 Subject: [PATCH 0159/1338] Try to fix freez with some MD renderers --- packages/rocketchat-markdown/markdown.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index 2d1f1cfece7..b02eb49a596 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -11,10 +11,10 @@ class Markdown msg = message.html # Support  - msg = msg.replace(/!\[(.*)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$2" title="$1" class="swipebox" target="_blank"><div class="inline-image" style="background-image: url($2);"></div></a>') + 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>') # Support [Text](http://link) - msg = msg.replace(/\[(([\d\w\.-_] ?)+)\]\((https?:\/\/([\da-z\.-]+)([\/\w\# \.-]*)*\/?)\)/gm, '<a href="$3" target="_blank">$1</a>') + msg = msg.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/gm, '<a href="$2" target="_blank">$1</a>') if RocketChat.settings.get('Markdown_Headers') # Support # Text for h1 -- GitLab From 318af692b7fb4d4c6acf4d97c2e851664afcddb9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 19 Oct 2015 12:13:35 +0200 Subject: [PATCH 0160/1338] Add 2 callbacks in oembed package to allow another packages to improve their parsers --- packages/rocketchat-oembed/server/server.coffee | 10 ++++++++++ .../rocketchat-soundcloud/lib/server/server.coffee | 10 ++++++++++ packages/rocketchat-soundcloud/package.js | 3 +++ 3 files changed, 23 insertions(+) create mode 100644 packages/rocketchat-soundcloud/lib/server/server.coffee diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 38d596b59d5..58b2fa5b780 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -23,6 +23,10 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> parsedUrl = _.pick urlObj, ['host', 'hash', 'pathname', 'protocol', 'port', 'query'] + RocketChat.callbacks.run 'oembed:beforeGetUrlContent', + requestOptions: opts + parsedUrl: parsedUrl + request = httpOrHttps.request opts, (response) -> if response.statusCode is 301 and response.headers.location? request.abort() @@ -112,6 +116,12 @@ OEmbed.getUrlMeta = (url, withFragment) -> for header, value of content.headers headers[changeCase.camelCase(header)] = value + RocketChat.callbacks.run 'oembed:afterParseContent', + meta: metas + headers: headers + parsedUrl: content.parsedUrl + content: content + return { meta: metas headers: headers diff --git a/packages/rocketchat-soundcloud/lib/server/server.coffee b/packages/rocketchat-soundcloud/lib/server/server.coffee new file mode 100644 index 00000000000..fc6cacf8351 --- /dev/null +++ b/packages/rocketchat-soundcloud/lib/server/server.coffee @@ -0,0 +1,10 @@ +RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> + # if data.parsedUrl is 'soundcloud.com' + # Do whatever you whant in sync way + # You can modify the object data.requestOptions to change how the request will be executed + + +RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> + # if data.parsedUrl is 'soundcloud.com' + # Do whatever you whant in sync way + # You can modify the object data to change the parsed object diff --git a/packages/rocketchat-soundcloud/package.js b/packages/rocketchat-soundcloud/package.js index 6ce6ef8c864..3be89da9c73 100644 --- a/packages/rocketchat-soundcloud/package.js +++ b/packages/rocketchat-soundcloud/package.js @@ -9,6 +9,7 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use([ + 'rocketchat:lib', 'coffeescript', 'templating', 'rocketchat:oembed@0.0.1' @@ -16,6 +17,8 @@ Package.onUse(function(api) { api.addFiles('lib/client/widget.coffee', 'client'); api.addFiles('lib/client/oembedSoundcloudWidget.html', 'client'); + + api.addFiles('lib/server/server.coffee', 'server'); }); Package.onTest(function(api) { -- GitLab From d804a9ce06a6032bb0504db7dffbace56bc69da0 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 19 Oct 2015 11:41:14 +0100 Subject: [PATCH 0161/1338] sort packages --- .meteor/packages | 42 +++++++++++++++++++++--------------------- .meteor/versions | 4 +--- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index c4f22bcb778..5d932b0a4ae 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -9,27 +9,42 @@ accounts-google accounts-meteor-developer accounts-password accounts-twitter +blaze-html-templates +check coffeescript +ddp-rate-limiter +ejson email fastclick http jquery less +logging +meteor-base +mobile-experience +mongo +random reactive-dict reactive-var +reload service-configuration +session +spacebars +standard-minifiers +tracker arunoda:streams rocketchat:lib +rocketchat:authorization rocketchat:autolinker rocketchat:colors rocketchat:custom-oauth rocketchat:emojione rocketchat:favico rocketchat:file +rocketchat:github-enterprise rocketchat:gitlab -rocketchat:wordpress rocketchat:highlight rocketchat:ldap rocketchat:logger @@ -41,14 +56,16 @@ rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join rocketchat:slashcommands-leave -#rocketchat:soundcloud rocketchat:spotify rocketchat:statistics +rocketchat:theme rocketchat:webrtc +rocketchat:wordpress #rocketchat:chatops -#rocketchat:livechat #rocketchat:hubot #rocketchat:irc +#rocketchat:livechat +#rocketchat:soundcloud konecty:change-case konecty:delayed-task @@ -76,6 +93,7 @@ mystor:device-detection nimble:restivus nooitaf:colors pauli:accounts-linkedin +perak:codemirror percolate:migrations percolate:synced-cron raix:handlebar-helpers @@ -89,23 +107,5 @@ todda00:friendly-slugs underscorestring:underscore.string yasaricli:slugify yasinuslu:blaze-meta -rocketchat:theme -rocketchat:authorization -perak:codemirror -standard-minifiers -meteor-base -mobile-experience -mongo -blaze-html-templates -session -tracker -logging -reload -random -ejson -spacebars -check -rocketchat:github-enterprise # sanjo:jasmine # velocity:html-reporter -ddp-rate-limiter diff --git a/.meteor/versions b/.meteor/versions index 4b911104a02..c726382e74f 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -27,7 +27,6 @@ chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.10 cosmos:browserify@0.8.1 dandv:caret-position@2.1.1 -dburles:google-maps@1.1.5 ddp@1.2.2 ddp-client@1.2.1 ddp-common@1.2.1 @@ -58,7 +57,7 @@ jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 -kadira:blaze-layout@2.1.0 +kadira:blaze-layout@2.2.0 kadira:flow-router@2.7.0 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 @@ -123,7 +122,6 @@ reload@1.1.4 retry@1.0.4 rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 -rocketchat:chatops@0.0.1 rocketchat:colors@0.0.1 rocketchat:custom-oauth@1.0.0 rocketchat:emojione@0.0.1 -- GitLab From 54db4ff4f9c7c53f16fc28197065f497282c5b62 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Mon, 19 Oct 2015 12:01:30 +0100 Subject: [PATCH 0162/1338] Update to use use RocketChat.settings.get(ID) instead Settings.findOne(ID).value and remove callback --- client/views/account/accountProfile.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 449c7e59161..30c71e5b4d9 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -13,7 +13,7 @@ Template.accountProfile.helpers return Meteor.user().username allowUsernameChange: -> - return Settings.findOne("Accounts_AllowUsernameChange").value + return RocketChat.settings.get("Accounts_AllowUsernameChange") usernameChangeDisabled: -> return t('Username_Change_Disabled') @@ -46,9 +46,9 @@ Template.accountProfile.onCreated -> @save = -> instance = @ - if !Settings.findOne("Accounts_AllowUsernameChange").value + if !RocketChat.settings.get("Accounts_AllowUsernameChange") toastr.error t('Username_Change_Disabled') - return callback() + return oldPassword = _.trim($('#oldPassword').val()) newPassword = _.trim($('#password').val()) -- GitLab From 1c2fc2ceed8f0677f51d22139dfec7c709c38503 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Mon, 19 Oct 2015 12:53:16 +0100 Subject: [PATCH 0163/1338] Fix conflict --- packages/rocketchat-lib/settings/server/startup.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 5dd66c58257..9cbea62501b 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -34,14 +34,13 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', grou 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' } -<<<<<<< HEAD RocketChat.settings.add 'Accounts_AllowUsernameChange', true, { type: 'boolean', 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/*', { type: 'string', group: 'FileUpload', public: true } ->>>>>>> 5329b815e10553d0dd2ecd97a9a40fb3ce517e6d + RocketChat.settings.addGroup 'General' RocketChat.settings.add 'Site_Url', __meteor_runtime_config__?.ROOT_URL, { type: 'string', group: 'General', i18nDescription: 'Site_Url_Description', public: true } -- GitLab From 7bb1968ba761dd95638dacccdb83c64cae17707d Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Mon, 19 Oct 2015 10:59:40 -0200 Subject: [PATCH 0164/1338] Fixing Markdown regex for image support --- packages/rocketchat-markdown/markdown.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index b02eb49a596..4af338c7d79 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -11,7 +11,7 @@ class Markdown msg = message.html # 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>') + 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>') # Support [Text](http://link) msg = msg.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/gm, '<a href="$2" target="_blank">$1</a>') -- GitLab From 13cd7576d6812904cd166d4efcb5f7d3c1153980 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 19 Oct 2015 21:04:46 +0200 Subject: [PATCH 0165/1338] Improve image oembed --- .../client/oembedImageWidget.html | 14 +++++++++----- .../rocketchat-theme/assets/stylesheets/base.less | 11 ++++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-oembed/client/oembedImageWidget.html b/packages/rocketchat-oembed/client/oembedImageWidget.html index b0b4e5ec49e..8d277d96502 100644 --- a/packages/rocketchat-oembed/client/oembedImageWidget.html +++ b/packages/rocketchat-oembed/client/oembedImageWidget.html @@ -1,10 +1,14 @@ <template name="oembedImageWidget"> {{#if showImage}} - <a href="{{url}}" class="swipebox" target="_blank"> - {{#if parsedUrl}} - <div class="inline-image" style="background-image: url({{url}});"></div> - {{/if}} - </a> + {{#if parsedUrl}} + <div> + <a href="{{url}}" class="swipebox" target="_blank"> + <div class="inline-image" style="background-image: url({{url}});"> + <img src="{{url}}"> + </div> + </a> + </div> + {{/if}} {{else}} {{#if parsedUrl}} <div class="image-to-download" data-url="{{url}}"> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 1f106971bc8..e3625821c6d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2520,7 +2520,16 @@ a.github-fork { background-size: contain; background-repeat: no-repeat; background-position: center left; - height: 200px; + display: inline-flex; + box-shadow: inset 0 0 0 1px rgba(0,0,0,.1); + border-radius: 3px; + overflow: hidden; + + img { + max-height: 200px; + max-width: 100%; + opacity: 0; + } } } &.temp .body { -- GitLab From a3cb1c3332231833ab9f025d84d08b76af622d64 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 19 Oct 2015 21:10:43 +0200 Subject: [PATCH 0166/1338] Change display to inline-block --- packages/rocketchat-theme/assets/stylesheets/base.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index e3625821c6d..64abe7ab733 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2520,7 +2520,8 @@ a.github-fork { background-size: contain; background-repeat: no-repeat; background-position: center left; - display: inline-flex; + display: inline-block; + line-height: 0px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.1); border-radius: 3px; overflow: hidden; -- GitLab From 34bcd2bdd54f98f893fcf74cb21092a7993d9347 Mon Sep 17 00:00:00 2001 From: Johan Ekhager <ekhager@gmail.com> Date: Tue, 20 Oct 2015 11:33:04 +0200 Subject: [PATCH 0167/1338] Added some styling for files list. --- client/views/app/tabBar/uploadedFilesList.html | 10 ++++++---- .../assets/stylesheets/base.less | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/client/views/app/tabBar/uploadedFilesList.html b/client/views/app/tabBar/uploadedFilesList.html index e97b07b3fdc..ba76402103e 100644 --- a/client/views/app/tabBar/uploadedFilesList.html +++ b/client/views/app/tabBar/uploadedFilesList.html @@ -1,6 +1,6 @@ <template name="uploadedFilesList"> <div class="content"> - <div class="list-view"> + <div class="list-view uploaded-files-list"> <div class="status"> <h2>{{_ "Room_uploaded_file_list"}}</h2> </div> @@ -9,8 +9,10 @@ <ul class='list clearfix lines'> {{#each files}} <li> - <i class="{{getFileIcon type}}"></i> - <a title="{{name}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}">{{name}}</a> + <a title="{{name}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> + <i class="{{getFileIcon type}}"></i> + <p>{{name}}</p> + </a> </li> {{/each}} </ul> @@ -22,4 +24,4 @@ {{/if}} </div> </div> -</template> +</template> \ No newline at end of file diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 64abe7ab733..546661cab0c 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2785,6 +2785,23 @@ a.github-fork { border: none; } } + &.uploaded-files-list { + a { + color: #008ce3; + padding: 10px 5px; + border-bottom: 1px solid #eaeaea; + display: block; + &:hover { + color: #006db0; + text-decoration: underline; + } + } + i { + float: left; + color: #444; + margin-right: 10px; + } + } } .user-view { -- GitLab From 791f4fa7dca13aec6716fbb4e6d137049b4d2044 Mon Sep 17 00:00:00 2001 From: Jonas Friedmann <j@frd.mn> Date: Tue, 20 Oct 2015 12:45:05 +0200 Subject: [PATCH 0168/1338] Improve german i18n --- i18n/de.i18n.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 2a2e7e0a2fb..487a94c7cbf 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -39,7 +39,7 @@ "Add_users" : "Benutzer hinzufügen", "Administration" : "Administration", "All_channels" : "Alle Kanäle", - "Allow_Invalid_SelfSigned_Certs" : "Selbstsignierte SSL-Zertifikate zulassen für die Link-Validierung und der Vorschauen", + "Allow_Invalid_SelfSigned_Certs" : "Selbstsignierte SSL-Zertifikate für die Link-Validierung und die Vorschau zulassen", "and" : "und", "API" : "API", "API_Analytics" : "Analytics", @@ -68,7 +68,7 @@ "Channels" : "Kanäle", "Channels_list" : "Liste der öffentlichen Channels", "Chat_Rooms" : "Chaträume", - "close" : "schliessen", + "close" : "schließen", "coming_soon" : "kommt bald", "Confirm_password" : "Bestätigen Sie Ihr Passwort", "Contact" : "Kontakt", @@ -357,8 +357,8 @@ "Welcome" : "Willkommen <em>%s</em>.", "Welcome_to_the" : "Willkommen bei", "With_whom" : "Mit wem?", - "Yes_delete_it" : "Ja, lösche es!", - "you_are_in_preview_mode_of" : "Sie sind m Vorschau-Modus des Kanals #<strong>__room_name__</strong>", + "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!", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", -- GitLab From 88c65b367b600a0600f4f1817e43e9950064ddda Mon Sep 17 00:00:00 2001 From: Boris Gomelsky <boris_gomelsky@playstation.sony.com> Date: Tue, 20 Oct 2015 09:13:41 -0400 Subject: [PATCH 0169/1338] Enabled 'un-star' message option in the right tab bar --- .../client/views/starredMessages.coffee | 15 +++++++++++---- .../client/views/stylesheets/messagestar.less | 4 ---- .../server/publications/starredMessages.coffee | 3 +++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-message-star/client/views/starredMessages.coffee b/packages/rocketchat-message-star/client/views/starredMessages.coffee index eecc38865f5..2bdb4770e91 100644 --- a/packages/rocketchat-message-star/client/views/starredMessages.coffee +++ b/packages/rocketchat-message-star/client/views/starredMessages.coffee @@ -1,13 +1,20 @@ Template.starredMessages.helpers hasMessages: -> - return StarredMessage.find({ rid: Session.get 'openedRoom' }, { sort: { ts: -1 } }).count() > 0 + return StarredMessage.find({ rid: this.rid }, { sort: { ts: -1 } }).count() > 0 messages: -> - return StarredMessage.find { rid: Session.get 'openedRoom' }, { sort: { ts: -1 } } + return StarredMessage.find { rid: this.rid }, { sort: { ts: -1 } } notReadySubscription: -> return 'notready' unless Template.instance().subscriptionsReady() Template.starredMessages.onCreated -> - this.autorun => - this.subscribe 'starredMessages', Session.get('openedRoom') + this.subscribe 'starredMessages', Template.currentData().rid + +Template.starredMessages.events + 'click .message-cog': (e) -> + e.stopPropagation() + e.preventDefault() + message_id = $(e.currentTarget).closest('.message').attr('id') + $('.message-dropdown:visible').hide() + $(".starred-messages-list \##{message_id} .message-dropdown").show() diff --git a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less index 920ff634764..43fdc3fd5a6 100644 --- a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less +++ b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less @@ -1,10 +1,6 @@ .starred-messages-list { padding: 30px 0; - .message-cog, .starred-messages-list .message-dropdown { - display: none; - } - &.notready { background-image: url(/images/logo/loading.gif); background-repeat: no-repeat; diff --git a/packages/rocketchat-message-star/server/publications/starredMessages.coffee b/packages/rocketchat-message-star/server/publications/starredMessages.coffee index f50bc70c2ee..badaa2b3bdd 100644 --- a/packages/rocketchat-message-star/server/publications/starredMessages.coffee +++ b/packages/rocketchat-message-star/server/publications/starredMessages.coffee @@ -13,6 +13,9 @@ Meteor.publish 'starredMessages', (rid, options = {}) -> changed: (_id, record) -> publication.changed('rocketchat_starred_message', _id, record) + removed: (_id) -> + publication.removed('rocketchat_starred_message', _id) + @ready() @onStop -> cursorHandle.stop() -- GitLab From 8f9cfb4517f89894d969e1c4bbdec7592ad6d506 Mon Sep 17 00:00:00 2001 From: Boris Gomelsky <boris_gomelsky@playstation.sony.com> Date: Tue, 20 Oct 2015 11:01:06 -0400 Subject: [PATCH 0170/1338] Reverted autorun call --- .../client/views/starredMessages.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-message-star/client/views/starredMessages.coffee b/packages/rocketchat-message-star/client/views/starredMessages.coffee index 2bdb4770e91..24124e12f4f 100644 --- a/packages/rocketchat-message-star/client/views/starredMessages.coffee +++ b/packages/rocketchat-message-star/client/views/starredMessages.coffee @@ -9,7 +9,8 @@ Template.starredMessages.helpers return 'notready' unless Template.instance().subscriptionsReady() Template.starredMessages.onCreated -> - this.subscribe 'starredMessages', Template.currentData().rid + this.autorun => + this.subscribe 'starredMessages', Template.currentData().rid Template.starredMessages.events 'click .message-cog': (e) -> -- GitLab From 41852253f4c26ce552e8b2afcee2588a194fe033 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 20 Oct 2015 15:50:40 -0200 Subject: [PATCH 0171/1338] Added oEmbed video support. --- packages/rocketchat-oembed/client/baseWidget.coffee | 4 +++- .../rocketchat-oembed/client/oembedVideoWidget.html | 10 ++++++++++ packages/rocketchat-oembed/package.js | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-oembed/client/oembedVideoWidget.html diff --git a/packages/rocketchat-oembed/client/baseWidget.coffee b/packages/rocketchat-oembed/client/baseWidget.coffee index 41a6f91006c..4e4d68b4391 100644 --- a/packages/rocketchat-oembed/client/baseWidget.coffee +++ b/packages/rocketchat-oembed/client/baseWidget.coffee @@ -1,6 +1,5 @@ Template.oembedBaseWidget.helpers template: -> - # console.log this if this._overrideTemplate return this._overrideTemplate @@ -10,6 +9,9 @@ Template.oembedBaseWidget.helpers if this.headers?.contentType?.match(/audio\/.*/)? return 'oembedAudioWidget' + if this.headers?.contentType?.match(/video\/.*/)? + return 'oembedVideoWidget' + if this.parsedUrl?.host is 'www.youtube.com' and this.meta?.twitterPlayer? return 'oembedYoutubeWidget' diff --git a/packages/rocketchat-oembed/client/oembedVideoWidget.html b/packages/rocketchat-oembed/client/oembedVideoWidget.html new file mode 100644 index 00000000000..389b694c70b --- /dev/null +++ b/packages/rocketchat-oembed/client/oembedVideoWidget.html @@ -0,0 +1,10 @@ +<template name="oembedVideoWidget"> +{{#if parsedUrl}} + <blockquote> + <video controls class="inline-video"> + <source src="{{url}}" type="{{headers.contentType}}"> + Your browser does not support the video element. + </video> + </blockquote> +{{/if}} +</template> diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index fc9d4ff799c..8a7d58e9629 100644 --- a/packages/rocketchat-oembed/package.js +++ b/packages/rocketchat-oembed/package.js @@ -21,6 +21,7 @@ Package.onUse(function(api) { api.addFiles('client/oembedImageWidget.coffee', 'client'); api.addFiles('client/oembedAudioWidget.html', 'client'); + api.addFiles('client/oembedVideoWidget.html', 'client'); api.addFiles('client/oembedYoutubeWidget.html', 'client'); -- GitLab From d9914c55fb4d7d9c9549ea515b6f9fbf34719a76 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 20 Oct 2015 19:01:17 -0200 Subject: [PATCH 0172/1338] Added domain white list for accounts registration. --- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 1 + .../rocketchat-lib/settings/server/startup.coffee | 1 + server/lib/accounts.coffee | 15 ++++++++++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 01d2fa52b40..990823fb628 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -2,6 +2,7 @@ "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", + "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", "Accounts_OAuth_Facebook" : "Facebook Login", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index e467246e160..32c44d5693b 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -2,6 +2,7 @@ "Access_online_demo" : "Acesse o demo online", "Access_Online_Demo" : "Acesse o Demo Online", "Accounts" : "Contas", + "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", "Accounts_denyUnverifiedEmail" : "Proibir e-mail não verificado", "Accounts_EmailVerification" : "Verificação de E-mail", "Accounts_OAuth_Facebook" : "Login do Facebook", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index e6c3fa4df82..61a2a5be2c2 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -6,6 +6,7 @@ RocketChat.settings.addGroup 'Accounts' RocketChat.settings.add 'Accounts_RegistrationRequired', true, { type: 'boolean', group: 'Accounts', public: true, section: 'Registration' } 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_AvatarStoreType', 'GridFS', { type: 'string', group: 'Accounts', section: 'Avatar' } RocketChat.settings.add 'Accounts_AvatarStorePath', '/var/www/rocket.chat/uploads/avatar/', { type: 'string', group: 'Accounts', section: 'Avatar' } diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index b7902045707..52df5010c23 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -1,5 +1,18 @@ # Deny Account.createUser in client -Accounts.config { forbidClientAccountCreation: true } +accountsConfig = { forbidClientAccountCreation: true } + +domainWhiteList = _.map RocketChat.settings.get('Account_AllowedDomainsList').split(','), (domain) -> domain.trim() +if domainWhiteList + accountsConfig.restrictCreationByEmailDomain = (email) -> + ret = false + for domain in domainWhiteList + if email.match(domain + '$') + ret = true + break; + + return ret + +Accounts.config accountsConfig Accounts.emailTemplates.siteName = RocketChat.settings.get 'Site_Name'; Accounts.emailTemplates.from = "#{RocketChat.settings.get 'Site_Name'} <#{RocketChat.settings.get 'From_Email'}>"; -- GitLab From a0257bfdfc991d8164905ee6606db7d9d8b890fb Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 20 Oct 2015 19:02:26 -0200 Subject: [PATCH 0173/1338] Fix translation copy-and-paste --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 990823fb628..87b20caad96 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -2,7 +2,7 @@ "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", - "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", + "Accounts_AllowedDomainsList" : "Comma-separated list of allowed domains", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", "Accounts_OAuth_Facebook" : "Facebook Login", -- GitLab From 293e8ff1c28b80c67e6037991faf19e6d1b39804 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 20 Oct 2015 19:24:13 -0200 Subject: [PATCH 0174/1338] Test attempt. --- .travis.yml | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index 220c79dbeb3..3ec9c2e7006 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ node_js: - '0.10' before_install: - curl https://install.meteor.com | /bin/sh -- npm install -g npm@'>=2.13.5' - mkdir -p node_modules - npm install phantomjs - npm install velocity-cli @@ -19,29 +18,6 @@ before_install: - export VELOCITY_DEBUG_MIRROR=1 script: -- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi -- cd .travis -- npm install -- npm start -- cd .. -- meteor build ../build -- cd .travis -- sh ./namefiles.sh -- cd .. -- meteor add-platform ios -- meteor add rocketchat:livechat rocketchat:hubot -- meteor build --server demo.rocket.chat ../build -- cd .travis -- sh ./namedemo.sh -- cd .. -after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" -deploy: - provider: s3 - access_key_id: "AKIAIKIA7H7D47KUHYCA" - secret_access_key: $ACCESSKEY - bucket: "rocketchatbuild" - skip_cleanup: true - local_dir: ../build - on: - branch: master +- meteor add sanjo:jasmine velocity:console-reporter +- ./node_modules/velocity-cli/bin/velocity test-packages --ci +- ./node_modules/velocity-cli/bin/velocity test-app --ci \ No newline at end of file -- GitLab From d8547e4377dbf43d2ba75da215af6aa1eadae40d Mon Sep 17 00:00:00 2001 From: Alexandru Mihai <92.alexandru.mihai@gmail.com> Date: Wed, 21 Oct 2015 02:09:39 +0300 Subject: [PATCH 0175/1338] Fixed #1140 added ascii emoji to autocomplete and sorted them --- client/views/app/messagePopupConfig.coffee | 26 ++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/client/views/app/messagePopupConfig.coffee b/client/views/app/messagePopupConfig.coffee index 6d72aad25af..1fc657a759a 100644 --- a/client/views/app/messagePopupConfig.coffee +++ b/client/views/app/messagePopupConfig.coffee @@ -116,12 +116,14 @@ Template.messagePopupConfig.helpers getInput: self.getInput getFilter: (collection, filter) -> results = [] + key = ':' + filter # show common used emojis, when use input a single ':' if filter == '' commonEmojis = [ ':laughing:', ':smiley:', + ':stuck_out_tongue:', ':sunglasses:', ':wink:', ':innocent:', @@ -137,18 +139,29 @@ Template.messagePopupConfig.helpers data: collection[shortname] return results; - for shortname, data of collection - if shortname.indexOf(filter) > -1 + # use ascii + for shortname, value of RocketChat.emoji.asciiList + if results.length > 10 + break + + if shortname.startsWith(key) results.push _id: shortname - data: data + data: [value] + # use shortnames + for shortname, data of collection if results.length > 10 break - if filter.length >= 3 - results.sort (a, b) -> - a.length > b.length + if shortname.startsWith(key) + results.push + _id: shortname + data: data + + #if filter.length >= 3 + results.sort (a, b) -> + a._id.length - b._id.length return results @@ -167,4 +180,3 @@ Template.messagePopupConfig.onCreated -> @autorun -> template.channelSubscription = template.subscribe 'channelAutocomplete', template.channelFilter.get() - -- GitLab From ae28b3e044d753bf1f3b3a52e4c3e40b1bf6fdd6 Mon Sep 17 00:00:00 2001 From: Rainer Eli <claushellsing@gmail.com> Date: Tue, 20 Oct 2015 22:55:52 -0600 Subject: [PATCH 0176/1338] Update README.md Small typo and grammatical fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c3181d68fe8..4c5013e8d0b 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ It is a great solution for communities and companies wanting to privately host t - Kerberos Authentication: [Issue #839](https://github.com/RocketChat/Rocket.Chat/issues/839) - XMPP Multi-user chat (MUC): [Issue #404](https://github.com/RocketChat/Rocket.Chat/issues/404) - More webhooks: GitLab, Confluence, Jira, Piwik, Wordpress: [Issue #233](https://github.com/RocketChat/Rocket.Chat/issues/233), [Issue #525](https://github.com/RocketChat/Rocket.Chat/issues/525), [Issue #637](https://github.com/RocketChat/Rocket.Chat/issues/637), [Issue #638](https://github.com/RocketChat/Rocket.Chat/issues/638), [Issue #747](https://github.com/RocketChat/Rocket.Chat/issues/747) -- Clusterize / Descentralize: [Issue #520](https://github.com/RocketChat/Rocket.Chat/issues/520), [Issue #601](https://github.com/RocketChat/Rocket.Chat/issues/601) +- Clusterize / Decentralize: [Issue #520](https://github.com/RocketChat/Rocket.Chat/issues/520), [Issue #601](https://github.com/RocketChat/Rocket.Chat/issues/601) - Anonymous use of Rocket.Chat: [Issue #604](https://github.com/RocketChat/Rocket.Chat/issues/604) - File Sharing via P2P and Scalable Multicast: [Issue #369](https://github.com/RocketChat/Rocket.Chat/issues/369), [Issue #370](https://github.com/RocketChat/Rocket.Chat/issues/370) - Anti-virus checking on file uploads: [Issue #757](https://github.com/RocketChat/Rocket.Chat/issues/757) @@ -249,7 +249,7 @@ If you want to help, send an email to support at rocket.chat to be invited to th ### Community -Join the the conversation at [Twitter](http://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) +Join the conversation at [Twitter](http://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) ### License -- GitLab From a5888efc0f6648648cf977b86308831a12385b2a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 21 Oct 2015 11:09:34 +0200 Subject: [PATCH 0177/1338] initial support for custom room-list templates --- client/startup/defaultRoomTypes.coffee | 5 +++++ client/views/app/sideNav/sideNav.coffee | 7 +++++++ client/views/app/sideNav/sideNav.html | 6 ------ .../rocketchat-authorization/client/hasRole.coffee | 4 +++- packages/rocketchat-lib/client/lib/roomTypes.coffee | 13 +++++++++++++ packages/rocketchat-lib/package.js | 1 + 6 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 client/startup/defaultRoomTypes.coffee create mode 100644 packages/rocketchat-lib/client/lib/roomTypes.coffee diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee new file mode 100644 index 00000000000..4cf021b41f7 --- /dev/null +++ b/client/startup/defaultRoomTypes.coffee @@ -0,0 +1,5 @@ +Meteor.startup -> + RocketChat.roomTypes.add('starredRooms', 'user'); + RocketChat.roomTypes.add('channels', 'user'); + RocketChat.roomTypes.add('directMessages', 'user'); + RocketChat.roomTypes.add('privateGroups', 'user'); diff --git a/client/views/app/sideNav/sideNav.coffee b/client/views/app/sideNav/sideNav.coffee index 9c4c10294f2..15a2572e28b 100644 --- a/client/views/app/sideNav/sideNav.coffee +++ b/client/views/app/sideNav/sideNav.coffee @@ -88,3 +88,10 @@ Template.sideNav.onRendered -> menu.updateUnreadBars() AccountBox.init() + + wrapper = $('.rooms-list .wrapper').get(0) + lastLink = $('.rooms-list h3').get(0) + + RocketChat.roomTypes.get().forEach (roomType) -> + if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? + Blaze.render Template[roomType.template], wrapper, lastLink diff --git a/client/views/app/sideNav/sideNav.html b/client/views/app/sideNav/sideNav.html index e88a90091e7..92a938073f9 100644 --- a/client/views/app/sideNav/sideNav.html +++ b/client/views/app/sideNav/sideNav.html @@ -35,12 +35,6 @@ </div> <div class="rooms-list"> <div class="wrapper"> - {{#if showStarredRooms }} - {{> starredRooms }} - {{/if}} - {{> channels }} - {{> directMessages }} - {{> privateGroups }} <h3> <a href="{{pathFor 'privateHistory'}}">{{_ "History"}}</a> </h3> diff --git a/packages/rocketchat-authorization/client/hasRole.coffee b/packages/rocketchat-authorization/client/hasRole.coffee index f0a95261041..3140a74bfe6 100644 --- a/packages/rocketchat-authorization/client/hasRole.coffee +++ b/packages/rocketchat-authorization/client/hasRole.coffee @@ -2,5 +2,7 @@ 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) \ No newline at end of file + return Roles.userIsInRole(userId, roleName, scope) diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee new file mode 100644 index 00000000000..9ff0a2ae143 --- /dev/null +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -0,0 +1,13 @@ +RocketChat.roomTypes = new class + rooms = [] + + add = (template, roles = []) -> + rooms.push + template: template + roles: [].concat roles + + getAll = -> + return rooms + + add: add + get: getAll diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index cd20abff3c4..1197135ec12 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -46,6 +46,7 @@ Package.onUse(function(api) { // CLIENT + api.addFiles('client/lib/roomTypes.coffee', 'client'); api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); api.addFiles('client/MessageAction.coffee', 'client'); -- GitLab From 9747999e9d8f94cf8392c215e107b8bc140604e6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 21 Oct 2015 11:45:09 +0200 Subject: [PATCH 0178/1338] api for new menu options --- client/lib/accountBox.coffee | 23 ++++++++++++++++++++++- client/views/app/sideNav/sideNav.coffee | 3 +++ client/views/app/sideNav/sideNav.html | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/client/lib/accountBox.coffee b/client/lib/accountBox.coffee index 86f1c483eb9..c27a48268dd 100644 --- a/client/lib/accountBox.coffee +++ b/client/lib/accountBox.coffee @@ -1,6 +1,7 @@ @AccountBox = (-> status = 0 self = {} + options = new ReactiveVar [] setStatus = (status) -> Meteor.call('UserPresence:setDefaultStatus', status) @@ -27,9 +28,29 @@ self.box = $(".account-box") self.options = self.box.find(".options") + ### + # @param newOption: + # name: Button label + # icon: Button icon + # class: Class of item + # roles: Which roles see this options + ### + addOption = (newOption) -> + Tracker.nonreactive -> + actual = options.get() + actual.push newOption + options.set actual + + getOptions = -> + return _.filter options.get(), (option) -> + if not option.roles? or RocketChat.authz.hasRole(Meteor.userId(), option.roles) + return true + setStatus: setStatus toggle: toggle open: open close: close init: init -)() \ No newline at end of file + addOption: addOption + getOptions: getOptions +)() diff --git a/client/views/app/sideNav/sideNav.coffee b/client/views/app/sideNav/sideNav.coffee index 15a2572e28b..17b43e967cc 100644 --- a/client/views/app/sideNav/sideNav.coffee +++ b/client/views/app/sideNav/sideNav.coffee @@ -35,6 +35,9 @@ Template.sideNav.helpers showAdminOption: -> return RocketChat.authz.hasAtLeastOnePermission( ['view-statistics', 'view-room-administration', 'view-user-administration', 'view-privileged-setting']) + registeredMenus: -> + return AccountBox.getOptions() + Template.sideNav.events 'click .close-flex': -> SideNav.closeFlex() diff --git a/client/views/app/sideNav/sideNav.html b/client/views/app/sideNav/sideNav.html index 92a938073f9..dc43b568f97 100644 --- a/client/views/app/sideNav/sideNav.html +++ b/client/views/app/sideNav/sideNav.html @@ -20,6 +20,11 @@ <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> + + {{#each registeredMenus}} + <a href="" class="{{class}}"><i class="{{icon}}"></i><span>{{name}}</span></a> + {{/each}} + {{#if showAdminOption }} <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> {{/if}} -- GitLab From c0071b9caaa55c095efaf668c51a7acaa0f25ef9 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 21 Oct 2015 12:01:36 +0200 Subject: [PATCH 0179/1338] revert some unwanted modifications --- packages/rocketchat-livechat/livechat.coffee | 33 + .../rocketchat-livechat/publications.coffee | 9 + packages/rocketchat-theme/assets/colors.less | 1198 +++++++++++++++++ 3 files changed, 1240 insertions(+) create mode 100644 packages/rocketchat-livechat/livechat.coffee create mode 100644 packages/rocketchat-livechat/publications.coffee create mode 100644 packages/rocketchat-theme/assets/colors.less diff --git a/packages/rocketchat-livechat/livechat.coffee b/packages/rocketchat-livechat/livechat.coffee new file mode 100644 index 00000000000..4ff8e57dc72 --- /dev/null +++ b/packages/rocketchat-livechat/livechat.coffee @@ -0,0 +1,33 @@ +WebApp = Package.webapp.WebApp +Autoupdate = Package.autoupdate.Autoupdate + +WebApp.connectHandlers.use '/livechat/', (req, res, next) -> + res.setHeader 'content-type', 'html' + + head = Assets.getText('public/head.html') + + html = """ + <html> + <head> + <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/packages/rocketchat_livechat/public/livechat.css?_dc=#{Autoupdate.autoupdateVersion}"> + <script type="text/javascript"> + __meteor_runtime_config__ = { + "meteorRelease": "METEOR@1.1.0.2", + "ROOT_URL": "#{Meteor.absoluteUrl()}", + "ROOT_URL_PATH_PREFIX": "", + "autoupdateVersion": "#{Autoupdate.autoupdateVersion}", + "autoupdateVersionRefreshable": "#{Autoupdate.autoupdateVersionRefreshable}", + "autoupdateVersionCordova": "#{Autoupdate.autoupdateVersionCordova}" + }; + </script> + <script type="text/javascript" src="/packages/rocketchat_livechat/public/livechat.js?_dc=#{Autoupdate.autoupdateVersion}"></script> + + #{head} + </head> + <body> + </body> + </html> + """ + + res.write html + res.end() diff --git a/packages/rocketchat-livechat/publications.coffee b/packages/rocketchat-livechat/publications.coffee new file mode 100644 index 00000000000..e51b3841a7e --- /dev/null +++ b/packages/rocketchat-livechat/publications.coffee @@ -0,0 +1,9 @@ +Meteor.publish 'visitorRoom', (visitorToken) -> + return RocketChat.models.Rooms.findByVisitorToken visitorToken, + fields: + name: 1 + t: 1 + cl: 1 + u: 1 + usernames: 1 + v: 1 diff --git a/packages/rocketchat-theme/assets/colors.less b/packages/rocketchat-theme/assets/colors.less new file mode 100644 index 00000000000..516091345e5 --- /dev/null +++ b/packages/rocketchat-theme/assets/colors.less @@ -0,0 +1,1198 @@ +// Colors +// -------------- + +.custom-scroll(@background, @thumb, @width: 8px) { + &::-webkit-scrollbar { + width: @width; + background: @background; + } + &::-webkit-scrollbar-thumb { + background-color: @thumb; + -webkit-border-radius: 50px; + } + &::-webkit-scrollbar-corner { + background-color: @background; + } +} + +a { + &:hover, + &:active { + color: @primary-font-color; + } +} + +code { + background-color: @code-background; + border-color: @code-border; + color: @code-color; +} + +blockquote { + &:before { + background-color: @blockquote-background; + } +} + +.login-terms { + color: @smallprint-font-color; + a { + color: @smallprint-font-color; + &:hover { + color: @smallprint-hover-color; + } + } +} + +.upload-preview { + background-color: @secondary-background-color; +} + +.upload-preview-title { + background-color: @tertiary-background-color; +} + +.first-unread { + &.first-unread-opaque { + .body { + &::before { + background-color: lighten(@info-font-color, 25%); + } + + &::after { + color: @info-font-color; + } + } + } + .body { + &::before { + background-color: lighten(@info-active-font-color, 25%); + } + + &::after { + background-color: @content-background-color; + color: @info-active-font-color; + } + } +} + +.alert { + border-color: rgba(0, 0, 0, 0); +} + +.alert-warning { + color: #8A6D3B; + background-color: #FCF8E3; + border-color: #FAEBCC; +} + +.alert-danger { + color: #A94442; + background-color: #F2DEDE; + border-color: #EBCCD1; +} + +.scrollable { + .custom-scroll(transparent, #BFBFBF); +} + +.rocket-form { + legend { + &:after { + background-color: #DFDFDF; + } + } +} + +.input-line { + &.search { + .icon-search { + color: @secondary-font-color; + } + } + > label { + color: @primary-font-color; + } +} + +.rocket-h2 { + color: #EFEFEF; +} + +.rocket-h3 { + color: #EAEAEA; +} + +html { + .custom-scroll(transparent, rgba(255, 255, 255, 0.05), 3px); +} + +body { + color: @primary-font-color; + background-color: @primary-background-color; +} + +textarea, +select, +input[type='text'], +input[type='number'], +input[type='email'], +input[type='password'] { + border-color: #E7E7E7; + background-color: #fff; +} + +input.search { + &:before { + background-color: #000; + } +} + +.form-horizontal .control-label { + color: @primary-font-color; +} + +.-autocomplete-container { + p { + color: @secondary-font-color; + } +} + +.-autocomplete-item { + color: @secondary-font-color; + i { + color: @secondary-font-color; + } + &.selected { + background-color: @tertiary-background-color; + color: @primary-font-color; + } +} + +label.required:after { + color: red; +} + +.status-offline, +.icon-at.status-offline { + color: @status-offline; +} + +.status-online, +.icon-at.status-online { + color: @status-online; +} + +.status-busy, +.icon-at.status-busy { + color: @status-busy; +} + +.status-away, +.icon-at.status-away { + color: @status-away; +} + +// TODO -- Refactor favorite styles and logic; +.favorite-room { + color: #FECF09; +} + +.toggle-favorite { + color: #AAA; +} + +.btn-loading { + color: #444 !important; + background-color: transparent !important; + &:hover { + background-color: transparent !important; + } +} + +// new layout buttons +.button { + background-color: #FFF; + color: rgba(255, 255, 255, 0.85); + background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); + &:before { + background-color: rgba(0, 0, 0, 0.1); + } + &:hover { + color: #FFF; + } + &.secondary { + background-color: @tertiary-background-color; + color: @primary-font-color; + &:before { + background-color: rgba(0, 0, 0, 0.045); + } + } + &.delete, + &.remove, + &.red { + background-color: #bc2031; + } + &.lightblue { + background-color: #02acec; + } + &.clean { + background-color: rgba(0, 0, 0, 0.025); + } + &.facebook { + background-color: #325c99; + } + &.twitter { + background-color: #02acec; + } + &.google { + background-color: #dd4b39; + } + &.github { + background-color: #4c4c4c; + } + &.gitlab { + background-color: #373d47; + } + &.trello { + background-color: #026aa7; + } + &.meteor-developer { + background-color: #de4f4f; + } +} + +.burger { + i { + background-color: #333; + } + + .unread-burger-alert { + background-color: #F95555; + color: @content-background-color; + } +} + +.arrow { + &:before, + &:after { + background-color: #aaa; + } +} + +.a-plus { + &:before, + &:after { + background-color: #aaa; + } +} + +a.github-fork { + background-color: #5c5c5c; + color: #f0f0f0; + &:hover { + background-color: #4b4b4b; + color: #FFF; + } + &:before { + border-top-color: #f0f0f0; + } + &:after { + border-top-color: #f0f0f0; + } +} + +.mac-bar { + background-color: #ddd; + i { + background-color: #ff5f57; + &:nth-child(2) { + background-color: #ffbd2e; + } + &:nth-child(3) { + background-color: #28ca41; + } + } +} + +.avatar { + .avatar-image { + background-color: transparent; + } + &[initials]:before { + color: #FFF; + } +} + +#rocket-chat { + background-color: @content-background-color; +} + +.account-box { + .info { + h4 { + color: rgba(255, 255, 255, 0.65); + } + &.status-offline { + .thumb:after { + border-color: darken(@status-offline, 5%); + background-color: @status-offline; + } + } + &.status-online { + .thumb:after { + border-color: darken(@status-online, 5%); + background-color: @status-online; + } + } + &.status-away { + .thumb:after { + border-color: darken(@status-away, 5%); + background-color: @status-away; + } + } + &.status-busy { + .thumb:after { + border-color: darken(@status-busy, 5%); + background-color: @status-busy; + } + } + } + .options { + background-color: @primary-background-color; + .status { + &:after { + border-color: #6f6f6f; + } + &.offline { + &:after { + border-color: #666666; + background-color: #7b7b7b; + } + } + &.online { + &:after { + border-color: #2c9210; + background-color: #35AC19; + } + } + &.away { + &:after { + border-color: #e69200; + background-color: #fcb316; + } + } + &.busy { + &:after { + border-color: #9f0030; + background-color: #D30230; + } + } + } + span.soon { + color: #aaa; + } + a { + color: rgba(255, 255, 255, 0.5); + border-bottom-color: darken(@primary-background-color, 2%); + &:hover { + background-color: darken(@primary-background-color, 2%); + color: rgba(255, 255, 255, 0.75); + } + } + } + &.active .info, + .info:hover { + h4 { + color: rgba(255, 255, 255, 0.85); + } + } + .hover & { + .info h4 { + color: rgba(255, 255, 255, 0.85); + } + } +} + +// rooms-box +.flex-nav { + //background-color: @primary-background-color; + background-color: transparent; + color: @tertiary-font-color; + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + header { + background-color: @primary-background-color; + } + footer { + background-color: @primary-background-color; + } + .content { + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + background-color: @primary-background-color; + } + .input-line { + input[type='text'], + input[type='password'], + select { + border-color: @tertiary-font-color; + background-color: #04436a; + color: @input-font-color; + } + + & label { + color:@input-font-color; + } + } + .selected-users { + li { + background-color: rgba(0, 0, 0, 0.1); + } + } +} + +.side-nav { + background-color: #F4F4F4; + color: #000; + &:before { + background-color: #dfdfdf; + } + .rooms-list { + background-color: lighten(@primary-background-color, 2%); + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + } + .more { + color: @tertiary-font-color; + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + .input-error { + color: #f09286; + } + .empty { + color: @tertiary-font-color; + } + .header { + color: #fff; + background-color: @primary-background-color; + } + > .arrow { + &.hover, + &:hover { + &:before, + &:after { + background-color: rgba(255, 255, 255, 0.85); + } + } + } + .footer { + background: #fff; + background-color: @primary-background-color; + small { + color: @tertiary-font-color; + } + } + h3 { + color: @tertiary-font-color; + a { + color: inherit; + } + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + .unread { + background-color: #1dce73; + color: #FFF; + } + ul { + li { + .remove, + .erase { + color: #666; + } + &:hover { + .opt { + background-color: transparent; + } + } + &.active { + a { + background-color: rgba(255, 255, 255, 0.075); + color: rgba(255, 255, 255, 0.75); + } + .opt { + background-color: transparent; + } + } + &.has-alert { + .name { + color: #ffffff; + } + } + &.away { + a { + color: #666; + } + } + } + a { + color: @tertiary-font-color; + &:hover { + background-color: rgba(255, 255, 255, 0.05); + } + } + .opt { + background-color: transparent; + i { + color: rgba(255, 255, 255, 0.5); + &:hover { + color: rgba(255, 255, 255, 0.75); + } + } + } + i { + color: rgba(255, 255, 255, 0.35); + } + input[type=text] { + color: #000; + } + } +} + +.page-container { + .content { + .custom-scroll(transparent, #EAEAEA); + } +} + +.fixed-title { + background: #fff; + border-bottom-color: @tertiary-background-color; +} + +.cms-page { + color: #444; + background-color: @content-background-color; +} + +.spotlight { + background-color: rgba(0,0,0,.3); + > .spotlight-input { + color: #444; + > i { + color: #aaa; + } + } +} + +.mobile-message-menu { + background-color: rgba(0,0,0,.3); +} + +.page-static { + .content { + .section { + .section-content { + border-color: #ddd; + } + } + } +} + +.page-list { + .results { + border-bottom-color: #DFDFDF; + color: @secondary-font-color; + } + .list { + a { + color: @primary-font-color; + border-bottom-color: @secondary-background-color; + &:hover { + background-color: @secondary-background-color; + } + } + li { + color: @secondary-font-color; + &:after { + background-color: @secondary-font-color; + } + } + .info { + a { + color: @primary-font-color; + } + } + .status { + color: @secondary-font-color; + } + } +} + +.image-to-download { + background-color: #fafafa; + border-color: #ddd; + color: #aaa; +} + +.room-not-found { + color: orange; +} + +.upload-progress { + background-color: #b2d5c9; + color: @content-background-color; + .upload-progress-item { + border-bottom-color: #6a8179; + &:first-child { + border-top-color: #6a8179; + } + &.upload-error { + background-color: #FF6161; + border-color: #863737; + } + .upload-progress-progress { + background-color: #4c9789; + } + > a { + &:hover { + color: #eee; + } + } + } +} + +// change to page-messages +.messages-container { + .edit-room-title { + color: @secondary-font-color; + &:hover { + color: @primary-font-color; + } + } + .wrapper { + .custom-scroll(transparent, #EAEAEA); + } + .footer { + background: #FCFCFC; + border-top-color: @tertiary-background-color; + } + .message-popup { + background: #FAFAFA; + } + .message-popup-title { + background-color: @secondary-background-color; + border-bottom-color: #EEE; + } + .popup-item { + color: @secondary-font-color; + &.selected { + background-color: @tertiary-background-color; + color: @primary-font-color; + } + } + .popup-user-status { + border-color: rgba(0,0,0,.2); + } + .popup-user-status-system { + border-color: transparent; + } + .popup-user-status-offline { + background-color: @status-offline; + } + .popup-user-status-online { + background-color: @status-online; + } + .popup-user-status-away { + background-color: @status-away; + } + .popup-user-status-busy { + background-color: @status-busy; + } + .message-form { + > div { + > .file { + border-color: #E7E7E7; + color: #888; + background-color: #FCFCFC; + &:hover { + background-color: #F1F1F1; + color: #666; + } + } + > .mic, .stop-mic { + color: #888; + background-color: #FCFCFC; + &:hover { + background-color: #F1F1F1; + color: #666; + } + } + } + textarea { + &.editing { + background-color: #fff7d8; + } + } + .icon-paper-plane { + color: @secondary-font-color; + &:hover { + color: @primary-font-color; + } + } + .users-typing { + color: #888888; + background: #FCFCFC; + } + .formatting-tips { + color: #888888; + &:hover { + color: #444444; + } + q { + border-left-color: #ccc; + } + } + .editing-commands { + .editing-commands-cancel { + color: #888888; + } + .editing-commands-save { + color: #888888; + } + } + } +} + +.messages-box { + .load-more { + span { + border-color: #CCC; + background-color: #EEE; + } + } + .start { + color: @secondary-font-color; + } + .new-message { + background: #428bca; + color: #FFF; + } + .editing { + .body { + background-color: #fff7d8; + } + } +} + +.message { + &.new-day { + &:before { + color: @secondary-font-color; + background-color: @content-background-color; + } + &:after { + border-top-color: #ddd; + } + } + .user { + color: #444444; + &:hover { + color: #333; + } + } + .info { + color: @info-font-color; + } + &.system { + .body { + color: @info-font-color; + } + } + a { + color: @link-font-color; + &:hover { + color: darken(@link-font-color, 10%); + } + } +} + +// FLEX-TAB and FLEX-TAB views +.flex-tab { + background-color: @secondary-background-color; + border-left-color: @tertiary-background-color; + .control { + background-color: @secondary-background-color; + &:before { + background-color: @tertiary-background-color; + } + .more { + background-color: @tertiary-background-color; + border-bottom-color: @tertiary-background-color; + color: @secondary-font-color; + &:hover { + .arrow { + .arrow { + &:before, + &:after { + background-color: #4a4a4a; + } + } + } + } + .arrow { + &:before, + &:after { + background-color: #7a7a7a; + } + } + .flex-opened & { + background-color: @secondary-background-color; + &:hover { + .arrow { + &:before, + &:after { + background-color: #7a7a7a; + } + } + } + } + } + .search-form { + .icon-plus { + color: @secondary-font-color; + } + } + .info-tabs { + a { + color: inherit; + border-left-color: rgb(234, 234, 234); + &.active { + background-color: #F4F4F4; + } + &:last-child { + border-right-color: rgb(234, 234, 234); + } + } + } + } + .content { + .custom-scroll(transparent, #DADADA); + } +} + +.list-view { + > .status { + p { + color: @secondary-font-color; + } + .see-all { + color: @secondary-font-color; + background-color: transparent; + } + } +} + +.user-view { + .info { + h3 { + i.status-offline { + &:after { + border-color: darken(@status-offline, 5%); + background-color: @status-offline; + } + } + i.status-online { + &:after { + border-color: darken(@status-online, 5%); + background-color: @status-online; + } + } + i.status-away { + &:after { + border-color: darken(@status-away, 5%); + background-color: @status-away; + } + } + i.status-busy { + &:after { + border-color: darken(@status-busy, 5%); + background-color: @status-busy; + } + } + } + p { + color: @secondary-font-color; + } + } + .stats { + li { + background-color: #e9e9e9; + } + } + .box { + h4 { + } + &:after { + background-color: #CDCDCD; + } + } + .tags { + li { + background-color: #CDCDCD; + } + } + .links { + a { + color: #6f6f6f; + &:hover { + background-color: #e9e9e9; + color: #333; + } + } + } + .channels { + p { + color: @secondary-font-color; + } + a { + color: #6f6f6f; + } + } + .edit-form { + p { + color: @secondary-font-color; + } + } +} + +.user-image-status(@color) { + .avatar { + &:after { + background-color: darken(@color, 5%); + } + } +} + +.user-image { + background-color: @tertiary-background-color; + &:hover, + &.selected { + .avatar { + &:after { + } + .status-offline { + &:after { + background-color: @status-offline; + } + } + .status-online { + &:after { + background-color: @status-online; + } + } + .status-away { + &:after { + background-color: @status-away; + } + } + .status-busy { + &:after { + background-color: @status-busy; + } + } + p { + color: @primary-font-color; + } + } + } + .lines & { + background-color: transparent; + a { + background-color: transparent; + } + p { + color: @secondary-font-color; + } + } + &.status-offline { + .user-image-status(@status-offline); + } + &.status-online { + .user-image-status(@status-online); + } + &.status-away { + .user-image-status(@status-away); + } + &.status-busy { + .user-image-status(@status-busy); + } +} + +.user-profile { + .info { + a { + color: @primary-font-color; + &:hover { + color: @secondary-font-color; + } + } + } +} + +.rocket-modal { + background-color: rgba(0, 0, 0, 0.5); + &.fluid { + .modal { + main { + .custom-scroll(transparent, #CFCFCF); + } + } + } + legend { + color: @secondary-font-color; + &:before { + background-color: #dfdfdf; + } + } + .modal { + background-color: @content-background-color; + header { + background-color: #DADADA; + .close { + i { + color: @secondary-font-color; + } + &:hover { + i { + color: @primary-font-color; + } + } + } + } + main { + background-color: @content-background-color; + } + footer { + background-color: #eaeaea; + } + } +} + +#login-card { + background-color: #FAFAFA; + h2 { + color: @primary-font-color; + &.error { + color: #b40202; + } + } + h3 { + &.error { + color: #b40202; + } + } + a { + color: @primary-background-color; + &:active { + color: @primary-background-color; + } + &:hover { + color: darken(@primary-background-color, 10%); + } + } + .input-text { + input { + background-color: transparent; + border-bottom-color: #DFDFDF; + &.error { + border-bottom-color: #b40202; + &::-webkit-input-placeholder { + color: #b40202; + } + &:-moz-placeholder { + color: #b40202; + } + /* Firefox 18- */ + &::-moz-placeholder { + color: #b40202; + } + /* Firefox 19+ */ + &:-ms-input-placeholder { + color: #b40202; + } + } + } + input:-webkit-autofill { + color: @content-background-color !important; + } + input:-webkit-autofill { + background-color: transparent !important; + } + } +} + +.full-page { + background-color: darken(@primary-background-color, 10%); + .background-image(linear-gradient(darken(@primary-background-color,10%),@primary-background-color)); + .text { + color: #FFF; + .button { + background-color: #bc2031; + color: #FFF; + } + } + footer { + color: #fff; + div.switch-language { + a { + color: @secondary-font-color; + } + } + } +} + +.avatar-suggestion-item { + background-color: @secondary-background-color; + border-color: darken(@secondary-background-color, 10%); + .avatar { + background-size: cover; + background-color: @tertiary-background-color; + } + .question-mark { + &::before { + color: darken(@tertiary-background-color, 10%); + } + } +} + +.statistics-table { + border-color: #F9F9F9; +} + +@media all and(max-width: 780px) { + #rocket-chat { + .main-content { + background-color: @content-background-color; + } + } +} + +.dropzone { + &.over .dropzone-overlay { + background-color: rgba(0, 0, 0, 0.5); + color: @content-background-color; + > div { + background-color: rgba(0, 0, 0, 0.6); + } + } +} + +.is-cordova { + .flex-tab { + button.more { + background-color: #fff; + } + } +} -- GitLab From 79d51adec4d7253ce1e2ede095ef6d0227ee5dee Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 21 Oct 2015 12:06:45 +0200 Subject: [PATCH 0180/1338] revert more unwanted modifications --- packages/rocketchat-livechat/methods.coffee | 81 +++++++++++++++++++++ packages/rocketchat-livechat/package.js | 15 +--- 2 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 packages/rocketchat-livechat/methods.coffee diff --git a/packages/rocketchat-livechat/methods.coffee b/packages/rocketchat-livechat/methods.coffee new file mode 100644 index 00000000000..2edd1dd9c4f --- /dev/null +++ b/packages/rocketchat-livechat/methods.coffee @@ -0,0 +1,81 @@ +Meteor.methods + registerGuest: (token) -> + check token, String + + user = Meteor.users.findOne { "profile.token": token }, { fields: { _id: 1 } } + if user? + throw new Meteor.Error 'token-already-exists', 'Token already exists' + + pass = Meteor.uuid() + + loop + qt = Meteor.users.find({ 'profile.guest': true }).count() + 1 + user = 'guest-' + qt + + userExists = Meteor.users.findOne { 'username': user }, { fields: { _id: 1 } } + break if not userExists + + userData = + username: user + password: pass + + userId = Accounts.createUser userData + + Meteor.users.update userId, + $set: + name: user + "profile.guest": true + "profile.token": token + + return { + user: user + pass: pass + } + + sendMessageLivechat: (message) -> + 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 not room? + + # find an online user + operator = Meteor.users.findOne { operator: true, status: 'online' } + + unless 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: 'd' + ts: new Date() + v: + token: message.token + + RocketChat.models.Subscriptions.insert + rid: message.rid + name: guest.username + alert: true + open: true + unread: 1 + u: + _id: operator._id + username: operator.username + t: 'd' + + room = Meteor.call 'canAccessRoom', message.rid, guest._id + + if not room + throw new Meteor.Error 'cannot-acess-room' + + RocketChat.sendMessage guest, message, room + diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 7bf0d95652f..dff7c5ae6a0 100755 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -18,21 +18,14 @@ Package.registerBuildPlugin({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use(['ecmascript', 'webapp', 'autoupdate'], 'server'); + api.use(['coffeescript', 'webapp', 'autoupdate'], 'server'); - api.imply('alanning:roles@1.2.12'); - - api.addFiles('livechat.js', 'server'); - api.addFiles('server/methods.js', 'server'); - api.addFiles('server/publications.js', 'server'); - api.addFiles('permissions.js', 'server'); + api.addFiles('livechat.coffee', 'server'); + api.addFiles('methods.coffee', 'server'); + api.addFiles('publications.coffee', 'server'); api.addFiles('config.js', 'server'); - api.addFiles('client/ui.js', 'client'); - api.addFiles('client/views/sideNav/livechat.html', 'client'); - api.addFiles('client/views/sideNav/livechat.js', 'client'); - api.addAssets('rocket-livechat.js', 'client'); api.addAssets('public/livechat.css', 'client'); api.addAssets('public/livechat.js', 'client'); -- GitLab From 3b5acd9ab011222eda2ea3d96fe969ea533aad5e Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Wed, 21 Oct 2015 12:44:29 +0200 Subject: [PATCH 0181/1338] Fixes reggae on user autocomplete --- client/views/app/messagePopup.coffee | 8 ++++---- client/views/app/messagePopupConfig.coffee | 4 ++-- lib/RegExp.coffee | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 lib/RegExp.coffee diff --git a/client/views/app/messagePopup.coffee b/client/views/app/messagePopup.coffee index e154bd0c876..511bb0684be 100644 --- a/client/views/app/messagePopup.coffee +++ b/client/views/app/messagePopup.coffee @@ -44,13 +44,13 @@ Template.messagePopup.onCreated -> template.suffix = val(template.data.suffix, ' ') if template.triggerAnywhere is true - template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^| )#{template.trigger}[^\s]*$") + template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^| )#{template.trigger}[^\\s]*$") else - template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^)#{template.trigger}[^\s]*$") + template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^)#{template.trigger}[^\\s]*$") - template.selectorRegex = val(template.data.selectorRegex, new RegExp "#{template.trigger}([^\s]*)$") + template.selectorRegex = val(template.data.selectorRegex, new RegExp "#{template.trigger}([^\\s]*)$") - template.replaceRegex = val(template.data.replaceRegex, new RegExp "#{template.trigger}[^\s]*$") + template.replaceRegex = val(template.data.replaceRegex, new RegExp "#{template.trigger}[^\\s]*$") template.getValue = val template.data.getValue, (_id) -> return _id diff --git a/client/views/app/messagePopupConfig.coffee b/client/views/app/messagePopupConfig.coffee index 6d72aad25af..2a72868abb3 100644 --- a/client/views/app/messagePopupConfig.coffee +++ b/client/views/app/messagePopupConfig.coffee @@ -12,7 +12,7 @@ Template.messagePopupConfig.helpers getInput: self.getInput textFilterDelay: 200 getFilter: (collection, filter) -> - exp = new RegExp("#{filter}", 'i') + exp = new RegExp("#{RegExp.escape filter}", 'i') template.userFilter.set filter if template.userSubscription.ready() items = filteredUsers.find({$or: [{username: exp}, {name: exp}]}, {limit: 5}).fetch() @@ -24,7 +24,7 @@ Template.messagePopupConfig.helpers name: t 'Notify_all_in_this_room' compatibility: 'channel group' - exp = new RegExp("(^|\\s)#{filter}", 'i') + exp = new RegExp("(^|\\s)#{RegExp.escape filter}", 'i') if exp.test(all.username) or exp.test(all.compatibility) items.unshift all return items diff --git a/lib/RegExp.coffee b/lib/RegExp.coffee new file mode 100644 index 00000000000..c068aefc58d --- /dev/null +++ b/lib/RegExp.coffee @@ -0,0 +1,2 @@ +RegExp.escape = (s) -> + return s.replace /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' \ No newline at end of file -- GitLab From 9a014c7512db23a803bd28efba53d30cf875a89e Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 21 Oct 2015 12:55:50 -0200 Subject: [PATCH 0182/1338] Fixing embedded urls on updated messages. --- server/methods/updateMessage.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 3591ac2d723..dc6b47d9c53 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -4,7 +4,7 @@ Meteor.methods throw new Meteor.Error('invalid-user', "[methods] updateMessage -> Invalid user") originalMessage = RocketChat.models.Messages.findOneById message._id - + if not originalMessage?._id? return @@ -31,7 +31,7 @@ Meteor.methods message.ets = new Date() if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g - message.urls = urls + message.urls = urls.map (url) -> url: url message = RocketChat.callbacks.run 'beforeSaveMessage', message @@ -43,5 +43,5 @@ Meteor.methods , $set: message - # Meteor.defer -> - # RocketChat.callbacks.run 'afterSaveMessage', RocketChat.models.Messages.findOneById(message.id) + Meteor.defer -> + RocketChat.callbacks.run 'afterSaveMessage', RocketChat.models.Messages.findOneById(tempid) -- GitLab From caf69d6fdcb195df1abdc5eb6fc05f93ebe94dad Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 21 Oct 2015 15:33:20 -0200 Subject: [PATCH 0183/1338] New attempt for application test. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3ec9c2e7006..930df60248c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,5 +19,6 @@ before_install: script: - meteor add sanjo:jasmine velocity:console-reporter +- meteor update - ./node_modules/velocity-cli/bin/velocity test-packages --ci -- ./node_modules/velocity-cli/bin/velocity test-app --ci \ No newline at end of file +- meteor --test --once \ No newline at end of file -- GitLab From 5d893b7f36b3a346447a18ea6794a152a4034086 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 21 Oct 2015 16:01:57 -0200 Subject: [PATCH 0184/1338] Fixing addFiles order to make sure settings are added first. --- packages/rocketchat-github-enterprise/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-github-enterprise/package.js b/packages/rocketchat-github-enterprise/package.js index ebcbaf8d9c4..cca18ff40e3 100644 --- a/packages/rocketchat-github-enterprise/package.js +++ b/packages/rocketchat-github-enterprise/package.js @@ -11,9 +11,9 @@ Package.onUse(function(api) { api.use('rocketchat:lib@0.0.1'); api.use('rocketchat:custom-oauth'); - api.addFiles("common.coffee"); - api.addFiles('github-enterprise-login-button.css', 'client'); api.addFiles('startup.coffee', 'server'); + api.addFiles('github-enterprise-login-button.css', 'client'); + api.addFiles('common.coffee'); // TAPi18n api.use('templating', 'client'); -- GitLab From 7303c99b0d2b9b2fbb45a32cb693c8cc4ef689f4 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 21 Oct 2015 18:20:09 -0200 Subject: [PATCH 0185/1338] Avoid setting content-disposition header to images. Also deliver download files with original file name. --- lib/fileUpload.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 06797a05ad4..60a57342b09 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -39,7 +39,8 @@ if UploadFS? onFinishUpload: -> console.log arguments onRead: (fileId, file, req, res) -> - res.setHeader 'content-disposition', 'download' + unless file?.type?.match(/^image\/.*/) + res.setHeader 'content-disposition', "attachment; filename='#{ file.name }'" if Meteor.isServer initFileStore() -- GitLab From c517994c46504f995a19a3b6acb55c79c54ee2ec Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 21 Oct 2015 19:12:10 -0200 Subject: [PATCH 0186/1338] Adding support for all files (i.e. empty white list) --- lib/fileUpload.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 60a57342b09..85d21923564 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -12,12 +12,14 @@ if UploadFS? fileUploadMediaWhiteList = -> + return unless RocketChat.settings.get('FileUpload_MediaTypeWhiteList') + return _.map(RocketChat.settings.get('FileUpload_MediaTypeWhiteList').split(','), (item) -> return item.trim() ) @fileUploadIsValidContentType = (type) -> list = fileUploadMediaWhiteList() - if _.contains list, type + if !list or _.contains list, type return true else wildCardGlob = '/*' -- GitLab From b74dd61134bb8b617c89e15b073cee9814add31c Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 21 Oct 2015 19:26:21 -0200 Subject: [PATCH 0187/1338] Prevents breaking registration when field is empty (''.split(',') == ['']) --- server/lib/accounts.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 52df5010c23..23047777530 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -1,8 +1,8 @@ # Deny Account.createUser in client accountsConfig = { forbidClientAccountCreation: true } -domainWhiteList = _.map RocketChat.settings.get('Account_AllowedDomainsList').split(','), (domain) -> domain.trim() -if domainWhiteList +if RocketChat.settings.get('Account_AllowedDomainsList') + domainWhiteList = _.map RocketChat.settings.get('Account_AllowedDomainsList').split(','), (domain) -> domain.trim() accountsConfig.restrictCreationByEmailDomain = (email) -> ret = false for domain in domainWhiteList -- GitLab From 768ae884934919cebe6455e91027e0349cbf4201 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Thu, 22 Oct 2015 10:19:05 +0200 Subject: [PATCH 0188/1338] Removed edit and delete message action buttons from starred messages list --- .../meteor-accounts-saml/.npm/package/npm-shrinkwrap.json | 3 --- .../client/views/stylesheets/messagestar.less | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json index 16c8109f51a..69bde52fbee 100644 --- a/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json +++ b/packages/meteor-accounts-saml/.npm/package/npm-shrinkwrap.json @@ -54,9 +54,6 @@ "xml-crypto": { "version": "0.6.0", "dependencies": { - "xmldom": { - "version": "0.1.19" - }, "xpath.js": { "version": "1.0.6" } diff --git a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less index 43fdc3fd5a6..1750399d391 100644 --- a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less +++ b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less @@ -17,4 +17,10 @@ text-align: center; margin-top: 60px; } + + .message-cog-container { + .edit-message, .delete-message { + display: none !important; + } + } } -- GitLab From f580a2f00052c14817d675f8d7fd8856177429a8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 22 Oct 2015 10:52:35 +0200 Subject: [PATCH 0189/1338] Improve oembed server side to decode compressed contents --- .../rocketchat-oembed/server/server.coffee | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 58b2fa5b780..f1e52c0d782 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -1,8 +1,12 @@ URL = Npm.require('url') http = Npm.require('http') https = Npm.require('https') +zlib = Npm.require('zlib') querystring = Npm.require('querystring') +gunzipSync = Meteor.wrapAsync zlib.gunzip.bind(zlib) +inflateSync = Meteor.wrapAsync zlib.inflate.bind(zlib) + OEmbed = {} getUrlContent = (urlObj, redirectCount = 5, callback) -> @@ -15,9 +19,8 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> hostname: urlObj.hostname path: urlObj.path rejectUnauthorized: !RocketChat.settings.get 'Allow_Invalid_SelfSigned_Certs' - headers: { + headers: 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36' - } httpOrHttps = if urlObj.protocol is 'https:' then https else http @@ -27,7 +30,7 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> requestOptions: opts parsedUrl: parsedUrl - request = httpOrHttps.request opts, (response) -> + request = httpOrHttps.request opts, Meteor.bindEnvironment (response) -> if response.statusCode is 301 and response.headers.location? request.abort() console.log response.headers.location @@ -41,16 +44,26 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> if response.statusCode isnt 200 return callback null, {parsedUrl: parsedUrl} - str = '' + chunks = [] + chunksTotalLength = 0 response.on 'data', (chunk) -> - str += chunk - if str.length > 250000 + chunks.push chunk + chunksTotalLength += chunk.length + if chunksTotalLength > 250000 request.abort() - response.on 'end', -> + response.on 'end', Meteor.bindEnvironment -> + buffer = Buffer.concat(chunks) + + try + if response.headers['content-encoding'] is 'gzip' + buffer = gunzipSync buffer + else if response.headers['content-encoding'] is 'deflate' + buffer = inflateSync buffer + callback null, { headers: response.headers - body: str + body: buffer.toString() parsedUrl: parsedUrl } -- GitLab From 91f766a6c628a10833c97f5ebce94596444cb5d4 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 22 Oct 2015 10:53:13 +0200 Subject: [PATCH 0190/1338] Improve video widget to show gifv from imgur --- .../rocketchat-oembed/client/baseWidget.coffee | 2 +- .../client/oembedVideoWidget.coffee | 16 ++++++++++++++++ .../client/oembedVideoWidget.html | 4 +++- packages/rocketchat-oembed/package.js | 2 ++ .../assets/stylesheets/base.less | 4 ++++ 5 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-oembed/client/oembedVideoWidget.coffee diff --git a/packages/rocketchat-oembed/client/baseWidget.coffee b/packages/rocketchat-oembed/client/baseWidget.coffee index 4e4d68b4391..8a84ed7a506 100644 --- a/packages/rocketchat-oembed/client/baseWidget.coffee +++ b/packages/rocketchat-oembed/client/baseWidget.coffee @@ -9,7 +9,7 @@ Template.oembedBaseWidget.helpers if this.headers?.contentType?.match(/audio\/.*/)? return 'oembedAudioWidget' - if this.headers?.contentType?.match(/video\/.*/)? + if this.headers?.contentType?.match(/video\/.*/)? or this.meta?.twitterPlayerStreamContentType?.match(/video\/.*/)? return 'oembedVideoWidget' if this.parsedUrl?.host is 'www.youtube.com' and this.meta?.twitterPlayer? diff --git a/packages/rocketchat-oembed/client/oembedVideoWidget.coffee b/packages/rocketchat-oembed/client/oembedVideoWidget.coffee new file mode 100644 index 00000000000..65a616e4a02 --- /dev/null +++ b/packages/rocketchat-oembed/client/oembedVideoWidget.coffee @@ -0,0 +1,16 @@ +getTitle = (self) -> + if not self.meta? + return + + return self.meta.ogTitle or self.meta.twitterTitle or self.meta.title or self.meta.pageTitle + + +Template.oembedVideoWidget.helpers + url: -> + return @meta?.twitterPlayerStream or @url + + contentType: -> + return @meta?.twitterPlayerStreamContentType or @headers?.contentType + + title: -> + return getTitle @ diff --git a/packages/rocketchat-oembed/client/oembedVideoWidget.html b/packages/rocketchat-oembed/client/oembedVideoWidget.html index 389b694c70b..5377b5bf837 100644 --- a/packages/rocketchat-oembed/client/oembedVideoWidget.html +++ b/packages/rocketchat-oembed/client/oembedVideoWidget.html @@ -1,8 +1,10 @@ <template name="oembedVideoWidget"> {{#if parsedUrl}} <blockquote> + <div><a href="{{url}}">{{parsedUrl.host}}</a></div> + <div>{{title}}</div> <video controls class="inline-video"> - <source src="{{url}}" type="{{headers.contentType}}"> + <source src="{{url}}" type="{{contentType}}"> Your browser does not support the video element. </video> </blockquote> diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index 8a7d58e9629..eab59017ae9 100644 --- a/packages/rocketchat-oembed/package.js +++ b/packages/rocketchat-oembed/package.js @@ -21,7 +21,9 @@ Package.onUse(function(api) { api.addFiles('client/oembedImageWidget.coffee', 'client'); api.addFiles('client/oembedAudioWidget.html', 'client'); + api.addFiles('client/oembedVideoWidget.html', 'client'); + api.addFiles('client/oembedVideoWidget.coffee', 'client'); api.addFiles('client/oembedYoutubeWidget.html', 'client'); diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 546661cab0c..a58b0235e5f 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4018,3 +4018,7 @@ a.github-fork { text-indent: 34px; } } + +.inline-video { + max-height: 200px; +} -- GitLab From fc954de6d817e5c082321c7b6ae257b4dc437297 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 22 Oct 2015 11:39:31 +0200 Subject: [PATCH 0191/1338] Fix the cutted name in downloaded files --- lib/fileUpload.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 85d21923564..99755cae765 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -42,7 +42,7 @@ if UploadFS? console.log arguments onRead: (fileId, file, req, res) -> unless file?.type?.match(/^image\/.*/) - res.setHeader 'content-disposition', "attachment; filename='#{ file.name }'" + res.setHeader 'content-disposition', "attachment; filename=\"#{ file.name }\"" if Meteor.isServer initFileStore() -- GitLab From c7611642c29b041cf437cf8a248218b89a62f3ad Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 22 Oct 2015 12:17:25 +0000 Subject: [PATCH 0192/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/de.i18n.json | 37 +- i18n/en.i18n.json | 24 +- i18n/fi.i18n.json | 24 +- i18n/fr.i18n.json | 18 +- i18n/hr.i18n.json | 11 +- i18n/ja.i18n.json | 18 +- i18n/km.i18n.json | 61 ++- i18n/ko.i18n.json | 21 +- i18n/ms-MY.i18n.json | 368 ++++++++++++++++++ i18n/pt.i18n.json | 38 +- i18n/ru.i18n.json | 67 +++- packages/rocketchat-chatops/i18n/ar.i18n.json | 1 + packages/rocketchat-chatops/i18n/de.i18n.json | 4 + packages/rocketchat-chatops/i18n/el.i18n.json | 1 + packages/rocketchat-chatops/i18n/en.i18n.json | 8 +- packages/rocketchat-chatops/i18n/es.i18n.json | 1 + packages/rocketchat-chatops/i18n/fi.i18n.json | 4 + packages/rocketchat-chatops/i18n/fr.i18n.json | 4 + packages/rocketchat-chatops/i18n/he.i18n.json | 1 + packages/rocketchat-chatops/i18n/hr.i18n.json | 1 + packages/rocketchat-chatops/i18n/hu.i18n.json | 1 + packages/rocketchat-chatops/i18n/it.i18n.json | 1 + packages/rocketchat-chatops/i18n/ja.i18n.json | 1 + packages/rocketchat-chatops/i18n/km.i18n.json | 5 + packages/rocketchat-chatops/i18n/ko.i18n.json | 1 + .../rocketchat-chatops/i18n/ms-MY.i18n.json | 1 + packages/rocketchat-chatops/i18n/pl.i18n.json | 1 + packages/rocketchat-chatops/i18n/pt.i18n.json | 5 + packages/rocketchat-chatops/i18n/ru.i18n.json | 1 + .../rocketchat-chatops/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-chatops/i18n/tr.i18n.json | 1 + packages/rocketchat-chatops/i18n/ug.i18n.json | 1 + packages/rocketchat-chatops/i18n/uk.i18n.json | 1 + packages/rocketchat-chatops/i18n/zh.i18n.json | 1 + .../i18n/ar.i18n.json | 2 +- .../i18n/de.i18n.json | 7 +- .../i18n/el.i18n.json | 2 +- .../i18n/en.i18n.json | 2 +- .../i18n/es.i18n.json | 2 +- .../i18n/fi.i18n.json | 2 +- .../i18n/fr.i18n.json | 2 +- .../i18n/he.i18n.json | 2 +- .../i18n/hr.i18n.json | 2 +- .../i18n/hu.i18n.json | 2 +- .../i18n/it.i18n.json | 2 +- .../i18n/ja.i18n.json | 2 +- .../i18n/km.i18n.json | 8 +- .../i18n/ko.i18n.json | 2 +- .../i18n/ms-MY.i18n.json | 1 + .../i18n/pl.i18n.json | 2 +- .../i18n/pt.i18n.json | 7 +- .../i18n/ru.i18n.json | 2 +- .../i18n/ta-IN.i18n.json | 2 +- .../i18n/tr.i18n.json | 2 +- .../i18n/ug.i18n.json | 2 +- .../i18n/uk.i18n.json | 2 +- .../i18n/zh.i18n.json | 2 +- .../rocketchat-gitlab/i18n/ms-MY.i18n.json | 1 + packages/rocketchat-hubot/i18n/ar.i18n.json | 1 + packages/rocketchat-hubot/i18n/de.i18n.json | 5 + packages/rocketchat-hubot/i18n/el.i18n.json | 1 + packages/rocketchat-hubot/i18n/en.i18n.json | 8 +- packages/rocketchat-hubot/i18n/es.i18n.json | 1 + packages/rocketchat-hubot/i18n/fi.i18n.json | 5 + packages/rocketchat-hubot/i18n/fr.i18n.json | 5 + packages/rocketchat-hubot/i18n/he.i18n.json | 1 + packages/rocketchat-hubot/i18n/hr.i18n.json | 1 + packages/rocketchat-hubot/i18n/hu.i18n.json | 1 + packages/rocketchat-hubot/i18n/it.i18n.json | 1 + packages/rocketchat-hubot/i18n/ja.i18n.json | 1 + packages/rocketchat-hubot/i18n/km.i18n.json | 5 + packages/rocketchat-hubot/i18n/ko.i18n.json | 5 + .../rocketchat-hubot/i18n/ms-MY.i18n.json | 5 + packages/rocketchat-hubot/i18n/pl.i18n.json | 1 + packages/rocketchat-hubot/i18n/pt.i18n.json | 8 +- packages/rocketchat-hubot/i18n/ru.i18n.json | 1 + .../rocketchat-hubot/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-hubot/i18n/tr.i18n.json | 1 + packages/rocketchat-hubot/i18n/ug.i18n.json | 1 + packages/rocketchat-hubot/i18n/uk.i18n.json | 1 + packages/rocketchat-hubot/i18n/zh.i18n.json | 1 + packages/rocketchat-ldap/i18n/ms-MY.i18n.json | 5 + .../rocketchat-livechat/i18n/de.i18n.json | 5 +- .../rocketchat-livechat/i18n/fi.i18n.json | 5 +- .../rocketchat-livechat/i18n/fr.i18n.json | 5 +- .../rocketchat-livechat/i18n/km.i18n.json | 5 +- .../rocketchat-livechat/i18n/ko.i18n.json | 5 +- .../rocketchat-livechat/i18n/ms-MY.i18n.json | 4 + .../rocketchat-message-star/i18n/ar.i18n.json | 1 + .../rocketchat-message-star/i18n/de.i18n.json | 4 + .../rocketchat-message-star/i18n/el.i18n.json | 1 + .../rocketchat-message-star/i18n/en.i18n.json | 12 +- .../rocketchat-message-star/i18n/es.i18n.json | 1 + .../rocketchat-message-star/i18n/fi.i18n.json | 1 + .../rocketchat-message-star/i18n/fr.i18n.json | 7 + .../rocketchat-message-star/i18n/he.i18n.json | 1 + .../rocketchat-message-star/i18n/hr.i18n.json | 1 + .../rocketchat-message-star/i18n/hu.i18n.json | 1 + .../rocketchat-message-star/i18n/it.i18n.json | 1 + .../rocketchat-message-star/i18n/ja.i18n.json | 1 + .../rocketchat-message-star/i18n/km.i18n.json | 7 + .../rocketchat-message-star/i18n/ko.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 7 + .../rocketchat-message-star/i18n/pl.i18n.json | 1 + .../rocketchat-message-star/i18n/pt.i18n.json | 12 +- .../rocketchat-message-star/i18n/ru.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../rocketchat-message-star/i18n/tr.i18n.json | 1 + .../rocketchat-message-star/i18n/ug.i18n.json | 1 + .../rocketchat-message-star/i18n/uk.i18n.json | 1 + .../rocketchat-message-star/i18n/zh.i18n.json | 1 + .../i18n/ar.i18n.json | 1 + .../i18n/de.i18n.json | 5 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 2 +- .../i18n/es.i18n.json | 1 + .../i18n/fi.i18n.json | 4 + .../i18n/fr.i18n.json | 5 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 5 + .../i18n/ko.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 5 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 2 +- .../i18n/ru.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + .../i18n/ar.i18n.json | 1 + .../i18n/de.i18n.json | 3 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 2 +- .../i18n/es.i18n.json | 1 + .../i18n/fi.i18n.json | 3 + .../i18n/fr.i18n.json | 3 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 4 + .../i18n/ko.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 4 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 2 +- .../i18n/ru.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/ms-MY.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/ru.i18n.json | 1 + .../rocketchat-wordpress/i18n/de.i18n.json | 7 +- .../rocketchat-wordpress/i18n/fi.i18n.json | 7 +- .../rocketchat-wordpress/i18n/fr.i18n.json | 7 +- .../rocketchat-wordpress/i18n/hr.i18n.json | 4 +- .../rocketchat-wordpress/i18n/km.i18n.json | 7 +- .../rocketchat-wordpress/i18n/ko.i18n.json | 7 +- .../rocketchat-wordpress/i18n/ms-MY.i18n.json | 6 + .../rocketchat-wordpress/i18n/pt.i18n.json | 5 +- 167 files changed, 988 insertions(+), 107 deletions(-) create mode 100644 i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ar.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/de.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/el.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/es.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/fi.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/fr.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/he.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/hr.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/hu.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/it.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ja.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/km.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ko.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/pl.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/pt.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ru.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/tr.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ug.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/uk.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/zh.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ar.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/de.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/el.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/es.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/fi.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/fr.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/he.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/hr.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/hu.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/it.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ja.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/km.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ko.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/pl.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ru.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/tr.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ug.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/uk.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/zh.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ar.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/de.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/el.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/es.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/fi.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/fr.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/he.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/hr.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/hu.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/it.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ja.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/km.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ko.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/pl.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ru.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/tr.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ug.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/uk.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/zh.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/de.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/el.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/es.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/fr.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/he.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/hr.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/hu.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/it.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ja.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/km.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/tr.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ug.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/uk.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/zh.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ar.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/de.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/el.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/es.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/fi.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/fr.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/he.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/hr.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/hu.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/it.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ja.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/km.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ko.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/pl.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ru.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/tr.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ug.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/uk.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/zh.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/ms-MY.i18n.json diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 487a94c7cbf..08bb9ab3846 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -35,6 +35,7 @@ "Accounts_OAuth_Custom_Button_Label_Color" : "Button-Text-Farbe", "Accounts_OAuth_Custom_Button_Color" : "Buttonfarbe", "Activate" : "Aktivieren", + "Add_custom_oauth" : "Benutzerdefinierte oauth hinzufügen", "Add_Members" : "Mitglieder hinzufügen", "Add_users" : "Benutzer hinzufügen", "Administration" : "Administration", @@ -44,6 +45,7 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Einbetten", + "API_EmbedDisabledFor_Description" : "Durch Kommata getrennte Liste von Benutzernamen", "are_also_typing" : "schreiben auch", "are_typing" : "schreiben", "Are_you_sure" : "Sind Sie sicher?", @@ -70,6 +72,8 @@ "Chat_Rooms" : "Chaträume", "close" : "schließen", "coming_soon" : "kommt bald", + "Commands" : "Befehle", + "Compact_View" : "Kompakte Ansicht", "Confirm_password" : "Bestätigen Sie Ihr Passwort", "Contact" : "Kontakt", "Conversation" : "Konversation", @@ -79,12 +83,17 @@ "Create_new_private_group" : "Erstellen Sie eine neue private Gruppe", "Create_new_public_channel" : "Erstelle einen neuen öffentlichen Channel", "Created_at" : "Erstellt am", + "Custom_oauth_unique_name" : "Eindeutigen Namen von benutzerdefinierte oauth", + "Custom_oauth_helper" : "Bei der Einrichtung von OAuth, muss eine Callback-URL angegeben werden. Benutze <pre>%s</pre>", "days" : "Tage", "Deactivate" : "Deaktivieren", "Delete_User_Warning" : "Beim Löschen eines Benutzers, werden alle seine Nachrichten ebenfalls gelöscht. Dies kann nicht rückgängig gemacht werden.", "Delete" : "Löschen", "Deleted" : "Gelöscht!", + "Desktop_Notifications" : "Desktop-Benachrichtigungen", + "Desktop_Notifications_Enabled" : "Desktop-Benachrichtigungen sind 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", @@ -96,12 +105,19 @@ "Email_already_exists" : "E-Mail existiert bereits", "Email_or_username" : "Email oder Username", "Email_verified" : "Email bestätigt", + "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "Aktiviere Desktop-Benachrichtigungen", "Enter_info" : "Geben Sie Ihre Anmeldedaten an", "Enter_to" : "Enter um", "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", "Favorites" : "Favoriten", + "FileUpload" : "Datei-Upload", + "FileUpload_Enabled" : "Datei-Upload aktivieren", + "FileUpload_MaxFileSize" : "Max. Größe für hochgeladene Dateien (in Bytes)", + "FileUpload_MediaTypeWhiteList" : "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.", "Forgot_password" : "Passwort vergessen?", "Fork_it_on_github" : "Fork es auf GitHub", @@ -109,11 +125,13 @@ "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", "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.", "Has_more" : "Mehr", "Hide_room" : "Raum verstecken", "History" : "Chronik", "hours" : "Stunden", + "Incorrect_Password" : "Falsches Passwort", "inline_code" : "inline_code", "Invalid_confirm_pass" : "Die Passwörter stimmen nicht überein", "Invalid_email" : "Email-Adresse ungültigt", @@ -166,9 +184,11 @@ "Message" : "Nachricht", "Message_AllowDeleting" : "Erlaube Nachrichten zu löschen", "Message_AllowEditing" : "Erlaube Bearbeitung von Nachrichten", - "Message_AllowPinning" : "Erlaube es Nachrichten anzuheften", + "Message_AllowEditing_BlockEditInMinutes" : "Bearbeiten von Nachrichten blockieren nach (in Minuten - 0 zum deaktivieren)", + "Message_AudioRecorderEnabled" : "Audio Recorder Aktiviert", "Message_deleting_not_allowed" : "Nachrichten löschen nicht erlaubt", "Message_editing_not_allowed" : "Nachrichten bearbeiten nicht erlaubt", + "Message_editing_blocked" : "Diese Nachricht kann nicht mehr bearbeitet werden", "Message_MaxAllowedSize" : "Maximale Größe der Nachricht", "Message_pinning_not_allowed" : "Nachrichten anheften erlaubt", "Message_KeepHistory" : "Nachrichtenverlauf behalten", @@ -176,6 +196,7 @@ "Message_pinned" : "Nachricht angeheftet", "Message_ShowDeletedStatus" : "Zeige Löschstatus", "Message_ShowEditedStatus" : "Zeige Bearbeitungsstatus", + "Messages" : "Nachrichten", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Google Seiten", @@ -191,6 +212,7 @@ "My_Account" : "Mein Konto", "n_messages" : "%s Nachrichten", "Name" : "Name", + "Name_cant_be_empty" : "Name darf nicht leer sein", "New_messages" : "Neue Nachrichten", "New_password" : "Neues Passwort", "No_channels_yet" : "Sie sind kein Mitglied eines Channels.", @@ -205,6 +227,8 @@ "Not_found_or_not_allowed" : "Nicht gefunden oder erlaubt", "Nothing_found" : "Nichts gefunden", "Notify_all_in_this_room" : "Alle in diesem Raum benachrichtigen", + "Old_Password" : "Altes Passwort", + "Old_and_new_password_required" : "Das alte und neue Passwort müssen angegeben werden um das jetzige Passwort zu ändern.", "Only_you_can_see_this_message" : "Nur Sie können diese Nachricht sehen", "Online" : "Online", "Oops!" : "Oops", @@ -213,6 +237,7 @@ "others" : "andere", "Password" : "Passwort", "Password_changed_successfully" : "Passwort erfolgreich geändert", + "People" : "Leute", "Please_wait" : "Bitte warten", "Please_wait_activation" : "Bitte warten. ", "Please_wait_statistics" : "Bitte warten, Statistiken werden generiert.", @@ -238,16 +263,20 @@ "Quick_Search" : "Schnellsuche", "quote" : "Zitat", "Recents" : "Aktuell", + "Record" : "Aufnehmen", "Register" : "Registriere einen neuen Account", "Registration_Succeeded" : "Registrierung erfolgreich", "Remember_me" : "Erinnere dich an mich", "Remove" : "Entfernen", + "Remove_custom_oauth" : "Entferne benutzerdefiniertes oauth", "Remove_Admin" : "Admin entfernen", "Reset_password" : "Passwort zurücksetzen", "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_user_count" : "%s Benutzer", "Rooms" : "Räume", "Save" : "Speichern", @@ -278,6 +307,8 @@ "Silence" : "Ruhe", "since_creation" : "seit %s", "Site_Name" : "Seitenname:", + "Site_Url" : "Website URL", + "Site_Url_Description" : "Beispiel: https://chat.domain.com/", "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", @@ -310,6 +341,7 @@ "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", "S_new_messages_since_s" : "%s neue Nachrichten seit %s", @@ -340,6 +372,7 @@ "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_Settings" : "Benutzereinstellungen", "User_updated_successfully" : "Benutzer erfolgreich aktualisiert", @@ -363,4 +396,4 @@ "You_will_not_be_able_to_recover" : "Sie können es nicht wieder rückgängig machen!", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", "Your_Open_Source_solution" : "Deine eigene Open Source Chat Lösung" -} +} \ No newline at end of file diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 8d28d4eb24b..56b72649f2a 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -47,8 +47,8 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Embed", - "API_EmbedDisabledFor": "Disable Embed for Users", - "API_EmbedDisabledFor_Description": "Comma-separated usernames list", + "API_EmbedDisabledFor" : "Disable Embed for Users", + "API_EmbedDisabledFor_Description" : "Comma-separated usernames list", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", @@ -76,7 +76,7 @@ "close" : "close", "coming_soon" : "coming soon", "Commands" : "Commands", - "Compact_View": "Compact View", + "Compact_View" : "Compact View", "Confirm_password" : "Confirm your password", "Contact" : "Contact", "Conversation" : "Conversation", @@ -93,9 +93,9 @@ "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", "Delete" : "Delete", "Deleted" : "Deleted!", - "Desktop_Notifications": "Desktop Notifications", - "Desktop_Notifications_Disabled": "Desktop Notifications are Disabled. Change your browser preferences if you need Notifications enabled.", - "Desktop_Notifications_Enabled": "Desktop Notifications are Enabled", + "Desktop_Notifications" : "Desktop Notifications", + "Desktop_Notifications_Disabled" : "Desktop Notifications are Disabled. Change your browser preferences if you need Notifications enabled.", + "Desktop_Notifications_Enabled" : "Desktop Notifications are Enabled", "Direct_Messages" : "Direct Messages", "Disable_Favorite_Rooms" : "Disable Favorites", "Disable_New_Message_Notification" : "Disable New Message Notification", @@ -110,7 +110,7 @@ "Email_or_username" : "Email or username", "Email_verified" : "Email verified", "Emoji" : "Emoji", - "Enable_Desktop_Notifications": "Enable Desktop Notifications", + "Enable_Desktop_Notifications" : "Enable Desktop Notifications", "Enter_info" : "Enter your information", "Enter_to" : "Enter to", "Error_changing_password" : "Error changing password", @@ -189,7 +189,7 @@ "Message_AllowDeleting" : "Allow Message Deleting", "Message_AllowEditing" : "Allow Message Editing", "Message_AllowEditing_BlockEditInMinutes" : "Block message editing after (in minutes - 0 to disable)", - "Message_AudioRecorderEnabled": "Audio Recorder Enabled", + "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", "Message_deleting_not_allowed" : "Message deleting not allowed", "Message_editing_not_allowed" : "Message editing not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", @@ -200,8 +200,8 @@ "Message_pinned" : "Message pinned", "Message_ShowDeletedStatus" : "Show Deleted Status", "Message_ShowEditedStatus" : "Show Edited Status", - "Message_ShowFormattingTips": "Show Formatting Tips", - "Messages": "Messages", + "Message_ShowFormattingTips" : "Show Formatting Tips", + "Messages" : "Messages", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Google Site Verification", @@ -378,7 +378,7 @@ "User_left_female" : "User <em>__user_left__</em> left.", "User_left_male" : "User <em>__user_left__</em> left.", "User_logged_out" : "User is logged out", - "User_not_found_or_incorrect_password": "User not found or incorrect password", + "User_not_found_or_incorrect_password" : "User not found or incorrect password", "User_removed_by" : "User <em>__user_removed__</em> removed by <em>__user_by__</em>.", "User_Settings" : "User Settings", "User_updated_successfully" : "User updated successfully", @@ -402,4 +402,4 @@ "You_will_not_be_able_to_recover" : "You will not be able to recover!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", "Your_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 27cf59e059b..7a7e192dc8d 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -35,6 +35,7 @@ "Accounts_OAuth_Custom_Button_Label_Color" : "Painikkeen tekstin väri", "Accounts_OAuth_Custom_Button_Color" : "Painikkeen väri", "Activate" : "Aktivoi", + "Add_custom_oauth" : "Lisää mukautettu oauth", "Add_Members" : "Lisää osallistujia", "Add_users" : "Lisää käyttäjiä", "Administration" : "Ylläpito", @@ -70,6 +71,7 @@ "Chat_Rooms" : "Chathuoneet", "close" : "sulje", "coming_soon" : "tulossa", + "Commands" : "Komennot", "Confirm_password" : "Vahvista salasanasi", "Contact" : "Yhteys", "Conversation" : "Keskustelu", @@ -79,12 +81,15 @@ "Create_new_private_group" : "Luo uusi privaattiryhmä", "Create_new_public_channel" : "Luo uusi julkinen kanava", "Created_at" : "Luotu", + "Custom_oauth_unique_name" : "Mukautettu oauth yksilöllinen nimi", + "Custom_oauth_helper" : "Kun perustat OAuth Provider, sinun täytyy ilmoittaa Callback URL. Käytä <pre>%s</pre>.", "days" : "päivää", "Deactivate" : "Deaktivoi", "Delete_User_Warning" : "Käyttäjän poistaminen poistaa myös käyttäjän kaikki viestit. Toimintoa ei voi perua.", "Delete" : "Poista", "Deleted" : "Poistettu!", "Direct_Messages" : "Yksityisviestit", + "Disable_Favorite_Rooms" : "Poista käytöstä suosikit", "Disable_New_Message_Notification" : "Poista uuden viestin ilmoitus käytöstä", "Disable_New_Room_Notification" : "Poista uuden huoneen ilmoitus käytöstä", "Drop_to_upload_file" : "Vedä ja pudota lähettääksesi tiedoston", @@ -96,6 +101,7 @@ "Email_already_exists" : "Sähköpostiosoite on jo olemassa", "Email_or_username" : "Sähköpostiosoite tai käyttäjänimi", "Email_verified" : "Sähköpostiosoite vahvistettu", + "Emoji" : "Emoji", "Enter_info" : "Syötä kirjautumistietosi", "Enter_to" : "Astu sisään", "Error_changing_password" : "Virhe vaihtaessa salasanaa", @@ -109,11 +115,13 @@ "General" : "Yleinen", "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", "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.", "Has_more" : "Löytyy lisää", "Hide_room" : "Piilota kanava", "History" : "Historia", "hours" : "tuntia", + "Incorrect_Password" : "Väärä salasana", "inline_code" : "koodi", "Invalid_confirm_pass" : "Salasanat eivät täsmää", "Invalid_email" : "Annettu sähköpostiosoite ei ole oikea", @@ -166,9 +174,10 @@ "Message" : "Viesti", "Message_AllowDeleting" : "Salli viestin poisto", "Message_AllowEditing" : "Salli viestin muokkaus", - "Message_AllowPinning" : "Salli viestien kiinnittäminen", + "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus jälkeen (minuuteissa - 0 poistaa käytöstä)", "Message_deleting_not_allowed" : "Viestin poisto ei sallittu", "Message_editing_not_allowed" : "Viestin muokkaus ei sallittu", + "Message_editing_blocked" : "Tätä viestiä ei voi muokata enää.", "Message_MaxAllowedSize" : "Viestin suurin sallittu koko", "Message_pinning_not_allowed" : "Viestien kiinnittäminen ei sallittu", "Message_KeepHistory" : "Säilytä viestihistoria", @@ -191,6 +200,7 @@ "My_Account" : "Käyttäjätilini", "n_messages" : "%s viestiä", "Name" : "Nimi", + "Name_cant_be_empty" : "Nimi ei voi olla tyhjä", "New_messages" : "Uusia viestejä", "New_password" : "Uusi salasana", "No_channels_yet" : "Et ole vielä millään kanavalla.", @@ -205,6 +215,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", + "Old_Password" : "Vanha salasana", + "Old_and_new_password_required" : "Sinun täytyy antaa sekä vanha että uusi salasana, että saat vaihdettua salasanasi.", "Only_you_can_see_this_message" : "Vain sinä voit nähdä tämän viestin", "Online" : "Online", "Oops!" : "Oho", @@ -213,6 +225,7 @@ "others" : "muut", "Password" : "Salasana", "Password_changed_successfully" : "Salasana vaihdettu", + "People" : "Ihmiset", "Please_wait" : "Odota hetki", "Please_wait_activation" : "Odota, tämä voi kestää jonkin aikaa.", "Please_wait_statistics" : "Odota, tilastoja generoidaan.", @@ -238,16 +251,20 @@ "Quick_Search" : "Pikaetsintä", "quote" : "lainaus", "Recents" : "Viimeisimmät", + "Record" : "Nauhoita", "Register" : "Rekisteröi uusi käyttäjätili", "Registration_Succeeded" : "Rekisteröinti onnistui", "Remember_me" : "Muista minut", "Remove" : "Poista", + "Remove_custom_oauth" : "Poista mukautettu oauth", "Remove_Admin" : "Poista ylläpitäjyys", "Reset_password" : "Nollaa salasana", "Room" : "Huone", "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_uploaded_file_list" : "Tiedostolista", + "Room_uploaded_file_list_empty" : "Tiedostoja ei ole saatavilla.", "room_user_count" : "%s käyttäjää", "Rooms" : "Huoneet", "Save" : "Tallenna", @@ -266,6 +283,10 @@ "Send" : "Lähetä", "Send_confirmation_email" : "Lähetä vahvistussähköposti", "Send_invitation_email" : "Lähetä kutsu sähköposti", + "Send_invitation_email_error" : "Et ole antanyt yhtään pätevää sähköpostiosoitetta.", + "Send_invitation_email_info" : "Voit lähettää useita sähköpostikutsuja kerralla.", + "Send_invitation_email_success" : "Olet onnistuneesti lähettänyt sähköpostikutsun seuraaviin osoitteisiin:", + "Send_invitation_email_warning" : "Lähettääksesi sähköpostikutsuja, sinun täytyy ensin tehdä SMTP asetukset.", "Send_Message" : "Lähetä viesti", "Settings" : "Asetukset", "Settings_updated" : "Asetukset päivitetty", @@ -306,6 +327,7 @@ "Stats_Total_Private_Groups" : "Privaattiryhmien määrä", "Stats_Total_Rooms" : "Huoneiden määrä", "Stats_Total_Users" : "Käyttäjiä yhteensä", + "Stop_Recording" : "Lopeta nauhoittaminen", "strike" : "yliviivaa", "Submit" : "Lähetä", "S_new_messages_since_s" : "%s uutta viestiä lähtien %s", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index c52638b205d..d2e83235575 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -71,6 +71,7 @@ "Chat_Rooms" : "Salons de discussion", "close" : "fermer", "coming_soon" : "prochainement", + "Commands" : "Commandes", "Confirm_password" : "Confirmez votre mot de passe", "Contact" : "Contact", "Conversation" : "Conversation", @@ -81,12 +82,17 @@ "Create_new_public_channel" : "Créer un nouveau canal publique.", "Created_at" : "Créé le", "Custom_oauth_unique_name" : "Nom unique OAuth personnalisé", + "Custom_oauth_helper" : "Lorsque vous configurez votre service OAuth, vous devez indiquer une URL pour le Callback. Utilisez <pre>%s</pre>", "days" : "jours", "Deactivate" : "Désactiver", "Delete_User_Warning" : "Supprimer un utilisateur va également supprimer tous les messages de celui-ci. Cette action ne peut être annulée.", "Delete" : "Supprimer", "Deleted" : "Supprimé !", + "Desktop_Notifications" : "Notifications sur le bureau", + "Desktop_Notifications_Disabled" : "Les notifications du bureau sont désactivées, Modifiez les préférences de votre navigateur si vous avez besoin de les activer.", + "Desktop_Notifications_Enabled" : "Les notifications sur le bureau sont activées", "Direct_Messages" : "Messages directs", + "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", "Drop_to_upload_file" : "Glissez-déposez pour transférer un fichier", @@ -98,6 +104,8 @@ "Email_already_exists" : "L'adresse email existe déjà ", "Email_or_username" : "Adresse email ou nom d'utilisateur", "Email_verified" : "Email 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", @@ -117,6 +125,7 @@ "Hide_room" : "Cacher le salon", "History" : "Historique", "hours" : "heures", + "Incorrect_Password" : "Mot de passe incorrect", "inline_code" : "Ligne de code", "Invalid_confirm_pass" : "Les mots de passe renseignés ne sont pas les mêmes", "Invalid_email" : "L'adresse email saisie est invalide", @@ -170,7 +179,6 @@ "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_AllowPinning" : "Autoriser l'épinglement de messages", "Message_deleting_not_allowed" : "Suppression d'un message non autorisée", "Message_editing_not_allowed" : "Modification d'un message non autorisée", "Message_editing_blocked" : "Ce message ne peut plus être modifié", @@ -181,6 +189,7 @@ "Message_pinned" : "Message épinglé", "Message_ShowDeletedStatus" : "Afficher le statut de suppression", "Message_ShowEditedStatus" : "Afficher le statut de modification", + "Messages" : "Messages", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Google Site Verification", @@ -211,6 +220,8 @@ "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", + "Old_Password" : "Ancien mot de passe", + "Old_and_new_password_required" : "Vous devez renseigner votre ancien mot de passe et le nouveau afin de changer ce dernier.", "Only_you_can_see_this_message" : "Seul vous pouvez voir ce message", "Online" : "Connecté", "Oops!" : "Oups", @@ -219,6 +230,7 @@ "others" : "autres", "Password" : "Mot de passe", "Password_changed_successfully" : "Mot de passe modifié avec succès", + "People" : "Personnes", "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.", @@ -244,6 +256,7 @@ "Quick_Search" : "Recherche rapide", "quote" : "citation", "Recents" : "Récents", + "Record" : "Enregistrer", "Register" : "Créer un nouveau compte", "Registration_Succeeded" : "Enregistrement réussi", "Remember_me" : "Se souvenir de moi", @@ -255,6 +268,8 @@ "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_uploaded_file_list" : "Liste des fichiers", + "Room_uploaded_file_list_empty" : "Aucun fichier disponible.", "room_user_count" : "%s utilisateurs", "Rooms" : "Salons", "Save" : "Enregistrer", @@ -317,6 +332,7 @@ "Stats_Total_Private_Groups" : "Nombre total de groupes privés", "Stats_Total_Rooms" : "Nombre total de salons", "Stats_Total_Users" : "Nombre total d'utilisateurs", + "Stop_Recording" : "Arrêter l'enregistrement", "strike" : "barré", "Submit" : "Envoyer", "S_new_messages_since_s" : "%s nouveaux messages depuis %s", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 068e0df7a4c..788c918946c 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -64,6 +64,7 @@ "Delete" : "ObriÅ¡i", "Deleted" : "Obrisano!", "Direct_Messages" : "Izravne Poruke", + "Disable_Favorite_Rooms" : "Onemogući favorite", "Disable_New_Message_Notification" : "Onemogući obavijesti o novim porukama", "Disable_New_Room_Notification" : "Onemogući obavijesti o novim sobama", "Drop_to_upload_file" : "Ispusti datoteku da se uploada.", @@ -100,6 +101,7 @@ "Invalid_room_name" : "<strong>%s</strong> nije valjano ime sobe,<br/> koristi samo slova, brojeve i crtice", "invisible" : "nevidljiv", "Invisible" : "Nevidljiv", + "Invite_Users" : "Pozovite korisnike", "is_also_typing" : "isto tipka", "is_also_typing_female" : "isto tipka", "is_also_typing_male" : "isto tipka", @@ -134,9 +136,10 @@ "Message" : "Poruka", "Message_AllowDeleting" : "Dopusti Brisanje Poruka", "Message_AllowEditing" : "Dopusti UreÄ‘ivanje Poruka", - "Message_AllowPinning" : "Dopusti pribadanje poruka ", + "Message_AllowEditing_BlockEditInMinutes" : "Blokirajte ureÄ‘ivanje poruka nakon (u minutama - 0 kako bi onemoguÄili)", "Message_deleting_not_allowed" : "Brisanje poruka nije dopuÅ¡teno", "Message_editing_not_allowed" : "UreÄ‘ivanje poruka nije dopuÅ¡teno", + "Message_editing_blocked" : "Ova poruka se viÅ¡e ne može ureÄ‘ivati ", "Message_MaxAllowedSize" : "Maksimalna dopuÅ¡tena veliÄina poruke", "Message_pinning_not_allowed" : "Pribadanje poruka nije dopuÅ¡teno", "Message_KeepHistory" : "Zadrži Povijest Poruka", @@ -157,6 +160,7 @@ "My_Account" : "Moj RaÄun", "n_messages" : "%s poruka", "Name" : "Ime", + "Name_cant_be_empty" : "Ime ne može biti prazno", "New_messages" : "Nove Poruke", "New_password" : "Nova lozinka", "No_channels_yet" : "JoÅ¡ nisi dio nijednog kanala.", @@ -220,7 +224,12 @@ "Select_file" : "Odaberi fajl", "Select_service_to_login" : "Odaberi servis kako bi se prijavio/la da uÄitaÅ¡ svoju sliku ili ju uploadaj izravno sa svog raÄunala", "Selected_users" : "Odabrani Älanovi", + "Send" : "PoÅ¡alji", "Send_confirmation_email" : "PoÅ¡alji potvrdni email", + "Send_invitation_email" : "PoÅ¡aljite e-mail pozivnicu.", + "Send_invitation_email_error" : "Niste upisali nijednu valjanu e-mail adresu.", + "Send_invitation_email_info" : "Možete poslati viÅ¡e e-mail pozivnica odjednom.", + "Send_invitation_email_success" : "UspjeÅ¡no ste poslali e-mail pozivnicu na sljedeće adrese:", "Send_Message" : "PoÅ¡alji Poruku", "Settings" : "Postavke", "Settings_updated" : "Postavke su ažurirane", diff --git a/i18n/ja.i18n.json b/i18n/ja.i18n.json index 12d08e92e38..3f6b4f9338c 100644 --- a/i18n/ja.i18n.json +++ b/i18n/ja.i18n.json @@ -6,9 +6,9 @@ "and" : "ã¨", "are_also_typing" : "誰ã‹ãŒã¾ãŸå…¥åŠ›ã—ã¦ã„ã¾ã™", "are_typing" : "誰ã‹ãŒå…¥åŠ›ã—ã¦ã„ã¾ã™", - "Auto_Load_Images" : "ç”»åƒè‡ªå‹•èªã¿è¾¼ã¿", "away" : "離å¸ä¸", "Away" : "離å¸ä¸", + "Auto_Load_Images" : "ç”»åƒè‡ªå‹•èªã¿è¾¼ã¿", "Back_to_login" : "ãƒã‚°ã‚¤ãƒ³ã¸æˆ»ã‚‹", "bold" : "太å—", "busy" : "å–ã‚Šè¾¼ã¿ä¸", @@ -26,16 +26,16 @@ "Convert_Ascii_Emojis" : "ASCIIを絵文å—ã«å¤‰æ›ã™ã‚‹", "Create_new_public_channel" : "æ–°ã—ã„パブリックãƒãƒ£ãƒ³ãƒãƒ«ã‚’作æˆã—ã¾ã™", "Created_at" : "Created at", - "Desktop_Notifications": "デスクトップ通知", - "Desktop_Notifications_Disabled": "デスクトップ通知ãŒç„¡åŠ¹ãªã£ã¦ã„ã¾ã™ã€‚通知を有効ã«ã™ã‚‹å ´åˆã€ãƒ–ラウザã®è¨å®šã‚’変更ã—ã¦ãã ã•ã„。", - "Desktop_Notifications_Enabled": "デスクトップ通知ã¯æœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚", + "Desktop_Notifications" : "デスクトップ通知", + "Desktop_Notifications_Disabled" : "デスクトップ通知ãŒç„¡åŠ¹ãªã£ã¦ã„ã¾ã™ã€‚通知を有効ã«ã™ã‚‹å ´åˆã€ãƒ–ラウザã®è¨å®šã‚’変更ã—ã¦ãã ã•ã„。", + "Desktop_Notifications_Enabled" : "デスクトップ通知ã¯æœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚", "Direct_Messages" : "ダイレクトメッセージ", "Disable_New_Message_Notification" : "æ–°ã—ã„メッセージã®é€šçŸ¥ã‚’無効ã«ã™ã‚‹", "Disable_New_Room_Notification" : "æ–°ã—ã„ルームã®é€šçŸ¥ã‚’無効ã«ã™ã‚‹", "edited" : "編集", "Email_or_username" : "メールアドレスã¾ãŸã¯ãƒ¦ãƒ¼ã‚¶å", "Email_verified" : "メールアドレスã®æ¤œè¨¼", - "Enable_Desktop_Notifications": "デスクトップ通知を有効ã«ã™ã‚‹", + "Enable_Desktop_Notifications" : "デスクトップ通知を有効ã«ã™ã‚‹", "Enter_info" : "ãƒã‚°ã‚¤ãƒ³æƒ…å ±ã‚’å…¥åŠ›ã—ã¦ãã ã•ã„", "Error_changing_password" : "パスワード変更", "Favorites" : "ãŠæ°—ã«å…¥ã‚Š", @@ -71,7 +71,7 @@ "Members" : "メンãƒãƒ¼", "Members_List" : "メンãƒãƒ¼ãƒªã‚¹ãƒˆ", "Members_placeholder" : "メンãƒãƒ¼", - "Messages": "メッセージ", + "Messages" : "メッセージ", "More_channels" : "ãã®ä»–ã®ãƒãƒ£ãƒ³ãƒãƒ«", "Msgs" : "Msgs", "multi" : "マルãƒ", @@ -95,9 +95,9 @@ "Preferences" : "è¨å®š", "Preferences_saved" : "è¨å®šã‚’ä¿å˜ã—ã¾ã—ãŸã€‚", "Privacy" : "プライãƒã‚·ãƒ¼", + "Private_Groups" : "プライベートグループ", "Profile" : "プãƒãƒ•ã‚£ãƒ¼ãƒ«", "Profile_saved_successfully" : "プãƒãƒ•ã‚£ãƒ¼ãƒ«ã‚’ä¿å˜ã—ã¾ã—ãŸã€‚", - "Private_Groups" : "プライベートグループ", "Proudly_developed" : "Meteorã§èª‡ã‚Šã‚’æŒã£ã¦é–‹ç™º", "Quick_Search" : "クイック検索", "quote" : "引用", @@ -109,8 +109,8 @@ "Room" : "ルーム", "Room_name_changed" : "ルームåを変更ã—ã¾ã—ãŸ: <em>__room_name__</em> by <em>__user_by__</em>", "Room_name_changed_successfully" : "ルームåã®å¤‰æ›´ãŒæˆåŠŸã—ã¾ã—ãŸ", - "Save_Mobile_Bandwidth" : "モãƒã‚¤ãƒ«ãƒ‡ãƒ¼ã‚¿é€šä¿¡é‡ã‚’節約ã™ã‚‹", "Save" : "ä¿å˜", + "Save_Mobile_Bandwidth" : "モãƒã‚¤ãƒ«ãƒ‡ãƒ¼ã‚¿é€šä¿¡é‡ã‚’節約ã™ã‚‹", "Search" : "検索", "See_all" : "ã™ã¹ã¦è¦‹ã‚‹", "See_only_online" : "オンラインã®ã¿", @@ -153,4 +153,4 @@ "Welcome_to_the" : "Welcome to the", "You_need_confirm_email" : "ãƒã‚°ã‚¤ãƒ³ã™ã‚‹ãŸã‚ã«ã¯ãƒ¡ãƒ¼ãƒ«ã‚’確èªã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ï¼", "Your_Open_Source_solution" : "独自ã®ã‚ªãƒ¼ãƒ—ンソースãƒãƒ£ãƒƒãƒˆã‚½ãƒªãƒ¥ãƒ¼ã‚·ãƒ§ãƒ³" -} +} \ No newline at end of file diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index b50a1cd7682..893ab932571 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -26,19 +26,27 @@ "Accounts_OAuth_Twitter_secret" : "Twitter សម្ងាážáŸ‹", "Accounts_OAuth_Custom_ID" : "áž›áŸážážŸáž˜áŸ’គាល់", "Accounts_OAuth_Custom_URL" : "URL", + "Accounts_OAuth_Custom_Token_Path" : "ទីទាំង Token", + "Accounts_OAuth_Custom_Identity_Path" : "ទីទាំងអážáŸ’ážážŸáž‰áŸ’ញាណ", + "Accounts_OAuth_Custom_Authorize_Path" : "ទីážáž¶áŸ†áž„ផ្ទៀážáž•áŸ’ទាážáŸ‹", "Accounts_OAuth_Custom_Secret" : "ការ​សម្ងាážáŸ‹", "Accounts_OAuth_Custom_Enable" : "អនុញ្ញាáž", "Accounts_OAuth_Custom_Button_Label_Text" : "អážáŸ’ážáž”ទ​ប៊ូážáž»áž„", "Accounts_OAuth_Custom_Button_Label_Color" : "ពណ៌អážáŸ’ážáž”ទប៊ូážáž»áž„", "Accounts_OAuth_Custom_Button_Color" : "ពណ៌ប៊ូážáž»áž„", "Activate" : "ធ្វើ​ឱ្យ​សកម្ម", + "Add_custom_oauth" : "បន្ážáŸ‚ម oauth ផ្ទាល់​ážáŸ’លួន", "Add_Members" : "ážáŸ‚ម​សមាជិក", "Add_users" : "ážáŸ‚ម​អ្នក​ប្រើប្រាស់", "Administration" : "រដ្ឋបាល", "All_channels" : "គ្រប់​ប៉ិស្ážáž·áŸ", + "Allow_Invalid_SelfSigned_Certs" : "អនុញ្ញាážáž·áž²áŸ’យវិញ្ញាបនបáŸážáŸ’រមិនážáŸ’រឹមážáŸ’រូវ និងចុះហážáŸ’ážáž›áŸážáž¶ážáŸ’លួនឯង សម្រាប់ážáŸ†ážŽáž—្ជាប់ážáŸ’ážšáž½ážáž–áž·áž“áž·ážáŸ’áž™ និងមើលជាមុន", "and" : "áž“áž·áž„", + "API" : "ប្រើ API", "API_Analytics" : "វិភាគ", "API_Embed" : "បញ្ចូល", + "API_EmbedDisabledFor" : "មិនអនុញ្ញាážáž· Embed សម្រាប់អ្នកប្រើប្រាស់", + "API_EmbedDisabledFor_Description" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែងអ្នកប្រើប្រាស់ក្នុងបញ្ជី", "are_also_typing" : "គឺ​កំពុង​ព្យាយាម​ផង​ដែរ", "are_typing" : "កំពុង​វាយ", "Are_you_sure" : "ážáž¾â€‹áž¢áŸ’នក​ច្បាស់​ហើយ​ឬ?", @@ -65,6 +73,8 @@ "Chat_Rooms" : "បន្ទប់​ពិភាក្សា", "close" : "បិទ", "coming_soon" : "មក​ដល់​ឆាប់ៗ", + "Commands" : "ឃ្លាបញ្ជា", + "Compact_View" : "មើលជាážáž¶ážšáž¶áž„", "Confirm_password" : "បញ្ជាក់​ពាក្យ​សម្ងាážáŸ‹", "Contact" : "ទំនាក់ទំនង", "Conversation" : "កិច្ច​ពិភាក្សា", @@ -74,12 +84,18 @@ "Create_new_private_group" : "បង្កើážâ€‹áž€áŸ’រុម​ឯកជន", "Create_new_public_channel" : "បង្កើážâ€‹áž”៉ុស្ážáž·áŸâ€‹ážŸáž¶áž’ារណៈ​ážáŸ’មី", "Created_at" : "បាន​បង្កើážâ€‹áž€áž¶áž›â€‹áž–ី", + "Custom_oauth_unique_name" : "កំណážáŸ‹ oauth ឲ្យមានឈ្មោះážáŸ‚មួយគážáŸ‹", + "Custom_oauth_helper" : "áž–áŸáž›áž¢áŸ’នកកំពុងកំណážáŸ‹ OAuth Provider នោះអ្នកនឹងទទួល URL បញ្ជាក់មួយážáŸ’រឡប់មកវិញ, ដែលប្រើ <pre>%s</pre>", "days" : "ážáŸ’ងៃ", "Deactivate" : "ធ្វើឲ្យមិនសកម្ម", "Delete_User_Warning" : "ការ​លប់​អ្នក​ប្រើប្រាស់ នឹង​ážáŸ’រូវ​លប់​​គ្រប់​សារ​​របស់​​គាážáŸ‹â€‹áž•áž„​ដែរ។ ដូច​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ធ្វើ​បាន​ទ០។", "Delete" : "លុប", "Deleted" : "បាន​លប់!", + "Desktop_Notifications" : "ជំនូនដំណឹងលើ Desktop", + "Desktop_Notifications_Disabled" : "ជំនូនដំណឹងលើ Desktop មិនបានអនុញ្ញាážáž·, សូមផ្លាស់ប្ážáž¼ážšáž€áž¶ážšáž€áŸ†ážŽážáŸ‹áž“ៅលើ Browser របស់អ្នកប្រសិនបើចង់អនុញ្ញážáž·ážœáž¶", + "Desktop_Notifications_Enabled" : "ជំនូនដំណឹងលើ Desktop ážáŸ’រូវបានអនុញ្ញាážáž·", "Direct_Messages" : "សារ​ផ្ទាល់", + "Disable_Favorite_Rooms" : "បិទការពáŸáž‰áž…áž·ážáŸ’áž", "Disable_New_Message_Notification" : "បិទ​ការ​ជូន​ដំណឹង​សារ​ážáŸ’មី", "Disable_New_Room_Notification" : "បិទ​ការ​ជូន​ដំណឹង​បន្ទប់​ážáŸ’មី", "Drop_to_upload_file" : "ទម្លាក់​ឯកសារ​ដើម្បី​ផ្ទុក​ឡើង", @@ -87,16 +103,23 @@ "Duplicate_private_group_name" : "ក្រុម​ឯក​ជន​ដែល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "E-mail" : "អ៊ីមែល", "Edit" : "កែ​សម្រួល", - "edited" : "បាន​កែ", + "edited" : "បានកែសម្រួល", "Email_already_exists" : "អ៊ី​ម៉ែ​ល​ដែល​មាន​រួច​ហើយ", "Email_or_username" : "អ៊ីមែល ឬឈ្មោះ​សម្ងាážáŸ‹", "Email_verified" : "អ៊ីម៉ែល​បញ្ជាក់", + "Emoji" : "សញ្ញា​អារម្មណáŸ", + "Enable_Desktop_Notifications" : "អនុញ្ញាážáž·áž‡áŸ†áž“ូនដំណឹងលើ Desktop", "Enter_info" : "បញ្ចូល​ពáŸážáŸŒáž˜áž¶áž“​របស់​អ្នក", "Enter_to" : "បញ្ចូល", "Error_changing_password" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​ប្ážáž¼ážš", + "Error_too_many_requests" : "កំហុស, មានសំណើរច្រើន ដូចនáŸáŸ‡ážŸáž¼áž˜áž€áž¶ážáŸ‹áž”ន្ážáž™ážœáž¶ ព្រោះអ្នកážáŸ’រូវរង់ចាំ %s វិនាទីមុនព្យាយាមម្ážáž„ទៀáž", "Esc_to" : "Esc ដើម្បី", "False" : "មិន​ពិáž", "Favorites" : "áž–áŸáž‰â€‹áž…áž·ážáŸ’áž", + "FileUpload" : "ផ្ទុក​ឯកសារ​ឡើង", + "FileUpload_Enabled" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្ទុក​ឡើង​ឯកសារ", + "FileUpload_MaxFileSize" : "ទំហំអážáž·áž”រិមាកំណážáŸ‹ážŸáž˜áŸ’រាប់ការផ្ទុកឡើយឯកសារ(áž‚áž¹ážáž‡áž¶áž”ៃ)", + "FileUpload_MediaTypeWhiteList" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែកបញ្ជីប្រភáŸáž‘មáŸážŒáŸ€", "Follow_social_profiles" : "ážáž¶áž˜â€‹ážŠáž¶áž“​​​បណ្ážáž¶â€‹áž‚ណនីបណ្ážáž¶áž‰â€‹ážŸáž„្គម​របស់​យើង​, មើល​យើង​លើ​ github និង​ចែក​រំលែក​បទពិសោធនáŸâ€‹ážšáž”ស់​អ្នក​ជាមួយ​ rocket.chat app នៅ​លើ​ក្ážáž¶ážšážƒáŸ€áž“​របស់​យើង", "Forgot_password" : "ភ្លáŸáž…​ពាក្យ​សម្ងាážáŸ‹", "Fork_it_on_github" : "ទៅ​មើល​វា​លើ github", @@ -104,10 +127,13 @@ "General" : "ទូទៅ", "Get_to_know_the_team" : "ទៅ​ស្គាល់ Rocket.Team", "github_no_public_email" : "អ្នក​មិន​មាន​អ៊ីមែល​សាធារណៈ​ក្នុង​ GitHub នៅ​ឡើយ​ទáŸ", + "Give_a_unique_name_for_the_custom_oauth" : "ផ្ážáž›áŸ‹â€‹áž±áŸ’យ​ឈ្មោះ​ážáŸ‚​មួយ​គážáŸ‹â€‹ážŸáž˜áŸ’រាប់ oauth ផ្ទាល់​ážáŸ’លួន", "Have_your_own_chat" : "អ្នក​មាន Web Chat ផ្ទាល់​ážáŸ’លួនហើ​យឬ។ អភិវឌ្ឃនáŸâ€‹áž‡áž¶áž˜áž½áž™â€‹ Meteor.com, Rocket.Chat គឺ​ជា​ដំណោះ​ស្រាយ​ដáŸâ€‹áž›áŸ’អ​បំផុážâ€‹ážŸáž˜áŸ’រាប់អ្នក​អភិវឌ្ážáž“០ក្នុង​ការ​បង្កើហWeb Chat Plateform។", + "Has_more" : "សញ្ញា Has ច្រើនទៀáž", "Hide_room" : "លាក់​បន្ទប់", "History" : "ប្រវážáŸ’ážáž·", "hours" : "ម៉ោង", + "Incorrect_Password" : "ឃ្លាសំងាážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ", "inline_code" : "inline_code", "Invalid_confirm_pass" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ញ្ជាក់​មិន​ដូច​ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​បញ្ចូល​", "Invalid_email" : "អ៊ី​មែល​ដែល​បញ្ចូល​មិន​ážáŸ’រឹម​ážáŸ’រូវ", @@ -116,6 +142,9 @@ "Invalid_room_name" : "<strong>%s</strong> គឺ​ជា​ឈ្មោះ​បន្ទប់​មិន​ážáŸ’រឹម​ážáŸ’រូវ,<br/> ážáŸ’រូវ​ប្រើប្រាស់​​ážáŸ’រឹម​ážáŸ‚​ážáž½ážšâ€‹áž¢áž€áŸ’សរ, áž›áŸáž និង​ សញ្ញាចុច", "invisible" : "មិន​បង្ហាញ", "Invisible" : "មិន​បង្ហាញ", + "Invitation HTML" : "ការអញ្ជើញទម្រង់ HTML", + "Invitation_Subject" : "ប្រធានបទការអញ្ជើញ", + "Invite_Users" : "អញ្ជើញអ្នកប្រើប្រាស់", "is_also_typing" : "គឺ​កំពុង​វាយ", "is_also_typing_female" : "គឺ​កំពុង​វាយ", "is_also_typing_male" : "គឺ​កំពុង​វាយ", @@ -135,8 +164,10 @@ "Layout_Login_Header" : "ក្បាលទំពáŸážšáž…ូល", "Layout_Login_Terms" : "លក្ážáŸážŽáž…ូល", "Layout_Privacy_Policy" : "គោលការណáŸáž¯áž€áž‡áž“ភាព", + "Layout_Sidenav_Footer" : "ចំហៀង​របស់​កម្មវិធី​រុករក​បាážáž€ážáž¶", "Layout_Sidenav_Footer_description" : "​ទំហំ​បាន​គឺ 260x70", "Layout_Terms_of_Service" : "áž›áŸáž€áŸ’ážážáŸážŽáŸ’ឌ​នៃ​សáŸážœáž¶áž€áž˜áŸ’ម", + "LDAP" : "ប្រើ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", "Load_more" : "មើល​ទៀáž", @@ -155,7 +186,8 @@ "Message" : "សារ", "Message_AllowDeleting" : "អនុញ្ញាážâ€‹áž±áŸ’យ​មាន​ការ​លុប​សារ", "Message_AllowEditing" : "អនុញ្ញាážâ€‹áž±áŸ’យ​មាន​ការ​កែ​សម្រួល​សារ", - "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​", + "Message_AllowEditing_BlockEditInMinutes" : "បិទការកែស្រួលសារបន្ទាប់ (ជាចំនួននាទី ឬ0ដើម្បីបិទចោល)", + "Message_AudioRecorderEnabled" : "ការážážážŸáž˜áŸ’áž›áŸáž„បានអនុញ្ញាážáž·", "Message_deleting_not_allowed" : "ការ​លប់សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", "Message_editing_not_allowed" : "ការ​កែ​សម្រួល​សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", "Message_editing_blocked" : "សារ​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ážáŸ’រូវ​បាន​កែប្រែ​ទៀážâ€‹áž‘áŸ", @@ -166,6 +198,8 @@ "Message_pinned" : "សារ\n", "Message_ShowDeletedStatus" : "បង្ហាញ​ស្ážáž¶áž“ភាព​ដែល​បាន​លុប", "Message_ShowEditedStatus" : "បង្ហាញ​ស្ážáž¶áž“ភាព​អážáŸ’ážáž”ទ​​ដែល​បាន​កែ​សម្រួល", + "Message_ShowFormattingTips" : "បង្ហាញទ្រង់ទ្រាយដំបូន្មាន", + "Messages" : "សារ", "Meta" : "មáŸážáž¶", "Meta_fb_app_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ កម្មវិធី​ហ្វáŸážŸâ€‹áž”៊ូក", "Meta_google-site-verification" : "ការ​ផ្ទៀង​ផ្ទាážáŸ‹â€‹áž‡áž¶áž˜áž½áž™ Google Site", @@ -196,6 +230,8 @@ "Not_found_or_not_allowed" : "មិន​ប្រទះ ឬ​មិន​អនុញ្ញាážáž·", "Nothing_found" : "គ្មាន​អ្វី​ប្រទះ", "Notify_all_in_this_room" : "ជូន​ដំណឹង​ទាំង​អស់​នៅ​ក្នុង​បន្ទប់​នáŸáŸ‡", + "Old_Password" : "ឃ្លាសម្ងាážáŸ‹áž…ាស់", + "Old_and_new_password_required" : "អ្នកážáŸ’រូវážáŸ‚ផ្ážáž›áŸ‹áž‘ាំងពាក្យសម្ងាážáŸ‹áž…ាស់ áž“áž·áž„ážáŸ’មី ដើម្បីប្ážáž¼ážšáž–ាក្យសម្ងាážáŸ‹áŸ”", "Only_you_can_see_this_message" : "មានážáŸ‚អ្នកដែលអាចឃើញសារនáŸáŸ‡", "Online" : "លើបណ្ážáž¶áž‰", "Oops!" : "អូ!", @@ -204,6 +240,7 @@ "others" : "ផ្សáŸáž„ៗ", "Password" : "ពាក្យ​សម្ងាážáŸ‹", "Password_changed_successfully" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​ប្ážáž¼ážšâ€‹áž‡áŸ„គជáŸáž™", + "People" : "មនុស្ស", "Please_wait" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់​ចាំ", "Please_wait_activation" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់​ចាំ ការងារ​នáŸáŸ‡â€‹ážáŸ’រូវ​ចំណាយ​ពáŸáž›â€‹áž”ន្ážáž·áž…", "Please_wait_statistics" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់ចាំ ស្ážáž·ážáž·â€‹áž‚ឺ​កំពុង​គណនា", @@ -229,16 +266,20 @@ "Quick_Search" : "ស្វែង​រក​រហáŸážŸ", "quote" : "សំណៅ", "Recents" : "ážáŸ’មីៗ", + "Record" : "កំណážáŸ‹â€‹ážáŸ’រា", "Register" : "ចុះ​ឈ្មោះ​គណនី​ážáŸ’មី", "Registration_Succeeded" : "ការ​ចុះឈ្មោះ​ជោគជáŸáž™", "Remember_me" : "ចងចាំ​ážáŸ’ញុំ", "Remove" : "ដកចáŸáž‰", + "Remove_custom_oauth" : "លប់ចោល oauth ផ្ទាល់ážáŸ’លួន", "Remove_Admin" : "ដក​សិទ្ធ​អ្នក​គ្រប់គ្រង", "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" : "បន្ទប់", "Save" : "រក្សាទុក", @@ -259,6 +300,8 @@ "Send_invitation_email" : "ផ្ញើ​ការ​អញ្ជើញ​អ៊ីមែល", "Send_invitation_email_error" : "អ្នកមិនបានផ្ážáž›áŸ‹áž¢áž¶ážŸáŸáž™ážŠáŸ’ឋានអ៊ីមែលážáŸ’រឹមážáŸ’រូវទáŸ", "Send_invitation_email_info" : "អ្នកអាចផ្ញើរច្រើនការអញ្ជើញអ៊ីមែលក្នុងពáŸáž›ážáŸ‚មួយ", + "Send_invitation_email_success" : "អ្នកបានផ្ញើរអ៊ីមែលការអញ្ជើញដោយជោគជáŸáž™ážáž¶áž˜ážšáž™áŸˆáž¢áž¶ážŸáŸáž™ážŠáŸ’ឋានដូចជា៖", + "Send_invitation_email_warning" : "លំដាប់នៃការរៀបចំផ្ញើរអ៊ីមែលអញ្ជើញ គឺជាដំបូងអ្នកážáŸ’រូវកំណážáŸ‹áž–ិធីការ SMTP ជាមុនសិន។", "Send_Message" : "ផ្ញើរសារ", "Settings" : "ការកំណážáŸ‹", "Settings_updated" : "ការ​កំណážáŸ‹â€‹áž€áž¶ážšâ€‹áž’្វើ​ឱ្យ​ទាន់​សមáŸáž™", @@ -267,6 +310,10 @@ "Silence" : "ស្ងាážáŸ‹", "since_creation" : "ážáž¶áŸ†áž„ពី %s", "Site_Name" : "áž‚áŸáž ទំពáŸážšâ€‹ážˆáŸ’មោះ", + "Site_Url" : "ážáŸ†áž”ន់ URL", + "Site_Url_Description" : "ឧទាហរណáŸáŸ– https://chat.domain.com/", + "SAML" : "ប្រើ SAML", + "SMTP" : "ពិធីការ SMTP", "SMTP_Host" : "ម៉ាស៊ីន SMTP", "SMTP_Password" : "ឃ្លា​សម្ងាážáŸ‹ SMTP", "SMTP_Port" : "ផែ SMTP", @@ -282,11 +329,20 @@ "Stats_Away_Users" : "អ្នក​ប្រើ​ដែល​បាន​ចាក​ឆ្ងាយ", "Stats_Offline_Users" : "អ្នក​ប្រើ​ក្រៅ​ប​ណ្ážáž¶â€‹áž‰", "Stats_Online_Users" : "អ្នក​ប្រើ​លើ​បណ្ដាញ", + "Stats_OS_Cpus" : "រាប់ CPU ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", + "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_Messages" : "សារ​សរុប", "Stats_Total_Private_Groups" : "ក្រុម​ឯកជន​សរុប", "Stats_Total_Rooms" : "បន្ទប់​សរុប", "Stats_Total_Users" : "អ្នក​ប្រើ​ប្រាស់​សរុប", + "Stop_Recording" : "បញ្ឈប់​ការ​កážáŸ‹â€‹ážáŸ’រា", "strike" : "strike", "Submit" : "បញ្ចូល", "S_new_messages_since_s" : "%s សារážáŸ’មីចាប់ážáž¶áŸ†áž„ពី %s", @@ -317,6 +373,7 @@ "User_left_female" : "អ្នក​ប្រើ <em>__user_left__</em> បាន​ចáŸáž‰", "User_left_male" : "អ្នក​ប្រើ <em>__user_left__</em> បាន​ចáŸáž‰", "User_logged_out" : "អ្នក​ប្រើបាន​ចាកចáŸáž‰", + "User_not_found_or_incorrect_password" : "អ្នកប្រើប្រាស់ឬពាក្យសម្ងាážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ", "User_removed_by" : "អ្នក​ប្រើ <em>__user_removed__</em> បាន​ដក​ចáŸáž‰â€‹ážŠáŸ„áž™ <em>__user_by__</em>.", "User_Settings" : "ការ​កំណážáŸ‹â€‹ážšáž”ស់​អ្នក​ប្រើ", "User_updated_successfully" : "អ្នក​ប្រើប្រាស់​បាន​កែ​សម្រួល​ដោយ​ជោគជáŸáž™", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index 01ab953aab1..28014f5daf6 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -30,11 +30,12 @@ "Accounts_OAuth_Custom_Identity_Path" : "Identity 경로", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize 경로", "Accounts_OAuth_Custom_Secret" : "비밀", - "Accounts_OAuth_Custom_Enable" : "사용", + "Accounts_OAuth_Custom_Enable" : "사용 가능", "Accounts_OAuth_Custom_Button_Label_Text" : "버튼 í…스트", "Accounts_OAuth_Custom_Button_Label_Color" : "버튼 í…스트 색", "Accounts_OAuth_Custom_Button_Color" : "버튼 색", "Activate" : "활성화", + "Add_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth 추가", "Add_Members" : "멤버 추가", "Add_users" : "ì‚¬ìš©ìž ì¶”ê°€", "Administration" : "관리", @@ -78,12 +79,14 @@ "Create_new_private_group" : "새로운 ê°œì¸ ê·¸ë£¹ì„ ë§Œë“니다", "Create_new_public_channel" : "새 공용 ì±„ë„ ìƒì„±", "Created_at" : "ì œìž‘", + "Custom_oauth_unique_name" : "ì‚¬ìš©ìž ì •ì˜ OAuth ê³ ìœ í•œ ì´ë¦„", "days" : "ì¼", "Deactivate" : "비활성화", "Delete_User_Warning" : "ì‚¬ìš©ìž ì‚ì œì‹œ 사용ìžì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì·¨ì†Œí• ìˆ˜ 없습니다.", "Delete" : "ì‚ì œ", "Deleted" : "ì‚ì œ!", "Direct_Messages" : "ê·“ì†ë§", + "Disable_Favorite_Rooms" : "ì¦ê²¨ì°¾ê¸° 사용안함", "Disable_New_Message_Notification" : "새 메시지 알림 비활성화", "Disable_New_Room_Notification" : "새 ë°© 알림 비활성화", "Drop_to_upload_file" : "ì—…ë¡œë“œí• íŒŒì¼ ë“œë¡", @@ -95,6 +98,7 @@ "Email_already_exists" : "ì´ë©”ì¼ì´ ì´ë¯¸ 존재합니다", "Email_or_username" : "ì´ë©”ì¼ ë˜ëŠ” ì‚¬ìš©ìž ì´ë¦„", "Email_verified" : "Email 확ì¸", + "Emoji" : "Emoji", "Enter_info" : "ë¡œê·¸ì¸ ì •ë³´ë¥¼ ìž…ë ¥í•˜ì„¸ìš”", "Enter_to" : "Enter to", "Error_changing_password" : "암호 변경", @@ -108,11 +112,13 @@ "General" : "ì¼ë°˜", "Get_to_know_the_team" : "Rocket.Team 알아보기", "github_no_public_email" : "Github ê³„ì •ì— ê³µê°œëœ ì´ë©”ì¼ì´ 없습니다.", + "Give_a_unique_name_for_the_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuthì— ëŒ€í•œ ê³ ìœ ì´ë¦„ ì§€ì •", "Have_your_own_chat" : "ë‹¹ì‹ ë§Œì˜ ì›¹ ì±„íŒ…ì„ ë§Œë“œì„¸ìš”. Meteor.com으로 개발한 Rocket.Chatì€ ìžì‹ ë§Œì˜ ì±„íŒ… 플랫í¼ì„ ë§Œë“¤ê³ ê°œì„ í•´ 나아갈 개발ìžë“¤ì„ 위한 훌ë¥í•œ 솔루션입니다.", "Has_more" : "ë” ë§Žì´", "Hide_room" : "ë°© 숨김", "History" : "ì´ë ¥", "hours" : "시간", + "Incorrect_Password" : "ìž˜ëª»ëœ ì•”í˜¸", "inline_code" : "inline_code", "Invalid_confirm_pass" : "암호가 ì¼ì¹˜í•˜ì§€ 않습니다", "Invalid_email" : "ìž…ë ¥í•œ ì´ë©”ì¼ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤", @@ -165,9 +171,10 @@ "Message" : "메시지", "Message_AllowDeleting" : "메시지 ì‚ì œ 허용", "Message_AllowEditing" : "메시지 ìˆ˜ì • 허용", - "Message_AllowPinning" : "허용 메시지 ê³ ì •", + "Message_AllowEditing_BlockEditInMinutes" : "ì´í›„ë¡œ 메시지 ìˆ˜ì • ì•ˆë¨ (분 - 0 ì€ ì‚¬ìš©ì•ˆí•¨)", "Message_deleting_not_allowed" : "메시지 ì‚ì œë¥¼ í• ìˆ˜ 없습니다.", "Message_editing_not_allowed" : "메시지 ìˆ˜ì •ì„ í• ìˆ˜ 없습니다.", + "Message_editing_blocked" : "메시지를 ë” ì´ìƒ ìˆ˜ì •í• ìˆ˜ 없습니다.", "Message_MaxAllowedSize" : "메시지 최대 허용 í¬ê¸°", "Message_pinning_not_allowed" : "메시지를 ê³ ì •í• ìˆ˜ 없습니다.", "Message_KeepHistory" : "메시지 기ë¡ì„ ìœ ì§€", @@ -190,6 +197,7 @@ "My_Account" : "ë‚´ ê³„ì •", "n_messages" : "%s 메시지", "Name" : "ì´ë¦„", + "Name_cant_be_empty" : "ì´ë¦„ì„ ë¹„ì›Œ 둘 수 없습니다", "New_messages" : "새로운 메시지", "New_password" : "새로운 암호", "No_channels_yet" : "ì–´ë– í•œ 채ë„ì—ë„ ê°€ìž…í•˜ì§€ 않았습니다.", @@ -204,6 +212,8 @@ "Not_found_or_not_allowed" : "ì°¾ì„ ìˆ˜ 없거나 허용ë˜ì§€ 않았습니다", "Nothing_found" : "ì°¾ì„ ìˆ˜ 없습니다", "Notify_all_in_this_room" : "ì´ ë°©ì— ìžˆëŠ” ëª¨ë“ ì´ì—게 알림", + "Old_Password" : "기존 암호", + "Old_and_new_password_required" : "암호를 변경하기 위해서는 기존 암호와 새로 ì‚¬ìš©í• ì•”í˜¸ë¥¼ ìž…ë ¥í•´ì•¼í•©ë‹ˆë‹¤.", "Only_you_can_see_this_message" : "ì´ ë©”ì‹œì§€ëŠ” ë‹¹ì‹ ë§Œ ë³¼ 수 있습니다", "Online" : "온ë¼ì¸", "Oops!" : "ì•„ì°¨", @@ -237,10 +247,12 @@ "Quick_Search" : "ë¹ ë¥¸ 찾기", "quote" : "ì¸ìš©", "Recents" : "최근", + "Record" : "기ë¡", "Register" : "새로운 ê³„ì • 등ë¡", "Registration_Succeeded" : "ë“±ë¡ ì„±ê³µ", "Remember_me" : "ìžë™ 로그ì¸", "Remove" : "ì‚ì œ", + "Remove_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth ì œê±°", "Remove_Admin" : "ê´€ë¦¬ìž ê¶Œí•œ ì œê±°", "Reset_password" : "암호 ìž¬ì„¤ì •", "Room" : "ë°©", @@ -265,6 +277,10 @@ "Send" : "보내기", "Send_confirmation_email" : "í™•ì¸ ë©”ì¼ ë³´ëƒ„", "Send_invitation_email" : "초대 ë©”ì¼ ë³´ë‚´ê¸°", + "Send_invitation_email_error" : "ìœ íš¨í•œ ì´ë©”ì¼ ì£¼ì†Œê°€ ìž…ë ¥ë˜ì§€ 않았습니다.", + "Send_invitation_email_info" : "í•œë²ˆì— ì—¬ëŸ¬ 사람ì—게 초대 ì´ë©”ì¼ì„ 보낼 수 있습니다.", + "Send_invitation_email_success" : "ë‹¤ìŒ ì£¼ì†Œë¡œ 초대 ì´ë©”ì¼ì„ 발송하였습니다:", + "Send_invitation_email_warning" : "초대 ì´ë©”ì¼ì„ ë³´ë‚´ë ¤ë©´, ë¨¼ì € SMTP ì„¤ì •ì„ êµ¬ì„±í•´ì•¼ 합니다.", "Send_Message" : "메시지 보내기", "Settings" : "ì„¤ì •", "Settings_updated" : "ì„¤ì • ì—…ë°ì´íŠ¸", @@ -305,6 +321,7 @@ "Stats_Total_Private_Groups" : "ì „ì²´ 비밀 그룹", "Stats_Total_Rooms" : "ì „ì²´ ë°©", "Stats_Total_Users" : "ì´ ì‚¬ìš©ìž", + "Stop_Recording" : "ê¸°ë¡ ì¤‘ì§€", "strike" : "ì·¨ì†Œì„ ", "Submit" : "ì œì¶œ", "The_field_is_required" : "í•„ë“œ %s는 필요합니다.", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..652a9ea6ea5 --- /dev/null +++ b/i18n/ms-MY.i18n.json @@ -0,0 +1,368 @@ +{ + "Access_online_demo" : "Akses demo atas talian", + "Access_Online_Demo" : "Akses Demo Atas talian", + "Accounts" : "Akaun", + "Accounts_denyUnverifiedEmail" : "Menafikan e-mel yang tidak sah", + "Accounts_EmailVerification" : "Pengesahan E-mel", + "Accounts_OAuth_Facebook" : "Daftar masuk Facebook", + "Accounts_OAuth_Facebook_id" : "Facebook App Id", + "Accounts_OAuth_Facebook_secret" : "Facebook Secret", + "Accounts_OAuth_Github" : "OAuth Diaktifkan", + "Accounts_OAuth_Github_id" : "ID Klien", + "Accounts_OAuth_Github_secret" : "Rahsia Klien", + "Accounts_OAuth_Google" : "Daftar masuk Google", + "Accounts_OAuth_Google_id" : "Google Id", + "Accounts_OAuth_Google_secret" : "Google Secret", + "Accounts_OAuth_Linkedin" : "Daftar masuk LinkedIn", + "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", + "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", + "Accounts_OAuth_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", + "Accounts_OAuth_Meteor" : "Daftar masuk Meteor", + "Accounts_OAuth_Meteor_id" : "Meteor Id", + "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_OAuth_RegistrationRequired" : "Pendaftaran diperlukan", + "Accounts_OAuth_Twitter" : "Daftar masuk Twitter", + "Accounts_OAuth_Twitter_id" : "Twitter Id", + "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_URL" : "URL", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Enable" : "Aktifkan", + "Accounts_OAuth_Custom_Button_Label_Text" : "Butang Teks", + "Accounts_OAuth_Custom_Button_Label_Color" : "Butang Teks Berwarna", + "Accounts_OAuth_Custom_Button_Color" : "Butang Warna", + "Activate" : "Aktifkan", + "Add_Members" : "Tambah Ahli", + "Add_users" : "Tambah pengguna", + "Administration" : "Pentadbiran", + "All_channels" : "Semua saluran", + "and" : "dan", + "API" : "API", + "API_Analytics" : "Analisis", + "API_Embed" : "Benam", + "Are_you_sure" : "Adakah anda pasti?", + "Avatar_changed_successfully" : "Avatar berjaya ditukar", + "away" : "keluar", + "Away" : "Keluar", + "away_female" : "keluar", + "Away_female" : "Keluar", + "away_male" : "keluar", + "Away_male" : "Keluar", + "Auto_Load_Images" : "Automatik Memuat Gambar", + "Back_to_login" : "Kembali ke log masuk", + "busy" : "sibuk", + "Busy" : "Sibuk", + "busy_female" : "sibuk", + "Busy_female" : "Sibuk", + "busy_male" : "sibuk", + "Busy_male" : "Sibuk", + "Cancel" : "Batal", + "Change_avatar" : "Tukar avatar", + "Channels" : "Saluran", + "Channels_list" : "Senarai daripada saluran awam", + "Chat_Rooms" : "Bilik Sembang", + "close" : "tutup", + "coming_soon" : "akan datang", + "Commands" : "Arahan", + "Confirm_password" : "Sahkan kata laluan anda", + "Contact" : "Hubungi", + "Conversation" : "Perbualan", + "Convert_Ascii_Emojis" : "Menukar ASCII ke Emoji", + "Create_new" : "Buat baru", + "Create_new_direct_message_room" : "Buat bilik mesej langsung yang baru", + "Create_new_private_group" : "Buat kumpulan persendirian yang baru", + "Create_new_public_channel" : "Buat saluran awam yang baru", + "Created_at" : "Dibuat pada", + "days" : "hari", + "Deactivate" : "Nyahaktifkan", + "Delete_User_Warning" : "Memadam pengguna akan memadam semua mesej dari pengguna itu juga. Ini tidak boleh kembalikan asal.", + "Delete" : "Padam", + "Deleted" : "Dipadamkan!", + "Desktop_Notifications" : "Notifikasi Desktop", + "Desktop_Notifications_Disabled" : "Notifikasi Desktop dinyahaktifkan. Tukar tetapan pelayar web jika anda mahukan notifikasi diaktifkan.", + "Desktop_Notifications_Enabled" : "Notifikasi Desktop Diaktifkan", + "Direct_Messages" : "Mesej Secara Langsung", + "Disable_Favorite_Rooms" : "Nyahaktifkan Kegemaran", + "Disable_New_Message_Notification" : "Lumpuhkan Notifikasi Mesej Baru", + "Disable_New_Room_Notification" : "Lumpuhkan Notifikasi Bilik Baru", + "Drop_to_upload_file" : "Gugurkan untuk memuat naik fail", + "Duplicate_channel_name" : "Saluran dengan nama '%s' telah wujud", + "Duplicate_private_group_name" : "Kumpulan Persendirian dengan nama '%s' telah wujud", + "E-mail" : "E-mel", + "Edit" : "Sunting", + "edited" : "disunting", + "Email_already_exists" : "E-mel telah wujud", + "Email_or_username" : "E-mel atau nama pengguna", + "Email_verified" : "E-mel disahkan", + "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "Mengaktifkan Notifikasi Desktop", + "Enter_info" : "Masukkan maklumat anda", + "Enter_to" : "Masuk ke", + "Error_changing_password" : "Ralat menukar kata laluan", + "Esc_to" : "Esc untuk", + "False" : "Lumpuhkan", + "Favorites" : "Kegemaran", + "Forgot_password" : "Lupa kata laluan anda", + "Fork_it_on_github" : "Mencabang pada github", + "From_Email" : "Daripada E-mel", + "General" : "Umum", + "Get_to_know_the_team" : "Kenali Rocket.Team", + "Has_more" : "Ada lagi", + "Hide_room" : "Menyembunyikan bilik", + "History" : "Sejarah", + "hours" : "jam", + "Incorrect_Password" : "Kata Laluan salah", + "Invalid_confirm_pass" : "Pengesahan kata laluan tidak sepadan dengan kata laluan", + "Invalid_email" : "E-mel yang dimasukkan tidak sah", + "Invalid_name" : "Nama mesti tidak dikosongkan", + "Invalid_pass" : "Kata Laluan mesti tidak dikosongkan", + "invisible" : "tidak dalam dilihat", + "Invisible" : "Tidak dapat dilihat", + "Invitation HTML" : " HTML Jemputan", + "Invitation_Subject" : "Subjek Jemputan", + "Invite_Users" : "Jemput Pengguna", + "is_also_typing" : "turut menaip", + "is_also_typing_female" : "turut menaip", + "is_also_typing_male" : "turut menaip", + "is_typing" : "sedang menaip", + "is_typing_female" : "sedang menaip", + "is_typing_male" : "sedang menaip", + "italics" : "condong", + "join" : "Sertai", + "Join_the_Community" : "Sertai Komuniti", + "Language" : "Bahasa", + "Language_Version" : "Versi Bahasa Inggeris", + "Last_login" : "Log masuk terakhir", + "Last_message" : "Mesej terakhir", + "Layout" : "Tata atur", + "Layout_Home_Body" : "Badan Laman", + "Layout_Home_Title" : "Tajuk Halaman Utama", + "Layout_Login_Header" : "Login Header", + "Layout_Login_Terms" : "Terma Log masuk", + "Layout_Privacy_Policy" : "Dasar Privasi", + "Layout_Sidenav_Footer" : "Navigasi Belah Tepi Footer", + "Layout_Sidenav_Footer_description" : "Saiz footer ialah 260x70", + "Layout_Terms_of_Service" : "Terma Perkhidmatan", + "LDAP" : "LDAP", + "Leave_room" : "Meninggalkan bilik", + "line" : "garis", + "Load_more" : "Memuat lagi", + "Loading_more_from_history" : "Memuatkan lagi dari sejarah", + "Loading..." : "Memuatkan...", + "Loading_suggestion" : "Memuatkan cadangan...", + "Login" : "Log masuk", + "Login_with" : "Log masuk dengan %s", + "login_with" : "Atau log masuk secara terus dengan", + "Logout" : "Log keluar", + "Make_Admin" : "Lantik Pentadbir", + "Mark_as_read" : "Tanda sebagai telah dibaca", + "Members" : "Ahli", + "Members_List" : "Senarai Ahli", + "Members_placeholder" : "Ahli", + "Message" : "Mesej", + "Message_AllowDeleting" : "Benarkan Pemadaman Mesej", + "Message_AllowEditing" : "Benarkan Penyuntingan Mesej", + "Message_AllowEditing_BlockEditInMinutes" : "Sekat penyuntingan mesej selepas (dalam minit - 0 hingga melumpuhkan)", + "Message_deleting_not_allowed" : "Pemadaman mesej tidak dibenarkan", + "Message_editing_not_allowed" : "Penyuntingan mesej tidak dibenarkan", + "Message_editing_blocked" : "Mesej ini tidak boleh lagi disunting", + "Message_MaxAllowedSize" : "Saiz mesej maksimum yang dibenarkan", + "Message_KeepHistory" : "Simpan Sejarah Mesej", + "Message_removed" : "Mesej dipadam", + "Message_pinned" : "Mesej dipinkan", + "Message_ShowDeletedStatus" : "Tunjuk Status Pemadaman", + "Message_ShowEditedStatus" : "Tunjuk Status Penyuntingan", + "Messages" : "Mesej", + "Meta" : "Meta", + "Meta_fb_app_id" : "Facebook APP ID", + "Meta_google-site-verification" : "Pengesahan Laman Google", + "Meta_language" : "Bahasa", + "Meta_msvalidate01" : "MSValidate.01", + "Meta_robots" : "Robot", + "minutes" : "minit", + "More_channels" : "Lagi saluran", + "More_groups" : "Lagi kumpulan persendirian", + "More_unreads" : "Lagi belum dibaca", + "Msgs" : "Mesej", + "My_Account" : "Akaun Saya", + "n_messages" : "%s mesej", + "Name" : "Nama", + "Name_cant_be_empty" : "Nama tidak boleh dibiarkan kosong", + "New_messages" : "Mesej baru", + "New_password" : "Kata Laluan baru", + "No_channels_yet" : "Anda bukan daripada mana-mana saluran lagi.", + "No_direct_messages_yet" : "Anda tidak memulakan sebarang perbualan lagi.", + "No_favorites_yet" : "Anda belum menambah sebarang kegemaran lagi.", + "No_groups_yet" : "Anda tidak mempunyai kumpulan persendirian lagi.", + "No_permission_to_view_room" : "Anda tidak mempunyai kebenaran untuk melihat bilik ini", + "No_channel_with_name_%s_was_found" : "Tiada saluran dengan nama <strong>\"%s\"</strong> dijumpai!", + "No_group_with_name_%s_was_found" : "Tiada kumpulan persendirian dengan nama <strong>\"%s\"</strong> dijumpai!", + "No_user_with_username_%s_was_found" : "Tiada pengguna dengan nama pengguna <strong>\"%s\"</strong> dijumpai!", + "Not_allowed" : "Tidak dibenarkan", + "Not_found_or_not_allowed" : "Tidak Ditemui atau Tidak Dibenarkan", + "Nothing_found" : "Tiada apa Dijumpai", + "Notify_all_in_this_room" : "Memberitahu semua di dalam bilik ini", + "Old_Password" : "Kata Laluan lama", + "Old_and_new_password_required" : "Anda perlu memberikan kedua-dua kata laluan lama dan baru untuk menukar kata laluan anda.", + "Only_you_can_see_this_message" : "Hanya anda yang boleh melihat mesej ini", + "Online" : "Dalam talian", + "Oops!" : "Oops", + "Opt_out_statistics" : "Jangan hantar statistik saya ke Rocket.Chat", + "Opt_out_statistics_warning" : "Dengan menghantar statistik anda, ada akan membantu kami mengenalpasti berapa banyak", + "others" : "lain-lain", + "Password" : "Kata Laluan", + "Password_changed_successfully" : "Kata Laluan berjaya ditukar", + "People" : "Orang", + "Please_wait" : "Sila tunggu", + "Please_wait_activation" : "Sila tunggu, ini boleh mengambil beberapa masa.", + "Please_wait_statistics" : "Sila tunggu, statistik sedang dijana.", + "Powered_by" : "Dikuasakan oleh", + "Preferences" : "Keutamaan", + "Preferences_saved" : "Keutamaan disimpan", + "Privacy" : "Privasi", + "Private_Groups" : "Kumpulan Persendirian", + "Private_Groups_list" : "Senarai daripada Kumpulan Persendirian", + "Profile" : "Profil", + "Profile_saved_successfully" : "Profil berjaya disimpan", + "Proudly_developed" : "Dengan bangganya dibangunkan dengan Meteor", + "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" : "Frasa Laluan APN", + "Push_debug" : "Debug", + "Push_enable" : "Aktifkan", + "Push_production" : "Penerbitan", + "Quick_Search" : "Carian Pantas", + "Record" : "Rakam", + "Register" : "Mendaftar akaun baru", + "Registration_Succeeded" : "Pendaftaran Berjaya", + "Remember_me" : "Ingatkan saya", + "Remove" : "Padam", + "Remove_Admin" : "Padam Pentadbir", + "Reset_password" : "Menetapkan semula kata laluan", + "Room" : "Bilik", + "Room_name_changed" : "Nama bilik ditukar kepada: <em>__room_name__</em> daripada <em>__user_by__</em>", + "Room_name_changed_successfully" : "Nama bilik berjaya ditukar", + "Room_not_found" : "Bilik tidak dijumpai", + "Room_uploaded_file_list" : "Senarai fail", + "Room_uploaded_file_list_empty" : "Tiada fail yang ada.", + "room_user_count" : "Pengguna %s", + "Rooms" : "Bilik", + "Save" : "Simpan", + "Save_changes" : "Simpan perubahan", + "Save_Mobile_Bandwidth" : "Simpan Jalur lebar mudah alih", + "Search" : "Cari", + "Search_Messages" : "Cari Mesej", + "Search_settings" : "Tetapan carian", + "seconds" : "saat", + "See_all" : "Lihat semua", + "See_only_online" : "Hanya Dalam talian", + "Select_an_avatar" : "Pilih avatar", + "Select_file" : "Pilih fail", + "Select_service_to_login" : "Pilih perkhidmatan untuk log masuk untuk memuat gambar anda atau muat naik terus satu daripada komputer anda", + "Selected_users" : "Ahli yang terpilih", + "Send" : "Hantar", + "Send_confirmation_email" : "Hantar e-mel pengesahan", + "Send_invitation_email" : "Hantar jemputan e-mel", + "Send_invitation_email_error" : "Anda belum memberikan mana-mana alamat e-mel yang sah.", + "Send_invitation_email_info" : "Anda boleh menghantar beberapa e-mel jemputan sekaligus.", + "Send_invitation_email_success" : "Anda telah berjaya menghantar e-mel jemputan ke alamat berikut:", + "Send_invitation_email_warning" : "Untuk menghantar e-mel jemputan, anda mesti mengkonfigurasi tetapan SMTP", + "Send_Message" : "Hantar mesej", + "Settings" : "Tetapan", + "Settings_updated" : "Tetapan dikemaskini", + "Showing_online_users" : "Menunjukkan <b>__total_online__</b> dari __total__ pengguna", + "Showing_results" : "<p>Menunjukan <b>%s</b> keputusan</p>", + "Silence" : "Senyap", + "since_creation" : "sejak %s", + "Site_Name" : "Nama Laman:", + "SAML" : "SAML", + "SMTP" : "SMTP", + "SMTP_Host" : "Hos SMTP", + "SMTP_Password" : "Kata Laluan SMTP", + "SMTP_Port" : "Port SMTP", + "SMTP_Username" : "Nama Pengguna SMTP", + "Sound" : "Bunyi", + "Start_of_conversation" : "Permulaan perbualan", + "Statistics" : "Statistik", + "Stats_Active_Users" : "Pengguna Aktif", + "Stats_Avg_Channel_Users" : "Purata Pengguna Saluran", + "Stats_Avg_Private_Group_Users" : "Purata Pengguna Kumpulan Persendirian", + "Stats_Max_Room_Users" : "Maksimum Pengguna Bilik", + "Stats_Non_Active_Users" : "Pengguna Tidak Aktif", + "Stats_Away_Users" : "Pengguna Keluar", + "Stats_Offline_Users" : "Pengguna Luar talian", + "Stats_Online_Users" : "Pengguna Dalam talian", + "Stats_OS_Arch" : "OS Arch", + "Stats_OS_Cpus" : "OS CPU Count", + "Stats_OS_Freemem" : "OS Free Memory", + "Stats_OS_Loadavg" : "OS Load Average", + "Stats_OS_Platform" : "OS Platform", + "Stats_OS_Release" : "OS Release", + "Stats_OS_Totalmem" : "OS Total Memory", + "Stats_OS_Type" : "OS Type", + "Stats_OS_Uptime" : "OS Uptime", + "Stats_Total_Channels" : "Jumlah Saluran", + "Stats_Total_Direct_Messages" : "Jumlah Bilik Mesej Langsung", + "Stats_Total_Messages" : "Jumlah Mesej", + "Stats_Total_Private_Groups" : "Jumlah Kumpulan Persendirian", + "Stats_Total_Rooms" : "Jumlah Bilik", + "Stats_Total_Users" : "Jumlah Pengguna", + "Stop_Recording" : "Berhenti Merakam", + "Submit" : "Hantar", + "S_new_messages_since_s" : "%s mesej baru sejak %s", + "The_field_is_required" : "Medan ini %s diperlukan", + "True" : "Dayakan", + "Unnamed" : "Tidak dinamakan", + "Upload_file_question" : "Muat naik fail?", + "Use_Emojis" : "Guna Emoji", + "Use_initials_avatar" : "Guna singkatan nama pengguna anda", + "use_menu" : "Gunakan menu sebelah untuk mengakses bilik dan sembang anda", + "Use_service_avatar" : "Guna %s avatar", + "Use_this_username" : "Guna nama pengguna ini", + "Use_uploaded_avatar" : "Guna avatar yang dimuat naik", + "User_added" : "Pengguna <em>__user_added__</em> ditambah.", + "User_added_by" : "Pengguna <em>__user_added__</em> ditambah oleh <em>__user_by__</em>.", + "User_Channels" : "Saluran Pengguna", + "User_has_been_activated" : "Pengguna telah diaktifkan", + "User_has_been_deactivated" : "Pengguna telah dinyahaktifkan", + "User_has_been_deleted" : "Pengguna telah dipadam", + "User_Info" : "Maklumat Pengguna", + "User_is_no_longer_an_admin" : "Pengguna tidak lagi seorang pentadbir", + "User_is_not_activated" : "Pengguna tidak diaktifkan", + "User_is_now_an_admin" : "Pengguna sekarang adalah pentadbir", + "User_joined_channel" : "Telah menyertai saluran.", + "User_joined_channel_female" : "Telah menyertai saluran.", + "User_joined_channel_male" : "Telah menyertai saluran.", + "User_left" : "Pengguna <em>__user_left__</em> meninggalkan.", + "User_left_female" : "User <em>__user_left__</em> meninggalkan.", + "User_left_male" : "Pengguna <em>__user_left__</em> meninggalkan.", + "User_logged_out" : "Pengguna melog keluar", + "User_not_found_or_incorrect_password" : "Pengguna tidak dijumpai atau kata laluan salah", + "User_removed_by" : "Pengguna <em>__user_removed__</em> dibuang oleh <em>__user_by__</em>.", + "User_Settings" : "Tetapan Pengguna", + "User_updated_successfully" : "Pengguna berjaya dikemaskini", + "Users" : "Pengguna", + "Username" : "Nama Pengguna", + "Username_cant_be_empty" : "Nama Pengguna tidak boleh dibiarkan kosong", + "Username_description" : "Nama Pengguna adalah digunakan untuk membolehkan pengguna lain menyebut anda di mesej.", + "Username_invalid" : "<strong>%s</strong> bukan nama pengguna yang sah,<br/> guna hanya huruf, nombor, titik dan pemisah", + "Username_title" : "Daftar nama pengguna", + "Username_unavaliable" : "<strong>%s</strong> sudah digunakan :(", + "View_All" : "Lihat Semua", + "Wait_activation_warning" : "Sebelum anda boleh log masuk, akaun anda mesti diaktifkan secara manual oleh pentadbiran.", + "We_have_sent_registration_email" : "Kami telah menghantar kepada anda e-mel untuk mengesahkan pendaftaran anda. Jika anda tidak menerima e-mel berikut dalam masa terdekat. sila datang kembali dan cuba lagi.", + "Welcome" : "Selamat datang <em>%s</em>.", + "Welcome_to_the" : "Selamat datang ke", + "With_whom" : "Dengan siapa", + "Yes_delete_it" : "Ya, padam ia!", + "you_are_in_preview_mode_of" : "Anda berapa di dalam mod pralihat saluran #<strong>__room_name__</strong>", + "You_need_confirm_email" : "Anda perlu mengesahkan e-mel anda untuk melog masuk!", + "You_will_not_be_able_to_recover" : "Anda tidak boleh membaik pulih.", + "Your_entry_has_been_deleted" : "Entri anda telah dipadam." +} \ No newline at end of file diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 32c44d5693b..b40f078171f 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -36,6 +36,7 @@ "Accounts_OAuth_Custom_Button_Label_Color" : "Cor do texto do botão", "Accounts_OAuth_Custom_Button_Color" : "Cor do botão", "Activate" : "Ativar", + "Add_custom_oauth" : "Adicionar oauth customizado", "Add_Members" : "Adicionar membros", "Add_users" : "Adicionar usuários", "Administration" : "Administração", @@ -45,8 +46,8 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Embed", - "API_EmbedDisabledFor": "Desabilitar embed para os usuários", - "API_EmbedDisabledFor_Description": "Lista de nomes de usuário separados por vÃrgula", + "API_EmbedDisabledFor" : "Desabilitar embed para os usuários", + "API_EmbedDisabledFor_Description" : "Lista de nomes de usuário separados por vÃrgula", "are_also_typing" : "também estão digitando", "are_typing" : "estão digitando", "Are_you_sure" : "Você tem certeza?", @@ -73,7 +74,8 @@ "Chat_Rooms" : "Salas de Chat", "close" : "fechar", "coming_soon" : "em breve", - "Compact_View": "Visão Compacta", + "Commands" : "Comandos", + "Compact_View" : "Visão Compacta", "Confirm_password" : "Confirmar a senha", "Contact" : "Contato", "Conversation" : "Conversa", @@ -83,14 +85,16 @@ "Create_new_private_group" : "Criar um novo grupo privado", "Create_new_public_channel" : "Criar um canal público", "Created_at" : "Data criação", + "Custom_oauth_unique_name" : "Nome exclusivo para oauth customizado", + "Custom_oauth_helper" : "Ao configurar o seu Provedor de OAuth, você terá que informar uma URL de retorno de chamada. Use <pre>%s</pre>.", "days" : "dias", "Deactivate" : "Desativar", "Delete_User_Warning" : "Excluir um usuário irá apagar todas as mensagens desse usuário também. Isso não poderá ser desfeito.", "Delete" : "Deletar", "Deleted" : "Deletado!", - "Desktop_Notifications": "Notificações Desktop", - "Desktop_Notifications_Disabled": "Notificações Desktop estão Desativadas. Mude as preferências do seu navegador se quiser habilitar as notificações.", - "Desktop_Notifications_Enabled": "Notificações Desktop estão Habilitadas", + "Desktop_Notifications" : "Notificações Desktop", + "Desktop_Notifications_Disabled" : "Notificações Desktop estão Desativadas. Mude as preferências do seu navegador se quiser habilitar as notificações.", + "Desktop_Notifications_Enabled" : "Notificações Desktop estão Habilitadas", "Direct_Messages" : "Mensagens Diretas", "Disable_Favorite_Rooms" : "Desabilitar Favoritos", "Disable_New_Message_Notification" : "Desativar notificações de nova mensagem", @@ -104,10 +108,12 @@ "Email_already_exists" : "Email já cadastrado", "Email_or_username" : "Email ou nome de usuário", "Email_verified" : "Email verificado", - "Enable_Desktop_Notifications": "Habilitar Notificações Desktop", + "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "Habilitar Notificações Desktop", "Enter_info" : "Entre com seus dados de login", "Enter_to" : "Enter para", "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", "Esc_to" : "Esc para", "False" : "Falso", "Favorites" : "Favoritos", @@ -122,11 +128,13 @@ "General" : "Geral", "Get_to_know_the_team" : "Conheça o Rocket.Team", "github_no_public_email" : "Você não possui um e-mail público em sua conta do GitHub", + "Give_a_unique_name_for_the_custom_oauth" : "Dê um nome exclusivo para o oauth customizado", "Have_your_own_chat" : "Tenha seu próprio web chat. Desenvolvido com Meteor.com, o Rocket.Chat é uma excelente solução para desenvolvedores que querem construir e desenvolver sua própria plataforma de chat.", "Has_more" : "Há mais", "Hide_room" : "Esconder sala", "History" : "Histórico", "hours" : "horas", + "Incorrect_Password" : "Senha incorreta", "inline_code" : "código", "Invalid_confirm_pass" : "A confirmação de senha não é igual à senha", "Invalid_email" : "O e-mail informado é inválido", @@ -180,7 +188,7 @@ "Message_AllowDeleting" : "Permitir Exclusão de Mensagem", "Message_AllowEditing" : "Permitir Edição de Mensagem", "Message_AllowEditing_BlockEditInMinutes" : "Bloquear edição de mensagens após (em minutos - 0 para desabilitar)", - "Message_AudioRecorderEnabled": "Gravação de Ãudio Habilitada", + "Message_AudioRecorderEnabled" : "Gravação de Ãudio Habilitada", "Message_deleting_not_allowed" : "Exclusão de mensagem não permitido", "Message_editing_not_allowed" : "Edição de mensagem não permitido", "Message_editing_blocked" : "Esta mensagem não pode mais ser editada", @@ -191,8 +199,8 @@ "Message_pinned" : "Mensagem fixada", "Message_ShowDeletedStatus" : "Mostrar Status ExcluÃdo", "Message_ShowEditedStatus" : "Mostrar Status Editado", - "Message_ShowFormattingTips": "Exibir dicas de formatação", - "Messages": "Mensagens", + "Message_ShowFormattingTips" : "Exibir dicas de formatação", + "Messages" : "Mensagens", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Verificação de Site do Google", @@ -208,6 +216,7 @@ "My_Account" : "Minha Conta", "n_messages" : "%s mensagens", "Name" : "Nome", + "Name_cant_be_empty" : "Nome não pode ser vazio", "New_messages" : "Novas mensagens", "New_password" : "Nova senha", "No_channels_yet" : "Você não faz parte de nenhum canal ainda.", @@ -222,6 +231,8 @@ "Not_found_or_not_allowed" : "Não encontrado ou não permitido", "Nothing_found" : "Nada encontrado", "Notify_all_in_this_room" : "Notificar todos nesta sala", + "Old_Password" : "Senha Antiga", + "Old_and_new_password_required" : "Você precisa fornecer a senha antiga e a nova senha para alterar sua senha.", "Only_you_can_see_this_message" : "Apenas você pode ver esta mensagem", "Online" : "Online", "Oops!" : "Ops", @@ -230,6 +241,7 @@ "others" : "outros", "Password" : "Senha", "Password_changed_successfully" : "Senha alterada com sucesso", + "People" : "Pessoas", "Please_wait" : "Aguarde", "Please_wait_activation" : "Por favor aguarde, isso pode levar algum tempo.", "Please_wait_statistics" : "Por favor aguarde, as estatÃsticas estão sendo geradas.", @@ -255,10 +267,12 @@ "Quick_Search" : "Pesquisa Rápida", "quote" : "citação", "Recents" : "Recentes", + "Record" : "Gravar", "Register" : "Registrar-se", "Registration_Succeeded" : "Registrado com Sucesso", "Remember_me" : "Lembrar-me", "Remove" : "Remover", + "Remove_custom_oauth" : "Remover oauth customizado", "Remove_Admin" : "Remover Administrador", "Reset_password" : "Resetar senha", "Room" : "Sala", @@ -331,6 +345,7 @@ "Stats_Total_Private_Groups" : "Quantidade de Grupos Privados", "Stats_Total_Rooms" : "Quantidade de Salas", "Stats_Total_Users" : "Quantidade de Usuários", + "Stop_Recording" : "Parar Gravação", "strike" : "tachado", "Submit" : "Enviar", "S_new_messages_since_s" : "%s novas mensagens desde %s", @@ -361,6 +376,7 @@ "User_left_female" : "Usuário <em>__user_left__</em> deixou a conversa.", "User_left_male" : "Usuário <em>__user_left__</em> deixou a conversa.", "User_logged_out" : "Usuário não logado", + "User_not_found_or_incorrect_password" : "Usuário não encontrado ou senha incorreta", "User_removed_by" : "Usuário <em>__user_removed__</em> removido da conversa por <em>__user_by__</em>.", "User_Settings" : "Configurações do Usuário", "User_updated_successfully" : "Usuário atualizado com sucesso", @@ -384,4 +400,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} +} \ No newline at end of file diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index eef0892f2d4..db0f983b81e 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -1,13 +1,20 @@ { "Access_online_demo" : "Попробовать демо-верÑию", "Access_Online_Demo" : "Попробовать демо-верÑию", + "Accounts_EmailVerification" : "Подтверждение e-mail", + "Accounts_OAuth_Google" : "Google логин", + "Accounts_OAuth_Google_id" : "Google ID", + "Accounts_OAuth_Google_secret" : "Google пароль", + "Accounts_OAuth_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", "Add_Members" : "Добавить Пользователей", "Add_users" : "Добавить пользователей", "All_channels" : "Ð’Ñе Чаты", "and" : "и", + "API_Analytics" : "Ðналитика", "are_also_typing" : "вÑе ещё печатают", "are_typing" : "печатает", "Are_you_sure" : "Ð’Ñ‹ уверены?", + "Avatar_changed_successfully" : "Ðватар измененм уÑпешно", "away" : "отошёл", "Away" : "Отошёл", "away_female" : "отошла", @@ -38,12 +45,16 @@ "Created_at" : "Создано в", "Deleted" : "Удалено!", "Direct_Messages" : "Личные ÑообщениÑ", + "Drop_to_upload_file" : "ПеремеÑтите Ñюда Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ файла", + "Duplicate_channel_name" : "Канал Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%s' ÑущеÑтвует", + "Duplicate_private_group_name" : "ЧаÑÑ‚Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð° Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%s' ÑущеÑтвует", + "E-mail" : "ÐÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°", "edited" : "отредактировано", "Email_already_exists" : "Ðл. Ð°Ð´Ñ€ÐµÑ ÑƒÐ¶Ðµ ÑущеÑтвует", "Email_or_username" : "Почтовый Ñщик или логин", "Email_verified" : "Ðлектронный Ð°Ð´Ñ€ÐµÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐµÐ½", "Enter_info" : "ÐвторизациÑ", - "Error_changing_password" : "Пароль уÑпешно изменен", + "Error_changing_password" : "Ошибка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ", "Favorites" : "Избранные чаты", "Follow_social_profiles" : "ДобавлÑйте Ð½Ð°Ñ Ð² Ð´Ñ€ÑƒÐ·ÑŒÑ Ð² Ñоциальных ÑетÑÑ…, форкайте на github и пишите Ñвои отзывы о нашем приложении у Ð½Ð°Ñ Ð² trello.", "Forgot_password" : "Забыли пароль?", @@ -51,6 +62,7 @@ "github_no_public_email" : "Ð’ наÑтройках GitHub отÑутÑтвует публично доÑтупный e-mail", "Hide_room" : "Скрыть чат", "History" : "ИÑториÑ", + "hours" : "чаÑ(Ñ‹)", "inline_code" : "внутренний код", "Invalid_confirm_pass" : "Пароли не Ñовпадают", "Invalid_email" : "Ðеверный e-mail", @@ -80,13 +92,23 @@ "Login_with" : "ÐÐ²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ· %s", "login_with" : "ÐÐ²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ·", "Logout" : "Выйти", + "Make_Admin" : "Сделать админиÑтратором", "Members" : "УчаÑтники", "Members_List" : "СпиÑок учаÑтников", "Members_placeholder" : "УчаÑтники", "Message" : "Сообщение", + "Message_AllowDeleting" : "Разрешить удаление Ñообщений", + "Message_AllowEditing" : "Разрешить редактирование Ñообщений", + "Message_KeepHistory" : "Хранить иÑторию Ñообщений", + "Message_removed" : "Сообщение удалено", + "Message_ShowDeletedStatus" : "Отображать ÑÑ‚Ð°Ñ‚ÑƒÑ \"Удалено\"", + "Message_ShowEditedStatus" : "Отображать ÑÑ‚Ð°Ñ‚ÑƒÑ \"Отредактировано\"", + "Meta_language" : "Язык", + "minutes" : "минут(Ñ‹)", "More_channels" : "Другие чаты", "Msgs" : "СообщениÑ", "multi" : "много", + "My_Account" : "Мой аккаунт", "n_messages" : "%s Ñообщений", "Name" : "ИмÑ", "New_messages" : "Ðовые ÑообщениÑ", @@ -96,32 +118,48 @@ "No_favorites_yet" : "Ð’ избранном пуÑто. Попробуй добавить Ñюда что-нибудь.", "No_groups_yet" : "Ð’Ñ‹ не ÑоÑтоите ни в одном приватном чате.", "No_permission_to_view_room" : "У Ð²Ð°Ñ Ð½ÐµÑ‚ прав Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Ñтого чата.", + "No_channel_with_name_%s_was_found" : "Канал Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼Â <strong>\"%s\"</strong> не найден!", + "No_group_with_name_%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" : "Уведомить вÑех в данном чате", "Online" : "Ð’ Ñети", "Oops!" : "Ой", + "Opt_out_statistics" : "Ðе отправлÑÑ‚ÑŒ мою ÑтатиÑтику в Rocket.Chat", "others" : "другие", "Password" : "Пароль", "Password_changed_successfully" : "Пароль уÑпешно изменен", "Please_wait" : "Минуточку", + "Please_wait_activation" : "ПожалуйÑта, подождите, Ñто может занÑÑ‚ÑŒ некоторое времÑ.", + "Please_wait_statistics" : "ПожалуйÑта, подождите, ÑтатиÑтика генерируютÑÑ.", "Powered_by" : "Реализовано на", "Privacy" : "ПриватноÑÑ‚ÑŒ", "Private_Groups" : "Приватные чаты", + "Profile" : "Профиль", + "Profile_saved_successfully" : "Профиль уÑпешно Ñохранен", "Proudly_developed" : "Разработано Ñ Meteor", + "Push_debug" : "Отладка", + "Push_enable" : "Включить", "Quick_Search" : "БыÑтрый поиÑк", "quote" : "цитата", "Recents" : "Ðедавние", "Register" : "ЗарегиÑтрироватьÑÑ", + "Registration_Succeeded" : "УÑÐ¿ÐµÑˆÐ½Ð°Ñ Ñ€ÐµÐ³Ð¸ÑтрациÑ", "Remember_me" : "Запомните менÑ", "Remove" : "Удалить", "Reset_password" : "СброÑить пароль", "Room" : "Чат", "Room_name_changed" : "Ðазвание чата изменено: <em>__room_name__</em> пользователем <em>__user_by__</em>", "Room_name_changed_successfully" : "Ðазвание чата уÑпешно изменено", + "Room_not_found" : "Комната не найдена", + "room_user_count" : "%s пользователей", "Save" : "Сохранить", + "Save_changes" : "Сохранить изменениÑ", "Search" : "ПоиÑк", "Search_settings" : "ÐаÑтройки поиÑка", + "seconds" : "Ñекунд(Ñ‹)", "See_all" : "К общему ÑпиÑку", "See_only_online" : "Только в Ñети", "Select_an_avatar" : "Выбор автара", @@ -130,13 +168,32 @@ "Send_confirmation_email" : "Отправить пиÑьмо Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸ÐµÐ¼", "Send_Message" : "Отправить Ñообщение", "Settings" : "ÐаÑтройки", + "Settings_updated" : "ÐаÑтройки обновлены", "Showing_online_users" : "Отображено <b>__total_online__</b> из __total__ users", "Showing_results" : "<p>Отображено <b>%s</b> результатов</p>", "Silence" : "Тишина", "since_creation" : "Ñ %s", + "SMTP_Password" : "Пароль SMTP", + "SMTP_Port" : "SMTP Порт", + "SMTP_Username" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ SMTP-", "Start_of_conversation" : "Ðачать диалог", + "Stats_Active_Users" : "Ðктивные пользователи", + "Stats_Non_Active_Users" : "Ðеактивные пользователи", + "Stats_Offline_Users" : "Пользователи не в Ñети", + "Stats_Online_Users" : "Пользователи в Ñети", + "Stats_OS_Arch" : "Ðрхитектура ОС", + "Stats_OS_Cpus" : "КоличеÑтво процеÑÑоров в ОС", + "Stats_OS_Freemem" : "Свободное кол-во памÑти", + "Stats_OS_Platform" : "Платформа ОС", + "Stats_OS_Release" : "ВерÑÐ¸Ñ ÐžÐ¡", + "Stats_OS_Totalmem" : "Общее кол-во памÑти в ОС", + "Stats_OS_Type" : "Тип СиÑтемы", + "Stats_OS_Uptime" : "Ðптайм ÑиÑтемы", + "Stats_Total_Channels" : "Общее кол-во каналов", + "Stats_Total_Users" : "Ð’Ñего пользователей", "Submit" : "Отправить", "The_field_is_required" : "Поле %s обÑзательно.", + "Upload_file_question" : "Загрузить файл?", "Use_initials_avatar" : "ИÑпользовать Ñтандартный аватар", "use_menu" : "ИÑпользуйте боковое меню Ð´Ð»Ñ Ð´Ð¾Ñтупа к вашим ÑообщениÑм и чатам", "Use_service_avatar" : "ИÑпользовать %s аватар", @@ -146,6 +203,10 @@ "User_added_by" : "Пользователь <em>__user_added__</em> добавлен <em>__user_by__</em>.", "User_has_been_activated" : "Пользователь активирован", "User_has_been_deactivated" : "Пользователь деактивирован", + "User_has_been_deleted" : "Пользователь был удален", + "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" : "ПриÑоединилÑÑ Ðº чату.", @@ -154,6 +215,8 @@ "User_left_male" : "Пользователь <em>__user_left__</em> покинул чат.", "User_logged_out" : "Пользователь не в Ñети", "User_removed_by" : "Пользователь <em>__user_removed__</em> удален <em>__user_by__</em>.", + "User_Settings" : "ПользовательÑкие наÑтройки", + "User_updated_successfully" : "Пользователь уÑпешно обновлен", "Username" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ", "Username_cant_be_empty" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ может быть пуÑтым", "Username_description" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтников к вам.", @@ -161,10 +224,12 @@ "Username_title" : "ЗарегиÑтрировать логин", "Username_unavaliable" : "<strong>%s</strong> уже иÑпользуетÑÑ :(", "View_All" : "ПоÑмотреть вÑех", + "Wait_activation_warning" : "Прежде чем вы Ñможете войти в ваш аккаунт, он должен быть активирован вручную админиÑтратором.", "We_have_sent_password_email" : "Ðа вашу почту было отправлено пиÑьмо Ñ Ð¸Ð½ÑтрукциÑми. ЕÑли по каким-то причинам пиÑьмо не пришло, попробуйте еще раз и/или напишите нам.", "We_have_sent_registration_email" : "Ð’Ñе отлично. ОÑталоÑÑŒ только подтвердить региÑтрацию - пиÑьмо выÑлано на почту. ЕÑли что-то пошло не так, попробуйте еще раз и/или напишите нам.", "Welcome" : "Добро пожаловать, <em>%s</em>.", "Welcome_to_the" : "Добро пожаловать в", + "With_whom" : "C кем", "Yes_delete_it" : "Да, удалить его!", "you_are_in_preview_mode_of" : "Ð’Ñ‹ находитеÑÑŒ в режиме предварительного проÑмотра канала # <strong>__room_name__</strong>", "You_need_confirm_email" : "Ðеобходимо подтвердить email Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°!", diff --git a/packages/rocketchat-chatops/i18n/ar.i18n.json b/packages/rocketchat-chatops/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/de.i18n.json b/packages/rocketchat-chatops/i18n/de.i18n.json new file mode 100644 index 00000000000..92a7ee53ca8 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Chatops_Enabled" : "Chatops aktivieren", + "Chatops_Username" : "Chatops Benutzername" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/el.i18n.json b/packages/rocketchat-chatops/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/en.i18n.json b/packages/rocketchat-chatops/i18n/en.i18n.json index 818eea232e6..92e629a0490 100644 --- a/packages/rocketchat-chatops/i18n/en.i18n.json +++ b/packages/rocketchat-chatops/i18n/en.i18n.json @@ -1,5 +1,5 @@ { - "Chatops_Enabled" : "Enable Chatops", - "Chatops_Title": "Chatops panel", - "Chatops_Username": "Chatops username" -} + "Chatops_Enabled" : "Enable Chatops", + "Chatops_Title" : "Chatops panel", + "Chatops_Username" : "Chatops username" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/es.i18n.json b/packages/rocketchat-chatops/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/fi.i18n.json b/packages/rocketchat-chatops/i18n/fi.i18n.json new file mode 100644 index 00000000000..73d7555f644 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/fi.i18n.json @@ -0,0 +1,4 @@ +{ + "Chatops_Enabled" : "Ota käyttöön Chatops", + "Chatops_Title" : "Chatops paneeli" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/fr.i18n.json b/packages/rocketchat-chatops/i18n/fr.i18n.json new file mode 100644 index 00000000000..36d9014b31a --- /dev/null +++ b/packages/rocketchat-chatops/i18n/fr.i18n.json @@ -0,0 +1,4 @@ +{ + "Chatops_Enabled" : "Activer Chatops", + "Chatops_Title" : "Panneau de contrôle des Chatops" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/he.i18n.json b/packages/rocketchat-chatops/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/hr.i18n.json b/packages/rocketchat-chatops/i18n/hr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/hu.i18n.json b/packages/rocketchat-chatops/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/it.i18n.json b/packages/rocketchat-chatops/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ja.i18n.json b/packages/rocketchat-chatops/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/km.i18n.json b/packages/rocketchat-chatops/i18n/km.i18n.json new file mode 100644 index 00000000000..b9833e600e3 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/km.i18n.json @@ -0,0 +1,5 @@ +{ + "Chatops_Enabled" : "អនុញ្ញាážáž· Chatops", + "Chatops_Title" : "ផ្ទាំង Chatops", + "Chatops_Username" : "ឈ្មោះអ្នកប្រើប្រាស់ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ms-MY.i18n.json b/packages/rocketchat-chatops/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/pl.i18n.json b/packages/rocketchat-chatops/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/pt.i18n.json b/packages/rocketchat-chatops/i18n/pt.i18n.json new file mode 100644 index 00000000000..3f6832aa558 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/pt.i18n.json @@ -0,0 +1,5 @@ +{ + "Chatops_Enabled" : "Ativar Chatops", + "Chatops_Title" : "Painel Chatops", + "Chatops_Username" : "Ops do chat" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ru.i18n.json b/packages/rocketchat-chatops/i18n/ru.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ta-IN.i18n.json b/packages/rocketchat-chatops/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/tr.i18n.json b/packages/rocketchat-chatops/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ug.i18n.json b/packages/rocketchat-chatops/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/uk.i18n.json b/packages/rocketchat-chatops/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/zh.i18n.json b/packages/rocketchat-chatops/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ar.i18n.json b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/ar.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json @@ -1 +1 @@ -{ } +{ } \ 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 7eb5f77e2d3..77967ea7cdd 100644 --- a/packages/rocketchat-github-enterprise/i18n/de.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/de.i18n.json @@ -1,3 +1,6 @@ { - "API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} + "Accounts_OAuth_GitHub_Enterprise" : "OAuth aktiviert", + "API_GitHub_Enterprise_URL" : "GitHub Enterprise", + "Accounts_OAuth_GitHub_Enterprise_id" : "Client-ID", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/el.i18n.json b/packages/rocketchat-github-enterprise/i18n/el.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/el.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/el.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index 187124f550e..64dca2dc2c2 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -4,4 +4,4 @@ "Accounts_OAuth_GitHub_Enterprise_id" : "Client ID", "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", "Github_Enterprise_Url_No_Trail" : "Note: Please exclude trailing slash" -} +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/es.i18n.json b/packages/rocketchat-github-enterprise/i18n/es.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/es.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/es.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/fi.i18n.json b/packages/rocketchat-github-enterprise/i18n/fi.i18n.json index 7eb5f77e2d3..06dd996c99c 100644 --- a/packages/rocketchat-github-enterprise/i18n/fi.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/fi.i18n.json @@ -1,3 +1,3 @@ { "API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} +} \ 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 7eb5f77e2d3..06dd996c99c 100644 --- a/packages/rocketchat-github-enterprise/i18n/fr.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/fr.i18n.json @@ -1,3 +1,3 @@ { "API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/he.i18n.json b/packages/rocketchat-github-enterprise/i18n/he.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/he.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/he.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/hr.i18n.json b/packages/rocketchat-github-enterprise/i18n/hr.i18n.json index 7eb5f77e2d3..06dd996c99c 100644 --- a/packages/rocketchat-github-enterprise/i18n/hr.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/hr.i18n.json @@ -1,3 +1,3 @@ { "API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/hu.i18n.json b/packages/rocketchat-github-enterprise/i18n/hu.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/hu.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/hu.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/it.i18n.json b/packages/rocketchat-github-enterprise/i18n/it.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/it.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/it.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ja.i18n.json b/packages/rocketchat-github-enterprise/i18n/ja.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/ja.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ja.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/km.i18n.json b/packages/rocketchat-github-enterprise/i18n/km.i18n.json index 7eb5f77e2d3..ef0c0f296f3 100644 --- a/packages/rocketchat-github-enterprise/i18n/km.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/km.i18n.json @@ -1,3 +1,7 @@ { - "API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} + "Accounts_OAuth_GitHub_Enterprise" : "OAuth បានអនុញ្ញាážáž·", + "API_GitHub_Enterprise_URL" : "GitHub Enterprise", + "Accounts_OAuth_GitHub_Enterprise_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Client", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client សម្ងាážáŸ‹", + "Github_Enterprise_Url_No_Trail" : "ចំណាំ: សូមដកចáŸáž‰áž“ូវ trailing slash" +} \ 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 7eb5f77e2d3..06dd996c99c 100644 --- a/packages/rocketchat-github-enterprise/i18n/ko.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ko.i18n.json @@ -1,3 +1,3 @@ { "API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ms-MY.i18n.json b/packages/rocketchat-github-enterprise/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/pl.i18n.json b/packages/rocketchat-github-enterprise/i18n/pl.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/pl.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/pl.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/pt.i18n.json b/packages/rocketchat-github-enterprise/i18n/pt.i18n.json index d3f2f3a3d23..d10b177181f 100644 --- a/packages/rocketchat-github-enterprise/i18n/pt.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/pt.i18n.json @@ -1,3 +1,6 @@ { -"API_GitHub_Enterprise_URL" : "GitHub Enterprise" -} + "Accounts_OAuth_GitHub_Enterprise" : "OAuth Ativado", + "API_GitHub_Enterprise_URL" : "URL do servidor", + "Accounts_OAuth_GitHub_Enterprise_id" : "GitHub Id", + "Github_Enterprise_Url_No_Trail" : "Nota: excluir barra 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 ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/ru.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ru.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ta-IN.i18n.json b/packages/rocketchat-github-enterprise/i18n/ta-IN.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/ta-IN.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ta-IN.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/tr.i18n.json b/packages/rocketchat-github-enterprise/i18n/tr.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/tr.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/tr.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ug.i18n.json b/packages/rocketchat-github-enterprise/i18n/ug.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/ug.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ug.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/uk.i18n.json b/packages/rocketchat-github-enterprise/i18n/uk.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/uk.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/uk.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/zh.i18n.json b/packages/rocketchat-github-enterprise/i18n/zh.i18n.json index ffcd4415b08..6f31cf5a2e6 100644 --- a/packages/rocketchat-github-enterprise/i18n/zh.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/zh.i18n.json @@ -1 +1 @@ -{ } +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/ms-MY.i18n.json b/packages/rocketchat-gitlab/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ar.i18n.json b/packages/rocketchat-hubot/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/de.i18n.json b/packages/rocketchat-hubot/i18n/de.i18n.json new file mode 100644 index 00000000000..e077ae8144f --- /dev/null +++ b/packages/rocketchat-hubot/i18n/de.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RocketBot aktivieren", + "RocketBot_Name" : "RocketBot Name", + "RocketBot_Name_Description" : "RocketBot Name muss einen registrierten Benutzernamen auf dem Server haben." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/el.i18n.json b/packages/rocketchat-hubot/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/en.i18n.json b/packages/rocketchat-hubot/i18n/en.i18n.json index 4e031582c84..4b362c7dacf 100644 --- a/packages/rocketchat-hubot/i18n/en.i18n.json +++ b/packages/rocketchat-hubot/i18n/en.i18n.json @@ -1,5 +1,5 @@ { - "RocketBot_Enabled": "RocketBot Enabled", - "RocketBot_Name": "RocketBot Name", - "RocketBot_Name_Description": "RocketBot name must be a valid username registered on your server." -} + "RocketBot_Enabled" : "RocketBot Enabled", + "RocketBot_Name" : "RocketBot Name", + "RocketBot_Name_Description" : "RocketBot name must be a valid username registered on your server." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/es.i18n.json b/packages/rocketchat-hubot/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/fi.i18n.json b/packages/rocketchat-hubot/i18n/fi.i18n.json new file mode 100644 index 00000000000..8cfaffcb858 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/fi.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RocketBot otettu käyttöön", + "RocketBot_Name" : "RocketBot nimi", + "RocketBot_Name_Description" : "RocketBot nimen on oltava kelvollinen käyttäjänimi rekisteröityneenä palvelimellasi." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/fr.i18n.json b/packages/rocketchat-hubot/i18n/fr.i18n.json new file mode 100644 index 00000000000..226a2e8ec21 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/fr.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RocketBot activé", + "RocketBot_Name" : "Nom du RocketBot", + "RocketBot_Name_Description" : "Le nom du RocketBot doit être un nom valide enregistré sur votre site" +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/he.i18n.json b/packages/rocketchat-hubot/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/hr.i18n.json b/packages/rocketchat-hubot/i18n/hr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/hu.i18n.json b/packages/rocketchat-hubot/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/it.i18n.json b/packages/rocketchat-hubot/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ja.i18n.json b/packages/rocketchat-hubot/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/km.i18n.json b/packages/rocketchat-hubot/i18n/km.i18n.json new file mode 100644 index 00000000000..8574cfe605e --- /dev/null +++ b/packages/rocketchat-hubot/i18n/km.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RocketBot បានអនុញ្ញាážáž·", + "RocketBot_Name" : "ឈ្មោះ RocketBot", + "RocketBot_Name_Description" : "ឈ្មោះ RocketBot ážáŸ’រូវážáŸ‚ជាឈ្មោះដែលបានចុះážáŸ’រឹមážáŸ’រូវនៅលើ Server ។" +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ko.i18n.json b/packages/rocketchat-hubot/i18n/ko.i18n.json new file mode 100644 index 00000000000..74e856f3789 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ko.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RockBot 사용", + "RocketBot_Name" : "RocketBot ì´ë¦„", + "RocketBot_Name_Description" : "RocketBot ì´ë¦„ì€ ì„œë²„ì— ë“±ë¡ëœ ì‚¬ìš©ìž ì´ë¦„ì´ì—¬ì•¼ 합니다." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ms-MY.i18n.json b/packages/rocketchat-hubot/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..901613c1d85 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ms-MY.i18n.json @@ -0,0 +1,5 @@ +{ + "RocketBot_Enabled" : "RocketBot Diaktifkan", + "RocketBot_Name" : "Nama RocketBot", + "RocketBot_Name_Description" : "Nama RocketBot mesti mengandungi nama pengguna yang sah berdaftar pada pelayan anda." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/pl.i18n.json b/packages/rocketchat-hubot/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/pt.i18n.json b/packages/rocketchat-hubot/i18n/pt.i18n.json index 32348991336..d8b359c8916 100644 --- a/packages/rocketchat-hubot/i18n/pt.i18n.json +++ b/packages/rocketchat-hubot/i18n/pt.i18n.json @@ -1,5 +1,5 @@ { - "RocketBot_Enabled": "RocketBot Habilitado", - "RocketBot_Name": "Nome do RocketBot", - "RocketBot_Name_Description": "O nome deve ser um username registrado." -} + "RocketBot_Enabled" : "RocketBot Habilitado", + "RocketBot_Name" : "Nome do RocketBot", + "RocketBot_Name_Description" : "O nome deve ser um username registrado." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ru.i18n.json b/packages/rocketchat-hubot/i18n/ru.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ta-IN.i18n.json b/packages/rocketchat-hubot/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/tr.i18n.json b/packages/rocketchat-hubot/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ug.i18n.json b/packages/rocketchat-hubot/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/uk.i18n.json b/packages/rocketchat-hubot/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/zh.i18n.json b/packages/rocketchat-hubot/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ms-MY.i18n.json b/packages/rocketchat-ldap/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..d6c3fbb791a --- /dev/null +++ b/packages/rocketchat-ldap/i18n/ms-MY.i18n.json @@ -0,0 +1,5 @@ +{ + "LDAP_Url" : "URL LDAP", + "LDAP_Port" : "Port LDAP", + "LDAP_Dn" : "LDAP DN" +} \ 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 6f31cf5a2e6..30411a053d4 100644 --- a/packages/rocketchat-livechat/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/i18n/de.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_title" : "Livechat Titel", + "Livechat_title_color" : "Livechat Titel Hintergrundfarbe" +} \ 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 6f31cf5a2e6..828c21abf53 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_title" : "Livechat otsikko", + "Livechat_title_color" : "Livechat otsikko taustaväri" +} \ 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 6f31cf5a2e6..27798a2d834 100644 --- a/packages/rocketchat-livechat/i18n/fr.i18n.json +++ b/packages/rocketchat-livechat/i18n/fr.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_title" : "Titre du chat en direct", + "Livechat_title_color" : "Couleur de fond du titre du chat en direct" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/km.i18n.json b/packages/rocketchat-livechat/i18n/km.i18n.json index 6f31cf5a2e6..e5650816ce1 100644 --- a/packages/rocketchat-livechat/i18n/km.i18n.json +++ b/packages/rocketchat-livechat/i18n/km.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_title" : "ចំណង​ជើង LiveChat", + "Livechat_title_color" : "ពណ៌ផ្ទៃážáž¶áž„ក្រោយចំណងជើង LiveChat" +} \ 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 6f31cf5a2e6..6a58a7a6ee1 100644 --- a/packages/rocketchat-livechat/i18n/ko.i18n.json +++ b/packages/rocketchat-livechat/i18n/ko.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_title" : "Livechat ì œëª©", + "Livechat_title_color" : "Livechat ì œëª© 배경색" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ms-MY.i18n.json b/packages/rocketchat-livechat/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..a33545bd7bb --- /dev/null +++ b/packages/rocketchat-livechat/i18n/ms-MY.i18n.json @@ -0,0 +1,4 @@ +{ + "Livechat_title" : "Tajuk Livechat", + "Livechat_title_color" : "Warna latar belakang tajuk Livechat" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ar.i18n.json b/packages/rocketchat-message-star/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/de.i18n.json b/packages/rocketchat-message-star/i18n/de.i18n.json new file mode 100644 index 00000000000..ceffff43684 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Star_Message" : "Stern-Nachrichten", + "Unstar_Message" : "Stern entfernen" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/el.i18n.json b/packages/rocketchat-message-star/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/en.i18n.json b/packages/rocketchat-message-star/i18n/en.i18n.json index 148a8407c59..7377102ab14 100644 --- a/packages/rocketchat-message-star/i18n/en.i18n.json +++ b/packages/rocketchat-message-star/i18n/en.i18n.json @@ -1,7 +1,7 @@ { - "Message_AllowStarring" : "Allow Message Starring", - "Star_Message": "Star Message", - "Unstar_Message": "Remove Star", - "Starred_Messages": "Starred Messages", - "No_starred_messages": "No starred messages" -} + "Message_AllowStarring" : "Allow Message Starring", + "Star_Message" : "Star Message", + "Unstar_Message" : "Remove Star", + "Starred_Messages" : "Starred Messages", + "No_starred_messages" : "No starred messages" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/es.i18n.json b/packages/rocketchat-message-star/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/fi.i18n.json b/packages/rocketchat-message-star/i18n/fi.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/fr.i18n.json b/packages/rocketchat-message-star/i18n/fr.i18n.json new file mode 100644 index 00000000000..4e510e7cc87 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/fr.i18n.json @@ -0,0 +1,7 @@ +{ + "Message_AllowStarring" : "Autoriser les favoris pour les messages", + "Star_Message" : "Mettre en favori", + "Unstar_Message" : "Supprimer des favoris", + "Starred_Messages" : "Messages favoris", + "No_starred_messages" : "Aucun messages en favoris" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/he.i18n.json b/packages/rocketchat-message-star/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/hu.i18n.json b/packages/rocketchat-message-star/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/it.i18n.json b/packages/rocketchat-message-star/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ja.i18n.json b/packages/rocketchat-message-star/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/km.i18n.json b/packages/rocketchat-message-star/i18n/km.i18n.json new file mode 100644 index 00000000000..4331f2976fa --- /dev/null +++ b/packages/rocketchat-message-star/i18n/km.i18n.json @@ -0,0 +1,7 @@ +{ + "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/ko.i18n.json b/packages/rocketchat-message-star/i18n/ko.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ms-MY.i18n.json b/packages/rocketchat-message-star/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..b663a381c3e --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ms-MY.i18n.json @@ -0,0 +1,7 @@ +{ + "Message_AllowStarring" : "Benarkan Mesej Dibintangi", + "Star_Message" : "Bintangkan Mesej ", + "Unstar_Message" : "Padam Bintang", + "Starred_Messages" : "Mesej Berbintang", + "No_starred_messages" : "Tiada mesej berbintang" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/pl.i18n.json b/packages/rocketchat-message-star/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/pt.i18n.json b/packages/rocketchat-message-star/i18n/pt.i18n.json index 479d3bec81c..d6236034474 100644 --- a/packages/rocketchat-message-star/i18n/pt.i18n.json +++ b/packages/rocketchat-message-star/i18n/pt.i18n.json @@ -1,7 +1,7 @@ { - "Message_AllowStarring" : "Permitir Mensagens Favoritas", - "Star_Message": "Favoritar Message", - "Unstar_Message": "Remover Favorito", - "No_starred_messages": "Não há mensagens favoritas", - "Starred_Messages": "Mensagens Favoritas" -} + "Message_AllowStarring" : "Permitir Mensagens Favoritas", + "Star_Message" : "Favoritar Message", + "Unstar_Message" : "Remover Favorito", + "Starred_Messages" : "Mensagens Favoritas", + "No_starred_messages" : "Não há mensagens favoritas" +} \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ta-IN.i18n.json b/packages/rocketchat-message-star/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/tr.i18n.json b/packages/rocketchat-message-star/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ug.i18n.json b/packages/rocketchat-message-star/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/uk.i18n.json b/packages/rocketchat-message-star/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/zh.i18n.json b/packages/rocketchat-message-star/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..7ed315a21cd --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/de.i18n.json @@ -0,0 +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" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/el.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/en.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/en.i18n.json index a173ff9e187..8c37474cfca 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/en.i18n.json @@ -1,5 +1,5 @@ { "Invite_user_to_join_channel" : "Invite one user to join this channel", "User_doesnt_exist" : "No user exists by the name of `@%s`.", - "Username_is_already_in_here": "`@%s` is already in here." + "Username_is_already_in_here" : "`@%s` is already in here." } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/es.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json new file mode 100644 index 00000000000..1622a0afad9 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json @@ -0,0 +1,4 @@ +{ + "User_doesnt_exist" : "Yhtään käyttäjää ei ole olemassa nimellä `@%s`.", + "Username_is_already_in_here" : "`@%s` on jo täällä." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/fr.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/fr.i18n.json new file mode 100644 index 00000000000..bca6e077911 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/fr.i18n.json @@ -0,0 +1,5 @@ +{ + "Invite_user_to_join_channel" : "Inviter un utilisateur à rejoindre le salon", + "User_doesnt_exist" : "Aucun utilisateur nommé `@% s`.", + "Username_is_already_in_here" : "`@% s` est déjà présent." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/he.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/hu.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/it.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ja.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/km.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/km.i18n.json new file mode 100644 index 00000000000..b729d655532 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/km.i18n.json @@ -0,0 +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/ko.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ms-MY.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..861e3b334ae --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ms-MY.i18n.json @@ -0,0 +1,5 @@ +{ + "Invite_user_to_join_channel" : "Jemput satu pengguna untuk menyertai saluran ini", + "User_doesnt_exist" : "Tiada pengguna wujud dengan nama `@%s`.", + "Username_is_already_in_here" : "`@%s` sudah berada di sini." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/pt.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/pt.i18n.json index fd73455828f..a324df34490 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/pt.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/pt.i18n.json @@ -1,5 +1,5 @@ { "Invite_user_to_join_channel" : "Convidar um usuário para este canal", "User_doesnt_exist" : "O usuário `@%s` não existe.", - "Username_is_already_in_here": "`@%s` já está aqui." + "Username_is_already_in_here" : "`@%s` já está aqui." } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ta-IN.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/tr.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ug.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/uk.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/zh.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..78da1cc9d2c --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/de.i18n.json @@ -0,0 +1,3 @@ +{ + "Channel_doesnt_exist" : "Der Kanal `#% s` existiert nicht." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/el.i18n.json b/packages/rocketchat-slashcommands-join/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/en.i18n.json b/packages/rocketchat-slashcommands-join/i18n/en.i18n.json index 62980258fdc..2d7d6f0e5cf 100644 --- a/packages/rocketchat-slashcommands-join/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/en.i18n.json @@ -1,4 +1,4 @@ { "Channel_doesnt_exist" : "The channel `#%s` does not exist.", - "Join_the_given_channel": "Join the given channel" + "Join_the_given_channel" : "Join the given channel" } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/es.i18n.json b/packages/rocketchat-slashcommands-join/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json new file mode 100644 index 00000000000..17c66619689 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json @@ -0,0 +1,3 @@ +{ + "Channel_doesnt_exist" : "Kanavaa `#%s` ei ole olemassa." +} \ 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 new file mode 100644 index 00000000000..9565cca54e7 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/fr.i18n.json @@ -0,0 +1,3 @@ +{ + "Channel_doesnt_exist" : "Le canal `#%s` n'existe pas." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/he.i18n.json b/packages/rocketchat-slashcommands-join/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/hu.i18n.json b/packages/rocketchat-slashcommands-join/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/it.i18n.json b/packages/rocketchat-slashcommands-join/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ja.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/km.i18n.json b/packages/rocketchat-slashcommands-join/i18n/km.i18n.json new file mode 100644 index 00000000000..69aa8098bdb --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/km.i18n.json @@ -0,0 +1,4 @@ +{ + "Channel_doesnt_exist" : "ប៉ុស្ážáž·áŸáŸ– `#% s` មិនមានទáŸáŸ”", + "Join_the_given_channel" : "ចូលរួមប៉ុស្ážáž·áŸážŠáŸ‚លបានផ្ážáž›áŸ‹áž²áŸ’áž™" +} \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ms-MY.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..d0fff72a540 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ms-MY.i18n.json @@ -0,0 +1,4 @@ +{ + "Channel_doesnt_exist" : "Saluran `#% s` tidak wujud.", + "Join_the_given_channel" : "Sertai saluran yang dinyatakan" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/pt.i18n.json b/packages/rocketchat-slashcommands-join/i18n/pt.i18n.json index 7e1a751fb7c..bb7935e658a 100644 --- a/packages/rocketchat-slashcommands-join/i18n/pt.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/pt.i18n.json @@ -1,4 +1,4 @@ { "Channel_doesnt_exist" : "O canal `#%s` não existe.", - "Join_the_given_channel": "Entrar no canal informado" + "Join_the_given_channel" : "Entrar no canal informado" } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ta-IN.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/tr.i18n.json b/packages/rocketchat-slashcommands-join/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ug.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/uk.i18n.json b/packages/rocketchat-slashcommands-join/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/zh.i18n.json b/packages/rocketchat-slashcommands-join/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..ac751a74fe7 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Perbualan Video", + "Remote" : "Kawalan Jauh", + "Setup" : "Persediaan", + "Stop_Video" : "Berhentikan Video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json index 3e6ea9c3822..ebedecb615d 100644 --- a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json +++ b/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json @@ -1,5 +1,6 @@ { "Video_Chat" : "Видео чат", "Remote" : "Удалённый", + "Setup" : "УÑтановить", "Stop_Video" : "ОÑтановить видео" } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/de.i18n.json b/packages/rocketchat-wordpress/i18n/de.i18n.json index 6f31cf5a2e6..f269571244d 100644 --- a/packages/rocketchat-wordpress/i18n/de.i18n.json +++ b/packages/rocketchat-wordpress/i18n/de.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "Wordpress URL", + "Accounts_OAuth_Wordpress" : "WordPress Login", + "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/fi.i18n.json b/packages/rocketchat-wordpress/i18n/fi.i18n.json index 6f31cf5a2e6..6354e336572 100644 --- a/packages/rocketchat-wordpress/i18n/fi.i18n.json +++ b/packages/rocketchat-wordpress/i18n/fi.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "WordPress URL", + "Accounts_OAuth_Wordpress" : "WordPress Kirjaudu sisään", + "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 6f31cf5a2e6..315cdb25a08 100644 --- a/packages/rocketchat-wordpress/i18n/fr.i18n.json +++ b/packages/rocketchat-wordpress/i18n/fr.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "WordPress URL", + "Accounts_OAuth_Wordpress" : "WordPress Login", + "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/hr.i18n.json b/packages/rocketchat-wordpress/i18n/hr.i18n.json index 6f31cf5a2e6..5d3a54efc87 100644 --- a/packages/rocketchat-wordpress/i18n/hr.i18n.json +++ b/packages/rocketchat-wordpress/i18n/hr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "WordPress link" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/km.i18n.json b/packages/rocketchat-wordpress/i18n/km.i18n.json index 6f31cf5a2e6..5a6efeac1b2 100644 --- a/packages/rocketchat-wordpress/i18n/km.i18n.json +++ b/packages/rocketchat-wordpress/i18n/km.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "ážáŸ†ážŽáž—្ជាប់ URL របស់ WordPress", + "Accounts_OAuth_Wordpress" : "ការឡុកចូល Wordpress", + "Accounts_OAuth_Wordpress_id" : "áž›áŸážážŸáž˜áŸ’គាល់ WordPress", + "Accounts_OAuth_Wordpress_secret" : "WordPress សម្ងាážáŸ‹" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/ko.i18n.json b/packages/rocketchat-wordpress/i18n/ko.i18n.json index 6f31cf5a2e6..5b49c98976d 100644 --- a/packages/rocketchat-wordpress/i18n/ko.i18n.json +++ b/packages/rocketchat-wordpress/i18n/ko.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "WordPress URL", + "Accounts_OAuth_Wordpress" : "WordPress 로그ì¸", + "Accounts_OAuth_Wordpress_id" : "WordPress ID", + "Accounts_OAuth_Wordpress_secret" : "WordPress 암호" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/ms-MY.i18n.json b/packages/rocketchat-wordpress/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..411c3c287c5 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/ms-MY.i18n.json @@ -0,0 +1,6 @@ +{ + "API_Wordpress_URL" : " URL WordPress", + "Accounts_OAuth_Wordpress" : "Daftar masuk 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/pt.i18n.json b/packages/rocketchat-wordpress/i18n/pt.i18n.json index a3a4cf1c4e8..1983a52f7f7 100644 --- a/packages/rocketchat-wordpress/i18n/pt.i18n.json +++ b/packages/rocketchat-wordpress/i18n/pt.i18n.json @@ -1,3 +1,6 @@ { - "API_Wordpress_URL" : "URL do WordPress" + "API_Wordpress_URL" : "URL do WordPress", + "Accounts_OAuth_Wordpress" : "Login WordPress", + "Accounts_OAuth_Wordpress_id" : "WordPress ID", + "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" } \ No newline at end of file -- GitLab From 1fc1ac6490119e87859045a4616920b90896fe6e Mon Sep 17 00:00:00 2001 From: James Anderson <james@jamesanderson.me> Date: Thu, 22 Oct 2015 09:37:52 -0400 Subject: [PATCH 0193/1338] Changed icon for hiding direct messages in sideNav --- client/views/app/sideNav/chatRoomItem.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/sideNav/chatRoomItem.html b/client/views/app/sideNav/chatRoomItem.html index a3ae1aa21f2..1f434acba0d 100644 --- a/client/views/app/sideNav/chatRoomItem.html +++ b/client/views/app/sideNav/chatRoomItem.html @@ -7,7 +7,7 @@ <i class="{{roomIcon}} {{userStatus}}"></i> <span class='name'>{{name}}</span> <span class='opt'> - <i class="octicon octicon-eye hide-room" title="{{_ "Hide_room"}}"></i> + <i class="icon-eye-off hide-room" title="{{_ "Hide_room"}}"></i> {{#if canLeave}} <i class="octicon octicon-sign-out" title="{{_ "Leave_room"}}"></i> {{/if}} -- GitLab From 8c66cf45edcbe021a80a42faa2fb5b810da389d8 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 15:20:11 +0100 Subject: [PATCH 0194/1338] Updating i18n/en.i18n.json. - Adding missing entry for: Delete_Room_Warning - Adding 'this message' to : You_will_not_be_able_to_recover --- i18n/en.i18n.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 56b72649f2a..4c20dad34d0 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -91,6 +91,7 @@ "days" : "days", "Deactivate" : "Deactivate", "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", + "Delete_Room_Warning" : "Deleting a room will delete all messages posted within the room. This cannot be undone.", "Delete" : "Delete", "Deleted" : "Deleted!", "Desktop_Notifications" : "Desktop Notifications", @@ -399,7 +400,7 @@ "Yes_delete_it" : "Yes, delete it!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", "You_need_confirm_email" : "You need to confirm your email to login!", - "You_will_not_be_able_to_recover" : "You will not be able to recover!", + "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} -- GitLab From 274eb95f7655e257e6b11bb741087ba05d7d8a17 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 23:57:08 +0100 Subject: [PATCH 0195/1338] Updating i18n/en.i18n.json. --- i18n/en.i18n.json | 49 ++++++++++++++----- .../settings/server/startup.coffee | 4 +- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 4c20dad34d0..b61516b2833 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -4,29 +4,36 @@ "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Comma-separated list of allowed domains", "Accounts_AllowUsernameChange" : "Allow Username Change", + "Accounts_AvatarResize" : "Resize Avatars", + "Accounts_AvatarSize" : "Avatar Size", + "Accounts_AvatarStorePath" : "Avatar Storage Path", + "Accounts_AvatarStoreType" : "Avatar Storage Type", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", "Accounts_OAuth_Facebook" : "Facebook Login", "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_id" : "Client Id", "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Gitlab" : "OAuth Enabled", + "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" : "LinkedIn Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Manually aprove new users", "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_RegistrationRequired" : "Registration Required", + "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", + "Accounts_RegistrationRequired" : "Registration Required", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_Id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", @@ -48,7 +55,7 @@ "API_Analytics" : "Analytics", "API_Embed" : "Embed", "API_EmbedDisabledFor" : "Disable Embed for Users", - "API_EmbedDisabledFor_Description" : "Comma-separated usernames list", + "API_EmbedDisabledFor_Description" : "Comma-separated list of usernames", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", @@ -120,9 +127,10 @@ "False" : "False", "Favorites" : "Favorites", "FileUpload" : "File Upload", - "FileUpload_Enabled" : "Enable file upload", - "FileUpload_MaxFileSize" : "Max. size for uploaded files (in bytes)", - "FileUpload_MediaTypeWhiteList" : "Comma-separated Media Type list", + "FileUpload_Enabled" : "File Uploads Enabled", + "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", + "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", + "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", "Fork_it_on_github" : "Fork it on github", @@ -145,7 +153,7 @@ "Invalid_room_name" : "<strong>%s</strong> is not a valid room name,<br/> use only letters, numbers and dashes", "invisible" : "invisible", "Invisible" : "Invisible", - "Invitation HTML" : "Invitation HTML", + "Invitation_HTML" : "Invitation HTML", "Invitation_Subject" : "Invitation Subject", "Invite_Users" : "Invite Users", "is_also_typing" : "is also typing", @@ -168,9 +176,14 @@ "Layout_Login_Terms" : "Login Terms", "Layout_Privacy_Policy" : "Privacy Policy", "Layout_Sidenav_Footer" : "Side Navigation Footer", - "Layout_Sidenav_Footer_description" : "Footer size is 260x70", + "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", "LDAP" : "LDAP", + "LDAP_Bind_Search" : "Bind Search", + "LDAP_Dn" : "Distinguished Name (DN)", + "LDAP_Enable" : "Enable LDAP", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Leave room", "line" : "line", "Load_more" : "Load more", @@ -183,19 +196,22 @@ "Logout" : "Logout", "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", + "Markdown_Headers" : "Markdown Headers", "Members" : "Members", "Members_List" : "Members List", "Members_placeholder" : "Members", "Message" : "Message", "Message_AllowDeleting" : "Allow Message Deleting", "Message_AllowEditing" : "Allow Message Editing", - "Message_AllowEditing_BlockEditInMinutes" : "Block message editing after (in minutes - 0 to disable)", + "Message_AllowEditing_BlockEditInMinutes" : "Block Message Editing After (n) Minutes", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking", "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", "Message_deleting_not_allowed" : "Message deleting not allowed", "Message_editing_not_allowed" : "Message editing not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", - "Message_MaxAllowedSize" : "Message max allowed size", + "Message_MaxAllowedSize" : "Maximum Allowed Messages", "Message_pinning_not_allowed" : "Message pinning not allowed", + "Message_AllowPinning" : "Allow Message Pinning", "Message_KeepHistory" : "Keep Message History", "Message_removed" : "Message removed", "Message_pinned" : "Message pinned", @@ -204,7 +220,7 @@ "Message_ShowFormattingTips" : "Show Formatting Tips", "Messages" : "Messages", "Meta" : "Meta", - "Meta_fb_app_id" : "Facebook APP ID", + "Meta_fb_app_id" : "Facebook App Id", "Meta_google-site-verification" : "Google Site Verification", "Meta_language" : "Language", "Meta_msvalidate01" : "MSValidate.01", @@ -265,6 +281,8 @@ "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", "Push_enable" : "Enable", + "Push_gcm_api_key" : "GCM API Key", + "Push_gcm_project_number" : "GCM Project Number", "Push_production" : "Production", "Quick_Search" : "Quick Search", "quote" : "quote", @@ -316,6 +334,11 @@ "Site_Url" : "Site URL", "Site_Url_Description" : "Example: https://chat.domain.com/", "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", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP Password", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 8812e98f8d5..e16aa2ab629 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -40,7 +40,7 @@ RocketChat.settings.add 'Accounts_AllowUsernameChange', true, { type: 'boolean', 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/*', { type: 'string', group: 'FileUpload', public: true } +RocketChat.settings.add 'FileUpload_MediaTypeWhiteList', 'image/*', { type: 'string', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } RocketChat.settings.addGroup 'General' @@ -66,7 +66,7 @@ RocketChat.settings.add 'Invitation_HTML', '<h2>You have been invited to <h1>Roc 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 } +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 } -- GitLab From df1c39734f09470e89d32786f1696fe83737b4df Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 23:32:16 +0100 Subject: [PATCH 0196/1338] Revising rocketchat-github-enterprise English translations. --- packages/rocketchat-github-enterprise/i18n/en.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index 64dca2dc2c2..8c3694421a6 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -1,7 +1,7 @@ { "Accounts_OAuth_GitHub_Enterprise" : "OAuth Enabled", "API_GitHub_Enterprise_URL" : "Server URL", - "Accounts_OAuth_GitHub_Enterprise_id" : "Client ID", + "Accounts_OAuth_GitHub_Enterprise_id" : "Client Id", "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", "Github_Enterprise_Url_No_Trail" : "Note: Please exclude trailing slash" -} \ No newline at end of file +} -- GitLab From 421ade716f724eec7f102c34224b3f119f72e3be Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 23:32:00 +0100 Subject: [PATCH 0197/1338] Revising rocketchat-livechat English translations. --- packages/rocketchat-livechat/i18n/en.i18n.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 75795c5127b..86b2bc4611c 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -1,4 +1,4 @@ { - "Livechat_title" : "Livechat title", - "Livechat_title_color" : "Livechat title background color" -} \ No newline at end of file + "Livechat_title" : "Livechat Title", + "Livechat_title_color" : "Livechat Title Background Color" +} -- GitLab From 2e852c7f18062c1ebeb42ca49fd0a2f00e1f963d Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 23:31:10 +0100 Subject: [PATCH 0198/1338] Adding rocketchat-webrtc English translations. --- packages/rocketchat-webrtc/i18n/en.i18n.json | 5 +++++ packages/rocketchat-webrtc/package.js | 13 +++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 packages/rocketchat-webrtc/i18n/en.i18n.json diff --git a/packages/rocketchat-webrtc/i18n/en.i18n.json b/packages/rocketchat-webrtc/i18n/en.i18n.json new file mode 100644 index 00000000000..06cb81587e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/en.i18n.json @@ -0,0 +1,5 @@ +{ + "WebRTC_Enable_Channel" : "Enable for Public Channels", + "WebRTC_Enable_Direct" : "Enable for Direct Messages", + "WebRTC_Enable_Private" : "Enable for Private Channels" +} diff --git a/packages/rocketchat-webrtc/package.js b/packages/rocketchat-webrtc/package.js index e656f6d7b44..5ed915027e3 100644 --- a/packages/rocketchat-webrtc/package.js +++ b/packages/rocketchat-webrtc/package.js @@ -17,6 +17,19 @@ Package.onUse(function(api) { api.addFiles('server/settings.coffee', 'server'); + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-webrtc/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-webrtc/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.export('WebRTC'); }); -- GitLab From 664cf9b5a17552ed2065626e0fddbf9e04bee404 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 23:31:48 +0100 Subject: [PATCH 0199/1338] Revising rocketchat-wordpress English translations. --- packages/rocketchat-wordpress/i18n/en.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-wordpress/i18n/en.i18n.json b/packages/rocketchat-wordpress/i18n/en.i18n.json index 315cdb25a08..17e23404808 100644 --- a/packages/rocketchat-wordpress/i18n/en.i18n.json +++ b/packages/rocketchat-wordpress/i18n/en.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" : "WordPress Id", "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" -} \ No newline at end of file +} -- GitLab From d09450565e3908442a968db3ccf1d885a8ed7801 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Wed, 21 Oct 2015 17:31:55 +0100 Subject: [PATCH 0200/1338] Revising rocketchat-chatops English translations. --- packages/rocketchat-chatops/i18n/en.i18n.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-chatops/i18n/en.i18n.json b/packages/rocketchat-chatops/i18n/en.i18n.json index 92e629a0490..5d08d92bccd 100644 --- a/packages/rocketchat-chatops/i18n/en.i18n.json +++ b/packages/rocketchat-chatops/i18n/en.i18n.json @@ -1,5 +1,5 @@ { "Chatops_Enabled" : "Enable Chatops", - "Chatops_Title" : "Chatops panel", - "Chatops_Username" : "Chatops username" -} \ No newline at end of file + "Chatops_Title": "Chatops Panel", + "Chatops_Username": "Chatops Username" +} -- GitLab From b2cb7b1d4859b95aab26c0cdd8f5e6443fa11f4f Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sun, 18 Oct 2015 23:07:47 +0100 Subject: [PATCH 0201/1338] Setting top property to auto for .flex-tab .content. --- packages/rocketchat-theme/assets/stylesheets/base.less | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index a58b0235e5f..110af212a4c 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2703,6 +2703,7 @@ a.github-fork { &:extend(.fill-all); overflow-x: hidden; overflow-y: auto; + top: auto; -webkit-overflow-scrolling: touch; > div { .transition(transform .45s cubic-bezier(.5, -- GitLab From 26d292aecb58f03c460709c961531556732b7ec6 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sun, 18 Oct 2015 23:37:02 +0100 Subject: [PATCH 0202/1338] Adding bottom margin to .room-info-content > div. --- packages/rocketchat-theme/assets/stylesheets/base.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 110af212a4c..10e72fbb923 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2993,6 +2993,9 @@ a.github-fork { margin-top: 20px; } } + .room-info-content > div { + margin: 0 0 20px 0; + } } .user-image-status(@color) { -- GitLab From c0bf485791d79a6cb44f8f451ecf4d87ccc1806b Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 15:05:21 +0100 Subject: [PATCH 0203/1338] Changing icon from 'icon-hash' to 'icon-cancel'. --- client/views/admin/rooms/adminRooms.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/admin/rooms/adminRooms.html b/client/views/admin/rooms/adminRooms.html index ce0454d58f0..08756aff842 100644 --- a/client/views/admin/rooms/adminRooms.html +++ b/client/views/admin/rooms/adminRooms.html @@ -48,7 +48,7 @@ <div class="control"> <button class="more"><span class="arrow {{arrowPosition}}"></span></button> <div class="info-tabs"> - <a href="#adminRoomInfo" class="active"><i class="icon-hash"></i></a> + <a href="#adminRoomInfo" class="active"><i class="icon-cancel"></i></a> </div> </div> {{#if flexOpened}} -- GitLab From b74c050adfed98ab1ca7853fb4a8c3683f24d6ca Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Mon, 19 Oct 2015 16:57:23 +0100 Subject: [PATCH 0204/1338] Fixing alignment of '(edited)' status. Displaying as block-level element. --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 10e72fbb923..6ebf07d3fab 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2469,7 +2469,7 @@ a.github-fork { display: none; } .edited { - display: inline-block; + display: block; } .private { display: none; -- GitLab From 64b730adc5567e63f6a99bacf52e4c154cfaa7c2 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Wed, 21 Oct 2015 08:19:13 +0100 Subject: [PATCH 0205/1338] Styling channel listings. - Displaying links as block-level elements - Adding padding / margin --- .../rocketchat-theme/assets/stylesheets/base.less | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 6ebf07d3fab..bbe71d56869 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1847,6 +1847,19 @@ a.github-fork { } .list { + a { + display: block; + padding: 3px; + margin-bottom: 5px; + .info { + h3 { + margin-bottom: 5px; + } + ul { + margin-left: 3px; + } + } + } .user-image { float: right; margin-left: 12px; -- GitLab From bdc15442e65b78e92bcb310b669416dca0631fc8 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Wed, 21 Oct 2015 12:21:04 +0100 Subject: [PATCH 0206/1338] Styling room listings. - Adding padding / margin - Changing cursor to pointer - Adding background-color on hover --- packages/rocketchat-theme/assets/stylesheets/base.less | 8 ++++++++ .../assets/stylesheets/utils/_colors.import.less | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index bbe71d56869..294bc26cfb5 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1860,6 +1860,14 @@ a.github-fork { } } } + .room-info { + padding: 3px; + margin-bottom: 5px; + cursor: pointer; + h3 { + margin-bottom: 5px; + } + } .user-image { float: right; margin-left: 12px; diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index c65d61a4244..4832cf65688 100644 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -627,6 +627,11 @@ a.github-fork { color: @primary-font-color; } } + .room-info { + &:hover { + background-color: @secondary-background-color; + } + } .status { color: @secondary-font-color; } -- GitLab From 2e206bcb4e2dfd659a63c5d9c779da2e19483ea1 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Wed, 21 Oct 2015 13:24:23 +0100 Subject: [PATCH 0207/1338] Changing table headings from td to th. --- client/views/admin/users/adminUsers.html | 8 ++++---- packages/rocketchat-theme/assets/stylesheets/base.less | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/client/views/admin/users/adminUsers.html b/client/views/admin/users/adminUsers.html index b2eeb6c1d83..828ca152200 100644 --- a/client/views/admin/users/adminUsers.html +++ b/client/views/admin/users/adminUsers.html @@ -24,10 +24,10 @@ <table> <thead> <tr> - <td> </td> - <td width="34%">{{_ "Name"}}</td> - <td width="33%">{{_ "Username"}}</td> - <td width="33%">{{_ "E-mail"}}</td> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> </tr> </thead> <tbody> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 294bc26cfb5..6c1388ceeba 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1874,6 +1874,11 @@ a.github-fork { } table { width: 100%; + thead { + th { + text-align: left; + } + } tbody { td { vertical-align: middle; -- GitLab From 7e9250ec92ae8eac4254e259cf5145e48a96b442 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 22 Oct 2015 16:20:03 +0200 Subject: [PATCH 0208/1338] Use a better method to keep scroll at bottom --- client/views/app/room.coffee | 94 +++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 32c57de48d5..63e93849c53 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -481,6 +481,10 @@ Template.room.events if error toastr.error error.reason + 'load img': (e, template) -> + template.sendToBottomIfNecessary?() + + Template.room.onCreated -> # this.scrollOnBottom = true # this.typing = new msgTyping this.data._id @@ -508,57 +512,81 @@ Template.room.onRendered -> # ScrollListener.init() wrapper = this.find('.wrapper') + wrapperUl = this.find('.wrapper > ul') newMessage = this.find(".new-message") template = this wrapperOffset = $('.messages-box > .wrapper').offset() - onscroll = _.throttle -> - template.atBottom = wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight - , 200 - - updateUnreadCount = _.throttle -> - firstMessageOnScreen = document.elementFromPoint(wrapperOffset.left+1, wrapperOffset.top+50) - if firstMessageOnScreen?.id? - 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() - else - template.unreadCount.set 0 - , 300 - - Meteor.setInterval -> - if template.atBottom - wrapper.scrollTop = wrapper.scrollHeight - wrapper.clientHeight + template.isAtBottom = -> + if wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight newMessage.className = "new-message not" - , 100 + return true + return false - wrapper.addEventListener 'touchstart', -> - template.atBottom = false + template.sendToBottom = -> + wrapper.scrollTop = wrapper.scrollHeight - wrapper.clientHeight + newMessage.className = "new-message not" - wrapper.addEventListener 'touchend', -> - onscroll() + template.checkIfScrollIsAtBottom = -> + template.atBottom = template.isAtBottom() readMessage.enable() readMessage.read() - wrapper.addEventListener 'scroll', -> - template.atBottom = false - onscroll() - updateUnreadCount() + template.sendToBottomIfNecessary = -> + if template.atBottom is true and template.isAtBottom() isnt true + template.sendToBottom() + + template.sendToBottomIfNecessaryDebounced = _.debounce template.sendToBottomIfNecessary, 10 + + template.sendToBottomIfNecessary() + + if not window.MutationObserver? + wrapperUl.addEventListener 'DOMSubtreeModified', -> + template.sendToBottomIfNecessaryDebounced() + else + observer = new MutationObserver (mutations) -> + mutations.forEach (mutation) -> + template.sendToBottomIfNecessaryDebounced() + + observer.observe wrapperUl, + childList: true + # observer.disconnect() wrapper.addEventListener 'mousewheel', -> template.atBottom = false - onscroll() - readMessage.enable() - readMessage.read() + Meteor.defer -> + template.checkIfScrollIsAtBottom() wrapper.addEventListener 'wheel', -> template.atBottom = false - onscroll() - readMessage.enable() - readMessage.read() + Meteor.defer -> + template.checkIfScrollIsAtBottom() + + wrapper.addEventListener 'touchstart', -> + template.atBottom = false + + wrapper.addEventListener 'touchend', -> + Meteor.defer -> + template.checkIfScrollIsAtBottom() + Meteor.setTimeout -> + template.checkIfScrollIsAtBottom() + , 1000 + Meteor.setTimeout -> + template.checkIfScrollIsAtBottom() + , 2000 + + updateUnreadCount = _.throttle -> + firstMessageOnScreen = document.elementFromPoint(wrapperOffset.left+1, wrapperOffset.top+50) + if firstMessageOnScreen?.id? + 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() + else + template.unreadCount.set 0 + , 300 # salva a data da renderização para exibir alertas de novas mensagens $.data(this.firstNode, 'renderedAt', new Date) -- GitLab From 9694a19b0c08092501393d96dce8cc269c2c2835 Mon Sep 17 00:00:00 2001 From: acidicX <webmaster@carstenm.de> Date: Thu, 22 Oct 2015 16:27:20 +0200 Subject: [PATCH 0209/1338] added manifest.webapp and 512px icon for Firefox OS --- public/images/logo/favicon-512x512.png | Bin 0 -> 25808 bytes public/manifest.webapp | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 public/images/logo/favicon-512x512.png create mode 100644 public/manifest.webapp diff --git a/public/images/logo/favicon-512x512.png b/public/images/logo/favicon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..65e1e6a98ef1f5e38dac3f8233800caa51c6b44a GIT binary patch literal 25808 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 NS5qJMP2DEq{{S<_=mG!$ literal 0 HcmV?d00001 diff --git a/public/manifest.webapp b/public/manifest.webapp new file mode 100644 index 00000000000..5cd5d3ed37f --- /dev/null +++ b/public/manifest.webapp @@ -0,0 +1,17 @@ +{ + "name": "RocketChat", + "description": "The Ultimate Open Source WebChat Platform", + "launch_path": "/", + "icons": { + "128": "/images/logo/favicon-128x128.png", + "512": "/images/logo/favicon-512x512.png" + }, + "developer": { + "name": "Rocket.Chat", + "url": "https://rocket.chat/" + }, + "fullscreen": "true", + "chrome": { + "navigation": false + } +} -- GitLab From 646171730b835d30c1d3a75ee940d46a0957a3bc Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 22 Oct 2015 16:47:24 +0200 Subject: [PATCH 0210/1338] fix ""Invitation HTML" : to "Invitation_HTML" : --- i18n/de.i18n.json | 4 ++-- i18n/en.i18n.json | 4 ++-- i18n/fi.i18n.json | 4 ++-- i18n/fr.i18n.json | 4 ++-- i18n/km.i18n.json | 4 ++-- i18n/ko.i18n.json | 4 ++-- i18n/ms-MY.i18n.json | 4 ++-- i18n/pt.i18n.json | 4 ++-- i18n/zh.i18n.json | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 08bb9ab3846..c160eb6e11e 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -140,7 +140,7 @@ "Invalid_room_name" : "<strong>%s</strong> ist kein zulässiger Raumname.<br/> Benutze nur Buchstaben, Nummern und Bindestriche.", "invisible" : "unsichtbar", "Invisible" : "Unsichtbar", - "Invitation HTML" : "Einladungs HTML", + "Invitation_HTML" : "Einladungs HTML", "Invitation_Subject" : "Einladungs Betreff", "Invite_Users" : "Benutzer einladen", "is_also_typing" : "schreibt auch", @@ -396,4 +396,4 @@ "You_will_not_be_able_to_recover" : "Sie können es nicht wieder rückgängig machen!", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", "Your_Open_Source_solution" : "Deine eigene Open Source Chat Lösung" -} \ No newline at end of file +} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 56b72649f2a..cbaa9797006 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -144,7 +144,7 @@ "Invalid_room_name" : "<strong>%s</strong> is not a valid room name,<br/> use only letters, numbers and dashes", "invisible" : "invisible", "Invisible" : "Invisible", - "Invitation HTML" : "Invitation HTML", + "Invitation_HTML" : "Invitation HTML", "Invitation_Subject" : "Invitation Subject", "Invite_Users" : "Invite Users", "is_also_typing" : "is also typing", @@ -402,4 +402,4 @@ "You_will_not_be_able_to_recover" : "You will not be able to recover!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", "Your_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 7a7e192dc8d..e9d42609a06 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -130,7 +130,7 @@ "Invalid_room_name" : "<strong>%s</strong> ei ole hyväksyttävä kanavan nimi,<br/> käytä vain kirjaimia, numeroita ja viivaa", "invisible" : "näkymätön", "Invisible" : "Näkymätön", - "Invitation HTML" : "Kutsu HTML", + "Invitation_HTML" : "Kutsu HTML", "Invitation_Subject" : "Kutsu aihe", "Invite_Users" : "Kutsu käyttäjiä", "is_also_typing" : "kirjoittaa myös", @@ -381,4 +381,4 @@ "You_will_not_be_able_to_recover" : "Palauttaminen ei ole mahdollista!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", "Your_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index d2e83235575..10f63686a41 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -134,7 +134,7 @@ "Invalid_room_name" : "<strong>%s</strong> n'est pas un nom de canal valide,<br>/ utilisez des lettres, des chiffres et des tirets uniquement", "invisible" : "invisible", "Invisible" : "Invisible", - "Invitation HTML" : "Contenu HTML de l'invitation", + "Invitation_HTML" : "Contenu HTML de l'invitation", "Invitation_Subject" : "Sujet de l'invitation", "Invite_Users" : "Inviter des utilisateurs", "is_also_typing" : "est également en train d'écrire", @@ -386,4 +386,4 @@ "You_will_not_be_able_to_recover" : "Cette action n'est pas réversible !", "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/km.i18n.json b/i18n/km.i18n.json index 893ab932571..fdb57430a46 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -142,7 +142,7 @@ "Invalid_room_name" : "<strong>%s</strong> គឺ​ជា​ឈ្មោះ​បន្ទប់​មិន​ážáŸ’រឹម​ážáŸ’រូវ,<br/> ážáŸ’រូវ​ប្រើប្រាស់​​ážáŸ’រឹម​ážáŸ‚​ážáž½ážšâ€‹áž¢áž€áŸ’សរ, áž›áŸáž និង​ សញ្ញាចុច", "invisible" : "មិន​បង្ហាញ", "Invisible" : "មិន​បង្ហាញ", - "Invitation HTML" : "ការអញ្ជើញទម្រង់ HTML", + "Invitation_HTML" : "ការអញ្ជើញទម្រង់ HTML", "Invitation_Subject" : "ប្រធានបទការអញ្ជើញ", "Invite_Users" : "អញ្ជើញអ្នកប្រើប្រាស់", "is_also_typing" : "គឺ​កំពុង​វាយ", @@ -397,4 +397,4 @@ "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/ko.i18n.json b/i18n/ko.i18n.json index 28014f5daf6..0b4fd4e5822 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -127,7 +127,7 @@ "Invalid_room_name" : "<strong>%s</strong>ì€ ì‚¬ìš© 가능한 ë°© ì´ë¦„ì´ ì•„ë‹™ë‹ˆë‹¤.<br/>소문ìž, 숫ìž, 대시만 ì‚¬ìš©í• ìˆ˜ 있습니다", "invisible" : "보지 ì•ŠìŒ", "Invisible" : "보지 ì•ŠìŒ", - "Invitation HTML" : "HTML 초대 페ì´ì§€", + "Invitation_HTML" : "HTML 초대 페ì´ì§€", "Invitation_Subject" : "초대 ì œëª©", "Invite_Users" : "ì‚¬ìš©ìž ì´ˆëŒ€", "is_also_typing" : "ë˜í•œ ìž…ë ¥ì¤‘", @@ -374,4 +374,4 @@ "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/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 652a9ea6ea5..0ac68139706 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -121,7 +121,7 @@ "Invalid_pass" : "Kata Laluan mesti tidak dikosongkan", "invisible" : "tidak dalam dilihat", "Invisible" : "Tidak dapat dilihat", - "Invitation HTML" : " HTML Jemputan", + "Invitation_HTML" : " HTML Jemputan", "Invitation_Subject" : "Subjek Jemputan", "Invite_Users" : "Jemput Pengguna", "is_also_typing" : "turut menaip", @@ -365,4 +365,4 @@ "You_need_confirm_email" : "Anda perlu mengesahkan e-mel anda untuk melog masuk!", "You_will_not_be_able_to_recover" : "Anda tidak boleh membaik pulih.", "Your_entry_has_been_deleted" : "Entri anda telah dipadam." -} \ No newline at end of file +} diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index b40f078171f..54a3906fc7d 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -143,7 +143,7 @@ "Invalid_room_name" : "<strong>%s</strong> não é um nome válido,<br/> utilizar apenas letras, números e hÃfens", "invisible" : "invisÃvel", "Invisible" : "InvisÃvel", - "Invitation HTML" : "HTML do Convite", + "Invitation_HTML" : "HTML do Convite", "Invitation_Subject" : "Assunto do Convite", "Invite_Users" : "Convidar Usuários", "is_also_typing" : "também está digitando", @@ -400,4 +400,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} \ No newline at end of file +} diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index a77d1b7b6fc..b5799225943 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -96,7 +96,7 @@ "Invalid_room_name" : "<strong>%s</strong>ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„èŠå¤©å®¤å称, <br/>åªèƒ½ä½¿ç”¨å—æ¯ï¼Œæ•°å—,.å’Œ_", "invisible" : "éšèº«", "Invisible" : "éšèº«", - "Invitation HTML" : "邀请邮件HTML", + "Invitation_HTML" : "邀请邮件HTML", "Invitation_Subject" : "邀请邮件主题", "Invite_Users" : "邀请用户", "is_also_typing" : "也æ£åœ¨è¾“å…¥", @@ -316,4 +316,4 @@ "You_will_not_be_able_to_recover" : "æ‚¨å°†æ— æ³•æ¢å¤ï¼", "Your_entry_has_been_deleted" : "æ‚¨çš„é¡¹ç›®å·²è¢«åˆ é™¤ã€‚", "Your_Open_Source_solution" : "您自己的开æºèŠå¤©è§£å†³æ–¹æ¡ˆ" -} \ No newline at end of file +} -- GitLab From b4fe53b48342fb0585f968b114f11e1ad794a7c7 Mon Sep 17 00:00:00 2001 From: acidicX <webmaster@carstenm.de> Date: Thu, 22 Oct 2015 17:00:34 +0200 Subject: [PATCH 0211/1338] wrong icon, new icon path --- public/images/logo/favicon-512x512.png | Bin 25808 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 public/images/logo/favicon-512x512.png diff --git a/public/images/logo/favicon-512x512.png b/public/images/logo/favicon-512x512.png deleted file mode 100644 index 65e1e6a98ef1f5e38dac3f8233800caa51c6b44a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25808 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 NS5qJMP2DEq{{S<_=mG!$ -- GitLab From 4772aef6aeadacec0cc5695c7d7703c9a59e638b Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 22 Oct 2015 13:18:04 -0200 Subject: [PATCH 0212/1338] Reverting special treatment for image delivery. --- lib/fileUpload.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 99755cae765..5f1dc9ad99f 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -41,8 +41,7 @@ if UploadFS? onFinishUpload: -> console.log arguments onRead: (fileId, file, req, res) -> - unless file?.type?.match(/^image\/.*/) - res.setHeader 'content-disposition', "attachment; filename=\"#{ file.name }\"" + res.setHeader 'content-disposition', "attachment; filename=\"#{ file.name }\"" if Meteor.isServer initFileStore() -- GitLab From b717cf8ede3c5b020ab280cc23ff6dae9c331363 Mon Sep 17 00:00:00 2001 From: acidicX <webmaster@carstenm.de> Date: Thu, 22 Oct 2015 17:22:08 +0200 Subject: [PATCH 0213/1338] image path changed --- public/manifest.webapp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/manifest.webapp b/public/manifest.webapp index 5cd5d3ed37f..30949605959 100644 --- a/public/manifest.webapp +++ b/public/manifest.webapp @@ -4,7 +4,7 @@ "launch_path": "/", "icons": { "128": "/images/logo/favicon-128x128.png", - "512": "/images/logo/favicon-512x512.png" + "512": "/images/logo/512x512.png" }, "developer": { "name": "Rocket.Chat", -- GitLab From 27af4cddf11cacc7d8fc9e2e0208cc20e9c23e6d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 22 Oct 2015 17:25:31 +0200 Subject: [PATCH 0214/1338] Try to fix push notifications --- client/lib/cordova/push.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/lib/cordova/push.coffee b/client/lib/cordova/push.coffee index e4d52a76311..f8485d4716c 100644 --- a/client/lib/cordova/push.coffee +++ b/client/lib/cordova/push.coffee @@ -35,7 +35,7 @@ if Meteor.isCordova Meteor.call 'log', 'CLIENT', 'message', arguments Tracker.autorun -> - if RocketChat.settings.get('Push_enable') is true + if RocketChat.settings.get('Push_enable') is true and Meteor.userId()? Push.Configure gcm: projectNumber: RocketChat.settings.get 'Push_gcm_project_number' -- GitLab From 8dbb48634829b83b35ab77f817ea448b87f0125a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 22 Oct 2015 17:45:58 +0200 Subject: [PATCH 0215/1338] Normalising "Id" case --- i18n/de.i18n.json | 2 +- i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 2 +- i18n/fr.i18n.json | 2 +- i18n/km.i18n.json | 2 +- i18n/ko.i18n.json | 2 +- i18n/ms-MY.i18n.json | 2 +- i18n/pt.i18n.json | 2 +- packages/rocketchat-lib/settings/server/addOAuthService.coffee | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index c160eb6e11e..57a3a757b4d 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -24,7 +24,7 @@ "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token Pfad", "Accounts_OAuth_Custom_Identity_Path" : "Identitäts Pfad", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index b61516b2833..cea7643e59b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -33,7 +33,7 @@ "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_Id" : "Id", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index e9d42609a06..bcf547b9920 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -24,7 +24,7 @@ "Accounts_OAuth_Twitter" : "Twitter-tunnus", "Accounts_OAuth_Twitter_id" : "Twitter ID", "Accounts_OAuth_Twitter_secret" : "Twitter salalauseke", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token polku", "Accounts_OAuth_Custom_Identity_Path" : "Identity polku", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 10f63686a41..0e1fd72041a 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -24,7 +24,7 @@ "Accounts_OAuth_Twitter" : "Connexion avec Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "URL de Token", "Accounts_OAuth_Custom_Identity_Path" : "URL d'identification", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index fdb57430a46..9dd7bb03119 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -24,7 +24,7 @@ "Accounts_OAuth_Twitter" : "ចូលážáž¶áž˜ Twitter", "Accounts_OAuth_Twitter_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Twitter", "Accounts_OAuth_Twitter_secret" : "Twitter សម្ងាážáŸ‹", - "Accounts_OAuth_Custom_ID" : "áž›áŸážážŸáž˜áŸ’គាល់", + "Accounts_OAuth_Custom_id" : "áž›áŸážážŸáž˜áŸ’គាល់", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "ទីទាំង Token", "Accounts_OAuth_Custom_Identity_Path" : "ទីទាំងអážáŸ’ážážŸáž‰áŸ’ញាណ", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index 0b4fd4e5822..85a6d7c5457 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -24,7 +24,7 @@ "Accounts_OAuth_Twitter" : "트위터 로그ì¸", "Accounts_OAuth_Twitter_id" : "트위터 ID", "Accounts_OAuth_Twitter_secret" : "트위터 암호", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token 경로", "Accounts_OAuth_Custom_Identity_Path" : "Identity 경로", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 0ac68139706..95a53fe73d4 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -24,7 +24,7 @@ "Accounts_OAuth_Twitter" : "Daftar masuk Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 54a3906fc7d..483fed38619 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -25,7 +25,7 @@ "Accounts_OAuth_Twitter" : "Login do Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_ID" : "ID", + "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", diff --git a/packages/rocketchat-lib/settings/server/addOAuthService.coffee b/packages/rocketchat-lib/settings/server/addOAuthService.coffee index 67e28cb50e7..9ce3c9ca140 100644 --- a/packages/rocketchat-lib/settings/server/addOAuthService.coffee +++ b/packages/rocketchat-lib/settings/server/addOAuthService.coffee @@ -15,7 +15,7 @@ Meteor.methods RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_token_path" , '/oauth/token' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Token_Path'} RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_identity_path" , '/me' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Identity_Path'} 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'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_id" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_ID'} + RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_id" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_id'} RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_secret" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Secret'} 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'} 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'} -- GitLab From bca5eb5e9babe6634abce7a1322edae101062402 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 22 Oct 2015 18:16:26 +0200 Subject: [PATCH 0216/1338] option to configure routes by room type --- client/startup/defaultRoomTypes.coffee | 17 ++++++-- client/views/app/sideNav/chatRoomItem.coffee | 8 +--- client/views/app/sideNav/sideNav.coffee | 2 +- .../client/lib/roomTypes.coffee | 40 +++++++++++++++++-- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 4cf021b41f7..7287542d82a 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,5 +1,14 @@ Meteor.startup -> - RocketChat.roomTypes.add('starredRooms', 'user'); - RocketChat.roomTypes.add('channels', 'user'); - RocketChat.roomTypes.add('directMessages', 'user'); - RocketChat.roomTypes.add('privateGroups', 'user'); + RocketChat.roomTypes.addType('starredRooms', 'user'); + RocketChat.roomTypes.addType('channels', 'user'); + RocketChat.roomTypes.addType('directMessages', 'user'); + RocketChat.roomTypes.addType('privateGroups', 'user'); + + RocketChat.roomTypes.setRoute 'c', 'channel', (sub) -> + return { name: sub.name } + + RocketChat.roomTypes.setRoute 'd', 'direct', (sub) -> + return { username: sub.name } + + RocketChat.roomTypes.setRoute 'p', 'group', (sub) -> + return { name: sub.name } diff --git a/client/views/app/sideNav/chatRoomItem.coffee b/client/views/app/sideNav/chatRoomItem.coffee index 4209004733a..dc25a452a24 100644 --- a/client/views/app/sideNav/chatRoomItem.coffee +++ b/client/views/app/sideNav/chatRoomItem.coffee @@ -39,13 +39,7 @@ Template.chatRoomItem.helpers return true route: -> - return switch this.t - when 'd' - FlowRouter.path('direct', {username: this.name}) - when 'p' - FlowRouter.path('group', {name: this.name}) - when 'c' - FlowRouter.path('channel', {name: this.name}) + FlowRouter.path RocketChat.roomTypes.getRoute @t, @ Template.chatRoomItem.rendered = -> if not (FlowRouter.getParam('_id')? and FlowRouter.getParam('_id') is this.data.rid) and not this.data.ls diff --git a/client/views/app/sideNav/sideNav.coffee b/client/views/app/sideNav/sideNav.coffee index 17b43e967cc..49a02a7f80a 100644 --- a/client/views/app/sideNav/sideNav.coffee +++ b/client/views/app/sideNav/sideNav.coffee @@ -95,6 +95,6 @@ Template.sideNav.onRendered -> wrapper = $('.rooms-list .wrapper').get(0) lastLink = $('.rooms-list h3').get(0) - RocketChat.roomTypes.get().forEach (roomType) -> + RocketChat.roomTypes.getTypes().forEach (roomType) -> if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? Blaze.render Template[roomType.template], wrapper, lastLink diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index 9ff0a2ae143..af7d6c939f2 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -1,13 +1,45 @@ RocketChat.roomTypes = new class rooms = [] + routes = {} - add = (template, roles = []) -> + ### Sets a route for a room type + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param routeName: route's name for given type + @param dataCallback: callback for the route data. receives the whole subscription data as parameter + ### + setRoute = (roomType, routeName, dataCallback) -> + if routes[roomType]? + throw new Meteor.Error 'route-callback-exists', 'Route callback for the given type already exists' + + # dataCallback ?= -> return {} + + routes[roomType] = + name: routeName + data: dataCallback or -> return {} + + ### + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param subData: the user's subscription data + ### + getRoute = (roomType, subData) -> + unless routes[roomType]? + throw new Meteor.Error 'route-doesnt-exists', 'There is no route for the type: ' + roomType + + return FlowRouter.path routes[roomType].name, routes[roomType].data(subData) + + ### add a type of room + @param template: the name of the template to render on sideNav + @param roles[]: a list of roles a user must have to see the template + ### + addType = (template, roles = []) -> rooms.push template: template roles: [].concat roles - getAll = -> + getAllTypes = -> return rooms - add: add - get: getAll + addType: addType + getTypes: getAllTypes + setRoute: setRoute + getRoute: getRoute -- GitLab From e4241503784ea3fb3714c40976208641677b6be5 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 22 Oct 2015 18:21:34 +0200 Subject: [PATCH 0217/1338] Accounts_OAuth_ManuallyApproveNewUsers -> Accounts_ManuallyApproveNewUsers --- i18n/de.i18n.json | 2 +- i18n/el.i18n.json | 4 ++-- i18n/fi.i18n.json | 2 +- i18n/fr.i18n.json | 2 +- i18n/hr.i18n.json | 4 ++-- i18n/km.i18n.json | 2 +- i18n/ko.i18n.json | 2 +- i18n/ms-MY.i18n.json | 2 +- i18n/pt.i18n.json | 2 +- i18n/tr.i18n.json | 4 ++-- i18n/zh.i18n.json | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 57a3a757b4d..70ad680792d 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -16,7 +16,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Login", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "Linkeding Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", + "Accounts_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 4009ef6b07d..80b7bed9aeb 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -15,7 +15,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Login", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "ΧειÏοκίνητη ÎγκÏιση νÎων χÏηστών", + "Accounts_ManuallyApproveNewUsers" : "ΧειÏοκίνητη ÎγκÏιση νÎων χÏηστών", "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", @@ -285,4 +285,4 @@ "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/fi.i18n.json b/i18n/fi.i18n.json index bcf547b9920..c850370145c 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -16,7 +16,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn-tunnus", "Accounts_OAuth_Linkedin_id" : "LinkedIn ID", "Accounts_OAuth_Linkedin_secret" : "LinkedIn salalauseke", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", + "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", "Accounts_OAuth_Meteor" : "Meteor-tunnus", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor salalauseke", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 0e1fd72041a..68b7a2aa8f5 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -16,7 +16,7 @@ "Accounts_OAuth_Linkedin" : "Connexion avec LinkedIn", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Approuver manuellement les nouveaux utilisateurs", + "Accounts_ManuallyApproveNewUsers" : "Approuver manuellement les nouveaux utilisateurs", "Accounts_OAuth_Meteor" : "Connexion avec Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Id", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 788c918946c..82703c727fe 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -8,7 +8,7 @@ "Accounts_OAuth_Github" : "GitHub Prijava", "Accounts_OAuth_Google" : "Google Prijava", "Accounts_OAuth_Linkedin" : "LinkedIn Prijava", - "Accounts_OAuth_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", + "Accounts_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", "Accounts_OAuth_Meteor" : "Meteor Prijava", "Accounts_OAuth_RegistrationRequired" : "Potrebna je registracija", "Accounts_OAuth_Twitter" : "Twitter Prijava", @@ -314,4 +314,4 @@ "You_will_not_be_able_to_recover" : "Ovo nećeÅ¡ moći promijeniti!", "Your_entry_has_been_deleted" : "Tvoj unos je obrisan.", "Your_Open_Source_solution" : "VaÅ¡e vlastito Open Source chat rjeÅ¡enje" -} \ No newline at end of file +} diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 9dd7bb03119..206a9ef06b3 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -16,7 +16,7 @@ "Accounts_OAuth_Linkedin" : "ចូល​ážáž¶áž˜â€‹ LinkedIn", "Accounts_OAuth_Linkedin_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់​ LinkedIn", "Accounts_OAuth_Linkedin_secret" : "LinkedIn សម្ងាážáŸ‹", - "Accounts_OAuth_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", + "Accounts_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", "Accounts_OAuth_Meteor" : "ចូល​ážáž¶áž˜ Meteor", "Accounts_OAuth_Meteor_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ Meteor ", "Accounts_OAuth_Meteor_secret" : "Meteor សម្ងាážáŸ‹", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index 85a6d7c5457..e5af71ddd29 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -16,7 +16,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn 로그ì¸", "Accounts_OAuth_Linkedin_id" : "LinkedIn ID", "Accounts_OAuth_Linkedin_secret" : "LinkedIn 암호", - "Accounts_OAuth_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", + "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", "Accounts_OAuth_Meteor" : "Meteor 로그ì¸", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor 암호", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 95a53fe73d4..029bb528c8d 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -16,7 +16,7 @@ "Accounts_OAuth_Linkedin" : "Daftar masuk LinkedIn", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", + "Accounts_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", "Accounts_OAuth_Meteor" : "Daftar masuk Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 483fed38619..a29b74ccfe1 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -17,7 +17,7 @@ "Accounts_OAuth_Linkedin" : "Login do LinkedIn", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", + "Accounts_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", "Accounts_OAuth_Meteor" : "Login do Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 747ac0c1881..33aa7506190 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -6,7 +6,7 @@ "Accounts_OAuth_Github" : "GitHub ile giriÅŸ", "Accounts_OAuth_Google" : "Google ile giriÅŸ", "Accounts_OAuth_Linkedin" : "LinkedIn ile giriÅŸ", - "Accounts_OAuth_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", + "Accounts_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", "Accounts_OAuth_Meteor" : "Meteor ile giriÅŸ", "Accounts_OAuth_RegistrationRequired" : "Kayıt Gerekli", "Accounts_OAuth_Twitter" : "Twitter ile giriÅŸ", @@ -261,4 +261,4 @@ "You_will_not_be_able_to_recover" : "Sen kurtarmak mümkün olmayacaktır!", "Your_entry_has_been_deleted" : "Sizin kaydınız silindi.", "Your_Open_Source_solution" : "Açık Kaynak Sohbet Uygulaması" -} \ No newline at end of file +} diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index b5799225943..303f578c3b0 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -7,7 +7,7 @@ "Accounts_OAuth_Facebook" : "Facebook 登入", "Accounts_OAuth_Facebook_id" : "Facebook应用程åºID", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", - "Accounts_OAuth_ManuallyApproveNewUsers" : "æ‰‹åŠ¨å®¡æ ¸æ–°ç”¨æˆ·", + "Accounts_ManuallyApproveNewUsers" : "æ‰‹åŠ¨å®¡æ ¸æ–°ç”¨æˆ·", "Accounts_OAuth_RegistrationRequired" : "需è¦æ³¨å†Œ", "Activate" : "激活", "Add_Members" : "åŠ å…¥æˆå‘˜", -- GitLab From 86af1a5175bc996df9b021307ef9a30b433de5b9 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 22 Oct 2015 18:23:18 +0200 Subject: [PATCH 0218/1338] Accounts_OAuth_RegistrationRequired -> Accounts_RegistrationRequired --- i18n/de.i18n.json | 2 +- i18n/el.i18n.json | 2 +- i18n/fi.i18n.json | 2 +- i18n/fr.i18n.json | 2 +- i18n/hr.i18n.json | 2 +- i18n/km.i18n.json | 2 +- i18n/ko.i18n.json | 2 +- i18n/ms-MY.i18n.json | 2 +- i18n/pl.i18n.json | 4 ++-- i18n/pt.i18n.json | 2 +- i18n/ru.i18n.json | 4 ++-- i18n/tr.i18n.json | 2 +- i18n/zh.i18n.json | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 70ad680792d..17516e5b7bb 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -20,7 +20,7 @@ "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_RegistrationRequired" : "Anmeldung erforderlich", + "Accounts_RegistrationRequired" : "Anmeldung erforderlich", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 80b7bed9aeb..9d7100638c7 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -19,7 +19,7 @@ "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_RegistrationRequired" : "Απαιτείται ΕγγÏαφή", + "Accounts_RegistrationRequired" : "Απαιτείται ΕγγÏαφή", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index c850370145c..89fc9b37322 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -20,7 +20,7 @@ "Accounts_OAuth_Meteor" : "Meteor-tunnus", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor salalauseke", - "Accounts_OAuth_RegistrationRequired" : "Rekisteröinti vaaditaan", + "Accounts_RegistrationRequired" : "Rekisteröinti vaaditaan", "Accounts_OAuth_Twitter" : "Twitter-tunnus", "Accounts_OAuth_Twitter_id" : "Twitter ID", "Accounts_OAuth_Twitter_secret" : "Twitter salalauseke", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 68b7a2aa8f5..e398e6822bb 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -20,7 +20,7 @@ "Accounts_OAuth_Meteor" : "Connexion avec Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Id", - "Accounts_OAuth_RegistrationRequired" : "Enregistrement nécessaire", + "Accounts_RegistrationRequired" : "Enregistrement nécessaire", "Accounts_OAuth_Twitter" : "Connexion avec Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 82703c727fe..e7f5b2e0fb5 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -10,7 +10,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Prijava", "Accounts_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", "Accounts_OAuth_Meteor" : "Meteor Prijava", - "Accounts_OAuth_RegistrationRequired" : "Potrebna je registracija", + "Accounts_RegistrationRequired" : "Potrebna je registracija", "Accounts_OAuth_Twitter" : "Twitter Prijava", "Accounts_OAuth_Custom_Secret" : "Tajno", "Accounts_OAuth_Custom_Enable" : "Omogući", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 206a9ef06b3..4a1e291f92f 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -20,7 +20,7 @@ "Accounts_OAuth_Meteor" : "ចូល​ážáž¶áž˜ Meteor", "Accounts_OAuth_Meteor_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ Meteor ", "Accounts_OAuth_Meteor_secret" : "Meteor សម្ងាážáŸ‹", - "Accounts_OAuth_RegistrationRequired" : "ážáŸ’រូវ​ចុះ​ឈ្មោះ", + "Accounts_RegistrationRequired" : "ážáŸ’រូវ​ចុះ​ឈ្មោះ", "Accounts_OAuth_Twitter" : "ចូលážáž¶áž˜ Twitter", "Accounts_OAuth_Twitter_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Twitter", "Accounts_OAuth_Twitter_secret" : "Twitter សម្ងាážáŸ‹", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index e5af71ddd29..d5e67537b76 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -20,7 +20,7 @@ "Accounts_OAuth_Meteor" : "Meteor 로그ì¸", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor 암호", - "Accounts_OAuth_RegistrationRequired" : "등ë¡ì‹œ 필수", + "Accounts_RegistrationRequired" : "등ë¡ì‹œ 필수", "Accounts_OAuth_Twitter" : "트위터 로그ì¸", "Accounts_OAuth_Twitter_id" : "트위터 ID", "Accounts_OAuth_Twitter_secret" : "트위터 암호", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 029bb528c8d..7e341bb83c8 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -20,7 +20,7 @@ "Accounts_OAuth_Meteor" : "Daftar masuk Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_RegistrationRequired" : "Pendaftaran diperlukan", + "Accounts_RegistrationRequired" : "Pendaftaran diperlukan", "Accounts_OAuth_Twitter" : "Daftar masuk Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 253c5b7c722..d41fbc56149 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -14,7 +14,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Login", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_OAuth_RegistrationRequired" : "Wymagana rejestracja", + "Accounts_RegistrationRequired" : "Wymagana rejestracja", "Activate" : "Aktywować", "Add_Members" : "Dodaj czÅ‚onków", "Add_users" : "Dodaj użytkowników", @@ -252,4 +252,4 @@ "You_will_not_be_able_to_recover" : "Nie bÄ™dziesz w stanie odzyskać!", "Your_entry_has_been_deleted" : "Twój wpis zostaÅ‚ usuniÄ™ty.", "Your_Open_Source_solution" : "Twój wÅ‚asny czat Open Source" -} \ No newline at end of file +} diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index a29b74ccfe1..a11c4b4b6b4 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -21,7 +21,7 @@ "Accounts_OAuth_Meteor" : "Login do Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_RegistrationRequired" : "Registro Obrigatório", + "Accounts_RegistrationRequired" : "Registro Obrigatório", "Accounts_OAuth_Twitter" : "Login do Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index db0f983b81e..4ad9a465bbc 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -5,7 +5,7 @@ "Accounts_OAuth_Google" : "Google логин", "Accounts_OAuth_Google_id" : "Google ID", "Accounts_OAuth_Google_secret" : "Google пароль", - "Accounts_OAuth_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", + "Accounts_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", "Add_Members" : "Добавить Пользователей", "Add_users" : "Добавить пользователей", "All_channels" : "Ð’Ñе Чаты", @@ -235,4 +235,4 @@ "You_need_confirm_email" : "Ðеобходимо подтвердить email Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°!", "You_will_not_be_able_to_recover" : "Ð’Ñ‹ не Ñможете воÑÑтановить!", "Your_Open_Source_solution" : "Ваш ÑобÑтвенный чат на базе Open Source-технологий" -} \ No newline at end of file +} diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 33aa7506190..1efced40d75 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -8,7 +8,7 @@ "Accounts_OAuth_Linkedin" : "LinkedIn ile giriÅŸ", "Accounts_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", "Accounts_OAuth_Meteor" : "Meteor ile giriÅŸ", - "Accounts_OAuth_RegistrationRequired" : "Kayıt Gerekli", + "Accounts_RegistrationRequired" : "Kayıt Gerekli", "Accounts_OAuth_Twitter" : "Twitter ile giriÅŸ", "Add_Members" : "Ãœye ekle", "Add_users" : "Kullanıcı ekle", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index 303f578c3b0..fe0a91099c5 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -8,7 +8,7 @@ "Accounts_OAuth_Facebook_id" : "Facebook应用程åºID", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", "Accounts_ManuallyApproveNewUsers" : "æ‰‹åŠ¨å®¡æ ¸æ–°ç”¨æˆ·", - "Accounts_OAuth_RegistrationRequired" : "需è¦æ³¨å†Œ", + "Accounts_RegistrationRequired" : "需è¦æ³¨å†Œ", "Activate" : "激活", "Add_Members" : "åŠ å…¥æˆå‘˜", "Add_users" : "æ·»åŠ ç”¨æˆ·", -- GitLab From 83d17790d74ae9044f1d8a2f19f01f3129f41cbc Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 22 Oct 2015 16:25:17 +0000 Subject: [PATCH 0219/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/de.i18n.json | 8 ++++++-- i18n/el.i18n.json | 7 +++++-- i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 8 ++++++-- i18n/fr.i18n.json | 8 ++++++-- i18n/hr.i18n.json | 5 +++-- i18n/km.i18n.json | 8 ++++++-- i18n/ko.i18n.json | 8 ++++++-- i18n/ms-MY.i18n.json | 7 +++++-- i18n/pl.i18n.json | 5 ++++- i18n/pt.i18n.json | 8 ++++++-- i18n/ru.i18n.json | 5 ++++- i18n/tr.i18n.json | 6 ++++-- i18n/zh.i18n.json | 5 ++++- packages/rocketchat-chatops/i18n/en.i18n.json | 6 +++--- packages/rocketchat-github-enterprise/i18n/en.i18n.json | 2 +- packages/rocketchat-livechat/i18n/en.i18n.json | 2 +- packages/rocketchat-webrtc/i18n/ar.i18n.json | 1 + packages/rocketchat-webrtc/i18n/de.i18n.json | 1 + packages/rocketchat-webrtc/i18n/el.i18n.json | 1 + packages/rocketchat-webrtc/i18n/en.i18n.json | 2 +- packages/rocketchat-webrtc/i18n/es.i18n.json | 1 + packages/rocketchat-webrtc/i18n/fi.i18n.json | 1 + packages/rocketchat-webrtc/i18n/fr.i18n.json | 1 + packages/rocketchat-webrtc/i18n/he.i18n.json | 1 + packages/rocketchat-webrtc/i18n/hr.i18n.json | 1 + packages/rocketchat-webrtc/i18n/hu.i18n.json | 1 + packages/rocketchat-webrtc/i18n/it.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ja.i18n.json | 1 + packages/rocketchat-webrtc/i18n/km.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ko.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ms-MY.i18n.json | 1 + packages/rocketchat-webrtc/i18n/pl.i18n.json | 1 + packages/rocketchat-webrtc/i18n/pt.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ru.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-webrtc/i18n/tr.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ug.i18n.json | 1 + packages/rocketchat-webrtc/i18n/uk.i18n.json | 1 + packages/rocketchat-webrtc/i18n/zh.i18n.json | 1 + packages/rocketchat-wordpress/i18n/en.i18n.json | 2 +- 41 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 packages/rocketchat-webrtc/i18n/ar.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/de.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/el.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/es.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/fi.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/fr.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/he.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/hr.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/hu.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/it.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ja.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/km.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ko.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/pl.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/pt.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ru.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/tr.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ug.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/uk.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/zh.i18n.json diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 17516e5b7bb..f970e861837 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -16,10 +16,10 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Login", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "Linkeding Secret", - "Accounts_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", "Accounts_RegistrationRequired" : "Anmeldung erforderlich", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", @@ -166,6 +166,9 @@ "Layout_Sidenav_Footer_description" : "Die Footer Größe ist 260x70", "Layout_Terms_of_Service" : "Nutzungsbedingungen", "LDAP" : "LDAP", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Raum verlassen", "line" : "Zeilen", "Load_more" : "Mehr laden", @@ -191,6 +194,7 @@ "Message_editing_blocked" : "Diese Nachricht kann nicht mehr bearbeitet werden", "Message_MaxAllowedSize" : "Maximale Größe der Nachricht", "Message_pinning_not_allowed" : "Nachrichten anheften erlaubt", + "Message_AllowPinning" : "Erlaube es Nachrichten anzuheften", "Message_KeepHistory" : "Nachrichtenverlauf behalten", "Message_removed" : "Nachricht entfernt", "Message_pinned" : "Nachricht angeheftet", @@ -396,4 +400,4 @@ "You_will_not_be_able_to_recover" : "Sie können es nicht wieder rückgängig machen!", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", "Your_Open_Source_solution" : "Deine eigene Open Source Chat Lösung" -} +} \ No newline at end of file diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 9d7100638c7..786250d24c3 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -15,10 +15,10 @@ "Accounts_OAuth_Linkedin" : "LinkedIn Login", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_ManuallyApproveNewUsers" : "ΧειÏοκίνητη ÎγκÏιση νÎων χÏηστών", "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_ManuallyApproveNewUsers" : "ΧειÏοκίνητη ÎγκÏιση νÎων χÏηστών", "Accounts_RegistrationRequired" : "Απαιτείται ΕγγÏαφή", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", @@ -111,6 +111,9 @@ "Last_message" : "Τελευταίο μήνυμα", "Layout_Home_Body" : "ΑÏχική Σώμα", "Layout_Home_Title" : "ΑÏχική Τίτλος", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "LDAP ΘÏÏα", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Έξοδος από το δωμάτιο", "line" : "γÏαμμÎÏ‚", "Load_more" : "ΦόÏτωση πεÏισσότεÏων", @@ -285,4 +288,4 @@ "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/en.i18n.json b/i18n/en.i18n.json index cea7643e59b..e3523d57cd7 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -426,4 +426,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 89fc9b37322..62795415271 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -16,10 +16,10 @@ "Accounts_OAuth_Linkedin" : "LinkedIn-tunnus", "Accounts_OAuth_Linkedin_id" : "LinkedIn ID", "Accounts_OAuth_Linkedin_secret" : "LinkedIn salalauseke", - "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", "Accounts_OAuth_Meteor" : "Meteor-tunnus", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor salalauseke", + "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", "Accounts_RegistrationRequired" : "Rekisteröinti vaaditaan", "Accounts_OAuth_Twitter" : "Twitter-tunnus", "Accounts_OAuth_Twitter_id" : "Twitter ID", @@ -156,6 +156,9 @@ "Layout_Sidenav_Footer_description" : "Alatunnisteen koko on 260x70", "Layout_Terms_of_Service" : "Käyttöehdot", "LDAP" : "LDAP", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "LDAP portti", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Poistu kanavalta", "line" : "viiva", "Load_more" : "Lataa lisää", @@ -180,6 +183,7 @@ "Message_editing_blocked" : "Tätä viestiä ei voi muokata enää.", "Message_MaxAllowedSize" : "Viestin suurin sallittu koko", "Message_pinning_not_allowed" : "Viestien kiinnittäminen ei sallittu", + "Message_AllowPinning" : "Salli viestien kiinnittäminen", "Message_KeepHistory" : "Säilytä viestihistoria", "Message_removed" : "Viesti poistettu\n", "Message_pinned" : "Viesti kiinnitetty", @@ -381,4 +385,4 @@ "You_will_not_be_able_to_recover" : "Palauttaminen ei ole mahdollista!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", "Your_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index e398e6822bb..29399fc7c90 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -16,10 +16,10 @@ "Accounts_OAuth_Linkedin" : "Connexion avec LinkedIn", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_ManuallyApproveNewUsers" : "Approuver manuellement les nouveaux utilisateurs", "Accounts_OAuth_Meteor" : "Connexion avec Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Id", + "Accounts_ManuallyApproveNewUsers" : "Approuver manuellement les nouveaux utilisateurs", "Accounts_RegistrationRequired" : "Enregistrement nécessaire", "Accounts_OAuth_Twitter" : "Connexion avec Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", @@ -160,6 +160,9 @@ "Layout_Sidenav_Footer_description" : "La taille du pied de page est 260x70", "Layout_Terms_of_Service" : "Conditions de service", "LDAP" : "LDAP", + "LDAP_Dn" : "DN LDAP", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "Adresse LDAP", "Leave_room" : "Quitter le salon", "line" : "ligne", "Load_more" : "Charger plus", @@ -184,6 +187,7 @@ "Message_editing_blocked" : "Ce message ne peut plus être modifié", "Message_MaxAllowedSize" : "Taille maximum de message autorisée", "Message_pinning_not_allowed" : "L'épinglement de message n'est pas autorisé", + "Message_AllowPinning" : "Autoriser l'épinglement de messages", "Message_KeepHistory" : "Conserver l'historique des messages", "Message_removed" : "Message supprimé", "Message_pinned" : "Message épinglé", @@ -386,4 +390,4 @@ "You_will_not_be_able_to_recover" : "Cette action n'est pas réversible !", "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/hr.i18n.json b/i18n/hr.i18n.json index e7f5b2e0fb5..c323f9c37d8 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -8,8 +8,8 @@ "Accounts_OAuth_Github" : "GitHub Prijava", "Accounts_OAuth_Google" : "Google Prijava", "Accounts_OAuth_Linkedin" : "LinkedIn Prijava", - "Accounts_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", "Accounts_OAuth_Meteor" : "Meteor Prijava", + "Accounts_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", "Accounts_RegistrationRequired" : "Potrebna je registracija", "Accounts_OAuth_Twitter" : "Twitter Prijava", "Accounts_OAuth_Custom_Secret" : "Tajno", @@ -142,6 +142,7 @@ "Message_editing_blocked" : "Ova poruka se viÅ¡e ne može ureÄ‘ivati ", "Message_MaxAllowedSize" : "Maksimalna dopuÅ¡tena veliÄina poruke", "Message_pinning_not_allowed" : "Pribadanje poruka nije dopuÅ¡teno", + "Message_AllowPinning" : "Dopusti pribadanje poruka ", "Message_KeepHistory" : "Zadrži Povijest Poruka", "Message_removed" : "Poruka je maknuta", "Message_pinned" : "Poruka je pribodena", @@ -314,4 +315,4 @@ "You_will_not_be_able_to_recover" : "Ovo nećeÅ¡ moći promijeniti!", "Your_entry_has_been_deleted" : "Tvoj unos je obrisan.", "Your_Open_Source_solution" : "VaÅ¡e vlastito Open Source chat rjeÅ¡enje" -} +} \ No newline at end of file diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 4a1e291f92f..a8734d20cf2 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -16,10 +16,10 @@ "Accounts_OAuth_Linkedin" : "ចូល​ážáž¶áž˜â€‹ LinkedIn", "Accounts_OAuth_Linkedin_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់​ LinkedIn", "Accounts_OAuth_Linkedin_secret" : "LinkedIn សម្ងាážáŸ‹", - "Accounts_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", "Accounts_OAuth_Meteor" : "ចូល​ážáž¶áž˜ Meteor", "Accounts_OAuth_Meteor_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ Meteor ", "Accounts_OAuth_Meteor_secret" : "Meteor សម្ងាážáŸ‹", + "Accounts_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", "Accounts_RegistrationRequired" : "ážáŸ’រូវ​ចុះ​ឈ្មោះ", "Accounts_OAuth_Twitter" : "ចូលážáž¶áž˜ Twitter", "Accounts_OAuth_Twitter_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Twitter", @@ -168,6 +168,9 @@ "Layout_Sidenav_Footer_description" : "​ទំហំ​បាន​គឺ 260x70", "Layout_Terms_of_Service" : "áž›áŸáž€áŸ’ážážáŸážŽáŸ’ឌ​នៃ​សáŸážœáž¶áž€áž˜áŸ’ម", "LDAP" : "ប្រើ LDAP", + "LDAP_Dn" : " LDAP DN", + "LDAP_Port" : "ច្រក LDAP", + "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", "Load_more" : "មើល​ទៀáž", @@ -193,6 +196,7 @@ "Message_editing_blocked" : "សារ​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ážáŸ’រូវ​បាន​កែប្រែ​ទៀážâ€‹áž‘áŸ", "Message_MaxAllowedSize" : "ទំហំអážáž·áž”រមាដែលážáŸ’រូវបានអនុញ្ញាážážŸáž¶ážš", "Message_pinning_not_allowed" : "ការážáŸ’ទាស់​សារ​មិន​អនុញ្ញាážáž·â€‹", + "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​", "Message_KeepHistory" : "រក្សា​​ប្រវážáŸ’ážáž·â€‹ážŸáž¶ážš", "Message_removed" : "សារ​បាន​លប់", "Message_pinned" : "សារ\n", @@ -397,4 +401,4 @@ "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/ko.i18n.json b/i18n/ko.i18n.json index d5e67537b76..ddf0e3c0873 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -16,10 +16,10 @@ "Accounts_OAuth_Linkedin" : "LinkedIn 로그ì¸", "Accounts_OAuth_Linkedin_id" : "LinkedIn ID", "Accounts_OAuth_Linkedin_secret" : "LinkedIn 암호", - "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", "Accounts_OAuth_Meteor" : "Meteor 로그ì¸", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor 암호", + "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", "Accounts_RegistrationRequired" : "등ë¡ì‹œ 필수", "Accounts_OAuth_Twitter" : "트위터 로그ì¸", "Accounts_OAuth_Twitter_id" : "트위터 ID", @@ -153,6 +153,9 @@ "Layout_Sidenav_Footer_description" : "바닥글 í¬ê¸°ëŠ” 260x70입니다.", "Layout_Terms_of_Service" : "ì´ìš©ì•½ê´€", "LDAP" : "LDAP", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "LDAP í¬íŠ¸", + "LDAP_Url" : "LDAP URL", "Leave_room" : "ë°© 나가기", "line" : "밑줄", "Load_more" : "ë” ë³´ê¸°", @@ -177,6 +180,7 @@ "Message_editing_blocked" : "메시지를 ë” ì´ìƒ ìˆ˜ì •í• ìˆ˜ 없습니다.", "Message_MaxAllowedSize" : "메시지 최대 허용 í¬ê¸°", "Message_pinning_not_allowed" : "메시지를 ê³ ì •í• ìˆ˜ 없습니다.", + "Message_AllowPinning" : "허용 메시지 ê³ ì •", "Message_KeepHistory" : "메시지 기ë¡ì„ ìœ ì§€", "Message_removed" : "메시지 ì œê±°", "Message_pinned" : "메시지가 ê³ ì •ë˜ì—ˆìŠµë‹ˆë‹¤.", @@ -374,4 +378,4 @@ "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/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 7e341bb83c8..733b93e7088 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -16,10 +16,10 @@ "Accounts_OAuth_Linkedin" : "Daftar masuk LinkedIn", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", "Accounts_OAuth_Meteor" : "Daftar masuk Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", "Accounts_RegistrationRequired" : "Pendaftaran diperlukan", "Accounts_OAuth_Twitter" : "Daftar masuk Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", @@ -147,6 +147,9 @@ "Layout_Sidenav_Footer_description" : "Saiz footer ialah 260x70", "Layout_Terms_of_Service" : "Terma Perkhidmatan", "LDAP" : "LDAP", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "URL LDAP", "Leave_room" : "Meninggalkan bilik", "line" : "garis", "Load_more" : "Memuat lagi", @@ -365,4 +368,4 @@ "You_need_confirm_email" : "Anda perlu mengesahkan e-mel anda untuk melog masuk!", "You_will_not_be_able_to_recover" : "Anda tidak boleh membaik pulih.", "Your_entry_has_been_deleted" : "Entri anda telah dipadam." -} +} \ No newline at end of file diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index d41fbc56149..182c08aa265 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -106,6 +106,9 @@ "Last_message" : "Ostatnia wiadomość", "Layout_Home_Body" : "Treść strony głównej", "Layout_Home_Title" : "TytuÅ‚ strony głównej", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "Adres URL LDAP", "Leave_room" : "Opuść pokój", "line" : "linia", "Load_more" : "WiÄ™cej", @@ -252,4 +255,4 @@ "You_will_not_be_able_to_recover" : "Nie bÄ™dziesz w stanie odzyskać!", "Your_entry_has_been_deleted" : "Twój wpis zostaÅ‚ usuniÄ™ty.", "Your_Open_Source_solution" : "Twój wÅ‚asny czat Open Source" -} +} \ No newline at end of file diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index a11c4b4b6b4..a3008e91087 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -17,10 +17,10 @@ "Accounts_OAuth_Linkedin" : "Login do LinkedIn", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", "Accounts_OAuth_Meteor" : "Login do Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", "Accounts_RegistrationRequired" : "Registro Obrigatório", "Accounts_OAuth_Twitter" : "Login do Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", @@ -169,6 +169,9 @@ "Layout_Sidenav_Footer_description" : "Tamanho do rodapé é 260x70", "Layout_Terms_of_Service" : "Termos de Serviço", "LDAP" : "LDAP", + "LDAP_Dn" : "DN LDAP", + "LDAP_Port" : "Porta LDAP", + "LDAP_Url" : "URL LDAP", "Leave_room" : "Sair da sala", "line" : "linha", "Load_more" : "Carregar mais", @@ -194,6 +197,7 @@ "Message_editing_blocked" : "Esta mensagem não pode mais ser editada", "Message_MaxAllowedSize" : "Tamanho máximo de mensagem permitido ", "Message_pinning_not_allowed" : "Não Permitir Fixar Mensagem", + "Message_AllowPinning" : "Permitir Fixar Mensagem", "Message_KeepHistory" : "Manter Histórico de Mensagens", "Message_removed" : "Mensagem removida", "Message_pinned" : "Mensagem fixada", @@ -400,4 +404,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} +} \ No newline at end of file diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 4ad9a465bbc..f0f14796ac3 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -83,6 +83,9 @@ "Language" : "Язык", "Language_Version" : "РуÑÑÐºÐ°Ñ Ð²ÐµÑ€ÑиÑ", "Last_message" : "ПоÑледнее Ñообщение", + "LDAP_Dn" : "LDAP домен", + "LDAP_Port" : "LDAP Порт", + "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Leave_room" : "Покинуть чат", "line" : "линиÑ", "Load_more" : "Загрузить еще", @@ -235,4 +238,4 @@ "You_need_confirm_email" : "Ðеобходимо подтвердить email Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°!", "You_will_not_be_able_to_recover" : "Ð’Ñ‹ не Ñможете воÑÑтановить!", "Your_Open_Source_solution" : "Ваш ÑобÑтвенный чат на базе Open Source-технологий" -} +} \ No newline at end of file diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 1efced40d75..345683fceeb 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -6,8 +6,8 @@ "Accounts_OAuth_Github" : "GitHub ile giriÅŸ", "Accounts_OAuth_Google" : "Google ile giriÅŸ", "Accounts_OAuth_Linkedin" : "LinkedIn ile giriÅŸ", - "Accounts_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", "Accounts_OAuth_Meteor" : "Meteor ile giriÅŸ", + "Accounts_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", "Accounts_RegistrationRequired" : "Kayıt Gerekli", "Accounts_OAuth_Twitter" : "Twitter ile giriÅŸ", "Add_Members" : "Ãœye ekle", @@ -95,6 +95,8 @@ "Last_login" : "Son giriÅŸ", "Last_message" : "Son mesaj", "Layout_Home_Title" : "Anasayfa baÅŸlığı", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Odayı terket", "line" : "satır", "Load_more" : "Daha fazla", @@ -261,4 +263,4 @@ "You_will_not_be_able_to_recover" : "Sen kurtarmak mümkün olmayacaktır!", "Your_entry_has_been_deleted" : "Sizin kaydınız silindi.", "Your_Open_Source_solution" : "Açık Kaynak Sohbet Uygulaması" -} +} \ No newline at end of file diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index fe0a91099c5..8b169063f15 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -121,6 +121,9 @@ "Layout_Sidenav_Footer" : "侧é¢å¯¼èˆªé¡µè„š", "Layout_Terms_of_Service" : "æœåŠ¡æ¡æ¬¾", "LDAP" : "LDAP", + "LDAP_Dn" : "LDAP DN", + "LDAP_Port" : "LDAP端å£", + "LDAP_Url" : "LDAP URL", "Leave_room" : "离开èŠå¤©å®¤", "Load_more" : "åŠ è½½æ›´å¤š", "Loading_more_from_history" : "åŠ è½½æ›´å¤š", @@ -316,4 +319,4 @@ "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/packages/rocketchat-chatops/i18n/en.i18n.json b/packages/rocketchat-chatops/i18n/en.i18n.json index 5d08d92bccd..964a72c4ee0 100644 --- a/packages/rocketchat-chatops/i18n/en.i18n.json +++ b/packages/rocketchat-chatops/i18n/en.i18n.json @@ -1,5 +1,5 @@ { "Chatops_Enabled" : "Enable Chatops", - "Chatops_Title": "Chatops Panel", - "Chatops_Username": "Chatops Username" -} + "Chatops_Title" : "Chatops Panel", + "Chatops_Username" : "Chatops Username" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index 8c3694421a6..8fb066fbe08 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -4,4 +4,4 @@ "Accounts_OAuth_GitHub_Enterprise_id" : "Client Id", "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", "Github_Enterprise_Url_No_Trail" : "Note: Please exclude trailing slash" -} +} \ 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 86b2bc4611c..3e0c8629995 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -1,4 +1,4 @@ { "Livechat_title" : "Livechat Title", "Livechat_title_color" : "Livechat Title Background Color" -} +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ar.i18n.json b/packages/rocketchat-webrtc/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/de.i18n.json b/packages/rocketchat-webrtc/i18n/de.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/el.i18n.json b/packages/rocketchat-webrtc/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/en.i18n.json b/packages/rocketchat-webrtc/i18n/en.i18n.json index 06cb81587e6..c52ef5d8daa 100644 --- a/packages/rocketchat-webrtc/i18n/en.i18n.json +++ b/packages/rocketchat-webrtc/i18n/en.i18n.json @@ -2,4 +2,4 @@ "WebRTC_Enable_Channel" : "Enable for Public Channels", "WebRTC_Enable_Direct" : "Enable for Direct Messages", "WebRTC_Enable_Private" : "Enable for Private Channels" -} +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/es.i18n.json b/packages/rocketchat-webrtc/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/fi.i18n.json b/packages/rocketchat-webrtc/i18n/fi.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/fr.i18n.json b/packages/rocketchat-webrtc/i18n/fr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/he.i18n.json b/packages/rocketchat-webrtc/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/hr.i18n.json b/packages/rocketchat-webrtc/i18n/hr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/hu.i18n.json b/packages/rocketchat-webrtc/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/it.i18n.json b/packages/rocketchat-webrtc/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ja.i18n.json b/packages/rocketchat-webrtc/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/km.i18n.json b/packages/rocketchat-webrtc/i18n/km.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ko.i18n.json b/packages/rocketchat-webrtc/i18n/ko.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ms-MY.i18n.json b/packages/rocketchat-webrtc/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/pl.i18n.json b/packages/rocketchat-webrtc/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/pt.i18n.json b/packages/rocketchat-webrtc/i18n/pt.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ru.i18n.json b/packages/rocketchat-webrtc/i18n/ru.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ta-IN.i18n.json b/packages/rocketchat-webrtc/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/tr.i18n.json b/packages/rocketchat-webrtc/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ug.i18n.json b/packages/rocketchat-webrtc/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/uk.i18n.json b/packages/rocketchat-webrtc/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/zh.i18n.json b/packages/rocketchat-webrtc/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/en.i18n.json b/packages/rocketchat-wordpress/i18n/en.i18n.json index 17e23404808..06727b945fe 100644 --- a/packages/rocketchat-wordpress/i18n/en.i18n.json +++ b/packages/rocketchat-wordpress/i18n/en.i18n.json @@ -3,4 +3,4 @@ "Accounts_OAuth_Wordpress" : "WordPress Login", "Accounts_OAuth_Wordpress_id" : "WordPress Id", "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" -} +} \ No newline at end of file -- GitLab From 6d54916dae28c4b8b19e0f15e37e7c222b0849d0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 22 Oct 2015 18:28:55 +0200 Subject: [PATCH 0220/1338] Add ios platform before the build in build-old.sh --- build-old.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build-old.sh b/build-old.sh index 90b3c5b8eb8..1ae834b842a 100755 --- a/build-old.sh +++ b/build-old.sh @@ -3,6 +3,7 @@ source ./build-info.sh export METEOR_SETTINGS=$(cat settings.json) meteor add rocketchat:livechat meteor add rocketchat:hubot +meteor add-platform ios meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat cd /var/www/rocket.chat/bundle/programs/server npm install -- GitLab From 7e7ef28a5024c939ba1b0d0fef04930df5886888 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 22 Oct 2015 13:29:42 -0500 Subject: [PATCH 0221/1338] Add a field on the account profile to be able to change a user's real name. --- client/views/account/accountProfile.coffee | 14 ++++++++++---- client/views/account/accountProfile.html | 6 ++++++ packages/rocketchat-lib/package.js | 1 + .../server/methods/setName.coffee | 19 +++++++++++++++++++ server/methods/saveUserProfile.coffee | 3 +++ 5 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 packages/rocketchat-lib/server/methods/setName.coffee diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 30c71e5b4d9..1456288a7a2 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -9,16 +9,19 @@ Template.accountProfile.helpers userLanguage: (key) -> return (localStorage.getItem('userLanguage') or defaultUserLanguage())?.split('-').shift().toLowerCase() is key + realname: -> + return Meteor.user().name + username: -> return Meteor.user().username - + allowUsernameChange: -> return RocketChat.settings.get("Accounts_AllowUsernameChange") - + usernameChangeDisabled: -> return t('Username_Change_Disabled') - - + + Template.accountProfile.onCreated -> settingsTemplate = this.parentTemplate(3) @@ -62,6 +65,9 @@ Template.accountProfile.onCreated -> data.language = selectedLanguage reload = true + if _.trim $('#realname').val() + data.realname = _.trim $('#realname').val() + if _.trim $('#username').val() data.username = _.trim $('#username').val() diff --git a/client/views/account/accountProfile.html b/client/views/account/accountProfile.html index f8981c76aa8..97f24504e13 100644 --- a/client/views/account/accountProfile.html +++ b/client/views/account/accountProfile.html @@ -9,6 +9,12 @@ <div class="content"> <div class="rocket-form"> <fieldset> + <div class="input-line"> + <label for="realname">{{_ "Name"}}</label> + <div> + <input type="text" name="realname" id="realname" value="{{realname}}" /> + </div> + </div> <div class="input-line"> <label for="username">{{_ "Username"}}</label> <div> diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 6847496b701..10b7ea7146c 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -59,6 +59,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); + api.addFiles('server/methods/setName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/setName.coffee b/packages/rocketchat-lib/server/methods/setName.coffee new file mode 100644 index 00000000000..8125ac19357 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/setName.coffee @@ -0,0 +1,19 @@ +Meteor.methods + setName: (name) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] setName -> Invalid user") + + console.log '[methods] setName -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments + + user = Meteor.user() + + if user.name is name + return name + + if not /^[0-9a-zA-Z-_. ]+$/.test name + throw new Meteor.Error 'name-invalid', "#{name} is not a valid name, use only letters, numbers, dots, dashes, and spaces" + + unless RocketChat.models.Users.setName Meteor.userId(), name + throw new Meteor.Error 'could-not-change-name', "Could not change name" + + return name diff --git a/server/methods/saveUserProfile.coffee b/server/methods/saveUserProfile.coffee index cfd36bdbefc..4581cc02123 100644 --- a/server/methods/saveUserProfile.coffee +++ b/server/methods/saveUserProfile.coffee @@ -7,6 +7,9 @@ Meteor.methods # if settings.password? # Accounts.setPassword Meteor.userId(), settings.password, { logout: false } + if settings.realname? + Meteor.call 'setName', settings.realname + if settings.username? Meteor.call 'setUsername', settings.username -- GitLab From 467f5a421174f73a62cba39c61350de524d39ce8 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 22 Oct 2015 14:14:03 -0500 Subject: [PATCH 0222/1338] When suggest active users to mention --- packages/rocketchat-lib/server/models/Users.coffee | 13 +++++++++++++ server/publications/filteredUsers.coffee | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index 059635c6833..14201607bca 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -52,6 +52,19 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @find query, options + findByActiveUsersNameOrUsername: (nameOrUsername, options) -> + query = + username: + $exists: 1 + active: true + + $or: [ + {name: nameOrUsername} + {username: nameOrUsername} + ] + + return @find query, options + findUsersByNameOrUsername: (nameOrUsername, options) -> query = username: diff --git a/server/publications/filteredUsers.coffee b/server/publications/filteredUsers.coffee index f530ca213f1..fd93452f85c 100644 --- a/server/publications/filteredUsers.coffee +++ b/server/publications/filteredUsers.coffee @@ -18,7 +18,7 @@ Meteor.publish 'filteredUsers', (name) -> pub = this - cursorHandle = RocketChat.models.Users.findUsersByNameOrUsername(exp, options).observeChanges + cursorHandle = RocketChat.models.Users.findByActiveUsersNameOrUsername(exp, options).observeChanges added: (_id, record) -> pub.added('filtered-users', _id, record) -- GitLab From 82ee90c1f02e3be0985d97e8b8b06725320a7372 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Thu, 22 Oct 2015 18:25:28 -0200 Subject: [PATCH 0223/1338] hotfix: add room types to admin, moderator and user roles. --- client/startup/defaultRoomTypes.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 7287542d82a..5ef93048cc0 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,8 +1,9 @@ Meteor.startup -> - RocketChat.roomTypes.addType('starredRooms', 'user'); - RocketChat.roomTypes.addType('channels', 'user'); - RocketChat.roomTypes.addType('directMessages', 'user'); - RocketChat.roomTypes.addType('privateGroups', 'user'); + roles = ['admin', 'moderator', 'user'] + RocketChat.roomTypes.addType('starredRooms', roles); + RocketChat.roomTypes.addType('channels', roles); + RocketChat.roomTypes.addType('directMessages', roles); + RocketChat.roomTypes.addType('privateGroups', roles); RocketChat.roomTypes.setRoute 'c', 'channel', (sub) -> return { name: sub.name } -- GitLab From fd1ef6c6415d5ad70174e6da97cda153118ede44 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Thu, 22 Oct 2015 21:55:22 +0100 Subject: [PATCH 0224/1338] Add setting to disable password changes and correct bug where disabling username change also disabled changing of password and language. --- client/views/account/accountProfile.coffee | 24 +++++++++++++++---- client/views/account/accountProfile.html | 9 +++++++ i18n/en.i18n.json | 2 ++ .../settings/server/startup.coffee | 1 + 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 30c71e5b4d9..e1c59dcadbd 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -17,7 +17,12 @@ Template.accountProfile.helpers usernameChangeDisabled: -> return t('Username_Change_Disabled') - + + allowPasswordChange: -> + return RocketChat.settings.get("Accounts_AllowPasswordChange") + + passwordChangeDisabled: -> + return t('Password_Change_Disabled') Template.accountProfile.onCreated -> @@ -29,8 +34,10 @@ Template.accountProfile.onCreated -> @find('#language').value = localStorage.getItem('userLanguage') @find('#oldPassword').value = '' @find('#password').value = '' + @find('#username').value = '' @changePassword = (oldPassword, newPassword, callback) -> + instance = @ if not oldPassword and not newPassword return callback() @@ -38,6 +45,10 @@ Template.accountProfile.onCreated -> toastr.warning t('Old_and_new_password_required') else if newPassword and oldPassword + if !RocketChat.settings.get("Accounts_AllowPasswordChange") + toastr.error t('Password_Change_Disabled') + instance.clearForm() + return Accounts.changePassword oldPassword, newPassword, (error) -> if error toastr.error t('Incorrect_Password') @@ -46,9 +57,7 @@ Template.accountProfile.onCreated -> @save = -> instance = @ - if !RocketChat.settings.get("Accounts_AllowUsernameChange") - toastr.error t('Username_Change_Disabled') - return + oldPassword = _.trim($('#oldPassword').val()) newPassword = _.trim($('#password').val()) @@ -63,7 +72,12 @@ Template.accountProfile.onCreated -> reload = true if _.trim $('#username').val() - data.username = _.trim $('#username').val() + if !RocketChat.settings.get("Accounts_AllowUsernameChange") + toastr.error t('Username_Change_Disabled') + instance.clearForm() + return + else + data.username = _.trim $('#username').val() Meteor.call 'saveUserProfile', data, (error, results) -> if results diff --git a/client/views/account/accountProfile.html b/client/views/account/accountProfile.html index f8981c76aa8..ea2a331604c 100644 --- a/client/views/account/accountProfile.html +++ b/client/views/account/accountProfile.html @@ -22,13 +22,21 @@ <div class="input-line"> <label for="password">{{_ "Old_Password"}}</label> <div> + {{#if allowPasswordChange}} <input type="password" name="oldPassword" id="oldPassword" /> + {{else}} + <input type="password" name="oldPassword" id="oldPassword" disabled="disabled" title="{{passwordChangeDisabled}}" /> + {{/if}} </div> </div> <div class="input-line"> <label for="password">{{_ "Password"}}</label> <div> + {{#if allowPasswordChange}} <input type="password" name="password" id="password" /> + {{else}} + <input type="password" name="password" id="password" disabled="disabled" title="{{passwordChangeDisabled}}"/> + {{/if}} </div> </div> <div class="input-line"> @@ -44,6 +52,7 @@ </fieldset> <div class="submit"> <button class="button"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> + <a href="accountProfile.coffee"></a> </div> </div> </div> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e3523d57cd7..6bb56e8686c 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -4,6 +4,7 @@ "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Comma-separated list of allowed domains", "Accounts_AllowUsernameChange" : "Allow Username Change", + "Accounts_AllowPasswordChange" : "Allow Password Change", "Accounts_AvatarResize" : "Resize Avatars", "Accounts_AvatarSize" : "Avatar Size", "Accounts_AvatarStorePath" : "Avatar Storage Path", @@ -259,6 +260,7 @@ "others" : "others", "Password" : "Password", "Password_changed_successfully" : "Password changed successfully", + "Password_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of passwords", "People" : "People", "Please_wait" : "Please wait", "Please_wait_activation" : "Please wait, this can take some time.", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index e16aa2ab629..27d4e3a1f4a 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -36,6 +36,7 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter_id', '', { type: 'string', group RocketChat.settings.add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', group: 'Accounts', section: 'Twitter' } 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.addGroup 'FileUpload' RocketChat.settings.add 'FileUpload_Enabled', true, { type: 'boolean', group: 'FileUpload', public: true } -- GitLab From 034520ceccd444230e4680c9190dafea7a77a40e Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Thu, 22 Oct 2015 22:13:58 +0100 Subject: [PATCH 0225/1338] Remove accidental line of html --- client/views/account/accountProfile.html | 1 - 1 file changed, 1 deletion(-) diff --git a/client/views/account/accountProfile.html b/client/views/account/accountProfile.html index ea2a331604c..1aa23913094 100644 --- a/client/views/account/accountProfile.html +++ b/client/views/account/accountProfile.html @@ -52,7 +52,6 @@ </fieldset> <div class="submit"> <button class="button"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> - <a href="accountProfile.coffee"></a> </div> </div> </div> -- GitLab From 89480fc593abeed88a3b01b1d3d8e78afbd2d4c5 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Thu, 22 Oct 2015 23:33:13 +0200 Subject: [PATCH 0226/1338] Use SoundCloud Oembed API https://developers.soundcloud.com/docs/api/reference#oembed in order to support more links --- .../rocketchat-oembed/server/server.coffee | 2 +- .../lib/client/oembedSoundcloudWidget.html | 18 +++++++++++---- .../lib/client/widget.coffee | 2 +- .../lib/server/server.coffee | 23 +++++++++++++------ packages/rocketchat-soundcloud/package.js | 4 +++- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index f1e52c0d782..196d0f4affd 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -168,7 +168,7 @@ getRelevantHeaders = (headersObj) -> getRelevantMetaTags = (metaObj) -> tags = {} for key, value of metaObj - if /^(og|fb|twitter).+|description|title|pageTitle$/.test(key.toLowerCase()) and value?.trim() isnt '' + if /^(og|fb|twitter|oembed).+|description|title|pageTitle$/.test(key.toLowerCase()) and value?.trim() isnt '' tags[key] = value if Object.keys(tags).length > 0 diff --git a/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html b/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html index 7e4a1fa9a8b..f478120bed7 100644 --- a/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html +++ b/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html @@ -2,12 +2,20 @@ {{#if parsedUrl}} <blockquote> <a href="https://www.soundcloud.com" style="color: #9e9ea6">SoundCloud</a><br/> - {{#if meta.twitterAudioArtistName}} - <a href="https://www.soundcloud.com/{{meta.twitterAudioArtistName}}">{{meta.twitterAudioArtistName}}</a><br/> + {{#if meta.oembedAuthorName}} + {{#if meta.oembedAuthorUrl}} + <a href="meta.oembedAuthorUrl">{{meta.oembedAuthorName}}</a><br/> + {{/if}} {{/if}} - <a href="{{meta.ogUrl}}">{{meta.ogTitle}}</a><br/> - <p>{{meta.ogDescription}}</p> - <iframe width="100%" height="150" src="{{meta.twitterPlayer}}" frameborder="0"></iframe><br/> + {{#if meta.oembedTitle}} + {{#if meta.oembedUrl}} + <a href="{{meta.oembedUrl}}">{{meta.oembedTitle}}</a><br/> + {{/if}} + {{/if}} + {{#if meta.oembedDescription}} + <p>{{meta.oembedDescription}}</p> + {{/if}} + {{{meta.oembedHtml}}} </blockquote> {{/if}} </template> diff --git a/packages/rocketchat-soundcloud/lib/client/widget.coffee b/packages/rocketchat-soundcloud/lib/client/widget.coffee index 4f921d64352..bf4c284024d 100644 --- a/packages/rocketchat-soundcloud/lib/client/widget.coffee +++ b/packages/rocketchat-soundcloud/lib/client/widget.coffee @@ -1,3 +1,3 @@ Template.oembedBaseWidget.onCreated () -> - if this.data?.parsedUrl?.host is 'soundcloud.com' and this.data?.meta?.twitterPlayer? + if this.data?.parsedUrl?.host is 'soundcloud.com' and this.data?.meta?.oembedHtml? this.data._overrideTemplate = 'oembedSoundcloudWidget' diff --git a/packages/rocketchat-soundcloud/lib/server/server.coffee b/packages/rocketchat-soundcloud/lib/server/server.coffee index fc6cacf8351..b1bbe3be4eb 100644 --- a/packages/rocketchat-soundcloud/lib/server/server.coffee +++ b/packages/rocketchat-soundcloud/lib/server/server.coffee @@ -1,10 +1,19 @@ -RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> - # if data.parsedUrl is 'soundcloud.com' - # Do whatever you whant in sync way - # You can modify the object data.requestOptions to change how the request will be executed +URL = Npm.require('url') +RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> + if data.parsedUrl.host is 'soundcloud.com' + newUrlObj = URL.format data.parsedUrl + newUrlObj = URL.parse "https://soundcloud.com/oembed?url=" + encodeURIComponent newUrlObj + "&format=json&maxheight=150" + data.requestOptions.port = newUrlObj.port + data.requestOptions.hostname = newUrlObj.hostname + data.requestOptions.path = newUrlObj.path RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> - # if data.parsedUrl is 'soundcloud.com' - # Do whatever you whant in sync way - # You can modify the object data to change the parsed object + if data.parsedUrl.host is 'soundcloud.com' + if data.content?.body? + metas = JSON.parse data.content.body; + _.each metas, (value, key) -> + if _.isString value + data.meta[changeCase.camelCase('oembed_' + key)] = value + if data.parsedUrl? + data.meta['oembedUrl'] = URL.format data.parsedUrl diff --git a/packages/rocketchat-soundcloud/package.js b/packages/rocketchat-soundcloud/package.js index 3be89da9c73..054b7802923 100644 --- a/packages/rocketchat-soundcloud/package.js +++ b/packages/rocketchat-soundcloud/package.js @@ -9,9 +9,11 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use([ - 'rocketchat:lib', 'coffeescript', 'templating', + 'underscore', + 'konecty:change-case', + 'rocketchat:lib', 'rocketchat:oembed@0.0.1' ]); -- GitLab From aca7c1d3f63e903239d9aff668eba3973775c450 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 23 Oct 2015 10:37:36 +0200 Subject: [PATCH 0227/1338] Back raix:push to 2.6.13-rc.1 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index c726382e74f..ea33949e442 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -112,7 +112,7 @@ qnub:emojione@0.0.3 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 -raix:push@3.0.1 +raix:push@2.6.13-rc.1 raix:ui-dropped-event@0.0.7 random@1.0.4 rate-limit@1.0.0 -- GitLab From e58a16005a6c6275cc9b5aef1836b14ad597e6ad Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 23 Oct 2015 12:20:14 +0200 Subject: [PATCH 0228/1338] Enable soundcloud by default --- .meteor/packages | 2 +- .meteor/versions | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index 5d932b0a4ae..21af9041330 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -65,7 +65,7 @@ rocketchat:wordpress #rocketchat:hubot #rocketchat:irc #rocketchat:livechat -#rocketchat:soundcloud +rocketchat:soundcloud konecty:change-case konecty:delayed-task diff --git a/.meteor/versions b/.meteor/versions index ea33949e442..ff18b148896 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -141,6 +141,7 @@ rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 rocketchat:slashcommands-leave@0.0.1 +rocketchat:soundcloud@0.0.1 rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 rocketchat:theme@0.0.1 -- GitLab From 2876944a82532f4b7473bd37f51b790ad5791e8c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 23 Oct 2015 14:08:42 +0200 Subject: [PATCH 0229/1338] Keep scroll at bottom on window resize --- client/views/app/room.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 63e93849c53..17b349ad2f2 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -224,6 +224,7 @@ Template.room.helpers fileUploadAllowedMediaTypes: -> return RocketChat.settings.get('FileUpload_MediaTypeWhiteList') + Template.room.events "touchstart .message": (e, t) -> message = this._arguments[1] @@ -503,9 +504,13 @@ Template.room.onCreated -> evt["click .#{button.id}"] = button.action Template.room.events evt + Template.room.onDestroyed -> RocketChat.TabBar.resetButtons() + window.removeEventListener 'resize', this.onWindowResize + + Template.room.onRendered -> this.chatMessages = new ChatMessages this.chatMessages.init(this.firstNode) @@ -554,6 +559,12 @@ Template.room.onRendered -> childList: true # observer.disconnect() + template.onWindowResize = -> + Meteor.defer -> + template.sendToBottomIfNecessaryDebounced() + + window.addEventListener 'resize', template.onWindowResize + wrapper.addEventListener 'mousewheel', -> template.atBottom = false Meteor.defer -> -- GitLab From 16e1f1cc7dab95fea05679bd971bb3cfde5be424 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 23 Oct 2015 14:31:16 +0200 Subject: [PATCH 0230/1338] Try to keep scroll at bottom when flex bar opens --- client/views/app/room.coffee | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 85ddb1b5132..35f2083b865 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -226,6 +226,11 @@ Template.room.helpers Template.room.events + "click, touchend": (e, t) -> + Meteor.setTimeout -> + t.sendToBottomIfNecessaryDebounced() + , 100 + "touchstart .message": (e, t) -> message = this._arguments[1] doLongTouch = -> @@ -589,6 +594,11 @@ Template.room.onRendered -> template.checkIfScrollIsAtBottom() , 2000 + $('.flex-tab-bar').on 'click', (e, t) -> + Meteor.setTimeout -> + template.sendToBottomIfNecessaryDebounced() + , 100 + updateUnreadCount = _.throttle -> firstMessageOnScreen = document.elementFromPoint(containerBarsOffset.left+1, containerBarsOffset.top+containerBars.height()+1) if firstMessageOnScreen?.id? -- GitLab From 9fdc1bd7c53f454e53fe8918ba618428a75b57ec Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 23 Oct 2015 16:37:11 +0200 Subject: [PATCH 0231/1338] support for room's publish by type and api for routes --- client/routes/roomRoute.coffee | 85 ------------------- .../rocketchat-lib/client/lib/openRoom.coffee | 65 ++++++++++++++ .../rocketchat-lib/client/lib/roomExit.coffee | 17 ++++ .../{client => }/lib/roomTypes.coffee | 23 +++++ packages/rocketchat-lib/package.js | 4 +- server/publications/room.coffee | 24 +----- server/startup/roomPublishes.coffee | 32 +++++++ 7 files changed, 141 insertions(+), 109 deletions(-) create mode 100644 packages/rocketchat-lib/client/lib/openRoom.coffee create mode 100644 packages/rocketchat-lib/client/lib/roomExit.coffee rename packages/rocketchat-lib/{client => }/lib/roomTypes.coffee (65%) create mode 100644 server/startup/roomPublishes.coffee diff --git a/client/routes/roomRoute.coffee b/client/routes/roomRoute.coffee index 152d2ac02f4..96ecb33cede 100644 --- a/client/routes/roomRoute.coffee +++ b/client/routes/roomRoute.coffee @@ -1,88 +1,3 @@ -currentTracker = undefined - -openRoom = (type, name) -> - Session.set 'openedRoom', null - - Meteor.defer -> - currentTracker = Tracker.autorun (c) -> - if RoomManager.open(type + name).ready() isnt true - BlazeLayout.render 'main', {center: 'loading'} - return - - currentTracker = undefined - c.stop() - - query = - t: type - name: name - - if type is 'd' - delete query.name - query.usernames = - $all: [name, Meteor.user()?.username] - - room = ChatRoom.findOne(query) - if not room? - Session.set 'roomNotFound', {type: type, name: name} - BlazeLayout.render 'main', {center: 'roomNotFound'} - return - - mainNode = document.querySelector('.main-content') - if mainNode? - for child in mainNode.children - mainNode.removeChild child if child? - roomDom = RoomManager.getDomOfRoom(type + name, room._id) - mainNode.appendChild roomDom - if roomDom.classList.contains('room-container') - roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop - - Session.set 'openedRoom', room._id - - Session.set 'editRoomTitle', false - RoomManager.updateMentionsMarksOfRoom type + name - Meteor.setTimeout -> - readMessage.readNow() - , 2000 - # KonchatNotification.removeRoomNotification(params._id) - - if Meteor.Device.isDesktop() - setTimeout -> - $('.message-form .input-message').focus() - , 100 - - RocketChat.TabBar.resetButtons() - RocketChat.TabBar.addButton({ id: 'message-search', title: t('Search'), icon: 'octicon octicon-search', template: 'messageSearch', order: 1 }) - if type is 'd' - RocketChat.TabBar.addButton({ id: 'members-list', title: t('User_Info'), icon: 'octicon octicon-person', template: 'membersList', order: 2 }) - else - RocketChat.TabBar.addButton({ id: 'members-list', title: t('Members_List'), icon: 'octicon octicon-organization', template: 'membersList', order: 2 }) - RocketChat.TabBar.addButton({ id: 'uploaded-files-list', title: 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 - Meteor.call 'openRoom', room._id - - RocketChat.callbacks.run 'enter-room' - -roomExit = -> - BlazeLayout.render 'main', {center: 'none'} - - if currentTracker? - currentTracker.stop() - - mainNode = document.querySelector('.main-content') - if mainNode? - for child in mainNode.children - 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 - mainNode.removeChild child - - FlowRouter.route '/channel/:name', name: 'channel' diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee new file mode 100644 index 00000000000..9176289077e --- /dev/null +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -0,0 +1,65 @@ +currentTracker = undefined + +@openRoom = (type, name) -> + Session.set 'openedRoom', null + + Meteor.defer -> + currentTracker = Tracker.autorun (c) -> + if RoomManager.open(type + name).ready() isnt true + BlazeLayout.render 'main', {center: 'loading'} + return + + currentTracker = undefined + c.stop() + + query = + t: type + name: name + + if type is 'd' + delete query.name + query.usernames = + $all: [name, Meteor.user()?.username] + + room = ChatRoom.findOne(query) + if not room? + Session.set 'roomNotFound', {type: type, name: name} + BlazeLayout.render 'main', {center: 'roomNotFound'} + return + + mainNode = document.querySelector('.main-content') + if mainNode? + for child in mainNode.children + mainNode.removeChild child if child? + roomDom = RoomManager.getDomOfRoom(type + name, room._id) + mainNode.appendChild roomDom + if roomDom.classList.contains('room-container') + roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop + + Session.set 'openedRoom', room._id + + Session.set 'editRoomTitle', false + RoomManager.updateMentionsMarksOfRoom type + name + Meteor.setTimeout -> + readMessage.readNow() + , 2000 + # KonchatNotification.removeRoomNotification(params._id) + + if Meteor.Device.isDesktop() + setTimeout -> + $('.message-form .input-message').focus() + , 100 + + RocketChat.TabBar.resetButtons() + RocketChat.TabBar.addButton({ id: 'message-search', title: t('Search'), icon: 'octicon octicon-search', template: 'messageSearch', order: 1 }) + if type is 'd' + RocketChat.TabBar.addButton({ id: 'members-list', title: t('User_Info'), icon: 'octicon octicon-person', template: 'membersList', order: 2 }) + else + RocketChat.TabBar.addButton({ id: 'members-list', title: t('Members_List'), icon: 'octicon octicon-organization', template: 'membersList', order: 2 }) + RocketChat.TabBar.addButton({ id: 'uploaded-files-list', title: 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 + Meteor.call 'openRoom', room._id + + RocketChat.callbacks.run 'enter-room' diff --git a/packages/rocketchat-lib/client/lib/roomExit.coffee b/packages/rocketchat-lib/client/lib/roomExit.coffee new file mode 100644 index 00000000000..d8a44ae00a3 --- /dev/null +++ b/packages/rocketchat-lib/client/lib/roomExit.coffee @@ -0,0 +1,17 @@ +@roomExit = -> + BlazeLayout.render 'main', {center: 'none'} + + if currentTracker? + currentTracker.stop() + + mainNode = document.querySelector('.main-content') + if mainNode? + for child in mainNode.children + 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 + mainNode.removeChild child diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee similarity index 65% rename from packages/rocketchat-lib/client/lib/roomTypes.coffee rename to packages/rocketchat-lib/lib/roomTypes.coffee index af7d6c939f2..69622f99ede 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -1,6 +1,7 @@ RocketChat.roomTypes = new class rooms = [] routes = {} + publishes = {} ### Sets a route for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @@ -39,7 +40,29 @@ RocketChat.roomTypes = new class getAllTypes = -> return rooms + ### add a publish for a room type + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param callback: function that will return the publish's data + ### + addPublish = (roomType, callback) -> + if publishes[roomType]? + throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' + + publishes[roomType] = callback + + ### run the publish for a room type + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param identifier: identifier of the room + ### + runPublish = (roomType, identifier) -> + return unless publishes[roomType]? + return publishes[roomType].call this, identifier + addType: addType getTypes: getAllTypes + setRoute: setRoute getRoute: getRoute + + addPublish: addPublish + publish: runPublish diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 6847496b701..fbf3b9bc713 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -21,6 +21,7 @@ Package.onUse(function(api) { // COMMON api.addFiles('lib/core.coffee'); api.addFiles('lib/callbacks.coffee'); + api.addFiles('lib/roomTypes.coffee'); api.addFiles('lib/slashCommand.coffee'); // MODELS SERVER @@ -45,7 +46,8 @@ Package.onUse(function(api) { api.addFiles('settings/lib/settings.coffee'); // CLIENT - api.addFiles('client/lib/roomTypes.coffee', 'client'); + api.addFiles('client/lib/openRoom.coffee', 'client'); + api.addFiles('client/lib/roomExit.coffee', 'client'); api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); api.addFiles('client/MessageAction.coffee', 'client'); diff --git a/server/publications/room.coffee b/server/publications/room.coffee index a5cdcb4d92c..ef32aecaf2a 100644 --- a/server/publications/room.coffee +++ b/server/publications/room.coffee @@ -10,26 +10,4 @@ Meteor.publish 'room', (typeName) -> type = typeName.substr(0, 1) name = typeName.substr(1) - options = - fields: - name: 1 - t: 1 - cl: 1 - u: 1 - usernames: 1 - - switch type - when 'c' - return RocketChat.models.Rooms.findByTypeAndName 'c', name, options - - when 'p' - user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 - return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', name, user.username, options - - when 'd' - user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 - return RocketChat.models.Rooms.findByTypeContainigUsername 'd', user.username, options - - # Change to validate access manualy - # if not Meteor.call 'canAccessRoom', rid, this.userId - # return this.ready() + return RocketChat.roomTypes.publish.call(this, type, name) diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee new file mode 100644 index 00000000000..ae5cdd0225f --- /dev/null +++ b/server/startup/roomPublishes.coffee @@ -0,0 +1,32 @@ +Meteor.startup -> + RocketChat.roomTypes.addPublish 'c', (identifier) -> + options = + fields: + name: 1 + t: 1 + cl: 1 + u: 1 + usernames: 1 + return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options + + RocketChat.roomTypes.addPublish 'p', (identifier) -> + options = + fields: + name: 1 + t: 1 + cl: 1 + u: 1 + usernames: 1 + user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 + return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options + + RocketChat.roomTypes.addPublish 'd', (identifier) -> + options = + fields: + name: 1 + t: 1 + cl: 1 + u: 1 + usernames: 1 + user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 + return RocketChat.models.Rooms.findByTypeContainigUsername 'd', user.username, options -- GitLab From 66870bcbc27ec515c1d2d8e57e218656003356d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= <theess@subshell.com> Date: Fri, 23 Oct 2015 16:48:52 +0200 Subject: [PATCH 0232/1338] Removed unused query variable. --- packages/rocketchat-lib/server/sendMessage.coffee | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/packages/rocketchat-lib/server/sendMessage.coffee b/packages/rocketchat-lib/server/sendMessage.coffee index a2e0bc5fad9..b65901841a8 100644 --- a/packages/rocketchat-lib/server/sendMessage.coffee +++ b/packages/rocketchat-lib/server/sendMessage.coffee @@ -105,20 +105,6 @@ RocketChat.sendMessage = (user, message, room, options) -> # the mentioned user if mention isn't for all RocketChat.models.Subscriptions.incUnreadForRoomIdAndUserIds message.rid, mentionIds, 1 - query = - statusConnection: {$ne: 'online'} - - if toAll - if room.usernames?.length > 0 - query.username = - $in: room.usernames - else - query.username = - $in: [] - else - query._id = - $in: mentionIds - userIdsToNotify = _.pluck(usersOfMention, '_id') # If the message is @all, send a notification to all online room users except for the sender. -- GitLab From 22a1dbdfde7a85bbfa62787b1f25388f3c07f6bd Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 23 Oct 2015 17:16:31 +0200 Subject: [PATCH 0233/1338] Render the name of setting group in menu using the id if the i18nLabel does not exists --- client/views/admin/adminFlex.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/admin/adminFlex.html b/client/views/admin/adminFlex.html index cc7ebf87317..27bd9d2c7ec 100644 --- a/client/views/admin/adminFlex.html +++ b/client/views/admin/adminFlex.html @@ -32,7 +32,7 @@ {{#if hasPermission 'view-privileged-setting'}} {{#each groups}} <li> - <a href="{{pathFor 'admin' group=_id}}" class="admin-link">{{_ i18nLabel}}</a> + <a href="{{pathFor 'admin' group=_id}}" class="admin-link">{{label}}</a> </li> {{/each}} {{/if}} -- GitLab From 43ddb8e1b70a859ed615838a823be49ad96fa6a5 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Fri, 23 Oct 2015 10:21:56 -0500 Subject: [PATCH 0234/1338] Change method to setRealName and only trim the provided name. --- .../.npm/package/npm-shrinkwrap.json | 3 --- packages/rocketchat-lib/package.js | 2 +- .../server/methods/setName.coffee | 19 ------------------- .../server/methods/setRealName.coffee | 19 +++++++++++++++++++ server/methods/saveUserProfile.coffee | 2 +- 5 files changed, 21 insertions(+), 24 deletions(-) delete mode 100644 packages/rocketchat-lib/server/methods/setName.coffee create mode 100644 packages/rocketchat-lib/server/methods/setRealName.coffee diff --git a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json index 7e02a682309..3dd543e2c5e 100644 --- a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json @@ -59,9 +59,6 @@ } } } - }, - "dtrace-provider": { - "version": "0.2.8" } } } diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 10b7ea7146c..e535cdd56ee 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -59,7 +59,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); - api.addFiles('server/methods/setName.coffee', 'server'); + api.addFiles('server/methods/setRealName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/setName.coffee b/packages/rocketchat-lib/server/methods/setName.coffee deleted file mode 100644 index 8125ac19357..00000000000 --- a/packages/rocketchat-lib/server/methods/setName.coffee +++ /dev/null @@ -1,19 +0,0 @@ -Meteor.methods - setName: (name) -> - if not Meteor.userId() - throw new Meteor.Error('invalid-user', "[methods] setName -> Invalid user") - - console.log '[methods] setName -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - - user = Meteor.user() - - if user.name is name - return name - - if not /^[0-9a-zA-Z-_. ]+$/.test name - throw new Meteor.Error 'name-invalid', "#{name} is not a valid name, use only letters, numbers, dots, dashes, and spaces" - - unless RocketChat.models.Users.setName Meteor.userId(), name - throw new Meteor.Error 'could-not-change-name', "Could not change name" - - return name diff --git a/packages/rocketchat-lib/server/methods/setRealName.coffee b/packages/rocketchat-lib/server/methods/setRealName.coffee new file mode 100644 index 00000000000..2a913c93f3e --- /dev/null +++ b/packages/rocketchat-lib/server/methods/setRealName.coffee @@ -0,0 +1,19 @@ +Meteor.methods + setRealName: (name) -> + 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 + return name + + if _.trim name + name = _.trim name + + unless RocketChat.models.Users.setName Meteor.userId(), name + throw new Meteor.Error 'could-not-change-name', "Could not change name" + + return name diff --git a/server/methods/saveUserProfile.coffee b/server/methods/saveUserProfile.coffee index 4581cc02123..2103016f1a1 100644 --- a/server/methods/saveUserProfile.coffee +++ b/server/methods/saveUserProfile.coffee @@ -8,7 +8,7 @@ Meteor.methods # Accounts.setPassword Meteor.userId(), settings.password, { logout: false } if settings.realname? - Meteor.call 'setName', settings.realname + Meteor.call 'setRealName', settings.realname if settings.username? Meteor.call 'setUsername', settings.username -- GitLab From 1286527febd1867d2395524b9e8a217d3fdd11bb Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 23 Oct 2015 17:27:10 +0200 Subject: [PATCH 0235/1338] Re add CDN_PREFIX option --- packages/rocketchat-lib/server/cdn.coffee | 2 +- packages/rocketchat-lib/settings/server/startup.coffee | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/cdn.coffee b/packages/rocketchat-lib/server/cdn.coffee index 697648bb4a0..d41fcbd5d77 100644 --- a/packages/rocketchat-lib/server/cdn.coffee +++ b/packages/rocketchat-lib/server/cdn.coffee @@ -1,4 +1,4 @@ Meteor.startup -> cdnPrefix = RocketChat.settings.get 'CDN_PREFIX' - if cdnPrefix? + if cdnPrefix?.trim?() isnt '' WebAppInternals.setBundledJsCssPrefix cdnPrefix diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 27d4e3a1f4a..3a61e1e10a5 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -49,6 +49,7 @@ RocketChat.settings.add 'Site_Url', __meteor_runtime_config__?.ROOT_URL, { type: 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.addGroup 'API' RocketChat.settings.add 'API_Analytics', '', { type: 'string', group: 'API', public: true } -- GitLab From 7f0cc3e34348e149168618ec6241a57f4db236af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Thee=C3=9F?= <theess@subshell.com> Date: Fri, 23 Oct 2015 18:09:38 +0200 Subject: [PATCH 0236/1338] For @all send push notifications to online and offline users. --- .../rocketchat-lib/server/sendMessage.coffee | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-lib/server/sendMessage.coffee b/packages/rocketchat-lib/server/sendMessage.coffee index b65901841a8..0d4f33fe6f1 100644 --- a/packages/rocketchat-lib/server/sendMessage.coffee +++ b/packages/rocketchat-lib/server/sendMessage.coffee @@ -105,17 +105,21 @@ RocketChat.sendMessage = (user, message, room, options) -> # the mentioned user if mention isn't for all RocketChat.models.Subscriptions.incUnreadForRoomIdAndUserIds message.rid, mentionIds, 1 + # Get ids of all mentioned users. userIdsToNotify = _.pluck(usersOfMention, '_id') + userIdsToPushNotify = userIdsToNotify - # If the message is @all, send a notification to all online room users except for the sender. + # If the message is @all, notify all room users except for the sender. if toAll and room.usernames?.length > 0 - onlineUsersOfRoom = RocketChat.models.Users.find({ + usersOfRoom = RocketChat.models.Users.find({ username: {$in: room.usernames}, - _id: {$ne: user._id} - status: {$in: ['online', 'away', 'busy']}}, - {fields: {_id: 1, username: 1}}) + _id: {$ne: user._id}}, + {fields: {_id: 1, username: 1, status: 1}}) .fetch() + onlineUsersOfRoom = _.filter usersOfRoom, (user) -> + user.status in ['online', 'away', 'busy'] userIdsToNotify = _.union userIdsToNotify, _.pluck(onlineUsersOfRoom, '_id') + userIdsToPushNotify = _.union userIdsToPushNotify, _.pluck(usersOfRoom, '_id') if userIdsToNotify.length > 0 for usersOfMentionId in userIdsToNotify @@ -128,6 +132,7 @@ RocketChat.sendMessage = (user, message, room, options) -> type: room.t name: room.name + if userIdsToPushNotify.length > 0 if Push.enabled is true Push.send from: 'push' @@ -143,7 +148,7 @@ RocketChat.sendMessage = (user, message, room, options) -> type: room.t name: room.name query: - userId: $in: userIdsToNotify + userId: $in: userIdsToPushNotify ### Update all other subscriptions to alert their owners but witout incrementing -- GitLab From d1a23df686d17adc5b623dd932696d64faf27841 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Fri, 23 Oct 2015 12:56:47 -0500 Subject: [PATCH 0237/1338] Fix the error on startup after you rename your general channel --- server/startup/initialData.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index 567fb3af3ec..7840064f439 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -1,7 +1,7 @@ Meteor.startup -> Meteor.defer -> - if not RocketChat.models.Rooms.findOneByName('general')? + if not RocketChat.models.Rooms.findOneById('GENERAL')? RocketChat.models.Rooms.createWithIdTypeAndName 'GENERAL', 'c', 'general', default: true -- GitLab From e878f3317edd513bfa106b74338526c51e55936c Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Fri, 23 Oct 2015 20:02:28 -0200 Subject: [PATCH 0238/1338] Avoid trying to update mentions mark if there is no subscription. --- client/lib/RoomHistoryManager.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/lib/RoomHistoryManager.coffee b/client/lib/RoomHistoryManager.coffee index 9571ba74cfb..3b16390a9d0 100644 --- a/client/lib/RoomHistoryManager.coffee +++ b/client/lib/RoomHistoryManager.coffee @@ -48,9 +48,10 @@ heightDiff = wrapper.scrollHeight - previousHeight wrapper.scrollTop += heightDiff - Meteor.defer -> - readMessage.refreshUnreadMark(rid, true) - RoomManager.updateMentionsMarksOfRoom subscription.t + subscription.name + if ls + Meteor.defer -> + readMessage.refreshUnreadMark(rid, true) + RoomManager.updateMentionsMarksOfRoom subscription.t + subscription.name room.isLoading.set false room.loaded += result?.messages?.length -- GitLab From 1d74791ad40f925e5566572cf1aa9cc4d71d2930 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sat, 24 Oct 2015 06:25:02 -0400 Subject: [PATCH 0239/1338] Add add ons per #1045 Add missing chrome addons --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 930df60248c..72fd45e59af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,12 @@ branches: - master node_js: - '0.10' +addons: + apt: + sources: + - google-chrome + packages: + - google-chrome-stable before_install: - curl https://install.meteor.com | /bin/sh - mkdir -p node_modules @@ -21,4 +27,4 @@ script: - meteor add sanjo:jasmine velocity:console-reporter - meteor update - ./node_modules/velocity-cli/bin/velocity test-packages --ci -- meteor --test --once \ No newline at end of file +- meteor --test --once -- GitLab From 5a1a5ccbce4352ff134d6f4ce20bf38fdc84f37d Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Sat, 24 Oct 2015 13:02:07 +0200 Subject: [PATCH 0240/1338] added hubot avatar --- private/avatars/hubot.png | Bin 0 -> 43146 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 private/avatars/hubot.png diff --git a/private/avatars/hubot.png b/private/avatars/hubot.png new file mode 100644 index 0000000000000000000000000000000000000000..a603c4de9e0d6a71c4b371fb4bf7219441d2ada1 GIT binary patch literal 43146 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 GLSTYEIMt;9 literal 0 HcmV?d00001 -- GitLab From f1df23b7d71174ee66333343af1a6812ea500c4d Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Sat, 24 Oct 2015 13:03:04 +0200 Subject: [PATCH 0241/1338] removed temp package after merging with original --- packages/rocketchat-webrtc-ib/adapter.js | 5 - .../rocketchat-webrtc-ib/i18n/ar.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/de.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/el.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/en.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/es.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/fi.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/fr.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/he.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/hr.i18n.json | 4 - .../rocketchat-webrtc-ib/i18n/hu.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/it.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/ja.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/km.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/ko.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/ms-MY.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/pl.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/pt.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/ru.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/ta-IN.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/tr.i18n.json | 6 - .../rocketchat-webrtc-ib/i18n/ug.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/uk.i18n.json | 1 - .../rocketchat-webrtc-ib/i18n/zh.i18n.json | 6 - packages/rocketchat-webrtc-ib/package.js | 37 --- packages/rocketchat-webrtc-ib/webrtc.js | 259 ------------------ .../rocketchat-webrtc-ib/webrtcmsg.coffee | 8 - 27 files changed, 400 deletions(-) delete mode 100644 packages/rocketchat-webrtc-ib/adapter.js delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ar.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/de.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/el.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/en.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/es.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/fi.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/fr.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/he.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/hr.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/hu.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/it.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ja.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/km.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ko.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/pl.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/pt.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ru.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/tr.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ug.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/uk.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/zh.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/package.js delete mode 100644 packages/rocketchat-webrtc-ib/webrtc.js delete mode 100644 packages/rocketchat-webrtc-ib/webrtcmsg.coffee diff --git a/packages/rocketchat-webrtc-ib/adapter.js b/packages/rocketchat-webrtc-ib/adapter.js deleted file mode 100644 index a66bb37a2ae..00000000000 --- a/packages/rocketchat-webrtc-ib/adapter.js +++ /dev/null @@ -1,5 +0,0 @@ -window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; -window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription; -window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate; -window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription; -navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia; \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/de.i18n.json b/packages/rocketchat-webrtc-ib/i18n/de.i18n.json deleted file mode 100644 index 332a0f2d96e..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/de.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Video-Chat", - "Remote" : "Entfernt", - "Setup" : "Einrichten", - "Stop_Video" : "Video stoppen" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/el.i18n.json b/packages/rocketchat-webrtc-ib/i18n/el.i18n.json deleted file mode 100644 index d4fd3d2608d..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/el.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Συνομιλία μÎσω βίντεο", - "Remote" : "ΑπομακÏυσμÎνο", - "Setup" : "ΡÏθμιση", - "Stop_Video" : "Σταμάτημα Βίντεο" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json b/packages/rocketchat-webrtc-ib/i18n/en.i18n.json deleted file mode 100644 index 84f089985d2..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Video Chat", - "Remote" : "Remote", - "Setup" : "Setup", - "Stop_Video" : "Stop Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/es.i18n.json b/packages/rocketchat-webrtc-ib/i18n/es.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/es.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json deleted file mode 100644 index ab7aed7ca7b..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Videokeskustelu", - "Remote" : "Etä", - "Setup" : "Asennus", - "Stop_Video" : "Pysäytä video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json deleted file mode 100644 index 41647a551e7..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Tchat vidéo", - "Remote" : "À distance", - "Setup" : "Configuration", - "Stop_Video" : "Arrêter la vidéo" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/he.i18n.json b/packages/rocketchat-webrtc-ib/i18n/he.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/he.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json deleted file mode 100644 index 524e429ddff..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "Video_Chat" : "Video Chat", - "Stop_Video" : "Zaustavi Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json b/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/it.i18n.json b/packages/rocketchat-webrtc-ib/i18n/it.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/it.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/km.i18n.json b/packages/rocketchat-webrtc-ib/i18n/km.i18n.json deleted file mode 100644 index 98eedeb7c4d..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/km.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "ការ​ជជែក​កំសាន្ážâ€‹áž‡áž¶â€‹ážœáž¸ážŠáŸáž¢áž¼", - "Remote" : "ពី​ចម្ងាយ", - "Setup" : "ការ​ដំឡើង", - "Stop_Video" : "បញ្ឈប់​វីដáŸáž¢áž¼" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json deleted file mode 100644 index 36785947aeb..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "í™”ìƒ ì±„íŒ…", - "Remote" : "ì›ê²©", - "Setup" : "ì„¤ì •", - "Stop_Video" : "í™”ìƒ ì±„íŒ… ì •ì§€" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json deleted file mode 100644 index ac751a74fe7..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Perbualan Video", - "Remote" : "Kawalan Jauh", - "Setup" : "Persediaan", - "Stop_Video" : "Berhentikan Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json b/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json deleted file mode 100644 index ff189e84d63..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Chat wideo", - "Remote" : "Zdalny", - "Setup" : "Opcje", - "Stop_Video" : "Zatrzymaj wideo" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json b/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json deleted file mode 100644 index f9378d46d17..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Iniciar Video", - "Remote" : "Remoto", - "Setup" : "Configurar", - "Stop_Video" : "Encerrar Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json deleted file mode 100644 index ebedecb615d..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Видео чат", - "Remote" : "Удалённый", - "Setup" : "УÑтановить", - "Stop_Video" : "ОÑтановить видео" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json deleted file mode 100644 index c1fcf250151..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Görüntülü Sohbet", - "Remote" : "Uzak", - "Setup" : "Kurulum", - "Stop_Video" : "Vidyoyu durdur" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json b/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json b/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json deleted file mode 100644 index efbd1904e4b..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "视频", - "Remote" : "远程", - "Setup" : "设置", - "Stop_Video" : "åœæ¢è§†é¢‘" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/package.js b/packages/rocketchat-webrtc-ib/package.js deleted file mode 100644 index 9bb4f2f768a..00000000000 --- a/packages/rocketchat-webrtc-ib/package.js +++ /dev/null @@ -1,37 +0,0 @@ -Package.describe({ - name: 'rocketchat:webrtc-ib', - version: '0.0.1', - summary: 'Package WebRTC In-band Signaling for Meteor server', - git: '' -}); - -Package.onUse(function(api) { - api.versionsFrom('1.0'); - - api.use([ - 'coffeescript', - 'rocketchat:lib@0.0.1' - ]); - - api.addFiles('adapter.js', ['client']); - api.addFiles('webrtc.js', ['client']); - api.addFiles('webrtcmsg.coffee', ['client']); - - // TAPi18n - api.use('templating', 'client'); - var _ = Npm.require('underscore'); - var fs = Npm.require('fs'); - tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-webrtc-ib/i18n'), function(filename) { - if (fs.statSync('packages/rocketchat-webrtc-ib/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.export('webrtc') -}); - - -Package.onTest(function(api) {}); diff --git a/packages/rocketchat-webrtc-ib/webrtc.js b/packages/rocketchat-webrtc-ib/webrtc.js deleted file mode 100644 index 145ec5bb0ce..00000000000 --- a/packages/rocketchat-webrtc-ib/webrtc.js +++ /dev/null @@ -1,259 +0,0 @@ - -webrtc = { - // cid: Random.id(), - stackid: 'webrtc-ib', - pc: undefined, - to: undefined, - room: undefined, - activeMediastream: undefined, - remoteDataSDP: undefined, - mode: undefined, - lastSeenTimestamp: new Date(), - debug: false, - config: { - iceServers: [ - {url: "stun:23.21.150.121"}, - {url: "stun:stun.l.google.com:19302"} - ] - }, - send: function(data) { - console.log - data.to = webrtc.to; - data.from = Meteor.user().username; - Meteor.call('sendMessage', { - t: 'rtc', - u: {username: data.from}, - to: webrtc.to, - msg: JSON.stringify(data), - rid: webrtc.room, - mode: (webrtc.mode ? webrtc.mode : 0) - }); - - }, - stop: function(sendEvent) { - if (webrtc.activeMediastream) { - webrtc.activeMediastream = undefined; - } - - if (webrtc.pc) { - if (webrtc.pc.signalingState != 'closed') { - webrtc.pc.close(); - webrtc.pc = undefined; - webrtc.mode = 0; - } - } - - - this.onRemoteUrl(); - this.onSelfUrl(); - if (sendEvent != false) { - webrtc.send( {to: webrtc.to, close: true}); - } - }, - log: function() { - if (webrtc.debug === true) { - console.log.apply(console, arguments); - } - }, - onRemoteUrl: function() {}, - onSelfUrl: function() {} -} - -function onError() { - console.log(arguments); -} - -webrtc.activateLocalStream = function() { - var media ={ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}}} ; - - // get the local stream, show it in the local video element and send it - navigator.getUserMedia(media, function (stream) { - webrtc.log('getUserMedia got stream'); - webrtc.onSelfUrl(URL.createObjectURL(stream)); - webrtc.activeMediastream = stream; - - }, function(e) { webrtc.log('getUserMedia failed during activateLocalStream ' + e); }); -} - -// run start(true) to initiate a call -webrtc.start = function (isCaller, fromUsername) { - webrtc.pc = new RTCPeerConnection(webrtc.config); - - webrtc.pc.ondatachannel = function() {webrtc.log('ondatachannel', arguments)} - webrtc.pc.onidentityresult = function() {webrtc.log('onidentityresult', arguments)} - webrtc.pc.onidpassertionerror = function() {webrtc.log('onidpassertionerror', arguments)} - webrtc.pc.onidpvalidationerror = function() {webrtc.log('onidpvalidationerror', arguments)} - webrtc.pc.onnegotiationneeded = function() {webrtc.log('onnegotiationneeded', arguments)} - webrtc.pc.onpeeridentity = function() {webrtc.log('onpeeridentity', arguments)} - webrtc.pc.onremovestream = function() {webrtc.log('onremovestream', arguments)} - webrtc.pc.onsignalingstatechange = function() {webrtc.log('onsignalingstatechange', arguments)} - - // send any ice candidates to the other peer - webrtc.pc.onicecandidate = function (evt) { - webrtc.log('onicecandidate', arguments) - if (evt.candidate) { - webrtc.send({ "candidate": evt.candidate.toJSON(), cid: webrtc.cid }); - } - }; - - // once remote stream arrives, show it in the remote video element - webrtc.pc.onaddstream = function (evt) { - webrtc.log('onaddstream', arguments); - webrtc.onRemoteUrl(URL.createObjectURL(evt.stream)); - }; - - webrtc.pc.oniceconnectionstatechange = function(evt) { - webrtc.log('oniceconnectionstatechange', arguments) - var srcElement = evt.srcElement || evt.target; - if (srcElement.iceConnectionState == 'disconnected' || srcElement.iceConnectionState == 'closed') { - if (webrtc.pc) { - webrtc.pc.getLocalStreams().forEach(function(stream) { - stream.stop(); - webrtc.onSelfUrl(); - }); - webrtc.pc.getRemoteStreams().forEach(function(stream) { - if (stream.stop) { - stream.stop(); - } - webrtc.onRemoteUrl(); - }); - webrtc.pc = undefined; - webrtc.mode = 0; - } - - } - } - - - var gotDescription = function(desc) { - webrtc.pc.setLocalDescription(desc, function() {}, onError); - webrtc.send({ "sdp": desc.toJSON(), cid: webrtc.cid }); - - } - - var CreateMonitoringOffer = function() { - - webrtc.pc.createOffer(gotDescription, onError, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } }); - - } - - var AutoConnectStream = function() { - webrtc.pc.addStream(webrtc.activeMediastream); - webrtc.pc.setRemoteDescription(new RTCSessionDescription(webrtc.remoteDataSDP)); - webrtc.pc.createAnswer(gotDescription, onError); - - } - var LocalGetUserMedia = function() { - - - - var media ={ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}}} ; - - - // get the local stream, show it in the local video element and send it - navigator.getUserMedia(media, function (stream) { - webrtc.log('getUserMedia got stream'); - webrtc.onSelfUrl(URL.createObjectURL(stream)); - - webrtc.pc.addStream(stream); - - if (isCaller) { - webrtc.pc.createOffer(gotDescription, onError); - } else { - webrtc.pc.createAnswer(gotDescription, onError); - } - - }, function(e) { webrtc.log('getUserMedia failed' + e); }); - - } - - if (isCaller) { - webrtc.log('isCaller LocalGetUserMedia'); - if (webrtc.mode) { - if (webrtc.mode === 2) { - CreateMonitoringOffer(); - } else { // node === 1 - - LocalGetUserMedia(); - } - } else { - // no mode - LocalGetUserMedia(); - } - - } else { - if (!webrtc.activeMediastream) { - swal({ - title: "Video call from "+fromUsername, - text: "Do you want to accept?", - type: "warning", - showCancelButton: true, - confirmButtonColor: "#DD6B55", - confirmButtonText: "Yes", - cancelButtonText: "No" - }, function(isConfirm){ - if (isConfirm) { - LocalGetUserMedia(); - } else { - webrtc.stop(); - } - }); - } else { - AutoConnectStream(); - } - } -} - - -webrtc.processIncomingRtcMessage = function(data, from, room) { - webrtc.log('processIncomingRtcMessage()', Meteor.userId(), data) - if (!webrtc.to) { - webrtc.to = from; - } - - if (!webrtc.room) { - webrtc.room = room; - } - - - // do not stop local video if in monitoring mode - if (data.close == true) { - - if (webrtc.activeMediastream) { - if (webrtc.pc) { - webrtc.pc.getRemoteStreams().forEach(function(stream) { - if (!stream.stop) { - stream.stop(); - } - }); - webrtc.pc = undefined; - webrtc.mode = 0; - } - - } else { - - webrtc.stop(false); - - } - return - } - - - if (!webrtc.pc) { - if ((webrtc.activeMediastream) && (data.sdp != undefined)){ - webrtc.remoteDataSDP = data.sdp; - } - webrtc.start(false, data.from); - } - - if (data.sdp != undefined) { - webrtc.pc.setRemoteDescription(new RTCSessionDescription(data.sdp)); - } else { - if( ["closed", "failed", "disconnected", "completed"].indexOf(webrtc.pc.iceConnectionState) === -1) { - webrtc.pc.addIceCandidate(new RTCIceCandidate(data.candidate)); - } - } - -} - - diff --git a/packages/rocketchat-webrtc-ib/webrtcmsg.coffee b/packages/rocketchat-webrtc-ib/webrtcmsg.coffee deleted file mode 100644 index 3bfbbd751b3..00000000000 --- a/packages/rocketchat-webrtc-ib/webrtcmsg.coffee +++ /dev/null @@ -1,8 +0,0 @@ -class IncomingRtcMessageProcessor - constructor: (message) -> - if (message.to == Meteor.userId()) - if (message.ts > webrtc.lastSeenTimestamp) - webrtc.lastSeenTimestamp = message.ts - webrtc.processIncomingRtcMessage(JSON.parse(message.msg), message.rid.replace(message.to, ''), message.rid) - -RocketChat.callbacks.add 'renderRtcMessage', IncomingRtcMessageProcessor, RocketChat.callbacks.priority.LOW -- GitLab From 1c98fd1c1738d521ddb0d5c3a60b673d48d89855 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 10:32:10 -0200 Subject: [PATCH 0242/1338] Making sure we provide proper arguments for RoomManager.updateMentionsMarksOfRoom --- client/lib/RoomHistoryManager.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/client/lib/RoomHistoryManager.coffee b/client/lib/RoomHistoryManager.coffee index 3b16390a9d0..4ec46f52de3 100644 --- a/client/lib/RoomHistoryManager.coffee +++ b/client/lib/RoomHistoryManager.coffee @@ -30,10 +30,15 @@ ts = new Date ls = undefined + 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 Meteor.call 'loadHistory', rid, ts, limit, ls, (err, result) -> room.unreadNotLoaded.set result?.unreadNotLoaded @@ -48,10 +53,9 @@ heightDiff = wrapper.scrollHeight - previousHeight wrapper.scrollTop += heightDiff - if ls - Meteor.defer -> - readMessage.refreshUnreadMark(rid, true) - RoomManager.updateMentionsMarksOfRoom subscription.t + subscription.name + Meteor.defer -> + readMessage.refreshUnreadMark(rid, true) + RoomManager.updateMentionsMarksOfRoom typeName room.isLoading.set false room.loaded += result?.messages?.length -- GitLab From 96d86cc690d2deab53bef9cf525db782fd13c8a9 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 10:43:34 -0200 Subject: [PATCH 0243/1338] Fixing ability to leave rooms. --- client/views/app/sideNav/chatRoomItem.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/sideNav/chatRoomItem.html b/client/views/app/sideNav/chatRoomItem.html index 1f434acba0d..25060876e0d 100644 --- a/client/views/app/sideNav/chatRoomItem.html +++ b/client/views/app/sideNav/chatRoomItem.html @@ -9,7 +9,7 @@ <span class='opt'> <i class="icon-eye-off hide-room" title="{{_ "Hide_room"}}"></i> {{#if canLeave}} - <i class="octicon octicon-sign-out" title="{{_ "Leave_room"}}"></i> + <i class="octicon octicon-sign-out leave-room" title="{{_ "Leave_room"}}"></i> {{/if}} </span> </a> -- GitLab From 45453b5f45dd6720e78afea927e07fe9b87ae70c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 15:26:44 +0200 Subject: [PATCH 0244/1338] Remove border radious of login inputs --- packages/rocketchat-theme/assets/stylesheets/base.less | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index fdd592a5ea5..63014bb905d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -3425,6 +3425,7 @@ a.github-fork { border-bottom: 1px solid; font-family: "Roboto", "HelveticaNeue-Light", "sans-serif"; font-weight: 400; + border-radius: 0px; &.error { border-bottom: 1px solid; &::-webkit-input-placeholder { -- GitLab From 3a6a7199eb4041086efae51311af501c4c48329a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 15:26:51 +0200 Subject: [PATCH 0245/1338] Remove logs --- packages/meteor-streams/lib/ev.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/meteor-streams/lib/ev.js b/packages/meteor-streams/lib/ev.js index b02870db4d1..b4f06e96d08 100755 --- a/packages/meteor-streams/lib/ev.js +++ b/packages/meteor-streams/lib/ev.js @@ -30,7 +30,6 @@ function _EV() { self.removeListener = function removeListener(event, callback) { if(handlers[event]) { var index = handlers[event].indexOf(callback); - console.log(index); if (index > -1) handlers[event].splice(index, 1); } -- GitLab From 7b02a77f50708a9508148878e707a74fae70da25 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 15:37:47 +0200 Subject: [PATCH 0246/1338] Add option (shift+esc) to clear all unreads --- client/views/main.coffee | 17 +++++++++++++++++ i18n/en.i18n.json | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/client/views/main.coffee b/client/views/main.coffee index 1f23684215f..19264e67241 100644 --- a/client/views/main.coffee +++ b/client/views/main.coffee @@ -8,6 +8,23 @@ Template.body.onRendered -> if e.keyCode is 27 spotlight.hide() + unread = Session.get('unread') + if e.keyCode is 27 and e.shiftKey is true and unread? and unread isnt '' + e.stopPropagation() + swal + title: t('Clear_all_unreads_question') + type: 'warning' + confirmButtonText: t('Yes_clear_all') + showCancelButton: true + cancelButtonText: t('Cancel') + confirmButtonColor: '#DD6B55' + , -> + subscriptions = ChatSubscription.find({open: true}, { fields: { unread: 1, alert: 1, rid: 1, t: 1, name: 1, ls: 1 } }) + for subscription in subscriptions.fetch() + if subscription.alert or subscription.unread > 0 + Meteor.call 'readMessages', subscription.rid + + Tracker.autorun (c) -> w = window d = document diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 6bb56e8686c..f725b4f8b1e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -81,6 +81,7 @@ "Channels" : "Channels", "Channels_list" : "List of public channels", "Chat_Rooms" : "Chat Rooms", + "Clear_all_unreads_question" : "Clear all unreads?", "close" : "close", "coming_soon" : "coming soon", "Commands" : "Commands", @@ -423,9 +424,10 @@ "Welcome_to_the" : "Welcome to the", "With_whom" : "With whom", "Yes_delete_it" : "Yes, delete it!", + "Yes_clear_all" : "Yes, clear all!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", "You_need_confirm_email" : "You need to confirm your email to login!", "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} -- GitLab From 5f989120c9dae71e8cc67dfec210094ab089657c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Sat, 24 Oct 2015 15:43:06 +0200 Subject: [PATCH 0247/1338] rocketbot -> rocketcat --- private/images/{rocketbot.ai => rocketcat.ai} | 0 public/images/logo/{rocketbot.png => rocketcat.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) rename private/images/{rocketbot.ai => rocketcat.ai} (100%) rename public/images/logo/{rocketbot.png => rocketcat.png} (100%) diff --git a/private/images/rocketbot.ai b/private/images/rocketcat.ai similarity index 100% rename from private/images/rocketbot.ai rename to private/images/rocketcat.ai diff --git a/public/images/logo/rocketbot.png b/public/images/logo/rocketcat.png similarity index 100% rename from public/images/logo/rocketbot.png rename to public/images/logo/rocketcat.png -- GitLab From bf6086add289783da8cbce2f53da89560cc82a27 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 15:44:17 +0200 Subject: [PATCH 0248/1338] Remove animation of buttons "leave" and "hide" in navbar --- packages/rocketchat-theme/assets/stylesheets/base.less | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 63014bb905d..618cda58c1c 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1500,9 +1500,7 @@ a.github-fork { opacity: 0; display: block; top: 7px; - .transform(translateX(-10px)); - .transition(opacity .12s ease .25s, - transform .15s ease-out .25s); + .transition(opacity .12s ease); i { margin: 0 1px; &:hover { -- GitLab From 0b2097b0fa1ad60c45da8a958e0ae8982b3ea585 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 15:54:13 +0200 Subject: [PATCH 0249/1338] Remove animation of plus icons in side nav --- client/views/app/sideNav/channels.html | 2 +- client/views/app/sideNav/directMessages.html | 2 +- client/views/app/sideNav/privateGroups.html | 2 +- .../assets/stylesheets/base.less | 49 ------------------- .../stylesheets/utils/_colors.import.less | 7 --- 5 files changed, 3 insertions(+), 59 deletions(-) diff --git a/client/views/app/sideNav/channels.html b/client/views/app/sideNav/channels.html index 82defaa8d0d..82f971c984f 100644 --- a/client/views/app/sideNav/channels.html +++ b/client/views/app/sideNav/channels.html @@ -2,7 +2,7 @@ <h3 class="add-room {{isActive}}"> {{_ "Channels"}} {{#if hasPermission 'create-c'}} - <i class="a-plus"></i> + <i class="icon-plus"></i> {{/if}} </h3> <ul> diff --git a/client/views/app/sideNav/directMessages.html b/client/views/app/sideNav/directMessages.html index ccb98930a55..c19c56b1f4e 100644 --- a/client/views/app/sideNav/directMessages.html +++ b/client/views/app/sideNav/directMessages.html @@ -1,7 +1,7 @@ <template name="directMessages"> <h3 class="add-room {{isActive}}"> {{_ "Direct_Messages"}} - <i class="a-plus"></i> + <i class="icon-plus"></i> </h3> <ul> {{#each rooms}} diff --git a/client/views/app/sideNav/privateGroups.html b/client/views/app/sideNav/privateGroups.html index 2d5685cc455..4c111766898 100644 --- a/client/views/app/sideNav/privateGroups.html +++ b/client/views/app/sideNav/privateGroups.html @@ -2,7 +2,7 @@ <h3 class="add-room {{isActive}}"> {{_ "Private_Groups"}} {{#if hasPermission 'create-p'}} - <i class="a-plus"></i> + <i class="icon-plus"></i> {{/if}} </h3> <ul> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 618cda58c1c..7961f37d9cd 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -762,45 +762,6 @@ label.required:after { } } -.a-plus { - display: block; - width: 25px; - height: 25px; - z-index: 100; - position: relative; - &:before, - &:after { - content: " "; - display: block; - width: 2px; - height: 10px; - position: absolute; - .calc(top, - ~"50% - 5px"); - .calc(left, - ~"50% - 1px"); - .transform-origin(50%, - 50%); - } - &:after { - .transform(rotate(90deg)); - .transition(transform .315s ease-out .1s, - background .15s ease-out); - } - &:before { - .transition(transform .315s ease-out .3s, - background .15s ease-out); - } - &:hover { - &:before { - .transform(rotate(180deg)); - } - &:after { - .transform(rotate(-90deg)); - } - } -} - a.github-fork { position: fixed; display: block; @@ -1397,16 +1358,6 @@ a.github-fork { &:hover { } &.add-room { - &:hover { - i { - &:before { - .transform(rotate(180deg)); - } - &:after { - .transform(rotate(-90deg)); - } - } - } i { position: absolute; right: 6px; diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index 0a6430eda46..78306204dd3 100644 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -282,13 +282,6 @@ label.required:after { } } -.a-plus { - &:before, - &:after { - background-color: #aaa; - } -} - a.github-fork { background-color: #5c5c5c; color: #f0f0f0; -- GitLab From 2ba0606500becd3953606369a7ed153a34e2009e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 16:34:16 +0200 Subject: [PATCH 0250/1338] Fix name of downloaded files in windows --- lib/fileUpload.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 5f1dc9ad99f..62cf49677a5 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -41,7 +41,7 @@ if UploadFS? onFinishUpload: -> console.log arguments onRead: (fileId, file, req, res) -> - res.setHeader 'content-disposition', "attachment; filename=\"#{ file.name }\"" + res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" if Meteor.isServer initFileStore() -- GitLab From 3b618e96eb1059d923fce2cf793e8441b6b317a4 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 16:53:57 +0200 Subject: [PATCH 0251/1338] Theme - Fix background of navbar fields --- .../assets/stylesheets/utils/_colors.import.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index 78306204dd3..e0cb54f452a 100644 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -431,7 +431,7 @@ a.github-fork { input[type='password'], select { border-color: @tertiary-font-color; - background-color: #04436a; + background-color: @primary-background-color; color: @input-font-color; } -- GitLab From 0b504b4ad4d5da6d08b3bda049c5c93ef6606eaf Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 13:14:35 -0200 Subject: [PATCH 0252/1338] Joining default channels on creating LDAP user --- packages/rocketchat-ldap/ldap_server.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 9b6ca2f3f8e..ba571b8b071 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -279,6 +279,9 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { Meteor.users.update(userId, {$set: { ldap: true }}); + Meteor.runAsUser(userId, function() { + Meteor.call('joinDefaultChannels'); + }); } else { // Ldap success, but no user created throw new Meteor.Error("LDAP-login-error", "LDAP Authentication succeded, but no user exists in Mongo. Either create a user for this email or set LDAP_DEFAULTS.createNewUser to true"); -- GitLab From 0b97e8c78d241dc503b79baf541d8ceb10051a6a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Sat, 24 Oct 2015 18:49:07 +0200 Subject: [PATCH 0253/1338] less verbose --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index ebaad4d327c..9980acc5751 100755 --- a/build.sh +++ b/build.sh @@ -9,7 +9,7 @@ fi cd $ROOTPATH curl -fSL "https://s3.amazonaws.com/rocketchatbuild/demo.rocket.chat-v.latest.tgz" -o rocket.chat.tgz -tar zxvf rocket.chat.tgz && rm rocket.chat.tgz +tar zxf rocket.chat.tgz && rm rocket.chat.tgz cd $ROOTPATH/bundle/programs/server npm install pm2 startOrRestart $ROOTPATH/current/$PM2FILE -- GitLab From ea4f88a6f5cbe844eed301cb4b1dbc76752b69cd Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 16:28:16 -0200 Subject: [PATCH 0254/1338] Added user sync data setting and reverting indentation. --- packages/rocketchat-ldap/config_server.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index 7d54c412493..83527605789 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -2,11 +2,12 @@ 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', i18nLabel: 'LDAP_Dn', public: true } - RocketChat.settings.add 'LDAP_Bind_Search', '' , { type: 'string' , group: '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', i18nLabel: 'LDAP_Dn', public: true } + RocketChat.settings.add 'LDAP_Bind_Search', '', { type: 'string' , group: 'LDAP' } + RocketChat.settings.add 'LDAP_Sync_User_Data', false, { type: 'boolean' , group: 'LDAP' } timer = undefined -- GitLab From e16b4c1a6c6db1cc952a567d82160ad213867cc1 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 16:29:13 -0200 Subject: [PATCH 0255/1338] Syncing common user data during login based on admin setting. --- packages/rocketchat-ldap/ldap_server.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index ba571b8b071..895d593e8b6 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -203,6 +203,9 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { // Instantiate LDAP with options var userOptions = loginRequest.ldapOptions || {}; + if (RocketChat.settings.get('LDAP_Sync_User_Data')) { + userOptions.searchResultsProfileMap = true; + } // Don't allow overwriting url and port delete userOptions.url; @@ -287,6 +290,24 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { throw new Meteor.Error("LDAP-login-error", "LDAP Authentication succeded, but no user exists in Mongo. Either create a user for this email or set LDAP_DEFAULTS.createNewUser to true"); } + if (userId && RocketChat.settings.get('LDAP_Sync_User_Data')) { + userData = {}; + if (ldapResponse.searchResults.hasOwnProperty('mail')) { + userData.emails = [{ + address: ldapResponse.searchResults.mail, + verified: true + }]; + } + + if (ldapResponse.searchResults.hasOwnProperty('name')) { + userData.name = ldapResponse.searchResults.givenName; + } + + if (_.size(userData)) { + Meteor.users.update(userId, { $set: userData }); + } + } + return { userId: userId, token: stampedToken.token -- GitLab From d0c81f9bc4809186db903cd232e455695c38f671 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 16:37:11 -0200 Subject: [PATCH 0256/1338] Added translation messages --- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 1 + 2 files changed, 2 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index f725b4f8b1e..9197358c9e5 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -185,6 +185,7 @@ "LDAP_Dn" : "Distinguished Name (DN)", "LDAP_Enable" : "Enable LDAP", "LDAP_Port" : "LDAP Port", + "LDAP_Sync_User_Data" : "Keep user data in sync with server", "LDAP_Url" : "LDAP URL", "Leave_room" : "Leave room", "line" : "line", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index a3008e91087..92f93a4ea49 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -171,6 +171,7 @@ "LDAP" : "LDAP", "LDAP_Dn" : "DN LDAP", "LDAP_Port" : "Porta LDAP", + "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", "LDAP_Url" : "URL LDAP", "Leave_room" : "Sair da sala", "line" : "linha", -- GitLab From 6bf476b49ff99aca22166e7586f5a019d9f65ac9 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sat, 24 Oct 2015 16:52:01 -0200 Subject: [PATCH 0257/1338] Supporting single and multi e-mails addresses --- packages/rocketchat-ldap/ldap_server.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 895d593e8b6..b54011c73aa 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -293,10 +293,17 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { if (userId && RocketChat.settings.get('LDAP_Sync_User_Data')) { userData = {}; if (ldapResponse.searchResults.hasOwnProperty('mail')) { - userData.emails = [{ - address: ldapResponse.searchResults.mail, - verified: true - }]; + + if ('object' == typeof ldapResponse.searchResults.mail) { + userData.emails = _.map(ldapResponse.searchResults.mail, function (item) { + return { address: item, verified: true}; + }); + } else { + userData.emails = [{ + address: ldapResponse.searchResults.mail, + verified: true + }]; + } } if (ldapResponse.searchResults.hasOwnProperty('name')) { -- GitLab From 1a3a8f464f13628655449f398164acc4a1c1c573 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 21:35:04 +0200 Subject: [PATCH 0258/1338] Init tutum integration --- .meteor/packages | 1 + .meteor/versions | 1 + .../rocketchat-tutum/.npm/package/.gitignore | 1 + packages/rocketchat-tutum/.npm/package/README | 7 +++++++ .../.npm/package/npm-shrinkwrap.json | 12 +++++++++++ packages/rocketchat-tutum/package.js | 20 +++++++++++++++++++ packages/rocketchat-tutum/startup.coffee | 19 ++++++++++++++++++ 7 files changed, 61 insertions(+) create mode 100644 packages/rocketchat-tutum/.npm/package/.gitignore create mode 100644 packages/rocketchat-tutum/.npm/package/README create mode 100644 packages/rocketchat-tutum/.npm/package/npm-shrinkwrap.json create mode 100644 packages/rocketchat-tutum/package.js create mode 100644 packages/rocketchat-tutum/startup.coffee diff --git a/.meteor/packages b/.meteor/packages index 21af9041330..d16b2be6adf 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -109,3 +109,4 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter +rocketchat:tutum diff --git a/.meteor/versions b/.meteor/versions index ff18b148896..3c291beba49 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -145,6 +145,7 @@ rocketchat:soundcloud@0.0.1 rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 rocketchat:theme@0.0.1 +rocketchat:tutum@0.0.1 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 diff --git a/packages/rocketchat-tutum/.npm/package/.gitignore b/packages/rocketchat-tutum/.npm/package/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/packages/rocketchat-tutum/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/rocketchat-tutum/.npm/package/README b/packages/rocketchat-tutum/.npm/package/README new file mode 100644 index 00000000000..3d492553a43 --- /dev/null +++ b/packages/rocketchat-tutum/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/rocketchat-tutum/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-tutum/.npm/package/npm-shrinkwrap.json new file mode 100644 index 00000000000..f1a4a466ed7 --- /dev/null +++ b/packages/rocketchat-tutum/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,12 @@ +{ + "dependencies": { + "redis": { + "version": "2.2.5", + "dependencies": { + "double-ended-queue": { + "version": "2.1.0-0" + } + } + } + } +} diff --git a/packages/rocketchat-tutum/package.js b/packages/rocketchat-tutum/package.js new file mode 100644 index 00000000000..34a218788a3 --- /dev/null +++ b/packages/rocketchat-tutum/package.js @@ -0,0 +1,20 @@ +Package.describe({ + name: 'rocketchat:tutum', + version: '0.0.1', + summary: 'RocketChat tutum integration' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + api.use('coffeescript'); + + api.addFiles('startup.coffee', 'server'); +}); + +Npm.depends({ + 'redis': '2.2.5' +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee new file mode 100644 index 00000000000..2eee34f3b4a --- /dev/null +++ b/packages/rocketchat-tutum/startup.coffee @@ -0,0 +1,19 @@ +### Examples + +TUTUM_REDIS_HOST=127.0.0.1 +TUTUM_REDIS_PORT=6379 +TUTUM_CLIENT_HOST=mywebsite +TUTUM_CLIENT_NAME=www.dotcloud.com +TUTUM_CLIENT_ADDRESS=http://192.168.0.42:80 +### + +if process.env.TUTUM_REDIS_HOST? + redis = Npm.require 'redis' + + process.env.TUTUM_REDIS_PORT ?= 6379 + + client = redis.createClient(process.env.TUTUM_REDIS_PORT, process.env.TUTUM_REDIS_HOST) + + client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") + client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', process.env.TUTUM_CLIENT_NAME) + client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', process.env.TUTUM_CLIENT_ADDRESS) -- GitLab From c673c76c92a03862b11efe24d2fce15075ec7f83 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 21:38:53 +0200 Subject: [PATCH 0259/1338] Fix spelling --- packages/rocketchat-tutum/startup.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee index 2eee34f3b4a..1679930674a 100644 --- a/packages/rocketchat-tutum/startup.coffee +++ b/packages/rocketchat-tutum/startup.coffee @@ -2,8 +2,8 @@ TUTUM_REDIS_HOST=127.0.0.1 TUTUM_REDIS_PORT=6379 -TUTUM_CLIENT_HOST=mywebsite -TUTUM_CLIENT_NAME=www.dotcloud.com +TUTUM_CLIENT_NAME=mywebsite +TUTUM_CLIENT_HOST=www.dotcloud.com TUTUM_CLIENT_ADDRESS=http://192.168.0.42:80 ### -- GitLab From 1122af087ae813f539d98d2d56db9952828b0f63 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 23:05:17 +0200 Subject: [PATCH 0260/1338] Use internal ip to setup redis --- packages/rocketchat-tutum/startup.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee index 1679930674a..09d747cb39a 100644 --- a/packages/rocketchat-tutum/startup.coffee +++ b/packages/rocketchat-tutum/startup.coffee @@ -3,11 +3,10 @@ TUTUM_REDIS_HOST=127.0.0.1 TUTUM_REDIS_PORT=6379 TUTUM_CLIENT_NAME=mywebsite -TUTUM_CLIENT_HOST=www.dotcloud.com -TUTUM_CLIENT_ADDRESS=http://192.168.0.42:80 +TUTUM_CLIENT_HOST=mywebsite.dotcloud.com ### -if process.env.TUTUM_REDIS_HOST? +if process.env.TUTUM_REDIS_HOST? and process.env.TUTUM_CONTAINER_API_URL? redis = Npm.require 'redis' process.env.TUTUM_REDIS_PORT ?= 6379 @@ -16,4 +15,4 @@ if process.env.TUTUM_REDIS_HOST? client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', process.env.TUTUM_CLIENT_NAME) - client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', process.env.TUTUM_CLIENT_ADDRESS) + client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', "http://#{process.env.TUTUM_IP_ADDRESS.split('/')[0]}:3000") -- GitLab From 5edc5048459005a15426fa529fa0d1178c267ed7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 24 Oct 2015 23:31:41 +0200 Subject: [PATCH 0261/1338] Change the redis connection to allow auth --- packages/rocketchat-tutum/startup.coffee | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee index 09d747cb39a..6757de359fc 100644 --- a/packages/rocketchat-tutum/startup.coffee +++ b/packages/rocketchat-tutum/startup.coffee @@ -1,18 +1,15 @@ ### Examples -TUTUM_REDIS_HOST=127.0.0.1 -TUTUM_REDIS_PORT=6379 +TUTUM_REDIS_HOST=redis://:password@host:6379 TUTUM_CLIENT_NAME=mywebsite TUTUM_CLIENT_HOST=mywebsite.dotcloud.com ### -if process.env.TUTUM_REDIS_HOST? and process.env.TUTUM_CONTAINER_API_URL? +if process.env.TUTUM_REDIS_HOST? redis = Npm.require 'redis' - process.env.TUTUM_REDIS_PORT ?= 6379 - - client = redis.createClient(process.env.TUTUM_REDIS_PORT, process.env.TUTUM_REDIS_HOST) + client = redis.createClient(process.env.TUTUM_REDIS_HOST) client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") - client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', process.env.TUTUM_CLIENT_NAME) - client.rpush('frontend:#{process.env.TUTUM_CLIENT_HOST}', "http://#{process.env.TUTUM_IP_ADDRESS.split('/')[0]}:3000") + client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", process.env.TUTUM_CLIENT_NAME) + client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", "http://#{process.env.TUTUM_IP_ADDRESS.split('/')[0]}:3000") -- GitLab From 62d1bc657f22af43ea1e89e351677351cb039c5f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Sun, 25 Oct 2015 12:29:51 +0100 Subject: [PATCH 0262/1338] Use process.env values on first inserting settings. --- packages/rocketchat-lib/settings/server/methods.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 729522f1642..dab38c13425 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -10,7 +10,9 @@ RocketChat.settings.add = (_id, value, options = {}) -> # console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments - if Meteor.settings?[_id]? + if process?.env?[_id]? + value = process.env[_id] + else if Meteor.settings?[_id]? value = Meteor.settings[_id] updateSettings = -- GitLab From 2a3bb638eadc8dd44be78623abb420c3423fbbbb Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sun, 25 Oct 2015 15:15:19 -0200 Subject: [PATCH 0263/1338] Added admin setting for fiel mapping between LDAP -> RocketChat --- packages/rocketchat-ldap/config_server.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index 83527605789..1782d782b4d 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -8,6 +8,7 @@ Meteor.startup -> RocketChat.settings.add 'LDAP_DN', '', { type: 'string' , group: 'LDAP', i18nLabel: 'LDAP_Dn', 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' } timer = undefined -- GitLab From efe01c6e502c1f629448a825f43435ba24020540 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Sun, 25 Oct 2015 15:16:35 -0200 Subject: [PATCH 0264/1338] Refactoring - added support for dynamic field mapping --- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 1 + packages/rocketchat-ldap/ldap_server.js | 54 +++++++++++++++++-------- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9197358c9e5..3925308acac 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -186,6 +186,7 @@ "LDAP_Enable" : "Enable LDAP", "LDAP_Port" : "LDAP Port", "LDAP_Sync_User_Data" : "Keep user data in sync with server", + "LDAP_Sync_User_Data_FieldMap" : "User data field map", "LDAP_Url" : "LDAP URL", "Leave_room" : "Leave room", "line" : "line", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 92f93a4ea49..b54800e035b 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -172,6 +172,7 @@ "LDAP_Dn" : "DN LDAP", "LDAP_Port" : "Porta LDAP", "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", + "LDAP_Sync_User_Data_FieldMap" : "Mapeamento de campos do usuário", "LDAP_Url" : "URL LDAP", "Leave_room" : "Sair da sala", "line" : "linha", diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index b54011c73aa..68b8beb8c50 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -3,7 +3,7 @@ Future = Npm.require('fibers/future'); var slug = function (text) { text = slugify(text, '.'); return text.replace(/[^0-9a-z-_.]/g, ''); -} +}; // At a minimum, set up LDAP_DEFAULTS.url and .dn according to // your needs. url should appear as "ldap://your.url.here" @@ -86,7 +86,7 @@ LDAP.prototype.ldapCheck = function(options) { var bind = function(dn) { dn = dn.replace(/#{username}/g, options.username); - console.log('Attempt to bind', dn) + console.log('Attempt to bind', dn); //Attempt to bind to ldap server with provided info client.bind(dn, options.ldapPass, function(err) { try { @@ -127,7 +127,7 @@ LDAP.prototype.ldapCheck = function(options) { }); } }); - } + }; if (LDAP_DEFAULTS.bindSearch && LDAP_DEFAULTS.bindSearch.trim() != '') { try { @@ -290,29 +290,49 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { throw new Meteor.Error("LDAP-login-error", "LDAP Authentication succeded, but no user exists in Mongo. Either create a user for this email or set LDAP_DEFAULTS.createNewUser to true"); } - if (userId && RocketChat.settings.get('LDAP_Sync_User_Data')) { + // LDAP sync data logic + syncUserData = RocketChat.settings.get('LDAP_Sync_User_Data'); + syncUserDataFieldMap = RocketChat.settings.get('LDAP_Sync_User_Data_FieldMap').trim(); + if (userId && syncUserData && syncUserDataFieldMap) { userData = {}; - if (ldapResponse.searchResults.hasOwnProperty('mail')) { + fieldMap = JSON.parse(syncUserDataFieldMap); - if ('object' == typeof ldapResponse.searchResults.mail) { - userData.emails = _.map(ldapResponse.searchResults.mail, function (item) { - return { address: item, verified: true}; - }); - } else { - userData.emails = [{ - address: ldapResponse.searchResults.mail, - verified: true - }]; + emailList = []; + _.map(fieldMap, function(userField, ldapField) { + if (!ldapResponse.searchResults.hasOwnProperty(ldapField)) { + return; } - } - if (ldapResponse.searchResults.hasOwnProperty('name')) { - userData.name = ldapResponse.searchResults.givenName; + // restrict field mapping to a known list of fields + switch (userField) { + + case 'email': + if ('object' == typeof ldapResponse.searchResults[ldapField]) { + _.map(ldapResponse.searchResults[ldapField], function (item) { + emailList.push({ address: item, verified: true }); + }); + } else { + emailList.push({ address: ldapResponse.searchResults[ldapField], verified: true }); + } + break; + + case 'name': + userData.name = ldapResponse.searchResults[ldapField]; + break; + + default: + break; + } + }); + + if (emailList.length) { + userData.emails = emailList; } if (_.size(userData)) { Meteor.users.update(userId, { $set: userData }); } + } return { -- GitLab From 79b0097139564727aa54a62bcadfaf1d4ebf0861 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 26 Oct 2015 09:46:08 +0100 Subject: [PATCH 0265/1338] Closes #1213; Fix popup "new message" from not visible rooms --- client/views/app/message.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 01e2b06a639..27151ef7fe3 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -118,5 +118,5 @@ Template.message.onViewRendered = (context) -> view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom = true else if view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom isnt true - newMessage = document.querySelector(".new-message") + newMessage = view.parentView.parentView.parentView.parentView.parentView.templateInstance().find(".new-message") newMessage?.className = "new-message" -- GitLab From b8d0e284d90a7c0d520e3d7e3c590b6a8c1b6d45 Mon Sep 17 00:00:00 2001 From: Carsten <acidicX@users.noreply.github.com> Date: Mon, 26 Oct 2015 11:55:26 +0100 Subject: [PATCH 0266/1338] Update readme Added Firefox OS to WIP --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4c5013e8d0b..47dfcf1217f 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ It is a great solution for communities and companies wanting to privately host t - Support for PostgreSQL: [Issue #533](https://github.com/RocketChat/Rocket.Chat/issues/533), [Issue #822](https://github.com/RocketChat/Rocket.Chat/issues/822) - Native iOS Application [Issue #270](https://github.com/RocketChat/Rocket.Chat/issues/270), [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) - Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) +- Native Firefox OS Application [Issue #1204](https://github.com/RocketChat/Rocket.Chat/issues/1204) - Off-the-Record (OTR) Messaging [Issue #36](https://github.com/RocketChat/Rocket.Chat/issues/36), [Issue #268 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/268) - API-enabled methods: [Issue #202](https://github.com/RocketChat/Rocket.Chat/issues/202), [Issue #454](https://github.com/RocketChat/Rocket.Chat/issues/454), [Issue #455](https://github.com/RocketChat/Rocket.Chat/issues/455), [Issue #759](https://github.com/RocketChat/Rocket.Chat/issues/759) - Scalable WebRTC broadcaster / media-server integration, [Issue #1118 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/1118) -- GitLab From 365f236ee28a26a7d426fed6f9456546bf4754bf Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sat, 24 Oct 2015 13:24:38 +0100 Subject: [PATCH 0267/1338] Updating i18n/en.i18n.json. Translating CDN_PREFIX. --- i18n/en.i18n.json | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index f725b4f8b1e..6036bde99ec 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -51,6 +51,7 @@ "Administration" : "Administration", "All_channels" : "All channels", "Allow_Invalid_SelfSigned_Certs" : "Allow invalid and Self-Signed SSL certificate's for link validation and previews", + "CDN_PREFIX" : "CDN Prefix", "and" : "and", "API" : "API", "API_Analytics" : "Analytics", -- GitLab From ec7a050ed851a727862e757b347dfdb8994c2736 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sat, 24 Oct 2015 13:26:54 +0100 Subject: [PATCH 0268/1338] Updating i18n/en.i18n.json. Translating Room_uploaded_file_list. --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 6036bde99ec..498eecef72a 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -303,7 +303,7 @@ "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_uploaded_file_list" : "Files list", + "Room_uploaded_file_list" : "Files List", "Room_uploaded_file_list_empty" : "No files available.", "room_user_count" : "%s users", "Rooms" : "Rooms", -- GitLab From 0443c1f6de8ab24a0d19bc9d5e73494bb656818d Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Mon, 26 Oct 2015 10:33:20 +0000 Subject: [PATCH 0269/1338] Updating i18n/en.i18n.json. Fixing incorrect Message_MaxAllowedSize translation. --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 498eecef72a..feca05d095a 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -212,7 +212,7 @@ "Message_deleting_not_allowed" : "Message deleting not allowed", "Message_editing_not_allowed" : "Message editing not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", - "Message_MaxAllowedSize" : "Maximum Allowed Messages", + "Message_MaxAllowedSize" : "Maximum Allowed Message Size", "Message_pinning_not_allowed" : "Message pinning not allowed", "Message_AllowPinning" : "Allow Message Pinning", "Message_KeepHistory" : "Keep Message History", -- GitLab From 78c7822c0d7c7b59bc69ceec38454c8f254446a3 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sat, 24 Oct 2015 14:27:17 +0100 Subject: [PATCH 0270/1338] Resetting TabBar on render. --- client/views/app/privateHistory.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/views/app/privateHistory.coffee b/client/views/app/privateHistory.coffee index 91d0aed6e00..b04ecd4f803 100644 --- a/client/views/app/privateHistory.coffee +++ b/client/views/app/privateHistory.coffee @@ -30,6 +30,9 @@ 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 -- GitLab From 5a72c5a15e3eb0766bebeba367d38e38e126c23b Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Mon, 26 Oct 2015 11:19:11 +0000 Subject: [PATCH 0271/1338] Fixing 'undefined' button titles. --- client/views/admin/users/adminUsers.coffee | 8 ++++---- packages/rocketchat-lib/client/lib/openRoom.coffee | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/views/admin/users/adminUsers.coffee b/client/views/admin/users/adminUsers.coffee index 3883baba47d..098901fb5b2 100644 --- a/client/views/admin/users/adminUsers.coffee +++ b/client/views/admin/users/adminUsers.coffee @@ -37,7 +37,7 @@ Template.adminUsers.onCreated -> @filter = new ReactiveVar '' @ready = new ReactiveVar true - RocketChat.TabBar.addButton({ id: 'invite-user', title: t('Invite_Users'), icon: 'icon-plus', template: 'adminInviteUser', order: 1 }) + RocketChat.TabBar.addButton({ id: 'invite-user', i18nTitle: t('Invite_Users'), icon: 'icon-plus', template: 'adminInviteUser', order: 1 }) @autorun -> filter = instance.filter.get() @@ -49,11 +49,11 @@ 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', title: t('User_Info'), icon: 'icon-user', template: 'adminUserInfo', order: 2 }) - # RocketChat.TabBar.addButton({ id: 'user-channel', title: t('User_Channels'), icon: 'icon-hash', template: 'adminUserChannels', order: 3 }) + 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 }) else RocketChat.TabBar.reset() - RocketChat.TabBar.addButton({ id: 'invite-user', title: t('Invite_Users'), icon: 'icon-plus', template: 'adminInviteUser', order: 1 }) + RocketChat.TabBar.addButton({ id: 'invite-user', i18nTitle: t('Invite_Users'), icon: 'icon-plus', template: 'adminInviteUser', order: 1 }) @users = -> filter = _.trim instance.filter?.get() diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 9176289077e..c4dae8c00a1 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -51,12 +51,12 @@ currentTracker = undefined , 100 RocketChat.TabBar.resetButtons() - RocketChat.TabBar.addButton({ id: 'message-search', title: t('Search'), icon: 'octicon octicon-search', template: 'messageSearch', order: 1 }) + 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', title: t('User_Info'), icon: 'octicon octicon-person', template: 'membersList', order: 2 }) + 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', title: t('Members_List'), icon: 'octicon octicon-organization', template: 'membersList', order: 2 }) - RocketChat.TabBar.addButton({ id: 'uploaded-files-list', title: t('Room_uploaded_file_list'), icon: 'octicon octicon-file-symlink-directory', template: 'uploadedFilesList', order: 3 }) + 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 -- GitLab From 1216405a17e37ef5ab297e5da53650a32e5cb52e Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Wed, 21 Oct 2015 11:59:08 +0100 Subject: [PATCH 0272/1338] Chmodding files from 100755 to 100644. --- client/lib/customEventPolyfill.js | 0 packages/meteor-accounts-saml/saml_client.js | 0 packages/meteor-accounts-saml/saml_server.js | 0 packages/meteor-accounts-saml/saml_utils.js | 0 packages/meteor-streams/LICENSE | 0 packages/meteor-streams/README.md | 0 packages/meteor-streams/lib/client.js | 0 packages/meteor-streams/lib/ev.js | 0 packages/meteor-streams/lib/server.js | 0 packages/meteor-streams/lib/stream_permission.js | 0 packages/meteor-streams/package.js | 0 packages/rocketchat-favico/favico.js | 0 packages/rocketchat-favico/package.js | 0 .../client/stylesheets/utils/_keyframes.import.less | 0 .../client/stylesheets/utils/_lesshat.import.less | 0 packages/rocketchat-livechat/package.js | 0 packages/rocketchat-logger/package.js | 0 .../assets/stylesheets/utils/_keyframes.import.less | 0 .../assets/stylesheets/utils/_lesshat.import.less | 0 .../assets/stylesheets/utils/_octicons.less | 0 public/fonts/github/octicons.eot | Bin public/fonts/github/octicons.svg | 0 public/fonts/github/octicons.ttf | Bin public/fonts/github/octicons.woff | Bin public/images/logo/android-hdpi.png | Bin public/images/logo/android-mdpi.png | Bin public/images/logo/android-xhdpi.png | Bin public/images/logo/android-xxhdpi.png | Bin public/images/logo/android-xxxhdpi.png | Bin 29 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 client/lib/customEventPolyfill.js mode change 100755 => 100644 packages/meteor-accounts-saml/saml_client.js mode change 100755 => 100644 packages/meteor-accounts-saml/saml_server.js mode change 100755 => 100644 packages/meteor-accounts-saml/saml_utils.js mode change 100755 => 100644 packages/meteor-streams/LICENSE mode change 100755 => 100644 packages/meteor-streams/README.md mode change 100755 => 100644 packages/meteor-streams/lib/client.js mode change 100755 => 100644 packages/meteor-streams/lib/ev.js mode change 100755 => 100644 packages/meteor-streams/lib/server.js mode change 100755 => 100644 packages/meteor-streams/lib/stream_permission.js mode change 100755 => 100644 packages/meteor-streams/package.js mode change 100755 => 100644 packages/rocketchat-favico/favico.js mode change 100755 => 100644 packages/rocketchat-favico/package.js mode change 100755 => 100644 packages/rocketchat-livechat/app/client/stylesheets/utils/_keyframes.import.less mode change 100755 => 100644 packages/rocketchat-livechat/app/client/stylesheets/utils/_lesshat.import.less mode change 100755 => 100644 packages/rocketchat-livechat/package.js mode change 100755 => 100644 packages/rocketchat-logger/package.js mode change 100755 => 100644 packages/rocketchat-theme/assets/stylesheets/utils/_keyframes.import.less mode change 100755 => 100644 packages/rocketchat-theme/assets/stylesheets/utils/_lesshat.import.less mode change 100755 => 100644 packages/rocketchat-theme/assets/stylesheets/utils/_octicons.less mode change 100755 => 100644 public/fonts/github/octicons.eot mode change 100755 => 100644 public/fonts/github/octicons.svg mode change 100755 => 100644 public/fonts/github/octicons.ttf mode change 100755 => 100644 public/fonts/github/octicons.woff mode change 100755 => 100644 public/images/logo/android-hdpi.png mode change 100755 => 100644 public/images/logo/android-mdpi.png mode change 100755 => 100644 public/images/logo/android-xhdpi.png mode change 100755 => 100644 public/images/logo/android-xxhdpi.png mode change 100755 => 100644 public/images/logo/android-xxxhdpi.png diff --git a/client/lib/customEventPolyfill.js b/client/lib/customEventPolyfill.js old mode 100755 new mode 100644 diff --git a/packages/meteor-accounts-saml/saml_client.js b/packages/meteor-accounts-saml/saml_client.js old mode 100755 new mode 100644 diff --git a/packages/meteor-accounts-saml/saml_server.js b/packages/meteor-accounts-saml/saml_server.js old mode 100755 new mode 100644 diff --git a/packages/meteor-accounts-saml/saml_utils.js b/packages/meteor-accounts-saml/saml_utils.js old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/LICENSE b/packages/meteor-streams/LICENSE old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/README.md b/packages/meteor-streams/README.md old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/lib/client.js b/packages/meteor-streams/lib/client.js old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/lib/ev.js b/packages/meteor-streams/lib/ev.js old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/lib/server.js b/packages/meteor-streams/lib/server.js old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/lib/stream_permission.js b/packages/meteor-streams/lib/stream_permission.js old mode 100755 new mode 100644 diff --git a/packages/meteor-streams/package.js b/packages/meteor-streams/package.js old mode 100755 new mode 100644 diff --git a/packages/rocketchat-favico/favico.js b/packages/rocketchat-favico/favico.js old mode 100755 new mode 100644 diff --git a/packages/rocketchat-favico/package.js b/packages/rocketchat-favico/package.js old mode 100755 new mode 100644 diff --git a/packages/rocketchat-livechat/app/client/stylesheets/utils/_keyframes.import.less b/packages/rocketchat-livechat/app/client/stylesheets/utils/_keyframes.import.less old mode 100755 new mode 100644 diff --git a/packages/rocketchat-livechat/app/client/stylesheets/utils/_lesshat.import.less b/packages/rocketchat-livechat/app/client/stylesheets/utils/_lesshat.import.less old mode 100755 new mode 100644 diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js old mode 100755 new mode 100644 diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js old mode 100755 new mode 100644 diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_keyframes.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_keyframes.import.less old mode 100755 new mode 100644 diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_lesshat.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_lesshat.import.less old mode 100755 new mode 100644 diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_octicons.less b/packages/rocketchat-theme/assets/stylesheets/utils/_octicons.less old mode 100755 new mode 100644 diff --git a/public/fonts/github/octicons.eot b/public/fonts/github/octicons.eot old mode 100755 new mode 100644 diff --git a/public/fonts/github/octicons.svg b/public/fonts/github/octicons.svg old mode 100755 new mode 100644 diff --git a/public/fonts/github/octicons.ttf b/public/fonts/github/octicons.ttf old mode 100755 new mode 100644 diff --git a/public/fonts/github/octicons.woff b/public/fonts/github/octicons.woff old mode 100755 new mode 100644 diff --git a/public/images/logo/android-hdpi.png b/public/images/logo/android-hdpi.png old mode 100755 new mode 100644 diff --git a/public/images/logo/android-mdpi.png b/public/images/logo/android-mdpi.png old mode 100755 new mode 100644 diff --git a/public/images/logo/android-xhdpi.png b/public/images/logo/android-xhdpi.png old mode 100755 new mode 100644 diff --git a/public/images/logo/android-xxhdpi.png b/public/images/logo/android-xxhdpi.png old mode 100755 new mode 100644 diff --git a/public/images/logo/android-xxxhdpi.png b/public/images/logo/android-xxxhdpi.png old mode 100755 new mode 100644 -- GitLab From 066a3687293dee1a24b6626be9b9154162cb4b95 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sat, 24 Oct 2015 13:30:33 +0100 Subject: [PATCH 0273/1338] Fixing spelling error: 'sportlight' -> 'spotlight'. --- .../views/app/{sportlight => spotlight}/mobileMessageMenu.coffee | 0 client/views/app/{sportlight => spotlight}/mobileMessageMenu.html | 0 client/views/app/{sportlight => spotlight}/spotlight.coffee | 0 client/views/app/{sportlight => spotlight}/spotlight.html | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename client/views/app/{sportlight => spotlight}/mobileMessageMenu.coffee (100%) rename client/views/app/{sportlight => spotlight}/mobileMessageMenu.html (100%) rename client/views/app/{sportlight => spotlight}/spotlight.coffee (100%) rename client/views/app/{sportlight => spotlight}/spotlight.html (100%) diff --git a/client/views/app/sportlight/mobileMessageMenu.coffee b/client/views/app/spotlight/mobileMessageMenu.coffee similarity index 100% rename from client/views/app/sportlight/mobileMessageMenu.coffee rename to client/views/app/spotlight/mobileMessageMenu.coffee diff --git a/client/views/app/sportlight/mobileMessageMenu.html b/client/views/app/spotlight/mobileMessageMenu.html similarity index 100% rename from client/views/app/sportlight/mobileMessageMenu.html rename to client/views/app/spotlight/mobileMessageMenu.html diff --git a/client/views/app/sportlight/spotlight.coffee b/client/views/app/spotlight/spotlight.coffee similarity index 100% rename from client/views/app/sportlight/spotlight.coffee rename to client/views/app/spotlight/spotlight.coffee diff --git a/client/views/app/sportlight/spotlight.html b/client/views/app/spotlight/spotlight.html similarity index 100% rename from client/views/app/sportlight/spotlight.html rename to client/views/app/spotlight/spotlight.html -- GitLab From 20881c7493a23a268b0fe91e1d07f67d1ccbc288 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sat, 24 Oct 2015 13:30:51 +0100 Subject: [PATCH 0274/1338] Removing seemingly unused html. --- client/views/app/flexTabBar.html | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/client/views/app/flexTabBar.html b/client/views/app/flexTabBar.html index 01a5b3014aa..60f0bde69ba 100644 --- a/client/views/app/flexTabBar.html +++ b/client/views/app/flexTabBar.html @@ -4,22 +4,4 @@ <i class="{{icon}}"></i> </div> {{/each}} - {{!-- <div class="tab-button" data-target="messageSearch" title="Search"> - <i class="icon-search" aria-label="{{_ "Search"}}"></i> - </div> - <div class="tab-button" data-target="membersList" title="Member List"> - <i class="icon-users" aria-label="{{_ "Members_List"}}"></i> - </div> --}} - {{!-- <div class="tab-button" data-target="pinned-messages" title="Pinned Messages"> - <i class="icon-pin"></i> - </div> - <div class="tab-button" data-target="room-files" title="Files"> - <i class="icon-hdd"></i> - </div> - <div class="tab-button" data-target="chat-ops" title="ChatOps"> - <i class="icon-code"></i> - </div> - <div class="tab-button" data-target="channel-settings" title="Channel Settings"> - <i class="icon-cog"></i> - </div> --}} </template> -- GitLab From 8e87d96c8fede14c0b42e5de3601cc19363b54b2 Mon Sep 17 00:00:00 2001 From: Oliver Beddows <oliver.beddows@googlemail.com> Date: Sat, 24 Oct 2015 14:29:43 +0100 Subject: [PATCH 0275/1338] Removing disabled code. --- client/views/app/flexTabBar.coffee | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/client/views/app/flexTabBar.coffee b/client/views/app/flexTabBar.coffee index 53d12dae07d..0177eb907c6 100644 --- a/client/views/app/flexTabBar.coffee +++ b/client/views/app/flexTabBar.coffee @@ -25,15 +25,3 @@ Template.flexTabBar.events RocketChat.TabBar.setTemplate $(e.currentTarget).data('template'), -> $('.flex-tab')?.find("input[type='text']:first")?.focus() $('.flex-tab .content')?.scrollTop(0) - - # if Session.get('flexOpened') and Session.equals('whichFlexOpened', $(e.currentTarget).data('target')) - # Session.set('rtcLayoutmode', 0) - # Session.set('flexOpened',false) - # Session.set('whichFlexOpened') - # else - # $(e.currentTarget).addClass 'active' - # Session.set('flexOpened', true) - # Session.set('whichFlexOpened', $(e.currentTarget).data('target')) - - # # $('.user-info-content').hide() - # # $($(e.currentTarget).attr('href')).show() -- GitLab From fb6673656377e5aa8d84aa4877618aae4ba38485 Mon Sep 17 00:00:00 2001 From: Colin Shea <colin@evaryont.me> Date: Mon, 26 Oct 2015 23:02:15 +0000 Subject: [PATCH 0276/1338] Use user-select: text; to re-enable selections Firefox interprets user-select: all; to mean that any clicks should result in the entire element's container being selected, regardless of the user's gesture. This results in the inability to select only a subset of characters in a chat message. Fixes #1242 --- .../assets/stylesheets/base.less | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 7961f37d9cd..5ba2377c46f 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2291,15 +2291,15 @@ a.github-fork { min-height: 40px; .body, .user.user-card-message, .time { - -webkit-user-select: all; - -moz-user-select: all; - -ms-user-select: all; - user-select: all; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; * { - -webkit-user-select: all; - -moz-user-select: all; - -ms-user-select: all; - user-select: all; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; } } -- GitLab From 9fa691133556eb099221e73fa404c1a2a7b696b7 Mon Sep 17 00:00:00 2001 From: Erwin Goslawski <apps@cygery.com> Date: Tue, 27 Oct 2015 08:51:52 +0100 Subject: [PATCH 0277/1338] Updated version of qnub:emojione New version supports more representations of emojis containing an apostrophe and tooltips for emoji images using the title attribute which contains the text representation of the emoji (either shortcode or ASCII string). --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index 3c291beba49..d6c44e8a020 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -108,7 +108,7 @@ percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.0 -qnub:emojione@0.0.3 +qnub:emojione@1.5.1_1 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 -- GitLab From 8db4d65053bf5f2f914bdc7d023892baf6f68db4 Mon Sep 17 00:00:00 2001 From: Muhammad Mustadi <muhammad.mustadi@gmail.com> Date: Tue, 27 Oct 2015 15:48:56 +0700 Subject: [PATCH 0278/1338] fix typo in function getPupupConfig --- client/views/app/room.coffee | 2 +- client/views/app/room.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 35f2083b865..a3e30778731 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -159,7 +159,7 @@ Template.room.helpers else return t('See_all') - getPupupConfig: -> + getPopupConfig: -> template = Template.instance() return { getInput: -> diff --git a/client/views/app/room.html b/client/views/app/room.html index 6189f9058b1..3c2380b3929 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -86,7 +86,7 @@ <input type="file" accept="{{fileUploadAllowedMediaTypes}}"> </div> <div class="input-message-container"> - {{> messagePopupConfig getPupupConfig}} + {{> messagePopupConfig getPopupConfig}} <textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea> </div> @@ -154,4 +154,4 @@ {{> Template.dynamic template=flexTemplate data=flexData}} </section> </div> -</template> \ No newline at end of file +</template> -- GitLab From 2d2fdf0cd1da982a5fffd3c864218706fe108dc0 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 09:44:34 -0200 Subject: [PATCH 0279/1338] Applying velocity-cli for application test in CI mode --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 72fd45e59af..a7854560513 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,9 +22,7 @@ before_install: - export JASMINE_DEBUG=1 - export VELOCITY_DEBUG=1 - export VELOCITY_DEBUG_MIRROR=1 - script: - meteor add sanjo:jasmine velocity:console-reporter -- meteor update - ./node_modules/velocity-cli/bin/velocity test-packages --ci -- meteor --test --once +- ./node_modules/velocity-cli/bin/velocity test-app --ci -- GitLab From 80f8573ea32d1878d97ce4825c3dd743052b747e Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 09:57:21 -0200 Subject: [PATCH 0280/1338] Updating meteor --- .meteor/release | 2 +- .meteor/versions | 52 ++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.meteor/release b/.meteor/release index 5684262a835..3a05e0a2f70 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.2.0.2 +METEOR@1.2.1 diff --git a/.meteor/versions b/.meteor/versions index d6c44e8a020..b2a52c59f3e 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,15 +1,15 @@ -accounts-base@1.2.1 +accounts-base@1.2.2 accounts-facebook@1.0.6 accounts-github@1.0.6 accounts-google@1.0.6 accounts-meteor-developer@1.0.6 -accounts-oauth@1.1.7 -accounts-password@1.1.3 +accounts-oauth@1.1.8 +accounts-password@1.1.4 accounts-twitter@1.0.6 alanning:roles@1.2.14 aldeed:simple-schema@1.3.3 arunoda:streams@0.1.17 -autoupdate@1.2.3 +autoupdate@1.2.4 babel-compiler@5.8.24_1 babel-runtime@0.1.4 base64@1.0.4 @@ -22,36 +22,36 @@ caching-compiler@1.0.0 caching-html-compiler@1.0.2 callback-hook@1.0.4 cfs:http-methods@0.0.30 -check@1.0.6 +check@1.1.0 chrismbeckett:toastr@2.1.2_1 -coffeescript@1.0.10 +coffeescript@1.0.11 cosmos:browserify@0.8.1 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 -ddp-common@1.2.1 +ddp-common@1.2.2 ddp-rate-limiter@1.0.0 -ddp-server@1.2.1 +ddp-server@1.2.2 deps@1.0.9 diff-sequence@1.0.1 dispatch:run-as-user@1.1.1 -ecmascript@0.1.5 -ecmascript-collections@0.1.6 +ecmascript@0.1.6 +ecmascript-runtime@0.2.6 ejson@1.0.7 -email@1.0.7 +email@1.0.8 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 geojson-utils@1.0.4 github@1.1.4 -google@1.1.6 +google@1.1.7 hot-code-push@1.0.0 html-tools@1.0.5 htmljs@1.0.5 http@1.1.1 id-map@1.0.4 idorecall:email-normalize@1.0.0 -jalik:ufs@0.3.0 +jalik:ufs@0.3.3 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 @@ -68,15 +68,15 @@ konecty:multiple-instances-status@1.0.3 konecty:nrr@2.0.2 konecty:user-presence@1.2.6 launch-screen@1.0.4 -less@2.5.0_3 +less@2.5.1 livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 matb33:collection-hooks@0.8.1 -meteor@1.1.9 +meteor@1.1.10 meteor-base@1.0.1 -meteor-developer@1.1.4 -meteorhacks:kadira@2.23.6 +meteor-developer@1.1.5 +meteorhacks:kadira@2.24.1 meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 @@ -87,7 +87,7 @@ mobile-experience@1.0.1 mobile-status-bar@1.0.6 momentjs:moment@2.10.6 monbro:mongodb-mapreduce-aggregation@1.0.1 -mongo@1.1.2 +mongo@1.1.3 mongo-id@1.0.1 mongo-livedata@1.0.9 mrt:reactive-store@0.0.1 @@ -101,22 +101,22 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 -pauli:accounts-linkedin@1.1.2 -pauli:linkedin@1.1.2 +pauli:accounts-linkedin@1.2.0 +pauli:linkedin@1.2.0 perak:codemirror@1.2.8 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 -promise@0.5.0 +promise@0.5.1 qnub:emojione@1.5.1_1 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 raix:push@2.6.13-rc.1 raix:ui-dropped-event@0.0.7 -random@1.0.4 +random@1.0.5 rate-limit@1.0.0 -reactive-dict@1.1.2 +reactive-dict@1.1.3 reactive-var@1.0.6 reload@1.1.4 retry@1.0.4 @@ -157,10 +157,10 @@ simple:json-routes@1.0.4 spacebars@1.0.7 spacebars-compiler@1.0.7 srp@1.0.4 -standard-minifiers@1.0.1 +standard-minifiers@1.0.2 steffo:meteor-accounts-saml@0.0.1 tap:i18n@1.7.0 -templating@1.1.4 +templating@1.1.5 templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 tmeasday:crypto-md5@3.1.2 @@ -172,7 +172,7 @@ ui@1.0.8 underscore@1.0.4 underscorestring:underscore.string@3.2.2 url@1.0.5 -webapp@1.2.2 +webapp@1.2.3 webapp-hashing@1.0.5 yasaricli:slugify@0.0.7 yasinuslu:blaze-meta@0.3.3 -- GitLab From b4a24a2b73dd9dad6809d362000cb12177282d0d Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 12:08:32 -0200 Subject: [PATCH 0281/1338] Explicitly declaring vars to limit scope. --- packages/rocketchat-ldap/ldap_server.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 68b8beb8c50..dc82e57db7c 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -291,13 +291,13 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { } // LDAP sync data logic - syncUserData = RocketChat.settings.get('LDAP_Sync_User_Data'); - syncUserDataFieldMap = RocketChat.settings.get('LDAP_Sync_User_Data_FieldMap').trim(); + var syncUserData = RocketChat.settings.get('LDAP_Sync_User_Data'); + var syncUserDataFieldMap = RocketChat.settings.get('LDAP_Sync_User_Data_FieldMap').trim(); if (userId && syncUserData && syncUserDataFieldMap) { - userData = {}; - fieldMap = JSON.parse(syncUserDataFieldMap); + var userData = {}; + var fieldMap = JSON.parse(syncUserDataFieldMap); - emailList = []; + var = emailList = []; _.map(fieldMap, function(userField, ldapField) { if (!ldapResponse.searchResults.hasOwnProperty(ldapField)) { return; -- GitLab From 3f2338151800a7f5d24ac5e929e8d3444dffe424 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 12:34:20 -0200 Subject: [PATCH 0282/1338] Updating to Meteor 1.2.1 --- .meteor/release | 2 +- .meteor/versions | 52 ++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.meteor/release b/.meteor/release index 5684262a835..3a05e0a2f70 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.2.0.2 +METEOR@1.2.1 diff --git a/.meteor/versions b/.meteor/versions index d6c44e8a020..b2a52c59f3e 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,15 +1,15 @@ -accounts-base@1.2.1 +accounts-base@1.2.2 accounts-facebook@1.0.6 accounts-github@1.0.6 accounts-google@1.0.6 accounts-meteor-developer@1.0.6 -accounts-oauth@1.1.7 -accounts-password@1.1.3 +accounts-oauth@1.1.8 +accounts-password@1.1.4 accounts-twitter@1.0.6 alanning:roles@1.2.14 aldeed:simple-schema@1.3.3 arunoda:streams@0.1.17 -autoupdate@1.2.3 +autoupdate@1.2.4 babel-compiler@5.8.24_1 babel-runtime@0.1.4 base64@1.0.4 @@ -22,36 +22,36 @@ caching-compiler@1.0.0 caching-html-compiler@1.0.2 callback-hook@1.0.4 cfs:http-methods@0.0.30 -check@1.0.6 +check@1.1.0 chrismbeckett:toastr@2.1.2_1 -coffeescript@1.0.10 +coffeescript@1.0.11 cosmos:browserify@0.8.1 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 -ddp-common@1.2.1 +ddp-common@1.2.2 ddp-rate-limiter@1.0.0 -ddp-server@1.2.1 +ddp-server@1.2.2 deps@1.0.9 diff-sequence@1.0.1 dispatch:run-as-user@1.1.1 -ecmascript@0.1.5 -ecmascript-collections@0.1.6 +ecmascript@0.1.6 +ecmascript-runtime@0.2.6 ejson@1.0.7 -email@1.0.7 +email@1.0.8 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 geojson-utils@1.0.4 github@1.1.4 -google@1.1.6 +google@1.1.7 hot-code-push@1.0.0 html-tools@1.0.5 htmljs@1.0.5 http@1.1.1 id-map@1.0.4 idorecall:email-normalize@1.0.0 -jalik:ufs@0.3.0 +jalik:ufs@0.3.3 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 @@ -68,15 +68,15 @@ konecty:multiple-instances-status@1.0.3 konecty:nrr@2.0.2 konecty:user-presence@1.2.6 launch-screen@1.0.4 -less@2.5.0_3 +less@2.5.1 livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 matb33:collection-hooks@0.8.1 -meteor@1.1.9 +meteor@1.1.10 meteor-base@1.0.1 -meteor-developer@1.1.4 -meteorhacks:kadira@2.23.6 +meteor-developer@1.1.5 +meteorhacks:kadira@2.24.1 meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 @@ -87,7 +87,7 @@ mobile-experience@1.0.1 mobile-status-bar@1.0.6 momentjs:moment@2.10.6 monbro:mongodb-mapreduce-aggregation@1.0.1 -mongo@1.1.2 +mongo@1.1.3 mongo-id@1.0.1 mongo-livedata@1.0.9 mrt:reactive-store@0.0.1 @@ -101,22 +101,22 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 -pauli:accounts-linkedin@1.1.2 -pauli:linkedin@1.1.2 +pauli:accounts-linkedin@1.2.0 +pauli:linkedin@1.2.0 perak:codemirror@1.2.8 percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 -promise@0.5.0 +promise@0.5.1 qnub:emojione@1.5.1_1 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 raix:push@2.6.13-rc.1 raix:ui-dropped-event@0.0.7 -random@1.0.4 +random@1.0.5 rate-limit@1.0.0 -reactive-dict@1.1.2 +reactive-dict@1.1.3 reactive-var@1.0.6 reload@1.1.4 retry@1.0.4 @@ -157,10 +157,10 @@ simple:json-routes@1.0.4 spacebars@1.0.7 spacebars-compiler@1.0.7 srp@1.0.4 -standard-minifiers@1.0.1 +standard-minifiers@1.0.2 steffo:meteor-accounts-saml@0.0.1 tap:i18n@1.7.0 -templating@1.1.4 +templating@1.1.5 templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 tmeasday:crypto-md5@3.1.2 @@ -172,7 +172,7 @@ ui@1.0.8 underscore@1.0.4 underscorestring:underscore.string@3.2.2 url@1.0.5 -webapp@1.2.2 +webapp@1.2.3 webapp-hashing@1.0.5 yasaricli:slugify@0.0.7 yasinuslu:blaze-meta@0.3.3 -- GitLab From ed8a5c0581f2a4e1b5b3d36a0b85259a27dba8a6 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 13:22:54 -0200 Subject: [PATCH 0283/1338] Fixing typo --- packages/rocketchat-ldap/ldap_server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index dc82e57db7c..d12d9346940 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -297,7 +297,7 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { var userData = {}; var fieldMap = JSON.parse(syncUserDataFieldMap); - var = emailList = []; + var emailList = []; _.map(fieldMap, function(userField, ldapField) { if (!ldapResponse.searchResults.hasOwnProperty(ldapField)) { return; -- GitLab From 36738515ee40d11deed208e689ed044071ccdc20 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 18:16:55 -0200 Subject: [PATCH 0284/1338] Adding setting for protected uploads; updating jail:us to 0.3.3 --- .meteor/versions | 2 +- i18n/en.i18n.json | 2 ++ i18n/pt.i18n.json | 5 ++++- packages/rocketchat-lib/settings/server/startup.coffee | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index d6c44e8a020..9e4cef6ccf7 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -51,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.0 +jalik:ufs@0.3.3 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index feca05d095a..38fc0f71572 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -134,6 +134,8 @@ "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", "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.", "Forgot_password" : "Forgot your password", "Fork_it_on_github" : "Fork it on github", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index a3008e91087..fd6db446633 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -120,7 +120,10 @@ "FileUpload" : "Upload de Arquivos", "FileUpload_Enabled" : "Habilitar upload de arquivos", "FileUpload_MaxFileSize" : "Tamanho máximo dos arquivos (em bytes)", - "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia (separados por vÃrgula)", + "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia", + "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", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 3a61e1e10a5..d494a274e3c 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -42,6 +42,7 @@ 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/*', { type: 'string', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } +RocketChat.settings.add 'FileUpload_ProtectFiles', true, { type: 'boolean', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_ProtectFilesDescription' } RocketChat.settings.addGroup 'General' -- GitLab From 61ef96ce24562f7e517be29f7d90dcc2c59f26e3 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Tue, 27 Oct 2015 15:59:28 -0500 Subject: [PATCH 0285/1338] Allow the avatars to be set via a provided url, must currently be a jpg --- .meteor/packages | 1 + .meteor/versions | 1 + client/views/account/avatar/prompt.coffee | 9 +++++++++ client/views/account/avatar/prompt.html | 11 +++++++++++ i18n/en.i18n.json | 4 +++- server/methods/setAvatarFromService.coffee | 23 ++++++++++++++++++++++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index 21af9041330..af3ea3e5a99 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -109,3 +109,4 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter +froatsnook:request diff --git a/.meteor/versions b/.meteor/versions index ff18b148896..9b746e8d5ce 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -42,6 +42,7 @@ email@1.0.7 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 +froatsnook:request@2.64.0 geojson-utils@1.0.4 github@1.1.4 google@1.1.6 diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index a73f8da8f27..21fb3435d54 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -43,6 +43,15 @@ Template.avatarPrompt.events toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) else toastr.success t('Avatar_changed_successfully') + else if @service is 'url' + if _.trim $('#avatarurl').val() + Meteor.call 'setAvatarFromService', $('#avatarurl').val(), '', @service, (err) -> + if err?.details?.timeToReset? + toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) + else + toastr.success t('Avatar_changed_successfully') + else + toastr.error t('Please_enter_value_for_url') else Meteor.call 'setAvatarFromService', @blob, @contentType, @service, (err) -> if err?.details?.timeToReset? diff --git a/client/views/account/avatar/prompt.html b/client/views/account/avatar/prompt.html index b38fdae3468..86ccb8b6d8c 100644 --- a/client/views/account/avatar/prompt.html +++ b/client/views/account/avatar/prompt.html @@ -58,6 +58,17 @@ {{/unless}} </div> </div> + <div class="avatar-suggestion-item"> + {{#with service='url'}} + <div class="avatar question-mark icon-upload"></div> + <div class="action"> + <div class="input-line"> + <input type="text" name="avatarurl" id="avatarurl" /> + <button type="button" class="button primary select-service">{{_ "Use_url_for_avatar"}}</button> + </div> + </div> + {{/with}} + </div> {{#if suggestions.ready}} {{> avatarSuggestion suggestions.avatars.gravatar}} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 6bb56e8686c..c7bde60e951 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -265,6 +265,7 @@ "Please_wait" : "Please wait", "Please_wait_activation" : "Please wait, this can take some time.", "Please_wait_statistics" : "Please wait, statistics are being generated.", + "Please_enter_value_for_url": "Please enter a value for the url of your avatar.", "Powered_by" : "Powered by", "Preferences" : "Preferences", "Preferences_saved" : "Preferences saved", @@ -386,6 +387,7 @@ "Use_service_avatar" : "Use %s avatar", "Use_this_username" : "Use this username", "Use_uploaded_avatar" : "Use uploaded avatar", + "Use_url_for_avatar": "Use url for avatar", "User_added" : "User <em>__user_added__</em> added.", "User_added_by" : "User <em>__user_added__</em> added by <em>__user_by__</em>.", "User_Channels" : "User Channels", @@ -428,4 +430,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index 6083c8ecc21..efe29b838d6 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -11,6 +11,29 @@ Meteor.methods RocketChat.models.Users.setAvatarOrigin user._id, service return + if service is 'url' + headReq = request.headSync dataURI + + if headReq.response.statusCode != 200 + console.log "Not a valid response, #{headReq.response.statusCode}, from the avatar url:", dataURI + throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> error on checking the image type') + + if headReq.response.headers['content-type'] isnt 'image/jpeg' + throw new Meteor.Error('invalid-image-url', '[methods] setAvatarFromService -> url service -> Invalid url, it is not a jpeg') + + image = request.getSync dataURI, { encoding: null } + ars = RocketChatFile.bufferToStream image.body + aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", headReq.response.headers['content-type'] + aws.on 'end', Meteor.bindEnvironment -> + Meteor.setTimeout -> + console.log "Set #{user.username}'s avatar from the url: #{dataURI}" + RocketChat.models.Users.setAvatarOrigin user._id, service + RocketChat.Notifications.notifyAll 'updateAvatar', { username: user.username } + , 500 + + ars.pipe(aws) + return + {image, contentType} = RocketChatFile.dataURIParse dataURI rs = RocketChatFile.bufferToStream new Buffer(image, 'base64') -- GitLab From 3fb589c62b4c50faa029dbed5200e1ec05886a4e Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Tue, 27 Oct 2015 21:13:44 -0200 Subject: [PATCH 0286/1338] Protecting uploaded files --- .meteor/packages | 1 + .meteor/versions | 1 + lib/fileUpload.coffee | 17 ++++++++++++++++- .../rocketchat-lib/server/models/Users.coffee | 7 +++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index d16b2be6adf..17086e3ba92 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -92,6 +92,7 @@ mrt:reactive-store mystor:device-detection nimble:restivus nooitaf:colors +ostrio:cookies@2.0.1 pauli:accounts-linkedin perak:codemirror percolate:migrations diff --git a/.meteor/versions b/.meteor/versions index 9e4cef6ccf7..62724d6797e 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -101,6 +101,7 @@ 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.1.2 pauli:linkedin@1.1.2 perak:codemirror@1.2.8 diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 62cf49677a5..e927cc82cb2 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' @@ -41,12 +47,21 @@ if UploadFS? onFinishUpload: -> console.log arguments 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? + + unless uid and token and RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) + throw new Meteor.Error 403, 'Not Allowed' + res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" +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/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index 14201607bca..23541a64bcb 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -34,6 +34,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) -> -- GitLab From 5500a0cf651e5284d3c2c2cbbff4c94bdde1280b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Wed, 28 Oct 2015 11:04:51 +0100 Subject: [PATCH 0287/1338] Removed (coming soon) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47dfcf1217f..ff9f9466ded 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ We are developing the APIs based on the competition, so stay tuned and you will ### Documentation -Checkout [Github Wiki](https://github.com/RocketChat/Rocket.Chat/wiki) (coming soon) +Checkout [Github Wiki](https://github.com/RocketChat/Rocket.Chat/wiki) ## Production Deployment -- GitLab From 50c2858256c7fdeedddc581a9e6aad2be48d2190 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 28 Oct 2015 11:33:01 +0100 Subject: [PATCH 0288/1338] Allow add variables to theme class without persistence --- packages/rocketchat-theme/server/server.coffee | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index bea1fac137b..8958ab46563 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -90,18 +90,19 @@ RocketChat.theme = new class process.emit('message', {refresh: 'client'}) - addVariable: (type, name, value, isPublic=true) -> + addVariable: (type, name, value, persist=true) -> @variables[name] = type: type value: value - config = - group: 'Theme' - type: type - section: type - public: isPublic + if persist is true + config = + group: 'Theme' + type: type + section: type + public: false - RocketChat.settings.add "theme-#{type}-#{name}", value, config + RocketChat.settings.add "theme-#{type}-#{name}", value, config addPublicColor: (name, value) -> @addVariable 'color', name, value, true -- GitLab From ea05977fad4579d2c2e0a68e9b3e3b09cf45f1d8 Mon Sep 17 00:00:00 2001 From: acidicX <webmaster@carstenm.de> Date: Wed, 28 Oct 2015 15:53:02 +0100 Subject: [PATCH 0289/1338] added Firefox OS /fxos route and install methods as well as a few language strings --- client/routes/router.coffee | 6 +++++ client/views/fxos.coffee | 13 ++++++++++ client/views/fxos.html | 48 +++++++++++++++++++++++++++++++++++++ i18n/de.i18n.json | 6 ++++- i18n/en.i18n.json | 4 ++++ 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 client/views/fxos.coffee create mode 100644 client/views/fxos.html diff --git a/client/routes/router.coffee b/client/routes/router.coffee index 94845492369..951fba47212 100644 --- a/client/routes/router.coffee +++ b/client/routes/router.coffee @@ -97,3 +97,9 @@ FlowRouter.route '/room-not-found/:type/:name', action: (params) -> Session.set 'roomNotFound', {type: params.type, name: params.name} BlazeLayout.render 'main', {center: 'roomNotFound'} + +FlowRouter.route '/fxos', + name: 'firefox-os-install' + + action: -> + BlazeLayout.render 'fxOsInstallPrompt' diff --git a/client/views/fxos.coffee b/client/views/fxos.coffee new file mode 100644 index 00000000000..b8626a03db8 --- /dev/null +++ b/client/views/fxos.coffee @@ -0,0 +1,13 @@ +Template.fxOsInstallPrompt.onRendered -> + showPrompt = () -> + request = window.navigator.mozApps.install 'http://' + location.host + '/manifest.webapp' + request.onsuccess = () -> + # Save the App object that is returned + appRecord = this.result + BlazeLayout.render 'fxOsInstallDone' + + request.onerror = () -> + # Display the error information from the DOMError object + BlazeLayout.render 'fxOsInstallError', {installError: this.error.name} + + setTimeout(showPrompt, 2000); \ No newline at end of file diff --git a/client/views/fxos.html b/client/views/fxos.html new file mode 100644 index 00000000000..34418ad7ddf --- /dev/null +++ b/client/views/fxos.html @@ -0,0 +1,48 @@ +<template name="fxOsInstallPrompt"> + <section class="full-page"> + <div class="wrapper"> + <header> + <a class="logo" href="/"> + <img src="/images/logo/logo.svg?v=3" /> + </a> + </header> + <div class="cms-page"> + <h1>{{_ "Install_FxOs"}}</h1> + <p>{{_ "Install_FxOs_follow_instructions"}}</p> + </div> + </div> + </section> +</template> + +<template name="fxOsInstallDone"> + <section class="full-page"> + <div class="wrapper"> + <header> + <a class="logo" href="/"> + <img src="/images/logo/logo.svg?v=3" /> + </a> + </header> + <div class="cms-page"> + <h1>{{_ "Install_FxOs"}}</h1> + <p>{{_ "Install_FxOs_done"}}</p> + </div> + </div> + </section> +</template> + +<template name="fxOsInstallError"> + <section class="full-page"> + <div class="wrapper"> + <header> + <a class="logo" href="/"> + <img src="/images/logo/logo.svg?v=3" /> + </a> + </header> + <div class="cms-page"> + <h1>{{_ "Install_FxOs"}}</h1> + <p>{{_ "Install_FxOs_error"}}</p> + <p>{{installError}}</p> + </div> + </div> + </section> +</template> \ No newline at end of file diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index f970e861837..27f18d58870 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -133,6 +133,10 @@ "hours" : "Stunden", "Incorrect_Password" : "Falsches Passwort", "inline_code" : "inline_code", + "Install_FxOs": "Installiere Rocket.Chat auf deinem Firefox", + "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App (drücke \"Installieren\" in der Aufforderung).", + "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:", "Invalid_confirm_pass" : "Die Passwörter stimmen nicht überein", "Invalid_email" : "Email-Adresse ungültigt", "Invalid_name" : "Der Name darf nicht leer sein", @@ -400,4 +404,4 @@ "You_will_not_be_able_to_recover" : "Sie können es nicht wieder rückgängig machen!", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", "Your_Open_Source_solution" : "Deine eigene Open Source Chat Lösung" -} \ No newline at end of file +} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index feca05d095a..3347c25b98b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -149,6 +149,10 @@ "hours" : "hours", "Incorrect_Password" : "Incorrect Password", "inline_code" : "inline_code", + "Install_FxOs" : "Install Rocket.Chat on your Firefox", + "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", + "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:", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_email" : "The e-mail entered is invalid", "Invalid_name" : "The name must not be empty", -- GitLab From 1b671cb2fe499cc1a40b524a8b56d4fb8f255c26 Mon Sep 17 00:00:00 2001 From: Carsten <acidicX@users.noreply.github.com> Date: Wed, 28 Oct 2015 16:25:44 +0100 Subject: [PATCH 0290/1338] Added Firefox OS support to features --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff9f9466ded..ff41d8e0db8 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ It is a great solution for communities and companies wanting to privately host t - Native Cross-Platform Desktop Application [Windows, Mac OSX, or Linux](https://rocket.chat/) - Mobile app for iPhone, iPad, and iPod touch [Download on AppStore!](https://geo.itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) - Mobile app for Android phone, tablet, and TV stick [Available now on Google Play!](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) +- Native Firefox OS Application (also for Desktop Firefox and Firefox for Android!) - [Check the wiki page for install instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29) - Sandstorm.io instant Rocket.Chat server [Now on Sandstorm App Store](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) @@ -110,7 +111,6 @@ It is a great solution for communities and companies wanting to privately host t - Support for PostgreSQL: [Issue #533](https://github.com/RocketChat/Rocket.Chat/issues/533), [Issue #822](https://github.com/RocketChat/Rocket.Chat/issues/822) - Native iOS Application [Issue #270](https://github.com/RocketChat/Rocket.Chat/issues/270), [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) - Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) -- Native Firefox OS Application [Issue #1204](https://github.com/RocketChat/Rocket.Chat/issues/1204) - Off-the-Record (OTR) Messaging [Issue #36](https://github.com/RocketChat/Rocket.Chat/issues/36), [Issue #268 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/268) - API-enabled methods: [Issue #202](https://github.com/RocketChat/Rocket.Chat/issues/202), [Issue #454](https://github.com/RocketChat/Rocket.Chat/issues/454), [Issue #455](https://github.com/RocketChat/Rocket.Chat/issues/455), [Issue #759](https://github.com/RocketChat/Rocket.Chat/issues/759) - Scalable WebRTC broadcaster / media-server integration, [Issue #1118 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/1118) -- GitLab From 9dd9d3c90732e300e639b7abc80ace4c54a2907d Mon Sep 17 00:00:00 2001 From: Carsten <acidicX@users.noreply.github.com> Date: Wed, 28 Oct 2015 16:32:04 +0100 Subject: [PATCH 0291/1338] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index ff41d8e0db8..952137a5bac 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ Get the app for your Android phone: Now compatible with all Android devices as old as version 4.0.x - [download here](https://github.com/RocketChat/Rocket.Chat/wiki/Build-the-Android-Cordova-Web-App-and-connect-to-your-own-Rocket.Chat-Server), even on BlackBerry Passport! +Firefox OS support has landed as well (no Cordova required!): +https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29 + Host your own Rocket.Chat server in four seconds flat: [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) -- GitLab From 273fda833cf7720b54bff6ce7d167f6038f078f2 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 21 Oct 2015 12:17:35 +0200 Subject: [PATCH 0292/1338] initial coffescript migration --- packages/rocketchat-livechat/livechat.coffee | 33 ------ packages/rocketchat-livechat/livechat.js | 32 ++++++ packages/rocketchat-livechat/methods.coffee | 81 -------------- packages/rocketchat-livechat/package.js | 8 +- .../rocketchat-livechat/publications.coffee | 9 -- .../rocketchat-livechat/server/methods.js | 100 ++++++++++++++++++ .../server/publications.js | 12 +++ 7 files changed, 148 insertions(+), 127 deletions(-) delete mode 100644 packages/rocketchat-livechat/livechat.coffee create mode 100644 packages/rocketchat-livechat/livechat.js delete mode 100644 packages/rocketchat-livechat/methods.coffee delete mode 100644 packages/rocketchat-livechat/publications.coffee create mode 100644 packages/rocketchat-livechat/server/methods.js create mode 100644 packages/rocketchat-livechat/server/publications.js diff --git a/packages/rocketchat-livechat/livechat.coffee b/packages/rocketchat-livechat/livechat.coffee deleted file mode 100644 index 4ff8e57dc72..00000000000 --- a/packages/rocketchat-livechat/livechat.coffee +++ /dev/null @@ -1,33 +0,0 @@ -WebApp = Package.webapp.WebApp -Autoupdate = Package.autoupdate.Autoupdate - -WebApp.connectHandlers.use '/livechat/', (req, res, next) -> - res.setHeader 'content-type', 'html' - - head = Assets.getText('public/head.html') - - html = """ - <html> - <head> - <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/packages/rocketchat_livechat/public/livechat.css?_dc=#{Autoupdate.autoupdateVersion}"> - <script type="text/javascript"> - __meteor_runtime_config__ = { - "meteorRelease": "METEOR@1.1.0.2", - "ROOT_URL": "#{Meteor.absoluteUrl()}", - "ROOT_URL_PATH_PREFIX": "", - "autoupdateVersion": "#{Autoupdate.autoupdateVersion}", - "autoupdateVersionRefreshable": "#{Autoupdate.autoupdateVersionRefreshable}", - "autoupdateVersionCordova": "#{Autoupdate.autoupdateVersionCordova}" - }; - </script> - <script type="text/javascript" src="/packages/rocketchat_livechat/public/livechat.js?_dc=#{Autoupdate.autoupdateVersion}"></script> - - #{head} - </head> - <body> - </body> - </html> - """ - - res.write html - res.end() diff --git a/packages/rocketchat-livechat/livechat.js b/packages/rocketchat-livechat/livechat.js new file mode 100644 index 00000000000..efe29fc16ae --- /dev/null +++ b/packages/rocketchat-livechat/livechat.js @@ -0,0 +1,32 @@ +WebApp = Package.webapp.WebApp; +Autoupdate = Package.autoupdate.Autoupdate; + +WebApp.connectHandlers.use('/livechat/', (req, res, next) => { + res.setHeader('content-type', 'html'); + + head = Assets.getText('public/head.html'); + + html = `<html> + <head> + <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/packages/rocketchat_livechat/public/livechat.css?_dc=${Autoupdate.autoupdateVersion}"> + <script type="text/javascript"> + __meteor_runtime_config__ = { + "meteorRelease": "METEOR@1.1.0.2", + "ROOT_URL": "${Meteor.absoluteUrl()}", + "ROOT_URL_PATH_PREFIX": "", + "autoupdateVersion": "${Autoupdate.autoupdateVersion}", + "autoupdateVersionRefreshable": "${Autoupdate.autoupdateVersionRefreshable}", + "autoupdateVersionCordova": "${Autoupdate.autoupdateVersionCordova}" + }; + </script> + <script type="text/javascript" src="/packages/rocketchat_livechat/public/livechat.js?_dc=${Autoupdate.autoupdateVersion}"></script> + + ${head} + </head> + <body> + </body> + </html>`; + + res.write(html); + res.end(); +}); diff --git a/packages/rocketchat-livechat/methods.coffee b/packages/rocketchat-livechat/methods.coffee deleted file mode 100644 index 2edd1dd9c4f..00000000000 --- a/packages/rocketchat-livechat/methods.coffee +++ /dev/null @@ -1,81 +0,0 @@ -Meteor.methods - registerGuest: (token) -> - check token, String - - user = Meteor.users.findOne { "profile.token": token }, { fields: { _id: 1 } } - if user? - throw new Meteor.Error 'token-already-exists', 'Token already exists' - - pass = Meteor.uuid() - - loop - qt = Meteor.users.find({ 'profile.guest': true }).count() + 1 - user = 'guest-' + qt - - userExists = Meteor.users.findOne { 'username': user }, { fields: { _id: 1 } } - break if not userExists - - userData = - username: user - password: pass - - userId = Accounts.createUser userData - - Meteor.users.update userId, - $set: - name: user - "profile.guest": true - "profile.token": token - - return { - user: user - pass: pass - } - - sendMessageLivechat: (message) -> - 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 not room? - - # find an online user - operator = Meteor.users.findOne { operator: true, status: 'online' } - - unless 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: 'd' - ts: new Date() - v: - token: message.token - - RocketChat.models.Subscriptions.insert - rid: message.rid - name: guest.username - alert: true - open: true - unread: 1 - u: - _id: operator._id - username: operator.username - t: 'd' - - room = Meteor.call 'canAccessRoom', message.rid, guest._id - - if not room - throw new Meteor.Error 'cannot-acess-room' - - RocketChat.sendMessage guest, message, room - diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index dff7c5ae6a0..88369db925d 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -18,11 +18,11 @@ Package.registerBuildPlugin({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use(['coffeescript', 'webapp', 'autoupdate'], 'server'); + api.use(['ecmascript', 'webapp', 'autoupdate'], 'server'); - api.addFiles('livechat.coffee', 'server'); - api.addFiles('methods.coffee', 'server'); - api.addFiles('publications.coffee', 'server'); + api.addFiles('livechat.js', 'server'); + api.addFiles('server/methods.js', 'server'); + api.addFiles('server/publications.js', 'server'); api.addFiles('config.js', 'server'); diff --git a/packages/rocketchat-livechat/publications.coffee b/packages/rocketchat-livechat/publications.coffee deleted file mode 100644 index e51b3841a7e..00000000000 --- a/packages/rocketchat-livechat/publications.coffee +++ /dev/null @@ -1,9 +0,0 @@ -Meteor.publish 'visitorRoom', (visitorToken) -> - return RocketChat.models.Rooms.findByVisitorToken visitorToken, - fields: - name: 1 - t: 1 - cl: 1 - u: 1 - usernames: 1 - v: 1 diff --git a/packages/rocketchat-livechat/server/methods.js b/packages/rocketchat-livechat/server/methods.js new file mode 100644 index 00000000000..241674b00b9 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods.js @@ -0,0 +1,100 @@ +Meteor.methods({ + registerGuest: function(token) { + var pass, qt, user, userData, userExists, userId; + 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; + userExists = Meteor.users.findOne({ + 'username': user + }, { + fields: { + _id: 1 + } + }); + if (!userExists) { + break; + } + } + userData = { + username: user, + password: pass + }; + userId = Accounts.createUser(userData); + Meteor.users.update(userId, { + $set: { + name: user, + "profile.guest": true, + "profile.token": token + } + }); + 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/publications.js b/packages/rocketchat-livechat/server/publications.js new file mode 100644 index 00000000000..76fe1b8abba --- /dev/null +++ b/packages/rocketchat-livechat/server/publications.js @@ -0,0 +1,12 @@ +Meteor.publish('visitorRoom', (visitorToken) => { + return RocketChat.models.Rooms.findByVisitorToken(visitorToken, { + fields: { + name: 1, + t: 1, + cl: 1, + u: 1, + usernames: 1, + v: 1 + } + }); +}); -- GitLab From f587f128b12e93a247d2063e89237236c703e0ca Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 28 Oct 2015 16:42:35 +0100 Subject: [PATCH 0293/1338] removed duplicated file --- .../stylesheets/utils/_colors.import.less | 1210 ----------------- 1 file changed, 1210 deletions(-) delete mode 100644 packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less deleted file mode 100644 index e0cb54f452a..00000000000 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ /dev/null @@ -1,1210 +0,0 @@ -.custom-scroll(@background, @thumb, @width: 8px, @height: 8px) { - &::-webkit-scrollbar { - height: @height; - width: @width; - background: @background; - } - &::-webkit-scrollbar-thumb { - background-color: @thumb; - -webkit-border-radius: 50px; - } - &::-webkit-scrollbar-corner { - background-color: @background; - } -} - -a { - &:hover, - &:active { - color: @primary-font-color; - } -} - -code { - background-color: @code-background; - border-color: @code-border; - color: @code-color; -} - -blockquote { - &:before { - background-color: @blockquote-background; - } -} - -.login-terms { - color: @smallprint-font-color; - a { - color: @smallprint-font-color; - &:hover { - color: @smallprint-hover-color; - } - } -} - -.upload-preview { - background-color: @secondary-background-color; -} - -.upload-preview-title { - background-color: @tertiary-background-color; -} - -.first-unread { - &.first-unread-opaque { - .body { - &::before { - background-color: lighten(@info-font-color, 25%); - } - - &::after { - color: @info-font-color; - } - } - } - .body { - &::before { - background-color: lighten(@info-active-font-color, 25%); - } - - &::after { - background-color: @content-background-color; - color: @info-active-font-color; - } - } -} - -.alert { - border-color: rgba(0, 0, 0, 0); -} - -.alert-warning { - color: #8A6D3B; - background-color: #FCF8E3; - border-color: #FAEBCC; -} - -.alert-danger { - color: #A94442; - background-color: #F2DEDE; - border-color: #EBCCD1; -} - -.scrollable { - .custom-scroll(transparent, #BFBFBF); -} - -.rocket-form { - legend { - &:after { - background-color: #DFDFDF; - } - } -} - -.input-line { - .clearfix; - &.search { - .icon-search { - color: @secondary-font-color; - } - } - > label { - color: @primary-font-color; - } -} - -.rocket-h2 { - color: #EFEFEF; -} - -.rocket-h3 { - color: #EAEAEA; -} - -html { - .custom-scroll(transparent, rgba(255, 255, 255, 0.05), 3px); -} - -body { - color: @primary-font-color; - background-color: @primary-background-color; -} - -textarea, -select, -input[type='text'], -input[type='number'], -input[type='email'], -input[type='password'] { - border-color: #E7E7E7; - background-color: #fff; -} - -input.search { - &:before { - background-color: #000; - } -} - -.form-horizontal .control-label { - color: @primary-font-color; -} - -.-autocomplete-container { - p { - color: @secondary-font-color; - } -} - -.-autocomplete-item { - color: @secondary-font-color; - i { - color: @secondary-font-color; - } - &.selected { - background-color: @tertiary-background-color; - color: @primary-font-color; - } -} - -label.required:after { - color: red; -} - -.status-offline, -.icon-at.status-offline { - color: @status-offline; -} - -.status-online, -.icon-at.status-online { - color: @status-online; -} - -.status-busy, -.icon-at.status-busy { - color: @status-busy; -} - -.status-away, -.icon-at.status-away { - color: @status-away; -} - -// TODO -- Refactor favorite styles and logic; -.favorite-room { - color: #FECF09; -} - -.toggle-favorite { - color: #AAA; -} - -.btn-loading { - color: #444 !important; - background-color: transparent !important; - &:hover { - background-color: transparent !important; - } -} - -// new layout buttons -.button { - background-color: #FFF; - color: rgba(255, 255, 255, 0.85); - background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); - &:before { - background-color: rgba(0, 0, 0, 0.1); - } - &:hover { - color: #FFF; - } - &.secondary { - background-color: @tertiary-background-color; - color: @primary-font-color; - &:before { - background-color: rgba(0, 0, 0, 0.045); - } - } - &.delete, - &.remove, - &.red { - background-color: #bc2031; - } - &.lightblue { - background-color: #02acec; - } - &.clean { - background-color: rgba(0, 0, 0, 0.025); - } - &.facebook { - background-color: #325c99; - } - &.twitter { - background-color: #02acec; - } - &.google { - background-color: #dd4b39; - } - &.github { - background-color: #4c4c4c; - } - &.gitlab { - background-color: #373d47; - } - &.trello { - background-color: #026aa7; - } - &.meteor-developer { - background-color: #de4f4f; - } - &.wordpress { - background-color: #1e8cbe; - } -} - -.burger { - i { - background-color: #333; - } - - .unread-burger-alert { - background-color: #F95555; - color: @content-background-color; - } -} - -.arrow { - &:before, - &:after { - background-color: #aaa; - } -} - -a.github-fork { - background-color: #5c5c5c; - color: #f0f0f0; - &:hover { - background-color: #4b4b4b; - color: #FFF; - } - &:before { - border-top-color: #f0f0f0; - } - &:after { - border-top-color: #f0f0f0; - } -} - -.mac-bar { - background-color: #ddd; - i { - background-color: #ff5f57; - &:nth-child(2) { - background-color: #ffbd2e; - } - &:nth-child(3) { - background-color: #28ca41; - } - } -} - -.avatar { - .avatar-image { - background-color: transparent; - } - &[initials]:before { - color: #FFF; - } -} - -#rocket-chat { - background-color: @content-background-color; -} - -.account-box { - .info { - background-color:@primary-background-color; - h4 { - color: rgba(255, 255, 255, 0.65); - } - &.status-offline { - .thumb:after { - border-color: darken(@status-offline, 5%); - background-color: @status-offline; - } - } - &.status-online { - .thumb:after { - border-color: darken(@status-online, 5%); - background-color: @status-online; - } - } - &.status-away { - .thumb:after { - border-color: darken(@status-away, 5%); - background-color: @status-away; - } - } - &.status-busy { - .thumb:after { - border-color: darken(@status-busy, 5%); - background-color: @status-busy; - } - } - } - .options { - background-color: @primary-background-color; - .status { - &:after { - border-color: #6f6f6f; - } - &.offline { - &:after { - border-color: #666666; - background-color: #7b7b7b; - } - } - &.online { - &:after { - border-color: #2c9210; - background-color: #35AC19; - } - } - &.away { - &:after { - border-color: #e69200; - background-color: #fcb316; - } - } - &.busy { - &:after { - border-color: #9f0030; - background-color: #D30230; - } - } - } - span.soon { - color: #aaa; - } - a { - color: rgba(255, 255, 255, 0.5); - border-bottom-color: darken(@primary-background-color, 2%); - &:hover { - background-color: darken(@primary-background-color, 2%); - color: rgba(255, 255, 255, 0.75); - } - } - } - &.active .info, - .info:hover { - h4 { - color: rgba(255, 255, 255, 0.85); - } - } - .hover & { - .info h4 { - color: rgba(255, 255, 255, 0.85); - } - } -} - -// rooms-box -.flex-nav { - //background-color: @primary-background-color; - background-color: transparent; - color: @tertiary-font-color; - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); - header { - background-color: @primary-background-color; - } - footer { - background-color: @primary-background-color; - } - .content { - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); - background-color: @primary-background-color; - } - .input-line { - input[type='text'], - input[type='password'], - select { - border-color: @tertiary-font-color; - background-color: @primary-background-color; - color: @input-font-color; - } - - & label { - color:@input-font-color; - } - } - .selected-users { - li { - background-color: rgba(0, 0, 0, 0.1); - } - } -} - -.side-nav { - background-color: #F4F4F4; - color: #000; - &:before { - background-color: #dfdfdf; - } - .rooms-list { - background-color: lighten(@primary-background-color, 2%); - .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); - } - .more { - color: @tertiary-font-color; - &:hover { - background-color: rgba(0, 0, 0, 0.1); - } - } - .input-error { - color: #f09286; - } - .empty { - color: @tertiary-font-color; - } - .header { - color: #fff; - background-color: @primary-background-color; - } - > .arrow { - &.hover, - &:hover { - &:before, - &:after { - background-color: rgba(255, 255, 255, 0.85); - } - } - } - .footer { - background: #fff; - background-color: @primary-background-color; - small { - color: @tertiary-font-color; - } - } - h3 { - color: @tertiary-font-color; - a { - color: inherit; - } - &:hover { - background-color: rgba(0, 0, 0, 0.1); - } - } - .unread { - background-color: #1dce73; - color: #FFF; - } - ul { - li { - .remove, - .erase { - color: #666; - } - &:hover { - .opt { - background-color: transparent; - } - } - &.active { - a { - background-color: rgba(255, 255, 255, 0.075); - color: rgba(255, 255, 255, 0.75); - } - .opt { - background-color: transparent; - } - } - &.has-alert { - .name { - color: #ffffff; - } - } - &.away { - a { - color: #666; - } - } - } - a { - color: @tertiary-font-color; - &:hover { - background-color: rgba(255, 255, 255, 0.05); - } - } - .opt { - background-color: transparent; - i { - color: rgba(255, 255, 255, 0.5); - &:hover { - color: rgba(255, 255, 255, 0.75); - } - } - } - i { - color: rgba(255, 255, 255, 0.35); - } - input[type=text] { - color: #000; - } - } -} - -.page-container { - .content { - .custom-scroll(transparent, #EAEAEA); - } -} - -.fixed-title { - background: #fff; - border-bottom-color: @tertiary-background-color; -} - -.cms-page { - color: #444; - background-color: @content-background-color; -} - -.spotlight { - background-color: rgba(0,0,0,.3); - > .spotlight-input { - color: #444; - > i { - color: #aaa; - } - } -} - -.mobile-message-menu { - background-color: rgba(0,0,0,.3); -} - -.page-static { - .content { - .section { - .section-content { - border-color: #ddd; - } - } - } -} - -.page-list { - .results { - border-bottom-color: #DFDFDF; - color: @secondary-font-color; - } - .list { - a { - color: @primary-font-color; - border-bottom-color: @secondary-background-color; - &:hover { - background-color: @secondary-background-color; - } - } - li { - color: @secondary-font-color; - &:after { - background-color: @secondary-font-color; - } - } - .info { - a { - color: @primary-font-color; - } - } - .room-info { - &:hover { - background-color: @secondary-background-color; - } - } - .status { - color: @secondary-font-color; - } - - table { - tbody { - tr:nth-child(odd) { - background-color: @secondary-background-color; - } - } - } - } -} - -.image-to-download { - background-color: #fafafa; - border-color: #ddd; - color: #aaa; -} - -.room-not-found { - color: orange; -} - -.container-bars { - >div { - border-color: #ffffff; - } - - .upload-progress { - background-color: #b2d5c9; - color: @content-background-color; - - &.upload-error { - background-color: #FF6161; - border-color: #863737; - } - .upload-progress-progress { - background-color: #4c9789; - } - > a { - &:hover { - color: #eee; - } - } - } - - .unread-bar { - background-color: #E6F4FD; - color: #068FE4; - } -} - -// change to page-messages -.messages-container { - .edit-room-title { - color: @secondary-font-color; - &:hover { - color: @primary-font-color; - } - } - .wrapper { - .custom-scroll(transparent, rgba(180,180,180,.75)); - } - .footer { - background: #FCFCFC; - border-top-color: @tertiary-background-color; - } - .message-popup { - background: #FAFAFA; - } - .message-popup-title { - background-color: @secondary-background-color; - border-bottom-color: #EEE; - } - .popup-item { - color: @secondary-font-color; - &.selected { - background-color: @tertiary-background-color; - color: @primary-font-color; - } - } - .popup-user-status { - border-color: rgba(0,0,0,.2); - } - .popup-user-status-system { - border-color: transparent; - } - .popup-user-status-offline { - background-color: @status-offline; - } - .popup-user-status-online { - background-color: @status-online; - } - .popup-user-status-away { - background-color: @status-away; - } - .popup-user-status-busy { - background-color: @status-busy; - } - .message-form { - > div { - > .file { - border-color: #E7E7E7; - color: #888; - background-color: #FCFCFC; - &:hover { - background-color: #F1F1F1; - color: #666; - } - } - > .mic, .stop-mic { - color: #888; - background-color: #FCFCFC; - &:hover { - background-color: #F1F1F1; - color: #666; - } - } - } - textarea { - &.editing { - background-color: #fff7d8; - } - } - .icon-paper-plane { - color: @secondary-font-color; - &:hover { - color: @primary-font-color; - } - } - .users-typing { - color: #888888; - background: #FCFCFC; - } - .formatting-tips { - color: #444444; - q { - border-left-color: #ccc; - } - } - .editing-commands { - .editing-commands-cancel { - color: #888888; - } - .editing-commands-save { - color: #888888; - } - } - } -} - -.messages-box { - .load-more { - span { - border-color: #CCC; - background-color: #EEE; - } - } - .start { - color: @secondary-font-color; - } - .new-message { - background: #428bca; - color: #FFF; - } - .editing { - .body { - background-color: #fff7d8; - } - } -} - -.message { - &.new-day { - &:before { - color: @secondary-font-color; - background-color: @content-background-color; - } - &:after { - border-top-color: #ddd; - } - } - .user { - color: #444444; - &:hover { - color: #333; - } - } - .info { - color: @info-font-color; - } - &.system { - .body { - color: @info-font-color; - } - } - a { - color: @link-font-color; - &:hover { - color: darken(@link-font-color, 10%); - } - } -} - -// FLEX-TAB and FLEX-TAB views -.flex-tab { - background-color: @secondary-background-color; - border-left-color: @tertiary-background-color; - .control { - background-color: @secondary-background-color; - &:before { - background-color: @tertiary-background-color; - } - .more { - background-color: @tertiary-background-color; - border-bottom-color: @tertiary-background-color; - color: @secondary-font-color; - &:hover { - .arrow { - .arrow { - &:before, - &:after { - background-color: #4a4a4a; - } - } - } - } - .arrow { - &:before, - &:after { - background-color: #7a7a7a; - } - } - .flex-opened & { - background-color: @secondary-background-color; - &:hover { - .arrow { - &:before, - &:after { - background-color: #7a7a7a; - } - } - } - } - } - .search-form { - .icon-plus { - color: @secondary-font-color; - } - } - .info-tabs { - a { - color: inherit; - border-left-color: rgb(234, 234, 234); - &.active { - background-color: #F4F4F4; - } - &:last-child { - border-right-color: rgb(234, 234, 234); - } - } - } - } - .content { - .custom-scroll(transparent, #DADADA); - } -} - -.list-view { - > .status { - p { - color: @secondary-font-color; - } - .see-all { - color: @secondary-font-color; - background-color: transparent; - } - } -} - -.user-view { - .info { - h3 { - i.status-offline { - &:after { - border-color: darken(@status-offline, 5%); - background-color: @status-offline; - } - } - i.status-online { - &:after { - border-color: darken(@status-online, 5%); - background-color: @status-online; - } - } - i.status-away { - &:after { - border-color: darken(@status-away, 5%); - background-color: @status-away; - } - } - i.status-busy { - &:after { - border-color: darken(@status-busy, 5%); - background-color: @status-busy; - } - } - } - p { - color: @secondary-font-color; - } - } - .stats { - li { - background-color: #e9e9e9; - } - } - .box { - h4 { - } - &:after { - background-color: #CDCDCD; - } - } - .tags { - li { - background-color: #CDCDCD; - } - } - .links { - a { - color: #6f6f6f; - &:hover { - background-color: #e9e9e9; - color: #333; - } - } - } - .channels { - p { - color: @secondary-font-color; - } - a { - color: #6f6f6f; - } - } - .edit-form { - p { - color: @secondary-font-color; - } - } -} - -.user-image-status(@color) { - .avatar { - &:after { - background-color: darken(@color, 5%); - } - } -} - -.user-image { - background-color: @tertiary-background-color; - &:hover, - &.selected { - .avatar { - &:after { - } - .status-offline { - &:after { - background-color: @status-offline; - } - } - .status-online { - &:after { - background-color: @status-online; - } - } - .status-away { - &:after { - background-color: @status-away; - } - } - .status-busy { - &:after { - background-color: @status-busy; - } - } - p { - color: @primary-font-color; - } - } - } - .lines & { - background-color: transparent; - a { - background-color: transparent; - } - p { - color: @secondary-font-color; - } - } - &.status-offline { - .user-image-status(@status-offline); - } - &.status-online { - .user-image-status(@status-online); - } - &.status-away { - .user-image-status(@status-away); - } - &.status-busy { - .user-image-status(@status-busy); - } -} - -.user-profile { - .info { - a { - color: @primary-font-color; - &:hover { - color: @secondary-font-color; - } - } - } -} - -.rocket-modal { - background-color: rgba(0, 0, 0, 0.5); - &.fluid { - .modal { - main { - .custom-scroll(transparent, #CFCFCF); - } - } - } - legend { - color: @secondary-font-color; - &:before { - background-color: #dfdfdf; - } - } - .modal { - background-color: @content-background-color; - header { - background-color: #DADADA; - .close { - i { - color: @secondary-font-color; - } - &:hover { - i { - color: @primary-font-color; - } - } - } - } - main { - background-color: @content-background-color; - } - footer { - background-color: #eaeaea; - } - } -} - -#login-card { - background-color: #FAFAFA; - h2 { - color: @primary-font-color; - &.error { - color: #b40202; - } - } - h3 { - &.error { - color: #b40202; - } - } - a { - color: @primary-background-color; - &:active { - color: @primary-background-color; - } - &:hover { - color: darken(@primary-background-color, 10%); - } - } - .input-text { - input { - background-color: transparent; - border-bottom-color: #DFDFDF; - &.error { - border-bottom-color: #b40202; - &::-webkit-input-placeholder { - color: #b40202; - } - &:-moz-placeholder { - color: #b40202; - } - /* Firefox 18- */ - &::-moz-placeholder { - color: #b40202; - } - /* Firefox 19+ */ - &:-ms-input-placeholder { - color: #b40202; - } - } - } - input:-webkit-autofill { - color: @content-background-color !important; - } - input:-webkit-autofill { - background-color: transparent !important; - } - } -} - -.full-page { - background-color: darken(@primary-background-color, 10%); - .background-image(linear-gradient(darken(@primary-background-color,10%),@primary-background-color)); - .text { - color: #FFF; - .button { - background-color: #bc2031; - color: #FFF; - } - } - footer { - color: #fff; - div.switch-language { - a { - color: @secondary-font-color; - } - } - } -} - -.avatar-suggestion-item { - background-color: @secondary-background-color; - border-color: darken(@secondary-background-color, 10%); - .avatar { - background-size: cover; - background-color: @tertiary-background-color; - } - .question-mark { - &::before { - color: darken(@tertiary-background-color, 10%); - } - } -} - -.statistics-table { - border-color: #F9F9F9; -} - -@media all and(max-width: 780px) { - #rocket-chat { - .main-content { - background-color: @content-background-color; - } - } -} - -.dropzone { - &.over .dropzone-overlay { - background-color: rgba(0, 0, 0, 0.5); - color: @content-background-color; - > div { - background-color: rgba(0, 0, 0, 0.6); - } - } -} - -.is-cordova { - .flex-tab { - button.more { - background-color: #fff; - } - } -} -- GitLab From 8642b18710d20d0aefc0b3aded1fc25b22c7ee4a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 22 Oct 2015 10:13:36 +0200 Subject: [PATCH 0294/1338] livechat templates and permissions --- packages/rocketchat-livechat/client/ui.js | 4 +++ .../client/views/sideNav/livechat.html | 12 +++++++ .../client/views/sideNav/livechat.js | 33 +++++++++++++++++++ packages/rocketchat-livechat/package.js | 7 ++++ packages/rocketchat-livechat/permissions.js | 32 ++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 packages/rocketchat-livechat/client/ui.js create mode 100644 packages/rocketchat-livechat/client/views/sideNav/livechat.html create mode 100644 packages/rocketchat-livechat/client/views/sideNav/livechat.js create mode 100644 packages/rocketchat-livechat/permissions.js diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js new file mode 100644 index 00000000000..f861e437b71 --- /dev/null +++ b/packages/rocketchat-livechat/client/ui.js @@ -0,0 +1,4 @@ +Meteor.startup(function() { + RocketChat.roomTypes.add('livechat', ['livechat-agent', 'livechat-manager']); + AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); +}); diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechat.html b/packages/rocketchat-livechat/client/views/sideNav/livechat.html new file mode 100644 index 00000000000..c6aab41be12 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/sideNav/livechat.html @@ -0,0 +1,12 @@ +<template name="livechat"> + <h3 class="{{isActive}}"> + {{_ "Livechat"}} + </h3> + <ul> + {{#each rooms}} + {{> chatRoomItem }} + {{else}} + <p class="empty">{{_ "No_livechats" }}</p> + {{/each}} + </ul> +</template> diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechat.js b/packages/rocketchat-livechat/client/views/sideNav/livechat.js new file mode 100644 index 00000000000..5c3b73247da --- /dev/null +++ b/packages/rocketchat-livechat/client/views/sideNav/livechat.js @@ -0,0 +1,33 @@ +Template.livechat.helpers({ + isActive: function() { + if (ChatSubscription.findOne({ + t: 'l', + f: { + $ne: true + }, + open: true, + rid: Session.get('openedRoom') + }, { + fields: { + _id: 1 + } + }) != null) { + return 'active'; + } + }, + rooms: function() { + var query = { + t: 'l', + open: true + }; + return ChatSubscription.find(query, { + sort: { + 't': 1, + 'name': 1 + } + }); + } +}); + +Template.livechat.events({ +}); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 88369db925d..7bf0d95652f 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -20,12 +20,19 @@ Package.onUse(function(api) { api.use(['ecmascript', 'webapp', 'autoupdate'], 'server'); + api.imply('alanning:roles@1.2.12'); + api.addFiles('livechat.js', 'server'); api.addFiles('server/methods.js', 'server'); api.addFiles('server/publications.js', 'server'); + api.addFiles('permissions.js', 'server'); api.addFiles('config.js', 'server'); + api.addFiles('client/ui.js', 'client'); + api.addFiles('client/views/sideNav/livechat.html', 'client'); + api.addFiles('client/views/sideNav/livechat.js', 'client'); + api.addAssets('rocket-livechat.js', 'client'); api.addAssets('public/livechat.css', 'client'); api.addAssets('public/livechat.js', 'client'); diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js new file mode 100644 index 00000000000..4c4c84f3ff4 --- /dev/null +++ b/packages/rocketchat-livechat/permissions.js @@ -0,0 +1,32 @@ +Meteor.startup(function() { + var i, j, len, len1, permission, ref, role, roles, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + var permissions = [ + { + _id: 'receive-livechat', + roles : ['livechat-agent'] + }, + { + _id: 'edit-livechat-settings', + roles : ['livechat-manager'] + } + ]; + + roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); + + for (i = 0, len = permissions.length; i < len; i++) { + permission = permissions[i]; + RocketChat.models.Permissions.upsert(permission._id, { + $setOnInsert: permission + }); + ref = permission.roles; + for (j = 0, len1 = ref.length; j < len1; j++) { + role = ref[j]; + if (indexOf.call(roles, role) < 0) { + Roles.createRole(role); + roles.push(role); + } + } + } +}); -- GitLab From 80d1e52a5be285bdcd3d0b24d58e046f3ab09a98 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 22 Oct 2015 16:50:38 +0200 Subject: [PATCH 0295/1338] moved some files for further migration --- .../app/client/lib/{ => fromApp}/RoomHistoryManager.coffee | 0 .../app/client/lib/{ => fromApp}/avatar.coffee | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/rocketchat-livechat/app/client/lib/{ => fromApp}/RoomHistoryManager.coffee (100%) rename packages/rocketchat-livechat/app/client/lib/{ => fromApp}/avatar.coffee (100%) diff --git a/packages/rocketchat-livechat/app/client/lib/RoomHistoryManager.coffee b/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee similarity index 100% rename from packages/rocketchat-livechat/app/client/lib/RoomHistoryManager.coffee rename to packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee diff --git a/packages/rocketchat-livechat/app/client/lib/avatar.coffee b/packages/rocketchat-livechat/app/client/lib/fromApp/avatar.coffee similarity index 100% rename from packages/rocketchat-livechat/app/client/lib/avatar.coffee rename to packages/rocketchat-livechat/app/client/lib/fromApp/avatar.coffee -- GitLab From 1d80dfbca25a82f8a9669b5f3f1eb5a25243a359 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 23 Oct 2015 15:10:54 +0200 Subject: [PATCH 0296/1338] fixing livechat route --- packages/rocketchat-livechat/client/ui.js | 7 ++++++- packages/rocketchat-livechat/package.js | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index f861e437b71..7642597fd25 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -1,4 +1,9 @@ Meteor.startup(function() { - RocketChat.roomTypes.add('livechat', ['livechat-agent', 'livechat-manager']); + RocketChat.roomTypes.addType('livechat', ['livechat-agent', 'livechat-manager']); + RocketChat.roomTypes.setRoute('l', 'live', function(sub) { + console.log('livechat route ->',sub); + return { name: sub.name }; + }); + AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); }); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 7bf0d95652f..3702ab9f0cd 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -21,6 +21,7 @@ Package.onUse(function(api) { api.use(['ecmascript', 'webapp', 'autoupdate'], 'server'); api.imply('alanning:roles@1.2.12'); + api.use('kadira:flow-router', 'client'); api.addFiles('livechat.js', 'server'); api.addFiles('server/methods.js', 'server'); @@ -30,6 +31,7 @@ Package.onUse(function(api) { api.addFiles('config.js', 'server'); api.addFiles('client/ui.js', 'client'); + api.addFiles('client/route.js', 'client'); api.addFiles('client/views/sideNav/livechat.html', 'client'); api.addFiles('client/views/sideNav/livechat.js', 'client'); -- GitLab From c7cc5e92b844127f306b710069e2a8f62721c061 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 23 Oct 2015 18:43:57 +0200 Subject: [PATCH 0297/1338] livechat route --- packages/rocketchat-livechat/client/route.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/rocketchat-livechat/client/route.js diff --git a/packages/rocketchat-livechat/client/route.js b/packages/rocketchat-livechat/client/route.js new file mode 100644 index 00000000000..fb95d8c23c9 --- /dev/null +++ b/packages/rocketchat-livechat/client/route.js @@ -0,0 +1,11 @@ +FlowRouter.route('/live/:name', { + name: 'live', + + action: function(params, queryParams) { + console.log('action route livechat'); + Session.set('showUserInfo'); + openRoom('l', params.name); + }, + + triggersExit: [roomExit] +}); -- GitLab From d5771492478dbac10a6f50dc571d0431f79d85f0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 28 Oct 2015 16:46:57 +0100 Subject: [PATCH 0298/1338] Fix spotlight search --- client/views/app/roomSearch.html | 2 +- client/views/app/spotlight/spotlight.coffee | 5 ++-- server/publications/spotlight.coffee | 29 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 server/publications/spotlight.coffee diff --git a/client/views/app/roomSearch.html b/client/views/app/roomSearch.html index 4f7f3ee0c3e..fe3610237e2 100644 --- a/client/views/app/roomSearch.html +++ b/client/views/app/roomSearch.html @@ -1,5 +1,5 @@ <template name="roomSearch"> - <i class="{{roomIcon}} {{userStatus}}"></i> {{username}} + <i class="{{roomIcon}} {{userStatus}}"></i> {{name}} </template> <template name="roomSearchEmpty"> <p>{{_ "Nothing_found"}}.</p> diff --git a/client/views/app/spotlight/spotlight.coffee b/client/views/app/spotlight/spotlight.coffee index db4bbfc98b6..f52ba4fa767 100644 --- a/client/views/app/spotlight/spotlight.coffee +++ b/client/views/app/spotlight/spotlight.coffee @@ -14,12 +14,11 @@ Template.spotlight.helpers rules: [ { collection: 'UserAndRoom' - subscription: 'roomSearch' + subscription: 'spotlight' field: 'name' template: Template.roomSearch noMatchTemplate: Template.roomSearchEmpty matchAll: true - filter: { uid: { $ne: Meteor.userId() } } sort: 'name' } ] @@ -43,4 +42,4 @@ Template.spotlight.events event.currentTarget.value = '' - spotlight.hide() \ No newline at end of file + spotlight.hide() diff --git a/server/publications/spotlight.coffee b/server/publications/spotlight.coffee new file mode 100644 index 00000000000..3a1231593be --- /dev/null +++ b/server/publications/spotlight.coffee @@ -0,0 +1,29 @@ +Meteor.publish 'spotlight', (selector, options, collName) -> + unless this.userId + return this.ready() + + console.log '[publish] spotlight -> '.green, 'selector:', selector, 'options:', options, 'collName:', collName + + self = this + subHandleUsers = null + subHandleRooms = null + + subHandleUsers = RocketChat.models.Users.findUsersByNameOrUsername(new RegExp(selector.name.$regex, 'i'), { limit: 10, fields: { name: 1, username: 1, status: 1 } }).observeChanges + added: (id, fields) -> + data = { type: 'u', uid: id, name: fields.username + ' - ' + fields.name, status: fields.status } + self.added("autocompleteRecords", id, data) + removed: (id) -> + self.removed("autocompleteRecords", id) + + subHandleRooms = RocketChat.models.Rooms.findByNameContainingAndTypes(selector.name.$regex, ['c'], { limit: 10, fields: { t: 1, name: 1 } }).observeChanges + added: (id, fields) -> + data = { type: 'r', rid: id, name: fields.name, t: fields.t } + self.added("autocompleteRecords", id, data) + removed: (id) -> + self.removed("autocompleteRecords", id) + + this.ready() + + this.onStop -> + subHandleUsers?.stop() + subHandleRooms?.stop() -- GitLab From 5468c93c9c091665f71553ef211cf5e60952ba8a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 28 Oct 2015 16:55:53 +0100 Subject: [PATCH 0299/1338] added back _colors files --- .../stylesheets/utils/_colors.import.less | 1210 +++++++++++++++++ 1 file changed, 1210 insertions(+) create mode 100644 packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less new file mode 100644 index 00000000000..e0cb54f452a --- /dev/null +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -0,0 +1,1210 @@ +.custom-scroll(@background, @thumb, @width: 8px, @height: 8px) { + &::-webkit-scrollbar { + height: @height; + width: @width; + background: @background; + } + &::-webkit-scrollbar-thumb { + background-color: @thumb; + -webkit-border-radius: 50px; + } + &::-webkit-scrollbar-corner { + background-color: @background; + } +} + +a { + &:hover, + &:active { + color: @primary-font-color; + } +} + +code { + background-color: @code-background; + border-color: @code-border; + color: @code-color; +} + +blockquote { + &:before { + background-color: @blockquote-background; + } +} + +.login-terms { + color: @smallprint-font-color; + a { + color: @smallprint-font-color; + &:hover { + color: @smallprint-hover-color; + } + } +} + +.upload-preview { + background-color: @secondary-background-color; +} + +.upload-preview-title { + background-color: @tertiary-background-color; +} + +.first-unread { + &.first-unread-opaque { + .body { + &::before { + background-color: lighten(@info-font-color, 25%); + } + + &::after { + color: @info-font-color; + } + } + } + .body { + &::before { + background-color: lighten(@info-active-font-color, 25%); + } + + &::after { + background-color: @content-background-color; + color: @info-active-font-color; + } + } +} + +.alert { + border-color: rgba(0, 0, 0, 0); +} + +.alert-warning { + color: #8A6D3B; + background-color: #FCF8E3; + border-color: #FAEBCC; +} + +.alert-danger { + color: #A94442; + background-color: #F2DEDE; + border-color: #EBCCD1; +} + +.scrollable { + .custom-scroll(transparent, #BFBFBF); +} + +.rocket-form { + legend { + &:after { + background-color: #DFDFDF; + } + } +} + +.input-line { + .clearfix; + &.search { + .icon-search { + color: @secondary-font-color; + } + } + > label { + color: @primary-font-color; + } +} + +.rocket-h2 { + color: #EFEFEF; +} + +.rocket-h3 { + color: #EAEAEA; +} + +html { + .custom-scroll(transparent, rgba(255, 255, 255, 0.05), 3px); +} + +body { + color: @primary-font-color; + background-color: @primary-background-color; +} + +textarea, +select, +input[type='text'], +input[type='number'], +input[type='email'], +input[type='password'] { + border-color: #E7E7E7; + background-color: #fff; +} + +input.search { + &:before { + background-color: #000; + } +} + +.form-horizontal .control-label { + color: @primary-font-color; +} + +.-autocomplete-container { + p { + color: @secondary-font-color; + } +} + +.-autocomplete-item { + color: @secondary-font-color; + i { + color: @secondary-font-color; + } + &.selected { + background-color: @tertiary-background-color; + color: @primary-font-color; + } +} + +label.required:after { + color: red; +} + +.status-offline, +.icon-at.status-offline { + color: @status-offline; +} + +.status-online, +.icon-at.status-online { + color: @status-online; +} + +.status-busy, +.icon-at.status-busy { + color: @status-busy; +} + +.status-away, +.icon-at.status-away { + color: @status-away; +} + +// TODO -- Refactor favorite styles and logic; +.favorite-room { + color: #FECF09; +} + +.toggle-favorite { + color: #AAA; +} + +.btn-loading { + color: #444 !important; + background-color: transparent !important; + &:hover { + background-color: transparent !important; + } +} + +// new layout buttons +.button { + background-color: #FFF; + color: rgba(255, 255, 255, 0.85); + background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); + &:before { + background-color: rgba(0, 0, 0, 0.1); + } + &:hover { + color: #FFF; + } + &.secondary { + background-color: @tertiary-background-color; + color: @primary-font-color; + &:before { + background-color: rgba(0, 0, 0, 0.045); + } + } + &.delete, + &.remove, + &.red { + background-color: #bc2031; + } + &.lightblue { + background-color: #02acec; + } + &.clean { + background-color: rgba(0, 0, 0, 0.025); + } + &.facebook { + background-color: #325c99; + } + &.twitter { + background-color: #02acec; + } + &.google { + background-color: #dd4b39; + } + &.github { + background-color: #4c4c4c; + } + &.gitlab { + background-color: #373d47; + } + &.trello { + background-color: #026aa7; + } + &.meteor-developer { + background-color: #de4f4f; + } + &.wordpress { + background-color: #1e8cbe; + } +} + +.burger { + i { + background-color: #333; + } + + .unread-burger-alert { + background-color: #F95555; + color: @content-background-color; + } +} + +.arrow { + &:before, + &:after { + background-color: #aaa; + } +} + +a.github-fork { + background-color: #5c5c5c; + color: #f0f0f0; + &:hover { + background-color: #4b4b4b; + color: #FFF; + } + &:before { + border-top-color: #f0f0f0; + } + &:after { + border-top-color: #f0f0f0; + } +} + +.mac-bar { + background-color: #ddd; + i { + background-color: #ff5f57; + &:nth-child(2) { + background-color: #ffbd2e; + } + &:nth-child(3) { + background-color: #28ca41; + } + } +} + +.avatar { + .avatar-image { + background-color: transparent; + } + &[initials]:before { + color: #FFF; + } +} + +#rocket-chat { + background-color: @content-background-color; +} + +.account-box { + .info { + background-color:@primary-background-color; + h4 { + color: rgba(255, 255, 255, 0.65); + } + &.status-offline { + .thumb:after { + border-color: darken(@status-offline, 5%); + background-color: @status-offline; + } + } + &.status-online { + .thumb:after { + border-color: darken(@status-online, 5%); + background-color: @status-online; + } + } + &.status-away { + .thumb:after { + border-color: darken(@status-away, 5%); + background-color: @status-away; + } + } + &.status-busy { + .thumb:after { + border-color: darken(@status-busy, 5%); + background-color: @status-busy; + } + } + } + .options { + background-color: @primary-background-color; + .status { + &:after { + border-color: #6f6f6f; + } + &.offline { + &:after { + border-color: #666666; + background-color: #7b7b7b; + } + } + &.online { + &:after { + border-color: #2c9210; + background-color: #35AC19; + } + } + &.away { + &:after { + border-color: #e69200; + background-color: #fcb316; + } + } + &.busy { + &:after { + border-color: #9f0030; + background-color: #D30230; + } + } + } + span.soon { + color: #aaa; + } + a { + color: rgba(255, 255, 255, 0.5); + border-bottom-color: darken(@primary-background-color, 2%); + &:hover { + background-color: darken(@primary-background-color, 2%); + color: rgba(255, 255, 255, 0.75); + } + } + } + &.active .info, + .info:hover { + h4 { + color: rgba(255, 255, 255, 0.85); + } + } + .hover & { + .info h4 { + color: rgba(255, 255, 255, 0.85); + } + } +} + +// rooms-box +.flex-nav { + //background-color: @primary-background-color; + background-color: transparent; + color: @tertiary-font-color; + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + header { + background-color: @primary-background-color; + } + footer { + background-color: @primary-background-color; + } + .content { + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + background-color: @primary-background-color; + } + .input-line { + input[type='text'], + input[type='password'], + select { + border-color: @tertiary-font-color; + background-color: @primary-background-color; + color: @input-font-color; + } + + & label { + color:@input-font-color; + } + } + .selected-users { + li { + background-color: rgba(0, 0, 0, 0.1); + } + } +} + +.side-nav { + background-color: #F4F4F4; + color: #000; + &:before { + background-color: #dfdfdf; + } + .rooms-list { + background-color: lighten(@primary-background-color, 2%); + .custom-scroll(transparent, rgba(255, 255, 255, 0.05)); + } + .more { + color: @tertiary-font-color; + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + .input-error { + color: #f09286; + } + .empty { + color: @tertiary-font-color; + } + .header { + color: #fff; + background-color: @primary-background-color; + } + > .arrow { + &.hover, + &:hover { + &:before, + &:after { + background-color: rgba(255, 255, 255, 0.85); + } + } + } + .footer { + background: #fff; + background-color: @primary-background-color; + small { + color: @tertiary-font-color; + } + } + h3 { + color: @tertiary-font-color; + a { + color: inherit; + } + &:hover { + background-color: rgba(0, 0, 0, 0.1); + } + } + .unread { + background-color: #1dce73; + color: #FFF; + } + ul { + li { + .remove, + .erase { + color: #666; + } + &:hover { + .opt { + background-color: transparent; + } + } + &.active { + a { + background-color: rgba(255, 255, 255, 0.075); + color: rgba(255, 255, 255, 0.75); + } + .opt { + background-color: transparent; + } + } + &.has-alert { + .name { + color: #ffffff; + } + } + &.away { + a { + color: #666; + } + } + } + a { + color: @tertiary-font-color; + &:hover { + background-color: rgba(255, 255, 255, 0.05); + } + } + .opt { + background-color: transparent; + i { + color: rgba(255, 255, 255, 0.5); + &:hover { + color: rgba(255, 255, 255, 0.75); + } + } + } + i { + color: rgba(255, 255, 255, 0.35); + } + input[type=text] { + color: #000; + } + } +} + +.page-container { + .content { + .custom-scroll(transparent, #EAEAEA); + } +} + +.fixed-title { + background: #fff; + border-bottom-color: @tertiary-background-color; +} + +.cms-page { + color: #444; + background-color: @content-background-color; +} + +.spotlight { + background-color: rgba(0,0,0,.3); + > .spotlight-input { + color: #444; + > i { + color: #aaa; + } + } +} + +.mobile-message-menu { + background-color: rgba(0,0,0,.3); +} + +.page-static { + .content { + .section { + .section-content { + border-color: #ddd; + } + } + } +} + +.page-list { + .results { + border-bottom-color: #DFDFDF; + color: @secondary-font-color; + } + .list { + a { + color: @primary-font-color; + border-bottom-color: @secondary-background-color; + &:hover { + background-color: @secondary-background-color; + } + } + li { + color: @secondary-font-color; + &:after { + background-color: @secondary-font-color; + } + } + .info { + a { + color: @primary-font-color; + } + } + .room-info { + &:hover { + background-color: @secondary-background-color; + } + } + .status { + color: @secondary-font-color; + } + + table { + tbody { + tr:nth-child(odd) { + background-color: @secondary-background-color; + } + } + } + } +} + +.image-to-download { + background-color: #fafafa; + border-color: #ddd; + color: #aaa; +} + +.room-not-found { + color: orange; +} + +.container-bars { + >div { + border-color: #ffffff; + } + + .upload-progress { + background-color: #b2d5c9; + color: @content-background-color; + + &.upload-error { + background-color: #FF6161; + border-color: #863737; + } + .upload-progress-progress { + background-color: #4c9789; + } + > a { + &:hover { + color: #eee; + } + } + } + + .unread-bar { + background-color: #E6F4FD; + color: #068FE4; + } +} + +// change to page-messages +.messages-container { + .edit-room-title { + color: @secondary-font-color; + &:hover { + color: @primary-font-color; + } + } + .wrapper { + .custom-scroll(transparent, rgba(180,180,180,.75)); + } + .footer { + background: #FCFCFC; + border-top-color: @tertiary-background-color; + } + .message-popup { + background: #FAFAFA; + } + .message-popup-title { + background-color: @secondary-background-color; + border-bottom-color: #EEE; + } + .popup-item { + color: @secondary-font-color; + &.selected { + background-color: @tertiary-background-color; + color: @primary-font-color; + } + } + .popup-user-status { + border-color: rgba(0,0,0,.2); + } + .popup-user-status-system { + border-color: transparent; + } + .popup-user-status-offline { + background-color: @status-offline; + } + .popup-user-status-online { + background-color: @status-online; + } + .popup-user-status-away { + background-color: @status-away; + } + .popup-user-status-busy { + background-color: @status-busy; + } + .message-form { + > div { + > .file { + border-color: #E7E7E7; + color: #888; + background-color: #FCFCFC; + &:hover { + background-color: #F1F1F1; + color: #666; + } + } + > .mic, .stop-mic { + color: #888; + background-color: #FCFCFC; + &:hover { + background-color: #F1F1F1; + color: #666; + } + } + } + textarea { + &.editing { + background-color: #fff7d8; + } + } + .icon-paper-plane { + color: @secondary-font-color; + &:hover { + color: @primary-font-color; + } + } + .users-typing { + color: #888888; + background: #FCFCFC; + } + .formatting-tips { + color: #444444; + q { + border-left-color: #ccc; + } + } + .editing-commands { + .editing-commands-cancel { + color: #888888; + } + .editing-commands-save { + color: #888888; + } + } + } +} + +.messages-box { + .load-more { + span { + border-color: #CCC; + background-color: #EEE; + } + } + .start { + color: @secondary-font-color; + } + .new-message { + background: #428bca; + color: #FFF; + } + .editing { + .body { + background-color: #fff7d8; + } + } +} + +.message { + &.new-day { + &:before { + color: @secondary-font-color; + background-color: @content-background-color; + } + &:after { + border-top-color: #ddd; + } + } + .user { + color: #444444; + &:hover { + color: #333; + } + } + .info { + color: @info-font-color; + } + &.system { + .body { + color: @info-font-color; + } + } + a { + color: @link-font-color; + &:hover { + color: darken(@link-font-color, 10%); + } + } +} + +// FLEX-TAB and FLEX-TAB views +.flex-tab { + background-color: @secondary-background-color; + border-left-color: @tertiary-background-color; + .control { + background-color: @secondary-background-color; + &:before { + background-color: @tertiary-background-color; + } + .more { + background-color: @tertiary-background-color; + border-bottom-color: @tertiary-background-color; + color: @secondary-font-color; + &:hover { + .arrow { + .arrow { + &:before, + &:after { + background-color: #4a4a4a; + } + } + } + } + .arrow { + &:before, + &:after { + background-color: #7a7a7a; + } + } + .flex-opened & { + background-color: @secondary-background-color; + &:hover { + .arrow { + &:before, + &:after { + background-color: #7a7a7a; + } + } + } + } + } + .search-form { + .icon-plus { + color: @secondary-font-color; + } + } + .info-tabs { + a { + color: inherit; + border-left-color: rgb(234, 234, 234); + &.active { + background-color: #F4F4F4; + } + &:last-child { + border-right-color: rgb(234, 234, 234); + } + } + } + } + .content { + .custom-scroll(transparent, #DADADA); + } +} + +.list-view { + > .status { + p { + color: @secondary-font-color; + } + .see-all { + color: @secondary-font-color; + background-color: transparent; + } + } +} + +.user-view { + .info { + h3 { + i.status-offline { + &:after { + border-color: darken(@status-offline, 5%); + background-color: @status-offline; + } + } + i.status-online { + &:after { + border-color: darken(@status-online, 5%); + background-color: @status-online; + } + } + i.status-away { + &:after { + border-color: darken(@status-away, 5%); + background-color: @status-away; + } + } + i.status-busy { + &:after { + border-color: darken(@status-busy, 5%); + background-color: @status-busy; + } + } + } + p { + color: @secondary-font-color; + } + } + .stats { + li { + background-color: #e9e9e9; + } + } + .box { + h4 { + } + &:after { + background-color: #CDCDCD; + } + } + .tags { + li { + background-color: #CDCDCD; + } + } + .links { + a { + color: #6f6f6f; + &:hover { + background-color: #e9e9e9; + color: #333; + } + } + } + .channels { + p { + color: @secondary-font-color; + } + a { + color: #6f6f6f; + } + } + .edit-form { + p { + color: @secondary-font-color; + } + } +} + +.user-image-status(@color) { + .avatar { + &:after { + background-color: darken(@color, 5%); + } + } +} + +.user-image { + background-color: @tertiary-background-color; + &:hover, + &.selected { + .avatar { + &:after { + } + .status-offline { + &:after { + background-color: @status-offline; + } + } + .status-online { + &:after { + background-color: @status-online; + } + } + .status-away { + &:after { + background-color: @status-away; + } + } + .status-busy { + &:after { + background-color: @status-busy; + } + } + p { + color: @primary-font-color; + } + } + } + .lines & { + background-color: transparent; + a { + background-color: transparent; + } + p { + color: @secondary-font-color; + } + } + &.status-offline { + .user-image-status(@status-offline); + } + &.status-online { + .user-image-status(@status-online); + } + &.status-away { + .user-image-status(@status-away); + } + &.status-busy { + .user-image-status(@status-busy); + } +} + +.user-profile { + .info { + a { + color: @primary-font-color; + &:hover { + color: @secondary-font-color; + } + } + } +} + +.rocket-modal { + background-color: rgba(0, 0, 0, 0.5); + &.fluid { + .modal { + main { + .custom-scroll(transparent, #CFCFCF); + } + } + } + legend { + color: @secondary-font-color; + &:before { + background-color: #dfdfdf; + } + } + .modal { + background-color: @content-background-color; + header { + background-color: #DADADA; + .close { + i { + color: @secondary-font-color; + } + &:hover { + i { + color: @primary-font-color; + } + } + } + } + main { + background-color: @content-background-color; + } + footer { + background-color: #eaeaea; + } + } +} + +#login-card { + background-color: #FAFAFA; + h2 { + color: @primary-font-color; + &.error { + color: #b40202; + } + } + h3 { + &.error { + color: #b40202; + } + } + a { + color: @primary-background-color; + &:active { + color: @primary-background-color; + } + &:hover { + color: darken(@primary-background-color, 10%); + } + } + .input-text { + input { + background-color: transparent; + border-bottom-color: #DFDFDF; + &.error { + border-bottom-color: #b40202; + &::-webkit-input-placeholder { + color: #b40202; + } + &:-moz-placeholder { + color: #b40202; + } + /* Firefox 18- */ + &::-moz-placeholder { + color: #b40202; + } + /* Firefox 19+ */ + &:-ms-input-placeholder { + color: #b40202; + } + } + } + input:-webkit-autofill { + color: @content-background-color !important; + } + input:-webkit-autofill { + background-color: transparent !important; + } + } +} + +.full-page { + background-color: darken(@primary-background-color, 10%); + .background-image(linear-gradient(darken(@primary-background-color,10%),@primary-background-color)); + .text { + color: #FFF; + .button { + background-color: #bc2031; + color: #FFF; + } + } + footer { + color: #fff; + div.switch-language { + a { + color: @secondary-font-color; + } + } + } +} + +.avatar-suggestion-item { + background-color: @secondary-background-color; + border-color: darken(@secondary-background-color, 10%); + .avatar { + background-size: cover; + background-color: @tertiary-background-color; + } + .question-mark { + &::before { + color: darken(@tertiary-background-color, 10%); + } + } +} + +.statistics-table { + border-color: #F9F9F9; +} + +@media all and(max-width: 780px) { + #rocket-chat { + .main-content { + background-color: @content-background-color; + } + } +} + +.dropzone { + &.over .dropzone-overlay { + background-color: rgba(0, 0, 0, 0.5); + color: @content-background-color; + > div { + background-color: rgba(0, 0, 0, 0.6); + } + } +} + +.is-cordova { + .flex-tab { + button.more { + background-color: #fff; + } + } +} -- GitLab From 3eb818d3d3b7bc9eebd6505835b7d52abd0941fd Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Wed, 28 Oct 2015 10:56:13 -0500 Subject: [PATCH 0300/1338] Remove reference to request and instead use the http module --- .meteor/packages | 1 - .meteor/versions | 1 - server/methods/setAvatarFromService.coffee | 39 +++++++++++----------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 59a9aa4b678..d16b2be6adf 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -109,5 +109,4 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter -froatsnook:request rocketchat:tutum diff --git a/.meteor/versions b/.meteor/versions index 61f7761f8f5..b2a52c59f3e 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -42,7 +42,6 @@ email@1.0.8 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 -froatsnook:request@2.64.0 geojson-utils@1.0.4 github@1.1.4 google@1.1.7 diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index efe29b838d6..cdcd27f5b3d 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -12,26 +12,25 @@ Meteor.methods return if service is 'url' - headReq = request.headSync dataURI - - if headReq.response.statusCode != 200 - console.log "Not a valid response, #{headReq.response.statusCode}, from the avatar url:", dataURI - throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> error on checking the image type') - - if headReq.response.headers['content-type'] isnt 'image/jpeg' - throw new Meteor.Error('invalid-image-url', '[methods] setAvatarFromService -> url service -> Invalid url, it is not a jpeg') - - image = request.getSync dataURI, { encoding: null } - ars = RocketChatFile.bufferToStream image.body - aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", headReq.response.headers['content-type'] - aws.on 'end', Meteor.bindEnvironment -> - Meteor.setTimeout -> - console.log "Set #{user.username}'s avatar from the url: #{dataURI}" - RocketChat.models.Users.setAvatarOrigin user._id, service - RocketChat.Notifications.notifyAll 'updateAvatar', { username: user.username } - , 500 - - ars.pipe(aws) + try + result = HTTP.get dataURI, npmRequestOptions: {encoding: 'binary'} + + if result.statusCode isnt 200 + console.log "Not a valid response, #{result.statusCode}, from the avatar url: #{dataURI}" + throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> error on getting the avatar from url') + + ars = RocketChatFile.bufferToStream new Buffer(result.content, 'binary') + aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", result.headers['content-type'] + aws.on 'end', Meteor.bindEnvironment -> + Meteor.setTimeout -> + console.log "Set #{user.username}'s avatar from the url: #{dataURI}" + RocketChat.models.Users.setAvatarOrigin user._id, service + RocketChat.Notifications.notifyAll 'updateAvatar', { username: user.username } + , 500 + + ars.pipe(aws) + catch e + throw e return {image, contentType} = RocketChatFile.dataURIParse dataURI -- GitLab From 2a7411a3e0ea6645858dd94ef3193af896d1a4f3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 28 Oct 2015 18:05:50 +0100 Subject: [PATCH 0301/1338] Fix problems with data load --- client/lib/RoomHistoryManager.coffee | 2 +- server/methods/loadHistory.coffee | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/lib/RoomHistoryManager.coffee b/client/lib/RoomHistoryManager.coffee index 4ec46f52de3..44807d2d76c 100644 --- a/client/lib/RoomHistoryManager.coffee +++ b/client/lib/RoomHistoryManager.coffee @@ -27,7 +27,7 @@ if lastMessage? ts = lastMessage.ts else - ts = new Date + ts = undefined ls = undefined typeName = undefined diff --git a/server/methods/loadHistory.coffee b/server/methods/loadHistory.coffee index 94b0a3a9db1..f7058298f32 100644 --- a/server/methods/loadHistory.coffee +++ b/server/methods/loadHistory.coffee @@ -14,7 +14,12 @@ Meteor.methods if not RocketChat.settings.get 'Message_ShowEditedStatus' options.fields = { ets: 0 } - messages = _.map RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestamp(rid, end, options).fetch(), (message) -> + if end? + records = RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestamp(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 -- GitLab From b1e9f3c0d392d6c5c45688739be9682f0fc4eeb1 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 21:14:12 +0100 Subject: [PATCH 0302/1338] meteor update --- .meteor/versions | 223 +++++++++++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 94 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index f0c9af8cfc7..b308953777b 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,112 +1,134 @@ -accounts-base@1.2.0 -accounts-facebook@1.0.4 -accounts-github@1.0.4 -accounts-google@1.0.4 -accounts-meteor-developer@1.0.4 -accounts-oauth@1.1.5 -accounts-password@1.1.1 -accounts-twitter@1.0.4 +accounts-base@1.2.2 +accounts-facebook@1.0.6 +accounts-github@1.0.6 +accounts-google@1.0.6 +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.3.3 arunoda:streams@0.1.17 -autoupdate@1.2.1 -base64@1.0.3 -binary-heap@1.0.3 -blaze@2.1.2 -blaze-tools@1.0.3 -boilerplate-generator@1.0.3 -callback-hook@1.0.3 -cfs:http-methods@0.0.29 -check@1.0.5 +autoupdate@1.2.4 +babel-compiler@5.8.24_1 +babel-runtime@0.1.4 +base64@1.0.4 +binary-heap@1.0.4 +blaze@2.1.3 +blaze-html-templates@1.0.1 +blaze-tools@1.0.4 +boilerplate-generator@1.0.4 +caching-compiler@1.0.0 +caching-html-compiler@1.0.2 +callback-hook@1.0.4 +cfs:http-methods@0.0.30 +check@1.1.0 chrismbeckett:toastr@2.1.2_1 -coffeescript@1.0.6 -cosmos:browserify@0.5.0 +coffeescript@1.0.11 +cosmos:browserify@0.5.1 dandv:caret-position@2.1.1 -ddp@1.1.0 -deps@1.0.7 +ddp@1.2.2 +ddp-client@1.2.1 +ddp-common@1.2.2 +ddp-rate-limiter@1.0.0 +ddp-server@1.2.2 +deps@1.0.9 +diff-sequence@1.0.1 dispatch:run-as-user@0.0.2 -ejson@1.0.6 -email@1.0.6 -facebook@1.2.1 -fastclick@1.0.3 -francocatena:status@1.3.2 -geojson-utils@1.0.3 -github@1.1.3 -google@1.1.5 -html-tools@1.0.4 -htmljs@1.0.4 -http@1.1.0 -id-map@1.0.3 +ecmascript@0.1.6 +ecmascript-runtime@0.2.6 +ejson@1.0.7 +email@1.0.8 +facebook@1.2.2 +fastclick@1.0.7 +francocatena:status@1.5.0 +geojson-utils@1.0.4 +github@1.1.4 +google@1.1.7 +hot-code-push@1.0.0 +html-tools@1.0.5 +htmljs@1.0.5 +http@1.1.1 +id-map@1.0.4 idorecall:email-normalize@1.0.0 -jalik:ufs@0.2.8 -jalik:ufs-gridfs@0.1.0 +jalik:ufs@0.3.3 +jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 -jquery@1.11.3_2 -json@1.0.3 -kadira:blaze-layout@2.0.1 -kadira:flow-router@2.4.0 -kenton:accounts-sandstorm@0.1.4 +jquery@1.11.4 +kadira:blaze-layout@2.2.0 +kadira:flow-router@2.7.0 +kenton:accounts-sandstorm@0.1.7 kevohagan:sweetalert@1.0.0 -konecty:autolinker@1.0.2 +konecty:autolinker@1.0.3 konecty:change-case@2.3.0 konecty:delayed-task@1.0.0 konecty:mongo-counter@0.0.3 konecty:multiple-instances-status@1.0.3 konecty:nrr@2.0.2 -konecty:user-presence@1.2.5 -launch-screen@1.0.2 -less@1.0.14 -livedata@1.0.13 -localstorage@1.0.3 -logging@1.0.7 -matb33:collection-hooks@0.7.14 -meteor@1.1.6 -meteor-developer@1.1.3 -meteor-platform@1.2.2 -meteorhacks:kadira@2.23.1 -meteorhacks:meteorx@1.3.1 +konecty:user-presence@1.2.6 +launch-screen@1.0.4 +less@2.5.1 +livedata@1.0.15 +localstorage@1.0.5 +logging@1.0.8 +matb33:collection-hooks@0.7.15 +meteor@1.1.10 +meteor-base@1.0.1 +meteor-developer@1.1.5 +meteorhacks:kadira@2.24.1 +meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 -minifiers@1.1.5 -minimongo@1.0.8 +minifiers@1.1.7 +minimongo@1.0.10 mizzao:autocomplete@0.5.1 -mizzao:timesync@0.3.3 -mobile-status-bar@1.0.3 +mizzao:timesync@0.3.4 +mobile-experience@1.0.1 +mobile-status-bar@1.0.6 momentjs:moment@2.10.6 monbro:mongodb-mapreduce-aggregation@1.0.1 -mongo@1.1.0 -mongo-livedata@1.0.8 +mongo@1.1.3 +mongo-id@1.0.1 +mongo-livedata@1.0.9 mrt:reactive-store@0.0.1 mystor:device-detection@0.2.0 nimble:restivus@0.8.4 nooitaf:colors@0.0.2 npm-bcrypt@0.7.8_2 -oauth@1.1.4 -oauth1@1.1.4 -oauth2@1.1.3 -observe-sequence@1.0.6 -ordered-dict@1.0.3 -pauli:accounts-linkedin@1.1.2 -pauli:linkedin@1.1.2 -percolate:migrations@0.7.6 -percolate:synced-cron@1.2.1 +npm-mongo@1.4.39_1 +oauth@1.1.6 +oauth1@1.1.5 +oauth2@1.1.5 +observe-sequence@1.0.7 +ordered-dict@1.0.4 +pauli:accounts-linkedin@1.2.0 +pauli:linkedin@1.2.0 +perak:codemirror@1.2.8 +percolate:migrations@0.9.6 +percolate:synced-cron@1.3.0 +pntbr:js-yaml-client@0.0.1 +promise@0.5.1 qnub:emojione@0.0.3 raix:eventemitter@0.1.3 -raix:eventstate@0.0.2 -raix:handlebar-helpers@0.2.4 +raix:eventstate@0.0.4 +raix:handlebar-helpers@0.2.5 raix:push@2.6.13-rc.1 raix:ui-dropped-event@0.0.7 -random@1.0.3 -reactive-dict@1.1.0 -reactive-var@1.0.5 -reload@1.1.3 -retry@1.0.3 +random@1.0.5 +rate-limit@1.0.0 +reactive-dict@1.1.3 +reactive-var@1.0.6 +reload@1.1.4 +retry@1.0.4 +rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 rocketchat:colors@0.0.1 rocketchat:custom-oauth@1.0.0 rocketchat:emojione@0.0.1 rocketchat:favico@0.0.1 rocketchat:file@0.0.1 +rocketchat:github-enterprise@0.0.1 rocketchat:gitlab@0.0.1 rocketchat:highlight@0.0.1 rocketchat:ldap@0.0.1 @@ -115,30 +137,43 @@ rocketchat:logger@0.0.1 rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 +rocketchat:message-star@0.0.1 +rocketchat:oembed@0.0.1 +rocketchat:slashcommands-invite@0.0.1 +rocketchat:slashcommands-join@0.0.1 +rocketchat:slashcommands-leave@0.0.1 +rocketchat:soundcloud@0.0.1 +rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 -rocketchat:webrtc-ib@0.0.1 -routepolicy@1.0.5 -service-configuration@1.0.4 -session@1.1.0 -sha@1.0.3 +rocketchat:theme@0.0.1 +rocketchat:tutum@0.0.1 +rocketchat:webrtc@0.0.1 +rocketchat:wordpress@0.0.1 +routepolicy@1.0.6 +service-configuration@1.0.5 +session@1.1.1 +sha@1.0.4 simple:highlight.js@1.0.9 simple:json-routes@1.0.4 -spacebars@1.0.6 -spacebars-compiler@1.0.6 -srp@1.0.3 -tap:i18n@1.5.1 -templating@1.1.1 +spacebars@1.0.7 +spacebars-compiler@1.0.7 +srp@1.0.4 +standard-minifiers@1.0.2 +steffo:meteor-accounts-saml@0.0.1 +tap:i18n@1.7.0 +templating@1.1.5 +templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 tmeasday:crypto-md5@3.1.2 tmeasday:errors@2.0.0 todda00:friendly-slugs@0.3.4 -tracker@1.0.7 -twitter@1.1.4 -ui@1.0.6 -underscore@1.0.3 -underscorestring:underscore.string@3.2.0 -url@1.0.4 -webapp@1.2.0 -webapp-hashing@1.0.3 +tracker@1.0.9 +twitter@1.1.5 +ui@1.0.8 +underscore@1.0.4 +underscorestring:underscore.string@3.2.2 +url@1.0.5 +webapp@1.2.3 +webapp-hashing@1.0.5 yasaricli:slugify@0.0.7 -yasinuslu:blaze-meta@0.3.1 +yasinuslu:blaze-meta@0.3.3 -- GitLab From a0418d6257f5f8d8323938d04414bd22d0ffc822 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 21:28:54 +0100 Subject: [PATCH 0303/1338] meteor update --- .meteor/versions | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index b308953777b..15562e4f1fe 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,7 @@ cfs:http-methods@0.0.30 check@1.1.0 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.11 -cosmos:browserify@0.5.1 +cosmos:browserify@0.8.1 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 @@ -34,7 +34,7 @@ ddp-rate-limiter@1.0.0 ddp-server@1.2.2 deps@1.0.9 diff-sequence@1.0.1 -dispatch:run-as-user@0.0.2 +dispatch:run-as-user@1.1.1 ecmascript@0.1.6 ecmascript-runtime@0.2.6 ejson@1.0.7 @@ -73,7 +73,7 @@ less@2.5.1 livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 -matb33:collection-hooks@0.7.15 +matb33:collection-hooks@0.8.1 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 @@ -109,7 +109,7 @@ percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 -qnub:emojione@0.0.3 +qnub:emojione@1.5.1_1 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 @@ -153,7 +153,7 @@ routepolicy@1.0.6 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 -simple:highlight.js@1.0.9 +simple:highlight.js@1.2.0 simple:json-routes@1.0.4 spacebars@1.0.7 spacebars-compiler@1.0.7 -- GitLab From d0e6e017576aff488fc21c2d4487f76a49371861 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 21:59:17 +0100 Subject: [PATCH 0304/1338] remove limitation because we are going to disable services if they are not configured. --- client/views/account/avatar/prompt.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/views/account/avatar/prompt.html b/client/views/account/avatar/prompt.html index b47f5db908c..f43f9c8fd1f 100644 --- a/client/views/account/avatar/prompt.html +++ b/client/views/account/avatar/prompt.html @@ -58,7 +58,6 @@ {{/unless}} </div> </div> - <!-- disable for sandstorm {{#if suggestions.ready}} {{> avatarSuggestion suggestions.avatars.gravatar}} {{> avatarSuggestion suggestions.avatars.facebook}} @@ -87,11 +86,9 @@ {{> avatarSuggestionLogin 'twitter'}} {{/if}} - {{else}} {{_ "Loading_suggestion"}} {{/if}} - --> </div> </div> -- GitLab From 5aa83bf8d87e6f3cb05a1f4d75383c88313a5531 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 22:02:37 +0100 Subject: [PATCH 0305/1338] code formatting --- packages/rocketchat-hubot/hubot.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-hubot/hubot.coffee b/packages/rocketchat-hubot/hubot.coffee index 75bb0c03174..5851315dad1 100644 --- a/packages/rocketchat-hubot/hubot.coffee +++ b/packages/rocketchat-hubot/hubot.coffee @@ -55,8 +55,8 @@ class RocketChatAdapter extends Hubot.Adapter console.log 'ROCKETCHATADAPTER -> send'.blue # console.log envelope, strings sendHelper @robot, envelope, strings, (string) => - # console.log "send #{envelope.room}: #{string} (#{envelope.user.id})" if DEBUG - RocketChat.sendMessage RocketBot.user, { msg: string }, { _id: envelope.room } + console.log "send #{envelope.room}: #{string} (#{envelope.user.id})" if DEBUG + RocketChat.sendMessage RocketBot.user, { msg: string }, { _id: envelope.room } # Public: Raw method for sending emote data back to the chat source. # -- GitLab From bdef293f3b13ed921a99cf28f95b0f9f0ea95074 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 28 Oct 2015 19:04:16 -0200 Subject: [PATCH 0306/1338] Fixing message search. --- client/views/app/tabBar/messageSearch.coffee | 16 ++++++++++------ client/views/app/tabBar/messageSearch.html | 4 +--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/client/views/app/tabBar/messageSearch.coffee b/client/views/app/tabBar/messageSearch.coffee index b054cbbd823..9f9a520abd0 100644 --- a/client/views/app/tabBar/messageSearch.coffee +++ b/client/views/app/tabBar/messageSearch.coffee @@ -1,9 +1,9 @@ Template.messageSearch.helpers tSearchMessages: -> return t('Search_Messages') - - searchResult: -> - return Template.instance().searchResult.get() + + searchResultMessages: -> + return Template.instance().searchResult.get()?.messages Template.messageSearch.events "keydown #message-search": (e) -> @@ -11,16 +11,20 @@ Template.messageSearch.events e.preventDefault() "keyup #message-search": _.debounce (e, t) -> - t.searchResult.set undefined value = e.target.value.trim() - if value is '' + if value is '' and t.currentSearchTerm + t.searchResult.set undefined + return + else if value is t.currentSearchTerm 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 - , 1000 + t.currentSearchTerm = value + , 500 Template.messageSearch.onCreated -> + this.currentSearchTerm = '' this.searchResult = new ReactiveVar diff --git a/client/views/app/tabBar/messageSearch.html b/client/views/app/tabBar/messageSearch.html index 6be33db762a..6a56385a986 100644 --- a/client/views/app/tabBar/messageSearch.html +++ b/client/views/app/tabBar/messageSearch.html @@ -8,12 +8,10 @@ </div> </form> </div> - {{#if searchResult.messages}} <ul> - {{#each searchResult.messages}} + {{#each searchResultMessages}} {{#nrr nrrargs 'message' .}}{{/nrr}} {{/each}} </ul> - {{/if}} </div> </template> -- GitLab From c0148b9bcc3148959caf20a014fd6a8d463b1e16 Mon Sep 17 00:00:00 2001 From: George Secrieru <george.secrieru@gmail.com> Date: Wed, 28 Oct 2015 19:09:01 -0200 Subject: [PATCH 0307/1338] Small fix for searching same string again. --- client/views/app/tabBar/messageSearch.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/client/views/app/tabBar/messageSearch.coffee b/client/views/app/tabBar/messageSearch.coffee index 9f9a520abd0..59d128eec8e 100644 --- a/client/views/app/tabBar/messageSearch.coffee +++ b/client/views/app/tabBar/messageSearch.coffee @@ -13,6 +13,7 @@ Template.messageSearch.events "keyup #message-search": _.debounce (e, t) -> value = e.target.value.trim() if value is '' and t.currentSearchTerm + t.currentSearchTerm = '' t.searchResult.set undefined return else if value is t.currentSearchTerm -- GitLab From 1cf277225c7fef14ad8f3a02fa83be991b5be1f7 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 22:10:39 +0100 Subject: [PATCH 0308/1338] code formatting --- packages/rocketchat-lib/settings/server/updateServices.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-lib/settings/server/updateServices.coffee b/packages/rocketchat-lib/settings/server/updateServices.coffee index a8f8f2e0d88..da290e2d081 100644 --- a/packages/rocketchat-lib/settings/server/updateServices.coffee +++ b/packages/rocketchat-lib/settings/server/updateServices.coffee @@ -9,7 +9,6 @@ updateServices = -> serviceName = service._id.replace('Accounts_OAuth_', '') - if serviceName is 'Meteor' serviceName = 'meteor-developer' -- GitLab From c531e9ae176b7b57880a779c7dca456744ba32b6 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 22:23:21 +0100 Subject: [PATCH 0309/1338] rollback avatar changes --- server/startup/avatar.coffee | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 3dcda869241..a2949af98fd 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -1,11 +1,8 @@ Meteor.startup -> - storeType = 'FileSystem' - - - # Sandstorm must store avatar in mongo - #if RocketChat.settings.get 'avatarStore_type' - # storeType = RocketChat.settings.get 'avatarStore_type' + storeType = 'GridFS' + if RocketChat.settings.get 'Accounts_AvatarStoreType' + storeType = RocketChat.settings.get 'Accounts_AvatarStoreType' RocketChatStore = RocketChatFile[storeType] @@ -21,7 +18,7 @@ Meteor.startup -> transformWrite = (file, readStream, writeStream) -> RocketChatFile.gm(readStream, file.fileName).background('#ffffff').resize(width, height+'^>').gravity('Center').extent(width, height).stream('jpeg').pipe(writeStream) - path = "/var" + path = "~/uploads" if RocketChat.settings.get('Accounts_AvatarStorePath')?.trim() isnt '' path = RocketChat.settings.get 'Accounts_AvatarStorePath' @@ -32,7 +29,6 @@ Meteor.startup -> transformWrite: transformWrite WebApp.connectHandlers.use '/avatar/', (req, res, next) -> - console.log 'avatar called!' this.params = username: req.url.replace(/^\//, '').replace(/\?.*$/, '') -- GitLab From ef9d28bdbe6324d2a650bb519fbfc3bf0e8fb921 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 22:26:06 +0100 Subject: [PATCH 0310/1338] added sandstorm --- server/configuration/accounts_meld.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/configuration/accounts_meld.coffee b/server/configuration/accounts_meld.coffee index e03c09e36b3..4cd8d92f9d2 100644 --- a/server/configuration/accounts_meld.coffee +++ b/server/configuration/accounts_meld.coffee @@ -1,6 +1,6 @@ orig_updateOrCreateUserFromExternalService = Accounts.updateOrCreateUserFromExternalService Accounts.updateOrCreateUserFromExternalService = (serviceName, serviceData, options) -> - if serviceName not in ['facebook', 'github', 'google', 'meteor-developer', 'linkedin', 'twitter'] and serviceData._oAuthCustom isnt true + if serviceName not in ['facebook', 'github', 'gitlab', 'google', 'meteor-developer', 'linkedin', 'twitter', 'sandstorm'] and serviceData._oAuthCustom isnt true return if serviceName is 'meteor-developer' -- GitLab From f6a58ab903c3fc878bc5d8c63602966eab72cc3c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 22:39:37 +0100 Subject: [PATCH 0311/1338] added sandstorm --- client/views/account/avatar/prompt.html | 2 ++ client/views/app/sideNav/userStatus.html | 3 --- client/views/username/sandstormshare.html | 7 ------- 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 client/views/username/sandstormshare.html diff --git a/client/views/account/avatar/prompt.html b/client/views/account/avatar/prompt.html index f43f9c8fd1f..b38fdae3468 100644 --- a/client/views/account/avatar/prompt.html +++ b/client/views/account/avatar/prompt.html @@ -58,6 +58,7 @@ {{/unless}} </div> </div> + {{#if suggestions.ready}} {{> avatarSuggestion suggestions.avatars.gravatar}} {{> avatarSuggestion suggestions.avatars.facebook}} @@ -86,6 +87,7 @@ {{> avatarSuggestionLogin 'twitter'}} {{/if}} + {{else}} {{_ "Loading_suggestion"}} {{/if}} diff --git a/client/views/app/sideNav/userStatus.html b/client/views/app/sideNav/userStatus.html index 1e5261484da..5bac582d2c1 100644 --- a/client/views/app/sideNav/userStatus.html +++ b/client/views/app/sideNav/userStatus.html @@ -18,13 +18,10 @@ <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> - <!-- disable admin and logout for sandstorm {{#if showAdminOption }} <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> {{/if}} - <a href="" id="logout"><i class="icon-logout"></i><span>{{_ "Logout"}}</span></a> - --> </div> </nav> {{/with}} diff --git a/client/views/username/sandstormshare.html b/client/views/username/sandstormshare.html deleted file mode 100644 index 090a89d8a45..00000000000 --- a/client/views/username/sandstormshare.html +++ /dev/null @@ -1,7 +0,0 @@ -<template name="sandstormshare"> - <section class="full-page"> - <div class="wrapper"> - - </div> - </section> -</template> -- GitLab From 35416302e549f90acd4476fbfef0919b0e76b2cd Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 28 Oct 2015 22:43:35 +0100 Subject: [PATCH 0312/1338] added sandstorm --- client/views/main.html | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/client/views/main.html b/client/views/main.html index 41f7573c800..9eab99a5bec 100644 --- a/client/views/main.html +++ b/client/views/main.html @@ -41,18 +41,11 @@ <template name="main"> {{#if subsReady}} -<!-- {{#unless logged}} {{> loginLayout}} {{else}} ---> {{#unless hasUsername}} - {{#if logged}} - {{> username}} - {{else}} - <!-- shared link cannot be disabled in sandstorm, so we show a blank page --> - {{> sandstormshare}} - {{/if}} + {{> username}} {{else}} {{> spotlight}} {{> mobileMessageMenu}} @@ -71,10 +64,7 @@ {{> sideNav }} </div> {{> audioNotification }} - {{/unless}} -<!-- {{/unless}} ---> {{/if}} </template> -- GitLab From f3976ad7aff23081413035c2a2e05f0ab5b571c7 Mon Sep 17 00:00:00 2001 From: Mark Hurwitz <mhurwitzus@gmail.com> Date: Wed, 28 Oct 2015 17:29:43 -0500 Subject: [PATCH 0313/1338] webrtc: fix deprecation warning 'MediaStream.stop() is deprecated' --- packages/rocketchat-webrtc/WebRTCClass.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-webrtc/WebRTCClass.coffee b/packages/rocketchat-webrtc/WebRTCClass.coffee index f2b22be0240..ffa9785b84b 100644 --- a/packages/rocketchat-webrtc/WebRTCClass.coffee +++ b/packages/rocketchat-webrtc/WebRTCClass.coffee @@ -447,7 +447,9 @@ class WebRTCClass @active = false @monitor = false @remoteMonitoring = false - @localStream?.stop() + if @localStream? and typeof @localStream isnt 'undefined' + @localStream.getTracks().forEach (track) -> + track.stop() @localUrl.set undefined delete @localStream -- GitLab From a8cc313156d5752af6600defef087ee3c202c96c Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 28 Oct 2015 21:11:01 -0400 Subject: [PATCH 0314/1338] Improve FirefoxOS announcement Also add beta announcement for host/provisioning. --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 952137a5bac..656a3c4d28e 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,15 @@ Get the app for your Android phone: Now compatible with all Android devices as old as version 4.0.x - [download here](https://github.com/RocketChat/Rocket.Chat/wiki/Build-the-Android-Cordova-Web-App-and-connect-to-your-own-Rocket.Chat-Server), even on BlackBerry Passport! -Firefox OS support has landed as well (no Cordova required!): -https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29 - Host your own Rocket.Chat server in four seconds flat: [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) +Also available as FirefoxOS app: + +[](https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29) + + Try it on Ubuntu: @@ -100,6 +102,7 @@ It is a great solution for communities and companies wanting to privately host t - REST APIs - Remote Locations Video Monitoring - Chat-ops powered by Hubot: scalable horizontal app integration (early access) +- Massively scalable hosting and provisioning (beta testing now) - Native Cross-Platform Desktop Application [Windows, Mac OSX, or Linux](https://rocket.chat/) - Mobile app for iPhone, iPad, and iPod touch [Download on AppStore!](https://geo.itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) - Mobile app for Android phone, tablet, and TV stick [Available now on Google Play!](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) @@ -127,7 +130,6 @@ It is a great solution for communities and companies wanting to privately host t - Anonymous use of Rocket.Chat: [Issue #604](https://github.com/RocketChat/Rocket.Chat/issues/604) - File Sharing via P2P and Scalable Multicast: [Issue #369](https://github.com/RocketChat/Rocket.Chat/issues/369), [Issue #370](https://github.com/RocketChat/Rocket.Chat/issues/370) - Anti-virus checking on file uploads: [Issue #757](https://github.com/RocketChat/Rocket.Chat/issues/757) -- Massively scalable hosting and provisioning ### Issues -- GitLab From 01797cd89c74ec504601eff0fc3e515b9da58f0d Mon Sep 17 00:00:00 2001 From: Making GitHub Delicious <iron@waffle.io> Date: Thu, 29 Oct 2015 05:40:42 -0600 Subject: [PATCH 0315/1338] add waffle.io badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 656a3c4d28e..e096dcf2258 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[](https://waffle.io/RocketChat/Rocket.Chat)  The Ultimate Open Source WebChat Platform -- GitLab From b0ee3e58ccd2186250266f1438fb935882ad3e60 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 29 Oct 2015 12:44:17 +0100 Subject: [PATCH 0316/1338] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e096dcf2258..2b559138dc3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -[](https://waffle.io/RocketChat/Rocket.Chat)  The Ultimate Open Source WebChat Platform @@ -47,6 +46,7 @@ Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron] [](https://coveralls.io/r/RocketChat/Rocket.Chat) [](https://codeclimate.com/github/RocketChat/Rocket.Chat) [](https://github.com/RocketChat/Rocket.Chat/raw/master/LICENSE) +[](https://waffle.io/RocketChat/Rocket.Chat) Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](https://www.meteor.com/install) fullstack framework. -- GitLab From 32050432f6be6cfb1be5bb7074a8e92527e29a6f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 29 Oct 2015 12:45:11 +0100 Subject: [PATCH 0317/1338] added a division to list rooms with unread messages --- client/views/account/accountPreferences.coffee | 1 + client/views/account/accountPreferences.html | 7 +++++++ client/views/app/sideNav/channels.coffee | 4 ++++ client/views/app/sideNav/directMessages.coffee | 8 +++++++- client/views/app/sideNav/privateGroups.coffee | 8 +++++++- client/views/app/sideNav/sideNav.coffee | 2 +- client/views/app/sideNav/sideNav.html | 4 +++- client/views/app/sideNav/starredRooms.coffee | 8 +++++++- client/views/app/sideNav/unreadRooms.coffee | 14 ++++++++++++++ client/views/app/sideNav/unreadRooms.html | 13 +++++++++++++ .../rocketchat-theme/assets/stylesheets/base.less | 11 +++++++++++ server/methods/saveUserPreferences.coffee | 3 +++ 12 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 client/views/app/sideNav/unreadRooms.coffee create mode 100644 client/views/app/sideNav/unreadRooms.html diff --git a/client/views/account/accountPreferences.coffee b/client/views/account/accountPreferences.coffee index e948afe3858..d8171ec2f97 100644 --- a/client/views/account/accountPreferences.coffee +++ b/client/views/account/accountPreferences.coffee @@ -40,6 +40,7 @@ Template.accountPreferences.onCreated -> data.convertAsciiEmoji = $('input[name=convertAsciiEmoji]:checked').val() data.saveMobileBandwidth = $('input[name=saveMobileBandwidth]:checked').val() data.compactView = $('input[name=compactView]:checked').val() + data.unreadRoomsMode = $('input[name=unreadRoomsMode]:checked').val() data.autoImageLoad = $('input[name=autoImageLoad]:checked').val() Meteor.call 'saveUserPreferences', data, (error, results) -> diff --git a/client/views/account/accountPreferences.html b/client/views/account/accountPreferences.html index 2eabe151307..331a1764cd2 100644 --- a/client/views/account/accountPreferences.html +++ b/client/views/account/accountPreferences.html @@ -61,6 +61,13 @@ <label><input type="radio" name="compactView" value="0" checked="{{checked 'compactView' false true}}" /> {{_ "False"}}</label> </div> </div> + <div class="input-line double-col" id="unreadRoomsMode"> + <label>{{_ "Unread_Rooms_Mode"}}</label> + <div> + <label><input type="radio" name="unreadRoomsMode" value="1" checked="{{checked 'unreadRoomsMode' true}}" /> {{_ "True"}}</label> + <label><input type="radio" name="unreadRoomsMode" value="0" checked="{{checked 'unreadRoomsMode' false true}}" /> {{_ "False"}}</label> + </div> + </div> </div> </div> <div class="section"> diff --git a/client/views/app/sideNav/channels.coffee b/client/views/app/sideNav/channels.coffee index 3e4dd131a7a..28da6235546 100644 --- a/client/views/app/sideNav/channels.coffee +++ b/client/views/app/sideNav/channels.coffee @@ -13,6 +13,10 @@ Template.channels.helpers if !RocketChat.settings.get 'Disable_Favorite_Rooms' query.f = { $ne: true } + if Meteor.user()?.settings?.preferences?.unreadRoomsMode + query.alert = + $ne: true + return ChatSubscription.find query, { sort: 't': 1, 'name': 1 } Template.channels.events diff --git a/client/views/app/sideNav/directMessages.coffee b/client/views/app/sideNav/directMessages.coffee index 8260e0e91df..2451177750e 100644 --- a/client/views/app/sideNav/directMessages.coffee +++ b/client/views/app/sideNav/directMessages.coffee @@ -1,6 +1,12 @@ Template.directMessages.helpers rooms: -> - return ChatSubscription.find { t: { $in: ['d']}, f: { $ne: true }, open: true }, { sort: 't': 1, 'name': 1 } + query = { t: { $in: ['d']}, f: { $ne: true }, open: true } + + if Meteor.user()?.settings?.preferences?.unreadRoomsMode + query.alert = + $ne: true + + return ChatSubscription.find query, { sort: 't': 1, 'name': 1 } isActive: -> return 'active' if ChatSubscription.findOne({ t: { $in: ['d']}, f: { $ne: true }, open: true, rid: Session.get('openedRoom') }, { fields: { _id: 1 } })? diff --git a/client/views/app/sideNav/privateGroups.coffee b/client/views/app/sideNav/privateGroups.coffee index 1b577816fe4..6b30d7b4849 100644 --- a/client/views/app/sideNav/privateGroups.coffee +++ b/client/views/app/sideNav/privateGroups.coffee @@ -3,7 +3,13 @@ Template.privateGroups.helpers return t('Members_placeholder') rooms: -> - return ChatSubscription.find { t: { $in: ['p']}, f: { $ne: true }, open: true }, { sort: 't': 1, 'name': 1 } + query = { t: { $in: ['p']}, f: { $ne: true }, open: true } + + if Meteor.user()?.settings?.preferences?.unreadRoomsMode + query.alert = + $ne: true + + return ChatSubscription.find query, { sort: 't': 1, 'name': 1 } total: -> return ChatSubscription.find({ t: { $in: ['p']}, f: { $ne: true } }).count() diff --git a/client/views/app/sideNav/sideNav.coffee b/client/views/app/sideNav/sideNav.coffee index 49a02a7f80a..66d6bbada55 100644 --- a/client/views/app/sideNav/sideNav.coffee +++ b/client/views/app/sideNav/sideNav.coffee @@ -93,7 +93,7 @@ Template.sideNav.onRendered -> AccountBox.init() wrapper = $('.rooms-list .wrapper').get(0) - lastLink = $('.rooms-list h3').get(0) + lastLink = $('.rooms-list h3.history-div').get(0) RocketChat.roomTypes.getTypes().forEach (roomType) -> if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? diff --git a/client/views/app/sideNav/sideNav.html b/client/views/app/sideNav/sideNav.html index f44faababb6..605c277d14e 100644 --- a/client/views/app/sideNav/sideNav.html +++ b/client/views/app/sideNav/sideNav.html @@ -38,7 +38,9 @@ </div> <div class="rooms-list"> <div class="wrapper"> - <h3> + {{ > unreadRooms }} + + <h3 class="history-div"> <a href="{{pathFor 'privateHistory'}}">{{_ "History"}}</a> </h3> </div> diff --git a/client/views/app/sideNav/starredRooms.coffee b/client/views/app/sideNav/starredRooms.coffee index 859ed21b6f2..38a3aa889d3 100644 --- a/client/views/app/sideNav/starredRooms.coffee +++ b/client/views/app/sideNav/starredRooms.coffee @@ -1,6 +1,12 @@ Template.starredRooms.helpers rooms: -> - return ChatSubscription.find { f: true, open: true }, { sort: 't': 1, 'name': 1 } + query = { f: true, open: true } + + if Meteor.user()?.settings?.preferences?.unreadRoomsMode + query.alert = + $ne: true + + return ChatSubscription.find query, { sort: 't': 1, 'name': 1 } total: -> return ChatSubscription.find({ f: true }).count() isActive: -> diff --git a/client/views/app/sideNav/unreadRooms.coffee b/client/views/app/sideNav/unreadRooms.coffee new file mode 100644 index 00000000000..afe1ac54e24 --- /dev/null +++ b/client/views/app/sideNav/unreadRooms.coffee @@ -0,0 +1,14 @@ +Template.unreadRooms.helpers + hasUnread: -> + return 'has-unread' if Meteor.user()?.settings?.preferences?.unreadRoomsMode and Template.instance().unreadRooms.count() > 0 + + rooms: -> + return Template.instance().unreadRooms + +Template.unreadRooms.onCreated -> + @autorun => + query = + alert: true + open: true + + @unreadRooms = ChatSubscription.find query, { sort: 't': 1, 'name': 1 } diff --git a/client/views/app/sideNav/unreadRooms.html b/client/views/app/sideNav/unreadRooms.html new file mode 100644 index 00000000000..79f532749b7 --- /dev/null +++ b/client/views/app/sideNav/unreadRooms.html @@ -0,0 +1,13 @@ +<template name="unreadRooms"> + <div class="unread-rooms-mode {{hasUnread}}"> + <h3> + {{_ "Unread_Rooms"}} + </h3> + + <ul> + {{#each rooms}} + {{> chatRoomItem }} + {{/each}} + </ul> + </div> +</template> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 5ba2377c46f..d858917f161 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1503,6 +1503,17 @@ a.github-fork { font-size: 12px; } } + .unread-rooms-mode { + max-height: 0; + opacity: 0; + overflow: hidden; + + &.has-unread { + .transition(max-height 1s ease-in,opacity .5s linear); + max-height: 5000px; + opacity: 1; + } + } } .new-room-highlight a { diff --git a/server/methods/saveUserPreferences.coffee b/server/methods/saveUserPreferences.coffee index 8d9c86442ef..5cf457a2315 100644 --- a/server/methods/saveUserPreferences.coffee +++ b/server/methods/saveUserPreferences.coffee @@ -23,6 +23,9 @@ Meteor.methods if settings.compactView? preferences.compactView = if settings.compactView is "1" then true else false + if settings.unreadRoomsMode? + preferences.unreadRoomsMode = if settings.unreadRoomsMode is "1" then true else false + if settings.autoImageLoad? preferences.autoImageLoad = if settings.autoImageLoad is "1" then true else false -- GitLab From e8ca004e6042508d3c620ea19cbefa93750869ca Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 29 Oct 2015 09:56:25 -0500 Subject: [PATCH 0318/1338] Check the content type of the downloaded file and also report errors back up to the client --- client/views/account/avatar/prompt.coffee | 8 +++- i18n/en.i18n.json | 1 + server/methods/setAvatarFromService.coffee | 49 ++++++++++++---------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index 21fb3435d54..a1c787a0dac 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -46,8 +46,12 @@ Template.avatarPrompt.events else if @service is 'url' if _.trim $('#avatarurl').val() Meteor.call 'setAvatarFromService', $('#avatarurl').val(), '', @service, (err) -> - if err?.details?.timeToReset? - toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) + console.log err + if err + if err.details?.timeToReset? + toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) + else + toastr.error t('Avatar_url_invalid_or_error') else toastr.success t('Avatar_changed_successfully') else diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 65ee3d351e9..6c6a6fa4b2e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -62,6 +62,7 @@ "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", "Avatar_changed_successfully" : "Avatar changed successfully", + "Avatar_url_invalid_or_error": "The url provided is invalid or not accessible. Please try again, but with a different url.", "away" : "away", "Away" : "Away", "away_female" : "away", diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index cdcd27f5b3d..a30230edf7f 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -12,25 +12,32 @@ Meteor.methods return if service is 'url' + result = null + try result = HTTP.get dataURI, npmRequestOptions: {encoding: 'binary'} - - if result.statusCode isnt 200 - console.log "Not a valid response, #{result.statusCode}, from the avatar url: #{dataURI}" - throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> error on getting the avatar from url') - - ars = RocketChatFile.bufferToStream new Buffer(result.content, 'binary') - aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", result.headers['content-type'] - aws.on 'end', Meteor.bindEnvironment -> - Meteor.setTimeout -> - console.log "Set #{user.username}'s avatar from the url: #{dataURI}" - RocketChat.models.Users.setAvatarOrigin user._id, service - RocketChat.Notifications.notifyAll 'updateAvatar', { username: user.username } - , 500 - - ars.pipe(aws) catch e - throw e + console.log "Error while handling the setting of the avatar from a url (#{dataURI}) for #{user.username}:", e + throw new Meteor.Error('avatar-url-http-error', '[methods] setAvatarFromService -> http.get result -> error') + + if result.statusCode isnt 200 + console.log "Not a valid response, #{result.statusCode}, from the avatar url: #{dataURI}" + throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> error on getting the avatar from url') + + if not /image\/.+/.test result.headers['content-type'] + console.log "Not a valid content-type from the provided url, #{result.headers['content-type']}, from the avatar url: #{dataURI}" + throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> invalid content-type') + + ars = RocketChatFile.bufferToStream new Buffer(result.content, 'binary') + aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", result.headers['content-type'] + aws.on 'end', Meteor.bindEnvironment -> + Meteor.setTimeout -> + console.log "Set #{user.username}'s avatar from the url: #{dataURI}" + RocketChat.models.Users.setAvatarOrigin user._id, service + RocketChat.Notifications.notifyAll 'updateAvatar', { username: user.username } + , 500 + + ars.pipe(aws) return {image, contentType} = RocketChatFile.dataURIParse dataURI @@ -46,8 +53,8 @@ Meteor.methods rs.pipe(ws) return -DDPRateLimiter.addRule - type: 'method' - name: 'setAvatarFromService' - userId: -> return true -, 1, 60000 +# DDPRateLimiter.addRule +# type: 'method' +# name: 'setAvatarFromService' +# userId: -> return true +# , 1, 60000 -- GitLab From df9066f404b2b24893dc9f52bbc67acb92292cc7 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 29 Oct 2015 09:59:36 -0500 Subject: [PATCH 0319/1338] Remove the logging into the console of the error on incorrect urls for avatars --- client/views/account/avatar/prompt.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index a1c787a0dac..2d52531560d 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -46,7 +46,6 @@ Template.avatarPrompt.events else if @service is 'url' if _.trim $('#avatarurl').val() Meteor.call 'setAvatarFromService', $('#avatarurl').val(), '', @service, (err) -> - console.log err if err if err.details?.timeToReset? toastr.error t('Error_too_many_requests', parseInt(err.details.timeToReset / 1000)) -- GitLab From d26be144f067407791dde8e686506f92ca5da340 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 29 Oct 2015 10:00:52 -0500 Subject: [PATCH 0320/1338] Re-enable the rate limiter for the updating avatar, disabled it for debugging purposes --- server/methods/setAvatarFromService.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index a30230edf7f..c65162af35f 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -53,8 +53,8 @@ Meteor.methods rs.pipe(ws) return -# DDPRateLimiter.addRule -# type: 'method' -# name: 'setAvatarFromService' -# userId: -> return true -# , 1, 60000 +DDPRateLimiter.addRule + type: 'method' + name: 'setAvatarFromService' + userId: -> return true +, 1, 60000 -- GitLab From ccc435fb056547a72d3b84635447ed1b63ad9e06 Mon Sep 17 00:00:00 2001 From: James Allman-Talbot <jallmantalbot@gmail.com> Date: Thu, 29 Oct 2015 11:50:53 -0400 Subject: [PATCH 0321/1338] fixed user leave message --- server/methods/leaveRoom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/methods/leaveRoom.coffee b/server/methods/leaveRoom.coffee index 6e15ab31176..e3f103ba6b6 100644 --- a/server/methods/leaveRoom.coffee +++ b/server/methods/leaveRoom.coffee @@ -16,7 +16,7 @@ Meteor.methods if room.t isnt 'c' and room.usernames.indexOf(user.username) isnt -1 removedUser = user - RocketChat.models.Messages.createUserJoinWithRoomIdAndUser rid, removedUser + RocketChat.models.Messages.createUserLeaveWithRoomIdAndUser rid, removedUser if room.u?._id is Meteor.userId() newOwner = _.without(room.usernames, user.username)[0] -- GitLab From c10bc50182d8f65c5aa8c6e47e0dc2d60ab4976e Mon Sep 17 00:00:00 2001 From: James Allman-Talbot <jallmantalbot@gmail.com> Date: Thu, 29 Oct 2015 12:05:38 -0400 Subject: [PATCH 0322/1338] changed user left message to bring it inline with the join message --- i18n/en.i18n.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 65ee3d351e9..e3d3ca2a09a 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -410,9 +410,9 @@ "User_joined_channel" : "Has joined the channel.", "User_joined_channel_female" : "Has joined the channel.", "User_joined_channel_male" : "Has joined the channel.", - "User_left" : "User <em>__user_left__</em> left.", - "User_left_female" : "User <em>__user_left__</em> left.", - "User_left_male" : "User <em>__user_left__</em> left.", + "User_left" : "Has left the channel.", + "User_left_female" : "Has left the channel.", + "User_left_male" : "Has left the channel.", "User_logged_out" : "User is logged out", "User_not_found_or_incorrect_password" : "User not found or incorrect password", "User_removed_by" : "User <em>__user_removed__</em> removed by <em>__user_by__</em>.", -- GitLab From ac60580fc323eb5badaff3f3b0c8add4e490dd04 Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 02:09:41 +0100 Subject: [PATCH 0323/1338] Implemented AllowUserAvatarChange and Accounts_AllowUserProfileChange account settings --- client/views/account/accountFlex.coffee | 6 ++++++ client/views/account/accountFlex.html | 9 +++++++-- client/views/account/accountProfile.coffee | 2 ++ client/views/account/avatar/prompt.coffee | 2 ++ packages/rocketchat-lib/settings/server/startup.coffee | 2 ++ server/methods/resetAvatar.coffee | 3 +++ server/methods/saveUserProfile.coffee | 3 +++ server/methods/setAvatarFromService.coffee | 5 ++++- 8 files changed, 29 insertions(+), 3 deletions(-) diff --git a/client/views/account/accountFlex.coffee b/client/views/account/accountFlex.coffee index 99875905bb4..1e04bc7ce91 100644 --- a/client/views/account/accountFlex.coffee +++ b/client/views/account/accountFlex.coffee @@ -13,3 +13,9 @@ Template.accountFlex.events 'click .account-link': -> menu.close() + +Template.accountFlex.helpers + allowUserProfileChange: -> + return RocketChat.settings.get("Accounts_AllowUserProfileChange") + allowUserAvatarChange: -> + return RocketChat.settings.get("Accounts_AllowUserAvatarChange") \ No newline at end of file diff --git a/client/views/account/accountFlex.html b/client/views/account/accountFlex.html index 86777dafe91..8a41d5b26e2 100644 --- a/client/views/account/accountFlex.html +++ b/client/views/account/accountFlex.html @@ -9,10 +9,15 @@ <ul> <li> <a href="{{pathFor 'account' group='preferences'}}" class="account-link">{{_ "Preferences"}}</a> - <a href="{{pathFor 'account' group='profile'}}" class="account-link">{{_ "Profile"}}</a> + {{#if allowUserProfileChange}} + <a href="{{pathFor 'account' group='profile'}}" class="account-link">{{_ "Profile"}}</a> + {{/if}} {{!-- <a href="{{pathFor 'account' group='account'}}" class="account-link">{{_ "Account_Settings"}}</a> --}} {{!-- <a href="{{pathFor 'account' group='notification'}}" class="account-link">{{_ "Notification"}}</a> --}} - <a href="{{pathFor 'changeAvatar'}}" class="account-link">{{_ "Change_avatar"}}</a> {{!-- move this to profile --}} + {{#if allowUserProfileChange}} + <a href="{{pathFor 'changeAvatar'}}" class="account-link">{{_ "Change_avatar"}}</a> + {{/if}} + {{!-- move this to profile --}} </li> </ul> </div> diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 03425e6f7eb..2da61911ef9 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -98,6 +98,8 @@ Template.accountProfile.onCreated -> Template.accountProfile.onRendered -> Tracker.afterFlush -> + # this should throw an error-template + window.location.href = "/" if !RocketChat.settings.get("Accounts_AllowUserAvatarChange") SideNav.setFlex "accountFlex" SideNav.openFlex() diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index 2d52531560d..270c8cb34d9 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -14,6 +14,8 @@ Template.avatarPrompt.onCreated -> Template.avatarPrompt.onRendered -> Tracker.afterFlush -> + # this should throw an error-template + # window.location.href = "/" if !RocketChat.settings.get("Accounts_AllowUserProfileChange") SideNav.setFlex "accountFlex" SideNav.openFlex() diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 3a61e1e10a5..bb753133174 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -35,6 +35,8 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', grou 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', false, { type: 'boolean', group: 'Accounts', section: 'General', public: true } +RocketChat.settings.add 'Accounts_AllowUserAvatarChange', false, { 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 } diff --git a/server/methods/resetAvatar.coffee b/server/methods/resetAvatar.coffee index 2e30ef85391..0bb66f0d140 100644 --- a/server/methods/resetAvatar.coffee +++ b/server/methods/resetAvatar.coffee @@ -3,6 +3,9 @@ Meteor.methods unless Meteor.userId() throw new Meteor.Error(403, "[methods] resetAvatar -> Invalid user") + 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() diff --git a/server/methods/saveUserProfile.coffee b/server/methods/saveUserProfile.coffee index 2103016f1a1..46b39972fba 100644 --- a/server/methods/saveUserProfile.coffee +++ b/server/methods/saveUserProfile.coffee @@ -1,5 +1,8 @@ Meteor.methods saveUserProfile: (settings) -> + unless RocketChat.settings.get("Accounts_AllowUserProfileChange") + throw new Meteor.Error(403, "[methods] resetAvatar -> Invalid access") + if Meteor.userId() if settings.language? RocketChat.models.Users.setLanguage Meteor.userId(), settings.language diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index c65162af35f..c27f698a40c 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -1,8 +1,11 @@ Meteor.methods setAvatarFromService: (dataURI, contentType, service) -> - if not Meteor.userId() + unless Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] setAvatarFromService -> Invalid user") + 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() -- GitLab From a7f77a0cb7e23648e05fcf0443d718a82a2ac402 Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 02:28:26 +0100 Subject: [PATCH 0324/1338] Added server check to the Accounts_AllowUsernameChange setting --- packages/rocketchat-lib/server/methods/setUsername.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 1dfab8b8783..4ea4a1cce94 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -3,6 +3,9 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] setUsername -> Invalid user") + unless RocketChat.settings.get("Accounts_AllowUsernameChange") + throw new Meteor.Error(403, "[methods] resetAvatar -> Invalid access") + console.log '[methods] setUsername -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments user = Meteor.user() -- GitLab From f63fd8c13bc7b2ae9e5fbc5d8eb522adfb5bbb74 Mon Sep 17 00:00:00 2001 From: "Yakira C. Bristol" <hello@yakirac.me> Date: Fri, 30 Oct 2015 06:50:50 -0400 Subject: [PATCH 0325/1338] Remove registration name requirement Name is now optional when registering --- client/views/login/form.coffee | 2 -- client/views/login/form.html | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/client/views/login/form.coffee b/client/views/login/form.coffee index c1a78915ea1..89e4ddada50 100644 --- a/client/views/login/form.coffee +++ b/client/views/login/form.coffee @@ -129,8 +129,6 @@ Template.loginForm.onCreated -> validationObj['pass'] = t('Invalid_pass') if instance.state.get() is 'register' - unless formObj['name'] - validationObj['name'] = t('Invalid_name') if formObj['confirm-pass'] isnt formObj['pass'] validationObj['confirm-pass'] = t('Invalid_confirm_pass') diff --git a/client/views/login/form.html b/client/views/login/form.html index ee95ca7ca6d..e5f81cf61c7 100644 --- a/client/views/login/form.html +++ b/client/views/login/form.html @@ -15,7 +15,7 @@ {{/if}} <div class="fields"> <div class='input-text active {{showName}}'> - <input type="text" name='name' placeholder='{{_ "Name"}}' dir="auto" /> + <input type="text" name='name' placeholder='{{_ "Name(optional)"}}' dir="auto" /> </div> <div class='input-text active {{showEmailOrUsername}}'> <input type="text" name='emailOrUsername' placeholder='{{_ "Email_or_username"}}' autocapitalize="off" autocorrect="off" /> -- GitLab From 5a6a7f906c992afe4c4b6469ec1b4a867f3077da Mon Sep 17 00:00:00 2001 From: rcaferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 12:16:17 +0100 Subject: [PATCH 0326/1338] Update accountProfile.coffee --- client/views/account/accountProfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 2da61911ef9..6cc72cf2f74 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -99,7 +99,7 @@ Template.accountProfile.onCreated -> Template.accountProfile.onRendered -> Tracker.afterFlush -> # this should throw an error-template - window.location.href = "/" if !RocketChat.settings.get("Accounts_AllowUserAvatarChange") + FlowRouter.go("home") if !RocketChat.settings.get("Accounts_AllowUserAvatarChange") SideNav.setFlex "accountFlex" SideNav.openFlex() -- GitLab From b287494223301dcb8f3773c7f5e911779bb7e90d Mon Sep 17 00:00:00 2001 From: rcaferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 12:16:57 +0100 Subject: [PATCH 0327/1338] Update prompt.coffee --- client/views/account/avatar/prompt.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index 270c8cb34d9..48794b37d1e 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -15,7 +15,7 @@ Template.avatarPrompt.onCreated -> Template.avatarPrompt.onRendered -> Tracker.afterFlush -> # this should throw an error-template - # window.location.href = "/" if !RocketChat.settings.get("Accounts_AllowUserProfileChange") + FlowRouter.go ‘home’ if !RocketChat.settings.get("Accounts_AllowUserProfileChange") SideNav.setFlex "accountFlex" SideNav.openFlex() -- GitLab From bd11bd6748f68bf8d4f6285e4dbeacff97bc8ef6 Mon Sep 17 00:00:00 2001 From: rcaferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 12:17:32 +0100 Subject: [PATCH 0328/1338] Update prompt.coffee --- client/views/account/avatar/prompt.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index 48794b37d1e..27e8e53a237 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -15,7 +15,7 @@ Template.avatarPrompt.onCreated -> Template.avatarPrompt.onRendered -> Tracker.afterFlush -> # this should throw an error-template - FlowRouter.go ‘home’ if !RocketChat.settings.get("Accounts_AllowUserProfileChange") + FlowRouter.go("home") if !RocketChat.settings.get("Accounts_AllowUserProfileChange") SideNav.setFlex "accountFlex" SideNav.openFlex() -- GitLab From 861704f5636e0e11cbb8a832ee72feeebac6ac53 Mon Sep 17 00:00:00 2001 From: rcaferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 12:18:12 +0100 Subject: [PATCH 0329/1338] Update startup.coffee --- packages/rocketchat-lib/settings/server/startup.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index bb753133174..9c0cd80b4a7 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -35,8 +35,8 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter', false, { type: 'boolean', grou 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', false, { type: 'boolean', group: 'Accounts', section: 'General', public: true } -RocketChat.settings.add 'Accounts_AllowUserAvatarChange', false, { type: 'boolean', group: 'Accounts', section: 'General', public: true } +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 } -- GitLab From e9ba1dd2fb15ded816ca079c8e8e760bbec5bb21 Mon Sep 17 00:00:00 2001 From: rcaferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 12:18:59 +0100 Subject: [PATCH 0330/1338] Update accountProfile.coffee --- client/views/account/accountProfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/account/accountProfile.coffee b/client/views/account/accountProfile.coffee index 6cc72cf2f74..78c1828d504 100644 --- a/client/views/account/accountProfile.coffee +++ b/client/views/account/accountProfile.coffee @@ -99,7 +99,7 @@ Template.accountProfile.onCreated -> Template.accountProfile.onRendered -> Tracker.afterFlush -> # this should throw an error-template - FlowRouter.go("home") if !RocketChat.settings.get("Accounts_AllowUserAvatarChange") + FlowRouter.go("home") if !RocketChat.settings.get("Accounts_AllowUserProfileChange") SideNav.setFlex "accountFlex" SideNav.openFlex() -- GitLab From 83649f152a2a2f8a10c2104a07876e58389c225e Mon Sep 17 00:00:00 2001 From: rcaferati <rafael@caferati.me> Date: Fri, 30 Oct 2015 12:19:19 +0100 Subject: [PATCH 0331/1338] Update prompt.coffee --- client/views/account/avatar/prompt.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/account/avatar/prompt.coffee b/client/views/account/avatar/prompt.coffee index 27e8e53a237..e1982da5a20 100644 --- a/client/views/account/avatar/prompt.coffee +++ b/client/views/account/avatar/prompt.coffee @@ -15,7 +15,7 @@ Template.avatarPrompt.onCreated -> Template.avatarPrompt.onRendered -> Tracker.afterFlush -> # this should throw an error-template - FlowRouter.go("home") if !RocketChat.settings.get("Accounts_AllowUserProfileChange") + FlowRouter.go("home") if !RocketChat.settings.get("Accounts_AllowUserAvatarChange") SideNav.setFlex "accountFlex" SideNav.openFlex() -- GitLab From 28038b88b85c54e7f65c3d9868e0d494bb548fc8 Mon Sep 17 00:00:00 2001 From: "Yakira C. Bristol" <hello@yakirac.me> Date: Fri, 30 Oct 2015 16:28:38 -0400 Subject: [PATCH 0332/1338] Update PR With Admin Settings Option --- client/views/login/form.coffee | 5 +++++ client/views/login/form.html | 2 +- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 3 ++- packages/rocketchat-lib/settings/server/startup.coffee | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client/views/login/form.coffee b/client/views/login/form.coffee index 89e4ddada50..de98936d2de 100644 --- a/client/views/login/form.coffee +++ b/client/views/login/form.coffee @@ -2,6 +2,9 @@ Template.loginForm.helpers userName: -> return Meteor.user()?.username + namePlaceholder: -> + return if RocketChat.settings.get 'Accounts_RequireNameForSignUp' then 'Name' else 'Name(optional)' + showName: -> return 'hidden' unless Template.instance().state.get() is 'register' @@ -129,6 +132,8 @@ Template.loginForm.onCreated -> validationObj['pass'] = t('Invalid_pass') if instance.state.get() is 'register' + if RocketChat.settings.get 'Accounts_RequireNameForSignUp' and not formObj['name'] + validationObj['name'] = t('Invalid_name') if formObj['confirm-pass'] isnt formObj['pass'] validationObj['confirm-pass'] = t('Invalid_confirm_pass') diff --git a/client/views/login/form.html b/client/views/login/form.html index e5f81cf61c7..c1247d08a25 100644 --- a/client/views/login/form.html +++ b/client/views/login/form.html @@ -15,7 +15,7 @@ {{/if}} <div class="fields"> <div class='input-text active {{showName}}'> - <input type="text" name='name' placeholder='{{_ "Name(optional)"}}' dir="auto" /> + <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" /> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 7d09638e92e..338b99443c3 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -44,6 +44,7 @@ "Accounts_OAuth_Custom_Button_Label_Text" : "Button Text", "Accounts_OAuth_Custom_Button_Label_Color" : "Button Text Color", "Accounts_OAuth_Custom_Button_Color" : "Button Color", + "Accounts_RequireNameForSignUp" : "Require name for signup", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index b54800e035b..c04e5b7bc3c 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -35,6 +35,7 @@ "Accounts_OAuth_Custom_Button_Label_Text" : "Texto do botão", "Accounts_OAuth_Custom_Button_Label_Color" : "Cor do texto do botão", "Accounts_OAuth_Custom_Button_Color" : "Cor do botão", + "Accounts_RequireNameForSignUp" : "Nome é obrigatório para cadastro", "Activate" : "Ativar", "Add_custom_oauth" : "Adicionar oauth customizado", "Add_Members" : "Adicionar membros", @@ -406,4 +407,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} \ No newline at end of file +} diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 3a61e1e10a5..79209546fe8 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -37,6 +37,7 @@ RocketChat.settings.add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', g 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.addGroup 'FileUpload' RocketChat.settings.add 'FileUpload_Enabled', true, { type: 'boolean', group: 'FileUpload', public: true } -- GitLab From 5b16e73edefb8d063aa11fe3c7eaef0c96e5c19d Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Fri, 30 Oct 2015 21:25:16 +0000 Subject: [PATCH 0333/1338] Auto hide audio recorder when wav uploads are not white listed --- client/views/app/room.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index a3e30778731..a005cb3af08 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -188,7 +188,9 @@ Template.room.helpers return !! ChatRoom.findOne { _id: @_id, t: 'c' } canRecordAudio: -> - return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) + wavRegex = /audio\/wav|audio\/\*/i + wavEnabled = RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) + return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) and wavEnabled unreadSince: -> room = ChatRoom.findOne(this._id, { reactive: false }) -- GitLab From 783d47969b8459de5314974909ac3f27c7f161f0 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Fri, 30 Oct 2015 22:07:26 +0000 Subject: [PATCH 0334/1338] Add description to Audio recorder setting --- client/views/admin/admin.html | 5 +++-- i18n/en.i18n.json | 1 + packages/rocketchat-lib/settings/server/startup.coffee | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index 2cffc76a600..ea58eccdb14 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -65,10 +65,11 @@ <div> <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> - </div> {{#if description}} - <small>{{description}}</small> + <br /><small>{{description}}</small> {{/if}} + </div> + </div> {{/if}} {{#if $eq type 'color'}} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 7d09638e92e..d8c640f4397 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -216,6 +216,7 @@ "Message_AllowEditing_BlockEditInMinutes" : "Block Message Editing After (n) Minutes", "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking", "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", + "Message_AudioRecorderEnabledDescription" : "For this to work upload of Wav files must be enabled in the 'File Upload' section", "Message_deleting_not_allowed" : "Message deleting not allowed", "Message_editing_not_allowed" : "Message editing not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 9c0cd80b4a7..af44e376026 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -78,7 +78,7 @@ RocketChat.settings.add 'Message_ShowDeletedStatus', false, { type: 'boolean', g 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 } +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' } -- GitLab From e654aef983378f5fc23d132831cc8802f0da9072 Mon Sep 17 00:00:00 2001 From: "Yakira C. Bristol" <hello@yakirac.me> Date: Fri, 30 Oct 2015 19:56:50 -0400 Subject: [PATCH 0335/1338] Expand live support chat text entry field When entering text, the field will now accommodate long messages --- .../rocketchat-livechat/app/client/stylesheets/main.less | 5 +++-- packages/rocketchat-livechat/app/client/views/room.coffee | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index c43ea669f2b..1573e9cc323 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -290,7 +290,7 @@ input:focus { position: fixed; bottom: 0; width: 100%; - height: @footer-min-height; + height: auto; border-top: 1px solid #E7E7E7; border-left: 1px solid #E7E7E7; border-right: 1px solid #E7E7E7; @@ -301,11 +301,12 @@ input:focus { display: block; padding: 6px 8px; padding-right: 38px; - overflow-y: hidden; + 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; diff --git a/packages/rocketchat-livechat/app/client/views/room.coffee b/packages/rocketchat-livechat/app/client/views/room.coffee index 4a856e8cc01..c518f76a54a 100644 --- a/packages/rocketchat-livechat/app/client/views/room.coffee +++ b/packages/rocketchat-livechat/app/client/views/room.coffee @@ -13,6 +13,14 @@ Template.room.helpers Template.room.events 'keyup .input-message': (event) -> Template.instance().chatMessages.keyup(visitor.getRoom(), event, Template.instance()) + # Inital height is 28. If the scrollHeight is greater than that( we have more text than area ), + # increase the size of the textarea. The max-height is set at 200 + # even if the scrollHeight become bigger than that it should never exceed that. + # Account for no text in the textarea when increasing the height. + # If there is no text, reset the height. + inputScrollHeight = $(event.currentTarget).prop('scrollHeight') + if inputScrollHeight > 28 + $(event.currentTarget).height( if $(event.currentTarget).val() == '' then '15px' else (if inputScrollHeight >= 200 then inputScrollHeight-50 else inputScrollHeight-20)) 'keydown .input-message': (event) -> Template.instance().chatMessages.keydown(visitor.getRoom(), event, Template.instance()) -- GitLab From 2ebd4c832e0e1b9e0a2a6a1a10eccdff1fda60f8 Mon Sep 17 00:00:00 2001 From: "Yakira C. Bristol" <hello@yakirac.me> Date: Fri, 30 Oct 2015 20:00:24 -0400 Subject: [PATCH 0336/1338] Expand live support chat text entry field Removing extra space --- packages/rocketchat-livechat/app/client/views/room.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/app/client/views/room.coffee b/packages/rocketchat-livechat/app/client/views/room.coffee index c518f76a54a..3ac81b7c284 100644 --- a/packages/rocketchat-livechat/app/client/views/room.coffee +++ b/packages/rocketchat-livechat/app/client/views/room.coffee @@ -19,7 +19,7 @@ Template.room.events # Account for no text in the textarea when increasing the height. # If there is no text, reset the height. inputScrollHeight = $(event.currentTarget).prop('scrollHeight') - if inputScrollHeight > 28 + if inputScrollHeight > 28 $(event.currentTarget).height( if $(event.currentTarget).val() == '' then '15px' else (if inputScrollHeight >= 200 then inputScrollHeight-50 else inputScrollHeight-20)) 'keydown .input-message': (event) -> -- GitLab From 29af18a7a66f1f4850df2b58cf7429de9c8018d1 Mon Sep 17 00:00:00 2001 From: Ed <ed002002@gmail.com> Date: Sat, 31 Oct 2015 18:55:56 +0000 Subject: [PATCH 0337/1338] Hide recorder if uploads are disabled --- client/views/app/room.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index a005cb3af08..80dd1c74fb9 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -190,7 +190,7 @@ Template.room.helpers canRecordAudio: -> wavRegex = /audio\/wav|audio\/\*/i wavEnabled = RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) - return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) and wavEnabled + return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) and wavEnabled and RocketChat.settings.get('FileUpload_Enabled') unreadSince: -> room = ChatRoom.findOne(this._id, { reactive: false }) -- GitLab From ed7240a8f6b91424917001e2b88c34beed96e4fa Mon Sep 17 00:00:00 2001 From: "Yakira C. Bristol" <hello@yakirac.me> Date: Sun, 1 Nov 2015 18:04:20 -0500 Subject: [PATCH 0338/1338] Utilize i18n for displaying registration name field placeholder text --- client/views/login/form.coffee | 2 +- i18n/de.i18n.json | 1 + i18n/en.i18n.json | 1 + i18n/es.i18n.json | 3 ++- i18n/fr.i18n.json | 3 ++- i18n/it.i18n.json | 3 ++- i18n/pt.i18n.json | 1 + 7 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client/views/login/form.coffee b/client/views/login/form.coffee index de98936d2de..face5c303d9 100644 --- a/client/views/login/form.coffee +++ b/client/views/login/form.coffee @@ -3,7 +3,7 @@ Template.loginForm.helpers return Meteor.user()?.username namePlaceholder: -> - return if RocketChat.settings.get 'Accounts_RequireNameForSignUp' then 'Name' else 'Name(optional)' + return if RocketChat.settings.get 'Accounts_RequireNameForSignUp' then t('Name') else t('Name_optional') showName: -> return 'hidden' unless Template.instance().state.get() is 'register' diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 27f18d58870..5df7c46aa5d 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -220,6 +220,7 @@ "My_Account" : "Mein Konto", "n_messages" : "%s Nachrichten", "Name" : "Name", + "Name_optional" : "Name(freiwillig)", "Name_cant_be_empty" : "Name darf nicht leer sein", "New_messages" : "Neue Nachrichten", "New_password" : "Neues Passwort", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 338b99443c3..8a0c5a72482 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -245,6 +245,7 @@ "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", + "Name_optional" : "Name(optional)", "Name_cant_be_empty" : "Name can't be empty", "New_messages" : "New messages", "New_password" : "New password", diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json index 7ddc9011322..760d8811f49 100644 --- a/i18n/es.i18n.json +++ b/i18n/es.i18n.json @@ -68,6 +68,7 @@ "Msgs" : "Mensajes", "n_messages" : "%s mensajes", "Name" : "Nombre", + "Name_optional" : "Nombre(opcional)", "New_messages" : "Nuevos mensajes", "New_password" : "Nueva contraseña", "No_channels_yet" : "TodavÃa no eres parte de un canal.", @@ -136,4 +137,4 @@ "With_whom" : "Con quien", "You_need_confirm_email" : "¡Es necesario confirmar tu correo electrónico para poder identificarte!", "Your_Open_Source_solution" : "Tu propia solución de chat de código abierto" -} \ No newline at end of file +} diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 29399fc7c90..b9d183bb2e8 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -209,6 +209,7 @@ "My_Account" : "Mon compte", "n_messages" : "%s messages", "Name" : "Nom", + "Name_optional" : "Nom(optionnel)", "Name_cant_be_empty" : "Le nom ne peut pas être vide", "New_messages" : "Nouveaux messages", "New_password" : "Nouveau mot de passe", @@ -390,4 +391,4 @@ "You_will_not_be_able_to_recover" : "Cette action n'est pas réversible !", "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/it.i18n.json b/i18n/it.i18n.json index 81fedc920ec..b38087dd60d 100644 --- a/i18n/it.i18n.json +++ b/i18n/it.i18n.json @@ -62,6 +62,7 @@ "Msgs" : "Msgs", "n_messages" : "% messaggi", "Name" : "Nome", + "Name_optional" : "Nome(opzionale)", "New_messages" : "Nuovi messaggi", "New_password" : "Nuova password", "No_channels_yet" : "Non fai parte di nessun canale ancora.", @@ -126,4 +127,4 @@ "Welcome_to_the" : "Benvenuto a", "You_need_confirm_email" : "Hai bisogno di confermare il tuo email per accedere!", "Your_Open_Source_solution" : "La tua soluzione per chat Open Source" -} \ No newline at end of file +} diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index c04e5b7bc3c..f03f1c7c6d0 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -223,6 +223,7 @@ "My_Account" : "Minha Conta", "n_messages" : "%s mensagens", "Name" : "Nome", + "Name_optional" : "Nome(opcional)", "Name_cant_be_empty" : "Nome não pode ser vazio", "New_messages" : "Novas mensagens", "New_password" : "Nova senha", -- GitLab From 98dbc13c862156832d9482f9d9b4b28b309d4fae Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 3 Nov 2015 07:24:50 -0200 Subject: [PATCH 0339/1338] Create role when adding a user to a non-existing role --- .../server/functions/addUsersToRoles.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee b/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee index 3b04cfa6fd5..3af878e6814 100644 --- a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee @@ -16,11 +16,13 @@ RocketChat.authz.addUsersToRoles = (userIds, roleNames, scope ) -> existingRoleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name') invalidRoleNames = _.difference( roleNames, existingRoleNames) unless _.isEmpty(invalidRoleNames) - throw new Meteor.Error 'invalid-role' + # 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 \ No newline at end of file + return true -- GitLab From 76dca9f5cd1402d438c7057b1b030352bd7a000b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 3 Nov 2015 07:25:20 -0200 Subject: [PATCH 0340/1338] Enable robot calling methods on Rocket.Chat --- packages/rocketchat-lib/package.js | 1 + .../server/methods/robotMethods.coffee | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 packages/rocketchat-lib/server/methods/robotMethods.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index ea4c4ff85f5..207c43bb040 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -59,6 +59,7 @@ Package.onUse(function(api) { api.addFiles('server/functions/setUsername.coffee', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); + api.addFiles('server/methods/robotMethods.coffee', 'server'); api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/robotMethods.coffee b/packages/rocketchat-lib/server/methods/robotMethods.coffee new file mode 100644 index 00000000000..9ebebe73ea8 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/robotMethods.coffee @@ -0,0 +1,16 @@ +Meteor.methods + 'robot.modelCall': (model, method, args) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] robot.modelCall -> Invalid user' + + 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' + + call = RocketChat.models[model][method].apply(RocketChat.models[model], args) + console.log call + return call -- GitLab From fc51d7fa21c0c0c0ff965f29d4a946626361933d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 3 Nov 2015 09:26:25 -0200 Subject: [PATCH 0341/1338] Fix translation for Direct Messages and Private Groups in Admin/Rooms --- client/views/admin/rooms/adminRooms.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/views/admin/rooms/adminRooms.html b/client/views/admin/rooms/adminRooms.html index 08756aff842..cc39896ec68 100644 --- a/client/views/admin/rooms/adminRooms.html +++ b/client/views/admin/rooms/adminRooms.html @@ -17,8 +17,8 @@ {{#unless isReady}}<i class="icon-spin4"></i>{{/unless}} </div> <input type="checkbox" name="room-type" value="c"> {{_ "Channels"}} - <input type="checkbox" name="room-type" value="d"> {{_ "Direct Messages"}} - <input type="checkbox" name="room-type" value="p"> {{_ "Private Groups"}} + <input type="checkbox" name="room-type" value="d"> {{_ "Direct_Messages"}} + <input type="checkbox" name="room-type" value="p"> {{_ "Private_Groups"}} </form> <div class="results"> {{{_ "Showing_results" roomCount}}} -- GitLab From 51ac8d68737892659f7d682bb1138ff520fef3e0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 3 Nov 2015 09:53:15 -0200 Subject: [PATCH 0342/1338] translation for unread rooms division --- i18n/en.i18n.json | 2 ++ i18n/pt.i18n.json | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 7d09638e92e..499e7b2148f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -389,6 +389,8 @@ "The_field_is_required" : "The field %s is required.", "True" : "True", "Unnamed" : "Unnamed", + "Unread_Rooms": "Unread Rooms", + "Unread_Rooms_Mode": "Unread Rooms Mode", "Upload_file_question" : "Upload file?", "Use_Emojis" : "Use Emojis", "Use_initials_avatar" : "Use your username initials", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index b54800e035b..eace2ee8f4a 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -358,6 +358,8 @@ "The_field_is_required" : "O campo %s é obrigatório.", "True" : "Verdadeiro", "Unnamed" : "Sem nome", + "Unread_Rooms": "Não Lidas", + "Unread_Rooms_Mode": "Agrupar Salas Não Lidas", "Upload_file_question" : "Enviar arquivo?", "Use_Emojis" : "Usar Emojis", "Use_initials_avatar" : "Usar as iniciais do seu nome de usuário", @@ -406,4 +408,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} \ No newline at end of file +} -- GitLab From 93e293a5b2afda0209bddc692ed9cd3518a694df Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Sun, 25 Oct 2015 19:59:32 +0100 Subject: [PATCH 0343/1338] First draft to support Oembed protocol as defined http://oembed.com/ Currently only support soundcloud (futur providers will be add) --- .meteor/versions | 1 - .../client/baseWidget.coffee | 3 + .../client/oembedFrameWidget.html} | 8 ++- packages/rocketchat-oembed/package.js | 5 ++ .../rocketchat-oembed/server/providers.coffee | 55 +++++++++++++++++++ .../lib/client/widget.coffee | 3 - .../lib/server/server.coffee | 19 ------- packages/rocketchat-soundcloud/package.js | 28 ---------- 8 files changed, 69 insertions(+), 53 deletions(-) rename packages/{rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html => rocketchat-oembed/client/oembedFrameWidget.html} (67%) create mode 100644 packages/rocketchat-oembed/server/providers.coffee delete mode 100644 packages/rocketchat-soundcloud/lib/client/widget.coffee delete mode 100644 packages/rocketchat-soundcloud/lib/server/server.coffee delete mode 100644 packages/rocketchat-soundcloud/package.js diff --git a/.meteor/versions b/.meteor/versions index 15562e4f1fe..937836621ce 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -142,7 +142,6 @@ rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 rocketchat:slashcommands-leave@0.0.1 -rocketchat:soundcloud@0.0.1 rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 rocketchat:theme@0.0.1 diff --git a/packages/rocketchat-oembed/client/baseWidget.coffee b/packages/rocketchat-oembed/client/baseWidget.coffee index 8a84ed7a506..9caa79832b0 100644 --- a/packages/rocketchat-oembed/client/baseWidget.coffee +++ b/packages/rocketchat-oembed/client/baseWidget.coffee @@ -15,4 +15,7 @@ Template.oembedBaseWidget.helpers if this.parsedUrl?.host is 'www.youtube.com' and this.meta?.twitterPlayer? return 'oembedYoutubeWidget' + if this.meta?.oembedHtml? + return 'oembedFrameWidget' + return 'oembedUrlWidget' diff --git a/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html b/packages/rocketchat-oembed/client/oembedFrameWidget.html similarity index 67% rename from packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html rename to packages/rocketchat-oembed/client/oembedFrameWidget.html index f478120bed7..6965b8e6102 100644 --- a/packages/rocketchat-soundcloud/lib/client/oembedSoundcloudWidget.html +++ b/packages/rocketchat-oembed/client/oembedFrameWidget.html @@ -1,7 +1,11 @@ -<template name="oembedSoundcloudWidget"> +<template name="oembedFrameWidget"> {{#if parsedUrl}} <blockquote> - <a href="https://www.soundcloud.com" style="color: #9e9ea6">SoundCloud</a><br/> + {{#if meta.oembedProviderName}} + {{#if meta.oembedProviderUrl}} + <a href="{{meta.oembedProviderUrl}}" style="color: #9e9ea6">{{meta.oembedProviderName}}</a><br/> + {{/if}} + {{/if}} {{#if meta.oembedAuthorName}} {{#if meta.oembedAuthorUrl}} <a href="meta.oembedAuthorUrl">{{meta.oembedAuthorName}}</a><br/> diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index eab59017ae9..ace7d0496be 100644 --- a/packages/rocketchat-oembed/package.js +++ b/packages/rocketchat-oembed/package.js @@ -11,6 +11,8 @@ Package.onUse(function(api) { api.use([ 'templating', 'coffeescript', + 'underscore', + 'konecty:change-case', 'rocketchat:lib@0.0.1' ]); @@ -30,7 +32,10 @@ Package.onUse(function(api) { api.addFiles('client/oembedUrlWidget.html', 'client'); api.addFiles('client/oembedUrlWidget.coffee', 'client'); + api.addFiles('client/oembedFrameWidget.html', 'client'); + api.addFiles('server/server.coffee', 'server'); + api.addFiles('server/providers.coffee', 'server'); api.addFiles('server/models/OEmbedCache.coffee', 'server'); api.export('OEmbed', 'server'); diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee new file mode 100644 index 00000000000..b2b570e6f66 --- /dev/null +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -0,0 +1,55 @@ +URL = Npm.require('url') + +class Providers + providers: [] + + @getConsumerUrl: (provider, url) -> + urlObj = URL.parse provider.endPoint, true + urlObj.query['url'] = url + delete urlObj.search + return URL.format urlObj + + registerProvider: (provider) -> + this.providers.push(provider) + + getProviders: () -> + return this.providers + + getProviderForUrl: (url) -> + return _.find this.providers, (provider) -> + candidate = _.find provider.urls, (re) -> + return re.test url + return candidate? + +providers = new Providers() +providers.registerProvider + urls: [new RegExp('https?://soundcloud.com/\\S+')] + endPoint: 'https://soundcloud.com/oembed?format=json&maxheight=150' + +RocketChat.oembed = {} +RocketChat.oembed.providers = providers + +RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> + if data.parsedUrl? + url = URL.format data.parsedUrl + provider = providers.getProviderForUrl url + if provider? + consumerUrl = Providers.getConsumerUrl provider, url + consumerUrl = URL.parse consumerUrl, true + _.extend data.parsedUrl, consumerUrl + data.requestOptions.port = consumerUrl.port + data.requestOptions.hostname = consumerUrl.hostname + data.requestOptions.path = consumerUrl.path + +RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> + if data.parsedUrl? + url = URL.format data.parsedUrl + provider = providers.getProviderForUrl url + if provider? + if data.content?.body? + metas = JSON.parse data.content.body; + _.each metas, (value, key) -> + if _.isString value + data.meta[changeCase.camelCase('oembed_' + key)] = value + if data.parsedUrl?.query?.url? + data.meta['oembedUrl'] = data.parsedUrl.query.url diff --git a/packages/rocketchat-soundcloud/lib/client/widget.coffee b/packages/rocketchat-soundcloud/lib/client/widget.coffee deleted file mode 100644 index bf4c284024d..00000000000 --- a/packages/rocketchat-soundcloud/lib/client/widget.coffee +++ /dev/null @@ -1,3 +0,0 @@ -Template.oembedBaseWidget.onCreated () -> - if this.data?.parsedUrl?.host is 'soundcloud.com' and this.data?.meta?.oembedHtml? - this.data._overrideTemplate = 'oembedSoundcloudWidget' diff --git a/packages/rocketchat-soundcloud/lib/server/server.coffee b/packages/rocketchat-soundcloud/lib/server/server.coffee deleted file mode 100644 index b1bbe3be4eb..00000000000 --- a/packages/rocketchat-soundcloud/lib/server/server.coffee +++ /dev/null @@ -1,19 +0,0 @@ -URL = Npm.require('url') - -RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> - if data.parsedUrl.host is 'soundcloud.com' - newUrlObj = URL.format data.parsedUrl - newUrlObj = URL.parse "https://soundcloud.com/oembed?url=" + encodeURIComponent newUrlObj + "&format=json&maxheight=150" - data.requestOptions.port = newUrlObj.port - data.requestOptions.hostname = newUrlObj.hostname - data.requestOptions.path = newUrlObj.path - -RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> - if data.parsedUrl.host is 'soundcloud.com' - if data.content?.body? - metas = JSON.parse data.content.body; - _.each metas, (value, key) -> - if _.isString value - data.meta[changeCase.camelCase('oembed_' + key)] = value - if data.parsedUrl? - data.meta['oembedUrl'] = URL.format data.parsedUrl diff --git a/packages/rocketchat-soundcloud/package.js b/packages/rocketchat-soundcloud/package.js deleted file mode 100644 index 054b7802923..00000000000 --- a/packages/rocketchat-soundcloud/package.js +++ /dev/null @@ -1,28 +0,0 @@ -Package.describe({ - name: 'rocketchat:soundcloud', - version: '0.0.1', - summary: 'Soundcloud integration', - git: '' -}); - -Package.onUse(function(api) { - api.versionsFrom('1.0'); - - api.use([ - 'coffeescript', - 'templating', - 'underscore', - 'konecty:change-case', - 'rocketchat:lib', - 'rocketchat:oembed@0.0.1' - ]); - - api.addFiles('lib/client/widget.coffee', 'client'); - api.addFiles('lib/client/oembedSoundcloudWidget.html', 'client'); - - api.addFiles('lib/server/server.coffee', 'server'); -}); - -Package.onTest(function(api) { - -}); -- GitLab From 18c3af395b37617f8b071a7dd94ec4ae085afdc9 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Mon, 26 Oct 2015 14:34:06 +0100 Subject: [PATCH 0344/1338] Add Vimeo --- packages/rocketchat-oembed/server/providers.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index b2b570e6f66..84033ccce75 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -25,6 +25,9 @@ providers = new Providers() providers.registerProvider urls: [new RegExp('https?://soundcloud.com/\\S+')] endPoint: 'https://soundcloud.com/oembed?format=json&maxheight=150' +providers.registerProvider + urls: [new RegExp('https?://vimeo.com/[^/]+'), new RegExp('https?://vimeo.com/channels/[^/]+/[^/]+'), new RegExp('https://vimeo.com/groups/[^/]+/videos/[^/]+')] + endPoint: 'https://vimeo.com/api/oembed.json?maxheight=200' RocketChat.oembed = {} RocketChat.oembed.providers = providers -- GitLab From cde041b0a3e4ca40f0b5c61909410ea831dcb6b5 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Wed, 28 Oct 2015 17:27:55 +0100 Subject: [PATCH 0345/1338] Add YouTube --- packages/rocketchat-oembed/client/baseWidget.coffee | 3 --- packages/rocketchat-oembed/server/providers.coffee | 3 +++ packages/rocketchat-oembed/server/server.coffee | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-oembed/client/baseWidget.coffee b/packages/rocketchat-oembed/client/baseWidget.coffee index 9caa79832b0..ebe69afefc4 100644 --- a/packages/rocketchat-oembed/client/baseWidget.coffee +++ b/packages/rocketchat-oembed/client/baseWidget.coffee @@ -12,9 +12,6 @@ Template.oembedBaseWidget.helpers if this.headers?.contentType?.match(/video\/.*/)? or this.meta?.twitterPlayerStreamContentType?.match(/video\/.*/)? return 'oembedVideoWidget' - if this.parsedUrl?.host is 'www.youtube.com' and this.meta?.twitterPlayer? - return 'oembedYoutubeWidget' - if this.meta?.oembedHtml? return 'oembedFrameWidget' diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index 84033ccce75..f2b42048cda 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -28,6 +28,9 @@ providers.registerProvider providers.registerProvider urls: [new RegExp('https?://vimeo.com/[^/]+'), new RegExp('https?://vimeo.com/channels/[^/]+/[^/]+'), new RegExp('https://vimeo.com/groups/[^/]+/videos/[^/]+')] endPoint: 'https://vimeo.com/api/oembed.json?maxheight=200' +providers.registerProvider + urls: [new RegExp('https?://www.youtube.com/\\S+'), new RegExp('https?://www.youtu.be/\\S+')] + endPoint: 'https://www.youtube.com/oembed?maxheight=200' RocketChat.oembed = {} RocketChat.oembed.providers = providers diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 196d0f4affd..4a59fda45e2 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -24,7 +24,7 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> httpOrHttps = if urlObj.protocol is 'https:' then https else http - parsedUrl = _.pick urlObj, ['host', 'hash', 'pathname', 'protocol', 'port', 'query'] + parsedUrl = _.pick urlObj, ['host', 'hash', 'pathname', 'protocol', 'port', 'query', 'search'] RocketChat.callbacks.run 'oembed:beforeGetUrlContent', requestOptions: opts -- GitLab From 3716674883bc3c7b87b81e2806b4fccaee165807 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Wed, 28 Oct 2015 18:21:51 +0100 Subject: [PATCH 0346/1338] Add Rdio --- packages/rocketchat-oembed/server/providers.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index f2b42048cda..1b14f250405 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -31,6 +31,9 @@ providers.registerProvider providers.registerProvider urls: [new RegExp('https?://www.youtube.com/\\S+'), new RegExp('https?://www.youtu.be/\\S+')] endPoint: 'https://www.youtube.com/oembed?maxheight=200' +providers.registerProvider + urls: [new RegExp('https?://www.rdio.com/\\S+'), new RegExp('https?://rd.io/\\S+')] + endPoint: 'http://www.rdio.com/api/oembed/?format=json&maxheight=150' RocketChat.oembed = {} RocketChat.oembed.providers = providers -- GitLab From 7d2cc943cadd4da651179e955edde767f6a72b76 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Wed, 28 Oct 2015 18:26:29 +0100 Subject: [PATCH 0347/1338] Add SlideShare --- packages/rocketchat-oembed/server/providers.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index 1b14f250405..27830c4be32 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -34,6 +34,9 @@ providers.registerProvider providers.registerProvider urls: [new RegExp('https?://www.rdio.com/\\S+'), new RegExp('https?://rd.io/\\S+')] endPoint: 'http://www.rdio.com/api/oembed/?format=json&maxheight=150' +providers.registerProvider + urls: [new RegExp('https?://www.slideshare.net/[^/]+/[^/]+')] + endPoint: 'http://www.slideshare.net/api/oembed/2?format=json&maxheight=200' RocketChat.oembed = {} RocketChat.oembed.providers = providers -- GitLab From 5b7fd5d2f5418754b51eb86b43a9ba346bc6498d Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Wed, 28 Oct 2015 18:35:36 +0100 Subject: [PATCH 0348/1338] Use https instead of http --- packages/rocketchat-oembed/server/providers.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index 27830c4be32..41831c15111 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -33,10 +33,10 @@ providers.registerProvider endPoint: 'https://www.youtube.com/oembed?maxheight=200' providers.registerProvider urls: [new RegExp('https?://www.rdio.com/\\S+'), new RegExp('https?://rd.io/\\S+')] - endPoint: 'http://www.rdio.com/api/oembed/?format=json&maxheight=150' + endPoint: 'https://www.rdio.com/api/oembed/?format=json&maxheight=150' providers.registerProvider urls: [new RegExp('https?://www.slideshare.net/[^/]+/[^/]+')] - endPoint: 'http://www.slideshare.net/api/oembed/2?format=json&maxheight=200' + endPoint: 'https://www.slideshare.net/api/oembed/2?format=json&maxheight=200' RocketChat.oembed = {} RocketChat.oembed.providers = providers -- GitLab From fefeb35ce6b1f7b1abdbf8f9b8e4c28c08f38d1f Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Wed, 28 Oct 2015 18:48:38 +0100 Subject: [PATCH 0349/1338] Add DailyMotion and fix afterParseContent callback --- packages/rocketchat-oembed/server/providers.coffee | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index 41831c15111..f1140c9fe90 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -37,6 +37,9 @@ providers.registerProvider providers.registerProvider urls: [new RegExp('https?://www.slideshare.net/[^/]+/[^/]+')] endPoint: 'https://www.slideshare.net/api/oembed/2?format=json&maxheight=200' +providers.registerProvider + urls: [new RegExp('https?://www.dailymotion.com/video/\\S+')] + endPoint: 'https://www.dailymotion.com/services/oembed?maxheight=200' RocketChat.oembed = {} RocketChat.oembed.providers = providers @@ -54,8 +57,8 @@ RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> data.requestOptions.path = consumerUrl.path RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> - if data.parsedUrl? - url = URL.format data.parsedUrl + if data.parsedUrl?.query?.url? + url = data.parsedUrl.query.url provider = providers.getProviderForUrl url if provider? if data.content?.body? @@ -63,5 +66,4 @@ RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> _.each metas, (value, key) -> if _.isString value data.meta[changeCase.camelCase('oembed_' + key)] = value - if data.parsedUrl?.query?.url? - data.meta['oembedUrl'] = data.parsedUrl.query.url + data.meta['oembedUrl'] = url -- GitLab From b39af353dc4b3180c58544d2ec37ebde0afaba30 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Tue, 3 Nov 2015 15:49:00 +0100 Subject: [PATCH 0350/1338] handle correctly querystring when passing as string and not as object --- .../rocketchat-oembed/server/providers.coffee | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-oembed/server/providers.coffee b/packages/rocketchat-oembed/server/providers.coffee index f1140c9fe90..ddb4f66802a 100644 --- a/packages/rocketchat-oembed/server/providers.coffee +++ b/packages/rocketchat-oembed/server/providers.coffee @@ -1,4 +1,5 @@ URL = Npm.require('url') +QueryString = Npm.require('querystring') class Providers providers: [] @@ -57,13 +58,17 @@ RocketChat.callbacks.add 'oembed:beforeGetUrlContent', (data) -> data.requestOptions.path = consumerUrl.path RocketChat.callbacks.add 'oembed:afterParseContent', (data) -> - if data.parsedUrl?.query?.url? - url = data.parsedUrl.query.url - provider = providers.getProviderForUrl url - if provider? - if data.content?.body? - metas = JSON.parse data.content.body; - _.each metas, (value, key) -> - if _.isString value - data.meta[changeCase.camelCase('oembed_' + key)] = value - data.meta['oembedUrl'] = url + if data.parsedUrl?.query? + queryString = data.parsedUrl.query + if _.isString data.parsedUrl.query + queryString = QueryString.parse data.parsedUrl.query + if queryString.url? + url = queryString.url + provider = providers.getProviderForUrl url + if provider? + if data.content?.body? + metas = JSON.parse data.content.body; + _.each metas, (value, key) -> + if _.isString value + data.meta[changeCase.camelCase('oembed_' + key)] = value + data.meta['oembedUrl'] = url -- GitLab From 90044bfbadc0820a9eaf73a1a53e6b74f8252054 Mon Sep 17 00:00:00 2001 From: kakawait <thibaud.lepretre@gmail.com> Date: Tue, 3 Nov 2015 16:17:13 +0100 Subject: [PATCH 0351/1338] remove soundcloud package --- .meteor/packages | 1 - 1 file changed, 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index 395aeb47694..3d15d0183fe 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -56,7 +56,6 @@ rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join rocketchat:slashcommands-leave -rocketchat:soundcloud rocketchat:spotify rocketchat:statistics rocketchat:theme -- GitLab From 06939a3a9b402be3f821c5df883a844e6fb50e9f Mon Sep 17 00:00:00 2001 From: Christopher Perrin <perrin@uni-trier.de> Date: Tue, 3 Nov 2015 19:58:26 +0100 Subject: [PATCH 0352/1338] Fixed strange date generation for SAML instant time that causes problems with some IDPs --- packages/meteor-accounts-saml/saml_utils.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/meteor-accounts-saml/saml_utils.js b/packages/meteor-accounts-saml/saml_utils.js index 31d572c5949..c90734a6451 100644 --- a/packages/meteor-accounts-saml/saml_utils.js +++ b/packages/meteor-accounts-saml/saml_utils.js @@ -58,8 +58,7 @@ SAML.prototype.generateUniqueID = function () { }; SAML.prototype.generateInstant = function () { - var date = new Date(); - return date.getUTCFullYear() + '-' + ('0' + (date.getUTCMonth() + 1)).slice(-2) + '-' + ('0' + date.getUTCDate()).slice(-2) + 'T' + ('0' + (date.getUTCHours() + 2)).slice(-2) + ":" + ('0' + date.getUTCMinutes()).slice(-2) + ":" + ('0' + date.getUTCSeconds()).slice(-2) + "Z"; + return new Date().toISOString(); }; SAML.prototype.signRequest = function (xml) { @@ -105,7 +104,7 @@ SAML.prototype.generateLogoutRequest = function (options) { // options should be of the form // nameId: <nameId as submitted during SAML SSO> // sessionIndex: sessionIndex - // --- NO SAMLsettings: <Meteor.setting.saml entry for the provider you want to SLO from + // --- NO SAMLsettings: <Meteor.setting.saml entry for the provider you want to SLO from var id = "_" + this.generateUniqueID(); var instant = this.generateInstant(); @@ -172,7 +171,7 @@ SAML.prototype.requestToUrl = function (request, operation, callback) { samlRequest.Signature = self.signRequest(querystring.stringify(samlRequest)); } - // TBD. We should really include a proper RelayState here + // TBD. We should really include a proper RelayState here if (operation === 'logout') { // in case of logout we want to be redirected back to the Meteor app. var relayState = Meteor.absoluteUrl(); @@ -438,7 +437,7 @@ SAML.prototype.generateServiceProviderMetadata = function (callbackUrl) { if (!decryptionCert) { decryptionCert = this.options.privateCert; - } + } if (this.options.privateKey) { if (!decryptionCert) { -- GitLab From 88c176221b082e402bd69134c82ad3574dca785e Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 31 Oct 2015 17:49:56 -0400 Subject: [PATCH 0353/1338] refactor(views/admin.html): DRY up settings display html --- client/views/admin/admin.html | 39 +++++++---------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index ea58eccdb14..ba70980c0d8 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -33,56 +33,33 @@ {{/if}} {{/if}} {{#each settings}} - {{#if $eq type 'string'}} <div class="input-line double-col"> <label>{{label}}</label> <div> + {{#if $eq type 'string'}} {{#if multiline}} <textarea name="{{_id}}" rows="4" style="height: auto">{{value}}</textarea> {{else}} <input type="text" name="{{_id}}" value="{{value}}" /> {{/if}} - {{#if description}} - <small>{{description}}</small> - {{/if}} - </div> - </div> {{/if}} {{#if $eq type 'int'}} - <div class="input-line double-col"> - <label>{{label}}</label> - <div> <input type="number" name="{{_id}}" value="{{value}}" /> - {{#if description}} - <small>{{description}}</small> - {{/if}} - </div> - </div> {{/if}} {{#if $eq type 'boolean'}} - <div class="input-line double-col"> - <label>{{label}}</label> - <div> <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> - {{#if description}} - <br /><small>{{description}}</small> - {{/if}} - </div> - - </div> {{/if}} {{#if $eq type 'color'}} - <div class="input-line double-col"> - <label>{{label}}</label> - <div> <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> - {{#if description}} - <small>{{description}}</small> - {{/if}} - </div> - </div> {{/if}} + <div> + {{#if description}} + <small>{{description}}</small> + {{/if}} + </div> + </div> + </div><!-- end setting --> {{/each}} {{#if section}} -- GitLab From 6362c0328db592b5c5d15312155991c32a6d881a Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 31 Oct 2015 17:52:40 -0400 Subject: [PATCH 0354/1338] feat(settings): always allow default settings description key This should cut down on the redundant i18nDescription declarations by allowing developers to utilize the default key + "_Description" convention in the i18n/ files for settings and setting groups Example: setting LDAP_Enable will look for the LDAP_Enable_Description key unless it's explicitly overriden. --- .../rocketchat-lib/settings/server/methods.coffee | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index dab38c13425..056ef90cbfb 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -18,7 +18,12 @@ RocketChat.settings.add = (_id, value, options = {}) -> updateSettings = i18nLabel: options.i18nLabel or _id - updateSettings.i18nDescription = options.i18nDescription if options.i18nDescription? + # default description i18n key will be the setting name + "_Description" + # (eg: LDAP_Enable -> LDAP_Enable_Description) + updateSettings.i18nDescription = if options.i18nDescription? + options.i18nDescription + else + "#{_id}_Description" updateSettings.type = options.type if options.type updateSettings.multiline = options.multiline if options.multiline updateSettings.group = options.group if options.group @@ -49,7 +54,10 @@ RocketChat.settings.addGroup = (_id, options = {}) -> type: 'group' i18nLabel: options.i18nLabel or _id - updateSettings.i18nDescription = options.i18nDescription if options.i18nDescription? + updateSettings.i18nDescription = if options.i18nDescription? + options.i18nDescription + else + "#{_id}_Description" upsertChanges = { $set: updateSettings } if options.persistent is true -- GitLab From 2cbed6b4754a208f6f724bf847bb841fa3b872ba Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 31 Oct 2015 18:32:44 -0400 Subject: [PATCH 0355/1338] refactor(i18n): normalize LDAP_Dn i18nLabel to default key name --- i18n/de.i18n.json | 2 +- i18n/el.i18n.json | 2 +- i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 2 +- i18n/fr.i18n.json | 2 +- i18n/km.i18n.json | 2 +- i18n/ko.i18n.json | 2 +- i18n/ms-MY.i18n.json | 2 +- i18n/pl.i18n.json | 2 +- i18n/pt.i18n.json | 2 +- i18n/ru.i18n.json | 2 +- i18n/zh.i18n.json | 2 +- packages/rocketchat-ldap/config_server.coffee | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 27f18d58870..cf4f9c729f8 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -170,7 +170,7 @@ "Layout_Sidenav_Footer_description" : "Die Footer Größe ist 260x70", "Layout_Terms_of_Service" : "Nutzungsbedingungen", "LDAP" : "LDAP", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "LDAP Port", "LDAP_Url" : "LDAP URL", "Leave_room" : "Raum verlassen", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 786250d24c3..16134efdb1f 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -111,7 +111,7 @@ "Last_message" : "Τελευταίο μήνυμα", "Layout_Home_Body" : "ΑÏχική Σώμα", "Layout_Home_Title" : "ΑÏχική Τίτλος", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "LDAP ΘÏÏα", "LDAP_Url" : "LDAP URL", "Leave_room" : "Έξοδος από το δωμάτιο", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 2ddfab02df2..3700163221b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -188,7 +188,7 @@ "Layout_Terms_of_Service" : "Terms of Service", "LDAP" : "LDAP", "LDAP_Bind_Search" : "Bind Search", - "LDAP_Dn" : "Distinguished Name (DN)", + "LDAP_DN" : "Distinguished Name (DN)", "LDAP_Enable" : "Enable LDAP", "LDAP_Port" : "LDAP Port", "LDAP_Sync_User_Data" : "Keep user data in sync with server", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 62795415271..57e94fa882c 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -156,7 +156,7 @@ "Layout_Sidenav_Footer_description" : "Alatunnisteen koko on 260x70", "Layout_Terms_of_Service" : "Käyttöehdot", "LDAP" : "LDAP", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "LDAP portti", "LDAP_Url" : "LDAP URL", "Leave_room" : "Poistu kanavalta", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 29399fc7c90..d83cdcc0d02 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -160,7 +160,7 @@ "Layout_Sidenav_Footer_description" : "La taille du pied de page est 260x70", "Layout_Terms_of_Service" : "Conditions de service", "LDAP" : "LDAP", - "LDAP_Dn" : "DN LDAP", + "LDAP_DN" : "DN LDAP", "LDAP_Port" : "Port LDAP", "LDAP_Url" : "Adresse LDAP", "Leave_room" : "Quitter le salon", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index a8734d20cf2..8630369cc99 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -168,7 +168,7 @@ "Layout_Sidenav_Footer_description" : "​ទំហំ​បាន​គឺ 260x70", "Layout_Terms_of_Service" : "áž›áŸáž€áŸ’ážážáŸážŽáŸ’ឌ​នៃ​សáŸážœáž¶áž€áž˜áŸ’ម", "LDAP" : "ប្រើ LDAP", - "LDAP_Dn" : " LDAP DN", + "LDAP_DN" : " LDAP DN", "LDAP_Port" : "ច្រក LDAP", "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index ddf0e3c0873..d6239451b3a 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -153,7 +153,7 @@ "Layout_Sidenav_Footer_description" : "바닥글 í¬ê¸°ëŠ” 260x70입니다.", "Layout_Terms_of_Service" : "ì´ìš©ì•½ê´€", "LDAP" : "LDAP", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "LDAP í¬íŠ¸", "LDAP_Url" : "LDAP URL", "Leave_room" : "ë°© 나가기", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 733b93e7088..86ca15e2301 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -147,7 +147,7 @@ "Layout_Sidenav_Footer_description" : "Saiz footer ialah 260x70", "Layout_Terms_of_Service" : "Terma Perkhidmatan", "LDAP" : "LDAP", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "Port LDAP", "LDAP_Url" : "URL LDAP", "Leave_room" : "Meninggalkan bilik", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 182c08aa265..c3f99d81122 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -106,7 +106,7 @@ "Last_message" : "Ostatnia wiadomość", "Layout_Home_Body" : "Treść strony głównej", "Layout_Home_Title" : "TytuÅ‚ strony głównej", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "Port LDAP", "LDAP_Url" : "Adres URL LDAP", "Leave_room" : "Opuść pokój", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index eace2ee8f4a..ace75a7f56d 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -169,7 +169,7 @@ "Layout_Sidenav_Footer_description" : "Tamanho do rodapé é 260x70", "Layout_Terms_of_Service" : "Termos de Serviço", "LDAP" : "LDAP", - "LDAP_Dn" : "DN LDAP", + "LDAP_DN" : "DN LDAP", "LDAP_Port" : "Porta LDAP", "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", "LDAP_Sync_User_Data_FieldMap" : "Mapeamento de campos do usuário", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index f0f14796ac3..5b683bd48d6 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -83,7 +83,7 @@ "Language" : "Язык", "Language_Version" : "РуÑÑÐºÐ°Ñ Ð²ÐµÑ€ÑиÑ", "Last_message" : "ПоÑледнее Ñообщение", - "LDAP_Dn" : "LDAP домен", + "LDAP_DN" : "LDAP домен", "LDAP_Port" : "LDAP Порт", "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Leave_room" : "Покинуть чат", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index 8b169063f15..8501a5a2a43 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -121,7 +121,7 @@ "Layout_Sidenav_Footer" : "侧é¢å¯¼èˆªé¡µè„š", "Layout_Terms_of_Service" : "æœåŠ¡æ¡æ¬¾", "LDAP" : "LDAP", - "LDAP_Dn" : "LDAP DN", + "LDAP_DN" : "LDAP DN", "LDAP_Port" : "LDAP端å£", "LDAP_Url" : "LDAP URL", "Leave_room" : "离开èŠå¤©å®¤", diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index 1782d782b4d..fd4f3f5f133 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -5,7 +5,7 @@ Meteor.startup -> 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', i18nLabel: 'LDAP_Dn', public: true } + 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' } -- GitLab From 5978e5f7c428a29046af1afa0ecfc3fa1e1dea71 Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 31 Oct 2015 18:33:37 -0400 Subject: [PATCH 0356/1338] feat(i18n/en): add ldap setting descriptions --- i18n/en.i18n.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3700163221b..b0f8de71eb1 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -187,13 +187,21 @@ "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", "LDAP" : "LDAP", + "LDAP_Description": "LDAP is a heirarchical 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 twiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", "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_DN" : "Distinguished Name (DN)", + "LDAP_DN_Description": "Search root; example: dc=domain,dc=com", "LDAP_Enable" : "Enable LDAP", + "LDAP_Enable_Description": "Attempt to utilize ldap for authentication.", "LDAP_Port" : "LDAP Port", - "LDAP_Sync_User_Data" : "Keep user data in sync with server", + "LDAP_Port_Description": "Port to access LDAP on; eg: 389", + "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" : "Allows configuring how to populate user account fields (like email) from a record in ldap (once found). As an example, {\"cn\":\"name\", \"mail\":\"email\"} will choose a persion's human readable name from the cn attribute, and their email from the mail attribute. Available fields include name, and email.", "LDAP_Url" : "LDAP URL", + "LDAP_Url_Description": "Uri of the ldap server; example: ldap://company.dns.com", "Leave_room" : "Leave room", "line" : "line", "Load_more" : "Load more", -- GitLab From 12b690088591bbf0a754a52809d4e1a2cb428d70 Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 31 Oct 2015 18:45:17 -0400 Subject: [PATCH 0357/1338] feat(views/admin.html): allow text selection of setting descriptions This change also swaps out the settings group display from <h3> to <p> for a better look and feel. --- client/views/admin/admin.html | 4 ++-- packages/rocketchat-theme/assets/stylesheets/base.less | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index ba70980c0d8..1b09b9535aa 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -12,7 +12,7 @@ {{else}} {{#with group}} <div class="info"> - <h3>{{description}}</h3> + <p class="settings-description">{{description}}</p> </div> {{/with}} <div class="rocket-form"> @@ -55,7 +55,7 @@ {{/if}} <div> {{#if description}} - <small>{{description}}</small> + <small class="settings-description">{{description}}</small> {{/if}} </div> </div> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index d858917f161..c4c7707f344 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -20,6 +20,12 @@ -ms-user-select: none; user-select: none; } +.allow-text-selection { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} :focus { outline: 0 !important; @@ -1706,6 +1712,9 @@ a.github-fork { } .page-settings { + .settings-description { + .allow-text-selection; + } .rocket-form { max-width: none; width: 100%; -- GitLab From a63d9ac08896655c6107d34f29e21a7a62c12c14 Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Thu, 5 Nov 2015 21:14:20 -0500 Subject: [PATCH 0358/1338] style(whitespace): switch spaces to tabs Note that this also makes a minor tweak to scope of "if description" check in admin.html, that is more correct. --- client/views/admin/admin.html | 14 +++++++------- .../settings/server/methods.coffee | 16 ++++++++-------- .../assets/stylesheets/base.less | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index 1b09b9535aa..36d96f01d31 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -53,13 +53,13 @@ {{#if $eq type 'color'}} <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> {{/if}} - <div> - {{#if description}} - <small class="settings-description">{{description}}</small> - {{/if}} - </div> - </div> - </div><!-- end setting --> + {{#if description}} + <div> + <small class="settings-description">{{description}}</small> + </div> + {{/if}} + </div> + </div> {{/each}} {{#if section}} diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 056ef90cbfb..812e413119d 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -18,12 +18,12 @@ RocketChat.settings.add = (_id, value, options = {}) -> updateSettings = i18nLabel: options.i18nLabel or _id - # default description i18n key will be the setting name + "_Description" - # (eg: LDAP_Enable -> LDAP_Enable_Description) + # default description i18n key will be the setting name + "_Description" + # (eg: LDAP_Enable -> LDAP_Enable_Description) updateSettings.i18nDescription = if options.i18nDescription? - options.i18nDescription - else - "#{_id}_Description" + options.i18nDescription + else + "#{_id}_Description" updateSettings.type = options.type if options.type updateSettings.multiline = options.multiline if options.multiline updateSettings.group = options.group if options.group @@ -55,9 +55,9 @@ RocketChat.settings.addGroup = (_id, options = {}) -> i18nLabel: options.i18nLabel or _id updateSettings.i18nDescription = if options.i18nDescription? - options.i18nDescription - else - "#{_id}_Description" + options.i18nDescription + else + "#{_id}_Description" upsertChanges = { $set: updateSettings } if options.persistent is true diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c4c7707f344..14e3f7720e2 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -21,10 +21,10 @@ user-select: none; } .allow-text-selection { - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; } :focus { @@ -1712,9 +1712,9 @@ a.github-fork { } .page-settings { - .settings-description { - .allow-text-selection; - } + .settings-description { + .allow-text-selection; + } .rocket-form { max-width: none; width: 100%; -- GitLab From f96399d492df36bcef90e914ca096c16888131b5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 6 Nov 2015 09:08:48 -0200 Subject: [PATCH 0359/1338] Add a space between name and (optional) --- i18n/de.i18n.json | 2 +- i18n/en.i18n.json | 2 +- i18n/es.i18n.json | 2 +- i18n/fr.i18n.json | 2 +- i18n/it.i18n.json | 2 +- i18n/pt.i18n.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 5df7c46aa5d..fb0b365de34 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -220,7 +220,7 @@ "My_Account" : "Mein Konto", "n_messages" : "%s Nachrichten", "Name" : "Name", - "Name_optional" : "Name(freiwillig)", + "Name_optional" : "Name (freiwillig)", "Name_cant_be_empty" : "Name darf nicht leer sein", "New_messages" : "Neue Nachrichten", "New_password" : "Neues Passwort", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 8a0c5a72482..939c0b3ddf5 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -245,7 +245,7 @@ "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", - "Name_optional" : "Name(optional)", + "Name_optional" : "Name (optional)", "Name_cant_be_empty" : "Name can't be empty", "New_messages" : "New messages", "New_password" : "New password", diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json index 760d8811f49..9320d5b0887 100644 --- a/i18n/es.i18n.json +++ b/i18n/es.i18n.json @@ -68,7 +68,7 @@ "Msgs" : "Mensajes", "n_messages" : "%s mensajes", "Name" : "Nombre", - "Name_optional" : "Nombre(opcional)", + "Name_optional" : "Nombre (opcional)", "New_messages" : "Nuevos mensajes", "New_password" : "Nueva contraseña", "No_channels_yet" : "TodavÃa no eres parte de un canal.", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index b9d183bb2e8..482df5d626f 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -209,7 +209,7 @@ "My_Account" : "Mon compte", "n_messages" : "%s messages", "Name" : "Nom", - "Name_optional" : "Nom(optionnel)", + "Name_optional" : "Nom (optionnel)", "Name_cant_be_empty" : "Le nom ne peut pas être vide", "New_messages" : "Nouveaux messages", "New_password" : "Nouveau mot de passe", diff --git a/i18n/it.i18n.json b/i18n/it.i18n.json index b38087dd60d..123e7892a29 100644 --- a/i18n/it.i18n.json +++ b/i18n/it.i18n.json @@ -62,7 +62,7 @@ "Msgs" : "Msgs", "n_messages" : "% messaggi", "Name" : "Nome", - "Name_optional" : "Nome(opzionale)", + "Name_optional" : "Nome (opzionale)", "New_messages" : "Nuovi messaggi", "New_password" : "Nuova password", "No_channels_yet" : "Non fai parte di nessun canale ancora.", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index f03f1c7c6d0..071c9beae1b 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -223,7 +223,7 @@ "My_Account" : "Minha Conta", "n_messages" : "%s mensagens", "Name" : "Nome", - "Name_optional" : "Nome(opcional)", + "Name_optional" : "Nome (opcional)", "Name_cant_be_empty" : "Nome não pode ser vazio", "New_messages" : "Novas mensagens", "New_password" : "Nova senha", -- GitLab From 16051d479a2c76406fb7b4c326d6be34573a5f25 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 3 Nov 2015 07:25:20 -0200 Subject: [PATCH 0360/1338] Enable robot calling methods on Rocket.Chat --- packages/rocketchat-lib/package.js | 1 + .../server/methods/robotMethods.coffee | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 packages/rocketchat-lib/server/methods/robotMethods.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index ea4c4ff85f5..207c43bb040 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -59,6 +59,7 @@ Package.onUse(function(api) { api.addFiles('server/functions/setUsername.coffee', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); + api.addFiles('server/methods/robotMethods.coffee', 'server'); api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/robotMethods.coffee b/packages/rocketchat-lib/server/methods/robotMethods.coffee new file mode 100644 index 00000000000..9ebebe73ea8 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/robotMethods.coffee @@ -0,0 +1,16 @@ +Meteor.methods + 'robot.modelCall': (model, method, args) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] robot.modelCall -> Invalid user' + + 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' + + call = RocketChat.models[model][method].apply(RocketChat.models[model], args) + console.log call + return call -- GitLab From ab2740df47efeb397e55b66425dad409d46a39de Mon Sep 17 00:00:00 2001 From: frankenbot <frankensteinbot@gmail.com> Date: Fri, 6 Nov 2015 09:55:58 -0800 Subject: [PATCH 0361/1338] Update redirects --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2b559138dc3..427b89f9d11 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron] [](https://travis-ci.org/RocketChat/Rocket.Chat) [](https://coveralls.io/r/RocketChat/Rocket.Chat) [](https://codeclimate.com/github/RocketChat/Rocket.Chat) -[](https://github.com/RocketChat/Rocket.Chat/raw/master/LICENSE) +[](https://github.com/RocketChat/Rocket.Chat/raw/master/LICENSE) [](https://waffle.io/RocketChat/Rocket.Chat) Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](https://www.meteor.com/install) fullstack framework. @@ -57,7 +57,7 @@ It is a great solution for communities and companies wanting to privately host t ##### [Hacker News](https://news.ycombinator.com/item?id=9624737) > Yes, we made it to the #1 -##### [Product Hunt](http://www.producthunt.com/posts/rocket-chat) +##### [Product Hunt](https://www.producthunt.com/tech/rocket-chat) > Your own open source Slack-like chat ##### [JavaScript Weekly](http://javascriptweekly.com/issues/234) @@ -115,7 +115,7 @@ It is a great solution for communities and companies wanting to privately host t #### In Progress - Support multiple teams on the same instance / same VPS infrastructure: [Issue #658](https://github.com/RocketChat/Rocket.Chat/issues/658), [Issue #630](https://github.com/RocketChat/Rocket.Chat/issues/630) -- Support for PostgreSQL: [Issue #533](https://github.com/RocketChat/Rocket.Chat/issues/533), [Issue #822](https://github.com/RocketChat/Rocket.Chat/issues/822) +- Support for PostgreSQL: [Issue #533](https://github.com/RocketChat/Rocket.Chat/issues/533), [Issue #822](https://github.com/RocketChat/Rocket.Chat/pull/822) - Native iOS Application [Issue #270](https://github.com/RocketChat/Rocket.Chat/issues/270), [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) - Native Android Application [Issue #271 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/271) - Off-the-Record (OTR) Messaging [Issue #36](https://github.com/RocketChat/Rocket.Chat/issues/36), [Issue #268 - HELP WANTED](https://github.com/RocketChat/Rocket.Chat/issues/268) @@ -181,9 +181,9 @@ Easy one click install right from your Ubuntu Desktop (coming soon). ### Docker -Use the automated build at our [Official Docker Registry](https://registry.hub.docker.com/u/rocketchat/rocket.chat/) +Use the automated build at our [Official Docker Registry](https://hub.docker.com/r/rocketchat/rocket.chat/) -[](https://registry.hub.docker.com/u/rocketchat/rocket.chat/) +[](https://hub.docker.com/r/rocketchat/rocket.chat/) ``` docker pull rocketchat/rocket.chat @@ -256,7 +256,7 @@ If you want to help, send an email to support at rocket.chat to be invited to th ### Community -Join the conversation at [Twitter](http://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) +Join the conversation at [Twitter](https://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) ### License -- GitLab From 8b4b4fd0a3bb28224c1287a023da9bd089c0db1b Mon Sep 17 00:00:00 2001 From: frankenbot <frankensteinbot@gmail.com> Date: Fri, 6 Nov 2015 09:57:10 -0800 Subject: [PATCH 0362/1338] Update iTunes link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 427b89f9d11..f5184d66e5d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Checkout the latest version at [https://demo.rocket.chat](https://demo.rocket.ch Available from the AppStore: -[](https://geo.itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) +[](https://itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) Get the app for your Android phone: -- GitLab From b75394789126d6070e1f90d2d7ab1a4158a4c568 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 6 Nov 2015 16:48:26 -0200 Subject: [PATCH 0363/1338] Robot methods return fetch if fetch exists; Added user method for searching users from same domain --- .../server/methods/robotMethods.coffee | 7 +++++-- packages/rocketchat-lib/server/models/Users.coffee | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/methods/robotMethods.coffee b/packages/rocketchat-lib/server/methods/robotMethods.coffee index 9ebebe73ea8..664cb049bda 100644 --- a/packages/rocketchat-lib/server/methods/robotMethods.coffee +++ b/packages/rocketchat-lib/server/methods/robotMethods.coffee @@ -12,5 +12,8 @@ Meteor.methods throw new Meteor.Error 'invalid-method', '[methods] robot.modelCall -> Invalid method' call = RocketChat.models[model][method].apply(RocketChat.models[model], args) - console.log call - return call + + if call?.fetch?()? + return call.fetch() + else + return call diff --git a/packages/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index 14201607bca..38ed2b66880 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -28,6 +28,18 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @findOne query, options + findOneVerifiedFromSameDomain: (email, options) -> + domain = s.strRight(email, '@') + query = + emails: + $elemMatch: + address: + $regex: new RegExp "@" + domain + "$", "i" + $ne: email + verified: true + + return @findOne query, options + findOneAdmin: (admin, options) -> query = admin: admin -- GitLab From 60e4620b61b1ffe816cb8c2b93c2a0de15b34632 Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 7 Nov 2015 12:08:13 -0500 Subject: [PATCH 0364/1338] feat(message-ui/edit-info): add information about message editor This comes in the form of the user's avatar, along with a hover title that shows username and edit time. As a side note, this requires us to start saving 'editBy' id as part of message updates. This has been tested with all 4 of the current avatar methods. fixes #824 --- client/methods/updateMessage.coffee | 1 + client/views/app/message.coffee | 11 +++++++++-- client/views/app/message.html | 12 +++++++++++- .../rocketchat-theme/assets/stylesheets/base.less | 7 +++++++ server/methods/updateMessage.coffee | 2 ++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/client/methods/updateMessage.coffee b/client/methods/updateMessage.coffee index b784413eb90..485dcee63c2 100644 --- a/client/methods/updateMessage.coffee +++ b/client/methods/updateMessage.coffee @@ -23,6 +23,7 @@ Meteor.methods Tracker.nonreactive -> + message.editBy = Meteor.userId() message.ets = new Date(Date.now() + TimeSync.serverOffset()) message = RocketChat.callbacks.run 'beforeSaveMessage', message diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 27151ef7fe3..697ec84ee91 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -1,3 +1,5 @@ +wasEdited = (msg) -> + msg.ets and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] Template.message.helpers actions: -> return RocketChat.MessageAction.getButtons(this) @@ -46,8 +48,13 @@ Template.message.helpers system: -> return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] - edited: -> - return @ets and @t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + edited: -> wasEdited(@) + editTime: -> + return "" unless wasEdited(@) + moment(@ets).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? + editedBy: -> + return "" unless wasEdited(@) + Meteor.users.findOne(@editBy ? Meteor.userId())?.username pinned: -> return this.pinned canEdit: -> diff --git a/client/views/app/message.html b/client/views/app/message.html index 6dc5bfa222b..377df9a12db 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -5,7 +5,17 @@ <span class="info"> <span class="time">{{time}}</span> {{#if edited}} - <span class="edited">({{_ "edited"}})</span> + <span class="edited"> + (<a + title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' + class="thumb thumb-small user-card-message" + href="#" + data-username="{{editedBy}}" + tabindex="1"> + {{> avatar username=editedBy}} + </a> + {{_ "edited"}}) + </span> {{/if}} {{#if private}} <span class="private">{{_ "Only_you_can_see_this_message"}}</span> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 14e3f7720e2..44ae8954eeb 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2448,6 +2448,13 @@ a.github-fork { display: block; width: 40px; height: 40px; + &.thumb-small { + position: initial; + width: 20px; + height: 20px; + display: inline-block; + vertical-align: bottom; + } } .info { font-size: 12px; diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index dc6b47d9c53..7e84063a814 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -29,6 +29,8 @@ Meteor.methods RocketChat.models.Messages.cloneAndSaveAsHistoryById originalMessage._id message.ets = new Date() + # save who message was edited by + message.editBy = Meteor.userId() if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g message.urls = urls.map (url) -> url: url -- GitLab From c6cd46d7dc3592bd8dcfb0b3998d692171a22531 Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 7 Nov 2015 14:30:37 -0500 Subject: [PATCH 0365/1338] fix(message-ui/edit-info): handle the case where editor can't be found This uses a special "?" character that is understood by the /avatar/ route and will be treated specially. This change also adds url encoding/decoding around username usage via the url for the avatar. --- client/lib/avatar.coffee | 2 +- client/views/app/message.coffee | 12 +++++++++++- server/startup/avatar.coffee | 28 ++++++++++++++++------------ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/client/lib/avatar.coffee b/client/lib/avatar.coffee index 6fb117efa59..7fb7cf46f3c 100644 --- a/client/lib/avatar.coffee +++ b/client/lib/avatar.coffee @@ -8,7 +8,7 @@ path = Meteor.absoluteUrl() else path = '/' - return "#{path}avatar/#{username}.jpg?_dc=#{random}" + "#{path}avatar/#{encodeURIComponent(username)}.jpg?_dc=#{random}" Blaze.registerHelper 'avatarUrlFromUsername', getAvatarUrlFromUsername diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 697ec84ee91..36cf10d76bf 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -54,7 +54,17 @@ Template.message.helpers moment(@ets).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? editedBy: -> return "" unless wasEdited(@) - Meteor.users.findOne(@editBy ? Meteor.userId())?.username + # try to return the username of the editor, + # otherwise a special "?" character that will be + # rendered as a special avatar + if @editBy + user = Meteor.users.findOne(@editBy) + if user? + user.username + else + "?" + else + "?" pinned: -> return this.pinned canEdit: -> diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index a2949af98fd..142bc327f18 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -30,13 +30,14 @@ Meteor.startup -> WebApp.connectHandlers.use '/avatar/', (req, res, next) -> this.params = - username: req.url.replace(/^\//, '').replace(/\?.*$/, '') + username: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) if this.params.username[0] isnt '@' file = RocketChatFileAvatarInstance.getFileWithReadStream this.params.username else this.params.username = this.params.username.replace '@', '' + #console.log "[avatar] checking username #{@params.username} (derrived from path #{req.url})" res.setHeader 'Content-Disposition', 'inline' if not file? @@ -45,19 +46,22 @@ Meteor.startup -> colors = ['#F44336','#E91E63','#9C27B0','#673AB7','#3F51B5','#2196F3','#03A9F4','#00BCD4','#009688','#4CAF50','#8BC34A','#CDDC39','#FFC107','#FF9800','#FF5722','#795548','#9E9E9E','#607D8B'] - username = this.params.username.replace('.jpg', '') - position = username.length % colors.length - color = colors[position] - - username = username.replace(/[^A-Za-z0-9]/g, '.').replace(/\.+/g, '.').replace(/(^\.)|(\.$)/g, '') - usernameParts = username.split('.') + username = @params.username.replace('.jpg', '') + color = '' initials = '' - if usernameParts.length > 1 - initials = _.first(usernameParts)[0] + _.last(usernameParts)[0] + if username is "?" + color = "#000" + initials = username else - initials = username.replace(/[^A-Za-z0-9]/g, '').substr(0, 2) - - initials = initials.toUpperCase() + position = username.length % colors.length + color = colors[position] + username = username.replace(/[^A-Za-z0-9]/g, '.').replace(/\.+/g, '.').replace(/(^\.)|(\.$)/g, '') + usernameParts = username.split('.') + initials = if usernameParts.length > 1 + _.first(usernameParts)[0] + _.last(usernameParts)[0] + else + username.replace(/[^A-Za-z0-9]/g, '').substr(0, 2) + initials = initials.toUpperCase() svg = """ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -- GitLab From 97e8132a02d7b1e1f3ea0b00d5303ea507246ac1 Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 7 Nov 2015 15:19:40 -0500 Subject: [PATCH 0366/1338] fix(message-ui): skip negative margin on edit thumbnail in compact mode --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 44ae8954eeb..0d7e4d701c8 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2553,7 +2553,7 @@ a.github-fork { .compact { .message { padding: 5px 20px 5px 70px; - .thumb .avatar { + .thumb:not(.thumb-small) .avatar { margin-top: -15px; } } -- GitLab From 8a1ff94a9b625f2a676a3c6e7f5540eee0b700a5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Sat, 7 Nov 2015 21:16:17 +0000 Subject: [PATCH 0367/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'chinello@gmail.com'. --- packages/rocketchat-github-enterprise/i18n/fi.i18n.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-github-enterprise/i18n/fi.i18n.json b/packages/rocketchat-github-enterprise/i18n/fi.i18n.json index 06dd996c99c..107ca5894b8 100644 --- a/packages/rocketchat-github-enterprise/i18n/fi.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/fi.i18n.json @@ -1,3 +1,7 @@ { - "API_GitHub_Enterprise_URL" : "GitHub Enterprise" + "Accounts_OAuth_GitHub_Enterprise" : "OAuth Käytössä", + "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" : "Huom: Älä syötä viimeistä kenoviivaa" } \ No newline at end of file -- GitLab From 8736f903de674f73bc78d0aa8f348179f57bc22c Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Sat, 7 Nov 2015 21:19:11 +0000 Subject: [PATCH 0368/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'chinello@gmail.com'. --- i18n/de.i18n.json | 8 +- i18n/en.i18n.json | 24 +-- i18n/es.i18n.json | 14 +- i18n/fi.i18n.json | 138 +++++++++++++----- i18n/fr.i18n.json | 2 +- i18n/hr.i18n.json | 15 ++ i18n/it.i18n.json | 2 +- i18n/km.i18n.json | 28 ++++ i18n/ms-MY.i18n.json | 9 ++ i18n/pt.i18n.json | 10 +- i18n/ru.i18n.json | 31 +++- i18n/tr.i18n.json | 6 + packages/rocketchat-chatops/i18n/fi.i18n.json | 3 +- packages/rocketchat-gitlab/i18n/fi.i18n.json | 2 +- .../rocketchat-livechat/i18n/fi.i18n.json | 2 +- .../rocketchat-message-star/i18n/fi.i18n.json | 8 +- .../rocketchat-message-star/i18n/hr.i18n.json | 5 +- .../rocketchat-message-star/i18n/ru.i18n.json | 7 +- .../rocketchat-message-star/i18n/tr.i18n.json | 6 +- .../i18n/fi.i18n.json | 1 + .../i18n/fi.i18n.json | 3 +- .../rocketchat-webrtc-ib/i18n/ar.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/de.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/el.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/en.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/es.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/fi.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/fr.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/he.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/hr.i18n.json | 4 + .../rocketchat-webrtc-ib/i18n/hu.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/it.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/ja.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/km.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/ko.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/ms-MY.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/pl.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/pt.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/ru.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/ta-IN.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/tr.i18n.json | 6 + .../rocketchat-webrtc-ib/i18n/ug.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/uk.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/zh.i18n.json | 6 + packages/rocketchat-webrtc/i18n/fi.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/hr.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/km.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/pt.i18n.json | 4 +- .../rocketchat-wordpress/i18n/fi.i18n.json | 2 +- 49 files changed, 369 insertions(+), 70 deletions(-) create mode 100644 packages/rocketchat-webrtc-ib/i18n/ar.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/de.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/el.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/en.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/es.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/fi.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/fr.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/he.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/hr.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/hu.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/it.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ja.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/km.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ko.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/pl.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/pt.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ru.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/tr.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/ug.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/uk.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/zh.i18n.json diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index feead0bbb3e..117f5c7df70 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -41,6 +41,7 @@ "Administration" : "Administration", "All_channels" : "Alle Kanäle", "Allow_Invalid_SelfSigned_Certs" : "Selbstsignierte SSL-Zertifikate für die Link-Validierung und die Vorschau zulassen", + "CDN_PREFIX" : "CDN Präfix", "and" : "und", "API" : "API", "API_Analytics" : "Analytics", @@ -70,6 +71,7 @@ "Channels" : "Kanäle", "Channels_list" : "Liste der öffentlichen Channels", "Chat_Rooms" : "Chaträume", + "Clear_all_unreads_question" : "Alle ungelesenen löschen?", "close" : "schließen", "coming_soon" : "kommt bald", "Commands" : "Befehle", @@ -133,7 +135,7 @@ "hours" : "Stunden", "Incorrect_Password" : "Falsches Passwort", "inline_code" : "inline_code", - "Install_FxOs": "Installiere Rocket.Chat auf deinem Firefox", + "Install_FxOs" : "Installiere Rocket.Chat auf deinem Firefox", "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App (drücke \"Installieren\" in der Aufforderung).", "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:", @@ -319,6 +321,7 @@ "Site_Url" : "Website URL", "Site_Url_Description" : "Beispiel: https://chat.domain.com/", "SAML" : "SAML", + "SAML_Custom_Generate_Username" : "Benutzernamen generieren", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP Passwort", @@ -400,9 +403,10 @@ "Welcome_to_the" : "Willkommen bei", "With_whom" : "Mit wem?", "Yes_delete_it" : "Ja, löschen!", + "Yes_clear_all" : "Ja, alles!", "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!", "Your_entry_has_been_deleted" : "Ihr Eintrag wurde gelöscht.", "Your_Open_Source_solution" : "Deine eigene Open Source Chat Lösung" -} +} \ No newline at end of file diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 76fa01d5c23..5abc995c31a 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -63,7 +63,7 @@ "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", "Avatar_changed_successfully" : "Avatar changed successfully", - "Avatar_url_invalid_or_error": "The url provided is invalid or not accessible. Please try again, but with a different url.", + "Avatar_url_invalid_or_error" : "The url provided is invalid or not accessible. Please try again, but with a different url.", "away" : "away", "Away" : "Away", "away_female" : "away", @@ -188,21 +188,21 @@ "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", "LDAP" : "LDAP", - "LDAP_Description": "LDAP is a heirarchical 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 twiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", + "LDAP_Description" : "LDAP is a heirarchical 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 twiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", "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_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_DN" : "Distinguished Name (DN)", - "LDAP_DN_Description": "Search root; example: dc=domain,dc=com", + "LDAP_DN_Description" : "Search root; example: dc=domain,dc=com", "LDAP_Enable" : "Enable LDAP", - "LDAP_Enable_Description": "Attempt to utilize ldap for authentication.", + "LDAP_Enable_Description" : "Attempt to utilize ldap for authentication.", "LDAP_Port" : "LDAP Port", - "LDAP_Port_Description": "Port to access LDAP on; eg: 389", + "LDAP_Port_Description" : "Port to access LDAP on; eg: 389", "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" : "Allows configuring how to populate user account fields (like email) from a record in ldap (once found). As an example, {\"cn\":\"name\", \"mail\":\"email\"} will choose a persion's human readable name from the cn attribute, and their email from the mail attribute. Available fields include name, and email.", "LDAP_Url" : "LDAP URL", - "LDAP_Url_Description": "Uri of the ldap server; example: ldap://company.dns.com", + "LDAP_Url_Description" : "Uri of the ldap server; example: ldap://company.dns.com", "Leave_room" : "Leave room", "line" : "line", "Load_more" : "Load more", @@ -285,7 +285,7 @@ "Please_wait" : "Please wait", "Please_wait_activation" : "Please wait, this can take some time.", "Please_wait_statistics" : "Please wait, statistics are being generated.", - "Please_enter_value_for_url": "Please enter a value for the url of your avatar.", + "Please_enter_value_for_url" : "Please enter a value for the url of your avatar.", "Powered_by" : "Powered by", "Preferences" : "Preferences", "Preferences_saved" : "Preferences saved", @@ -400,8 +400,8 @@ "The_field_is_required" : "The field %s is required.", "True" : "True", "Unnamed" : "Unnamed", - "Unread_Rooms": "Unread Rooms", - "Unread_Rooms_Mode": "Unread Rooms Mode", + "Unread_Rooms" : "Unread Rooms", + "Unread_Rooms_Mode" : "Unread Rooms Mode", "Upload_file_question" : "Upload file?", "Use_Emojis" : "Use Emojis", "Use_initials_avatar" : "Use your username initials", @@ -409,7 +409,7 @@ "Use_service_avatar" : "Use %s avatar", "Use_this_username" : "Use this username", "Use_uploaded_avatar" : "Use uploaded avatar", - "Use_url_for_avatar": "Use url for avatar", + "Use_url_for_avatar" : "Use url for avatar", "User_added" : "User <em>__user_added__</em> added.", "User_added_by" : "User <em>__user_added__</em> added by <em>__user_by__</em>.", "User_Channels" : "User Channels", @@ -453,4 +453,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json index 9320d5b0887..7ccb803a6bb 100644 --- a/i18n/es.i18n.json +++ b/i18n/es.i18n.json @@ -1,6 +1,7 @@ { "Access_online_demo" : "Accede a la demo en lÃnea", "Access_Online_Demo" : "Accede a la demo online", + "Add_Members" : "Agregar miembros", "Add_users" : "Añadir usuarios", "All_channels" : "Todos los canales", "and" : "y", @@ -10,6 +11,7 @@ "away" : "lejos", "Away" : "Lejos", "Back_to_login" : "Volver a identificarse", + "bold" : "negrita", "busy" : "ocupado", "Busy" : "Ocupado", "Cancel" : "Cancelar", @@ -23,15 +25,17 @@ "Contact" : "Contacto", "Conversation" : "Conversación", "Create_new" : "Crear nuevo", + "Create_new_direct_message_room" : "Crear una sala de mensajes directos", "Create_new_private_group" : "Crear un nuevo grupo privado", "Create_new_public_channel" : "Crear un nuevo canal público", "Created_at" : "Creado en", + "Deleted" : "¡Eliminar!", "Direct_Messages" : "Mensajes Directos", "edited" : "Editado", "Email_or_username" : "Correo electrónico o nombre de usuario", "Email_verified" : "Correo electrónico verificado", "Enter_info" : "Introduce tus datos de acceso", - "Error_changing_password" : "Contraseña cambiada", + "Error_changing_password" : "Error al cambiar de contraseña", "Favorites" : "Favoritas", "Follow_social_profiles" : "Sigue nuestros perfiles sociales, realiza un fork en github y comparte tus pensamientos acerca de la aplicación rocket.chat en nuestro tablero de Trello.", "Forgot_password" : "Olvidaste tu contraseña", @@ -50,6 +54,8 @@ "Invisible" : "Invisible", "is_also_typing" : "está también escribiendo", "is_typing" : "está escribiendo", + "italics" : "cursiva", + "join" : "Unirse", "Join_the_Community" : "Únete a la Comunidad", "Language" : "Idioma", "Language_Version" : "Versión en Inglés", @@ -88,6 +94,7 @@ "Private_Groups" : "Grupos Privados", "Proudly_developed" : "Orgullosamente desarrollado con Meteor", "Quick_Search" : "Búsqueda rápida", + "quote" : "cita", "Recents" : "Recientes", "Register" : "Registrar una nueva cuenta", "Remember_me" : "Recuérdame", @@ -120,6 +127,7 @@ "Use_uploaded_avatar" : "Utilizar avatar subido", "User_added" : "Usuario <em>__user_added__</em> añadido.", "User_added_by" : "El usuario <em>__user_added__</em> ha sido añadido por <em>__user_by__</em>.", + "User_joined_channel" : "Se ha unido al canal.", "User_left" : "Usuario <em>__user_left__</em> ha salido.", "User_logged_out" : "El usuario está desconectado", "User_removed_by" : "El usuario <em>__user_removed__</em> ha sido eliminado por <em>__user_by__</em>.", @@ -135,6 +143,8 @@ "Welcome" : "Bienvenido <em>%s</em>.", "Welcome_to_the" : "Bienvenido a la", "With_whom" : "Con quien", + "Yes_delete_it" : "¡SÃ, eliminarla!", + "you_are_in_preview_mode_of" : "Estás en modo vista previa del canal #<strong>__room_name__</strong>", "You_need_confirm_email" : "¡Es necesario confirmar tu correo electrónico para poder identificarte!", "Your_Open_Source_solution" : "Tu propia solución de chat de código abierto" -} +} \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 57e94fa882c..144a5e0bd52 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -2,28 +2,38 @@ "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Tilit", + "Accounts_AllowedDomainsList" : "Pilkkueroteltu lista sallituista domaineista", + "Accounts_AllowUsernameChange" : "Salli käyttäjätunnuksen muuttaminen", + "Accounts_AllowPasswordChange" : "Salli salasanan vaihto", + "Accounts_AvatarResize" : "Muuta avatarien kokoa", + "Accounts_AvatarSize" : "Avatarin koko", + "Accounts_AvatarStorePath" : "Avatarin tallennuspolku", + "Accounts_AvatarStoreType" : "Avatarien tallennusmuoto", "Accounts_denyUnverifiedEmail" : "Estä vahvistamaton sähköpostiosoite", "Accounts_EmailVerification" : "Sähköpostiosoitteen varmistaminen", "Accounts_OAuth_Facebook" : "Facebook-tunnus", "Accounts_OAuth_Facebook_id" : "Facebook App Id", - "Accounts_OAuth_Facebook_secret" : "Facebook salalauseke", - "Accounts_OAuth_Github" : "GitHub-tunnus", - "Accounts_OAuth_Github_id" : "GitHub ID", - "Accounts_OAuth_Github_secret" : "GitHub salalauseke", + "Accounts_OAuth_Facebook_secret" : "Facebook Secret", + "Accounts_OAuth_Github" : "OAuth Käytössä", + "Accounts_OAuth_Github_id" : "Client ID", + "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Gitlab" : "OAuth käytössä", + "Accounts_OAuth_Gitlab_id" : "Gitlab Id", + "Accounts_OAuth_Gitlab_secret" : "Client Secret", "Accounts_OAuth_Google" : "Google-tunnus", "Accounts_OAuth_Google_id" : "Google ID", - "Accounts_OAuth_Google_secret" : "Google salalauseke", + "Accounts_OAuth_Google_secret" : "Google Secret", "Accounts_OAuth_Linkedin" : "LinkedIn-tunnus", "Accounts_OAuth_Linkedin_id" : "LinkedIn ID", - "Accounts_OAuth_Linkedin_secret" : "LinkedIn salalauseke", + "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", "Accounts_OAuth_Meteor" : "Meteor-tunnus", "Accounts_OAuth_Meteor_id" : "Meteor ID", - "Accounts_OAuth_Meteor_secret" : "Meteor salalauseke", + "Accounts_OAuth_Meteor_secret" : "Meteor Secret", "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", "Accounts_RegistrationRequired" : "Rekisteröinti vaaditaan", "Accounts_OAuth_Twitter" : "Twitter-tunnus", "Accounts_OAuth_Twitter_id" : "Twitter ID", - "Accounts_OAuth_Twitter_secret" : "Twitter salalauseke", + "Accounts_OAuth_Twitter_secret" : "Twitter Secret", "Accounts_OAuth_Custom_id" : "Id", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Custom_Token_Path" : "Token polku", @@ -34,6 +44,7 @@ "Accounts_OAuth_Custom_Button_Label_Text" : "Painikkeen teksti", "Accounts_OAuth_Custom_Button_Label_Color" : "Painikkeen tekstin väri", "Accounts_OAuth_Custom_Button_Color" : "Painikkeen väri", + "Accounts_RequireNameForSignUp" : "Vaadi nimi rekisteröityessä", "Activate" : "Aktivoi", "Add_custom_oauth" : "Lisää mukautettu oauth", "Add_Members" : "Lisää osallistujia", @@ -41,14 +52,18 @@ "Administration" : "Ylläpito", "All_channels" : "Kaikki kanavat", "Allow_Invalid_SelfSigned_Certs" : "Salli virheelliset ja itse allekirjoitetut SSL varmenteet linkin validointiin ja esikatseluihin", + "CDN_PREFIX" : "CDN etuliite", "and" : "ja", "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Upota", + "API_EmbedDisabledFor" : "Poista upotustoiminto käyttäjiltä", + "API_EmbedDisabledFor_Description" : "Pilkkueroteltu lista käyttäjätunnuksista", "are_also_typing" : "kirjoittavat myös", "are_typing" : "kirjoittavat", "Are_you_sure" : "Oletko varma?", "Avatar_changed_successfully" : "Avatar vaihdettu onnistuneesti", + "Avatar_url_invalid_or_error" : "URL on virheellinen tai ei ole käytettävissä. Yritä uudestaan.", "away" : "poissa", "Away" : "Poissa", "away_female" : "poissa", @@ -69,9 +84,11 @@ "Channels" : "Kanavat", "Channels_list" : "Julkiset kanavat", "Chat_Rooms" : "Chathuoneet", + "Clear_all_unreads_question" : "Tyhjennä kaikki lukemattomat?", "close" : "sulje", "coming_soon" : "tulossa", "Commands" : "Komennot", + "Compact_View" : "Suppea näkymä", "Confirm_password" : "Vahvista salasanasi", "Contact" : "Yhteys", "Conversation" : "Keskustelu", @@ -82,14 +99,18 @@ "Create_new_public_channel" : "Luo uusi julkinen kanava", "Created_at" : "Luotu", "Custom_oauth_unique_name" : "Mukautettu oauth yksilöllinen nimi", - "Custom_oauth_helper" : "Kun perustat OAuth Provider, sinun täytyy ilmoittaa Callback URL. Käytä <pre>%s</pre>.", + "Custom_oauth_helper" : "Kun perustat OAuth Providerin, sinun täytyy ilmoittaa Callback URL. Käytä <pre>%s</pre>.", "days" : "päivää", "Deactivate" : "Deaktivoi", "Delete_User_Warning" : "Käyttäjän poistaminen poistaa myös käyttäjän kaikki viestit. Toimintoa ei voi perua.", + "Delete_Room_Warning" : "Huomeen poistaminen poistaa kaikki huoneessa olevat viestit.\nToimintoa ei voi perua.", "Delete" : "Poista", "Deleted" : "Poistettu!", + "Desktop_Notifications" : "Työpöytäilmoituksia", + "Desktop_Notifications_Disabled" : "Työpöytäilmoitukset eivät ole käytössä. Muuta selaimen asetuksia mikäli haluat ilmoitukset käyttöön.", + "Desktop_Notifications_Enabled" : "Työpöytäilmoitukset ovat käytössä.", "Direct_Messages" : "Yksityisviestit", - "Disable_Favorite_Rooms" : "Poista käytöstä suosikit", + "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ä", "Drop_to_upload_file" : "Vedä ja pudota lähettääksesi tiedoston", @@ -102,16 +123,23 @@ "Email_or_username" : "Sähköpostiosoite tai käyttäjänimi", "Email_verified" : "Sähköpostiosoite vahvistettu", "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "Ota työpöytäilmoitukset käyttöön", "Enter_info" : "Syötä kirjautumistietosi", "Enter_to" : "Astu sisään", "Error_changing_password" : "Virhe vaihtaessa salasanaa", + "Error_too_many_requests" : "Virhe, liikaa pyyntöjä. Rauhoitu hieman.\nOdota %s sekuntia ennen uudelleenyritystä.", "Esc_to" : "Poistu", "False" : "Ei", "Favorites" : "Suosikit", + "FileUpload" : "Lähetä tiedosto", + "FileUpload_Enabled" : "Tiedostojen lähetykset käytössä", + "FileUpload_MaxFileSize" : "Suurin lähetettävän tiedoston koko (tavuina)", + "FileUpload_MediaTypeWhiteList" : "Hyväksytyt mediatyypit", + "FileUpload_MediaTypeWhiteListDescription" : "Pilkkueroteltu lista mediatyypeistä", "Follow_social_profiles" : "Seuraa someamme, forkkaa Githubissa ja jaa ajatuksiasi rocket.chatista trellossa.", "Forgot_password" : "Unohditko salasanasi?", "Fork_it_on_github" : "Forkkaa GitHubissa", - "From_Email" : "Sähköpostilta", + "From_Email" : "Sähköpostista", "General" : "Yleinen", "Get_to_know_the_team" : "Tutustu Rocket.Teamiin", "github_no_public_email" : "GitHub-tunnukseltasi ei löydy julkisia sähköpostiosoitetietoja", @@ -123,6 +151,10 @@ "hours" : "tuntia", "Incorrect_Password" : "Väärä salasana", "inline_code" : "koodi", + "Install_FxOs" : "Asenna Rocket.Chat Firefoxiisi", + "Install_FxOs_follow_instructions" : "Vahvista sovelluksen asennus laitteellasi (paina \"Install\" käskettäessä)", + "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:", "Invalid_confirm_pass" : "Salasanat eivät täsmää", "Invalid_email" : "Annettu sähköpostiosoite ei ole oikea", "Invalid_name" : "Nimi ei voi olla tyhjä", @@ -131,7 +163,7 @@ "invisible" : "näkymätön", "Invisible" : "Näkymätön", "Invitation_HTML" : "Kutsu HTML", - "Invitation_Subject" : "Kutsu aihe", + "Invitation_Subject" : "Kutsun aihe", "Invite_Users" : "Kutsu käyttäjiä", "is_also_typing" : "kirjoittaa myös", "is_also_typing_female" : "kirjoittaa myös", @@ -146,7 +178,7 @@ "Language_Version" : "Suomi", "Last_login" : "Viimeisin kirjautuminen", "Last_message" : "Viimeinen viesti", - "Layout" : "Layout", + "Layout" : "Ulkoasu", "Layout_Home_Body" : "Etusivun runko", "Layout_Home_Title" : "Etusivun otsikko", "Layout_Login_Header" : "Kirjautumisruudun ylätunniste", @@ -156,11 +188,23 @@ "Layout_Sidenav_Footer_description" : "Alatunnisteen koko on 260x70", "Layout_Terms_of_Service" : "Käyttöehdot", "LDAP" : "LDAP", + "LDAP_Description" : "LDAP on laajasti käytössä oleva hierarkinen tietokantapalvelu, jolla organisaatioiden palveluille mahdollistetaan kertakirjautuminen (SSO).\nMääritystiedot ja esimerkit, katso wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication", + "LDAP_Bind_Search" : "Bind haku", + "LDAP_Bind_Search_Description" : "JSON, joka määrää yhdistämistiedot.\nMuoto: {\"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_DN" : "LDAP DN", + "LDAP_DN_Description" : "Etsintäpolku, esimerkiksi: dc = domain, dc = com", + "LDAP_Enable" : "Kytke LDAP päälle", + "LDAP_Enable_Description" : "Käytä LDAPia autentikointiin", "LDAP_Port" : "LDAP portti", + "LDAP_Port_Description" : "LDAP-portti (esim 389)", + "LDAP_Sync_User_Data" : "Synkronoi käyttäjädata", + "LDAP_Sync_User_Data_Description" : "Pidä käyttäjädata synkronoituna palvelimelta kirjautumishetkellä (esim nimi, sähköposti)", + "LDAP_Sync_User_Data_FieldMap" : "Käyttäjätietojen kohdistus", + "LDAP_Sync_User_Data_FieldMap_Description" : "Määrittää, miten käyttäjätietojen kentät tuodaan LDAP-palvelimelta.\nEsimerkiksi, {\"cn\":\"name\", \"mail\":\"email\"} -määritys tuo käyttäjän nimen cn-tiedosta ja sähköpostin email-tiedosta. Käytettävissä olevat kentät ovat \"name\" ja \"email\".", "LDAP_Url" : "LDAP URL", + "LDAP_Url_Description" : "LDAP-palvelimen URI, esimerkiksi: ldap://company.example.com", "Leave_room" : "Poistu kanavalta", - "line" : "viiva", + "line" : "riviä", "Load_more" : "Lataa lisää", "Loading_more_from_history" : "Ladataan lisää historiasta", "Loading..." : "Ladataan...", @@ -171,13 +215,17 @@ "Logout" : "Kirjaudu ulos", "Make_Admin" : "Tee ylläpitäjäksi", "Mark_as_read" : "Merkitse luetuksi", + "Markdown_Headers" : "Markdown otsikot", "Members" : "Jäsenet", "Members_List" : "Jäsenlista", "Members_placeholder" : "Jäsenet", "Message" : "Viesti", "Message_AllowDeleting" : "Salli viestin poisto", "Message_AllowEditing" : "Salli viestin muokkaus", - "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus jälkeen (minuuteissa - 0 poistaa käytöstä)", + "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus (x) minuutin jälkeen", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Syötä 0 poistaaksesi muutoseston", + "Message_AudioRecorderEnabled" : "Äänentallennin käytössä", + "Message_AudioRecorderEnabledDescription" : "Jotta tämä toimisi, WAV-tiedostojen lähetys tulee olla sallittu", "Message_deleting_not_allowed" : "Viestin poisto ei sallittu", "Message_editing_not_allowed" : "Viestin muokkaus ei sallittu", "Message_editing_blocked" : "Tätä viestiä ei voi muokata enää.", @@ -189,28 +237,31 @@ "Message_pinned" : "Viesti kiinnitetty", "Message_ShowDeletedStatus" : "Näytä poistotila", "Message_ShowEditedStatus" : "Näytä muokkaustila", + "Message_ShowFormattingTips" : "Näytä muotoiluvihjeet", + "Messages" : "Viestit", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", - "Meta_google-site-verification" : "Google sivuston vahvistaminen", + "Meta_google-site-verification" : "Google Site Verification", "Meta_language" : "Kieli", "Meta_msvalidate01" : "MSValidate.01", "Meta_robots" : "Hakurobotit", "minutes" : "minuuttia", "More_channels" : "Lisää kanavia", - "More_groups" : "Lisää yksityisiä ryhmiä", + "More_groups" : "Lisää privaattiryhmiä", "More_unreads" : "Lisää lukemattomia", "Msgs" : "Viestit", - "multi" : "moni", + "multi" : "monta", "My_Account" : "Käyttäjätilini", "n_messages" : "%s viestiä", "Name" : "Nimi", + "Name_optional" : "Nimi (valinnainen)", "Name_cant_be_empty" : "Nimi ei voi olla tyhjä", "New_messages" : "Uusia viestejä", "New_password" : "Uusi salasana", "No_channels_yet" : "Et ole vielä millään kanavalla.", "No_direct_messages_yet" : "Et ole vielä aloittanut mitään keskustelua.", "No_favorites_yet" : "Et ole vielä lisännyt suosikkeja.", - "No_groups_yet" : "Sinulla ei ole vielä yksityisviestikeskusteluja.", + "No_groups_yet" : "Sinulla ei ole vielä privaattiryhmiä.", "No_permission_to_view_room" : "Sinulla ei ole oikeutta katsella tätä", "No_channel_with_name_%s_was_found" : "Kanavaa nimeltä '%s' ei löytynyt!", "No_group_with_name_%s_was_found" : "Privaattiryhmää '%s' ei löytynyt!", @@ -229,28 +280,32 @@ "others" : "muut", "Password" : "Salasana", "Password_changed_successfully" : "Salasana vaihdettu", + "Password_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut salasanan vaihtamismahdollisuuden", "People" : "Ihmiset", "Please_wait" : "Odota hetki", "Please_wait_activation" : "Odota, tämä voi kestää jonkin aikaa.", "Please_wait_statistics" : "Odota, tilastoja generoidaan.", + "Please_enter_value_for_url" : "Anna avatarisi URL", "Powered_by" : "Powered by", "Preferences" : "Asetukset", "Preferences_saved" : "Asetukset tallennettu", "Privacy" : "Yksityisyys", - "Private_Groups" : "Yksityisviestikeskustelut", - "Private_Groups_list" : "Luettelo yksityisistä ryhmistä", + "Private_Groups" : "Privaatiryhmät", + "Private_Groups_list" : "Privaattiryhmäluettelo", "Profile" : "Profiili", "Profile_saved_successfully" : "Profiili tallennettu onnistuneesti", "Proudly_developed" : "Proudly developed with Meteor", - "Push" : "Työnnä", + "Push" : "Push", "Push_apn_cert" : "APN Cert", "Push_apn_dev_cert" : "APN Cert (kehitys)", - "Push_apn_dev_key" : "APN Avain (kehitys)", - "Push_apn_dev_passphrase" : "APN Tunnuslause (kehitys)", - "Push_apn_key" : "APN Avain", - "Push_apn_passphrase" : "APN Tunnuslause", + "Push_apn_dev_key" : "APN Key (kehitys)", + "Push_apn_dev_passphrase" : "APN Passphrase (kehitys)", + "Push_apn_key" : "APN Key", + "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", "Push_enable" : "Kytke päälle", + "Push_gcm_api_key" : "GCM API Key", + "Push_gcm_project_number" : "GCM Project Number", "Push_production" : "Tuotanto", "Quick_Search" : "Pikaetsintä", "quote" : "lainaus", @@ -272,7 +327,7 @@ "room_user_count" : "%s käyttäjää", "Rooms" : "Huoneet", "Save" : "Tallenna", - "Save_changes" : "Tallenna", + "Save_changes" : "Tallenna muutokset", "Save_Mobile_Bandwidth" : "Säästä kaistaa mobiilissa", "Search" : "Etsi", "Search_Messages" : "Etsi viestejä", @@ -286,8 +341,8 @@ "Selected_users" : "Valitut käyttäjät", "Send" : "Lähetä", "Send_confirmation_email" : "Lähetä vahvistussähköposti", - "Send_invitation_email" : "Lähetä kutsu sähköposti", - "Send_invitation_email_error" : "Et ole antanyt yhtään pätevää sähköpostiosoitetta.", + "Send_invitation_email" : "Lähetä kutsusähköposti", + "Send_invitation_email_error" : "Et ole antanyt yhtään validia sähköpostiosoitetta.", "Send_invitation_email_info" : "Voit lähettää useita sähköpostikutsuja kerralla.", "Send_invitation_email_success" : "Olet onnistuneesti lähettänyt sähköpostikutsun seuraaviin osoitteisiin:", "Send_invitation_email_warning" : "Lähettääksesi sähköpostikutsuja, sinun täytyy ensin tehdä SMTP asetukset.", @@ -299,7 +354,14 @@ "Silence" : "Hiljaisuus", "since_creation" : "%s saakka", "Site_Name" : "Sivuston nimi:", + "Site_Url" : "Sivuston URL-osoite", + "Site_Url_Description" : "Esimerkiksi: https://chat.domain.com/", "SAML" : "SAML", + "SAML_Custom_Cert" : "Custom sertifikaatti", + "SAML_Custom_Entry_point" : "Custom Entry Point", + "SAML_Custom_Generate_Username" : "Generoi käyttäjätunnus", + "SAML_Custom_Issuer" : "Custom Issuer", + "SAML_Custom_Provider" : "Custom Provider", "SMTP" : "SMTP", "SMTP_Host" : "SMTP-palvelin", "SMTP_Password" : "SMTP Salasana", @@ -338,6 +400,8 @@ "The_field_is_required" : "Kenttä %s vaaditaan.", "True" : "Kyllä", "Unnamed" : "Nimetön", + "Unread_Rooms" : "Lukemattomia", + "Unread_Rooms_Mode" : "Lukemattomien tila", "Upload_file_question" : "Lähetä tiedosto?", "Use_Emojis" : "Käytä Emojia", "Use_initials_avatar" : "Käytä käyttäjätunnuksen nimikirjaimia", @@ -345,12 +409,14 @@ "Use_service_avatar" : "Käytä %s avataria", "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_added" : "Käyttäjä <em>__user_added__</em> lisätty.", "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", + "Username_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut käyttäjätunnuksen vaihtamismahdollisuuden", "User_has_been_deactivated" : "Käyttäjä on deaktivoitu", - "User_has_been_deleted" : "Käyttä", + "User_has_been_deleted" : "Käyttäjä on poistettu", "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", @@ -358,12 +424,13 @@ "User_joined_channel" : "Liittyi kanavalle.", "User_joined_channel_female" : "Liittyi kanavalle.", "User_joined_channel_male" : "Liittyi kanavalle.", - "User_left" : "Käyttäjä <em>__user_left__</em> poistui.", - "User_left_female" : "Käyttäjä <em>__user_left__</em> poistui.", - "User_left_male" : "Käyttäjä <em>__user_left__</em> poistui.", + "User_left" : "Käyttäjä poistui kanavalta.", + "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_not_found_or_incorrect_password" : "Käyttäjää ei löydy tai väärä salasana", "User_removed_by" : "Käyttäjä <em>__user_removed__</em> poistettu <em>__user_by__</em> toimesta.", - "User_Settings" : "Käyttäjä", + "User_Settings" : "Käyttäjän asetukset", "User_updated_successfully" : "Käyttäjän tiedot päivitetty", "Users" : "Käyttäjät", "Username" : "Käyttäjänimi", @@ -380,9 +447,10 @@ "Welcome_to_the" : "Tervetuloa", "With_whom" : "kanssa", "Yes_delete_it" : "Kyllä, poista!", + "Yes_clear_all" : "Jep, tyhjennä kaikki!", "you_are_in_preview_mode_of" : "Tämä on kanavan #<strong>__room_name__</strong> esikatselutila", "You_need_confirm_email" : "Sinun tulee vahvistaa sähköpostiosoitteesi!", - "You_will_not_be_able_to_recover" : "Palauttaminen ei ole mahdollista!", + "You_will_not_be_able_to_recover" : "Viestin palauttaminen ei ole mahdollista!", "Your_entry_has_been_deleted" : "Your entry has been deleted.", "Your_Open_Source_solution" : "Your own Open Source chat solution" } \ No newline at end of file diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index a8a768a01ca..0c1046c4a71 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -391,4 +391,4 @@ "You_will_not_be_able_to_recover" : "Cette action n'est pas réversible !", "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/hr.i18n.json b/i18n/hr.i18n.json index c323f9c37d8..439b5db8e47 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -2,6 +2,9 @@ "Access_online_demo" : "Pristupi online demonstraciji", "Access_Online_Demo" : "Pristupi Online demonstraciji", "Accounts" : "RaÄuni", + "Accounts_AllowUsernameChange" : "Dopusti promjenu korisniÄkog imena", + "Accounts_AllowPasswordChange" : "Dopusti promjenu lozinke", + "Accounts_AvatarSize" : "VeliÄina Avatara", "Accounts_denyUnverifiedEmail" : "Odbij neprovjereni e-mail", "Accounts_EmailVerification" : "E-mail Verifikacija", "Accounts_OAuth_Facebook" : "Facebook prijava", @@ -61,6 +64,7 @@ "days" : "dana", "Deactivate" : "IskljuÄi", "Delete_User_Warning" : "Brisanje korisnika će izbrisati i sve poruke od tog korisnika. Ovo se ne može poniÅ¡titi.", + "Delete_Room_Warning" : "Brisanje sobe će obrisati sve poruke u toj sobi. Ovo se ne može poniÅ¡titi.", "Delete" : "ObriÅ¡i", "Deleted" : "Obrisano!", "Direct_Messages" : "Izravne Poruke", @@ -93,7 +97,9 @@ "Hide_room" : "Sakrij sobu", "History" : "Povijest", "hours" : "sati", + "Incorrect_Password" : "NetoÄna lozinka", "inline_code" : "jednolinijski kôd", + "Install_FxOs" : "Instalirajte Rocket.Chat na svoj Firefox", "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", @@ -148,6 +154,7 @@ "Message_pinned" : "Poruka je pribodena", "Message_ShowDeletedStatus" : "Pokaži Izbrisan status", "Message_ShowEditedStatus" : "Prikaži ureÄ‘eni status", + "Messages" : "Poruke", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook App-ID", "Meta_language" : "Jezik", @@ -176,6 +183,7 @@ "Not_found_or_not_allowed" : "Nije NaÄ‘eno ili Nije Dozvoljeno", "Nothing_found" : "NiÅ¡ta nije naÄ‘eno", "Notify_all_in_this_room" : "Obavijesti sve u ovoj sobi", + "Old_Password" : "Stara Lozinka", "Only_you_can_see_this_message" : "Samo ti možeÅ¡ vidjeti ovu poruku", "Online" : "Online", "Oops!" : "Ups", @@ -183,6 +191,8 @@ "others" : "drugi", "Password" : "Lozinka", "Password_changed_successfully" : "Lozinka je uspjeÅ¡no promijenjena", + "Password_Change_Disabled" : "VaÅ¡ Rocket.Chat Administrator je onemogućio izmjenu lozinke", + "People" : "Ljudi", "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.", @@ -211,6 +221,8 @@ "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", + "Room_uploaded_file_list" : "Popis datoteka", + "Room_uploaded_file_list_empty" : "Nijedna datoteka nije dostupna", "room_user_count" : "% korisnika", "Rooms" : "Sobe", "Save" : "SaÄuvaj", @@ -239,6 +251,7 @@ "Silence" : "TiÅ¡ina", "since_creation" : "%s", "Site_Name" : "Ime Stranice:", + "SAML_Custom_Generate_Username" : "Izradi korisniÄko ime", "SMTP_Password" : "SMTP lozinka", "SMTP_Port" : "SMTP port", "SMTP_Username" : "SMTP korisniÄko ime", @@ -279,6 +292,7 @@ "User_added_by" : "Korisnik <em>__user_added__</em> dodan od <em>__user_by__</em>.", "User_Channels" : "KorisniÄki kanali", "User_has_been_activated" : "Korisnik je aktiviran", + "Username_Change_Disabled" : "VaÅ¡ Rocket.Chat Administrator je onemogućio izmjenu korisniÄkih imena", "User_has_been_deactivated" : "Korisnik je deaktiviran", "User_has_been_deleted" : "Korisnik je obrisan", "User_Info" : "Podaci o korisniku", @@ -292,6 +306,7 @@ "User_left_female" : "Korisnica <em>__user_left__</em> je otiÅ¡la.", "User_left_male" : "Korisnik <em>__user_left__</em> je otiÅ¡ao.", "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_Settings" : "KorisniÄke postavke", "User_updated_successfully" : "Korisnik je uspjeÅ¡no ažuriran", diff --git a/i18n/it.i18n.json b/i18n/it.i18n.json index 123e7892a29..f11784d932a 100644 --- a/i18n/it.i18n.json +++ b/i18n/it.i18n.json @@ -127,4 +127,4 @@ "Welcome_to_the" : "Benvenuto a", "You_need_confirm_email" : "Hai bisogno di confermare il tuo email per accedere!", "Your_Open_Source_solution" : "La tua soluzione per chat Open Source" -} +} \ No newline at end of file diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 8630369cc99..e12c2f83d1f 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -2,6 +2,13 @@ "Access_online_demo" : "ចូល​ទៅ​សាក​ល្បងវា​លើ​អ៊ីនធើណិážâ€‹áž‡áž¶â€‹áž˜áž»áž“​សិន", "Access_Online_Demo" : "ចូល​ទៅ​សាក​ល្បងវា​លើ​អ៊ីនធើណិážâ€‹áž‡áž¶â€‹áž˜áž»áž“​សិន", "Accounts" : "គណនី", + "Accounts_AllowedDomainsList" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែង Domain ដែលអនុញ្ញាážáž·áž€áŸ’នុងបញ្ជី", + "Accounts_AllowUsernameChange" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹ážˆáŸ’មោះ​អ្នក​ប្រើ", + "Accounts_AllowPasswordChange" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹áž–ាក្យ​សម្ងាážáŸ‹", + "Accounts_AvatarResize" : "ប្ážáž¼â€‹ážšâ€‹áž‘ំហំ Avatar", + "Accounts_AvatarSize" : "ទំហំ Avatar", + "Accounts_AvatarStorePath" : "ទីážáž¶áŸ†áž„ផ្ទុក Avatar", + "Accounts_AvatarStoreType" : "ប្រភáŸáž‘បន្ទុក Avatar", "Accounts_denyUnverifiedEmail" : "រាំងážáŸ’ទប់អ្នកមិនបានផ្ទៀážáž•áŸ’ទាážáŸ‹áž¢áŸŠáž¸áž˜áŸ‚áž›", "Accounts_EmailVerification" : "ការ​ផ្ទៀងផ្ទាážáŸ‹â€‹ážáž¶áž˜â€‹â€‹áž¢áŸŠáž¸â€‹áž˜áŸ‰áŸ‚​ល", "Accounts_OAuth_Facebook" : "ចូល​ážáž¶áž˜â€‹áž ្វáŸážŸáž”៊ូក", @@ -10,6 +17,9 @@ "Accounts_OAuth_Github" : "ចូល​ážáž¶áž˜ Github", "Accounts_OAuth_Github_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ GitHub", "Accounts_OAuth_Github_secret" : "GitHub សម្ងាážáŸ‹", + "Accounts_OAuth_Gitlab" : "OAuth បានអនុញ្ញាážáž·", + "Accounts_OAuth_Gitlab_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Gitlab", + "Accounts_OAuth_Gitlab_secret" : "Client សម្ងាážáŸ‹", "Accounts_OAuth_Google" : "ចូល​ážáž¶áž˜ Google", "Accounts_OAuth_Google_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ Google", "Accounts_OAuth_Google_secret" : "Google សម្ងាážáŸ‹", @@ -71,6 +81,7 @@ "Channels" : "ប៉ុស្ážáž·áŸ", "Channels_list" : "បណ្ážáž¶áž”៉ុស្ážáž·áŸâ€‹ážŸáž¶áž’ារណៈ", "Chat_Rooms" : "បន្ទប់​ពិភាក្សា", + "Clear_all_unreads_question" : "ចង់ជម្រះចោលគ្រប់សារមិនបានអានឬ?", "close" : "បិទ", "coming_soon" : "មក​ដល់​ឆាប់ៗ", "Commands" : "ឃ្លាបញ្ជា", @@ -89,6 +100,7 @@ "days" : "ážáŸ’ងៃ", "Deactivate" : "ធ្វើឲ្យមិនសកម្ម", "Delete_User_Warning" : "ការ​លប់​អ្នក​ប្រើប្រាស់ នឹង​ážáŸ’រូវ​លប់​​គ្រប់​សារ​​របស់​​គាážáŸ‹â€‹áž•áž„​ដែរ។ ដូច​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ធ្វើ​បាន​ទ០។", + "Delete_Room_Warning" : "ការលប់បន្ទប់មួយនឹងážáŸ’រូវលប់ចោលទាំងអស់នូវរាល់សារដែលបានប្រកាសនៅក្នុងបន្ទប់នáŸáŸ‡, ដំណើរការនáŸáŸ‡áž˜áž·áž“ទាន់បានបញ្ចប់ទáŸ", "Delete" : "លុប", "Deleted" : "បាន​លប់!", "Desktop_Notifications" : "ជំនូនដំណឹងលើ Desktop", @@ -120,6 +132,7 @@ "FileUpload_Enabled" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្ទុក​ឡើង​ឯកសារ", "FileUpload_MaxFileSize" : "ទំហំអážáž·áž”រិមាកំណážáŸ‹ážŸáž˜áŸ’រាប់ការផ្ទុកឡើយឯកសារ(áž‚áž¹ážáž‡áž¶áž”ៃ)", "FileUpload_MediaTypeWhiteList" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែកបញ្ជីប្រភáŸáž‘មáŸážŒáŸ€", + "FileUpload_MediaTypeWhiteListDescription" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែងប្រភáŸáž‘ Media ក្នុងបញ្ជី", "Follow_social_profiles" : "ážáž¶áž˜â€‹ážŠáž¶áž“​​​បណ្ážáž¶â€‹áž‚ណនីបណ្ážáž¶áž‰â€‹ážŸáž„្គម​របស់​យើង​, មើល​យើង​លើ​ github និង​ចែក​រំលែក​បទពិសោធនáŸâ€‹ážšáž”ស់​អ្នក​ជាមួយ​ rocket.chat app នៅ​លើ​ក្ážáž¶ážšážƒáŸ€áž“​របស់​យើង", "Forgot_password" : "ភ្លáŸáž…​ពាក្យ​សម្ងាážáŸ‹", "Fork_it_on_github" : "ទៅ​មើល​វា​លើ github", @@ -135,6 +148,10 @@ "hours" : "ម៉ោង", "Incorrect_Password" : "ឃ្លាសំងាážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ", "inline_code" : "inline_code", + "Install_FxOs" : "ដំឡើង Rocket.Chat នៅ​លើ Firefox របស់​អ្នក", + "Install_FxOs_follow_instructions" : "សូមបញ្ជាក់ការដំឡើងកម្មវិធីនáŸáŸ‡áž“ៅលើឧបករណáŸážšáž”ស់អ្នក(ចុច \"Install\" áž–áŸáž›áž”ញ្ចាក់)", + "Install_FxOs_done" : "អស្ចារ្យណាស់ឥឡូវអ្នកអាចប្រើប្រាស់ Rocket.Chat ážáž¶áž˜ážšáž™áŸˆ Icon នៅលើ Homescreen។ សូមរីករាយជាមួយ Rocket.Chat!", + "Install_FxOs_error" : "សុំទោស ដែលវាមិនដំណើរការážážŽáŸˆáž˜áž¶áž“បញ្ហាលáŸáž…ឡើងដូចážáž¶áž„ក្រោម", "Invalid_confirm_pass" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ញ្ជាក់​មិន​ដូច​ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​បញ្ចូល​", "Invalid_email" : "អ៊ី​មែល​ដែល​បញ្ចូល​មិន​ážáŸ’រឹម​ážáŸ’រូវ", "Invalid_name" : "ឈ្មោះ​មិន​​អាច​ទំនáŸážš", @@ -168,8 +185,11 @@ "Layout_Sidenav_Footer_description" : "​ទំហំ​បាន​គឺ 260x70", "Layout_Terms_of_Service" : "áž›áŸáž€áŸ’ážážáŸážŽáŸ’ឌ​នៃ​សáŸážœáž¶áž€áž˜áŸ’ម", "LDAP" : "ប្រើ LDAP", + "LDAP_Bind_Search" : "ចំណងស្វែងរក", "LDAP_DN" : " LDAP DN", + "LDAP_Enable" : "អនុញ្ញាážáž· LDAP", "LDAP_Port" : "ច្រក LDAP", + "LDAP_Sync_User_Data" : "រក្សាទិន្ននáŸáž™ User ដោយ Sync ជាមួយ Server", "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", @@ -190,6 +210,7 @@ "Message_AllowDeleting" : "អនុញ្ញាážâ€‹áž±áŸ’យ​មាន​ការ​លុប​សារ", "Message_AllowEditing" : "អនុញ្ញាážâ€‹áž±áŸ’យ​មាន​ការ​កែ​សម្រួល​សារ", "Message_AllowEditing_BlockEditInMinutes" : "បិទការកែស្រួលសារបន្ទាប់ (ជាចំនួននាទី ឬ0ដើម្បីបិទចោល)", + "Message_AllowEditing_BlockEditInMinutesDescription" : "បញ្ចូលលáŸáž 0 ដើម្បីបិទការ Block", "Message_AudioRecorderEnabled" : "ការážážážŸáž˜áŸ’áž›áŸáž„បានអនុញ្ញាážáž·", "Message_deleting_not_allowed" : "ការ​លប់សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", "Message_editing_not_allowed" : "ការ​កែ​សម្រួល​សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", @@ -244,10 +265,12 @@ "others" : "ផ្សáŸáž„ៗ", "Password" : "ពាក្យ​សម្ងាážáŸ‹", "Password_changed_successfully" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​ប្ážáž¼ážšâ€‹áž‡áŸ„គជáŸáž™", + "Password_Change_Disabled" : "សិទ្ធជាអ្នកគ្រប់គ្រង Rocket.Chat ážáŸ’រូវបានបិទមិនឲ្យប្ážáž¼ážšáž–ាក្យសម្ងាážáŸ‹áž¡áž¾áž™", "People" : "មនុស្ស", "Please_wait" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់​ចាំ", "Please_wait_activation" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់​ចាំ ការងារ​នáŸáŸ‡â€‹ážáŸ’រូវ​ចំណាយ​ពáŸáž›â€‹áž”ន្ážáž·áž…", "Please_wait_statistics" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់ចាំ ស្ážáž·ážáž·â€‹áž‚ឺ​កំពុង​គណនា", + "Please_enter_value_for_url" : "សូមបញ្ចូលážáž˜áŸ’លៃរបស់ URL នៃ Avatar របស់អ្នក", "Powered_by" : "រក្សាសិទ្ធិ​ដោយ", "Preferences" : "ចំណង់​ចំណូល​ចិážáŸ’áž", "Preferences_saved" : "ចំណង់​ចំណូល​ចិážáŸ’ážâ€‹ážŠáŸ‚ល​បាន​រក្សាទុក", @@ -317,6 +340,8 @@ "Site_Url" : "ážáŸ†áž”ន់ URL", "Site_Url_Description" : "ឧទាហរណáŸáŸ– https://chat.domain.com/", "SAML" : "ប្រើ SAML", + "SAML_Custom_Cert" : "វិញ្ញាបនបážáŸ’រ​ផ្ទាល់ážáŸ’លួន", + "SAML_Custom_Generate_Username" : "គណនាឈ្មោះអ្នកប្រើប្រាស់", "SMTP" : "ពិធីការ SMTP", "SMTP_Host" : "ម៉ាស៊ីន SMTP", "SMTP_Password" : "ឃ្លា​សម្ងាážáŸ‹ SMTP", @@ -360,10 +385,12 @@ "Use_service_avatar" : "ប្រើ %s រូប", "Use_this_username" : "ប្រើ​ឈ្មោះ​នáŸáŸ‡", "Use_uploaded_avatar" : "ប្រើ​រូប​បាន​ផ្ទុក​ឡើង", + "Use_url_for_avatar" : "ប្រើប្រាស់ URL សម្រាប់ Avatar", "User_added" : "អ្នក​ប្រើ <em>__user_added__</em> បាន​បន្ážáŸ‚ម", "User_added_by" : "អ្នក​ប្រើ <em>__user_added__</em> បាន​ážáŸ‚ម​ដោយ <em>__user_by__</em>.", "User_Channels" : "ប៉ុស្ážáž·áŸáž¢áŸ’នកប្រើប្រាស់", "User_has_been_activated" : "អ្នក​ប្រើ​ដែល​បាន​ធ្វើ​ឱ្យ​សកម្ម", + "Username_Change_Disabled" : "សិទ្ធជាអ្នកគ្រប់គ្រង Rocket.Chat ážáŸ’រូវបានបិទមិនឲ្យប្ážáž¼ážšážˆáŸ’មោះអ្នកប្រើប្រាស់ឡើយ", "User_has_been_deactivated" : "អ្នក​ប្រើ​ដែល​ážáŸ’រូវ​បាន​ធ្វើ​ឱ្យ​អសកម្ម", "User_has_been_deleted" : "អ្នក​ប្រើប្រាស់​ដែល​បាន​លប់", "User_Info" : "áž–áŸážâ€‹áž˜áž¶áž“​របស់​អ្នក​ប្រើ", @@ -396,6 +423,7 @@ "Welcome_to_the" : "ស្វាគមនáŸâ€‹áž˜áž€â€‹áž€áž¶áž“់", "With_whom" : "ជា​មួយ​នរណា", "Yes_delete_it" : "បាទ លប់​វា!", + "Yes_clear_all" : "បាទ, សម្អាážáž…ោលទាំងអស់", "you_are_in_preview_mode_of" : "អ្នក​ស្ážáž·ážâ€‹áž€áŸ’នុង​ទម្រង់​មើល​ជា​មុន​នៃ​ប៉ុស្ážáž·áŸ #<strong>__room_name__</strong>", "You_need_confirm_email" : "អ្នក​ážáŸ’រូវ​បញ្ជាក់អ៊ីមែល​ដើម្បី​ឡុកចូល!", "You_will_not_be_able_to_recover" : "អ្នក​នឹង​មិនអាច​ទាញ​មក​វិញ!", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 86ca15e2301..8bafffc9e7f 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -67,6 +67,7 @@ "close" : "tutup", "coming_soon" : "akan datang", "Commands" : "Arahan", + "Compact_View" : "Paparan Kompak", "Confirm_password" : "Sahkan kata laluan anda", "Contact" : "Hubungi", "Conversation" : "Perbualan", @@ -105,11 +106,15 @@ "Esc_to" : "Esc untuk", "False" : "Lumpuhkan", "Favorites" : "Kegemaran", + "FileUpload" : "Muat Naik Fail", + "FileUpload_Enabled" : "Naik Fail Diaktifkan", + "FileUpload_MaxFileSize" : "Fail muat naik saiz Maksimum (dalam bytes)", "Forgot_password" : "Lupa kata laluan anda", "Fork_it_on_github" : "Mencabang pada github", "From_Email" : "Daripada E-mel", "General" : "Umum", "Get_to_know_the_team" : "Kenali Rocket.Team", + "github_no_public_email" : "Anda tidak mempunyai sebarang e-mel umum pada akaun GitHub anda", "Has_more" : "Ada lagi", "Hide_room" : "Menyembunyikan bilik", "History" : "Sejarah", @@ -169,6 +174,7 @@ "Message_AllowDeleting" : "Benarkan Pemadaman Mesej", "Message_AllowEditing" : "Benarkan Penyuntingan Mesej", "Message_AllowEditing_BlockEditInMinutes" : "Sekat penyuntingan mesej selepas (dalam minit - 0 hingga melumpuhkan)", + "Message_AudioRecorderEnabled" : "Perakam Audio Diaktifkan", "Message_deleting_not_allowed" : "Pemadaman mesej tidak dibenarkan", "Message_editing_not_allowed" : "Penyuntingan mesej tidak dibenarkan", "Message_editing_blocked" : "Mesej ini tidak boleh lagi disunting", @@ -178,6 +184,7 @@ "Message_pinned" : "Mesej dipinkan", "Message_ShowDeletedStatus" : "Tunjuk Status Pemadaman", "Message_ShowEditedStatus" : "Tunjuk Status Penyuntingan", + "Message_ShowFormattingTips" : "Tunjuk Tip Pemformatan", "Messages" : "Mesej", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", @@ -241,6 +248,7 @@ "Push_enable" : "Aktifkan", "Push_production" : "Penerbitan", "Quick_Search" : "Carian Pantas", + "Recents" : "baru-baru ini", "Record" : "Rakam", "Register" : "Mendaftar akaun baru", "Registration_Succeeded" : "Pendaftaran Berjaya", @@ -329,6 +337,7 @@ "Use_service_avatar" : "Guna %s avatar", "Use_this_username" : "Guna nama pengguna ini", "Use_uploaded_avatar" : "Guna avatar yang dimuat naik", + "Use_url_for_avatar" : "Guna url untuk avatar", "User_added" : "Pengguna <em>__user_added__</em> ditambah.", "User_added_by" : "Pengguna <em>__user_added__</em> ditambah oleh <em>__user_by__</em>.", "User_Channels" : "Saluran Pengguna", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 6264e3c458a..8b257039aa2 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -3,6 +3,9 @@ "Access_Online_Demo" : "Acesse o Demo Online", "Accounts" : "Contas", "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", + "Accounts_AllowUsernameChange" : "Permitir alterar usuário", + "Accounts_AvatarResize" : "Redimensionar Avatares", + "Accounts_AvatarSize" : "Tamanho do Avatar", "Accounts_denyUnverifiedEmail" : "Proibir e-mail não verificado", "Accounts_EmailVerification" : "Verificação de E-mail", "Accounts_OAuth_Facebook" : "Login do Facebook", @@ -11,6 +14,7 @@ "Accounts_OAuth_Github" : "Login do GitHub", "Accounts_OAuth_Github_id" : "GitHub Id", "Accounts_OAuth_Github_secret" : "GitHub Secret", + "Accounts_OAuth_Gitlab_id" : "Gitlab Id", "Accounts_OAuth_Google" : "Login do Google", "Accounts_OAuth_Google_id" : "Google Id", "Accounts_OAuth_Google_secret" : "Google Secret", @@ -360,8 +364,8 @@ "The_field_is_required" : "O campo %s é obrigatório.", "True" : "Verdadeiro", "Unnamed" : "Sem nome", - "Unread_Rooms": "Não Lidas", - "Unread_Rooms_Mode": "Agrupar Salas Não Lidas", + "Unread_Rooms" : "Não Lidas", + "Unread_Rooms_Mode" : "Agrupar Salas Não Lidas", "Upload_file_question" : "Enviar arquivo?", "Use_Emojis" : "Usar Emojis", "Use_initials_avatar" : "Usar as iniciais do seu nome de usuário", @@ -410,4 +414,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} +} \ No newline at end of file diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 5b683bd48d6..1cb2a8f913f 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -6,6 +6,11 @@ "Accounts_OAuth_Google_id" : "Google ID", "Accounts_OAuth_Google_secret" : "Google пароль", "Accounts_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", + "Accounts_OAuth_Custom_Secret" : "Ключ", + "Accounts_OAuth_Custom_Enable" : "Включить", + "Accounts_OAuth_Custom_Button_Label_Text" : "ТекÑÑ‚ кнопки", + "Accounts_OAuth_Custom_Button_Label_Color" : "Цвет текÑта кнопки", + "Accounts_OAuth_Custom_Button_Color" : "Цвет кнопки", "Add_Members" : "Добавить Пользователей", "Add_users" : "Добавить пользователей", "All_channels" : "Ð’Ñе Чаты", @@ -21,6 +26,7 @@ "Away_female" : "Отошла", "away_male" : "отошёл", "Away_male" : "Отошёл", + "Auto_Load_Images" : "Ðвтозагрузка изображений", "Back_to_login" : "Ðа Ñтраницу авторизации", "bold" : "жирный", "busy" : "занÑÑ‚", @@ -36,6 +42,7 @@ "Chat_Rooms" : "Чаты", "close" : "закрыть", "coming_soon" : "в разработке", + "Compact_View" : "Компактный вид", "Confirm_password" : "Подтвердить пароль", "Contact" : "Контакт", "Conversation" : "Диалог", @@ -43,7 +50,9 @@ "Create_new_private_group" : "Создать новый приватный чат", "Create_new_public_channel" : "Создать новый публичный чат", "Created_at" : "Создано в", + "days" : "дней", "Deleted" : "Удалено!", + "Desktop_Notifications_Enabled" : "Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ Ñтола включены", "Direct_Messages" : "Личные ÑообщениÑ", "Drop_to_upload_file" : "ПеремеÑтите Ñюда Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ файла", "Duplicate_channel_name" : "Канал Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%s' ÑущеÑтвует", @@ -53,13 +62,15 @@ "Email_already_exists" : "Ðл. Ð°Ð´Ñ€ÐµÑ ÑƒÐ¶Ðµ ÑущеÑтвует", "Email_or_username" : "Почтовый Ñщик или логин", "Email_verified" : "Ðлектронный Ð°Ð´Ñ€ÐµÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐµÐ½", - "Enter_info" : "ÐвторизациÑ", + "Enable_Desktop_Notifications" : "Включить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ Ñтола", + "Enter_info" : "Введите Ñвои данные", "Error_changing_password" : "Ошибка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ", "Favorites" : "Избранные чаты", "Follow_social_profiles" : "ДобавлÑйте Ð½Ð°Ñ Ð² Ð´Ñ€ÑƒÐ·ÑŒÑ Ð² Ñоциальных ÑетÑÑ…, форкайте на github и пишите Ñвои отзывы о нашем приложении у Ð½Ð°Ñ Ð² trello.", "Forgot_password" : "Забыли пароль?", "Fork_it_on_github" : "Форкайте на github", "github_no_public_email" : "Ð’ наÑтройках GitHub отÑутÑтвует публично доÑтупный e-mail", + "Has_more" : "Еще", "Hide_room" : "Скрыть чат", "History" : "ИÑториÑ", "hours" : "чаÑ(Ñ‹)", @@ -71,6 +82,7 @@ "Invalid_room_name" : "<strong>%s</strong> недопуÑтимое Ð¸Ð¼Ñ ÐºÐ¾Ð¼Ð½Ð°Ñ‚Ñ‹, <br/> допуÑтимые Ñимволы: цифры, подчеркивание и буквы.", "invisible" : "невидимый", "Invisible" : "Ðевидимый", + "Invite_Users" : "ПриглаÑить пользователей", "is_also_typing" : "вÑе ещё печатает", "is_also_typing_female" : "вÑе ещё печатает", "is_also_typing_male" : "вÑе ещё печатает", @@ -83,12 +95,15 @@ "Language" : "Язык", "Language_Version" : "РуÑÑÐºÐ°Ñ Ð²ÐµÑ€ÑиÑ", "Last_message" : "ПоÑледнее Ñообщение", + "Layout_Privacy_Policy" : "Политика конфиденциальноÑти", + "Layout_Terms_of_Service" : "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ÑпользованиÑ", "LDAP_DN" : "LDAP домен", "LDAP_Port" : "LDAP Порт", "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Leave_room" : "Покинуть чат", "line" : "линиÑ", "Load_more" : "Загрузить еще", + "Loading_more_from_history" : "Загрузка еще из иÑтории", "Loading..." : "Загрузка...", "Loading_suggestion" : "Загрузка предпочтений...", "Login" : "Войти", @@ -96,6 +111,7 @@ "login_with" : "ÐÐ²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ·", "Logout" : "Выйти", "Make_Admin" : "Сделать админиÑтратором", + "Mark_as_read" : "пометить как прочитанное", "Members" : "УчаÑтники", "Members_List" : "СпиÑок учаÑтников", "Members_placeholder" : "УчаÑтники", @@ -106,9 +122,11 @@ "Message_removed" : "Сообщение удалено", "Message_ShowDeletedStatus" : "Отображать ÑÑ‚Ð°Ñ‚ÑƒÑ \"Удалено\"", "Message_ShowEditedStatus" : "Отображать ÑÑ‚Ð°Ñ‚ÑƒÑ \"Отредактировано\"", + "Messages" : "СообщениÑ", "Meta_language" : "Язык", "minutes" : "минут(Ñ‹)", "More_channels" : "Другие чаты", + "More_unreads" : "Еще непрочитанные", "Msgs" : "СообщениÑ", "multi" : "много", "My_Account" : "Мой аккаунт", @@ -138,6 +156,8 @@ "Please_wait_activation" : "ПожалуйÑта, подождите, Ñто может занÑÑ‚ÑŒ некоторое времÑ.", "Please_wait_statistics" : "ПожалуйÑта, подождите, ÑтатиÑтика генерируютÑÑ.", "Powered_by" : "Реализовано на", + "Preferences" : "ÐаÑтройки", + "Preferences_saved" : "ÐаÑтройки Ñохранены", "Privacy" : "ПриватноÑÑ‚ÑŒ", "Private_Groups" : "Приватные чаты", "Profile" : "Профиль", @@ -161,6 +181,7 @@ "Save" : "Сохранить", "Save_changes" : "Сохранить изменениÑ", "Search" : "ПоиÑк", + "Search_Messages" : "ПоиÑк Ñообщений", "Search_settings" : "ÐаÑтройки поиÑка", "seconds" : "Ñекунд(Ñ‹)", "See_all" : "К общему ÑпиÑку", @@ -168,7 +189,9 @@ "Select_an_avatar" : "Выбор автара", "Select_file" : "Выберите файл", "Selected_users" : "Выбранные учаÑтники", + "Send" : "ПоÑлать", "Send_confirmation_email" : "Отправить пиÑьмо Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸ÐµÐ¼", + "Send_invitation_email" : "Отправить приглашение по Ñлектронной почте", "Send_Message" : "Отправить Ñообщение", "Settings" : "ÐаÑтройки", "Settings_updated" : "ÐаÑтройки обновлены", @@ -176,9 +199,11 @@ "Showing_results" : "<p>Отображено <b>%s</b> результатов</p>", "Silence" : "Тишина", "since_creation" : "Ñ %s", + "Site_Name" : "Ðазвание Ñайта", "SMTP_Password" : "Пароль SMTP", "SMTP_Port" : "SMTP Порт", "SMTP_Username" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ SMTP-", + "Sound" : "Звук", "Start_of_conversation" : "Ðачать диалог", "Stats_Active_Users" : "Ðктивные пользователи", "Stats_Non_Active_Users" : "Ðеактивные пользователи", @@ -193,9 +218,11 @@ "Stats_OS_Type" : "Тип СиÑтемы", "Stats_OS_Uptime" : "Ðптайм ÑиÑтемы", "Stats_Total_Channels" : "Общее кол-во каналов", + "Stats_Total_Messages" : "Ð’Ñего Ñообщений", "Stats_Total_Users" : "Ð’Ñего пользователей", "Submit" : "Отправить", "The_field_is_required" : "Поле %s обÑзательно.", + "True" : "ИÑтина", "Upload_file_question" : "Загрузить файл?", "Use_initials_avatar" : "ИÑпользовать Ñтандартный аватар", "use_menu" : "ИÑпользуйте боковое меню Ð´Ð»Ñ Ð´Ð¾Ñтупа к вашим ÑообщениÑм и чатам", @@ -204,9 +231,11 @@ "Use_uploaded_avatar" : "ИÑпользовать загруженную аватарку", "User_added" : "Пользователь <em>__user_added__</em> добавлен.", "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" : "Пользователь теперь админиÑтратор", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 345683fceeb..959b8388524 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -52,10 +52,12 @@ "Created_at" : "OluÅŸturulma saati", "days" : "gün", "Delete_User_Warning" : "Bu kullanıcıyı silerseniz tüm mesajları da beraberinde silinecektir! Bu iÅŸlemi bir daha geri alamazsınız.", + "Delete" : "Sil", "Deleted" : "SilinmiÅŸ!", "Direct_Messages" : "Direkt Mesajlar", "Drop_to_upload_file" : "Dosya yüklemek için sürükle", "E-mail" : "E-posta", + "Edit" : "Düzenle", "edited" : "düzenlendi", "Email_already_exists" : "Bu e-posta zaten var", "Email_or_username" : "E-posta ya da kullanıcı adı", @@ -139,6 +141,7 @@ "Not_allowed" : "Izin verilmedi", "Not_found_or_not_allowed" : "Bulunamadı veya izin verilmiyor", "Nothing_found" : "Bulunamadı", + "Notify_all_in_this_room" : "Bu odadaki tüm bildirimleri göster", "Online" : "Çevrimiçi", "Oops!" : "Hata", "others" : "DiÄŸerleri", @@ -178,6 +181,7 @@ "Save" : "Kaydet", "Save_changes" : "DeÄŸiÅŸiklikleri kaydet", "Search" : "Ara", + "Search_Messages" : "Mesajlarda ara", "Search_settings" : "Arama ayarları", "seconds" : "saniye", "See_all" : "Tümünü gör", @@ -194,6 +198,7 @@ "Showing_results" : "<p> <b>%s</b> kayıt bulundu</p>", "Silence" : "Sessizlik", "since_creation" : "tarih %s", + "Site_Name" : "Site adı", "SMTP_Host" : "SMTP Sunucusu", "SMTP_Password" : "SMTP Åžifre", "SMTP_Port" : "SMTP BaÄŸlantı Noktası(Port)", @@ -214,6 +219,7 @@ "Stats_OS_Type" : "Ä°ÅŸletim Sistemi Tipi", "Stats_Total_Channels" : "Toplam Kanal", "Stats_Total_Direct_Messages" : "Toplam Direkt Mesajlar", + "Stats_Total_Messages" : "Toplam Ä°leti", "Stats_Total_Private_Groups" : "Toplam Özel Gruplar", "Stats_Total_Rooms" : "Toplam Kanal", "Stats_Total_Users" : "Toplam Kullanıcı", diff --git a/packages/rocketchat-chatops/i18n/fi.i18n.json b/packages/rocketchat-chatops/i18n/fi.i18n.json index 73d7555f644..70ebca1f53b 100644 --- a/packages/rocketchat-chatops/i18n/fi.i18n.json +++ b/packages/rocketchat-chatops/i18n/fi.i18n.json @@ -1,4 +1,5 @@ { "Chatops_Enabled" : "Ota käyttöön Chatops", - "Chatops_Title" : "Chatops paneeli" + "Chatops_Title" : "Chatops paneeli", + "Chatops_Username" : "Chatops käyttäjätunnus" } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/fi.i18n.json b/packages/rocketchat-gitlab/i18n/fi.i18n.json index ce7e0675b85..aa29615cd10 100644 --- a/packages/rocketchat-gitlab/i18n/fi.i18n.json +++ b/packages/rocketchat-gitlab/i18n/fi.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-livechat/i18n/fi.i18n.json b/packages/rocketchat-livechat/i18n/fi.i18n.json index 828c21abf53..7a2d15b05eb 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -1,4 +1,4 @@ { "Livechat_title" : "Livechat otsikko", - "Livechat_title_color" : "Livechat otsikko taustaväri" + "Livechat_title_color" : "Livechat otsikon taustaväri" } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/fi.i18n.json b/packages/rocketchat-message-star/i18n/fi.i18n.json index 6f31cf5a2e6..9eea3ddfbbf 100644 --- a/packages/rocketchat-message-star/i18n/fi.i18n.json +++ b/packages/rocketchat-message-star/i18n/fi.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Message_AllowStarring" : "Salli viesteille tähti-merkki", + "Star_Message" : "Merkkaa tähdellä", + "Unstar_Message" : "Poista tähti", + "Starred_Messages" : "Tähdellä merkityt viestit", + "No_starred_messages" : "Ei tähdellä merkittyjä viestejä" +} \ 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 6f31cf5a2e6..f57e88dc1e8 100644 --- a/packages/rocketchat-message-star/i18n/hr.i18n.json +++ b/packages/rocketchat-message-star/i18n/hr.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Unstar_Message" : "Ukloni zvjezdicu", + "Starred_Messages" : "Poruke sa zvjezdicom" +} \ 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 6f31cf5a2e6..24843cb079a 100644 --- a/packages/rocketchat-message-star/i18n/ru.i18n.json +++ b/packages/rocketchat-message-star/i18n/ru.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Star_Message" : "Оценить Ñообщение", + "Unstar_Message" : "Убрать оценку", + "Starred_Messages" : "Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ Ð¾Ñ†ÐµÐ½ÐºÐ¾Ð¹", + "No_starred_messages" : "Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð±ÐµÐ· оценки" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/tr.i18n.json b/packages/rocketchat-message-star/i18n/tr.i18n.json index 6f31cf5a2e6..4f7823db29f 100644 --- a/packages/rocketchat-message-star/i18n/tr.i18n.json +++ b/packages/rocketchat-message-star/i18n/tr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Star_Message" : "Favorilere ekle", + "Starred_Messages" : "Favori Ä°letilerim", + "No_starred_messages" : "Favori iletin yok" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json index 1622a0afad9..b455034ccb2 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/fi.i18n.json @@ -1,4 +1,5 @@ { + "Invite_user_to_join_channel" : "Kutsu käyttäjä kanavalle", "User_doesnt_exist" : "Yhtään käyttäjää ei ole olemassa nimellä `@%s`.", "Username_is_already_in_here" : "`@%s` on jo täällä." } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json index 17c66619689..40103a63b26 100644 --- a/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/fi.i18n.json @@ -1,3 +1,4 @@ { - "Channel_doesnt_exist" : "Kanavaa `#%s` ei ole olemassa." + "Channel_doesnt_exist" : "Kanavaa `#%s` ei ole olemassa.", + "Join_the_given_channel" : "Liity kanavalle" } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/de.i18n.json b/packages/rocketchat-webrtc-ib/i18n/de.i18n.json new file mode 100644 index 00000000000..332a0f2d96e --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/de.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Video-Chat", + "Remote" : "Entfernt", + "Setup" : "Einrichten", + "Stop_Video" : "Video stoppen" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/el.i18n.json b/packages/rocketchat-webrtc-ib/i18n/el.i18n.json new file mode 100644 index 00000000000..d4fd3d2608d --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/el.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Συνομιλία μÎσω βίντεο", + "Remote" : "ΑπομακÏυσμÎνο", + "Setup" : "ΡÏθμιση", + "Stop_Video" : "Σταμάτημα Βίντεο" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json b/packages/rocketchat-webrtc-ib/i18n/en.i18n.json new file mode 100644 index 00000000000..84f089985d2 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/en.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Video Chat", + "Remote" : "Remote", + "Setup" : "Setup", + "Stop_Video" : "Stop Video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/es.i18n.json b/packages/rocketchat-webrtc-ib/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json new file mode 100644 index 00000000000..ab7aed7ca7b --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Videokeskustelu", + "Remote" : "Etä", + "Setup" : "Asennus", + "Stop_Video" : "Pysäytä video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json new file mode 100644 index 00000000000..41647a551e7 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Tchat vidéo", + "Remote" : "À distance", + "Setup" : "Configuration", + "Stop_Video" : "Arrêter la vidéo" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/he.i18n.json b/packages/rocketchat-webrtc-ib/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json new file mode 100644 index 00000000000..524e429ddff --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json @@ -0,0 +1,4 @@ +{ + "Video_Chat" : "Video Chat", + "Stop_Video" : "Zaustavi Video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json b/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/it.i18n.json b/packages/rocketchat-webrtc-ib/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/km.i18n.json b/packages/rocketchat-webrtc-ib/i18n/km.i18n.json new file mode 100644 index 00000000000..98eedeb7c4d --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/km.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "ការ​ជជែក​កំសាន្ážâ€‹áž‡áž¶â€‹ážœáž¸ážŠáŸáž¢áž¼", + "Remote" : "ពី​ចម្ងាយ", + "Setup" : "ការ​ដំឡើង", + "Stop_Video" : "បញ្ឈប់​វីដáŸáž¢áž¼" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json new file mode 100644 index 00000000000..36785947aeb --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "í™”ìƒ ì±„íŒ…", + "Remote" : "ì›ê²©", + "Setup" : "ì„¤ì •", + "Stop_Video" : "í™”ìƒ ì±„íŒ… ì •ì§€" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..ac751a74fe7 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Perbualan Video", + "Remote" : "Kawalan Jauh", + "Setup" : "Persediaan", + "Stop_Video" : "Berhentikan Video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json b/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json new file mode 100644 index 00000000000..ff189e84d63 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Chat wideo", + "Remote" : "Zdalny", + "Setup" : "Opcje", + "Stop_Video" : "Zatrzymaj wideo" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json b/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json new file mode 100644 index 00000000000..f9378d46d17 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Iniciar Video", + "Remote" : "Remoto", + "Setup" : "Configurar", + "Stop_Video" : "Encerrar Video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json new file mode 100644 index 00000000000..ebedecb615d --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Видео чат", + "Remote" : "Удалённый", + "Setup" : "УÑтановить", + "Stop_Video" : "ОÑтановить видео" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json new file mode 100644 index 00000000000..c1fcf250151 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "Görüntülü Sohbet", + "Remote" : "Uzak", + "Setup" : "Kurulum", + "Stop_Video" : "Vidyoyu durdur" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json b/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json b/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json new file mode 100644 index 00000000000..efbd1904e4b --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json @@ -0,0 +1,6 @@ +{ + "Video_Chat" : "视频", + "Remote" : "远程", + "Setup" : "设置", + "Stop_Video" : "åœæ¢è§†é¢‘" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/fi.i18n.json b/packages/rocketchat-webrtc/i18n/fi.i18n.json index 6f31cf5a2e6..15ae2233e74 100644 --- a/packages/rocketchat-webrtc/i18n/fi.i18n.json +++ b/packages/rocketchat-webrtc/i18n/fi.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "Ota käyttöön julkisilla kanavilla", + "WebRTC_Enable_Direct" : "Ota käyttöön yksityisviesteissä", + "WebRTC_Enable_Private" : "Ota käyttöön privaattiryhmissä" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/hr.i18n.json b/packages/rocketchat-webrtc/i18n/hr.i18n.json index 6f31cf5a2e6..54271ccbfcc 100644 --- a/packages/rocketchat-webrtc/i18n/hr.i18n.json +++ b/packages/rocketchat-webrtc/i18n/hr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "Omogući za javne kanale", + "WebRTC_Enable_Direct" : "Omogući za izravne poruke", + "WebRTC_Enable_Private" : "Omogući za privatne kanale" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/km.i18n.json b/packages/rocketchat-webrtc/i18n/km.i18n.json index 6f31cf5a2e6..33241c7353a 100644 --- a/packages/rocketchat-webrtc/i18n/km.i18n.json +++ b/packages/rocketchat-webrtc/i18n/km.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/pt.i18n.json b/packages/rocketchat-webrtc/i18n/pt.i18n.json index 6f31cf5a2e6..a0c6d126b99 100644 --- a/packages/rocketchat-webrtc/i18n/pt.i18n.json +++ b/packages/rocketchat-webrtc/i18n/pt.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Direct" : "Ativar Mensagens Diretas" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/fi.i18n.json b/packages/rocketchat-wordpress/i18n/fi.i18n.json index 6354e336572..1cdd8e853ed 100644 --- a/packages/rocketchat-wordpress/i18n/fi.i18n.json +++ b/packages/rocketchat-wordpress/i18n/fi.i18n.json @@ -1,6 +1,6 @@ { "API_Wordpress_URL" : "WordPress URL", - "Accounts_OAuth_Wordpress" : "WordPress Kirjaudu sisään", + "Accounts_OAuth_Wordpress" : "WordPress-kirjautuminen", "Accounts_OAuth_Wordpress_id" : "WordPress ID", "Accounts_OAuth_Wordpress_secret" : "Wordpress Secret" } \ No newline at end of file -- GitLab From 1f6ee5f192fc85d758baa64899d683338d2a6e6b Mon Sep 17 00:00:00 2001 From: Zach Auclair <zach101@gmail.com> Date: Sat, 7 Nov 2015 21:30:14 -0500 Subject: [PATCH 0369/1338] refactor(models/message): split message edit attributes into sub-object This change also alters how edits are displayed both for sequential and non-sequential messages. See #1357 --- client/methods/updateMessage.coffee | 8 +++++--- client/views/app/message.coffee | 8 ++++---- client/views/app/message.html | 20 +++++++++++++------ .../server/models/Messages.coffee | 12 +++++++---- .../app/client/views/message.html | 4 ++-- .../assets/stylesheets/base.less | 13 +++++++++++- server/methods/loadHistory.coffee | 2 +- server/methods/loadMissedMessages.coffee | 2 +- server/methods/updateMessage.coffee | 6 +++--- server/stream/messages.coffee | 2 +- 10 files changed, 51 insertions(+), 26 deletions(-) diff --git a/client/methods/updateMessage.coffee b/client/methods/updateMessage.coffee index 485dcee63c2..c88fc0f6c64 100644 --- a/client/methods/updateMessage.coffee +++ b/client/methods/updateMessage.coffee @@ -23,8 +23,9 @@ Meteor.methods Tracker.nonreactive -> - message.editBy = Meteor.userId() - message.ets = new Date(Date.now() + TimeSync.serverOffset()) + message.edit = + by: Meteor.userId() + at: new Date(Date.now() + TimeSync.serverOffset()) message = RocketChat.callbacks.run 'beforeSaveMessage', message ChatMessage.update @@ -32,5 +33,6 @@ Meteor.methods 'u._id': Meteor.userId() , $set: - ets: message.ets + "edit.by": message.edit.by + "edit.at": message.edit.at msg: message.msg diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 36cf10d76bf..ce07b11fc2f 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -1,5 +1,5 @@ wasEdited = (msg) -> - msg.ets and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + msg.edit?.at? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] Template.message.helpers actions: -> return RocketChat.MessageAction.getButtons(this) @@ -51,14 +51,14 @@ Template.message.helpers edited: -> wasEdited(@) editTime: -> return "" unless wasEdited(@) - moment(@ets).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? + moment(@edit.at).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? editedBy: -> return "" unless wasEdited(@) # try to return the username of the editor, # otherwise a special "?" character that will be # rendered as a special avatar - if @editBy - user = Meteor.users.findOne(@editBy) + if @edit.by + user = Meteor.users.findOne(@edit.by) if user? user.username else diff --git a/client/views/app/message.html b/client/views/app/message.html index 377df9a12db..88d10219e75 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -3,19 +3,27 @@ <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> <a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</a> <span class="info"> - <span class="time">{{time}}</span> {{#if edited}} - <span class="edited"> - (<a - title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' + <span + title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' + class="time"> + {{time}} + </span> + <span + class="edited" + title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}'> + <i class="icon-edit"></i> + {{_ "by"}} + <a class="thumb thumb-small user-card-message" href="#" data-username="{{editedBy}}" tabindex="1"> - {{> avatar username=editedBy}} + {{> avatar username=editedBy}} </a> - {{_ "edited"}}) </span> + {{else}} + <span class="time">{{time}}</span> {{/if}} {{#if private}} <span class="private">{{_ "Only_you_can_see_this_message"}}</span> diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 9c2787eb72d..980ac8d04d0 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -3,7 +3,8 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base @_initModel 'message' @tryEnsureIndex { 'rid': 1, 'ts': 1 } - @tryEnsureIndex { 'ets': 1 }, { sparse: 1 } + @tryEnsureIndex { 'edit.at': 1 }, { sparse: 1 } + @tryEnsureIndex { 'edit.by': 1 }, { sparse: 1 } @tryEnsureIndex { 'rid': 1, 't': 1, 'u._id': 1 } @tryEnsureIndex { 'expireAt': 1 }, { expireAfterSeconds: 0 } @tryEnsureIndex { 'msg': 'text' } @@ -76,7 +77,7 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base ts: $gt: timestamp , - ets: + 'edit.at': $gt: timestamp ] @@ -96,7 +97,9 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base record = @findOneById _id record._hidden = true record.parent = record._id - record.ets = new Date() + record.edit = + at: new Date() + by: Meteor.userId() delete record._id return @insert record @@ -121,7 +124,8 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base $set: msg: '' t: 'rm' - ets: new Date() + 'edit.at': new Date() + 'edit.by': Meteor.userId() return @update query, update diff --git a/packages/rocketchat-livechat/app/client/views/message.html b/packages/rocketchat-livechat/app/client/views/message.html index 101d5ce431c..056a0cee163 100644 --- a/packages/rocketchat-livechat/app/client/views/message.html +++ b/packages/rocketchat-livechat/app/client/views/message.html @@ -1,10 +1,10 @@ <template name="message"> <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}} {{error}}" data-username="{{u.username}}" data-date="{{date}}"> - <span class="thumb" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</span> + <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> - {{#if ets}} + {{#if edit}} <span class="edited">({{_ "edited"}})</span> {{/if}} </span> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 0d7e4d701c8..c8a913a1aa3 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2454,10 +2454,18 @@ a.github-fork { height: 20px; display: inline-block; vertical-align: bottom; + .avatar { + border-radius: 50%; + } } } .info { font-size: 12px; + .edited { + border-left: 1px dotted #BAB8B8; + padding-left: 3px; + margin-left: 3px; + } } .private { margin-left: 10px; @@ -2469,7 +2477,7 @@ a.github-fork { .user { display: none; } - .thumb { + .thumb:not(.thumb-small) { display: none; } .info { @@ -2482,6 +2490,9 @@ a.github-fork { } .edited { display: block; + border-left: 0; + margin-left: 0; + padding-left: 0; } .private { display: none; diff --git a/server/methods/loadHistory.coffee b/server/methods/loadHistory.coffee index f7058298f32..266f10a9e1c 100644 --- a/server/methods/loadHistory.coffee +++ b/server/methods/loadHistory.coffee @@ -12,7 +12,7 @@ Meteor.methods limit: limit if not RocketChat.settings.get 'Message_ShowEditedStatus' - options.fields = { ets: 0 } + options.fields = { 'edit.at': 0 } if end? records = RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestamp(rid, end, options).fetch() diff --git a/server/methods/loadMissedMessages.coffee b/server/methods/loadMissedMessages.coffee index 7978c0b6224..de65bfb319a 100644 --- a/server/methods/loadMissedMessages.coffee +++ b/server/methods/loadMissedMessages.coffee @@ -11,6 +11,6 @@ Meteor.methods ts: -1 if not RocketChat.settings.get 'Message_ShowEditedStatus' - options.fields = { ets: 0 } + options.fields = { 'edit.at': 0 } return RocketChat.models.Messages.findVisibleByRoomIdAfterTimestamp(rid, start, options).fetch() diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 7e84063a814..21c8bcb4870 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -28,9 +28,9 @@ Meteor.methods if RocketChat.settings.get 'Message_KeepHistory' RocketChat.models.Messages.cloneAndSaveAsHistoryById originalMessage._id - message.ets = new Date() - # save who message was edited by - message.editBy = Meteor.userId() + message.edit = + at: new Date() + by: Meteor.userId() if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g message.urls = urls.map (url) -> url: url diff --git a/server/stream/messages.coffee b/server/stream/messages.coffee index cd90dc5995a..eca7a5e3906 100644 --- a/server/stream/messages.coffee +++ b/server/stream/messages.coffee @@ -23,7 +23,7 @@ Meteor.startup -> options = {} if not RocketChat.settings.get 'Message_ShowEditedStatus' - options.fields = { ets: 0 } + options.fields = { 'edit.at': 0 } RocketChat.models.Messages.findVisibleCreatedOrEditedAfterTimestamp(new Date(), options).observe added: (record) -> -- GitLab From 0c27f0a6162726da68ce8f7d307adaf36a2b6aec Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 9 Nov 2015 13:20:38 -0200 Subject: [PATCH 0370/1338] Changed edit to editedAt and editedBy --- client/methods/updateMessage.coffee | 14 ++++--- client/views/app/message.coffee | 23 ++++------- .../server/functions/setUsername.coffee | 1 + .../server/models/Messages.coffee | 41 +++++++++++++++---- server/methods/loadHistory.coffee | 2 +- server/methods/loadMissedMessages.coffee | 2 +- server/methods/updateMessage.coffee | 9 ++-- server/startup/migrations/v22.coffee | 10 +++++ server/stream/messages.coffee | 2 +- 9 files changed, 71 insertions(+), 33 deletions(-) create mode 100644 server/startup/migrations/v22.coffee diff --git a/client/methods/updateMessage.coffee b/client/methods/updateMessage.coffee index c88fc0f6c64..378bb0c9bda 100644 --- a/client/methods/updateMessage.coffee +++ b/client/methods/updateMessage.coffee @@ -9,6 +9,8 @@ Meteor.methods editAllowed = RocketChat.settings.get 'Message_AllowEditing' editOwn = originalMessage?.u?._id is Meteor.userId() + me = Meteor.users.findOne Meteor.userId() + unless hasPermission or (editAllowed and editOwn) toastr.error t('Message_editing_not_allowed') throw new Meteor.Error 'message-editing-not-allowed', t('Message_editing_not_allowed') @@ -23,9 +25,11 @@ Meteor.methods Tracker.nonreactive -> - message.edit = - by: Meteor.userId() - at: new Date(Date.now() + TimeSync.serverOffset()) + message.editedAt = new Date(Date.now() + TimeSync.serverOffset()) + message.editedBy = + _id: Meteor.userId() + username: me.username + message = RocketChat.callbacks.run 'beforeSaveMessage', message ChatMessage.update @@ -33,6 +37,6 @@ Meteor.methods 'u._id': Meteor.userId() , $set: - "edit.by": message.edit.by - "edit.at": message.edit.at + "editedAt": message.editedAt + "editedBy": message.editedBy msg: message.msg diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index ce07b11fc2f..b0bb174c48b 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -1,5 +1,3 @@ -wasEdited = (msg) -> - msg.edit?.at? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] Template.message.helpers actions: -> return RocketChat.MessageAction.getButtons(this) @@ -48,23 +46,16 @@ Template.message.helpers system: -> return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] - edited: -> wasEdited(@) + edited: -> Template.instance().wasEdited?(@) editTime: -> - return "" unless wasEdited(@) - moment(@edit.at).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? + return "" unless Template.instance().wasEdited?(@) + moment(@editedAt).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? editedBy: -> - return "" unless wasEdited(@) + 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 - if @edit.by - user = Meteor.users.findOne(@edit.by) - if user? - user.username - else - "?" - else - "?" + return @editedBy?.username or "?" pinned: -> return this.pinned canEdit: -> @@ -99,6 +90,10 @@ Template.message.helpers else if @label return @label +Template.message.onCreated -> + @wasEdited = (msg) -> + msg.editedAt? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + Template.message.onViewRendered = (context) -> view = this this._domrange.onAttached (domRange) -> diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 24cabea806f..9497f705f71 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -19,6 +19,7 @@ RocketChat.setUsername = (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.updateUsernameOfEditByUserId user._id, username RocketChat.models.Messages.findByMention(previousUsername).forEach (msg) -> updatedMsg = msg.msg.replace(new RegExp("@#{previousUsername}", "ig"), "@#{username}") diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 980ac8d04d0..603fb99ad96 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -3,8 +3,8 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base @_initModel 'message' @tryEnsureIndex { 'rid': 1, 'ts': 1 } - @tryEnsureIndex { 'edit.at': 1 }, { sparse: 1 } - @tryEnsureIndex { 'edit.by': 1 }, { sparse: 1 } + @tryEnsureIndex { 'editedAt': 1 }, { sparse: 1 } + @tryEnsureIndex { 'editedBy._id': 1 }, { sparse: 1 } @tryEnsureIndex { 'rid': 1, 't': 1, 'u._id': 1 } @tryEnsureIndex { 'expireAt': 1 }, { expireAfterSeconds: 0 } @tryEnsureIndex { 'msg': 'text' } @@ -77,7 +77,7 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base ts: $gt: timestamp , - 'edit.at': + 'editedAt': $gt: timestamp ] @@ -94,12 +94,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find query, options cloneAndSaveAsHistoryById: (_id) -> + me = RocketChat.models.Users.findOneById Meteor.userId() record = @findOneById _id record._hidden = true record.parent = record._id - record.edit = - at: new Date() - by: Meteor.userId() + record.editedAt = new Date + record.editedBy = + _id: Meteor.userId() + username: me.username delete record._id return @insert record @@ -117,6 +119,7 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @update query, update setAsDeletedById: (_id) -> + me = RocketChat.models.Users.findOneById Meteor.userId() query = _id: _id @@ -124,8 +127,10 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base $set: msg: '' t: 'rm' - 'edit.at': new Date() - 'edit.by': Meteor.userId() + editedAt: new Date() + editedBy: + _id: Meteor.userId() + username: me.username return @update query, update @@ -161,6 +166,16 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @update query, update, { multi: true } + updateUsernameOfEditByUserId: (userId, username) -> + query = + 'editedBy._id': userId + + update = + $set: + "editedBy.username": username + + return @update query, update, { multi: true } + updateUsernameAndMessageOfMentionByIdAndOldUsername: (_id, oldUsername, newUsername, newMessage) -> query = _id: _id @@ -188,6 +203,16 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @update query, update + upgradeEtsToEditAt: -> + query = + ets: { $exists: 1 } + + update = + $rename: + "ets": "editedAt" + + return @update query, update, { multi: true } + # INSERT createWithTypeRoomIdMessageAndUser: (type, roomId, message, user, extraData) -> record = diff --git a/server/methods/loadHistory.coffee b/server/methods/loadHistory.coffee index 266f10a9e1c..921bfae150a 100644 --- a/server/methods/loadHistory.coffee +++ b/server/methods/loadHistory.coffee @@ -12,7 +12,7 @@ Meteor.methods limit: limit if not RocketChat.settings.get 'Message_ShowEditedStatus' - options.fields = { 'edit.at': 0 } + options.fields = { 'editedAt': 0 } if end? records = RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestamp(rid, end, options).fetch() diff --git a/server/methods/loadMissedMessages.coffee b/server/methods/loadMissedMessages.coffee index de65bfb319a..e6c201aa77b 100644 --- a/server/methods/loadMissedMessages.coffee +++ b/server/methods/loadMissedMessages.coffee @@ -11,6 +11,6 @@ Meteor.methods ts: -1 if not RocketChat.settings.get 'Message_ShowEditedStatus' - options.fields = { 'edit.at': 0 } + options.fields = { 'editedAt': 0 } return RocketChat.models.Messages.findVisibleByRoomIdAfterTimestamp(rid, start, options).fetch() diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 21c8bcb4870..09ce1aa2d6f 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -12,6 +12,8 @@ Meteor.methods editAllowed = RocketChat.settings.get 'Message_AllowEditing' editOwn = originalMessage?.u?._id is Meteor.userId() + me = RocketChat.models.Users.findOneById Meteor.userId() + unless hasPermission or (editAllowed and editOwn) throw new Meteor.Error 'message-editing-not-allowed', "[methods] updateMessage -> Message editing not allowed" @@ -28,9 +30,10 @@ Meteor.methods if RocketChat.settings.get 'Message_KeepHistory' RocketChat.models.Messages.cloneAndSaveAsHistoryById originalMessage._id - message.edit = - at: new Date() - by: Meteor.userId() + message.editedAt = new Date() + message.editedBy = + _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 message.urls = urls.map (url) -> url: url diff --git a/server/startup/migrations/v22.coffee b/server/startup/migrations/v22.coffee new file mode 100644 index 00000000000..8ee08ea3e79 --- /dev/null +++ b/server/startup/migrations/v22.coffee @@ -0,0 +1,10 @@ +Meteor.startup -> + Migrations.add + version: 22 + up: -> + ### + # Update message edit field + ### + + RocketChat.models.Messages.upgradeEtsToEditAt() + console.log 'Updated old messages\' ets edited timestamp to new editedAt timestamp.' diff --git a/server/stream/messages.coffee b/server/stream/messages.coffee index eca7a5e3906..d82a0c1d164 100644 --- a/server/stream/messages.coffee +++ b/server/stream/messages.coffee @@ -23,7 +23,7 @@ Meteor.startup -> options = {} if not RocketChat.settings.get 'Message_ShowEditedStatus' - options.fields = { 'edit.at': 0 } + options.fields = { 'editedAt': 0 } RocketChat.models.Messages.findVisibleCreatedOrEditedAfterTimestamp(new Date(), options).observe added: (record) -> -- GitLab From 6605c7a9c8cd37322b93ab30ad69b7db800905c1 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 9 Nov 2015 19:46:26 -0200 Subject: [PATCH 0371/1338] Added BountySource --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f5184d66e5d..90e01aed53a 100644 --- a/README.md +++ b/README.md @@ -267,3 +267,5 @@ Note that Rocket.Chat is distributed under the [MIT License](http://opensource.o Rocket.Chat will be free forever, but you can help us speed-up the development! [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) + +[BountySource](https://www.bountysource.com/teams/rocketchat) -- GitLab From 0ddf25e43b999c3f4620fa9ff8000d05910f4b0d Mon Sep 17 00:00:00 2001 From: icode <intelligentcodemail@gmail.com> Date: Tue, 10 Nov 2015 16:09:09 +0800 Subject: [PATCH 0372/1338] update ldapjs for support node 0.12.x tls --- packages/rocketchat-ldap/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ldap/package.js b/packages/rocketchat-ldap/package.js index 83d74fcf59f..f832514eb3d 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -6,7 +6,7 @@ Package.describe({ }); Npm.depends({ - ldapjs: "0.7.1", + ldapjs: "1.0.0", }); // Loads all i18n.json files into tapi18nFiles -- GitLab From 277bb79a6a0a730a851f9a9b7d4d058641c5e9e1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 10 Nov 2015 14:07:45 -0200 Subject: [PATCH 0373/1338] Close #1358; Fix misspelling --- packages/rocketchat-lib/server/models/_Base.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/models/_Base.coffee b/packages/rocketchat-lib/server/models/_Base.coffee index c3d5e7f3b0c..9c91ac7380d 100644 --- a/packages/rocketchat-lib/server/models/_Base.coffee +++ b/packages/rocketchat-lib/server/models/_Base.coffee @@ -29,7 +29,7 @@ RocketChat.models._Base = class return @model.allow.apply @model, arguments deny: -> - return @model.allow.apply @model, arguments + return @model.deny.apply @model, arguments ensureIndex: -> return @model._ensureIndex.apply @model, arguments -- GitLab From c1b6952df03b59f87ced8c9522a5eee4a24d2789 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 10 Nov 2015 14:09:38 -0200 Subject: [PATCH 0374/1338] meteor update --- .meteor/versions | 10 +- .../.npm/package/npm-shrinkwrap.json | 128 +++++++++++++----- 2 files changed, 96 insertions(+), 42 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 937836621ce..cfb8b8accef 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,7 @@ cfs:http-methods@0.0.30 check@1.1.0 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.11 -cosmos:browserify@0.8.1 +cosmos:browserify@0.8.3 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 @@ -58,7 +58,7 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 kadira:blaze-layout@2.2.0 -kadira:flow-router@2.7.0 +kadira:flow-router@2.8.0 kenton:accounts-sandstorm@0.1.7 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 @@ -77,7 +77,7 @@ matb33:collection-hooks@0.8.1 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 -meteorhacks:kadira@2.24.1 +meteorhacks:kadira@2.26.3 meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 @@ -109,7 +109,7 @@ percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 -qnub:emojione@1.5.1_1 +qnub:emojione@1.5.1_2 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 @@ -165,7 +165,7 @@ templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 tmeasday:crypto-md5@3.1.2 tmeasday:errors@2.0.0 -todda00:friendly-slugs@0.3.4 +todda00:friendly-slugs@0.3.6 tracker@1.0.9 twitter@1.1.5 ui@1.0.8 diff --git a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json index 3dd543e2c5e..0835e040aaf 100644 --- a/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-ldap/.npm/package/npm-shrinkwrap.json @@ -1,62 +1,116 @@ { "dependencies": { "ldapjs": { - "version": "0.7.1", + "version": "1.0.0", "dependencies": { "asn1": { - "version": "0.2.1" + "version": "0.2.3" }, "assert-plus": { "version": "0.1.5" }, "bunyan": { - "version": "0.22.1", + "version": "1.5.1", "dependencies": { "mv": { - "version": "0.0.5" - } - } - }, - "nopt": { - "version": "2.1.1", - "dependencies": { - "abbrev": { - "version": "1.0.7" - } - } - }, - "pooling": { - "version": "0.4.6", - "dependencies": { - "once": { - "version": "1.3.0" - }, - "vasync": { - "version": "1.4.0", + "version": "2.1.1", "dependencies": { - "jsprim": { - "version": "0.3.0", + "mkdirp": { + "version": "0.5.1", "dependencies": { - "extsprintf": { - "version": "1.0.0" - }, - "json-schema": { - "version": "0.2.2" - }, - "verror": { - "version": "1.3.3" + "minimist": { + "version": "0.0.8" } } }, - "verror": { - "version": "1.1.0", + "ncp": { + "version": "2.0.0" + }, + "rimraf": { + "version": "2.4.3", "dependencies": { - "extsprintf": { - "version": "1.0.0" + "glob": { + "version": "5.0.15", + "dependencies": { + "inflight": { + "version": "1.0.4", + "dependencies": { + "wrappy": { + "version": "1.0.1" + } + } + }, + "inherits": { + "version": "2.0.1" + }, + "minimatch": { + "version": "3.0.0", + "dependencies": { + "brace-expansion": { + "version": "1.1.1", + "dependencies": { + "balanced-match": { + "version": "0.2.1" + }, + "concat-map": { + "version": "0.0.1" + } + } + } + } + }, + "path-is-absolute": { + "version": "1.0.0" + } + } } } } } + }, + "safe-json-stringify": { + "version": "1.0.3" + } + } + }, + "dashdash": { + "version": "1.10.1" + }, + "backoff": { + "version": "2.4.1", + "dependencies": { + "precond": { + "version": "0.2.3" + } + } + }, + "ldap-filter": { + "version": "0.2.2" + }, + "once": { + "version": "1.3.2", + "dependencies": { + "wrappy": { + "version": "1.0.1" + } + } + }, + "vasync": { + "version": "1.6.3" + }, + "verror": { + "version": "1.6.0", + "dependencies": { + "extsprintf": { + "version": "1.2.0" + } + } + }, + "dtrace-provider": { + "version": "0.6.0", + "dependencies": { + "nan": { + "version": "2.1.0" } } } -- GitLab From 253bea2b34a6564f9899ee1d8d75251d01f18818 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 10 Nov 2015 15:21:43 -0200 Subject: [PATCH 0375/1338] meteor update --- .meteor/versions | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index b2a52c59f3e..ef882d8d5ad 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,7 @@ cfs:http-methods@0.0.30 check@1.1.0 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.11 -cosmos:browserify@0.8.1 +cosmos:browserify@0.8.3 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 @@ -58,7 +58,7 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 kadira:blaze-layout@2.2.0 -kadira:flow-router@2.7.0 +kadira:flow-router@2.8.0 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 konecty:change-case@2.3.0 @@ -76,7 +76,7 @@ matb33:collection-hooks@0.8.1 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 -meteorhacks:kadira@2.24.1 +meteorhacks:kadira@2.26.3 meteorhacks:meteorx@1.4.1 meteorspark:util@0.2.0 minifiers@1.1.7 @@ -108,7 +108,7 @@ percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 -qnub:emojione@1.5.1_1 +qnub:emojione@1.5.1_2 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 @@ -165,7 +165,7 @@ templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 tmeasday:crypto-md5@3.1.2 tmeasday:errors@2.0.0 -todda00:friendly-slugs@0.3.4 +todda00:friendly-slugs@0.3.6 tracker@1.0.9 twitter@1.1.5 ui@1.0.8 -- GitLab From af24b4aec30d54cc7889b34528066d6853ba1760 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 10 Nov 2015 16:00:29 -0200 Subject: [PATCH 0376/1338] Merging .travis.yml --- .travis.yml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a7854560513..f0ef0c8b968 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ addons: - google-chrome-stable before_install: - curl https://install.meteor.com | /bin/sh +- npm install -g npm@'>=2.13.5' - mkdir -p node_modules - npm install phantomjs - npm install velocity-cli @@ -23,6 +24,31 @@ before_install: - export VELOCITY_DEBUG=1 - export VELOCITY_DEBUG_MIRROR=1 script: -- meteor add sanjo:jasmine velocity:console-reporter +- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi +- cd .travis +- npm install +- npm start +- cd .. +- meteor build ../build +- cd .travis +- sh ./namefiles.sh +- cd .. +- meteor add-platform ios +- meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter - ./node_modules/velocity-cli/bin/velocity test-packages --ci - ./node_modules/velocity-cli/bin/velocity test-app --ci +- meteor build --server demo.rocket.chat ../build +- cd .travis +- sh ./namedemo.sh +- cd .. +after_deploy: +- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" +deploy: + provider: s3 + access_key_id: "AKIAIKIA7H7D47KUHYCA" + secret_access_key: $ACCESSKEY + bucket: "rocketchatbuild" + skip_cleanup: true + local_dir: ../build + on: + branch: master -- GitLab From 3da68fdd2720a6882001553351de74e53cbd4b3b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 10 Nov 2015 17:45:37 -0200 Subject: [PATCH 0377/1338] Initial commit --- .meteor/packages | 1 + .meteor/versions | 1 + client/views/admin/adminFlex.coffee | 2 + client/views/admin/adminFlex.html | 8 +++ .../rocketchat-lib/client/AdminBox.coffee | 16 ++++++ packages/rocketchat-lib/package.js | 2 + .../rocketchat-mailer/client/router.coffee | 16 ++++++ .../rocketchat-mailer/client/startup.coffee | 5 ++ .../client/views/rocketMailer.coffee | 4 ++ .../client/views/rocketMailer.html | 43 ++++++++++++++++ .../client/views/rocketMailerUnsubscribe.html | 14 ++++++ packages/rocketchat-mailer/i18n/en.i18n.json | 9 ++++ packages/rocketchat-mailer/i18n/pt.i18n.json | 9 ++++ .../rocketchat-mailer/lib/RocketMailer.coffee | 1 + packages/rocketchat-mailer/package.js | 50 +++++++++++++++++++ .../server/functions/sendMail.coffee | 7 +++ .../server/functions/unsubscribe.coffee | 5 ++ .../server/methods/unsubscribe.coffee | 10 ++++ .../server/models/Users.coffee | 14 ++++++ .../rocketchat-mailer/server/startup.coffee | 2 + 20 files changed, 219 insertions(+) create mode 100644 packages/rocketchat-lib/client/AdminBox.coffee create mode 100644 packages/rocketchat-mailer/client/router.coffee create mode 100644 packages/rocketchat-mailer/client/startup.coffee create mode 100644 packages/rocketchat-mailer/client/views/rocketMailer.coffee create mode 100644 packages/rocketchat-mailer/client/views/rocketMailer.html create mode 100644 packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html create mode 100644 packages/rocketchat-mailer/i18n/en.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/pt.i18n.json create mode 100644 packages/rocketchat-mailer/lib/RocketMailer.coffee create mode 100644 packages/rocketchat-mailer/package.js create mode 100644 packages/rocketchat-mailer/server/functions/sendMail.coffee create mode 100644 packages/rocketchat-mailer/server/functions/unsubscribe.coffee create mode 100644 packages/rocketchat-mailer/server/methods/unsubscribe.coffee create mode 100644 packages/rocketchat-mailer/server/models/Users.coffee create mode 100644 packages/rocketchat-mailer/server/startup.coffee diff --git a/.meteor/packages b/.meteor/packages index 3d15d0183fe..79114a9da06 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -48,6 +48,7 @@ rocketchat:gitlab rocketchat:highlight rocketchat:ldap rocketchat:logger +rocketchat:mailer rocketchat:markdown rocketchat:me rocketchat:mentions diff --git a/.meteor/versions b/.meteor/versions index cfb8b8accef..187972be76a 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -134,6 +134,7 @@ rocketchat:highlight@0.0.1 rocketchat:ldap@0.0.1 rocketchat:lib@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 diff --git a/client/views/admin/adminFlex.coffee b/client/views/admin/adminFlex.coffee index 2e289263147..3e664a14bb2 100644 --- a/client/views/admin/adminFlex.coffee +++ b/client/views/admin/adminFlex.coffee @@ -3,6 +3,8 @@ Template.adminFlex.helpers return Settings.find({type: 'group'}, { sort: { sort: 1, i18nLabel: 1 } }).fetch() label: -> return TAPi18n.__(@i18nLabel or @_id) + adminBoxOptions: -> + return RocketChat.AdminBox.getOptions() Template.adminFlex.events 'mouseenter header': -> diff --git a/client/views/admin/adminFlex.html b/client/views/admin/adminFlex.html index 27bd9d2c7ec..c5c7b917f4d 100644 --- a/client/views/admin/adminFlex.html +++ b/client/views/admin/adminFlex.html @@ -25,6 +25,14 @@ </li> {{/if}} + {{#each adminBoxOptions}} + {{#if permissionGranted}} + <li> + <a href="{{pathFor href}}" class="admin-link">{{label}}</a> + </li> + {{/if}} + {{/each}} + <h3 class="add-room"> {{_ "Settings"}} </h3> diff --git a/packages/rocketchat-lib/client/AdminBox.coffee b/packages/rocketchat-lib/client/AdminBox.coffee new file mode 100644 index 00000000000..c2cc37bf180 --- /dev/null +++ b/packages/rocketchat-lib/client/AdminBox.coffee @@ -0,0 +1,16 @@ +RocketChat.AdminBox = new class + options = new ReactiveVar [] + + addOption = (option) -> + Tracker.nonreactive -> + actual = options.get() + actual.push option + options.set actual + + getOptions = -> + return _.filter options.get(), (option) -> + if not option.permissionGranted? or option.permissionGranted() + return true + + addOption: addOption + getOptions: getOptions diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 207c43bb040..633a8be7f36 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -13,6 +13,7 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('random'); api.use('check'); + api.use('tracker'); api.use('ddp-rate-limiter'); api.use('underscore'); api.use('underscorestring:underscore.string'); @@ -48,6 +49,7 @@ Package.onUse(function(api) { // CLIENT api.addFiles('client/lib/openRoom.coffee', 'client'); api.addFiles('client/lib/roomExit.coffee', 'client'); + api.addFiles('client/AdminBox.coffee', 'client'); api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); api.addFiles('client/MessageAction.coffee', 'client'); diff --git a/packages/rocketchat-mailer/client/router.coffee b/packages/rocketchat-mailer/client/router.coffee new file mode 100644 index 00000000000..6eefaffcda8 --- /dev/null +++ b/packages/rocketchat-mailer/client/router.coffee @@ -0,0 +1,16 @@ +tabReset = -> + RocketChat.TabBar.reset() + +FlowRouter.route '/rocket-mailer', + name: 'rocket-mailer' + triggersEnter: [tabReset] + triggersExit: [tabReset] + action: -> + BlazeLayout.render 'main', {center: 'rocketMailer'} + +FlowRouter.route '/rocket-mailer/unsubscribe/:hash', + name: 'rocket-mailer-unsubscribe' + action: (params) -> + console.log params.hash + Meteor.call 'RocketMailer.unsubscribe', params.hash + BlazeLayout.render 'rocketMailerUnsubscribe' diff --git a/packages/rocketchat-mailer/client/startup.coffee b/packages/rocketchat-mailer/client/startup.coffee new file mode 100644 index 00000000000..c7abd7b5de9 --- /dev/null +++ b/packages/rocketchat-mailer/client/startup.coffee @@ -0,0 +1,5 @@ +RocketChat.AdminBox.addOption + href: 'rocket-mailer' + i18nLabel: 'Rocket_Mailer' + permissionGranted: -> + return RocketChat.authz.hasAllPermission('access-rocket-mailer') diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.coffee b/packages/rocketchat-mailer/client/views/rocketMailer.coffee new file mode 100644 index 00000000000..c2f118c4a5b --- /dev/null +++ b/packages/rocketchat-mailer/client/views/rocketMailer.coffee @@ -0,0 +1,4 @@ +Template.rocketMailer.events + 'click .send': (e) -> + e.preventDefault() + console.log 'Must send e-mail' diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.html b/packages/rocketchat-mailer/client/views/rocketMailer.html new file mode 100644 index 00000000000..f15935ece4d --- /dev/null +++ b/packages/rocketchat-mailer/client/views/rocketMailer.html @@ -0,0 +1,43 @@ +<template name="rocketMailer"> + <section class="page-container page-list"> + <head class="fixed-title"> + {{> burger}} + <h2> + <span class="room-title">{{_ "Rocket_Mailer"}}</span> + </h2> + </head> + <div class="content"> + {{#unless hasPermission 'access-rocket-mailer'}} + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> + {{else}} + <form> + <div class="rocket-form"> + <fieldset> + <div class="input-line"> + <label>{{_ "Email_from"}}</label> + <div> + <input type="text" name="from" value="" />@rocket.chat + </div> + </div> + <div class="input-line"> + <label>{{_ "Email_subject"}}</label> + <div> + <input type="text" name="subject" value="" /> + </div> + </div> + <div class="input-line"> + <label>{{_ "Email_body"}}</label> + <div> + <textarea name="body" rows="10" style="height: auto"></textarea> + </div> + </div> + </fieldset> + <div class="submit"> + <button class="button send"><i class="icon-send"></i><span>{{_ "Send_email"}}</span></button> + </div> + </div> + </form> + {{/unless}} + </div> + </section> +</template> diff --git a/packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html b/packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html new file mode 100644 index 00000000000..0460087f1a3 --- /dev/null +++ b/packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html @@ -0,0 +1,14 @@ +<template name="rocketMailerUnsubscribe"> + <section class="full-page"> + <div class="wrapper"> + <header> + <a class="logo" href="/"> + <img src="/images/logo/logo.svg?v=3" /> + </a> + </header> + <div class="cms-page"> + {{_ "You_have_successfully_unsubscribed"}} + </div> + </div> + </section> +</template> diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json new file mode 100644 index 00000000000..feec3b4a84c --- /dev/null +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -0,0 +1,9 @@ +{ + "Email_from": "From", + "Email_subject": "Subject", + "Email_body": "E-mail body", + "Rocket_Mailer": "Rocket Mailer", + "Send_email": "Send E-mail", + "You_are_not_authorized_to_view_this_page": "You are not authorized to view this page.", + "You_have_successfully_unsubscribed": "You have successfully unsubscribed from our Mailling List." +} diff --git a/packages/rocketchat-mailer/i18n/pt.i18n.json b/packages/rocketchat-mailer/i18n/pt.i18n.json new file mode 100644 index 00000000000..560bfbe200a --- /dev/null +++ b/packages/rocketchat-mailer/i18n/pt.i18n.json @@ -0,0 +1,9 @@ +{ + "Email_from": "De", + "Email_subject": "Assunto", + "Email_body": "Corpo do E-mail", + "Rocket_Mailer": "Rocket Mailer", + "Send_email": "Enviar E-mail", + "You_are_not_authorized_to_view_this_page": "Você não possui permissão para visualizar esta página.", + "You_have_successfully_unsubscribed": "A partir de agora você não está mais cadastrado em nossa lista de e-mails." +} diff --git a/packages/rocketchat-mailer/lib/RocketMailer.coffee b/packages/rocketchat-mailer/lib/RocketMailer.coffee new file mode 100644 index 00000000000..90d0dee81ab --- /dev/null +++ b/packages/rocketchat-mailer/lib/RocketMailer.coffee @@ -0,0 +1 @@ +RocketMailer = {} diff --git a/packages/rocketchat-mailer/package.js b/packages/rocketchat-mailer/package.js new file mode 100644 index 00000000000..73eb2af02ef --- /dev/null +++ b/packages/rocketchat-mailer/package.js @@ -0,0 +1,50 @@ +Package.describe({ + name: 'rocketchat:mailer', + version: '0.0.1', + summary: 'Mailer for Rocket.Chat' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'ddp-rate-limiter', + 'kadira:flow-router', + 'rocketchat:lib@0.0.1', + 'rocketchat:authorization@0.0.1' + ]); + + api.addFiles('lib/RocketMailer.coffee'); + + api.addFiles([ + 'client/startup.coffee', + 'client/router.coffee', + 'client/views/rocketMailer.html', + 'client/views/rocketMailer.coffee', + 'client/views/rocketMailerUnsubscribe.html' + ], 'client'); + + api.addFiles([ + 'server/startup.coffee', + 'server/models/Users.coffee', + 'server/functions/sendMail.coffee', + 'server/functions/unsubscribe.coffee', + 'server/methods/unsubscribe.coffee' + ], 'server'); + + // TAPi18n + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + api.use('templating', 'client'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-mailer/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-mailer/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.export('RocketMailer'); +}); diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee new file mode 100644 index 00000000000..98313f17013 --- /dev/null +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -0,0 +1,7 @@ +RocketMailer.sendMail = (from, subject, body) -> + Meteor.users.find({ "rocketMailer.unsubscribed": { $exists: 0 } }).forEach (user) -> + email = user.emails?[0]?.address + if email + Meteor.defer -> + console.log email + # mailsend diff --git a/packages/rocketchat-mailer/server/functions/unsubscribe.coffee b/packages/rocketchat-mailer/server/functions/unsubscribe.coffee new file mode 100644 index 00000000000..003876c879f --- /dev/null +++ b/packages/rocketchat-mailer/server/functions/unsubscribe.coffee @@ -0,0 +1,5 @@ +RocketMailer.unsubscribe = (hash) -> + [_id, createdAt] = hash.split ':' + if _id and createdAt + return RocketChat.models.Users.RocketMailUnsubscribe(_id, createdAt) == 1 + return false diff --git a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee new file mode 100644 index 00000000000..2da214aba7a --- /dev/null +++ b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee @@ -0,0 +1,10 @@ +Meteor.methods + 'RocketMailer.unsubscribe': (hash) -> + return RocketMailer.unsubscribe hash + +# Limit setting username once per minute +DDPRateLimiter.addRule + type: 'method' + name: 'RocketMailer.unsubscribe' + connectionId: -> return true +, 1, 60000 diff --git a/packages/rocketchat-mailer/server/models/Users.coffee b/packages/rocketchat-mailer/server/models/Users.coffee new file mode 100644 index 00000000000..a9e61ffde87 --- /dev/null +++ b/packages/rocketchat-mailer/server/models/Users.coffee @@ -0,0 +1,14 @@ +# Extends model Users + +RocketChat.models.Users.RocketMailUnsubscribe = (_id, createdAt) -> + console.log '[RocketMailer.Unsubscribe]', _id, createdAt, new Date(parseInt createdAt) + + query = + _id: _id + createdAt: new Date(parseInt createdAt) + + update = + $set: + "rocketMailer.unsubscribed": true + + return @update query, update diff --git a/packages/rocketchat-mailer/server/startup.coffee b/packages/rocketchat-mailer/server/startup.coffee new file mode 100644 index 00000000000..24ee1c22c77 --- /dev/null +++ b/packages/rocketchat-mailer/server/startup.coffee @@ -0,0 +1,2 @@ +Meteor.startup -> + RocketChat.models.Permissions.upsert( 'access-rocket-mailer', { $setOnInsert : { _id: 'access-rocket-mailer', roles : ['admin'] } }) -- GitLab From 5ad059c091499a785db2da6050b0317f88c9819c Mon Sep 17 00:00:00 2001 From: Mitar <mitar.git@tnode.com> Date: Tue, 10 Nov 2015 21:26:43 -0800 Subject: [PATCH 0378/1338] Moved oembed code to a template helper. This makes message rendering much more self-contained and Meteor-like. --- client/views/app/message.coffee | 85 ++++++++++++++++++--------------- client/views/app/message.html | 5 ++ 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index b0bb174c48b..017a6b671d4 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -20,38 +20,17 @@ Template.message.helpers return body: -> - switch this.t - when 'r' then t('Room_name_changed', { room_name: this.msg, user_by: this.u.username }) - when 'au' then t('User_added_by', { user_added: this.msg, user_by: this.u.username }) - when 'ru' then t('User_removed_by', { user_removed: this.msg, user_by: this.u.username }) - when 'ul' then t('User_left', { user_left: this.u.username }) - when 'nu' then t('User_added', { user_added: this.u.username }) - when 'uj' then t('User_joined_channel', { user: this.u.username }) - when 'wm' then t('Welcome', { user: this.u.username }) - when 'rm' then t('Message_removed', { user: this.u.username }) - when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this - else - if this.u?.username is RocketChat.settings.get('Chatops_Username') - this.html = this.msg - message = RocketChat.callbacks.run 'renderMentions', this - # console.log JSON.stringify message - return this.html - this.html = this.msg - if _.trim(this.html) isnt '' - this.html = _.escapeHTML this.html - message = RocketChat.callbacks.run 'renderMessage', this - # console.log JSON.stringify message - this.html = message.html.replace /\n/gm, '<br/>' - return this.html + Template.instance().body system: -> return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] - edited: -> Template.instance().wasEdited?(@) + edited: -> + Template.instance().wasEdited editTime: -> - return "" unless Template.instance().wasEdited?(@) + return "" unless Template.instance().wasEdited moment(@editedAt).format('LL hh:mma') #TODO profile pref for 12hr/24hr clock? editedBy: -> - return "" unless Template.instance().wasEdited?(@) + 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 @@ -90,9 +69,48 @@ Template.message.helpers else if @label return @label + hasOembed: -> + return false unless this.urls?.length > 0 and Template.oembedBaseWidget? and RocketChat.settings.get 'API_Embed' + + return false unless this.u?.username not in RocketChat.settings.get('API_EmbedDisabledFor')?.split(',') + + return true + + oembed: -> + $body = $(Template.instance().body) + return null unless $body.is('a[href="'+this.url+'"]') or $body.has('a[href="'+this.url+'"]').is() + + Template.oembedBaseWidget + Template.message.onCreated -> - @wasEdited = (msg) -> - msg.editedAt? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + msg = Template.currentData() + + @wasEdited = msg.editedAt? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + + @body = do -> + switch msg.t + when 'r' then t('Room_name_changed', { room_name: msg.msg, user_by: msg.u.username }) + when 'au' then t('User_added_by', { user_added: msg.msg, user_by: msg.u.username }) + when 'ru' then t('User_removed_by', { user_removed: msg.msg, user_by: msg.u.username }) + when 'ul' then t('User_left', { user_left: msg.u.username }) + when 'nu' then t('User_added', { user_added: msg.u.username }) + when 'uj' then t('User_joined_channel', { user: msg.u.username }) + when 'wm' then t('Welcome', { user: msg.u.username }) + when 'rm' then t('Message_removed', { user: msg.u.username }) + when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', msg + else + if msg.u?.username is RocketChat.settings.get('Chatops_Username') + msg.html = msg.msg + message = RocketChat.callbacks.run 'renderMentions', msg + # console.log JSON.stringify message + return msg.html + msg.html = msg.msg + if _.trim(msg.html) isnt '' + msg.html = _.escapeHTML msg.html + message = RocketChat.callbacks.run 'renderMessage', msg + # console.log JSON.stringify message + msg.html = message.html.replace /\n/gm, '<br/>' + return msg.html Template.message.onViewRendered = (context) -> view = this @@ -114,17 +132,6 @@ Template.message.onViewRendered = (context) -> if lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username $(lastNode.nextElementSibling).removeClass('sequential') - ul = lastNode.parentElement - wrapper = ul.parentElement - - if context.urls?.length > 0 and Template.oembedBaseWidget? and RocketChat.settings.get 'API_Embed' - if context.u?.username not in RocketChat.settings.get('API_EmbedDisabledFor')?.split(',') - for item in context.urls - do (item) -> - urlNode = lastNode.querySelector('.body a[href="'+item.url+'"]') - if urlNode? - $(lastNode.querySelector('.body')).append Blaze.toHTMLWithData Template.oembedBaseWidget, item - if not lastNode.nextElementSibling? if lastNode.classList.contains('own') is true view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom = true diff --git a/client/views/app/message.html b/client/views/app/message.html index 88d10219e75..0ab99b3fb52 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -45,6 +45,11 @@ <div class="body" dir="auto"> {{{body}}} + {{#if hasOembed}} + {{#each urls}} + {{> oembed}} + {{/each}} + {{/if}} </div> </li> </template> -- GitLab From 22ae0c595ed9ed0d9a88b65d0a319c046d04b7f9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 11 Nov 2015 11:52:57 -0200 Subject: [PATCH 0379/1338] Close #1222; Fix shared variable with username info when generate avatar --- server/startup/avatar.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 142bc327f18..387fed26d88 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -29,13 +29,13 @@ Meteor.startup -> transformWrite: transformWrite WebApp.connectHandlers.use '/avatar/', (req, res, next) -> - this.params = + params = username: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) - if this.params.username[0] isnt '@' - file = RocketChatFileAvatarInstance.getFileWithReadStream this.params.username + if params.username[0] isnt '@' + file = RocketChatFileAvatarInstance.getFileWithReadStream params.username else - this.params.username = this.params.username.replace '@', '' + params.username = params.username.replace '@', '' #console.log "[avatar] checking username #{@params.username} (derrived from path #{req.url})" res.setHeader 'Content-Disposition', 'inline' @@ -46,7 +46,7 @@ Meteor.startup -> colors = ['#F44336','#E91E63','#9C27B0','#673AB7','#3F51B5','#2196F3','#03A9F4','#00BCD4','#009688','#4CAF50','#8BC34A','#CDDC39','#FFC107','#FF9800','#FF5722','#795548','#9E9E9E','#607D8B'] - username = @params.username.replace('.jpg', '') + username = params.username.replace('.jpg', '') color = '' initials = '' if username is "?" -- GitLab From ee1ea063515688ab65a97e131ce39f240e5d262a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 11 Nov 2015 14:21:44 -0200 Subject: [PATCH 0380/1338] preventDefault on shift + esc shortcut --- client/views/main.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/client/views/main.coffee b/client/views/main.coffee index 19264e67241..e43df650fbd 100644 --- a/client/views/main.coffee +++ b/client/views/main.coffee @@ -10,6 +10,7 @@ Template.body.onRendered -> unread = Session.get('unread') if e.keyCode is 27 and e.shiftKey is true and unread? and unread isnt '' + e.preventDefault() e.stopPropagation() swal title: t('Clear_all_unreads_question') -- GitLab From 6bd67b45bbc4c17cf1df3d243514c802f6250440 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 11 Nov 2015 15:23:21 -0200 Subject: [PATCH 0381/1338] RocketMailer and Unsubscription --- .../rocketchat-mailer/client/router.coffee | 5 ++- .../client/views/rocketMailer.coffee | 13 ++++++-- .../client/views/rocketMailer.html | 8 ++++- packages/rocketchat-mailer/i18n/en.i18n.json | 7 +++- packages/rocketchat-mailer/package.js | 1 + .../server/functions/sendMail.coffee | 33 +++++++++++++++++-- .../server/functions/unsubscribe.coffee | 3 +- .../server/methods/sendMail.coffee | 13 ++++++++ .../server/methods/unsubscribe.coffee | 4 +-- .../server/models/Users.coffee | 7 ++-- 10 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 packages/rocketchat-mailer/server/methods/sendMail.coffee diff --git a/packages/rocketchat-mailer/client/router.coffee b/packages/rocketchat-mailer/client/router.coffee index 6eefaffcda8..361cd663ae9 100644 --- a/packages/rocketchat-mailer/client/router.coffee +++ b/packages/rocketchat-mailer/client/router.coffee @@ -8,9 +8,8 @@ FlowRouter.route '/rocket-mailer', action: -> BlazeLayout.render 'main', {center: 'rocketMailer'} -FlowRouter.route '/rocket-mailer/unsubscribe/:hash', +FlowRouter.route '/rocket-mailer/unsubscribe/:_id/:createdAt', name: 'rocket-mailer-unsubscribe' action: (params) -> - console.log params.hash - Meteor.call 'RocketMailer.unsubscribe', params.hash + Meteor.call 'RocketMailer.unsubscribe', params._id, params.createdAt BlazeLayout.render 'rocketMailerUnsubscribe' diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.coffee b/packages/rocketchat-mailer/client/views/rocketMailer.coffee index c2f118c4a5b..8b50abbb9a8 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailer.coffee +++ b/packages/rocketchat-mailer/client/views/rocketMailer.coffee @@ -1,4 +1,13 @@ Template.rocketMailer.events - 'click .send': (e) -> + 'click .send': (e, t) -> e.preventDefault() - console.log 'Must send e-mail' + from = $(t.find('[name=from]')).val() + subject = $(t.find('[name=subject]')).val() + body = $(t.find('[name=body]')).val() + + if body.indexOf('[unsubscribe]') is -1 + toastr.error TAPi18n.__('You_must_provide_the_unsubscribe_link') + else + Meteor.call 'RocketMailer.sendMail', from, subject, body, (err) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__('The_emails_are_being_sent') diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.html b/packages/rocketchat-mailer/client/views/rocketMailer.html index f15935ece4d..c7855d98474 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailer.html +++ b/packages/rocketchat-mailer/client/views/rocketMailer.html @@ -16,7 +16,10 @@ <div class="input-line"> <label>{{_ "Email_from"}}</label> <div> - <input type="text" name="from" value="" />@rocket.chat + <input type="text" name="from" value="" /> + </div> + <div> + <small class="settings-description">{{_ "Currently_only_rocket_chat_emails"}}</small> </div> </div> <div class="input-line"> @@ -30,6 +33,9 @@ <div> <textarea name="body" rows="10" style="height: auto"></textarea> </div> + <div> + <small class="settings-description">{{{_ "RocketMailer_body_tags"}}}</small> + </div> </div> </fieldset> <div class="submit"> diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index feec3b4a84c..60bfa23db94 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -1,9 +1,14 @@ { + "Currently_only_rocket_chat_emails": "Currently only accepting @rocket.chat e-mails", "Email_from": "From", "Email_subject": "Subject", "Email_body": "E-mail body", "Rocket_Mailer": "Rocket Mailer", + "RocketMailer_body_tags": "You <b>must</b> use [unsubscribe] for the unsubscription link.<br />You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Send_email": "Send E-mail", + "The_emails_are_being_sent": "The e-mails are being sent.", "You_are_not_authorized_to_view_this_page": "You are not authorized to view this page.", - "You_have_successfully_unsubscribed": "You have successfully unsubscribed from our Mailling List." + "You_have_successfully_unsubscribed": "You have successfully unsubscribed from our Mailling List.", + "You_informed_an_invalid_FROM_address": "You informed an invalid FROM address.", + "You_must_provide_the_unsubscribe_link": "You must provide the [unsubscribe] link." } diff --git a/packages/rocketchat-mailer/package.js b/packages/rocketchat-mailer/package.js index 73eb2af02ef..db49ba91bc2 100644 --- a/packages/rocketchat-mailer/package.js +++ b/packages/rocketchat-mailer/package.js @@ -30,6 +30,7 @@ Package.onUse(function(api) { 'server/models/Users.coffee', 'server/functions/sendMail.coffee', 'server/functions/unsubscribe.coffee', + 'server/methods/sendMail.coffee', 'server/methods/unsubscribe.coffee' ], 'server'); diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee index 98313f17013..0d73dd7478f 100644 --- a/packages/rocketchat-mailer/server/functions/sendMail.coffee +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -1,7 +1,34 @@ RocketMailer.sendMail = (from, subject, body) -> + + rocketchatMailPattern = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@rocket.chat)(?:>?)$/ + unless rocketchatMailPattern.test from + throw new Meteor.Error 'invalid-from-address', TAPi18n.__('You_informed_an_invalid_FROM_address') + + if body.indexOf('[unsubscribe]') is -1 + throw new Meteor.Error 'missing-unsubscribe-link', TAPi18n.__('You_must_provide_the_unsubscribe_link') + Meteor.users.find({ "rocketMailer.unsubscribed": { $exists: 0 } }).forEach (user) -> + # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> email = user.emails?[0]?.address - if email + + html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('rocket-mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) + html = html.replace /\[name\]/g, user.name + fname = _.strLeft user.name, ' ' + lname = _.strRightBack user.name, ' ' + html = html.replace /\[fname\]/g, fname + html = html.replace /\[lname\]/g, lname + html = html.replace /\[email\]/g, email + html = html.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2') + + # 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])?)*)(?:>?)$/ + # if rfcMailPatternWithName.test email + rfcMailPattern = /^[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])?)*$/ + if rfcMailPattern.test email Meteor.defer -> - console.log email - # mailsend + Email.send + to: email + from: from + subject: subject + html: html + + console.log 'Sending email to ' + email diff --git a/packages/rocketchat-mailer/server/functions/unsubscribe.coffee b/packages/rocketchat-mailer/server/functions/unsubscribe.coffee index 003876c879f..9b559f1d38a 100644 --- a/packages/rocketchat-mailer/server/functions/unsubscribe.coffee +++ b/packages/rocketchat-mailer/server/functions/unsubscribe.coffee @@ -1,5 +1,4 @@ -RocketMailer.unsubscribe = (hash) -> - [_id, createdAt] = hash.split ':' +RocketMailer.unsubscribe = (_id, createdAt) -> if _id and createdAt return RocketChat.models.Users.RocketMailUnsubscribe(_id, createdAt) == 1 return false diff --git a/packages/rocketchat-mailer/server/methods/sendMail.coffee b/packages/rocketchat-mailer/server/methods/sendMail.coffee new file mode 100644 index 00000000000..7c693bd6b57 --- /dev/null +++ b/packages/rocketchat-mailer/server/methods/sendMail.coffee @@ -0,0 +1,13 @@ +Meteor.methods + 'RocketMailer.sendMail': (from, subject, body) -> + + console.log '[method] RocketMailer.sendMail', from, subject, body + + return RocketMailer.sendMail from, subject, body + +# Limit setting username once per minute +# DDPRateLimiter.addRule +# type: 'method' +# name: 'RocketMailer.sendMail' +# connectionId: -> return true +# , 1, 60000 diff --git a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee index 2da214aba7a..5d0a1e6a448 100644 --- a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee +++ b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee @@ -1,6 +1,6 @@ Meteor.methods - 'RocketMailer.unsubscribe': (hash) -> - return RocketMailer.unsubscribe hash + 'RocketMailer.unsubscribe': (_id, createdAt) -> + return RocketMailer.unsubscribe _id, createdAt # Limit setting username once per minute DDPRateLimiter.addRule diff --git a/packages/rocketchat-mailer/server/models/Users.coffee b/packages/rocketchat-mailer/server/models/Users.coffee index a9e61ffde87..1125205ccc0 100644 --- a/packages/rocketchat-mailer/server/models/Users.coffee +++ b/packages/rocketchat-mailer/server/models/Users.coffee @@ -1,7 +1,6 @@ # Extends model Users RocketChat.models.Users.RocketMailUnsubscribe = (_id, createdAt) -> - console.log '[RocketMailer.Unsubscribe]', _id, createdAt, new Date(parseInt createdAt) query = _id: _id @@ -11,4 +10,8 @@ RocketChat.models.Users.RocketMailUnsubscribe = (_id, createdAt) -> $set: "rocketMailer.unsubscribed": true - return @update query, update + affectedRows = @update query, update + + console.log '[RocketMailer.Unsubscribe]', _id, createdAt, new Date(parseInt createdAt), affectedRows + + return affectedRows -- GitLab From 7fc68cd913de08cd340c82d3d00f86e19406ed9d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 11 Nov 2015 17:29:27 -0200 Subject: [PATCH 0382/1338] Add enrollment email --- client/views/admin/admin.html | 2 +- i18n/en.i18n.json | 4 +++- .../rocketchat-lib/settings/server/startup.coffee | 1 + server/lib/accounts.coffee | 11 +++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index 36d96f01d31..bb87193a709 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -55,7 +55,7 @@ {{/if}} {{#if description}} <div> - <small class="settings-description">{{description}}</small> + <small class="settings-description">{{{description}}}</small> </div> {{/if}} </div> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 5abc995c31a..301e266eb31 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -45,6 +45,8 @@ "Accounts_OAuth_Custom_Button_Label_Color" : "Button Text Color", "Accounts_OAuth_Custom_Button_Color" : "Button Color", "Accounts_RequireNameForSignUp" : "Require name for signup", + "Accounts_Enrollment_Email": "Enrollment E-mail", + "Accounts_Enrollment_Email_Description": "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", @@ -453,4 +455,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 7821c68fefe..f579dc06b94 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -68,6 +68,7 @@ RocketChat.settings.add 'From_Email', 'no-reply@rocket.chat', { type: 'string', 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 https://demo.rocket.chat 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 } diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 23047777530..eb0878f6cfc 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -27,6 +27,17 @@ Accounts.emailTemplates.resetPassword.text = (user, url) -> url = url.replace Meteor.absoluteUrl(), Meteor.absoluteUrl() + 'login/' verifyEmailText user, url +if RocketChat.settings.get 'Accounts_Enrollment_Email' + Accounts.emailTemplates.enrollAccount.text = (user, url) -> + text = RocketChat.settings.get 'Accounts_Enrollment_Email' + + text = text.replace /\[name\]/g, user.name or '' + text = text.replace /\[fname\]/g, _.strLeft(user.name, ' ') or '' + text = text.replace /\[lname\]/g, _.strRightBack(user.name, ' ') or '' + text = text.replace /\[email\]/g, user.emails?[0]?.address or '' + + return text + Accounts.onCreateUser (options, user) -> # console.log 'onCreateUser ->',JSON.stringify arguments, null, ' ' # console.log 'options ->',JSON.stringify options, null, ' ' -- GitLab From ceb25677fddf8c4135ce913a9b47143a2079b3b6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 11 Nov 2015 18:01:03 -0200 Subject: [PATCH 0383/1338] room icons --- client/startup/defaultRoomTypes.coffee | 4 ++++ client/views/app/sideNav/chatRoomItem.coffee | 8 +------- packages/rocketchat-lib/lib/roomTypes.coffee | 14 ++++++++++++++ packages/rocketchat-livechat/client/ui.js | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 5ef93048cc0..0bba73ffdef 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -5,6 +5,10 @@ Meteor.startup -> RocketChat.roomTypes.addType('directMessages', roles); RocketChat.roomTypes.addType('privateGroups', roles); + RocketChat.roomTypes.setIcon('c', 'icon-hash'); + RocketChat.roomTypes.setIcon('d', 'icon-at'); + RocketChat.roomTypes.setIcon('p', 'icon-lock'); + RocketChat.roomTypes.setRoute 'c', 'channel', (sub) -> return { name: sub.name } diff --git a/client/views/app/sideNav/chatRoomItem.coffee b/client/views/app/sideNav/chatRoomItem.coffee index dc25a452a24..c1482357b98 100644 --- a/client/views/app/sideNav/chatRoomItem.coffee +++ b/client/views/app/sideNav/chatRoomItem.coffee @@ -8,9 +8,6 @@ Template.chatRoomItem.helpers if (FlowRouter.getParam('_id') isnt this.rid or not document.hasFocus()) and this.unread > 0 return this.unread - isDirectRoom: -> - return this.t is 'd' - userStatus: -> return 'status-' + (Session.get('user_' + this.name + '_status') or 'offline') if this.t is 'd' return '' @@ -19,10 +16,7 @@ Template.chatRoomItem.helpers return this.name roomIcon: -> - switch this.t - when 'd' then return 'icon-at' - when 'c' then return 'icon-hash' - when 'p' then return 'icon-lock' + return RocketChat.roomTypes.getIcon this.t active: -> if Session.get('openedRoom') is this.rid diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index 69622f99ede..891ec9d27ea 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -2,6 +2,7 @@ RocketChat.roomTypes = new class rooms = [] routes = {} publishes = {} + icons = {} ### Sets a route for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @@ -58,9 +59,22 @@ RocketChat.roomTypes = new class return unless publishes[roomType]? return publishes[roomType].call this, identifier + getIcon = (roomType) -> + return icons[roomType] + + ### + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param iconClass: iconClass to display on sideNav + ### + setIcon = (roomType, iconClass) -> + icons[roomType] = iconClass + addType: addType getTypes: getAllTypes + setIcon: setIcon + getIcon: getIcon + setRoute: setRoute getRoute: getRoute diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index 7642597fd25..78c60da223b 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -1,7 +1,7 @@ Meteor.startup(function() { RocketChat.roomTypes.addType('livechat', ['livechat-agent', 'livechat-manager']); + RocketChat.roomTypes.setIcon('l', 'icon-chat-empty'); RocketChat.roomTypes.setRoute('l', 'live', function(sub) { - console.log('livechat route ->',sub); return { name: sub.name }; }); -- GitLab From ebf6fbdb2db0c3c5769b8e9678b042e4dc8c866e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 11 Nov 2015 18:01:15 -0200 Subject: [PATCH 0384/1338] livechat room publish --- packages/rocketchat-livechat/package.js | 2 +- .../rocketchat-livechat/server/publications.js | 12 ------------ packages/rocketchat-livechat/server/startup.js | 14 ++++++++++++++ 3 files changed, 15 insertions(+), 13 deletions(-) delete mode 100644 packages/rocketchat-livechat/server/publications.js create mode 100644 packages/rocketchat-livechat/server/startup.js diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 3702ab9f0cd..f02fe7245eb 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -25,7 +25,7 @@ Package.onUse(function(api) { api.addFiles('livechat.js', 'server'); api.addFiles('server/methods.js', 'server'); - api.addFiles('server/publications.js', 'server'); + api.addFiles('server/startup.js', 'server'); api.addFiles('permissions.js', 'server'); api.addFiles('config.js', 'server'); diff --git a/packages/rocketchat-livechat/server/publications.js b/packages/rocketchat-livechat/server/publications.js deleted file mode 100644 index 76fe1b8abba..00000000000 --- a/packages/rocketchat-livechat/server/publications.js +++ /dev/null @@ -1,12 +0,0 @@ -Meteor.publish('visitorRoom', (visitorToken) => { - return RocketChat.models.Rooms.findByVisitorToken(visitorToken, { - fields: { - name: 1, - t: 1, - cl: 1, - u: 1, - usernames: 1, - v: 1 - } - }); -}); diff --git a/packages/rocketchat-livechat/server/startup.js b/packages/rocketchat-livechat/server/startup.js new file mode 100644 index 00000000000..f9beb312b1c --- /dev/null +++ b/packages/rocketchat-livechat/server/startup.js @@ -0,0 +1,14 @@ +Meteor.startup(function() { + RocketChat.roomTypes.addPublish('l', function(identifier) { + return RocketChat.models.Rooms.findByTypeAndName('l', identifier, { + fields: { + name: 1, + t: 1, + cl: 1, + u: 1, + usernames: 1, + v: 1 + } + }); + }); +}); -- GitLab From f5df20aff1e99a6b44f467bc7c2cbf823e70c5f8 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Wed, 11 Nov 2015 17:34:20 -0600 Subject: [PATCH 0385/1338] Update message pinning to show up on the tab list with a few options to allow/disallow it and whether to allow anyone to pin messages --- .meteor/packages | 1 + .meteor/versions | 1 + .../server/models/Messages.coffee | 19 +++++-- .../client/actionButton.coffee | 44 +++++++++++++++ .../client/lib/PinnedMessage.coffee | 1 + .../client/tabBar.coffee | 5 ++ .../client/views/pinnedMessages.coffee | 21 ++++++++ .../client/views/pinnedMessages.html | 22 ++++++++ .../client/views/stylesheets/messagepin.less | 26 +++++++++ .../rocketchat-message-pin/i18n/en.i18n.json | 10 ++++ packages/rocketchat-message-pin/package.js | 48 +++++++++++++++++ .../server/pinMessage.coffee | 53 +++++++++++++++++++ .../server/publications/pinnedMessages.coffee | 21 ++++++++ .../server/settings.coffee | 3 ++ .../server/startup/indexes.coffee | 3 ++ .../client/views/stylesheets/messagestar.less | 4 +- server/methods/pinMessage.coffee | 23 -------- server/methods/unpinMessage.coffee | 23 -------- 18 files changed, 277 insertions(+), 51 deletions(-) create mode 100644 packages/rocketchat-message-pin/client/actionButton.coffee create mode 100644 packages/rocketchat-message-pin/client/lib/PinnedMessage.coffee create mode 100644 packages/rocketchat-message-pin/client/tabBar.coffee create mode 100644 packages/rocketchat-message-pin/client/views/pinnedMessages.coffee create mode 100644 packages/rocketchat-message-pin/client/views/pinnedMessages.html create mode 100644 packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less create mode 100644 packages/rocketchat-message-pin/i18n/en.i18n.json create mode 100644 packages/rocketchat-message-pin/package.js create mode 100644 packages/rocketchat-message-pin/server/pinMessage.coffee create mode 100644 packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee create mode 100644 packages/rocketchat-message-pin/server/settings.coffee create mode 100644 packages/rocketchat-message-pin/server/startup/indexes.coffee delete mode 100644 server/methods/pinMessage.coffee delete mode 100644 server/methods/unpinMessage.coffee diff --git a/.meteor/packages b/.meteor/packages index 3d15d0183fe..50be765cc67 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -51,6 +51,7 @@ rocketchat:logger rocketchat:markdown rocketchat:me rocketchat:mentions +rocketchat:message-pin rocketchat:message-star rocketchat:oembed rocketchat:slashcommands-invite diff --git a/.meteor/versions b/.meteor/versions index 937836621ce..e1d29328f2f 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -137,6 +137,7 @@ rocketchat:logger@0.0.1 rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 +rocketchat:message-pin@0.0.1 rocketchat:message-star@0.0.1 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 603fb99ad96..7c7d85c224a 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -93,6 +93,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find query, options + findPinnedByRoom: (roomId, options) -> + query = + _hidden: { $ne: true } + pinned: true + rid: roomId + + return @find query, options + cloneAndSaveAsHistoryById: (_id) -> me = RocketChat.models.Users.findOneById Meteor.userId() record = @findOneById _id @@ -102,6 +110,11 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base record.editedBy = _id: Meteor.userId() username: me.username + message.pinned = record.pinned + message.pinnedAt = record.pinnedAt + message.pinnedBy = + _id: record.pinnedBy?._id + username: record.pinnedBy?.username delete record._id return @insert record @@ -134,15 +147,15 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @update query, update - setPinnedByIdAndUserId: (_id, userId, pinned=true) -> + setPinnedByIdAndUserId: (_id, pinnedBy, pinned=true) -> query = _id: _id - 'u._id': userId update = $set: pinned: pinned - pts: new Date + pinnedAt: new Date + pinnedBy: pinnedBy return @update query, update diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee new file mode 100644 index 00000000000..b1600f68d57 --- /dev/null +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -0,0 +1,44 @@ +Meteor.startup -> + RocketChat.MessageAction.addButton + id: 'pin-message' + icon: 'icon-pin' + i18nLabel: 'Pin_Message' + action: (event, instance) -> + message = @_arguments[1] + Meteor.call 'pinMessage', message, (error, result) -> + if error + return Errors.throw error.reason + validation: (message) -> + if message.pinned + return false + + if !RocketChat.settings.get('Message_AllowPinning') + return false + + if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' + return true + + return room.u?._id is Meteor.userId() + order: 20 + + RocketChat.MessageAction.addButton + id: 'unpin-message' + icon: 'icon-pin' + i18nLabel: 'Unpin_Message' + action: (event, instance) -> + message = @_arguments[1] + Meteor.call 'unpinMessage', message, (error, result) -> + if error + return Errors.throw error.reason + validation: (message) -> + if not message.pinned + return false + + if !RocketChat.settings.get('Message_AllowPinning') + return false + + if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' + return true + + return room.u?._id is Meteor.userId() + order: 20 diff --git a/packages/rocketchat-message-pin/client/lib/PinnedMessage.coffee b/packages/rocketchat-message-pin/client/lib/PinnedMessage.coffee new file mode 100644 index 00000000000..ff0a36d7d66 --- /dev/null +++ b/packages/rocketchat-message-pin/client/lib/PinnedMessage.coffee @@ -0,0 +1 @@ +@PinnedMessage = new Meteor.Collection 'rocketchat_pinned_message' diff --git a/packages/rocketchat-message-pin/client/tabBar.coffee b/packages/rocketchat-message-pin/client/tabBar.coffee new file mode 100644 index 00000000000..f4b8d24a66b --- /dev/null +++ b/packages/rocketchat-message-pin/client/tabBar.coffee @@ -0,0 +1,5 @@ +Meteor.startup -> + RocketChat.callbacks.add 'enter-room', -> + 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' diff --git a/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee new file mode 100644 index 00000000000..c60783c49ef --- /dev/null +++ b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee @@ -0,0 +1,21 @@ +Template.pinnedMessages.helpers + hasMessages: -> + return PinnedMessage.find({ rid: this.rid }, { sort: { ts: -1 } }).count() > 0 + + messages: -> + return PinnedMessage.find { rid: this.rid }, { sort: { ts: -1 } } + + notReadySubscription: -> + return 'notready' unless Template.instance().subscriptionsReady() + +Template.pinnedMessages.onCreated -> + this.autorun => + this.subscribe 'pinnedMessages', Template.currentData().rid + +Template.pinnedMessages.events + 'click .message-cog': (e) -> + e.stopPropagation() + e.preventDefault() + message_id = $(e.currentTarget).closest('.message').attr('id') + $('.message-dropdown:visible').hide() + $(".pinned-messages-list \##{message_id} .message-dropdown").show() diff --git a/packages/rocketchat-message-pin/client/views/pinnedMessages.html b/packages/rocketchat-message-pin/client/views/pinnedMessages.html new file mode 100644 index 00000000000..d1c470c7f41 --- /dev/null +++ b/packages/rocketchat-message-pin/client/views/pinnedMessages.html @@ -0,0 +1,22 @@ +<template name="pinnedMessages"> + <div class="control"> + <div class="header"> + <h2>{{_ "Pinned_Messages"}}</h2> + </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 new file mode 100644 index 00000000000..de3c15683ba --- /dev/null +++ b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less @@ -0,0 +1,26 @@ +.pinned-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; + } + } + + li.empty { + color: #7f7f7f; + text-align: center; + margin-top: 60px; + } + + .message-cog-container { + .edit-message, .delete-message, .star-message, .unstar-message { + display: none !important; + } + } +} diff --git a/packages/rocketchat-message-pin/i18n/en.i18n.json b/packages/rocketchat-message-pin/i18n/en.i18n.json new file mode 100644 index 00000000000..4568852052a --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/en.i18n.json @@ -0,0 +1,10 @@ +{ + "Message_AllowPinning" : "Allow Message Pinning", + "Message_AllowPinning_Description": "Allow messages to be pinned to any of the channels.", + "Message_AllowPinningByAnyone": "Allow Anyone to Pin Messages", + "Message_AllowPinningByAnyone_Description": "If true, anyone will be able to pin a messages in any channels but if false then only channel owners and admins will be allowed to.", + "Pin_Message" : "Pin Message", + "Unpin_Message" : "Unpin Message", + "Pinned_Messages" : "Pinned Messages", + "No_pinned_messages" : "No pinned messages" +} diff --git a/packages/rocketchat-message-pin/package.js b/packages/rocketchat-message-pin/package.js new file mode 100644 index 00000000000..69f0358da29 --- /dev/null +++ b/packages/rocketchat-message-pin/package.js @@ -0,0 +1,48 @@ +Package.describe({ + name: 'rocketchat:message-pin', + version: '0.0.1', + summary: 'Pin Messages' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'less@2.5.0', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles([ + 'client/lib/PinnedMessage.coffee', + 'client/actionButton.coffee', + 'client/tabBar.coffee', + 'client/views/pinnedMessages.html', + 'client/views/pinnedMessages.coffee', + 'client/views/stylesheets/messagepin.less', + ], 'client'); + + api.addFiles([ + 'server/settings.coffee', + 'server/pinMessage.coffee', + 'server/publications/pinnedMessages.coffee', + 'server/startup/indexes.coffee' + ], 'server'); + + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-message-pin/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-message-pin/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use(["tap:i18n@1.5.1"], ["client", "server"]); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles, ["client", "server"]); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-message-pin/server/pinMessage.coffee b/packages/rocketchat-message-pin/server/pinMessage.coffee new file mode 100644 index 00000000000..7a62e55f3da --- /dev/null +++ b/packages/rocketchat-message-pin/server/pinMessage.coffee @@ -0,0 +1,53 @@ +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' + + 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 + + me = RocketChat.models.Users.findOneById Meteor.userId() + + message.pinned = true + message.pinnedAt = Date.now + message.pinnedBy = + _id: Meteor.userId() + username: me.username + + message = RocketChat.callbacks.run 'beforeSaveMessage', message + + RocketChat.models.Messages.setPinnedByIdAndUserId message._id, message.pinnedBy, message.pinned + + unpinMessage: (message) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] unpinMessage -> Invalid user") + + 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 + + me = RocketChat.models.Users.findOneById Meteor.userId() + + message.pinned = false + message.pinnedBy = + _id: Meteor.userId() + username: me.username + + message = RocketChat.callbacks.run 'beforeSaveMessage', message + + RocketChat.models.Messages.setPinnedByIdAndUserId message._id, message.pinnedBy, message.pinned + + + # Meteor.defer -> + # RocketChat.callbacks.run 'afterSaveMessage', RocketChat.models.Messages.findOneById(message.id) diff --git a/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee new file mode 100644 index 00000000000..7daf7a32bd5 --- /dev/null +++ b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee @@ -0,0 +1,21 @@ +Meteor.publish 'pinnedMessages', (rid, options = {}) -> + 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 + added: (_id, record) -> + publication.added('rocketchat_pinned_message', _id, record) + + changed: (_id, record) -> + publication.changed('rocketchat_pinned_message', _id, record) + + removed: (_id) -> + publication.removed('rocketchat_pinned_message', _id) + + @ready() + @onStop -> + cursorHandle.stop() diff --git a/packages/rocketchat-message-pin/server/settings.coffee b/packages/rocketchat-message-pin/server/settings.coffee new file mode 100644 index 00000000000..364d316c894 --- /dev/null +++ b/packages/rocketchat-message-pin/server/settings.coffee @@ -0,0 +1,3 @@ +Meteor.startup -> + RocketChat.settings.add 'Message_AllowPinning', true, { type: 'boolean', group: 'Message', public: true } + RocketChat.settings.add 'Message_AllowPinningByAnyone', false, { type: 'boolean', group: 'Message', public: true } diff --git a/packages/rocketchat-message-pin/server/startup/indexes.coffee b/packages/rocketchat-message-pin/server/startup/indexes.coffee new file mode 100644 index 00000000000..c008b0c3657 --- /dev/null +++ b/packages/rocketchat-message-pin/server/startup/indexes.coffee @@ -0,0 +1,3 @@ +Meteor.startup -> + Meteor.defer -> + RocketChat.models.Messages.tryEnsureIndex { 'pinnedBy._id': 1 }, { sparse: 1 } diff --git a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less index 1750399d391..b31cb69553a 100644 --- a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less +++ b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less @@ -19,8 +19,8 @@ } .message-cog-container { - .edit-message, .delete-message { + .edit-message, .delete-message, .pin-message, .unpin-message { display: none !important; } - } + } } diff --git a/server/methods/pinMessage.coffee b/server/methods/pinMessage.coffee deleted file mode 100644 index 727e230fc09..00000000000 --- a/server/methods/pinMessage.coffee +++ /dev/null @@ -1,23 +0,0 @@ -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" - - console.log '[methods] pinMessage -> '.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 message._id - - message.pinned = true - - message = RocketChat.callbacks.run 'beforeSaveMessage', message - - RocketChat.models.Messages.setPinnedByIdAndUserId message._id, Meteor.userId(), message.pinned - - - # Meteor.defer -> - # RocketChat.callbacks.run 'afterSaveMessage', RocketChat.models.Messages.findOneById(message.id) diff --git a/server/methods/unpinMessage.coffee b/server/methods/unpinMessage.coffee deleted file mode 100644 index 5381b5b796a..00000000000 --- a/server/methods/unpinMessage.coffee +++ /dev/null @@ -1,23 +0,0 @@ -Meteor.methods - unpinMessage: (message) -> - if not Meteor.userId() - throw new Meteor.Error('invalid-user', "[methods] unpinMessage -> Invalid user") - - if not RocketChat.settings.get 'Message_AllowPinning' - throw new Meteor.Error 'message-pinning-not-allowed', "[methods] unpinMessage -> Message pinning not allowed" - - console.log '[methods] unpinMessage -> '.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 message._id - - message.pinned = false - - message = RocketChat.callbacks.run 'beforeSaveMessage', message - - RocketChat.models.Messages.setPinnedByIdAndUserId message._id, Meteor.userId(), message.pinned - - - # Meteor.defer -> - # RocketChat.callbacks.run 'afterSaveMessage', RocketChat.models.Messages.findOneById(message.id) -- GitLab From 4f5d309102a4a5c440c6a5dfc545f261ec9ffa0a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 11 Nov 2015 23:15:42 -0200 Subject: [PATCH 0386/1338] there is no message to update yet --- packages/rocketchat-livechat/app/client/lib/chatMessages.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee index 2f3b198b310..2cee37e8e78 100644 --- a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee +++ b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee @@ -95,12 +95,10 @@ class @ChatMessages if not Meteor.userId() Meteor.call 'registerGuest', visitor.getToken(), (error, result) -> if error? - ChatMessage.update msgObject._id, { $set: { error: true } } return showError error.reason Meteor.loginWithPassword result.user, result.pass, (error) -> if error - ChatMessage.update msgObject._id, { $set: { error: true } } return showError error.reason sendMessage() -- GitLab From 78b3d9c01f8a5a5c7772c766888ece225743d04c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 11 Nov 2015 23:28:30 -0200 Subject: [PATCH 0387/1338] update old build script --- build-old.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build-old.sh b/build-old.sh index 1ae834b842a..11571d29951 100755 --- a/build-old.sh +++ b/build-old.sh @@ -1,9 +1,8 @@ #!/bin/bash source ./build-info.sh export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat -meteor add rocketchat:hubot meteor add-platform ios +meteor add rocketchat:livechat rocketchat:hubot meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat cd /var/www/rocket.chat/bundle/programs/server npm install -- GitLab From 064d54d9cbde363076c87fbbe8ecba4a1cf8ac3b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 11 Nov 2015 23:31:25 -0200 Subject: [PATCH 0388/1338] meteor update --- .meteor/versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index cfb8b8accef..b614712a8a3 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -58,8 +58,8 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 kadira:blaze-layout@2.2.0 -kadira:flow-router@2.8.0 -kenton:accounts-sandstorm@0.1.7 +kadira:flow-router@2.9.0 +kenton:accounts-sandstorm@0.1.8 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 konecty:change-case@2.3.0 -- GitLab From f3e8ba980a5118066b970fc9f45142c2038b030a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 12 Nov 2015 02:00:59 +0000 Subject: [PATCH 0389/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/de.i18n.json | 4 ++-- i18n/el.i18n.json | 4 ++-- i18n/en.i18n.json | 4 ++-- i18n/fa.i18n.json | 1 + i18n/fi.i18n.json | 12 ++++++------ i18n/fr.i18n.json | 4 ++-- i18n/km.i18n.json | 4 ++-- i18n/ko.i18n.json | 4 ++-- i18n/ms-MY.i18n.json | 4 ++-- i18n/pl.i18n.json | 4 ++-- i18n/pt.i18n.json | 4 ++-- i18n/ru.i18n.json | 4 ++-- i18n/tr.i18n.json | 4 ++-- i18n/zh.i18n.json | 4 ++-- packages/rocketchat-chatops/i18n/fa.i18n.json | 1 + .../rocketchat-github-enterprise/i18n/fa.i18n.json | 1 + packages/rocketchat-gitlab/i18n/fa.i18n.json | 1 + packages/rocketchat-hubot/i18n/fa.i18n.json | 1 + packages/rocketchat-livechat/i18n/fa.i18n.json | 1 + packages/rocketchat-message-star/i18n/fa.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../rocketchat-slashcommands-join/i18n/fa.i18n.json | 1 + packages/rocketchat-webrtc-ib/i18n/fa.i18n.json | 1 + packages/rocketchat-webrtc/i18n/fa.i18n.json | 1 + packages/rocketchat-wordpress/i18n/fa.i18n.json | 1 + 25 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 i18n/fa.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/fa.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/fa.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/fa.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/fa.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/fa.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/fa.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/fa.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/fa.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/fa.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/fa.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/fa.i18n.json diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 117f5c7df70..5af137e6794 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -137,7 +137,9 @@ "inline_code" : "inline_code", "Install_FxOs" : "Installiere Rocket.Chat auf deinem Firefox", "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App (drücke \"Installieren\" in der Aufforderung).", + "LDAP_Port" : "LDAP Port", "Install_FxOs_done" : "Super! Du kannst Rocket.Chat nun über das Icon auf deinem Startbildschirm nutzen. Viel Spaß mit Rocket.Chat!", + "LDAP_Url" : "LDAP URL", "Install_FxOs_error" : "Schade, das hat leider nicht geklappt! Der folgende Fehler ist aufgetreten:", "Invalid_confirm_pass" : "Die Passwörter stimmen nicht überein", "Invalid_email" : "Email-Adresse ungültigt", @@ -173,8 +175,6 @@ "Layout_Terms_of_Service" : "Nutzungsbedingungen", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", - "LDAP_Port" : "LDAP Port", - "LDAP_Url" : "LDAP URL", "Leave_room" : "Raum verlassen", "line" : "Zeilen", "Load_more" : "Mehr laden", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 16134efdb1f..0dfa868553e 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -89,6 +89,8 @@ "History" : "ΙστοÏικό", "hours" : "ÏŽÏες", "inline_code" : "γÏαμμή κώδικα", + "LDAP_Port" : "LDAP ΘÏÏα", + "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "Η επιβεβαίωση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î´ÎµÎ½ ταιÏιάζει με τον αÏχικό κωδικό", "Invalid_email" : "Το e-mail που δώσατε δεν είναι ÎγκυÏο", "Invalid_name" : "Το όνομα δεν Ï€ÏÎπει να Îιναι κενό", @@ -112,8 +114,6 @@ "Layout_Home_Body" : "ΑÏχική Σώμα", "Layout_Home_Title" : "ΑÏχική Τίτλος", "LDAP_DN" : "LDAP DN", - "LDAP_Port" : "LDAP ΘÏÏα", - "LDAP_Url" : "LDAP URL", "Leave_room" : "Έξοδος από το δωμάτιο", "line" : "γÏαμμÎÏ‚", "Load_more" : "ΦόÏτωση πεÏισσότεÏων", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 5abc995c31a..21bfd68cb4e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -153,7 +153,9 @@ "inline_code" : "inline_code", "Install_FxOs" : "Install Rocket.Chat on your Firefox", "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", + "LDAP_Port" : "LDAP Port", "Install_FxOs_done" : "Great! You can now use Rocket.Chat via the icon on your homescreen. Have fun with Rocket.Chat!", + "LDAP_Url" : "LDAP URL", "Install_FxOs_error" : "Sorry, that did not work as intended! The following error appeared:", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_email" : "The e-mail entered is invalid", @@ -195,13 +197,11 @@ "LDAP_DN_Description" : "Search root; example: dc=domain,dc=com", "LDAP_Enable" : "Enable LDAP", "LDAP_Enable_Description" : "Attempt to utilize ldap for authentication.", - "LDAP_Port" : "LDAP Port", "LDAP_Port_Description" : "Port to access LDAP on; eg: 389", "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" : "Allows configuring how to populate user account fields (like email) from a record in ldap (once found). As an example, {\"cn\":\"name\", \"mail\":\"email\"} will choose a persion's human readable name from the cn attribute, and their email from the mail attribute. Available fields include name, and email.", - "LDAP_Url" : "LDAP URL", "LDAP_Url_Description" : "Uri of the ldap server; example: ldap://company.dns.com", "Leave_room" : "Leave room", "line" : "line", diff --git a/i18n/fa.i18n.json b/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 144a5e0bd52..4ba8e67c83e 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -1,7 +1,7 @@ { "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", - "Accounts" : "Tilit", + "Accounts" : "Käyttäjätilit", "Accounts_AllowedDomainsList" : "Pilkkueroteltu lista sallituista domaineista", "Accounts_AllowUsernameChange" : "Salli käyttäjätunnuksen muuttaminen", "Accounts_AllowPasswordChange" : "Salli salasanan vaihto", @@ -139,7 +139,7 @@ "Follow_social_profiles" : "Seuraa someamme, forkkaa Githubissa ja jaa ajatuksiasi rocket.chatista trellossa.", "Forgot_password" : "Unohditko salasanasi?", "Fork_it_on_github" : "Forkkaa GitHubissa", - "From_Email" : "Sähköpostista", + "From_Email" : "Sähköpostin lähettäjä", "General" : "Yleinen", "Get_to_know_the_team" : "Tutustu Rocket.Teamiin", "github_no_public_email" : "GitHub-tunnukseltasi ei löydy julkisia sähköpostiosoitetietoja", @@ -153,7 +153,9 @@ "inline_code" : "koodi", "Install_FxOs" : "Asenna Rocket.Chat Firefoxiisi", "Install_FxOs_follow_instructions" : "Vahvista sovelluksen asennus laitteellasi (paina \"Install\" käskettäessä)", + "LDAP_Port" : "LDAP portti", "Install_FxOs_done" : "Hienoa! Voit käyttää nyt Rocket.Chatiä etusivulla olevan kuvakkeen kautta. Pidä kivaa!", + "LDAP_Url" : "LDAP URL", "Install_FxOs_error" : "Pahoittelut, asennus ei onnistunut, seuraava virhe ilmeni:", "Invalid_confirm_pass" : "Salasanat eivät täsmää", "Invalid_email" : "Annettu sähköpostiosoite ei ole oikea", @@ -195,13 +197,11 @@ "LDAP_DN_Description" : "Etsintäpolku, esimerkiksi: dc = domain, dc = com", "LDAP_Enable" : "Kytke LDAP päälle", "LDAP_Enable_Description" : "Käytä LDAPia autentikointiin", - "LDAP_Port" : "LDAP portti", "LDAP_Port_Description" : "LDAP-portti (esim 389)", "LDAP_Sync_User_Data" : "Synkronoi käyttäjädata", "LDAP_Sync_User_Data_Description" : "Pidä käyttäjädata synkronoituna palvelimelta kirjautumishetkellä (esim nimi, sähköposti)", "LDAP_Sync_User_Data_FieldMap" : "Käyttäjätietojen kohdistus", "LDAP_Sync_User_Data_FieldMap_Description" : "Määrittää, miten käyttäjätietojen kentät tuodaan LDAP-palvelimelta.\nEsimerkiksi, {\"cn\":\"name\", \"mail\":\"email\"} -määritys tuo käyttäjän nimen cn-tiedosta ja sähköpostin email-tiedosta. Käytettävissä olevat kentät ovat \"name\" ja \"email\".", - "LDAP_Url" : "LDAP URL", "LDAP_Url_Description" : "LDAP-palvelimen URI, esimerkiksi: ldap://company.example.com", "Leave_room" : "Poistu kanavalta", "line" : "riviä", @@ -219,7 +219,7 @@ "Members" : "Jäsenet", "Members_List" : "Jäsenlista", "Members_placeholder" : "Jäsenet", - "Message" : "Viesti", + "Message" : "Viestit", "Message_AllowDeleting" : "Salli viestin poisto", "Message_AllowEditing" : "Salli viestin muokkaus", "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus (x) minuutin jälkeen", @@ -290,7 +290,7 @@ "Preferences" : "Asetukset", "Preferences_saved" : "Asetukset tallennettu", "Privacy" : "Yksityisyys", - "Private_Groups" : "Privaatiryhmät", + "Private_Groups" : "Privaattiryhmät", "Private_Groups_list" : "Privaattiryhmäluettelo", "Profile" : "Profiili", "Profile_saved_successfully" : "Profiili tallennettu onnistuneesti", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 0c1046c4a71..9cf51047ebc 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -127,6 +127,8 @@ "hours" : "heures", "Incorrect_Password" : "Mot de passe incorrect", "inline_code" : "Ligne de code", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "Adresse LDAP", "Invalid_confirm_pass" : "Les mots de passe renseignés ne sont pas les mêmes", "Invalid_email" : "L'adresse email saisie est invalide", "Invalid_name" : "Le nom doit être renseigné", @@ -161,8 +163,6 @@ "Layout_Terms_of_Service" : "Conditions de service", "LDAP" : "LDAP", "LDAP_DN" : "DN LDAP", - "LDAP_Port" : "Port LDAP", - "LDAP_Url" : "Adresse LDAP", "Leave_room" : "Quitter le salon", "line" : "ligne", "Load_more" : "Charger plus", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index e12c2f83d1f..6e7b111924d 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -150,7 +150,9 @@ "inline_code" : "inline_code", "Install_FxOs" : "ដំឡើង Rocket.Chat នៅ​លើ Firefox របស់​អ្នក", "Install_FxOs_follow_instructions" : "សូមបញ្ជាក់ការដំឡើងកម្មវិធីនáŸáŸ‡áž“ៅលើឧបករណáŸážšáž”ស់អ្នក(ចុច \"Install\" áž–áŸáž›áž”ញ្ចាក់)", + "LDAP_Port" : "ច្រក LDAP", "Install_FxOs_done" : "អស្ចារ្យណាស់ឥឡូវអ្នកអាចប្រើប្រាស់ Rocket.Chat ážáž¶áž˜ážšáž™áŸˆ Icon នៅលើ Homescreen។ សូមរីករាយជាមួយ Rocket.Chat!", + "LDAP_Url" : "URL របស់ LDAP", "Install_FxOs_error" : "សុំទោស ដែលវាមិនដំណើរការážážŽáŸˆáž˜áž¶áž“បញ្ហាលáŸáž…ឡើងដូចážáž¶áž„ក្រោម", "Invalid_confirm_pass" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ញ្ជាក់​មិន​ដូច​ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​បញ្ចូល​", "Invalid_email" : "អ៊ី​មែល​ដែល​បញ្ចូល​មិន​ážáŸ’រឹម​ážáŸ’រូវ", @@ -188,9 +190,7 @@ "LDAP_Bind_Search" : "ចំណងស្វែងរក", "LDAP_DN" : " LDAP DN", "LDAP_Enable" : "អនុញ្ញាážáž· LDAP", - "LDAP_Port" : "ច្រក LDAP", "LDAP_Sync_User_Data" : "រក្សាទិន្ននáŸáž™ User ដោយ Sync ជាមួយ Server", - "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", "Load_more" : "មើល​ទៀáž", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index d6239451b3a..af366b1cf05 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -120,6 +120,8 @@ "hours" : "시간", "Incorrect_Password" : "ìž˜ëª»ëœ ì•”í˜¸", "inline_code" : "inline_code", + "LDAP_Port" : "LDAP í¬íŠ¸", + "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "암호가 ì¼ì¹˜í•˜ì§€ 않습니다", "Invalid_email" : "ìž…ë ¥í•œ ì´ë©”ì¼ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤", "Invalid_name" : "ì´ë¦„ì„ ë¹„ì›Œ 둘 수 없습니다", @@ -154,8 +156,6 @@ "Layout_Terms_of_Service" : "ì´ìš©ì•½ê´€", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", - "LDAP_Port" : "LDAP í¬íŠ¸", - "LDAP_Url" : "LDAP URL", "Leave_room" : "ë°© 나가기", "line" : "밑줄", "Load_more" : "ë” ë³´ê¸°", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 8bafffc9e7f..ab45c915178 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -120,6 +120,8 @@ "History" : "Sejarah", "hours" : "jam", "Incorrect_Password" : "Kata Laluan salah", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "URL LDAP", "Invalid_confirm_pass" : "Pengesahan kata laluan tidak sepadan dengan kata laluan", "Invalid_email" : "E-mel yang dimasukkan tidak sah", "Invalid_name" : "Nama mesti tidak dikosongkan", @@ -153,8 +155,6 @@ "Layout_Terms_of_Service" : "Terma Perkhidmatan", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", - "LDAP_Port" : "Port LDAP", - "LDAP_Url" : "URL LDAP", "Leave_room" : "Meninggalkan bilik", "line" : "garis", "Load_more" : "Memuat lagi", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index c3f99d81122..e4c31ed3289 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -82,6 +82,8 @@ "Hide_room" : "Ukryj pokój", "History" : "Historia", "inline_code" : "inline", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "Adres URL LDAP", "Invalid_confirm_pass" : "Podane hasÅ‚a nie sÄ… jednakowe", "Invalid_email" : "E-mail jest nieprawidÅ‚owy", "Invalid_name" : "Nazwa nie może być pusta", @@ -107,8 +109,6 @@ "Layout_Home_Body" : "Treść strony głównej", "Layout_Home_Title" : "TytuÅ‚ strony głównej", "LDAP_DN" : "LDAP DN", - "LDAP_Port" : "Port LDAP", - "LDAP_Url" : "Adres URL LDAP", "Leave_room" : "Opuść pokój", "line" : "linia", "Load_more" : "WiÄ™cej", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 8b257039aa2..5815821369a 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -141,6 +141,8 @@ "hours" : "horas", "Incorrect_Password" : "Senha incorreta", "inline_code" : "código", + "LDAP_Port" : "Porta LDAP", + "LDAP_Url" : "URL LDAP", "Invalid_confirm_pass" : "A confirmação de senha não é igual à senha", "Invalid_email" : "O e-mail informado é inválido", "Invalid_name" : "O nome não pode ser vazio", @@ -175,10 +177,8 @@ "Layout_Terms_of_Service" : "Termos de Serviço", "LDAP" : "LDAP", "LDAP_DN" : "DN LDAP", - "LDAP_Port" : "Porta LDAP", "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", "LDAP_Sync_User_Data_FieldMap" : "Mapeamento de campos do usuário", - "LDAP_Url" : "URL LDAP", "Leave_room" : "Sair da sala", "line" : "linha", "Load_more" : "Carregar mais", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 1cb2a8f913f..311d6500653 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -75,6 +75,8 @@ "History" : "ИÑториÑ", "hours" : "чаÑ(Ñ‹)", "inline_code" : "внутренний код", + "LDAP_Port" : "LDAP Порт", + "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Invalid_confirm_pass" : "Пароли не Ñовпадают", "Invalid_email" : "Ðеверный e-mail", "Invalid_name" : "Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым", @@ -98,8 +100,6 @@ "Layout_Privacy_Policy" : "Политика конфиденциальноÑти", "Layout_Terms_of_Service" : "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ÑпользованиÑ", "LDAP_DN" : "LDAP домен", - "LDAP_Port" : "LDAP Порт", - "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Leave_room" : "Покинуть чат", "line" : "линиÑ", "Load_more" : "Загрузить еще", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 959b8388524..e8bcbecfba9 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -76,6 +76,8 @@ "History" : "GeçmiÅŸ", "hours" : "saat", "inline_code" : "kod_satırı", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "Åžifreler eÅŸleÅŸmiyor", "Invalid_email" : "Girilen e-posta geçersiz", "Invalid_name" : "Ä°sim boÅŸ bırakılamaz", @@ -97,8 +99,6 @@ "Last_login" : "Son giriÅŸ", "Last_message" : "Son mesaj", "Layout_Home_Title" : "Anasayfa baÅŸlığı", - "LDAP_Port" : "LDAP Port", - "LDAP_Url" : "LDAP URL", "Leave_room" : "Odayı terket", "line" : "satır", "Load_more" : "Daha fazla", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index 8501a5a2a43..719deed685a 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -89,6 +89,8 @@ "Hide_room" : "éšè—èŠå¤©å®¤", "History" : "历å²", "hours" : "å°æ—¶", + "LDAP_Port" : "LDAP端å£", + "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "第二次密ç 输入与第一次ä¸åŒ¹é…", "Invalid_email" : "æ— æ•ˆçš„ç”µå邮件", "Invalid_name" : "用户åä¸èƒ½ä¸ºç©º", @@ -122,8 +124,6 @@ "Layout_Terms_of_Service" : "æœåŠ¡æ¡æ¬¾", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", - "LDAP_Port" : "LDAP端å£", - "LDAP_Url" : "LDAP URL", "Leave_room" : "离开èŠå¤©å®¤", "Load_more" : "åŠ è½½æ›´å¤š", "Loading_more_from_history" : "åŠ è½½æ›´å¤š", diff --git a/packages/rocketchat-chatops/i18n/fa.i18n.json b/packages/rocketchat-chatops/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/fa.i18n.json b/packages/rocketchat-github-enterprise/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/fa.i18n.json b/packages/rocketchat-gitlab/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/fa.i18n.json b/packages/rocketchat-hubot/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/fa.i18n.json b/packages/rocketchat-livechat/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/fa.i18n.json b/packages/rocketchat-message-star/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/fa.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/fa.i18n.json b/packages/rocketchat-slashcommands-join/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fa.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/fa.i18n.json b/packages/rocketchat-webrtc/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/fa.i18n.json b/packages/rocketchat-wordpress/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file -- GitLab From a8040a38613013db9398c2644d00d30612a0c05f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 12 Nov 2015 00:01:21 -0200 Subject: [PATCH 0390/1338] use correct settings for livechat app --- packages/rocketchat-livechat/livechat.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/rocketchat-livechat/livechat.js b/packages/rocketchat-livechat/livechat.js index efe29fc16ae..b33e6eb5909 100644 --- a/packages/rocketchat-livechat/livechat.js +++ b/packages/rocketchat-livechat/livechat.js @@ -10,14 +10,7 @@ WebApp.connectHandlers.use('/livechat/', (req, res, next) => { <head> <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/packages/rocketchat_livechat/public/livechat.css?_dc=${Autoupdate.autoupdateVersion}"> <script type="text/javascript"> - __meteor_runtime_config__ = { - "meteorRelease": "METEOR@1.1.0.2", - "ROOT_URL": "${Meteor.absoluteUrl()}", - "ROOT_URL_PATH_PREFIX": "", - "autoupdateVersion": "${Autoupdate.autoupdateVersion}", - "autoupdateVersionRefreshable": "${Autoupdate.autoupdateVersionRefreshable}", - "autoupdateVersionCordova": "${Autoupdate.autoupdateVersionCordova}" - }; + __meteor_runtime_config__ = ${JSON.stringify(__meteor_runtime_config__)}; </script> <script type="text/javascript" src="/packages/rocketchat_livechat/public/livechat.js?_dc=${Autoupdate.autoupdateVersion}"></script> -- GitLab From ec7d4562dad20dd9c3291bb9b373b9893128d9d2 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 12 Nov 2015 02:12:41 +0000 Subject: [PATCH 0391/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/de.i18n.json | 8 ++++---- i18n/el.i18n.json | 4 ++-- i18n/en.i18n.json | 8 ++++---- i18n/fa.i18n.json | 4 +++- i18n/fi.i18n.json | 8 ++++---- i18n/fr.i18n.json | 8 ++++---- i18n/hr.i18n.json | 4 ++-- i18n/km.i18n.json | 8 ++++---- i18n/ko.i18n.json | 8 ++++---- i18n/ms-MY.i18n.json | 8 ++++---- i18n/pl.i18n.json | 8 ++++---- i18n/pt.i18n.json | 8 ++++---- i18n/ru.i18n.json | 4 ++-- i18n/tr.i18n.json | 8 ++++---- i18n/zh.i18n.json | 8 ++++---- packages/rocketchat-ldap/i18n/de.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/el.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/en.i18n.json | 2 -- packages/rocketchat-ldap/i18n/fa.i18n.json | 1 + packages/rocketchat-ldap/i18n/fi.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/fr.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/km.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/ko.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/ms-MY.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/pl.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/pt.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/ru.i18n.json | 6 +----- packages/rocketchat-ldap/i18n/tr.i18n.json | 5 +---- packages/rocketchat-ldap/i18n/zh.i18n.json | 6 +----- 29 files changed, 66 insertions(+), 112 deletions(-) create mode 100644 packages/rocketchat-ldap/i18n/fa.i18n.json diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 5af137e6794..a0410acf56a 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -78,6 +78,7 @@ "Compact_View" : "Kompakte Ansicht", "Confirm_password" : "Bestätigen Sie Ihr Passwort", "Contact" : "Kontakt", + "Delete" : "Löschen", "Conversation" : "Konversation", "Convert_Ascii_Emojis" : "Konvertiere ASCII zu Emoji", "Create_new" : "Neu erstellen", @@ -90,7 +91,7 @@ "days" : "Tage", "Deactivate" : "Deaktivieren", "Delete_User_Warning" : "Beim Löschen eines Benutzers, werden alle seine Nachrichten ebenfalls gelöscht. Dies kann nicht rückgängig gemacht werden.", - "Delete" : "Löschen", + "Edit" : "Bearbeiten", "Deleted" : "Gelöscht!", "Desktop_Notifications" : "Desktop-Benachrichtigungen", "Desktop_Notifications_Enabled" : "Desktop-Benachrichtigungen sind aktiviert", @@ -102,7 +103,6 @@ "Duplicate_channel_name" : "Ein Kanal mit dem Namen, '%s', existiert", "Duplicate_private_group_name" : "Eine private Gruppe mit dem Namen, '%s', existiert", "E-mail" : "E-Mail", - "Edit" : "Bearbeiten", "edited" : "bearbeitet", "Email_already_exists" : "E-Mail existiert bereits", "Email_or_username" : "Email oder Username", @@ -122,7 +122,9 @@ "FileUpload_MediaTypeWhiteList" : "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.", "Forgot_password" : "Passwort vergessen?", + "LDAP_Port" : "LDAP Port", "Fork_it_on_github" : "Fork es auf GitHub", + "LDAP_Url" : "LDAP URL", "From_Email" : "E-Mail von", "General" : "Allgemein", "Get_to_know_the_team" : "Lernen Sie das Rocket.Team kennen", @@ -137,9 +139,7 @@ "inline_code" : "inline_code", "Install_FxOs" : "Installiere Rocket.Chat auf deinem Firefox", "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App (drücke \"Installieren\" in der Aufforderung).", - "LDAP_Port" : "LDAP Port", "Install_FxOs_done" : "Super! Du kannst Rocket.Chat nun über das Icon auf deinem Startbildschirm nutzen. Viel Spaß mit Rocket.Chat!", - "LDAP_Url" : "LDAP URL", "Install_FxOs_error" : "Schade, das hat leider nicht geklappt! Der folgende Fehler ist aufgetreten:", "Invalid_confirm_pass" : "Die Passwörter stimmen nicht überein", "Invalid_email" : "Email-Adresse ungültigt", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 0dfa868553e..5b148a28dd2 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -81,7 +81,9 @@ "Favorites" : "Αγαπημενα", "Follow_social_profiles" : "Ακολουθήστε μας στα κοινωνικά δίκτυα, κάντε μας fork στο github και μοιÏαστείτε τις σκÎψεις σας για την εφαÏμογή rocket.chat στον πίνακα trello.", "Forgot_password" : "ΞÎχασα τον κωδικό μου", + "LDAP_Port" : "LDAP ΘÏÏα", "Fork_it_on_github" : "Fork it on github", + "LDAP_Url" : "LDAP URL", "Get_to_know_the_team" : "ΓνωÏίστε την ομάδα του Rocket.Team", "github_no_public_email" : "Δεν Îχετε κανÎνα δημόσιο email στον GitHub λογαÏιασμό σας", "Have_your_own_chat" : "Αποκτήστε το δικό σας web chat. ΑναπτÏγμÎνο με το Meteor.com, το Rocket.Chat είναι μια Ï€Î¿Î»Ï ÎºÎ±Î»Î® λÏση για Ï€ÏογÏαμματιστÎÏ‚ που θÎλουν να φτιάξουν και να εξελίξουν την δικιά τους πλατφόÏμα chat.", @@ -89,8 +91,6 @@ "History" : "ΙστοÏικό", "hours" : "ÏŽÏες", "inline_code" : "γÏαμμή κώδικα", - "LDAP_Port" : "LDAP ΘÏÏα", - "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "Η επιβεβαίωση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î´ÎµÎ½ ταιÏιάζει με τον αÏχικό κωδικό", "Invalid_email" : "Το e-mail που δώσατε δεν είναι ÎγκυÏο", "Invalid_name" : "Το όνομα δεν Ï€ÏÎπει να Îιναι κενό", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 21bfd68cb4e..1cf012f42bb 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -91,6 +91,7 @@ "Compact_View" : "Compact View", "Confirm_password" : "Confirm your password", "Contact" : "Contact", + "Delete" : "Delete", "Conversation" : "Conversation", "Convert_Ascii_Emojis" : "Convert ASCII to Emoji", "Create_new" : "Create new", @@ -103,8 +104,8 @@ "days" : "days", "Deactivate" : "Deactivate", "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", + "Edit" : "Edit", "Delete_Room_Warning" : "Deleting a room will delete all messages posted within the room. This cannot be undone.", - "Delete" : "Delete", "Deleted" : "Deleted!", "Desktop_Notifications" : "Desktop Notifications", "Desktop_Notifications_Disabled" : "Desktop Notifications are Disabled. Change your browser preferences if you need Notifications enabled.", @@ -117,7 +118,6 @@ "Duplicate_channel_name" : "A Channel with name '%s' exists", "Duplicate_private_group_name" : "A Private Group with name '%s' exists", "E-mail" : "E-mail", - "Edit" : "Edit", "edited" : "edited", "Email_already_exists" : "Email already exists", "Email_or_username" : "Email or username", @@ -138,7 +138,9 @@ "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", + "LDAP_Port" : "LDAP Port", "Fork_it_on_github" : "Fork it on github", + "LDAP_Url" : "LDAP URL", "From_Email" : "From Email", "General" : "General", "Get_to_know_the_team" : "Get to know the Rocket.Team", @@ -153,9 +155,7 @@ "inline_code" : "inline_code", "Install_FxOs" : "Install Rocket.Chat on your Firefox", "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", - "LDAP_Port" : "LDAP Port", "Install_FxOs_done" : "Great! You can now use Rocket.Chat via the icon on your homescreen. Have fun with Rocket.Chat!", - "LDAP_Url" : "LDAP URL", "Install_FxOs_error" : "Sorry, that did not work as intended! The following error appeared:", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_email" : "The e-mail entered is invalid", diff --git a/i18n/fa.i18n.json b/i18n/fa.i18n.json index 6f31cf5a2e6..ff270db49a1 100644 --- a/i18n/fa.i18n.json +++ b/i18n/fa.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Accounts" : "Øساب ها" +} \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 4ba8e67c83e..aca274efb21 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -91,6 +91,7 @@ "Compact_View" : "Suppea näkymä", "Confirm_password" : "Vahvista salasanasi", "Contact" : "Yhteys", + "Delete" : "Poista", "Conversation" : "Keskustelu", "Convert_Ascii_Emojis" : "Muunna ASCII-merkit Emojiksi", "Create_new" : "Luo uusi", @@ -103,8 +104,8 @@ "days" : "päivää", "Deactivate" : "Deaktivoi", "Delete_User_Warning" : "Käyttäjän poistaminen poistaa myös käyttäjän kaikki viestit. Toimintoa ei voi perua.", + "Edit" : "Muokkaa", "Delete_Room_Warning" : "Huomeen poistaminen poistaa kaikki huoneessa olevat viestit.\nToimintoa ei voi perua.", - "Delete" : "Poista", "Deleted" : "Poistettu!", "Desktop_Notifications" : "Työpöytäilmoituksia", "Desktop_Notifications_Disabled" : "Työpöytäilmoitukset eivät ole käytössä. Muuta selaimen asetuksia mikäli haluat ilmoitukset käyttöön.", @@ -117,7 +118,6 @@ "Duplicate_channel_name" : "Kanava nimeltä '%s' on olemassa jo", "Duplicate_private_group_name" : "Privaattiryhmä '%s' on olemassa jo", "E-mail" : "Sähköpostiosoite", - "Edit" : "Muokkaa", "edited" : "muokattu", "Email_already_exists" : "Sähköpostiosoite on jo olemassa", "Email_or_username" : "Sähköpostiosoite tai käyttäjänimi", @@ -138,7 +138,9 @@ "FileUpload_MediaTypeWhiteListDescription" : "Pilkkueroteltu lista mediatyypeistä", "Follow_social_profiles" : "Seuraa someamme, forkkaa Githubissa ja jaa ajatuksiasi rocket.chatista trellossa.", "Forgot_password" : "Unohditko salasanasi?", + "LDAP_Port" : "LDAP portti", "Fork_it_on_github" : "Forkkaa GitHubissa", + "LDAP_Url" : "LDAP URL", "From_Email" : "Sähköpostin lähettäjä", "General" : "Yleinen", "Get_to_know_the_team" : "Tutustu Rocket.Teamiin", @@ -153,9 +155,7 @@ "inline_code" : "koodi", "Install_FxOs" : "Asenna Rocket.Chat Firefoxiisi", "Install_FxOs_follow_instructions" : "Vahvista sovelluksen asennus laitteellasi (paina \"Install\" käskettäessä)", - "LDAP_Port" : "LDAP portti", "Install_FxOs_done" : "Hienoa! Voit käyttää nyt Rocket.Chatiä etusivulla olevan kuvakkeen kautta. Pidä kivaa!", - "LDAP_Url" : "LDAP URL", "Install_FxOs_error" : "Pahoittelut, asennus ei onnistunut, seuraava virhe ilmeni:", "Invalid_confirm_pass" : "Salasanat eivät täsmää", "Invalid_email" : "Annettu sähköpostiosoite ei ole oikea", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 9cf51047ebc..c448b6f0f8d 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -74,6 +74,7 @@ "Commands" : "Commandes", "Confirm_password" : "Confirmez votre mot de passe", "Contact" : "Contact", + "Delete" : "Supprimer", "Conversation" : "Conversation", "Convert_Ascii_Emojis" : "Convertir code ASCII vers émoticônes", "Create_new" : "Créer nouveau", @@ -86,7 +87,7 @@ "days" : "jours", "Deactivate" : "Désactiver", "Delete_User_Warning" : "Supprimer un utilisateur va également supprimer tous les messages de celui-ci. Cette action ne peut être annulée.", - "Delete" : "Supprimer", + "Edit" : "Modifier", "Deleted" : "Supprimé !", "Desktop_Notifications" : "Notifications sur le bureau", "Desktop_Notifications_Disabled" : "Les notifications du bureau sont désactivées, Modifiez les préférences de votre navigateur si vous avez besoin de les activer.", @@ -99,7 +100,6 @@ "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", - "Edit" : "Modifier", "edited" : "modifié", "Email_already_exists" : "L'adresse email existe déjà ", "Email_or_username" : "Adresse email ou nom d'utilisateur", @@ -114,7 +114,9 @@ "Favorites" : "Favoris", "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é", + "LDAP_Port" : "Port LDAP", "Fork_it_on_github" : "Cloner sur GitHub", + "LDAP_Url" : "Adresse LDAP", "From_Email" : "De", "General" : "Général", "Get_to_know_the_team" : "Venez nous rencontrer", @@ -127,8 +129,6 @@ "hours" : "heures", "Incorrect_Password" : "Mot de passe incorrect", "inline_code" : "Ligne de code", - "LDAP_Port" : "Port LDAP", - "LDAP_Url" : "Adresse LDAP", "Invalid_confirm_pass" : "Les mots de passe renseignés ne sont pas les mêmes", "Invalid_email" : "L'adresse email saisie est invalide", "Invalid_name" : "Le nom doit être renseigné", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 439b5db8e47..50a645a054d 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -54,6 +54,7 @@ "coming_soon" : "dolazi uskoro", "Confirm_password" : "Potvrdi svoju lozinku", "Contact" : "Kontakt", + "Delete" : "ObriÅ¡i", "Conversation" : "Razgovor", "Convert_Ascii_Emojis" : "Pretvori ASCII u Emoji", "Create_new" : "Stvori novi", @@ -64,8 +65,8 @@ "days" : "dana", "Deactivate" : "IskljuÄi", "Delete_User_Warning" : "Brisanje korisnika će izbrisati i sve poruke od tog korisnika. Ovo se ne može poniÅ¡titi.", + "Edit" : "Uredi", "Delete_Room_Warning" : "Brisanje sobe će obrisati sve poruke u toj sobi. Ovo se ne može poniÅ¡titi.", - "Delete" : "ObriÅ¡i", "Deleted" : "Obrisano!", "Direct_Messages" : "Izravne Poruke", "Disable_Favorite_Rooms" : "Onemogući favorite", @@ -75,7 +76,6 @@ "Duplicate_channel_name" : "Kanal s nazivom '% s' postoji", "Duplicate_private_group_name" : "Privatna Grupa s nazivom '% s' postoji", "E-mail" : "E-mail", - "Edit" : "Uredi", "edited" : "ureÄ‘eno", "Email_already_exists" : "Email već postoji", "Email_or_username" : "Email or username", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 6e7b111924d..540a8098d32 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -88,6 +88,7 @@ "Compact_View" : "មើលជាážáž¶ážšáž¶áž„", "Confirm_password" : "បញ្ជាក់​ពាក្យ​សម្ងាážáŸ‹", "Contact" : "ទំនាក់ទំនង", + "Delete" : "លុប", "Conversation" : "កិច្ច​ពិភាក្សា", "Convert_Ascii_Emojis" : "បម្លែង ASCII áž“áŸáŸ‡â€‹áž‘ៅ Emoji", "Create_new" : "បង្កើážâ€‹ážáŸ’មី", @@ -100,8 +101,8 @@ "days" : "ážáŸ’ងៃ", "Deactivate" : "ធ្វើឲ្យមិនសកម្ម", "Delete_User_Warning" : "ការ​លប់​អ្នក​ប្រើប្រាស់ នឹង​ážáŸ’រូវ​លប់​​គ្រប់​សារ​​របស់​​គាážáŸ‹â€‹áž•áž„​ដែរ។ ដូច​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ធ្វើ​បាន​ទ០។", + "Edit" : "កែ​សម្រួល", "Delete_Room_Warning" : "ការលប់បន្ទប់មួយនឹងážáŸ’រូវលប់ចោលទាំងអស់នូវរាល់សារដែលបានប្រកាសនៅក្នុងបន្ទប់នáŸáŸ‡, ដំណើរការនáŸáŸ‡áž˜áž·áž“ទាន់បានបញ្ចប់ទáŸ", - "Delete" : "លុប", "Deleted" : "បាន​លប់!", "Desktop_Notifications" : "ជំនូនដំណឹងលើ Desktop", "Desktop_Notifications_Disabled" : "ជំនូនដំណឹងលើ Desktop មិនបានអនុញ្ញាážáž·, សូមផ្លាស់ប្ážáž¼ážšáž€áž¶ážšáž€áŸ†ážŽážáŸ‹áž“ៅលើ Browser របស់អ្នកប្រសិនបើចង់អនុញ្ញážáž·ážœáž¶", @@ -114,7 +115,6 @@ "Duplicate_channel_name" : "ប៉ុស្ážáž·áŸâ€‹ážŠáŸ‚ល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "Duplicate_private_group_name" : "ក្រុម​ឯក​ជន​ដែល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "E-mail" : "អ៊ីមែល", - "Edit" : "កែ​សម្រួល", "edited" : "បានកែសម្រួល", "Email_already_exists" : "អ៊ី​ម៉ែ​ល​ដែល​មាន​រួច​ហើយ", "Email_or_username" : "អ៊ីមែល ឬឈ្មោះ​សម្ងាážáŸ‹", @@ -135,7 +135,9 @@ "FileUpload_MediaTypeWhiteListDescription" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែងប្រភáŸáž‘ Media ក្នុងបញ្ជី", "Follow_social_profiles" : "ážáž¶áž˜â€‹ážŠáž¶áž“​​​បណ្ážáž¶â€‹áž‚ណនីបណ្ážáž¶áž‰â€‹ážŸáž„្គម​របស់​យើង​, មើល​យើង​លើ​ github និង​ចែក​រំលែក​បទពិសោធនáŸâ€‹ážšáž”ស់​អ្នក​ជាមួយ​ rocket.chat app នៅ​លើ​ក្ážáž¶ážšážƒáŸ€áž“​របស់​យើង", "Forgot_password" : "ភ្លáŸáž…​ពាក្យ​សម្ងាážáŸ‹", + "LDAP_Port" : "ច្រក LDAP", "Fork_it_on_github" : "ទៅ​មើល​វា​លើ github", + "LDAP_Url" : "URL របស់ LDAP", "From_Email" : "ពី​អ៊ី​ម៉ែ​ល", "General" : "ទូទៅ", "Get_to_know_the_team" : "ទៅ​ស្គាល់ Rocket.Team", @@ -150,9 +152,7 @@ "inline_code" : "inline_code", "Install_FxOs" : "ដំឡើង Rocket.Chat នៅ​លើ Firefox របស់​អ្នក", "Install_FxOs_follow_instructions" : "សូមបញ្ជាក់ការដំឡើងកម្មវិធីនáŸáŸ‡áž“ៅលើឧបករណáŸážšáž”ស់អ្នក(ចុច \"Install\" áž–áŸáž›áž”ញ្ចាក់)", - "LDAP_Port" : "ច្រក LDAP", "Install_FxOs_done" : "អស្ចារ្យណាស់ឥឡូវអ្នកអាចប្រើប្រាស់ Rocket.Chat ážáž¶áž˜ážšáž™áŸˆ Icon នៅលើ Homescreen។ សូមរីករាយជាមួយ Rocket.Chat!", - "LDAP_Url" : "URL របស់ LDAP", "Install_FxOs_error" : "សុំទោស ដែលវាមិនដំណើរការážážŽáŸˆáž˜áž¶áž“បញ្ហាលáŸáž…ឡើងដូចážáž¶áž„ក្រោម", "Invalid_confirm_pass" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ញ្ជាក់​មិន​ដូច​ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​បញ្ចូល​", "Invalid_email" : "អ៊ី​មែល​ដែល​បញ្ចូល​មិន​ážáŸ’រឹម​ážáŸ’រូវ", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index af366b1cf05..b6e958eb76d 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -72,6 +72,7 @@ "coming_soon" : "곧", "Confirm_password" : "암호를 확ì¸í•˜ì„¸ìš”", "Contact" : "ì ‘ì†", + "Delete" : "ì‚ì œ", "Conversation" : "대화", "Convert_Ascii_Emojis" : "ASCII를 Emojisë¡œ 변환", "Create_new" : "새로 만들기", @@ -83,7 +84,7 @@ "days" : "ì¼", "Deactivate" : "비활성화", "Delete_User_Warning" : "ì‚¬ìš©ìž ì‚ì œì‹œ 사용ìžì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì·¨ì†Œí• ìˆ˜ 없습니다.", - "Delete" : "ì‚ì œ", + "Edit" : "ìˆ˜ì •", "Deleted" : "ì‚ì œ!", "Direct_Messages" : "ê·“ì†ë§", "Disable_Favorite_Rooms" : "ì¦ê²¨ì°¾ê¸° 사용안함", @@ -93,7 +94,6 @@ "Duplicate_channel_name" : "'%s' ì±„ë„ ì´ë¦„ì€ ì´ë¯¸ 존재합니다.", "Duplicate_private_group_name" : "'%s'는 ì´ë¯¸ 존재하는 ê°œì¸ ê·¸ë£¹ìž…ë‹ˆë‹¤.", "E-mail" : "ì´ë©”ì¼", - "Edit" : "ìˆ˜ì •", "edited" : "ìˆ˜ì •ë¨", "Email_already_exists" : "ì´ë©”ì¼ì´ ì´ë¯¸ 존재합니다", "Email_or_username" : "ì´ë©”ì¼ ë˜ëŠ” ì‚¬ìš©ìž ì´ë¦„", @@ -107,7 +107,9 @@ "Favorites" : "ì¦ê²¨ì°¾ê¸°", "Follow_social_profiles" : "소셜 프로파ì¼ì— ë”°ë¼ì£¼ì‹ì‹œì˜¤. Githubì—ì„œ í¬í¬í•˜ê³ , ìš°ë¦¬ì˜ trello ë³´ë“œì—ì„œ rocket.chat appì—대한 ì˜ê²¬ì„ ê³µìœ í•©ë‹ˆë‹¤.", "Forgot_password" : "암호를 잊었습니다", + "LDAP_Port" : "LDAP í¬íŠ¸", "Fork_it_on_github" : "Githubì—ì„œ í¬í¬", + "LDAP_Url" : "LDAP URL", "From_Email" : "ì´ë©”ì¼ë¡œë¶€í„°", "General" : "ì¼ë°˜", "Get_to_know_the_team" : "Rocket.Team 알아보기", @@ -120,8 +122,6 @@ "hours" : "시간", "Incorrect_Password" : "ìž˜ëª»ëœ ì•”í˜¸", "inline_code" : "inline_code", - "LDAP_Port" : "LDAP í¬íŠ¸", - "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "암호가 ì¼ì¹˜í•˜ì§€ 않습니다", "Invalid_email" : "ìž…ë ¥í•œ ì´ë©”ì¼ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤", "Invalid_name" : "ì´ë¦„ì„ ë¹„ì›Œ 둘 수 없습니다", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index ab45c915178..60e9bcff984 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -70,6 +70,7 @@ "Compact_View" : "Paparan Kompak", "Confirm_password" : "Sahkan kata laluan anda", "Contact" : "Hubungi", + "Delete" : "Padam", "Conversation" : "Perbualan", "Convert_Ascii_Emojis" : "Menukar ASCII ke Emoji", "Create_new" : "Buat baru", @@ -80,7 +81,7 @@ "days" : "hari", "Deactivate" : "Nyahaktifkan", "Delete_User_Warning" : "Memadam pengguna akan memadam semua mesej dari pengguna itu juga. Ini tidak boleh kembalikan asal.", - "Delete" : "Padam", + "Edit" : "Sunting", "Deleted" : "Dipadamkan!", "Desktop_Notifications" : "Notifikasi Desktop", "Desktop_Notifications_Disabled" : "Notifikasi Desktop dinyahaktifkan. Tukar tetapan pelayar web jika anda mahukan notifikasi diaktifkan.", @@ -93,7 +94,6 @@ "Duplicate_channel_name" : "Saluran dengan nama '%s' telah wujud", "Duplicate_private_group_name" : "Kumpulan Persendirian dengan nama '%s' telah wujud", "E-mail" : "E-mel", - "Edit" : "Sunting", "edited" : "disunting", "Email_already_exists" : "E-mel telah wujud", "Email_or_username" : "E-mel atau nama pengguna", @@ -110,7 +110,9 @@ "FileUpload_Enabled" : "Naik Fail Diaktifkan", "FileUpload_MaxFileSize" : "Fail muat naik saiz Maksimum (dalam bytes)", "Forgot_password" : "Lupa kata laluan anda", + "LDAP_Port" : "Port LDAP", "Fork_it_on_github" : "Mencabang pada github", + "LDAP_Url" : "URL LDAP", "From_Email" : "Daripada E-mel", "General" : "Umum", "Get_to_know_the_team" : "Kenali Rocket.Team", @@ -120,8 +122,6 @@ "History" : "Sejarah", "hours" : "jam", "Incorrect_Password" : "Kata Laluan salah", - "LDAP_Port" : "Port LDAP", - "LDAP_Url" : "URL LDAP", "Invalid_confirm_pass" : "Pengesahan kata laluan tidak sepadan dengan kata laluan", "Invalid_email" : "E-mel yang dimasukkan tidak sah", "Invalid_name" : "Nama mesti tidak dikosongkan", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index e4c31ed3289..5c673f37c93 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -51,6 +51,7 @@ "coming_soon" : "wkrótce", "Confirm_password" : "Potwierdź hasÅ‚o", "Contact" : "Kontakt", + "Delete" : "UsuÅ„", "Conversation" : "Rozmowa", "Create_new" : "Utwórz nowe", "Create_new_direct_message_room" : "Utwórz nowy kanaÅ‚ prywatny", @@ -58,13 +59,12 @@ "Create_new_public_channel" : "Utwórz kanaÅ‚ publiczny", "Created_at" : "Utworzono", "Deactivate" : "Dezaktywować", - "Delete" : "UsuÅ„", + "Edit" : "Edycja", "Deleted" : "UsuniÄ™te!", "Direct_Messages" : "BezpoÅ›rednie wiadomoÅ›ci", "Drop_to_upload_file" : "PrzeciÄ…gnij, aby przesÅ‚ać plik", "Duplicate_channel_name" : "KanaÅ‚ o nazwie \"% s\" istnieje", "Duplicate_private_group_name" : "Grupa Prywatna o nazwie '% s' istnieje", - "Edit" : "Edycja", "edited" : "zmieniono", "Email_already_exists" : "Email już istnieje", "Email_or_username" : "Email lub nazwa użytkownika", @@ -75,15 +75,15 @@ "Favorites" : "Ulubione", "Follow_social_profiles" : "Åšledź nasze profile spoÅ‚eczne, widelec do nas na github i podziel siÄ™ swoimi przemyÅ›leniami na temat rocket.chat aplikacji na naszej trello pokÅ‚adzie.", "Forgot_password" : "ZapomniaÅ‚eÅ› hasÅ‚a", + "LDAP_Port" : "Port LDAP", "Fork_it_on_github" : "Fork it on GitHub", + "LDAP_Url" : "Adres URL LDAP", "Get_to_know_the_team" : "Poznaj Rocket.Team", "github_no_public_email" : "Nie posiadasz publicznego konta e-mail przypisanego do swojego profilu GitHub.", "Have_your_own_chat" : "Załóż swój wÅ‚asny czat. DziÄ™ki Meteor.com, Rocket.Chat jest idealnym rozwiÄ…zaniem dla wszystkich chcÄ…cych budować i rozwijać swojÄ… wÅ‚asnÄ… platformÄ™ do rozmów.", "Hide_room" : "Ukryj pokój", "History" : "Historia", "inline_code" : "inline", - "LDAP_Port" : "Port LDAP", - "LDAP_Url" : "Adres URL LDAP", "Invalid_confirm_pass" : "Podane hasÅ‚a nie sÄ… jednakowe", "Invalid_email" : "E-mail jest nieprawidÅ‚owy", "Invalid_name" : "Nazwa nie może być pusta", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 5815821369a..433c30b4678 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -83,6 +83,7 @@ "Compact_View" : "Visão Compacta", "Confirm_password" : "Confirmar a senha", "Contact" : "Contato", + "Delete" : "Deletar", "Conversation" : "Conversa", "Convert_Ascii_Emojis" : "Converter ASCII para Emoji", "Create_new" : "Criar um novo", @@ -95,7 +96,7 @@ "days" : "dias", "Deactivate" : "Desativar", "Delete_User_Warning" : "Excluir um usuário irá apagar todas as mensagens desse usuário também. Isso não poderá ser desfeito.", - "Delete" : "Deletar", + "Edit" : "Editar", "Deleted" : "Deletado!", "Desktop_Notifications" : "Notificações Desktop", "Desktop_Notifications_Disabled" : "Notificações Desktop estão Desativadas. Mude as preferências do seu navegador se quiser habilitar as notificações.", @@ -108,7 +109,6 @@ "Duplicate_channel_name" : "Já existe um Canal com nome '%s'", "Duplicate_private_group_name" : "Já existe um Grupo Privado com nome '%s'", "E-mail" : "E-mail", - "Edit" : "Editar", "edited" : "editado", "Email_already_exists" : "Email já cadastrado", "Email_or_username" : "Email ou nome de usuário", @@ -128,7 +128,9 @@ "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia (separados por vÃrgula)", "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", + "LDAP_Port" : "Porta LDAP", "Fork_it_on_github" : "Fork it on github", + "LDAP_Url" : "URL LDAP", "From_Email" : "Email De", "General" : "Geral", "Get_to_know_the_team" : "Conheça o Rocket.Team", @@ -141,8 +143,6 @@ "hours" : "horas", "Incorrect_Password" : "Senha incorreta", "inline_code" : "código", - "LDAP_Port" : "Porta LDAP", - "LDAP_Url" : "URL LDAP", "Invalid_confirm_pass" : "A confirmação de senha não é igual à senha", "Invalid_email" : "O e-mail informado é inválido", "Invalid_name" : "O nome não pode ser vazio", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 311d6500653..b2b3d359c6f 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -68,15 +68,15 @@ "Favorites" : "Избранные чаты", "Follow_social_profiles" : "ДобавлÑйте Ð½Ð°Ñ Ð² Ð´Ñ€ÑƒÐ·ÑŒÑ Ð² Ñоциальных ÑетÑÑ…, форкайте на github и пишите Ñвои отзывы о нашем приложении у Ð½Ð°Ñ Ð² trello.", "Forgot_password" : "Забыли пароль?", + "LDAP_Port" : "LDAP Порт", "Fork_it_on_github" : "Форкайте на github", + "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "github_no_public_email" : "Ð’ наÑтройках GitHub отÑутÑтвует публично доÑтупный e-mail", "Has_more" : "Еще", "Hide_room" : "Скрыть чат", "History" : "ИÑториÑ", "hours" : "чаÑ(Ñ‹)", "inline_code" : "внутренний код", - "LDAP_Port" : "LDAP Порт", - "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Invalid_confirm_pass" : "Пароли не Ñовпадают", "Invalid_email" : "Ðеверный e-mail", "Invalid_name" : "Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index e8bcbecfba9..a1e4251b590 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -44,6 +44,7 @@ "coming_soon" : "yakında", "Confirm_password" : "Parolanızı onaylayın", "Contact" : "Ä°letiÅŸim", + "Delete" : "Sil", "Conversation" : "Direkt Mesaj", "Create_new" : "Yeni oluÅŸtur", "Create_new_direct_message_room" : "Yeni doÄŸrudan mesaj odası oluÅŸtur", @@ -52,12 +53,11 @@ "Created_at" : "OluÅŸturulma saati", "days" : "gün", "Delete_User_Warning" : "Bu kullanıcıyı silerseniz tüm mesajları da beraberinde silinecektir! Bu iÅŸlemi bir daha geri alamazsınız.", - "Delete" : "Sil", + "Edit" : "Düzenle", "Deleted" : "SilinmiÅŸ!", "Direct_Messages" : "Direkt Mesajlar", "Drop_to_upload_file" : "Dosya yüklemek için sürükle", "E-mail" : "E-posta", - "Edit" : "Düzenle", "edited" : "düzenlendi", "Email_already_exists" : "Bu e-posta zaten var", "Email_or_username" : "E-posta ya da kullanıcı adı", @@ -68,7 +68,9 @@ "Favorites" : "Favoriler", "Follow_social_profiles" : "Bizi sosyal aÄŸlardan takip edebilir, rocket.chat uygulaması hakkında düşüncelerinizi paylaÅŸabilir ve uygulamayı github üzerinden çatallayabilirsiniz.", "Forgot_password" : "Åžifrenizi mi unuttunuz", + "LDAP_Port" : "LDAP Port", "Fork_it_on_github" : "Github üzerinde çatalla", + "LDAP_Url" : "LDAP URL", "Get_to_know_the_team" : "Rocket.Team'ı tanıyın", "github_no_public_email" : "Sen GitHub hesabınızda kamu e-posta olarak herhangi bir e-posta yok", "Have_your_own_chat" : "Rocket.Chat, açık kaynak gönüllülerinin bir araya gelerek Meteor ile geliÅŸtirdikleri sohbet uygulamasıdır.", @@ -76,8 +78,6 @@ "History" : "GeçmiÅŸ", "hours" : "saat", "inline_code" : "kod_satırı", - "LDAP_Port" : "LDAP Port", - "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "Åžifreler eÅŸleÅŸmiyor", "Invalid_email" : "Girilen e-posta geçersiz", "Invalid_name" : "Ä°sim boÅŸ bırakılamaz", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index 719deed685a..3a2c8bf04c1 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -47,6 +47,7 @@ "coming_soon" : "å³å°†æŽ¨å‡º", "Confirm_password" : "确认密ç ", "Contact" : "è”系人", + "Delete" : "åˆ é™¤", "Conversation" : "è°ˆè¯", "Convert_Ascii_Emojis" : "自动识别文å—ä¸çš„表情", "Create_new" : "新建", @@ -57,7 +58,7 @@ "days" : "天", "Deactivate" : "ç¦ç”¨", "Delete_User_Warning" : "åˆ é™¤ç”¨æˆ·å°†åˆ é™¤è¯¥ç”¨æˆ·çš„æ‰€æœ‰æ¶ˆæ¯ã€‚è¿™ä¸èƒ½è¢«æ’¤æ¶ˆã€‚", - "Delete" : "åˆ é™¤", + "Edit" : "编辑", "Deleted" : "å·²åˆ é™¤ï¼", "Direct_Messages" : "直接å‘é€æ¶ˆæ¯", "Disable_New_Message_Notification" : "ç¦ç”¨æ–°æ¶ˆæ¯é€šçŸ¥", @@ -66,7 +67,6 @@ "Duplicate_channel_name" : "é¢‘é“ '%s' å·²å˜åœ¨", "Duplicate_private_group_name" : "ç§æœ‰ç»„ '%s' å·²å˜åœ¨", "E-mail" : "电å邮件", - "Edit" : "编辑", "edited" : "已编辑", "Email_already_exists" : "邮件已å˜åœ¨", "Email_or_username" : "电å邮件或用户å", @@ -79,7 +79,9 @@ "Favorites" : "收è—", "Follow_social_profiles" : "关注我们的社交资讯,fork我们在github的项目或者在trelloä¸Šåˆ†äº«ä½ å…³äºŽrocket.chat的想法。", "Forgot_password" : "忘记密ç ", + "LDAP_Port" : "LDAP端å£", "Fork_it_on_github" : "在Github上Fork它", + "LDAP_Url" : "LDAP URL", "From_Email" : "从电å邮件", "General" : "通用", "Get_to_know_the_team" : "结识Rocket.Team", @@ -89,8 +91,6 @@ "Hide_room" : "éšè—èŠå¤©å®¤", "History" : "历å²", "hours" : "å°æ—¶", - "LDAP_Port" : "LDAP端å£", - "LDAP_Url" : "LDAP URL", "Invalid_confirm_pass" : "第二次密ç 输入与第一次ä¸åŒ¹é…", "Invalid_email" : "æ— æ•ˆçš„ç”µå邮件", "Invalid_name" : "用户åä¸èƒ½ä¸ºç©º", diff --git a/packages/rocketchat-ldap/i18n/de.i18n.json b/packages/rocketchat-ldap/i18n/de.i18n.json index b45818dfbc3..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/de.i18n.json +++ b/packages/rocketchat-ldap/i18n/de.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP Port", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/el.i18n.json b/packages/rocketchat-ldap/i18n/el.i18n.json index a649fce780d..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/el.i18n.json +++ b/packages/rocketchat-ldap/i18n/el.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP ΘÏÏα", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/en.i18n.json b/packages/rocketchat-ldap/i18n/en.i18n.json index b45818dfbc3..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/en.i18n.json +++ b/packages/rocketchat-ldap/i18n/en.i18n.json @@ -1,5 +1,3 @@ { - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP Port", "LDAP_Dn" : "LDAP DN" } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/fa.i18n.json b/packages/rocketchat-ldap/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/fi.i18n.json b/packages/rocketchat-ldap/i18n/fi.i18n.json index 733d1e150a5..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/fi.i18n.json +++ b/packages/rocketchat-ldap/i18n/fi.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP portti", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/fr.i18n.json b/packages/rocketchat-ldap/i18n/fr.i18n.json index 9970877ee67..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/fr.i18n.json +++ b/packages/rocketchat-ldap/i18n/fr.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "Adresse LDAP", - "LDAP_Port" : "Port LDAP", - "LDAP_Dn" : "DN LDAP" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/km.i18n.json b/packages/rocketchat-ldap/i18n/km.i18n.json index 8ff98cb68f0..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/km.i18n.json +++ b/packages/rocketchat-ldap/i18n/km.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "URL របស់ LDAP", - "LDAP_Port" : "ច្រក LDAP", - "LDAP_Dn" : " LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ko.i18n.json b/packages/rocketchat-ldap/i18n/ko.i18n.json index ce57535ed74..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/ko.i18n.json +++ b/packages/rocketchat-ldap/i18n/ko.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP í¬íŠ¸", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ms-MY.i18n.json b/packages/rocketchat-ldap/i18n/ms-MY.i18n.json index d6c3fbb791a..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/ms-MY.i18n.json +++ b/packages/rocketchat-ldap/i18n/ms-MY.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "URL LDAP", - "LDAP_Port" : "Port LDAP", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/pl.i18n.json b/packages/rocketchat-ldap/i18n/pl.i18n.json index 860e847dc2a..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/pl.i18n.json +++ b/packages/rocketchat-ldap/i18n/pl.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "Adres URL LDAP", - "LDAP_Port" : "Port LDAP", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/pt.i18n.json b/packages/rocketchat-ldap/i18n/pt.i18n.json index 94b6eca223c..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/pt.i18n.json +++ b/packages/rocketchat-ldap/i18n/pt.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "URL LDAP", - "LDAP_Port" : "Porta LDAP", - "LDAP_Dn" : "DN LDAP" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ru.i18n.json b/packages/rocketchat-ldap/i18n/ru.i18n.json index 29d388a254a..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/ru.i18n.json +++ b/packages/rocketchat-ldap/i18n/ru.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", - "LDAP_Port" : "LDAP Порт", - "LDAP_Dn" : "LDAP домен" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/tr.i18n.json b/packages/rocketchat-ldap/i18n/tr.i18n.json index 85805bc82c6..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/tr.i18n.json +++ b/packages/rocketchat-ldap/i18n/tr.i18n.json @@ -1,4 +1 @@ -{ - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP Port" -} \ No newline at end of file +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/zh.i18n.json b/packages/rocketchat-ldap/i18n/zh.i18n.json index 2d41c6ba40c..6f31cf5a2e6 100644 --- a/packages/rocketchat-ldap/i18n/zh.i18n.json +++ b/packages/rocketchat-ldap/i18n/zh.i18n.json @@ -1,5 +1 @@ -{ - "LDAP_Url" : "LDAP URL", - "LDAP_Port" : "LDAP端å£", - "LDAP_Dn" : "LDAP DN" -} \ No newline at end of file +{ } \ No newline at end of file -- GitLab From 7997a30d7eacfd4a8e9b3a395aea1f6d200fc1db Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 12 Nov 2015 00:18:30 -0200 Subject: [PATCH 0392/1338] sorting i18n strings --- i18n/en.i18n.json | 98 +++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1cf012f42bb..13031607068 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -3,14 +3,25 @@ "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Comma-separated list of allowed domains", - "Accounts_AllowUsernameChange" : "Allow Username Change", "Accounts_AllowPasswordChange" : "Allow Password Change", + "Accounts_AllowUsernameChange" : "Allow Username Change", "Accounts_AvatarResize" : "Resize Avatars", "Accounts_AvatarSize" : "Avatar Size", "Accounts_AvatarStorePath" : "Avatar Storage Path", "Accounts_AvatarStoreType" : "Avatar Storage Type", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", + "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", + "Accounts_OAuth_Custom_Button_Color" : "Button Color", + "Accounts_OAuth_Custom_Button_Label_Color" : "Button Text Color", + "Accounts_OAuth_Custom_Button_Label_Text" : "Button Text", + "Accounts_OAuth_Custom_Enable" : "Enable", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook Login", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -29,21 +40,10 @@ "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", - "Accounts_RegistrationRequired" : "Registration Required", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "Token Path", - "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", - "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", - "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Enable" : "Enable", - "Accounts_OAuth_Custom_Button_Label_Text" : "Button Text", - "Accounts_OAuth_Custom_Button_Label_Color" : "Button Text Color", - "Accounts_OAuth_Custom_Button_Color" : "Button Color", + "Accounts_RegistrationRequired" : "Registration Required", "Accounts_RequireNameForSignUp" : "Require name for signup", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", @@ -52,7 +52,6 @@ "Administration" : "Administration", "All_channels" : "All channels", "Allow_Invalid_SelfSigned_Certs" : "Allow invalid and Self-Signed SSL certificate's for link validation and previews", - "CDN_PREFIX" : "CDN Prefix", "and" : "and", "API" : "API", "API_Analytics" : "Analytics", @@ -62,6 +61,7 @@ "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", + "Auto_Load_Images" : "Auto Load Images", "Avatar_changed_successfully" : "Avatar changed successfully", "Avatar_url_invalid_or_error" : "The url provided is invalid or not accessible. Please try again, but with a different url.", "away" : "away", @@ -70,7 +70,6 @@ "Away_female" : "Away", "away_male" : "away", "Away_male" : "Away", - "Auto_Load_Images" : "Auto Load Images", "Back_to_login" : "Back to login", "bold" : "bold", "busy" : "busy", @@ -80,6 +79,7 @@ "busy_male" : "busy", "Busy_male" : "Busy", "Cancel" : "Cancel", + "CDN_PREFIX" : "CDN Prefix", "Change_avatar" : "Change avatar", "Channels" : "Channels", "Channels_list" : "List of public channels", @@ -91,7 +91,6 @@ "Compact_View" : "Compact View", "Confirm_password" : "Confirm your password", "Contact" : "Contact", - "Delete" : "Delete", "Conversation" : "Conversation", "Convert_Ascii_Emojis" : "Convert ASCII to Emoji", "Create_new" : "Create new", @@ -99,13 +98,13 @@ "Create_new_private_group" : "Create a new private group", "Create_new_public_channel" : "Create a new public channel", "Created_at" : "Created at", - "Custom_oauth_unique_name" : "Custom oauth unique name", "Custom_oauth_helper" : "When setting up your OAuth Provider, you'll have to inform a Callback URL. Use <pre>%s</pre> .", + "Custom_oauth_unique_name" : "Custom oauth unique name", "days" : "days", "Deactivate" : "Deactivate", - "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", - "Edit" : "Edit", + "Delete" : "Delete", "Delete_Room_Warning" : "Deleting a room will delete all messages posted within the room. This cannot be undone.", + "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", "Deleted" : "Deleted!", "Desktop_Notifications" : "Desktop Notifications", "Desktop_Notifications_Disabled" : "Desktop Notifications are Disabled. Change your browser preferences if you need Notifications enabled.", @@ -118,6 +117,7 @@ "Duplicate_channel_name" : "A Channel with name '%s' exists", "Duplicate_private_group_name" : "A Private Group with name '%s' exists", "E-mail" : "E-mail", + "Edit" : "Edit", "edited" : "edited", "Email_already_exists" : "Email already exists", "Email_or_username" : "Email or username", @@ -138,25 +138,23 @@ "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", - "LDAP_Port" : "LDAP Port", "Fork_it_on_github" : "Fork it on github", - "LDAP_Url" : "LDAP URL", "From_Email" : "From Email", "General" : "General", "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", - "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.", "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", "History" : "History", "hours" : "hours", "Incorrect_Password" : "Incorrect Password", "inline_code" : "inline_code", "Install_FxOs" : "Install Rocket.Chat on your Firefox", - "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", "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).", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_email" : "The e-mail entered is invalid", "Invalid_name" : "The name must not be empty", @@ -190,24 +188,26 @@ "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", "LDAP" : "LDAP", - "LDAP_Description" : "LDAP is a heirarchical 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 twiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", "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_Description" : "LDAP is a heirarchical 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 twiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", "LDAP_DN" : "Distinguished Name (DN)", "LDAP_DN_Description" : "Search root; example: dc=domain,dc=com", "LDAP_Enable" : "Enable LDAP", "LDAP_Enable_Description" : "Attempt to utilize ldap for authentication.", + "LDAP_Port" : "LDAP Port", "LDAP_Port_Description" : "Port to access LDAP on; eg: 389", "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" : "Allows configuring how to populate user account fields (like email) from a record in ldap (once found). As an example, {\"cn\":\"name\", \"mail\":\"email\"} will choose a persion's human readable name from the cn attribute, and their email from the mail attribute. Available fields include name, and email.", + "LDAP_Url" : "LDAP URL", "LDAP_Url_Description" : "Uri of the ldap server; example: ldap://company.dns.com", "Leave_room" : "Leave room", "line" : "line", "Load_more" : "Load more", - "Loading_more_from_history" : "Loading more from history", "Loading..." : "Loading...", + "Loading_more_from_history" : "Loading more from history", "Loading_suggestion" : "Loading suggestions...", "Login" : "Login", "Login_with" : "Login with %s", @@ -224,17 +224,17 @@ "Message_AllowEditing" : "Allow Message Editing", "Message_AllowEditing_BlockEditInMinutes" : "Block Message Editing After (n) Minutes", "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking", + "Message_AllowPinning" : "Allow Message Pinning", "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", "Message_AudioRecorderEnabledDescription" : "For this to work upload of Wav files must be enabled in the 'File Upload' section", "Message_deleting_not_allowed" : "Message deleting not allowed", - "Message_editing_not_allowed" : "Message editing not allowed", "Message_editing_blocked" : "This message cannot be edited anymore", + "Message_editing_not_allowed" : "Message editing not allowed", + "Message_KeepHistory" : "Keep Message History", "Message_MaxAllowedSize" : "Maximum Allowed Message Size", + "Message_pinned" : "Message pinned", "Message_pinning_not_allowed" : "Message pinning not allowed", - "Message_AllowPinning" : "Allow Message Pinning", - "Message_KeepHistory" : "Keep Message History", "Message_removed" : "Message removed", - "Message_pinned" : "Message pinned", "Message_ShowDeletedStatus" : "Show Deleted Status", "Message_ShowEditedStatus" : "Show Edited Status", "Message_ShowFormattingTips" : "Show Formatting Tips", @@ -254,38 +254,38 @@ "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", - "Name_optional" : "Name (optional)", "Name_cant_be_empty" : "Name can't be empty", + "Name_optional" : "Name (optional)", "New_messages" : "New messages", "New_password" : "New password", + "No_channel_with_name_%s_was_found" : "No channel with name <strong>\"%s\"</strong> was found!", "No_channels_yet" : "You aren't part of any channel yet.", "No_direct_messages_yet" : "You haven't started any conversations yet.", "No_favorites_yet" : "You haven't added any favorites yet.", + "No_group_with_name_%s_was_found" : "No private group with name <strong>\"%s\"</strong> was found!", "No_groups_yet" : "You have no private groups yet.", "No_permission_to_view_room" : "You don't have permission to view this room", - "No_channel_with_name_%s_was_found" : "No channel with name <strong>\"%s\"</strong> was found!", - "No_group_with_name_%s_was_found" : "No private group with name <strong>\"%s\"</strong> was found!", "No_user_with_username_%s_was_found" : "No user with username <strong>\"%s\"</strong> was found!", "Not_allowed" : "Not allowed", "Not_found_or_not_allowed" : "Not Found or Not Allowed", "Nothing_found" : "Nothing found", "Notify_all_in_this_room" : "Notify all in this room", - "Old_Password" : "Old Password", "Old_and_new_password_required" : "You need to provide both old and new password for changing your password.", - "Only_you_can_see_this_message" : "Only you can see this message", + "Old_Password" : "Old Password", "Online" : "Online", + "Only_you_can_see_this_message" : "Only you can see this message", "Oops!" : "Oops", "Opt_out_statistics" : "Don't send my statistics to Rocket.Chat", "Opt_out_statistics_warning" : "By sending your statistics, you'll help us identify how many instances of Rocket.Chat are deployed, as well as how good the system is behaving, so we can further improve it. Don't worry, as no user information is sent and all the information we receive is kept confidential. If you want to continue sending us your statistics, uncheck the above checkbox. Thank you.", "others" : "others", "Password" : "Password", - "Password_changed_successfully" : "Password changed successfully", "Password_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of passwords", + "Password_changed_successfully" : "Password changed successfully", "People" : "People", + "Please_enter_value_for_url" : "Please enter a value for the url of your avatar.", "Please_wait" : "Please wait", "Please_wait_activation" : "Please wait, this can take some time.", "Please_wait_statistics" : "Please wait, statistics are being generated.", - "Please_enter_value_for_url" : "Please enter a value for the url of your avatar.", "Powered_by" : "Powered by", "Preferences" : "Preferences", "Preferences_saved" : "Preferences saved", @@ -315,8 +315,8 @@ "Registration_Succeeded" : "Registration Succeeded", "Remember_me" : "Remember me", "Remove" : "Remove", - "Remove_custom_oauth" : "Remove custom oauth", "Remove_Admin" : "Remove Admin", + "Remove_custom_oauth" : "Remove custom oauth", "Reset_password" : "Reset password", "Room" : "Room", "Room_name_changed" : "Room name changed to: <em>__room_name__</em> by <em>__user_by__</em>", @@ -326,6 +326,13 @@ "Room_uploaded_file_list_empty" : "No files available.", "room_user_count" : "%s users", "Rooms" : "Rooms", + "S_new_messages_since_s" : "%s new messages since %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" : "Save", "Save_changes" : "Save changes", "Save_Mobile_Bandwidth" : "Save Mobile Bandwidth", @@ -356,12 +363,6 @@ "Site_Name" : "Site Name", "Site_Url" : "Site URL", "Site_Url_Description" : "Example: https://chat.domain.com/", - "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", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP Password", @@ -373,9 +374,9 @@ "Stats_Active_Users" : "Active Users", "Stats_Avg_Channel_Users" : "Average Channel Users", "Stats_Avg_Private_Group_Users" : "Average Private Group Users", + "Stats_Away_Users" : "Away Users", "Stats_Max_Room_Users" : "Max Rooms Users", "Stats_Non_Active_Users" : "Inactive Users", - "Stats_Away_Users" : "Away Users", "Stats_Offline_Users" : "Offline Users", "Stats_Online_Users" : "Online Users", "Stats_OS_Arch" : "OS Arch", @@ -396,7 +397,6 @@ "Stop_Recording" : "Stop Recording", "strike" : "strike", "Submit" : "Submit", - "S_new_messages_since_s" : "%s new messages since %s", "The_field_is_required" : "The field %s is required.", "True" : "True", "Unnamed" : "Unnamed", @@ -414,7 +414,6 @@ "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", - "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "User_has_been_deactivated" : "User has been deactivated", "User_has_been_deleted" : "User has been deleted", "User_Info" : "User Info", @@ -432,13 +431,14 @@ "User_removed_by" : "User <em>__user_removed__</em> removed by <em>__user_by__</em>.", "User_Settings" : "User Settings", "User_updated_successfully" : "User updated successfully", - "Users" : "Users", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", + "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "Username_description" : "The username is used to allow others to mention you in messages.", "Username_invalid" : "<strong>%s</strong> is not a valid username,<br/> use only letters, numbers, dots and dashes", "Username_title" : "Register username", "Username_unavaliable" : "<strong>%s</strong> is already in use :(", + "Users" : "Users", "View_All" : "View All", "Wait_activation_warning" : "Before you can login, your account must be manually activated by an administrator.", "We_have_sent_password_email" : "We have sent you an e-mail with password reset instructions. If you do not receive an e-mail shortly, please come back and try again.", @@ -446,11 +446,11 @@ "Welcome" : "Welcome <em>%s</em>.", "Welcome_to_the" : "Welcome to the", "With_whom" : "With whom", - "Yes_delete_it" : "Yes, delete it!", "Yes_clear_all" : "Yes, clear all!", + "Yes_delete_it" : "Yes, delete it!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", "You_need_confirm_email" : "You need to confirm your email to login!", "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} -- GitLab From 64751a178178badc9d7548c51b9a07f6a3e99661 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 12 Nov 2015 00:35:25 -0200 Subject: [PATCH 0393/1338] try new guest count every loop --- packages/rocketchat-livechat/server/methods.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/server/methods.js b/packages/rocketchat-livechat/server/methods.js index 241674b00b9..f97d83ecce6 100644 --- a/packages/rocketchat-livechat/server/methods.js +++ b/packages/rocketchat-livechat/server/methods.js @@ -1,6 +1,7 @@ Meteor.methods({ registerGuest: function(token) { - var pass, qt, user, userData, userExists, userId; + console.log('registerGuest ->'.green, token); + var pass, qt, user, userData, userExists, userId, inc = 0; check(token, String); user = Meteor.users.findOne({ "profile.token": token @@ -17,7 +18,7 @@ Meteor.methods({ qt = Meteor.users.find({ 'profile.guest': true }).count() + 1; - user = 'guest-' + qt; + user = 'guest-' + (qt + inc++); userExists = Meteor.users.findOne({ 'username': user }, { @@ -25,6 +26,7 @@ Meteor.methods({ _id: 1 } }); + console.log('userExists ->',userExists); if (!userExists) { break; } -- GitLab From 1cdaf3811499146f95e1b09c1e9c594fd247ac37 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 12 Nov 2015 02:37:13 +0000 Subject: [PATCH 0394/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/de.i18n.json | 76 +++++++-------- i18n/el.i18n.json | 8 +- i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 96 +++++++++---------- i18n/fr.i18n.json | 68 ++++++------- i18n/hr.i18n.json | 52 +++++----- i18n/ja.i18n.json | 2 +- i18n/km.i18n.json | 84 ++++++++-------- i18n/ko.i18n.json | 62 ++++++------ i18n/ms-MY.i18n.json | 58 +++++------ i18n/pl.i18n.json | 14 +-- i18n/pt.i18n.json | 68 ++++++------- i18n/ru.i18n.json | 22 ++--- i18n/tr.i18n.json | 12 +-- i18n/zh.i18n.json | 30 +++--- packages/rocketchat-ldap/i18n/de.i18n.json | 4 +- packages/rocketchat-ldap/i18n/el.i18n.json | 4 +- packages/rocketchat-ldap/i18n/fi.i18n.json | 4 +- packages/rocketchat-ldap/i18n/fr.i18n.json | 4 +- packages/rocketchat-ldap/i18n/km.i18n.json | 4 +- packages/rocketchat-ldap/i18n/ko.i18n.json | 4 +- packages/rocketchat-ldap/i18n/ms-MY.i18n.json | 4 +- packages/rocketchat-ldap/i18n/pl.i18n.json | 4 +- packages/rocketchat-ldap/i18n/pt.i18n.json | 4 +- packages/rocketchat-ldap/i18n/ru.i18n.json | 4 +- packages/rocketchat-ldap/i18n/zh.i18n.json | 4 +- 26 files changed, 360 insertions(+), 338 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index a0410acf56a..80aef3352ec 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -4,6 +4,17 @@ "Accounts" : "Kontos", "Accounts_denyUnverifiedEmail" : "Nicht verifizierte E-Mails ablehnen", "Accounts_EmailVerification" : "E-Mail-Verifizierung", + "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_Enable" : "Aktivieren", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identitäts Pfad", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token Pfad", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook Login", "Accounts_OAuth_Facebook_id" : "Facebook-App-ID", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -19,21 +30,10 @@ "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", - "Accounts_RegistrationRequired" : "Anmeldung erforderlich", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "Token Pfad", - "Accounts_OAuth_Custom_Identity_Path" : "Identitäts Pfad", - "Accounts_OAuth_Custom_Authorize_Path" : "Autorisierungspfad", - "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Enable" : "Aktivieren", - "Accounts_OAuth_Custom_Button_Label_Text" : "Button-Text", - "Accounts_OAuth_Custom_Button_Label_Color" : "Button-Text-Farbe", - "Accounts_OAuth_Custom_Button_Color" : "Buttonfarbe", + "Accounts_RegistrationRequired" : "Anmeldung erforderlich", "Activate" : "Aktivieren", "Add_custom_oauth" : "Benutzerdefinierte oauth hinzufügen", "Add_Members" : "Mitglieder hinzufügen", @@ -41,7 +41,6 @@ "Administration" : "Administration", "All_channels" : "Alle Kanäle", "Allow_Invalid_SelfSigned_Certs" : "Selbstsignierte SSL-Zertifikate für die Link-Validierung und die Vorschau zulassen", - "CDN_PREFIX" : "CDN Präfix", "and" : "und", "API" : "API", "API_Analytics" : "Analytics", @@ -50,6 +49,7 @@ "are_also_typing" : "schreiben auch", "are_typing" : "schreiben", "Are_you_sure" : "Sind Sie sicher?", + "Auto_Load_Images" : "Automatisches Laden der Bilder", "Avatar_changed_successfully" : "Avatar erfolgreich geändert", "away" : "abwesend", "Away" : "Abwesend", @@ -57,7 +57,6 @@ "Away_female" : "Abwesend", "away_male" : "abwesend", "Away_male" : "Abwesend", - "Auto_Load_Images" : "Automatisches Laden der Bilder", "Back_to_login" : "Zurück zum Login", "bold" : "fett", "busy" : "beschäftigt", @@ -67,6 +66,7 @@ "busy_male" : "beschäftigt", "Busy_male" : "Beschäftigt", "Cancel" : "Abbrechen", + "CDN_PREFIX" : "CDN Präfix", "Change_avatar" : "Ändere dein Avatar", "Channels" : "Kanäle", "Channels_list" : "Liste der öffentlichen Channels", @@ -78,7 +78,6 @@ "Compact_View" : "Kompakte Ansicht", "Confirm_password" : "Bestätigen Sie Ihr Passwort", "Contact" : "Kontakt", - "Delete" : "Löschen", "Conversation" : "Konversation", "Convert_Ascii_Emojis" : "Konvertiere ASCII zu Emoji", "Create_new" : "Neu erstellen", @@ -86,12 +85,12 @@ "Create_new_private_group" : "Erstellen Sie eine neue private Gruppe", "Create_new_public_channel" : "Erstelle einen neuen öffentlichen Channel", "Created_at" : "Erstellt am", - "Custom_oauth_unique_name" : "Eindeutigen Namen von benutzerdefinierte oauth", "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", "days" : "Tage", "Deactivate" : "Deaktivieren", + "Delete" : "Löschen", "Delete_User_Warning" : "Beim Löschen eines Benutzers, werden alle seine Nachrichten ebenfalls gelöscht. Dies kann nicht rückgängig gemacht werden.", - "Edit" : "Bearbeiten", "Deleted" : "Gelöscht!", "Desktop_Notifications" : "Desktop-Benachrichtigungen", "Desktop_Notifications_Enabled" : "Desktop-Benachrichtigungen sind aktiviert", @@ -103,6 +102,7 @@ "Duplicate_channel_name" : "Ein Kanal mit dem Namen, '%s', existiert", "Duplicate_private_group_name" : "Eine private Gruppe mit dem Namen, '%s', existiert", "E-mail" : "E-Mail", + "Edit" : "Bearbeiten", "edited" : "bearbeitet", "Email_already_exists" : "E-Mail existiert bereits", "Email_or_username" : "Email oder Username", @@ -122,25 +122,23 @@ "FileUpload_MediaTypeWhiteList" : "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.", "Forgot_password" : "Passwort vergessen?", - "LDAP_Port" : "LDAP Port", "Fork_it_on_github" : "Fork es auf GitHub", - "LDAP_Url" : "LDAP URL", "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", - "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.", "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.", "Hide_room" : "Raum verstecken", "History" : "Chronik", "hours" : "Stunden", "Incorrect_Password" : "Falsches Passwort", "inline_code" : "inline_code", "Install_FxOs" : "Installiere Rocket.Chat auf deinem Firefox", - "Install_FxOs_follow_instructions" : "Bitte bestätige die Installation der App (drücke \"Installieren\" in der Aufforderung).", "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", @@ -175,11 +173,13 @@ "Layout_Terms_of_Service" : "Nutzungsbedingungen", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Raum verlassen", "line" : "Zeilen", "Load_more" : "Mehr laden", - "Loading_more_from_history" : "Lade mehr aus der Historie", "Loading..." : "Wird geladen ...", + "Loading_more_from_history" : "Lade mehr aus der Historie", "Loading_suggestion" : "Vorschläge werden geladen...", "Login" : "Login", "Login_with" : "Login mit %s", @@ -194,16 +194,16 @@ "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_AllowPinning" : "Erlaube es Nachrichten anzuheften", "Message_AudioRecorderEnabled" : "Audio Recorder Aktiviert", "Message_deleting_not_allowed" : "Nachrichten löschen nicht erlaubt", - "Message_editing_not_allowed" : "Nachrichten bearbeiten nicht erlaubt", "Message_editing_blocked" : "Diese Nachricht kann nicht mehr bearbeitet werden", + "Message_editing_not_allowed" : "Nachrichten bearbeiten nicht erlaubt", + "Message_KeepHistory" : "Nachrichtenverlauf behalten", "Message_MaxAllowedSize" : "Maximale Größe der Nachricht", + "Message_pinned" : "Nachricht angeheftet", "Message_pinning_not_allowed" : "Nachrichten anheften erlaubt", - "Message_AllowPinning" : "Erlaube es Nachrichten anzuheften", - "Message_KeepHistory" : "Nachrichtenverlauf behalten", "Message_removed" : "Nachricht entfernt", - "Message_pinned" : "Nachricht angeheftet", "Message_ShowDeletedStatus" : "Zeige Löschstatus", "Message_ShowEditedStatus" : "Zeige Bearbeitungsstatus", "Messages" : "Nachrichten", @@ -222,26 +222,26 @@ "My_Account" : "Mein Konto", "n_messages" : "%s Nachrichten", "Name" : "Name", - "Name_optional" : "Name (freiwillig)", "Name_cant_be_empty" : "Name darf nicht leer sein", + "Name_optional" : "Name (freiwillig)", "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_direct_messages_yet" : "Sie haben keine Konversation gestartet.", "No_favorites_yet" : "Sie haben 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_channel_with_name_%s_was_found" : "Es wurde keine Kanal mit dem Namen <strong>\"%s\"</strong> gefunden!", - "No_group_with_name_%s_was_found" : "Es wurde keine private Gruppe mit dem Namen <strong>\"%s\"</strong> gefunden!", "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_Password" : "Altes Passwort", "Old_and_new_password_required" : "Das alte und neue Passwort müssen angegeben werden um das jetzige Passwort zu ändern.", - "Only_you_can_see_this_message" : "Nur Sie können diese Nachricht sehen", + "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.", @@ -279,8 +279,8 @@ "Registration_Succeeded" : "Registrierung erfolgreich", "Remember_me" : "Erinnere dich an mich", "Remove" : "Entfernen", - "Remove_custom_oauth" : "Entferne benutzerdefiniertes oauth", "Remove_Admin" : "Admin entfernen", + "Remove_custom_oauth" : "Entferne benutzerdefiniertes oauth", "Reset_password" : "Passwort zurücksetzen", "Room" : "Raum", "Room_name_changed" : "Raumname geändert zu: <em>__room_name__</em> von <em>__user_by__</em>", @@ -290,6 +290,9 @@ "Room_uploaded_file_list_empty" : "Keine Dateien zur Verfügung.", "room_user_count" : "%s Benutzer", "Rooms" : "Räume", + "S_new_messages_since_s" : "%s neue Nachrichten seit %s", + "SAML" : "SAML", + "SAML_Custom_Generate_Username" : "Benutzernamen generieren", "Save" : "Speichern", "Save_changes" : "Änderungen speichern", "Save_Mobile_Bandwidth" : "Mobilfunkbandbreite verringern", @@ -320,8 +323,6 @@ "Site_Name" : "Seitenname:", "Site_Url" : "Website URL", "Site_Url_Description" : "Beispiel: https://chat.domain.com/", - "SAML" : "SAML", - "SAML_Custom_Generate_Username" : "Benutzernamen generieren", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP Passwort", @@ -333,9 +334,9 @@ "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_Away_Users" : "Beschäftige Benutzer", "Stats_Offline_Users" : "Benutzer offline", "Stats_Online_Users" : "Benutzer online", "Stats_OS_Arch" : "OS Arch", @@ -356,7 +357,6 @@ "Stop_Recording" : "Aufnahme stoppen", "strike" : "durchgestrichen", "Submit" : "Abschicken", - "S_new_messages_since_s" : "%s neue Nachrichten seit %s", "The_field_is_required" : "Das Feld %s ist erforderlich.", "True" : "Wahr", "Unnamed" : "Unbenannt", @@ -388,13 +388,13 @@ "User_removed_by" : "Benutzer <em>__user_removed__</em> entfernt von <em>__user_by__</em>.", "User_Settings" : "Benutzereinstellungen", "User_updated_successfully" : "Benutzer erfolgreich aktualisiert", - "Users" : "Benutzer", "Username" : "Benutzername", "Username_cant_be_empty" : "Der Benutzername darf nicht leer sein", "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_title" : "Benutzernamen festlegen", "Username_unavaliable" : "<strong>%s</strong> wird schon verwendet :(", + "Users" : "Benutzer", "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.", @@ -402,8 +402,8 @@ "Welcome" : "Willkommen <em>%s</em>.", "Welcome_to_the" : "Willkommen bei", "With_whom" : "Mit wem?", - "Yes_delete_it" : "Ja, löschen!", "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!", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index 5b148a28dd2..a83669140d7 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -3,6 +3,7 @@ "Access_Online_Demo" : "Δείτε το Online Demo", "Accounts_denyUnverifiedEmail" : "ΆÏνηση ανεπιβεβαίωτου e-mail", "Accounts_EmailVerification" : "Επιβεβαίωση E-mail", + "Accounts_ManuallyApproveNewUsers" : "ΧειÏοκίνητη ÎγκÏιση νÎων χÏηστών", "Accounts_OAuth_Facebook" : "Facebook Login", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -18,11 +19,10 @@ "Accounts_OAuth_Meteor" : "Meteor Login", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_ManuallyApproveNewUsers" : "ΧειÏοκίνητη ÎγκÏιση νÎων χÏηστών", - "Accounts_RegistrationRequired" : "Απαιτείται ΕγγÏαφή", "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_RegistrationRequired" : "Απαιτείται ΕγγÏαφή", "Add_Members" : "Î ÏοσθÎστε ÎœÎλη", "Add_users" : "Î Ïοσθήκη χÏηστών", "Administration" : "ΔιαχείÏιση", @@ -81,9 +81,7 @@ "Favorites" : "Αγαπημενα", "Follow_social_profiles" : "Ακολουθήστε μας στα κοινωνικά δίκτυα, κάντε μας fork στο github και μοιÏαστείτε τις σκÎψεις σας για την εφαÏμογή rocket.chat στον πίνακα trello.", "Forgot_password" : "ΞÎχασα τον κωδικό μου", - "LDAP_Port" : "LDAP ΘÏÏα", "Fork_it_on_github" : "Fork it on github", - "LDAP_Url" : "LDAP URL", "Get_to_know_the_team" : "ΓνωÏίστε την ομάδα του Rocket.Team", "github_no_public_email" : "Δεν Îχετε κανÎνα δημόσιο email στον GitHub λογαÏιασμό σας", "Have_your_own_chat" : "Αποκτήστε το δικό σας web chat. ΑναπτÏγμÎνο με το Meteor.com, το Rocket.Chat είναι μια Ï€Î¿Î»Ï ÎºÎ±Î»Î® λÏση για Ï€ÏογÏαμματιστÎÏ‚ που θÎλουν να φτιάξουν και να εξελίξουν την δικιά τους πλατφόÏμα chat.", @@ -114,6 +112,8 @@ "Layout_Home_Body" : "ΑÏχική Σώμα", "Layout_Home_Title" : "ΑÏχική Τίτλος", "LDAP_DN" : "LDAP DN", + "LDAP_Port" : "LDAP ΘÏÏα", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Έξοδος από το δωμάτιο", "line" : "γÏαμμÎÏ‚", "Load_more" : "ΦόÏτωση πεÏισσότεÏων", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 13031607068..02af0e5c012 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -453,4 +453,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index aca274efb21..23f4567bc82 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -3,14 +3,25 @@ "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Käyttäjätilit", "Accounts_AllowedDomainsList" : "Pilkkueroteltu lista sallituista domaineista", - "Accounts_AllowUsernameChange" : "Salli käyttäjätunnuksen muuttaminen", "Accounts_AllowPasswordChange" : "Salli salasanan vaihto", + "Accounts_AllowUsernameChange" : "Salli käyttäjätunnuksen muuttaminen", "Accounts_AvatarResize" : "Muuta avatarien kokoa", "Accounts_AvatarSize" : "Avatarin koko", "Accounts_AvatarStorePath" : "Avatarin tallennuspolku", "Accounts_AvatarStoreType" : "Avatarien tallennusmuoto", "Accounts_denyUnverifiedEmail" : "Estä vahvistamaton sähköpostiosoite", "Accounts_EmailVerification" : "Sähköpostiosoitteen varmistaminen", + "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", + "Accounts_OAuth_Custom_Authorize_Path" : "Auktorisointipolku", + "Accounts_OAuth_Custom_Button_Color" : "Painikkeen väri", + "Accounts_OAuth_Custom_Button_Label_Color" : "Painikkeen tekstin väri", + "Accounts_OAuth_Custom_Button_Label_Text" : "Painikkeen teksti", + "Accounts_OAuth_Custom_Enable" : "Kytke päälle", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identity polku", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token polku", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook-tunnus", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -29,21 +40,10 @@ "Accounts_OAuth_Meteor" : "Meteor-tunnus", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", - "Accounts_RegistrationRequired" : "Rekisteröinti vaaditaan", "Accounts_OAuth_Twitter" : "Twitter-tunnus", "Accounts_OAuth_Twitter_id" : "Twitter ID", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "Token polku", - "Accounts_OAuth_Custom_Identity_Path" : "Identity polku", - "Accounts_OAuth_Custom_Authorize_Path" : "Auktorisointipolku", - "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Enable" : "Kytke päälle", - "Accounts_OAuth_Custom_Button_Label_Text" : "Painikkeen teksti", - "Accounts_OAuth_Custom_Button_Label_Color" : "Painikkeen tekstin väri", - "Accounts_OAuth_Custom_Button_Color" : "Painikkeen väri", + "Accounts_RegistrationRequired" : "Rekisteröinti vaaditaan", "Accounts_RequireNameForSignUp" : "Vaadi nimi rekisteröityessä", "Activate" : "Aktivoi", "Add_custom_oauth" : "Lisää mukautettu oauth", @@ -52,7 +52,6 @@ "Administration" : "Ylläpito", "All_channels" : "Kaikki kanavat", "Allow_Invalid_SelfSigned_Certs" : "Salli virheelliset ja itse allekirjoitetut SSL varmenteet linkin validointiin ja esikatseluihin", - "CDN_PREFIX" : "CDN etuliite", "and" : "ja", "API" : "API", "API_Analytics" : "Analytics", @@ -62,6 +61,7 @@ "are_also_typing" : "kirjoittavat myös", "are_typing" : "kirjoittavat", "Are_you_sure" : "Oletko varma?", + "Auto_Load_Images" : "Lataa kuvat automaattisesti\n", "Avatar_changed_successfully" : "Avatar vaihdettu onnistuneesti", "Avatar_url_invalid_or_error" : "URL on virheellinen tai ei ole käytettävissä. Yritä uudestaan.", "away" : "poissa", @@ -70,7 +70,6 @@ "Away_female" : "Poissa", "away_male" : "poissa", "Away_male" : "Poissa", - "Auto_Load_Images" : "Lataa kuvat automaattisesti\n", "Back_to_login" : "Takaisin kirjautumiseen", "bold" : "lihavoitu", "busy" : "varattu", @@ -80,6 +79,7 @@ "busy_male" : "varattu", "Busy_male" : "Varattu", "Cancel" : "Peruuta", + "CDN_PREFIX" : "CDN etuliite", "Change_avatar" : "Vaihda avatar", "Channels" : "Kanavat", "Channels_list" : "Julkiset kanavat", @@ -91,7 +91,6 @@ "Compact_View" : "Suppea näkymä", "Confirm_password" : "Vahvista salasanasi", "Contact" : "Yhteys", - "Delete" : "Poista", "Conversation" : "Keskustelu", "Convert_Ascii_Emojis" : "Muunna ASCII-merkit Emojiksi", "Create_new" : "Luo uusi", @@ -99,13 +98,13 @@ "Create_new_private_group" : "Luo uusi privaattiryhmä", "Create_new_public_channel" : "Luo uusi julkinen kanava", "Created_at" : "Luotu", - "Custom_oauth_unique_name" : "Mukautettu oauth yksilöllinen nimi", "Custom_oauth_helper" : "Kun perustat OAuth Providerin, sinun täytyy ilmoittaa Callback URL. Käytä <pre>%s</pre>.", + "Custom_oauth_unique_name" : "Mukautettu oauth yksilöllinen nimi", "days" : "päivää", "Deactivate" : "Deaktivoi", - "Delete_User_Warning" : "Käyttäjän poistaminen poistaa myös käyttäjän kaikki viestit. Toimintoa ei voi perua.", - "Edit" : "Muokkaa", + "Delete" : "Poista", "Delete_Room_Warning" : "Huomeen poistaminen poistaa kaikki huoneessa olevat viestit.\nToimintoa ei voi perua.", + "Delete_User_Warning" : "Käyttäjän poistaminen poistaa myös käyttäjän kaikki viestit. Toimintoa ei voi perua.", "Deleted" : "Poistettu!", "Desktop_Notifications" : "Työpöytäilmoituksia", "Desktop_Notifications_Disabled" : "Työpöytäilmoitukset eivät ole käytössä. Muuta selaimen asetuksia mikäli haluat ilmoitukset käyttöön.", @@ -118,6 +117,7 @@ "Duplicate_channel_name" : "Kanava nimeltä '%s' on olemassa jo", "Duplicate_private_group_name" : "Privaattiryhmä '%s' on olemassa jo", "E-mail" : "Sähköpostiosoite", + "Edit" : "Muokkaa", "edited" : "muokattu", "Email_already_exists" : "Sähköpostiosoite on jo olemassa", "Email_or_username" : "Sähköpostiosoite tai käyttäjänimi", @@ -138,25 +138,23 @@ "FileUpload_MediaTypeWhiteListDescription" : "Pilkkueroteltu lista mediatyypeistä", "Follow_social_profiles" : "Seuraa someamme, forkkaa Githubissa ja jaa ajatuksiasi rocket.chatista trellossa.", "Forgot_password" : "Unohditko salasanasi?", - "LDAP_Port" : "LDAP portti", "Fork_it_on_github" : "Forkkaa GitHubissa", - "LDAP_Url" : "LDAP URL", "From_Email" : "Sähköpostin lähettäjä", "General" : "Yleinen", "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", - "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.", "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", "History" : "Historia", "hours" : "tuntia", "Incorrect_Password" : "Väärä salasana", "inline_code" : "koodi", "Install_FxOs" : "Asenna Rocket.Chat Firefoxiisi", - "Install_FxOs_follow_instructions" : "Vahvista sovelluksen asennus laitteellasi (paina \"Install\" käskettäessä)", "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ä)", "Invalid_confirm_pass" : "Salasanat eivät täsmää", "Invalid_email" : "Annettu sähköpostiosoite ei ole oikea", "Invalid_name" : "Nimi ei voi olla tyhjä", @@ -190,24 +188,26 @@ "Layout_Sidenav_Footer_description" : "Alatunnisteen koko on 260x70", "Layout_Terms_of_Service" : "Käyttöehdot", "LDAP" : "LDAP", - "LDAP_Description" : "LDAP on laajasti käytössä oleva hierarkinen tietokantapalvelu, jolla organisaatioiden palveluille mahdollistetaan kertakirjautuminen (SSO).\nMääritystiedot ja esimerkit, katso wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication", "LDAP_Bind_Search" : "Bind haku", "LDAP_Bind_Search_Description" : "JSON, joka määrää yhdistämistiedot.\nMuoto: {\"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 on laajasti käytössä oleva hierarkinen tietokantapalvelu, jolla organisaatioiden palveluille mahdollistetaan kertakirjautuminen (SSO).\nMääritystiedot ja esimerkit, katso wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication", "LDAP_DN" : "LDAP DN", "LDAP_DN_Description" : "Etsintäpolku, esimerkiksi: dc = domain, dc = com", "LDAP_Enable" : "Kytke LDAP päälle", "LDAP_Enable_Description" : "Käytä LDAPia autentikointiin", + "LDAP_Port" : "LDAP portti", "LDAP_Port_Description" : "LDAP-portti (esim 389)", "LDAP_Sync_User_Data" : "Synkronoi käyttäjädata", "LDAP_Sync_User_Data_Description" : "Pidä käyttäjädata synkronoituna palvelimelta kirjautumishetkellä (esim nimi, sähköposti)", "LDAP_Sync_User_Data_FieldMap" : "Käyttäjätietojen kohdistus", "LDAP_Sync_User_Data_FieldMap_Description" : "Määrittää, miten käyttäjätietojen kentät tuodaan LDAP-palvelimelta.\nEsimerkiksi, {\"cn\":\"name\", \"mail\":\"email\"} -määritys tuo käyttäjän nimen cn-tiedosta ja sähköpostin email-tiedosta. Käytettävissä olevat kentät ovat \"name\" ja \"email\".", + "LDAP_Url" : "LDAP URL", "LDAP_Url_Description" : "LDAP-palvelimen URI, esimerkiksi: ldap://company.example.com", "Leave_room" : "Poistu kanavalta", "line" : "riviä", "Load_more" : "Lataa lisää", - "Loading_more_from_history" : "Ladataan lisää historiasta", "Loading..." : "Ladataan...", + "Loading_more_from_history" : "Ladataan lisää historiasta", "Loading_suggestion" : "Ladataan ehdotuksia...", "Login" : "Kirjaudu", "Login_with" : "Kirjaudu käyttäen %s", @@ -224,17 +224,17 @@ "Message_AllowEditing" : "Salli viestin muokkaus", "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus (x) minuutin jälkeen", "Message_AllowEditing_BlockEditInMinutesDescription" : "Syötä 0 poistaaksesi muutoseston", + "Message_AllowPinning" : "Salli viestien kiinnittäminen", "Message_AudioRecorderEnabled" : "Äänentallennin käytössä", "Message_AudioRecorderEnabledDescription" : "Jotta tämä toimisi, WAV-tiedostojen lähetys tulee olla sallittu", "Message_deleting_not_allowed" : "Viestin poisto ei sallittu", - "Message_editing_not_allowed" : "Viestin muokkaus ei sallittu", "Message_editing_blocked" : "Tätä viestiä ei voi muokata enää.", + "Message_editing_not_allowed" : "Viestin muokkaus ei sallittu", + "Message_KeepHistory" : "Säilytä viestihistoria", "Message_MaxAllowedSize" : "Viestin suurin sallittu koko", + "Message_pinned" : "Viesti kiinnitetty", "Message_pinning_not_allowed" : "Viestien kiinnittäminen ei sallittu", - "Message_AllowPinning" : "Salli viestien kiinnittäminen", - "Message_KeepHistory" : "Säilytä viestihistoria", "Message_removed" : "Viesti poistettu\n", - "Message_pinned" : "Viesti kiinnitetty", "Message_ShowDeletedStatus" : "Näytä poistotila", "Message_ShowEditedStatus" : "Näytä muokkaustila", "Message_ShowFormattingTips" : "Näytä muotoiluvihjeet", @@ -254,38 +254,38 @@ "My_Account" : "Käyttäjätilini", "n_messages" : "%s viestiä", "Name" : "Nimi", - "Name_optional" : "Nimi (valinnainen)", "Name_cant_be_empty" : "Nimi ei voi olla tyhjä", + "Name_optional" : "Nimi (valinnainen)", "New_messages" : "Uusia viestejä", "New_password" : "Uusi salasana", + "No_channel_with_name_%s_was_found" : "Kanavaa nimeltä '%s' ei löytynyt!", "No_channels_yet" : "Et ole vielä millään kanavalla.", "No_direct_messages_yet" : "Et ole vielä aloittanut mitään keskustelua.", "No_favorites_yet" : "Et ole vielä lisännyt suosikkeja.", + "No_group_with_name_%s_was_found" : "Privaattiryhmää '%s' ei löytynyt!", "No_groups_yet" : "Sinulla ei ole vielä privaattiryhmiä.", "No_permission_to_view_room" : "Sinulla ei ole oikeutta katsella tätä", - "No_channel_with_name_%s_was_found" : "Kanavaa nimeltä '%s' ei löytynyt!", - "No_group_with_name_%s_was_found" : "Privaattiryhmää '%s' ei löytynyt!", "No_user_with_username_%s_was_found" : "Käyttäjää nimeltä <strong>\"%s\"</strong> ei löytynyt!", "Not_allowed" : "Ei sallittu", "Not_found_or_not_allowed" : "Ei löydy tai ei sallittu", "Nothing_found" : "Ei löytynyt", "Notify_all_in_this_room" : "Ilmoita kaikille kanavallaolijoille", - "Old_Password" : "Vanha salasana", "Old_and_new_password_required" : "Sinun täytyy antaa sekä vanha että uusi salasana, että saat vaihdettua salasanasi.", - "Only_you_can_see_this_message" : "Vain sinä voit nähdä tämän viestin", + "Old_Password" : "Vanha salasana", "Online" : "Online", + "Only_you_can_see_this_message" : "Vain sinä voit nähdä tämän viestin", "Oops!" : "Oho", "Opt_out_statistics" : "Älä lähetä anonyymejä tilastoja Rocket.Chatille", "Opt_out_statistics_warning" : "Lähettämällä anonyymit tilastot, autat meitä selvittämään, kuinka monta Rocket.Chat -ympäristöä on käynnistetty, kuten myös sen, miten hyvin järjestelmä toimii. Tätä tietoa käytetään Rocket.Chatin parantamiseen.\nJos haluat jatkaa anonyymien tilastojen lähettämistä, poista ylläoleva ruksi. Kiitos.", "others" : "muut", "Password" : "Salasana", - "Password_changed_successfully" : "Salasana vaihdettu", "Password_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut salasanan vaihtamismahdollisuuden", + "Password_changed_successfully" : "Salasana vaihdettu", "People" : "Ihmiset", + "Please_enter_value_for_url" : "Anna avatarisi URL", "Please_wait" : "Odota hetki", "Please_wait_activation" : "Odota, tämä voi kestää jonkin aikaa.", "Please_wait_statistics" : "Odota, tilastoja generoidaan.", - "Please_enter_value_for_url" : "Anna avatarisi URL", "Powered_by" : "Powered by", "Preferences" : "Asetukset", "Preferences_saved" : "Asetukset tallennettu", @@ -315,8 +315,8 @@ "Registration_Succeeded" : "Rekisteröinti onnistui", "Remember_me" : "Muista minut", "Remove" : "Poista", - "Remove_custom_oauth" : "Poista mukautettu oauth", "Remove_Admin" : "Poista ylläpitäjyys", + "Remove_custom_oauth" : "Poista mukautettu oauth", "Reset_password" : "Nollaa salasana", "Room" : "Huone", "Room_name_changed" : "Huoneen nimi vaihdettu <em>__room_name__</em> <em>__user_by__</em> toimesta", @@ -326,6 +326,13 @@ "Room_uploaded_file_list_empty" : "Tiedostoja ei ole saatavilla.", "room_user_count" : "%s käyttäjää", "Rooms" : "Huoneet", + "S_new_messages_since_s" : "%s uutta viestiä lähtien %s", + "SAML" : "SAML", + "SAML_Custom_Cert" : "Custom sertifikaatti", + "SAML_Custom_Entry_point" : "Custom Entry Point", + "SAML_Custom_Generate_Username" : "Generoi käyttäjätunnus", + "SAML_Custom_Issuer" : "Custom Issuer", + "SAML_Custom_Provider" : "Custom Provider", "Save" : "Tallenna", "Save_changes" : "Tallenna muutokset", "Save_Mobile_Bandwidth" : "Säästä kaistaa mobiilissa", @@ -356,12 +363,6 @@ "Site_Name" : "Sivuston nimi:", "Site_Url" : "Sivuston URL-osoite", "Site_Url_Description" : "Esimerkiksi: https://chat.domain.com/", - "SAML" : "SAML", - "SAML_Custom_Cert" : "Custom sertifikaatti", - "SAML_Custom_Entry_point" : "Custom Entry Point", - "SAML_Custom_Generate_Username" : "Generoi käyttäjätunnus", - "SAML_Custom_Issuer" : "Custom Issuer", - "SAML_Custom_Provider" : "Custom Provider", "SMTP" : "SMTP", "SMTP_Host" : "SMTP-palvelin", "SMTP_Password" : "SMTP Salasana", @@ -373,9 +374,9 @@ "Stats_Active_Users" : "Aktiivisia käyttäjiä", "Stats_Avg_Channel_Users" : "Keskimääräinen kanavan käyttäjämäärä", "Stats_Avg_Private_Group_Users" : "Keskimääräinen käyttäjämäärä", + "Stats_Away_Users" : "Poissaolevat käyttäjät", "Stats_Max_Room_Users" : "Maksimi käyttäjämäärä", "Stats_Non_Active_Users" : "Passiivisia käyttäjiä", - "Stats_Away_Users" : "Poissaolevat käyttäjät", "Stats_Offline_Users" : "Offline-käyttäjiä", "Stats_Online_Users" : "Online-käyttäjiä", "Stats_OS_Arch" : "OS Arkkitehtuuri", @@ -396,7 +397,6 @@ "Stop_Recording" : "Lopeta nauhoittaminen", "strike" : "yliviivaa", "Submit" : "Lähetä", - "S_new_messages_since_s" : "%s uutta viestiä lähtien %s", "The_field_is_required" : "Kenttä %s vaaditaan.", "True" : "Kyllä", "Unnamed" : "Nimetön", @@ -414,7 +414,6 @@ "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", - "Username_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut käyttäjätunnuksen vaihtamismahdollisuuden", "User_has_been_deactivated" : "Käyttäjä on deaktivoitu", "User_has_been_deleted" : "Käyttäjä on poistettu", "User_Info" : "Käyttäjän tiedot", @@ -432,13 +431,14 @@ "User_removed_by" : "Käyttäjä <em>__user_removed__</em> poistettu <em>__user_by__</em> toimesta.", "User_Settings" : "Käyttäjän asetukset", "User_updated_successfully" : "Käyttäjän tiedot päivitetty", - "Users" : "Käyttäjät", "Username" : "Käyttäjänimi", "Username_cant_be_empty" : "Käyttäjänimi ei voi olla tyhjä", + "Username_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut käyttäjätunnuksen vaihtamismahdollisuuden", "Username_description" : "Käyttäjänimeä käytetään sinun mainitsemiseen muiden viesteissä.", "Username_invalid" : "<strong>%s</strong> ei ole kelvollinen käyttäjänimi,<br/> käytä vain kirjaimia, numeroita, pistettä ja viivaa", "Username_title" : "Rekisteröi käyttäjänimi", "Username_unavaliable" : "<strong>%s</strong> on jo käytössä :(", + "Users" : "Käyttäjät", "View_All" : "Katso kaikki", "Wait_activation_warning" : "Ennen kuin voit kirjautua, tunnuksesi pitää aktivoida ylläpitäjän toimesta.", "We_have_sent_password_email" : "Lähetimme salasanan nollausohjeet sähköpostiisi. Mikäli et saanut sähköpostia, yritä uudelleen.", @@ -446,8 +446,8 @@ "Welcome" : "Tervetuloa <em>%s</em>.", "Welcome_to_the" : "Tervetuloa", "With_whom" : "kanssa", - "Yes_delete_it" : "Kyllä, poista!", "Yes_clear_all" : "Jep, tyhjennä kaikki!", + "Yes_delete_it" : "Kyllä, poista!", "you_are_in_preview_mode_of" : "Tämä on kanavan #<strong>__room_name__</strong> esikatselutila", "You_need_confirm_email" : "Sinun tulee vahvistaa sähköpostiosoitteesi!", "You_will_not_be_able_to_recover" : "Viestin palauttaminen ei ole mahdollista!", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index c448b6f0f8d..d23e79c7535 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -4,6 +4,17 @@ "Accounts" : "Comptes", "Accounts_denyUnverifiedEmail" : "Refuser les emails non vérifiées", "Accounts_EmailVerification" : "Vérification de l'e-mail", + "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_Identity_Path" : "URL d'identification", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "URL de Token", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Connexion avec Facebook", "Accounts_OAuth_Facebook_id" : "App Id Facebook", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -19,21 +30,10 @@ "Accounts_OAuth_Meteor" : "Connexion avec Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Id", - "Accounts_ManuallyApproveNewUsers" : "Approuver manuellement les nouveaux utilisateurs", - "Accounts_RegistrationRequired" : "Enregistrement nécessaire", "Accounts_OAuth_Twitter" : "Connexion avec Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "URL de Token", - "Accounts_OAuth_Custom_Identity_Path" : "URL d'identification", - "Accounts_OAuth_Custom_Authorize_Path" : "URL d'autorisation", - "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Enable" : "Activer", - "Accounts_OAuth_Custom_Button_Label_Text" : "Texte du bouton", - "Accounts_OAuth_Custom_Button_Label_Color" : "Couleur de texte du bouton", - "Accounts_OAuth_Custom_Button_Color" : "Couleur du bouton", + "Accounts_RegistrationRequired" : "Enregistrement nécessaire", "Activate" : "Activer", "Add_custom_oauth" : "Ajouter OAuth personnalisé", "Add_Members" : "Ajouter des membres", @@ -48,6 +48,7 @@ "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", "away" : "absent", "Away" : "Absent", @@ -55,7 +56,6 @@ "Away_female" : "Absente", "away_male" : "absent", "Away_male" : "Absent", - "Auto_Load_Images" : "Charger automatiquement les images", "Back_to_login" : "Retourner à l'écran de connexion", "bold" : "gras", "busy" : "occupé", @@ -74,7 +74,6 @@ "Commands" : "Commandes", "Confirm_password" : "Confirmez votre mot de passe", "Contact" : "Contact", - "Delete" : "Supprimer", "Conversation" : "Conversation", "Convert_Ascii_Emojis" : "Convertir code ASCII vers émoticônes", "Create_new" : "Créer nouveau", @@ -82,12 +81,12 @@ "Create_new_private_group" : "Créer un nouveau groupe privé", "Create_new_public_channel" : "Créer un nouveau canal publique.", "Created_at" : "Créé le", - "Custom_oauth_unique_name" : "Nom unique OAuth personnalisé", "Custom_oauth_helper" : "Lorsque vous configurez votre service OAuth, vous devez indiquer une URL pour le Callback. Utilisez <pre>%s</pre>", + "Custom_oauth_unique_name" : "Nom unique OAuth personnalisé", "days" : "jours", "Deactivate" : "Désactiver", + "Delete" : "Supprimer", "Delete_User_Warning" : "Supprimer un utilisateur va également supprimer tous les messages de celui-ci. Cette action ne peut être annulée.", - "Edit" : "Modifier", "Deleted" : "Supprimé !", "Desktop_Notifications" : "Notifications sur le bureau", "Desktop_Notifications_Disabled" : "Les notifications du bureau sont désactivées, Modifiez les préférences de votre navigateur si vous avez besoin de les activer.", @@ -100,6 +99,7 @@ "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", + "Edit" : "Modifier", "edited" : "modifié", "Email_already_exists" : "L'adresse email existe déjà ", "Email_or_username" : "Adresse email ou nom d'utilisateur", @@ -114,16 +114,14 @@ "Favorites" : "Favoris", "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é", - "LDAP_Port" : "Port LDAP", "Fork_it_on_github" : "Cloner sur GitHub", - "LDAP_Url" : "Adresse LDAP", "From_Email" : "De", "General" : "Général", "Get_to_know_the_team" : "Venez nous rencontrer", "github_no_public_email" : "Vous n'avez pas d'adresse email public associé à votre compte GitHub", "Give_a_unique_name_for_the_custom_oauth" : "Indiquez un nom unique pour l'OAuth personnalisé", - "Have_your_own_chat" : "Disposez de votre propre salon de discussion en ligne. Développé à l'aide de Meteor.com, Rocket.Chat est une solution pour les développeurs désirant mettre en place et faire évoluer leur propre plate-forme de discussion.", "Has_more" : "a plus de", + "Have_your_own_chat" : "Disposez de votre propre salon de discussion en ligne. Développé à l'aide de Meteor.com, Rocket.Chat est une solution pour les développeurs désirant mettre en place et faire évoluer leur propre plate-forme de discussion.", "Hide_room" : "Cacher le salon", "History" : "Historique", "hours" : "heures", @@ -163,11 +161,13 @@ "Layout_Terms_of_Service" : "Conditions de service", "LDAP" : "LDAP", "LDAP_DN" : "DN LDAP", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "Adresse LDAP", "Leave_room" : "Quitter le salon", "line" : "ligne", "Load_more" : "Charger plus", - "Loading_more_from_history" : "Charger plus d'historique", "Loading..." : "Chargement...", + "Loading_more_from_history" : "Charger plus d'historique", "Loading_suggestion" : "Chargement des suggestions ...", "Login" : "Se connecter", "Login_with" : "Connectez-vous avec %s", @@ -182,15 +182,15 @@ "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_AllowPinning" : "Autoriser l'épinglement de messages", "Message_deleting_not_allowed" : "Suppression d'un message non autorisée", - "Message_editing_not_allowed" : "Modification 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_KeepHistory" : "Conserver l'historique des messages", "Message_MaxAllowedSize" : "Taille maximum de message autorisée", + "Message_pinned" : "Message épinglé", "Message_pinning_not_allowed" : "L'épinglement de message n'est pas autorisé", - "Message_AllowPinning" : "Autoriser l'épinglement de messages", - "Message_KeepHistory" : "Conserver l'historique des messages", "Message_removed" : "Message supprimé", - "Message_pinned" : "Message épinglé", "Message_ShowDeletedStatus" : "Afficher le statut de suppression", "Message_ShowEditedStatus" : "Afficher le statut de modification", "Messages" : "Messages", @@ -209,26 +209,26 @@ "My_Account" : "Mon compte", "n_messages" : "%s messages", "Name" : "Nom", - "Name_optional" : "Nom (optionnel)", "Name_cant_be_empty" : "Le nom ne peut pas être vide", + "Name_optional" : "Nom (optionnel)", "New_messages" : "Nouveaux messages", "New_password" : "Nouveau mot de passe", + "No_channel_with_name_%s_was_found" : "Aucun salon nommé <strong>\"%s\"</strong> n'a été trouvé !", "No_channels_yet" : "Vous ne faites partie d’aucun canal pour le moment.", "No_direct_messages_yet" : "Vous n'avez pris part à aucune conversation pour le moment.", "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_permission_to_view_room" : "Vous n'avez pas la permission de voir ce salon", - "No_channel_with_name_%s_was_found" : "Aucun salon nommé <strong>\"%s\"</strong> n'a été trouvé !", - "No_group_with_name_%s_was_found" : "Aucun groupe privé nommé <strong>\"%s\"</strong> n'a été trouvé !", "No_user_with_username_%s_was_found" : "Aucun utilisateur nommé <strong>\"%s\"</strong> n'a été trouvé !", "Not_allowed" : "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", - "Old_Password" : "Ancien mot de passe", "Old_and_new_password_required" : "Vous devez renseigner votre ancien mot de passe et le nouveau afin de changer ce dernier.", - "Only_you_can_see_this_message" : "Seul vous pouvez voir ce message", + "Old_Password" : "Ancien mot de passe", "Online" : "Connecté", + "Only_you_can_see_this_message" : "Seul vous pouvez voir ce message", "Oops!" : "Oups", "Opt_out_statistics" : "Ne pas envoyer mes statistiques anonymes à Rocket.Chat", "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.", @@ -266,8 +266,8 @@ "Registration_Succeeded" : "Enregistrement réussi", "Remember_me" : "Se souvenir de moi", "Remove" : "Supprimer", - "Remove_custom_oauth" : "Supprimer OAuth personnalisé ", "Remove_Admin" : "Supprimer administrateur", + "Remove_custom_oauth" : "Supprimer OAuth personnalisé ", "Reset_password" : "Réinitialiser le mot de passe", "Room" : "Salon", "Room_name_changed" : "Nom du salon changé en : <em>__room_name__</em> par <em>__user_by__</em>", @@ -277,6 +277,8 @@ "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", "Save" : "Enregistrer", "Save_changes" : "Sauvegarder les modifications", "Save_Mobile_Bandwidth" : "Préserver la bande passante sur mobile", @@ -305,7 +307,6 @@ "Silence" : "Silence", "since_creation" : "depuis %s", "Site_Name" : "Nom du site :", - "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "Hôte SMTP", "SMTP_Password" : "Mot de passe SMTP", @@ -317,9 +318,9 @@ "Stats_Active_Users" : "Utilisateurs actifs", "Stats_Avg_Channel_Users" : "Nombre moyen d'utilisateurs dans les canaux", "Stats_Avg_Private_Group_Users" : "Nombre moyen d'utilisateurs dans les groupes privés", + "Stats_Away_Users" : "Utilisateurs indisponibles", "Stats_Max_Room_Users" : "Nombre d'utilisateur maximum par salon", "Stats_Non_Active_Users" : "Utilisateurs inactifs", - "Stats_Away_Users" : "Utilisateurs indisponibles", "Stats_Offline_Users" : "Utilisateurs hors ligne", "Stats_Online_Users" : "Utilisateurs en ligne", "Stats_OS_Arch" : "Architecture", @@ -340,7 +341,6 @@ "Stop_Recording" : "Arrêter l'enregistrement", "strike" : "barré", "Submit" : "Envoyer", - "S_new_messages_since_s" : "%s nouveaux messages depuis %s", "The_field_is_required" : "Le champ %s est requis.", "True" : "Oui", "Unnamed" : "Sans nom", @@ -371,13 +371,13 @@ "User_removed_by" : "L'utilisateur <em>__user_removed__</em> a été éjecté par <em>__user_by__</em>.", "User_Settings" : "Paramètres utilisateur", "User_updated_successfully" : "Utilisateur mis à jour avec succès", - "Users" : "Utilisateurs", "Username" : "Nom d'utilisateur", "Username_cant_be_empty" : "Le nom d'utilisateur doit être renseigné", "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", "Username_unavaliable" : "<strong>%s</strong> est déjà utilisé :(", + "Users" : "Utilisateurs", "View_All" : "Voir tous", "Wait_activation_warning" : "Avant de pouvoir vous connecter, votre compte doit être manuellement activé par un administrateur.", "We_have_sent_password_email" : "Nous vous avons envoyé un email avec des instructions de réinitialisation de votre mot de passe. Si vous ne le recevez pas dans quelques minutes, veuillez réessayer.", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 50a645a054d..79eb1d0b99d 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -2,23 +2,23 @@ "Access_online_demo" : "Pristupi online demonstraciji", "Access_Online_Demo" : "Pristupi Online demonstraciji", "Accounts" : "RaÄuni", - "Accounts_AllowUsernameChange" : "Dopusti promjenu korisniÄkog imena", "Accounts_AllowPasswordChange" : "Dopusti promjenu lozinke", + "Accounts_AllowUsernameChange" : "Dopusti promjenu korisniÄkog imena", "Accounts_AvatarSize" : "VeliÄina Avatara", "Accounts_denyUnverifiedEmail" : "Odbij neprovjereni e-mail", "Accounts_EmailVerification" : "E-mail Verifikacija", + "Accounts_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", + "Accounts_OAuth_Custom_Button_Color" : "Boja Gumba", + "Accounts_OAuth_Custom_Button_Label_Text" : "Tekst Gumba", + "Accounts_OAuth_Custom_Enable" : "Omogući", + "Accounts_OAuth_Custom_Secret" : "Tajno", "Accounts_OAuth_Facebook" : "Facebook prijava", "Accounts_OAuth_Github" : "GitHub Prijava", "Accounts_OAuth_Google" : "Google Prijava", "Accounts_OAuth_Linkedin" : "LinkedIn Prijava", "Accounts_OAuth_Meteor" : "Meteor Prijava", - "Accounts_ManuallyApproveNewUsers" : "RuÄno odobri nove korisnike", - "Accounts_RegistrationRequired" : "Potrebna je registracija", "Accounts_OAuth_Twitter" : "Twitter Prijava", - "Accounts_OAuth_Custom_Secret" : "Tajno", - "Accounts_OAuth_Custom_Enable" : "Omogući", - "Accounts_OAuth_Custom_Button_Label_Text" : "Tekst Gumba", - "Accounts_OAuth_Custom_Button_Color" : "Boja Gumba", + "Accounts_RegistrationRequired" : "Potrebna je registracija", "Activate" : "Aktiviraj", "Add_Members" : "Dodaj ÄŒlanove", "Add_users" : "Dodaj korisnike", @@ -29,6 +29,7 @@ "are_also_typing" : "isto tipkaju", "are_typing" : "tipkaju", "Are_you_sure" : "Jesi li siguran?", + "Auto_Load_Images" : "Automatski uÄitaj slike", "Avatar_changed_successfully" : "Avatar je uspjeÅ¡no promijenjen", "away" : "odsutan", "Away" : "Odsutan", @@ -36,7 +37,6 @@ "Away_female" : "Odsutna", "away_male" : "odsutan", "Away_male" : "Odsutan", - "Auto_Load_Images" : "Automatski uÄitaj slike", "Back_to_login" : "Natrag na prijavu", "bold" : "podebljaj", "busy" : "zaposlen", @@ -54,7 +54,6 @@ "coming_soon" : "dolazi uskoro", "Confirm_password" : "Potvrdi svoju lozinku", "Contact" : "Kontakt", - "Delete" : "ObriÅ¡i", "Conversation" : "Razgovor", "Convert_Ascii_Emojis" : "Pretvori ASCII u Emoji", "Create_new" : "Stvori novi", @@ -64,9 +63,9 @@ "Created_at" : "Stvoreno u", "days" : "dana", "Deactivate" : "IskljuÄi", - "Delete_User_Warning" : "Brisanje korisnika će izbrisati i sve poruke od tog korisnika. Ovo se ne može poniÅ¡titi.", - "Edit" : "Uredi", + "Delete" : "ObriÅ¡i", "Delete_Room_Warning" : "Brisanje sobe će obrisati sve poruke u toj sobi. Ovo se ne može poniÅ¡titi.", + "Delete_User_Warning" : "Brisanje korisnika će izbrisati i sve poruke od tog korisnika. Ovo se ne može poniÅ¡titi.", "Deleted" : "Obrisano!", "Direct_Messages" : "Izravne Poruke", "Disable_Favorite_Rooms" : "Onemogući favorite", @@ -76,6 +75,7 @@ "Duplicate_channel_name" : "Kanal s nazivom '% s' postoji", "Duplicate_private_group_name" : "Privatna Grupa s nazivom '% s' postoji", "E-mail" : "E-mail", + "Edit" : "Uredi", "edited" : "ureÄ‘eno", "Email_already_exists" : "Email već postoji", "Email_or_username" : "Email or username", @@ -92,8 +92,8 @@ "From_Email" : "Sa e-maila", "Get_to_know_the_team" : "Upoznajte Rocket.Team", "github_no_public_email" : "NemaÅ¡ ni1 javni email u svom GitHub raÄunu", - "Have_your_own_chat" : "Imaj svoj vlastiti web chat. Razvijen sa Meteor.com, Rocket.Chat je sjajno rjeÅ¡enje za developere koji žele sagraditi i dalje razvijati svoju vlastitu chat platformu.", "Has_more" : "Ima viÅ¡e", + "Have_your_own_chat" : "Imaj svoj vlastiti web chat. Razvijen sa Meteor.com, Rocket.Chat je sjajno rjeÅ¡enje za developere koji žele sagraditi i dalje razvijati svoju vlastitu chat platformu.", "Hide_room" : "Sakrij sobu", "History" : "Povijest", "hours" : "sati", @@ -127,8 +127,8 @@ "Leave_room" : "IzaÄ‘i iz sobe", "line" : "linija", "Load_more" : "UÄitaj viÅ¡e", - "Loading_more_from_history" : "UÄitavanje viÅ¡e iz povijesti", "Loading..." : "UÄitavanje ...", + "Loading_more_from_history" : "UÄitavanje viÅ¡e iz povijesti", "Loading_suggestion" : "UÄitavam sugestije...", "Login" : "Prijava", "Login_with" : "Prijavi se sa %s", @@ -143,15 +143,15 @@ "Message_AllowDeleting" : "Dopusti Brisanje Poruka", "Message_AllowEditing" : "Dopusti UreÄ‘ivanje Poruka", "Message_AllowEditing_BlockEditInMinutes" : "Blokirajte ureÄ‘ivanje poruka nakon (u minutama - 0 kako bi onemoguÄili)", + "Message_AllowPinning" : "Dopusti pribadanje poruka ", "Message_deleting_not_allowed" : "Brisanje poruka nije dopuÅ¡teno", - "Message_editing_not_allowed" : "UreÄ‘ivanje poruka nije dopuÅ¡teno", "Message_editing_blocked" : "Ova poruka se viÅ¡e ne može ureÄ‘ivati ", + "Message_editing_not_allowed" : "UreÄ‘ivanje poruka nije dopuÅ¡teno", + "Message_KeepHistory" : "Zadrži Povijest Poruka", "Message_MaxAllowedSize" : "Maksimalna dopuÅ¡tena veliÄina poruke", + "Message_pinned" : "Poruka je pribodena", "Message_pinning_not_allowed" : "Pribadanje poruka nije dopuÅ¡teno", - "Message_AllowPinning" : "Dopusti pribadanje poruka ", - "Message_KeepHistory" : "Zadrži Povijest Poruka", "Message_removed" : "Poruka je maknuta", - "Message_pinned" : "Poruka je pribodena", "Message_ShowDeletedStatus" : "Pokaži Izbrisan status", "Message_ShowEditedStatus" : "Prikaži ureÄ‘eni status", "Messages" : "Poruke", @@ -171,27 +171,27 @@ "Name_cant_be_empty" : "Ime ne može biti prazno", "New_messages" : "Nove Poruke", "New_password" : "Nova lozinka", + "No_channel_with_name_%s_was_found" : "Kanal s tim imenom nije naÄ‘en", "No_channels_yet" : "JoÅ¡ nisi dio nijednog kanala.", "No_direct_messages_yet" : "JoÅ¡ nisi zapoÄeo ni1 razgovor.", "No_favorites_yet" : "JoÅ¡ nisi dodao omiljene.", + "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_channel_with_name_%s_was_found" : "Kanal s tim imenom nije naÄ‘en", - "No_group_with_name_%s_was_found" : "Privatna grupa s tim imenom nije naÄ‘ena", "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", "Nothing_found" : "NiÅ¡ta nije naÄ‘eno", "Notify_all_in_this_room" : "Obavijesti sve u ovoj sobi", "Old_Password" : "Stara Lozinka", - "Only_you_can_see_this_message" : "Samo ti možeÅ¡ vidjeti ovu poruku", "Online" : "Online", + "Only_you_can_see_this_message" : "Samo ti možeÅ¡ vidjeti ovu poruku", "Oops!" : "Ups", "Opt_out_statistics" : "Ne Å¡alji moje anonimne statistike Rocket.Chatu", "others" : "drugi", "Password" : "Lozinka", - "Password_changed_successfully" : "Lozinka je uspjeÅ¡no promijenjena", "Password_Change_Disabled" : "VaÅ¡ Rocket.Chat Administrator je onemogućio izmjenu lozinke", + "Password_changed_successfully" : "Lozinka je uspjeÅ¡no promijenjena", "People" : "Ljudi", "Please_wait" : "PriÄekaj", "Please_wait_activation" : "Molimo priÄekajte, ovo bi moglo potrajati neko vrijeme.", @@ -225,6 +225,8 @@ "Room_uploaded_file_list_empty" : "Nijedna datoteka nije dostupna", "room_user_count" : "% korisnika", "Rooms" : "Sobe", + "S_new_messages_since_s" : "novih poruka od", + "SAML_Custom_Generate_Username" : "Izradi korisniÄko ime", "Save" : "SaÄuvaj", "Save_changes" : "Spremi promjene", "Search" : "Traži", @@ -251,7 +253,6 @@ "Silence" : "TiÅ¡ina", "since_creation" : "%s", "Site_Name" : "Ime Stranice:", - "SAML_Custom_Generate_Username" : "Izradi korisniÄko ime", "SMTP_Password" : "SMTP lozinka", "SMTP_Port" : "SMTP port", "SMTP_Username" : "SMTP korisniÄko ime", @@ -260,9 +261,9 @@ "Statistics" : "Statistike", "Stats_Active_Users" : "Aktivni korisnici", "Stats_Avg_Channel_Users" : "ProsjeÄan broj korisnika kanala", + "Stats_Away_Users" : "Odsutni Korisnici", "Stats_Max_Room_Users" : "Maksimalno Korisnika Sobe", "Stats_Non_Active_Users" : "Neaktivni korisnici", - "Stats_Away_Users" : "Odsutni Korisnici", "Stats_Offline_Users" : "Offline Korisnici", "Stats_Online_Users" : "Online Korisnici", "Stats_OS_Freemem" : "OS Slobodna Memorija", @@ -277,7 +278,6 @@ "Stats_Total_Users" : "Ukupno korisnika", "strike" : "precrtaj", "Submit" : "PoÅ¡alji", - "S_new_messages_since_s" : "novih poruka od", "The_field_is_required" : "Polje% s je traženo.", "True" : "Da", "Unnamed" : "Neimenovan", @@ -292,7 +292,6 @@ "User_added_by" : "Korisnik <em>__user_added__</em> dodan od <em>__user_by__</em>.", "User_Channels" : "KorisniÄki kanali", "User_has_been_activated" : "Korisnik je aktiviran", - "Username_Change_Disabled" : "VaÅ¡ Rocket.Chat Administrator je onemogućio izmjenu korisniÄkih imena", "User_has_been_deactivated" : "Korisnik je deaktiviran", "User_has_been_deleted" : "Korisnik je obrisan", "User_Info" : "Podaci o korisniku", @@ -310,13 +309,14 @@ "User_removed_by" : "Korisnik <em>__user_removed__</em> maknut od <em>__user_by__</em>.", "User_Settings" : "KorisniÄke postavke", "User_updated_successfully" : "Korisnik je uspjeÅ¡no ažuriran", - "Users" : "Korisnici", "Username" : "KorisniÄko ime", "Username_cant_be_empty" : "KorisniÄko ime ne može ostati prazno.", + "Username_Change_Disabled" : "VaÅ¡ Rocket.Chat Administrator je onemogućio izmjenu korisniÄkih imena", "Username_description" : "KorisniÄko ime se koristi kako bi te drugi mogli spomenuti u porukama.", "Username_invalid" : "<strong>%s</strong> nije valjano korisniÄko ime,<br/> koristi samo slova, brojeve, toÄke i crtice", "Username_title" : "Registriraj korisniÄko ime", "Username_unavaliable" : "<strong>%s</strong> je već zauzeto :(", + "Users" : "Korisnici", "View_All" : "Prikaži Sve", "Wait_activation_warning" : "Prije nego Å¡to se prijavite, vaÅ¡ raÄun mora ruÄno aktivirati administrator.", "We_have_sent_password_email" : "Poslan ti je e-mail sa uputama za resetiranje lozinke. Provjeri i spam folder! Ako ga ne primiÅ¡ uskoro, molimo te vrati se i pokuÅ¡aj opet.", diff --git a/i18n/ja.i18n.json b/i18n/ja.i18n.json index 3f6b4f9338c..05714689485 100644 --- a/i18n/ja.i18n.json +++ b/i18n/ja.i18n.json @@ -6,9 +6,9 @@ "and" : "ã¨", "are_also_typing" : "誰ã‹ãŒã¾ãŸå…¥åŠ›ã—ã¦ã„ã¾ã™", "are_typing" : "誰ã‹ãŒå…¥åŠ›ã—ã¦ã„ã¾ã™", + "Auto_Load_Images" : "ç”»åƒè‡ªå‹•èªã¿è¾¼ã¿", "away" : "離å¸ä¸", "Away" : "離å¸ä¸", - "Auto_Load_Images" : "ç”»åƒè‡ªå‹•èªã¿è¾¼ã¿", "Back_to_login" : "ãƒã‚°ã‚¤ãƒ³ã¸æˆ»ã‚‹", "bold" : "太å—", "busy" : "å–ã‚Šè¾¼ã¿ä¸", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 540a8098d32..58915330161 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -3,14 +3,25 @@ "Access_Online_Demo" : "ចូល​ទៅ​សាក​ល្បងវា​លើ​អ៊ីនធើណិážâ€‹áž‡áž¶â€‹áž˜áž»áž“​សិន", "Accounts" : "គណនី", "Accounts_AllowedDomainsList" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែង Domain ដែលអនុញ្ញាážáž·áž€áŸ’នុងបញ្ជី", - "Accounts_AllowUsernameChange" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹ážˆáŸ’មោះ​អ្នក​ប្រើ", "Accounts_AllowPasswordChange" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹áž–ាក្យ​សម្ងាážáŸ‹", + "Accounts_AllowUsernameChange" : "អនុញ្ញាážâ€‹áž±áŸ’យ​ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹ážˆáŸ’មោះ​អ្នក​ប្រើ", "Accounts_AvatarResize" : "ប្ážáž¼â€‹ážšâ€‹áž‘ំហំ Avatar", "Accounts_AvatarSize" : "ទំហំ Avatar", "Accounts_AvatarStorePath" : "ទីážáž¶áŸ†áž„ផ្ទុក Avatar", "Accounts_AvatarStoreType" : "ប្រភáŸáž‘បន្ទុក Avatar", "Accounts_denyUnverifiedEmail" : "រាំងážáŸ’ទប់អ្នកមិនបានផ្ទៀážáž•áŸ’ទាážáŸ‹áž¢áŸŠáž¸áž˜áŸ‚áž›", "Accounts_EmailVerification" : "ការ​ផ្ទៀងផ្ទាážáŸ‹â€‹ážáž¶áž˜â€‹â€‹áž¢áŸŠáž¸â€‹áž˜áŸ‰áŸ‚​ល", + "Accounts_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", + "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_id" : "áž›áŸážážŸáž˜áŸ’គាល់", + "Accounts_OAuth_Custom_Identity_Path" : "ទីទាំងអážáŸ’ážážŸáž‰áŸ’ញាណ", + "Accounts_OAuth_Custom_Secret" : "ការ​សម្ងាážáŸ‹", + "Accounts_OAuth_Custom_Token_Path" : "ទីទាំង Token", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "ចូល​ážáž¶áž˜â€‹áž ្វáŸážŸáž”៊ូក", "Accounts_OAuth_Facebook_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់​កម្មវិធី​ហ្វáŸážŸáž”៊ូក", "Accounts_OAuth_Facebook_secret" : "ហ្វáŸâ€‹ážŸâ€‹áž”៊ុ​ក​សម្ងាážáŸ‹", @@ -29,21 +40,10 @@ "Accounts_OAuth_Meteor" : "ចូល​ážáž¶áž˜ Meteor", "Accounts_OAuth_Meteor_id" : "áž›áŸážâ€‹ážŸáž˜áŸ’គាល់ Meteor ", "Accounts_OAuth_Meteor_secret" : "Meteor សម្ងាážáŸ‹", - "Accounts_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", - "Accounts_RegistrationRequired" : "ážáŸ’រូវ​ចុះ​ឈ្មោះ", "Accounts_OAuth_Twitter" : "ចូលážáž¶áž˜ Twitter", "Accounts_OAuth_Twitter_id" : "áž›áŸážážŸáž˜áŸ’គាល់ Twitter", "Accounts_OAuth_Twitter_secret" : "Twitter សម្ងាážáŸ‹", - "Accounts_OAuth_Custom_id" : "áž›áŸážážŸáž˜áŸ’គាល់", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "ទីទាំង Token", - "Accounts_OAuth_Custom_Identity_Path" : "ទីទាំងអážáŸ’ážážŸáž‰áŸ’ញាណ", - "Accounts_OAuth_Custom_Authorize_Path" : "ទីážáž¶áŸ†áž„ផ្ទៀážáž•áŸ’ទាážáŸ‹", - "Accounts_OAuth_Custom_Secret" : "ការ​សម្ងាážáŸ‹", - "Accounts_OAuth_Custom_Enable" : "អនុញ្ញាáž", - "Accounts_OAuth_Custom_Button_Label_Text" : "អážáŸ’ážáž”ទ​ប៊ូážáž»áž„", - "Accounts_OAuth_Custom_Button_Label_Color" : "ពណ៌អážáŸ’ážáž”ទប៊ូážáž»áž„", - "Accounts_OAuth_Custom_Button_Color" : "ពណ៌ប៊ូážáž»áž„", + "Accounts_RegistrationRequired" : "ážáŸ’រូវ​ចុះ​ឈ្មោះ", "Activate" : "ធ្វើ​ឱ្យ​សកម្ម", "Add_custom_oauth" : "បន្ážáŸ‚ម oauth ផ្ទាល់​ážáŸ’លួន", "Add_Members" : "ážáŸ‚ម​សមាជិក", @@ -60,6 +60,7 @@ "are_also_typing" : "គឺ​កំពុង​ព្យាយាម​ផង​ដែរ", "are_typing" : "កំពុង​វាយ", "Are_you_sure" : "ážáž¾â€‹áž¢áŸ’នក​ច្បាស់​ហើយ​ឬ?", + "Auto_Load_Images" : "ផ្ទុក​រូបភាព​ដោយ​ស្វáŸáž™áž”្រវážáŸ’ážáž·", "Avatar_changed_successfully" : "ផ្លាស់​ប្ážáž¼â€‹ážšâ€‹ážšáž¼áž”​ážáŸ†â€‹áž“ាង​ដោយ​ជោគជáŸáž™", "away" : "ឆ្ងាយ", "Away" : "ឆ្ងាយ", @@ -67,7 +68,6 @@ "Away_female" : "ឆ្ងាយ", "away_male" : "ឆ្ងាយ", "Away_male" : "ឆ្ងាយ", - "Auto_Load_Images" : "ផ្ទុក​រូបភាព​ដោយ​ស្វáŸáž™áž”្រវážáŸ’ážáž·", "Back_to_login" : "ážáŸ’រឡប់​មក​ឡុក​ចូល", "bold" : "ក្រាស់", "busy" : "រវល់", @@ -88,7 +88,6 @@ "Compact_View" : "មើលជាážáž¶ážšáž¶áž„", "Confirm_password" : "បញ្ជាក់​ពាក្យ​សម្ងាážáŸ‹", "Contact" : "ទំនាក់ទំនង", - "Delete" : "លុប", "Conversation" : "កិច្ច​ពិភាក្សា", "Convert_Ascii_Emojis" : "បម្លែង ASCII áž“áŸáŸ‡â€‹áž‘ៅ Emoji", "Create_new" : "បង្កើážâ€‹ážáŸ’មី", @@ -96,13 +95,13 @@ "Create_new_private_group" : "បង្កើážâ€‹áž€áŸ’រុម​ឯកជន", "Create_new_public_channel" : "បង្កើážâ€‹áž”៉ុស្ážáž·áŸâ€‹ážŸáž¶áž’ារណៈ​ážáŸ’មី", "Created_at" : "បាន​បង្កើážâ€‹áž€áž¶áž›â€‹áž–ី", - "Custom_oauth_unique_name" : "កំណážáŸ‹ oauth ឲ្យមានឈ្មោះážáŸ‚មួយគážáŸ‹", "Custom_oauth_helper" : "áž–áŸáž›áž¢áŸ’នកកំពុងកំណážáŸ‹ OAuth Provider នោះអ្នកនឹងទទួល URL បញ្ជាក់មួយážáŸ’រឡប់មកវិញ, ដែលប្រើ <pre>%s</pre>", + "Custom_oauth_unique_name" : "កំណážáŸ‹ oauth ឲ្យមានឈ្មោះážáŸ‚មួយគážáŸ‹", "days" : "ážáŸ’ងៃ", "Deactivate" : "ធ្វើឲ្យមិនសកម្ម", - "Delete_User_Warning" : "ការ​លប់​អ្នក​ប្រើប្រាស់ នឹង​ážáŸ’រូវ​លប់​​គ្រប់​សារ​​របស់​​គាážáŸ‹â€‹áž•áž„​ដែរ។ ដូច​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ធ្វើ​បាន​ទ០។", - "Edit" : "កែ​សម្រួល", + "Delete" : "លុប", "Delete_Room_Warning" : "ការលប់បន្ទប់មួយនឹងážáŸ’រូវលប់ចោលទាំងអស់នូវរាល់សារដែលបានប្រកាសនៅក្នុងបន្ទប់នáŸáŸ‡, ដំណើរការនáŸáŸ‡áž˜áž·áž“ទាន់បានបញ្ចប់ទáŸ", + "Delete_User_Warning" : "ការ​លប់​អ្នក​ប្រើប្រាស់ នឹង​ážáŸ’រូវ​លប់​​គ្រប់​សារ​​របស់​​គាážáŸ‹â€‹áž•áž„​ដែរ។ ដូច​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ធ្វើ​បាន​ទ០។", "Deleted" : "បាន​លប់!", "Desktop_Notifications" : "ជំនូនដំណឹងលើ Desktop", "Desktop_Notifications_Disabled" : "ជំនូនដំណឹងលើ Desktop មិនបានអនុញ្ញាážáž·, សូមផ្លាស់ប្ážáž¼ážšáž€áž¶ážšáž€áŸ†ážŽážáŸ‹áž“ៅលើ Browser របស់អ្នកប្រសិនបើចង់អនុញ្ញážáž·ážœáž¶", @@ -115,6 +114,7 @@ "Duplicate_channel_name" : "ប៉ុស្ážáž·áŸâ€‹ážŠáŸ‚ល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "Duplicate_private_group_name" : "ក្រុម​ឯក​ជន​ដែល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "E-mail" : "អ៊ីមែល", + "Edit" : "កែ​សម្រួល", "edited" : "បានកែសម្រួល", "Email_already_exists" : "អ៊ី​ម៉ែ​ល​ដែល​មាន​រួច​ហើយ", "Email_or_username" : "អ៊ីមែល ឬឈ្មោះ​សម្ងាážáŸ‹", @@ -135,25 +135,23 @@ "FileUpload_MediaTypeWhiteListDescription" : "ប្រើសញ្ញា ក្បៀស(,) ដើម្បីបែងចែងប្រភáŸáž‘ Media ក្នុងបញ្ជី", "Follow_social_profiles" : "ážáž¶áž˜â€‹ážŠáž¶áž“​​​បណ្ážáž¶â€‹áž‚ណនីបណ្ážáž¶áž‰â€‹ážŸáž„្គម​របស់​យើង​, មើល​យើង​លើ​ github និង​ចែក​រំលែក​បទពិសោធនáŸâ€‹ážšáž”ស់​អ្នក​ជាមួយ​ rocket.chat app នៅ​លើ​ក្ážáž¶ážšážƒáŸ€áž“​របស់​យើង", "Forgot_password" : "ភ្លáŸáž…​ពាក្យ​សម្ងាážáŸ‹", - "LDAP_Port" : "ច្រក LDAP", "Fork_it_on_github" : "ទៅ​មើល​វា​លើ github", - "LDAP_Url" : "URL របស់ LDAP", "From_Email" : "ពី​អ៊ី​ម៉ែ​ល", "General" : "ទូទៅ", "Get_to_know_the_team" : "ទៅ​ស្គាល់ Rocket.Team", "github_no_public_email" : "អ្នក​មិន​មាន​អ៊ីមែល​សាធារណៈ​ក្នុង​ GitHub នៅ​ឡើយ​ទáŸ", "Give_a_unique_name_for_the_custom_oauth" : "ផ្ážáž›áŸ‹â€‹áž±áŸ’យ​ឈ្មោះ​ážáŸ‚​មួយ​គážáŸ‹â€‹ážŸáž˜áŸ’រាប់ oauth ផ្ទាល់​ážáŸ’លួន", - "Have_your_own_chat" : "អ្នក​មាន Web Chat ផ្ទាល់​ážáŸ’លួនហើ​យឬ។ អភិវឌ្ឃនáŸâ€‹áž‡áž¶áž˜áž½áž™â€‹ Meteor.com, Rocket.Chat គឺ​ជា​ដំណោះ​ស្រាយ​ដáŸâ€‹áž›áŸ’អ​បំផុážâ€‹ážŸáž˜áŸ’រាប់អ្នក​អភិវឌ្ážáž“០ក្នុង​ការ​បង្កើហWeb Chat Plateform។", "Has_more" : "សញ្ញា Has ច្រើនទៀáž", + "Have_your_own_chat" : "អ្នក​មាន Web Chat ផ្ទាល់​ážáŸ’លួនហើ​យឬ។ អភិវឌ្ឃនáŸâ€‹áž‡áž¶áž˜áž½áž™â€‹ Meteor.com, Rocket.Chat គឺ​ជា​ដំណោះ​ស្រាយ​ដáŸâ€‹áž›áŸ’អ​បំផុážâ€‹ážŸáž˜áŸ’រាប់អ្នក​អភិវឌ្ážáž“០ក្នុង​ការ​បង្កើហWeb Chat Plateform។", "Hide_room" : "លាក់​បន្ទប់", "History" : "ប្រវážáŸ’ážáž·", "hours" : "ម៉ោង", "Incorrect_Password" : "ឃ្លាសំងាážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ", "inline_code" : "inline_code", "Install_FxOs" : "ដំឡើង Rocket.Chat នៅ​លើ Firefox របស់​អ្នក", - "Install_FxOs_follow_instructions" : "សូមបញ្ជាក់ការដំឡើងកម្មវិធីនáŸáŸ‡áž“ៅលើឧបករណáŸážšáž”ស់អ្នក(ចុច \"Install\" áž–áŸáž›áž”ញ្ចាក់)", "Install_FxOs_done" : "អស្ចារ្យណាស់ឥឡូវអ្នកអាចប្រើប្រាស់ Rocket.Chat ážáž¶áž˜ážšáž™áŸˆ Icon នៅលើ Homescreen។ សូមរីករាយជាមួយ Rocket.Chat!", "Install_FxOs_error" : "សុំទោស ដែលវាមិនដំណើរការážážŽáŸˆáž˜áž¶áž“បញ្ហាលáŸáž…ឡើងដូចážáž¶áž„ក្រោម", + "Install_FxOs_follow_instructions" : "សូមបញ្ជាក់ការដំឡើងកម្មវិធីនáŸáŸ‡áž“ៅលើឧបករណáŸážšáž”ស់អ្នក(ចុច \"Install\" áž–áŸáž›áž”ញ្ចាក់)", "Invalid_confirm_pass" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ញ្ជាក់​មិន​ដូច​ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​បញ្ចូល​", "Invalid_email" : "អ៊ី​មែល​ដែល​បញ្ចូល​មិន​ážáŸ’រឹម​ážáŸ’រូវ", "Invalid_name" : "ឈ្មោះ​មិន​​អាច​ទំនáŸážš", @@ -190,12 +188,14 @@ "LDAP_Bind_Search" : "ចំណងស្វែងរក", "LDAP_DN" : " LDAP DN", "LDAP_Enable" : "អនុញ្ញាážáž· LDAP", + "LDAP_Port" : "ច្រក LDAP", "LDAP_Sync_User_Data" : "រក្សាទិន្ននáŸáž™ User ដោយ Sync ជាមួយ Server", + "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", "Load_more" : "មើល​ទៀáž", - "Loading_more_from_history" : "លោážáž…្រើនទៀážáž–ីប្រវážáŸ’ážáž·", "Loading..." : "កំពុង​ដំណើរការ...", + "Loading_more_from_history" : "លោážáž…្រើនទៀážáž–ីប្រវážáŸ’ážáž·", "Loading_suggestion" : "កំពុង​មើល​ការ​សម្រáŸáž…​ចិážáŸ’áž...", "Login" : "ឡុក​ចូល", "Login_with" : "ឡុក​ចូល​ជាមួយ %s", @@ -211,16 +211,16 @@ "Message_AllowEditing" : "អនុញ្ញាážâ€‹áž±áŸ’យ​មាន​ការ​កែ​សម្រួល​សារ", "Message_AllowEditing_BlockEditInMinutes" : "បិទការកែស្រួលសារបន្ទាប់ (ជាចំនួននាទី ឬ0ដើម្បីបិទចោល)", "Message_AllowEditing_BlockEditInMinutesDescription" : "បញ្ចូលលáŸáž 0 ដើម្បីបិទការ Block", + "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​", "Message_AudioRecorderEnabled" : "ការážážážŸáž˜áŸ’áž›áŸáž„បានអនុញ្ញាážáž·", "Message_deleting_not_allowed" : "ការ​លប់សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", - "Message_editing_not_allowed" : "ការ​កែ​សម្រួល​សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", "Message_editing_blocked" : "សារ​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ážáŸ’រូវ​បាន​កែប្រែ​ទៀážâ€‹áž‘áŸ", + "Message_editing_not_allowed" : "ការ​កែ​សម្រួល​សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", + "Message_KeepHistory" : "រក្សា​​ប្រវážáŸ’ážáž·â€‹ážŸáž¶ážš", "Message_MaxAllowedSize" : "ទំហំអážáž·áž”រមាដែលážáŸ’រូវបានអនុញ្ញាážážŸáž¶ážš", + "Message_pinned" : "សារ\n", "Message_pinning_not_allowed" : "ការážáŸ’ទាស់​សារ​មិន​អនុញ្ញាážáž·â€‹", - "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​", - "Message_KeepHistory" : "រក្សា​​ប្រវážáŸ’ážáž·â€‹ážŸáž¶ážš", "Message_removed" : "សារ​បាន​លប់", - "Message_pinned" : "សារ\n", "Message_ShowDeletedStatus" : "បង្ហាញ​ស្ážáž¶áž“ភាព​ដែល​បាន​លុប", "Message_ShowEditedStatus" : "បង្ហាញ​ស្ážáž¶áž“ភាព​អážáŸ’ážáž”ទ​​ដែល​បាន​កែ​សម្រួល", "Message_ShowFormattingTips" : "បង្ហាញទ្រង់ទ្រាយដំបូន្មាន", @@ -243,34 +243,34 @@ "Name_cant_be_empty" : "ឈ្មោះ​មិន​អាច​ទទáŸ", "New_messages" : "សារ​ážáŸ’មី", "New_password" : "ពាក្យ​សម្ងាážáŸ‹â€‹ážáŸ’មី", + "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_groups_yet" : "អ្នក​មិន​ទាន់​មាន​ក្រុម​ឯកជន​នៅឡើយ", "No_permission_to_view_room" : "អ្នក​មិន​មាន​សិទ្ធ​មើល​បន្ទប់​នáŸáŸ‡â€‹áž¡áž¾áž™", - "No_channel_with_name_%s_was_found" : "មិន​មាន​ប៉ុស្ážáž·áŸâ€‹ážˆáŸ’មោះ <strong>\"%s\"</strong> ឡើយ​", - "No_group_with_name_%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_Password" : "ឃ្លាសម្ងាážáŸ‹áž…ាស់", "Old_and_new_password_required" : "អ្នកážáŸ’រូវážáŸ‚ផ្ážáž›áŸ‹áž‘ាំងពាក្យសម្ងាážáŸ‹áž…ាស់ áž“áž·áž„ážáŸ’មី ដើម្បីប្ážáž¼ážšáž–ាក្យសម្ងាážáŸ‹áŸ”", - "Only_you_can_see_this_message" : "មានážáŸ‚អ្នកដែលអាចឃើញសារនáŸáŸ‡", + "Old_Password" : "ឃ្លាសម្ងាážáŸ‹áž…ាស់", "Online" : "លើបណ្ážáž¶áž‰", + "Only_you_can_see_this_message" : "មានážáŸ‚អ្នកដែលអាចឃើញសារនáŸáŸ‡", "Oops!" : "អូ!", "Opt_out_statistics" : "កុំផ្ញើស្ážáž·ážáž·áž¢áž“ាមិករបស់អ្នកទៅ Rocket.Chat", "Opt_out_statistics_warning" : "ážáž¶áž˜áž€áž¶ážšáž•áŸ’ញើរស្ážáž·ážáž·áž¢áž“ាមិនរបស់អ្នក, អ្នកនឹងជួយយើងដើម្បីសម្គាល់ចំនួនករណីនៃ Rocket.Chat ដែលážáŸ’រូវបានដាក់ប្រើ ដូចជាករណីចំនួនប្រពáŸáž“្ធ ល្អកំពុងប្រើប្រាស់ ដូចនáŸáŸ‡áž™áž¾áž„អាចពង្រឹងវាបន្ážáŸ‚មទៀážáŸ” ប្រសិនបើអ្នកចង់បន្ážáž€áž¶ážšáž•áŸ’ញើរស្ážáž·ážáž·áž¢áž“ាមិនរបស់អ្នក សូមកុំធិចក្នុងប្រអប់ážáž¶áž„លើ សូមអរគុណ!", "others" : "ផ្សáŸáž„ៗ", "Password" : "ពាក្យ​សម្ងាážáŸ‹", - "Password_changed_successfully" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​ប្ážáž¼ážšâ€‹áž‡áŸ„គជáŸáž™", "Password_Change_Disabled" : "សិទ្ធជាអ្នកគ្រប់គ្រង Rocket.Chat ážáŸ’រូវបានបិទមិនឲ្យប្ážáž¼ážšáž–ាក្យសម្ងាážáŸ‹áž¡áž¾áž™", + "Password_changed_successfully" : "ពាក្យ​សម្ងាážáŸ‹â€‹áž”ាន​ប្ážáž¼ážšâ€‹áž‡áŸ„គជáŸáž™", "People" : "មនុស្ស", + "Please_enter_value_for_url" : "សូមបញ្ចូលážáž˜áŸ’លៃរបស់ URL នៃ Avatar របស់អ្នក", "Please_wait" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់​ចាំ", "Please_wait_activation" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់​ចាំ ការងារ​នáŸáŸ‡â€‹ážáŸ’រូវ​ចំណាយ​ពáŸáž›â€‹áž”ន្ážáž·áž…", "Please_wait_statistics" : "សូម​មáŸážáŸ’ážáž¶ážšáž„់ចាំ ស្ážáž·ážáž·â€‹áž‚ឺ​កំពុង​គណនា", - "Please_enter_value_for_url" : "សូមបញ្ចូលážáž˜áŸ’លៃរបស់ URL នៃ Avatar របស់អ្នក", "Powered_by" : "រក្សាសិទ្ធិ​ដោយ", "Preferences" : "ចំណង់​ចំណូល​ចិážáŸ’áž", "Preferences_saved" : "ចំណង់​ចំណូល​ចិážáŸ’ážâ€‹ážŠáŸ‚ល​បាន​រក្សាទុក", @@ -298,8 +298,8 @@ "Registration_Succeeded" : "ការ​ចុះឈ្មោះ​ជោគជáŸáž™", "Remember_me" : "ចងចាំ​ážáŸ’ញុំ", "Remove" : "ដកចáŸáž‰", - "Remove_custom_oauth" : "លប់ចោល oauth ផ្ទាល់ážáŸ’លួន", "Remove_Admin" : "ដក​សិទ្ធ​អ្នក​គ្រប់គ្រង", + "Remove_custom_oauth" : "លប់ចោល oauth ផ្ទាល់ážáŸ’លួន", "Reset_password" : "កំណážáŸ‹â€‹áž–ាក្យ​សម្ងាážáŸ‹â€‹áž¡áž¾áž„វិញ", "Room" : "បន្ទប់", "Room_name_changed" : "ឈ្មោះ​បន្ទប់​បាន​ប្ážáž¼ážšâ€‹áž‘ៅ​ជា: <em>__room_name__</em> ដោយ <em>__user_by__</em>", @@ -309,6 +309,10 @@ "Room_uploaded_file_list_empty" : "ពុំមានឯកសារដែលអាចប្រើបាន។", "room_user_count" : "%s អ្នក​ប្រើប្រាស់", "Rooms" : "បន្ទប់", + "S_new_messages_since_s" : "%s សារážáŸ’មីចាប់ážáž¶áŸ†áž„ពី %s", + "SAML" : "ប្រើ SAML", + "SAML_Custom_Cert" : "វិញ្ញាបនបážáŸ’រ​ផ្ទាល់ážáŸ’លួន", + "SAML_Custom_Generate_Username" : "គណនាឈ្មោះអ្នកប្រើប្រាស់", "Save" : "រក្សាទុក", "Save_changes" : "រក្សា​ទុក​ការ​ផ្លាស់​ប្ážáž¼â€‹ážš", "Save_Mobile_Bandwidth" : "រក្សាទុកកម្រិážáž”ញ្ជូនážáž¶áž˜áž‘ូរសáŸáž–្ទដៃ", @@ -339,9 +343,6 @@ "Site_Name" : "áž‚áŸáž ទំពáŸážšâ€‹ážˆáŸ’មោះ", "Site_Url" : "ážáŸ†áž”ន់ URL", "Site_Url_Description" : "ឧទាហរណáŸáŸ– https://chat.domain.com/", - "SAML" : "ប្រើ SAML", - "SAML_Custom_Cert" : "វិញ្ញាបនបážáŸ’រ​ផ្ទាល់ážáŸ’លួន", - "SAML_Custom_Generate_Username" : "គណនាឈ្មោះអ្នកប្រើប្រាស់", "SMTP" : "ពិធីការ SMTP", "SMTP_Host" : "ម៉ាស៊ីន SMTP", "SMTP_Password" : "ឃ្លា​សម្ងាážáŸ‹ SMTP", @@ -353,9 +354,9 @@ "Stats_Active_Users" : "អ្នក​ប្រើ​ប្រាស់​សកម្ម", "Stats_Avg_Channel_Users" : "ចំនួន​អ្នក​ប្រើប្រាស់​ជា​មធ្យម​ក្នុង​ប៉ុស្ážáž·áŸ", "Stats_Avg_Private_Group_Users" : "ចំនួន​អ្នក​ប្រើប្រាស់​ជា​មធ្យម​ក្នុងក្រុម​ឯកជន", + "Stats_Away_Users" : "អ្នក​ប្រើ​ដែល​បាន​ចាក​ឆ្ងាយ", "Stats_Max_Room_Users" : "អážáž·áž”រិមា​អ្នក​ប្រើប្រាស់​ក្នុង​បន្ទប់", "Stats_Non_Active_Users" : "អ្នក​ប្រើ​អសកម្ម", - "Stats_Away_Users" : "អ្នក​ប្រើ​ដែល​បាន​ចាក​ឆ្ងាយ", "Stats_Offline_Users" : "អ្នក​ប្រើ​ក្រៅ​ប​ណ្ážáž¶â€‹áž‰", "Stats_Online_Users" : "អ្នក​ប្រើ​លើ​បណ្ដាញ", "Stats_OS_Cpus" : "រាប់ CPU ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", @@ -374,7 +375,6 @@ "Stop_Recording" : "បញ្ឈប់​ការ​កážáŸ‹â€‹ážáŸ’រា", "strike" : "strike", "Submit" : "បញ្ចូល", - "S_new_messages_since_s" : "%s សារážáŸ’មីចាប់ážáž¶áŸ†áž„ពី %s", "The_field_is_required" : "ចន្លោះ %s ážáŸ’រូវ​បំពáŸáž‰", "True" : "áž–áž·áž", "Unnamed" : "គ្មាន​ឈ្មោះ", @@ -390,7 +390,6 @@ "User_added_by" : "អ្នក​ប្រើ <em>__user_added__</em> បាន​ážáŸ‚ម​ដោយ <em>__user_by__</em>.", "User_Channels" : "ប៉ុស្ážáž·áŸáž¢áŸ’នកប្រើប្រាស់", "User_has_been_activated" : "អ្នក​ប្រើ​ដែល​បាន​ធ្វើ​ឱ្យ​សកម្ម", - "Username_Change_Disabled" : "សិទ្ធជាអ្នកគ្រប់គ្រង Rocket.Chat ážáŸ’រូវបានបិទមិនឲ្យប្ážáž¼ážšážˆáŸ’មោះអ្នកប្រើប្រាស់ឡើយ", "User_has_been_deactivated" : "អ្នក​ប្រើ​ដែល​ážáŸ’រូវ​បាន​ធ្វើ​ឱ្យ​អសកម្ម", "User_has_been_deleted" : "អ្នក​ប្រើប្រាស់​ដែល​បាន​លប់", "User_Info" : "áž–áŸážâ€‹áž˜áž¶áž“​របស់​អ្នក​ប្រើ", @@ -408,13 +407,14 @@ "User_removed_by" : "អ្នក​ប្រើ <em>__user_removed__</em> បាន​ដក​ចáŸáž‰â€‹ážŠáŸ„áž™ <em>__user_by__</em>.", "User_Settings" : "ការ​កំណážáŸ‹â€‹ážšáž”ស់​អ្នក​ប្រើ", "User_updated_successfully" : "អ្នក​ប្រើប្រាស់​បាន​កែ​សម្រួល​ដោយ​ជោគជáŸáž™", - "Users" : "អ្នក​ប្រើ​ប្រាស់", "Username" : "ឈ្មោះ​សម្ងាážáŸ‹", "Username_cant_be_empty" : "ឈ្មោះ​សម្ងាážáŸ‹â€‹áž˜áž·áž“អាចទទáŸ", + "Username_Change_Disabled" : "សិទ្ធជាអ្នកគ្រប់គ្រង Rocket.Chat ážáŸ’រូវបានបិទមិនឲ្យប្ážáž¼ážšážˆáŸ’មោះអ្នកប្រើប្រាស់ឡើយ", "Username_description" : "ឈ្មោះ​សម្ងាážáŸ‹â€‹áž”ាន​អនុញ្ញាážáŸ‹â€‹áž²áŸ’យ​អ្នក​ផ្សáŸáž„​ដាក់​ស្លាក​ឈ្មោះ​អ្នក​", "Username_invalid" : "<strong>%s</strong> គឺ​ជា​ឈ្មោះ​សម្ងាážáŸ‹â€‹áž˜áž·áž“​ážáŸ’រឹម​ážáŸ’រូវ,<br/> ព្រោះ​អ្នក​អាច​ប្រើបាន​ážáŸ‚​ážáž½ážšâ€‹áž¢áž€áŸ’សរ, áž›áŸáž, ចុច áž“áž·áž„ ដក", "Username_title" : "ចុះ​ឈ្មោះ​សម្ងាážáŸ‹", "Username_unavaliable" : "<strong>%s</strong> គឺ​បាន​ប្រើហើយ :(", + "Users" : "អ្នក​ប្រើ​ប្រាស់", "View_All" : "មើល​ទាំង​អស់", "Wait_activation_warning" : "មុន​ពáŸáž›â€‹áž…ូល​ប្រើប្រាស់​គណនី​អ្នក​ážáŸ’រូវ​ážáŸ‚​ទទួល​បាន​ការ​អនុញ្ញាážáž·â€‹áž–ី​អ្នក​គ្រប់​គ្រង​ជាមុន​សិន​", "We_have_sent_password_email" : "យើងបាន​ផ្ញើរ​អ៊ីមែល​ជាមួយ​លំណែនាំ​ក្នុង​ការ​ប្ážáž¼ážšâ€‹ážƒáŸ’លា​សម្ងាážáŸ‹áŸ” ប្រសិន​បើ​អ្នក​មិន​បាន​ទទួល​អ៊ី​មែល​ទáŸâ€‹ážŸáž¼áž˜â€‹ážšáž½ážŸâ€‹ážšáž¶áž“់​មក​ទីនáŸáŸ‡â€‹ ដើម្បី​ធ្វើ​វា​ម្ážáž„​ទៀážâ€‹áŸ”", @@ -422,8 +422,8 @@ "Welcome" : "ស្វាគមន០<em>%s</em>.", "Welcome_to_the" : "ស្វាគមនáŸâ€‹áž˜áž€â€‹áž€áž¶áž“់", "With_whom" : "ជា​មួយ​នរណា", - "Yes_delete_it" : "បាទ លប់​វា!", "Yes_clear_all" : "បាទ, សម្អាážáž…ោលទាំងអស់", + "Yes_delete_it" : "បាទ លប់​វា!", "you_are_in_preview_mode_of" : "អ្នក​ស្ážáž·ážâ€‹áž€áŸ’នុង​ទម្រង់​មើល​ជា​មុន​នៃ​ប៉ុស្ážáž·áŸ #<strong>__room_name__</strong>", "You_need_confirm_email" : "អ្នក​ážáŸ’រូវ​បញ្ជាក់អ៊ីមែល​ដើម្បី​ឡុកចូល!", "You_will_not_be_able_to_recover" : "អ្នក​នឹង​មិនអាច​ទាញ​មក​វិញ!", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index b6e958eb76d..c8c1d47859f 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -4,6 +4,17 @@ "Accounts" : "ê³„ì •", "Accounts_denyUnverifiedEmail" : "확ì¸ë˜ì§€ ì•Šì€ ì´ë©”ì¼ ê±°ë¶€", "Accounts_EmailVerification" : "ì´ë©”ì¼ í™•ì¸", + "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize 경로", + "Accounts_OAuth_Custom_Button_Color" : "버튼 색", + "Accounts_OAuth_Custom_Button_Label_Color" : "버튼 í…스트 색", + "Accounts_OAuth_Custom_Button_Label_Text" : "버튼 í…스트", + "Accounts_OAuth_Custom_Enable" : "사용 가능", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identity 경로", + "Accounts_OAuth_Custom_Secret" : "비밀", + "Accounts_OAuth_Custom_Token_Path" : "Token 경로", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook 로그ì¸", "Accounts_OAuth_Facebook_id" : "Facebook 앱 ID", "Accounts_OAuth_Facebook_secret" : "Facebook 암호", @@ -19,21 +30,10 @@ "Accounts_OAuth_Meteor" : "Meteor 로그ì¸", "Accounts_OAuth_Meteor_id" : "Meteor ID", "Accounts_OAuth_Meteor_secret" : "Meteor 암호", - "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", - "Accounts_RegistrationRequired" : "등ë¡ì‹œ 필수", "Accounts_OAuth_Twitter" : "트위터 로그ì¸", "Accounts_OAuth_Twitter_id" : "트위터 ID", "Accounts_OAuth_Twitter_secret" : "트위터 암호", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "Token 경로", - "Accounts_OAuth_Custom_Identity_Path" : "Identity 경로", - "Accounts_OAuth_Custom_Authorize_Path" : "Authorize 경로", - "Accounts_OAuth_Custom_Secret" : "비밀", - "Accounts_OAuth_Custom_Enable" : "사용 가능", - "Accounts_OAuth_Custom_Button_Label_Text" : "버튼 í…스트", - "Accounts_OAuth_Custom_Button_Label_Color" : "버튼 í…스트 색", - "Accounts_OAuth_Custom_Button_Color" : "버튼 색", + "Accounts_RegistrationRequired" : "등ë¡ì‹œ 필수", "Activate" : "활성화", "Add_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth 추가", "Add_Members" : "멤버 추가", @@ -47,6 +47,7 @@ "are_also_typing" : "ë˜í•œ ìž…ë ¥ì¤‘", "are_typing" : "ìž…ë ¥ 중", "Are_you_sure" : "괜찮아요?", + "Auto_Load_Images" : "ì´ë¯¸ì§€ ìžë™ 로드", "Avatar_changed_successfully" : "아바타를 성공ì 으로 변경하였습니다", "away" : "ìžë¦¬ë¹„움", "Away" : "ìžë¦¬ë¹„움", @@ -54,7 +55,6 @@ "Away_female" : "ìžë¦¬ë¹„움", "away_male" : "ìžë¦¬ë¹„움", "Away_male" : "ìžë¦¬ë¹„움", - "Auto_Load_Images" : "ì´ë¯¸ì§€ ìžë™ 로드", "Back_to_login" : "로그ì¸ìœ¼ë¡œ ëŒì•„가기", "bold" : "굵게", "busy" : "ë°”ì¨", @@ -72,7 +72,6 @@ "coming_soon" : "곧", "Confirm_password" : "암호를 확ì¸í•˜ì„¸ìš”", "Contact" : "ì ‘ì†", - "Delete" : "ì‚ì œ", "Conversation" : "대화", "Convert_Ascii_Emojis" : "ASCII를 Emojisë¡œ 변환", "Create_new" : "새로 만들기", @@ -83,8 +82,8 @@ "Custom_oauth_unique_name" : "ì‚¬ìš©ìž ì •ì˜ OAuth ê³ ìœ í•œ ì´ë¦„", "days" : "ì¼", "Deactivate" : "비활성화", + "Delete" : "ì‚ì œ", "Delete_User_Warning" : "ì‚¬ìš©ìž ì‚ì œì‹œ 사용ìžì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì·¨ì†Œí• ìˆ˜ 없습니다.", - "Edit" : "ìˆ˜ì •", "Deleted" : "ì‚ì œ!", "Direct_Messages" : "ê·“ì†ë§", "Disable_Favorite_Rooms" : "ì¦ê²¨ì°¾ê¸° 사용안함", @@ -94,6 +93,7 @@ "Duplicate_channel_name" : "'%s' ì±„ë„ ì´ë¦„ì€ ì´ë¯¸ 존재합니다.", "Duplicate_private_group_name" : "'%s'는 ì´ë¯¸ 존재하는 ê°œì¸ ê·¸ë£¹ìž…ë‹ˆë‹¤.", "E-mail" : "ì´ë©”ì¼", + "Edit" : "ìˆ˜ì •", "edited" : "ìˆ˜ì •ë¨", "Email_already_exists" : "ì´ë©”ì¼ì´ ì´ë¯¸ 존재합니다", "Email_or_username" : "ì´ë©”ì¼ ë˜ëŠ” ì‚¬ìš©ìž ì´ë¦„", @@ -107,16 +107,14 @@ "Favorites" : "ì¦ê²¨ì°¾ê¸°", "Follow_social_profiles" : "소셜 프로파ì¼ì— ë”°ë¼ì£¼ì‹ì‹œì˜¤. Githubì—ì„œ í¬í¬í•˜ê³ , ìš°ë¦¬ì˜ trello ë³´ë“œì—ì„œ rocket.chat appì—대한 ì˜ê²¬ì„ ê³µìœ í•©ë‹ˆë‹¤.", "Forgot_password" : "암호를 잊었습니다", - "LDAP_Port" : "LDAP í¬íŠ¸", "Fork_it_on_github" : "Githubì—ì„œ í¬í¬", - "LDAP_Url" : "LDAP URL", "From_Email" : "ì´ë©”ì¼ë¡œë¶€í„°", "General" : "ì¼ë°˜", "Get_to_know_the_team" : "Rocket.Team 알아보기", "github_no_public_email" : "Github ê³„ì •ì— ê³µê°œëœ ì´ë©”ì¼ì´ 없습니다.", "Give_a_unique_name_for_the_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuthì— ëŒ€í•œ ê³ ìœ ì´ë¦„ ì§€ì •", - "Have_your_own_chat" : "ë‹¹ì‹ ë§Œì˜ ì›¹ ì±„íŒ…ì„ ë§Œë“œì„¸ìš”. Meteor.com으로 개발한 Rocket.Chatì€ ìžì‹ ë§Œì˜ ì±„íŒ… 플랫í¼ì„ ë§Œë“¤ê³ ê°œì„ í•´ 나아갈 개발ìžë“¤ì„ 위한 훌ë¥í•œ 솔루션입니다.", "Has_more" : "ë” ë§Žì´", + "Have_your_own_chat" : "ë‹¹ì‹ ë§Œì˜ ì›¹ ì±„íŒ…ì„ ë§Œë“œì„¸ìš”. Meteor.com으로 개발한 Rocket.Chatì€ ìžì‹ ë§Œì˜ ì±„íŒ… 플랫í¼ì„ ë§Œë“¤ê³ ê°œì„ í•´ 나아갈 개발ìžë“¤ì„ 위한 훌ë¥í•œ 솔루션입니다.", "Hide_room" : "ë°© 숨김", "History" : "ì´ë ¥", "hours" : "시간", @@ -156,11 +154,13 @@ "Layout_Terms_of_Service" : "ì´ìš©ì•½ê´€", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", + "LDAP_Port" : "LDAP í¬íŠ¸", + "LDAP_Url" : "LDAP URL", "Leave_room" : "ë°© 나가기", "line" : "밑줄", "Load_more" : "ë” ë³´ê¸°", - "Loading_more_from_history" : "ì´ì „ ë‚´ìš©ì—ì„œ ê°€ì ¸ì˜¤ê¸°", "Loading..." : "로딩 중 ...", + "Loading_more_from_history" : "ì´ì „ ë‚´ìš©ì—ì„œ ê°€ì ¸ì˜¤ê¸°", "Loading_suggestion" : "ì œì•ˆ 로딩중...", "Login" : "로그ì¸", "Login_with" : "%s으로 로그ì¸", @@ -175,15 +175,15 @@ "Message_AllowDeleting" : "메시지 ì‚ì œ 허용", "Message_AllowEditing" : "메시지 ìˆ˜ì • 허용", "Message_AllowEditing_BlockEditInMinutes" : "ì´í›„ë¡œ 메시지 ìˆ˜ì • ì•ˆë¨ (분 - 0 ì€ ì‚¬ìš©ì•ˆí•¨)", + "Message_AllowPinning" : "허용 메시지 ê³ ì •", "Message_deleting_not_allowed" : "메시지 ì‚ì œë¥¼ í• ìˆ˜ 없습니다.", - "Message_editing_not_allowed" : "메시지 ìˆ˜ì •ì„ í• ìˆ˜ 없습니다.", "Message_editing_blocked" : "메시지를 ë” ì´ìƒ ìˆ˜ì •í• ìˆ˜ 없습니다.", + "Message_editing_not_allowed" : "메시지 ìˆ˜ì •ì„ í• ìˆ˜ 없습니다.", + "Message_KeepHistory" : "메시지 기ë¡ì„ ìœ ì§€", "Message_MaxAllowedSize" : "메시지 최대 허용 í¬ê¸°", + "Message_pinned" : "메시지가 ê³ ì •ë˜ì—ˆìŠµë‹ˆë‹¤.", "Message_pinning_not_allowed" : "메시지를 ê³ ì •í• ìˆ˜ 없습니다.", - "Message_AllowPinning" : "허용 메시지 ê³ ì •", - "Message_KeepHistory" : "메시지 기ë¡ì„ ìœ ì§€", "Message_removed" : "메시지 ì œê±°", - "Message_pinned" : "메시지가 ê³ ì •ë˜ì—ˆìŠµë‹ˆë‹¤.", "Message_ShowDeletedStatus" : "ì‚ì œëœ ìƒíƒœ 확ì¸", "Message_ShowEditedStatus" : "ìˆ˜ì • ìƒíƒœ 확ì¸", "Meta" : "메타", @@ -204,22 +204,22 @@ "Name_cant_be_empty" : "ì´ë¦„ì„ ë¹„ì›Œ 둘 수 없습니다", "New_messages" : "새로운 메시지", "New_password" : "새로운 암호", + "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_groups_yet" : "ê°œì¸ ê·¸ë£¹ì„ ë§Œë“¤ì§€ 않았습니다.", "No_permission_to_view_room" : "ì´ ë°©ì„ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤", - "No_channel_with_name_%s_was_found" : "<strong>\"%s\"</strong> ì±„ë„ ì´ë¦„ì„ ì°¾ì„ ìˆ˜ 없습니다!", - "No_group_with_name_%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_Password" : "기존 암호", "Old_and_new_password_required" : "암호를 변경하기 위해서는 기존 암호와 새로 ì‚¬ìš©í• ì•”í˜¸ë¥¼ ìž…ë ¥í•´ì•¼í•©ë‹ˆë‹¤.", - "Only_you_can_see_this_message" : "ì´ ë©”ì‹œì§€ëŠ” ë‹¹ì‹ ë§Œ ë³¼ 수 있습니다", + "Old_Password" : "기존 암호", "Online" : "온ë¼ì¸", + "Only_you_can_see_this_message" : "ì´ ë©”ì‹œì§€ëŠ” ë‹¹ì‹ ë§Œ ë³¼ 수 있습니다", "Oops!" : "ì•„ì°¨", "Opt_out_statistics" : "ë‚˜ì˜ ì–´ë–¤ 무기명 í†µê³„ë„ Rocket.chat으로 보내지 마ì‹ì‹œì˜¤.", "Opt_out_statistics_warning" : "ë‹¹ì‹ ì˜ ë¬´ê¸°ëª… 통계 ìžë£Œë¥¼ ì „ì†¡í•˜ëŠ” 것으로 우리는 ëª‡ê°œì˜ Rocket.Chat 서비스를 설치하였는지 ì•Œ 수 있으며 얼마나 ì‹œìŠ¤í…œì´ ìž˜ ìž‘ë™í•˜ëŠ”지 ì•Œ ìˆ˜ë¡ ì„œë¹„ìŠ¤ë¥¼ ê°œì„ í•˜ëŠ”ë° ë„ì›€ì´ ë©ë‹ˆë‹¤. ë§Œì¼ ë¬´ê¸°ëª… 통계 ì •ë³´ë¥¼ ì „ì†¡í•˜ê¸¸ ì›í•˜ì‹œë©´ ìœ„ì˜ ì²´í¬ë°•ìŠ¤ë¥¼ ì„¤ì •ì„ í•´ì œí•´ì£¼ì‹ì‹œì˜¤. ê³ ë§™ìŠµë‹ˆë‹¤.", @@ -256,8 +256,8 @@ "Registration_Succeeded" : "ë“±ë¡ ì„±ê³µ", "Remember_me" : "ìžë™ 로그ì¸", "Remove" : "ì‚ì œ", - "Remove_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth ì œê±°", "Remove_Admin" : "ê´€ë¦¬ìž ê¶Œí•œ ì œê±°", + "Remove_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth ì œê±°", "Reset_password" : "암호 ìž¬ì„¤ì •", "Room" : "ë°©", "Room_name_changed" : "ë°© ì´ë¦„ 변경: <em>__user_by__</em>ì—ì„œ <em>__room_name__</em>ë¡œ.", @@ -265,6 +265,7 @@ "Room_not_found" : "ë°©ì„ ì°¾ì„ ìˆ˜ 없습니다.", "room_user_count" : "%s 사용ìž", "Rooms" : "ë°©", + "SAML" : "SAML", "Save" : "ì €ìž¥", "Save_changes" : "ë³€ê²½ì‚¬í• ì €ìž¥", "Save_Mobile_Bandwidth" : "ëª¨ë°”ì¼ ëŒ€ì—í ì €ìž¥", @@ -293,7 +294,6 @@ "Silence" : "무언", "since_creation" : "%s ì´í›„", "Site_Name" : "사ì´íŠ¸ ì´ë¦„:", - "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "SMTP 호스트", "SMTP_Password" : "SMTP 암호", @@ -305,9 +305,9 @@ "Stats_Active_Users" : "활성 사용ìž", "Stats_Avg_Channel_Users" : "ì±„ë„ ì‚¬ìš©ìž í‰ê· ", "Stats_Avg_Private_Group_Users" : "비밀 그룹 ì‚¬ìš©ìž í‰ê· ", + "Stats_Away_Users" : "ìžë¦¬ë¹„움 사용ìž", "Stats_Max_Room_Users" : "최대 ë°© 사용ìž", "Stats_Non_Active_Users" : "비활성 사용ìž", - "Stats_Away_Users" : "ìžë¦¬ë¹„움 사용ìž", "Stats_Offline_Users" : "현실 세계ì¸", "Stats_Online_Users" : "ê°€ìƒ ì„¸ê³„ì¸", "Stats_OS_Arch" : "OS Arch", @@ -358,13 +358,13 @@ "User_removed_by" : "ì‚¬ìš©ìž <em>__user_removed__</em>ì„/를 <em>__user_by__</em>ì—ì„œ ì‚ì œë¨.", "User_Settings" : "ì‚¬ìš©ìž ì„¤ì •", "User_updated_successfully" : "사용ìžë¥¼ 성공ì 으로 ì—…ë°ì´íŠ¸í•˜ì˜€ìŠµë‹ˆë‹¤.", - "Users" : "사용ìž", "Username" : "ì‚¬ìš©ìž ì´ë¦„", "Username_cant_be_empty" : "ì‚¬ìš©ìž ì´ë¦„ì„ ë¹„ì›Œë‘˜ 수 없습니다", "Username_description" : "ì‚¬ìš©ìž ì´ë¦„ì€ ë‹¤ë¥¸ ì‚¬ëžŒì´ ë©”ì‹œì§€ì—ì„œ ì–¸ê¸‰í• ìˆ˜ 있ë„ë¡ í•˜ëŠ”ë° ì‚¬ìš©ë©ë‹ˆë‹¤.", "Username_invalid" : "<strong>&s</strong>는 ì•Œë§žì€ ì‚¬ìš©ìžëª…ì´ ì•„ë‹™ë‹ˆë‹¤,<br/> 문ìž, 숫ìž, 마침표와 ë°‘ì¤„ì„ ì‚¬ìš©í•˜ì‹ì‹œì˜¤.", "Username_title" : "ì‚¬ìš©ìž ì´ë¦„ 등ë¡", "Username_unavaliable" : "<strong>%s</strong> 는 사용중입니다. :(", + "Users" : "사용ìž", "View_All" : "ëª¨ë‘ ë³´ê¸°", "Wait_activation_warning" : "로그ì¸í•˜ê¸° ì „ì— ê´€ë¦¬ìžê°€ ê³„ì •ì„ ìˆ˜ë™ìœ¼ë¡œ 활성화시켜야합니다.", "We_have_sent_password_email" : "암호 ìž¬ì„¤ì • ìš”ì² ì´ë©”ì¼ì„ 보냈습니다. ì´ë©”ì¼ì„ 받지 못한 경우, 다시 ì‹œë„하세요.", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 60e9bcff984..bc4dbc06a3d 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -4,6 +4,17 @@ "Accounts" : "Akaun", "Accounts_denyUnverifiedEmail" : "Menafikan e-mel yang tidak sah", "Accounts_EmailVerification" : "Pengesahan E-mel", + "Accounts_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", + "Accounts_OAuth_Custom_Button_Color" : "Butang Warna", + "Accounts_OAuth_Custom_Button_Label_Color" : "Butang Teks Berwarna", + "Accounts_OAuth_Custom_Button_Label_Text" : "Butang Teks", + "Accounts_OAuth_Custom_Enable" : "Aktifkan", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Daftar masuk Facebook", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -19,21 +30,10 @@ "Accounts_OAuth_Meteor" : "Daftar masuk Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_ManuallyApproveNewUsers" : "Secara manual meluluskan pengguna baru", - "Accounts_RegistrationRequired" : "Pendaftaran diperlukan", "Accounts_OAuth_Twitter" : "Daftar masuk Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "Token Path", - "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", - "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", - "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Enable" : "Aktifkan", - "Accounts_OAuth_Custom_Button_Label_Text" : "Butang Teks", - "Accounts_OAuth_Custom_Button_Label_Color" : "Butang Teks Berwarna", - "Accounts_OAuth_Custom_Button_Color" : "Butang Warna", + "Accounts_RegistrationRequired" : "Pendaftaran diperlukan", "Activate" : "Aktifkan", "Add_Members" : "Tambah Ahli", "Add_users" : "Tambah pengguna", @@ -44,6 +44,7 @@ "API_Analytics" : "Analisis", "API_Embed" : "Benam", "Are_you_sure" : "Adakah anda pasti?", + "Auto_Load_Images" : "Automatik Memuat Gambar", "Avatar_changed_successfully" : "Avatar berjaya ditukar", "away" : "keluar", "Away" : "Keluar", @@ -51,7 +52,6 @@ "Away_female" : "Keluar", "away_male" : "keluar", "Away_male" : "Keluar", - "Auto_Load_Images" : "Automatik Memuat Gambar", "Back_to_login" : "Kembali ke log masuk", "busy" : "sibuk", "Busy" : "Sibuk", @@ -70,7 +70,6 @@ "Compact_View" : "Paparan Kompak", "Confirm_password" : "Sahkan kata laluan anda", "Contact" : "Hubungi", - "Delete" : "Padam", "Conversation" : "Perbualan", "Convert_Ascii_Emojis" : "Menukar ASCII ke Emoji", "Create_new" : "Buat baru", @@ -80,8 +79,8 @@ "Created_at" : "Dibuat pada", "days" : "hari", "Deactivate" : "Nyahaktifkan", + "Delete" : "Padam", "Delete_User_Warning" : "Memadam pengguna akan memadam semua mesej dari pengguna itu juga. Ini tidak boleh kembalikan asal.", - "Edit" : "Sunting", "Deleted" : "Dipadamkan!", "Desktop_Notifications" : "Notifikasi Desktop", "Desktop_Notifications_Disabled" : "Notifikasi Desktop dinyahaktifkan. Tukar tetapan pelayar web jika anda mahukan notifikasi diaktifkan.", @@ -94,6 +93,7 @@ "Duplicate_channel_name" : "Saluran dengan nama '%s' telah wujud", "Duplicate_private_group_name" : "Kumpulan Persendirian dengan nama '%s' telah wujud", "E-mail" : "E-mel", + "Edit" : "Sunting", "edited" : "disunting", "Email_already_exists" : "E-mel telah wujud", "Email_or_username" : "E-mel atau nama pengguna", @@ -110,9 +110,7 @@ "FileUpload_Enabled" : "Naik Fail Diaktifkan", "FileUpload_MaxFileSize" : "Fail muat naik saiz Maksimum (dalam bytes)", "Forgot_password" : "Lupa kata laluan anda", - "LDAP_Port" : "Port LDAP", "Fork_it_on_github" : "Mencabang pada github", - "LDAP_Url" : "URL LDAP", "From_Email" : "Daripada E-mel", "General" : "Umum", "Get_to_know_the_team" : "Kenali Rocket.Team", @@ -155,11 +153,13 @@ "Layout_Terms_of_Service" : "Terma Perkhidmatan", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "URL LDAP", "Leave_room" : "Meninggalkan bilik", "line" : "garis", "Load_more" : "Memuat lagi", - "Loading_more_from_history" : "Memuatkan lagi dari sejarah", "Loading..." : "Memuatkan...", + "Loading_more_from_history" : "Memuatkan lagi dari sejarah", "Loading_suggestion" : "Memuatkan cadangan...", "Login" : "Log masuk", "Login_with" : "Log masuk dengan %s", @@ -176,12 +176,12 @@ "Message_AllowEditing_BlockEditInMinutes" : "Sekat penyuntingan mesej selepas (dalam minit - 0 hingga melumpuhkan)", "Message_AudioRecorderEnabled" : "Perakam Audio Diaktifkan", "Message_deleting_not_allowed" : "Pemadaman mesej tidak dibenarkan", - "Message_editing_not_allowed" : "Penyuntingan mesej tidak dibenarkan", "Message_editing_blocked" : "Mesej ini tidak boleh lagi disunting", - "Message_MaxAllowedSize" : "Saiz mesej maksimum yang dibenarkan", + "Message_editing_not_allowed" : "Penyuntingan mesej tidak dibenarkan", "Message_KeepHistory" : "Simpan Sejarah Mesej", - "Message_removed" : "Mesej dipadam", + "Message_MaxAllowedSize" : "Saiz mesej maksimum yang dibenarkan", "Message_pinned" : "Mesej dipinkan", + "Message_removed" : "Mesej dipadam", "Message_ShowDeletedStatus" : "Tunjuk Status Pemadaman", "Message_ShowEditedStatus" : "Tunjuk Status Penyuntingan", "Message_ShowFormattingTips" : "Tunjuk Tip Pemformatan", @@ -203,22 +203,22 @@ "Name_cant_be_empty" : "Nama tidak boleh dibiarkan kosong", "New_messages" : "Mesej baru", "New_password" : "Kata Laluan baru", + "No_channel_with_name_%s_was_found" : "Tiada saluran dengan nama <strong>\"%s\"</strong> dijumpai!", "No_channels_yet" : "Anda bukan daripada mana-mana saluran lagi.", "No_direct_messages_yet" : "Anda tidak memulakan sebarang perbualan lagi.", "No_favorites_yet" : "Anda belum menambah sebarang kegemaran lagi.", + "No_group_with_name_%s_was_found" : "Tiada kumpulan persendirian dengan nama <strong>\"%s\"</strong> dijumpai!", "No_groups_yet" : "Anda tidak mempunyai kumpulan persendirian lagi.", "No_permission_to_view_room" : "Anda tidak mempunyai kebenaran untuk melihat bilik ini", - "No_channel_with_name_%s_was_found" : "Tiada saluran dengan nama <strong>\"%s\"</strong> dijumpai!", - "No_group_with_name_%s_was_found" : "Tiada kumpulan persendirian dengan nama <strong>\"%s\"</strong> dijumpai!", "No_user_with_username_%s_was_found" : "Tiada pengguna dengan nama pengguna <strong>\"%s\"</strong> dijumpai!", "Not_allowed" : "Tidak dibenarkan", "Not_found_or_not_allowed" : "Tidak Ditemui atau Tidak Dibenarkan", "Nothing_found" : "Tiada apa Dijumpai", "Notify_all_in_this_room" : "Memberitahu semua di dalam bilik ini", - "Old_Password" : "Kata Laluan lama", "Old_and_new_password_required" : "Anda perlu memberikan kedua-dua kata laluan lama dan baru untuk menukar kata laluan anda.", - "Only_you_can_see_this_message" : "Hanya anda yang boleh melihat mesej ini", + "Old_Password" : "Kata Laluan lama", "Online" : "Dalam talian", + "Only_you_can_see_this_message" : "Hanya anda yang boleh melihat mesej ini", "Oops!" : "Oops", "Opt_out_statistics" : "Jangan hantar statistik saya ke Rocket.Chat", "Opt_out_statistics_warning" : "Dengan menghantar statistik anda, ada akan membantu kami mengenalpasti berapa banyak", @@ -264,6 +264,8 @@ "Room_uploaded_file_list_empty" : "Tiada fail yang ada.", "room_user_count" : "Pengguna %s", "Rooms" : "Bilik", + "S_new_messages_since_s" : "%s mesej baru sejak %s", + "SAML" : "SAML", "Save" : "Simpan", "Save_changes" : "Simpan perubahan", "Save_Mobile_Bandwidth" : "Simpan Jalur lebar mudah alih", @@ -292,7 +294,6 @@ "Silence" : "Senyap", "since_creation" : "sejak %s", "Site_Name" : "Nama Laman:", - "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "Hos SMTP", "SMTP_Password" : "Kata Laluan SMTP", @@ -304,9 +305,9 @@ "Stats_Active_Users" : "Pengguna Aktif", "Stats_Avg_Channel_Users" : "Purata Pengguna Saluran", "Stats_Avg_Private_Group_Users" : "Purata Pengguna Kumpulan Persendirian", + "Stats_Away_Users" : "Pengguna Keluar", "Stats_Max_Room_Users" : "Maksimum Pengguna Bilik", "Stats_Non_Active_Users" : "Pengguna Tidak Aktif", - "Stats_Away_Users" : "Pengguna Keluar", "Stats_Offline_Users" : "Pengguna Luar talian", "Stats_Online_Users" : "Pengguna Dalam talian", "Stats_OS_Arch" : "OS Arch", @@ -326,7 +327,6 @@ "Stats_Total_Users" : "Jumlah Pengguna", "Stop_Recording" : "Berhenti Merakam", "Submit" : "Hantar", - "S_new_messages_since_s" : "%s mesej baru sejak %s", "The_field_is_required" : "Medan ini %s diperlukan", "True" : "Dayakan", "Unnamed" : "Tidak dinamakan", @@ -359,13 +359,13 @@ "User_removed_by" : "Pengguna <em>__user_removed__</em> dibuang oleh <em>__user_by__</em>.", "User_Settings" : "Tetapan Pengguna", "User_updated_successfully" : "Pengguna berjaya dikemaskini", - "Users" : "Pengguna", "Username" : "Nama Pengguna", "Username_cant_be_empty" : "Nama Pengguna tidak boleh dibiarkan kosong", "Username_description" : "Nama Pengguna adalah digunakan untuk membolehkan pengguna lain menyebut anda di mesej.", "Username_invalid" : "<strong>%s</strong> bukan nama pengguna yang sah,<br/> guna hanya huruf, nombor, titik dan pemisah", "Username_title" : "Daftar nama pengguna", "Username_unavaliable" : "<strong>%s</strong> sudah digunakan :(", + "Users" : "Pengguna", "View_All" : "Lihat Semua", "Wait_activation_warning" : "Sebelum anda boleh log masuk, akaun anda mesti diaktifkan secara manual oleh pentadbiran.", "We_have_sent_registration_email" : "Kami telah menghantar kepada anda e-mel untuk mengesahkan pendaftaran anda. Jika anda tidak menerima e-mel berikut dalam masa terdekat. sila datang kembali dan cuba lagi.", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 5c673f37c93..70dfdf999fc 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -51,7 +51,6 @@ "coming_soon" : "wkrótce", "Confirm_password" : "Potwierdź hasÅ‚o", "Contact" : "Kontakt", - "Delete" : "UsuÅ„", "Conversation" : "Rozmowa", "Create_new" : "Utwórz nowe", "Create_new_direct_message_room" : "Utwórz nowy kanaÅ‚ prywatny", @@ -59,12 +58,13 @@ "Create_new_public_channel" : "Utwórz kanaÅ‚ publiczny", "Created_at" : "Utworzono", "Deactivate" : "Dezaktywować", - "Edit" : "Edycja", + "Delete" : "UsuÅ„", "Deleted" : "UsuniÄ™te!", "Direct_Messages" : "BezpoÅ›rednie wiadomoÅ›ci", "Drop_to_upload_file" : "PrzeciÄ…gnij, aby przesÅ‚ać plik", "Duplicate_channel_name" : "KanaÅ‚ o nazwie \"% s\" istnieje", "Duplicate_private_group_name" : "Grupa Prywatna o nazwie '% s' istnieje", + "Edit" : "Edycja", "edited" : "zmieniono", "Email_already_exists" : "Email już istnieje", "Email_or_username" : "Email lub nazwa użytkownika", @@ -75,9 +75,7 @@ "Favorites" : "Ulubione", "Follow_social_profiles" : "Åšledź nasze profile spoÅ‚eczne, widelec do nas na github i podziel siÄ™ swoimi przemyÅ›leniami na temat rocket.chat aplikacji na naszej trello pokÅ‚adzie.", "Forgot_password" : "ZapomniaÅ‚eÅ› hasÅ‚a", - "LDAP_Port" : "Port LDAP", "Fork_it_on_github" : "Fork it on GitHub", - "LDAP_Url" : "Adres URL LDAP", "Get_to_know_the_team" : "Poznaj Rocket.Team", "github_no_public_email" : "Nie posiadasz publicznego konta e-mail przypisanego do swojego profilu GitHub.", "Have_your_own_chat" : "Załóż swój wÅ‚asny czat. DziÄ™ki Meteor.com, Rocket.Chat jest idealnym rozwiÄ…zaniem dla wszystkich chcÄ…cych budować i rozwijać swojÄ… wÅ‚asnÄ… platformÄ™ do rozmów.", @@ -109,6 +107,8 @@ "Layout_Home_Body" : "Treść strony głównej", "Layout_Home_Title" : "TytuÅ‚ strony głównej", "LDAP_DN" : "LDAP DN", + "LDAP_Port" : "Port LDAP", + "LDAP_Url" : "Adres URL LDAP", "Leave_room" : "Opuść pokój", "line" : "linia", "Load_more" : "WiÄ™cej", @@ -150,8 +150,8 @@ "Not_found_or_not_allowed" : "Nie znaleziono lub nie dozwolone", "Nothing_found" : "Nic nie znaleziono", "Notify_all_in_this_room" : "Powiadom wszystkich w pokoju", - "Only_you_can_see_this_message" : "Tylko Ty widzisz tÄ™ wiadomość", "Online" : "Online", + "Only_you_can_see_this_message" : "Tylko Ty widzisz tÄ™ wiadomość", "Oops!" : "Ups", "others" : "inni", "Password" : "HasÅ‚o", @@ -184,6 +184,7 @@ "Room_name_changed_successfully" : "Nazwa pokoju zmieniona", "room_user_count" : "%s użytkowników", "Rooms" : "Pokoje", + "SAML" : "SAML", "Save" : "Zapisz", "Save_changes" : "Zapisz zmiany", "Search" : "Szukaj", @@ -204,7 +205,6 @@ "Showing_results" : "<p>WyÅ›wietlono <b>% s</b>wyników</p>", "Silence" : "Cisza", "since_creation" : "od %s", - "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "HasÅ‚o SMTP", @@ -236,13 +236,13 @@ "User_logged_out" : "Użytkownik jest wylogowany", "User_removed_by" : "Użytkownik <em>__user_removed__</em>usuniÄ™ty przez <em>__user_by__</em>.", "User_Settings" : "Ustawienia użytkownika", - "Users" : "Użytkownicy", "Username" : "Nazwa użytkownika", "Username_cant_be_empty" : "Nazwa użytkownika nie może być pusta", "Username_description" : "Nazwa użytkownika jest używana, by inni mogli CiÄ™ wspomnieć w wiadomoÅ›ci.", "Username_invalid" : "<strong>% s</strong>nie jest prawidÅ‚owÄ… nazwÄ… użytkownika, <br / >użyj jedynie liter, cyfr, kropek i kresek", "Username_title" : "Zarejestruj użytkownika", "Username_unavaliable" : "<strong>% s</strong> jest zajÄ™te :(", + "Users" : "Użytkownicy", "View_All" : "Zobacz wszystkie", "We_have_sent_password_email" : "WysÅ‚aliÅ›my Ci e-mail z instrukcjami resetowania hasÅ‚a. JeÅ›li nie dostaniesz wiadomoÅ›ci, spróbuj proszÄ™ ponownie.", "We_have_sent_registration_email" : "WysÅ‚aliÅ›my e-mail w celu potwierdzenie Twojej rejestracji. JeÅ›li nie dostaniesz wiadomoÅ›ci, spróbuj proszÄ™ ponownie.", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 433c30b4678..3d8e5e26c51 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -8,6 +8,17 @@ "Accounts_AvatarSize" : "Tamanho do Avatar", "Accounts_denyUnverifiedEmail" : "Proibir e-mail não verificado", "Accounts_EmailVerification" : "Verificação de E-mail", + "Accounts_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", + "Accounts_OAuth_Custom_Button_Color" : "Cor do botão", + "Accounts_OAuth_Custom_Button_Label_Color" : "Cor do texto do botão", + "Accounts_OAuth_Custom_Button_Label_Text" : "Texto do botão", + "Accounts_OAuth_Custom_Enable" : "Enable", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Login do Facebook", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -24,21 +35,10 @@ "Accounts_OAuth_Meteor" : "Login do Meteor", "Accounts_OAuth_Meteor_id" : "Meteor Id", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", - "Accounts_RegistrationRequired" : "Registro Obrigatório", "Accounts_OAuth_Twitter" : "Login do Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Custom_id" : "Id", - "Accounts_OAuth_Custom_URL" : "URL", - "Accounts_OAuth_Custom_Token_Path" : "Token Path", - "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", - "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", - "Accounts_OAuth_Custom_Secret" : "Secret", - "Accounts_OAuth_Custom_Enable" : "Enable", - "Accounts_OAuth_Custom_Button_Label_Text" : "Texto do botão", - "Accounts_OAuth_Custom_Button_Label_Color" : "Cor do texto do botão", - "Accounts_OAuth_Custom_Button_Color" : "Cor do botão", + "Accounts_RegistrationRequired" : "Registro Obrigatório", "Accounts_RequireNameForSignUp" : "Nome é obrigatório para cadastro", "Activate" : "Ativar", "Add_custom_oauth" : "Adicionar oauth customizado", @@ -56,6 +56,7 @@ "are_also_typing" : "também estão digitando", "are_typing" : "estão digitando", "Are_you_sure" : "Você tem certeza?", + "Auto_Load_Images" : "Auto Carregar Imagens", "Avatar_changed_successfully" : "Avatar alterado com sucesso", "away" : "ausente", "Away" : "Ausente", @@ -63,7 +64,6 @@ "Away_female" : "Ausente", "away_male" : "ausente", "Away_male" : "ausente", - "Auto_Load_Images" : "Auto Carregar Imagens", "Back_to_login" : "Voltar para o login", "bold" : "negrito", "busy" : "ocupado", @@ -83,7 +83,6 @@ "Compact_View" : "Visão Compacta", "Confirm_password" : "Confirmar a senha", "Contact" : "Contato", - "Delete" : "Deletar", "Conversation" : "Conversa", "Convert_Ascii_Emojis" : "Converter ASCII para Emoji", "Create_new" : "Criar um novo", @@ -91,12 +90,12 @@ "Create_new_private_group" : "Criar um novo grupo privado", "Create_new_public_channel" : "Criar um canal público", "Created_at" : "Data criação", - "Custom_oauth_unique_name" : "Nome exclusivo para oauth customizado", "Custom_oauth_helper" : "Ao configurar o seu Provedor de OAuth, você terá que informar uma URL de retorno de chamada. Use <pre>%s</pre>.", + "Custom_oauth_unique_name" : "Nome exclusivo para oauth customizado", "days" : "dias", "Deactivate" : "Desativar", + "Delete" : "Deletar", "Delete_User_Warning" : "Excluir um usuário irá apagar todas as mensagens desse usuário também. Isso não poderá ser desfeito.", - "Edit" : "Editar", "Deleted" : "Deletado!", "Desktop_Notifications" : "Notificações Desktop", "Desktop_Notifications_Disabled" : "Notificações Desktop estão Desativadas. Mude as preferências do seu navegador se quiser habilitar as notificações.", @@ -109,6 +108,7 @@ "Duplicate_channel_name" : "Já existe um Canal com nome '%s'", "Duplicate_private_group_name" : "Já existe um Grupo Privado com nome '%s'", "E-mail" : "E-mail", + "Edit" : "Editar", "edited" : "editado", "Email_already_exists" : "Email já cadastrado", "Email_or_username" : "Email ou nome de usuário", @@ -128,16 +128,14 @@ "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia (separados por vÃrgula)", "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", - "LDAP_Port" : "Porta LDAP", "Fork_it_on_github" : "Fork it on github", - "LDAP_Url" : "URL LDAP", "From_Email" : "Email De", "General" : "Geral", "Get_to_know_the_team" : "Conheça o Rocket.Team", "github_no_public_email" : "Você não possui um e-mail público em sua conta do GitHub", "Give_a_unique_name_for_the_custom_oauth" : "Dê um nome exclusivo para o oauth customizado", - "Have_your_own_chat" : "Tenha seu próprio web chat. Desenvolvido com Meteor.com, o Rocket.Chat é uma excelente solução para desenvolvedores que querem construir e desenvolver sua própria plataforma de chat.", "Has_more" : "Há mais", + "Have_your_own_chat" : "Tenha seu próprio web chat. Desenvolvido com Meteor.com, o Rocket.Chat é uma excelente solução para desenvolvedores que querem construir e desenvolver sua própria plataforma de chat.", "Hide_room" : "Esconder sala", "History" : "Histórico", "hours" : "horas", @@ -177,13 +175,15 @@ "Layout_Terms_of_Service" : "Termos de Serviço", "LDAP" : "LDAP", "LDAP_DN" : "DN LDAP", + "LDAP_Port" : "Porta LDAP", "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", "LDAP_Sync_User_Data_FieldMap" : "Mapeamento de campos do usuário", + "LDAP_Url" : "URL LDAP", "Leave_room" : "Sair da sala", "line" : "linha", "Load_more" : "Carregar mais", - "Loading_more_from_history" : "Carregando mais a partir do histórico", "Loading..." : "Carregando...", + "Loading_more_from_history" : "Carregando mais a partir do histórico", "Loading_suggestion" : "Buscando sugestões...", "Login" : "Entrar", "Login_with" : "Login com %s", @@ -198,16 +198,16 @@ "Message_AllowDeleting" : "Permitir Exclusão de Mensagem", "Message_AllowEditing" : "Permitir Edição de Mensagem", "Message_AllowEditing_BlockEditInMinutes" : "Bloquear edição de mensagens após (em minutos - 0 para desabilitar)", + "Message_AllowPinning" : "Permitir Fixar Mensagem", "Message_AudioRecorderEnabled" : "Gravação de Ãudio Habilitada", "Message_deleting_not_allowed" : "Exclusão de mensagem não permitido", - "Message_editing_not_allowed" : "Edição de mensagem não permitido", "Message_editing_blocked" : "Esta mensagem não pode mais ser editada", + "Message_editing_not_allowed" : "Edição de mensagem não permitido", + "Message_KeepHistory" : "Manter Histórico de Mensagens", "Message_MaxAllowedSize" : "Tamanho máximo de mensagem permitido ", + "Message_pinned" : "Mensagem fixada", "Message_pinning_not_allowed" : "Não Permitir Fixar Mensagem", - "Message_AllowPinning" : "Permitir Fixar Mensagem", - "Message_KeepHistory" : "Manter Histórico de Mensagens", "Message_removed" : "Mensagem removida", - "Message_pinned" : "Mensagem fixada", "Message_ShowDeletedStatus" : "Mostrar Status ExcluÃdo", "Message_ShowEditedStatus" : "Mostrar Status Editado", "Message_ShowFormattingTips" : "Exibir dicas de formatação", @@ -227,26 +227,26 @@ "My_Account" : "Minha Conta", "n_messages" : "%s mensagens", "Name" : "Nome", - "Name_optional" : "Nome (opcional)", "Name_cant_be_empty" : "Nome não pode ser vazio", + "Name_optional" : "Nome (opcional)", "New_messages" : "Novas mensagens", "New_password" : "Nova senha", + "No_channel_with_name_%s_was_found" : "Nenhum canal com nome <strong>\"%s\"</strong> foi encontrado!", "No_channels_yet" : "Você não faz parte de nenhum canal ainda.", "No_direct_messages_yet" : "Você não iniciou nenhuma conversa ainda.", "No_favorites_yet" : "Nenhum favorito ainda.", + "No_group_with_name_%s_was_found" : "Nenhum grupo privado com nome <strong>\"%s\"</strong> foi encontrado!", "No_groups_yet" : "Nenhum grupo privado ainda.", "No_permission_to_view_room" : "Sem permissões para ver a sala", - "No_channel_with_name_%s_was_found" : "Nenhum canal com nome <strong>\"%s\"</strong> foi encontrado!", - "No_group_with_name_%s_was_found" : "Nenhum grupo privado com nome <strong>\"%s\"</strong> foi encontrado!", "No_user_with_username_%s_was_found" : "Nenhum usuário com nome de usuário <strong>\"%s\"</strong> foi encontrado!", "Not_allowed" : "Não permitido", "Not_found_or_not_allowed" : "Não encontrado ou não permitido", "Nothing_found" : "Nada encontrado", "Notify_all_in_this_room" : "Notificar todos nesta sala", - "Old_Password" : "Senha Antiga", "Old_and_new_password_required" : "Você precisa fornecer a senha antiga e a nova senha para alterar sua senha.", - "Only_you_can_see_this_message" : "Apenas você pode ver esta mensagem", + "Old_Password" : "Senha Antiga", "Online" : "Online", + "Only_you_can_see_this_message" : "Apenas você pode ver esta mensagem", "Oops!" : "Ops", "Opt_out_statistics" : "Não envie as minhas estatÃsticas anonimamente para Rocket.Chat", "Opt_out_statistics_warning" : "Enviando suas estatÃsticas anonimamente você nos ajudará a identificar quantas instâncias do Rocket.Chat são implantadas, bem como o quão bom o sistema está se comportando, para que nós possamos melhorar ainda mais. Se você quiser continuar nos enviando suas estatÃsticas anonimamente, desmarque a caixa de seleção acima. Obrigado", @@ -284,8 +284,8 @@ "Registration_Succeeded" : "Registrado com Sucesso", "Remember_me" : "Lembrar-me", "Remove" : "Remover", - "Remove_custom_oauth" : "Remover oauth customizado", "Remove_Admin" : "Remover Administrador", + "Remove_custom_oauth" : "Remover oauth customizado", "Reset_password" : "Resetar senha", "Room" : "Sala", "Room_name_changed" : "Nome da sala alterado para: <em>__room_name__</em> por <em>__user_by__</em>", @@ -295,6 +295,8 @@ "Room_uploaded_file_list_empty" : "Nenhum arquivo disponÃvel", "room_user_count" : "%s usuários", "Rooms" : "Salas", + "S_new_messages_since_s" : "%s novas mensagens desde %s", + "SAML" : "SAML", "Save" : "Salvar", "Save_changes" : "Salvar alterações", "Save_Mobile_Bandwidth" : "Economizar Banda Móvel", @@ -325,7 +327,6 @@ "Site_Name" : "Nome do Site", "Site_Url" : "URL do Site", "Site_Url_Description" : "Exemplo: https://chat.dominio.com.br/", - "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "Host SMTP", "SMTP_Password" : "Senha SMTP", @@ -337,9 +338,9 @@ "Stats_Active_Users" : "Usuários Ativos", "Stats_Avg_Channel_Users" : "Média de Usuários por Canal", "Stats_Avg_Private_Group_Users" : "Média de Usuários por Grupo Privado", + "Stats_Away_Users" : "Usuários ausentes", "Stats_Max_Room_Users" : "Número Máximo de Usuários em um Sala", "Stats_Non_Active_Users" : "Usuários Inativos", - "Stats_Away_Users" : "Usuários ausentes", "Stats_Offline_Users" : "Usuários Offline", "Stats_Online_Users" : "Usuários Online", "Stats_OS_Arch" : "Arquitetura", @@ -360,7 +361,6 @@ "Stop_Recording" : "Parar Gravação", "strike" : "tachado", "Submit" : "Enviar", - "S_new_messages_since_s" : "%s novas mensagens desde %s", "The_field_is_required" : "O campo %s é obrigatório.", "True" : "Verdadeiro", "Unnamed" : "Sem nome", @@ -394,13 +394,13 @@ "User_removed_by" : "Usuário <em>__user_removed__</em> removido da conversa por <em>__user_by__</em>.", "User_Settings" : "Configurações do Usuário", "User_updated_successfully" : "Usuário atualizado com sucesso", - "Users" : "Usuários", "Username" : "Nome de usuário", "Username_cant_be_empty" : "O nome de usuário não pode ser vazio", "Username_description" : "O nome de usuário serve para que outras pessoas possam mencionar você em mensagens", "Username_invalid" : "<strong>%s</strong> não é um nome de usuário válido, <br/> usar somente letras, números, pontos e traços", "Username_title" : "Cadastre um nome de usuário", "Username_unavaliable" : "<strong>%s</strong> já está sendo usado :(", + "Users" : "Usuários", "View_All" : "Ver Todos", "Wait_activation_warning" : "Antes que você possa fazer o login, sua conta deve ser manualmente ativada por um administrador.", "We_have_sent_password_email" : "Nós lhe enviamos um e-mail com instruções para redefinir sua senha. Se você não receber um e-mail em breve, por favor retorne e tente novamente.", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index b2b3d359c6f..f5d887b9157 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -2,15 +2,15 @@ "Access_online_demo" : "Попробовать демо-верÑию", "Access_Online_Demo" : "Попробовать демо-верÑию", "Accounts_EmailVerification" : "Подтверждение e-mail", + "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_Google" : "Google логин", "Accounts_OAuth_Google_id" : "Google ID", "Accounts_OAuth_Google_secret" : "Google пароль", "Accounts_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", - "Accounts_OAuth_Custom_Secret" : "Ключ", - "Accounts_OAuth_Custom_Enable" : "Включить", - "Accounts_OAuth_Custom_Button_Label_Text" : "ТекÑÑ‚ кнопки", - "Accounts_OAuth_Custom_Button_Label_Color" : "Цвет текÑта кнопки", - "Accounts_OAuth_Custom_Button_Color" : "Цвет кнопки", "Add_Members" : "Добавить Пользователей", "Add_users" : "Добавить пользователей", "All_channels" : "Ð’Ñе Чаты", @@ -19,6 +19,7 @@ "are_also_typing" : "вÑе ещё печатают", "are_typing" : "печатает", "Are_you_sure" : "Ð’Ñ‹ уверены?", + "Auto_Load_Images" : "Ðвтозагрузка изображений", "Avatar_changed_successfully" : "Ðватар измененм уÑпешно", "away" : "отошёл", "Away" : "Отошёл", @@ -26,7 +27,6 @@ "Away_female" : "Отошла", "away_male" : "отошёл", "Away_male" : "Отошёл", - "Auto_Load_Images" : "Ðвтозагрузка изображений", "Back_to_login" : "Ðа Ñтраницу авторизации", "bold" : "жирный", "busy" : "занÑÑ‚", @@ -68,9 +68,7 @@ "Favorites" : "Избранные чаты", "Follow_social_profiles" : "ДобавлÑйте Ð½Ð°Ñ Ð² Ð´Ñ€ÑƒÐ·ÑŒÑ Ð² Ñоциальных ÑетÑÑ…, форкайте на github и пишите Ñвои отзывы о нашем приложении у Ð½Ð°Ñ Ð² trello.", "Forgot_password" : "Забыли пароль?", - "LDAP_Port" : "LDAP Порт", "Fork_it_on_github" : "Форкайте на github", - "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "github_no_public_email" : "Ð’ наÑтройках GitHub отÑутÑтвует публично доÑтупный e-mail", "Has_more" : "Еще", "Hide_room" : "Скрыть чат", @@ -100,11 +98,13 @@ "Layout_Privacy_Policy" : "Политика конфиденциальноÑти", "Layout_Terms_of_Service" : "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ÑпользованиÑ", "LDAP_DN" : "LDAP домен", + "LDAP_Port" : "LDAP Порт", + "LDAP_Url" : "URL-Ð°Ð´Ñ€ÐµÑ LDAP", "Leave_room" : "Покинуть чат", "line" : "линиÑ", "Load_more" : "Загрузить еще", - "Loading_more_from_history" : "Загрузка еще из иÑтории", "Loading..." : "Загрузка...", + "Loading_more_from_history" : "Загрузка еще из иÑтории", "Loading_suggestion" : "Загрузка предпочтений...", "Login" : "Войти", "Login_with" : "ÐÐ²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ· %s", @@ -134,13 +134,13 @@ "Name" : "ИмÑ", "New_messages" : "Ðовые ÑообщениÑ", "New_password" : "Ðовый пароль", + "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_groups_yet" : "Ð’Ñ‹ не ÑоÑтоите ни в одном приватном чате.", "No_permission_to_view_room" : "У Ð²Ð°Ñ Ð½ÐµÑ‚ прав Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Ñтого чата.", - "No_channel_with_name_%s_was_found" : "Канал Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼Â <strong>\"%s\"</strong> не найден!", - "No_group_with_name_%s_was_found" : "ЧаÑÑ‚Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð° Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ <strong>\"%s\"</strong> не ÑущеÑтвует", "No_user_with_username_%s_was_found" : "Ðет Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼  <strong>\"%s\"</strong>!", "Not_allowed" : "Ðе допуÑкаетÑÑ", "Not_found_or_not_allowed" : "Чат не ÑущеÑтвует или владелец ограничил доÑтуп ", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index a1e4251b590..f4e2cccd903 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -2,14 +2,14 @@ "Access_online_demo" : "Canlı önizleme", "Access_Online_Demo" : "Canlı Önizleme", "Accounts_EmailVerification" : "E-Posta DoÄŸrulama", + "Accounts_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", "Accounts_OAuth_Facebook" : "Facebook ile giriÅŸ", "Accounts_OAuth_Github" : "GitHub ile giriÅŸ", "Accounts_OAuth_Google" : "Google ile giriÅŸ", "Accounts_OAuth_Linkedin" : "LinkedIn ile giriÅŸ", "Accounts_OAuth_Meteor" : "Meteor ile giriÅŸ", - "Accounts_ManuallyApproveNewUsers" : "Yeni kullanıcıları onayla", - "Accounts_RegistrationRequired" : "Kayıt Gerekli", "Accounts_OAuth_Twitter" : "Twitter ile giriÅŸ", + "Accounts_RegistrationRequired" : "Kayıt Gerekli", "Add_Members" : "Ãœye ekle", "Add_users" : "Kullanıcı ekle", "Administration" : "Yönetim", @@ -44,7 +44,6 @@ "coming_soon" : "yakında", "Confirm_password" : "Parolanızı onaylayın", "Contact" : "Ä°letiÅŸim", - "Delete" : "Sil", "Conversation" : "Direkt Mesaj", "Create_new" : "Yeni oluÅŸtur", "Create_new_direct_message_room" : "Yeni doÄŸrudan mesaj odası oluÅŸtur", @@ -52,12 +51,13 @@ "Create_new_public_channel" : "Yeni bir kanal oluÅŸtur", "Created_at" : "OluÅŸturulma saati", "days" : "gün", + "Delete" : "Sil", "Delete_User_Warning" : "Bu kullanıcıyı silerseniz tüm mesajları da beraberinde silinecektir! Bu iÅŸlemi bir daha geri alamazsınız.", - "Edit" : "Düzenle", "Deleted" : "SilinmiÅŸ!", "Direct_Messages" : "Direkt Mesajlar", "Drop_to_upload_file" : "Dosya yüklemek için sürükle", "E-mail" : "E-posta", + "Edit" : "Düzenle", "edited" : "düzenlendi", "Email_already_exists" : "Bu e-posta zaten var", "Email_or_username" : "E-posta ya da kullanıcı adı", @@ -68,9 +68,7 @@ "Favorites" : "Favoriler", "Follow_social_profiles" : "Bizi sosyal aÄŸlardan takip edebilir, rocket.chat uygulaması hakkında düşüncelerinizi paylaÅŸabilir ve uygulamayı github üzerinden çatallayabilirsiniz.", "Forgot_password" : "Åžifrenizi mi unuttunuz", - "LDAP_Port" : "LDAP Port", "Fork_it_on_github" : "Github üzerinde çatalla", - "LDAP_Url" : "LDAP URL", "Get_to_know_the_team" : "Rocket.Team'ı tanıyın", "github_no_public_email" : "Sen GitHub hesabınızda kamu e-posta olarak herhangi bir e-posta yok", "Have_your_own_chat" : "Rocket.Chat, açık kaynak gönüllülerinin bir araya gelerek Meteor ile geliÅŸtirdikleri sohbet uygulamasıdır.", @@ -99,6 +97,8 @@ "Last_login" : "Son giriÅŸ", "Last_message" : "Son mesaj", "Layout_Home_Title" : "Anasayfa baÅŸlığı", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", "Leave_room" : "Odayı terket", "line" : "satır", "Load_more" : "Daha fazla", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index 3a2c8bf04c1..10060566f7a 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -4,10 +4,10 @@ "Accounts" : "å¸æˆ·", "Accounts_denyUnverifiedEmail" : "æ‹’ç»æœªç»éªŒè¯çš„电å邮件", "Accounts_EmailVerification" : "邮件验è¯", + "Accounts_ManuallyApproveNewUsers" : "æ‰‹åŠ¨å®¡æ ¸æ–°ç”¨æˆ·", "Accounts_OAuth_Facebook" : "Facebook 登入", "Accounts_OAuth_Facebook_id" : "Facebook应用程åºID", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", - "Accounts_ManuallyApproveNewUsers" : "æ‰‹åŠ¨å®¡æ ¸æ–°ç”¨æˆ·", "Accounts_RegistrationRequired" : "需è¦æ³¨å†Œ", "Activate" : "激活", "Add_Members" : "åŠ å…¥æˆå‘˜", @@ -22,6 +22,7 @@ "are_also_typing" : "也æ£åœ¨è¾“å…¥", "are_typing" : "æ£åœ¨è¾“å…¥", "Are_you_sure" : "ä½ ç¡®å®šå—?", + "Auto_Load_Images" : "自动载入图片", "Avatar_changed_successfully" : "头åƒæ›´æ–°æˆåŠŸ", "away" : "离开", "Away" : "离开", @@ -29,7 +30,6 @@ "Away_female" : "离开", "away_male" : "离开", "Away_male" : "离开", - "Auto_Load_Images" : "自动载入图片", "Back_to_login" : "返回登录界é¢", "bold" : "粗体", "busy" : "å¿™", @@ -47,7 +47,6 @@ "coming_soon" : "å³å°†æŽ¨å‡º", "Confirm_password" : "确认密ç ", "Contact" : "è”系人", - "Delete" : "åˆ é™¤", "Conversation" : "è°ˆè¯", "Convert_Ascii_Emojis" : "自动识别文å—ä¸çš„表情", "Create_new" : "新建", @@ -57,8 +56,8 @@ "Created_at" : "创建于", "days" : "天", "Deactivate" : "ç¦ç”¨", + "Delete" : "åˆ é™¤", "Delete_User_Warning" : "åˆ é™¤ç”¨æˆ·å°†åˆ é™¤è¯¥ç”¨æˆ·çš„æ‰€æœ‰æ¶ˆæ¯ã€‚è¿™ä¸èƒ½è¢«æ’¤æ¶ˆã€‚", - "Edit" : "编辑", "Deleted" : "å·²åˆ é™¤ï¼", "Direct_Messages" : "直接å‘é€æ¶ˆæ¯", "Disable_New_Message_Notification" : "ç¦ç”¨æ–°æ¶ˆæ¯é€šçŸ¥", @@ -67,6 +66,7 @@ "Duplicate_channel_name" : "é¢‘é“ '%s' å·²å˜åœ¨", "Duplicate_private_group_name" : "ç§æœ‰ç»„ '%s' å·²å˜åœ¨", "E-mail" : "电å邮件", + "Edit" : "编辑", "edited" : "已编辑", "Email_already_exists" : "邮件已å˜åœ¨", "Email_or_username" : "电å邮件或用户å", @@ -79,15 +79,13 @@ "Favorites" : "收è—", "Follow_social_profiles" : "关注我们的社交资讯,fork我们在github的项目或者在trelloä¸Šåˆ†äº«ä½ å…³äºŽrocket.chat的想法。", "Forgot_password" : "忘记密ç ", - "LDAP_Port" : "LDAP端å£", "Fork_it_on_github" : "在Github上Fork它", - "LDAP_Url" : "LDAP URL", "From_Email" : "从电å邮件", "General" : "通用", "Get_to_know_the_team" : "结识Rocket.Team", "github_no_public_email" : "在您的GitHub上å¸æˆ·ä¸ï¼Œæ‚¨æ²¡æœ‰è®¾ç½®ä»»ä½•ç”µå邮件作为公共电å邮件地å€ã€‚", - "Have_your_own_chat" : "拥有自己的网络èŠå¤©ã€‚对于希望建立和å‘展自己的èŠå¤©å¹³å°çš„å¼€å‘者而言,使用Meteorå¼€å‘çš„Rocket.Chat是优秀的解决方案。", "Has_more" : "有更多", + "Have_your_own_chat" : "拥有自己的网络èŠå¤©ã€‚对于希望建立和å‘展自己的èŠå¤©å¹³å°çš„å¼€å‘者而言,使用Meteorå¼€å‘çš„Rocket.Chat是优秀的解决方案。", "Hide_room" : "éšè—èŠå¤©å®¤", "History" : "历å²", "hours" : "å°æ—¶", @@ -124,10 +122,12 @@ "Layout_Terms_of_Service" : "æœåŠ¡æ¡æ¬¾", "LDAP" : "LDAP", "LDAP_DN" : "LDAP DN", + "LDAP_Port" : "LDAP端å£", + "LDAP_Url" : "LDAP URL", "Leave_room" : "离开èŠå¤©å®¤", "Load_more" : "åŠ è½½æ›´å¤š", - "Loading_more_from_history" : "åŠ è½½æ›´å¤š", "Loading..." : "åŠ è½½ä¸...", + "Loading_more_from_history" : "åŠ è½½æ›´å¤š", "Loading_suggestion" : "载入建议ä¸...", "Login" : "登录", "Login_with" : "使用%s登录", @@ -143,8 +143,8 @@ "Message_AllowEditing" : "å…许编辑消æ¯", "Message_deleting_not_allowed" : "ä¸å…è®¸åˆ é™¤æ¶ˆæ¯", "Message_editing_not_allowed" : "ä¸å…许编辑消æ¯", - "Message_MaxAllowedSize" : "消æ¯æœ€å¤§å…许大å°", "Message_KeepHistory" : "ä¿å˜æ¶ˆæ¯åŽ†å²è®°å½•", + "Message_MaxAllowedSize" : "消æ¯æœ€å¤§å…许大å°", "Message_removed" : "消æ¯å·²åˆ 除", "Message_ShowDeletedStatus" : "æ˜¾ç¤ºåˆ é™¤çŠ¶æ€", "Message_ShowEditedStatus" : "显示编辑状æ€", @@ -163,20 +163,20 @@ "Name" : "姓å", "New_messages" : "新消æ¯", "New_password" : "新密ç ", + "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_groups_yet" : "ä½ è¿˜æ²¡æœ‰ç§æœ‰ç»„。", "No_permission_to_view_room" : "您没有æƒé™è®¿é—®è¿™ä¸ªèŠå¤©å®¤", - "No_channel_with_name_%s_was_found" : "æœªæ‰¾åˆ°é¢‘é“ <strong>\"%s\"</strong> !", - "No_group_with_name_%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" : "æ醒房间ä¸çš„所有人", - "Only_you_can_see_this_message" : "åªæœ‰ä½ 能看到这æ¡ä¿¡æ¯", "Online" : "在线", + "Only_you_can_see_this_message" : "åªæœ‰ä½ 能看到这æ¡ä¿¡æ¯", "Oops!" : "å“Žå‘€", "others" : "其他", "Password" : "密ç ", @@ -218,6 +218,8 @@ "Room_not_found" : "未找到房间", "room_user_count" : "%s 个用户", "Rooms" : "房间", + "S_new_messages_since_s" : "%s 新消æ¯ï¼Œè‡ªä»Ž %s", + "SAML" : "SAML", "Save" : "ä¿å˜", "Save_changes" : "ä¿å˜ä¿®æ”¹", "Save_Mobile_Bandwidth" : "节约移动带宽", @@ -245,7 +247,6 @@ "Showing_results" : "<p>显示<b>%s</b>æ¡ç»“æžœ</p>", "Silence" : "é™éŸ³", "since_creation" : "自从%s", - "SAML" : "SAML", "SMTP" : "SMTP", "SMTP_Host" : "SMTP主机", "SMTP_Password" : "SMTP密ç ", @@ -268,7 +269,6 @@ "Stats_Total_Users" : "用户总数", "strike" : "划线", "Submit" : "æ交", - "S_new_messages_since_s" : "%s 新消æ¯ï¼Œè‡ªä»Ž %s", "The_field_is_required" : "å—段 %s 必须填写。", "True" : "是", "Unnamed" : "未命å", @@ -299,13 +299,13 @@ "User_removed_by" : "用户 <em>__user_removed__</em> 已被 <em>__user_by__</em> 移除。", "User_Settings" : "用户设置", "User_updated_successfully" : "用户更新æˆåŠŸ", - "Users" : "用户", "Username" : "用户å", "Username_cant_be_empty" : "用户åä¸èƒ½ä¸ºç©º", "Username_description" : "这个用户å用于让别人在èŠå¤©æ¶ˆæ¯ä¸é€šçŸ¥æ‚¨ã€‚", "Username_invalid" : "<strong>%s</strong>ä¸æ˜¯ä¸€ä¸ªæœ‰æ•ˆçš„用户å, <br/>åªèƒ½ä½¿ç”¨å—æ¯ï¼Œæ•°å—,.å’Œ_", "Username_title" : "注册用户å", "Username_unavaliable" : "<strong>%s</strong>已被使用 :(", + "Users" : "用户", "View_All" : "查看全部", "Wait_activation_warning" : "您的å¸æˆ·å¿…须由管ç†å‘˜æ‰‹å·¥å¯åŠ¨åŽæ‰èƒ½ç™»å½•ã€‚", "We_have_sent_password_email" : "我们已ç»å‘您å‘é€å¯†ç é‡ç½®çš„电å邮件。如果您没有收到邮件,请é‡è¯•ã€‚", diff --git a/packages/rocketchat-ldap/i18n/de.i18n.json b/packages/rocketchat-ldap/i18n/de.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/de.i18n.json +++ b/packages/rocketchat-ldap/i18n/de.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/el.i18n.json b/packages/rocketchat-ldap/i18n/el.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/el.i18n.json +++ b/packages/rocketchat-ldap/i18n/el.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/fi.i18n.json b/packages/rocketchat-ldap/i18n/fi.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/fi.i18n.json +++ b/packages/rocketchat-ldap/i18n/fi.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/fr.i18n.json b/packages/rocketchat-ldap/i18n/fr.i18n.json index 6f31cf5a2e6..edcc9623eef 100644 --- a/packages/rocketchat-ldap/i18n/fr.i18n.json +++ b/packages/rocketchat-ldap/i18n/fr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "DN LDAP" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/km.i18n.json b/packages/rocketchat-ldap/i18n/km.i18n.json index 6f31cf5a2e6..7d77c88f8a0 100644 --- a/packages/rocketchat-ldap/i18n/km.i18n.json +++ b/packages/rocketchat-ldap/i18n/km.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : " LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ko.i18n.json b/packages/rocketchat-ldap/i18n/ko.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/ko.i18n.json +++ b/packages/rocketchat-ldap/i18n/ko.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ms-MY.i18n.json b/packages/rocketchat-ldap/i18n/ms-MY.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/ms-MY.i18n.json +++ b/packages/rocketchat-ldap/i18n/ms-MY.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/pl.i18n.json b/packages/rocketchat-ldap/i18n/pl.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/pl.i18n.json +++ b/packages/rocketchat-ldap/i18n/pl.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/pt.i18n.json b/packages/rocketchat-ldap/i18n/pt.i18n.json index 6f31cf5a2e6..edcc9623eef 100644 --- a/packages/rocketchat-ldap/i18n/pt.i18n.json +++ b/packages/rocketchat-ldap/i18n/pt.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "DN LDAP" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ru.i18n.json b/packages/rocketchat-ldap/i18n/ru.i18n.json index 6f31cf5a2e6..89e00dcc897 100644 --- a/packages/rocketchat-ldap/i18n/ru.i18n.json +++ b/packages/rocketchat-ldap/i18n/ru.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP домен" +} \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/zh.i18n.json b/packages/rocketchat-ldap/i18n/zh.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/zh.i18n.json +++ b/packages/rocketchat-ldap/i18n/zh.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ No newline at end of file -- GitLab From 41e2b38bba52af12329370c5344980792b585b57 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 12 Nov 2015 00:51:03 -0200 Subject: [PATCH 0395/1338] 3,000 commits!! Silly.. I know. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 90e01aed53a..73b34b6b932 100644 --- a/README.md +++ b/README.md @@ -269,3 +269,5 @@ Rocket.Chat will be free forever, but you can help us speed-up the development! [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) [BountySource](https://www.bountysource.com/teams/rocketchat) + + 3,000 commits!! -- GitLab From f5a6bfc4b9e6f122989186a277fb424983095727 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 12 Nov 2015 02:04:27 -0200 Subject: [PATCH 0396/1338] Using official emojione package --- packages/rocketchat-emojione/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-emojione/package.js b/packages/rocketchat-emojione/package.js index 607949ec77b..761d9d0ff87 100644 --- a/packages/rocketchat-emojione/package.js +++ b/packages/rocketchat-emojione/package.js @@ -10,7 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', - 'qnub:emojione', + 'emojione:emojione', 'rocketchat:lib@0.0.1' ]); -- GitLab From 3c161e3c09bcd1105ca0e2aa8cc7b676bcd2d137 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 12 Nov 2015 02:07:27 -0200 Subject: [PATCH 0397/1338] Using official emojione package --- .meteor/versions | 2 +- README.md | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index b614712a8a3..e14a67dbf4c 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -39,6 +39,7 @@ ecmascript@0.1.6 ecmascript-runtime@0.2.6 ejson@1.0.7 email@1.0.8 +emojione:emojione@1.5.2 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 @@ -109,7 +110,6 @@ percolate:migrations@0.9.6 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 -qnub:emojione@1.5.1_2 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 diff --git a/README.md b/README.md index 73b34b6b932..47e916bffbe 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Available from the AppStore: [](https://itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) -Get the app for your Android phone: +Get the app for your Android phone: [](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) @@ -90,18 +90,18 @@ It is a great solution for communities and companies wanting to privately host t - Transcripts / History - File Upload / Sharing - Full text search -- Live chat / Messaging call center -- LDAP Authentication +- Live chat / Messaging call center +- LDAP Authentication - Support for Okta SSO through SAML v2 -- I18n - Supports 22 Languages +- I18n - Supports 22 Languages - Hubot Friendly - Face to Face Video Conferencing (aka WebRTC) - Multi-users Video Group Chat - Audio calls - Multi-users Audio Conference - Screensharing -- REST APIs -- Remote Locations Video Monitoring +- REST APIs +- Remote Locations Video Monitoring - Chat-ops powered by Hubot: scalable horizontal app integration (early access) - Massively scalable hosting and provisioning (beta testing now) - Native Cross-Platform Desktop Application [Windows, Mac OSX, or Linux](https://rocket.chat/) @@ -145,7 +145,7 @@ Everyone can start hacking the adapter code, or launch his/her own bot within a Please head over to the [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) for more information. -#### Chat-ops integrations powered by Hubot +#### Chat-ops integrations powered by Hubot Integrate your application with fly-in panels today! Early access is available for developers. @@ -269,5 +269,3 @@ Rocket.Chat will be free forever, but you can help us speed-up the development! [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) [BountySource](https://www.bountysource.com/teams/rocketchat) - - 3,000 commits!! -- GitLab From 35506a5a216caee84e35faa984a28b203c784b09 Mon Sep 17 00:00:00 2001 From: Reid Wakida <rwakida@gmail.com> Date: Wed, 11 Nov 2015 14:59:53 -1000 Subject: [PATCH 0398/1338] Update rest bulk api to work with backend changes and remove role requirements because restivus is not compatible with alanning:roles with groups --- server/methods/createChannel.coffee | 2 +- server/methods/registerUser.coffee | 2 ++ server/restapi/restapi.coffee | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index c3dff18c170..817412e5083 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -14,7 +14,7 @@ Meteor.methods now = new Date() user = Meteor.user() - members.push user.username + members.push user.username if user.username not in members # avoid duplicate names if RocketChat.models.Rooms.findOneByName name diff --git a/server/methods/registerUser.coffee b/server/methods/registerUser.coffee index ec9baf84f49..4a73cd73167 100644 --- a/server/methods/registerUser.coffee +++ b/server/methods/registerUser.coffee @@ -10,3 +10,5 @@ Meteor.methods if userData.email Accounts.sendVerificationEmail(userId, userData.email); + + return userId diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 90ba65e19b1..79abfe263c3 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -99,7 +99,7 @@ NOTE: remove room is NOT recommended; use Meteor.reset() to clear db and re-se ### Api.addRoute 'bulk/register', authRequired: true, post: - roleRequired: ['testagent', 'adminautomation'] + #roleRequired: ['testagent', 'adminautomation'] action: -> try Api.testapiValidateUsers @bodyParams.users @@ -107,10 +107,10 @@ Api.addRoute 'bulk/register', authRequired: true, ids = [] endCount = @bodyParams.users.length - 1 for incoming, i in @bodyParams.users - ids[i] = Meteor.call 'registerUser', incoming - Meteor.runAsUser ids[i].uid, () => - Meteor.call 'setUsername', incoming.name - Meteor.call 'joinDefaultChannels' + ids[i] = {uid: Meteor.call 'registerUser', incoming} + Meteor.runAsUser ids[i].uid, () => + Meteor.call 'setUsername', incoming.name + Meteor.call 'joinDefaultChannels' status: 'success', ids: ids catch e @@ -136,7 +136,7 @@ Api.testapiValidateRooms = (rooms) -> @apiName createRoom @apiGroup TestAndAdminAutomation @apiVersion 0.0.1 -@apiParam {json} rooms An array of rooms in the body of the POST. +@apiParam {json} rooms An array of rooms in the body of the POST. 'name' is room name, 'members' is array of usernames @apiParamExample {json} POST Request Body example: { 'rooms':[ {'name': 'room1', @@ -163,7 +163,7 @@ NOTE: remove room is NOT recommended; use Meteor.reset() to clear db and re-se ### Api.addRoute 'bulk/createRoom', authRequired: true, post: - roleRequired: ['testagent', 'adminautomation'] + #roleRequired: ['testagent', 'adminautomation'] action: -> try this.response.setTimeout (1000 * @bodyParams.rooms.length) -- GitLab From 55efdea054a290d194aa6ce7480a9548ec3477bd Mon Sep 17 00:00:00 2001 From: Reid Wakida <rwakida@gmail.com> Date: Wed, 11 Nov 2015 18:55:01 -1000 Subject: [PATCH 0399/1338] Adds 2 new permissions related to bulk user registration and bulk channel creation. Permissions are assigned admin role. The nimble:restivus package, used by REST api, does not support alanning:roles with 'groups'. It doesn't even use the alanning:roles API to check for roles. As a workaround, I removed restivus's rolesRequired check from the bulk api methods and added Rocketchat.authz.hasPermission checks. --- .../server/startup.coffee | 5 ++ server/restapi/restapi.coffee | 64 ++++++++++++------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index a8072af4f3c..c7cd71d4072 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -72,6 +72,11 @@ Meteor.startup -> { _id: 'delete-d', roles : ['admin', 'site-moderator']} + { _id: 'bulk-register-user', + roles : ['admin']} + + { _id: 'bulk-create-c', + roles : ['admin']} ] #alanning:roles diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 79abfe263c3..55f4c2bea0f 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -99,23 +99,31 @@ NOTE: remove room is NOT recommended; use Meteor.reset() to clear db and re-se ### Api.addRoute 'bulk/register', authRequired: true, post: + # restivus 0.8.4 does not support alanning:roles using groups #roleRequired: ['testagent', 'adminautomation'] action: -> - try - Api.testapiValidateUsers @bodyParams.users - this.response.setTimeout (500 * @bodyParams.users.length) - ids = [] - endCount = @bodyParams.users.length - 1 - for incoming, i in @bodyParams.users - ids[i] = {uid: Meteor.call 'registerUser', incoming} - Meteor.runAsUser ids[i].uid, () => - Meteor.call 'setUsername', incoming.name - Meteor.call 'joinDefaultChannels' + if RocketChat.authz.hasPermission(@userId, 'bulk-register-user') + try + + Api.testapiValidateUsers @bodyParams.users + this.response.setTimeout (500 * @bodyParams.users.length) + ids = [] + endCount = @bodyParams.users.length - 1 + for incoming, i in @bodyParams.users + ids[i] = {uid: Meteor.call 'registerUser', incoming} + Meteor.runAsUser ids[i].uid, () => + Meteor.call 'setUsername', incoming.name + Meteor.call 'joinDefaultChannels' + + status: 'success', ids: ids + catch e + statusCode: 400 # bad request or other errors + body: status: 'fail', message: e.name + ' :: ' + e.message + else + console.log '[restapi] bulk/register -> '.red, "User does not have 'bulk-register-user' permission" + statusCode: 403 + body: status: 'error', message: 'You do not have permission to do this' - status: 'success', ids: ids - catch e - statusCode: 400 # bad request or other errors - body: status: 'fail', message: e.name + ' :: ' + e.message @@ -163,18 +171,26 @@ NOTE: remove room is NOT recommended; use Meteor.reset() to clear db and re-se ### Api.addRoute 'bulk/createRoom', authRequired: true, post: + # restivus 0.8.4 does not support alanning:roles using groups #roleRequired: ['testagent', 'adminautomation'] action: -> - try - this.response.setTimeout (1000 * @bodyParams.rooms.length) - Api.testapiValidateRooms @bodyParams.rooms - ids = [] - Meteor.runAsUser this.userId, () => - (ids[i] = Meteor.call 'createChannel', incoming.name, incoming.members) for incoming,i in @bodyParams.rooms - status: 'success', ids: ids # need to handle error - catch e - statusCode: 400 # bad request or other errors - body: status: 'fail', message: e.name + ' :: ' + e.message + # user must also have create-c permission because + # createChannel method requires it + if RocketChat.authz.hasPermission(@userId, 'bulk-create-c') + try + this.response.setTimeout (1000 * @bodyParams.rooms.length) + Api.testapiValidateRooms @bodyParams.rooms + ids = [] + Meteor.runAsUser this.userId, () => + (ids[i] = Meteor.call 'createChannel', incoming.name, incoming.members) for incoming,i in @bodyParams.rooms + status: 'success', ids: ids # need to handle error + catch e + statusCode: 400 # bad request or other errors + body: status: 'fail', message: e.name + ' :: ' + e.message + else + console.log '[restapi] bulk/createRoom -> '.red, "User does not have 'bulk-create-c' permission" + statusCode: 403 + body: status: 'error', message: 'You do not have permission to do this' -- GitLab From b2d6757e8ac4dce38586ea1de57879040c2f9d53 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Thu, 12 Nov 2015 00:53:27 -0500 Subject: [PATCH 0400/1338] add SECURITY.md --- SECURITY.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..ccb618ae4b1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,7 @@ +# Reporting Security Issues + +Please report any security issues you discovered to security[at]rocket[dot]chat + +We will assess the risk, plus make a fix available before we create a GitHub issue. + +Thank you for your contribution. -- GitLab From 63c0d152813c077b970d4d914d00ad8e265743cc Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 12 Nov 2015 09:06:42 -0200 Subject: [PATCH 0401/1338] Fix #1381 --- client/views/app/message.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index b0bb174c48b..57e40f877bf 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -130,5 +130,5 @@ Template.message.onViewRendered = (context) -> view.parentView.parentView.parentView.parentView.parentView.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") + newMessage = view.parentView.parentView.parentView.parentView.parentView.templateInstance?()?.find(".new-message") newMessage?.className = "new-message" -- GitLab From 61608d2c9cfc51c1d35087d20b505a255e38ddab Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 12 Nov 2015 13:12:22 -0200 Subject: [PATCH 0402/1338] Add default allowed file upload --- packages/rocketchat-lib/settings/server/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 7821c68fefe..bc30723937a 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -44,7 +44,7 @@ RocketChat.settings.add 'Accounts_RequireNameForSignUp', true, { type: 'boolean' 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/*', { type: 'string', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } +RocketChat.settings.add 'FileUpload_MediaTypeWhiteList', 'image/*, audio/*, .pdf, .doc, .txt', { type: 'string', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } RocketChat.settings.addGroup 'General' -- GitLab From 81cae6884552cad5f9d6b0a4905b2de6860d8bc3 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 12 Nov 2015 13:58:54 -0200 Subject: [PATCH 0403/1338] Changes to rocketmailer allows any from address. --- client/views/admin/admin.html | 4 ++-- .../settings/server/methods.coffee | 1 + .../settings/server/startup.coffee | 4 ++-- .../client/views/rocketMailer.coffee | 17 +++++++++++++---- .../client/views/rocketMailer.html | 4 ++-- packages/rocketchat-mailer/i18n/en.i18n.json | 3 ++- .../server/functions/sendMail.coffee | 13 +++++++------ 7 files changed, 29 insertions(+), 17 deletions(-) diff --git a/client/views/admin/admin.html b/client/views/admin/admin.html index 36d96f01d31..e08a30a2a24 100644 --- a/client/views/admin/admin.html +++ b/client/views/admin/admin.html @@ -40,11 +40,11 @@ {{#if multiline}} <textarea name="{{_id}}" rows="4" style="height: auto">{{value}}</textarea> {{else}} - <input type="text" name="{{_id}}" value="{{value}}" /> + <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> {{/if}} {{/if}} {{#if $eq type 'int'}} - <input type="number" name="{{_id}}" value="{{value}}" /> + <input type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> {{/if}} {{#if $eq type 'boolean'}} <label><input type="radio" name="{{_id}}" value="1" checked="{{$eq value true}}" /> {{_ "True"}}</label> diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 812e413119d..20939369bc4 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -29,6 +29,7 @@ RocketChat.settings.add = (_id, value, options = {}) -> updateSettings.group = options.group if options.group updateSettings.section = options.section if options.section updateSettings.public = options.public if options.public + updateSettings.placeholder = options.placeholder if options.placeholder upsertChanges = { $setOnInsert: { value: value }, $set: updateSettings } diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index bc30723937a..e32e50c37aa 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -64,10 +64,10 @@ 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', 'no-reply@rocket.chat', { type: 'string', group: 'SMTP' } +RocketChat.settings.add 'From_Email', '', { type: 'string', group: 'SMTP', placeholder: 'Name <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 https://demo.rocket.chat and try the best open source chat solution available today!</p>', { type: 'string', multiline: true, 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.addGroup 'Message' RocketChat.settings.add 'Message_AllowEditing', true, { type: 'boolean', group: 'Message', public: true } diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.coffee b/packages/rocketchat-mailer/client/views/rocketMailer.coffee index 8b50abbb9a8..d615dad8f39 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailer.coffee +++ b/packages/rocketchat-mailer/client/views/rocketMailer.coffee @@ -1,3 +1,7 @@ +Template.rocketMailer.helpers + fromEmail: -> + return RocketChat.settings.get 'From_Email' + Template.rocketMailer.events 'click .send': (e, t) -> e.preventDefault() @@ -5,9 +9,14 @@ Template.rocketMailer.events subject = $(t.find('[name=subject]')).val() body = $(t.find('[name=body]')).val() + unless from + toastr.error TAPi18n.__('From_email_is_required') + return + if body.indexOf('[unsubscribe]') is -1 toastr.error TAPi18n.__('You_must_provide_the_unsubscribe_link') - else - Meteor.call 'RocketMailer.sendMail', from, subject, body, (err) -> - return toastr.error err.reason if err - toastr.success TAPi18n.__('The_emails_are_being_sent') + return + + Meteor.call 'RocketMailer.sendMail', from, subject, body, (err) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__('The_emails_are_being_sent') diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.html b/packages/rocketchat-mailer/client/views/rocketMailer.html index c7855d98474..309b0d66122 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailer.html +++ b/packages/rocketchat-mailer/client/views/rocketMailer.html @@ -16,10 +16,10 @@ <div class="input-line"> <label>{{_ "Email_from"}}</label> <div> - <input type="text" name="from" value="" /> + <input type="text" name="from" value="" placeholder="{{fromEmail}}" /> </div> <div> - <small class="settings-description">{{_ "Currently_only_rocket_chat_emails"}}</small> + <small class="settings-description">{{{_ "From_email_warning"}}}</small> </div> </div> <div class="input-line"> diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index 60bfa23db94..4d969327fd3 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -1,5 +1,6 @@ { - "Currently_only_rocket_chat_emails": "Currently only accepting @rocket.chat e-mails", + "From_email_warning": "<b>Warning</b>: The field <b>From</b> is subject to your mail server settings.", + "From_email_is_required": "From e-mail is required", "Email_from": "From", "Email_subject": "Subject", "Email_body": "E-mail body", diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee index 0d73dd7478f..ed46eafdf7c 100644 --- a/packages/rocketchat-mailer/server/functions/sendMail.coffee +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -1,7 +1,9 @@ RocketMailer.sendMail = (from, subject, body) -> - rocketchatMailPattern = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@rocket.chat)(?:>?)$/ - unless rocketchatMailPattern.test from + 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])?)*)(?:>?)$/ + # rfcMailPattern = /^[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])?)*$/ + + unless rfcMailPatternWithName.test from throw new Meteor.Error 'invalid-from-address', TAPi18n.__('You_informed_an_invalid_FROM_address') if body.indexOf('[unsubscribe]') is -1 @@ -20,10 +22,9 @@ RocketMailer.sendMail = (from, subject, body) -> html = html.replace /\[email\]/g, email html = html.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2') - # 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])?)*)(?:>?)$/ - # if rfcMailPatternWithName.test email - rfcMailPattern = /^[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])?)*$/ - if rfcMailPattern.test email + email = "#{user.name} <#{email}>" + + if rfcMailPatternWithName.test email Meteor.defer -> Email.send to: email -- GitLab From 3f2463d5e8bc0b3151fdcae31a6048d7d431b3d8 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 12 Nov 2015 10:15:03 -0600 Subject: [PATCH 0404/1338] Combine the first two checks into one to make it more readable --- .../client/actionButton.coffee | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index b1600f68d57..0f5c8fe789a 100644 --- a/packages/rocketchat-message-pin/client/actionButton.coffee +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -5,14 +5,12 @@ Meteor.startup -> i18nLabel: 'Pin_Message' action: (event, instance) -> message = @_arguments[1] + message.pinned = true Meteor.call 'pinMessage', message, (error, result) -> if error return Errors.throw error.reason validation: (message) -> - if message.pinned - return false - - if !RocketChat.settings.get('Message_AllowPinning') + if message.pinned or not RocketChat.settings.get('Message_AllowPinning') return false if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' @@ -27,18 +25,17 @@ Meteor.startup -> i18nLabel: 'Unpin_Message' action: (event, instance) -> message = @_arguments[1] + message.pinned = false Meteor.call 'unpinMessage', message, (error, result) -> if error return Errors.throw error.reason validation: (message) -> - if not message.pinned - return false - - if !RocketChat.settings.get('Message_AllowPinning') + if not message.pinned or not RocketChat.settings.get('Message_AllowPinning') return false if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' return true + console.log 'UNpin-message', '---- is user the room owner', room.u?._id is Meteor.userId() return room.u?._id is Meteor.userId() - order: 20 + order: 21 -- GitLab From 8034fff9e0d6e21130fa99d43659b1452f953449 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Thu, 12 Nov 2015 10:16:05 -0600 Subject: [PATCH 0405/1338] Remove the added console log --- packages/rocketchat-message-pin/client/actionButton.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index 0f5c8fe789a..ca8577a124f 100644 --- a/packages/rocketchat-message-pin/client/actionButton.coffee +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -36,6 +36,5 @@ Meteor.startup -> if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' return true - console.log 'UNpin-message', '---- is user the room owner', room.u?._id is Meteor.userId() return room.u?._id is Meteor.userId() order: 21 -- GitLab From 2b8524f9c71cd42a78b92787fdb8ea58e7ca2b70 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 12 Nov 2015 14:31:28 -0200 Subject: [PATCH 0406/1338] Send e-mail on first username set --- packages/rocketchat-lib/server/functions/setUsername.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 9497f705f71..2e4d5982937 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -16,6 +16,10 @@ RocketChat.setUsername = (user, username) -> previousUsername = user.username + # If first time setting username, send Enrollment Email + if not previousUsername and RocketChat.settings.get 'Accounts_Enrollment_Email' + Accounts.sendEnrollmentEmail(user._id) + # Username is available; if coming from old username, update all references if previousUsername RocketChat.models.Messages.updateAllUsernamesByUserId user._id, username -- GitLab From 2ddb27db6ae460f5c26d6602b379481876728af5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 12 Nov 2015 17:51:47 -0200 Subject: [PATCH 0407/1338] Removed unused 'nu' message type --- client/views/app/message.coffee | 5 ++--- i18n/en.i18n.json | 3 +-- packages/rocketchat-livechat/app/client/views/message.coffee | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 57e40f877bf..590a796fe6a 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -25,7 +25,6 @@ Template.message.helpers when 'au' then t('User_added_by', { user_added: this.msg, user_by: this.u.username }) when 'ru' then t('User_removed_by', { user_removed: this.msg, user_by: this.u.username }) when 'ul' then t('User_left', { user_left: this.u.username }) - when 'nu' then t('User_added', { user_added: this.u.username }) when 'uj' then t('User_joined_channel', { user: this.u.username }) when 'wm' then t('Welcome', { user: this.u.username }) when 'rm' then t('Message_removed', { user: this.u.username }) @@ -45,7 +44,7 @@ Template.message.helpers return this.html system: -> - return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj', 'rm'] edited: -> Template.instance().wasEdited?(@) editTime: -> return "" unless Template.instance().wasEdited?(@) @@ -92,7 +91,7 @@ Template.message.helpers Template.message.onCreated -> @wasEdited = (msg) -> - msg.editedAt? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj', 'rm'] + msg.editedAt? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj', 'rm'] Template.message.onViewRendered = (context) -> view = this diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 02af0e5c012..e8451784080 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -410,7 +410,6 @@ "Use_this_username" : "Use this username", "Use_uploaded_avatar" : "Use uploaded avatar", "Use_url_for_avatar" : "Use url for avatar", - "User_added" : "User <em>__user_added__</em> added.", "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", @@ -453,4 +452,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index fd6455ab38d..1b49884bd82 100644 --- a/packages/rocketchat-livechat/app/client/views/message.coffee +++ b/packages/rocketchat-livechat/app/client/views/message.coffee @@ -23,7 +23,6 @@ Template.message.helpers when 'au' then t('User_added_by', { user_added: this.msg, user_by: this.u.username }) when 'ru' then t('User_removed_by', { user_removed: this.msg, user_by: this.u.username }) when 'ul' then tr('User_left', { context: this.u.gender }, { user_left: this.u.username }) - when 'nu' then t('User_added', { user_added: this.u.username }) when 'uj' then tr('User_joined_channel', { context: this.u.gender }, { user: this.u.username }) when 'wm' then t('Welcome', { user: this.u.username }) # when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this @@ -37,7 +36,7 @@ Template.message.helpers return this.html system: -> - return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj'] + return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj'] Template.message.onViewRendered = (context) -> -- GitLab From c9cf46a3dd9e191beda2cb7cd6ee655bb1b7af1f Mon Sep 17 00:00:00 2001 From: Reid Wakida <rwakida@gmail.com> Date: Thu, 12 Nov 2015 16:32:27 -1000 Subject: [PATCH 0408/1338] Fix Room model's removeByTypeContainingUsername. usernames field missing trailing 's' --- packages/rocketchat-lib/server/models/Rooms.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index e31711c7f4c..579091a1080 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -332,6 +332,6 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base removeByTypeContainingUsername: (type, username) -> query = t: type - username: username + usernames: username return @remove query -- GitLab From 260b3b7724eb860df2c6cad7b893873ef3b190f2 Mon Sep 17 00:00:00 2001 From: Reid Wakida <rwakida@gmail.com> Date: Thu, 12 Nov 2015 16:34:04 -1000 Subject: [PATCH 0409/1338] Deletes direct message subscription for users conversing with user being deleted. Fixes #1149 where "other" user's subscription for non-deleted, direct message, was not deleted. This led to duplicate key error if a new user, with the same username as the deleted user, is created and tries to direct message the "other" user. --- server/methods/deleteUser.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/methods/deleteUser.coffee b/server/methods/deleteUser.coffee index b388826833b..c2fd053f6e0 100644 --- a/server/methods/deleteUser.coffee +++ b/server/methods/deleteUser.coffee @@ -18,13 +18,12 @@ Meteor.methods room = RocketChat.models.Rooms.findOneById subscription.rid if room.t isnt 'c' and room.usernames.length is 1 RocketChat.models.Rooms.removeById subscription.rid # Remove non-channel rooms with only 1 user (the one being deleted) + if room.t is 'd' + RocketChat.models.Subscriptions.removeByRoomId subscription.rid + RocketChat.models.Messages.removeByRoomId subscription.rid RocketChat.models.Subscriptions.removeByUserId userId # Remove user subscriptions - - rooms = RocketChat.models.Rooms.findByUserId(userId).fetch() - - RocketChat.models.Rooms.removeByTypeContainingUsername 'd', user.username # Remove direct rooms with the user RocketChat.models.Rooms.removeUsernameFromAll user.username # Remove user from all other rooms RocketChat.models.Users.removeById userId # Remove user from users database -- GitLab From a3ea777cf1b295225fb1e1c5a4feaa364a04f440 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 13 Nov 2015 10:15:43 -0200 Subject: [PATCH 0410/1338] Created RocketChat.MessageTypes class to hold message type rendering rules --- client/views/app/message.coffee | 43 ++++++------ .../rocketchat-lib/client/MessageTypes.coffee | 70 +++++++++++++++++++ packages/rocketchat-lib/package.js | 1 + 3 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 packages/rocketchat-lib/client/MessageTypes.coffee diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 590a796fe6a..a04193e9b74 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -20,31 +20,34 @@ Template.message.helpers return body: -> - switch this.t - when 'r' then t('Room_name_changed', { room_name: this.msg, user_by: this.u.username }) - when 'au' then t('User_added_by', { user_added: this.msg, user_by: this.u.username }) - when 'ru' then t('User_removed_by', { user_removed: this.msg, user_by: this.u.username }) - when 'ul' then t('User_left', { user_left: this.u.username }) - when 'uj' then t('User_joined_channel', { user: this.u.username }) - when 'wm' then t('Welcome', { user: this.u.username }) - when 'rm' then t('Message_removed', { user: this.u.username }) - when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this + messageType = RocketChat.MessageTypes.getType(this) + if messageType?.render? + return messageType.render(message) + else if messageType?.template? + # render template + else if messageType?.message? + if messageType.data?(this)? + return TAPi18n.__(messageType.message, messageType.data(this)) else - if this.u?.username is RocketChat.settings.get('Chatops_Username') - this.html = this.msg - message = RocketChat.callbacks.run 'renderMentions', this - # console.log JSON.stringify message - return this.html + return TAPi18n.__(messageType.message) + else + if this.u?.username is RocketChat.settings.get('Chatops_Username') this.html = this.msg - if _.trim(this.html) isnt '' - this.html = _.escapeHTML this.html - message = RocketChat.callbacks.run 'renderMessage', this + message = RocketChat.callbacks.run 'renderMentions', this # console.log JSON.stringify message - this.html = message.html.replace /\n/gm, '<br/>' return this.html + this.html = this.msg + if _.trim(this.html) isnt '' + this.html = _.escapeHTML this.html + message = RocketChat.callbacks.run 'renderMessage', this + # console.log JSON.stringify message + this.html = message.html.replace /\n/gm, '<br/>' + return this.html system: -> - return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj', 'rm'] + if RocketChat.MessageTypes.isSystemMessage(this) + return 'system' + edited: -> Template.instance().wasEdited?(@) editTime: -> return "" unless Template.instance().wasEdited?(@) @@ -91,7 +94,7 @@ Template.message.helpers Template.message.onCreated -> @wasEdited = (msg) -> - msg.editedAt? and msg.t not in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj', 'rm'] + msg.editedAt? and not RocketChat.MessageTypes.isSystemMessage(this) Template.message.onViewRendered = (context) -> view = this diff --git a/packages/rocketchat-lib/client/MessageTypes.coffee b/packages/rocketchat-lib/client/MessageTypes.coffee new file mode 100644 index 00000000000..3e374f4d7ca --- /dev/null +++ b/packages/rocketchat-lib/client/MessageTypes.coffee @@ -0,0 +1,70 @@ +RocketChat.MessageTypes = new class + types = {} + + registerType = (options) -> + types[options.id] = options + + getType = (message) -> + return types[message?.t] + + isSystemMessage = (message) -> + return types[message?.t]?.system + + registerType: registerType + getType: getType + isSystemMessage: isSystemMessage + +Meteor.startup -> + RocketChat.MessageTypes.registerType + id: 'r' + system: true + message: 'Room_name_changed' + data: (message) -> + return { room_name: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'au' + system: true + message: 'User_added_by' + data: (message) -> + return { user_added: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'ru' + system: true + message: 'User_removed_by' + data: (message) -> + return { user_removed: message.msg, user_by: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'ul' + system: true + message: 'User_left' + data: (message) -> + return { user_left: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'uj' + system: true + message: 'User_joined_channel' + data: (message) -> + return { user: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'wm' + system: true + message: 'Welcome' + data: (message) -> + return { user: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'rm' + system: true + message: 'Message_removed' + data: (message) -> + return { user: message.u.username } + + RocketChat.MessageTypes.registerType + id: 'rtc' + render: (message) -> + RocketChat.callbacks.run 'renderRtcMessage', message diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 668e157f2ef..fde76ff1f86 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -56,6 +56,7 @@ 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('settings/client/rocketchat.coffee', 'client'); -- GitLab From 1977d10e7477dc5d7fc951cdaea7472437ba42c7 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 13 Nov 2015 13:49:29 -0200 Subject: [PATCH 0411/1338] Change channel type; Closes #1037 --- .meteor/versions | 1 + client/lib/RoomManager.coffee | 8 +------- client/lib/trackRoomNameChanged.coffee | 12 +++++++++++ client/views/app/videoCall/videoCall.coffee | 2 +- .../client/startup/messageTypes.coffee | 20 +++++++++++++++++++ .../client/{ => startup}/tabBar.coffee | 5 +++-- .../client/startup/trackSettingsChange.coffee | 15 ++++++++++++++ .../client/views/channelSettings.coffee | 11 ++++++++-- .../i18n/en.i18n.json | 4 +++- .../rocketchat-channel-settings/package.js | 9 ++++++--- .../server/methods/saveRoomSettings.coffee | 11 ++++++++-- .../server/models/Messages.coffee | 2 ++ .../rocketchat-lib/client/lib/openRoom.coffee | 2 +- 13 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 client/lib/trackRoomNameChanged.coffee create mode 100644 packages/rocketchat-channel-settings/client/startup/messageTypes.coffee rename packages/rocketchat-channel-settings/client/{ => startup}/tabBar.coffee (66%) create mode 100644 packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee create mode 100644 packages/rocketchat-channel-settings/server/models/Messages.coffee diff --git a/.meteor/versions b/.meteor/versions index 70b645b5e82..359a1e769b1 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -123,6 +123,7 @@ reload@1.1.4 retry@1.0.4 rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 +rocketchat:channel-settings@0.0.1 rocketchat:colors@0.0.1 rocketchat:custom-oauth@1.0.0 rocketchat:emojione@0.0.1 diff --git a/client/lib/RoomManager.coffee b/client/lib/RoomManager.coffee index b5684d5785e..a9e8a7a406b 100644 --- a/client/lib/RoomManager.coffee +++ b/client/lib/RoomManager.coffee @@ -110,13 +110,7 @@ RocketChat.Notifications.onUser 'message', (msg) -> Meteor.defer -> RoomManager.updateMentionsMarksOfRoom typeName - # If room was renamed then close current room and send user to the new one - 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 + RocketChat.callbacks.run 'streamMessage', msg RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream diff --git a/client/lib/trackRoomNameChanged.coffee b/client/lib/trackRoomNameChanged.coffee new file mode 100644 index 00000000000..8b3a0769feb --- /dev/null +++ b/client/lib/trackRoomNameChanged.coffee @@ -0,0 +1,12 @@ +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/client/views/app/videoCall/videoCall.coffee b/client/views/app/videoCall/videoCall.coffee index d777b030727..a3431aa73a0 100644 --- a/client/views/app/videoCall/videoCall.coffee +++ b/client/views/app/videoCall/videoCall.coffee @@ -9,7 +9,7 @@ Template.videoCall.helpers videoActive: -> webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom')) overlay = @overlay? - if overlay isnt webrtc.overlayEnabled.get() + if overlay isnt webrtc?.overlayEnabled.get() return false return webrtc.localUrl.get()? or webrtc.remoteItems.get()?.length > 0 diff --git a/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee b/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee new file mode 100644 index 00000000000..3870f1ef762 --- /dev/null +++ b/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee @@ -0,0 +1,20 @@ +Meteor.startup -> + RocketChat.MessageTypes.registerType + id: 'room_changed_privacy' + system: true + message: 'room_changed_privacy' + data: (message) -> + return { + user_by: message.u?.username + room_type: message.msg + } + + RocketChat.MessageTypes.registerType + id: 'room_changed_topic' + system: true + message: 'room_changed_topic' + data: (message) -> + return { + user_by: message.u?.username + room_topic: message.msg + } diff --git a/packages/rocketchat-channel-settings/client/tabBar.coffee b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee similarity index 66% rename from packages/rocketchat-channel-settings/client/tabBar.coffee rename to packages/rocketchat-channel-settings/client/startup/tabBar.coffee index 46bc83eacd8..17d1680317e 100644 --- a/packages/rocketchat-channel-settings/client/tabBar.coffee +++ b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee @@ -1,11 +1,12 @@ Meteor.startup -> - RocketChat.callbacks.add 'enter-room', -> + 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' diff --git a/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee b/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee new file mode 100644 index 00000000000..b3618dd7232 --- /dev/null +++ b/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee @@ -0,0 +1,15 @@ +Meteor.startup -> + roomSettingsChangedCallback = (msg) -> + Tracker.nonreactive -> + if msg.t is 'room_changed_privacy' + 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') + + subscription = ChatSubscription.findOne({ rid: msg.rid }) + route = if subscription.t is 'c' then 'channel' else 'group' + FlowRouter.go route, name: subscription.name + + return msg + + RocketChat.callbacks.add 'streamMessage', roomSettingsChangedCallback, RocketChat.callbacks.priority.HIGH diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index c2e80b09d07..4f9f5d344c5 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -8,9 +8,16 @@ Template.channelSettings.events 'click .save': (e, t) -> e.preventDefault() - settings = + settings = roomType: t.$('input[name=roomType]:checked').val() Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> return toastr.error err.reason if err - toastr.success TAPi18n.__ 'Settings_updated' \ No newline at end of file + toastr.success TAPi18n.__ 'Settings_updated' + + + # switch room.t + # when 'c' + # FlowRouter.go 'channel', name: name + # when 'p' + # FlowRouter.go 'group', name: name diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index 3a052c3d63b..ba1d6c016df 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -2,5 +2,7 @@ "Channel": "Channel", "Private_Group": "Private Group", "Room_Type": "Room Type", - "Room_Settings": "Room Settings" + "Room_Settings": "Room Settings", + "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>" } diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 446e9b3e97e..06b8f3fe128 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -16,15 +16,18 @@ Package.onUse(function(api) { ]); api.addFiles([ - 'client/tabBar.coffee', + 'client/startup/messageTypes.coffee', + 'client/startup/tabBar.coffee', + 'client/startup/trackSettingsChange.coffee', 'client/views/channelSettings.html', 'client/views/channelSettings.coffee', - 'client/stylesheets/channel-settings.less', + 'client/stylesheets/channel-settings.less' ], 'client'); api.addFiles([ 'server/functions/changeRoomType.coffee', - 'server/methods/saveRoomSettings.coffee' + 'server/methods/saveRoomSettings.coffee', + 'server/models/Messages.coffee' ], 'server'); // TAPi18n diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee index e3e807ffb48..6375bf5f289 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -1,4 +1,4 @@ -Meteor.methods +Meteor.methods saveRoomSettings: (rid, settings) -> console.log '[method] saveRoomSettings'.green, rid, settings @@ -16,4 +16,11 @@ Meteor.methods if settings.roomType isnt room.t RocketChat.changeRoomType(rid, settings.roomType) - return true \ No newline at end of file + if settings.roomType 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 new file mode 100644 index 00000000000..0a8e900e45d --- /dev/null +++ b/packages/rocketchat-channel-settings/server/models/Messages.coffee @@ -0,0 +1,2 @@ +RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser = (type, roomId, message, user, extraData) -> + return @createWithTypeRoomIdMessageAndUser type, roomId, message, user, extraData diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index c4dae8c00a1..545dce131b8 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -62,4 +62,4 @@ currentTracker = undefined if ChatSubscription.findOne({rid: room._id})?.open is false Meteor.call 'openRoom', room._id - RocketChat.callbacks.run 'enter-room' + RocketChat.callbacks.run 'enter-room', ChatSubscription.findOne({rid: room._id}) -- GitLab From 01830674d633d4a5d960bd6f8c6b7dc380f6224c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 13 Nov 2015 14:12:13 -0200 Subject: [PATCH 0412/1338] added Git Flow and HISTORY.md --- HISTORY.md | 0 README.md | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 HISTORY.md diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/README.md b/README.md index 47e916bffbe..154dce49355 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,12 @@ A lot of work has already gone into Rocket.Chat, but we have much bigger plans f So if you'd like to be part of the project, please check out the [roadmap](https://github.com/RocketChat/Rocket.Chat/milestones) and [issues](https://github.com/RocketChat/Rocket.Chat/issues) to see if there's anything you can help with. +### Branching Model + +The [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branching-model/) section below is derived from Vincent Driessen at nvie. + +See also this [Git Workflows Comparison](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for more details. + ### Translations We are experimenting [Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard). -- GitLab From b9a969a5b561a2fee018a8d767f93bb886e907fb Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 13 Nov 2015 15:19:50 -0200 Subject: [PATCH 0413/1338] Fixed conflicts --- client/views/app/message.coffee | 6 ------ client/views/app/message.html | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index fc499b0c425..a2c3f0f7e0d 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -78,12 +78,6 @@ Template.message.helpers return true - oembed: -> - $body = $(Template.instance().body) - return null unless $body.is('a[href="'+this.url+'"]') or $body.has('a[href="'+this.url+'"]').is() - - Template.oembedBaseWidget - Template.message.onCreated -> msg = Template.currentData() diff --git a/client/views/app/message.html b/client/views/app/message.html index 0ab99b3fb52..18d776036fa 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -42,12 +42,11 @@ </div> {{/if}} </span> - <div class="body" dir="auto"> {{{body}}} {{#if hasOembed}} {{#each urls}} - {{> oembed}} + {{> oembedBaseWidget}} {{/each}} {{/if}} </div> -- GitLab From 645949e57422984902dafea08399ccde3541486b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Fri, 13 Nov 2015 18:17:51 +0000 Subject: [PATCH 0414/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 1 - i18n/de.i18n.json | 1 - i18n/el.i18n.json | 1 - i18n/en.i18n.json | 6 +- i18n/es.i18n.json | 1 - i18n/fi.i18n.json | 1 - i18n/fr.i18n.json | 1 - i18n/he.i18n.json | 1 - i18n/hr.i18n.json | 1 - i18n/hu.i18n.json | 1 - i18n/it.i18n.json | 1 - i18n/ja.i18n.json | 1 - i18n/km.i18n.json | 1 - i18n/ko.i18n.json | 1 - i18n/ms-MY.i18n.json | 1 - i18n/pl.i18n.json | 1 - i18n/pt.i18n.json | 1 - i18n/ru.i18n.json | 1 - i18n/sv.i18n.json | 235 ++++++++++++++++++ i18n/ta-IN.i18n.json | 1 - i18n/tr.i18n.json | 1 - i18n/ug.i18n.json | 1 - i18n/uk.i18n.json | 1 - i18n/zh.i18n.json | 1 - packages/rocketchat-chatops/i18n/sv.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + packages/rocketchat-gitlab/i18n/sv.i18n.json | 1 + packages/rocketchat-hubot/i18n/sv.i18n.json | 1 + packages/rocketchat-ldap/i18n/sv.i18n.json | 1 + .../rocketchat-livechat/i18n/sv.i18n.json | 1 + packages/rocketchat-mailer/i18n/ar.i18n.json | 1 + packages/rocketchat-mailer/i18n/de.i18n.json | 1 + packages/rocketchat-mailer/i18n/el.i18n.json | 1 + packages/rocketchat-mailer/i18n/en.i18n.json | 28 +-- packages/rocketchat-mailer/i18n/es.i18n.json | 1 + packages/rocketchat-mailer/i18n/fa.i18n.json | 1 + packages/rocketchat-mailer/i18n/fi.i18n.json | 1 + packages/rocketchat-mailer/i18n/fr.i18n.json | 1 + packages/rocketchat-mailer/i18n/he.i18n.json | 1 + packages/rocketchat-mailer/i18n/hr.i18n.json | 1 + packages/rocketchat-mailer/i18n/hu.i18n.json | 1 + packages/rocketchat-mailer/i18n/it.i18n.json | 1 + packages/rocketchat-mailer/i18n/ja.i18n.json | 1 + packages/rocketchat-mailer/i18n/km.i18n.json | 1 + packages/rocketchat-mailer/i18n/ko.i18n.json | 1 + .../rocketchat-mailer/i18n/ms-MY.i18n.json | 1 + packages/rocketchat-mailer/i18n/pl.i18n.json | 1 + packages/rocketchat-mailer/i18n/pt.i18n.json | 16 +- packages/rocketchat-mailer/i18n/ru.i18n.json | 1 + packages/rocketchat-mailer/i18n/sv.i18n.json | 1 + .../rocketchat-mailer/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-mailer/i18n/tr.i18n.json | 1 + packages/rocketchat-mailer/i18n/ug.i18n.json | 1 + packages/rocketchat-mailer/i18n/uk.i18n.json | 1 + packages/rocketchat-mailer/i18n/zh.i18n.json | 1 + .../rocketchat-message-pin/i18n/ar.i18n.json | 1 + .../rocketchat-message-pin/i18n/de.i18n.json | 1 + .../rocketchat-message-pin/i18n/el.i18n.json | 1 + .../rocketchat-message-pin/i18n/en.i18n.json | 9 +- .../rocketchat-message-pin/i18n/es.i18n.json | 1 + .../rocketchat-message-pin/i18n/fa.i18n.json | 1 + .../rocketchat-message-pin/i18n/fi.i18n.json | 1 + .../rocketchat-message-pin/i18n/fr.i18n.json | 1 + .../rocketchat-message-pin/i18n/he.i18n.json | 1 + .../rocketchat-message-pin/i18n/hr.i18n.json | 1 + .../rocketchat-message-pin/i18n/hu.i18n.json | 1 + .../rocketchat-message-pin/i18n/it.i18n.json | 1 + .../rocketchat-message-pin/i18n/ja.i18n.json | 1 + .../rocketchat-message-pin/i18n/km.i18n.json | 1 + .../rocketchat-message-pin/i18n/ko.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 1 + .../rocketchat-message-pin/i18n/pl.i18n.json | 1 + .../rocketchat-message-pin/i18n/pt.i18n.json | 1 + .../rocketchat-message-pin/i18n/ru.i18n.json | 1 + .../rocketchat-message-pin/i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../rocketchat-message-pin/i18n/tr.i18n.json | 1 + .../rocketchat-message-pin/i18n/ug.i18n.json | 1 + .../rocketchat-message-pin/i18n/uk.i18n.json | 1 + .../rocketchat-message-pin/i18n/zh.i18n.json | 1 + .../rocketchat-message-star/i18n/sv.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../rocketchat-webrtc-ib/i18n/sv.i18n.json | 5 + packages/rocketchat-webrtc/i18n/sv.i18n.json | 1 + .../rocketchat-wordpress/i18n/sv.i18n.json | 1 + 86 files changed, 327 insertions(+), 52 deletions(-) create mode 100644 i18n/sv.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/sv.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/sv.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/sv.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/sv.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/sv.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/sv.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ar.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/de.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/el.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/es.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/fa.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/fi.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/fr.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/he.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/hr.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/hu.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/it.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ja.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/km.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ko.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/pl.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ru.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/sv.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/tr.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ug.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/uk.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/zh.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ar.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/de.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/el.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/es.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/fa.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/fi.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/fr.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/he.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/hr.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/hu.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/it.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ja.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/km.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ko.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/pl.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/pt.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ru.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/sv.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/tr.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ug.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/uk.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/zh.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/sv.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/sv.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/sv.i18n.json create mode 100644 packages/rocketchat-webrtc-ib/i18n/sv.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/sv.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/sv.i18n.json diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index aeb03b4246f..861332c202f 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -1,7 +1,6 @@ { "and" : "Ùˆ", "Email_verified" : "البريد الإلكتروني التØقق", - "User_added" : "وأضا٠العضو <em>__user_added__</em>.", "User_joined_channel" : "وقد انضمت قناة.", "User_left" : "العضو <em>__user_left__</em>يقم." } \ No newline at end of file diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 80aef3352ec..e4307a71625 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -367,7 +367,6 @@ "Use_service_avatar" : "Benutze %s avatar", "Use_this_username" : "Benutzen Sie folgenden Benutzernamen", "Use_uploaded_avatar" : "Benutze diesen Avatar", - "User_added" : "Benutzer <em>__user_added__</em> wurde hinzugefügt.", "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", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index a83669140d7..d9495ff5276 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -251,7 +251,6 @@ "Use_service_avatar" : "ΧÏήση %s avatar", "Use_this_username" : "ΧÏήση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… username", "Use_uploaded_avatar" : "ΧÏηση ανεβασμÎνου avatar", - "User_added" : "Ο χÏήστης <em>__user_added__</em> Ï€ÏστÎθηκε.", "User_added_by" : "Ο χÏήστης <em>__user_added__</em> Ï€ÏστÎθηκε από τον <em>__user_by__</em>.", "User_has_been_activated" : "Ο χÏήστης Îχει ενεÏγοποιηθεί", "User_has_been_deactivated" : "Ο χÏήστης Îχει απενεÏγοποιηθεί", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3c39e0ccab8..e4b831f67d6 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -45,8 +45,8 @@ "Accounts_OAuth_Twitter_secret" : "Twitter Secret", "Accounts_RegistrationRequired" : "Registration Required", "Accounts_RequireNameForSignUp" : "Require name for signup", - "Accounts_Enrollment_Email": "Enrollment E-mail", - "Accounts_Enrollment_Email_Description": "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Accounts_Enrollment_Email" : "Enrollment E-mail", + "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", @@ -454,4 +454,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json index 7ccb803a6bb..d9c22cd7cfb 100644 --- a/i18n/es.i18n.json +++ b/i18n/es.i18n.json @@ -125,7 +125,6 @@ "Use_service_avatar" : "Usar %s avatar", "Use_this_username" : "Usar este nombre de usuario", "Use_uploaded_avatar" : "Utilizar avatar subido", - "User_added" : "Usuario <em>__user_added__</em> añadido.", "User_added_by" : "El usuario <em>__user_added__</em> ha sido añadido por <em>__user_by__</em>.", "User_joined_channel" : "Se ha unido al canal.", "User_left" : "Usuario <em>__user_left__</em> ha salido.", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 23f4567bc82..f72c176ffe4 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -410,7 +410,6 @@ "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_added" : "Käyttäjä <em>__user_added__</em> lisätty.", "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", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index d23e79c7535..a32780abcc8 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -351,7 +351,6 @@ "Use_service_avatar" : "Utiliser l'avatar %s", "Use_this_username" : "Utilisez ce nom d'utilisateur", "Use_uploaded_avatar" : "Utiliser l'avatar transmis", - "User_added" : "L'utilisateur <em>__user_added__</em> a été ajouté.", "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é", diff --git a/i18n/he.i18n.json b/i18n/he.i18n.json index 58742fb751b..c6f3ffa45c4 100644 --- a/i18n/he.i18n.json +++ b/i18n/he.i18n.json @@ -126,7 +126,6 @@ "Use_service_avatar" : "השתמש ב×וו×טר %s", "Use_this_username" : "השתמש ×‘×©× ×”×ž×©×ª×ž×© ×”×–×”", "Use_uploaded_avatar" : "השתמש ב×וו×טר שהועלה", - "User_added" : "המשתמש <em>__user_added__</em> × ×•×¡×£.", "User_added_by" : "המשתמש <em>__user_added__</em> × ×•×¡×£ על ידי <em>__user_by__</em>", "User_joined_channel" : "הצטרף לערוץ.", "User_left" : "המשתמש <em>__user_left__</em> עזב ×ת השיחה.", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 79eb1d0b99d..c881293a275 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -288,7 +288,6 @@ "Use_service_avatar" : "Koristi %s avatar", "Use_this_username" : "Koristi ovo korisniÄko ime", "Use_uploaded_avatar" : "Koristi uploadani avatar", - "User_added" : "Korisnik <em>__user_added__</em> je dodan.", "User_added_by" : "Korisnik <em>__user_added__</em> dodan od <em>__user_by__</em>.", "User_Channels" : "KorisniÄki kanali", "User_has_been_activated" : "Korisnik je aktiviran", diff --git a/i18n/hu.i18n.json b/i18n/hu.i18n.json index f9c03008434..fbc75e72ccf 100644 --- a/i18n/hu.i18n.json +++ b/i18n/hu.i18n.json @@ -108,7 +108,6 @@ "Use_service_avatar" : "%s használata", "Use_this_username" : "Használd ezt a felhasználónevet", "Use_uploaded_avatar" : "Feltöltött kép használata", - "User_added" : "<em>__user_added__</em> hozzáadva.", "User_added_by" : "<em>__user_added__</em> felhasználót hozzáadta <em>__user_by__</em>.", "User_left" : "<em>__user_left__</em> kilépett.", "User_logged_out" : "Nem elérhetÅ‘", diff --git a/i18n/it.i18n.json b/i18n/it.i18n.json index f11784d932a..672374e1b9d 100644 --- a/i18n/it.i18n.json +++ b/i18n/it.i18n.json @@ -109,7 +109,6 @@ "Use_service_avatar" : "Usa l'avatar %s", "Use_this_username" : "Usa questo nome di utente", "Use_uploaded_avatar" : "Usare l'avatar caricato", - "User_added" : "Utente <em>__user_added__</em> aggiunto.", "User_added_by" : "Utente <em>__user_added__</em> aggiunto da <em>__user_by__</em>.", "User_left" : "Utente <em>__user_left__</em> ha lasciato.", "User_logged_out" : "L'utente è disconnesso ", diff --git a/i18n/ja.i18n.json b/i18n/ja.i18n.json index 05714689485..318b963b6d9 100644 --- a/i18n/ja.i18n.json +++ b/i18n/ja.i18n.json @@ -135,7 +135,6 @@ "Use_service_avatar" : "%s ã®ã‚¢ãƒã‚¿ãƒ¼ã‚’使用", "Use_this_username" : "ユーザåを使用", "Use_uploaded_avatar" : "アップãƒãƒ¼ãƒ‰ã—ãŸã‚¢ãƒã‚¿ãƒ¼ã‚’使用", - "User_added" : "ユーザ <em>%s</em> è¿½åŠ ã—ã¾ã—ãŸã€‚", "User_added_by" : "ユーザ <em>__user_added__</em> ã‚’è¿½åŠ ã—ã¾ã—ãŸã€‚ by <em>__user_by__</em>.", "User_left" : "User <em>__user_left__</em> left.", "User_logged_out" : "ユーザã¯ãƒã‚°ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸ", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 58915330161..4bbd96dbedb 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -386,7 +386,6 @@ "Use_this_username" : "ប្រើ​ឈ្មោះ​នáŸáŸ‡", "Use_uploaded_avatar" : "ប្រើ​រូប​បាន​ផ្ទុក​ឡើង", "Use_url_for_avatar" : "ប្រើប្រាស់ URL សម្រាប់ Avatar", - "User_added" : "អ្នក​ប្រើ <em>__user_added__</em> បាន​បន្ážáŸ‚ម", "User_added_by" : "អ្នក​ប្រើ <em>__user_added__</em> បាន​ážáŸ‚ម​ដោយ <em>__user_by__</em>.", "User_Channels" : "ប៉ុស្ážáž·áŸáž¢áŸ’នកប្រើប្រាស់", "User_has_been_activated" : "អ្នក​ប្រើ​ដែល​បាន​ធ្វើ​ឱ្យ​សកម្ម", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index c8c1d47859f..f6e1c8fe9f8 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -338,7 +338,6 @@ "Use_service_avatar" : "아바타 %s 사용", "Use_this_username" : "ì´ ì‚¬ìš©ìž ì´ë¦„ 사용", "Use_uploaded_avatar" : "ì—…ë¡œë“œëœ ì•„ë°”íƒ€ 사용", - "User_added" : "ì‚¬ìš©ìž <em>__user_added__</em> 추가함.", "User_added_by" : "ì‚¬ìš©ìž <em>__user_added__</em>ì„/를 <em>__user_by__</em>ì— ì¶”ê°€í•¨.", "User_Channels" : "ì‚¬ìš©ìž ì±„ë„", "User_has_been_activated" : "사용ìžê°€ 활성화ë˜ì—ˆìŠµë‹ˆë‹¤", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index bc4dbc06a3d..cb00194771e 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -338,7 +338,6 @@ "Use_this_username" : "Guna nama pengguna ini", "Use_uploaded_avatar" : "Guna avatar yang dimuat naik", "Use_url_for_avatar" : "Guna url untuk avatar", - "User_added" : "Pengguna <em>__user_added__</em> ditambah.", "User_added_by" : "Pengguna <em>__user_added__</em> ditambah oleh <em>__user_by__</em>.", "User_Channels" : "Saluran Pengguna", "User_has_been_activated" : "Pengguna telah diaktifkan", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 70dfdf999fc..9c5ca9b4252 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -223,7 +223,6 @@ "Use_service_avatar" : "Użyj %s avatar", "Use_this_username" : "Użyj tej nazwy użytkownika", "Use_uploaded_avatar" : "Użyj dodany awatar", - "User_added" : "Użytkownik <em>__user_added__</em> dodany.", "User_added_by" : "Użytkownik <em>__user_added__</em>dodany przez <em>__user_by__</em>.", "User_has_been_activated" : "Użytkownik zostaÅ‚ aktywowany", "User_has_been_deactivated" : "Użytkownik zostaÅ‚ deaktywowany", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 3d8e5e26c51..69fd6340f1a 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -373,7 +373,6 @@ "Use_service_avatar" : "Use o avatar de %s", "Use_this_username" : "Usar este nome de usuário", "Use_uploaded_avatar" : "Use o avatar de upload", - "User_added" : "Usuário <em>__user_added__</em> adicionado à conversa.", "User_added_by" : "Usuário <em>__user_added__</em> adicionado à conversa por <em>__user_by__</em>.", "User_Channels" : "Canais do Usuário", "User_has_been_activated" : "Usuário foi ativado", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index f5d887b9157..c069e2dc5e4 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -229,7 +229,6 @@ "Use_service_avatar" : "ИÑпользовать %s аватар", "Use_this_username" : "ИÑпользовать Ñто Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ", "Use_uploaded_avatar" : "ИÑпользовать загруженную аватарку", - "User_added" : "Пользователь <em>__user_added__</em> добавлен.", "User_added_by" : "Пользователь <em>__user_added__</em> добавлен <em>__user_by__</em>.", "User_Channels" : "Чаты пользователÑ", "User_has_been_activated" : "Пользователь активирован", diff --git a/i18n/sv.i18n.json b/i18n/sv.i18n.json new file mode 100644 index 00000000000..561a0a5f033 --- /dev/null +++ b/i18n/sv.i18n.json @@ -0,0 +1,235 @@ +{ + "Access_online_demo" : "GÃ¥ till onlinedemo", + "Access_Online_Demo" : "GÃ¥ till onlinedemo", + "Accounts_denyUnverifiedEmail" : "Neka okontrollerade e-postadresser", + "Accounts_EmailVerification" : "E-postverifiering", + "Accounts_OAuth_Facebook" : "Facebook-inloggning", + "Accounts_OAuth_Facebook_id" : "Facebook App-ID", + "Accounts_OAuth_Facebook_secret" : "Facebook Secret", + "Accounts_OAuth_Github" : "OAuth Aktiverad", + "Accounts_OAuth_Github_id" : "Client-ID", + "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Google" : "Google-inloggning", + "Accounts_OAuth_Google_id" : "Google ID", + "Accounts_OAuth_Google_secret" : "Google Secret", + "Accounts_OAuth_Linkedin" : "LinkedIn-inloggning", + "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", + "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", + "Accounts_OAuth_Meteor" : "Meteor-inloggning", + "Accounts_OAuth_Meteor_id" : "Meteor-Id", + "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_OAuth_Twitter" : "Twitter-inloggning", + "Accounts_OAuth_Twitter_id" : "Twitter Id", + "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_RegistrationRequired" : "Registrering krävs", + "Add_Members" : "Lägg till medlemmar", + "Add_users" : "Lägg till användare", + "Administration" : "Administrering", + "All_channels" : "Alla kanaler", + "and" : "och", + "are_also_typing" : "skriver ocksÃ¥", + "are_typing" : "skriver", + "Are_you_sure" : "Är du säker?", + "Avatar_changed_successfully" : "Avataren har ändrats", + "away" : "borta", + "Away" : "Borta", + "away_female" : "borta", + "Away_female" : "Borta", + "away_male" : "borta", + "Away_male" : "Borta", + "Back_to_login" : "Tillbaka till inloggningen", + "bold" : "fetstil", + "busy" : "upptagen", + "Busy" : "Upptagen", + "busy_female" : "upptagen", + "Busy_female" : "Upptagen", + "busy_male" : "upptagen", + "Busy_male" : "Upptagen", + "Cancel" : "Avbryt", + "Change_avatar" : "Byt avatar", + "Channels" : "Kanaler", + "Channels_list" : "Lista över offentliga kanaler", + "Chat_Rooms" : "Chattrum", + "close" : "stäng", + "coming_soon" : "kommer snart", + "Confirm_password" : "Bekräfta ditt lösenord", + "Contact" : "Kontakta", + "Conversation" : "Samtal", + "Create_new" : "Skapa ny", + "Create_new_direct_message_room" : "Skapa ett nytt direktmeddelanderum", + "Create_new_private_group" : "Skapa en ny privat grupp", + "Create_new_public_channel" : "Skapa en ny offentlig kanal", + "Created_at" : "Skapad ", + "days" : "dagar", + "Deleted" : "Borttaget!", + "Direct_Messages" : "Direktmeddelanden", + "Drop_to_upload_file" : "Släpp för att ladda upp filen", + "Duplicate_channel_name" : "En kanal med namnet \\\"%s\\\" existerar redan", + "Duplicate_private_group_name" : "En privat grupp med namnet \\\"%s\\\" existerar redan", + "edited" : "redigerad", + "Email_already_exists" : "E-postadressen finns redan", + "Email_or_username" : "Epost eller användarnamn", + "Email_verified" : "E-post verifierad", + "Enter_info" : "Fyll i dina uppgifter", + "Error_changing_password" : "Fel vid ändring av lösenord", + "Favorites" : "Favoriter", + "Follow_social_profiles" : "Följ vÃ¥ra sociala mediakonton, forka oss pÃ¥ github och dela med dig av dina tankar om rocket.chatt pÃ¥ vÃ¥r trello.", + "Forgot_password" : "Glömt ditt lösenord", + "Fork_it_on_github" : "Forka det pÃ¥ github", + "Get_to_know_the_team" : "Lär känna teamet bakom Rocket.Chat", + "github_no_public_email" : "Du har inte nÃ¥gon publik epost i ditt GitHub-konto", + "Hide_room" : "Dölj rum", + "History" : "Historik", + "inline_code" : "inline_kod", + "Invalid_confirm_pass" : "Bekräftelsen matchar inte lösenordet", + "Invalid_email" : "Den angivna epostadressen är ogiltig", + "Invalid_name" : "Namnet fÃ¥r inte vara tomt", + "Invalid_pass" : "Lösenordet fÃ¥r inte vara tomt", + "Invalid_room_name" : "<strong>%s</strong> är inte ett giltigt rumsnamn,<br/> använd bara siffror, nummer och bindestreck", + "invisible" : "osynlig", + "Invisible" : "Osynlig", + "is_also_typing" : "skriver ocksÃ¥", + "is_also_typing_female" : "skriver ocksÃ¥", + "is_also_typing_male" : "skriver ocksÃ¥", + "is_typing" : "skriver", + "is_typing_female" : "skriver", + "is_typing_male" : "skriver", + "italics" : "kursiv", + "join" : "Anslut", + "Join_the_Community" : "GÃ¥ med i communityt", + "Language" : "SprÃ¥k", + "Language_Version" : "Engelsk version", + "Last_login" : "Senaste inloggning", + "Last_message" : "Senaste meddelande", + "Layout_Home_Body" : "Hem Body", + "Layout_Home_Title" : "Hem Titel", + "Leave_room" : "Lämna rum", + "Load_more" : "Ladda mer", + "Loading..." : "Laddar..", + "Loading_suggestion" : "Laddar förslag...", + "Login" : "Login", + "Login_with" : "Logga in med %s", + "login_with" : "Eller logga in direkt med", + "Logout" : "Logga Ut", + "Members" : "Medlemmar", + "Members_List" : "Medlemslista", + "Members_placeholder" : "Medlemmar", + "Message" : "Meddelande", + "Message_AllowDeleting" : "TillÃ¥t radering meddelanden", + "Message_AllowEditing" : "TillÃ¥t meddelanderedigering", + "Message_deleting_not_allowed" : "Borttagning av meddelanden inte tillÃ¥tet", + "Message_editing_not_allowed" : "Meddelanderedigering tillÃ¥ts inte", + "Message_KeepHistory" : "BehÃ¥ll meddelandehistorik", + "Message_removed" : "Meddelandet borttaget", + "Message_ShowDeletedStatus" : "Visa borttagenstatus", + "Message_ShowEditedStatus" : "Visa Redigeradstatus", + "Meta_fb_app_id" : "Facebook App-ID", + "Meta_google-site-verification" : "Google Site Verification", + "Meta_language" : "SprÃ¥k", + "Meta_msvalidate01" : "MSValidate.01", + "Meta_robots" : "Robots", + "More_channels" : "Fler kanaler", + "My_Account" : "Mitt Konto", + "n_messages" : "%s meddelanden", + "Name" : "Namn", + "New_messages" : "Nya meddelanden", + "New_password" : "Nytt lösenord", + "No_channels_yet" : "Du är inte en del av nÃ¥gon kanal ännu.", + "No_direct_messages_yet" : "Du har inte startat nÃ¥gra samtal än.", + "No_favorites_yet" : "Du har inte lagt till nÃ¥gra favoriter än.", + "No_groups_yet" : "Du har inga privata grupper än.", + "No_permission_to_view_room" : "Du har inte behörighet att visa detta rum", + "Not_allowed" : "Inte tillÃ¥ten", + "Not_found_or_not_allowed" : "Inte hittad eller inte tillÃ¥ten", + "Nothing_found" : "Inget hittat", + "Notify_all_in_this_room" : "Meddela alla i det här rummet", + "Online" : "Online", + "Oops!" : "Oj", + "others" : "andra", + "Password" : "Lösenord", + "Password_changed_successfully" : "Lösenord ändrat", + "Please_wait" : "Vänligen vänta", + "Powered_by" : "Drivs av", + "Privacy" : "Integritet", + "Private_Groups" : "Privata Grupper", + "Profile" : "Profil", + "Profile_saved_successfully" : "Profil sparad", + "Proudly_developed" : "Stolt utvecklad med Meteor", + "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" : "Debug", + "Quick_Search" : "Snabbsökning", + "quote" : "citat", + "Register" : "Registrera ett nytt konto", + "Remember_me" : "Kom ihÃ¥g mig", + "Remove" : "Ta bort", + "Reset_password" : "Ã…terställ lösenord", + "Room" : "Rum", + "Room_name_changed" : "Rummets namn ändrat till : <em>__room_name__</em> av <em>__user_by__</em>", + "Room_name_changed_successfully" : "Rummets namn har ändrats ", + "room_user_count" : "%s användare", + "Save" : "Spara", + "Save_changes" : "Spara ändringar", + "Search" : "Sök", + "Search_settings" : "Sökinställningar", + "See_all" : "Visa alla", + "See_only_online" : "Bara online", + "Select_an_avatar" : "Välj en avatar", + "Select_file" : "Välj fil", + "Select_service_to_login" : "Välj en tjänst för att logga in för att välja din bild, eller ladda upp en direkt frÃ¥n din dator", + "Selected_users" : "Utvalda medlemmar", + "Send_confirmation_email" : "Skicka e-postbekräftelse", + "Send_Message" : "Skicka meddelande", + "Settings" : "Inställningar", + "Settings_updated" : "Inställningar uppdaterade", + "Showing_online_users" : "Visar <b>__total_online__</b> av __total__ users", + "Showing_results" : "<p>Visar <b>%s</b> resultat</p>", + "Silence" : "Tystnad", + "since_creation" : "sedan %s", + "SMTP_Host" : "SMTP-Host", + "SMTP_Password" : "SMTP lösenord", + "SMTP_Port" : "SMTP Port", + "SMTP_Username" : "SMTP Användarnamn", + "Start_of_conversation" : "Början av samtalet", + "Submit" : "Skicka", + "The_field_is_required" : "Fältet %s krävs.", + "Upload_file_question" : "Ladda upp fil?", + "Use_initials_avatar" : "Använd ditt användarnamns initialer", + "use_menu" : "Använd sidomenyn för att fÃ¥ tillgÃ¥ng till dina rum och chattar", + "Use_service_avatar" : "Använd %s avatar", + "Use_this_username" : "Använd det här användarnamnet", + "Use_uploaded_avatar" : "Använd uppladdad avatar", + "User_added_by" : "Användaren <em>__user_added__</em> tillagd av <em>__user_by__</em>.", + "User_has_been_activated" : "Användaren har aktiverats", + "User_has_been_deactivated" : "Användaren har deaktiverats", + "User_joined_channel" : "Har anslutit sig till kanalen.", + "User_joined_channel_female" : "Har anslutit sig till kanalen.", + "User_joined_channel_male" : "Har anslutit sig till kanalen.", + "User_left" : "Har lämnat kanalen.", + "User_left_female" : "Har lämnat kanalen.", + "User_left_male" : "Har lämnat kanalen.", + "User_logged_out" : "Användaren är utloggad", + "User_removed_by" : "Användaren <em>__user_removed__</em> avlägsnad av <em>__user_by__</em>.", + "User_Settings" : "Användarinställningar", + "Username" : "Användarnamn", + "Username_cant_be_empty" : "Användarnamnet kan inte vara tomt", + "Username_description" : "Användarnamnet används för att lÃ¥ta andra nämna dig i meddelanden.", + "Username_invalid" : "<strong>%s</strong> är inte ett giltigt användarnamn,<br/> använd bara bokstäver, siffror, punkter och bindestreck", + "Username_title" : "Registrera användarnamn", + "Username_unavaliable" : "<strong>%s</strong> används redan :(", + "View_All" : "Visa alla", + "We_have_sent_password_email" : "Vi har skickat ett mail med instruktioner för Ã¥terställande av lösenord. Om du inte fÃ¥r ett mail inom kort, kom tillbaka och försök igen.", + "We_have_sent_registration_email" : "Vi har skickat ett mail för att bekräfta din registrering. Om du inte fÃ¥r ett mail inom kort, kom tillbaka och försök igen.", + "Welcome" : "Välkommen <em>%s</em>.", + "With_whom" : "Med vem", + "Yes_delete_it" : "Ja, ta bort det!", + "you_are_in_preview_mode_of" : "Du befinner dig i förhandsgranskningsläge i kanalen #<strong>__room_name__</strong>", + "You_need_confirm_email" : "Du mÃ¥ste bekräfta din e-postadress för att logga in!", + "You_will_not_be_able_to_recover" : "Du kommer inte att kunna Ã¥terskapa detta meddelande!", + "Your_entry_has_been_deleted" : "Ditt meddelande har tagits bort.", + "Your_Open_Source_solution" : "Din egen Open Source-chatlösning" +} \ No newline at end of file diff --git a/i18n/ta-IN.i18n.json b/i18n/ta-IN.i18n.json index 88d38369c66..473329c3c2b 100644 --- a/i18n/ta-IN.i18n.json +++ b/i18n/ta-IN.i18n.json @@ -87,7 +87,6 @@ "Submit" : "சமரà¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯", "Use_initials_avatar" : "உஙà¯à®•à®³à¯ பயனர௠பெயர௠மà¯à®¤à®²à¯†à®´à¯à®¤à¯à®¤à¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯", "Use_this_username" : "இநà¯à®¤ பயனர௠பெயரை பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯", - "User_added" : "பயனர௠<em>__user_added__</em>சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®°à¯.", "User_added_by" : "பயனர௠<em>__user_added__</em><em>__user_by__</em>மூலம௠சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®°à¯.", "User_left" : "பயனர௠<em>__user_left__</em>செனà¯à®±à¯à®µà®¿à®Ÿà¯à®Ÿà®¾à®°à¯.", "User_removed_by" : "பயனர௠<em>__user_removed__</em><em>__user_by__</em>மூலம௠அகறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®°à¯.", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index f4e2cccd903..8c154fde9d4 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -234,7 +234,6 @@ "Use_service_avatar" : "%s Avatar olarak kullan", "Use_this_username" : "Bu kullanıcı adını kullan", "Use_uploaded_avatar" : "Yüklenen avatarı kullanın", - "User_added" : "<em>__user_added__</em> eklendi.", "User_added_by" : "<em>__user_added__</em>,  <em>__user_by__</em> tarafından eklendi.", "User_has_been_activated" : "Kullanıcı aktif edildi", "User_has_been_deactivated" : "Kullanıcı devre dışı bırakıldı", diff --git a/i18n/ug.i18n.json b/i18n/ug.i18n.json index c370f792337..893c8ddb903 100644 --- a/i18n/ug.i18n.json +++ b/i18n/ug.i18n.json @@ -121,7 +121,6 @@ "Use_service_avatar" : "%s باش رەسىمنى ئىشلىتىش", "Use_this_username" : "بۇ ئىسىمنى ئىشلىتىÚ", "Use_uploaded_avatar" : "يۈكلەنگەن باش رەسىمنى ئىشلىتىش", - "User_added" : "<em>__user_added__</em> ئەزا قوشۇلدى.", "User_added_by" : " <em>__user_by__</em> ÙŠÛÚىدىن <em>__user_added__</em> دÛÚ¯Û•Ù† ئەزانى قوشتى.", "User_joined_channel" : "قانالغا قوشۇلدى.", "User_left" : "<em>__user_left__</em> پاراÚخانىدىن Ú†Ûكىندى.", diff --git a/i18n/uk.i18n.json b/i18n/uk.i18n.json index 5947d6aad39..47ccaa042ed 100644 --- a/i18n/uk.i18n.json +++ b/i18n/uk.i18n.json @@ -109,7 +109,6 @@ "Use_service_avatar" : "ВикориÑтовуйте% Ðватар", "Use_this_username" : "ВикориÑтовувати це ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача ", "Use_uploaded_avatar" : "ВикориÑтовувати завантажений аватар", - "User_added" : "КориÑтувач <em>__user_added__</em> доданий.", "User_added_by" : "КориÑтувач <em>__user_added__</em> даданий <em>__user_by__</em>.", "User_left" : "КориÑтучач <em>__user_left__</em> вийшов.", "User_logged_out" : "КориÑтувач вийшов з ÑиÑтеми", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index 10060566f7a..f8091f5d049 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -279,7 +279,6 @@ "Use_service_avatar" : "使用 %s 头åƒ", "Use_this_username" : "使用æ¤ç”¨æˆ·å", "Use_uploaded_avatar" : "ä½¿ç”¨ä¸Šä¼ å¤´åƒ", - "User_added" : "å·²æ·»åŠ ç”¨æˆ· <em>__user_added__</em> 。", "User_added_by" : " <em>__user_by__</em> æ·»åŠ äº† <em>__user_added__</em> 。", "User_Channels" : "用户频é“", "User_has_been_activated" : "用户已ç»æ¿€æ´»", diff --git a/packages/rocketchat-chatops/i18n/sv.i18n.json b/packages/rocketchat-chatops/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/sv.i18n.json b/packages/rocketchat-github-enterprise/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/sv.i18n.json b/packages/rocketchat-gitlab/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/sv.i18n.json b/packages/rocketchat-hubot/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/sv.i18n.json b/packages/rocketchat-ldap/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/sv.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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ar.i18n.json b/packages/rocketchat-mailer/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/de.i18n.json b/packages/rocketchat-mailer/i18n/de.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/el.i18n.json b/packages/rocketchat-mailer/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index 4d969327fd3..bbde6b8b807 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -1,15 +1,15 @@ { - "From_email_warning": "<b>Warning</b>: The field <b>From</b> is subject to your mail server settings.", - "From_email_is_required": "From e-mail is required", - "Email_from": "From", - "Email_subject": "Subject", - "Email_body": "E-mail body", - "Rocket_Mailer": "Rocket Mailer", - "RocketMailer_body_tags": "You <b>must</b> use [unsubscribe] for the unsubscription link.<br />You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", - "Send_email": "Send E-mail", - "The_emails_are_being_sent": "The e-mails are being sent.", - "You_are_not_authorized_to_view_this_page": "You are not authorized to view this page.", - "You_have_successfully_unsubscribed": "You have successfully unsubscribed from our Mailling List.", - "You_informed_an_invalid_FROM_address": "You informed an invalid FROM address.", - "You_must_provide_the_unsubscribe_link": "You must provide the [unsubscribe] link." -} + "From_email_warning" : "<b>Warning</b>: The field <b>From</b> is subject to your mail server settings.", + "From_email_is_required" : "From e-mail is required", + "Email_from" : "From", + "Email_subject" : "Subject", + "Email_body" : "E-mail body", + "Rocket_Mailer" : "Rocket Mailer", + "RocketMailer_body_tags" : "You <b>must</b> use [unsubscribe] for the unsubscription link.<br />You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Send_email" : "Send E-mail", + "The_emails_are_being_sent" : "The e-mails are being sent.", + "You_are_not_authorized_to_view_this_page" : "You are not authorized to view this page.", + "You_have_successfully_unsubscribed" : "You have successfully unsubscribed from our Mailling List.", + "You_informed_an_invalid_FROM_address" : "You informed an invalid FROM address.", + "You_must_provide_the_unsubscribe_link" : "You must provide the [unsubscribe] link." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/es.i18n.json b/packages/rocketchat-mailer/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/fa.i18n.json b/packages/rocketchat-mailer/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/fi.i18n.json b/packages/rocketchat-mailer/i18n/fi.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/fr.i18n.json b/packages/rocketchat-mailer/i18n/fr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/he.i18n.json b/packages/rocketchat-mailer/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/hr.i18n.json b/packages/rocketchat-mailer/i18n/hr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/hu.i18n.json b/packages/rocketchat-mailer/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/it.i18n.json b/packages/rocketchat-mailer/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ja.i18n.json b/packages/rocketchat-mailer/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/km.i18n.json b/packages/rocketchat-mailer/i18n/km.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ko.i18n.json b/packages/rocketchat-mailer/i18n/ko.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ms-MY.i18n.json b/packages/rocketchat-mailer/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/pl.i18n.json b/packages/rocketchat-mailer/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/pt.i18n.json b/packages/rocketchat-mailer/i18n/pt.i18n.json index 560bfbe200a..cff0ad90bed 100644 --- a/packages/rocketchat-mailer/i18n/pt.i18n.json +++ b/packages/rocketchat-mailer/i18n/pt.i18n.json @@ -1,9 +1,9 @@ { - "Email_from": "De", - "Email_subject": "Assunto", - "Email_body": "Corpo do E-mail", - "Rocket_Mailer": "Rocket Mailer", - "Send_email": "Enviar E-mail", - "You_are_not_authorized_to_view_this_page": "Você não possui permissão para visualizar esta página.", - "You_have_successfully_unsubscribed": "A partir de agora você não está mais cadastrado em nossa lista de e-mails." -} + "Email_from" : "De", + "Email_subject" : "Assunto", + "Email_body" : "Corpo do E-mail", + "Rocket_Mailer" : "Rocket Mailer", + "Send_email" : "Enviar E-mail", + "You_are_not_authorized_to_view_this_page" : "Você não possui permissão para visualizar esta página.", + "You_have_successfully_unsubscribed" : "A partir de agora você não está mais cadastrado em nossa lista de e-mails." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ru.i18n.json b/packages/rocketchat-mailer/i18n/ru.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/sv.i18n.json b/packages/rocketchat-mailer/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ta-IN.i18n.json b/packages/rocketchat-mailer/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/tr.i18n.json b/packages/rocketchat-mailer/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ug.i18n.json b/packages/rocketchat-mailer/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/uk.i18n.json b/packages/rocketchat-mailer/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/zh.i18n.json b/packages/rocketchat-mailer/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ar.i18n.json b/packages/rocketchat-message-pin/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/el.i18n.json b/packages/rocketchat-message-pin/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/en.i18n.json b/packages/rocketchat-message-pin/i18n/en.i18n.json index 4568852052a..8ae61d2f419 100644 --- a/packages/rocketchat-message-pin/i18n/en.i18n.json +++ b/packages/rocketchat-message-pin/i18n/en.i18n.json @@ -1,10 +1,9 @@ { - "Message_AllowPinning" : "Allow Message Pinning", - "Message_AllowPinning_Description": "Allow messages to be pinned to any of the channels.", - "Message_AllowPinningByAnyone": "Allow Anyone to Pin Messages", - "Message_AllowPinningByAnyone_Description": "If true, anyone will be able to pin a messages in any channels but if false then only channel owners and admins will be allowed to.", + "Message_AllowPinning_Description" : "Allow messages to be pinned to any of the channels.", + "Message_AllowPinningByAnyone" : "Allow Anyone to Pin Messages", + "Message_AllowPinningByAnyone_Description" : "If true, anyone will be able to pin a messages in any channels but if false then only channel owners and admins will be allowed to.", "Pin_Message" : "Pin Message", "Unpin_Message" : "Unpin Message", "Pinned_Messages" : "Pinned Messages", "No_pinned_messages" : "No pinned messages" -} +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/es.i18n.json b/packages/rocketchat-message-pin/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/fa.i18n.json b/packages/rocketchat-message-pin/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/fi.i18n.json b/packages/rocketchat-message-pin/i18n/fi.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/hr.i18n.json b/packages/rocketchat-message-pin/i18n/hr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/hu.i18n.json b/packages/rocketchat-message-pin/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/it.i18n.json b/packages/rocketchat-message-pin/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ja.i18n.json b/packages/rocketchat-message-pin/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ms-MY.i18n.json b/packages/rocketchat-message-pin/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/pl.i18n.json b/packages/rocketchat-message-pin/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/pt.i18n.json b/packages/rocketchat-message-pin/i18n/pt.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/sv.i18n.json b/packages/rocketchat-message-pin/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ta-IN.i18n.json b/packages/rocketchat-message-pin/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/tr.i18n.json b/packages/rocketchat-message-pin/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ug.i18n.json b/packages/rocketchat-message-pin/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/uk.i18n.json b/packages/rocketchat-message-pin/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/zh.i18n.json b/packages/rocketchat-message-pin/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/sv.i18n.json b/packages/rocketchat-message-star/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/sv.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/sv.i18n.json b/packages/rocketchat-slashcommands-join/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/sv.i18n.json b/packages/rocketchat-webrtc-ib/i18n/sv.i18n.json new file mode 100644 index 00000000000..cd7a07141b6 --- /dev/null +++ b/packages/rocketchat-webrtc-ib/i18n/sv.i18n.json @@ -0,0 +1,5 @@ +{ + "Video_Chat" : "Videochatt", + "Setup" : "Inställningar", + "Stop_Video" : "Stoppa video" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/sv.i18n.json b/packages/rocketchat-webrtc/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/sv.i18n.json b/packages/rocketchat-wordpress/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file -- GitLab From fd17d28b83d63b70418d53e984bf5f791c09e4fe Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 13 Nov 2015 16:27:17 -0200 Subject: [PATCH 0415/1338] added develop branch to the .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f0ef0c8b968..2e6d898173b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: node_js branches: only: - master + - develop node_js: - '0.10' addons: -- GitLab From c46c70cf333be5cfd6ce18f19eb000b76a078bb5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 13 Nov 2015 16:34:28 -0200 Subject: [PATCH 0416/1338] Updated README.md Added liminality.xyz post link --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 154dce49355..90d8b845908 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ It is a great solution for communities and companies wanting to privately host t ##### [snowulf.com](https://snowulf.com/2015/09/25/why-slack-when-you-can-rocket-chat/) > Why Slack when you can Rocket.chat? +##### [liminality.xyz](http://liminality.xyz/self-hosting/) +> SELF-HOSTED ALTERNATIVES TO POPULAR CLOUD SERVICES + + ## Features - BYOS (bring your own server) -- GitLab From a2b41bca5bfa202362e854aac936dadeb6220658 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 13 Nov 2015 17:19:10 -0200 Subject: [PATCH 0417/1338] new roomTypes API --- client/startup/defaultRoomTypes.coffee | 80 +++++++++-- client/views/app/roomSearch.coffee | 5 +- client/views/app/sideNav/chatRoomItem.coffee | 2 +- client/views/app/sideNav/sideNav.coffee | 4 +- client/views/app/spotlight/spotlight.coffee | 7 +- packages/rocketchat-lib/lib/roomTypes.coffee | 124 +++++++++++------- packages/rocketchat-livechat/client/ui.js | 19 ++- .../rocketchat-livechat/server/startup.js | 4 +- server/publications/room.coffee | 2 +- server/publications/roomSearch.coffee | 2 +- server/startup/roomPublishes.coffee | 8 +- 11 files changed, 175 insertions(+), 82 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 0bba73ffdef..0e893d51a38 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,19 +1,73 @@ Meteor.startup -> roles = ['admin', 'moderator', 'user'] - RocketChat.roomTypes.addType('starredRooms', roles); - RocketChat.roomTypes.addType('channels', roles); - RocketChat.roomTypes.addType('directMessages', roles); - RocketChat.roomTypes.addType('privateGroups', roles); - RocketChat.roomTypes.setIcon('c', 'icon-hash'); - RocketChat.roomTypes.setIcon('d', 'icon-at'); - RocketChat.roomTypes.setIcon('p', 'icon-lock'); + RocketChat.roomTypes.add 'c', + template: 'channels' + icon: 'icon-hash' + route: + name: 'channel' + path: '/channel/:name' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'c', params.name + link: (sub) -> + return { name: sub.name } + permissions: [ 'view-channel' ] - RocketChat.roomTypes.setRoute 'c', 'channel', (sub) -> - return { name: sub.name } + RocketChat.roomTypes.add 'd', + template: 'directMessages' + icon: 'icon-at' + route: + name: 'direct' + path: '/direct/:username' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'd', params.name + link: (sub) -> + return { username: sub.name } + permissions: [ 'view-direct' ] - RocketChat.roomTypes.setRoute 'd', 'direct', (sub) -> - return { username: sub.name } + RocketChat.roomTypes.add 'p', + template: 'privateGroups' + icon: 'icon-lock' + route: + name: 'group' + path: '/group/:name' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'p', params.name + link: (sub) -> + return { name: sub.name } + permissions: [ 'view-group' ] - RocketChat.roomTypes.setRoute 'p', 'group', (sub) -> - return { name: sub.name } + # RocketChat.roomTypes.addPublish 'c', (identifier) -> + # publish: (identifier) -> + # options = + # fields: + # name: 1 + # t: 1 + # cl: 1 + # u: 1 + # usernames: 1 + # return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options + + + + + # RocketChat.roomTypes.addType('starredRooms', roles); + # RocketChat.roomTypes.addType('channels', roles); + # RocketChat.roomTypes.addType('directMessages', roles); + # RocketChat.roomTypes.addType('privateGroups', roles); + + # RocketChat.roomTypes.setIcon('c', 'icon-hash'); + # RocketChat.roomTypes.setIcon('d', 'icon-at'); + # RocketChat.roomTypes.setIcon('p', 'icon-lock'); + + # RocketChat.roomTypes.setRoute 'c', 'channel', (sub) -> + # return { name: sub.name } + + # RocketChat.roomTypes.setRoute 'd', 'direct', (sub) -> + # return { username: sub.name } + + # RocketChat.roomTypes.setRoute 'p', 'group', (sub) -> + # return { name: sub.name } diff --git a/client/views/app/roomSearch.coffee b/client/views/app/roomSearch.coffee index 25a18fe420b..5e880050085 100644 --- a/client/views/app/roomSearch.coffee +++ b/client/views/app/roomSearch.coffee @@ -3,10 +3,7 @@ Template.roomSearch.helpers return 'icon-at' if this.type is 'u' if this.type is 'r' - switch this.t - when 'd' then return 'icon-at' - when 'c' then return 'icon-hash' - when 'p' then return 'icon-lock' + return RocketChat.roomTypes.getIcon this.t userStatus: -> if this.type is 'u' diff --git a/client/views/app/sideNav/chatRoomItem.coffee b/client/views/app/sideNav/chatRoomItem.coffee index c1482357b98..12767b5eabd 100644 --- a/client/views/app/sideNav/chatRoomItem.coffee +++ b/client/views/app/sideNav/chatRoomItem.coffee @@ -33,7 +33,7 @@ Template.chatRoomItem.helpers return true route: -> - FlowRouter.path RocketChat.roomTypes.getRoute @t, @ + FlowRouter.path RocketChat.roomTypes.getRouteLink @t, @ Template.chatRoomItem.rendered = -> if not (FlowRouter.getParam('_id')? and FlowRouter.getParam('_id') is this.data.rid) and not this.data.ls diff --git a/client/views/app/sideNav/sideNav.coffee b/client/views/app/sideNav/sideNav.coffee index 49a02a7f80a..faef155e33d 100644 --- a/client/views/app/sideNav/sideNav.coffee +++ b/client/views/app/sideNav/sideNav.coffee @@ -95,6 +95,8 @@ Template.sideNav.onRendered -> wrapper = $('.rooms-list .wrapper').get(0) lastLink = $('.rooms-list h3').get(0) + # @TODO validate role/permission inside roomTypes object RocketChat.roomTypes.getTypes().forEach (roomType) -> - if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? + if Template[roomType.template]? + # if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? Blaze.render Template[roomType.template], wrapper, lastLink diff --git a/client/views/app/spotlight/spotlight.coffee b/client/views/app/spotlight/spotlight.coffee index db4bbfc98b6..65d35227162 100644 --- a/client/views/app/spotlight/spotlight.coffee +++ b/client/views/app/spotlight/spotlight.coffee @@ -36,11 +36,8 @@ Template.spotlight.events FlowRouter.go('direct', { username: doc.username }) event.currentTarget.value = '' else if doc.type is 'r' - if doc.t is 'c' - FlowRouter.go('channel', { name: doc.name }) - else if doc.t is 'p' - FlowRouter.go('group', { name: doc.name }) + FlowRouter.go FlowRouter.path RocketChat.roomTypes.getRouteLink doc.t, doc event.currentTarget.value = '' - spotlight.hide() \ No newline at end of file + spotlight.hide() diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index 891ec9d27ea..bb0392be8dc 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -1,82 +1,114 @@ RocketChat.roomTypes = new class - rooms = [] - routes = {} - publishes = {} - icons = {} - - ### Sets a route for a room type - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param routeName: route's name for given type - @param dataCallback: callback for the route data. receives the whole subscription data as parameter + # rooms = [] + # routes = {} + # publishes = {} + # icons = {} + + roomTypesOrder = [] + roomTypes = {} + + ### Adds a room type to app + @param identifier MUST BE equals to `db.rocketchat_room.t` field + @param config + template: template name to render on sideNav + permission: list of permissions to see the sideNav template + icon: icon class + route: + name: route name + action: route action function ### - setRoute = (roomType, routeName, dataCallback) -> - if routes[roomType]? - throw new Meteor.Error 'route-callback-exists', 'Route callback for the given type already exists' + add = (identifier, config) -> + if roomTypes[identifier]? + throw new Meteor.Error 'identifier-already-set', t('Room_type_identifier_already_set') + + # @TODO validate config options + roomTypesOrder.push identifier + roomTypes[identifier] = config - # dataCallback ?= -> return {} + # ### Sets a route for a room type + # @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + # @param routeName: route's name for given type + # @param dataCallback: callback for the route data. receives the whole subscription data as parameter + # ### + # setRoute = (roomType, routeName, dataCallback) -> + # if routes[roomType]? + # throw new Meteor.Error 'route-callback-exists', 'Route callback for the given type already exists' - routes[roomType] = - name: routeName - data: dataCallback or -> return {} + # # dataCallback ?= -> return {} + + # routes[roomType] = + # name: routeName + # data: dataCallback or -> return {} ### @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param subData: the user's subscription data ### - getRoute = (roomType, subData) -> - unless routes[roomType]? + getRouteLink = (roomType, subData) -> + unless roomTypes[roomType]? throw new Meteor.Error 'route-doesnt-exists', 'There is no route for the type: ' + roomType - return FlowRouter.path routes[roomType].name, routes[roomType].data(subData) + return FlowRouter.path roomTypes[roomType].route.name, roomTypes[roomType].route.link(subData) - ### add a type of room - @param template: the name of the template to render on sideNav - @param roles[]: a list of roles a user must have to see the template - ### - addType = (template, roles = []) -> - rooms.push - template: template - roles: [].concat roles + # ### add a type of room + # @param template: the name of the template to render on sideNav + # @param roles[]: a list of roles a user must have to see the template + # ### + # addType = (template, roles = []) -> + # rooms.push + # template: template + # roles: [].concat roles getAllTypes = -> - return rooms + return _.map roomTypesOrder, (type) -> return roomTypes[type] ### add a publish for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param callback: function that will return the publish's data ### - addPublish = (roomType, callback) -> - if publishes[roomType]? + setPublish = (roomType, callback) -> + if roomTypes[roomType]?.publish? throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' - publishes[roomType] = callback + unless roomTypes[roomType]? + roomTypesOrder.push roomType + roomTypes[roomType] = {} + + roomTypes[roomType].publish = callback ### run the publish for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param identifier: identifier of the room ### runPublish = (roomType, identifier) -> - return unless publishes[roomType]? - return publishes[roomType].call this, identifier + return unless roomTypes[roomType].publish? + return roomTypes[roomType].publish.call this, identifier getIcon = (roomType) -> - return icons[roomType] + return roomTypes[roomType]?.icon - ### - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param iconClass: iconClass to display on sideNav - ### - setIcon = (roomType, iconClass) -> - icons[roomType] = iconClass + # ### + # @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + # @param iconClass: iconClass to display on sideNav + # ### + # setIcon = (roomType, iconClass) -> + # icons[roomType] = iconClass - addType: addType + getIdentifiers = (except) -> + except = [].concat except + return _.reject roomTypesOrder, (t) -> return except.indexOf(t) isnt -1 + + # addType: addType getTypes: getAllTypes + getIdentifiers: getIdentifiers - setIcon: setIcon + # setIcon: setIcon getIcon: getIcon - setRoute: setRoute - getRoute: getRoute + # setRoute: setRoute + getRouteLink: getRouteLink + + setPublish: setPublish + runPublish: runPublish - addPublish: addPublish - publish: runPublish + add: add diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index 78c60da223b..72230a468d8 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -1,8 +1,19 @@ Meteor.startup(function() { - RocketChat.roomTypes.addType('livechat', ['livechat-agent', 'livechat-manager']); - RocketChat.roomTypes.setIcon('l', 'icon-chat-empty'); - RocketChat.roomTypes.setRoute('l', 'live', function(sub) { - return { name: sub.name }; + RocketChat.roomTypes.add('l', { + template: 'livechat', + icon: 'icon-chat-empty', + route: { + name: 'live', + path: '/live/:name', + action: (params, queryParams) => { + Session.set('showUserInfo'); + openRoom('l', params.name); + }, + link: (sub) => { + return { name: sub.name } + } + }, + permissions: [ 'view-livechat' ] }); AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); diff --git a/packages/rocketchat-livechat/server/startup.js b/packages/rocketchat-livechat/server/startup.js index f9beb312b1c..90644834099 100644 --- a/packages/rocketchat-livechat/server/startup.js +++ b/packages/rocketchat-livechat/server/startup.js @@ -1,5 +1,5 @@ -Meteor.startup(function() { - RocketChat.roomTypes.addPublish('l', function(identifier) { +Meteor.startup(() => { + RocketChat.roomTypes.setPublish('l', (identifier) => { return RocketChat.models.Rooms.findByTypeAndName('l', identifier, { fields: { name: 1, diff --git a/server/publications/room.coffee b/server/publications/room.coffee index ef32aecaf2a..960f1c40de9 100644 --- a/server/publications/room.coffee +++ b/server/publications/room.coffee @@ -10,4 +10,4 @@ Meteor.publish 'room', (typeName) -> type = typeName.substr(0, 1) name = typeName.substr(1) - return RocketChat.roomTypes.publish.call(this, type, name) + return RocketChat.roomTypes.runPublish.call(this, type, name) diff --git a/server/publications/roomSearch.coffee b/server/publications/roomSearch.coffee index e5d9a2ae375..c499c1a89f7 100644 --- a/server/publications/roomSearch.coffee +++ b/server/publications/roomSearch.coffee @@ -24,7 +24,7 @@ Meteor.publish 'roomSearch', (selector, options, collName) -> self.removed("autocompleteRecords", id) if not searchType? or searchType is 'r' - subHandleRooms = RocketChat.models.Rooms.findByTypesAndNotUserIdContainingUsername(['c', 'p'], selector.uid?.$ne, RocketChat.models.Users.findOneById(this.userId).username, { limit: 10, fields: { t: 1, name: 1 } }).observeChanges + subHandleRooms = RocketChat.models.Rooms.findByTypesAndNotUserIdContainingUsername(RocketChat.roomTypes.getIdentifiers('d'), selector.uid?.$ne, RocketChat.models.Users.findOneById(this.userId).username, { limit: 10, fields: { t: 1, name: 1 } }).observeChanges added: (id, fields) -> data = { type: 'r', rid: id, name: fields.name, t: fields.t } self.added("autocompleteRecords", id, data) diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index ae5cdd0225f..409131cc9b4 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -1,5 +1,5 @@ Meteor.startup -> - RocketChat.roomTypes.addPublish 'c', (identifier) -> + RocketChat.roomTypes.setPublish 'c', (identifier) -> options = fields: name: 1 @@ -9,7 +9,7 @@ Meteor.startup -> usernames: 1 return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options - RocketChat.roomTypes.addPublish 'p', (identifier) -> + RocketChat.roomTypes.setPublish 'p', (identifier) -> options = fields: name: 1 @@ -20,7 +20,7 @@ Meteor.startup -> user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options - RocketChat.roomTypes.addPublish 'd', (identifier) -> + RocketChat.roomTypes.setPublish 'd', (identifier) -> options = fields: name: 1 @@ -29,4 +29,4 @@ Meteor.startup -> u: 1 usernames: 1 user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 - return RocketChat.models.Rooms.findByTypeContainigUsername 'd', user.username, options + return RocketChat.models.Rooms.findByTypeContainigUsernames 'd', [user.username, identifier], options -- GitLab From 5a15700475946b42be74435e725f2ba814a39b20 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 13 Nov 2015 17:19:51 -0200 Subject: [PATCH 0418/1338] fix direct room publish --- packages/rocketchat-lib/server/models/Rooms.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index e31711c7f4c..ae1e96018d5 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -106,6 +106,13 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @find query, options + findByTypeContainigUsernames: (type, username, options) -> + query = + t: type + usernames: { $all: [].concat(username) } + + return @find query, options + findByTypesAndNotUserIdContainingUsername: (types, userId, username, options) -> query = t: -- GitLab From 177d026c0581ab5add7cc4b35d27dab2e6035845 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 13 Nov 2015 17:20:17 -0200 Subject: [PATCH 0419/1338] support to unread rooms --- .../rocketchat-livechat/client/views/sideNav/livechat.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechat.js b/packages/rocketchat-livechat/client/views/sideNav/livechat.js index 5c3b73247da..ec42e0b9e65 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechat.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechat.js @@ -20,6 +20,15 @@ Template.livechat.helpers({ t: 'l', open: true }; + + var user = Meteor.user(); + + if (user && user.settings && user.settings.preferences && user.settings.preferences.unreadRoomsMode) { + query.alert = { + $ne: true + }; + } + return ChatSubscription.find(query, { sort: { 't': 1, -- GitLab From 3ad8244e9835189888c23e274d0a995cd335f966 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 13 Nov 2015 21:20:35 -0200 Subject: [PATCH 0420/1338] Updated default value for FileUpload_MediaTypeWhiteList --- packages/rocketchat-lib/settings/server/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index c6dd4baa38c..09e68acfbec 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -44,7 +44,7 @@ RocketChat.settings.add 'Accounts_RequireNameForSignUp', true, { type: 'boolean' 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/*, .pdf, .doc, .txt', { type: 'string', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_MediaTypeWhiteListDescription' } +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' -- GitLab From a4784610d9b55e81131ddd2632b54edbfa22e450 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 11:18:43 +0000 Subject: [PATCH 0421/1338] Revising (en.i18n) LDAP translations. Fixing spelling errors, correcting grammar and casing. --- i18n/en.i18n.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e4b831f67d6..f4007bb2c14 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -192,19 +192,19 @@ "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_Description" : "LDAP is a heirarchical 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 twiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", + "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", "LDAP_Enable" : "Enable LDAP", - "LDAP_Enable_Description" : "Attempt to utilize ldap for authentication.", + "LDAP_Enable_Description" : "Attempt to utilize LDAP for authentication.", "LDAP_Port" : "LDAP Port", "LDAP_Port_Description" : "Port to access LDAP on; eg: 389", "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" : "Allows configuring how to populate user account fields (like email) from a record in ldap (once found). As an example, {\"cn\":\"name\", \"mail\":\"email\"} will choose a persion's human readable name from the cn attribute, and their email from the mail attribute. Available fields include name, and 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_Url" : "LDAP URL", - "LDAP_Url_Description" : "Uri of the ldap server; example: ldap://company.dns.com", + "LDAP_Url_Description" : "URL of the LDAP server; example: ldap://company.dns.com", "Leave_room" : "Leave room", "line" : "line", "Load_more" : "Load more", -- GitLab From 0dbd90d414487458ad25b7fee44501eceb021232 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 12:51:00 +0000 Subject: [PATCH 0422/1338] Adding empty placeholders for optional descriptions. --- i18n/en.i18n.json | 107 +++++++++++++++++- .../i18n/en.i18n.json | 5 +- .../rocketchat-message-star/i18n/en.i18n.json | 3 +- packages/rocketchat-webrtc/i18n/en.i18n.json | 8 +- .../rocketchat-wordpress/i18n/en.i18n.json | 8 +- 5 files changed, 122 insertions(+), 9 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index f4007bb2c14..3180b43fc41 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -2,16 +2,30 @@ "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", + "Accounts_Description" : "", "Accounts_AllowedDomainsList" : "Comma-separated list of allowed domains", + "Accounts_AllowedDomainsList_Description" : "", "Accounts_AllowPasswordChange" : "Allow Password Change", + "Accounts_AllowPasswordChange_Description" : "", + "Accounts_AllowUserAvatarChange": "Allow User Avatar Change", + "Accounts_AllowUserAvatarChange_Description": "", + "Accounts_AllowUserProfileChange": "Allow User Profile Change", + "Accounts_AllowUserProfileChange_Description": "", "Accounts_AllowUsernameChange" : "Allow Username Change", + "Accounts_AllowUsernameChange_Description" : "", "Accounts_AvatarResize" : "Resize Avatars", + "Accounts_AvatarResize_Description" : "", "Accounts_AvatarSize" : "Avatar Size", + "Accounts_AvatarSize_Description" : "", "Accounts_AvatarStorePath" : "Avatar Storage Path", + "Accounts_AvatarStorePath_Description" : "", "Accounts_AvatarStoreType" : "Avatar Storage Type", + "Accounts_AvatarStoreType_Description" : "", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", + "Accounts_EmailVerification_Description" : "", "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", + "Accounts_ManuallyApproveNewUsers_Description" : "", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", "Accounts_OAuth_Custom_Button_Color" : "Button Color", "Accounts_OAuth_Custom_Button_Label_Color" : "Button Text Color", @@ -23,30 +37,53 @@ "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook Login", + "Accounts_OAuth_Facebook_Description" : "", "Accounts_OAuth_Facebook_id" : "Facebook App Id", + "Accounts_OAuth_Facebook_id_Description" : "", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", + "Accounts_OAuth_Facebook_secret_Description" : "", "Accounts_OAuth_Github" : "OAuth Enabled", + "Accounts_OAuth_Github_Description" : "", "Accounts_OAuth_Github_id" : "Client Id", + "Accounts_OAuth_Github_id_Description" : "", "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Github_secret_Description" : "", "Accounts_OAuth_Gitlab" : "OAuth Enabled", + "Accounts_OAuth_Gitlab_Description" : "", "Accounts_OAuth_Gitlab_id" : "Gitlab Id", + "Accounts_OAuth_Gitlab_id_Description" : "", "Accounts_OAuth_Gitlab_secret" : "Client Secret", + "Accounts_OAuth_Google_secret_Description" : "", "Accounts_OAuth_Google" : "Google Login", + "Accounts_OAuth_Google_Description" : "", "Accounts_OAuth_Google_id" : "Google Id", + "Accounts_OAuth_Google_id_Description" : "", "Accounts_OAuth_Google_secret" : "Google Secret", + "Accounts_OAuth_Gitlab_secret_Description" : "", "Accounts_OAuth_Linkedin" : "LinkedIn Login", + "Accounts_OAuth_Linkedin_Description" : "", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", + "Accounts_OAuth_Linkedin_id_Description" : "", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", + "Accounts_OAuth_Linkedin_secret_Description" : "", "Accounts_OAuth_Meteor" : "Meteor Login", + "Accounts_OAuth_Meteor_Description" : "", "Accounts_OAuth_Meteor_id" : "Meteor Id", + "Accounts_OAuth_Meteor_id_Description" : "", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_OAuth_Meteor_secret_Description" : "", "Accounts_OAuth_Twitter" : "Twitter Login", + "Accounts_OAuth_Twitter_Description" : "", "Accounts_OAuth_Twitter_id" : "Twitter Id", + "Accounts_OAuth_Twitter_id_Description" : "", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_OAuth_Twitter_secret_Description" : "", "Accounts_RegistrationRequired" : "Registration Required", + "Accounts_RegistrationRequired_Description" : "", "Accounts_RequireNameForSignUp" : "Require name for signup", - "Accounts_Enrollment_Email" : "Enrollment E-mail", - "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Accounts_RequireNameForSignUp_Description" : "", + "Accounts_Enrollment_Email": "Enrollment E-mail", + "Accounts_Enrollment_Email_Description": "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", @@ -54,12 +91,17 @@ "Administration" : "Administration", "All_channels" : "All channels", "Allow_Invalid_SelfSigned_Certs" : "Allow invalid and Self-Signed SSL certificate's for link validation and previews", + "Allow_Invalid_SelfSigned_Certs_Description" : "", "and" : "and", "API" : "API", + "API_Description" : "", "API_Analytics" : "Analytics", + "API_Analytics_Description" : "", "API_Embed" : "Embed", + "API_Embed_Description" : "", "API_EmbedDisabledFor" : "Disable Embed for Users", "API_EmbedDisabledFor_Description" : "Comma-separated list of usernames", + "API_Gitlab_URL_Description" : "", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", @@ -82,6 +124,7 @@ "Busy_male" : "Busy", "Cancel" : "Cancel", "CDN_PREFIX" : "CDN Prefix", + "CDN_PREFIX_Description" : "", "Change_avatar" : "Change avatar", "Channels" : "Channels", "Channels_list" : "List of public channels", @@ -113,6 +156,7 @@ "Desktop_Notifications_Enabled" : "Desktop Notifications are Enabled", "Direct_Messages" : "Direct Messages", "Disable_Favorite_Rooms" : "Disable Favorites", + "Disable_Favorite_Rooms_Description" : "", "Disable_New_Message_Notification" : "Disable New Message Notification", "Disable_New_Room_Notification" : "Disable New Room Notification", "Drop_to_upload_file" : "Drop to upload file", @@ -134,15 +178,20 @@ "False" : "False", "Favorites" : "Favorites", "FileUpload" : "File Upload", + "FileUpload_Description" : "", "FileUpload_Enabled" : "File Uploads Enabled", + "FileUpload_Enabled_Description" : "", "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", + "FileUpload_MaxFileSize_Description" : "", "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", "Fork_it_on_github" : "Fork it on github", "From_Email" : "From Email", + "From_Email_Description" : "", "General" : "General", + "General_Description" : "", "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", @@ -165,7 +214,9 @@ "invisible" : "invisible", "Invisible" : "Invisible", "Invitation_HTML" : "Invitation HTML", + "Invitation_HTML_Description" : "", "Invitation_Subject" : "Invitation Subject", + "Invitation_Subject_Description" : "", "Invite_Users" : "Invite Users", "is_also_typing" : "is also typing", "is_also_typing_female" : "is also typing", @@ -181,14 +232,21 @@ "Last_login" : "Last login", "Last_message" : "Last message", "Layout" : "Layout", + "Layout_Description" : "", "Layout_Home_Body" : "Home Body", + "Layout_Home_Body_Description" : "", "Layout_Home_Title" : "Home Title", + "Layout_Home_Title_Description" : "", "Layout_Login_Header" : "Login Header", + "Layout_Login_Header_Description" : "", "Layout_Login_Terms" : "Login Terms", + "Layout_Login_Terms_Description" : "", "Layout_Privacy_Policy" : "Privacy Policy", + "Layout_Privacy_Policy_Description" : "", "Layout_Sidenav_Footer" : "Side Navigation Footer", "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", + "Layout_Terms_of_Service_Description" : "", "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\"}", @@ -218,12 +276,16 @@ "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", "Markdown_Headers" : "Markdown Headers", + "Markdown_Headers_Description" : "", "Members" : "Members", "Members_List" : "Members List", "Members_placeholder" : "Members", "Message" : "Message", + "Message_Description" : "", "Message_AllowDeleting" : "Allow Message Deleting", + "Message_AllowDeleting_Description" : "", "Message_AllowEditing" : "Allow Message Editing", + "Message_AllowEditing_Description" : "", "Message_AllowEditing_BlockEditInMinutes" : "Block Message Editing After (n) Minutes", "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking", "Message_AllowPinning" : "Allow Message Pinning", @@ -233,20 +295,31 @@ "Message_editing_blocked" : "This message cannot be edited anymore", "Message_editing_not_allowed" : "Message editing not allowed", "Message_KeepHistory" : "Keep Message History", + "Message_KeepHistory_Description" : "", "Message_MaxAllowedSize" : "Maximum Allowed Message Size", + "Message_MaxAllowedSize_Description" : "", "Message_pinned" : "Message pinned", "Message_pinning_not_allowed" : "Message pinning not allowed", "Message_removed" : "Message removed", "Message_ShowDeletedStatus" : "Show Deleted Status", + "Message_ShowDeletedStatus_Description" : "", "Message_ShowEditedStatus" : "Show Edited Status", + "Message_ShowEditedStatus_Description" : "", "Message_ShowFormattingTips" : "Show Formatting Tips", + "Message_ShowFormattingTips_Description" : "", "Messages" : "Messages", "Meta" : "Meta", + "Meta_Description" : "", "Meta_fb_app_id" : "Facebook App Id", + "Meta_fb_app_id_Description" : "", "Meta_google-site-verification" : "Google Site Verification", + "Meta_google-site-verification_Description" : "", "Meta_language" : "Language", + "Meta_language_Description" : "", "Meta_msvalidate01" : "MSValidate.01", + "Meta_msvalidate01_Description" : "", "Meta_robots" : "Robots", + "Meta_robots_Description" : "", "minutes" : "minutes", "More_channels" : "More channels", "More_groups" : "More private groups", @@ -298,17 +371,29 @@ "Profile_saved_successfully" : "Profile saved successfully", "Proudly_developed" : "Proudly developed with Meteor", "Push" : "Push", + "Push_Description" : "", "Push_apn_cert" : "APN Cert", + "Push_apn_cert_Description" : "", "Push_apn_dev_cert" : "APN Dev Cert", + "Push_apn_dev_cert_Description" : "", "Push_apn_dev_key" : "APN Dev Key", + "Push_apn_dev_key_Description" : "", "Push_apn_dev_passphrase" : "APN Dev Passphrase", + "Push_apn_dev_passphrase_Description" : "", "Push_apn_key" : "APN Key", + "Push_apn_key_Description" : "", "Push_apn_passphrase" : "APN Passphrase", + "Push_apn_passphrase_Description" : "", "Push_debug" : "Debug", + "Push_debug_Description" : "", "Push_enable" : "Enable", + "Push_enable_Description" : "", "Push_gcm_api_key" : "GCM API Key", + "Push_gcm_api_key_Description" : "", "Push_gcm_project_number" : "GCM Project Number", + "Push_gcm_project_number_Description" : "", "Push_production" : "Production", + "Push_production_Description" : "", "Quick_Search" : "Quick Search", "quote" : "quote", "Recents" : "Recents", @@ -330,11 +415,21 @@ "Rooms" : "Rooms", "S_new_messages_since_s" : "%s new messages since %s", "SAML" : "SAML", + "SAML_Description" : "", + "SAML_Custom_default_button_color_Description" : "", + "SAML_Custom_default_button_label_color_Description" : "", + "SAML_Custom_default_button_label_text_Description" : "", + "SAML_Custom_default_Description" : "", "SAML_Custom_Cert" : "Custom Certificate", + "SAML_Custom_default_cert_Description" : "", "SAML_Custom_Entry_point" : "Custom Entry Point", + "SAML_Custom_default_entry_point_Description" : "", "SAML_Custom_Generate_Username" : "Generate Username", + "SAML_Custom_default_generate_username_Description" : "", "SAML_Custom_Issuer" : "Custom Issuer", + "SAML_Custom_default_issuer_Description" : "", "SAML_Custom_Provider" : "Custom Provider", + "SAML_Custom_default_provider_Description" : "", "Save" : "Save", "Save_changes" : "Save changes", "Save_Mobile_Bandwidth" : "Save Mobile Bandwidth", @@ -363,13 +458,19 @@ "Silence" : "Silence", "since_creation" : "since %s", "Site_Name" : "Site Name", + "Site_Name_Description" : "", "Site_Url" : "Site URL", "Site_Url_Description" : "Example: https://chat.domain.com/", "SMTP" : "SMTP", + "SMTP_Description" : "", "SMTP_Host" : "SMTP Host", + "SMTP_Host_Description" : "", "SMTP_Password" : "SMTP Password", + "SMTP_Password_Description" : "", "SMTP_Port" : "SMTP Port", + "SMTP_Port_Description" : "", "SMTP_Username" : "SMTP Username", + "SMTP_Username_Description" : "", "Sound" : "Sound", "Start_of_conversation" : "Start of conversation", "Statistics" : "Statistics", @@ -454,4 +555,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index 8fb066fbe08..654d46ed9fb 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -1,7 +1,10 @@ { "Accounts_OAuth_GitHub_Enterprise" : "OAuth Enabled", + "Accounts_OAuth_GitHub_Enterprise_Description": "", "API_GitHub_Enterprise_URL" : "Server URL", "Accounts_OAuth_GitHub_Enterprise_id" : "Client Id", + "Accounts_OAuth_GitHub_Enterprise_id_Description" : "", "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", + "Accounts_OAuth_GitHub_Enterprise_secret_Description" : "", "Github_Enterprise_Url_No_Trail" : "Note: Please exclude trailing slash" -} \ No newline at end of file +} diff --git a/packages/rocketchat-message-star/i18n/en.i18n.json b/packages/rocketchat-message-star/i18n/en.i18n.json index 7377102ab14..756eaee93e8 100644 --- a/packages/rocketchat-message-star/i18n/en.i18n.json +++ b/packages/rocketchat-message-star/i18n/en.i18n.json @@ -1,7 +1,8 @@ { "Message_AllowStarring" : "Allow Message Starring", + "Message_AllowStarring_Description" : "", "Star_Message" : "Star Message", "Unstar_Message" : "Remove Star", "Starred_Messages" : "Starred Messages", "No_starred_messages" : "No starred messages" -} \ No newline at end of file +} diff --git a/packages/rocketchat-webrtc/i18n/en.i18n.json b/packages/rocketchat-webrtc/i18n/en.i18n.json index c52ef5d8daa..e88088a6e9e 100644 --- a/packages/rocketchat-webrtc/i18n/en.i18n.json +++ b/packages/rocketchat-webrtc/i18n/en.i18n.json @@ -1,5 +1,9 @@ { + "WebRTC_Description" : "", "WebRTC_Enable_Channel" : "Enable for Public Channels", + "WebRTC_Enable_Channel_Description" : "", "WebRTC_Enable_Direct" : "Enable for Direct Messages", - "WebRTC_Enable_Private" : "Enable for Private Channels" -} \ No newline at end of file + "WebRTC_Enable_Direct_Description" : "", + "WebRTC_Enable_Private" : "Enable for Private Channels", + "WebRTC_Enable_Private_Description" : "" +} diff --git a/packages/rocketchat-wordpress/i18n/en.i18n.json b/packages/rocketchat-wordpress/i18n/en.i18n.json index 06727b945fe..129f9acb958 100644 --- a/packages/rocketchat-wordpress/i18n/en.i18n.json +++ b/packages/rocketchat-wordpress/i18n/en.i18n.json @@ -1,6 +1,10 @@ { "API_Wordpress_URL" : "WordPress URL", + "API_Wordpress_URL_Description" : "", "Accounts_OAuth_Wordpress" : "WordPress Login", + "Accounts_OAuth_Wordpress_Description" : "", "Accounts_OAuth_Wordpress_id" : "WordPress Id", - "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" -} \ No newline at end of file + "Accounts_OAuth_Wordpress_id_Description" : "", + "Accounts_OAuth_Wordpress_secret" : "WordPress Secret", + "Accounts_OAuth_Wordpress_secret_Description" : "" +} -- GitLab From e7a502033fb25ea7a5abaf5b80cb88e9e4bda1df Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 12:51:29 +0000 Subject: [PATCH 0423/1338] Normalising case. --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3180b43fc41..1b0f82c70b2 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -80,7 +80,7 @@ "Accounts_OAuth_Twitter_secret_Description" : "", "Accounts_RegistrationRequired" : "Registration Required", "Accounts_RegistrationRequired_Description" : "", - "Accounts_RequireNameForSignUp" : "Require name for signup", + "Accounts_RequireNameForSignUp" : "Require Name For Signup", "Accounts_RequireNameForSignUp_Description" : "", "Accounts_Enrollment_Email": "Enrollment E-mail", "Accounts_Enrollment_Email_Description": "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", -- GitLab From 3655b34382f152518dafd7fec609614a0dd1fde5 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 12:55:26 +0000 Subject: [PATCH 0424/1338] Revising 'Accounts_AllowedDomainsList' and 'Description'. --- i18n/en.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1b0f82c70b2..10c1bf7cc92 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -3,8 +3,8 @@ "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", "Accounts_Description" : "", - "Accounts_AllowedDomainsList" : "Comma-separated list of allowed domains", - "Accounts_AllowedDomainsList_Description" : "", + "Accounts_AllowedDomainsList" : "Allowed Domains List", + "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains", "Accounts_AllowPasswordChange" : "Allow Password Change", "Accounts_AllowPasswordChange_Description" : "", "Accounts_AllowUserAvatarChange": "Allow User Avatar Change", -- GitLab From b186a0574f66ea9f0c47dbc8ea8fe876020c3e57 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 13:02:38 +0000 Subject: [PATCH 0425/1338] Revising 'Github_Enterprise_Url_No_Trail'. --- packages/rocketchat-github-enterprise/i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index 654d46ed9fb..dac5ec52b61 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -6,5 +6,5 @@ "Accounts_OAuth_GitHub_Enterprise_id_Description" : "", "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", "Accounts_OAuth_GitHub_Enterprise_secret_Description" : "", - "Github_Enterprise_Url_No_Trail" : "Note: Please exclude trailing slash" + "Github_Enterprise_Url_No_Trail" : "Example: http://domain.com (excluding trailing slash)" } -- GitLab From f1d6856d867e18fc21e03e6834dc3ad7b72d7f31 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 13:06:28 +0000 Subject: [PATCH 0426/1338] Revising 'Message_AllowPinningByAnyone_Description'. --- packages/rocketchat-message-pin/i18n/en.i18n.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-message-pin/i18n/en.i18n.json b/packages/rocketchat-message-pin/i18n/en.i18n.json index 8ae61d2f419..834bea1c96d 100644 --- a/packages/rocketchat-message-pin/i18n/en.i18n.json +++ b/packages/rocketchat-message-pin/i18n/en.i18n.json @@ -1,9 +1,10 @@ { - "Message_AllowPinning_Description" : "Allow messages to be pinned to any of the channels.", - "Message_AllowPinningByAnyone" : "Allow Anyone to Pin Messages", - "Message_AllowPinningByAnyone_Description" : "If true, anyone will be able to pin a messages in any channels but if false then only channel owners and admins will be allowed to.", + "Message_AllowPinning" : "Allow Message Pinning", + "Message_AllowPinning_Description": "Allow messages to be pinned to any of the channels.", + "Message_AllowPinningByAnyone": "Allow Anyone to Pin Messages", + "Message_AllowPinningByAnyone_Description": "Allow anyone to pin messages to a channel, not just administrators.", "Pin_Message" : "Pin Message", "Unpin_Message" : "Unpin Message", "Pinned_Messages" : "Pinned Messages", "No_pinned_messages" : "No pinned messages" -} \ No newline at end of file +} -- GitLab From bb9e52c8fdfcd8c8c1a7e092d973ca406ff1c0df Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 13:10:53 +0000 Subject: [PATCH 0427/1338] Revising 'Message_AudioRecorderEnabledDescription'. --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 10c1bf7cc92..cfae10d2b38 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -290,7 +290,7 @@ "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking", "Message_AllowPinning" : "Allow Message Pinning", "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", - "Message_AudioRecorderEnabledDescription" : "For this to work upload of Wav files must be enabled in the 'File Upload' section", + "Message_AudioRecorderEnabledDescription" : "Requires 'audio/wav' files to be an accepted media type within 'File Upload' settings.", "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", -- GitLab From 2a74688a2acb5597da1def534c6a751dc63c475b Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 13:11:22 +0000 Subject: [PATCH 0428/1338] Adding punctuation. --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index cfae10d2b38..da7d7384401 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -287,7 +287,7 @@ "Message_AllowEditing" : "Allow Message Editing", "Message_AllowEditing_Description" : "", "Message_AllowEditing_BlockEditInMinutes" : "Block Message Editing After (n) Minutes", - "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking.", "Message_AllowPinning" : "Allow Message Pinning", "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", "Message_AudioRecorderEnabledDescription" : "Requires 'audio/wav' files to be an accepted media type within 'File Upload' settings.", -- GitLab From 7da62d740e6d55cbff47f1277475a93c15576a6c Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 13:14:34 +0000 Subject: [PATCH 0429/1338] Revising 'Allow_Invalid_SelfSigned_Certs' and 'Description'. --- i18n/en.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index da7d7384401..eb98ef0d128 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -90,8 +90,8 @@ "Add_users" : "Add users", "Administration" : "Administration", "All_channels" : "All channels", - "Allow_Invalid_SelfSigned_Certs" : "Allow invalid and Self-Signed SSL certificate's for link validation and previews", - "Allow_Invalid_SelfSigned_Certs_Description" : "", + "Allow_Invalid_SelfSigned_Certs" : "Allow Invalid Self-Signed Certs", + "Allow_Invalid_SelfSigned_Certs_Description" : "Allow invalid and self-signed SSL certificate's for link validation and previews.", "and" : "and", "API" : "API", "API_Description" : "", -- GitLab From 055b0b376feadaa5a816661a8b019bfd3d36a788 Mon Sep 17 00:00:00 2001 From: Olivier Beddows <oliver.beddows@googlemail.com> Date: Fri, 13 Nov 2015 14:20:35 +0000 Subject: [PATCH 0430/1338] Configuring rocketchat-theme translations. Adding initial en.i18n translations. --- packages/rocketchat-theme/i18n/en.i18n.json | 45 +++++++++++++++++++++ packages/rocketchat-theme/package.js | 13 ++++++ 2 files changed, 58 insertions(+) create mode 100644 packages/rocketchat-theme/i18n/en.i18n.json diff --git a/packages/rocketchat-theme/i18n/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json new file mode 100644 index 00000000000..31987697d1d --- /dev/null +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -0,0 +1,45 @@ +{ + "Theme_Description" : "", + "theme-color-blockquote-background" : "Blockquote Background Color", + "theme-color-blockquote-background_Description" : "", + "theme-color-code-background" : "Code Background Color", + "theme-color-code-background_Description" : "", + "theme-color-code-border" : "Code Border Color", + "theme-color-code-border_Description" : "", + "theme-color-code-color" : "Code Color", + "theme-color-code-color_Description" : "", + "theme-color-content-background-color" : "Content Background Color", + "theme-color-content-background-color_Description" : "", + "theme-color-info-active-font-color" : "Active Info Font Color", + "theme-color-info-active-font-color_Description" : "", + "theme-color-info-font-color" : "Info Font Color", + "theme-color-info-font-color_Description" : "", + "theme-color-input-font-color" : "Input Font Color", + "theme-color-input-font-color_Description" : "", + "theme-color-link-font-color" : "Link Font Color", + "theme-color-link-font-color_Description" : "", + "theme-color-primary-background-color" : "Primary Background Color", + "theme-color-primary-background-color_Description" : "", + "theme-color-primary-font-color" : "Primary Font Color", + "theme-color-primary-font-color_Description" : "", + "theme-color-secondary-background-color" : "Secondary Background Color", + "theme-color-secondary-background-color_Description" : "", + "theme-color-secondary-font-color" : "Secondary Font Color", + "theme-color-secondary-font-color_Description" : "", + "theme-color-smallprint-font-color" : "Small Print Font Color", + "theme-color-smallprint-font-color_Description" : "", + "theme-color-smallprint-hover-color" : "Small Print Hover Color", + "theme-color-smallprint-hover-color_Description" : "", + "theme-color-status-away" : "Away Status Color", + "theme-color-status-away_Description" : "", + "theme-color-status-busy" : "Busy Status Color", + "theme-color-status-busy_Description" : "", + "theme-color-status-offline" : "Offline Status Color", + "theme-color-status-offline_Description" : "", + "theme-color-status-online" : "Online Status Color", + "theme-color-status-online_Description" : "", + "theme-color-tertiary-background-color" : "Tertiary Background Color", + "theme-color-tertiary-background-color_Description" : "", + "theme-color-tertiary-font-color" : "Tertiary Font Color", + "theme-color-tertiary-font-color_Description" : "" +} diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index f061fa72b39..7a2d5830675 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -37,6 +37,19 @@ Package.onUse(function(api) { api.addAssets('assets/stylesheets/fontello.css', 'server'); api.addAssets('assets/stylesheets/rtl.less', 'server'); api.addAssets('assets/stylesheets/swipebox.min.css', 'server'); + + // TAPi18n + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + api.use('templating', 'client'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-theme/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-theme/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']); }); Npm.depends({ -- GitLab From c4367d16cb7e0f18c1b456b6e47af7c349b89390 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sat, 14 Nov 2015 21:16:03 -0500 Subject: [PATCH 0431/1338] All build activities on develop (for now) Move all builds - including demo server to develop. Please merge down to master. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2e6d898173b..d85821c591a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ sudo: required language: node_js branches: only: - - master - develop node_js: - '0.10' @@ -52,4 +51,4 @@ deploy: skip_cleanup: true local_dir: ../build on: - branch: master + branch: develop -- GitLab From 40638c700ca786c5526f9d7faf5a5bd070034481 Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Sun, 15 Nov 2015 01:44:28 -0600 Subject: [PATCH 0432/1338] Fix for #1411 and #1407. Corrected the malreferenced variables, was not able to verify #1407 as being fixed since there wasn't clear instructions on how to replicate. --- packages/rocketchat-lib/server/models/Messages.coffee | 6 +++--- packages/rocketchat-message-pin/client/actionButton.coffee | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 7c7d85c224a..49ed13ec71a 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -110,9 +110,9 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base record.editedBy = _id: Meteor.userId() username: me.username - message.pinned = record.pinned - message.pinnedAt = record.pinnedAt - message.pinnedBy = + record.pinned = record.pinned + record.pinnedAt = record.pinnedAt + record.pinnedBy = _id: record.pinnedBy?._id username: record.pinnedBy?.username delete record._id diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index ca8577a124f..78527e098fd 100644 --- a/packages/rocketchat-message-pin/client/actionButton.coffee +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -16,7 +16,7 @@ Meteor.startup -> if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' return true - return room.u?._id is Meteor.userId() + return ChatRoom.findOne(message.rid).u?._id is Meteor.userId() order: 20 RocketChat.MessageAction.addButton @@ -36,5 +36,5 @@ Meteor.startup -> if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin' return true - return room.u?._id is Meteor.userId() + return ChatRoom.findOne(message.rid).u?._id is Meteor.userId() order: 21 -- GitLab From d70c4e2ee624e268fd09d74aadb84fff3092d3f0 Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Sun, 15 Nov 2015 17:53:53 +0100 Subject: [PATCH 0433/1338] rocketchat-ui initial implementation --- .meteor/packages | 5 + .meteor/versions | 5 + client/lib/accounts.coffee | 16 - .../rocketchat-ui-account/README.md | 0 .../account/account.coffee | 0 .../account/account.html | 0 .../account/accountFlex.coffee | 0 .../account/accountFlex.html | 0 .../account/accountPreferences.coffee | 0 .../account/accountPreferences.html | 0 .../account/accountProfile.coffee | 0 .../account/accountProfile.html | 0 .../account/avatar/avatar.coffee | 0 .../account/avatar/avatar.html | 0 .../account/avatar/prompt.coffee | 0 .../account/avatar/prompt.html | 0 packages/rocketchat-ui-account/package.js | 39 +++ .../rocketchat-ui-account-tests.js | 5 + .../rocketchat-ui-account.js | 1 + .../rocketchat-ui-account/styles/account.less | 0 packages/rocketchat-ui-admin/README.md | 0 .../rocketchat-ui-admin}/admin/admin.coffee | 0 .../rocketchat-ui-admin}/admin/admin.html | 0 .../admin/adminFlex.coffee | 0 .../rocketchat-ui-admin}/admin/adminFlex.html | 0 .../admin/adminStatistics.coffee | 0 .../admin/adminStatistics.html | 0 .../admin/rooms/adminRoomInfo.coffee | 0 .../admin/rooms/adminRoomInfo.html | 0 .../admin/rooms/adminRooms.coffee | 0 .../admin/rooms/adminRooms.html | 0 .../admin/users/adminInviteUser.coffee | 0 .../admin/users/adminInviteUser.html | 0 .../admin/users/adminUserChannels.coffee | 0 .../admin/users/adminUserChannels.html | 0 .../admin/users/adminUserEdit.coffee | 0 .../admin/users/adminUserEdit.html | 0 .../admin/users/adminUserInfo.coffee | 0 .../admin/users/adminUserInfo.html | 0 .../admin/users/adminUsers.coffee | 0 .../admin/users/adminUsers.html | 0 packages/rocketchat-ui-admin/package.js | 54 ++++ .../rocketchat-ui-admin-tests.js | 5 + .../rocketchat-ui-admin.js | 1 + packages/rocketchat-ui-login/README.md | 0 .../rocketchat-ui-login}/login/footer.coffee | 0 .../rocketchat-ui-login}/login/footer.html | 0 .../rocketchat-ui-login}/login/form.coffee | 0 .../rocketchat-ui-login}/login/form.html | 0 .../rocketchat-ui-login}/login/header.coffee | 0 .../rocketchat-ui-login}/login/header.html | 0 .../rocketchat-ui-login}/login/intro.html | 0 .../rocketchat-ui-login}/login/layout.html | 0 .../login/services.coffee | 0 .../rocketchat-ui-login}/login/services.html | 0 .../rocketchat-ui-login/login/social.coffee | 0 .../rocketchat-ui-login}/login/social.html | 0 packages/rocketchat-ui-login/package.js | 39 +++ .../.npm/package/.gitignore | 1 + .../rocketchat-ui-sidenav/.npm/package/README | 7 + .../.npm/package/npm-shrinkwrap.json | 285 ++++++++++++++++++ packages/rocketchat-ui-sidenav/README.md | 0 packages/rocketchat-ui-sidenav/package.js | 54 ++++ .../side-nav}/channels.coffee | 0 .../side-nav}/channels.html | 0 .../side-nav}/chatRoomItem.coffee | 0 .../side-nav}/chatRoomItem.html | 0 .../side-nav}/createChannelFlex.coffee | 0 .../side-nav}/createChannelFlex.html | 0 .../side-nav}/directMessages.coffee | 0 .../side-nav}/directMessages.html | 0 .../side-nav}/directMessagesFlex.coffee | 0 .../side-nav}/directMessagesFlex.html | 0 .../side-nav}/listChannelsFlex.coffee | 0 .../side-nav}/listChannelsFlex.html | 0 .../side-nav}/listPrivateGroupsFlex.coffee | 0 .../side-nav}/listPrivateGroupsFlex.html | 0 .../side-nav}/privateGroups.coffee | 0 .../side-nav}/privateGroups.html | 0 .../side-nav}/privateGroupsFlex.coffee | 0 .../side-nav}/privateGroupsFlex.html | 0 .../side-nav}/sideNav.coffee | 0 .../side-nav}/sideNav.html | 0 .../side-nav}/starredRooms.coffee | 0 .../side-nav}/starredRooms.html | 0 .../side-nav}/unreadRooms.coffee | 0 .../side-nav}/unreadRooms.html | 0 .../side-nav}/userStatus.html | 0 .../styles/side-nav.less | 0 packages/rocketchat-ui/README.md | 0 .../rocketchat-ui}/lib/Modernizr.js | 0 .../lib/RoomHistoryManager.coffee | 0 .../rocketchat-ui}/lib/RoomManager.coffee | 0 .../rocketchat-ui}/lib/accountBox.coffee | 0 packages/rocketchat-ui/lib/accounts.coffee | 17 ++ .../rocketchat-ui}/lib/avatar.coffee | 0 .../rocketchat-ui}/lib/chatMessages.coffee | 0 .../rocketchat-ui}/lib/collections.coffee | 0 .../rocketchat-ui}/lib/constallation.js | 0 .../lib/cordova/facebook-login.coffee | 0 .../lib/cordova/keyboard-fix.coffee | 0 .../rocketchat-ui}/lib/cordova/push.coffee | 0 .../rocketchat-ui}/lib/cordova/urls.coffee | 0 .../lib/cordova/user-state.coffee | 0 .../rocketchat-ui}/lib/customEventPolyfill.js | 0 .../rocketchat-ui}/lib/fileUpload.coffee | 0 .../rocketchat-ui}/lib/fireEvent.coffee | 0 .../rocketchat-ui}/lib/jquery.swipebox.min.js | 0 .../rocketchat-ui}/lib/menu.coffee | 0 .../rocketchat-ui}/lib/modal.coffee | 0 .../rocketchat-ui}/lib/msgTyping.coffee | 0 .../rocketchat-ui}/lib/notification.coffee | 0 .../rocketchat-ui}/lib/parentTemplate.js | 0 .../rocketchat-ui}/lib/particles.js | 0 .../rocketchat-ui}/lib/readMessages.coffee | 0 .../lib/recorderjs/audioRecorder.coffee | 0 .../rocketchat-ui}/lib/recorderjs/recorder.js | 0 .../rocketchat-ui}/lib/rocket.coffee | 0 .../rocketchat-ui}/lib/sideNav.coffee | 0 .../rocketchat-ui}/lib/tapi18n.coffee | 0 .../rocketchat-ui}/lib/textarea-autogrow.js | 0 .../lib/trackRoomNameChanged.coffee | 0 packages/rocketchat-ui/package.js | 115 +++++++ .../views/404/roomNotFound.coffee | 0 .../views/404/roomNotFound.html | 0 .../views/app/audioNotification.html | 0 .../rocketchat-ui}/views/app/burguer.coffee | 0 .../rocketchat-ui}/views/app/burguer.html | 0 .../views/app/flexTabBar.coffee | 0 .../rocketchat-ui}/views/app/flexTabBar.html | 0 .../rocketchat-ui}/views/app/home.coffee | 0 .../rocketchat-ui}/views/app/home.html | 0 .../rocketchat-ui}/views/app/message.coffee | 0 .../rocketchat-ui}/views/app/message.html | 0 .../views/app/messagePopup.coffee | 0 .../views/app/messagePopup.html | 0 .../views/app/messagePopupChannel.html | 0 .../views/app/messagePopupConfig.coffee | 0 .../views/app/messagePopupConfig.html | 0 .../views/app/messagePopupEmoji.coffee | 0 .../views/app/messagePopupEmoji.html | 0 .../views/app/messagePopupSlashCommand.html | 0 .../views/app/messagePopupUser.html | 0 .../views/app/privateHistory.coffee | 0 .../views/app/privateHistory.html | 0 .../rocketchat-ui}/views/app/room.coffee | 0 .../rocketchat-ui}/views/app/room.html | 0 .../views/app/roomSearch.coffee | 0 .../rocketchat-ui}/views/app/roomSearch.html | 0 .../app/spotlight/mobileMessageMenu.coffee | 0 .../app/spotlight/mobileMessageMenu.html | 0 .../views/app/spotlight/spotlight.coffee | 0 .../views/app/spotlight/spotlight.html | 0 .../views/app/tabBar/membersList.coffee | 0 .../views/app/tabBar/membersList.html | 0 .../views/app/tabBar/messageSearch.coffee | 0 .../views/app/tabBar/messageSearch.html | 0 .../views/app/tabBar/uploadedFilesList.coffee | 0 .../views/app/tabBar/uploadedFilesList.html | 0 .../rocketchat-ui}/views/app/userInfo.coffee | 0 .../rocketchat-ui}/views/app/userInfo.html | 0 .../rocketchat-ui}/views/app/userSearch.html | 0 .../views/app/videoCall/videoButtons.coffee | 0 .../views/app/videoCall/videoButtons.html | 0 .../views/app/videoCall/videoCall.coffee | 0 .../views/app/videoCall/videoCall.html | 0 .../rocketchat-ui}/views/cmsPage.coffee | 0 .../rocketchat-ui}/views/cmsPage.html | 0 .../rocketchat-ui}/views/error.html | 0 .../rocketchat-ui}/views/fxos.coffee | 0 .../rocketchat-ui}/views/fxos.html | 0 .../rocketchat-ui}/views/loading.html | 0 .../rocketchat-ui}/views/main.coffee | 0 .../rocketchat-ui}/views/main.html | 0 .../rocketchat-ui}/views/modal.coffee | 0 .../rocketchat-ui}/views/modal.html | 0 .../rocketchat-ui}/views/username/layout.html | 0 .../views/username/username.coffee | 0 .../views/username/username.html | 0 179 files changed, 633 insertions(+), 16 deletions(-) delete mode 100644 client/lib/accounts.coffee rename client/views/login/social.coffee => packages/rocketchat-ui-account/README.md (100%) rename {client/views => packages/rocketchat-ui-account}/account/account.coffee (100%) rename {client/views => packages/rocketchat-ui-account}/account/account.html (100%) rename {client/views => packages/rocketchat-ui-account}/account/accountFlex.coffee (100%) rename {client/views => packages/rocketchat-ui-account}/account/accountFlex.html (100%) rename {client/views => packages/rocketchat-ui-account}/account/accountPreferences.coffee (100%) rename {client/views => packages/rocketchat-ui-account}/account/accountPreferences.html (100%) rename {client/views => packages/rocketchat-ui-account}/account/accountProfile.coffee (100%) rename {client/views => packages/rocketchat-ui-account}/account/accountProfile.html (100%) rename {client/views => packages/rocketchat-ui-account}/account/avatar/avatar.coffee (100%) rename {client/views => packages/rocketchat-ui-account}/account/avatar/avatar.html (100%) rename {client/views => packages/rocketchat-ui-account}/account/avatar/prompt.coffee (100%) rename {client/views => packages/rocketchat-ui-account}/account/avatar/prompt.html (100%) create mode 100644 packages/rocketchat-ui-account/package.js create mode 100644 packages/rocketchat-ui-account/rocketchat-ui-account-tests.js create mode 100644 packages/rocketchat-ui-account/rocketchat-ui-account.js create mode 100644 packages/rocketchat-ui-account/styles/account.less create mode 100644 packages/rocketchat-ui-admin/README.md rename {client/views => packages/rocketchat-ui-admin}/admin/admin.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/admin.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/adminFlex.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/adminFlex.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/adminStatistics.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/adminStatistics.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/rooms/adminRoomInfo.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/rooms/adminRoomInfo.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/rooms/adminRooms.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/rooms/adminRooms.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminInviteUser.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminInviteUser.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUserChannels.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUserChannels.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUserEdit.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUserEdit.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUserInfo.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUserInfo.html (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUsers.coffee (100%) rename {client/views => packages/rocketchat-ui-admin}/admin/users/adminUsers.html (100%) create mode 100644 packages/rocketchat-ui-admin/package.js create mode 100644 packages/rocketchat-ui-admin/rocketchat-ui-admin-tests.js create mode 100644 packages/rocketchat-ui-admin/rocketchat-ui-admin.js create mode 100644 packages/rocketchat-ui-login/README.md rename {client/views => packages/rocketchat-ui-login}/login/footer.coffee (100%) rename {client/views => packages/rocketchat-ui-login}/login/footer.html (100%) rename {client/views => packages/rocketchat-ui-login}/login/form.coffee (100%) rename {client/views => packages/rocketchat-ui-login}/login/form.html (100%) rename {client/views => packages/rocketchat-ui-login}/login/header.coffee (100%) rename {client/views => packages/rocketchat-ui-login}/login/header.html (100%) rename {client/views => packages/rocketchat-ui-login}/login/intro.html (100%) rename {client/views => packages/rocketchat-ui-login}/login/layout.html (100%) rename {client/views => packages/rocketchat-ui-login}/login/services.coffee (100%) rename {client/views => packages/rocketchat-ui-login}/login/services.html (100%) create mode 100644 packages/rocketchat-ui-login/login/social.coffee rename {client/views => packages/rocketchat-ui-login}/login/social.html (100%) create mode 100644 packages/rocketchat-ui-login/package.js create mode 100644 packages/rocketchat-ui-sidenav/.npm/package/.gitignore create mode 100644 packages/rocketchat-ui-sidenav/.npm/package/README create mode 100644 packages/rocketchat-ui-sidenav/.npm/package/npm-shrinkwrap.json create mode 100644 packages/rocketchat-ui-sidenav/README.md create mode 100644 packages/rocketchat-ui-sidenav/package.js rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/channels.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/channels.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/chatRoomItem.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/chatRoomItem.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/createChannelFlex.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/createChannelFlex.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/directMessages.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/directMessages.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/directMessagesFlex.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/directMessagesFlex.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/listChannelsFlex.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/listChannelsFlex.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/listPrivateGroupsFlex.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/listPrivateGroupsFlex.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/privateGroups.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/privateGroups.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/privateGroupsFlex.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/privateGroupsFlex.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/sideNav.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/sideNav.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/starredRooms.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/starredRooms.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/unreadRooms.coffee (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/unreadRooms.html (100%) rename {client/views/app/sideNav => packages/rocketchat-ui-sidenav/side-nav}/userStatus.html (100%) create mode 100644 packages/rocketchat-ui-sidenav/styles/side-nav.less create mode 100644 packages/rocketchat-ui/README.md rename {client => packages/rocketchat-ui}/lib/Modernizr.js (100%) rename {client => packages/rocketchat-ui}/lib/RoomHistoryManager.coffee (100%) rename {client => packages/rocketchat-ui}/lib/RoomManager.coffee (100%) rename {client => packages/rocketchat-ui}/lib/accountBox.coffee (100%) create mode 100644 packages/rocketchat-ui/lib/accounts.coffee rename {client => packages/rocketchat-ui}/lib/avatar.coffee (100%) rename {client => packages/rocketchat-ui}/lib/chatMessages.coffee (100%) rename {client => packages/rocketchat-ui}/lib/collections.coffee (100%) rename {client => packages/rocketchat-ui}/lib/constallation.js (100%) rename {client => packages/rocketchat-ui}/lib/cordova/facebook-login.coffee (100%) rename {client => packages/rocketchat-ui}/lib/cordova/keyboard-fix.coffee (100%) rename {client => packages/rocketchat-ui}/lib/cordova/push.coffee (100%) rename {client => packages/rocketchat-ui}/lib/cordova/urls.coffee (100%) rename {client => packages/rocketchat-ui}/lib/cordova/user-state.coffee (100%) rename {client => packages/rocketchat-ui}/lib/customEventPolyfill.js (100%) rename {client => packages/rocketchat-ui}/lib/fileUpload.coffee (100%) rename {client => packages/rocketchat-ui}/lib/fireEvent.coffee (100%) rename {client => packages/rocketchat-ui}/lib/jquery.swipebox.min.js (100%) rename {client => packages/rocketchat-ui}/lib/menu.coffee (100%) rename {client => packages/rocketchat-ui}/lib/modal.coffee (100%) rename {client => packages/rocketchat-ui}/lib/msgTyping.coffee (100%) rename {client => packages/rocketchat-ui}/lib/notification.coffee (100%) rename {client => packages/rocketchat-ui}/lib/parentTemplate.js (100%) rename {client => packages/rocketchat-ui}/lib/particles.js (100%) rename {client => packages/rocketchat-ui}/lib/readMessages.coffee (100%) rename {client => packages/rocketchat-ui}/lib/recorderjs/audioRecorder.coffee (100%) rename {client => packages/rocketchat-ui}/lib/recorderjs/recorder.js (100%) rename {client => packages/rocketchat-ui}/lib/rocket.coffee (100%) rename {client => packages/rocketchat-ui}/lib/sideNav.coffee (100%) rename {client => packages/rocketchat-ui}/lib/tapi18n.coffee (100%) rename {client => packages/rocketchat-ui}/lib/textarea-autogrow.js (100%) rename {client => packages/rocketchat-ui}/lib/trackRoomNameChanged.coffee (100%) create mode 100644 packages/rocketchat-ui/package.js rename {client => packages/rocketchat-ui}/views/404/roomNotFound.coffee (100%) rename {client => packages/rocketchat-ui}/views/404/roomNotFound.html (100%) rename {client => packages/rocketchat-ui}/views/app/audioNotification.html (100%) rename {client => packages/rocketchat-ui}/views/app/burguer.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/burguer.html (100%) rename {client => packages/rocketchat-ui}/views/app/flexTabBar.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/flexTabBar.html (100%) rename {client => packages/rocketchat-ui}/views/app/home.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/home.html (100%) rename {client => packages/rocketchat-ui}/views/app/message.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/message.html (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopup.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopup.html (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupChannel.html (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupConfig.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupConfig.html (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupEmoji.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupEmoji.html (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupSlashCommand.html (100%) rename {client => packages/rocketchat-ui}/views/app/messagePopupUser.html (100%) rename {client => packages/rocketchat-ui}/views/app/privateHistory.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/privateHistory.html (100%) rename {client => packages/rocketchat-ui}/views/app/room.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/room.html (100%) rename {client => packages/rocketchat-ui}/views/app/roomSearch.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/roomSearch.html (100%) rename {client => packages/rocketchat-ui}/views/app/spotlight/mobileMessageMenu.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/spotlight/mobileMessageMenu.html (100%) rename {client => packages/rocketchat-ui}/views/app/spotlight/spotlight.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/spotlight/spotlight.html (100%) rename {client => packages/rocketchat-ui}/views/app/tabBar/membersList.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/tabBar/membersList.html (100%) rename {client => packages/rocketchat-ui}/views/app/tabBar/messageSearch.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/tabBar/messageSearch.html (100%) rename {client => packages/rocketchat-ui}/views/app/tabBar/uploadedFilesList.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/tabBar/uploadedFilesList.html (100%) rename {client => packages/rocketchat-ui}/views/app/userInfo.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/userInfo.html (100%) rename {client => packages/rocketchat-ui}/views/app/userSearch.html (100%) rename {client => packages/rocketchat-ui}/views/app/videoCall/videoButtons.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/videoCall/videoButtons.html (100%) rename {client => packages/rocketchat-ui}/views/app/videoCall/videoCall.coffee (100%) rename {client => packages/rocketchat-ui}/views/app/videoCall/videoCall.html (100%) rename {client => packages/rocketchat-ui}/views/cmsPage.coffee (100%) rename {client => packages/rocketchat-ui}/views/cmsPage.html (100%) rename {client => packages/rocketchat-ui}/views/error.html (100%) rename {client => packages/rocketchat-ui}/views/fxos.coffee (100%) rename {client => packages/rocketchat-ui}/views/fxos.html (100%) rename {client => packages/rocketchat-ui}/views/loading.html (100%) rename {client => packages/rocketchat-ui}/views/main.coffee (100%) rename {client => packages/rocketchat-ui}/views/main.html (100%) rename {client => packages/rocketchat-ui}/views/modal.coffee (100%) rename {client => packages/rocketchat-ui}/views/modal.html (100%) rename {client => packages/rocketchat-ui}/views/username/layout.html (100%) rename {client => packages/rocketchat-ui}/views/username/username.coffee (100%) rename {client => packages/rocketchat-ui}/views/username/username.html (100%) diff --git a/.meteor/packages b/.meteor/packages index 719996033a2..4780122cfc8 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -113,3 +113,8 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter +rocketchat:rocketchat-ui +rocketchat:rocketchat-ui-sidenav +rocketchat:rocketchat-ui-account +rocketchat:rocketchat-ui-admin +rocketchat:rocketchat-ui-login diff --git a/.meteor/versions b/.meteor/versions index 06e1c2c87c1..5fb5f258908 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -142,6 +142,11 @@ rocketchat:mentions@0.0.1 rocketchat:message-pin@0.0.1 rocketchat:message-star@0.0.1 rocketchat:oembed@0.0.1 +rocketchat:rocketchat-ui@0.1.0 +rocketchat:rocketchat-ui-account@0.0.1 +rocketchat:rocketchat-ui-admin@0.0.1 +rocketchat:rocketchat-ui-login@0.0.1 +rocketchat:rocketchat-ui-sidenav@0.1.0 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 rocketchat:slashcommands-leave@0.0.1 diff --git a/client/lib/accounts.coffee b/client/lib/accounts.coffee deleted file mode 100644 index 05c7d4e2ea7..00000000000 --- a/client/lib/accounts.coffee +++ /dev/null @@ -1,16 +0,0 @@ -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 diff --git a/client/views/login/social.coffee b/packages/rocketchat-ui-account/README.md similarity index 100% rename from client/views/login/social.coffee rename to packages/rocketchat-ui-account/README.md diff --git a/client/views/account/account.coffee b/packages/rocketchat-ui-account/account/account.coffee similarity index 100% rename from client/views/account/account.coffee rename to packages/rocketchat-ui-account/account/account.coffee diff --git a/client/views/account/account.html b/packages/rocketchat-ui-account/account/account.html similarity index 100% rename from client/views/account/account.html rename to packages/rocketchat-ui-account/account/account.html diff --git a/client/views/account/accountFlex.coffee b/packages/rocketchat-ui-account/account/accountFlex.coffee similarity index 100% rename from client/views/account/accountFlex.coffee rename to packages/rocketchat-ui-account/account/accountFlex.coffee diff --git a/client/views/account/accountFlex.html b/packages/rocketchat-ui-account/account/accountFlex.html similarity index 100% rename from client/views/account/accountFlex.html rename to packages/rocketchat-ui-account/account/accountFlex.html diff --git a/client/views/account/accountPreferences.coffee b/packages/rocketchat-ui-account/account/accountPreferences.coffee similarity index 100% rename from client/views/account/accountPreferences.coffee rename to packages/rocketchat-ui-account/account/accountPreferences.coffee diff --git a/client/views/account/accountPreferences.html b/packages/rocketchat-ui-account/account/accountPreferences.html similarity index 100% rename from client/views/account/accountPreferences.html rename to packages/rocketchat-ui-account/account/accountPreferences.html diff --git a/client/views/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee similarity index 100% rename from client/views/account/accountProfile.coffee rename to packages/rocketchat-ui-account/account/accountProfile.coffee diff --git a/client/views/account/accountProfile.html b/packages/rocketchat-ui-account/account/accountProfile.html similarity index 100% rename from client/views/account/accountProfile.html rename to packages/rocketchat-ui-account/account/accountProfile.html diff --git a/client/views/account/avatar/avatar.coffee b/packages/rocketchat-ui-account/account/avatar/avatar.coffee similarity index 100% rename from client/views/account/avatar/avatar.coffee rename to packages/rocketchat-ui-account/account/avatar/avatar.coffee diff --git a/client/views/account/avatar/avatar.html b/packages/rocketchat-ui-account/account/avatar/avatar.html similarity index 100% rename from client/views/account/avatar/avatar.html rename to packages/rocketchat-ui-account/account/avatar/avatar.html diff --git a/client/views/account/avatar/prompt.coffee b/packages/rocketchat-ui-account/account/avatar/prompt.coffee similarity index 100% rename from client/views/account/avatar/prompt.coffee rename to packages/rocketchat-ui-account/account/avatar/prompt.coffee diff --git a/client/views/account/avatar/prompt.html b/packages/rocketchat-ui-account/account/avatar/prompt.html similarity index 100% rename from client/views/account/avatar/prompt.html rename to packages/rocketchat-ui-account/account/avatar/prompt.html diff --git a/packages/rocketchat-ui-account/package.js b/packages/rocketchat-ui-account/package.js new file mode 100644 index 00000000000..e6f617f4ce9 --- /dev/null +++ b/packages/rocketchat-ui-account/package.js @@ -0,0 +1,39 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-account', + version: '0.0.1', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('account/account.html', 'client'); + api.addFiles('account/accountFlex.html', 'client'); + api.addFiles('account/accountPreferences.html', 'client'); + api.addFiles('account/accountProfile.html', 'client'); + api.addFiles('account/avatar/avatar.html', 'client'); + api.addFiles('account/avatar/prompt.html', 'client'); + + api.addFiles('account/account.coffee', 'client'); + api.addFiles('account/accountFlex.coffee', 'client'); + api.addFiles('account/accountPreferences.coffee', 'client'); + api.addFiles('account/accountProfile.coffee', 'client'); + api.addFiles('account/avatar/avatar.coffee', 'client'); + 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-account/rocketchat-ui-account-tests.js b/packages/rocketchat-ui-account/rocketchat-ui-account-tests.js new file mode 100644 index 00000000000..c5623d89b9b --- /dev/null +++ b/packages/rocketchat-ui-account/rocketchat-ui-account-tests.js @@ -0,0 +1,5 @@ +// Write your tests here! +// Here is an example. +Tinytest.add('example', function (test) { + test.equal(true, true); +}); diff --git a/packages/rocketchat-ui-account/rocketchat-ui-account.js b/packages/rocketchat-ui-account/rocketchat-ui-account.js new file mode 100644 index 00000000000..164ddd9eed0 --- /dev/null +++ b/packages/rocketchat-ui-account/rocketchat-ui-account.js @@ -0,0 +1 @@ +// Write your package code here! diff --git a/packages/rocketchat-ui-account/styles/account.less b/packages/rocketchat-ui-account/styles/account.less new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-ui-admin/README.md b/packages/rocketchat-ui-admin/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/client/views/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee similarity index 100% rename from client/views/admin/admin.coffee rename to packages/rocketchat-ui-admin/admin/admin.coffee diff --git a/client/views/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html similarity index 100% rename from client/views/admin/admin.html rename to packages/rocketchat-ui-admin/admin/admin.html diff --git a/client/views/admin/adminFlex.coffee b/packages/rocketchat-ui-admin/admin/adminFlex.coffee similarity index 100% rename from client/views/admin/adminFlex.coffee rename to packages/rocketchat-ui-admin/admin/adminFlex.coffee diff --git a/client/views/admin/adminFlex.html b/packages/rocketchat-ui-admin/admin/adminFlex.html similarity index 100% rename from client/views/admin/adminFlex.html rename to packages/rocketchat-ui-admin/admin/adminFlex.html diff --git a/client/views/admin/adminStatistics.coffee b/packages/rocketchat-ui-admin/admin/adminStatistics.coffee similarity index 100% rename from client/views/admin/adminStatistics.coffee rename to packages/rocketchat-ui-admin/admin/adminStatistics.coffee diff --git a/client/views/admin/adminStatistics.html b/packages/rocketchat-ui-admin/admin/adminStatistics.html similarity index 100% rename from client/views/admin/adminStatistics.html rename to packages/rocketchat-ui-admin/admin/adminStatistics.html diff --git a/client/views/admin/rooms/adminRoomInfo.coffee b/packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.coffee similarity index 100% rename from client/views/admin/rooms/adminRoomInfo.coffee rename to packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.coffee diff --git a/client/views/admin/rooms/adminRoomInfo.html b/packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.html similarity index 100% rename from client/views/admin/rooms/adminRoomInfo.html rename to packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.html diff --git a/client/views/admin/rooms/adminRooms.coffee b/packages/rocketchat-ui-admin/admin/rooms/adminRooms.coffee similarity index 100% rename from client/views/admin/rooms/adminRooms.coffee rename to packages/rocketchat-ui-admin/admin/rooms/adminRooms.coffee diff --git a/client/views/admin/rooms/adminRooms.html b/packages/rocketchat-ui-admin/admin/rooms/adminRooms.html similarity index 100% rename from client/views/admin/rooms/adminRooms.html rename to packages/rocketchat-ui-admin/admin/rooms/adminRooms.html diff --git a/client/views/admin/users/adminInviteUser.coffee b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.coffee similarity index 100% rename from client/views/admin/users/adminInviteUser.coffee rename to packages/rocketchat-ui-admin/admin/users/adminInviteUser.coffee diff --git a/client/views/admin/users/adminInviteUser.html b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html similarity index 100% rename from client/views/admin/users/adminInviteUser.html rename to packages/rocketchat-ui-admin/admin/users/adminInviteUser.html diff --git a/client/views/admin/users/adminUserChannels.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserChannels.coffee similarity index 100% rename from client/views/admin/users/adminUserChannels.coffee rename to packages/rocketchat-ui-admin/admin/users/adminUserChannels.coffee diff --git a/client/views/admin/users/adminUserChannels.html b/packages/rocketchat-ui-admin/admin/users/adminUserChannels.html similarity index 100% rename from client/views/admin/users/adminUserChannels.html rename to packages/rocketchat-ui-admin/admin/users/adminUserChannels.html diff --git a/client/views/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee similarity index 100% rename from client/views/admin/users/adminUserEdit.coffee rename to packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee diff --git a/client/views/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html similarity index 100% rename from client/views/admin/users/adminUserEdit.html rename to packages/rocketchat-ui-admin/admin/users/adminUserEdit.html diff --git a/client/views/admin/users/adminUserInfo.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserInfo.coffee similarity index 100% rename from client/views/admin/users/adminUserInfo.coffee rename to packages/rocketchat-ui-admin/admin/users/adminUserInfo.coffee diff --git a/client/views/admin/users/adminUserInfo.html b/packages/rocketchat-ui-admin/admin/users/adminUserInfo.html similarity index 100% rename from client/views/admin/users/adminUserInfo.html rename to packages/rocketchat-ui-admin/admin/users/adminUserInfo.html diff --git a/client/views/admin/users/adminUsers.coffee b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee similarity index 100% rename from client/views/admin/users/adminUsers.coffee rename to packages/rocketchat-ui-admin/admin/users/adminUsers.coffee diff --git a/client/views/admin/users/adminUsers.html b/packages/rocketchat-ui-admin/admin/users/adminUsers.html similarity index 100% rename from client/views/admin/users/adminUsers.html rename to packages/rocketchat-ui-admin/admin/users/adminUsers.html diff --git a/packages/rocketchat-ui-admin/package.js b/packages/rocketchat-ui-admin/package.js new file mode 100644 index 00000000000..22967b6a286 --- /dev/null +++ b/packages/rocketchat-ui-admin/package.js @@ -0,0 +1,54 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-admin', + version: '0.0.1', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + // template files + api.addFiles('admin/admin.html', 'client'); + api.addFiles('admin/adminFlex.html', 'client'); + api.addFiles('admin/adminStatistics.html', 'client'); + + api.addFiles('admin/rooms/adminRoomInfo.html', 'client'); + api.addFiles('admin/rooms/adminRooms.html', 'client'); + + api.addFiles('admin/users/adminInviteUser.html', 'client'); + api.addFiles('admin/users/adminUserChannels.html', 'client'); + api.addFiles('admin/users/adminUserEdit.html', 'client'); + api.addFiles('admin/users/adminUserInfo.html', 'client'); + api.addFiles('admin/users/adminUsers.html', 'client'); + + // coffee files + api.addFiles('admin/admin.coffee', 'client'); + api.addFiles('admin/adminFlex.coffee', 'client'); + api.addFiles('admin/adminStatistics.coffee', 'client'); + + api.addFiles('admin/rooms/adminRoomInfo.coffee', 'client'); + api.addFiles('admin/rooms/adminRooms.coffee', 'client'); + + api.addFiles('admin/users/adminInviteUser.coffee', 'client'); + api.addFiles('admin/users/adminUserChannels.coffee', 'client'); + api.addFiles('admin/users/adminUserEdit.coffee', 'client'); + api.addFiles('admin/users/adminUserInfo.coffee', 'client'); + api.addFiles('admin/users/adminUsers.coffee', 'client'); + + + // api.addAssets('styles/side-nav.less', 'client'); +}); diff --git a/packages/rocketchat-ui-admin/rocketchat-ui-admin-tests.js b/packages/rocketchat-ui-admin/rocketchat-ui-admin-tests.js new file mode 100644 index 00000000000..c5623d89b9b --- /dev/null +++ b/packages/rocketchat-ui-admin/rocketchat-ui-admin-tests.js @@ -0,0 +1,5 @@ +// Write your tests here! +// Here is an example. +Tinytest.add('example', function (test) { + test.equal(true, true); +}); diff --git a/packages/rocketchat-ui-admin/rocketchat-ui-admin.js b/packages/rocketchat-ui-admin/rocketchat-ui-admin.js new file mode 100644 index 00000000000..164ddd9eed0 --- /dev/null +++ b/packages/rocketchat-ui-admin/rocketchat-ui-admin.js @@ -0,0 +1 @@ +// Write your package code here! diff --git a/packages/rocketchat-ui-login/README.md b/packages/rocketchat-ui-login/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/client/views/login/footer.coffee b/packages/rocketchat-ui-login/login/footer.coffee similarity index 100% rename from client/views/login/footer.coffee rename to packages/rocketchat-ui-login/login/footer.coffee diff --git a/client/views/login/footer.html b/packages/rocketchat-ui-login/login/footer.html similarity index 100% rename from client/views/login/footer.html rename to packages/rocketchat-ui-login/login/footer.html diff --git a/client/views/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee similarity index 100% rename from client/views/login/form.coffee rename to packages/rocketchat-ui-login/login/form.coffee diff --git a/client/views/login/form.html b/packages/rocketchat-ui-login/login/form.html similarity index 100% rename from client/views/login/form.html rename to packages/rocketchat-ui-login/login/form.html diff --git a/client/views/login/header.coffee b/packages/rocketchat-ui-login/login/header.coffee similarity index 100% rename from client/views/login/header.coffee rename to packages/rocketchat-ui-login/login/header.coffee diff --git a/client/views/login/header.html b/packages/rocketchat-ui-login/login/header.html similarity index 100% rename from client/views/login/header.html rename to packages/rocketchat-ui-login/login/header.html diff --git a/client/views/login/intro.html b/packages/rocketchat-ui-login/login/intro.html similarity index 100% rename from client/views/login/intro.html rename to packages/rocketchat-ui-login/login/intro.html diff --git a/client/views/login/layout.html b/packages/rocketchat-ui-login/login/layout.html similarity index 100% rename from client/views/login/layout.html rename to packages/rocketchat-ui-login/login/layout.html diff --git a/client/views/login/services.coffee b/packages/rocketchat-ui-login/login/services.coffee similarity index 100% rename from client/views/login/services.coffee rename to packages/rocketchat-ui-login/login/services.coffee diff --git a/client/views/login/services.html b/packages/rocketchat-ui-login/login/services.html similarity index 100% rename from client/views/login/services.html rename to packages/rocketchat-ui-login/login/services.html diff --git a/packages/rocketchat-ui-login/login/social.coffee b/packages/rocketchat-ui-login/login/social.coffee new file mode 100644 index 00000000000..e69de29bb2d diff --git a/client/views/login/social.html b/packages/rocketchat-ui-login/login/social.html similarity index 100% rename from client/views/login/social.html rename to packages/rocketchat-ui-login/login/social.html diff --git a/packages/rocketchat-ui-login/package.js b/packages/rocketchat-ui-login/package.js new file mode 100644 index 00000000000..a24f33f3466 --- /dev/null +++ b/packages/rocketchat-ui-login/package.js @@ -0,0 +1,39 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-login', + version: '0.0.1', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('login/footer.html', 'client'); + api.addFiles('login/form.html', 'client'); + api.addFiles('login/header.html', 'client'); + api.addFiles('login/intro.html', 'client'); + api.addFiles('login/layout.html', 'client'); + api.addFiles('login/services.html', 'client'); + api.addFiles('login/social.html', 'client'); + + api.addFiles('login/footer.coffee', 'client'); + api.addFiles('login/form.coffee', 'client'); + api.addFiles('login/header.coffee', 'client'); + api.addFiles('login/services.coffee', 'client'); + api.addFiles('login/social.coffee', 'client'); + + // api.addAssets('styles/side-nav.less', 'client'); +}); \ No newline at end of file diff --git a/packages/rocketchat-ui-sidenav/.npm/package/.gitignore b/packages/rocketchat-ui-sidenav/.npm/package/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/packages/rocketchat-ui-sidenav/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/rocketchat-ui-sidenav/.npm/package/README b/packages/rocketchat-ui-sidenav/.npm/package/README new file mode 100644 index 00000000000..3d492553a43 --- /dev/null +++ b/packages/rocketchat-ui-sidenav/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/rocketchat-ui-sidenav/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-ui-sidenav/.npm/package/npm-shrinkwrap.json new file mode 100644 index 00000000000..943eb58f7fd --- /dev/null +++ b/packages/rocketchat-ui-sidenav/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,285 @@ +{ + "dependencies": { + "less": { + "version": "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6", + "dependencies": { + "errno": { + "version": "0.1.4", + "dependencies": { + "prr": { + "version": "0.0.0" + } + } + }, + "graceful-fs": { + "version": "3.0.8" + }, + "image-size": { + "version": "0.3.5" + }, + "mime": { + "version": "1.3.4" + }, + "mkdirp": { + "version": "0.5.1", + "dependencies": { + "minimist": { + "version": "0.0.8" + } + } + }, + "promise": { + "version": "6.1.0", + "dependencies": { + "asap": { + "version": "1.0.0" + } + } + }, + "request": { + "version": "2.65.0", + "dependencies": { + "bl": { + "version": "1.0.0", + "dependencies": { + "readable-stream": { + "version": "2.0.4", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "inherits": { + "version": "2.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "process-nextick-args": { + "version": "1.0.3" + }, + "string_decoder": { + "version": "0.10.31" + }, + "util-deprecate": { + "version": "1.0.2" + } + } + } + } + }, + "caseless": { + "version": "0.11.0" + }, + "extend": { + "version": "3.0.0" + }, + "forever-agent": { + "version": "0.6.1" + }, + "form-data": { + "version": "1.0.0-rc3", + "dependencies": { + "async": { + "version": "1.5.0" + } + } + }, + "json-stringify-safe": { + "version": "5.0.1" + }, + "mime-types": { + "version": "2.1.7", + "dependencies": { + "mime-db": { + "version": "1.19.0" + } + } + }, + "node-uuid": { + "version": "1.4.7" + }, + "qs": { + "version": "5.2.0" + }, + "tunnel-agent": { + "version": "0.4.1" + }, + "tough-cookie": { + "version": "2.2.1" + }, + "http-signature": { + "version": "0.11.0", + "dependencies": { + "assert-plus": { + "version": "0.1.5" + }, + "asn1": { + "version": "0.1.11" + }, + "ctype": { + "version": "0.5.3" + } + } + }, + "oauth-sign": { + "version": "0.8.0" + }, + "hawk": { + "version": "3.1.1", + "dependencies": { + "hoek": { + "version": "2.16.3" + }, + "boom": { + "version": "2.10.1" + }, + "cryptiles": { + "version": "2.0.5" + }, + "sntp": { + "version": "1.0.9" + } + } + }, + "aws-sign2": { + "version": "0.6.0" + }, + "stringstream": { + "version": "0.0.5" + }, + "combined-stream": { + "version": "1.0.5", + "dependencies": { + "delayed-stream": { + "version": "1.0.0" + } + } + }, + "isstream": { + "version": "0.1.2" + }, + "har-validator": { + "version": "2.0.2", + "dependencies": { + "chalk": { + "version": "1.1.1", + "dependencies": { + "ansi-styles": { + "version": "2.1.0" + }, + "escape-string-regexp": { + "version": "1.0.3" + }, + "has-ansi": { + "version": "2.0.0", + "dependencies": { + "ansi-regex": { + "version": "2.0.0" + } + } + }, + "strip-ansi": { + "version": "3.0.0", + "dependencies": { + "ansi-regex": { + "version": "2.0.0" + } + } + }, + "supports-color": { + "version": "2.0.0" + } + } + }, + "commander": { + "version": "2.9.0", + "dependencies": { + "graceful-readlink": { + "version": "1.0.1" + } + } + }, + "is-my-json-valid": { + "version": "2.12.3", + "dependencies": { + "generate-function": { + "version": "2.0.0" + }, + "generate-object-property": { + "version": "1.2.0", + "dependencies": { + "is-property": { + "version": "1.0.2" + } + } + }, + "jsonpointer": { + "version": "2.0.0" + }, + "xtend": { + "version": "4.0.1" + } + } + }, + "pinkie-promise": { + "version": "1.0.0", + "dependencies": { + "pinkie": { + "version": "1.0.0" + } + } + } + } + } + } + }, + "source-map": { + "version": "0.4.4", + "dependencies": { + "amdefine": { + "version": "1.0.0" + } + } + } + } + }, + "less-plugin-autoprefix": { + "version": "1.4.2", + "dependencies": { + "autoprefixer-core": { + "version": "5.2.1", + "dependencies": { + "browserslist": { + "version": "0.4.0" + }, + "num2fraction": { + "version": "1.2.2" + }, + "caniuse-db": { + "version": "1.0.30000362" + } + } + }, + "postcss": { + "version": "4.1.16", + "dependencies": { + "es6-promise": { + "version": "2.3.0" + }, + "source-map": { + "version": "0.4.4", + "dependencies": { + "amdefine": { + "version": "1.0.0" + } + } + }, + "js-base64": { + "version": "2.1.9" + } + } + } + } + } + } +} diff --git a/packages/rocketchat-ui-sidenav/README.md b/packages/rocketchat-ui-sidenav/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js new file mode 100644 index 00000000000..041b15f5d7e --- /dev/null +++ b/packages/rocketchat-ui-sidenav/package.js @@ -0,0 +1,54 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-sidenav', + version: '0.1.0', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('side-nav/channels.html', 'client'); + api.addFiles('side-nav/chatRoomItem.html', 'client'); + api.addFiles('side-nav/createChannelFlex.html', 'client'); + api.addFiles('side-nav/directMessages.html', 'client'); + api.addFiles('side-nav/listChannelsFlex.html', 'client'); + api.addFiles('side-nav/listPrivateGroupsFlex.html', 'client'); + api.addFiles('side-nav/privateGroups.html', 'client'); + api.addFiles('side-nav/privateGroupsFlex.html', 'client'); + api.addFiles('side-nav/sideNav.html', 'client'); + api.addFiles('side-nav/starredRooms.html', 'client'); + api.addFiles('side-nav/unreadRooms.html', 'client'); + api.addFiles('side-nav/userStatus.html', 'client'); + + api.addFiles('side-nav/channels.coffee', 'client'); + api.addFiles('side-nav/chatRoomItem.coffee', 'client'); + api.addFiles('side-nav/createChannelFlex.coffee', 'client'); + api.addFiles('side-nav/directMessages.coffee', 'client'); + api.addFiles('side-nav/listChannelsFlex.coffee', 'client'); + api.addFiles('side-nav/listPrivateGroupsFlex.coffee', 'client'); + api.addFiles('side-nav/privateGroups.coffee', 'client'); + api.addFiles('side-nav/privateGroupsFlex.coffee', 'client'); + api.addFiles('side-nav/sideNav.coffee', 'client'); + api.addFiles('side-nav/starredRooms.coffee', 'client'); + api.addFiles('side-nav/unreadRooms.coffee', 'client'); + +}); + +Npm.depends({ + 'less': 'https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6', + 'less-plugin-autoprefix': '1.4.2' +}); diff --git a/client/views/app/sideNav/channels.coffee b/packages/rocketchat-ui-sidenav/side-nav/channels.coffee similarity index 100% rename from client/views/app/sideNav/channels.coffee rename to packages/rocketchat-ui-sidenav/side-nav/channels.coffee diff --git a/client/views/app/sideNav/channels.html b/packages/rocketchat-ui-sidenav/side-nav/channels.html similarity index 100% rename from client/views/app/sideNav/channels.html rename to packages/rocketchat-ui-sidenav/side-nav/channels.html diff --git a/client/views/app/sideNav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee similarity index 100% rename from client/views/app/sideNav/chatRoomItem.coffee rename to packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee diff --git a/client/views/app/sideNav/chatRoomItem.html b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html similarity index 100% rename from client/views/app/sideNav/chatRoomItem.html rename to packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html diff --git a/client/views/app/sideNav/createChannelFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee similarity index 100% rename from client/views/app/sideNav/createChannelFlex.coffee rename to packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee diff --git a/client/views/app/sideNav/createChannelFlex.html b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.html similarity index 100% rename from client/views/app/sideNav/createChannelFlex.html rename to packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.html diff --git a/client/views/app/sideNav/directMessages.coffee b/packages/rocketchat-ui-sidenav/side-nav/directMessages.coffee similarity index 100% rename from client/views/app/sideNav/directMessages.coffee rename to packages/rocketchat-ui-sidenav/side-nav/directMessages.coffee diff --git a/client/views/app/sideNav/directMessages.html b/packages/rocketchat-ui-sidenav/side-nav/directMessages.html similarity index 100% rename from client/views/app/sideNav/directMessages.html rename to packages/rocketchat-ui-sidenav/side-nav/directMessages.html diff --git a/client/views/app/sideNav/directMessagesFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/directMessagesFlex.coffee similarity index 100% rename from client/views/app/sideNav/directMessagesFlex.coffee rename to packages/rocketchat-ui-sidenav/side-nav/directMessagesFlex.coffee diff --git a/client/views/app/sideNav/directMessagesFlex.html b/packages/rocketchat-ui-sidenav/side-nav/directMessagesFlex.html similarity index 100% rename from client/views/app/sideNav/directMessagesFlex.html rename to packages/rocketchat-ui-sidenav/side-nav/directMessagesFlex.html diff --git a/client/views/app/sideNav/listChannelsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/listChannelsFlex.coffee similarity index 100% rename from client/views/app/sideNav/listChannelsFlex.coffee rename to packages/rocketchat-ui-sidenav/side-nav/listChannelsFlex.coffee diff --git a/client/views/app/sideNav/listChannelsFlex.html b/packages/rocketchat-ui-sidenav/side-nav/listChannelsFlex.html similarity index 100% rename from client/views/app/sideNav/listChannelsFlex.html rename to packages/rocketchat-ui-sidenav/side-nav/listChannelsFlex.html diff --git a/client/views/app/sideNav/listPrivateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee similarity index 100% rename from client/views/app/sideNav/listPrivateGroupsFlex.coffee rename to packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee diff --git a/client/views/app/sideNav/listPrivateGroupsFlex.html b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.html similarity index 100% rename from client/views/app/sideNav/listPrivateGroupsFlex.html rename to packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.html diff --git a/client/views/app/sideNav/privateGroups.coffee b/packages/rocketchat-ui-sidenav/side-nav/privateGroups.coffee similarity index 100% rename from client/views/app/sideNav/privateGroups.coffee rename to packages/rocketchat-ui-sidenav/side-nav/privateGroups.coffee diff --git a/client/views/app/sideNav/privateGroups.html b/packages/rocketchat-ui-sidenav/side-nav/privateGroups.html similarity index 100% rename from client/views/app/sideNav/privateGroups.html rename to packages/rocketchat-ui-sidenav/side-nav/privateGroups.html diff --git a/client/views/app/sideNav/privateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee similarity index 100% rename from client/views/app/sideNav/privateGroupsFlex.coffee rename to packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee diff --git a/client/views/app/sideNav/privateGroupsFlex.html b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html similarity index 100% rename from client/views/app/sideNav/privateGroupsFlex.html rename to packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html diff --git a/client/views/app/sideNav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee similarity index 100% rename from client/views/app/sideNav/sideNav.coffee rename to packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee diff --git a/client/views/app/sideNav/sideNav.html b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html similarity index 100% rename from client/views/app/sideNav/sideNav.html rename to packages/rocketchat-ui-sidenav/side-nav/sideNav.html diff --git a/client/views/app/sideNav/starredRooms.coffee b/packages/rocketchat-ui-sidenav/side-nav/starredRooms.coffee similarity index 100% rename from client/views/app/sideNav/starredRooms.coffee rename to packages/rocketchat-ui-sidenav/side-nav/starredRooms.coffee diff --git a/client/views/app/sideNav/starredRooms.html b/packages/rocketchat-ui-sidenav/side-nav/starredRooms.html similarity index 100% rename from client/views/app/sideNav/starredRooms.html rename to packages/rocketchat-ui-sidenav/side-nav/starredRooms.html diff --git a/client/views/app/sideNav/unreadRooms.coffee b/packages/rocketchat-ui-sidenav/side-nav/unreadRooms.coffee similarity index 100% rename from client/views/app/sideNav/unreadRooms.coffee rename to packages/rocketchat-ui-sidenav/side-nav/unreadRooms.coffee diff --git a/client/views/app/sideNav/unreadRooms.html b/packages/rocketchat-ui-sidenav/side-nav/unreadRooms.html similarity index 100% rename from client/views/app/sideNav/unreadRooms.html rename to packages/rocketchat-ui-sidenav/side-nav/unreadRooms.html diff --git a/client/views/app/sideNav/userStatus.html b/packages/rocketchat-ui-sidenav/side-nav/userStatus.html similarity index 100% rename from client/views/app/sideNav/userStatus.html rename to packages/rocketchat-ui-sidenav/side-nav/userStatus.html diff --git a/packages/rocketchat-ui-sidenav/styles/side-nav.less b/packages/rocketchat-ui-sidenav/styles/side-nav.less new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-ui/README.md b/packages/rocketchat-ui/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/client/lib/Modernizr.js b/packages/rocketchat-ui/lib/Modernizr.js similarity index 100% rename from client/lib/Modernizr.js rename to packages/rocketchat-ui/lib/Modernizr.js diff --git a/client/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee similarity index 100% rename from client/lib/RoomHistoryManager.coffee rename to packages/rocketchat-ui/lib/RoomHistoryManager.coffee diff --git a/client/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee similarity index 100% rename from client/lib/RoomManager.coffee rename to packages/rocketchat-ui/lib/RoomManager.coffee diff --git a/client/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee similarity index 100% rename from client/lib/accountBox.coffee rename to packages/rocketchat-ui/lib/accountBox.coffee diff --git a/packages/rocketchat-ui/lib/accounts.coffee b/packages/rocketchat-ui/lib/accounts.coffee new file mode 100644 index 00000000000..d81d0e7c5a4 --- /dev/null +++ b/packages/rocketchat-ui/lib/accounts.coffee @@ -0,0 +1,17 @@ +Meteor.startup -> + 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 diff --git a/client/lib/avatar.coffee b/packages/rocketchat-ui/lib/avatar.coffee similarity index 100% rename from client/lib/avatar.coffee rename to packages/rocketchat-ui/lib/avatar.coffee diff --git a/client/lib/chatMessages.coffee b/packages/rocketchat-ui/lib/chatMessages.coffee similarity index 100% rename from client/lib/chatMessages.coffee rename to packages/rocketchat-ui/lib/chatMessages.coffee diff --git a/client/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee similarity index 100% rename from client/lib/collections.coffee rename to packages/rocketchat-ui/lib/collections.coffee diff --git a/client/lib/constallation.js b/packages/rocketchat-ui/lib/constallation.js similarity index 100% rename from client/lib/constallation.js rename to packages/rocketchat-ui/lib/constallation.js diff --git a/client/lib/cordova/facebook-login.coffee b/packages/rocketchat-ui/lib/cordova/facebook-login.coffee similarity index 100% rename from client/lib/cordova/facebook-login.coffee rename to packages/rocketchat-ui/lib/cordova/facebook-login.coffee diff --git a/client/lib/cordova/keyboard-fix.coffee b/packages/rocketchat-ui/lib/cordova/keyboard-fix.coffee similarity index 100% rename from client/lib/cordova/keyboard-fix.coffee rename to packages/rocketchat-ui/lib/cordova/keyboard-fix.coffee diff --git a/client/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee similarity index 100% rename from client/lib/cordova/push.coffee rename to packages/rocketchat-ui/lib/cordova/push.coffee diff --git a/client/lib/cordova/urls.coffee b/packages/rocketchat-ui/lib/cordova/urls.coffee similarity index 100% rename from client/lib/cordova/urls.coffee rename to packages/rocketchat-ui/lib/cordova/urls.coffee diff --git a/client/lib/cordova/user-state.coffee b/packages/rocketchat-ui/lib/cordova/user-state.coffee similarity index 100% rename from client/lib/cordova/user-state.coffee rename to packages/rocketchat-ui/lib/cordova/user-state.coffee diff --git a/client/lib/customEventPolyfill.js b/packages/rocketchat-ui/lib/customEventPolyfill.js similarity index 100% rename from client/lib/customEventPolyfill.js rename to packages/rocketchat-ui/lib/customEventPolyfill.js diff --git a/client/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee similarity index 100% rename from client/lib/fileUpload.coffee rename to packages/rocketchat-ui/lib/fileUpload.coffee diff --git a/client/lib/fireEvent.coffee b/packages/rocketchat-ui/lib/fireEvent.coffee similarity index 100% rename from client/lib/fireEvent.coffee rename to packages/rocketchat-ui/lib/fireEvent.coffee diff --git a/client/lib/jquery.swipebox.min.js b/packages/rocketchat-ui/lib/jquery.swipebox.min.js similarity index 100% rename from client/lib/jquery.swipebox.min.js rename to packages/rocketchat-ui/lib/jquery.swipebox.min.js diff --git a/client/lib/menu.coffee b/packages/rocketchat-ui/lib/menu.coffee similarity index 100% rename from client/lib/menu.coffee rename to packages/rocketchat-ui/lib/menu.coffee diff --git a/client/lib/modal.coffee b/packages/rocketchat-ui/lib/modal.coffee similarity index 100% rename from client/lib/modal.coffee rename to packages/rocketchat-ui/lib/modal.coffee diff --git a/client/lib/msgTyping.coffee b/packages/rocketchat-ui/lib/msgTyping.coffee similarity index 100% rename from client/lib/msgTyping.coffee rename to packages/rocketchat-ui/lib/msgTyping.coffee diff --git a/client/lib/notification.coffee b/packages/rocketchat-ui/lib/notification.coffee similarity index 100% rename from client/lib/notification.coffee rename to packages/rocketchat-ui/lib/notification.coffee diff --git a/client/lib/parentTemplate.js b/packages/rocketchat-ui/lib/parentTemplate.js similarity index 100% rename from client/lib/parentTemplate.js rename to packages/rocketchat-ui/lib/parentTemplate.js diff --git a/client/lib/particles.js b/packages/rocketchat-ui/lib/particles.js similarity index 100% rename from client/lib/particles.js rename to packages/rocketchat-ui/lib/particles.js diff --git a/client/lib/readMessages.coffee b/packages/rocketchat-ui/lib/readMessages.coffee similarity index 100% rename from client/lib/readMessages.coffee rename to packages/rocketchat-ui/lib/readMessages.coffee diff --git a/client/lib/recorderjs/audioRecorder.coffee b/packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee similarity index 100% rename from client/lib/recorderjs/audioRecorder.coffee rename to packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee diff --git a/client/lib/recorderjs/recorder.js b/packages/rocketchat-ui/lib/recorderjs/recorder.js similarity index 100% rename from client/lib/recorderjs/recorder.js rename to packages/rocketchat-ui/lib/recorderjs/recorder.js diff --git a/client/lib/rocket.coffee b/packages/rocketchat-ui/lib/rocket.coffee similarity index 100% rename from client/lib/rocket.coffee rename to packages/rocketchat-ui/lib/rocket.coffee diff --git a/client/lib/sideNav.coffee b/packages/rocketchat-ui/lib/sideNav.coffee similarity index 100% rename from client/lib/sideNav.coffee rename to packages/rocketchat-ui/lib/sideNav.coffee diff --git a/client/lib/tapi18n.coffee b/packages/rocketchat-ui/lib/tapi18n.coffee similarity index 100% rename from client/lib/tapi18n.coffee rename to packages/rocketchat-ui/lib/tapi18n.coffee diff --git a/client/lib/textarea-autogrow.js b/packages/rocketchat-ui/lib/textarea-autogrow.js similarity index 100% rename from client/lib/textarea-autogrow.js rename to packages/rocketchat-ui/lib/textarea-autogrow.js diff --git a/client/lib/trackRoomNameChanged.coffee b/packages/rocketchat-ui/lib/trackRoomNameChanged.coffee similarity index 100% rename from client/lib/trackRoomNameChanged.coffee rename to packages/rocketchat-ui/lib/trackRoomNameChanged.coffee diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js new file mode 100644 index 00000000000..490bae4b8a8 --- /dev/null +++ b/packages/rocketchat-ui/package.js @@ -0,0 +1,115 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui', + version: '0.1.0', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'mongo', + 'session', + 'jquery', + 'tracker', + 'reactive-var', + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + // LIB FILES + api.addFiles('lib/accountBox.coffee', 'client'); + api.addFiles('lib/accounts.coffee', 'client'); + api.addFiles('lib/avatar.coffee', 'client'); + api.addFiles('lib/chatMessages.coffee', 'client'); + api.addFiles('lib/collections.coffee', 'client'); + api.addFiles('lib/constallation.js', 'client'); + api.addFiles('lib/customEventPolyfill.js', 'client'); + api.addFiles('lib/fileUpload.coffee', 'client'); + api.addFiles('lib/fireEvent.coffee', 'client'); + api.addFiles('lib/jquery.swipebox.min.js', 'client'); + api.addFiles('lib/menu.coffee', 'client'); + api.addFiles('lib/modal.coffee', 'client'); + api.addFiles('lib/Modernizr.js', 'client'); + api.addFiles('lib/msgTyping.coffee', 'client'); + api.addFiles('lib/notification.coffee', 'client'); + api.addFiles('lib/parentTemplate.js', 'client'); + api.addFiles('lib/particles.js', 'client'); + api.addFiles('lib/readMessages.coffee', 'client'); + api.addFiles('lib/rocket.coffee', 'client'); + api.addFiles('lib/RoomHistoryManager.coffee', 'client'); + api.addFiles('lib/RoomManager.coffee', 'client'); + 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'); + + // TEMPLATE FILES + api.addFiles('views/cmsPage.html', 'client'); + api.addFiles('views/error.html', 'client'); + api.addFiles('views/fxos.html', 'client'); + api.addFiles('views/loading.html', 'client'); + api.addFiles('views/main.html', 'client'); + api.addFiles('views/modal.html', 'client'); + api.addFiles('views/404/roomNotFound.html', 'client'); + api.addFiles('views/username/layout.html', 'client'); + api.addFiles('views/username/username.html', 'client'); + api.addFiles('views/app/audioNotification.html', 'client'); + api.addFiles('views/app/burguer.html', 'client'); + api.addFiles('views/app/flexTabBar.html', 'client'); + api.addFiles('views/app/home.html', 'client'); + api.addFiles('views/app/message.html', 'client'); + api.addFiles('views/app/messagePopup.html', 'client'); + api.addFiles('views/app/messagePopupChannel.html', 'client'); + api.addFiles('views/app/messagePopupConfig.html', 'client'); + api.addFiles('views/app/messagePopupEmoji.html', 'client'); + api.addFiles('views/app/messagePopupSlashCommand.html', 'client'); + api.addFiles('views/app/messagePopupUser.html', 'client'); + api.addFiles('views/app/privateHistory.html', 'client'); + api.addFiles('views/app/room.html', 'client'); + api.addFiles('views/app/roomSearch.html', 'client'); + api.addFiles('views/app/userInfo.html', 'client'); + api.addFiles('views/app/userSearch.html', 'client'); + api.addFiles('views/app/spotlight/mobileMessageMenu.html', 'client'); + api.addFiles('views/app/spotlight/spotlight.html', 'client'); + api.addFiles('views/app/tabBar/membersList.html', 'client'); + api.addFiles('views/app/tabBar/messageSearch.html', 'client'); + api.addFiles('views/app/tabBar/uploadedFilesList.html', 'client'); + api.addFiles('views/app/videoCall/videoButtons.html', 'client'); + api.addFiles('views/app/videoCall/videoCall.html', 'client'); + + api.addFiles('views/cmsPage.coffee', 'client'); + api.addFiles('views/fxos.coffee', 'client'); + api.addFiles('views/main.coffee', 'client'); + api.addFiles('views/modal.coffee', 'client'); + api.addFiles('views/404/roomNotFound.coffee', 'client'); + api.addFiles('views/username/username.coffee', 'client'); + api.addFiles('views/app/burguer.coffee', 'client'); + api.addFiles('views/app/flexTabBar.coffee', 'client'); + api.addFiles('views/app/home.coffee', 'client'); + api.addFiles('views/app/message.coffee', 'client'); + api.addFiles('views/app/messagePopup.coffee', 'client'); + api.addFiles('views/app/messagePopupConfig.coffee', 'client'); + api.addFiles('views/app/messagePopupEmoji.coffee', 'client'); + api.addFiles('views/app/privateHistory.coffee', 'client'); + api.addFiles('views/app/room.coffee', 'client'); + api.addFiles('views/app/roomSearch.coffee', 'client'); + api.addFiles('views/app/userInfo.coffee', 'client'); + api.addFiles('views/app/spotlight/mobileMessageMenu.coffee', 'client'); + api.addFiles('views/app/spotlight/spotlight.coffee', 'client'); + api.addFiles('views/app/tabBar/membersList.coffee', 'client'); + api.addFiles('views/app/tabBar/messageSearch.coffee', 'client'); + api.addFiles('views/app/tabBar/uploadedFilesList.coffee', 'client'); + api.addFiles('views/app/videoCall/videoButtons.coffee', 'client'); + api.addFiles('views/app/videoCall/videoCall.coffee', 'client'); + +}); \ No newline at end of file diff --git a/client/views/404/roomNotFound.coffee b/packages/rocketchat-ui/views/404/roomNotFound.coffee similarity index 100% rename from client/views/404/roomNotFound.coffee rename to packages/rocketchat-ui/views/404/roomNotFound.coffee diff --git a/client/views/404/roomNotFound.html b/packages/rocketchat-ui/views/404/roomNotFound.html similarity index 100% rename from client/views/404/roomNotFound.html rename to packages/rocketchat-ui/views/404/roomNotFound.html diff --git a/client/views/app/audioNotification.html b/packages/rocketchat-ui/views/app/audioNotification.html similarity index 100% rename from client/views/app/audioNotification.html rename to packages/rocketchat-ui/views/app/audioNotification.html diff --git a/client/views/app/burguer.coffee b/packages/rocketchat-ui/views/app/burguer.coffee similarity index 100% rename from client/views/app/burguer.coffee rename to packages/rocketchat-ui/views/app/burguer.coffee diff --git a/client/views/app/burguer.html b/packages/rocketchat-ui/views/app/burguer.html similarity index 100% rename from client/views/app/burguer.html rename to packages/rocketchat-ui/views/app/burguer.html diff --git a/client/views/app/flexTabBar.coffee b/packages/rocketchat-ui/views/app/flexTabBar.coffee similarity index 100% rename from client/views/app/flexTabBar.coffee rename to packages/rocketchat-ui/views/app/flexTabBar.coffee diff --git a/client/views/app/flexTabBar.html b/packages/rocketchat-ui/views/app/flexTabBar.html similarity index 100% rename from client/views/app/flexTabBar.html rename to packages/rocketchat-ui/views/app/flexTabBar.html diff --git a/client/views/app/home.coffee b/packages/rocketchat-ui/views/app/home.coffee similarity index 100% rename from client/views/app/home.coffee rename to packages/rocketchat-ui/views/app/home.coffee diff --git a/client/views/app/home.html b/packages/rocketchat-ui/views/app/home.html similarity index 100% rename from client/views/app/home.html rename to packages/rocketchat-ui/views/app/home.html diff --git a/client/views/app/message.coffee b/packages/rocketchat-ui/views/app/message.coffee similarity index 100% rename from client/views/app/message.coffee rename to packages/rocketchat-ui/views/app/message.coffee diff --git a/client/views/app/message.html b/packages/rocketchat-ui/views/app/message.html similarity index 100% rename from client/views/app/message.html rename to packages/rocketchat-ui/views/app/message.html diff --git a/client/views/app/messagePopup.coffee b/packages/rocketchat-ui/views/app/messagePopup.coffee similarity index 100% rename from client/views/app/messagePopup.coffee rename to packages/rocketchat-ui/views/app/messagePopup.coffee diff --git a/client/views/app/messagePopup.html b/packages/rocketchat-ui/views/app/messagePopup.html similarity index 100% rename from client/views/app/messagePopup.html rename to packages/rocketchat-ui/views/app/messagePopup.html diff --git a/client/views/app/messagePopupChannel.html b/packages/rocketchat-ui/views/app/messagePopupChannel.html similarity index 100% rename from client/views/app/messagePopupChannel.html rename to packages/rocketchat-ui/views/app/messagePopupChannel.html diff --git a/client/views/app/messagePopupConfig.coffee b/packages/rocketchat-ui/views/app/messagePopupConfig.coffee similarity index 100% rename from client/views/app/messagePopupConfig.coffee rename to packages/rocketchat-ui/views/app/messagePopupConfig.coffee diff --git a/client/views/app/messagePopupConfig.html b/packages/rocketchat-ui/views/app/messagePopupConfig.html similarity index 100% rename from client/views/app/messagePopupConfig.html rename to packages/rocketchat-ui/views/app/messagePopupConfig.html diff --git a/client/views/app/messagePopupEmoji.coffee b/packages/rocketchat-ui/views/app/messagePopupEmoji.coffee similarity index 100% rename from client/views/app/messagePopupEmoji.coffee rename to packages/rocketchat-ui/views/app/messagePopupEmoji.coffee diff --git a/client/views/app/messagePopupEmoji.html b/packages/rocketchat-ui/views/app/messagePopupEmoji.html similarity index 100% rename from client/views/app/messagePopupEmoji.html rename to packages/rocketchat-ui/views/app/messagePopupEmoji.html diff --git a/client/views/app/messagePopupSlashCommand.html b/packages/rocketchat-ui/views/app/messagePopupSlashCommand.html similarity index 100% rename from client/views/app/messagePopupSlashCommand.html rename to packages/rocketchat-ui/views/app/messagePopupSlashCommand.html diff --git a/client/views/app/messagePopupUser.html b/packages/rocketchat-ui/views/app/messagePopupUser.html similarity index 100% rename from client/views/app/messagePopupUser.html rename to packages/rocketchat-ui/views/app/messagePopupUser.html diff --git a/client/views/app/privateHistory.coffee b/packages/rocketchat-ui/views/app/privateHistory.coffee similarity index 100% rename from client/views/app/privateHistory.coffee rename to packages/rocketchat-ui/views/app/privateHistory.coffee diff --git a/client/views/app/privateHistory.html b/packages/rocketchat-ui/views/app/privateHistory.html similarity index 100% rename from client/views/app/privateHistory.html rename to packages/rocketchat-ui/views/app/privateHistory.html diff --git a/client/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee similarity index 100% rename from client/views/app/room.coffee rename to packages/rocketchat-ui/views/app/room.coffee diff --git a/client/views/app/room.html b/packages/rocketchat-ui/views/app/room.html similarity index 100% rename from client/views/app/room.html rename to packages/rocketchat-ui/views/app/room.html diff --git a/client/views/app/roomSearch.coffee b/packages/rocketchat-ui/views/app/roomSearch.coffee similarity index 100% rename from client/views/app/roomSearch.coffee rename to packages/rocketchat-ui/views/app/roomSearch.coffee diff --git a/client/views/app/roomSearch.html b/packages/rocketchat-ui/views/app/roomSearch.html similarity index 100% rename from client/views/app/roomSearch.html rename to packages/rocketchat-ui/views/app/roomSearch.html diff --git a/client/views/app/spotlight/mobileMessageMenu.coffee b/packages/rocketchat-ui/views/app/spotlight/mobileMessageMenu.coffee similarity index 100% rename from client/views/app/spotlight/mobileMessageMenu.coffee rename to packages/rocketchat-ui/views/app/spotlight/mobileMessageMenu.coffee diff --git a/client/views/app/spotlight/mobileMessageMenu.html b/packages/rocketchat-ui/views/app/spotlight/mobileMessageMenu.html similarity index 100% rename from client/views/app/spotlight/mobileMessageMenu.html rename to packages/rocketchat-ui/views/app/spotlight/mobileMessageMenu.html diff --git a/client/views/app/spotlight/spotlight.coffee b/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee similarity index 100% rename from client/views/app/spotlight/spotlight.coffee rename to packages/rocketchat-ui/views/app/spotlight/spotlight.coffee diff --git a/client/views/app/spotlight/spotlight.html b/packages/rocketchat-ui/views/app/spotlight/spotlight.html similarity index 100% rename from client/views/app/spotlight/spotlight.html rename to packages/rocketchat-ui/views/app/spotlight/spotlight.html diff --git a/client/views/app/tabBar/membersList.coffee b/packages/rocketchat-ui/views/app/tabBar/membersList.coffee similarity index 100% rename from client/views/app/tabBar/membersList.coffee rename to packages/rocketchat-ui/views/app/tabBar/membersList.coffee diff --git a/client/views/app/tabBar/membersList.html b/packages/rocketchat-ui/views/app/tabBar/membersList.html similarity index 100% rename from client/views/app/tabBar/membersList.html rename to packages/rocketchat-ui/views/app/tabBar/membersList.html diff --git a/client/views/app/tabBar/messageSearch.coffee b/packages/rocketchat-ui/views/app/tabBar/messageSearch.coffee similarity index 100% rename from client/views/app/tabBar/messageSearch.coffee rename to packages/rocketchat-ui/views/app/tabBar/messageSearch.coffee diff --git a/client/views/app/tabBar/messageSearch.html b/packages/rocketchat-ui/views/app/tabBar/messageSearch.html similarity index 100% rename from client/views/app/tabBar/messageSearch.html rename to packages/rocketchat-ui/views/app/tabBar/messageSearch.html diff --git a/client/views/app/tabBar/uploadedFilesList.coffee b/packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.coffee similarity index 100% rename from client/views/app/tabBar/uploadedFilesList.coffee rename to packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.coffee diff --git a/client/views/app/tabBar/uploadedFilesList.html b/packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.html similarity index 100% rename from client/views/app/tabBar/uploadedFilesList.html rename to packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.html diff --git a/client/views/app/userInfo.coffee b/packages/rocketchat-ui/views/app/userInfo.coffee similarity index 100% rename from client/views/app/userInfo.coffee rename to packages/rocketchat-ui/views/app/userInfo.coffee diff --git a/client/views/app/userInfo.html b/packages/rocketchat-ui/views/app/userInfo.html similarity index 100% rename from client/views/app/userInfo.html rename to packages/rocketchat-ui/views/app/userInfo.html diff --git a/client/views/app/userSearch.html b/packages/rocketchat-ui/views/app/userSearch.html similarity index 100% rename from client/views/app/userSearch.html rename to packages/rocketchat-ui/views/app/userSearch.html diff --git a/client/views/app/videoCall/videoButtons.coffee b/packages/rocketchat-ui/views/app/videoCall/videoButtons.coffee similarity index 100% rename from client/views/app/videoCall/videoButtons.coffee rename to packages/rocketchat-ui/views/app/videoCall/videoButtons.coffee diff --git a/client/views/app/videoCall/videoButtons.html b/packages/rocketchat-ui/views/app/videoCall/videoButtons.html similarity index 100% rename from client/views/app/videoCall/videoButtons.html rename to packages/rocketchat-ui/views/app/videoCall/videoButtons.html diff --git a/client/views/app/videoCall/videoCall.coffee b/packages/rocketchat-ui/views/app/videoCall/videoCall.coffee similarity index 100% rename from client/views/app/videoCall/videoCall.coffee rename to packages/rocketchat-ui/views/app/videoCall/videoCall.coffee diff --git a/client/views/app/videoCall/videoCall.html b/packages/rocketchat-ui/views/app/videoCall/videoCall.html similarity index 100% rename from client/views/app/videoCall/videoCall.html rename to packages/rocketchat-ui/views/app/videoCall/videoCall.html diff --git a/client/views/cmsPage.coffee b/packages/rocketchat-ui/views/cmsPage.coffee similarity index 100% rename from client/views/cmsPage.coffee rename to packages/rocketchat-ui/views/cmsPage.coffee diff --git a/client/views/cmsPage.html b/packages/rocketchat-ui/views/cmsPage.html similarity index 100% rename from client/views/cmsPage.html rename to packages/rocketchat-ui/views/cmsPage.html diff --git a/client/views/error.html b/packages/rocketchat-ui/views/error.html similarity index 100% rename from client/views/error.html rename to packages/rocketchat-ui/views/error.html diff --git a/client/views/fxos.coffee b/packages/rocketchat-ui/views/fxos.coffee similarity index 100% rename from client/views/fxos.coffee rename to packages/rocketchat-ui/views/fxos.coffee diff --git a/client/views/fxos.html b/packages/rocketchat-ui/views/fxos.html similarity index 100% rename from client/views/fxos.html rename to packages/rocketchat-ui/views/fxos.html diff --git a/client/views/loading.html b/packages/rocketchat-ui/views/loading.html similarity index 100% rename from client/views/loading.html rename to packages/rocketchat-ui/views/loading.html diff --git a/client/views/main.coffee b/packages/rocketchat-ui/views/main.coffee similarity index 100% rename from client/views/main.coffee rename to packages/rocketchat-ui/views/main.coffee diff --git a/client/views/main.html b/packages/rocketchat-ui/views/main.html similarity index 100% rename from client/views/main.html rename to packages/rocketchat-ui/views/main.html diff --git a/client/views/modal.coffee b/packages/rocketchat-ui/views/modal.coffee similarity index 100% rename from client/views/modal.coffee rename to packages/rocketchat-ui/views/modal.coffee diff --git a/client/views/modal.html b/packages/rocketchat-ui/views/modal.html similarity index 100% rename from client/views/modal.html rename to packages/rocketchat-ui/views/modal.html diff --git a/client/views/username/layout.html b/packages/rocketchat-ui/views/username/layout.html similarity index 100% rename from client/views/username/layout.html rename to packages/rocketchat-ui/views/username/layout.html diff --git a/client/views/username/username.coffee b/packages/rocketchat-ui/views/username/username.coffee similarity index 100% rename from client/views/username/username.coffee rename to packages/rocketchat-ui/views/username/username.coffee diff --git a/client/views/username/username.html b/packages/rocketchat-ui/views/username/username.html similarity index 100% rename from client/views/username/username.html rename to packages/rocketchat-ui/views/username/username.html -- GitLab From 6e89276ca5c4517fe06611ffd34bbe3c973f2a07 Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Sun, 15 Nov 2015 18:08:29 +0100 Subject: [PATCH 0434/1338] Added directMessagesFlex template to the side-nav --- packages/rocketchat-ui-sidenav/package.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index 041b15f5d7e..47e557c5394 100644 --- a/packages/rocketchat-ui-sidenav/package.js +++ b/packages/rocketchat-ui-sidenav/package.js @@ -25,6 +25,7 @@ Package.onUse(function(api) { api.addFiles('side-nav/chatRoomItem.html', 'client'); api.addFiles('side-nav/createChannelFlex.html', 'client'); api.addFiles('side-nav/directMessages.html', 'client'); + api.addFiles('side-nav/directMessagesFlex.html', 'client'); api.addFiles('side-nav/listChannelsFlex.html', 'client'); api.addFiles('side-nav/listPrivateGroupsFlex.html', 'client'); api.addFiles('side-nav/privateGroups.html', 'client'); @@ -38,6 +39,7 @@ Package.onUse(function(api) { api.addFiles('side-nav/chatRoomItem.coffee', 'client'); api.addFiles('side-nav/createChannelFlex.coffee', 'client'); api.addFiles('side-nav/directMessages.coffee', 'client'); + api.addFiles('side-nav/directMessagesFlex.coffee', 'client'); api.addFiles('side-nav/listChannelsFlex.coffee', 'client'); api.addFiles('side-nav/listPrivateGroupsFlex.coffee', 'client'); api.addFiles('side-nav/privateGroups.coffee', 'client'); -- GitLab From bd037d11c81a41a22e770085543cc502ed42b09a Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Sun, 15 Nov 2015 20:43:02 +0100 Subject: [PATCH 0435/1338] Created rocketchat-ui-message-input package --- .meteor/packages | 1 + .meteor/versions | 1 + packages/rocketchat-ui-login/package.js | 5 +- .../username/layout.html | 0 .../username/username.coffee | 0 .../username/username.html | 0 .../rocketchat-ui-message-input/README.md | 0 .../message-input}/messagePopup.coffee | 0 .../message-input}/messagePopup.html | 0 .../message-input}/messagePopupChannel.html | 0 .../message-input}/messagePopupConfig.coffee | 0 .../message-input}/messagePopupConfig.html | 0 .../message-input}/messagePopupEmoji.coffee | 0 .../message-input}/messagePopupEmoji.html | 0 .../messagePopupSlashCommand.html | 0 .../message-input}/messagePopupUser.html | 0 .../rocketchat-ui-message-input/package.js | 37 +++++ packages/rocketchat-ui/package.js | 26 ++-- .../rocketchat-ui/views/app/messageBox.coffee | 135 ++++++++++++++++++ .../rocketchat-ui/views/app/messageBox.html | 72 ++++++++++ packages/rocketchat-ui/views/app/room.coffee | 135 ++++-------------- packages/rocketchat-ui/views/app/room.html | 73 +--------- 22 files changed, 295 insertions(+), 190 deletions(-) rename packages/{rocketchat-ui/views => rocketchat-ui-login}/username/layout.html (100%) rename packages/{rocketchat-ui/views => rocketchat-ui-login}/username/username.coffee (100%) rename packages/{rocketchat-ui/views => rocketchat-ui-login}/username/username.html (100%) create mode 100644 packages/rocketchat-ui-message-input/README.md rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopup.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopup.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupChannel.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupConfig.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupConfig.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupEmoji.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupEmoji.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupSlashCommand.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message-input/message-input}/messagePopupUser.html (100%) create mode 100644 packages/rocketchat-ui-message-input/package.js create mode 100644 packages/rocketchat-ui/views/app/messageBox.coffee create mode 100644 packages/rocketchat-ui/views/app/messageBox.html diff --git a/.meteor/packages b/.meteor/packages index 4780122cfc8..44cebd6e92f 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -118,3 +118,4 @@ rocketchat:rocketchat-ui-sidenav rocketchat:rocketchat-ui-account rocketchat:rocketchat-ui-admin rocketchat:rocketchat-ui-login +rocketchat:rocketchat-ui-message-input diff --git a/.meteor/versions b/.meteor/versions index 5fb5f258908..72fbd13ca02 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -146,6 +146,7 @@ rocketchat:rocketchat-ui@0.1.0 rocketchat:rocketchat-ui-account@0.0.1 rocketchat:rocketchat-ui-admin@0.0.1 rocketchat:rocketchat-ui-login@0.0.1 +rocketchat:rocketchat-ui-message-input@0.1.0 rocketchat:rocketchat-ui-sidenav@0.1.0 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 diff --git a/packages/rocketchat-ui-login/package.js b/packages/rocketchat-ui-login/package.js index a24f33f3466..271e6de4e8d 100644 --- a/packages/rocketchat-ui-login/package.js +++ b/packages/rocketchat-ui-login/package.js @@ -29,11 +29,14 @@ Package.onUse(function(api) { api.addFiles('login/services.html', 'client'); api.addFiles('login/social.html', 'client'); + api.addFiles('username/layout.html', 'client'); + api.addFiles('username/username.html', 'client'); + api.addFiles('login/footer.coffee', 'client'); api.addFiles('login/form.coffee', 'client'); api.addFiles('login/header.coffee', 'client'); api.addFiles('login/services.coffee', 'client'); api.addFiles('login/social.coffee', 'client'); + api.addFiles('username/username.coffee', 'client'); - // api.addAssets('styles/side-nav.less', 'client'); }); \ No newline at end of file diff --git a/packages/rocketchat-ui/views/username/layout.html b/packages/rocketchat-ui-login/username/layout.html similarity index 100% rename from packages/rocketchat-ui/views/username/layout.html rename to packages/rocketchat-ui-login/username/layout.html diff --git a/packages/rocketchat-ui/views/username/username.coffee b/packages/rocketchat-ui-login/username/username.coffee similarity index 100% rename from packages/rocketchat-ui/views/username/username.coffee rename to packages/rocketchat-ui-login/username/username.coffee diff --git a/packages/rocketchat-ui/views/username/username.html b/packages/rocketchat-ui-login/username/username.html similarity index 100% rename from packages/rocketchat-ui/views/username/username.html rename to packages/rocketchat-ui-login/username/username.html diff --git a/packages/rocketchat-ui-message-input/README.md b/packages/rocketchat-ui-message-input/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-ui/views/app/messagePopup.coffee b/packages/rocketchat-ui-message-input/message-input/messagePopup.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopup.coffee rename to packages/rocketchat-ui-message-input/message-input/messagePopup.coffee diff --git a/packages/rocketchat-ui/views/app/messagePopup.html b/packages/rocketchat-ui-message-input/message-input/messagePopup.html similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopup.html rename to packages/rocketchat-ui-message-input/message-input/messagePopup.html diff --git a/packages/rocketchat-ui/views/app/messagePopupChannel.html b/packages/rocketchat-ui-message-input/message-input/messagePopupChannel.html similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupChannel.html rename to packages/rocketchat-ui-message-input/message-input/messagePopupChannel.html diff --git a/packages/rocketchat-ui/views/app/messagePopupConfig.coffee b/packages/rocketchat-ui-message-input/message-input/messagePopupConfig.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupConfig.coffee rename to packages/rocketchat-ui-message-input/message-input/messagePopupConfig.coffee diff --git a/packages/rocketchat-ui/views/app/messagePopupConfig.html b/packages/rocketchat-ui-message-input/message-input/messagePopupConfig.html similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupConfig.html rename to packages/rocketchat-ui-message-input/message-input/messagePopupConfig.html diff --git a/packages/rocketchat-ui/views/app/messagePopupEmoji.coffee b/packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupEmoji.coffee rename to packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.coffee diff --git a/packages/rocketchat-ui/views/app/messagePopupEmoji.html b/packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.html similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupEmoji.html rename to packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.html diff --git a/packages/rocketchat-ui/views/app/messagePopupSlashCommand.html b/packages/rocketchat-ui-message-input/message-input/messagePopupSlashCommand.html similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupSlashCommand.html rename to packages/rocketchat-ui-message-input/message-input/messagePopupSlashCommand.html diff --git a/packages/rocketchat-ui/views/app/messagePopupUser.html b/packages/rocketchat-ui-message-input/message-input/messagePopupUser.html similarity index 100% rename from packages/rocketchat-ui/views/app/messagePopupUser.html rename to packages/rocketchat-ui-message-input/message-input/messagePopupUser.html diff --git a/packages/rocketchat-ui-message-input/package.js b/packages/rocketchat-ui-message-input/package.js new file mode 100644 index 00000000000..68ac9348ad2 --- /dev/null +++ b/packages/rocketchat-ui-message-input/package.js @@ -0,0 +1,37 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-message-input', + version: '0.1.0', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'mongo', + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles("message-input/messagePopup.html", "client"); + api.addFiles("message-input/messagePopupChannel.html", "client"); + api.addFiles("message-input/messagePopupConfig.html", "client"); + api.addFiles("message-input/messagePopupEmoji.html", "client"); + api.addFiles("message-input/messagePopupSlashCommand.html", "client"); + api.addFiles("message-input/messagePopupUser.html", "client"); + + api.addFiles("message-input/messagePopup.coffee", "client"); + api.addFiles("message-input/messagePopupConfig.coffee", "client"); + api.addFiles("message-input/messagePopupEmoji.coffee", "client"); + + +}); \ No newline at end of file diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 490bae4b8a8..ffbe92480bf 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -53,6 +53,17 @@ Package.onUse(function(api) { api.addFiles('lib/textarea-autogrow.js', 'client'); api.addFiles('lib/trackRoomNameChanged.coffee', 'client'); + // LIB CORDOVA + api.addFiles('lib/cordova/facebook-login.coffee', 'client'); + api.addFiles('lib/cordova/keyboard-fix.coffee', 'client'); + api.addFiles('lib/cordova/push.coffee', 'client'); + api.addFiles('lib/cordova/urls.coffee', 'client'); + api.addFiles('lib/cordova/user-state.coffee', 'client'); + + // LIB RECORDERJS + api.addFiles('lib/recorderjs/audioRecorder.coffee', 'client'); + api.addFiles('lib/recorderjs/recorder.js', 'client'); + // TEMPLATE FILES api.addFiles('views/cmsPage.html', 'client'); api.addFiles('views/error.html', 'client'); @@ -61,19 +72,11 @@ Package.onUse(function(api) { api.addFiles('views/main.html', 'client'); api.addFiles('views/modal.html', 'client'); api.addFiles('views/404/roomNotFound.html', 'client'); - api.addFiles('views/username/layout.html', 'client'); - api.addFiles('views/username/username.html', 'client'); api.addFiles('views/app/audioNotification.html', 'client'); api.addFiles('views/app/burguer.html', 'client'); api.addFiles('views/app/flexTabBar.html', 'client'); api.addFiles('views/app/home.html', 'client'); api.addFiles('views/app/message.html', 'client'); - api.addFiles('views/app/messagePopup.html', 'client'); - api.addFiles('views/app/messagePopupChannel.html', 'client'); - api.addFiles('views/app/messagePopupConfig.html', 'client'); - api.addFiles('views/app/messagePopupEmoji.html', 'client'); - api.addFiles('views/app/messagePopupSlashCommand.html', 'client'); - api.addFiles('views/app/messagePopupUser.html', 'client'); api.addFiles('views/app/privateHistory.html', 'client'); api.addFiles('views/app/room.html', 'client'); api.addFiles('views/app/roomSearch.html', 'client'); @@ -86,20 +89,17 @@ Package.onUse(function(api) { api.addFiles('views/app/tabBar/uploadedFilesList.html', 'client'); api.addFiles('views/app/videoCall/videoButtons.html', 'client'); api.addFiles('views/app/videoCall/videoCall.html', 'client'); + api.addFiles('views/app/messageBox.html', 'client'); api.addFiles('views/cmsPage.coffee', 'client'); api.addFiles('views/fxos.coffee', 'client'); api.addFiles('views/main.coffee', 'client'); api.addFiles('views/modal.coffee', 'client'); api.addFiles('views/404/roomNotFound.coffee', 'client'); - api.addFiles('views/username/username.coffee', 'client'); api.addFiles('views/app/burguer.coffee', 'client'); api.addFiles('views/app/flexTabBar.coffee', 'client'); api.addFiles('views/app/home.coffee', 'client'); api.addFiles('views/app/message.coffee', 'client'); - api.addFiles('views/app/messagePopup.coffee', 'client'); - api.addFiles('views/app/messagePopupConfig.coffee', 'client'); - api.addFiles('views/app/messagePopupEmoji.coffee', 'client'); api.addFiles('views/app/privateHistory.coffee', 'client'); api.addFiles('views/app/room.coffee', 'client'); api.addFiles('views/app/roomSearch.coffee', 'client'); @@ -111,5 +111,5 @@ Package.onUse(function(api) { api.addFiles('views/app/tabBar/uploadedFilesList.coffee', 'client'); api.addFiles('views/app/videoCall/videoButtons.coffee', 'client'); api.addFiles('views/app/videoCall/videoCall.coffee', 'client'); - + api.addFiles('views/app/messageBox.coffee', 'client'); }); \ No newline at end of file diff --git a/packages/rocketchat-ui/views/app/messageBox.coffee b/packages/rocketchat-ui/views/app/messageBox.coffee new file mode 100644 index 00000000000..53f2e00f7f3 --- /dev/null +++ b/packages/rocketchat-ui/views/app/messageBox.coffee @@ -0,0 +1,135 @@ +isSubscribed = (_id) -> + return ChatSubscription.find({ rid: _id }).count() > 0 + +Template.messageBox.helpers + roomName: -> + roomData = Session.get('roomData' + this._id) + return '' unless roomData + + if roomData.t is 'd' + return ChatSubscription.findOne({ rid: this._id }, { fields: { name: 1 } })?.name + else + return roomData.name + showMarkdown: -> + return RocketChat.Markdown + showFormattingTips: -> + return RocketChat.settings.get('Message_ShowFormattingTips') and (RocketChat.Markdown or RocketChat.Highlight) + canJoin: -> + return !! ChatRoom.findOne { _id: @_id, t: 'c' } + subscribed: -> + return isSubscribed(this._id) + getPopupConfig: -> + template = Template.instance() + return { + getInput: -> + return template.find('.input-message') + } + canRecordAudio: -> + wavRegex = /audio\/wav|audio\/\*/i + wavEnabled = RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) + return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) and wavEnabled and RocketChat.settings.get('FileUpload_Enabled') + usersTyping: -> + users = MsgTyping.get @_id + if users.length is 0 + return + if users.length is 1 + return { + multi: false + selfTyping: MsgTyping.selfTyping.get() + users: users[0] + } + # usernames = _.map messages, (message) -> return message.u.username + last = users.pop() + if users.length > 4 + last = t('others') + # else + usernames = users.join(', ') + usernames = [usernames, last] + return { + multi: true + selfTyping: MsgTyping.selfTyping.get() + users: usernames.join " #{t 'and'} " + } + +Template.messageBox.events + 'click .join': (event) -> + event.stopPropagation() + event.preventDefault() + Meteor.call 'joinRoom', @_id + + 'focus .input-message': (event) -> + KonchatNotification.removeRoomNotification @_id + + 'keyup .input-message': (event) -> + Template.instance().chatMessages.keyup(@_id, event, Template.instance()) + + 'paste .input-message': (e) -> + if not e.originalEvent.clipboardData? + return + + items = e.originalEvent.clipboardData.items + files = [] + for item in items + if item.kind is 'file' and item.type.indexOf('image/') isnt -1 + e.preventDefault() + files.push + file: item.getAsFile() + name: 'Clipboard' + + if files.length > 0 + fileUpload files + + 'keydown .input-message': (event) -> + Template.instance().chatMessages.keydown(@_id, event, Template.instance()) + + 'click .message-form .icon-paper-plane': (event) -> + input = $(event.currentTarget).siblings("textarea") + Template.instance().chatMessages.send(this._id, input.get(0)) + event.preventDefault() + event.stopPropagation() + input.focus() + input.get(0).updateAutogrow() + + "click .editing-commands-cancel > a": (e) -> + Template.instance().chatMessages.clearEditing() + + "click .editing-commands-save > a": (e) -> + chatMessages = Template.instance().chatMessages + chatMessages.send(@_id, chatMessages.input) + + + + 'change .message-form input[type=file]': (event, template) -> + e = event.originalEvent or event + files = e.target.files + if not files or files.length is 0 + files = e.dataTransfer?.files or [] + + filesToUpload = [] + for file in files + filesToUpload.push + file: file + name: file.name + + fileUpload filesToUpload + + 'click .message-form .mic': (e, t) -> + console.log window.AudioRecorder + AudioRecorder.start -> + t.$('.stop-mic').removeClass('hidden') + t.$('.mic').addClass('hidden') + + 'click .message-form .stop-mic': (e, t) -> + AudioRecorder.stop (blob) -> + fileUpload [{ + file: blob + type: 'audio' + name: 'Audio record' + }] + + t.$('.stop-mic').addClass('hidden') + t.$('.mic').removeClass('hidden') + +Template.messageBox.onRendered -> + this.chatMessages = new ChatMessages + this.chatMessages.init(this.firstNode) \ No newline at end of file diff --git a/packages/rocketchat-ui/views/app/messageBox.html b/packages/rocketchat-ui/views/app/messageBox.html new file mode 100644 index 00000000000..3b1113685e9 --- /dev/null +++ b/packages/rocketchat-ui/views/app/messageBox.html @@ -0,0 +1,72 @@ +<template name="messageBox"> + {{#if subscribed}} + <form class="message-form" method="post" action="/"> + <div style="display: flex"> + <div class="file"> + <i class="octicon octicon-cloud-upload file"></i> + <input type="file" accept="{{fileUploadAllowedMediaTypes}}"> + </div> + <div class="input-message-container"> + {{> messagePopupConfig getPopupConfig}} + <textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea> + </div> + + {{#if canRecordAudio}} + <div class="mic"> + <i class="icon-mic" aria-label="{{_ "Record"}}"></i> + </div> + <div class="stop-mic hidden"> + <i class="icon-stop" aria-label="{{_ "Stop_Recording"}}"></i> + </div> + {{/if}} + </div> + <div class="users-typing"> + {{#with usersTyping}} + <strong>{{users}}</strong> + {{#if multi}} + {{#if selfTyping}} + {{_ "are_also_typing"}} + {{else}} + {{_ "are_typing"}} + {{/if}} + {{else}} + {{#if selfTyping}} + {{_ "is_also_typing" context="male"}} + {{else}} + {{_ "is_typing" context="male"}} + {{/if}} + {{/if}} + {{/with}} + </div> + + {{#if showFormattingTips}} + <div class="formatting-tips" aria-hidden="true" dir="auto"> + {{#if showMarkdown}} + <b>*{{_ "bold"}}*</b> + <i>_{{_ "italics"}}_</i> + <span>~<strike>{{_ "strike"}}</strike>~</span> + <code class="inline">`{{_ "inline_code"}}`</code> + {{/if}} + {{#if showHighlight}} + <code class="inline"><span class="hidden-br"><br></span>```<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "multi"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "line"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>```</code> + {{/if}} + {{#if showMarkdown}} + <q><span class="hidden-br"><br></span>>{{_ "quote"}}</q> + {{/if}} + + </div> + {{/if}} + <div class="editing-commands" aria-hidden="true" dir="auto"> + <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="">{{_ 'Cancel'}}</a></div> + <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="">{{_ 'Save_changes'}}</a></div> + </div> + </form> + {{else}} + {{#if canJoin}} + <div> + {{{_ "you_are_in_preview_mode_of" room_name=roomName}}} + <button class="button join"><span><i class="icon-login"></i> {{_ "join"}}</span></button> + </div> + {{/if}} + {{/if}} +</template> \ No newline at end of file diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 80dd1c74fb9..3eac444e9e3 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -7,12 +7,12 @@ favoritesEnabled = -> # @TODO bug com o botão para "rolar até o fim" (novas mensagens) quando há uma mensagem com texto que gere rolagem horizontal Template.room.helpers - showFormattingTips: -> - return RocketChat.settings.get('Message_ShowFormattingTips') and (RocketChat.Markdown or RocketChat.Highlight) - showMarkdown: -> - return RocketChat.Markdown - showHighlight: -> - return RocketChat.Highlight + # showFormattingTips: -> + # return RocketChat.settings.get('Message_ShowFormattingTips') and (RocketChat.Markdown or RocketChat.Highlight) + # showMarkdown: -> + # return RocketChat.Markdown + # showHighlight: -> + # return RocketChat.Highlight favorite: -> sub = ChatSubscription.findOne { rid: this._id }, { fields: { f: 1 } } return 'icon-star favorite-room' if sub?.f? and sub.f and favoritesEnabled @@ -36,30 +36,30 @@ Template.room.helpers uploading: -> return Session.get 'uploading' - usersTyping: -> - users = MsgTyping.get @_id - if users.length is 0 - return - if users.length is 1 - return { - multi: false - selfTyping: MsgTyping.selfTyping.get() - users: users[0] - } - - # usernames = _.map messages, (message) -> return message.u.username - - last = users.pop() - if users.length > 4 - last = t('others') - # else - usernames = users.join(', ') - usernames = [usernames, last] - return { - multi: true - selfTyping: MsgTyping.selfTyping.get() - users: usernames.join " #{t 'and'} " - } + # usersTyping: -> + # users = MsgTyping.get @_id + # if users.length is 0 + # return + # if users.length is 1 + # return { + # multi: false + # selfTyping: MsgTyping.selfTyping.get() + # users: users[0] + # } + + # # usernames = _.map messages, (message) -> return message.u.username + + # last = users.pop() + # if users.length > 4 + # last = t('others') + # # else + # usernames = users.join(', ') + # usernames = [usernames, last] + # return { + # multi: true + # selfTyping: MsgTyping.selfTyping.get() + # users: usernames.join " #{t 'and'} " + # } roomName: -> roomData = Session.get('roomData' + this._id) @@ -295,44 +295,6 @@ Template.room.events event.preventDefault() Meteor.call 'toogleFavorite', @_id, !$('i', event.currentTarget).hasClass('favorite-room') - 'click .join': (event) -> - event.stopPropagation() - event.preventDefault() - Meteor.call 'joinRoom', @_id - - 'focus .input-message': (event) -> - KonchatNotification.removeRoomNotification @_id - - 'keyup .input-message': (event) -> - Template.instance().chatMessages.keyup(@_id, event, Template.instance()) - - 'paste .input-message': (e) -> - if not e.originalEvent.clipboardData? - return - - items = e.originalEvent.clipboardData.items - files = [] - for item in items - if item.kind is 'file' and item.type.indexOf('image/') isnt -1 - e.preventDefault() - files.push - file: item.getAsFile() - name: 'Clipboard' - - if files.length > 0 - fileUpload files - - 'keydown .input-message': (event) -> - Template.instance().chatMessages.keydown(@_id, event, Template.instance()) - - 'click .message-form .icon-paper-plane': (event) -> - input = $(event.currentTarget).siblings("textarea") - Template.instance().chatMessages.send(this._id, input.get(0)) - event.preventDefault() - event.stopPropagation() - input.focus() - input.get(0).updateAutogrow() - 'click .edit-room-title': (event) -> event.preventDefault() Session.set('editRoomTitle', true) @@ -390,13 +352,6 @@ Template.room.events 'click .message-dropdown-close': -> $('.message-dropdown:visible').hide() - "click .editing-commands-cancel > a": (e) -> - Template.instance().chatMessages.clearEditing() - - "click .editing-commands-save > a": (e) -> - chatMessages = Template.instance().chatMessages - chatMessages.send(@_id, chatMessages.input) - "click .mention-link": (e) -> channel = $(e.currentTarget).data('channel') if channel? @@ -441,36 +396,6 @@ Template.room.events fileUpload filesToUpload - 'change .message-form input[type=file]': (event, template) -> - e = event.originalEvent or event - files = e.target.files - if not files or files.length is 0 - files = e.dataTransfer?.files or [] - - filesToUpload = [] - for file in files - filesToUpload.push - file: file - name: file.name - - fileUpload filesToUpload - - 'click .message-form .mic': (e, t) -> - AudioRecorder.start -> - t.$('.stop-mic').removeClass('hidden') - t.$('.mic').addClass('hidden') - - 'click .message-form .stop-mic': (e, t) -> - AudioRecorder.stop (blob) -> - fileUpload [{ - file: blob - type: 'audio' - name: 'Audio record' - }] - - t.$('.stop-mic').addClass('hidden') - t.$('.mic').removeClass('hidden') - 'click .deactivate': -> username = Session.get('showUserInfo') user = Meteor.users.findOne { username: String(username) } diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index 3c2380b3929..919ef914666 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -78,80 +78,11 @@ </div> </div> <footer class="footer"> - {{#if subscribed}} - <form class="message-form" method="post" action="/"> - <div style="display: flex"> - <div class="file"> - <i class="octicon octicon-cloud-upload file"></i> - <input type="file" accept="{{fileUploadAllowedMediaTypes}}"> - </div> - <div class="input-message-container"> - {{> messagePopupConfig getPopupConfig}} - <textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea> - </div> - - {{#if canRecordAudio}} - <div class="mic"> - <i class="icon-mic" aria-label="{{_ "Record"}}"></i> - </div> - <div class="stop-mic hidden"> - <i class="icon-stop" aria-label="{{_ "Stop_Recording"}}"></i> - </div> - {{/if}} - </div> - <div class="users-typing"> - {{#with usersTyping}} - <strong>{{users}}</strong> - {{#if multi}} - {{#if selfTyping}} - {{_ "are_also_typing"}} - {{else}} - {{_ "are_typing"}} - {{/if}} - {{else}} - {{#if selfTyping}} - {{_ "is_also_typing" context="male"}} - {{else}} - {{_ "is_typing" context="male"}} - {{/if}} - {{/if}} - {{/with}} - </div> - - {{#if showFormattingTips}} - <div class="formatting-tips" aria-hidden="true" dir="auto"> - {{#if showMarkdown}} - <b>*{{_ "bold"}}*</b> - <i>_{{_ "italics"}}_</i> - <span>~<strike>{{_ "strike"}}</strike>~</span> - <code class="inline">`{{_ "inline_code"}}`</code> - {{/if}} - {{#if showHighlight}} - <code class="inline"><span class="hidden-br"><br></span>```<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "multi"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "line"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>```</code> - {{/if}} - {{#if showMarkdown}} - <q><span class="hidden-br"><br></span>>{{_ "quote"}}</q> - {{/if}} - - </div> - {{/if}} - <div class="editing-commands" aria-hidden="true" dir="auto"> - <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="">{{_ 'Cancel'}}</a></div> - <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="">{{_ 'Save_changes'}}</a></div> - </div> - </form> - {{else}} - {{#if canJoin}} - <div> - {{{_ "you_are_in_preview_mode_of" room_name=roomName}}} - <button class="button join"><span><i class="icon-login"></i> {{_ "join"}}</span></button> - </div> - {{/if}} - {{/if}} + {{> messageBox}} </footer> </section> <section class="flex-tab"> {{> Template.dynamic template=flexTemplate data=flexData}} </section> </div> -</template> +</template> \ No newline at end of file -- GitLab From 6c7a9814f04492d109cd6f1b76be30ab3347adaa Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Sun, 15 Nov 2015 22:56:32 +0100 Subject: [PATCH 0436/1338] implemented rocketchat-ui-flextab, rocketchat-ui-master and renamed ui-message package --- .meteor/packages | 4 +- .meteor/versions | 10 +- packages/rocketchat-ui-account/package.js | 2 +- packages/rocketchat-ui-admin/package.js | 2 +- .../README.md | 0 .../flex-tab}/flexTabBar.coffee | 0 .../flex-tab}/flexTabBar.html | 0 .../flex-tab/tabs}/membersList.coffee | 0 .../flex-tab/tabs}/membersList.html | 0 .../flex-tab/tabs}/messageSearch.coffee | 0 .../flex-tab/tabs}/messageSearch.html | 0 .../flex-tab/tabs}/uploadedFilesList.coffee | 0 .../flex-tab/tabs}/uploadedFilesList.html | 0 .../flex-tab/tabs}/userInfo.coffee | 0 .../flex-tab/tabs}/userInfo.html | 0 packages/rocketchat-ui-flextab/package.js | 37 +++ packages/rocketchat-ui-login/package.js | 4 +- packages/rocketchat-ui-master/README.md | 0 .../rocketchat-ui-master/master/error.html | 12 + .../rocketchat-ui-master/master/loading.html | 24 ++ .../rocketchat-ui-master/master/main.coffee | 216 ++++++++++++++++++ .../rocketchat-ui-master/master/main.html | 70 ++++++ packages/rocketchat-ui-master/package.js | 30 +++ .../rocketchat-ui-message-input/package.js | 37 --- packages/rocketchat-ui-message/README.md | 0 .../message}/message.coffee | 0 .../message}/message.html | 0 .../message}/messageBox.coffee | 0 .../message}/messageBox.html | 0 .../message/popup}/messagePopup.coffee | 0 .../message/popup}/messagePopup.html | 0 .../message/popup}/messagePopupChannel.html | 0 .../message/popup}/messagePopupConfig.coffee | 0 .../message/popup}/messagePopupConfig.html | 0 .../message/popup}/messagePopupEmoji.coffee | 0 .../message/popup}/messagePopupEmoji.html | 0 .../popup}/messagePopupSlashCommand.html | 0 .../message/popup}/messagePopupUser.html | 0 packages/rocketchat-ui-message/package.js | 41 ++++ packages/rocketchat-ui/package.js | 18 -- 40 files changed, 442 insertions(+), 65 deletions(-) rename packages/{rocketchat-ui-message-input => rocketchat-ui-flextab}/README.md (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-flextab/flex-tab}/flexTabBar.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-flextab/flex-tab}/flexTabBar.html (100%) rename packages/{rocketchat-ui/views/app/tabBar => rocketchat-ui-flextab/flex-tab/tabs}/membersList.coffee (100%) rename packages/{rocketchat-ui/views/app/tabBar => rocketchat-ui-flextab/flex-tab/tabs}/membersList.html (100%) rename packages/{rocketchat-ui/views/app/tabBar => rocketchat-ui-flextab/flex-tab/tabs}/messageSearch.coffee (100%) rename packages/{rocketchat-ui/views/app/tabBar => rocketchat-ui-flextab/flex-tab/tabs}/messageSearch.html (100%) rename packages/{rocketchat-ui/views/app/tabBar => rocketchat-ui-flextab/flex-tab/tabs}/uploadedFilesList.coffee (100%) rename packages/{rocketchat-ui/views/app/tabBar => rocketchat-ui-flextab/flex-tab/tabs}/uploadedFilesList.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-flextab/flex-tab/tabs}/userInfo.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-flextab/flex-tab/tabs}/userInfo.html (100%) create mode 100644 packages/rocketchat-ui-flextab/package.js create mode 100644 packages/rocketchat-ui-master/README.md create mode 100644 packages/rocketchat-ui-master/master/error.html create mode 100644 packages/rocketchat-ui-master/master/loading.html create mode 100644 packages/rocketchat-ui-master/master/main.coffee create mode 100644 packages/rocketchat-ui-master/master/main.html create mode 100644 packages/rocketchat-ui-master/package.js delete mode 100644 packages/rocketchat-ui-message-input/package.js create mode 100644 packages/rocketchat-ui-message/README.md rename packages/{rocketchat-ui/views/app => rocketchat-ui-message/message}/message.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message/message}/message.html (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message/message}/messageBox.coffee (100%) rename packages/{rocketchat-ui/views/app => rocketchat-ui-message/message}/messageBox.html (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopup.coffee (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopup.html (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupChannel.html (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupConfig.coffee (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupConfig.html (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupEmoji.coffee (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupEmoji.html (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupSlashCommand.html (100%) rename packages/{rocketchat-ui-message-input/message-input => rocketchat-ui-message/message/popup}/messagePopupUser.html (100%) create mode 100644 packages/rocketchat-ui-message/package.js diff --git a/.meteor/packages b/.meteor/packages index 44cebd6e92f..44a8be3e83f 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -118,4 +118,6 @@ rocketchat:rocketchat-ui-sidenav rocketchat:rocketchat-ui-account rocketchat:rocketchat-ui-admin rocketchat:rocketchat-ui-login -rocketchat:rocketchat-ui-message-input +rocketchat:rocketchat-ui-flextab +rocketchat:rocketchat-ui-message +rocketchat:rocketchat-ui-master diff --git a/.meteor/versions b/.meteor/versions index 72fbd13ca02..4d949732d9e 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -143,10 +143,12 @@ rocketchat:message-pin@0.0.1 rocketchat:message-star@0.0.1 rocketchat:oembed@0.0.1 rocketchat:rocketchat-ui@0.1.0 -rocketchat:rocketchat-ui-account@0.0.1 -rocketchat:rocketchat-ui-admin@0.0.1 -rocketchat:rocketchat-ui-login@0.0.1 -rocketchat:rocketchat-ui-message-input@0.1.0 +rocketchat:rocketchat-ui-account@0.1.0 +rocketchat:rocketchat-ui-admin@0.1.0 +rocketchat:rocketchat-ui-flextab@0.1.0 +rocketchat:rocketchat-ui-login@0.1.0 +rocketchat:rocketchat-ui-master@0.1.0 +rocketchat:rocketchat-ui-message@0.1.0 rocketchat:rocketchat-ui-sidenav@0.1.0 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 diff --git a/packages/rocketchat-ui-account/package.js b/packages/rocketchat-ui-account/package.js index e6f617f4ce9..5b2a9d5fe44 100644 --- a/packages/rocketchat-ui-account/package.js +++ b/packages/rocketchat-ui-account/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'rocketchat:rocketchat-ui-account', - version: '0.0.1', + version: '0.1.0', // Brief, one-line summary of the package. summary: '', // URL to the Git repository containing the source code for this package. diff --git a/packages/rocketchat-ui-admin/package.js b/packages/rocketchat-ui-admin/package.js index 22967b6a286..0dcf68ef2c6 100644 --- a/packages/rocketchat-ui-admin/package.js +++ b/packages/rocketchat-ui-admin/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'rocketchat:rocketchat-ui-admin', - version: '0.0.1', + version: '0.1.0', // Brief, one-line summary of the package. summary: '', // URL to the Git repository containing the source code for this package. diff --git a/packages/rocketchat-ui-message-input/README.md b/packages/rocketchat-ui-flextab/README.md similarity index 100% rename from packages/rocketchat-ui-message-input/README.md rename to packages/rocketchat-ui-flextab/README.md diff --git a/packages/rocketchat-ui/views/app/flexTabBar.coffee b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/flexTabBar.coffee rename to packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee diff --git a/packages/rocketchat-ui/views/app/flexTabBar.html b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html similarity index 100% rename from packages/rocketchat-ui/views/app/flexTabBar.html rename to packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html diff --git a/packages/rocketchat-ui/views/app/tabBar/membersList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/membersList.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/tabBar/membersList.coffee rename to packages/rocketchat-ui-flextab/flex-tab/tabs/membersList.coffee diff --git a/packages/rocketchat-ui/views/app/tabBar/membersList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/membersList.html similarity index 100% rename from packages/rocketchat-ui/views/app/tabBar/membersList.html rename to packages/rocketchat-ui-flextab/flex-tab/tabs/membersList.html diff --git a/packages/rocketchat-ui/views/app/tabBar/messageSearch.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/tabBar/messageSearch.coffee rename to packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee diff --git a/packages/rocketchat-ui/views/app/tabBar/messageSearch.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html similarity index 100% rename from packages/rocketchat-ui/views/app/tabBar/messageSearch.html rename to packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html diff --git a/packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.coffee rename to packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee diff --git a/packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html similarity index 100% rename from packages/rocketchat-ui/views/app/tabBar/uploadedFilesList.html rename to packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html diff --git a/packages/rocketchat-ui/views/app/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/userInfo.coffee rename to packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee diff --git a/packages/rocketchat-ui/views/app/userInfo.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html similarity index 100% rename from packages/rocketchat-ui/views/app/userInfo.html rename to packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html diff --git a/packages/rocketchat-ui-flextab/package.js b/packages/rocketchat-ui-flextab/package.js new file mode 100644 index 00000000000..249d92acecc --- /dev/null +++ b/packages/rocketchat-ui-flextab/package.js @@ -0,0 +1,37 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-flextab', + version: '0.1.0', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'mongo', + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib' + ]); + + api.addFiles('flex-tab/flexTabBar.html', 'client'); + api.addFiles('flex-tab/tabs/membersList.html', 'client'); + api.addFiles('flex-tab/tabs/messageSearch.html', 'client'); + api.addFiles('flex-tab/tabs/uploadedFilesList.html', 'client'); + api.addFiles('flex-tab/tabs/userInfo.html', 'client'); + + api.addFiles('flex-tab/flexTabBar.coffee', 'client'); + api.addFiles('flex-tab/tabs/membersList.coffee', 'client'); + api.addFiles('flex-tab/tabs/messageSearch.coffee', 'client'); + api.addFiles('flex-tab/tabs/uploadedFilesList.coffee', 'client'); + api.addFiles('flex-tab/tabs/userInfo.coffee', 'client'); + +}); diff --git a/packages/rocketchat-ui-login/package.js b/packages/rocketchat-ui-login/package.js index 271e6de4e8d..382048964de 100644 --- a/packages/rocketchat-ui-login/package.js +++ b/packages/rocketchat-ui-login/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'rocketchat:rocketchat-ui-login', - version: '0.0.1', + version: '0.1.0', // Brief, one-line summary of the package. summary: '', // URL to the Git repository containing the source code for this package. @@ -12,7 +12,6 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.2.1'); - api.use([ 'ecmascript', 'templating', @@ -38,5 +37,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-master/README.md b/packages/rocketchat-ui-master/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-ui-master/master/error.html b/packages/rocketchat-ui-master/master/error.html new file mode 100644 index 00000000000..c818e16b9b9 --- /dev/null +++ b/packages/rocketchat-ui-master/master/error.html @@ -0,0 +1,12 @@ +<template name="error"> + <section class="full-page"> + <div class="wrapper"> + <header> + <a class="logo" href="/"> + <img src="/images/logo/logo.svg?v=3" /> + </a> + </header> + <h1>{{_ "Not_found_or_not_allowed"}}</h1> + </div> + </section> +</template> diff --git a/packages/rocketchat-ui-master/master/loading.html b/packages/rocketchat-ui-master/master/loading.html new file mode 100644 index 00000000000..91f1bf7aee0 --- /dev/null +++ b/packages/rocketchat-ui-master/master/loading.html @@ -0,0 +1,24 @@ +<template name="loading"> + <svg class="rocket-loader" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve"> + <g> + <path class="outer" fill="#CC3333" d="M188.146,99.881c0-8.852-2.647-17.341-7.873-25.232c-4.691-7.083-11.263-13.354-19.533-18.637 + c-15.967-10.199-36.953-15.817-59.089-15.817c-7.395,0-14.682,0.625-21.751,1.863c-4.387-4.105-9.521-7.798-14.953-10.72 + c-29.024-14.066-53.094-0.331-53.094-0.331s22.379,18.383,18.739,34.499c-10.012,9.931-15.438,21.906-15.438,34.375 + c0,0.04,0.002,0.08,0.003,0.119c-0.001,0.04-0.003,0.08-0.003,0.119c0,12.469,5.426,24.443,15.438,34.375 + c3.64,16.114-18.739,34.498-18.739,34.498s24.069,13.735,53.094-0.33c5.433-2.922,10.566-6.615,14.953-10.721 + c7.069,1.239,14.356,1.863,21.751,1.863c22.136,0,43.122-5.617,59.089-15.816c8.271-5.282,14.842-11.554,19.533-18.637 + c5.226-7.892,7.873-16.38,7.873-25.232c0-0.04-0.002-0.08-0.002-0.119S188.146,99.92,188.146,99.881z"/> + <path class="inner" fill="#FFFFFF" d="M101.686,51.726c41.843,0,75.765,21.667,75.765,48.395c0,26.728-33.922,48.396-75.765,48.396 + c-9.317,0-18.239-1.076-26.483-3.042c-8.378,10.08-26.809,24.092-44.713,19.562c5.823-6.255,14.452-16.825,12.604-34.233 + c-10.731-8.351-17.173-19.037-17.173-30.683C25.921,73.393,59.842,51.726,101.686,51.726"/> + <g> + <circle fill="#CC3333" cx="136.68" cy="100.121" r="10.063"/> + <circle fill="#CC3333" cx="101.685" cy="100.121" r="10.064"/> + <circle fill="#CC3333" cx="66.691" cy="100.121" r="10.064"/> + </g> + <path class="inner" fill="#CCCCCC" d="M101.686,142.149c-9.317,0-18.239-0.933-26.483-2.636c-7.397,7.713-22.634,18.081-38.425,17.699 + c-2.079,3.153-4.34,5.732-6.288,7.824c17.904,4.53,36.335-9.481,44.713-19.562c8.244,1.966,17.166,3.042,26.483,3.042 + c41.507,0,75.214-21.324,75.752-47.755C176.899,123.67,143.192,142.149,101.686,142.149z"/> + </g> + </svg> +</template> diff --git a/packages/rocketchat-ui-master/master/main.coffee b/packages/rocketchat-ui-master/master/main.coffee new file mode 100644 index 00000000000..e43df650fbd --- /dev/null +++ b/packages/rocketchat-ui-master/master/main.coffee @@ -0,0 +1,216 @@ +Template.body.onRendered -> + $(document.body).on 'keydown', (e) -> + if e.keyCode is 80 and (e.ctrlKey is true or e.metaKey is true) + e.preventDefault() + e.stopPropagation() + spotlight.show() + + if e.keyCode is 27 + spotlight.hide() + + unread = Session.get('unread') + if e.keyCode is 27 and e.shiftKey is true and unread? and unread isnt '' + e.preventDefault() + e.stopPropagation() + swal + title: t('Clear_all_unreads_question') + type: 'warning' + confirmButtonText: t('Yes_clear_all') + showCancelButton: true + cancelButtonText: t('Cancel') + confirmButtonColor: '#DD6B55' + , -> + subscriptions = ChatSubscription.find({open: true}, { fields: { unread: 1, alert: 1, rid: 1, t: 1, name: 1, ls: 1 } }) + for subscription in subscriptions.fetch() + if subscription.alert or subscription.unread > 0 + Meteor.call 'readMessages', subscription.rid + + + Tracker.autorun (c) -> + w = window + d = document + s = 'script' + l = 'dataLayer' + i = RocketChat.settings.get 'API_Analytics' + if Match.test(i, String) and i.trim() isnt '' + c.stop() + do (w,d,s,l,i) -> + w[l] = w[l] || [] + w[l].push {'gtm.start': new Date().getTime(), event:'gtm.js'} + f = d.getElementsByTagName(s)[0] + j = d.createElement(s) + dl = if l isnt 'dataLayer' then '&l=' + l else '' + j.async = true + j.src = '//www.googletagmanager.com/gtm.js?id=' + i + dl + f.parentNode.insertBefore j, f + + Tracker.autorun (c) -> + if RocketChat.settings.get 'Meta_language' + c.stop() + + Meta.set + name: 'http-equiv' + property: 'content-language' + content: RocketChat.settings.get 'Meta_language' + Meta.set + name: 'name' + property: 'language' + content: RocketChat.settings.get 'Meta_language' + + Tracker.autorun (c) -> + if RocketChat.settings.get 'Meta_fb_app_id' + c.stop() + + Meta.set + name: 'property' + property: 'fb:app_id' + content: RocketChat.settings.get 'Meta_fb_app_id' + + Tracker.autorun (c) -> + if RocketChat.settings.get 'Meta_robots' + c.stop() + + Meta.set + name: 'name' + property: 'robots' + content: RocketChat.settings.get 'Meta_robots' + + Tracker.autorun (c) -> + if RocketChat.settings.get 'Meta_google-site-verification' + c.stop() + + Meta.set + name: 'name' + property: 'google-site-verification' + content: RocketChat.settings.get 'Meta_google-site-verification' + + Tracker.autorun (c) -> + if RocketChat.settings.get 'Meta_msvalidate01' + c.stop() + + Meta.set + name: 'name' + property: 'msvalidate.01' + content: RocketChat.settings.get 'Meta_msvalidate01' + + Tracker.autorun (c) -> + c.stop() + + Meta.set + name: 'name' + property: 'application-name' + content: RocketChat.settings.get 'Site_Name' + + Meta.set + name: 'name' + property: 'apple-mobile-web-app-title' + content: RocketChat.settings.get 'Site_Name' + + if Meteor.isCordova + $(document.body).addClass 'is-cordova' + + +Template.main.helpers + + siteName: -> + return RocketChat.settings.get 'Site_Name' + + logged: -> + if Meteor.userId()? + $('html').addClass("noscroll").removeClass("scroll") + return true + else + $('html').addClass("scroll").removeClass("noscroll") + return false + + subsReady: -> + return not Meteor.userId()? or (FlowRouter.subsReady('userData', 'activeUsers')) + + hasUsername: -> + return Meteor.userId()? and Meteor.user().username? + + flexOpened: -> + console.log 'layout.helpers flexOpened' if window.rocketDebug + return 'flex-opened' if RocketChat.TabBar.isFlexOpen() + + flexOpenedRTC1: -> + console.log 'layout.helpers flexOpenedRTC1' if window.rocketDebug + return 'layout1' if Session.equals('rtcLayoutmode', 1) + + flexOpenedRTC2: -> + console.log 'layout.helpers flexOpenedRTC2' if window.rocketDebug + return 'layout2' if (Session.get('rtcLayoutmode') > 1) + + +Template.main.events + + "click .burger": -> + console.log 'room click .burger' if window.rocketDebug + chatContainer = $("#rocket-chat") + menu.toggle() + + 'touchstart': (e, t) -> + if document.body.clientWidth > 780 + return + + t.touchstartX = undefined + t.touchstartY = undefined + t.movestarted = false + t.blockmove = false + if $(e.currentTarget).closest('.main-content').length > 0 + t.touchstartX = e.originalEvent.touches[0].clientX + t.touchstartY = e.originalEvent.touches[0].clientY + t.mainContent = $('.main-content') + t.wrapper = $('.messages-box > .wrapper') + + 'touchmove': (e, t) -> + if t.touchstartX? + touch = e.originalEvent.touches[0] + diffX = t.touchstartX - touch.clientX + diffY = t.touchstartY - touch.clientY + absX = Math.abs(diffX) + absY = Math.abs(diffY) + + if t.movestarted isnt true and t.blockmove isnt true and absY > 5 + t.blockmove = true + + if t.blockmove isnt true and (t.movestarted is true or absX > 5) + t.movestarted = true + + if menu.isOpen() + t.left = 260 - diffX + else + t.left = -diffX + + if t.left > 260 + t.left = 260 + if t.left < 0 + t.left = 0 + + t.mainContent.addClass('notransition') + t.mainContent.css('transform', 'translate('+t.left+'px)') + t.wrapper.css('overflow', 'hidden') + + 'touchend': (e, t) -> + if t.movestarted is true + t.mainContent.removeClass('notransition') + t.mainContent.css('transform', ''); + t.wrapper.css('overflow', '') + + if menu.isOpen() + if t.left >= 200 + menu.open() + else + menu.close() + else + if t.left >= 60 + menu.open() + else + menu.close() + + +Template.main.onRendered -> + + # RTL Support - Need config option on the UI + if isRtl localStorage.getItem "userLanguage" + $('html').addClass "rtl" diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html new file mode 100644 index 00000000000..9eab99a5bec --- /dev/null +++ b/packages/rocketchat-ui-master/master/main.html @@ -0,0 +1,70 @@ +<head> + <title>Rocket.Chat</title> + <meta charset="utf-8" /> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <meta http-equiv="expires" content="-1" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="fragment" content="!" /> + <meta name="distribution" content="global" /> + <meta name="rating" content="general" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <meta name="msapplication-TileColor" content="#04436a"> + <meta name="msapplication-TileImage" content="/images/logo/mstile-144x144.png?v=3"> + <meta name="msapplication-config" content="/images/logo/browserconfig.xml?v=3"> + <meta name="theme-color" content="#04436a"> + <link rel="manifest" href="/images/logo/manifest.json?v=3"> + <link rel="icon" sizes="any" type="image/svg+xml" href="/images/logo/icon.svg?v=3"> + <link rel="icon" sizes="256x256" type="image/png" href="/images/logo/favicon-256x256.png?v=3"> + <link rel="icon" sizes="192x192" type="image/png" href="/images/logo/android-chrome-192x192.png?v=3"> + <link rel="icon" sizes="128x128" type="image/png" href="/images/logo/favicon-128x128.png?v=3"> + <link rel="icon" sizes="96x96" type="image/png" href="/images/logo/favicon-96x96.png?v=3"> + <link rel="icon" sizes="64x64" type="image/png" href="/images/logo/favicon-64x64.png?v=3"> + <!-- + <link rel="icon" sizes="48x48" type="image/png" href="/images/logo/favicon-48x48.png?v=3"> + <link rel="icon" sizes="32x32" type="image/png" href="/images/logo/favicon-32x32.png?v=3"> + <link rel="icon" sizes="16x16" type="image/png" href="/images/logo/favicon-16x16.png?v=3"> + --> + <link rel="shortcut icon" sizes="16x16 32x32 48x48" type="image/x-icon" href="/favicon.ico?v=3" /> + <link rel="apple-touch-icon" sizes="57x57" href="/images/logo/apple-touch-icon-57x57.png?v=3"> + <link rel="apple-touch-icon" sizes="60x60" href="/images/logo/apple-touch-icon-60x60.png?v=3"> + <link rel="apple-touch-icon" sizes="72x72" href="/images/logo/apple-touch-icon-72x72.png?v=3"> + <link rel="apple-touch-icon" sizes="76x76" href="/images/logo/apple-touch-icon-76x76.png?v=3"> + <link rel="apple-touch-icon" sizes="114x114" href="/images/logo/apple-touch-icon-114x114.png?v=3"> + <link rel="apple-touch-icon" sizes="120x120" href="/images/logo/apple-touch-icon-120x120.png?v=3"> + <link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-touch-icon-144x144.png?v=3"> + <link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-touch-icon-152x152.png?v=3"> + <link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png?v=3"> +</head> + +<body> +</body> + +<template name="main"> + {{#if subsReady}} + {{#unless logged}} + {{> loginLayout}} + {{else}} + {{#unless hasUsername}} + {{> username}} + {{else}} + {{> spotlight}} + {{> mobileMessageMenu}} + {{> videoCall overlay=true}} + <div id="user-card-popover"></div> + <div id="rocket-chat" class="menu-nav menu-closed"> + <div class="connection-status"> + {{> status}} + </div> + <div class="flex-tab-bar"> + {{> flexTabBar}} + </div> + <div class="main-content {{flexOpened}} {{flexOpenedRTC1}} {{flexOpenedRTC2}}"> + {{> Template.dynamic template=center}} + </div> + {{> sideNav }} + </div> + {{> audioNotification }} + {{/unless}} + {{/unless}} + {{/if}} +</template> diff --git a/packages/rocketchat-ui-master/package.js b/packages/rocketchat-ui-master/package.js new file mode 100644 index 00000000000..15886dd5e64 --- /dev/null +++ b/packages/rocketchat-ui-master/package.js @@ -0,0 +1,30 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-master', + version: '0.1.0', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'mongo', + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib' + ]); + + api.addFiles('master/main.html', 'client'); + api.addFiles('master/loading.html', 'client'); + api.addFiles('master/error.html', 'client'); + + api.addFiles('master/main.coffee', 'client'); +}); \ No newline at end of file diff --git a/packages/rocketchat-ui-message-input/package.js b/packages/rocketchat-ui-message-input/package.js deleted file mode 100644 index 68ac9348ad2..00000000000 --- a/packages/rocketchat-ui-message-input/package.js +++ /dev/null @@ -1,37 +0,0 @@ -Package.describe({ - name: 'rocketchat:rocketchat-ui-message-input', - version: '0.1.0', - // Brief, one-line summary of the package. - summary: '', - // URL to the Git repository containing the source code for this package. - git: '', - // By default, Meteor will default to using README.md for documentation. - // To avoid submitting documentation, set this field to null. - documentation: 'README.md' -}); - -Package.onUse(function(api) { - api.versionsFrom('1.2.1'); - - api.use([ - 'mongo', - 'ecmascript', - 'templating', - 'coffeescript', - 'underscore', - 'rocketchat:lib@0.0.1' - ]); - - api.addFiles("message-input/messagePopup.html", "client"); - api.addFiles("message-input/messagePopupChannel.html", "client"); - api.addFiles("message-input/messagePopupConfig.html", "client"); - api.addFiles("message-input/messagePopupEmoji.html", "client"); - api.addFiles("message-input/messagePopupSlashCommand.html", "client"); - api.addFiles("message-input/messagePopupUser.html", "client"); - - api.addFiles("message-input/messagePopup.coffee", "client"); - api.addFiles("message-input/messagePopupConfig.coffee", "client"); - api.addFiles("message-input/messagePopupEmoji.coffee", "client"); - - -}); \ No newline at end of file diff --git a/packages/rocketchat-ui-message/README.md b/packages/rocketchat-ui-message/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-ui/views/app/message.coffee b/packages/rocketchat-ui-message/message/message.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/message.coffee rename to packages/rocketchat-ui-message/message/message.coffee diff --git a/packages/rocketchat-ui/views/app/message.html b/packages/rocketchat-ui-message/message/message.html similarity index 100% rename from packages/rocketchat-ui/views/app/message.html rename to packages/rocketchat-ui-message/message/message.html diff --git a/packages/rocketchat-ui/views/app/messageBox.coffee b/packages/rocketchat-ui-message/message/messageBox.coffee similarity index 100% rename from packages/rocketchat-ui/views/app/messageBox.coffee rename to packages/rocketchat-ui-message/message/messageBox.coffee diff --git a/packages/rocketchat-ui/views/app/messageBox.html b/packages/rocketchat-ui-message/message/messageBox.html similarity index 100% rename from packages/rocketchat-ui/views/app/messageBox.html rename to packages/rocketchat-ui-message/message/messageBox.html diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopup.coffee b/packages/rocketchat-ui-message/message/popup/messagePopup.coffee similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopup.coffee rename to packages/rocketchat-ui-message/message/popup/messagePopup.coffee diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopup.html b/packages/rocketchat-ui-message/message/popup/messagePopup.html similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopup.html rename to packages/rocketchat-ui-message/message/popup/messagePopup.html diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupChannel.html b/packages/rocketchat-ui-message/message/popup/messagePopupChannel.html similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupChannel.html rename to packages/rocketchat-ui-message/message/popup/messagePopupChannel.html diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupConfig.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupConfig.coffee rename to packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupConfig.html b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.html similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupConfig.html rename to packages/rocketchat-ui-message/message/popup/messagePopupConfig.html diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.coffee rename to packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.html b/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.html similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupEmoji.html rename to packages/rocketchat-ui-message/message/popup/messagePopupEmoji.html diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupSlashCommand.html b/packages/rocketchat-ui-message/message/popup/messagePopupSlashCommand.html similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupSlashCommand.html rename to packages/rocketchat-ui-message/message/popup/messagePopupSlashCommand.html diff --git a/packages/rocketchat-ui-message-input/message-input/messagePopupUser.html b/packages/rocketchat-ui-message/message/popup/messagePopupUser.html similarity index 100% rename from packages/rocketchat-ui-message-input/message-input/messagePopupUser.html rename to packages/rocketchat-ui-message/message/popup/messagePopupUser.html diff --git a/packages/rocketchat-ui-message/package.js b/packages/rocketchat-ui-message/package.js new file mode 100644 index 00000000000..626bf9f5ced --- /dev/null +++ b/packages/rocketchat-ui-message/package.js @@ -0,0 +1,41 @@ +Package.describe({ + name: 'rocketchat:rocketchat-ui-message', + version: '0.1.0', + // Brief, one-line summary of the package. + summary: '', + // URL to the Git repository containing the source code for this package. + git: '', + // By default, Meteor will default to using README.md for documentation. + // To avoid submitting documentation, set this field to null. + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + + api.use([ + 'mongo', + 'ecmascript', + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib' + ]); + + api.addFiles('message/message.html', 'client'); + api.addFiles("message/messageBox.html", "client"); + api.addFiles("message/popup/messagePopup.html", "client"); + api.addFiles("message/popup/messagePopupChannel.html", "client"); + api.addFiles("message/popup/messagePopupConfig.html", "client"); + api.addFiles("message/popup/messagePopupEmoji.html", "client"); + api.addFiles("message/popup/messagePopupSlashCommand.html", "client"); + api.addFiles("message/popup/messagePopupUser.html", "client"); + + api.addFiles('message/message.coffee', 'client'); + api.addFiles('message/messageBox.coffee', 'client'); + api.addFiles("message/popup/messagePopup.coffee", "client"); + api.addFiles("message/popup/messagePopupConfig.coffee", "client"); + api.addFiles("message/popup/messagePopupEmoji.coffee", "client"); + + +}); \ No newline at end of file diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index ffbe92480bf..730b0d3e9de 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -66,50 +66,32 @@ Package.onUse(function(api) { // TEMPLATE FILES api.addFiles('views/cmsPage.html', 'client'); - api.addFiles('views/error.html', 'client'); api.addFiles('views/fxos.html', 'client'); - api.addFiles('views/loading.html', 'client'); - api.addFiles('views/main.html', 'client'); api.addFiles('views/modal.html', 'client'); api.addFiles('views/404/roomNotFound.html', 'client'); api.addFiles('views/app/audioNotification.html', 'client'); api.addFiles('views/app/burguer.html', 'client'); - api.addFiles('views/app/flexTabBar.html', 'client'); api.addFiles('views/app/home.html', 'client'); - api.addFiles('views/app/message.html', 'client'); api.addFiles('views/app/privateHistory.html', 'client'); api.addFiles('views/app/room.html', 'client'); api.addFiles('views/app/roomSearch.html', 'client'); - api.addFiles('views/app/userInfo.html', 'client'); api.addFiles('views/app/userSearch.html', 'client'); api.addFiles('views/app/spotlight/mobileMessageMenu.html', 'client'); api.addFiles('views/app/spotlight/spotlight.html', 'client'); - api.addFiles('views/app/tabBar/membersList.html', 'client'); - api.addFiles('views/app/tabBar/messageSearch.html', 'client'); - api.addFiles('views/app/tabBar/uploadedFilesList.html', 'client'); api.addFiles('views/app/videoCall/videoButtons.html', 'client'); api.addFiles('views/app/videoCall/videoCall.html', 'client'); - api.addFiles('views/app/messageBox.html', 'client'); api.addFiles('views/cmsPage.coffee', 'client'); api.addFiles('views/fxos.coffee', 'client'); - api.addFiles('views/main.coffee', 'client'); api.addFiles('views/modal.coffee', 'client'); api.addFiles('views/404/roomNotFound.coffee', 'client'); api.addFiles('views/app/burguer.coffee', 'client'); - api.addFiles('views/app/flexTabBar.coffee', 'client'); api.addFiles('views/app/home.coffee', 'client'); - api.addFiles('views/app/message.coffee', 'client'); api.addFiles('views/app/privateHistory.coffee', 'client'); api.addFiles('views/app/room.coffee', 'client'); api.addFiles('views/app/roomSearch.coffee', 'client'); - api.addFiles('views/app/userInfo.coffee', 'client'); api.addFiles('views/app/spotlight/mobileMessageMenu.coffee', 'client'); api.addFiles('views/app/spotlight/spotlight.coffee', 'client'); - api.addFiles('views/app/tabBar/membersList.coffee', 'client'); - api.addFiles('views/app/tabBar/messageSearch.coffee', 'client'); - api.addFiles('views/app/tabBar/uploadedFilesList.coffee', 'client'); api.addFiles('views/app/videoCall/videoButtons.coffee', 'client'); api.addFiles('views/app/videoCall/videoCall.coffee', 'client'); - api.addFiles('views/app/messageBox.coffee', 'client'); }); \ No newline at end of file -- GitLab From 36dec24abd0ed491d3ef0618ce84a8cad9863624 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sun, 15 Nov 2015 20:27:32 -0200 Subject: [PATCH 0437/1338] Update raix:push from 2.6.13-rc.1 to 3.0.2 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index cfb8b8accef..09eedc91faa 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -113,7 +113,7 @@ qnub:emojione@1.5.1_2 raix:eventemitter@0.1.3 raix:eventstate@0.0.4 raix:handlebar-helpers@0.2.5 -raix:push@2.6.13-rc.1 +raix:push@3.0.2 raix:ui-dropped-event@0.0.7 random@1.0.5 rate-limit@1.0.0 -- GitLab From 32e865c09f625b3a90ab756c949cb431de9158d7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sun, 15 Nov 2015 20:27:51 -0200 Subject: [PATCH 0438/1338] Add package autoupdate to remote autoupdate for cordova --- packages/autoupdate/.gitignore | 1 + packages/autoupdate/QA.md | 115 ++++++++ packages/autoupdate/README.md | 11 + packages/autoupdate/autoupdate_client.js | 156 +++++++++++ packages/autoupdate/autoupdate_cordova.js | 314 ++++++++++++++++++++++ packages/autoupdate/autoupdate_server.js | 198 ++++++++++++++ packages/autoupdate/package.js | 35 +++ 7 files changed, 830 insertions(+) create mode 100644 packages/autoupdate/.gitignore create mode 100644 packages/autoupdate/QA.md create mode 100644 packages/autoupdate/README.md create mode 100644 packages/autoupdate/autoupdate_client.js create mode 100644 packages/autoupdate/autoupdate_cordova.js create mode 100644 packages/autoupdate/autoupdate_server.js create mode 100644 packages/autoupdate/package.js diff --git a/packages/autoupdate/.gitignore b/packages/autoupdate/.gitignore new file mode 100644 index 00000000000..677a6fc2637 --- /dev/null +++ b/packages/autoupdate/.gitignore @@ -0,0 +1 @@ +.build* diff --git a/packages/autoupdate/QA.md b/packages/autoupdate/QA.md new file mode 100644 index 00000000000..62afdc6cdf0 --- /dev/null +++ b/packages/autoupdate/QA.md @@ -0,0 +1,115 @@ +# QA Notes +## Hot Code Push Reload + +Run the leaderboard example, and click on one of the names. Make a +change to the leaderboard.html file, see the client reload, and see +that the name is still selected. + + +## AUTOUPDATE_VERSION + +Set the `AUTOUPDATE_VERSION` environment variable when running the +application: + + $ AUTOUPDATE_VERSION=abc meteor + +Now when you make an HTML change, it won't appear in the client +automatically. (Note the leader list flickers when the server +subscription restarts, but that's not a window reload). + +Conversely, you can force a client reload (even without making any +client code changes) by restarting the server with a new value for +`AUTOUPDATE_VERSION`. + + +## No Client Reload on Server-only Change + +Revert previous changes and run the example without setting +AUTOUPDATE_VERSION. + +Note that it might look like the browser is reloading because the page +content in the leaderboard example will flicker when the server +restarts because the example is using autopublish, but that the window +won't actually be reloading. + +In the browser console, assign a variable such as `a = true` so that +you can easily verify that the client hasn't reloaded. + +In the leaderboard example directory, create the `server` directory +and add `foo.js`. See in the browser console that `a` is still +defined, indicating the browser hasn't reloaded. + + +## Test with the appcache + +Add the appcache package: + + $ meteor add appcache + +And do the above tests again. + +Note that if 1) AUTOUPDATE_VERSION is set so the client doesn't +automatically reload, 2) you make a client change, and 3) you manually +reload the browser page, you usually *won't* see the updated HTML the +*first* time you reload (unless the browser happened to check the app +cache manifest between steps 2 and 3). This is normal browser app +cache behavior: the browser populates the app cache in the background, +so it doesn't wait for new files to download before displaying the web +page. + + +## Autoupdate.newClientAvailable + +Undo previous changes made, such as by using `git checkout .` Reload +the client, which will cause the browser to stop using the app cache. + +It's hard to see the `newClientAvailable` reactive variable when the +client automatically reloads. Remove the `hot-code-push` package so you can +see the variable without having the client also reload. + + $ meteor remove meteor-base + $ meteor add meteor webapp ddp autoupdate + +Add to leaderboard.js: + + Template.leaderboard.helpers({ + available: function () { + return Autoupdate.newClientAvailable().toString(); + } + }); + +And add `{{available}}` to the leaderboard template in +leaderboard.html. + +Initially you'll see `false`, and then when you make a change to the +leaderboard HTML you'll see the variable change to `true`. (You won't +see the new HTML on the client because you disabled reload). + +Amusingly, you can undo the addition you made to the HTML and the "new +client available" variable will go back to `false` (you now don't have +client code available on the server different than what's running in +the browser), because by default the client version is based on a hash +of the client files. + + +## DDP Version Negotiation Failure + +A quick way to test DDP version negotiation failure is to force the +client to use the wrong DDP version. At the top of +livedata_connection.js: + + var Connection = function (url, options) { + var self = this; + + options.supportedDDPVersions = ['abc']; + +You will see the client reload (in the hope that new client code will +be available that can successfully negotiation the DDP version). Each +reload takes longer than the one before, using an exponential backoff. + +If you remove the `options.supportedDDPVersions` line and allow the +client to connect (or manually reload the browser page so you don't +have to wait), this will reset the exponential backoff counter. + +You can verify the counter was reset by adding the line back in a +second time, and you'll see the reload cycle start over again with +first reloading quickly, and then again taking longer between tries. diff --git a/packages/autoupdate/README.md b/packages/autoupdate/README.md new file mode 100644 index 00000000000..87e43546764 --- /dev/null +++ b/packages/autoupdate/README.md @@ -0,0 +1,11 @@ +# autoupdate + +This package is the heart of Meteor's Hot Code Push functionality. It has a +client component and a server component component. The client component uses a +DDP API provided by the server to subscribe to the version ID of the most recent +build of the app's client. When it sees that a new version is available, it uses +the [reload](https://atmospherejs.com/meteor/reload) package (if included in the +app) to gracefully save the app's state and reload it in place. + +`autoupdate` is part of the [Webapp](https://www.meteor.com/webapp) +project. diff --git a/packages/autoupdate/autoupdate_client.js b/packages/autoupdate/autoupdate_client.js new file mode 100644 index 00000000000..3f34c965894 --- /dev/null +++ b/packages/autoupdate/autoupdate_client.js @@ -0,0 +1,156 @@ +// Subscribe to the `meteor_autoupdate_clientVersions` collection, +// which contains the set of acceptable client versions. +// +// A "hard code push" occurs when the running client version is not in +// the set of acceptable client versions (or the server updates the +// collection, there is a published client version marked `current` and +// the running client version is no longer in the set). +// +// When the `reload` package is loaded, a hard code push causes +// the browser to reload, so that it will load the latest client +// version from the server. +// +// A "soft code push" represents the situation when the running client +// version is in the set of acceptable versions, but there is a newer +// version available on the server. +// +// `Autoupdate.newClientAvailable` is a reactive data source which +// becomes `true` if there is a new version of the client is available on +// the server. +// +// This package doesn't implement a soft code reload process itself, +// but `newClientAvailable` could be used for example to display a +// "click to reload" link to the user. + +// The client version of the client code currently running in the +// browser. +var autoupdateVersion = __meteor_runtime_config__.autoupdateVersion || "unknown"; +var autoupdateVersionRefreshable = + __meteor_runtime_config__.autoupdateVersionRefreshable || "unknown"; + +// The collection of acceptable client versions. +ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions"); + +Autoupdate = {}; + +Autoupdate.newClientAvailable = function () { + return !! ClientVersions.findOne({ + _id: "version", + version: {$ne: autoupdateVersion} }) || + !! ClientVersions.findOne({ + _id: "version-refreshable", + version: {$ne: autoupdateVersionRefreshable} }); +}; +Autoupdate._ClientVersions = ClientVersions; // Used by a self-test + +var knownToSupportCssOnLoad = false; + +var retry = new Retry({ + // Unlike the stream reconnect use of Retry, which we want to be instant + // in normal operation, this is a wacky failure. We don't want to retry + // right away, we can start slowly. + // + // A better way than timeconstants here might be to use the knowledge + // of when we reconnect to help trigger these retries. Typically, the + // server fixing code will result in a restart and reconnect, but + // potentially the subscription could have a transient error. + minCount: 0, // don't do any immediate retries + baseTimeout: 30*1000 // start with 30s +}); +var failures = 0; + +Autoupdate._retrySubscription = function () { + Meteor.subscribe("meteor_autoupdate_clientVersions", { + onError: function (error) { + Meteor._debug("autoupdate subscription failed:", error); + failures++; + retry.retryLater(failures, function () { + // Just retry making the subscription, don't reload the whole + // page. While reloading would catch more cases (for example, + // the server went back a version and is now doing old-style hot + // code push), it would also be more prone to reload loops, + // which look really bad to the user. Just retrying the + // subscription over DDP means it is at least possible to fix by + // updating the server. + Autoupdate._retrySubscription(); + }); + }, + onReady: function () { + if (Package.reload) { + var checkNewVersionDocument = function (doc) { + var self = this; + if (doc._id === 'version-refreshable' && + doc.version !== autoupdateVersionRefreshable) { + autoupdateVersionRefreshable = doc.version; + // Switch out old css links for the new css links. Inspired by: + // https://github.com/guard/guard-livereload/blob/master/js/livereload.js#L710 + var newCss = (doc.assets && doc.assets.allCss) || []; + var oldLinks = []; + _.each(document.getElementsByTagName('link'), function (link) { + if (link.className === '__meteor-css__') { + oldLinks.push(link); + } + }); + + var waitUntilCssLoads = function (link, callback) { + var executeCallback = _.once(callback); + link.onload = function () { + knownToSupportCssOnLoad = true; + executeCallback(); + }; + if (! knownToSupportCssOnLoad) { + var id = Meteor.setInterval(function () { + if (link.sheet) { + executeCallback(); + Meteor.clearInterval(id); + } + }, 50); + } + }; + + var removeOldLinks = _.after(newCss.length, function () { + _.each(oldLinks, function (oldLink) { + oldLink.parentNode.removeChild(oldLink); + }); + }); + + var attachStylesheetLink = function (newLink) { + document.getElementsByTagName("head").item(0).appendChild(newLink); + + waitUntilCssLoads(newLink, function () { + Meteor.setTimeout(removeOldLinks, 200); + }); + }; + + if (newCss.length !== 0) { + _.each(newCss, function (css) { + var newLink = document.createElement("link"); + newLink.setAttribute("rel", "stylesheet"); + newLink.setAttribute("type", "text/css"); + newLink.setAttribute("class", "__meteor-css__"); + newLink.setAttribute("href", Meteor._relativeToSiteRootUrl(css.url)); + attachStylesheetLink(newLink); + }); + } else { + removeOldLinks(); + } + + } + else if (doc._id === 'version' && doc.version !== autoupdateVersion) { + handle && handle.stop(); + + if (Package.reload) { + Package.reload.Reload._reload(); + } + } + }; + + var handle = ClientVersions.find().observe({ + added: checkNewVersionDocument, + changed: checkNewVersionDocument + }); + } + } + }); +}; +Autoupdate._retrySubscription(); diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js new file mode 100644 index 00000000000..2cc2290db91 --- /dev/null +++ b/packages/autoupdate/autoupdate_cordova.js @@ -0,0 +1,314 @@ +var DEBUG_TAG = 'METEOR CORDOVA DEBUG (autoupdate_cordova.js) '; +var log = function (msg) { + console.log(DEBUG_TAG + msg); +}; + +// This constant was picked by testing on iOS 7.1 +// We limit the number of concurrent downloads because iOS gets angry on the +// application when a certain limit is exceeded and starts timing-out the +// connections in 1-2 minutes which makes the whole HCP really slow. +var MAX_NUM_CONCURRENT_DOWNLOADS = 30; +var MAX_RETRY_COUNT = 5; + +var autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova || "unknown"; + +// The collection of acceptable client versions. +ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions"); + +Autoupdate = {}; + +Autoupdate.newClientAvailable = function () { + return !! ClientVersions.findOne({ + _id: 'version-cordova', + version: {$ne: autoupdateVersionCordova} + }); +}; + +var writeFile = function (directoryPath, fileName, content, cb) { + var fail = function (err) { + cb(new Error("Failed to write file: ", err), null); + }; + + window.resolveLocalFileSystemURL(directoryPath, function (dirEntry) { + var success = function (fileEntry) { + fileEntry.createWriter(function (writer) { + writer.onwrite = function (evt) { + var result = evt.target.result; + cb(null, result); + }; + writer.onerror = fail; + writer.write(content); + }, fail); + }; + + dirEntry.getFile(fileName, { + create: true, + exclusive: false + }, success, fail); + }, fail); +}; + +var restartServer = function (location) { + log('restartServer with location ' + location); + var fail = function (err) { log("Unexpected error in restartServer: " + err.message) }; + var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate; + + if (! httpd) { + fail(new Error('no httpd')); + return; + } + + var startServer = function (cordovajsRoot) { + httpd.startServer({ + 'www_root' : location, + 'cordovajs_root': cordovajsRoot + }, function (url) { + if (Package.reload) { + Package.reload.Reload._reload(); + } else { + window.location.reload(); + } + }, fail); + }; + + httpd.getCordovajsRoot(function (cordovajsRoot) { + startServer(cordovajsRoot); + }, fail); +}; + +var hasCalledReload = false; +var updating = false; +var localPathPrefix = null; + +var onNewVersion = function () { + var ft = new FileTransfer(); + var urlPrefix = Meteor.absoluteUrl() + '__cordova'; + HTTP.get(urlPrefix + '/manifest.json', function (err, res) { + if (err || ! res.data) { + log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content)); + return; + } + + updating = true; + ensureLocalPathPrefix(_.bind(downloadNewVersion, null, res.data)); + }); +}; + +var downloadNewVersion = function (program) { + var urlPrefix = Meteor.absoluteUrl() + '__cordova'; + var manifest = _.clone(program.manifest); + var version = program.version; + var ft = new FileTransfer(); + + manifest.push({ url: '/index.html?' + Random.id() }); + + var versionPrefix = localPathPrefix + version; + + var queue = []; + _.each(manifest, function (item) { + if (! item.url) return; + + var url = item.url; + url = url.replace(/\?.+$/, ''); + + queue.push(url); + }); + + var afterAllFilesDownloaded = _.after(queue.length, function () { + var wroteManifest = function (err) { + if (err) { + log("Failed to write manifest.json: " + err); + // XXX do something smarter? + return; + } + + // success! downloaded all sources and saved the manifest + // save the version string for atomicity + writeFile(localPathPrefix, 'version', version, function (err) { + if (err) { + log("Failed to write version: " + err); + return; + } + + // don't call reload twice! + if (! hasCalledReload) { + var location = uriToPath(localPathPrefix + version); + restartServer(location); + } + }); + }; + + writeFile(versionPrefix, 'manifest.json', + JSON.stringify(program, undefined, 2), wroteManifest); + }); + + var downloadUrl = function (url) { + console.log(DEBUG_TAG + "start downloading " + url); + // Add a cache buster to ensure that we don't cache an old asset. + var uri = encodeURI(urlPrefix + url + '?' + Random.id()); + + // Try to download the file a few times. + var tries = 0; + var tryDownload = function () { + ft.download(uri, versionPrefix + encodeURI(url), function (entry) { + if (entry) { + console.log(DEBUG_TAG + "done downloading " + url); + // start downloading next queued url + if (queue.length) + downloadUrl(queue.shift()); + afterAllFilesDownloaded(); + } + }, function (err) { + // It failed, try again if we have tried less than 5 times. + if (tries++ < MAX_RETRY_COUNT) { + log("Download error, will retry (#" + tries + "): " + uri); + tryDownload(); + } else { + log('Download failed: ' + JSON.stringify(err) + ", source=" + err.source + ", target=" + err.target); + } + }); + }; + + tryDownload(); + }; + + _.times(Math.min(MAX_NUM_CONCURRENT_DOWNLOADS, queue.length), function () { + var nextUrl = queue.shift(); + // XXX defer the next download so iOS doesn't rate limit us on concurrent + // downloads + Meteor.setTimeout(downloadUrl.bind(null, nextUrl), 50); + }); +}; + +var retry = new Retry({ + minCount: 0, // don't do any immediate retries + baseTimeout: 30*1000 // start with 30s +}); +var failures = 0; + +Autoupdate._retrySubscription = function () { + var appId = __meteor_runtime_config__.appId; + Meteor.subscribe("meteor_autoupdate_clientVersions", appId, { + onError: function (err) { + Meteor._debug("autoupdate subscription failed:", err); + failures++; + retry.retryLater(failures, function () { + // Just retry making the subscription, don't reload the whole + // page. While reloading would catch more cases (for example, + // the server went back a version and is now doing old-style hot + // code push), it would also be more prone to reload loops, + // which look really bad to the user. Just retrying the + // subscription over DDP means it is at least possible to fix by + // updating the server. + Autoupdate._retrySubscription(); + }); + } + }); + if (Package.reload) { + var checkNewVersionDocument = function (doc) { + var self = this; + if (doc.version !== autoupdateVersionCordova) { + onNewVersion(); + } + }; + + var handle = ClientVersions.find({ + _id: 'version-cordova' + }).observe({ + added: checkNewVersionDocument, + changed: checkNewVersionDocument + }); + } +}; + +Meteor.startup(function () { + clearAutoupdateCache(autoupdateVersionCordova); +}); +Meteor.startup(Autoupdate._retrySubscription); + + +// A helper that removes old directories left from previous autoupdates +var clearAutoupdateCache = function (currentVersion) { + ensureLocalPathPrefix(function () { + // Try to clean up our cache directory, make sure to scan the directory + // *before* loading the actual app. This ordering will prevent race + // conditions when the app code tries to download a new version before + // the old-cache removal has scanned the cache folder. + listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) { + // Couldn't get the list of dirs or risking to get into a race with an + // on-going update to disk. + if (err || updating) { + return; + } + + _.each(names, function (name) { + // Skip the folder with the latest version + if (name === currentVersion) + return; + + // remove everything else, as we don't want to keep too much cache + // around on disk + removeDirectory(localPathPrefix + name + '/', function (err) { + if (err) { + log('Failed to remove an old cache folder ' + + name + ':' + err.message); + } else { + log('Successfully removed an old cache folder ' + name); + } + }); + }); + }); + }) +}; + +// Cordova File plugin helpers +var listDirectory = function (url, options, cb) { + if (typeof options === 'function') + cb = options, options = {}; + + var fail = function (err) { cb(err); }; + window.resolveLocalFileSystemURL(url, function (entry) { + var reader = entry.createReader(); + reader.readEntries(function (entries) { + var names = []; + _.each(entries, function (entry) { + if (! options.dirsOnly || entry.isDirectory) + names.push(entry.name); + }); + cb(null, names); + }, fail); + }, fail); +}; + +var removeDirectory = function (url, cb) { + var fail = function (err) { + cb(err); + }; + window.resolveLocalFileSystemURL(url, function (entry) { + entry.removeRecursively(function () { cb(); }, fail); + }, fail); +}; + +var uriToPath = function (uri) { + return decodeURI(uri).replace(/^file:\/\//g, ''); +}; + +var ensureLocalPathPrefix = function (cb) { + if (! localPathPrefix) { + if (! cordova.file.dataDirectory) { + // Since ensureLocalPathPrefix function is always called on + // Meteor.startup, all Cordova plugins should be ready. + // XXX Experiments have shown that it is not always the case, even when + // the cordova.file symbol is attached, properties like dataDirectory + // still can be null. Poll until we are sure the property is attached. + console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms'); + Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20); + } else { + localPathPrefix = cordova.file.dataDirectory + 'meteor/'; + cb(); + } + } else { + cb(); + } +}; + diff --git a/packages/autoupdate/autoupdate_server.js b/packages/autoupdate/autoupdate_server.js new file mode 100644 index 00000000000..e8cc1785792 --- /dev/null +++ b/packages/autoupdate/autoupdate_server.js @@ -0,0 +1,198 @@ +// Publish the current client versions to the client. When a client +// sees the subscription change and that there is a new version of the +// client available on the server, it can reload. +// +// By default there are two current client versions. The refreshable client +// version is identified by a hash of the client resources seen by the browser +// that are refreshable, such as CSS, while the non refreshable client version +// is identified by a hash of the rest of the client assets +// (the HTML, code, and static files in the `public` directory). +// +// If the environment variable `AUTOUPDATE_VERSION` is set it will be +// used as the client id instead. You can use this to control when +// the client reloads. For example, if you want to only force a +// reload on major changes, you can use a custom AUTOUPDATE_VERSION +// which you only change when something worth pushing to clients +// immediately happens. +// +// The server publishes a `meteor_autoupdate_clientVersions` +// collection. There are two documents in this collection, a document +// with _id 'version' which represents the non refreshable client assets, +// and a document with _id 'version-refreshable' which represents the +// refreshable client assets. Each document has a 'version' field +// which is equivalent to the hash of the relevant assets. The refreshable +// document also contains a list of the refreshable assets, so that the client +// can swap in the new assets without forcing a page refresh. Clients can +// observe changes on these documents to detect when there is a new +// version available. +// +// In this implementation only two documents are present in the collection +// the current refreshable client version and the current nonRefreshable client +// version. Developers can easily experiment with different versioning and +// updating models by forking this package. + +var Future = Npm.require("fibers/future"); + +Autoupdate = {}; + +// The collection of acceptable client versions. +ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions", + { connection: null }); + +// The client hash includes __meteor_runtime_config__, so wait until +// all packages have loaded and have had a chance to populate the +// runtime config before using the client hash as our default auto +// update version id. + +// Note: Tests allow people to override Autoupdate.autoupdateVersion before +// startup. +Autoupdate.autoupdateVersion = null; +Autoupdate.autoupdateVersionRefreshable = null; +Autoupdate.autoupdateVersionCordova = null; +Autoupdate.appId = __meteor_runtime_config__.appId = process.env.APP_ID; + +var syncQueue = new Meteor._SynchronousQueue(); + +// updateVersions can only be called after the server has fully loaded. +var updateVersions = function (shouldReloadClientProgram) { + // Step 1: load the current client program on the server and update the + // hash values in __meteor_runtime_config__. + if (shouldReloadClientProgram) { + WebAppInternals.reloadClientPrograms(); + } + + // If we just re-read the client program, or if we don't have an autoupdate + // version, calculate it. + if (shouldReloadClientProgram || Autoupdate.autoupdateVersion === null) { + Autoupdate.autoupdateVersion = + process.env.AUTOUPDATE_VERSION || + WebApp.calculateClientHashNonRefreshable(); + } + // If we just recalculated it OR if it was set by (eg) test-in-browser, + // ensure it ends up in __meteor_runtime_config__. + __meteor_runtime_config__.autoupdateVersion = + Autoupdate.autoupdateVersion; + + Autoupdate.autoupdateVersionRefreshable = + __meteor_runtime_config__.autoupdateVersionRefreshable = + process.env.AUTOUPDATE_VERSION || + WebApp.calculateClientHashRefreshable(); + + Autoupdate.autoupdateVersionCordova = + __meteor_runtime_config__.autoupdateVersionCordova = + process.env.AUTOUPDATE_VERSION || + WebApp.calculateClientHashCordova(); + + // Step 2: form the new client boilerplate which contains the updated + // assets and __meteor_runtime_config__. + if (shouldReloadClientProgram) { + WebAppInternals.generateBoilerplate(); + } + + // XXX COMPAT WITH 0.8.3 + if (! ClientVersions.findOne({current: true})) { + // To ensure apps with version of Meteor prior to 0.9.0 (in + // which the structure of documents in `ClientVersions` was + // different) also reload. + ClientVersions.insert({current: true}); + } + + if (! ClientVersions.findOne({_id: "version"})) { + ClientVersions.insert({ + _id: "version", + version: Autoupdate.autoupdateVersion + }); + } else { + ClientVersions.update("version", { $set: { + version: Autoupdate.autoupdateVersion + }}); + } + + if (! ClientVersions.findOne({_id: "version-cordova"})) { + ClientVersions.insert({ + _id: "version-cordova", + version: Autoupdate.autoupdateVersionCordova, + refreshable: false + }); + } else { + ClientVersions.update("version-cordova", { $set: { + version: Autoupdate.autoupdateVersionCordova + }}); + } + + // Use `onListening` here because we need to use + // `WebAppInternals.refreshableAssets`, which is only set after + // `WebApp.generateBoilerplate` is called by `main` in webapp. + WebApp.onListening(function () { + if (! ClientVersions.findOne({_id: "version-refreshable"})) { + ClientVersions.insert({ + _id: "version-refreshable", + version: Autoupdate.autoupdateVersionRefreshable, + assets: WebAppInternals.refreshableAssets + }); + } else { + ClientVersions.update("version-refreshable", { $set: { + version: Autoupdate.autoupdateVersionRefreshable, + assets: WebAppInternals.refreshableAssets + }}); + } + }); +}; + +Meteor.publish( + "meteor_autoupdate_clientVersions", + function (appId) { + // `null` happens when a client doesn't have an appId and passes + // `undefined` to `Meteor.subscribe`. `undefined` is translated to + // `null` as JSON doesn't have `undefined. + check(appId, Match.OneOf(String, undefined, null)); + + // Don't notify clients using wrong appId such as mobile apps built with a + // different server but pointing at the same local url + if (Autoupdate.appId && appId && Autoupdate.appId !== appId) + return []; + + return ClientVersions.find(); + }, + {is_auto: true} +); + +Meteor.startup(function () { + updateVersions(false); +}); + +var fut = new Future(); + +// We only want 'refresh' to trigger 'updateVersions' AFTER onListen, +// so we add a queued task that waits for onListen before 'refresh' can queue +// tasks. Note that the `onListening` callbacks do not fire until after +// Meteor.startup, so there is no concern that the 'updateVersions' calls from +// 'refresh' will overlap with the `updateVersions` call from Meteor.startup. + +syncQueue.queueTask(function () { + fut.wait(); +}); + +WebApp.onListening(function () { + fut.return(); +}); + +var enqueueVersionsRefresh = function () { + syncQueue.queueTask(function () { + updateVersions(true); + }); +}; + +// Listen for the special {refresh: 'client'} message, which signals that a +// client asset has changed. +process.on('message', Meteor.bindEnvironment(function (m) { + if (m && m.refresh === 'client') { + enqueueVersionsRefresh(); + } +}, "handling client refresh message")); + +// Another way to tell the process to refresh: send SIGHUP signal +process.on('SIGHUP', Meteor.bindEnvironment(function () { + enqueueVersionsRefresh(); +}, "handling SIGHUP signal for refresh")); + diff --git a/packages/autoupdate/package.js b/packages/autoupdate/package.js new file mode 100644 index 00000000000..9d81493e206 --- /dev/null +++ b/packages/autoupdate/package.js @@ -0,0 +1,35 @@ +Package.describe({ + summary: "Update the client when new client code is available", + version: '1.2.4' +}); + +Cordova.depends({ + 'cordova-plugin-file': '2.1.0', + 'cordova-plugin-file-transfer': '1.2.0' +}); + +Package.onUse(function (api) { + api.use([ + 'webapp', + 'check' + ], 'server'); + + api.use([ + 'tracker', + 'retry' + ], 'client'); + + api.use([ + 'ddp', + 'mongo', + 'underscore' + ], ['client', 'server']); + + api.use(['http', 'random'], 'web.cordova'); + + api.addFiles('autoupdate_server.js', 'server'); + api.addFiles('autoupdate_client.js', 'web.browser'); + // api.addFiles('autoupdate_cordova.js', 'web.cordova'); + + api.export('Autoupdate'); +}); -- GitLab From be8ec94f6f28e0b30334696d1db53856ad2ea4af Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sun, 15 Nov 2015 22:04:28 -0200 Subject: [PATCH 0439/1338] Fix code of Push for new package version --- server/lib/cordova.coffee | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/server/lib/cordova.coffee b/server/lib/cordova.coffee index 2e74f6fdd62..c8b966982fd 100644 --- a/server/lib/cordova.coffee +++ b/server/lib/cordova.coffee @@ -12,16 +12,20 @@ Meteor.startup -> send: (userId, notification) -> return RocketChat.authz.hasRole(userId, 'admin') - Push.Configure - apn: - passphrase: RocketChat.settings.get 'Push_apn_passphrase' - keyData: RocketChat.settings.get 'Push_apn_key' - certData: RocketChat.settings.get 'Push_apn_cert' - 'apn-dev': + apn = + passphrase: RocketChat.settings.get 'Push_apn_passphrase' + keyData: RocketChat.settings.get 'Push_apn_key' + certData: RocketChat.settings.get 'Push_apn_cert' + + if RocketChat.settings.get('Push_production') isnt true + apn = passphrase: RocketChat.settings.get 'Push_apn_dev_passphrase' keyData: RocketChat.settings.get 'Push_apn_dev_key' certData: RocketChat.settings.get 'Push_apn_dev_cert' gateway: 'gateway.sandbox.push.apple.com' + + Push.Configure + apn: apn gcm: apiKey: RocketChat.settings.get 'Push_gcm_api_key' projectNumber: RocketChat.settings.get 'Push_gcm_project_number' -- GitLab From ada54fe7c147f42a941b104e40c4008574906a56 Mon Sep 17 00:00:00 2001 From: Nolan Darilek <nolan@thewordnerd.info> Date: Sun, 15 Nov 2015 23:42:02 -0600 Subject: [PATCH 0440/1338] Fix confusing text labels on video/audio call buttons. --- client/views/app/videoCall/videoButtons.html | 8 ++++---- packages/rocketchat-webrtc-ib/i18n/en.i18n.json | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/views/app/videoCall/videoButtons.html b/client/views/app/videoCall/videoButtons.html index fac8fced588..05f71735789 100644 --- a/client/views/app/videoCall/videoButtons.html +++ b/client/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"><i class="icon-videocam"></i>{{_ "Video"}}</button> + <button class="join-audio-call button secondary"><i class="icon-phone"></i>{{_ "Audio"}}</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"><i class="icon-videocam"></i>{{_ "Video_Chat"}}</button> + <button class="start-audio-call button"><i class="icon-phone"></i>{{_ "Audio_Chat"}}</button> {{/if}} {{/unless}} {{/if}} diff --git a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json b/packages/rocketchat-webrtc-ib/i18n/en.i18n.json index 84f089985d2..59bab58c66a 100644 --- a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json +++ b/packages/rocketchat-webrtc-ib/i18n/en.i18n.json @@ -1,4 +1,7 @@ { + "Audio" : "Audio", + "Audio_Chat" : "Audio Chat", + "Video" : "Video", "Video_Chat" : "Video Chat", "Remote" : "Remote", "Setup" : "Setup", -- GitLab From dc8200ff5d09cb4d7430670e1e1c27d0598ca287 Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Mon, 16 Nov 2015 07:24:35 +0100 Subject: [PATCH 0441/1338] Removed master templates from the rocketchat-ui package --- packages/rocketchat-ui/views/error.html | 12 -- packages/rocketchat-ui/views/loading.html | 24 --- packages/rocketchat-ui/views/main.coffee | 216 ---------------------- packages/rocketchat-ui/views/main.html | 70 ------- 4 files changed, 322 deletions(-) delete mode 100644 packages/rocketchat-ui/views/error.html delete mode 100644 packages/rocketchat-ui/views/loading.html delete mode 100644 packages/rocketchat-ui/views/main.coffee delete mode 100644 packages/rocketchat-ui/views/main.html diff --git a/packages/rocketchat-ui/views/error.html b/packages/rocketchat-ui/views/error.html deleted file mode 100644 index c818e16b9b9..00000000000 --- a/packages/rocketchat-ui/views/error.html +++ /dev/null @@ -1,12 +0,0 @@ -<template name="error"> - <section class="full-page"> - <div class="wrapper"> - <header> - <a class="logo" href="/"> - <img src="/images/logo/logo.svg?v=3" /> - </a> - </header> - <h1>{{_ "Not_found_or_not_allowed"}}</h1> - </div> - </section> -</template> diff --git a/packages/rocketchat-ui/views/loading.html b/packages/rocketchat-ui/views/loading.html deleted file mode 100644 index 91f1bf7aee0..00000000000 --- a/packages/rocketchat-ui/views/loading.html +++ /dev/null @@ -1,24 +0,0 @@ -<template name="loading"> - <svg class="rocket-loader" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve"> - <g> - <path class="outer" fill="#CC3333" d="M188.146,99.881c0-8.852-2.647-17.341-7.873-25.232c-4.691-7.083-11.263-13.354-19.533-18.637 - c-15.967-10.199-36.953-15.817-59.089-15.817c-7.395,0-14.682,0.625-21.751,1.863c-4.387-4.105-9.521-7.798-14.953-10.72 - c-29.024-14.066-53.094-0.331-53.094-0.331s22.379,18.383,18.739,34.499c-10.012,9.931-15.438,21.906-15.438,34.375 - c0,0.04,0.002,0.08,0.003,0.119c-0.001,0.04-0.003,0.08-0.003,0.119c0,12.469,5.426,24.443,15.438,34.375 - c3.64,16.114-18.739,34.498-18.739,34.498s24.069,13.735,53.094-0.33c5.433-2.922,10.566-6.615,14.953-10.721 - c7.069,1.239,14.356,1.863,21.751,1.863c22.136,0,43.122-5.617,59.089-15.816c8.271-5.282,14.842-11.554,19.533-18.637 - c5.226-7.892,7.873-16.38,7.873-25.232c0-0.04-0.002-0.08-0.002-0.119S188.146,99.92,188.146,99.881z"/> - <path class="inner" fill="#FFFFFF" d="M101.686,51.726c41.843,0,75.765,21.667,75.765,48.395c0,26.728-33.922,48.396-75.765,48.396 - c-9.317,0-18.239-1.076-26.483-3.042c-8.378,10.08-26.809,24.092-44.713,19.562c5.823-6.255,14.452-16.825,12.604-34.233 - c-10.731-8.351-17.173-19.037-17.173-30.683C25.921,73.393,59.842,51.726,101.686,51.726"/> - <g> - <circle fill="#CC3333" cx="136.68" cy="100.121" r="10.063"/> - <circle fill="#CC3333" cx="101.685" cy="100.121" r="10.064"/> - <circle fill="#CC3333" cx="66.691" cy="100.121" r="10.064"/> - </g> - <path class="inner" fill="#CCCCCC" d="M101.686,142.149c-9.317,0-18.239-0.933-26.483-2.636c-7.397,7.713-22.634,18.081-38.425,17.699 - c-2.079,3.153-4.34,5.732-6.288,7.824c17.904,4.53,36.335-9.481,44.713-19.562c8.244,1.966,17.166,3.042,26.483,3.042 - c41.507,0,75.214-21.324,75.752-47.755C176.899,123.67,143.192,142.149,101.686,142.149z"/> - </g> - </svg> -</template> diff --git a/packages/rocketchat-ui/views/main.coffee b/packages/rocketchat-ui/views/main.coffee deleted file mode 100644 index e43df650fbd..00000000000 --- a/packages/rocketchat-ui/views/main.coffee +++ /dev/null @@ -1,216 +0,0 @@ -Template.body.onRendered -> - $(document.body).on 'keydown', (e) -> - if e.keyCode is 80 and (e.ctrlKey is true or e.metaKey is true) - e.preventDefault() - e.stopPropagation() - spotlight.show() - - if e.keyCode is 27 - spotlight.hide() - - unread = Session.get('unread') - if e.keyCode is 27 and e.shiftKey is true and unread? and unread isnt '' - e.preventDefault() - e.stopPropagation() - swal - title: t('Clear_all_unreads_question') - type: 'warning' - confirmButtonText: t('Yes_clear_all') - showCancelButton: true - cancelButtonText: t('Cancel') - confirmButtonColor: '#DD6B55' - , -> - subscriptions = ChatSubscription.find({open: true}, { fields: { unread: 1, alert: 1, rid: 1, t: 1, name: 1, ls: 1 } }) - for subscription in subscriptions.fetch() - if subscription.alert or subscription.unread > 0 - Meteor.call 'readMessages', subscription.rid - - - Tracker.autorun (c) -> - w = window - d = document - s = 'script' - l = 'dataLayer' - i = RocketChat.settings.get 'API_Analytics' - if Match.test(i, String) and i.trim() isnt '' - c.stop() - do (w,d,s,l,i) -> - w[l] = w[l] || [] - w[l].push {'gtm.start': new Date().getTime(), event:'gtm.js'} - f = d.getElementsByTagName(s)[0] - j = d.createElement(s) - dl = if l isnt 'dataLayer' then '&l=' + l else '' - j.async = true - j.src = '//www.googletagmanager.com/gtm.js?id=' + i + dl - f.parentNode.insertBefore j, f - - Tracker.autorun (c) -> - if RocketChat.settings.get 'Meta_language' - c.stop() - - Meta.set - name: 'http-equiv' - property: 'content-language' - content: RocketChat.settings.get 'Meta_language' - Meta.set - name: 'name' - property: 'language' - content: RocketChat.settings.get 'Meta_language' - - Tracker.autorun (c) -> - if RocketChat.settings.get 'Meta_fb_app_id' - c.stop() - - Meta.set - name: 'property' - property: 'fb:app_id' - content: RocketChat.settings.get 'Meta_fb_app_id' - - Tracker.autorun (c) -> - if RocketChat.settings.get 'Meta_robots' - c.stop() - - Meta.set - name: 'name' - property: 'robots' - content: RocketChat.settings.get 'Meta_robots' - - Tracker.autorun (c) -> - if RocketChat.settings.get 'Meta_google-site-verification' - c.stop() - - Meta.set - name: 'name' - property: 'google-site-verification' - content: RocketChat.settings.get 'Meta_google-site-verification' - - Tracker.autorun (c) -> - if RocketChat.settings.get 'Meta_msvalidate01' - c.stop() - - Meta.set - name: 'name' - property: 'msvalidate.01' - content: RocketChat.settings.get 'Meta_msvalidate01' - - Tracker.autorun (c) -> - c.stop() - - Meta.set - name: 'name' - property: 'application-name' - content: RocketChat.settings.get 'Site_Name' - - Meta.set - name: 'name' - property: 'apple-mobile-web-app-title' - content: RocketChat.settings.get 'Site_Name' - - if Meteor.isCordova - $(document.body).addClass 'is-cordova' - - -Template.main.helpers - - siteName: -> - return RocketChat.settings.get 'Site_Name' - - logged: -> - if Meteor.userId()? - $('html').addClass("noscroll").removeClass("scroll") - return true - else - $('html').addClass("scroll").removeClass("noscroll") - return false - - subsReady: -> - return not Meteor.userId()? or (FlowRouter.subsReady('userData', 'activeUsers')) - - hasUsername: -> - return Meteor.userId()? and Meteor.user().username? - - flexOpened: -> - console.log 'layout.helpers flexOpened' if window.rocketDebug - return 'flex-opened' if RocketChat.TabBar.isFlexOpen() - - flexOpenedRTC1: -> - console.log 'layout.helpers flexOpenedRTC1' if window.rocketDebug - return 'layout1' if Session.equals('rtcLayoutmode', 1) - - flexOpenedRTC2: -> - console.log 'layout.helpers flexOpenedRTC2' if window.rocketDebug - return 'layout2' if (Session.get('rtcLayoutmode') > 1) - - -Template.main.events - - "click .burger": -> - console.log 'room click .burger' if window.rocketDebug - chatContainer = $("#rocket-chat") - menu.toggle() - - 'touchstart': (e, t) -> - if document.body.clientWidth > 780 - return - - t.touchstartX = undefined - t.touchstartY = undefined - t.movestarted = false - t.blockmove = false - if $(e.currentTarget).closest('.main-content').length > 0 - t.touchstartX = e.originalEvent.touches[0].clientX - t.touchstartY = e.originalEvent.touches[0].clientY - t.mainContent = $('.main-content') - t.wrapper = $('.messages-box > .wrapper') - - 'touchmove': (e, t) -> - if t.touchstartX? - touch = e.originalEvent.touches[0] - diffX = t.touchstartX - touch.clientX - diffY = t.touchstartY - touch.clientY - absX = Math.abs(diffX) - absY = Math.abs(diffY) - - if t.movestarted isnt true and t.blockmove isnt true and absY > 5 - t.blockmove = true - - if t.blockmove isnt true and (t.movestarted is true or absX > 5) - t.movestarted = true - - if menu.isOpen() - t.left = 260 - diffX - else - t.left = -diffX - - if t.left > 260 - t.left = 260 - if t.left < 0 - t.left = 0 - - t.mainContent.addClass('notransition') - t.mainContent.css('transform', 'translate('+t.left+'px)') - t.wrapper.css('overflow', 'hidden') - - 'touchend': (e, t) -> - if t.movestarted is true - t.mainContent.removeClass('notransition') - t.mainContent.css('transform', ''); - t.wrapper.css('overflow', '') - - if menu.isOpen() - if t.left >= 200 - menu.open() - else - menu.close() - else - if t.left >= 60 - menu.open() - else - menu.close() - - -Template.main.onRendered -> - - # RTL Support - Need config option on the UI - if isRtl localStorage.getItem "userLanguage" - $('html').addClass "rtl" diff --git a/packages/rocketchat-ui/views/main.html b/packages/rocketchat-ui/views/main.html deleted file mode 100644 index 9eab99a5bec..00000000000 --- a/packages/rocketchat-ui/views/main.html +++ /dev/null @@ -1,70 +0,0 @@ -<head> - <title>Rocket.Chat</title> - <meta charset="utf-8" /> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <meta http-equiv="expires" content="-1" /> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="fragment" content="!" /> - <meta name="distribution" content="global" /> - <meta name="rating" content="general" /> - <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> - <meta name="msapplication-TileColor" content="#04436a"> - <meta name="msapplication-TileImage" content="/images/logo/mstile-144x144.png?v=3"> - <meta name="msapplication-config" content="/images/logo/browserconfig.xml?v=3"> - <meta name="theme-color" content="#04436a"> - <link rel="manifest" href="/images/logo/manifest.json?v=3"> - <link rel="icon" sizes="any" type="image/svg+xml" href="/images/logo/icon.svg?v=3"> - <link rel="icon" sizes="256x256" type="image/png" href="/images/logo/favicon-256x256.png?v=3"> - <link rel="icon" sizes="192x192" type="image/png" href="/images/logo/android-chrome-192x192.png?v=3"> - <link rel="icon" sizes="128x128" type="image/png" href="/images/logo/favicon-128x128.png?v=3"> - <link rel="icon" sizes="96x96" type="image/png" href="/images/logo/favicon-96x96.png?v=3"> - <link rel="icon" sizes="64x64" type="image/png" href="/images/logo/favicon-64x64.png?v=3"> - <!-- - <link rel="icon" sizes="48x48" type="image/png" href="/images/logo/favicon-48x48.png?v=3"> - <link rel="icon" sizes="32x32" type="image/png" href="/images/logo/favicon-32x32.png?v=3"> - <link rel="icon" sizes="16x16" type="image/png" href="/images/logo/favicon-16x16.png?v=3"> - --> - <link rel="shortcut icon" sizes="16x16 32x32 48x48" type="image/x-icon" href="/favicon.ico?v=3" /> - <link rel="apple-touch-icon" sizes="57x57" href="/images/logo/apple-touch-icon-57x57.png?v=3"> - <link rel="apple-touch-icon" sizes="60x60" href="/images/logo/apple-touch-icon-60x60.png?v=3"> - <link rel="apple-touch-icon" sizes="72x72" href="/images/logo/apple-touch-icon-72x72.png?v=3"> - <link rel="apple-touch-icon" sizes="76x76" href="/images/logo/apple-touch-icon-76x76.png?v=3"> - <link rel="apple-touch-icon" sizes="114x114" href="/images/logo/apple-touch-icon-114x114.png?v=3"> - <link rel="apple-touch-icon" sizes="120x120" href="/images/logo/apple-touch-icon-120x120.png?v=3"> - <link rel="apple-touch-icon" sizes="144x144" href="/images/logo/apple-touch-icon-144x144.png?v=3"> - <link rel="apple-touch-icon" sizes="152x152" href="/images/logo/apple-touch-icon-152x152.png?v=3"> - <link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png?v=3"> -</head> - -<body> -</body> - -<template name="main"> - {{#if subsReady}} - {{#unless logged}} - {{> loginLayout}} - {{else}} - {{#unless hasUsername}} - {{> username}} - {{else}} - {{> spotlight}} - {{> mobileMessageMenu}} - {{> videoCall overlay=true}} - <div id="user-card-popover"></div> - <div id="rocket-chat" class="menu-nav menu-closed"> - <div class="connection-status"> - {{> status}} - </div> - <div class="flex-tab-bar"> - {{> flexTabBar}} - </div> - <div class="main-content {{flexOpened}} {{flexOpenedRTC1}} {{flexOpenedRTC2}}"> - {{> Template.dynamic template=center}} - </div> - {{> sideNav }} - </div> - {{> audioNotification }} - {{/unless}} - {{/unless}} - {{/if}} -</template> -- GitLab From 877c67b26f12de6bf1dab6aebb48b942c8855b1f Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Mon, 16 Nov 2015 13:07:22 +0100 Subject: [PATCH 0442/1338] updated package names --- .meteor/packages | 16 ++++++++-------- .meteor/versions | 16 ++++++++-------- packages/rocketchat-ui-account/package.js | 2 +- packages/rocketchat-ui-admin/package.js | 2 +- packages/rocketchat-ui-flextab/package.js | 2 +- packages/rocketchat-ui-login/package.js | 2 +- packages/rocketchat-ui-master/package.js | 2 +- packages/rocketchat-ui-message/package.js | 2 +- packages/rocketchat-ui-sidenav/package.js | 2 +- packages/rocketchat-ui/package.js | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 44a8be3e83f..bbabb86e121 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -113,11 +113,11 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter -rocketchat:rocketchat-ui -rocketchat:rocketchat-ui-sidenav -rocketchat:rocketchat-ui-account -rocketchat:rocketchat-ui-admin -rocketchat:rocketchat-ui-login -rocketchat:rocketchat-ui-flextab -rocketchat:rocketchat-ui-message -rocketchat:rocketchat-ui-master +rocketchat:ui +rocketchat:ui-sidenav +rocketchat:ui-account +rocketchat:ui-admin +rocketchat:ui-login +rocketchat:ui-flextab +rocketchat:ui-message +rocketchat:ui-master diff --git a/.meteor/versions b/.meteor/versions index 4d949732d9e..cf344a57481 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -142,14 +142,6 @@ rocketchat:mentions@0.0.1 rocketchat:message-pin@0.0.1 rocketchat:message-star@0.0.1 rocketchat:oembed@0.0.1 -rocketchat:rocketchat-ui@0.1.0 -rocketchat:rocketchat-ui-account@0.1.0 -rocketchat:rocketchat-ui-admin@0.1.0 -rocketchat:rocketchat-ui-flextab@0.1.0 -rocketchat:rocketchat-ui-login@0.1.0 -rocketchat:rocketchat-ui-master@0.1.0 -rocketchat:rocketchat-ui-message@0.1.0 -rocketchat:rocketchat-ui-sidenav@0.1.0 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 rocketchat:slashcommands-leave@0.0.1 @@ -157,6 +149,14 @@ rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 rocketchat:theme@0.0.1 rocketchat:tutum@0.0.1 +rocketchat:ui@0.1.0 +rocketchat:ui-account@0.1.0 +rocketchat:ui-admin@0.1.0 +rocketchat:ui-flextab@0.1.0 +rocketchat:ui-login@0.1.0 +rocketchat:ui-master@0.1.0 +rocketchat:ui-message@0.1.0 +rocketchat:ui-sidenav@0.1.0 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 diff --git a/packages/rocketchat-ui-account/package.js b/packages/rocketchat-ui-account/package.js index 5b2a9d5fe44..77b86dc6268 100644 --- a/packages/rocketchat-ui-account/package.js +++ b/packages/rocketchat-ui-account/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-account', + name: 'rocketchat:ui-account', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui-admin/package.js b/packages/rocketchat-ui-admin/package.js index 0dcf68ef2c6..bebed82fd63 100644 --- a/packages/rocketchat-ui-admin/package.js +++ b/packages/rocketchat-ui-admin/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-admin', + name: 'rocketchat:ui-admin', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui-flextab/package.js b/packages/rocketchat-ui-flextab/package.js index 249d92acecc..e508f10d508 100644 --- a/packages/rocketchat-ui-flextab/package.js +++ b/packages/rocketchat-ui-flextab/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-flextab', + name: 'rocketchat:ui-flextab', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui-login/package.js b/packages/rocketchat-ui-login/package.js index 382048964de..5b2c11042cb 100644 --- a/packages/rocketchat-ui-login/package.js +++ b/packages/rocketchat-ui-login/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-login', + name: 'rocketchat:ui-login', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui-master/package.js b/packages/rocketchat-ui-master/package.js index 15886dd5e64..280af721a3f 100644 --- a/packages/rocketchat-ui-master/package.js +++ b/packages/rocketchat-ui-master/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-master', + name: 'rocketchat:ui-master', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui-message/package.js b/packages/rocketchat-ui-message/package.js index 626bf9f5ced..f06271a56d7 100644 --- a/packages/rocketchat-ui-message/package.js +++ b/packages/rocketchat-ui-message/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-message', + name: 'rocketchat:ui-message', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index 47e557c5394..8c51ef517ef 100644 --- a/packages/rocketchat-ui-sidenav/package.js +++ b/packages/rocketchat-ui-sidenav/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui-sidenav', + name: 'rocketchat:ui-sidenav', version: '0.1.0', // Brief, one-line summary of the package. summary: '', diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 730b0d3e9de..6c7570eabf1 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -1,5 +1,5 @@ Package.describe({ - name: 'rocketchat:rocketchat-ui', + name: 'rocketchat:ui', version: '0.1.0', // Brief, one-line summary of the package. summary: '', -- GitLab From e39134ae973b6f860a98816ed5dbe102e92ad9fb Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Mon, 16 Nov 2015 14:50:33 +0100 Subject: [PATCH 0443/1338] Fixed chatMessage bug --- .../message/messageBox.coffee | 16 ++++++++-------- packages/rocketchat-ui/lib/chatMessages.coffee | 3 +-- packages/rocketchat-ui/views/app/room.coffee | 12 +++++++----- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/rocketchat-ui-message/message/messageBox.coffee b/packages/rocketchat-ui-message/message/messageBox.coffee index 53f2e00f7f3..815aca534b8 100644 --- a/packages/rocketchat-ui-message/message/messageBox.coffee +++ b/packages/rocketchat-ui-message/message/messageBox.coffee @@ -61,7 +61,7 @@ Template.messageBox.events KonchatNotification.removeRoomNotification @_id 'keyup .input-message': (event) -> - Template.instance().chatMessages.keyup(@_id, event, Template.instance()) + chatMessages[Session.get('openedRoom')].keyup(@_id, event, Template.instance()) 'paste .input-message': (e) -> if not e.originalEvent.clipboardData? @@ -80,22 +80,21 @@ Template.messageBox.events fileUpload files 'keydown .input-message': (event) -> - Template.instance().chatMessages.keydown(@_id, event, Template.instance()) + chatMessages[Session.get('openedRoom')].keydown(@_id, event, Template.instance()) 'click .message-form .icon-paper-plane': (event) -> input = $(event.currentTarget).siblings("textarea") - Template.instance().chatMessages.send(this._id, input.get(0)) + chatMessages[Session.get('openedRoom')].send(this._id, input.get(0)) event.preventDefault() event.stopPropagation() input.focus() input.get(0).updateAutogrow() "click .editing-commands-cancel > a": (e) -> - Template.instance().chatMessages.clearEditing() + chatMessages[Session.get('openedRoom')].clearEditing() "click .editing-commands-save > a": (e) -> - chatMessages = Template.instance().chatMessages - chatMessages.send(@_id, chatMessages.input) + chatMessages[Session.get('openedRoom')].send(@_id, chatMessages.input) @@ -131,5 +130,6 @@ Template.messageBox.events t.$('.mic').removeClass('hidden') Template.messageBox.onRendered -> - this.chatMessages = new ChatMessages - this.chatMessages.init(this.firstNode) \ No newline at end of file + # unless window.chatMessages[Session.get('openedRoom')] + # window.chatMessages[Session.get('openedRoom')] = new ChatMessages + # this.chatMessages.init(this.firstNode) \ No newline at end of file diff --git a/packages/rocketchat-ui/lib/chatMessages.coffee b/packages/rocketchat-ui/lib/chatMessages.coffee index e2e881ede3f..fa01c9bd018 100644 --- a/packages/rocketchat-ui/lib/chatMessages.coffee +++ b/packages/rocketchat-ui/lib/chatMessages.coffee @@ -1,7 +1,6 @@ class @ChatMessages init: (node) -> this.editing = {} - this.messageMaxSize = RocketChat.settings.get('Message_MaxAllowedSize') this.wrapper = $(node).find(".wrapper") this.input = $(node).find(".input-message").get(0) @@ -41,7 +40,7 @@ class @ChatMessages edit: (element, index) -> id = element.getAttribute("id") - message = ChatMessage.findOne { _id: id } + message = ChatMessage.findOne { _id: id } hasPermission = RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid) editAllowed = RocketChat.settings.get 'Message_AllowEditing' editOwn = message?.u?._id is Meteor.userId() diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 3eac444e9e3..2aa4d409355 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -368,11 +368,10 @@ Template.room.events 'click .pin-message': (event) -> message = @_arguments[1] instance = Template.instance() - if message.pinned - instance.chatMessages.unpinMsg(message) + chatMessages[Session.get('openedRoom')].unpinMsg(message) else - instance.chatMessages.pinMsg(message) + chatMessages[Session.get('openedRoom')].pinMsg(message) 'dragenter .dropzone': (e) -> e.currentTarget.classList.add 'over' @@ -444,8 +443,11 @@ Template.room.onDestroyed -> Template.room.onRendered -> - this.chatMessages = new ChatMessages - this.chatMessages.init(this.firstNode) + unless window.chatMessages + window.chatMessages = {} + unless window.chatMessages[Session.get('openedRoom')] + window.chatMessages[Session.get('openedRoom')] = new ChatMessages + chatMessages[Session.get('openedRoom')].init(this.firstNode) # ScrollListener.init() wrapper = this.find('.wrapper') -- GitLab From 525207cf93f0fe06ae898f4d01b3eb4b0ca4da4c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 16 Nov 2015 12:17:10 -0200 Subject: [PATCH 0444/1338] update server to support mobile clients by default --- .meteor/packages | 18 +++++++++--------- .meteor/platforms | 1 + .meteor/versions | 2 +- .travis.yml | 8 +++++--- build-ios.sh | 1 - build-old.sh | 1 - 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index bbabb86e121..164b3e945ae 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -38,6 +38,7 @@ rocketchat:lib rocketchat:authorization rocketchat:autolinker +rocketchat:channel-settings rocketchat:colors rocketchat:custom-oauth rocketchat:emojione @@ -62,8 +63,15 @@ rocketchat:spotify rocketchat:statistics rocketchat:theme rocketchat:tutum +rocketchat:ui +rocketchat:ui-account +rocketchat:ui-admin +rocketchat:ui-flextab +rocketchat:ui-login +rocketchat:ui-master +rocketchat:ui-message +rocketchat:ui-sidenav rocketchat:webrtc -rocketchat:channel-settings rocketchat:wordpress #rocketchat:chatops #rocketchat:hubot @@ -113,11 +121,3 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter -rocketchat:ui -rocketchat:ui-sidenav -rocketchat:ui-account -rocketchat:ui-admin -rocketchat:ui-login -rocketchat:ui-flextab -rocketchat:ui-message -rocketchat:ui-master diff --git a/.meteor/platforms b/.meteor/platforms index 8a3a35f9f62..81ae7012de9 100644 --- a/.meteor/platforms +++ b/.meteor/platforms @@ -1,2 +1,3 @@ browser +ios server diff --git a/.meteor/versions b/.meteor/versions index cf344a57481..4496c6366b2 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,7 @@ cfs:http-methods@0.0.30 check@1.1.0 chrismbeckett:toastr@2.1.2_1 coffeescript@1.0.11 -cosmos:browserify@0.8.3 +cosmos:browserify@0.9.0 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 diff --git a/.travis.yml b/.travis.yml index d85821c591a..6b7015ad45e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,10 @@ sudo: required language: node_js branches: only: + - master - develop node_js: -- '0.10' +- '0.12' addons: apt: sources: @@ -33,7 +34,6 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- meteor add-platform ios - meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter - ./node_modules/velocity-cli/bin/velocity test-packages --ci - ./node_modules/velocity-cli/bin/velocity test-app --ci @@ -51,4 +51,6 @@ deploy: skip_cleanup: true local_dir: ../build on: - branch: develop + branch: + - master + - develop diff --git a/build-ios.sh b/build-ios.sh index 8ab71526426..92c9444debb 100755 --- a/build-ios.sh +++ b/build-ios.sh @@ -1,6 +1,5 @@ #!/bin/bash -meteor add-platform ios rm -rf .meteor/local/cordova-build rm -rf ../Rocket.Chat-build meteor build ../Rocket.Chat-build --server https://demo.rocket.chat diff --git a/build-old.sh b/build-old.sh index 11571d29951..0017dc40e43 100755 --- a/build-old.sh +++ b/build-old.sh @@ -1,7 +1,6 @@ #!/bin/bash source ./build-info.sh export METEOR_SETTINGS=$(cat settings.json) -meteor add-platform ios meteor add rocketchat:livechat rocketchat:hubot meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat cd /var/www/rocket.chat/bundle/programs/server -- GitLab From 3dcdcc6f489a5af98cc4a8e5b21ba34bb331d470 Mon Sep 17 00:00:00 2001 From: Rafael Caferati <rafael@caferati.me> Date: Mon, 16 Nov 2015 15:21:29 +0100 Subject: [PATCH 0445/1338] fixed cog editing bug --- .../rocketchat-lib/client/MessageAction.coffee | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee index d77cf8fc80d..3aec40bcb3e 100644 --- a/packages/rocketchat-lib/client/MessageAction.coffee +++ b/packages/rocketchat-lib/client/MessageAction.coffee @@ -1,6 +1,6 @@ RocketChat.MessageAction = new class buttons = new ReactiveVar {} - + ### config expects the following keys (only id is mandatory): id (mandatory) @@ -9,7 +9,7 @@ RocketChat.MessageAction = new class action: function(event, instance) validation: function(message) order: integer - ### + ### addButton = (config) -> unless config?.id throw new Meteor.Error "MessageAction-addButton-error", "Button id was not informed." @@ -29,18 +29,18 @@ RocketChat.MessageAction = new class Tracker.nonreactive -> btns = buttons.get() if btns[id] - btns[id] = _.extend btns[id], config + btns[id] = _.extend btns[id], config buttons.set btns getButtons = (message) -> allButtons = _.toArray buttons.get() if message - allowedButtons = _.compact _.map allButtons, (button) -> + allowedButtons = _.compact _.map allButtons, (button) -> if not button.validation? or button.validation(message) return button else allowedButtons = allButtons - + return _.sortBy allowedButtons, 'order' resetButtons = -> @@ -59,7 +59,7 @@ Meteor.startup -> i18nLabel: 'Edit' action: (event, instance) -> message = $(event.currentTarget).closest('.message')[0] - instance.chatMessages.edit(message) + chatMessages[Session.get('openedRoom')].edit(message) $("\##{message.id} .message-dropdown").hide() input = instance.find('.input-message') Meteor.setTimeout -> @@ -108,7 +108,7 @@ Meteor.startup -> timer: 1000 showConfirmButton: false - instance.chatMessages.deleteMsg(message) + chatMessages[Session.get('openedRoom')].deleteMsg(message) validation: (message) -> return RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid ) or RocketChat.settings.get('Message_AllowDeleting') and message.u?._id is Meteor.userId() order: 2 \ No newline at end of file -- GitLab From 1a514fb4d3357c2f1286d4f680e691de699f838d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 16 Nov 2015 12:57:19 -0200 Subject: [PATCH 0446/1338] Channel settings: change name, topic, type --- client/methods/saveRoomName.coffee | 26 ---------- client/views/app/room.coffee | 22 ++------ client/views/app/room.html | 7 +-- i18n/en.i18n.json | 1 + .../client/views/channelSettings.coffee | 50 ++++++++++++++++--- .../client/views/channelSettings.html | 14 ++++++ .../i18n/en.i18n.json | 2 + .../rocketchat-channel-settings/package.js | 2 + .../server/functions/changeRoomTopic.coffee | 6 +++ .../server/functions/changeRoomType.coffee | 39 +-------------- .../server}/methods/saveRoomName.coffee | 4 +- .../server/methods/saveRoomSettings.coffee | 14 ++++-- .../rocketchat-lib/server/models/Rooms.coffee | 16 ++++-- .../assets/stylesheets/base.less | 6 ++- server/startup/roomPublishes.coffee | 2 + 15 files changed, 108 insertions(+), 103 deletions(-) delete mode 100644 client/methods/saveRoomName.coffee create mode 100644 packages/rocketchat-channel-settings/server/functions/changeRoomTopic.coffee rename {server => packages/rocketchat-channel-settings/server}/methods/saveRoomName.coffee (82%) diff --git a/client/methods/saveRoomName.coffee b/client/methods/saveRoomName.coffee deleted file mode 100644 index 2072d68fa0b..00000000000 --- a/client/methods/saveRoomName.coffee +++ /dev/null @@ -1,26 +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') - - 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/views/app/room.coffee b/client/views/app/room.coffee index 80dd1c74fb9..4c128db8ece 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -70,6 +70,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 @@ -114,26 +119,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() diff --git a/client/views/app/room.html b/client/views/app/room.html index 3c2380b3929..3399c50d213 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -13,11 +13,8 @@ <a href="#favorite" class="toggle-favorite"><i class="{{favorite}}"></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"> diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3c39e0ccab8..69cd384193e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -162,6 +162,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.", "invisible" : "invisible", "Invisible" : "Invisible", "Invitation_HTML" : "Invitation HTML", diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 4f9f5d344c5..26abf2d703f 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -3,6 +3,10 @@ Template.channelSettings.helpers return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> return ChatRoom.findOne(@rid)?.t + roomName: -> + return ChatRoom.findOne(@rid)?.name + roomTopic: -> + return ChatRoom.findOne(@rid)?.topic Template.channelSettings.events 'click .save': (e, t) -> @@ -10,14 +14,44 @@ Template.channelSettings.events settings = roomType: t.$('input[name=roomType]:checked').val() + roomName: t.$('input[name=roomName]').val() + roomTopic: t.$('input[name=roomTopic]').val() - Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> - return toastr.error err.reason if err - toastr.success TAPi18n.__ 'Settings_updated' + if t.validate() + Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> + if err + if err.error in [ 'duplicate-name', 'name-invalid' ] + return toastr.error TAPi18n.__(err.reason, err.details.channelName) + 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.__ 'Settings_updated' - # switch room.t - # when 'c' - # FlowRouter.go 'channel', name: name - # when 'p' - # FlowRouter.go 'group', name: name +Template.channelSettings.onCreated -> + @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 room.u._id isnt Meteor.userId() 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 + + @validate = => + return @validateRoomType() and @validateRoomName() and @validateRoomTopic() diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index c72ecae4ad6..13b76fb9cb7 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -7,6 +7,20 @@ <div class="channel-settings scrollable"> <form> <fieldset> + {{#if notDirect}} + <div class="input-line double-col"> + <label>{{_ "Room_Name"}}</label> + <div> + <input type="text" name="roomName" value="{{roomName}}" /> + </div> + </div> + {{/if}} + <div class="input-line double-col"> + <label>{{_ "Room_Topic"}}</label> + <div> + <input type="text" name="roomTopic" value="{{roomTopic}}" /> + </div> + </div> {{#if notDirect}} <div class="input-line double-col"> <label>{{_ "Room_Type"}}</label> diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index ba1d6c016df..3100cf532a8 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,6 +1,8 @@ { "Channel": "Channel", "Private_Group": "Private Group", + "Room_Name": "Room Name", + "Room_Topic": "Room Topic", "Room_Type": "Room Type", "Room_Settings": "Room Settings", "room_changed_privacy": "Room type changed to: <em>__room_type__</em> by <em>__user_by__</em>", diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 06b8f3fe128..eaffbdf1f56 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -26,6 +26,8 @@ Package.onUse(function(api) { api.addFiles([ 'server/functions/changeRoomType.coffee', + 'server/functions/changeRoomTopic.coffee', + 'server/methods/saveRoomName.coffee', 'server/methods/saveRoomSettings.coffee', 'server/models/Messages.coffee' ], 'server'); diff --git a/packages/rocketchat-channel-settings/server/functions/changeRoomTopic.coffee b/packages/rocketchat-channel-settings/server/functions/changeRoomTopic.coffee new file mode 100644 index 00000000000..9fd7c3f3ea6 --- /dev/null +++ b/packages/rocketchat-channel-settings/server/functions/changeRoomTopic.coffee @@ -0,0 +1,6 @@ +RocketChat.changeRoomTopic = (rid, roomTopic) -> + unless Match.test rid, String + throw new Meteor.Error 'invalid-rid' + + console.log '[function] RocketChat.changeRoomTopic'.green, rid, roomTopic + return RocketChat.models.Rooms.setTopicById(rid, roomTopic) diff --git a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee b/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee index e9c89567302..6885b59b03c 100644 --- a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee +++ b/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee @@ -5,43 +5,6 @@ RocketChat.changeRoomType = (rid, roomType) -> throw new Meteor.Error 'invalid-rid' if roomType not in ['c', 'p'] - throw new Meteor.Error 'invalid-room-type' + 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) - - - # 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/server/methods/saveRoomName.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee similarity index 82% rename from server/methods/saveRoomName.coffee rename to packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee index 7dba0b2d710..2dddd534423 100644 --- a/server/methods/saveRoomName.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee @@ -13,7 +13,7 @@ Meteor.methods throw new Meteor.Error 403, 'Not allowed' if not /^[0-9a-z-_]+$/.test name - throw new Meteor.Error 'name-invalid' + throw new Meteor.Error 'name-invalid', 'Invalid_room_name', { channelName: name } name = _.slugify name @@ -22,7 +22,7 @@ Meteor.methods # avoid duplicate names if RocketChat.models.Rooms.findOneByName name - throw new Meteor.Error 'duplicate-name' + throw new Meteor.Error 'duplicate-name', 'Duplicate_channel_name', { channelName: name } RocketChat.models.Rooms.setNameById rid, name diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee index 6375bf5f289..340a0feeabc 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -3,10 +3,10 @@ Meteor.methods console.log '[method] saveRoomSettings'.green, rid, settings 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' + unless Match.test settings, Match.ObjectIncluding { roomName: String, roomTopic: String, roomType: String } + 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' @@ -23,4 +23,12 @@ Meteor.methods RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_privacy', rid, message, Meteor.user() + if settings.roomName isnt room.name + name = Meteor.call 'saveRoomName', rid, settings.roomName + + if settings.roomTopic isnt room.topic + RocketChat.changeRoomTopic(rid, settings.roomTopic) + message = settings.roomTopic + RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', rid, message, Meteor.user() + return true diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index dddc8f8c021..0ccfb2519b9 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -291,15 +291,25 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @update query, update setTypeById: (_id, type) -> - query = + query = _id: _id - update = - $set: + update = + $set: t: type return @update query, update + setTopicById: (_id, topic) -> + query = + _id: _id + + update = + $set: + topic: topic + + return @update query, update + # INSERT createWithTypeNameUserAndUsernames: (type, name, user, usernames, extraData) -> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c8a913a1aa3..c7610498524 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1989,7 +1989,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; diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index ae5cdd0225f..d7561a38b16 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -7,6 +7,7 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + topic: 1 return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options RocketChat.roomTypes.addPublish 'p', (identifier) -> @@ -17,6 +18,7 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + topic: 1 user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options -- GitLab From 20c4ced0744afebc9002cba14b4f8d9a89325728 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 16 Nov 2015 13:23:45 -0200 Subject: [PATCH 0447/1338] Adding Bradley Hilton as the real name for Graywolf336 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 90d8b845908..2b43efc6772 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ It is a great solution for communities and companies wanting to privately host t > Why Slack when you can Rocket.chat? ##### [liminality.xyz](http://liminality.xyz/self-hosting/) -> SELF-HOSTED ALTERNATIVES TO POPULAR CLOUD SERVICES +> Self-hosted alternatives to popular cloud services ## Features @@ -231,19 +231,19 @@ docker run -it -p 3000:3000 -v "$(pwd)":/app danieldent/meteor ## Credits Thanks to +[Aaron Ogle](https://github.com/geekgonecrazy), +[Bradley Hilton](https://github.com/Graywolf336) [Diego Sampaio](https://github.com/sampaiodiego), [Gabriel Engel](https://github.com/engelgabriel), [Marcelo Schmidt](https://github.com/marceloschmidt), [Rafael Caferati](https://github.com/rcaferati), [Rodrigo Nascimento](https://github.com/rodrigok), [Sing Li](https://github.com/Sing-Li), -[Aaron Ogle](https://github.com/geekgonecrazy), -[Graywolf336](https://github.com/Graywolf336) Emoji provided free by [Emoji One](http://emojione.com) -Performance monitoring provided by [Kadira](https://kadira.io/) +Performance monitoring provided by [Kadira](https://kadira.io) ### Contributions -- GitLab From 045df9a49753a41aa995498df13b71474745ec9c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 16 Nov 2015 13:35:22 -0200 Subject: [PATCH 0448/1338] fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b43efc6772..a07134a1840 100644 --- a/README.md +++ b/README.md @@ -232,14 +232,14 @@ docker run -it -p 3000:3000 -v "$(pwd)":/app danieldent/meteor Thanks to [Aaron Ogle](https://github.com/geekgonecrazy), -[Bradley Hilton](https://github.com/Graywolf336) +[Bradley Hilton](https://github.com/Graywolf336), [Diego Sampaio](https://github.com/sampaiodiego), [Gabriel Engel](https://github.com/engelgabriel), [Marcelo Schmidt](https://github.com/marceloschmidt), [Rafael Caferati](https://github.com/rcaferati), [Rodrigo Nascimento](https://github.com/rodrigok), [Sing Li](https://github.com/Sing-Li), - +and many others. Emoji provided free by [Emoji One](http://emojione.com) -- GitLab From 2ddcf2c50ca53646868a3a0c897822366d748cd9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 16 Nov 2015 15:23:22 -0200 Subject: [PATCH 0449/1338] Redesign --- client/lib/trackRoomNameChanged.coffee | 12 ----- client/views/app/room.coffee | 45 ------------------- .../client/startup/tabBar.coffee | 2 +- .../client/startup/trackSettingsChange.coffee | 12 +++++ .../client/stylesheets/channel-settings.less | 12 +++++ .../client/views/channelSettings.coffee | 6 +++ .../client/views/channelSettings.html | 29 +++++++----- .../i18n/en.i18n.json | 6 +-- .../rocketchat-channel-settings/package.js | 6 +-- .../server/functions/saveRoomName.coffee | 29 ++++++++++++ ...eRoomTopic.coffee => saveRoomTopic.coffee} | 4 +- ...ngeRoomType.coffee => saveRoomType.coffee} | 4 +- .../server/methods/saveRoomName.coffee | 33 -------------- .../server/methods/saveRoomSettings.coffee | 14 +++--- .../server/models/Messages.coffee | 3 ++ .../server/models/Messages.coffee | 4 -- 16 files changed, 99 insertions(+), 122 deletions(-) delete mode 100644 client/lib/trackRoomNameChanged.coffee create mode 100644 packages/rocketchat-channel-settings/server/functions/saveRoomName.coffee rename packages/rocketchat-channel-settings/server/functions/{changeRoomTopic.coffee => saveRoomTopic.coffee} (51%) rename packages/rocketchat-channel-settings/server/functions/{changeRoomType.coffee => saveRoomType.coffee} (72%) delete mode 100644 packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee diff --git a/client/lib/trackRoomNameChanged.coffee b/client/lib/trackRoomNameChanged.coffee deleted file mode 100644 index 8b3a0769feb..00000000000 --- a/client/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/client/views/app/room.coffee b/client/views/app/room.coffee index 4c128db8ece..f13aa98a970 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -329,18 +329,6 @@ 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')) @@ -613,36 +601,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-channel-settings/client/startup/tabBar.coffee b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee index 17d1680317e..487be2c65a7 100644 --- a/packages/rocketchat-channel-settings/client/startup/tabBar.coffee +++ b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee @@ -6,7 +6,7 @@ Meteor.startup -> RocketChat.TabBar.addButton id: 'channel-settings' i18nTitle: 'Channel_Settings' - icon: 'octicon octicon-gear' + icon: 'octicon octicon-info' template: 'channelSettings' order: 0 , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-channel-settings' diff --git a/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee b/packages/rocketchat-channel-settings/client/startup/trackSettingsChange.coffee index b3618dd7232..4594215267d 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 0227c11170d..05f745e0abc 100644 --- a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less +++ b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less @@ -15,3 +15,15 @@ } } } + +.input-line.double-col { + div { + line-height: 15px; + padding: 10px 20px 10px 0; + i.octicon { + font-size: 13px; + opacity: 0.4; + vertical-align: top; + } + } +} diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 26abf2d703f..a56bc8f54cb 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -1,8 +1,14 @@ Template.channelSettings.helpers + canEdit: -> + return true + editing: (field) -> + return false notDirect: -> return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> return ChatRoom.findOne(@rid)?.t + roomTypeDescription: -> + return if ChatRoom.findOne(@rid)?.t is 'c' then t('Channel') else t('Private_Group') roomName: -> return ChatRoom.findOne(@rid)?.name roomTopic: -> diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index 13b76fb9cb7..36a5cc72b4b 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -9,31 +9,40 @@ <fieldset> {{#if notDirect}} <div class="input-line double-col"> - <label>{{_ "Room_Name"}}</label> + <label>{{_ "Name"}}</label> <div> - <input type="text" name="roomName" value="{{roomName}}" /> + {{#if editing 'roomName'}} + <input type="text" name="roomName" value="{{roomName}}" /> + {{else}} + {{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil"></i>{{/if}} + {{/if}} </div> </div> {{/if}} <div class="input-line double-col"> - <label>{{_ "Room_Topic"}}</label> + <label>{{_ "Topic"}}</label> <div> - <input type="text" name="roomTopic" value="{{roomTopic}}" /> + {{#if editing 'roomTopic'}} + <input type="text" name="roomTopic" value="{{roomTopic}}" /> + {{else}} + {{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil"></i>{{/if}} + {{/if}} </div> </div> {{#if notDirect}} <div class="input-line double-col"> - <label>{{_ "Room_Type"}}</label> + <label>{{_ "Type"}}</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 'roomType'}} + <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> + {{else}} + {{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil"></i>{{/if}} + {{/if}} </div> </div> {{/if}} </fieldset> - <div class="submit"> - <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> - </div> </form> </div> </template> diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index 3100cf532a8..1191953e3ba 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,9 +1,9 @@ { "Channel": "Channel", "Private_Group": "Private Group", - "Room_Name": "Room Name", - "Room_Topic": "Room Topic", - "Room_Type": "Room Type", + "Name": "Name", + "Topic": "Topic", + "Type": "Type", "Room_Settings": "Room Settings", "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>" diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index eaffbdf1f56..127e1226940 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -25,9 +25,9 @@ Package.onUse(function(api) { ], 'client'); api.addFiles([ - 'server/functions/changeRoomType.coffee', - 'server/functions/changeRoomTopic.coffee', - 'server/methods/saveRoomName.coffee', + 'server/functions/saveRoomType.coffee', + 'server/functions/saveRoomTopic.coffee', + 'server/functions/saveRoomName.coffee', 'server/methods/saveRoomSettings.coffee', 'server/models/Messages.coffee' ], 'server'); 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 00000000000..9833b88764b --- /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/changeRoomTopic.coffee b/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee similarity index 51% rename from packages/rocketchat-channel-settings/server/functions/changeRoomTopic.coffee rename to packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee index 9fd7c3f3ea6..6c08f38edfe 100644 --- a/packages/rocketchat-channel-settings/server/functions/changeRoomTopic.coffee +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee @@ -1,6 +1,6 @@ -RocketChat.changeRoomTopic = (rid, roomTopic) -> +RocketChat.saveRoomTopic = (rid, roomTopic) -> unless Match.test rid, String throw new Meteor.Error 'invalid-rid' - console.log '[function] RocketChat.changeRoomTopic'.green, rid, roomTopic + console.log '[function] RocketChat.saveRoomTopic'.green, rid, roomTopic return RocketChat.models.Rooms.setTopicById(rid, roomTopic) diff --git a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee b/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee similarity index 72% rename from packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee rename to packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee index 6885b59b03c..5cd6d4c5259 100644 --- a/packages/rocketchat-channel-settings/server/functions/changeRoomType.coffee +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee @@ -1,5 +1,5 @@ -RocketChat.changeRoomType = (rid, roomType) -> - console.log '[function] RocketChat.changeRoomType'.green, rid, roomType +RocketChat.saveRoomType = (rid, roomType) -> + console.log '[function] RocketChat.saveRoomType'.green, rid, roomType unless Match.test rid, String throw new Meteor.Error 'invalid-rid' diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee deleted file mode 100644 index 2dddd534423..00000000000 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomName.coffee +++ /dev/null @@ -1,33 +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' - - 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 - - RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser rid, name, Meteor.user() - - return name diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee index 340a0feeabc..9cc15ad6fb4 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -13,8 +13,12 @@ Meteor.methods room = RocketChat.models.Rooms.findOneById rid if room? + if settings.roomName isnt room.name + name = RocketChat.saveRoomName rid, settings.roomName + RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser rid, name, Meteor.user() + if settings.roomType isnt room.t - RocketChat.changeRoomType(rid, settings.roomType) + RocketChat.saveRoomType(rid, settings.roomType) if settings.roomType is 'c' message = TAPi18n.__('Channel') @@ -23,12 +27,8 @@ Meteor.methods RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_privacy', rid, message, Meteor.user() - if settings.roomName isnt room.name - name = Meteor.call 'saveRoomName', rid, settings.roomName - if settings.roomTopic isnt room.topic - RocketChat.changeRoomTopic(rid, settings.roomTopic) - message = settings.roomTopic - RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', rid, message, Meteor.user() + RocketChat.saveRoomTopic(rid, settings.roomTopic) + RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', rid, settings.roomTopic, 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 0a8e900e45d..9a72fcd32bb 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-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 7c7d85c224a..523309c14b8 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -258,10 +258,6 @@ 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 - - # REMOVE removeById: (_id) -> query = -- GitLab From 1530ee02d289f13f9bf48bea9b73668389b0eac9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 16 Nov 2015 15:41:46 -0200 Subject: [PATCH 0450/1338] Update icon.ai --- private/images/icon.ai | 1082 +++++++++++++++++++++------------------- 1 file changed, 558 insertions(+), 524 deletions(-) diff --git a/private/images/icon.ai b/private/images/icon.ai index b2a399f35d9..9279c915b9e 100644 --- a/private/images/icon.ai +++ b/private/images/icon.ai @@ -1,5 +1,5 @@ %PDF-1.5 %âãÏÓ -1 0 obj <</Metadata 2 0 R/OCProperties<</D<</OFF[5 0 R 6 0 R 7 0 R]/ON[8 0 R 33 0 R 51 0 R 69 0 R 70 0 R 90 0 R 91 0 R 111 0 R 112 0 R 135 0 R 136 0 R 159 0 R 160 0 R 182 0 R 183 0 R]/Order 184 0 R/RBGroups[]>>/OCGs[5 0 R 6 0 R 7 0 R 8 0 R 33 0 R 51 0 R 69 0 R 70 0 R 90 0 R 91 0 R 111 0 R 112 0 R 135 0 R 136 0 R 159 0 R 160 0 R 182 0 R 183 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 47054/Subtype/XML/Type/Metadata>>stream +1 0 obj <</Metadata 2 0 R/OCProperties<</D<</OFF[5 0 R 6 0 R 7 0 R]/ON[8 0 R 33 0 R 51 0 R 69 0 R 70 0 R 90 0 R 91 0 R 111 0 R 112 0 R 135 0 R 136 0 R 159 0 R 160 0 R 182 0 R 183 0 R 204 0 R 205 0 R 226 0 R 227 0 R 248 0 R 249 0 R]/Order 250 0 R/RBGroups[]>>/OCGs[5 0 R 6 0 R 7 0 R 8 0 R 33 0 R 51 0 R 69 0 R 70 0 R 90 0 R 91 0 R 111 0 R 112 0 R 135 0 R 136 0 R 159 0 R 160 0 R 182 0 R 183 0 R 204 0 R 205 0 R 226 0 R 227 0 R 248 0 R 249 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 47430/Subtype/XML/Type/Metadata>>stream <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> @@ -17,15 +17,15 @@ xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/"> <xmp:CreatorTool>Adobe Illustrator CS6 (Macintosh)</xmp:CreatorTool> <xmp:CreateDate>2015-07-14T15:28:51-03:00</xmp:CreateDate> - <xmp:ModifyDate>2015-08-11T22:47:20-03:00</xmp:ModifyDate> - <xmp:MetadataDate>2015-08-11T22:47:20-03:00</xmp:MetadataDate> + <xmp:ModifyDate>2015-11-15T14:09:12-02:00</xmp:ModifyDate> + <xmp:MetadataDate>2015-11-15T14:09:12-02:00</xmp:MetadataDate> <xmp:Thumbnails> <rdf:Alt> <rdf:li rdf:parseType="Resource"> <xmpGImg:width>256</xmpGImg:width> <xmpGImg:height>256</xmpGImg:height> <xmpGImg:format>JPEG</xmpGImg:format> - <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A5ZXOgdK6uKurirq4q6uK
urirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4
q6uKurirq4q6uKtVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXV
xV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVargV1cVdXFXVxV1cVdXFXVxV1cVdXFX
VxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cV
W1wJdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdX
FXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFWq4pdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVd
XFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFVtcCurirq4q6uK
uriq5I5H+wpb5An9WQnkjH6iA3YtPkyfRGUvcCVZbC8PSI/TQfrzHOvwj+IOwh2FrJcscvsH3rjp
t6P91/iv9cgO0sH877D+ptPs7rR/k/8AZR/Wsazul6xN9Ar+rLY6zFLlIONl7I1UOeOXyv7lE7Gh
2PhmSDbr5RINFquLF1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVx
V1cVdXFXVxVquKXVxV1cVXRhGdQ7cVJ3alaZDJIiJIFltwQhKYE5cMTzNXXwTu306zQBgvqE7hm3
/szmM/aGaRq+HyG37X0zQ9gaPEBIDxPOW/2ckWAAKAUA7DMAknm7yMQBQ2DsCXYq7FVskUUgo6Bh
7iuWY8sofSSGjPpcWYVkiJe8IGfR4WqYiUPgdx/XNng7XnHaY4h9rzWt9k8M98R4D3cx+v70suLa
aBqSLTwbsfpzd4NTDKLiXi9d2bm0sqyRrz6H4qVcyHBdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXF
XVxV1cVdXFXVxV1cVdXFXVxV1cVdXFVtcCurirq4q6uKo/TtRMLCOQ1iPQ/y/wBmavtDQDIOKP1/
e9N2D24dPLw8h/dH/Y/s7/mnYIIqOmc0Q+kAgiw7FXYq7FXYq7FWnRHUq4DKeoOShMxNg0WvLhhk
iYzAlE9Ck99pjRAyQ1aPuvcf2Z0Oi7SE/TPaX3vAds+zksF5MPqx9R1j+sfd9qXgEmgFT4DNqSBz
eWjEyNAWqLbXLdInP+xOVHU4xzlH5hyodnaiXLHM/wCaVwsrw/7pb7sgdbh/nBvHY+rP+Tn8nGyv
B/ulvuxGtw/zgg9j6sf5OfyWtbXK9YnHzU5ManGeUo/MNM+z9RHnjmP80qZBBoRQ+By0EHk4somJ
oimq4WLq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirVcUurirq4q6uKuriqb6Pe8h9Wc7j+
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
VU9iRX7uuWQwzn9IJcbPrcOH65CPx/QlF55pgQFbVDI387bL93U/hmww9mSP1mnnNZ7U447YY8R7
zsPlzP2JDd31zdyc53LHsOgHyGbbFhjjFRDyGr12XUS4skr+4e4KFctcR1cVdXFXVxV1cVdXFXVx
V1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVW1xS6uKurirq4q6uKrklkjNUYofFSQfw
yMog82cMkoG4kg+SJTV9TUUFzJ9LE/ryk6XEf4Q5sO1tVHlkl87+9edc1Uje4b6AB+oZEaLF/NbT
23qz/lD9n6lGTUb+TZ7iRh4cjT7ssjgxjlEONk7Q1E/qySPxKHqcucN1cVdXFXVxV1cVdXFXVxV1
cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVawK7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWq4Eurirq4q6uKurirq4
q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKur
irq4q6uKurirVcVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVd
XFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFXVxV1cVdXFVtcUurirq4q6uKurirq4q6uKurirq4q6uK
urirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirq4q6uKurirWB
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq//2Q==</xmpGImg:image> + <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
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</xmpGImg:image> </rdf:li> </rdf:Alt> </xmp:Thumbnails> @@ -37,7 +37,7 @@ <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass> <xmpMM:OriginalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</xmpMM:OriginalDocumentID> <xmpMM:DocumentID>xmp.did:05801174072068118083E6B8DFAD3211</xmpMM:DocumentID> - <xmpMM:InstanceID>uuid:c13f4026-f884-c44f-9f69-7c6a0e5ade17</xmpMM:InstanceID> + <xmpMM:InstanceID>uuid:9fbc347a-8c8c-a044-b8b1-cab794b5c2dd</xmpMM:InstanceID> <xmpMM:DerivedFrom rdf:parseType="Resource"> <stRef:instanceID>uuid:dd072d7b-0748-3146-9743-f08357fdf253</stRef:instanceID> <stRef:documentID>xmp.did:03801174072068118083E6B8DFAD3211</stRef:documentID> @@ -600,11 +600,10 @@ -<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 2/Kids[10 0 R 162 0 R]/Type/Pages>> endobj 10 0 obj <</ArtBox[0.0 0.0 512.0 512.0]/BleedBox[0.0 0.0 512.0 512.0]/Contents 185 0 R/LastModified(D:20150811224719-03'00')/MediaBox[0.0 0.0 512.0 512.0]/Parent 3 0 R/PieceInfo<</Illustrator 186 0 R>>/Resources<</ColorSpace<</CS0 187 0 R>>/ExtGState<</GS0 188 0 R>>/Properties<</MC0 182 0 R/MC1 183 0 R>>/Shading<</Sh0 189 0 R>>>>/Thumb 143 0 R/TrimBox[0.0 0.0 512.0 512.0]/Type/Page>> endobj 162 0 obj <</ArtBox[0.0 0.0 640.0 640.0]/BleedBox[0.0 0.0 640.0 640.0]/Contents 190 0 R/LastModified(D:20150811224719-03'00')/MediaBox[0.0 0.0 640.0 640.0]/Parent 3 0 R/PieceInfo<</Illustrator 186 0 R>>/Resources<</ColorSpace<</CS0 187 0 R>>/ExtGState<</GS0 188 0 R>>/Properties<</MC0 182 0 R/MC1 183 0 R>>/Shading<</Sh0 189 0 R>>>>/TrimBox[0.0 0.0 640.0 640.0]/Type/Page>> endobj 190 0 obj <</Filter/FlateDecode/Length 980>>stream -H‰ÄVËŽ1¼ÏWä’±8+â„ЊÜG<. ÁJHü=e§ÓÝBpcW³ÛN;N•íræúú!\_=Pxöü!\¾^(P¨e~¾½¿¼ _°x}ù†ÂǧK¤Dø‘"ÞÛsé=ß»Kæ‘ÆÊÜ<ÚíóåÙ»p}ó‰ÂÓ§ðâ]x¼¼x…3¯OŽa!ˆ'×€¸=ဎø'<ݾì辟ƒª&9d¡T«°mo쯔ÄÌ-a½Ø_ Q8•˜=Õ1ÂísIB=ô–Fo!ªø&&MT›KªK)æÏÜØ#–¹B†O•¤4pDV<è¾€M˜5ד6•6°�’„se”Ô¤Öæ� Up2€eq’Q°'ã ’áÐá(Ž®pI¥j KGš@Nñþ‡½à…-Ç4{/=ÖÂÈIÁê;\´‚O µ&Uðƒ["9§Qún’Ÿ6ŸÑ,Lë³…ë²³Ùyƒwx¤ì@ŸÍŠ£N H:Àxa‹É'9àG¤OJž)˜#瞬%=‘;¬–gf’¢*uJd´L Ò‚4¬d£¾#e½UÈu$AWìE‹¬hŠîWeá…VSXÅÇJNì+[‡ì+ÖW[^«Ó¢µZ·óf3F4b»¶vÖ¯Íkkç¶5ý&v¸âyA£4µzîY§½¦ðºk·¶bV·ÆÈ›ƒýºpÁÚ¬èé,Ê©µZÅ2£ÅÄ"2-,Öuï6glª&©}I¨8ص; -ò§(&®À”M3k)–bš Ú&Àf™l³Z¢.@TwXÿH—dE. -ž:ìjY‡jz±¬SOÊmÖ“dxs õÝŠ¬h·áȇ¼]ic€‹} -ÖL_<0"L™i@.ŸWö4Ä_S,•ømžêac¬£¼FŠ‘N@g*ÉÚ\04¬Ûü?ﶉ s9<@¹›>W€Íö©±=¯WÛÖ»˜¼LËŒŸ½Ù´¶ä.ÅBUÑ¿sñÊdò¿‘‘{2÷T"÷4äLâÞÓÀ±ÿÂC j\¬åxôÿXþg6³åæçO#@ÈƯÊAoÉ”–>e¢Mœ ÜïhD\,П#ÜNmÃMê—r“¹Ø2/n¨8ÛÈ:Ƽ—zÔ:ÇêR3dšÙ‡å.y›¼˜’ûHÈ’ÇÔÀ•3Çø6Vì†!Ÿýsì0Ú![Û¬§›;š_ |ÅY>|ÃjÑ.lPa¤ºöê#o:(9¼µÿ,tÿšõxù)À�j³äž endstream endobj 189 0 obj <</AntiAlias false/ColorSpace 187 0 R/Coords[0.0 0.0 1.0 0.0]/Domain[0.0 1.0]/Extend[true true]/Function 191 0 R/ShadingType 2>> endobj 187 0 obj [/ICCBased 192 0 R] endobj 191 0 obj <</Bounds[]/Domain[0.0 1.0]/Encode[0.0 1.0]/FunctionType 3/Functions[193 0 R]>> endobj 193 0 obj <</C0[0.14902 0.32549 0.501961]/C1[0.0745098 0.160784 0.25098]/Domain[0.0 1.0]/FunctionType 2/N 1.0>> endobj 192 0 obj <</Filter/FlateDecode/Length 2574/N 3>>stream +<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 2/Kids[10 0 R 162 0 R]/Type/Pages>> endobj 10 0 obj <</ArtBox[11.293 52.1318 491.293 460.543]/BleedBox[0.0 0.0 512.0 512.0]/Contents 251 0 R/LastModified(D:20151115140912-02'00')/MediaBox[0.0 0.0 512.0 512.0]/Parent 3 0 R/PieceInfo<</Illustrator 252 0 R>>/Resources<</ColorSpace<</CS0 253 0 R>>/ExtGState<</GS0 254 0 R>>/Properties<</MC0 248 0 R/MC1 249 0 R>>>>/Thumb 143 0 R/TrimBox[0.0 0.0 512.0 512.0]/Type/Page>> endobj 162 0 obj <</ArtBox[75.293 116.132 555.293 524.543]/BleedBox[0.0 0.0 640.0 640.0]/Contents 255 0 R/LastModified(D:20151115140912-02'00')/MediaBox[0.0 0.0 640.0 640.0]/Parent 3 0 R/PieceInfo<</Illustrator 252 0 R>>/Resources<</ColorSpace<</CS0 253 0 R>>/ExtGState<</GS0 254 0 R>>/Properties<</MC0 248 0 R/MC1 249 0 R>>>>/TrimBox[0.0 0.0 640.0 640.0]/Type/Page>> endobj 255 0 obj <</Filter/FlateDecode/Length 933>>stream +H‰ÄVKŽ7Ü÷)tiHŠÔg›I•^ä�NV ` ·OQjµúÙ0œ1螦$J¬"‹z/¿½†—w¯~úù5¿¼ÃëeñútP(:Ÿè¯ÏßÃßÇËë +·@©á‘ñ„·&~ÅÄŸoǧÀðÇÁÌ’ô²P*E8<þ:|Æߢ‰)‡XÆÕߢpÒ\Ci©ôGÌš„Zh5õVC4NL–¨0œ5 Ì=©ª¯gn‰º;jˆ\BÆš"ɨãˆlø°k�N‚0K.·5pÒÚ1�„s¥kªR[zdT€É× XR±KÅ�|2ÒŒ eD§¬I‹øØQh8Ãü¿>ß.ÇTŸ—–z¡çd@õ–XžJIfÀ‡e‰8䜺¶Ë¤qÚüŽÎÖ©ÛÂeÙÙí|†·W((»m`Êw³à¨ÛH’u ^±ÅòIvøô‰æIÁ„9·Ä\'‘¬š' “¤(‚L݈ŒÎ”€Ð°ÈF~{Êx+‘KO‚ª¸’ÙPm@\™Å*”šaƒ•|ŒäÄcä¬kÄëê,£½jUZôRk~Þ,ÆȺ¸×Y®Ñëµzaå¶ä]ï!ÄÇPC<w/(”jžÏ‹uºòc¨\ɺ¬3™—íɦU4JããýÁÁÿ†p·`3²ÓèTãTkÑXf”˜ø¦¥híP÷es†SqI]CB:‚]ÞQÀŸ!™´?‡Svͬ¡¨Ét°]€Õ™¬3[bC€Èn÷ú‘&É“¬†%<uØÌY‡jš:ëÔ’qyD'é£8@}ó$ÊÈ°r餷FX<Ü°êúâŽáÊÜ ²Öv¹hˆ_R7‹;_5Ò[>¼5¤×Aa§[E ‰³o*ÉË\Ð4¼Úƾl‚κW�rs}® N{tó{M®O{ò2™qöiÓrÛà6õŠØ÷±ŒÌo0¹÷¯ÀÈ3˜g(È3¹Ãð]ŸaàØÿƒC j"ˆìû8ÚL +ÿ6šYróùVòök²á-™ÒÒ§ÌFtŠ³¢ƒ{‘!èOn§zÆM6.å2;³ú2/n¨8û÷y#.õhe¶Õ¥fÈ4óh–—ä½ó¢K^-!Hºï®+g¶ñ³ø C£÷϶Ã(‡ìe³¾£ÝÑü1F¼‘Uħ„Èyö<@aP]Z-o.0á-ÿ»ÐǬ÷Ç�Ìø endstream endobj 248 0 obj <</Intent 256 0 R/Name(Layer 2)/Type/OCG/Usage 257 0 R>> endobj 249 0 obj <</Intent 258 0 R/Name(Layer 5)/Type/OCG/Usage 259 0 R>> endobj 258 0 obj [/View/Design] endobj 259 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 256 0 obj [/View/Design] endobj 257 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 254 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 253 0 obj [/ICCBased 260 0 R] endobj 260 0 obj <</Filter/FlateDecode/Length 2574/N 3>>stream H‰œ–yTSwÇoÉž•°Ãc [€°5la‘QIBHØADED„ª•2ÖmtFOE.®cÖ}êÒõ0êè8´×Ž8GNg¦Óïï÷9÷wïïÝß½÷ó� '¥ªµÕ0�Ö ÏJŒÅb¤ � �2y.-;!à’ÆK°ZÜ ü‹ž^i½"LÊÀ0ðÿ‰-×é �@8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ V³)gB£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚ó�ÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAüom?çW= @@ -613,449 +612,421 @@ H N'çÎ)Î].ÂuæJ¸rî î÷wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…EŒ…ÒbÅ~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â*6X[ݱF=3ë·YŸ±~dó ·‘ÛtÛ´¹iÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„Æfm“Ž;'_9 œr:œ8Ýq¦:‹ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=G</zÁ^Á^j¯^—¼ Þ¡ÞZïQïBº0FX'Ü+œòáû¤útøŒû<öuñ-ôÝà{Ö÷µ__•ß˜ß-G”,ê}çïé/÷ñ¿ÀHh8ðm W 2p[àŸƒ¸AiA«‚Ný#8$X¼?øAˆKHIÈ{!7Ä<q†¸Wüy(!46´-ôãÐaÁa†°ƒa†W†ï ¿¿@°@¹`lÁݧYÄŽˆÉH,²$òýÈÉ(Ç(YÔhÔ7ÑÎÑŠèÑ÷b<b*böÅ<Žõ‹ÕÇ~ûL&Y&9‡Ä%ÆuÇMÄsâsã‡ã¿NpJP%ìM˜IJlN<žDHJIÚtCj'•KwKg’C’—%ŸN¡§d§§|“ꙪO=–§%§mL»½Ðu¡váx:H—¦oL¿“!ȨÉøC&13#s$ó/Y¢¬–¬³ÙÜìâì=ÙOsbsúrnåºçsOæ1óŠòvç=ËËïÏŸ\ä»hÙ¢óÖê‚#…¤Â¼Â…³‹ãoZ<]TÔUt}‰`IÃ’sK—V-ý¤˜Y,+>TB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%—®K7YV³©fFŸ¢ßYÕ.©=bàá?SŒîÆ•Æ©ºÈº‘ºçõyõ‡Ø Ú†žkï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹³mzyâò]íÔöÊö?uøuôw|¿"űN»ÎåwW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝèþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_p߶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO�¤[þ˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬ÐD¸®-®¡¯¯‹°�°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ -¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäüå„æ æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ�÷„óû endstream endobj 182 0 obj <</Intent 194 0 R/Name(Layer 2)/Type/OCG/Usage 195 0 R>> endobj 183 0 obj <</Intent 196 0 R/Name(Layer 5)/Type/OCG/Usage 197 0 R>> endobj 196 0 obj [/View/Design] endobj 197 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 194 0 obj [/View/Design] endobj 195 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 188 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 186 0 obj <</LastModified(D:20150811224719-03'00')/Private 198 0 R>> endobj 198 0 obj <</AIMetaData 199 0 R/AIPrivateData1 200 0 R/AIPrivateData2 201 0 R/AIPrivateData3 202 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 3/RoundtripStreamType 1/RoundtripVersion 16>> endobj 199 0 obj <</Length 944>>stream -%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 16.0 %%AI8_CreatorVersion: 16.0.0 %%For: (Gabriel Engel) () %%Title: (icon.ai) %%CreationDate: 11/08/2015 22:47 %%Canvassize: 16383 %%BoundingBox: -69 -576 571 64 %%HiResBoundingBox: -69 -576 571 64 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 12.0 %AI12_BuildNumber: 682 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: -69 -576 571 64 %AI3_TemplateBox: 256.5 -256.5 256.5 -256.5 %AI3_TileBox: -28.5 -636 530.5 147 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 2 %AI9_OpenToView: -311 80.4463 1.34 1928 970 18 0 0 -4 38 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 77 %%PageOrigin:-144 -556 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 200 0 obj <</Length 28598>>stream -%%BoundingBox: -69 -576 571 64 %%HiResBoundingBox: -69 -576 571 64 %AI7_Thumbnail: 128 128 8 %%BeginData: 28466 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C452F282F282F282F282F282F282F282F282F282F282F282F282F282F %282F282F282F282F282F282F282F282F282F282F282F282F282F282F282F %282F282F282F282F282F282F282F282F282F282F282F282F282F282F282F %282F282F282F282F282F282F282F282F282F282F282F282F282F282F282F %282F282F282F282F282F28062F0628062F0628062F0628062F0628062F06 %28062F0628062F0628062F0628062F0628062F0628062F0628062F062806 %2F0628062F0628062F0628062F0628062F0628062F0628062F0628062F06 %28062F0628062F0628062F0628062F0628062F0628062F0628062F062806 %2F0628062F0628062F0628062F0628062F06282F062F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F28062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E2F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F280628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E2F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F0606 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E06282F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F06062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E06282E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %280628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E2F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F062F282F062F282F062F282F062F282F %062F282F062F282F062F282F062F282F062F282F062F282F062F282F062F %282F062F282F062F282F062F282F062F280628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E2F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E06062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %28062806280628062806282F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E06062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E06282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F2806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E062F280628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E0628062E2E %282E062E282E062E282E062E282E062E282E062E062E062F062E062E282E %062E062E062F062E062E282E062E282E062E282E062E282E062E282E062E %282E062E282E062E282E062E282E062E282E062E282E062E282E062E282E %062E282E062E282E062E282E062E282E062E282E062E282E062E282E062E %282E062E282E060628062806280628062806280628062806280606062827 %4C4B6F6F6F68936F6F696F4B4C2728060606280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %2806280628062806280628062806282F282E062F282E062F282E062F282E %062F06524B94939393B5FD0793B593B593936F704B2E062E062F282E062F %282E062F282E062F282E062F282E062F282E062F282E062F282E062F282E %062F282E062F282E062F282E062F282E062F282E062F282E062F282E062F %282E062F282E062F282E062F282E062F282E06062E0628062E0628062E06 %28062E06284B6F93938C9393936893939368939393689393936893939369 %702728062E0628062E0628062E0628062E0628062E0628062E0628062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %2E0628062E0628062E0628062E0628062E0628062E0628062E06282E062E %282E062E282E062E282E062E6FB5FD1A936F4C062E282E062E282E062E28 %2E062E282E062E282E062E282E062E282E062E282E062E282E062E282E06 %2E282E062E282E062E282E062E282E062E282E062E282E062E282E062E28 %2E062E282E062E282E062E28062806280628062806280628062806286F93 %68936F9368936F9368936F9368936F9368936F9368936F9368938C6F2706 %062806280628062806280628062806280628062806280628062806280628 %062806280628062806280628062806280628062806280628062806280628 %06280628062806280628062806280628062806282E062E282E062E282E06 %2E282E062E062E6FB5FD1C934B2E062E282E062E282E062E282E062E282E %062E282E062E282E062E282E062E282E062E282E062E282E062E282E062E %282E062E282E062E282E062E282E062E282E062E282E062E282E062E282E %062E280628062806280628062806280628062806286F9393936893939368 %939393689393936893939368939393689393938C936F2806280628062806 %280628062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062806280628062806280628062806 %28062806280628062806282E282E062E282E062E282E062E282E062E062E %6FB5FD1B93B56F4C062E062E062E062E062E062E062E062E062E062E062E %062E062E282E062E282E062E282E062E282E062E282E062E282E062E282E %062E282E062E282E062E282E062E282E062E282E062E282E060528062805 %28062805280628052806280528062869936F9368936F9368936F9368936F %9368936F9368936F9368936F9368936F4C06282728274C4B4B4B6F4B6F4B %6F4B6F4B4C4B4C2728062806060628062806280528062805280628052806 %280528062805280628052806280528062805280628052806280528062805 %2806282E282E062E282E062E282E062E282E062E282E0652FD1F93706FFD %0493B593B5939393B5939393B5FD06936F704B4C282F062E062E282E062E %282E062E282E062E282E062E282E062E282E062E282E062E282E062E282E %062E282E062E282E06062806280628062806280628062806280628062806 %4C9393689393936893939368939393689393936893939368939393689393 %938C939393689393936893939368939393689393938C9393938C9393934B %4C2728062806280628062806280628062806280628062806280628062806 %280628062806280628062806280628062828062E2828062E2828062E2828 %062E2828062E28280670FD3C936F70272E062E062E2828062E2828062E28 %28062E2828062E2828062E2828062E2828062E2828062E2828062E280628 %05280628052806280528062805280628052806062793929368936F936893 %6F9368936F9368936F9368936F9368936F9368936F9368936F9368936F93 %68936F9368936F9368936F9368936F9368936F9368938C93694C27060628 %062805280628052806280528062805280628052806280528062805280628 %0528062805282E062E282E062E282E062E282E062E282E062E282E062F4B %FD25938C938D938C9393938DFD1093B593936F52062E062E282E062E282E %062E282E062E282E062E282E062E282E062E282E062E282E062E28062806 %2806280628062806280628062806280628062806286F9368939393689393 %93689393936893939368939393689393936893689368FD04939A9AA19AC3 %9AA19AC39A9AFD049368938C936893939368939393689393938C6F270606 %280628062806280628062806280628062806280628062806280628062806 %2806282E0628062E0628062E0628062E0628062E0628062E06280670FD16 %938C9393939AC3A1CACAFD0FFFCAFFCAC39ABC93938CFD0D936F28062E06 %28062E0628062E0628062E0628062E0628062E0628062E0628062E062806 %052806280528062805280628052806280528062805280606279393936893 %6F9368936F9368936F93689369936893939A9BCACAFD1BFFA1A193936893 %68936F9368936F9368936F4B050606280528062805280628052806280528 %06280528062805280628052806282E282E062E282E062E282E062E282E06 %2E282E062E282E062E6FFD1293C3C3FD24FFCA9A938CFD0B93282E062E28 %2E062E282E062E282E062E282E062E282E062E282E062E282E0605280628 %0528062805280628052806280528062805280628066F9393689393936893 %939368939393689AA1FD29FFA8C3939368939393689393938C934B280628 %062805280628052806280528062805280628052806280528062828062E06 %28062E0628062E0628062E0628062E0628062E06284BB5FD0A938C939ACA %FD2EFFCA9A8DFD0893B56F28062E0628062E0628062E0628062E0628062E %0628062E0628062E06052805280528052805280528052805280528052805 %280528066F8C936F9368936F936893689AA8FD32FFCA9A93689368936F93 %68936F280528052805280528052805280528052805280528052805280528 %2E062E282E062E282E062E282E062E282E062E282E062E062E6FB5FD0893 %9ACAFD36FFCA9A8CFD07936F52062E062E282E062E282E062E282E062E28 %2E062E282E062E2806280528062805280628052806280528062805280628 %050627938C93939368936893A1FD3AFFC368939393689393936828062805 %2806280528062805280628052806280528062805282E0628062E0628062E %0628062E0628062E0628062E062827FD07938C9ACAFD3CFFCAFD08936F2E %0628062E0628062E0628062E0628062E0628062E06280605280528052805 %28052805280528052805280528052805938C936F936893689AFD40FF9A93 %689368936F93692805280528052805280528052805280528052805280528 %2E2828062E2828062E2828062E2828062E2828062E066FFD0793C3FD42FF %A1FD0693B56F2E062E2828062E2828062E2828062E2828062E2828060528 %062805280628052806280528062805280628057093936893939368C3FD44 %FFA1936893939368934B0605280628052806280528062805280628052806 %2828062E0628062E0628062E0628062E0628062E064CFD06938CC3FD46FF %A1FD07932828062E0628062E0628062E0628062E0628062E060528052805 %2805280528052805280528052805286F9368936F9368C3FD48FF9A936893 %6F938C6F052805280528052805280528052805280528052828062E282806 %2E2828062E2828062E2828062E4BFD05938CBCFD4AFF9AFD06934C062E28 %28062E2828062E2828062E2828062E280528052805280528052805280528 %052805280593939368938C93CAFD4BFF6F93939368936F06052805280528 %052805280528052805280528280628062806280628062806280628062806 %4CFD0693A1FD4CFFC38CFD05932728062806280628062806280628062806 %28060528052805280528052805280528052805284B9368936F9393FD4EFF %9468936F938C6F0528052805280528052805280528052805282E2828062E %2828062E2828062E2828062E28FD05938CCAFD4EFFA1FD069328062E2828 %062E2828062E2828062E2828060528052805280528052805280528052805 %4C939368938C93FD50FFFD04936893270605280528052805280528052805 %28052828052806280528062805280628052806284BB5FD0493A1FD13FFA1 %C3A1CAFD0EFFCACAA1C3A1FD0FFFA1C3A1CACAFD12FFC368FD0493700628 %052806280528062805280628052806052805280528052805280528052805 %28056F8C936F9368CAFD11FFC36F93688C6893A1FD0BFFA193689368936F %CAFD0BFFCA939368936893A1FD11FFA19368936F93452805280528052805 %28052805280528052828062E0628062E0628062E0628062E06286FFD0493 %9AFD11FFCA8CFD0793CAFD09FFC3938DFD0693CAFD09FFCAFD06938D93C3 %FD11FFFD06932828062E0628062E0628062E0628062E0605280528052805 %28052805280528052827938CFD0493FD11FF9393699393936893689AFD08 %FFCA938C9368939393699393FD09FFFD0493689393936893CAFD10FF9A68 %939393692805280528052805280528052805280528280628052806280528 %062805280628054CFD05939AFD10FFA1FD0A93CAFD07FFCA8CFD0993C3FD %07FFC3FD09938CCAFD10FF9AFD0593272806280528062805280628052806 %2805052805280528052805280528052805062793939368939AFD10FF9A68 %936F9368936F936893A1FD07FF9A8D68936F9368936F9368C3FD07FFC368 %9368936F9368936F8D9AFD10FF9A689368936F2805280528052805280528 %0528052805282E0628052E0628052E0628052E0628064CFD04938DC3FD10 %FF9AFD09938CC3FD07FFC38CFD0993A1FD07FFA1FD09938CC3FD10FF9AFD %0593272E0628052E0628052E0628052E0628050528052805280528052805 %28052805062793939368939AFD10FFC368939393689393936893A1FD07FF %A193689393936893939368CAFD07FFCA68936893939368939393A1FD10FF %9A8C9368936F280528052805280528052805280528052828052806280528 %06280528062805280628FD04938C9AFD10FFCA938CFD0893FD09FFFD0993 %94FD09FF9AFD0993FD11FFFD069328280528062805280628052806280528 %0605280528052805280528052805280528059368936F936FFD11FFA19368 %936F93689368CAFD09FFCA689368936F936893A1FD09FFA1936893689369 %9368CAFD10FFA89368936F93692805280528052805280528052805280528 %28052E0628052E0628052E0628052E06286FB5FD0493CAFD11FFA19A8C93 %8C9393CAFD0BFFCA93938C938C9ACAFD0BFFCA9A8C938C9393CAFD11FFCA %FD0593700628052E0628052E0628052E0628052E06052805280528052805 %28052805280528054B8C93939368C3FD12FFCACAA1A1A1FD0FFFA1C3A1C3 %CAFD0EFFC39AC3A1FD13FF9A93689393934B060528052805280528052805 %2805280528280628052806280528062805280628052827FD0693FD4FFFA8 %9AFD05934C05280628052806280528062805280628050528052805280528 %052805280528052805286F9368936993A1FD4DFFAFA168936F938C930506 %052805280528052805280528052805282806280528062805280628052806 %280528066FFD04938CBCFD4EFFFD0593B54B280528062805280628052806 %280528062805052805280528052805280528052805280506279368939393 %68CAFD4CFFA193689393938C280528052805280528052805280528052805 %28280528052805280528052805280528052805286FFD0693FD4BFFA1FD06 %936F05280528052805280528052805280528052805052805280528052805 %280528052805280528054C929368936F9393FD49FF849A68936F93689327 %060528052805280528052805280528052805282805280628052806280528 %0628052806280528066FFD0693A1FD47FFA8A18CFD0493B56F2805280628 %052806280528062805280628052806052805280528052805280528052805 %280528052827938C9393936893A1FD44FFA884A18C936893939369280528 %052805280528052805280528052805280528280528052805280528052805 %2805280528052805284BFD0793A1FD41FFA8A8A8A18CFD06934C05280528 %052805280528052805280528052805280505280528052805280528052805 %2805280528052805064B9368936F936893A1FD3FFFA8A884A18C9368936F %938C6F050605280528052805280528052805280528052805282805280528 %0528052805280528052805280528052805286FB5FD06939AFD3DFFA8A8A8 %A1FD08930528052805280528052805280528052805280528052805052805 %2805280528052805280528052805280528052805286993939368938C93A8 %FD39FFA8A87DA8A19A689393936893936F05280528052805280528052805 %280528052805280528052828052805280528052805280528052805280528 %0528052805286FFD0693FD39FFFD04A89AFD099327280528052805280528 %052805280528052805280528052805052800280528002805280028052800 %280528002805280028056F8C936F936893A8FD33FFFD04A87DA884A19393 %68936F936893926F00060528002805280028052800280528002805280028 %05280028280528052805280528052805280528052805280528052805284B %B5FD0593FD31FFA8FFFD05A8AFA19AFD09936F2728052805280528052805 %280528052805280528052805280528050528052805280528052805280528 %05280528052805280528056F8C9393936893CAFD11FFA8FD19FFA8FFFD04 %A87DA8A8A884A89A9368939393689393938C6F0506052805280528052805 %280528052805280528052805280528052828052805280528052805280528 %0528052805280528052805286FFD0693FD11FFFD07A8FFA8FFA8FD07FFA8 %FFA8FFA8FFFD0CA8A19AFD0993B5934C0528052805280528052805280528 %052805280528052805280528052805002805270028052700280527002805 %270028052700280505009393936893689AFD0FFFA87DA884A87DA87DA87D %A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA884A884A8A19A6F9368 %9368936F9368939393692805050028052700280527002805270028052700 %280527002805270028052728052805280528052805280528052805280528 %05280528054CFD0693A1FD0EFFFD06A8AFFD1AA89A9A93938CFD0B934B28 %052805280528052805280528052805280528052805280528052805280528 %050528052805280528052805280528052805280528052805064593939368 %938CCAFD0CFFA8A87DA8A19A939A9AA1A1A87DA8A8A884A8A8A884A8A8A8 %84A8A8A8A1A89A9AFD0493689393936893939368939393686F0506052805 %280528052805280528052805280528052805280528052805280528052828 %0528052805280528052805280528052805280528052827FD05938C9AFD0C %FFFD05A89A8C9393938CFD04939A9AA19AA19AA19AA1FD049AFD04938CFD %0F934B280528052805280528052805280528052805280528052805280528 %052805280528052805052700280527002805270028052700280527002805 %05006F929368936F8DA1FD0AFFA87DA87DA87D9A689368936F9368936893 %6893689368936893689368936893689368936F9368936F93689393938C93 %6F4B00060505002805270028052700280527002805270028052700280527 %002805270028052700282805280528052805280528052805280528052805 %28054CFD0793FD09FFFD06A8A19AFD27936F4B2805280528052805280528 %052805280528052805280528052805280528052805280528052805280505 %27052805270528052705280527052805270528050569939393689368C3FD %06FFA8A87DA8A8A87DA8A193689393936893939368939393689393936893 %93936893939368939393689393938C939393696F4B270506052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705282805280528052805280528052805280528052805284BFD05938C %9AFD04FFFD0AA89AFD0893B5FD1793B593936F6F27280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528050028050500280505002805050028050500280505219393 %93689368937DA8A8A87DA87DA87DA87DA884A8939368936F936893929345 %6F6F93689392938C9392938C9392938C93939368936F6F21270505000605 %050028050500280505002805050028050500280505002805050028050500 %280505002805050028050500280505280528052805280528052805280528 %0528052827FD0793A1AFFD0BA8A1FD0A9327280528274C274C4B704B6F4B %704B6F4B4C4B4C2728052805280528052805280528052805280528052805 %280528052805280528052805280528052805280528052805280528052805 %2805280500280527002805270028052700280527000605938C9393936893 %9AA87DA8A8A87DA8A8A884A89A9368939393689393938C6F050500280505 %000605050006050500060505000605050028052700280527002805270028 %052700280527002805270028052700280527002805270028052700280527 %002805270028052700280527280528052805280528052805280528050605 %FD07939AAFFD08A8A1A1FD0B936F05280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %05280505050027050500270505002705050006056F8C936F9368938C9A7D %A8A1A87DA89A9A6F93689368936F9368939393684B050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027050500270505002705 %050027050500270505002728052805280528052805280528052827FD1193 %8CFD0B934B28052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805052700 %2805270028052700280505006F93938C9393936893939368939393689393 %936893939368939393686F27050028052700280527002805270028052700 %280527002805270028052700280527002805270028052700280527002805 %270028052700280527002805270028052700280527002805270028052700 %2805270028280528052805280528052805280528054C6F9393B5FD14934B %280528052805280528052805280528052805280528052805280528052805 %280528052805280528052805280528052805280528052805280528052805 %280528052805280528052805280528052805280528052805280500270005 %0027000500270005002700050005004B459393938C9393938C9393938C93 %9293686F4B27000600050027000500270005002700050027000500270005 %002700050027000500270005002700050027000500270005002700050027 %000500270005002700050027000500270005002700050027000500270005 %00270005280528052805280528052805280528052805280528052827706F %6F6F93FD046F4B4B27280506052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280500280505002805050028050500280505002805 %050028050500060505002805050006050500280505002805050028050500 %280505002805050028050500280505002805050028050500280505002805 %050028050500280505002805050028050500280505002805050028050500 %280505002805050028050500280505002805052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002728052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528050505002705050027050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805002705050027050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027050527052805270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %050005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280505050027050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027050500270505002705 %050027050500270505002705050027050500270505002705050027050500 %270505002705050027050500270505002705050027050500272805270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528052805280528052805280528 %052805280528052805280528052805280528050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705280500050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500272705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705280527052805270528052705280527052805270528052705280527 %052805270528052705280527052805270528052705280527052805270528 %052705280527052805270528052705280527052805000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002727 %052700270527002705270027052700270527002705270027052700270527 %002705270027052700270527002705270027052700270527002705270027 %052700270527002705270027052700270527002705270027052700270527 %002705270027052700270527002705270027052700270527002705270027 %052700270527000027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005002700050027000500270005002700 %050027000500270005002700050027000500270005002700050027000500 %270005002700050027000500270005 %%EndData endstream endobj 201 0 obj <</Length 65536>>stream -%AI12_CompressedDataxœì½m$Éq&øâ?ä}@.vŠáîî¼Å•YUZîRAR+‹A«§Eöª_==Òñ~ýÙ󘙻GfVOõËPÄiÊÑ]•–áoæöò˜ù_ý¿ùÝW·ß¼ý§_¥›ù0ýÕ_Þ½xöþí»_H=üêÕ«ï¿{ÿ¤Ÿýöç‡of¹èöWõk»ð¼x÷ÝË·o~ɯøåîþÙ_?û§w/_¼:Ü¿ùËW??üìçòÍï_¾õB¾{ùüí››g/î“ûïž½—oBøÅ\ç°büåRpÁ³7ÿúì»ï^þ¿ø:§š„v|ûý›o^¾ùÃñíÿóËÃWy;|µ–|XK8äE¾þ¯/û⻸æîíóï_¿xóþ7ïÞ>ñÝw§·¯Þ¾ûî—‡ÓŸž½9üͳ?È7Ïÿ÷‹W¯ÞþÛáøêÙó™¤Íë×/_½æ½~öþ"{û«¿>~ÿòÕ7ûýëz! Ï5‚œ¾f•ÿÔ%ÕâoË׿z-”ß½xÿ^ÞMˆûí_Ç×"ËÏþço_üá%;_:èýܪ}÷öÛ×ÏÞýËwWZ…ïÿâõ·¯¤3Ùî¸æ›õð•þ?صÒíŸXñUNRWšåÏ€¾Ç%½Ÿ^üëËÿöËÃß¾}óB;ãöÝûßé°,Ë<ëÿúÍo¿õâÝß¿yù^^2ƒ´ioüÍÛo^¼’ëÛý¯ž±XBÿ_/øý³wxñ^Æòí«ïßsŽU‚ôö¯Ÿýé†,êþîÛo~ÿöð¿J!ȵ7Ë’Ó!ܤå¶X[‘ê+ŸòÕrHµ=7ôÿµzT†ªü3ñ72p÷îå^¾ùåWÒXéú5ë˜þõ»—ßô!-ñPõ?¶å¦ÿ6ÿ§/-íÿþÅë™J§¿¦Æ|ó7¿“çÞ¿ùæôö5á;Ì}™odº¼zûý®ýÍoäöï¿ÕFðó×2^¿y÷ò êœþ–ßÔ¯óê{ùê¯ß½ýþÛ_½ùç·ÓÏtÿÏeAË~sø»úßòA–-§ëá÷ïž=— -äs»FÖï·?ÿ`uÒ¸w/ú¥ÜÉþû‡ï¾{ñϲÐúíJ½ó¯/^½ýv¨¶Qž½ùæðÏÞ}ûÃUÿæÕ³7ÏÞHo5ÿúå¿Ê7Ϥ§zÝö„Je¢|+Ã[xÉÙ>pÁðÕôìý…'½xóÍwný¸q¥ýp}¿{Ž9øîp|÷ýw<üþíÛWÚýWv#“Šëÿ2žñÞðæïÞh]>É.8’°¡¿¸§ÈÕ?A¾üK®ýôìÕ«—x÷ìÛ?¾|~íW¾oOÒï>fbýéõ?½}õò»×}> ”ß<{÷þåóW/~÷§ïÞ¿xýäÁ=ÜóR˜Ü#Ëøƒ×üîßž½þÇ_¿ü§wÏDúùàêÃ�üóË7ßÈÜÿÝ÷/ß¿èôöõ·^¿ûã³o_°ïÿøÀ+×*\¿Ö?2÷¯¾šÂáøf`ýýîÙ7/e×ëïß¼yöZØúŒtHåçÓUªìXñpüfúŸÓ™îORîXüçåaf V¢ý’X–+E¨ÿX¥øÿÿOüùO‹U=ý_òÇt\äßzÌüWEþÝ7ùwä¿»ãIþ=ï§Yþ…Sä¿Ä«ýŸNË)Ëï<Šü*§*ñ?þmúŸo±,˺ä¥HÙ–[)§åN -Z0¯QJZ—?EJ]o¥×Óz'EÚ˜gR^òšñSsò–o³´'Ÿò”‡üPæ¤Ä’ð©'K©,·å–o¶pŽáî¤ÃçbŒ).1Çk¼ÇxïÓœBJiIk*".ߦcºK÷˼Ä%I½•ï~/ïÖ4ñ…ñº§õ^^3ÊK®òØMÞKÞIÞ&É{àù§r_gmñò¼Ùhy¶–Ä¢?ÁÊŒb#yoåŽåÄr´r;I£n¥i(Õ -»"d–ÕÊÂ"ã[Hã‚ôÿ,ãp/åNZvZŽŸMZZ¥½Òé2røI|Õ =1Ë$½—r—dZHÿÜJÙ&é¬*]†‘Z¥ûéD´*H‡Î2)ï¥ÜE™MÒÍ·R6¾EËC¹/wÒAGé¦M:«È°2€I†2”Y†ö^:ó$]z+[¥{³t²ˆ¦ÒAfǽ̑“Ì–Ûu[ë$ã‘eT6/XÓî¬Y›5iµæHcä-–Ã_}}|'KVäÊÃ,f©ËVä÷R¶’îÍ:o5@ôœË²Š`zò,É_ɪⰊ,²¼Ô'’ç×_¬¾ãwx7LÀŒºæ°eÜs‰¤ÌÒ/3–mŽò;ÅuÙø^Ú*_í‹T'ov¼kÕYæèå²ýöÕ7/Þ~IyÚ}’ç媳•Àb#÷_¦ùü'œ•8”de±²òŸ—Œ“üKi¥ÎÛ®Üå(ådån(÷óÃ4?xÙ½Øø‡’†²ìŠæ‰¿t‰ëR¯CÙvå¶ñŠ£ñå—Gœäƒ3˜‡±Œ]Ç—óŸ4”e(+\V>ÞÚK›ýÿv(G-d cùØh¦Ýx.èö±•2µá]†AÖQGWø3cTën|·a„åÿɆÚû؆Yc”ïÇÑ–ÿõg¾:ÖqÚ t2Ví¬[™¸³ôýßZÙŒ%~ù–±E¨n7}ÌPt|È6, ÉÆcu²rÇroEÅ_[Òˆq,Gi±Ž¯ìÐ#Éû&²ñ™ÍÛØ”¾A/Ü +'ÌqâsñœÈ=:sÞdÂ.ý £„«AÖÀN Iã(Ì_wk•1²l›I²eOòBAf©ŠÕ¤Šwï™Ò„JU¶¦£lRwåAæI¨QvÇUäR·z[õ®Þ×™/qÚÒ¶lRÏV·m;n§í~{Id“\D¬É·õv»½½Ñëöt{w{Ï™)¥”ÍT2;©<v -{⤮"2Õíéx:îN2ÙGa9)ßÉËÝÕ»íîxw™óá~–qÉå>ß‹ðq¿Ý˳ NC)q& -ÒÒy÷‡[)òȇ;ˆ¨ûËYF³}¾ÊÝPNC9îÊíP6/“üW‡R†’weÊ^*îE&àÔ$à¸caùÎã«ß?w»rÒ¢2üq(·CÙv¥¥%eî×V–]IC‰C C™Ç¢]>Yßo?þœ†rÔ•¹ÇýèíÇÌGk?DûaYT9Fb‚}Çï»Ûºù¬oÙŸSëÒ}Gî{oßcgý´ïšé¬G´7nl,ÕJ±BÝânµB•å.Y‰×žm™ÊúÛô÷–é³üçÈrkec©VdmCµÊVV+ÉOÉŠ²^gôÂA},ï9~GŽWåø¬¦vý=;ûÈÎìË•½‡>›ÙGwìtDØò•mEg6èŽ ¸å+¾áÂ7 -Ðeø G©YBÇ„¶ ½3 -7Ÿ'™H÷ÒË'az·Âþª(dY˜á"L1 -kœe‚ÝKÿŸ„aÞ -Û¬[º -#M²Ùd"ÜI7…ÛnµNÂx³0àEtŽ(ìø3µˆ<OçŠÄÇêT‰îLÚR¨ -¦SîLýÁ¶Z¨.܈4½®ŠˆŽ¨Wá:¿Š×™.xGùMÕ¾JéO<Uíy«a~{¿bGìŒáa`õÊ6™T«L¨ “éÚTŠ¶Gp÷Áî@ë»ÐÊÕë;‘íEjÀgc¿k›]6Âùv—Úv‡ÍîTå~TéWSê)5Ph¸§ØLpX›èp;v;zrÚü UÊ -swüˆÕ¢kÅ7Ķ‹ò{¶œÖa0ÛAÚ,EÂЄ•ðTð¹mÖ Œñƒ5Æ›ãR³IÉT+X•WÔ«a%ì ½ùjOè+¥ƒ´()$ù"3àȹp&xW¬¶8ÇyNŸ*‡¼G»ø -;Ús£âEÚõg«ñ³ã±‰¿^º"Sw*N1µ'›™gÔŒL[švöž8Ú{¼ìU0ßcÎ,@'ûtœvŠš†\)Àïí¬Ô³Ò•Hý+OÍh´7%]”x¥ØÏ´Ót/:¬¸QHk¿ï®áSÓ´O¦ŒU;»Z¶GKu½o”|-ù‰¥«”ëX¦ýÇflè_–ôHᤘæøÄrƒ¯”é‰>ùçšîþY?_¬BßCëQ•Q]̾³¢–%ÜHQMv#†ôéÌŠëf‘>ýÏW³K¨¾zÇ{Ôuì*ýåj-Íw–]üÕmCi\ Ó¯Lù«™%ºyêl9ú‚¼›£Öhä:^]ŽÇiìrAš1å|}Ö•[gÜBsm‰¶ÏÓÅÊ<_„—‹òƒeº0^[©Z¿gËslŸ½†?´Žÿý—ݯðšˆ:j?—úÊ#—úK!3tè{J›i~ÙäØ´Ÿ‡Aâ(;‰#ühÔ€&Q © -%h¦¤:ЉÆÕƒjÓƒ’éAЄN¢©Uš’–‰ªPàâx V|‡'Èý•.èBІ¢jCÔ‡îL:RªÔ‡ s…É”¢j¸'zÒ A5ªT -TŽ—Ò5¤5¤#t}_¸T!ø“Ì£DÓŒú“îD]r’{”ʲ6R"§RÒƒ)ÖG-“Èm›ù”Šù•Ô«”(ÅÇ‹C¦=™o鸓Ï*(”ejœúBêd,·¤êï‘çKM^{„ S½`œ;ÉeÇ#wqÚÉ$(g¼í*[û€q)1<M<Ê>¾ä:6mQËh¦öf¹ÁÔ¸·…ù¾:ÙqWÒ®ìÍnëYÉ»R¦)¯ìŒ|•ŠÒ¾Üž•ãy™šÍËËÝE¹üy¸,>Ǧq§~WJ¼ZÒÕ²8Ì༬”ühi¶ÜigØ-47¨l?Pn§9ùz9>±¹O;Ëõ‡ÊÝÓÊt…xmŸ\¦G¿úÄŸËMôS+2ÃÍÜÔÏh-‹5gºy³XqëçfÅl£“™JýÇyC_6>ÎY]EvIÞ´j³]&´äVÜÌ[[٬ܶr¼Â£ägº`P×XS7Ý_çFšaBqŸÇ¸ÎÀiŽ´á<Îk>ÀcvLÅËôAžr…“ü™>Ì7žÀ2ÎXÃ4r‰Of ÃzŒ1<‘ \®üÇ×ñ‡ËŸi” ugE‘í¤ÆN:a#áRËd¨/÷ʼnûº'êK=²ŠûÊ%·æ™½ƒo–¸¯@PÕbÚ2Q>u/-ü´÷ôÔÎgÈ/üÀg{K~[, õÝÂ{Á’܉NÜ -I›ŽÜ£p£»æÎEüƒ$ Ÿî"¯ ¹P,ßDD¿¥÷$üâÞ¼¼óm˜DŽ”çáî…Ã7ßJúÛàø¥ëW -¦#Á@c¢x!P/ãÅñ>Óq£OX½Â'ò",íú‡çÆrÙ:›uöÚÙªqÔ©±ÒÎBuv¦Ùyeç‘7Žñnj|päïíyÝÈâF¶60³iàc{ÖuƬ®H>—ühi®Ë-q™3±c,Ó‡¸Æ²‰'n🺎; mÑ�lk>dÆuÈr9”t#$6@Ø.íü²›U¡`5܈˜îü:BÚB.ÛBð´ÛèkH¸²Fû:†5owVãMš×¥ƒÙ>·"¾ x+ño²È3îåZ”oÖµ-„å M˜â².‰Üëu¥›YØJ©/TŸ¾[žH(|s^ï«Âˆµ.‡Js…£¢.·uÛÕµÎó6¼Û—©ïÓG1–›šÒ†šêZ¶ÏÊóÚ®ÌT{óm»~þØ4Ý_ôƒàƼøwïžÿñå7?Ÿü¥ù&ç û$Æ1ÅR2Œ²¸Ø½ø#¿[¶vÇÁïÐÈ.»ã`wØ2=~ÒÍÚaO½Ý´ä›”0½?áÁûû?¦›÷/’>ÆÿrãâH{Ûl׉¶ß¬æÏ,¶»ÜÚ†r7:žm³X%»%!قἊ@z)<Ð*¤"A¦0pK1àž»€^Ø÷uÏ¿¥µïîب F÷©}[ÍäØ‹g€ªKלô -7PÜúVòÚÏãhØÑx½šQ†VBEN;ÑÐç†Âb( -ÅQ’‚¦Â{SœVuë~2 Cž„ }³M -Á>pRig€,MºÙFp§ãdx !½VGRfUa¥œ -ù´Cþo¥w¢þ¼+êG·î¢#/vÀ ³ÎÍëy¢uPÍÅÌ~‹y‚Ÿ˜yZFÝü÷¨Ø&Ã4Ý5Ó¡—ܾLIáI3…¢û}�Š6¨¨šOÕžšV±R³ÈÔ. -5ŒJkð-õŒ# wÅÊ*]åPôçʸ…B‹³Æ›¸îAíÃð ŠÕ¸Ä‰JH¥ÒÃOFUäL1]CÛ"Qî-e†‘}¯’`Nl$=Qª¾opÒH…ÄA¥£Fr¢Frt2…$ -I1eäHeäŽÊˆN»²zt¦…L´qt5äRYM¡*Òô#uj"ʇpgøç¤HOáåß÷íï=Õ¬æ“Á¨åƒù"ï»WÒÿ7õªWƒ¼A¬C³Ð§†°ï¿Óî÷bì×áØkÃÝ«ñ_¸â´CÞ;þ¾Øÿê5ÐÿÕ™Ûÿ¿Ýùîªmø{à(°Ú©Ì…‘ «ÍžŽª§dðÙ}Éõ¥–ˆ9_fœ1ÎÈêÿð3úÎýyÌ[9ºBsKŒŠK‡è¥Ouq/ǹ#öòÓøûüzÄ@ YÅn<ŽìH»¿Ó4|XÎ\6£#çºÏºß<ØÓ…¯Gû®»”{¯öîƒÐ=0;dêñ -2µ(µÃQˆjTåôÜáeŸÈn¹ÑëV_hÌXÉO’mùºéï]¢·Í%ZȬÌ-:Q -è¾Ñ;¾œn{ºñùÖ×6¿¶ýùHÌ(7AÙ'ÛÇpÜGìè=ºÇ6餂yHÏ1¤¡H?€#èÚ'ׂråK´øP~0Þ-ßfŸNú)]šQ}–ðÒV¸ôt˜¾Û!¦Ÿ•Õüy?7§-=b¥ç6QÌ®¤-ÓúmÎê¬Ý¸×qîN6}3·Â>‰“A•—«+×'ô½u×iðõëä–2Ù/6Ë3•Š(ÊzÉÁu£P¿°Nû{N}N~Å@\sÒ‡Dœ—ëžÀxnÜ¿š¸<±Çó_RL—ÑgpÿëA—0]®(gÛ|æÏ}<È"MÆY„¬œÇÖ¬œéêâ9Τ¾~Æ54¬¤³pT2ÓJÅâ;#2—T¡SÏA˜ÕJÛˆhÑ5C½^·Ö²3cÈÕqˆùü2õÑêSsÞµûMaO#›¥fÙ²Ö|#òSíoóÉ5ðùeIÂú`›JeCt*ï ¡ˆÜâ/4µ.Â3‡F¬Yn ÝPùÙ© ¬Î)±×´UýdŸ©g°)¸Æ5í]«f»Y×y4¢|~MeNùþõëï`QÑ?h3«Õ ù¹@6JUcei=Çú[콋î -†DëâõÚdèÒ$åÉ表£(ÜÃN©îMCÔbm(ÍPªˆNÅw>®sj´:ái„Uå܉øh[Ù½kž¢{½d�PÖCí:õĉ€§Bø“*¢®Œ}4Þä -ö¢á®M^ÖuZ–„B;D5•U‹íR<´¶Í¸y–DÔ0¤S«§VÖVúOi¥¶rÛʱ—)Ÿ†Ò½í{—Ëã»’†Â¾›ÊÒʺ+—?õ¬lWÊíTn/Êé‘r÷ÒÜFÓuŸ5•û-œÈS_¢\Æàö(ÜÒâp}•†}<Iå¢<öhb,ÅÉÔÑ]L -—Ùà _v×ðfq0wƒ¥fñõûÌdkâDïàÜ‚uW×–ääÖ›À‰fÇÕæfeÖ ÌÄ;Ì@wGΣKØÆXÉ@m Ñ>涗Jc/l/8hw™Íî²Òê¢.à9€ïÌú)Äu«Ä½Ù]èû~ÀýÛÀÛ`s91*Ï{Ã6ßïtæüÍ”;ÂÆÀ*ñv(M‡ÐtðÇj:sçTf»�ÊìÂ2¦abTÙƒ`\,;Ǻ\b\.ñt§é -ªå*še”[/Q-½LW$㫹'�ä–ëHºÇPt,ÔÔóëѺ¥ëñ¹=6×ß¡Ký&ÒB;Eô}ômcvɺKÑ=ж ȃ@|§ ¨}`ms/Ãi»jx¦ŽúàtE¼n¢¸PÏô@Ó§+ªà^Ü«ƒ{…°š)´´ÍnšZØUCWcK»1*âà (Þ7Å EOþàÛþ³µR[é{W߆×V–^&Ó+»v3Œºæ qö2jbÏiÐaN»r¼(·gåÚOÈN÷åêÎMSÏ㥉ASÿó¬,]¸ƒM[úå㣵?¯ÍÉé,Fò2f{)¹Û#·Í975ƒÝh¬»·iÚ u;3úêš·Îýu·>¾ÅÆG;4žÅ2œš§j;‹hHÝVgÖºûr7qÅ9ý7s` -§îºTÃ]w^îÝ—=Ò¡P¶]'wP/fÜ…<Ü“_í6 -%¥øVÏ[ÄÔk=Ø&w×Òk‡DhPD¶T[¡ÁÑRnI™Z”ăéÊ=O–ƒëhܧZ=ȦI˜’’ÒDÝÇCRÕظǢã<Îb»M¦~mƒ�úXPl/˵�Y“½ü¹Œc{,|ê -~º ÝJùŠ`”ºE\ÿÞ�ë\E¹#æFÚÍ�+l¡[!®&û´»?Æ:p‘à0\ËzvIwÚ†[ J³XÖŸðxܺ†¿?xôúd0Ôsê>ˆ>M-Û`5ÅÂ1§9ûpºíÝ[Ýı\(Iþâtß_ÿ¼ÇI[`F‹§f#ø�’vêíyúí…{Ž€±·wý=Y‡‡Ý뎚ÝcÉ®SOöX{â %AÉJOrû0õô$?jF•Ÿ^X_x°q§¥¬3’Æ¢Vgèâ…fØ5<]ùãz¶ÅϯJ¸£&3ßgKÜÑ>ƒÎóU*d©zÝqÑhà0¬çá ‰ØƒëF“—n-q©š]*—¤B˜4ÚíÔL‘ì¯ÐVx7$?s“ê{ê³b0z‚è25¸Êªb@•p~5›É8?ZNî·‡©™O¸M_YÌâPúlJ«A]·ðSŸ&³µ(Öþ΀.cé!»õž+q_¦¦Õõ’®–呲îËtFÈO*åñ2=úUý´2}ÄÅW”¿Ë2=í²§—Ÿ*¼rA“\ -Ë‹¨ì) ”]®ÅHtQ᦯ÆÜ.dÕt;µ<È*_a{³+&l³Áç,†§æ:`®…îL +ç‘;û¸Ær�’»ˆÜQ \nÆZá?“ÍÄ“9Tï-ˆc¶8ž`ê‰CçÖÏãÅmús;gñ~ív·~tÃH醔p^¦1ÐÎ*“vÜ…¼pl?çåŠã‘ÒmJu?<©\Xxöeú¡>¶<µÂ'ÿLO¿ô?L…qè÷O_©Eܪo¨å˦4x’VO£¾!¡Ã‰Z‚ú4C+t³‡†«^wÙYÕÕãÛÑÍs•ƒ8q¨í•è¿«\ÄùHAVAe&·;N¢ñs^ÒùI4“Kç*«Ù#Ë40ÿéstÏWvÈs�Œs˜é‚É<Ælâ#åŒãLOd@?ÄŽZ™>ôå'”ò¸O*?Uøg¨ðc¢Sžüó¡ -÷¸áta);;ŽÙp¦fÙeNÃlÚѧ&¹{;›é‰€Œ&‹=¨íŒ‹‡&-´®ìJGÉ"H -™Æ‘GGèᡤ‰ÎkE:€•Àî.R`ÝÖ«ÀfÔ#ש²ªÔ|Ö«ò¢ÉØÐÉB–à[ÍmŹ¥ó+wKu0•§‰TדFEhÔnö -ɹÐ:ü(‚øîJ¹Ì¦¢žàùƒ%N§øä²<¥LO»ì”ŸZ¦§_ú¦B7kÝ]$Ÿ=Êœ-÷«,:dc½³Ä]™ »f¦ê:ÒF•iŸ -–šë(³Œ®-¥`’‚= -Î,8²Ô‰¥ ó;¦ßRhùêy·è©jé‡kñhª©ÈŸ’zø<ùpK?ܱã“y™ÜÃäÞ¥dòÐœJw¼Ÿ×R7]H“yÜ}´w¹ã¨;ºËht¥î-šFgÑÎQtî&:w=âšÎD¹‡vΡy†¦ÇCלBOð16ç©åô”2=í²G,QWÊôôKÿÃTøù‰ƒüÄAþr×ç_~…?qŸ8ÈOä/w}þåWØ}ÝWO®{:®ò=30çe+L¨²Ê¥”U]ßaFôÔ•?øg¾â5ÿ¢µš™eB:¬áf6ºÑϾñëå™òE7ˆÛ?¤å&‡žßéWìï/Rëó!âÈÂ\¹ÿüŠv)W|þ#ù3ÝþñºÛ?ÂíŸÜíß²‰ÝŸA“ïÎ ÊîX·wåôqE«9‡!ãçC>—ïF!w Élpñ»†¿<z©^ÆÙ¸1q<F® ²ñäÅñÔųòWMObsj™ýºËæ‚Å~|vc«\CBÂóº´ãr씚v.§ðèIgênÆ“Í|î##K¹*§)i •¼g^˜+.!1/Ú¼Úá£ç\Çþ|¹*5ºtc`m"+iµp‘j9‡¼ªÓðœIxh¸¿¿Î§Ý¯Ïþ"Mùâ}ó™,ð*Œ½7<ã•nÔ`Œ“Ã.7Y.p“×ÀžghUÝûqÚæj¿ÞŠë Ò]{&oÒ§@(Þ'<Õã¾tLŸ0yD‡jÿxâ¾þñ°ç*u€éíxÃù?:Ê/]=~7× gÏ2¾ŽI–tK¸oi^{’×u8M3œ'fÉfHßÎ×S¹æ–ÂõÖâôtÞÒ=¥ñÆ‘*ÞJu¯”g£³êhÁÄ÷æ’ï°ž4Ä ÃU§ìDzóUfDÓ¨ÞhîùBµÇaz†4Ìò–Ýå<¿Ë˜á%Òù>Ó%ïY^Æ</C�ÉôXI;ÃHª|)8íõÕöt8íÙÜþØ\ ûð)ws/’ûæÙR‰ õNáV¹æÃõ£Å?æ¦Ï[gõêB«»ä-šç@³1;\Ô¤*=“þ<ó³ÃW;£AXõ†û†zhH¿Õo–Þ°Ë#x2Opâ:šï7ÙJÑ'<råõìAŽºèŠ~c#ϳå\Ë—®ä˱\9S0sÂC=¬Qw¬Ý%‘PÇïvœFxÍdÇíx”¡ÇªÅ«¦ÏíÏX¯>)~ uO{ZçlÓY\\´ 47§ãCKbÖpÏC†6ž.”ŽAúðŽy3³¼E”gâô fÃ$UÜ3ùã*,p¦}p“IµÊä -þ9ÊŒ+¾“,ÍF¹ÝòHL= òºdõ„Ó588ÄrŸg„_þ>·-§!•cË+ßpñŽßzŒíïÓ.Í@Ƕðõœ>bÌ®[™\Ún¯äËÿ�ß<çœÈbÕ±ÿðÿ:ô?·¦–ìTŠCîÌu—Á¡¿ßcúœE7ܯÁˆÅë°»¯»QèÐ\f’]GÐYNY¢ƒÙ Ö‹½�Пû‰˜Ÿ•XŸ1>‰¸Àyî áYØH˜œDÜÍF8 `2À·è›gÞÑÇzÔêô9gú‰Ä?½Ù'½Ù &f™ú‘ -~˜7*øyžH|7²<ÒÊà(ÍcuùGÏóUErrùájU°\æÈœàkȤû¤k)55ž$¤zWþhUæx³‰ -=¼éVÍ1Ÿg÷*à 6ß/fv?«VûtFâQ´Y¸ -¶†9m9Wm<“û_ù㪠ÿ…*ü,!¹&ã/;»9Ó&!{Oµ$íLÐîÌéÙ,1س&AÖ=òÞ6ÅdJ8¶½m2ýû®éßáä“/íxÏ/ÞVÏU¥’…<íO£:;ˆjÕˆß@5E5¦üð™yO+ÓÇiôÃåß¿BµËi*Þ}üln°´é9é*幄wl‰¬³Â&E>ÙÎhlÝÁ!ÏYÒª–O|±ìln89q—x0¤o¤ÉdiéÔˆ÷š¹DS Í–¶*Ò`G¸'^«–ã¬G,u@íà.9KFv~Ö7ó]]/ëÕ²Lu¹Zò§–éÓoýBêÔèY×<§Ú×ó6=±a±Û@÷TÍ0ð&Ïòéî“2ÿã÷˜äzÒ]@ö'áÝ?éç§ -Ÿpƒ‚1Ëj<‰ ÓpqîÌÓo<õ‚^¤Ä»…ÇÙÎ<È’Ý(×±ò˜X7vM´»3äÅe‘÷³gý¸ˆ4 ‡x{jüžQ<ev<q{»˜ò-#äþ¼úŸJÿ¤C«èxù,¿x…jŠ9Ù9Ð+M2#¸«ZÚMzÐ2|øP“©à‘÷F§…û8$Hr·'IܡΓYº,ŸÞÙ»Ofó>¶ØOßHzÂÌþ3düœÎòn.%=Râõ2=òEøÔ2}ú_¨BÅ:tŸÀèp¿@¸@@8þa<x¼çƹ1îÒâõ$éOɈ·Ï‰ÇÌ_º’Z£_öȯ³@š«‡eÞOEå\`WžVNÓƒ\>®üûW8øþÝ¥â£ÂêÓ#_\?tà2{ú˜EZÑtõ‚|‘]rŸa2\,$_FÇÉÖÐfk'›7nÙgd\\Iqθ=“üƒÝ'ZäÌ«6ù$»ùƒ¼ö‘œ<ïŽU÷•w©øs*¼®",è¦qL*È…²r–Qy„…uí§iDSKí{—f‘ÖÝEåÍ5{20ô‘ZX±D€E½HA…»‰RßÉ’þB3ÅŸeöƒ‰OÏ0ðÁ¼7Ý|Qå?µê©ðwœšÜG‰Ïä<Èwê ÆAx»¥®9,ýÙ#iªðâg¯ŸY ñÔ>øÙ;ñLáÛ+‚ -Jí(Ÿ½¦¹MƒªYÏTͲSR˜ªò™sñóg©ðêÁcÇZ™® u~¦Ó¨Î4-碩M†Ü/8 ¸Í‡Ø --™^²CÁòRÏr�jR=÷"Ž~Äy/öt†<H`k^£}¯3íDZ–”Ÿçê)–ÿÞRñçTøˆîðH1cºPA.••½23è9טú¹VŽ–U¤p?ä™[Ž‘dyÌ{:úNý¬ñÍ<¦ý`¿h‡‹ë~·ÓΔÍ]é÷;Ñ~èù[å…a¯VHÉ¿»TücTøAÝbzä‹Ç˜ûk:O׈¦!/£BÕÕ,Ï Ðu±ln„ÒÓôO¦ÄõãÚ¦è]fìOlï ¿l®sLŽõ»8WObÏ»³qO÷wg¨³" ø0a[8¹·áÆÜÅ ]ÍÕSê ú=”å&¬epÊ}^5tms܈£žCÌ<ŽGxfX5·ã’¶ˆf¾zôå…tXÊ°åþ2Ÿ]“ž~ôQMªå—›²{O®á³œië5gÚºC¦^ŽœïWON»,ç˜sLÎaEþ§!Ëé'ùÿý€Ãýñ]ÄJ矧h0žìx.$@àa«Ûë·pšºx–u:î<îÉÔ³‘:žßð0´vy€Ã6’¶?ÂaiG8ÄéÑSº~;˜§ l†}ÞÖÈÄæXKñS³ò,(2®€Æ‡G3µ~üÍzΖ, ºeN,±ØÕc6ű^‡¥~½Ÿ·Ö®ÂÀןpà?áÀÂQxÞ®4¡^D…'D=ž›Þ4º/l’i;ÍgÛRxûäíÇÝÙ9«~dP?4¨¶CƒòpxQ?0'#ñþ椻YøIwëy g)ì&ÜcßÖÜ*WE¦²~(ríѨ¯œ|°Ã_)ë²K¾6u‡êÝB±îÖSëÖ³µó“.ÞözxÚã“÷qf¹›Âsߧò߬Š§±ô'åÉ??±5ȦDíBæ,„uPæ¼m6ÅͶ¹~~¦èÙ:ù캾t¤Û?üñåûÿùp|õìù¿È²Ø}üsœri6ûÄs@¦‹„³ž®ÚÓÍŽ©fïÚq‚û\ÕžcöÔÕ½¥—}•<=þ˜ÿØññŸÿ? ï‰ÿŸ>=�ÀJKé‰ÏÍ.gV“ó|•Ëê'Ÿ°2©šúÈLñÜ«E©“¥ç'v¸ç(Ñwc€¿÷vàéòœŸå'6«á‡,†O‹·¸<láS#.ö©úaç)$î®$)xÒTø„“kæ/uvÍte"ìBuèÿ'Âx&©Oƒ!Yõ‡¦Â%¬Þ§«63òT?/Àå|RÜMŸâ2L‘a¢L˱OGñå¤g“¡ÿ|^óL];»ì¹Ût…¹]Ñ/®fÞ綀¢é3#ŠŠÆõ¢éÓcŠÌ³pTãÍén™dmìÓŽÜ_I<òc]ô)¦º«‡Mc¬kX>Gòyⶻžºm2³³·µämwOJ߶OÞfÑHÓç…#iT¯¡V4}z@«À3dCª¤*Ëéá,=L¹’A槩ðÓTøi*ü4KõI•.òC}ü½?–ÉI_ÿíÛ7¿y÷òÍû—oþðÕWƒ®=~1ýí·ø&é7¿yöþý‹woD ¿}õ§ï¾{&ê·ýqض›-§žÓ%çtˆËr#Û¸üòÌ¥Ì7½åÿÿøoòë{þé>Çü?þ7ùóñߤñ‡¿9üÏÿ5¾Ñ[~+¿ü^åáµ/tøõHõ÷ùõpÿ5Úîî7òï·ïÞß½|þþåÛ7ÏÞýéðKš,~q|ûö•´þWÖ_ßóòýÛw_Ÿ=ÿé¯ÿòÕ‹¯ûâùûŸþ³ÜðÊ?kêúžÜ±5ÇéqT Ú C\91™Õ’þÙªÕÏ -\¶:§íðÏXÑ®ãR7sÊ2îõ&‰d¯#M‹"pÖí&‹Hu#U‡µà°Vis•ËkL‡u½ ²¶Ïq[]odñÖÃo2B@Eò¿YdU–íF„~œ›o‚,ÀÃ’ndE»m»™…+’|YXyѧÅz³Fôë|³n›LÑr“`|åme¹D®ÊÌ•§eyʼäCŠúN ¤µn‡$ÍéVobµd˜k±Ïåò&üã¢DE’á\1UkZžo ”–|ƒ³Qº&ÈZ<,á&‰~shW¤õfñ›Âª¹½vÌ+r¥iÊ4$'Ëùf Ûr«©‚Þ•o¶òuãIRW]pîšnŒ “ñ›¤5첯°(tuª7óZÃa‘>ö'ẏ@v²ê}Òç€xB±f,ÂR6¼³Œ8:W>/‡Åxo6` 3_úSšÊÑD-\òÌ5K;Ӣ㵬7ò¦6^)ÜÈß2‡²ôkvÉíUÔ‰C^dÜVyäå!Ro–‡ÉÐêm2å‚tÜ¡dDkWv¢pç·ÉŽ$Y”i RO–YJ›T²J2êBÔï!ÍÒ Mƽ.2Î2L2ñ9ƒeJ -¿×“׺ɳô¹Ì@8™d*áaÒ²*w¯2§’Ì6NéuÖñ6`Ql"#¯‹t@BïɳäÝç5ÅÃÅ*Ã]ÿÌ}Ç!¯Le‡ë¹N^D™XÈGÈÙ²!èZ¦ZÙsû¬“G^K¶ê~¬Qê†JŒàòÙD™»[ÆUVÌ56¬=Ë m¦â…úUÞŽVÏYüÝ) #dXJ’5/óêõŽ¸è¼J2+e?Þ@íU8„°ÚUF±tÐd–YýªEŸÚëq‚=Mosb¼UÕnýáiFÐÛüÚUþÖž³¶y£ÿÓßËÿä âWß}ý7ÏdO=½ýöO_¿ýgnýîí÷ßêqýŽß¾øöų÷/¾ùZ±ÛI¶ÃÏ~~øǸ²§ÈÄXóLL‘ð•Ï¹éì&ŠJ\Çݤè¹Üº›,õ¦l«lŒX0‹ÎÜNDn¸Je‚ˆÞ/SY&J+½¬W !®{ì¢ l%‚(“Eo“Õˆ¨ƒCYµòFØì -ÞæÄ0ov_Ä.-;sÙ(ÂûrÜ -ï\lï×ÉÄÕëæª/Ö([ÕMž7:Q˜çykqÃÛݲ_ïaA©QºU¸ÊëQäp¬ ìp¡×9VÀV#£bµÈ_œû%èÂ$»R«£ìI£I2˜Oòjf]¦íQs_¶ýuÚEþš³fí&þnÊ¥4×HµYö:‡æµ„l™Žgæô¬êg—?¶EvlpQöNöèºÀ»*«ÄÊèn "V¿³|»®Â1¥°]ϲ×È~€wƒñÊY¸s–•ÌÜ*ûÆf·-²µVÙüd%o²ù6ÙD’ÐÛ°Hã6aÂøÜ×d÷ÙDèíB>"ÆȲmѶ#!–µê>"\ç!ۈƄÞa¹¼Š¸!\cN‹Ý&ÄEZt=¶O>,Wd$¢óþ8ÛY°8°·Ês×YžÿzGD{±K;×%qaÖDáq]nŸŸ{—û5²Ç#GI¯Ä ö(½Ë‰2¢ýZ5]»äþ,'èmöBý*åVÏYÃvs-n¿ýlÖ =Ê– ÁCö~]¤¸Ê(Éàʛ߄*sE†bƒ—ˆ¢ZAy”HÆ2†«¤³HF½'ØÓô6'–(à‡^ˆÌ«šô6§v•¿u«ç¬m÷T·bï}öZ 2UVÈ»˜2ÂÙаéf‘7ƒ°r^ùj¡D¬Ta32DXº†Î™d`´ÂxWÌr‘|o"Ö“Lÿ<ËÂ.äYÎý"Y5äÛ)9¿7‚h,w7¢/9Ëê,ÉÍ»M¤¡Z°)Ûuö 7™³¼†µ‹U¸ë¬*ÐvJ”é»ø*1Œ Üu6ŒX*Ü!Ô¾‰XÙ)¼SvØÊð÷ëä˺,Üò¨¾Ñ¶°ÚN%í•øþX³k€NáÅÇû$Þ)+.qË™!ßÈØÞ¤»ÌÆYö UßGCé=g#a¬œ~TÈäƒÜP¯+XÕ³õļõ“£q3ÐW�ÏP +¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäüå„æ æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ�÷„óû endstream endobj 252 0 obj <</LastModified(D:20151115140912-02'00')/Private 261 0 R>> endobj 261 0 obj <</AIMetaData 262 0 R/AIPrivateData1 263 0 R/AIPrivateData2 264 0 R/AIPrivateData3 265 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 3/RoundtripStreamType 1/RoundtripVersion 16>> endobj 262 0 obj <</Length 941>>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 16.0 %%AI8_CreatorVersion: 16.0.0 %%For: (Rodrigo Nascimento) () %%Title: (icon.ai) %%CreationDate: 15/11/15 14:09 %%Canvassize: 16383 %%BoundingBox: -69 -576 571 64 %%HiResBoundingBox: -69 -576 571 64 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 12.0 %AI12_BuildNumber: 682 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: -69 -576 571 64 %AI3_TemplateBox: 256.5 -256.5 256.5 -256.5 %AI3_TileBox: -28.5 -636 530.5 147 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 2 %AI9_OpenToView: -297 16 1.34 1444 866 18 0 0 0 38 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 77 %%PageOrigin:-144 -556 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 263 0 obj <</Length 7015>>stream +%%BoundingBox: -69 -576 571 64 %%HiResBoundingBox: -69 -576 571 64 %AI7_Thumbnail: 128 128 8 %%BeginData: 6884 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDC2FFA1C39A9A939A9393939A939A9AC3A8FD6EFFA1BCFD %1193C3A1FD68FFA19A939368FD11938C9393C3A8FD64FF9AFD19938D939A %CAFD63FF9A936F9393936F9393936F9393936F9393936F9393936F939393 %6F938D9AA8FD62FF9AFD0493949393939493939394939393949393939493 %9393949393939AC3FD62FF9AFD1B938D939AFD62FF9AFD1E93CAFD61FFFD %04936F9393936F9393936F9393936F9393936F9393936F9393936F9393CA %FFFFCACAA1C4A1A19AC39A9A9AC39AA19AC3A1CAA8FD4CFF939393949393 %93949393939493939394939393949393939493939394939393C39494FD11 %9394939A9AC3C3FD47FFC38DFD1D9368FD1793689393949AC3CAFD43FFBD %FD3A938D939AC3CAFD40FFA89393936F9393936F9393936F9393936F9393 %936F9393936F9393936F9393936F9393936F9393936F9393936F9393936F %9393936F9393936F9393936F93689393C3CAFD3EFFA19393949393939493 %9393949393939493939394939393949393939493939394FD139394939393 %9493939394FD05939A9AFD3EFFFD1C938CFD0493FD049AA19AC39AA19AC3 %9A9A9394939368FD1093C3CAFD3BFFC3FD19939A9AC3A1CACAFD11FFCACA %9ABC93938CFD0B938D939AFD3AFFA89393936F9393936F9393936F939393 %6F9393936893939AA1CACAFD1BFFA8C39A938C93699393936F9393936F93 %93C3FD39FF93939394939393949393939493939394939393C3CAFD24FFCA %9A9A939393949393939493938DBCCAFD37FFC38DFD0D93699AA1FD29FFCA %CA9A9368FD07936893A1FD36FF9AFD0B938D939ACAFD2EFFCAC3FD0A939A %FD35FFA1689393936F9393936F938D9AA8FD32FFCA9A938D936F9393936F %9393CAFD33FF9AFD049394FD04939ACAFD36FFCA9AFD059394939393FD32 %FFA8FD07938D93A1FD3AFFC3FD0993CAFD2FFFCA94FD06938CBCCAFD3DFF %FD0993FD2EFFCA93689393936F938CA1FD40FF9A9393936FFD0493FD2DFF %BC939AFD0593C3FD42FFA193939AFD04939AFD2BFFC38CFD059368C3FD44 %FFA1FD0793A1FD29FFCAFD0793C4FD46FFA1FD0793CAFD28FF9A936F9393 %9368C3FD48FF9A936F939393689AFD27FFCA939394939393C3FD4AFF9AFD %04939493CAFD26FF9AFD0693CAFD4BFFFD06939AFD25FFCAFD0693C3FD4C %FFCA8DFD0593CAFD24FF9A936FFD0493FD4EFF9A6893939368C3FD24FF9A %9394939393CAFD4EFFA1FD0693FD23FFCAFD05939AFD50FFFD0693A8FD22 %FF9AFD0593A1FD13FFA1C3A1CAFD0FFFCAA1C3A1FD0FFFA1C3A1CAFD13FF %C38C9393938CC3FD22FF9A6893939368CAFD11FFC493936893689AA8FD0B %FFA1936893689393CAFD0BFFCA939368938C93A1FD11FFA1936F9393939A %FD22FFFD05939AFD11FFCAFD0593949393CAFD09FFCA939394FD0593CAFD %09FFCA93939394FD0493CAFD11FFFD0593BCFD21FFCAFD0693FD11FFFD08 %938D9AFD08FFCA9AFD0993FD09FFFD0893699ACAFD10FF9A8DFD0493FD22 %FFFD0593C3FD10FFA1FD0A93CAFD07FFCA8DFD0993CAFD07FFCAFD09938D %CAFD10FF9AFD0593CAFD20FFA19393936F939AFD10FFA1689393936F9393 %936F93A1FD07FF9B936F9393936F93939368C3FD07FFC368936F9393936F %9393939AFD10FF9A8C936F9393CAFD20FFCA9393939493C3FD10FF9AFD04 %93949393939493C3FD07FFC38D9493939394FD0493A1FD07FFA193939493 %93939493938DC3FD10FF9A9393949393CAFD20FFA8FD05939AFD10FFC368 %FD0993A8FD07FFA1FD099368CAFD07FFCA8DFD0993A1FD10FFA18DFD0493 %FD22FFFD0593BCFD11FFFD0A93FD09FFFD09939AFD09FF9AFD0993FD11FF %9AFD04939AFD22FF9369FD0493FD11FFA193689393936F9393CAFD09FFCA %8C936F9393936893A1FD09FFA1938C936F93939368CAFD10FFA89369FD04 %93FD22FF9AFD0593CAFD11FFA19A93938D9393CAFD0BFFCAFD0593BCCAFD %0BFFCA9AFD0593CAFD11FFCAFD0593C3FD22FFA16893939368C3FD12FFCA %CAA1C3A1FD0FFFA1C3A1CACAFD0EFFCAA1C3A1FD13FF9AFD0593A1FD22FF %CAFD0693FD4FFFA89AFD0593CAFD23FF93936F939393A1FD4DFFAFA16893 %9393689AFD24FFC39394939393BCFD4EFF9AFD0593A1FD24FFA8FD059368 %CAFD4CFFA1FD0693CAFD25FF9AFD0693FD4BFFA89AFD0593C3FD26FFCA8C %936F9393939AFD49FFA89A689393936F93A8FD27FFC3939AFD0493A1FD47 %FFA8A19394FD04939AFD28FFCAFD0793A1FD44FFA8A8A1FD0793FD2AFFA1 %FD0793A1FD41FFA8A8A8A1FD0793CAFD2BFF9A936F9393936993A1FD3FFF %A8A884A193936F93939368C3FD2DFF94FD04939A93939BFD3DFFA8A8A8C3 %9393939493938DBCFD2FFFFD0893A8FD39FFA8A884AFA19A8CFD05938D9A %CAFD30FFFD0793FD39FFFD04A8A194FD06938D9AFD32FFA1689393936993 %A8FD33FFFD08A89393699393936F93689AA8FD32FF9BFD0693FD31FFA8FF %FD05A8AFA8C393939394FD0593BCFD34FFA168FD0593CAFD11FFA8FD19FF %A8FFFD04A87DFD05A89A938CFD079368C3FD35FF9AFD0693FD11FFFD05A8 %FFA8FFA8FFA8FD07FFA8FFFFFFA8FFFD0CA8A19AFD0B93CAFD35FFA89A93 %936F938C9AFD0FFFA87DA8A8A87DA8A8A87DA8A8A87DFD07A87DA8A8A87D %A8A8A884FD05A8A19A93938D936F9393936F9393939AFD37FFCA93939394 %9393A1FD0FFFA8AFA8A8A8FFA8A8A8AFFD0FA8AFA8AFA8FFA8A8A1C3FD07 %9394FD05939AA1FD38FF9AFD0693CAFD0CFFFD05A89A939A9AA1A1A8A1FD %04A8AFA8A8A8AFFD06A8A1A8A1A19A9493938CFD0C93C3CAFD38FFCAFD06 %93BCFD0CFFA8A8A8AFA89AFD0593949394939B9AA19AA19AA19AA19AA19A %9AFD12938D9AA1FD3BFFC368936F939393A1FD0AFFA87DFD04A89A8C936F %9393936F93939368938C9368938C9368938C93689393936F9393936F9393 %936F939393689393C3A8FD3CFF93939394939393FD09FFFD05A8AFA8BC93 %939394939393949393939493939394939393949393939493939394939393 %94FD0793C3CAFD3EFFFD06938CC3FD06FFFD07A8AFA1938CFD21938C9393 %9AA1FD40FFA1FD06939AFD04FFA8FFFD08A8A1FD1F938C9393949AC3CAFD %42FFA19393936F939393A1A8A8A87DFD09A89A93699393936F938D939A9A %93936F938D93689368936893689368FD04939A9AA1A1CACAFD44FFCA9A93 %9393949393A1AFFD09A8AFA8C39393939493939394939ACAFFFFFFCAFFCA %CAA1C3A1C3A1C4A1C3A1CAC3CACAFD4AFFCA9A68FD05939AFD0BA8A19A8C %FD0793689ACAFD5EFFCABCFD06939AAFFD05A8AFA8A8A8A1FD0B93C3FD5F %FFCA9A689393936F9393A1A1A8A1A8A1A8A19A93938C936F9393936FFD04 %93CAFD5FFFCA9A939A9393939493939394939A939AFD079394FD0693A1FD %61FFC38CFD1A93C3CAFD63FFCA9A938DFD1493BCA1FD68FFCAC39A9A9393 %68938C9368938D9368938C93939AA1CAFD6FFFA1C4A1C39ABC9ABC9AC3A1 %CACAFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFD0BFFFF %%EndData endstream endobj 264 0 obj <</Length 65536>>stream +%AI12_CompressedDataxœì½éŽ$É‘&øö¾? SASSÓøƒÂãàp†ÝMT±EcPÈÎÊ&s:BVVs¹O¿ò}"¢ªæîyIlW(2#\\MÍLQ9>ý›ÿã·_}qýÍÛ}ñE¼šÓßüÍÍ»ÏÞ¿}÷Ë©‡_¿zõýwïßô³/~ùj–J׿®_[Å|ñî»—oßü’_ñË{\ý³/ß~óîåïßþîÙwÏ_¾~ñæýÛŸ~ösùúw/ß¿z!^>ûæêÙËŸû=¥‘Ûgïå›~Â/B:„õ—󆯟½ùgß}÷òÿÅ—9Ö(´ãÛïß|óòÍïoÿŸ_¾ÈÛá‹Tò!•pÈ«|ýß_~ù⻨sûöù÷x°ß¾{ûüÅwßݼ}õöÝw¿<ÜüéÙ›Ãß>û½|óìð¿xõêíÇWÏžÿû$¯¾¾ùê…¼áëgïaÁû^ÿ:,_¿ù꛿ûþõ¿¾wÏu9~Í&ÿá;iKšÅß —¯ýZ(_½xÿ^žMnˆ>ûòWÇñ1„Èò³ùòÅï_²ÿ¥{þ×ÏÙwo¿}ýìÝ¿wáðýï^¼þö•t%ß{Iù*¾Ð_ã«+¯£ý³T|•£´ç+ô~Ñ*½Ÿ^üÇËüåáïÞ¾y¡qýîýW:,ë:Ïú¿~óå÷¯^¼û‡7/ßËCf6í¿}ûÍ‹WR¿]ÿê;%ôÿµÂïž½ûý‹÷2–o_}ÿžÓ¬ú¤·óìO/0d‹Þàï¿}ñæwoÿ‘ÏøŲ™,‡pW<×z¨Y>U»Q¬íŽ¡ÿ¯ £4â釿ùÙßË„~ùæ—_HsÒé)ëhþêÝËoú`–åPõ?¾ÅUþmþOWÞüýûo¬3dÝüí0)æ«¿ýJî{÷æ››·¯ÑýßaÖËlx#åÕÛßëwío~#—ÿ¾?-#õÛw/ß ÍéïøMýú·¯¾—¯~õîí÷ßþúÍ¿½~¦]žæÝ‹ƒ~)+•ý·,ÓoþèÕ·/þMÖD¿\©woþãÅ«·ßÍ6ʳ7ßþéÙ»o¸éß¾zöæÙ»éåß¼üù晼Zo»ÓžÐ¨Œì·/ž¿ç%¬rrƒG*_ýðþQ*¾}'kä›Ãßÿëÿ–Ò�×ÿáwïž=—qiw8íÕ³oèùŸ½ÿƒp¥o¾ù®5 ÷ý¡´~̯žc.¾;ß}ÿÝ¿{ûöUkvÿUkÝȤ¢þ_Ç=~ËÞüýí ó;Y…Ó; #ú«»‹Ô~øòå_së7Ï^½zùûwϾýÃËç—npáûv'ýîC&ÖŸ^ÿëÛW/¿{ÝçÓ@ùí³wï_>õâ«?}÷þÅë'îáî›—²àÖùêÏÞ?ÿÃo^þë»gï^¾xtõa�þíå›odîõýË÷/z½}ý-Ä—ÃWxöí¾Æû?ܳæWÁôµl#“ÿâ‹G¸¿l~Ç7Ã÷¿z÷ì›—²±ˆ,ö«·¯¾yñæð%øÑ´û$ÛX9¿™þeš–õð7_ßMÿmšOÂIY†¬VÿyÉø7ɯ±”Vê¼íÊõPŽRn¬Üån¾Ÿæ{/»–¡Ä¡¬»’´LüUB–Rø»eÛ•ëpl妕c¸•âŸn'ùpGÒm¸ËØu|8ÿ‰CY‡’–Œ2鯥¥.›ýÿz(G-Óÿui,͸ÏuÕ>¶R¦6¼ë0È:ªãèV)øQ»ñ݆–ÿ'jìcfýQ¾G[þןùâX/Ón £Œ+~cd1Æ™¥r”ËÉ_[ÙŒ%~ݱܞŒ¢ß4rû˜¡è ùm6X2@“ÆêÆÊ-Ë•{_Yx™q,GiµŽ¯ìÐ#É=ûfáËg¾ÞÆW¹å{ÂÌ)#0ñ¾¸Ïc\cŽE4±-¥ÜÆ{í°F‘³ÓZÖºnëõz\o×»õ^:rI1)§’¶tŽé&Ý¥ûI(È,]sÊ9×¼åë|Ì7ù6ßË\Ò kͦԲ•c¹)·å^æI¨K]kª¹–ºÕëz¬·õ®ÞË|Y¦-në&íluÛ¶ãv³Ým÷2iÂu¼^¯Óu¾®×ÛõõõQÊÍõíõgÒ"/°Ó±ëq“¯ŽÇ›ãÝñ^fW˜ØÛñf½I7ò�7ÛÍõÍñæææöæ^&[à(¬·é6ßÊÃÝÖÛíöx{s{w{7˸Ļõ.ß•»z·Ýɽînîn§»»»{̈{é°ût/oz/Ï~-Eny/WÞŸüÈXÎ2šíóÝPn‡r3”ã®\eó2Éu(e(yWÒPÖ¡Ä¡Èœî—VFÖ™ï<>úÝøs»+7Z&þ:åz(Û®Ô¡”¡ä¡¤é.µ²îJÊ2”0”y,Úå“õýøôãÏÍPŽZ¸2w㸽ý˜ùhí‡h?,2Ó0û!Øwü¾»›Oú–ý9µ.Ýwä¾÷ö=vÒOû®™NzD{ãÚÊÆR+™%YYY¢•eâÚ³-SY›þþfz/ÿ9²\[ÙXªYÛ“ü—$++K´¢¬×½pPË;Žß‘ãU9>‰‚A˜Ùí·ìæköja?®ì·À~ºcÇÙuâ›'¾+^pæÝò®ùÈ…O¸ò‰ä9d¶ÜIgÞߺþU…eáf«pµE¸ù<ÉDº“^¾¦w-ì¯^a„Ib”%È{/#~+ÝqÜ®…mÖMÂH£lAAöã{™·ÒMGá¶[“0Þ,xQXqû^fÈôá±\«®¥ÓN¼£°ð ý½Ì[éØ£0øM}vŸ„íGaþ!Ï“Lã;ãÙ®eƒ¨²Mä”dȲq‘îeºÝÊXeSÙds)k–mf•íf‘Mg–y'³âF6¢kÙê$;SŽIö¨({UYå^fèvQl«Øh“ln؈Ã2pÙ&ÐZ-ÔóZ¬'J7uÈoØù7J*)ˆìÀùðÀíØðËûÅ;–ÎîV¯,a“I•dB™L—¦Òb{wüè¸.±%®^߉l/ÂV$»¼7ö»¶Ùe™eõÂvÛv‡Íî7äÅMbˆ&ƒ—(4ÜQl&8¤&:\ÝŽ^€œ6ßk“òÂÜ-?bµèZñ ±í¢üžoηÖa¸¦Trw#K‘04¡G%<|T’»¡ ~'M²õu\j6)™j›ò†z3l„½¡_ì }äq tvÂ%…(#_d9N¤ïŠd€sœ‘çô©ÒùÎÈyÈ{´‹/°£=7ú!^¤]²?y1›øë¥+2u§âS{´¤fdÚÒdø +ä;u¯‚ùÓ´&鳧bwC Ú•üÞNJ=)]‰Ô¿òäjf+ëY‰ge¹PìgÚiºg +VÜ(¤µß·‹ð‰©iÚ7¦ŒU;»X¶Ku½o”|-ù‰¥«”i,Óþc36ô¿ÏK| pRLóòÄr©ƒ/”鉟üsIwÿ¤ŸÏÖ ï‹¡õ¨Ê¨.fßZQ Ën¤¨¦»ÃVúdj³/o7‹ô麚]BõÕ;.Ø£®cWéÏWki&€l%5A· ÅqN?¼2å¯f–èæ©“åèòvŒZ£‘ëxq9w¦±óiÆ”ÓõYwV¶nqÍ¥%Ú>Og+ótž/ÊGËtf0¼´R[¿'ËslŸ¼†[Çùe÷Ù¼$¢ŽÚϹþ£òȹþãRÈúŽÒÆfš_6yciÚÏý q”ıÐè@Ô€&Q © +%h¦¤:Ð ?ªÕ¦EÓƒ ݈t¤TiJZ'ªB‹ãžZñ-î ×WÑ„T‚6´¨6D}èÖô¡#õ¡J}8W˜L)º§†µH#¨F•ª”£•ÊQàRº§†tC :´¤"wEUQ„&Q”"Ùa iæŽêÒ¨KP˜ 2Ai‚ÚTÖDÅ ªS$§š©>Ý›b}Ô2‰ÜÉ ²[¡ü–Q?â'P~ê\2ŽE—ÒT2«T PÖ©qê3©k±Ü’ª¿G<ŠH”‡¦AÚ1Õ3ƹ“\v<rǧL‚rÂÛ.²µG$ˆs‰áilâAöñ9×±i‹ZF3Õø³7Ë ¦Æ½-Ì÷ÕÉþXv%îÊÞì–NJÞ•2íLyegä«T”öåú¤OËÔl^^nÏÊùÏýyñ96;õ}¸P–‹%^,fÉ;/é’,Í–;í»…ææÇÊöåzÚ™“/—ã™û´³\?VnŸV¦ÄKƒøä2=øÕGþœo¢Ûnæ¦~.æ±Ð²ZQs¦›7‹·~nVÌ6:™©Ôœ7ôeããáœÕUd—äÝJ«6Ûu¢ÑHKnÅͼµ•ÍÊu+Ç<J~¦3u‰5uÓýen4ð¡é&ô÷yˆëœæHÎüæ³c*ÆX¦GyÊNòC,dzœo<eœ°†iä͆õþcx"8_ù¯ãÇËŸi ugE‘íFtÂBΊë:‰¤—_ìQ8úcgóÈÂ'›è•"Pºgö¾YÙ\Ô9)ŠÂA[&ʧŸöŽžZõÕFH—ô×â>Ûk +ÀðÛb©ïÞ[–ôàNtâVHÚtä…Ý6wî,â$IøtWy<HÈ…bù&"ú5ý»7Â/îÌË;_‡Iäø…ò<ܽpøæëBI¿týJÁt„ h`ŒtüÐ\§ãFŸ°z…oÈ‹°´ïéžËufëlÖÙkg«ÆQ§ÆJ;uÖÙ™fç•GvÞ8rÄÛ©ñÁ‘ÿu¾·çu#‹ÙÚÀ̦íY× ³º ùœó£A¦¹,·<ÄeNÄŽ±LqdOÜà?v›áú_¦yÀ‡Ã"åC¯VY.‡¯d,¨úÕô7_?¥êñ»ó¯’TLó¡†+ÑóƒÍÖC[W!—m òe€v»8Z9Õº¬òGI‹}½„”·*h#ËUœÓÚnöÉ ñifÑLS–Z³,òŒëD¹å›mmkš7b¨…)®IþXð;mÅ«YØJ¨ÏÔž>[ž…¡¢æTx]F¬m‰ŠXµýE8*Ú’qKÛ®4ÏÛðlŸ§½Å¥\Õ7´TSÙ>q(O[»0SíÉ·íJøùCÓt_IZ9Þ6ˆ£#/ƒÿþÝó?¼üæç“ÿ!. ²x•s}ã—R2Œ²¸Ø½ø#¿[¶vÅÁ¯Ð€»â`WØ2•e}x¥¸X;ì©¢›Ö|#¦÷GÜxý‡tóWÿþ'écü/®ÚÁÿÍ÷Ÿ{ÛuÛo’ù3‹í.׶¡ÜŽŽgÛ,VÃBÉn@IHö‚`8¯•"^GŠ÷´ +©H)\S¸ã. ö}Ýó¯ií»=6*ˆÑ=BjßV39öâÙ� êÒu'½Â —ÂJ^úy ;¯“eh%Tä± =qj(,†¢P…!)h*¼30ÅMR·îãðò$lÈè›m‚P0èÀèð•vÁÚ¤›Ía·:Nc Iéµ:Š2«b+åTȧN“ôDÒ™l3ÅÐd€ÁÛ¢þqt«á.:òbÜ0Ûáܼž7´ª9°˜Ùo5A0Cø“3OBË( ›¿Õá¾(¶É0M· Çtmè%7‡'ƒ))<i¦Pt·ó¢@ÑUó©úÃcÓ*5‹Lí¢Pè´_SÏ8Ò°p;Q¬¼§ÂÑUEbÜTïPÍ£ëÔ>ªˆPèÐ@òD%¤R q5äv§Šœ(#¦‹`è5J}Ä5’éD%ÁœØHzC©ú®ÁI*$*5’j$wH'SHâ SFŽTFn©Œ(à´ë!ë ‡@iZÈDGWCΑdŠU‘¦‡©‹PQ>d€;Ã? Ez +Ïÿ¾kï©f5ŸF-Ìy×½’þ×ø»¬GP½ä bš…>6„}ÿw¿Wc¿ÇN w¯ÆáŠÓyïøûbÿ«×@ÿWgnÿÿzçc¸5¨¶áï ü£xÀjw¤v4F6¬v6_´z::¨ž~iÀg÷%×—Z$ æt™qÆ8#«ÿñ=fôœúò.˜·rt1„æ–çÑsŸêê^ŽSGìù§ñ÷éß#-yÄ@ YÄn<Œìˆ»¿ã4|XO\6£#ç²Ïºß<ØÓ™¯Gû®»”{¯öîƒÐ=0;dêñ2µ(µÃQˆjTåôÜáeŸÈ®¹ÑëV_hÌHä'Ѷ|Ýô÷.Ñëæ-dVæ(tßè-N·=Ýø|ëk›_Ûþ|$f”› lƒ“íƒãN8î…#vtÝãG‚tRÁÇ<¤§Ò‡P¤àH§ºöQൠ\ù->”ŒwË·Ù§†“>GJ—fTߣ¥¼´•.=!¦owˆé‡ge5ÿAÞÏÍi@KXé¹MÔ{³+é›iûÇ6guÖnÜë8w'›¾™[aŸÄÑ ÊËÕ•ëúκëfðõëä–2Ù/6Ë3•Š(ÊzÉÁu£P¿°Nû;N}N~Å@\rÒ†Dœ–ËžÀåÔ¸4q1xbç?¤˜Î£)Nàþ—ƒ*Î+,`º]QN<¶ùÄŸûpEœŒ³¬œ‡Ö¬œéââ9Τ¾~Æ54¬¤õîj!3&*ÎßaõFQ¡SÏA˜U¢mD´èš¡^§m ©ìÌR»›ø>W{´úÔœ·@í~AØ3ÈÇf©QW·å+‘Ÿjšn÷/kÖÛT,ÂúíÚŠÈýxCü…W«ðÌá%R–KC7T~rCj«sŒìÇ·J£Ÿì³5öô×ø¦½kÍlW)Í£åÓ[ú sÊ÷¯_¿x‹ŠþA#˜YÉϲQªÃ(Kƒì9ÖïØ‚`ï\tW0$Z¯S“¡K“”{$£‡¢Ž¢p;¥º7 Q‹µ¡4{@©":ßù°Î™¨uRžIXUÎmˆ¶•Ý¹æ)º'ÑK�e;Ô>±¡SOœx*„?©"êÊèÑ÷GãMî¡Pao1ܵ)ÃÉZMi¢¶J(íÕTV-¶KyðPj›qó,;ˆ¨aH§V¤VúOi¥¶rÝʱ—)ߥ{Û÷.—Æv%…}7•µ•´+ç?õ¤lÊõT®ÏÊÍåö‘ÒÜFÓeŸ5•û-œÈS]>G9ÁíQ¸¥Åáû* ûx’ÊEyìÑÄXŠ“©£»˜.³ûA¿ì®áÍâ`nKÍêëö™ÉÖÄ ½ƒsÖM®[in»¶é|G[&p¤Ù1ÙÜ„%æÈ™x‹èná…󨻄¯é¶ñ#V2Pˆ´¹í¥ÒØÛÚ]f³»$Z]Ô¼5ðYÁ� +qÝêqokvú~§pÿvð6Ø\nƒçá›ïw:qþfÊÆaãN`•x;”¦Ch:x†c58ó*³eváÓ01ªìA0.–b]Î1.çxº›éªå"še”[ÏQ-½L$㋹'�äÖËHº‡PtjêaŒÙõh]ÒõøÜ›ëÏÐ¥~é¡"ú>ú¶Ç1»dÝ¥èhÛäA ¾UPÔ>°¶‹¹çá´]5<QG}pº ^6Qœ©‚'z i‚ÓUp¯îÕÁ½BXÍZÚf—¦¦vÕЕå¥Ý˜ñ~PïšbТ‚'¿ñuÿÙZ©ô½«o镵—ÉôÊ®].ƒŽF]sÐ8{51Žç4è07»r<+×'åÒOÈN÷åâÎMSÏÃ¥‰ASÿó¤¬\¸ƒM[üåãµ×fˆät#y³½”ÜÇm‘Û望šÁn4ÖÝÙ4톺™N}uÍ[çþºkßb㣺œÄ2Ü4OÕvѻάuwåvâŠ?rúoæÀ*NÝu©†»î¼Ü»/{¤C¡l›&wP/æ²y¸#¿Ú>lJJ3ð%Ï[Äkí}÷¶ÉÝÒîwcœb‰Ð ‡<4Bƒ#T bjQ÷¦(÷T&w¤µðÚ,†81†NdÓ$LI‰q¢îã!©áBlÜCÑqg±ˆÝ&S¿¶A�}((¶—õR€¬‡ÉžÿœÇ±=>u?‘î>¦<†°"¥î@—¿7ÀEš«(wÄ܈@»`"Áöº¢ÙNpqõ‡XþáÍ›g¯_|sø½‘áçÓ%bǺ\Èø“š®1dý Çkøû½G¯OC=… îƒø÷àSõ«ÿ÷z‡9µbj€ÓmïÞê&ŽõLIò÷ ûþø§/pœô ÌhñÔl i§þ>Oà£=pÏ0öö®¿'ëð°{ÜQ³{(yÂeàoœz÷÷ÄA?J‚’Ï”žäú~êéI~ÔŒ*?=°>ð`ãŽkI3Ò.EÎÐÅÍ°WjxºðÇE†øšî¨™xIiMïhŸÆAçù"²4v\t1pÖó á ‘Øƒë&°ÑÒy'TÍ.•KR!Lš +ízj¦…ì¯ÐVx;$?s“ê{ê³b0z‚è25¸Êªb@•p>™Ídœ-'wÛýÔÌ' +\YL_YÍâPúlJ«A]·ðSŸ&³µ(ÖþÖ€.cé!»õž+q_¦¦Õõ/–õ’öe:!ä'•òp™üª~\™> òåï¼LO«öôòSƒ*4)Á¥°Ü¸ˆÊ^%²Ëµ¸]T¸é«1·Y5^OšË¨ÉWØÞÇ슑Ûlð9‹ái ¹˜k¡;SÃÊyäÎ>n§±€äÎ"w(—›±VøÏd3ñƪwÄ1[O0õÄ¡s©ÅóxqÛƒþ\OÆY¼_»ÃÝ0Ò£Dº!%œ–iÌ´³ÊÄ·;/é¬Nƒíç´\ðq<PºM©Nã‡'•3ϾL?TáCËS|òÏôôªÿi|ˆƒ@§¸3xz¢q¾¡–k,›ÒàIZÁ?LE› ”Ðcº´ÐÍî®:í²³ª«Ç!·£›ç"qâPÛѹˆó‘‚¬‚ÊL®wœD ⧼¤ó“ÅL.«$³G–i`,þÓç螯ì!§�ç0Ó“yˆÙ,”Ž3=‘ý;jezìË(ò¸*?5øghðC¢SžüóXƒ{Üp<3‹”Çl8S³Šì2'Ža6´Û¨Ä¥"wog3=¢‚Ñd±•ëv§û&´®ì{JGÑ"H +™d|¢%1ÑyH°Ø½ÕE +¬@¤Û:ØlF=bp*«ŠÍg”MƆn,d ¾ÕÙÜÖZ|‘ûX:¿r·T³Qyš¨Au=iT„Fíf¯œ +Ã"ˆo/”ól*ê ž-Ët³<¹¬O)ÓÓªÝ䧖ééUÿÓ4èfÛ³ä³G™³å.É¢C6Ö[KÜ•™°kfª®#mT™ö©`©¹Ž2ËèÚ‚Q +&)Ø£àÌ‚#KX +2¿eú-…–'Ï»EOUK?\‹GSM Dþ”Ôçɇ[ú᎟ÌËä&÷.Eƒ‡æTº€ä×CvîF¢i2’»ö®#wu§Qw£Ø½EÓè,Ú9ŠNÝD§N¢üCÓ‰ƒè!÷ÐÎ9ô˜ghzÈ1tÉ)ô?csžZnžR¦§U{Àu¡LO¯úŸ¦ÁŸ8ÈOä'ò×»>ÿúü‰ƒüÄA~â ½ëó¯¿Áîë¾xrÝÓ‰p•—ea£ëzÝ +ª$™c ”’ÔõfDO]øƒæ^óÏÚª9БY&ÄC +W³ð°Ñ~ò×—{Ê9\!nÿ׫z~§Gjì¯/ÒjZòa™¯"ŽÞ=¿þ´F»¾”>ÿ‘ü‰nÿå²ÛÛ?ºÛ¿e»;&ßž@”,ܱ®oÏÊ͇m憌ŸÇ|.gÞ!Bî@“Ùàâ· '~~ôR=³qcâxŒ\@eãÉ‹ã©‹'寮™žÄæ¦eöëv.›:ûñÙV¸„„0,„çuiÇåØ)5í\OáÑ“ÎÔ!ÝŒ'›ùÔ +##‹¹*§)1á8lá=óÊ\iu ‘yÑæ´nóráËØŸÏפF—¦y lMd%m.r@-çWCuž3 +×÷Çù¸ëõÞŸåU>{ß|"¼È�—ÇŽÞžñ‰G 7j0ÆÉa—?„›,g¸ÉK`Ï´ªîý8mó‘Ö/¿Åeéî}&¥Pþ ¼OxªÇ|î˜Þaòˆ„ÇZÿ�xâ¾ýñ°ç*u€éíxÃé?:Ê/^šëq7× g¶œd|“,é–p×Ò¼ö$¯i8M3œ'fÉfHßÎ×S¹æ–ÂõÚâôtÞÒ=¥ñÆU¼Du¯”g£³êhÁÄwæ’ï°ž8Ä ÃU§¬ÁÀ0á#æ÷Îâ{£á Yc¦gHÃ,oÙ]Nó»Œ^:ßgºä=ˢçe ™Š igcx�Iõ�’ϧ½¼Úž§=™Ûš+a¿�>æjîErÝ<#ûA!2¡£^)Ü*×<æÌn÷!}Ú:+ZÙ´‡²Ÿå îÙƒŽôŒÕ©ìËÃ,ujèô8=ÿTÚã:\çøW¹Ö¯zØï5žXí÷ºÞå_àTX8%¢Lý?Ò˜à?+<¸#PfðÈÿºÚ™_,¦Ä»·àˆÅ`8š` îòài¼ØÀ88-YVûÖÖ»ÅøÛz3ßeÆ—5¯YÆûŽ=î×¹ùÚÍìøôd?Dš ì¸qèáÄ®dU`P='ãÑ<éš‘Qþpœk\ü`çÙ[wö¶œÑhÓŒ1ƒ•ÅU}‘ú±]û#»ÆúÒp8žÂÆ,ZìÎòCÝœ˜Ô²e‰Z-*ÌmiwvÎáÛÐ&3 e˵šÉ,˜¥ìÎrGݘMLe£O=@õ4óÕô¡Ç§žä½YWÍN\ªp,0ª²Ì+6EcÅÌT²0>X®âåþ÷™Ú#GÜ0!:—9l—,¹,¤ÌÒ/sdV¡£l©ïª—xåçiîÓ¸h½ÈEë.ÅnË#é™$Çœöº7ÝT§Ôiþ|èp¸ ܵØy�ØõKýbùÑ¥3fc½1<M<[÷7ôLÇË9Øþt�úaŒ0?Í9v)ëX¸uÌ2ŽM-L×í2(îÁáÊ}vU> -™……ßîä5‘Ø&;´Ìcµ=âwé¿zß~tñNË# ÐÚݺ|8D/6æ&&êøгÈþzÇ£Ú6žÑ…yßÓ³É3rï™g°mt¾DiâŽ)t“pÖ™^–M&U’É& v”W„F2B°ÁkŒ†É »ÿeýô gÿpˆ¬qz®ÆúŸð¾m9 qÛé-ºÈQ°±³=CcØдKÖÒ#„Æ 1ÄgŒÔiÑ1Êäâ.tá©#ðÍSΉ\€=‚jŸº@•Û«–x_…²!qÚåÁéÏ÷ƒ>eÑ-zB‡`D4wðr)Ÿzõ�æãN#Ôò$371–ìç2 �”w‘“‰ˆÉ"%#Ñ‘�EÞ¹ö¨#‘èÅ2:À†@ ê“'ÈÚòz`õô)'Vû¹î?=ÙG=Ù ~Š¾RšIüÑLšçy…Þ|%Ë#&†˜j6Àó?z¶Ä*úïp"ÊgnVÕóu^x²BÊ!0£tßB12ŠÐNtÄË…?Z“y14'—|ÞfÕ¨ýi^Fo2\aóýlÎË“fµOg¤oÆ;Wá‹¥0Ç£3çª/Ï#R.üqÑò™ü$!½$ã¯;ï#“Ï!Zµ£.îyÌ…3GrqoéÍÀž5•¼î‘w¶)F3ebÛÛ&³bÞ6+f0‹Æjg4Œ§4´ã©ÆÓ©†£ýd!Oû3ýNŽóÛå7FÓìñô¶>~òèÓÊýôaÃýpùË7¨Þ Mh¾"…çþ +Êz&幄wlé�#skª çÆm8SÛÁ!ÏYê¿v*ƒ› Üü|Ã]âÞâ%ž×–”’QS3:k"¹Ù’ÿ-4;Näé+«eŠìqŸ=,ap:Ÿ¤t¬á¬ÄJºXÖ©®KþØ2}ü¥Ÿ©A=w¥'ôôKôÔbO[ìß6Ð=á=ÜdÑså/t©íÇÿñ{<*` Þ5ôQ??5ø„ì(¡YVãò8S§‰Ï<CüȳÃ!è-ò âAÀƒx·òPð™ÇC²å:âþëÁ®‰v·f ½6«¬[cýÐ8õS»Û#ý\’ñ¬îvJ÷îˆnŸò-¯îôàÙÜñ¬<˜»j,ÓÅ3»;½ûsågoPM17ô}ú½–D¶ZòMÓòÆ<~4ÔÔŽAÊ{£ÓÎOxÒ̹ŸÐSÍ®ÂPçÉü…÷–•ôÖ¼†7æ9<¶zßHzÚáþ3äMžN²¯g%>P–Ëezà‹ð±eúøK?SƒŠëžÕÑ·êÞÕp†#sYmYFÇ£"7.»ä¢ý¨‰§äÝgeþD�ŒŒ1„{üìI8âÅ#‡ï¦‡bÏ€O+7ÓC?¬üå |q©øÇhðQÝbzà‹ËG·œŸA1žEAhºxK>ËÑ»ÏÓÎ’/£ãdkh³µ“ Óਆž&ìr¢°pÂíyT +Ø}¤EþÞB"Ô&e7¿—Ç>’“gáÝKÕ}å/.Jƒ—U„õÂ4ŽéL9SVNòÒàÚ®ý4hjÉô}ïÒ\üº»¨¼£»o,¤äH-¬X:Õ•¢ÞBA‰Û‰RߥN-NB¿·ù¼aâS_7|0ïÍæÙ¾6ùOz*ü§&÷Qâ39ò¤:ˆqÞ®©k@‹ö|?5xö³×Ï,]ÃÔ>ø fˉ·WZÛh{Ms›U³ž¨še§¤Z1Uå;æìçÏÒàãªÁC‡¾Z™.¬wz2Þ¨Î4-笩M†€¹Ðï÷ öZJÒhG+æ!1©eRÕÔ¤îEýˆyÏÓÂö¤°<Žek^£}6Äæ+[hYÂÑ&<ÍUÏþKKÅŸÒàºÃÅ4ŽéL9WVöÊÌ ç\:ŽeꧯX9Zn¦~ÈÊÝ¥in™šÉÕô÷tôæÝ©7Ãñ¨ŽéZE½žv¦ìÅÙ•~¿Ú¯=�ÝÁ^’¿¸Tüc4ø¨n1=ðÅà +ÌÝ%§kDÓp–I/£BÕÕ,ϬÒu±ln„Ò;™L‰»N<¹Ùyö¾?ó¤C¥³¹Ìy09búì”ñUhv'ŒßÜÝž`w‹p$@Ê„mdæè[wñAÃOÉ\=¥^á¸ôCY¯B*ƒSîÓš¡k+ÍËÆh”9,™‡š ÏI3ä®q[cB¥2úòB<¬åJØr˜OnIÏû Wªå°¬We÷ÝÂ'9ÓÒ%gZÚ¡Ž/â^N÷«'§Ô^×SÌ)&§Y#‹Þ+ÜÛõsÜüÿ~LìþÝ.bÅÓÏÓN4ÏÇ= p‰°ÕN?w$ü‡áM]<É*=÷Ç÷#)²×?ž‚s?Wy~Î65¹?gmá,Óƒgát üz0OAØûì×ѦóRKñ³ó,hat–¨/Û˜?Éwýáëi…²$èv–9±.Å®¬ùµi4ÀeÀêG\ûikíb0Mú)šæ§hšŸ¢i>k4M¾´Ðò°ÎÀiæ*{·}™Ã<¶ÊFwá¡çµƒ_7üqðêþ¸<Ÿ¡-ŽÊ'¶óùžèSÇo»8€ÛyŒmxBŒíÃ'´˜Fþ™MjMRx"·xÂAÎ|ú¡y·vÚ¸œ×Ϋíè¼<á×ÍÖ8®ÝÞýÁ;ánö~ÔÕzjÐÙ‰B»YøÐ÷Ÿ4·ÊE‘·¤Çâ·Œ}~äüŸnür`u—=ó¥©;4領Û~0Z»7XO"µOÏÏ9{ÚËAÚOÞ‡7»Ý~x÷|êþùȪxÚ–ü¤ÓbNÏ-"TP;”9e”9o›MqÛ&Û\?=Yûd|r[Ÿ;ÞûŸþðòý‹ÿz8¾zöüßeYì>þ9ÎÂ:7{~äiXÓYÚu?´Á“® ×oÛ¡ºû<Óú Psw–d}â ö±3sìñ Ÿ¾q3œûÂøéã8¬´DÈž®øÔlvbõú1O;³Œô9c“š˜)žÁ:ÙÌ:Yz–~Waz¦~ ¾nÊË]þÁÓ>N²ô›Õ÷1‹ïÓâeÎú؈™}‚~äÐi"¥Û©zž4>âü¶ùsà6]˜»P+úolj0žÌíÓ`8²á±©ðCÇ6ìm07ÀT?-@étRÜN¢4L‘a¢LNµOÊôù¤g“¡ÿ| ^ò,ŽîÃÑ3;p·és» _\Ì¿¿Ï¾oaÓ'F„ ë!aÓÇÇ„™gè¨Æ#šâí:ÉÚØ'ߺ»~ëÇ:ÀïcLð›>ÄØÚ°˜ŽÄôô¥·=édf%æ0m)L?:Až§O'³| +·=žlúø€2"ŽGɆ4ÈX–ÓýI’´r!ÚOS᧩ðÓTøi*<”<ñRžeIüðk,““¾þ»·o~ûîå›÷/ßüþ‹/]{übú»oñMÔo~ûìýûïÞˆ~ýêOß}÷LÔoûã°mW[Ž+<ßkÎñ°¬ë•lãòGÈW2—2Ÿôšÿÿóå×÷üÓ}Æÿü'~üòçÿâåå{ø—ÿ5¾ÑK¾”_~oòðZˆg7:üf¤úóüf¸þmwõù÷‹ëwïo_>ÿòí›gïþtø%M¿8¾}ûJÞþ×Ö_ß}óòýÛw_Ÿ=ÿwé¯÷òÕ‹¯¿|ñüýÏÿU.ø?埽êùž ÜòmþžÓaÁ¹jƒÓ߈Ì?/ÕRßÚ1âÕOÌ]·:ÇíðÏÏØЮãbWsÌ2îõ*Šd¯#¯¶ˆÀuHÛU‘ê +þJšJ‡Tpd¹¼s•êu‰‡”®‚¬Ãs\VÓ•,ÞzHËUF¯HþW«¬ªÃº]‰ÐÔóUxX㕬µÅ.Û®fá +‡(_6^ônK½J2u¾JÛ&S´\E_yYY¯D‘ZÕr·,w™×|ˆ‹>1Õíå5DºÕË„B-ædìs¹‚¼ |Æ(_Ñ‚d8Sa‰Õ^-ÏWPJk¾Â x‡Eº&ÈZ<¬á*Š~sh5bºZý¢p%‚jn½ä„Œ¡š8):s¾ZöB’!•AЫòÕb>à¡n| iQÚª+N…Oñʘ€0¿HÞ†]öE¸…®ŽõjN5VéCaB§À|d'I¯“>D÷Š½Æ*,eÃ3ˈ£sW$]ÂÈxo6`3_úS^•£‰V¸,äž Žâªãµ¦+yR¯®äo™CYú5È{ÉåUÔ‰C^eÜ’Ür]ä&Òn–›ÉÐêe2å‚tÜ¡dDÛWv¢pç—ÉŽ$Y”1i'Ë,¥M*Y%m!jûgy¡Mƽ®2Î2L2ñ9ƒeJ +¿×“Ǻʳô¹Ì@8 e*áfòfU®N2§¢Ì6Né²è¬ãe2À¢Ø,Œœ/Ò½'÷’gŸS\g«Wýô-‡¼2¡+ês¼‰2±•—³…I¯dZá vÀÜ>ëä‘Ç’º×‘•#JÝЈüV>»•(sw˨eÍÈ\㋵{9¡ÍT<P¯åïÑÚ9y1ïÐ2,%Êš—yõzG\u^E™•²o Èö*BXm’Ql4™eAVF¯µê]{;N°»éeN\®Dc•Akí„«éÆúÝŒ —ù3µZþÔ“wó—þ/ÿ ÿýÓ7ˆ_÷õß>“=õæí·úúí¿qÃøÕ»·ß«;Äå+¾|ñí‹gï_|óµÜb·“l‡ŸýüðÏÿtaO‘‰‘2ó•!qÙFõ\Šô½Ÿ@¬q7áM6ÛMÖzU¶$#̪3·‘[®n™ ¢÷ËT–‰R…ÇJ/k ¤…a]„, ÊdÑËd5"jäP’6Þ›ÕàeNóf×-Ø¥eg!Ex_^¶Â+WÛÁ{=™¸Zo®ú`²UÝäy¡…Épž·7®`xÛá¬[öë=¬èa"u‘n®òzGù+;\EèuŽ°ÕȨØG}$¾Ë½ +º0Ê®ÔÚh»Sëhƒfż™Y—i»ÕÜ—mœVɸ5sòZ»‰¿›r1ÎUsåÉþ@çÐœJÈŠ Ù‰“?¶Uvlp‹ììѴ›”Ubå4™‚ˆÂo—Y¾MI2¦¶ëYöÙð¬s0^9wβ’¹U€[aßØì¶U¶Ö*›Ÿ¬äM6ŸÃ&»€Hzv�y¹M˜C +�ûšì>›=¢]ÈgáAÄÙC¶m±íHˆ%UÝG„ëÈ6¢1¡7E˜AªW7„kÌqµË„¸Êdσí“7ËUDÙDë +‰è´?Nv,ìrß4Ëý_ïˆx_ìÄòžiœF˜5‹ð¸€.·ÏϽK]zÙã‘c¦7⻕^åDdj¡ª5Sеkî÷r‚^fÔkù#·vN^l7×ÂáúÛOfmÒ£l™<dï×EÚˆIFIWžü*T™+2l3¼DÕÚÊ£D2–90Ô’^Ì"õvœ`wÓËœX® €z;"2'þ~7#èeþL–?ukçäÝZï©nÅÞûäµdª$È»˜2ÂÙаéf‘7ƒ°r^ùh¡,X©Âfdˆ°t7,2ÉÀh…ñ&Ìr‘|¯¬'™þy–…*\Èyivdý9÷J²jÈ·ct~oÑXînD^r–Õ X’›¯v™HCµ`S¶ëì=@o(2gy [)ªp×I*ÐvÊ"Ówõ+U$bA¸ël°T¸Ch}±²Sx¥ì°[•áïõäKZWnyT_Šh[Hv¥SÉ@DûBgE>?Öl +Ð 2¼øxþ ƒÄ+eÅEÎaÙ#3äÛ«¸b·‘Ù8Ë>!£êûh(½‡–YÆH+§2ù ÔÀz«z¶ž˜·¾qrô1Žaz`ðJAá�”UÖuíaàÂu¶|äÚåE{`þ²IIw Çßf½ÿé=Ù¦¡;p’ܦ˜tÓ©å38XQ^@Ö„]#‡N§øYÁá‡z‹¼~CS`wÔU:" +?š)4˲ni½²=Z«×ž¾µuú–Þ¢™jï`FÏiQ)c[˜ˆSEÁ{EÆK;JQ-KÇ£Q±²j:mÉz‘~O£è•ñjV>Ö“]ð«¡FÙݳQÛ³µ¶ÚóŸ¾gëY%ìQd©™¾Þ‘°Â¢öòZU ¢DÌB'83BÖ ^+WÖÖN#ØÝžÛtSb”)1·µ³Øµ»A×·?S«åOí휾ÛÃÒÚ§˜› #ÎBíK`oP´Ü¼u "ë楰Š&ZÖμ¡Tö¾™—Ta.àæ%ˆ¨ó¼®;óÚbÒh7/Wònn^ +4_ŸÍKä–àyn^’7¿‚ùº™—@X–½u),«Jqf]w•í=4ëYŸ(;ëù¦Íº„ C:mmÖ¥V£[—À2×µö§‹ˆB[Íͼ™ûÛθR©Â¡Ý¸Ô$7/a…ÕX·y Œ7EáÓͼ$‹h[`E3ë•ì;ã’,½4£ç̶$Ë_æíâ¦%ùW»i ü â˜0³,I1æÍ K·e Êή$b63ºYi£„\šUIvÌÙѦDÞ·•ÐlJè:‘nR’{_Á°3)¹+—”›”‚L× ¹k_Âm9kG“R€òZºE Ûç\óÚ,J¡.:‹G‹v*ŠµnQ’ûʦ,ì&¥³…u²w1^*¬;“R#º5Ó¡&‘Í\¦ŽL£I »ÕáÎë-anóFœ0y:ÑLA7µ{&¥ö@½–¿‡·súb#¯yhÝ™”:ÑLAà‹qKÍV$2'ÂÞ¶E áZCYoÚ›qÂ`ãéD³õvÌVÔï6X”Ú#µJþÌ™“7ûk7(}¼v/|©äBfœ{=Re)Ó@×ܲqT*„ Ól(%³C¥Xjæq›á=ŽI—¥hæInÅRC¶ w˜ýÆ$Œ¤™ñEÅàZv"O½„FP<ôÒ+Á²^D„¯Õü +NØ6m¿ÙßAÄj˜3R63á8U +#0Æ.y èËUÑ6¸„½Zë»`&êóÞ<1”Yí›ØDR;T§ +S~U+.=ËbÎðÅœB§hÏÁ óXoQOÁЖSüžn¶6j1—\kºG¯ÝÓ)z¥?[«×ßÊÛ:{ÏEÔiF~ȹ9oëÞ—…œ»9ÓPO´ùÒ½iMSÊî3wšìÔ"âJ÷§‰v/û0=l¶°ˆ|Ÿö5Êx‘w(.tf»Í§ÍAÄ"_3æTƒŠ›&‘{ÕÀÝøl͆=©[¸Ü¯†+`J7ÏšÈ2ø1u׬�2Ù}ÍsmLÄÁÒk²äæ\ƒ^”Õ„û¶2Û;¸‡*“Üjt±Euíì|l”<Óº4'\[«Ü¹yÙEuïe£r 5¤yÙ zÊn´n¶bR@÷³É>¦o䎶€}TF«¹ÚhnHÁtækË«OÅmPÏ·óÛÝmèÀyuöçþ6ª7ÞÑnË!^nÝã<$ÛšËm¡‹¤†îsã•xßætƒeµÍwº¡¹Z–ܽn°SRIi~7ÙÚDP3Os¼-4BÙ!›çmgtª9_³ÎÍï &!Š™î|ƒr¹JÎæî7|ÏeõzO²1/[wÀÁÁ—in±FÙ9á†zæ`Új»çÎFP¿ÖYxÛ=eç‹êµçom¾ç™;n‘®JÒi{0œ{ÍùµÙhKè.2'ìr½–í?CCb7ܹä0 Bro +jIX†aç“ëµÚ“·†Nßðÿ·BTˆAÍ•!Â(hÓ»!õ:|-Ú!vÖF:¨ßÒ§Ðdio&E¸)®hªƒ-#^‡’ˆ0ô6á:åVjðsŠjLQ=z½\nãÁQÒ†h<+$°^¿R´»R6$ÞS®œ#Ì60’b?:{Í (BŸ‚,Í};¨A7´‹4¬°[ s‡fJ§¨f"‹'Îy¨'œ§BÍëMuÊÜM§Ê+èöÝÚZ…,aîé”ç6’|´^ÍŸ¾5uö–Ë6ŸÃÏÿ çÀÎÑ;®Ž¯{zaÆŸáÁi®Þ ‚l{_/-żÒݸ`:Ë%¦aN5êêsÊݽKrÎèîÞFÙ¹{{=÷ã.\q¤ÄÒ'U§b(ÓèàÅ.6'£}=àó] +ãL†×{*|�Kî^߶cº3¶vžß^ͽº½©N±[ÜX©À·¶ Ó²æ·tÂÎ<TkOßš:}ËÁ~%|¡îµÄFu-±Y]KÄ´ QeÔÁ=DÔ_š–…*Ta‚®%Ââ@{á¨%6;žk‰Íç + ÌÐa⣖ÝoTI˜ÈV™Ì®$úçQGtZSa¦Îðï5Ý¿¸å½Ž+VYñl^ë9×ÏûòÔŽ”Õb±Ó;Õõ:še0«šî‡?rLe¯#Òê×e¨ªÚüz[2êkÕôºÞ–ë~ýž£ŽØŸ×koÕÚ:}ÏËåO1…¯É`)0<ÃéûzO-¦ô¬«; ³jXU3d–Fq{8-œC=ìèpÍõ¶ÅîéÌè›YZ[² ËÃ=âÆtsU¶zíù[[§ïù£x—¬Sºge# xO©]Ô†b´¨à°DZ²Íü©®ÀÅK¡áÐÍq29è‹‚A} Ê6Uä-i!Xa[}YÚæä°ÀùˆÍXm1„=`ÁAåÂT€dª]±Ùš€SÙEàÈËFêú9½²ly¥w•†^ô«t–Íi¨øo%û¾êÝðtURàˆ†¿µBˆýд;QádÓt~+€v¦üÇÍO¸"¦ÃÜ),¸‚ÀVa¯¥›/€§Ò嘱ˆªâ>ó¶Ìª«Ö,Íš ð- K…î.ZÀaO©3Òè£k¾‰¶ÿ•Uu$WÅP(TòtœhvKVü®XËjðæNu³f ½Ò'Àzj§êŠ7ŠÎ‘¨xœ¡žlŠ¡¦±F±{ê• þÚÛZt«î¹ôÍsx¶V¯=këô=)pI˜K—^u*Ãk0xœ/A éj^ÌÅ U3쬰¥¬Š£W™pöë .Ò(J[“Æ ljÕÜàÚÔ×Wºß&j¯W6‡ +nzÎJ….l£XN¨à„Ú2+U^mY6MìÔ]Ƥï~gäZ8í‡XG¹Æ>}Øì+è-ël¯éç eGU{!vØ-pÞÖ6hOà>|Xˆïúš› + :(³Ç�Ûˆ~OÎïyj’«”愈¿ØúK¢‰M¿RÙHÍ´y±îÈÉ+ɵÁ¥ë¥´Yà᥉=¸ÖvJƒ�”]ãIk\›Ù‹MÑó¹~ÂZ0%dÃËÐtözO•¥®jòÈkÕ±ZasÄæ ]ï]ÒѼ³×+êKÚj”8˜ë:5ᨲpÚ‚Uù~O£è•íÙZ½öüÓ÷l7™¶ôna¾s«z½§njÆX…n1Ø=hHâ]Œ¢H‡ Ø¡ž¬×%íÚj»§_iÔb®Öü¥0uö{:E¯ôgëõÚó·¶Nß³õ€Ì–°åŠòGXâë[s¡¹~v{ F’{a%¢|ÅÏtÿ÷j+’Æ¡©Fñ[ê• +ñ‡>CoPŠúí³2 +.¯Ô_ÈÛ9{EyØ[+Q_@uGs¸ÔÒ¯BõD˜TG%k˜E—K§(ïI&r§ÔÅÇò¶ŠÝS¯lÔÅ»Þü�p=ô{å¹==[«×žßÚ:ÏÖîÝEñL¢¸˜ÿ¬Qa_ƒN8cæÉr£¨ðoœ·Ð)ÏM,¡‹¨¼ƒ©Fñ[ºˆ`T³Zô¶„uMÙoiu؃y¥þBÞÎÙ+þú|Ã0c§ ÇkêÆV•™ÖQÝØ‚r‚£ÈaÝ0IÄêöwvCÐW¯‚#»ÃN°³5h÷"¢@ÚjhC�¨$MÈFŽíFG©CÓÁݨ“ûhÜM3Ț׎î¦ØIƒwƒŸÆíÞ7#`©á»a³vÎé>d@hüAýkñ†Uu1H5wj`KòºQž{·ƒßõÃ=´å¿§«AFÚ‹)¹} ý–NqIP×k/åM¾åeõüsà½éõZíÙ©ŠÒhàjÌ)™<[Ç`7Šš+ª=Ô34woªìŽza£Ê.ž «mM³÷[–Á\ÜÕkOßÚ:}ËÆÍ`º…³j»p +Ã^4ªPiˆ!«¨¥/˜qž=ü#ØÆ +›mYsêÅÙ€š¥Fñ;:SR*Ll@yõ¶0¡Öm¼§ST¬Ó'kµÚ³·–ÎÞñG1M4X1Ö¡Ô#ô²M†Ž}ÇBI‘^.¿CÇé!Ž~§', Áß!çleY:þ½QT¼Q�|¯æØvÛfwÊF}Ǩ䥇žB£ª#†‚m²uƒÁÃY®*„ÃÛÑû” ;%ÃÀàW6ªH3óBŸ†Áàï¡›¾ÁàEŃÁ÷zo_Š! :ÅÍ.85\ì(ø…n@dNnë(x¸!ÔNæ(x¸bÉ©£à¡KtåÃQðp³>ÑPðÔ9â;7å£áà: ½ÅaðòÕ†ƒÇF‚Ä9& Šx®Ÿá|ÊžØ%ŽA¦x½§Š +†£§âœï¼ Xx'ø$!~½×2ˆûÐP£Ø õÂFuÅ®5àÔ2¢ïE¯ôëõÚ÷¶N_²IúÌk èèðõFmwÌ~:KJB>:†+8þz[´ ûi÷4Š^iðõ¡žA܇¶ewÏFmÏÖÚjÏúž.Ž¹SV·^wª°0ax.ìÕLxµãÓÅYa콞#Ý{[b÷|> ˆxê&4¤ô¶f{³~O£èjoÏÖêµç÷¶ÎÞóa‰÷sàâw`1Æ7¬XCÆ7¬XƒÆï°b ß°b ß°bͶÊ5x|Ê5||Ê5€ü+Öò +Ö ò +æùT¬äT¬ÁäT¬ù×vP±ƒoP±†”oP±^g„Š5÷\{…—oX±†—b 0ßb1ïX±™±b 2ß°b™oP±†™‘b 4ï@1GÍ7œ˜ãæw81Î7˜˜#çJ̱ó;˜ƒçFÌÑó "fðù@¬áç@Ìô Öô#>¬!è>¬Aè»ÛAô;|˜£è<¬Áè<¬áèwð°¤o𰆤oø°óµxê5Èù6P ÓÕÀë ÷Õ0î;|XƒÂ÷zŽ–ïmuÊ€Õ¨†éjm5ÜW»çÖžm¨×žßÛ:{Ï‘ùÓ“´Ã‡ Tƒu9”Ý_ ï>ÂÃ*¾×2ÜüÐN£hj¨®Þ”¿ú xX{ªV©=wkçôý.©—Ý“s›°³÷4*, E¥¬D†R½aÖ—¸¢ê¿sù^O¸T\ÃØV£Ø=›á@©²¢Àʇ¶lËî9óy½þüÞÖÙ{¶õð) +öIÊ&juqUãLÁŠ½§²-¦�1‰Áš£ +»ÜíÅ0¦LµzÁ€.½©F±[>7ƒQ£«m%ìíi¼§QôJ´V=}kêô-{_~¼~ Oà\Tç™Ñ¤ÑN…m‹É+€4Ç €9ÿ4›*éÕ¼<QG«Çº”‡¶:Åî©Ý©Û¬ÐßÞ–PÊFÓî齧?[¯çÏßÛ:}ÏÆÖj’6,”×{*z×Ðg[J–:æ çXm¢ï<L]Æz²ÓÐ`ÚÛj»§ïiZ3!|Þ,hu¸£~Ö«ü¹¼Îð>ÖÊé~–EN¡H`êC‹ +.z½§uvSzN×`‰'"ÂÁ`©tJ[KyYÆzò�‹2´F±{ºÙ§Q5IVkjeüËpG%ø²·óZÃi;§¯Ø;òøn¦ê£0-tñõž +ÈYÔøfE—a-ðæS9§�îUÖf…`´jÕñ¯©N±[ºóר¢WÊ9Þ̬&ØòÜT\{²V¯=}kêô-”I üÄ"ú#+£9–œ¸ê.OÝb8@‰¨ª3‘ÓÚg}'‘õŠÜ¯ÕÉêÂé8Ánåʹe!¯t‚{3EÃ%ú½Ê©Ý¨xP…?²µsöbÝ•º¨¼! Åýˆ(½5gu~ÆEcÄêP¥ëe¬›*°àU5�m§ìnz™19À’Z;X?Û6ÜÍîzÕgjµü©½Ówû1–·Yˆ,P7è5z½§B¾Ë*³ÀEe^TšÐÌhNq>–cŒc=¼ý–ƶÅîé|̨E!ÝC[ÕÄŠ~ÏÚkÏÖêµçom¾çç'NúrIj„¦¼ ãèëÆx„¡ ˬf3Ê׋›WŒ '\hë6ÔšÕ[64ä¿¡^بßäЛ¢'ÖáŽNÑ+ýÁz½öJÓ—ü1d\0Îl c‚cD:q1PœµD¶x6 PrìUáâ²ôհƘգ5Õ(vGWþŒ +×1Ž-$/ u¸¥ôÂödš?|kéä?ÿ„¤ f¶xjY ŽAnT›’Ê[Ò†Ú5xË-æNÑ·bþÜm¬7Ó|14廣_7û„œ‰õ†„"ô:ÜÐ)Þÿú`½^{øÖÖéK~žÈž¨¡¯K|½#VOJÍ|ÈXŸUí¹HÖß)*\¬ž‰¯Õ)I…†¶Ånév¥JŸ1—Zok™5ð§ßÓ)ÏíaõÙz={üÞÔÉKz×}¶°®‡Ãµ>—ÏÐÈh߆fðkŪs0³¼è\€óq,3@Y ¬n„2WÄ^ÔÔ‘Ì…®ØÌ£÷0f™û",ÅŒô1gä` ªyÀ0#l+cxÂCé\jG0à QJܘavžÙÄ|¼„(Æ_N ïÁËr³™#íØe†G.¹c—3�Ô};v¹ÀµvèrÙdÝËlÈeŠÈ4Àe˜p·²æŽ\„Ò¡jND"eò¶í±Ë@Ë,°E;t²Ø;pùl´÷Ç +£3ØÐ[îD³`#ï"GÑÁÈéŽ%ì1Ë~€¼ub‘g«PX½NÀÃhãÞŽÁûÝ´r&¯ÕžÚÚ9{·‡ý+Ÿ„æXö(e q¾“kÚÁ’cEbC%Fœ†If™eH†ÿ#Xž=’!:w1f6š¡È²~7ؽ1"EÜ€/FÐÑ 9Ž”¹ç=âxîPcà€+v,C/Ð?NpÆP ;Æx±Çpä0’&å¼Ç¯ÌR×iH˜¾¶”àâաņnàç¤}Ú Å€0kçà&Çü+iíxâjOâhbÌ£9†=˜¸T[؆%F¿ŒHbæ›Í{±°Bé0bƒsî âZlü†Çl‡ëÊ!ÄœqŽÞM¿ýÚËYÍùÕpÃhP_æFÈÑÀ`Ƨ˜aÌ͵Ä|½™NÀ»hßÞŽÁ€ÛÍ°p"#ög¶fÎÞÌ_´”Ò(܉Ží¥ez@ÿˆ_N0Â"l–°aÙEóØJ#ì�ÂNtL¯·Ó`¿v³8ØÈiý‰•³÷òŽŒø@º¯G¢cy±¶È6·ä=*V¯P‡JØ¡è¦ôfœ0"t;Ñ€¼ÞŒ!}Û8p{¯ÓÞÂÛ8}-_äb +ó¶‡w¢¡wÑa„ý&ƈ_nñÀúS_ôZpMR«ôva�äv¢áv{;ííwÀý™¼V{joçôÝü¥aæIÌ÷9 Ñ»²8¶È<6ê…é©Ðs=`…™KˆpoòøÖŽF n'^·µcˆÞv³õÛžÈë´÷ðFN_ì’3Nï…ç#\°S䇸Ұzh0€€²ûâ¼®=^~çP–N¬H¯¼ ¸ÃF¡{è¿ÖŽƒ�ÛÝF¤`(§ö÷–Î_ð³k,â'H‡_üúÍû‡ŒüöÝ‹ÿxùâ_ùößÙ#<=¢wþâËÏ.KÂóHþû‹—¿ÿÃûÖ«¾ýökyÉûwoßü`Ýß¼ø·÷O®|ûò5ºîå‹ï¾þŸ/þ¤µðoÞ¾òwÔЫüø;þÓËoÞÿA/Xj¿žý«Tæ@þæíóáyæ›ÇãÿöÅ»ç/Þ¼ïõOÆòNÏȹ{ó]|ñÌœÿñò?^ü|Ò_Ô¯²ÎÏ̘o([UÔôRCœ.ž—£é;6Çnå 7ŒÒîv<÷¦QÛcý¦_‰¶»úÏqjMɲ#Ì8vxYqÊ4‹–YÏ$^üLâu—L%i®^¤\=8ˆ/‘½©,AH€]ÕqXøçªÇ Ägƒ¶TZRgk»"G•Ú£p´xTš›I ì•»�HâJ÷bD§‚,Pêe[.0ŸC^ÝV…€’¸Ù„d Á8´°ã H¡v€È4–’¢— +@‰¦íA�2™„¸´7Ó4ï–ë@)xLÑ”{'͇p +ȞʓýxK‘Jß0LhOS£F%0㔯Õ#uÍA/Œë¦”ÄñHÁrdÍ4¸õ+Såž´HçPuáõ’diFi´¾f9äGÔÎ|J&LcrMdÍáEå9Nr:AE�Y²&eµ0G‘V“¢ª3¿°,”è@þœíô †ºæ`ÖU¦0˜áxÓ0l=Kx‡ài7³ ƒkç]ÁÔzp¯ÔÕ(«RàeiW®´…*¶šñ™™‚‘?‹‡Ú㞌Ìeqc$¥ì:ñb£Í�tŠÊr3»"ðüÇó“ä–+A%«Ê…îX*rÙòŸÍfãÜ‚±DßX«f”«+†t†¹Ha¥1ÚQl5&Â7·jüTY 11ë¦ÒNᲬ¶tHÉþ°€ÊÙu‰u4K#ZOIÁŒ§�…2‰^CLHñjGMF8Ãwv5vƒ%]êÞø…«h¥Å+B/ÎÈS²Á±®à1¢å¿fhƒÜ'0li7kH �ÇuQ§$“ŸWh°™<ÂEÛÆ´$ N#öf¨xü¼º‹>`àe¬ +º>ä¡Û˜6UÓjâN|acÇl)„aò%,®Êì¬K¥ì=I"ÒVÁÀ·0$(«X‹ó¨)Ò¡ äÐÙˆC�Iöäs÷ÍxÂ5«¯s + ŽIäÌqŽÑGb¶Ê¬Â.áj–<p�}³HÔß™ñjUëÀ*Q €¶Æ êuˆæb! (Ò2ë"Fl˜W6€Ñg?ÊJÙ»cFH½|b´ËDX‡Ëªfèð†Ÿ[çËVM‹pÀ@bds’‰ó^I +P e¿lªì雽[AÄÊb¨Nè +pV,³":#¬o€ãÏžŸDZ3�ôÃd³í]Bž©&¶Âp³WfxIÕD5ubµ¨¿Šã¶°Ûø‹Á˼°o»E0Ô'M¬¾L'<.ÙAHç>àV€ã0¶ºÂ“°š…8 ½ µq¸È\\³ö5íÈ‹':z1èôFÎll½`-‚HÛjΚO—•`Þ-.½4þº!…¥üÎTæ`¤6K®ˆ*ê„Y +,U‰†42Œ0’Wl½›úme»çÀ&úrÖyUt”lW.6k“ÁŽkËC·ÌU¦ç8„Ü¥uÿß`0J:D–çá‹ÃBx,÷™cBì¬ï ƒñó¬#-«OAPÌk!„X’ÝšB.ôªøé*ë™Jõ‘7Ñùð +¢Ûú^Ò£:?˜)¸Ðº·"a"\rØ ÂU¦|ι倗mŽV…gõh0WT{Èš¤e'îM}”�€x +°tûñ«Ææ-Dšrg_6€†²Ñkà4·Œ…ù —&KhH°ðJpm�‹GÒ$ +K 0&6€+{¨T|šä°VõRÌ<\ +)Êu“3µq%<7a>bµZH¹Ï$› <·j‚@]£¼x°-‹kÑZ›.n‚»‹Æû n[ ˜9¦?[&!dR3±c®Œ}jŸƒ÷V5O¹´¢‘¢‹ŠÖÒØTžÑ¢rϲ2¶ExnrÐaÖPú Iu'ŠŽt^-Ãgœ R“T!i.5÷áœYdþÁU£ÒVžûgf}ÄH4,mi1kR¡‚@›Ä$Œ®š=5=ÜpBsݘ‘‹ç®àœšMÌ/®ºê{Uõ+c–Óœ•×™Þ8Ë¢ÎS¬ãZºä¶q›U>b$'”æÒ±·r³¤·Â/âcçÍßcá¡gøœ²ârj07Ù»è”B>^òŒ“ˆ1HÓ_£ò=*°ªuúÆ$ö€>KT‚¿:Cz‚I&¶d•Õ"œ]6k¤ƒh`J,\„†-³fõÕÕÔúÜm"ˆJ�±ÐöT5t„„iá¤Än‰9C»l8[íf �V®xu Wˬï¦l,XogÕ!ÖU-áZ³žÿÆ.ÂâÛ¢ó1ëss\è*öˆ¢oZ¶º„ÓÀ{ÉBÞrÚj!¾û¹m}ðÍb!OáF*CÃÅv€í|M¶í1'ÔÂÓ.¢K& ø”AŒH¶†x®)ÄE%0öqhe.í2¦Ä[WY`¡b¿MrÇxSª•¹s''P©SAÐŽèÉ7àÅPÂØ‹";³˜pÊЬM ¹Wj»jó“ɧzc‹Kå½@ãRDN,ªg¢9í·o1΀Ï1Y@‚š› Áø\½‘_�ü3%Æ•¤eNS~éûŽÚˆÕÔ?Æ`³œ)ÿ"hK%0ý¬ØD¥VÇT*ñÌEæ}âá_F„= +‰f+•¦W¨uL oSqĪôcK6¤æ¢z E%,ÕB̶b3úƒáuyFÐDrVN˜-惙«‹SÐq¥]E˜�šJQÕ5â&0K5â¦!ß5f… fᔳ!lq”@¤^¤’�9SJF›UX׌¬×W³Í*ä}]L"Çr"¢åÅï…5y�–—ì–èŠÉÅDÐÙRâ²Í÷ó¦‰A\¨˜nÄo!ýøÝWÁƒð³¾Z¸--u«8t%h“Èٗߥ‰Ír—ã1Ô„$-Åå² R!Ž£ š´”›-OŠÆ…ç›m±$wD/4E©G|´Cd–mf£Æ!Žœu8�B¯èU\qi¾cóGPŠŠš÷KŒªçq’3Ÿx 3S<{&ðó–1ý;‚æŠf½)Ywö¹q'"l]ñŸ5aº Ã1)ª_á¸úÆð9‰Š˜-˪æm,Æ)AФT«òË(íkîËËPÿb.ö>&w*œ<€’L²;Y�#¨„[ÓEòŒà?„=BõóSã=ö))ÒFuX7Åó2;¼\µ¡å²×ÚÔÔ[Šzl€¯äa}“hÒT‚²Ãð!u¦ˆÐÍ¥ŒÄMš.ê”ÓœíÐ2@'çQž„§Už._”0õgUe‰aö<˜` ŠyBF`ͧŽˆCfçOvÂR»Ôœ‚²þŒþ%1{ÇBòa2“�(³i¸Â?™×ý•Ìx¯w¨zå¢'9!,ÐïÀ#½èª²³-†Ý/cæ˜èV°ì|ËX-N +7=q€ÎEÀAKDÒx᫦²®Úï¦B·9߀1!e zîEÂ…›'“ÌœÔĸ²Kõ\”mÅwÏ~GÅ›fåï¨93ø¬P bíô&ÚWôÊ R“Š‰tá¶dÇ‘' +$ÈŠ +û\RËÿÍ,Šõ€É1óv#Ý9ºYUi¬E>]7"ÎN¦�Û_˺i¤(n +WË3“¯çò¢æTP×l¡14¥â-Ò¦°sBŠ@¡–îWRê5mÈ/Š¶x`3UâãÌŒ<‚Á“íá�£Y3‰/i±T;4xsŽeͤHð¹´ó_ÛJÂÆB#!¬Yð”LpZs�+„†²úAž›YLµ!îš%CžÉ§ÑÆ|V˜ðêÒ¯[5i/Í^¬¤à˜ì–Åò>RMºÜ~¤ÃË <t+O“Ü”YĆø<î<X +‚€š¹Š3ˆe€DbŒb@ÄreŒp°Fg·ØÃÂɘv +ƒØ DݘuGÆ1”íššßS.Š®õʹ›ÉQÜÒK2 +§0¤ôÍw/øIˆÁ…«ºÏ¢¨;ƒàIep3ûtŒó=ñö©ª"γ^©ù g“p`P£½Uz€V·fe«8ws£¹vAæÅÚ˜Ö52l|óµ<[òÍ)£Z€ :³l“«›ç6mà@KI¥¤‚âJØŒÁ`SÏäØädï†ÐLø2ÏjÂ|FLãÆs5”ÌžH2gqð…0JAƯ¤Qävzµ/QúÅ2ÏHÜv5&mÂ’·øû¼j*—m.E ¡/¦šôÐè¥ÎúrpVlæœc`ÖÌ°†X°TsN÷Q+ì2ë +dPëÌÂUÑ%ŸTI(y½‘Zô3œqŒ©‡ë„1Ç~0²ÎRcŒè†Ì„g„Ù:œV ŧ‰išYzÁ¹‡„¦Îš©„Á03S°t§Cf9Ôa¾,vÊ5÷38c²m ˜÷r§D_( Î<§¨-€èf~,ðtàû%ö‹(`ž2 ‰þ7™ ´{ñ|f!ò=¦¬zZ‘1ùVͤ³1<HäØ‹ðI$^?E§ê1‡'A&Va>äUA@ÞÎ !Ï@GbÕ£Í`‡d37¡äDâVˆôV‡ßß.\-Ka–®MMm4çGÊ3Ì´E bOUó7’¼ÎÌ̼pߪIA„ot:%7“€X‘˜ÄçH²ÅÛ¦Þ"bè-®Ï’w?<¨Ü+Ð4ÓUÏŒSÛHÉÙŽùFèo,°ÉZøà*v¦3ã~ЗÍQæ@ƒH·0¬\Üdw—² ó-AÅ�zÜŸÝj;Jga® x%…7VV#Œ¾WX I`˜H ”`i×Ùé³iÙ“g‚—±kpGFGƒÒîë…f3~†•½ºÀ@|ù¢¹µ™*k«j…T‰.éÇKRƒÑC¤–Å4ݪ)¤ì�R)ãG#L«&Cßé)0X@4k&MH)+¼Ÿ—ôÜGœÃZõì,MûÍzF)šnnAØG»PÏA H€‚銂®¢ÙÎÅú&ðƒk¯®ðZŠÅá[�$"æ�†$Ùpî1¼œÎ³ƒŠg0¼)gÄ;ò€9»ˆÛ1Çv¡½ ÛF`˜EÓÐÊù™nªÜU¦€FšÕ'¨á«ÊVtÀIíÈcŒM¡ý•¦Ÿ`‡¸_†=Ádu[â�òŸ˜×Tk!{ú"CÊÕà#÷#ýúìÆKÑiV°+œA˜ŠiV;-Ü#n`óÓìË¢[#BýiÐ+‹šÏ¬Ýjp5¡Ñ@&6h�fÒâËì³j£¦Ù Q±Ø+ì³Ê8vâ×ažÀ4ƒE´8j÷D£aÂ[BîÁ¢CPL³ž:¬´#íؽ„y‹p=LLNÀÑmik½®4ìèE§$ØgQd=íëÖ<œ quƒ–ÌQ΄¦p›1Tt1Îù™‡Ë2UñÍl>hqÙØŒˆÜEþ†M/ë†æºªDºÙ+0ðüê’!Ø3àà0W �%AB^ÝBݨSèq*€ie/ÅS)”zDff%ÚŒÓb€ãbç!‚PZ¿ÍÜ®‹ù˦Ž5nHAŸ‘8\6{ç&VÀy ¶&YE=¼)ϬÝúrcópÅd@¤ÞkÖ`€¸("„M Ö³ƒ`º‡X Laö¨C@"˜w hΚ¨ÖéeëÑ/ËwÈ^D÷;“xéGaÔl´ûì²&‰Ñ¬KðIé³ÂóS´O9ÊÐSÝûèÒCÑ=”- ýG«ÞMž—mô÷ø#R°g3fu.Ï´rK+\È‚$1ÁÛYÜ ‚M }"£@€(ª¡0ëØN¢r¨w37&\|iÓ¬]ôúÌ}ùÏ€™ÕÊ‘®tå±ßpúaZÈ ÌMÚºîÁ'™ÄÑjmEu0ä°JUhRe’]¦Dj¤Ð Ó©zÆøqòȯVÁ7õ1p‹u'ô5+¬“Ɏ™ÌèªÚì õH¹ßùÌÍ|«™à=Õ|ä¦!¹àl)ýÈ¥m¤T9‡K º#=Ràº`b3Ë¢"¾¡åq¡/¿@ÊÞMã!híså„j†ÈðYO" AKìª>J\5·$¥È³iSX˜™W‘Ýósdr8™½µ§6å�#Š,ïóz”b ¢„3ýÏ—Ú›U¤ØDT¶œªÔa 9TžñB ;hó'˜Iµ£n€<¤ +h©Åô%B‘ òu—@a{Ô|9kX‹œö–ƒÂe=G¿âÖã3Èœs:‰ÌFûá™Ds3=˜Z[Æ4TM”€£Òg'mq¤y“ƒgJ!g‚…¢Ëf¼Ï‘P4$.¾ÙŽ'‘^Çl%Úñkep^ÚçjûèZ:€AæÕ2³éÈÀ!Íš°ÑSˆ…nêkPµÞÙ•9«LÇD4%ôhGn£¡‡Ê¬¤e�5˜tiV‚-ýà:ÚWµÒ %0ü›l>{BVy µÛ� CÛcÍ^GÓ,Äkx™àöyº½—ÉœâbSO±`&/AÏuV8±_ð3ï<~¬Xž™¼é‚ò«2P=‹Yef{Ù®›!H�¯€rÎ.†n†{ºˆzƒ¡‘™(Š¦Û¢%ë.8>�ö0ÚiµdÀUk!›ùV-¦Qà·èz‰&”CßÊê°Ñ…0k6'bWÖnîav®ÉU³{U=±S>k€-œè¹_FøÌl°È`FUtߺÚÝÀ‡Aˆ®qÑ"È£cÔüÇ„Ë<¿ÍÞ±¬¾¯ÚN¶Sph%Ø6^HšTE6IÔ ŒL|èM™ÜÊ]«†v*`@™ypÜò ÒY»± D29ô#‘A�fÎ0Ù‘³†Ðg¦zC6ߢOÿâ– †ÙóÄÙ¨ˆP"ÓjkGûUtc`±¢™v“q©Áà+80vx²ËR¸,Y+@i>aXD´Á;Å,{Xs꨻f*.Ò¬Yh5ÄÒævƬ‰qfÚeØÎ�ºšUU!(1“^HÜ3…Sà!ÂcK@@…OOøšl–(‡Y×_ŒçHÃw™Ô¿XÅ +‚·ÞvøÅ(V-øQ© &E´©GÞ3˜¤‹\õ2š%P²_FD�ˆÕ’rS˜ËÑüb @Ò'pÒeÒ„,€‰\—H1BÇà/bNj¦þ[BË\ߪS +õE׌¸'À x_€÷î8…ZCHÆçŸõ’-7•[õ¢¨.$ «‚ž?/>µh» ò˜¼/ªbÂc» ŸCy”¢n"×r%è½Òj½@eÂ@¯ ƒ¶s¢b«.ßç6Ò\e�3Ø?Û®@0±nȳ⤺ÃOX™µ½Š & BQ¸ršÛ‘N³©è3–ûF†ílTXª¦qH›Ú&ThT*›uQOƒ 3+¸’h\(†`±¹O’"WÁFèAÃ)J¸;˜ ¦tH€àvß Jy^ÐhPšÍÊŽfªÆ”ýf¹*·©‡˜/ZëÝÆ;“ëÁ†‹ï®œó2P{ßêVWGš¶*n&˜UiëNjH{:gÜî=k~²†^,^ƒAËÉ¥–E]ÙfØígàSruñ«+q.dÇñÈP¹-±¥@¨VmØm½)¼@!�†„MóQŸ‚ÑGÛÃÓª¦ðÜfˆÊÃtäVNˆ…f§ˆTPàœÆä(´Á "¶}%ÓÞÏ„?·«]»úÙ̘'£þóÃ/¾zÿîå›ß~v<^?þýë/ß¾†º»x+;‰ÒA°ŠÂŠñÚ¨•qavªXÖ0+ªÓEÃrêàšÊˆ—�µ®*Hãª1/†Ë§´Êè–в¢û`E\ikç=•p3#Ÿú¢â„'&îõ6îÌý¡J“;¢pœYq!0CñPgÙÕ&ºÈq²*X½7 ×Íqqu+èdæ±³ŠbLeBB0 +qÈ'κk‚J< ))«ÕØ‚$‚n€B„ëjÎT<Œ§§ð g$f°ÅåÜŽúJ<’fù%¤±dãXïQ®šÊ«gCW‰ãƒÏÁF•J¸j]S»*çÈÔ{«^ED�tú5h|9ìfè}3hr' }³¨Fâ6gp*pXlW ÆAÌÕÌÅI +k‘Ã,jÖ#±ÙÒ—4)O¢Nm`kÛÉ”ÆùÃjøîFe•{CRöHÌlIAô°HudÑ{ãÚk¶$/<Ú²ixŒ·úCóüE Óý*&ªaŠÌ^ª8ÓJ£�€Qà0y¬ÝÑPÆy6Ö±FÔâ(Òñ¹Îž–4Xª°¿Íój'v&nÿ°¤±HÂ9è‹éU³õu2]d±PÅd „tHÓÌ̈q5ð +>¹oÊóÔT½)!š6ãóqêâCZ%ìª90…zp!à|€ü]ŽY8ìÂp`dO<º£–Âi¦{+rÆCÎe|™¿@òPg«¯Fj\VÅ\Ñ<fcþÒŽ¯B¦¬"©¹‚�ˆ�NJH³¶£i„²*î9dŠ}d¢™)1 5•Y%øÚAŠõÙlDpº‰Œ…õ!o®^²µª”0ºÆs\!PWuEófkT’²V#pÉ|¤Uç$À"1¡alVºjIT8kmLT@“6^5MMzYR¾Æ4žèn`Ù`¿‡,OŽD0¤IF/sb4µÐ +œøãB¶â¢[| `RÊZ-?¾\[Â=]¥tbMj²_è&˜‹ºë1û}>±ùÁ°�Â#ž<B°ò¬yÑ +2²ºÜ¤fç¬^¸¨ ËN¸¬bÍkt¥•Äqkq$œí8Ÿm±Š,Žu^t-3ˆ1kÜ ++|£xõU¥6ÜÙõyˆ$XxÚ76Ð"AV‚1#a6-z‘®¦,TïwÓh@äY{p‰ó=1¢P%]Æ-tk·¸ê…JQeST“€4p‘“{3ˆֶ^ÐÏEZÇ㇎ -Ùçþ$z¬š(£éfÎHG’52¥OÌ“žtÅMFjHÊ®6ÅÜlÕV5�]êŽFz62ÞTÏ“hR¬J$U§£ºéŸ†žCáypP»¾ÆÖjÖz‹‚ûªj¾¤ð£E²Òt4r0‰Ù¦Ç Ç`rö=’.eÝÑÃhd âN�Eçsrð"£†~èÀnTÄéÔqB‚úß-Â…×èÖsN*‡öêuÖLöt�E{tVŽGJ7¢5ÂJ›¦2%§`þUõÈYDj»©FšÃÊÆw¦¸;€-)=3#;¡™Äh÷Z³AyëH^°ÕÖhÔlñª˜v€§=,AeÛ½Üý9e{íy LÕɬÉÔ‚†zAÆe;PÆDó†áŒçVÍ´DuOc±°Æ4^„ÇÃP»nYõ¤unýÊèý슬²h,¡¦1¤§kæºaVCè_šÿ ¶‹¶LW_T4ùŸ7„™.œ& ò^t~,ži1(ì°GúÃ8ÈI£ö3¾à敇ΨÛ~i²bÂái€¯hnÞ‹Ás±eLäù‘‘{±¼p\éíÉÜQafSÇѵ¨»„€îˆ=h÷ŠpóEš +Q‡(§þ„ÕR—ÍjâUØÂxD5ôiM‘¦‘ý?‡Ðxú³h/0ßã$–Íb +€ÎÀÉB@§ÑN…s`h6¦¹Â¯Z-lÿ³&½¬À+ÌŠñ^8WÆo¦ShAl«A,€åWðð0îÂ!Ûâ8‰±@zp>¨èI¸@i÷âÁåš$s³¥ y<×Ëdð/æ+=·€wŸG"”ÛŠàEÉÓrû +A(e.fdã1K¤¦!é°vèµIÆ3͆h=¦¬HŠ¾!aåqÃj<õË +hzîD¦¥:dÏåP-ó„¥mÆ0gñü‹zŸg>d{T!ºAí‰+çú²XNK¨Z°…¨æîÙŽa]»[à’‡¦šo¨=*U¡Ï$@]^ƈxô3Bl‘ùÅ4"`ØÅÎöâ]˜–¢¼ÑC·yx¨¥ôä¶lÇ-!«ˆóã3F°0„+h„$‘%Ñ£ôrÃà—®ñÒ§ð&ˆ2¢ç=Ò¹B·¢2 ç4!4ë`& .lqÞÑí²ÅR>àHƒ>C‚kc¶\_-67ª¶¤1’ÂÌšÎw[7EÛñ˜†Â"ð.$-¢–̇ ÎsÏ®è¡ç0cûŽ¦š±°›@L–vÞŸe¬Ž›âÙ8SÊm–¿ñ»²àâ¦9 š}Rļè›QŠæúc(xU�ÑT:j‹zŒ¹èƒ²•–,¦�BL=,É:;3ȪÁ!o,VÖ¬°„ŽÕ¼6¨‘êÒ.#XDα¨ú¤.2~†"5@èU0bcJ„kð§‚,<Íjy‚ +Q\Ç+NIa%ìM4²boŠ«.×T<Ü,L»YTå†öÜ- ¸)D +h‹ÑÀA†Ý¿›bÇŠBŸÛNHuqEꌪIÊu^Uæ!àü*ZÎ^˜\‰Ñú°Î1ÛÐVís`ì\i^+©àu$²U<®~8¤Š®`½¬h‚�kW-÷6 sÌÊÊ@άg®0Lx6>WcÞÓ\.³mÎÑãZ³Â¯$rK +7X´áXÝL’‹úY½VøÌIÔõæWñ êqs@3•þÛU?-(NE— h"(cx’!€Ë"´X¸•ûÂ\(cÚ†èT“‰‰§^«ë“èØ™ÖÄa‡–gX,îší�>Æå-DaÝ4ᎴŠ2ÐÊÕÌiø}«…,I´˜Ãßò“HatŠet„¯æ¥ahvTÞ�’ŠeY'öâÙŒÑaà±KŠyIÃZ(зÃ7=jR-½8±™G¤z‡5W³ÑÂUQ:StÆζ)n†Ÿ™ï¨êºó«Vº€EÏÏ<ÎS? +àŸUºÆ"‡ê?…Rf&OÀÌêÅä[’'²š €š4K2ùYå5Øñ¡3 $å¼j84S9`ÿb:¨ÒSV1ŒDË÷@C/ÚNN o-uõmÓÍó<Ûð0<ƒAÓ8¢ïz³¦Eãûò¸ApLØS–d¹tÕÙÆÏꀛ›¯W+mÅ:DƒIõèÜ<¨…ÎÝv*bÛQP“:(ƒ�È#Šg 7)� zË�ªÙ×áý£AÎj‘�Ž‚fÐ�Obz"ÏùƒU¢XêæíÅSÆ\*¥ª@Ójáz8ÉÌÃ$vB]ÇˌȼéЪnßÀC0ñyµóœ ²[Uëx«µÍjFÐ #¤aî°F¬žÅ†Q�~j4ùªZ&ºÚ•CT¦£°´ÄZi-Y*`¸v݉¥QãèêbÁùÕ A€ ’áfE/k6l<³€HÿIÌ“–³áâ®æátD’¢Læ“Ù¢¦dWªÚ1D©ÒÐØ /$bñaˆ((ƒ�6Ž@%ÃFJ=x†˜çÞ—çÍk¼ÑØGT#<‚øÌœ…[Tì +šii•Lχ S‘m,Ò[•l×Ûl½Òvâ=ÌÇšÔˆä‘bŒ:Âä-LÔUÍÉ¥·ju©¶¡ó2@:`B‡Þ +EÀjAÔ~}Ë ÂË€²™}—¸h 3»¥î$\`çB&//\5vWfT`Çò8¼¥¨*«¯f)Ä@Ugså +50‰X`ªpp´>VÝÌ€QÕMÎ<¤T>Å¢0XZ5¶æ[tO‹æQÔ5 µŽÍu눻DËN¿·A"©+Öú~ÁM Y°�Áφ£ƒuÆyNQ¦P,1c« +T:ŠNÄUUÃðœ-à†`ïÕ‚‰Uƒ¦£gÕ(afœà•IÜñÕµ«~Fg*T6 +AH¾Æ Û¥ˆD{{Gz½TÞôªß†Ø‚N\4GzÑ4?p°ò\Nÿ{o·³]’¤åAŸÃ·cÉFjXùŸ¹ e,c!cƒ,«5®i`¬é4ùìýÜ?‘™ëýªð²7ؘézã[k=ë732âŽ+¢Ñ ÞTä² +ÃÆ^ª`-¹Áƒrašë×çó¨|\î]MˆÀºH�GxöK¤%ù'Œ…Fkç6T”ŸR=¿`Œ¤Ñ+܆ýå ©h{MiA¢¹Âeõ¥*gT~rV¦ŒŠàç×'ÉýñùcÇsMÞLèý$°!oØn>–$“bik`Nª]-.ÒH&PðpJ§=Iuí×ýGyËPÆ[_q³’ùôp°Ùƒ€çåT$ñUêVwÕÈWßè‡_Ññú;¿€pþO>Ðÿ÷0ê/´ÝÿwœÝ¯ýܺºßÔ]|©iÌ ÝÍlIU6s_4¹º‘»e)½È]4ÅûÄÝÎ>"ýîb-78x»X‘~~wãv±†šj)¸i»™5-uÃvñ7N5X»ø»ŠÐ»Q»Ü'µMÚÅqÇX´›Y³þÂìB¡h¤Šˆ³"z.Èn³rëbìB3M؈]J" „ÝjEÔ°{É×ÅðÖÀëÖ¢ðí‹®[‹”ü®’;QÁÖÎ~¿ÐºL²ådÝj…ÁºÍÓèÍÕ…¤RìWcuƒu¶©ºˆØ胿 ºˆZä2S—½yæ:H]&ãKyu›‹C6P·ií6O—†ÞÞ8ÝVÌYš.Ž“çaé6‹È^(]´Ä¹@$]èSxébe&”ÂÅÑeú³ôƒÑeÁÐ8Ý>CÂt1táñ–8wŽ!Íit1‹àt9U÷zø¹¬Ü +T1>±¨ïzÑs£bÉø\‰ÍÃÎåŸ.ÌÝÑyx·Ê{šœ‹Ž0šA Ε!¢›;©j.z`¦h.’ì(Ⱥ™¹Ë5™»3%ÌÅŸœ.0vY5h¹+i~1,îV'7+wvå!•‹/«Î å⼫öÝ \ˆ³O N.Kbñ©'—3!n7q˜Ó^›“ËYÏÄ[rr-"+/N.5døÈÍÉ¥‚,I +©õ$Ô/Î^Õµ6 N.îûcmè£8óË%w¹ËNPrõ« +P8##¸ucreœkÓla ¼oºÖ£ÁíÆäò]¡ÜÚ˜\z+d]»1òxcr—éÎAÉ»!é“ úý¦×f䮬_ +D®@È]Óú©‹>¦Àã"ª€Úí ãâ4Z¹Ù¸È¸3V"4.^ýG¥îb9 +Zw¡ª¥ÍÅåËSƒŠ‹¹+¾‹‰>©Ûû0<Û–¬ â¶CgÛ#P³î/x¸`àG‡Û¤ø»a¸Ma¯@ᢾ¿$\üÍ_¹HzHP@,ÜMŽœ‹€³PÆ ÁínÔÜîÄ` pïÆ+spYKÛG�p¡Gòk¯Y-)wão«Ky‚~Îõ}†ßŠW^ìÛj¼H°o««T}‹¿r¹É·û8ß2ÁÙ³À·µªþæÞŽ½Eº–Ô[øPíé/ê-WD«ô6w=÷`Þ~uÍ")0&çYÞÈ[E 4eâ-hM|[o›»Þ¼[Â!ž¹q·ÍåJA»Å>™"ÛS8‹•†ÚCŠu‹ßéìä.ˆmËZ\ [¢.n570·ÈS#òtQnQg^FÝ[Tl3~lÆmt»·�xâ•2Ѷ¹Yëù“B¹›o„q9tÛ–½4ܳ„ùbÛVç—mËïEÝ"Ûî?/°mJÂØö³PRá«a-Í7Ö¹mÐ=kÛ\CT[x¡¸ë7ÔnL¯i‹‘„É#mñÏMÜM´Å©'g -e(�žm«ŒåÝ4[˜øEg‹¿q׃f‹árf‡‹pP³l!ÆC˜%X¶Àª4AÕ÷䀜#Y‘l¡MD`"@¶¤_–úâØRÉð¹I±ÅàYÎ7ÄHÅa[S‚-H”ü/€ma?‘¼ùµO~^À×âï´Ê‹^›—øm¯Í +þº6þ×·6·¶0}•7¶¶Pš_ÔZ¤Ì²ŠžXQ +³ÎKªŸXøz!k‘‚ȇbEWu¬…¤€HÏ°öó¾âQX‹9NOÈS=ªñë›V‹Ò‚6¬®ÿ3«ö‘üü…ªjmŒCªÅ͹8µ‡¹›R‹‰ µ˜A©…䱨¡jÒØŽþ…¨jóÂFÔ"-!Š¬µKX¡ ™³gl@-Êb6[†wO©Ha&ÑO)(à6%4íRÔšYcò™mm0mü}siÃXÚ¥µ¼‰³àb}AiQQ‰Fʱÿº‘´ûï‹H¶�Ò¢ÞGÝ<Z¿f7Žv±\¼n-ÊçᢌöáX°ŒYܺ¢ ÑBÞA˜EÐhjÅÊ›F‹¯“"‘ Ñþ–i%¬EGû°bV,à=à ü³—‹F¯ +ªë3¿Y´ $díçeá¸Q´T9–7‰³ô“6ˆ8›‰øe€h1B0rƒhÙ=}΢}@Fd>H´Xc`¼A´¢h¥Ã¡}Ì-‚,e¾(´#ªZÈdžV‚A‹qçù… ÅŒÒQWj- ,Š‚„ŠJyñgsÓÐoþ,+›U¼ÌL;þžâîïTSÚØðY䔲f³)´s¡gá‡uá’ÛľK³nð,D†ÂÜÜÙ°vÒ9Ó¦Îò†½qtâá] æ,¤�9‹gwˆ‹8ÛdïIZŠë¸ƒ7‹{n/Ú,òìdÊ6[–á¦fÍ‚aëÊå]ÅW Ò,F6."ŒmE©ú›3‡ñº°!~G)³ñ÷ ™Ý63fÑœ÷aWïÑW—5Z„M庳jˆ1úF̦êbª˜…A8¬C˜MÅYÜM˜ÅVÂZ̃ï…0Kkº(±07|ÙÄŠÀ6Þ|YHXŠ}íÙEóß|YZf.o¾,ŽGùâæË +ºÊáËJS¾�f /N`0Ã]²ó˜%:u¤ùÌÒ*䨳øæ47`–ÿÁôÒM˜X¶ÌC˜åÕ!:³ ³ü§d$ï†Xåéê¹ Ì2ûÄ#³|4„¤Ý„Y$ˆ”Š2a÷驳¬ž<_a–y1F +ƒ0K¶)ªÊ1K=C—7b?€²—M˜Åù(?„Y’á×›0Ka£ŒA˜%?»o±d–ÙįaV’¨~�³4°sH�fa—è&ÌÎÊüef«TÜ7³ü)Ãxf™Ó‡dÂ,c<Ë÷‰Õk« ²óÌ‚¹ ²ø²` ˜xY4ªR«´/»ZT—š/ËÆ¡Ëâ0ËiÏ —EȆ6زL©¨ÂlY\•H/¶ìZþ-»’x~›,‹ä@ªo®,â„jf¬ì,Âmª,Xo¾ ²3GÓ43eaÐHYe/Ê›(‹m•(Ëð²ö(Ë|~ã ”å%ç§ ,¿Â�Ê‚ƒ‰¸äÍ“]®E4N±*ÿM“Åßµß,YX(+1Jx]#I–°ÍÏ÷tƒd³î)m’¬âäN2°€�³Ÿ0ŠI–ƒaÌA’åM¯zUÄiÀ¨~£dPjlH”, ˆ¶J–h7JV9˜–7JVi’96JVù—5_(Yœ2åa’e¹ ëk£Ñ#ÊMñ}Ü,Y¶8€† X²Úù™%Ë{ÂZ¹‹%K#âçfÉ23Žt°da`áfÉÂZ²di@\%X²4°-ÙÅ’¥ä‘šÃdÙ_Àd1|PqpÓd%ƒÌsÓd¹f¯ ɦìœÅM“…‘é… Én±¤h²‰ðžÑ^4YéKM–„ñ‚&K›Ã\4YŒÚ¤ä&+¢ÿJA“ekoX7OF–ÉP6‘ZæÊÒÀ*î(+#’Êò8,84P²Üo ,;! Û@YKä@Yöå;|eU4«²hWÃI;ˆ²P>SØze)‡6FšDÙTö5Q–ó¾²4B"HY©ª³2DäpñרMº‘²’Q뻦@ƒ–jI”Ý +é›(K·®e rx‚ÄOg&ˆ²Ñ?éPÆÄbÈ ÊÂâ)ê‰ðõä7R6öFÊòXìHYˆâ©²|!eqò³)ËùX ZÚàÞŒ/DY*X^DY짂¶ ÊâFˆlpe!a7ÕÝDY¼Xü((›š;F¾€²,—¡"$€²ìÂ¥Ô¬²ôÅHº²)2Þ(+ËÁÉ~ïÂoçcé#¥øÆÉ +’7Mc+¥Ñ¦ÉêÁ¯ôÂÉÒ_,p²84ÌÁ“…³ÒÍ“eš|Ž“åߘ¥‚'+C_/ž,~iäÀÉò{@’~f£È¶\ ù5”¨N–yÉÔ7'£Ðló“ÅxæÌ"m=Zk +%Û1À<óE’…í1óujbJÄ‘…:w¾(²ìD÷¹m‘í® ô&øCÂínéY`£…#B«XL?–0ÖUÃÄ^¯ozlü}Ác·ÉìØé97¨°`¥²Hç"ÇŽ¦¨ñÞ¦àØøûâÆn“±±Ÿs§ÎÑÔØùZuAcƒ–ÌØùhhdì|Ü0ê"Æb“_›™/v>zuo\ìpœ Å27¦i± ›wÁb -s³b*¨X ?Á Š… ŸR€bñ7r¡Á‰"·Þ”Øa©W@b‡»—#–AêÜ_ˆØn!±øÜ&KÄåÁèpb€X4¼A63ø°=+yáai*yÓa±‘„†ÃúÃèˆUÆFÃ"™‰”³È°€a±Y}å·Xì\X$f)W1vxMxSaÙΔ¦‚Âvq Û ý»‰°<‘ºy°l3}h°a¯ú‚Á²¸o¢Y°ÝÄÎ@ÁîClw~/8°ÃI“gÄ¢À‚JP °“Ò…|Ñ&ãBÀBÇÅÕIl³´\ +�,IWD»þ+‰¨!S* vÞ#Ñ_§õ +7ýu4ðW¨ÝY½dö+P¶(ӻȯ‹¡Ý²Á¯Xm²Áƒ‚ãïûºM¦¾‚ëÒEöVŽqq3_—¡0|Å:ŒŸk _‰7hjµ‘¯0JQ¬ˆu(]éšÊ/â+HCñFù[QKjä+· ÜôB¾b +ã¨ÈW8”eó^gÑ¿q¯X&¡Ò?h¯<›G©â~Â4¢u× ÀUÀ•îUn‚ ¹jÓ•Ü)öƽÚU(÷ +G³À½ÒÀòå÷J?‹'nÜ+ñ z‚÷úËñÃoþ³ò^BÃçæ½Òˆ(cð^V+y^-#Ýý"¾2(áI_‰yàÁE|]Uï |ÅsuÀ×½à+Â^ìïy_ÕúP‰¯4àœëèu9õŽç‰RÀWEÔzÛÀWÖô‘Ô~_XzœÌ’¬¨K@ÄWÆ/˜¾¯Û14ò•ïŸ…ª‹§+‹ý…|½Œ¹'GÀùJ¤CSšf#_)4‡ˆ%¯‰°Ýœ7òÕЊòB¾R!H=€‘¯b‚µ²‘¯x„\äÜÈW”g` ÄW”™¬jÖå¦7ïš$C¥é5Ã'Å(¸WÆŽªºümÜ+£] Åxܧ3p¯44UæÚk߸WÎÀ½ò×ò|Ñ^£codÓ^¹¬¬¿`=#L¤ Ø+Â0îÓÌê 0›°FÔ+K'r}‘^Q4Dh¬A¯cŠÛœ×á"ó +[QE"UíÃõ¢yþnÈ+tiËLW!EËÂëèŠäÜ€×Ñ\mo¾ë*B5Ý!²Ê/¸+ú5`L ¸k_îni¶kw¬íF»‚9„ Q]»"xÁu%£h´Ö•ÍC™ÕGÀPWöCãÅtí®¾Œ2Vô°Èª\gÍÎëí›èÊþõl +sÞ<W°¢àäÝ8W¸¼YçÄdº]a®ÕU€7ËkG7¯§ƒYçÀ2ä¿á‚ß W64ys\Ù+'—q€Ê•›âŠúGºÜ†¸¶¦m‚á +eÖÆ7Â6¸òp…"¦ ½ÊÕ$3¦µíêñV•€k«’Ã^û°‚èÆ·¢œ%ïfV„øVÔ’`þ¼é�MàwÞÚæîIË1U0$ë^ìVØð麵yz r+Σ˜¹ZÈÀj3¸ ÅqÔ} ‰g7¦Wº\+�p)7,§7³uº‘ül]^ݲu¹OO[¡é%âí¶B0Ê"FóZYB³ÖƵBŸŒ�ÜEk•Œy³Z—ÃØjÅßñ+Aje`®vZ#„ VÔõ€ƒpsZQ£Çµ§1Ë¿ ´.ÇsoH+rz3" ìŠí«Šæ”ÇÒJ#±Â–O%b4sÝV†³á«ÞV6¸Fè/ ˜Ø $£5E{‚‹ÑzŽdF+DУ•ê}%nF+¼˜x!”¦‚ÎÞÙf´:5»^ŒVz^lý`F+3˜u‚ÑúÃÁª_Ѻܲå…hEÔ•Bÿ ´"êÅ\Ï`JO&¶n9Ë"¥ÌÐV0¨ÔtVìÆÊ geQ¢¼j¢YWðUƒ¸ªpÙ…jÕkß%‡±º6M¯MXò:˜•n8óõfåb‡©å�³2„ç¾Weµ‘æ²ò¼P+½¹¬tpIÞúºc¯ÒÙ«Í1+bæø¶±¬´°ëe嬅1–•ÉÄXÖý÷ee8—ÕúƲª2wÖeeþŠÕ–•Áo6ˆ![{¤ì.+=ß,Àê©)„ç”ÓƲ"ö΢#SYùïEØMeåáΕ5E ²R¼Aô¦²ÒÈÚTV8¤˜ÊÊÁµ7••ÞÎ;¨¬0°:6¨¬0Pm~SY¹¨äØ/*+• K!#ý:F‡©„Ц²r‘‰»XV¼×í•U¹ÅR_TVò$€4*«Ü©o*+bóSn*+MÐU…`ìÍeUD_ãÕ¦²RÅ€@QPYi(¢°"€Å½ª7§¢š(ÞkSYÉ¥K +æ !Þ’nÐMe…ࡾ€²2×6“:-n&+xZLOïà9¸`(+Ò|?n(+ŒlÎ*(+`@tÊŠô#D7”•ì1,9Ê +=¶€²Ò�©ô e% ‡õü†²ŠØó¹›eån¬u¹ ¬©ÙM(+êZ¹¬(«šwƒ!| ¬L[±ÞÄPVžt•/@(+ðm\LVØô[f²&’jjÝLV7¹™¬0;LVnÅë7“•NâÄo&+òâT˜ÉŠ'K|U0Y·áf²£™¬88A[MÔçùb²"cJ§ko•µ€ $ëþû"²†-€¬‰.HdÝ/ã deæuÙde©0’ÓdeËüÓÝÆ%÷L_0’XX••É(ý½ëø¢WÝü¦äG<"ð¯X?Þ<Vâš|HeK°ÞÈÊμy¬D>Y’š¡OCUñÁcåÇääñÕa¢Ê50w$ð‚Ç +=›Ç +#õÁc¥ÁÍHÉc¥áÑqêùV²Ò¤&²2»J‘SY¡WcIÜ‹ÈŠÇÜÍY'“üCý@ d¥|‹ÀÈJ@]_4ÖÏÊæÈŠ·ŽŸ^DVXÉÞDVZðH6’• +Ún$+ÇVçd¥bŽU©d……q«ÉJ“ÙO#YI°T9$™y1Y·m3Y9Q—LVÞ«Y¾@YaÕ+e(+\ìo(+7¡f憲ÒÊ'PVῆ1Âufx/(+EtYK]3g×P±¡¬d(AY°e}r@YYIšq«|ëyÝ”•‹–tl+z¡pn"ë1´ƒ¢†˜Çúý«ºñŸ;Q…™88VU•§Mc…·ÎVÀXÉíõÍbEˆåµF±v©«7‰uª„ýbýØ©FªB6`a€X±jFƒž›ÃŠu\¿wP'n«õž/+jQ$`+ÚkˆC"+â•-Õ€’kTØ›¿ŠÐjfƒn +¬,ä7~¶I$«è«Ò=s³W¡ªG±Ì^…:^Åß!~“Wñ7Ê{oò*ᵟ!ȫОCÁ°O "[®FJŒÉ¸Å®B]]ðµ»´Tº…tAW¡¼!^ZjYß¹Z:[b_¼UxËãVÙ{í)›¶ +ª]}æ¶ZŠô�›µ +-x#’Õ%0 €èEZ…’Ñ�îóá¬DÔJycVË’’””UdBÉÔô‹‚T3[$\ŒÕj¶\ V[cV±`çºö¬":AžKĪSŒWíYÝtUب32\û,e&)}̸Ъͧ «6·Ÿ°j‹©æ€U¡:a Ý`UH"ðž« +çp¤TP&¸ÌTFÌRu°ÐïTE<‹–Jžê0Ú'pªØ‚›¦ +¥ó_†©b6Ù,UÈ°X§p¡Tqy˜¤ƒ¤ŠËgÕáI„j½9ª¼A·Uf«ENd¶®«Pÿf¨vóü¡%ÂAPí®ÿ¿ªlxPÖæ§î¢OãSK“Ó‹žZͼ +x* ŸH™ÚÊÆGnt*A¹nrjs[¡�§6«on*lE�TªjI•èySS[hþ¦¦Vìš +/Š]Óœ<Cõ{ú]ÈTŠFÙÄT:ðᘊ;�%åÍK…íY}ãR_œß–Z˜úH/Xj T‚•ZX~•Š?3®ê"¥ân<”Zðê‰dÂae~yaRQõú/V”¬é# ©¨)"×õb¤² ·HùjmB*ò”}¼ø¨¹«È2ð¨øÐ £â燐5#ò´ÃFYH¦›ÂV~è7•€tÛ�F…€9¾�£âeÍœn.jÚè9XTÌp +ƒŠŠøÐ#–ꆢ.ÖŒ§ÃD¬¸<HTŒ[zµ w³‰¨ÉS¦¨xjzáPñÁÝ*t“H_ ³"/÷‚¡‚’�ýC°P@TŠ ²ìy|!¡B=ÓkvýÉ/l½Yòƒúy±�›ØTF7ºÞZÞT„J=TLå�P‘áLýÍ?Eôy̓?ūʶ¦Ÿ~&þªŠÈ?-r^‚}š=3ú”e½x‹.ò)Ä}lî)$áö¥@OúB=�¾nè)e\*\ºP-{1O%U`cvIbCt«e)G–ºÊ¡ÜÐSDÓE‹6õ¡á çùÎÏý5h›ÃëÓ€žB�ÅU0OÈS䮦(¥›xŠ•8d<EÉ3„"Á;%q ®î£|ÓN›I;Åßc¾P§Íî ";ˆ¸{€NIŒ÷✶&ÚHŠH‚·�S�?œŸÚ”Ó™v”6,–yTµ4 Vã7â6ÜÈ œ.cö 8Rÿºñ¦ˆdcÖº)ª`Øò6Hœ!³t³MçT[Ï@›Ø3˜¥c*]qƒM^ƒ¶>% ¬iü}SMÃPÓáÙ5p¥£ky3M¡°,’oÑ6“B«A4Ý_@Ó°Ï”ÖU7Ît¡pÓL!1%ÉÄ0S�Íè ˜)gy¼X¦Ã½he:¬u p)^í’Çd +¨ñ§zMÓ¼c +¥[P;ƒbŠøZQ¼±þ]Å”qÄôb˜NCfa:Ýj'¦nl{óK³l5ð¥ÌqŠœÄ¹N9ÐzÃKƒÚìÒ9Ý&Ð¥Óß‹\:™”~ËEI,q p)þÎ +on)minl)X¯-µõ)ðÁnhé:ÃXÙEìHÁ,e•G~KB(€¥x礛7¯4Zÿ¾p¥3�ŒA+]±Z X)Ë®Ú|³JM¢Ý¤RœÏê‡SŠ¢VâݘR„‰ªÎ¼O*KHé>Â…(‘C4¡t:Å<Òø´o>)d¢Ÿ +O:“nÜÆŽŽjÙM'í + #2-ÄošMJõð¬o4épSêM&%£—&Ï©? iïxNªÐj;{•ôcP]æ %íŽön&i¢pÒe·ÛpIM@Òn@ËbŽ¬òž”’•úmÓHQV7:ÕÕO/i]Ql)õé=:.IY-žvÎÙTÔ±g÷LÕ¨N|¿ ¤ÍzÍ ER«µM AÁ½¤ÈBFüQ®†¼jCI@4-T(*ݱ¼¶f©˜6{´fõ´x¡G+×2ņA5Ñ&VËùnð(Þé¬l‹\O`G¿:'?üŠŽÏ¡ŽþÔQö_¢È�#égŒ•d¶4w§%Õ®'·eZÚŽ¯(VŒ—Ó’`h³ætwwBtŸ8þÔê +X]!zW×’Pk‘äò0¸ MG¤uç†Á뽌bQésh3ƒF‡å,Ôx‰eý VU‹¾f;{>HØŽ• W”&—§1eÎy9ÈWÙÒÔ™L°tHÆê#ñƨy]¨Å…O¨å£Û +d¶â.<ÔöYÅ›-ÉÑA'ÛÓäþX³9©¹„Ö¿3ÓJh,%= ‘£µu‘†Ý·kR\0,”q"=ÌßÜSšM^±ìeÛöųÅzžöG£&ÊFþ½WåSÙŽ•ó,dJê û™‹Û…“Ɉ~rQ¼ÄãHÌ#,k¨â7£+1Y£ì¿Cå;P>±PR›žjëp&]`Aè’Wý]²HãTCíÆV9Ý͵`é-þ ²LK/§9¼�mÐRK…G®6L8 ©;¯®=#'ÆåEÒv;a@›Ù!×Ùª+׎— NC¥Ðs€0T>&„®Ñu@(5L?ÄL—Œáòq+Á`1(o¬ZT GJå·:ý)Ñ’âláõy?d>ð7‹Rx|Vÿ–Ø�|·¬¦Æ÷ñ» +ËðV<PÕ§¤Ìã’Špõõ4;ãóRn¦¥.vTv_(|6cz²†•‚ ZAô£eð:‘U4À©Î¬¨ØM•BÃJSV¿Å°_~ÜãR–¨ô^.ð„UÚ8MM×W‰8.º,YŽãOÈ q<õD¬„-0*gu¥fst0Ý÷¥ÌQXùºð½aŽKæÅ–Ý®_ä6£lƒÍnŽCa(n'´?~!ñk’>¦1Ï(ÂÎ(~fßé; ^§S9ø ÃU@Àè ë,ĺ±ûj7°£6›†Àñ±ò;X*@Ñ3YÒp%.x’;R“̓þ–Ð §¸;µ¶‰]ï'ÌIìçªú}äŸü<(zà7…ç»[AàDé÷,KƒÓ\Â,é“Ë[2œ�‡X3²tÅoX€çó›ŸäW‰r+?~ÿ8íA'ö$½à:ÖÀ€ãªX¶×$JVäýð›j?9˜É.´ÈǤælÅžÙø(±ØclƒúÁ¬eo®Y,™”¬Ô¸å.xÉ”¬c±ÝÐ@WÃ8¯æ _#¬T<6r»ñ·Îó ù(ÝÒ_ZJLѨ]了V$Ù»»ñHr‰_,mèYɲDŸ™_†[˱'V&ˆ!V…·•ˆb>£KÎî%ì@nÓCÿiñ'õÞ!f�ù‰æöá·Šuvˆúóá¡‚Ï(êÇ‹Ù^þV¨ãÂòùuúd§°ïÛêz˜$H„'²fò3ÇÀðø-øÜÐ*KâË^ÞÜ?éÃAÙƒ_MܸºùìY*–ÛòEB¯·'¾Q-çÍ@>„¾"{ÔT!’ +—’ËXYÇKÊr2?Ç›¾œÑJÊK·"«¥~°QJX'^2³–Ô‰:Öî.؉}u//E}xa%¤�ÖÆWAgú½EP7ïÙ„¡×Ê9©“XAŸµõêE~„;ŸØ"— +•™¯íBåû[ªéVÑÍ|6Âuln@‹ +¬Ç-Éäìù•Ý¤ +ª#(ÊFò>¨ ùbBgÆ'ÔUs[ˆÓž1‡“ÖØ¥Pûlºª¢ðÎÉÍb¬çÏü×Ovt1O ç·a§žfŽçe™BÃ…‹LT>j5[tlÆš¹²•bQUY3TbÝmIЈ{±‹þÏR½º»&qÇø†XoÃö‡EÉZŠ‹/\wéŸ:¶F¬Ø-öÑ ˆ3¸üøgµ<]I‡sª{tÒ¤^3†ü )K6ëÌ&— ’¼êÞOçOrø£ã÷¹Üóeª_'%ª´´½~íX8õH FA0:ÖÔ\56©§vw‚é¯(Õ»UÕ\„Åâl¤ÂñÝ6—¤žOvV‘À|Ü:m‘àÄuSV—œ…>‰¹µ¤É¨·2ûŠ/S‰¡@²“Ý~ŽÔ2¨L!¯-T›–&MFÓšüN7[e …{²È‘ìý‘Ô {eCº)¿ Ä_±Ù÷¬#ð�˜âÐgâÒãCÖÉôUT1o‹²OU©û³VUœÓ©"Xzúå®Zö¹ßËŸ¢Ht$¨®$7ˆºOÑYâsFª‰2�TFðܪa,Lþ‘8”rìJÙ{J}GhÈÓ¬i¼H•x°á–,tøµ§½?(QòãPÖ^€wY;â:H¼\-ò¾RÂUÔ†§$Ÿ„�·þQ°‘eÊtö‹°døÍ`=VÐgȹ¯}ñ¨Ô¨òRF5wO‘F"w§Û.áiÖEiÇîA‘R€ÉçFð”©ó¶ <cè9ÖéE+¢®Å�çç´ ½¤<B[ô¢‡Ïv¶óêŠNòÖ—…²ïÆÖD-&?€OÞýº‚T'BOÁxœ,ûè6qv:%±Ù£Ç¤|Þ¯¶ËßYئ{ñÖå¿)êzˆ‘œ²Ô‹Ác«zH¤½ +ÇÓôh©* ¥v;{´é‹Î6%ìSUî¶LEüª˜”jôpC.œT7¨ÉôeMu1)\:°D‚Cˆ¶;Ä‚ï‘>C›¬Bô !0-ÞóãésƬXšp¸®”dŠ£P%pØ‘±%²FöwÈ…òI¤i61ív¬Òã¸þ ËLK,:()~?ì"&û©ô7Ž}Ù“:C%êÛ6¦¤o4ò#@Íû +Fç”_ 1I[ÌŽ¨<²–ìŠèáí›I.ËîÔ–Gè€aÕ>[ò¿=tù0ŠÚÁ‚g¦ñüñ0CáS•�œõþ +ç£ÑíGô=ðl+©‘"vЛ?•æ;V"Õ3"È‚ß2X·W»Š:ɤǥ%ñù1¾Ö²nƒi]Íì,› 1ôêñÃWœ7;5‘Ãz¡ê‹¯úcÇy4ÍÅ”jšmhxtŸŸ*-)æ¹ì %Ve»Éš·Û©“Á°óe”oõð'·ñaz>ÃHTòeüêäÇ £Nº¢:Â<¼“j‘…Ì{±wÀrÄ2¦ÌÛYßàâ6œ¢¹l¯Æ¹åbHÆ6‰½hzM?߀|€\æŽnÂØEÇÀx„ÎPœrJTk CEˆ†êˇ•Zô׎d ñøIgªV඄ž‡gy;å‡'àí^e©€qp¾&åLÂKkp3x´¼ „2KøÉâ–ã<…j$¬B0ðÓ�#—mŒ‹Áv° • + »ÇÔSxÇx8t+.]iÈL¿aTXPÀ‹lV‰ð0/MÓ¶cw*+þ·Jsˆ‹eàH;º´ Ï»% +7áíRõ9 &ƃoX"FsO¢¨yII¯cÎU(HÑ9(+•«‹Ü±_¾Y¢,¥"ødŸà#w:£‚awŒ‘Õ)}XK†nXGFŸ”``F€ƒÇJ{G:•¹º!……#,,<äO¦eƒåW™šTœbMJ[3’Î`?_2†r‡*¤q§Ù�-B~ûC_(Np4‘áŒN)–a+ûÅaj”Ý=L‘ò¸Ÿå£nç0ô\÷~³7Eó¸ Ãâ P(°V¬Ã%“"0éÏHõ)Pœxi¬X'1 +Í÷xX·¸sì£l5Œ0Bª-#N„îV<UB£ï@‰‘Fˆ"Ùþ–Ø!X8qCDz|å,eè ÉÈô½ÙîØ,îtüÃß ¡ˆ"a#ñ¬eVÛv(UTØx¼K”c$æeââ þ§fí)Åòc‡ˆ UŸ¬Ôã‡;Z8‡b¦Œ>ªÏ«S@þ¸zÑâÕ„g·¿gXcöS…²<–Þ0¢IíÐŽ9^¶}XŒ^ÒÇà]©‘sÂ8ļ"<£Çªœ 6cÒ !-ÜWhÃø°ù€ª¬ëÐÅŽ‘ïÇڜܪˆ}g‹v$‰Œw)™!E+9긲ÅÌÉcØÚc"[f7¼1lÉçÓb_lÞ¥œ–ó+:‡©¬U1âæHÂíðr‰#’1~Èf1?—ÇxÜ6%_9:ñâCKîæœ1 ú[”…2J~¯•É!¨è¢=�ÈZZ§ºˆ!Sù[´ÛpF>нq‡â! ‡[¼¢· +”0Í-Çr0ôöGãèQBVÏvÙMà¨L(÷pô–]qþŠ¿¸9ÅU…°1:–h1Ôƒ°¨Žk–SÝ «<‘)uL¦VÛ]´÷O’–Ù=fg¶¹ +¥ï'ü©GÎEDF¤(ó!ŸÕnè–þÉÑ üš=ì5¼¥°´GÛôPÈË:uËØ逇]Žqø½Vô‹ëüb•à‰©•ðÞ"äà +…„òº:+âܹ\¥©È?S +pg2 „NÑw"di@IÉu–®ñ†S°¬g:¹Ç¼¶YÍ“K¼9ÂÀÿÀ‚‹3 d9+ر`ƒ¥w§§©TÖžÖWÂÊ®-¸&’¼8bUR̲Šñ•´sÞ¡POPSs’Bœ„¾Fd32"?mh2èy÷ƒ&ÑF5fez_S-ûbÀИ§]·=ɆRÒŒ@óHÓÔ£E1Ó!œÀ¿Ø~@ÎÕ‰t •æw³”̆TÝÃ+B©ò fÁ¤À…]ŽÔìsCw™-üâ?çñb`*ˆ…à-[¼¥\”ïÎÌâ]FùkZ`l ¾*ª2³¨ëáf¶ˆ«Ã25YÛ5¾e$0MY>ËGýä{U°×ìë^Z^e®PåTÝRš=ã`!n +Q}9}ȹ3mÓU¨!;¹¡çèž«‘ð7‹aàtÆ-ÆX{¿NͳÐrÖŸ�”ºëg̓)D`¸{5%N•°`/¦«7ªkSäÔLÉVOJD³¾‰;ê(á`ìTÞÁC6«lsl7jÜ´ÑA<d˜bFáG¸+¬¼×(ËÞNb‚dYZ„·Û+§Z5àÎ#’`×vÌe1×=IíÙLøœì�Æ"œ¦ °”œoÂ"GªÈù9ÛfÐ Ô|†ÛxM +Û±>î"³<¿³¾œ§ ^Íaѽ- +ԟͲûÔ¨mÜFÎp¬•í‘ ¿>³Á&÷s:€ÚæI+ÏI‰‘[ÀÂnÌS(Egò!"É'B4£{.âËÝÛ±ï",lôÃÜýÊa‰(ú¬&Ô´¥N=Ì€Ã@5 š!/Ax‚ÐÌÓ0TÃF-‚3°LŸ,k±˜Ïg¢FmÊý,}«xpèÇü%Cáí`"J»?/jáÂyKlãë¦çJº‚êÁô#É^E窮8V ˆÒËÂYþÌ¡"ÄTºM\5?qr}…M +i¤²~ïòƒ¹þ, +âmÉñ‰<&ö‚ a·£b[”ÂÅT·ÂP®•á†¡!RŠ›ê“jXØ(½‡N~³»r-±Árr*ƒÊ£Ýà}Ar ·‡9¥°z;/âh™Iì,ù2 AÌ ‚2̦!´ÍVs÷e@Q"¥a•–ˆçUÚZJTøóm½•Î0Üvù¦90:éAÂÂËdÒÉmZ’¶32C€O„#QM¡$,AÒ=ÛáºXR¶pPʬMŒj{Ð2.¿(“H‹¸ øGš]¥§öØ‘("1â¹¼,ÑS&; ¹>çncZp9ÀG2²Wíì+3¹Ü?a£ƒøe]V}²ñÈóMA#â·OwM&4‘&‚ÍTŽ%1icº"—±¤r‡ù`1Á \aQªÛÔ£‰"'‡£ã‹÷ãÄBG†’™wÛí‡FDGŠXjŒžC}&)n KPÝ3 +רFOÈïãfs9ÈÍ80ÜšœÔU·«¸m7¼pVªWy¼Ñ‚¥5dÔi)Â^öžªµ.z£hàèŠx:¥fÙâQjj‹Ÿ|ܨ>ÑáÍy9„*‰ùÞnÖ¿ùÏ +ùe ’Ìe¶#5‚Vek»EeO¦d¹Nq(rž¿c‰*!¤§OWtÅLJZ¸)z¥7ì—ì®ÉtìÊ”öã +¸¥…rÏZ>g"º|±.ªõaºp‘Ý©æ¶c¤ÕÎM{ÅH«BQÔ±3 ~€âá"ã–K”ÙÃҟꔨÕÉIn/k$PÊÞ¸UjÊ,Ö¾ÈpŽÙ9—Qƒäµ?ø²›A'v§¹ß[§¦$Z˜q€‚…õåù±žŽš–2öž*ƒ(ŽDQœËF¤O‰s5°¸|†Ë¼Bu’ôÙPÌH *ò’Û嶙¡ÈȬW€‹Ìh-V¸l£Nœ‰…§¹^aÇ‚¡ÄSB*{A5qw"KŸÌ£¢AÉŠú‰:qô†±ñÅ{œ=--¸ G0"¶ç‰¹ßØc5lrT™ÉâÙü“Ða±jdXtèDeL ‘FZ:#WÃxî:TùK§ÆBbxÂ\TãfH´Z´KsOΔ(-dû°fÐJžåYÅMqU-@ W>¡ÇD†WW[µN©žES{G&WÍѳú® +¿P`VÝØ…²à$d•o~ì©ä;K(iBõ&æMªfuÑ1 !²diºNMVŒC…K˜<’³T•‡:ñÕP‹Ÿ‡‘:vIàÒѱTX4OŽlñ*f‹¬œ'ÙÝ.©Pk g&’¸°ì„ávV‘9Ì©²= +òœ•*Ô>K‚žx’½1G‰Ÿäª�‹ ~nÍ•ÿüy²Y£ +Öf™¢² H52(G9¬Súê=K‰aÐppÈ x1[÷I“’Y‹´6¡d6tÙXo€cŠÕ3%æÇZ%ŒÂ“atÓͱ¾âFé+ÇõAM„XÄ2t~º1ž@¶Q·Ã’Aj$œOÔ�äxïȇ… ÖÖ$TS{¶{OöÂÒÁ·ÌUìÄ8®ð½6aæ–ª‘ái]=+b¹•ü‹Ô7ráî ôÃ11BØÐ'ÿ“_}””‹ã|zLz”‹#?ÕC·¾ídò{W³ÁáP'jª9¶:–a]{ +„ËE%0¦ý¶œDÈŽ×[Ò½È;‡ãë¥ápØCºÄ³IUK¡6WºÐ°‡'ù¸ <Œ\™3ÁS ë‘›¹Y¶ßí™Ð€±µÇ© +nÇgÿ$ @123ßÊå1Ó‘-I VUBÙ$ÝáÐ�Û]@ +9(‹žhxÙ“âwœ£øÚõ¹�p:õFõ8@f„œØá85¨S“ýO䨲tX)÷‚âùt凂öÝô°rh4aUÕؘ.@4‘u¡ø¶&ìÁGß‘—ëxM]*|š¾Aò¤0ýgEŽ–\J&D ¬tÔ™+ŸÒ¯O†äØP6Y<µkàAR9¡ÄäئøÞø㯇0¦sR†^ŠÛüÁÖ©BŸÜÐò˜–^ž'ÿ{†²ŠqD¦·òãVÏìq¹vn®î ÷Ìꩶëdºôšzà̤ *eÞB‡A›“=´ÈiAy[î÷vÆ ³�L»éC°.(¨eÍŽy!|¤ŠzÅ• æ +gòcÇû²}ºÛÔ´óܽßÁØä†ï=§4“uM´°Qr媹I®Jì;¼“.™Ró_ÕiáQu[X>hµ,v(™1®_’uML“.?Í¡:¢¡ÈS<M.YDU³ò|è04?^•ÂaÇÙÓÞ‘=çhMNHƒñ�ã_TÃÇú%]d1G.Ÿ.²8¤3#R#2Æ’PÎP÷ÈØ•r]1Ü%‹ƒ`Èýì(€"Íz×—ÂÂ%4Ý~Ïž!¹´ÖœR=Ê¥¡öFˆUé$0’Pz6Ý+ü‡XmwU¤&¦Í²; !Z2QS¢D´U%±£ +äщ¹«ì®¯‰4|6ª(‚¸Û¹‚:sX9ŒBTÏÎxüp™ÕQt¬ÖPNÀÈðæH|0ÑIä‘舣 ¿èå‰û_½>ÊQ>U2b‹ÔÌð†¡÷1L¢Ec9ä' Žð/•o “¤OX”I¢HòÚYž”wPÞNvuñö“2™×˜Ñ‘¾@ø‡šcèMÔTÝ™Hl—‰’ +®ÃW|½` é# ¯µÐ«+{*¢úzN¦°ª¶‚+ëXzgayfü&üHÖWaÝ‹XJrÁá¦ï„ü«ø£+õÄ;Ër‚)]øÇ%VRÔ®€Ü0cñÍêø#‚(XˆB5¦ˆ!N×™U$ÐÂPݘéjV&F¹oFU +€ÇÖ�U(ÑŽÍ ”1–Îù!Ó n O¶ s(Ô¤·5;pQ£H¼(ZsMG ¿K— Z’÷··+±J›ä`ÔÛ‚ªäXþnëjÊvdö'¤Ð`©’{¿²L•é課ÐkH6×YWß9^«Ê°S;UuƒBÊìgñ#ѧϖ0v�í7FÓ£ÜÅIü&æÐa„–U›\ÎL),Ô~Â{Ý# +5èÛö#…¹™±d@îNffØy€ü°‰ŒfÓ$)å^3¢ü¼ð †$a/¶`Õ*U#*v–d¡«¥ÏÈ!ÛDR¸uÓÇcV–µ$ƒà”GüªŒx\¤”CËJMf4ð`Pøšý‰¨¾QßXÀP]H™�jÅ ÿLöòºÁcPäÌŽ·‚ž‰¼Ý™†G‚’œ„ŸÊ$D¬º„�u»[Å È`mza•¡•^ H]ȼƒyì¥&‚?'±æÔRþ¯²¸:ŠÛDÓpz¸ˆ×h²£Û¥fa¸lÛQüH¥Ý†{¶5YUCÝP©>5>Iêeåºo‘¦\wKM9á8Î+Ç\VßQXMV>'(ó°RÀý_ˆÁ"Å"bÍ嫦:O¿“—›ôÏU0OC²ržÆbES´Ø {ñ¢>N}OêR #ã…‡e‡ûžuY©”‘ÒµˆPp,y*L«=·µ»Òª›4¤]лø§ÿk®&Xy!XÑÔ{ÍJv©i¢@Í�^£=;½½6 +Ø&ÅÒ3»-[ @ô…:Õ¤¥6ÝîDòÁ¥9Ánw¬úVŠÚÕEš&c¸ +L7í’ÏÏ~C=öñeyÔ[n‡†ù‹J%-°ž¥¦½k–Y—Jä5"?Âl;5ýjHÕãy( +Œ(Å|êÔ5lÕÈ<ÿ¬Š‚zÔ¯CUŽ¦ÏÚ³9‰—….-xhÒص™W8BXŠ_de~‡ÛH¬vÎsZ‰‚/ùÙðÿÇÞD6i*\HŽjTU»Y» Èïz©J2KåñTp‚V`…l÷&þ$Û80* VÓ85J”¥dr�*Kº3±ôÉKe "Ú341°Ö¡«BÚéQÜÛð-‡�,ò>ù¦H'2ÒŠ`âSj2]+‰°Ò¦8%¬T/ÊRÜþê^ݦDã)uãÏHS‡ É»j.‰D·&q²ÚQß³|”¾zŽ¸^Ÿ¦ÌÃB1,<ÛÜ)Ž=…±ÇÒ$2÷ +Ôç<“)ò +» ¤} ²§g<‚Ð’yEQ9MÓ?V$/úð=(=g`É)…üîÚïX"ª;•¼L’'@+BÚðY<ÂzÈrW‘@\A¹‘ªYµêSp\îÉw¸0JQsä*ºj¨]½\Ôé8»û¨*™ eRç?øYªô ‘ØÑ©:L‘ÃÜ5Ÿå¹â©Ìfå\¤pNŠ)Z 5º2Çuа²�a\U¿ 2¡èa +-çýIOLúÁ©)ÏZéh¹8¯ÀëdmnC}fcC&HQúŸ\+®aõ¼õæï<*ª"^’|«WÜ„^ÊI£ÍãÒC6jÓy|Ö|R@ ªÎ[±awqá +¬)U]$-~³Ã5Í'¦òFP1§‡™–gÅcÿHfvD£|9;Šèö0Ò½ºDÝRâÓïñ°’©ê>)¿…=WPp7Ï +VUxE¢;ÁH£(}(Š¢=ÑhŠñËÇ]ª;²5$5H%(jÂJ@3ZX4×3q;Îy*»T™ŸxW>ùM®“`Ý_28WVÓñÛ6Ë£E”Vz4´²½TÇwÑØH¿h¥àŒô'ϲZ΢ñx6Òk7êA<Œ^5~„{"¥êÈayQRe ª…¥:;ª_ITrJ Ôdq2:27ôÕkÏa0ÄÒxa!cå0…×ã±×óÄ«NÑ®ü¥òw£Ì2-¶¥zì�Ôå×ÝÚ}d§#.ÄÎŒèÃJb¦6(Ù—Ü1˜óÚ³/²Ïi’׆CM•2»C9GJ¶D©IN–…¡(i¤âù¤ºžd®Å|‘HŸPÜ!Ö-ÕmºG,ãÒ„+a=ÖO{æÂ4ž«*BÛðÄüW„ÖSµÉíª¾U.L¦¦j½øXI=õ„$Lk‹}•rÜБ"åâ9l Æ¡d9Eìt}‚€¸›d”ûÇj¨™„mªžbf}ϲ¬3Ê"‡(‰ +9Ws'fàY/ÍÚa8¦ÛOC˜wz6¦:î|W<Ý(Ûƒeë¿B×Áò¸GUÚJ‡ç€¬}·0øU—’kz?T·É$,ß0ÈÓxÁÆCvÎи'TÊUdM}E„,K‡^eo¬¢ŠwM‹°l®P%t…` ì‰ÚëàXËø7g%ëYá$°@«Js¬R_´‹Î芞†‰!bÚ¶OHMÏ8⢧^¿"²”)<Ž•F÷FkĽq3V”_®Gë‹HyÊé_ç'lÇwQÈRµ§ð°lgM)9]¯€¢#}ª £·£…ÃŽ¢Þ®¦×µ¸V姑C‰â]:"b K»¶c+h–ù,K¶Ñ±³gòµÇìÃ)A‰Ù¬¯–ïa‘ï8•68Û1¼ß”fiõþû9Ò»måÕrbƒÌ› +-ˆ.é×Í Ë¬|彃ÝMkqÙQ÷f ¢HX/÷¸„hw÷vqdŠ~rxÏÔ'¢m¸Q„«d”âÇD™@Ê’€å¤ßV™‰‘)˜È+K�Êט£Yé1}¯ ƒM6VõÛÎèîÒ˜¿<=—<ôŸü{NÈ/…4y3™N…Å.©Š°ã˜…¿³¦@¸qøØ7ë&)™Åf¡ÕA¿)0¶ëYÇ¥DV[²f9I¨ŸLÏ/ûÜ“úšEÅ? ò?—ëÿcG¥í‘iKå‚Tm°™±‹X³Äc·~’삨b«ð6!‘""ÆéV; LqVc=ïð +lyȲ9–&±Ž“eB}«éufˆö³Ë’œnVoTDçhÒ{r–‡•:iZˆ…D'¦]bÇšqcÓŠlt}LÞYÎDZ™¾_ŒÛ¢ËLŠé°\›Ûá3}8”Ÿ4ws[4|ÃT÷v˜aà‡'JgœÚÿ®ÿ®ôb�ÃPý>‚>ʸ BV¸Ÿ +àÇ-ÅŸ§ +^k~LN“Ydé‡jùM,¬€b0´¸ªH+Öo»øÿXò]¬r¬IBVjñç%QÇÞvéW›[D¸“Òä4õ|`¡ò‹šË*µM먮L*¨¡`•&êjUã{–ã½=í= • 5~Aä×l·Q{¨¢.d17+~ŸŠ‘t@±<žguJÜšj¯vAF2• NŒ!ÍàøÌæ‡Cø¡HØ ™—¼vÜG:ò�_©Ü«Eâ5 +ÕCêEíù¨Oäyí1·aø‹nÖÄR¢Wzqú™%®Éd=ÀW?ë‡_щû/í¿‘£/Œ6¢di(‰Í#bڌƢh6#7C»,g^ƒ¡ *üê*ßb1Ü]Òåo‚6Ê3Yöd€vtžÚül,×ØçÆg祄é¦g“Ù?êЗǘ›ÍÝ’*U—ÃÁ‡ý +âGòR±ÚÍÍ®O 5ÍFdˆÙ‚ f7ëç^ÐìèK³™Ù$Ú;ÃIMµíEÌ>F³«›fn^6Є„Iܸl j›Sq-Z±mXvµràÅÊf²1«:™E EU²[Ì·(2Xñœä€àÆd³D Šðùm¸; Ù(–戌lJJy#²›ˆ6!½Õ²…ùèüUT·xó±Ù~Ím +™q<»Y¾÷bc�×ÊAc#þ¤–z&ccõ7|‚Ë\p釋͢3åæ˜@ì3cýnŠåaœYA§}†ª}WÃMÞöMÄæDÞ…É&›õ€F_eƒ/vT½m6!Ãß6›.=› lFU™ÀFa‹¬,:IØ£Š†rs°‡Ã$ƒýYÑ0ùµ)Ø˽ý^l¬Ø1ØKMƒ€½’–ˆ/�65Ú‡îŽÌ×.è×Ëý„_ðëÙ• ö5�xn£¯ÇsëE¾^S=7øšUg%«†€^6” ñfŠ³ÍD•ˆXœt$L…¯6øe7nðu¢BTÊNÑ%&À×´HP:o¶[÷28À×X??¡Fö +‹¦ oìõªN«öý8´Y`¯Ùƒ±·›{-ëT½«6O²ØB÷¸âñæ^Ã:¤ 7÷šmBºË½Ÿb¥7÷z™ç¾±×ÑD(¨×¨×h^Ëmè5æ‹å•=Î^Wmâõš!\»€×02¼kÄ5FÎß6îgÓ¤þÛ•Ìhð¬°Y×k˜,:å5œ|¸I×Xë2µ ëÙT#˜k”íʹ!×Ýmš6ãº-ylqÝ.Æẚ•™\ÈÁŸ¾u“"óE·nŽËÛºMÓEm Ãþ¥Èº"C¹w€£ágp©sÔ§´©ÖÌMP§h¨u¬i0Ûð+u#‘RŒÊYhÀöÂÉ19Åyó¬kT~κ>¡ÁtÖåÍEf] ÝÙ0ë5LÁ²†a´ñí…²>Ç2Éšùß¡¯Šª_–È°rþ€¬±¨››qÑ€\¢Š…Œ±†³Fö±Îý‘b9‘ÉÇ“®æ«'¡Ti¹1㋳|1¬Qõc ¬IiæU“`ž‘…`M"Ê£8:é!-ŠÝ_Ýšó€7½«"e^_c>5˜Ôìâ—ÞäjBAnÀu âup«£‹ì[”‹Rº¦V×aqC«‘Œc¬ófVŠÍ7/�Õ8¥fœc¤c¼Õ@–Še‚ø;jZ™ï…AEø¬ºFž>XÕ¸VNª>†‹TÍŠÈš©ºEû�U·($¹9Õ-ºU§ºE)I`ª›»áÝ”j–|ÈÄH8VJÛ˜Q ”½Õ8#Þµ Tƒ,Á*õ�T·ªX䧆M¢ùÔ0hÞ0žƒ%67šPb| §†h’¡ç€S@¤ª¦‹MÆn£©k³ˆ5ÈÔø ™©»ÁÔTŒ<ÊŠ²Ö¡:h±±Ô%¦Ù›J$üͤ®‘$u :ùM¤.¡- 5ªtÑ<jv$µð`ã¨3ÊP’vÁEú6‹:/ÅŒnuaBSòtz…™=Õé0x[ŠÉ½†åòŠ ›BwqeÀ¥³IëÛ‹AÝ÷ +ÛÃf¶Ákbd4Ýõਹ<k‡@Ý£ŒOüéÇ »~Úµ©‡>ý8!µáÓßkþž~Äô;èéçï¾ÁÓð«Ò;9=ƒ7vº²)«tôªz¬ÊÝÞÌéÉ tûv˜Ó°X9½œVy§—“€Aœæúåà¦ñç˜é=gkÀ7lš[•|±¦Ñ=Ò8êÚvœn£¦»JÈiznÐô6gz94øh†Ó8žcsøuoeÇx3¦á ¦·-ÓyW}`:^Å›/b€F±ðÒX*±½PÐ¥Æ"S}Ó¥q„ÜƼ´05¼4>hvQ~á¥BK9xéß2éV{:|i +Æ4ï{Xp>:óø—68bÓ¥s«o¸4VÙLU[zÑWmß‚-‘h–oo´4<V´›,ýð'«ÕpHQ>þ9?ïdixEuÎà2|&C]ìŹÑÒr +¤ÚdiK‚xÀÒ¸UÉrÅGÕæ/¬t6‘`S¥ÑþiE`€aKŠ¢‹) ÁHw¯Ú׫¡Ê«fÎ ”&´[Œ)ý·*Ù6OÊAnœ4ŽUšÜ(ç‘£ïNßK’ÛǺYÒp »{c«Âòð©ke ¡¯#{¤·18ÒPD°ž80Ò¼E©¾)ÒÄœ”q ÒÅEI›!-ð½Ò0ò¡AB„gÌÆÙ[›²Kqš‚]–ÅMu}ÊÃŽ®¡Í t4Š&¸ü "4hB”CÜàh¬1¢+&ý142`¥ÛpS£ÑÐ趬¾fôwNuøÜ‚ŒÉ»˜ÑêË3úaFS'Dz½`FS!H™ü…ŒÆ‡ÊXÀFFc3„CaŒ1c=1šÆtqŸõrçµÑ‰¨m¼Ñx¿È¸vìêb`4ÿžæ?·>¤GÝÀhÈ •K`´ÄHå1šÐ•1š’JƒM¨sè71šV1„MŒæã½b4¥+Ì»ÝÈhªUZ™M¥ +ÃQŒæ&É€íÃŽƒ¼žáâ@FS©ú´º‘ÑPáˆZx#£©kØÈèD¶/ŒŒÆ;)ò팦°™AÒ@FÃBÂfF‹dRöé˜Ô_i#£¡>Ræ0ÑÔ 3ö|#£©.cˆ5Ñl˜Áøª‘Ñ4ð5¿‘Ñ’¥õCŒ¦K¶MŒ†…uƒ/d4.IPç@FC¨˜w £)GRîõBF³¹n|G¬µfìJA#£—hÆÔ†Z3Æp½š„®›6{júxxÑ«E³ÑÜh\4ŽB çM‹^3ž«aѸ1ò°h\E_/X4Š"ÊNV4:¹“¯¨hòvUŠ hDDÕÑœèY„óÛ˜hj_²ÂÌ›>ÝjÿhH4btšÝª1ÒˆŠ”MˆfPê† D³É7ó†7!šWœ%5”“zÜ#j¢QõÚëøöD/W¶n>4[k;ïAÐ!»~‹Þ¼áаW4“ Ã($,44{?B^:QœŒcPš Z3‰;"n4´8pÅýHÙ팼…¥c ,jÇö› « ͆¦Í^‚ MC@¥7šVÖ&š?Pg á3¡µæ·gŠñ6š¥ *èŽT5óƒ¹áÐ,§ Š9àШP¾+àмAª²¼àÐIÅïëÛ†C³ß6ð‡fmÃc:̆C³ºdc¥‡¦…q €CӢΊšJT©”L‡fO¡æšJÉ2À‹è.#Üxh©SIN7šÛ‘OxhLGjï}ã¡éÕ¨Õ¡ñÐGÅxhXjPž7V9ÆCÓÀèdà¡iQó©ÍX«BM‡VgË€„îA˜‰ƒÛ ˆæ∑ D'BÁ'¦¹ú‹-+?]¢y,Õ¯Š ƒº9Ü„h¶H¡h!ÑZ˜¥p‡¡¾ Ñ*žjÒÕM•ôÏõˆæ‚eºè#¢)ÓOÞˆh*¹õYM‹>€‹M+EÁˆ–T>›P½�3ÑàbDK¯Ãi5 d™DODôV¼¿Ñô +Ù¿9Ѹe"ZÑŒ/„hF4T[kD4Ãœâ‚�G7¾#Ñé´31#ÚÑ‘yÑŒ¨ÌÀwìßü\¥ü´`DÓTr;V¬˜_¿"¢±$8’¬´Q(Ñ$³%÷RÞˆh~ÕåÁˆh¼fP!:µh—{¢Y>E•M¢ÙP!¢éÉçTß„è´Aˆ–åð¡¿_ìµFß'äþÁ‡Fi»ÀC'’/ŽäßHâÛ͇¦•Ò`ó¡q|IÎ ‹dé7 Və͇¦AiA¢eaÂëDãÙš*øÐHL2xhdòÞ·ñÐÌC²L)øЫ[ïØgq‘ÛtèQ"#kcÃÁ†î¨wHv£¡a|Ìnæ̃P;CCJ=ÁÚ®=ÛiRgm*tRÓتWg°n&twïë„É « =£¯6§˜M¢òªÇÈÞØMúpâ ·á¦A£aÐÓóù†<æ¤ +®=šÃâ{«"ìÍ&Aoà ‚>Fq G·ú40Ð JìvS 7; Ð=3%hÔ¼îB@c·à83x4C»�èùøu¿ùÏ#Zlþõ 4þÔÑ)/ú3Ñ¿Ð1ž²YÀÁ~IHÅ‹üÓ²ì j4ˆÇô2a¾±Ïã‰t®©Ïà ‘6ôÖ…ÞÌçn?d3Ÿ�eF ŸG|´ù¼‘jA|”iá�>ƒºYØ%¦±ÈÈ„<vÔ´çAœÂ›öÜ“ò¾f=# Ë´~ žuÁ2ܹ@Õƒèénõã2çyx•úÂ<³ïóª‡òܵòÚŒçÍñÌSªðŒÌ +ãñw±wÛÎ>ÂüܹR7ØÎ×Q6Ù¹Gf4ÀÎ#RHAqÞãÀu0Qe¼¦:cÌK7ÂyF¯Ä›é<»Åè{«ed{!åk&5ЙxËYφî›Hœó ÉsžÁš3ꘜ˜3ˆÕìÇy¡œ#Ù圱TfÞË çý÷Íq>Fcœt‰þ¬ܚÅľ⼂“g¬%õÕÃ9QÛîfv›á«0u£ú†$ÍWÇòÈpæÝÂÒ&©áË`A0œ¹ ?ôÃpƪé!ÎhðîR]¤ù±¦áqó›?—G®ÈÆ7ó”xwßÌ‚þ¼å]D§‘üfVôOC°ÕY0E×í›ßÌgÉB ó›ùJ4¢%^NV3¾øÍlW P7<=e8ïýð›ÿ¬�gÆI¹ºÎ´Râ�gEK>Àf†Õ,âB83\E}P œñ\ýF8ƒÇÈä&8ãÊU`糚 ‚³¾é© ôfÙñÕ>”2k9ê/ÛŽYv;#í³‡eœaj Î,ULJ‹àŒ«”:-Îxím +„3\; Ên†óñ`ƒáÌ×3¤"<I1”ÂÚçËj†3»÷2ôgX$»ÎÄ=PqçD¬¶+èÕK‚Z/7Ão¬Õf8S—§êW3œñ|UŽ|3œQF¢W œQª%\º¬—ü¼�ÎP—_ž?ÜhÁoÆ{ÂõÉÍof€‡Ãuð›à—À£-Í5 §ZŠV·ö¥Ž“Çb‘tð›ù“YÂof 2šÑ«äìyÜøæ5ƒ±}èÍ(§^Ùðæ9´ÚÝìf–×ðÌ/t3ºÁmr3¤“¬ÔpóˆÊ¿›Û<º‡ÇÀ6(^jóˆç¢6ca³ŒhfPd˜lÈfó8ïßÄæÑ‚ a`ó.‹6®ˆ0imc84™² +–üÖÜ||±šAébÜ,Pͽ¸õŽAÍÄz •CoN3;=Â9ó²p¾‚Aif÷ù¡dòNËõ¨�ŽÒjŠýa`]$®¢>b$lD3»¼W}Ö@!QÇo)�Í ®Ñ½ùÌÈÞŒxf@:sòÓÎÙÔ(¡ÆƒÌ/¼Â@3ðBÝiÑ0ô>,03[}år¸ÌàS]tc™Q«5‚©Ìy«€2c]ÄÛÉ# Ád†t©™£ÌU3ÄM"%^HfLÓ‘¹UÖ^»©¢õæ1s)F€ƒ¹-{Ý<f(K8Kß8f\-hÌmžîÞœLPW%‚öcnÃ_Z°˜[Ì^bÆù3w³ +L‚ÄŒ©h\¢Î6ÝíâÆ0Ãy×òßfœš †0Cä4Óz1˜W,Ò‚Á¼ZôÞ3‚yu§Ž/3´Ä*¤5€yuÿxð—mÃÜ:a5s2|y9°ÙË0Äomô2\z9’›¼‘©7xyŽè¨`îò +Àf`—WÂ/ê2-zoúŽÈs ÔÌ\ÿPS—iMÜ2¸D®wö«9&7uÖÅ‚ÿ .“å÷B‚ˆÝå†._‡3t¡›ºœ’Ý^Ðe|Ö:Ðeæ›); è²@V–>=ü@ +;ºÌ4/ç´€.ïAFPï׃./7›z1—×`a#—Q5Ïú˜ .ÃyHF0oÒ1Lo•&·ŒÝ˜ ºiË,Œ‡µ¼˜e/ö²Þgˆ4Yò›ûHnp–¯ÄÙEZæÒ€ºˆ -sAÆ~–æt éÆ%3Ô)ð´AË<3uÉ'ªi´Ý—=»¡¼êƒŠ~F”xd—ž\œeÖs¨ÞÊœe^ö`}•9ËÛrs–±£È&ÁYÆIºÿæ,몪Z¹8Ë°ªop–a¡”wƒ–é€óÝ eziY›1AJƒÊÜ„Yæ|d7f™'ÆHr`–ÓîI˜e–‚pн0Ë4VwaM ÍVÂ,sÐc1ÊY¦ƒ™-Ô/ZQ$•loÌ2,*S¸1Ë\kÎ0f9±®H׫“ÀØÁÒ…³ÌE1õÐÁYÆJ–5 YVR·Ô7f™q’:³Ì%’ºE³L6ZµìóDÜsh¥³L6Úôf|´9(`7f™jFÇŒY¦¡ªÌ�wêùÂ,#céûoÌ2ä êܘel£vc–‰Vì1Ä3Õ¹._ÁfZŽÁÜeÒ´XY³·kÍBû ,cݨ—ç¦,3¾LÖcP–ácÊÑÊ2bŠƒÝ”eqæ8”ejÿô š²L¥ô7eYJÊ>eYŒ+ÂDLYæž*³º(Ë‘l{Qêž¼Ú Ê2’‚‡_”eÉ'×<”ež~’²Œ�–ðdFÿ¢ ËséÄY¦…¡²«X†,s3ÝC–yì䶲ÌÕØ,Á¸,Ëh8C–á†,_VC–ñŠ²<™á"%ð/È2–ŠòîövÙK«`,Ã…XÞÆ ,s=§\½ Ëû}}–™z&a Ë,y§j ËLF댗¤uÙÔWì!WK",3FñŒ”ê~æ:6gÙ°Ìm¸â½Ë$ÏtËrÌCXf¤j~,ÛùähWœ"ò!�Ëüú"£u³©v<°K/Vˆ„ڪܩ`™±!°L‹æ1–iÐà",óö3cˆe¦º)XÄ2ªä¼ËD[¹;©¶P™uu4acڛ݄eê:r4Oà(�×GÙu–3))¿Ë°’ ¾Ë´ð!c™ +oÆ2GUN0–9QyõŠËtaÏ‹±L‡6»—„ƒcæîlÈ2 mDo†z¶5 ËœáV¯²Ì{ÆÞò7eV½hAY†EJ© ,sJ nÊ2|TAYaoôCY¦ŒP½<®’7J#YO”e(w8¬lÊ2³3thoÊ2£Ö¬¸Ê2x©@z2Ü ¶8{Q–¹rJ—q…# œÛp#–Ñ$*ôÆ/Ç€åï¼ú_uáÀÛý´ƒQÚ¡ðæ¦o¯Œ'\¦±èÊÝÝÆ^pånæêf+wŒ7ZyÕð"+OG7 Ùuꇬ<ã»ÁÊ“‘¸{/1q7Uyº¼äUFÑ•Of*ó i9ÊP0R}•t»ÊÐnqHPqvýëÍS†mš±¬¦]ü€)3´Ê›¥œ]9³YÊ0°V ”©©wH|ÃÐH§Æ*F(etÄ+]'¸bí{”Q¸@0lp”´1Ê%=ße§"ˆ2õÁu†2ðIëP.-œHó“K4å |2LN€nz2ÒÐÊNžŒŠ€fÆ2ÃzÅ´Ži|AN.!ôp2rRˆ¦¼¸É(…‰¾¹œ^‘jPÆÑoŠNDȾ É5XŽÁLfToƒL†ÞƒY⛘Œ½î�&C‚ÒíÈSRÔ{á’û$DÓ’±#ãKÆš»YÉÍ’µJnÑs3HÉͳԋ”Œw‘X )¦úÌIFþyèß÷lÊUÖ£o«ßaS0’ÑU½+,¾+&°ìË!ÛÂÇ2LÁÚ|dìÅ~(7eMG†c@{À‘¡¯SIËÅFƵv×B’JJS@*H`¾ÁȪ«ß6™š§y˜ùìW¼ È=Z‚y—¿¹Šñ""³ +e ò)V6¹¸�ö…C®‡2½L5¹•z 2A+\±¨"¿EÓ³ !·P«Þ dqÆæ “½Âõ‹1Èø-¶¥¸1ÈÕÅ›‚/M!ˆdîziéµÈÈb0/dPmø¹DÛõ€\vó>óQ¡!’¦ñǤ™™a¼éÇFðã2bêsj‚Zoô1_;KÃ8¯€-Gùv€7ïû棦Lõ†.Ê)ÙÓ’¨Ç )#›¯æBŽSóyÙæÔ˯‹Åys—ªóŽa D_¸ã1oÚñgšguáW“!ƒuÜ8 ªÆo£ŽÙZ!Œ˜1?°È5HÇx§³qÅtÜPéöÔSVˆasð2æÑ¥Ç|äM9^L†¦or\ÝÉ{3Ž‡J@߈ãÏ„¹,xâ8yZ±u¦/¾ñä2ÊFL[’ቂÌ,Ù$Ø×I»X&’–Õ„O/änqò7ÚXº¯C6ѪÀ`ã-n_\ã®*‹ƒ5¶0qS™P™â3éU‰Xü:º‰Æx+’AhŒ’°e®yÆxŸ½ÑW±OkšM3.öšfœÃ–1kÔ=âÊõn]Õ–ô”°¨á+¹9Æ(83JùÂ[ÒãÆ A:c®ªX¦zCŒ¥ å@ŒAý¬Óú¡SÎù„%dOÔŠÆv¬!€¥V—‹ñÁ}ïÿšÞ=FßiSŒëtÃÉ€«l3Œ[)í…0F�¡˜:I¯¸ªy`LGµ!¤ò@^¨IpÝAUƒ^ܲ3y»¸…¶Àèb¤[©÷r1r”Ò€_àâÖŒïqìjQz8&£ÿp$ö[<S$—e#"¶Ž-^I„³FVM²xEÿŽ äê ¶‹¾’çÔÀ£KÁ;o…`:î†Ïé–ÈÁ*ÞtÞ@MA÷ò&ÇM!f..8ÅÛpcŠÃ¸)ÅÃ3ø¦CÄËÕï )†øVg2œTˆâóçE(㮼êáÀŠÜxbˆ‘E2x4g¬ƒNÃ4O÷x¥Ñë;ØÄ#ÔI"Í9Ì›LîT ñzÏÀþ—ŸÍFï–x6;Ó%¦¡\XbƯÓJ<ƒäd&ñt;°@GëðH£²ÓæC“ÉD£qÄP_òÞ4â Ì +1‘‹L‡™E<ý¡¾PÄ(UJ&„F霚˜‰†ìèùÓˆ™(8Ä`:QAbñ*v�o +ñºÛ"Âc!êy¤!fÉ]~#ˆçbˆ+ÄHß«RÃ�âh¶þâÏà¨~xyYµéì$ŽøÀ‡ÍšÞèaœÐê<¼Š$»/î0>7ËvxE)LP‡¯ÃlæðŒ„l ‡§SS›/ÃÀ8µ«ˆÆæ ƒÖÇÅÕcéîÁþ #²ÖŒul˜šóY߬a$7F¨'‰§.›¾@ÃHLEé´hˆ’3ŒWs¯ºåétoÈp²`oÃ>F†»áF›o‹%m2Ív†Å'>×4z‘žJuQÞ.r”ŠÚÍÆŠGÀJ£…±Êé Æj*•~¸ÂXs~˜_Yµ˜àEnel¨00C¤ðºõ! +CÐD¤d�…¹6siËšI.-ó¦7–Ú¡ k%ÛL˜kÝ‘ß,a¬Š—ÑļÕ0¨ ß(ájeæ‹$€Tœ7¿ÈƒmŽðWGç‡_щúÿFø;<ð/¹}û{ÿèuú‹¿üÝ?ýËßÿ_öû¿þÝ?û‹¿þw&GMÁßûg¿ÿ“?ÿ™]þç?ûóßÿî¿ÿýŸýëóW¿È2ŽMÿâßþîsòÿÝ_þÅÿƒÛþøûõWÿÑÿ·öÜ’?ûý¿ûÝÿøûÿ[[ÿ¯ñ‡¿øó}¨¸þYã5þ¯ö§õo´Cý¥cãþäÿølÌôã_ütÏó‹‡ÇéÿÓßÿåO¿ÿã_í¿<Ëø›ÿêïÿ£ò»øÇ?õÎø»áïßý“¿øã?ý¼dõyÏ~û[™ÿÁïÿõçÞ]ÿð›òoñ/Sÿòþòßÿ»Çù¯ÿÉïÿú›ÿø–þ›ß<ßþþçÿþÅ_ÿæßÿæ†~¾ýŸÿø??¦¿þV¿ýãoÿÛÿþ|ûSlùÏ~óÛ±0†ãÿýaÿñ4ù~„…J±5~ÙüÙåÇû8?þæŸcÿO¿sÍ×ýYÖ`ù iþ€r0 Ï’ï³òÂ|ÆáNcsÿâOxLR“À³Mìv7t–¤Â¤ÛãöêcDµAþb{Ô î§ß¼ÌÇç^¥ãóz^'F�Kb,õßÛ&Åž^G=Æ×\æ}²ç ×U}~úÍ¿ú °J.&˜¢Ì†AÛS0±’þq´' +$>‹_äÁQ~´PÂù¹«éùö÷`ãJ-•tk!ý}Ì0b}]y!fÿÌCocSòƒWv™«ï£Â}ú¼ï3°ñ§Ÿ?±?ÿ\qüÃÇóø<*È8ˆÑ‰c—Ûì³`ñÝB�÷ôÅؤÚgl3rc¹{”ˆR¾½ÏÀÆŸ~þÄ|Æÿåõý¥×·ÎšMI›Œ¢|ÖÜÀ× âÍýŒög ®Np� +`ƒ#ƒÿåÆ"펺¤×)$/‡îs½l÷eóuÎA¯›uNàucQâŽ%Ç{[˜Ì/kßö˜Ï[°z¿.ßÝ¿å¸ð[žÉ=üuWqÖPj¼~ÿq.æ>ÑËv_Ó1_×zÝ©s¯»Š_€ÏüÞŽgþòºãû¹óyöAïwå»;ðë¼®Ô©µ¯#W¦Öü6ÿV#(¯‘ë2Þ#×e>#×uÔ3r]gp\¹K‰ýÞv ÐæëQñuÇ|í9êu]ß݃Ÿ4H&×|¹9˜=žòå ˜(*?ëç.ã}j—ù\ÆuÔsÁ×Ü7sÝ@ñµ-jû±ðzõ_gpÌ×Ùž£^×õÝ=ðÍ9wí5KŸg|ÍÒçm¸féËxÏÒ—ùÌÒ×QÏ,}Á=KŸg|o»ß†û¨Çø:ƒc¾Îöõº®ïîÁwoÎëæœg|ä¼ ×Ï]ÆûÔ.ó¹Œë¨ç‚¯3¸oÎyÆ÷¶ûm¸zŒ¯38æëlÏQ¯ëúîüôÕ÷ ]í;×ÃÖ—;ABËøj|´Âÿâz`ZDýíÏ9·¾Ìü6~q=îm;qŽzŒ¯3¸ÌçlÏQÏe}wþöä™tï{z„óãÇ“¸Îò2ÞWt9#çê/WæܧkÒ¿ïéå \ÛOâzRÛø~ªÇ|½û¨×«òõü*Óã™uïÛz<„óûÇ•¸Nô2Þuy#ç\¾Ì¹U׬ßÖËC¸¶=®Äõ°¶ñý`ùz öQ¯·åë øÛ¿ªçíÇ3b}>Õ0¿>j’Kíã#ðÇ—€-™žñ�²EÒïïÏÆ/À½íù¨ÏQñu—ùœí9êu]ß߃_yññºµç‹½Ná|Û×É^Æû®ááÜ„kp9·ëúï[{}±×¶çÛ¾Ø6¾î1_/Â>êýÊ|w~ÍåÇ뾞Oöúýóq_gz﫺Ƈs®ÑåÜ«ë;¼ïëõÉ^ÛžûzZÛø~²Ç|½û¨÷ûòÝ=ˆé¼ª0ዯS¬‡yùЂ@wðò.ãíi\æã•\G=þËu·¯óý‰Eðã»õ[¾¬wxZ,'ù2Þõe>Î÷uÔ㦗ï–:¯ßÅ)þs…UÿáÿôTý‰µ–¿]¬•wìk¼õ„Uñ‚ý‚Ñ»þøõX'æú·Žöjã´‰%ðçåÙGVXÏfO@Sz]¾Ø„œÜÓ†¬\úíuL®ëgþöúý0îicñe[º_G=Æû.ë>ÕsÌëš¾¿þ_mÒÀ¿¹É¤‹×)ÐÝàã=çzÙ®«:Öëœc^·êüþë¶Ê1É_¶ÍÒ¢½Ö6¾žë±ž7`ó~U¾»þ_eÂ`YÆ—{ú¸„æõû¼¼ò~U/ÛuIÇz]ý9æuŸÎï¿î)~ öþeÛ¬lèûImãë¡ëyüû˜÷{òÝõÿjÑ*”=y¸,ëÄ <æßjˆÍ£Æè]ÆcSzzÇl®ªyµHÛø>ƒXéßê'ÛùÝÛI]ßG=Æ×óu¶ç¨×u}w®˜C“«{ßNžíËA8Oöôþ¹ËxŸÚe>—qõ\ðu÷ÍÁT?çú²ë½ÞG=Æ×óu¶ç¨×u}w~…¥õ~9öRåX8ÿߖp^Ï*Œ_Þ–{Ûý\=¶öõMýXìÎœ´þcÙÇ:OìúÑs¿^'xîí½í~ +×A}}[|‚¿âG¿öå£óëöðVýbôå~¹•qkÞG}}_zŒ_zd÷QñuÇ|í9êu]ß݃ï>ú×Í9û:Èy4×Ï]ÆûÔ.ó¹Œë¨ï@£Ïàk Q¯Ð—@cýzs.ãëŽù:ÛsÔ뺾»ûžŽmùî¾"÷JÜÔýûÈÒâÅ~ée¼¯ê2Ÿ;põƒö|ÍA¿OìÊA¾õ1üãØ)ßfŸEŸí= ^Æ{ð½Ìg ¾Žz†ôëîáÿûûU†…ã ËÓûº°õåáÓÿsìÿíÿ}Y ÈWÝQd¯0ìÕ¾½q¿¬îm‹ŽzŒ¯3¸ÌçlÏQÏe}w~(²\áûž¯ýüøqﯳ¼Œ÷]„sõ×òâܧ˿ïéå¶_ÛÿþzRÛø~ªÇ|½û¨×«òõüZQd{Ã÷m=Žûùýãá_'zÖç\+Œs«.oü¾—ç~m{\üëamãûÁóõì£^oË×ðëD‘{„ÙæHß}ÿa~}ÔÅ1ÞFÄÚü:�°Æ,ï€a¶/_M_>þ³ÝùœÏñŽñõÛ—ùœç9æuEß_ý¯ +xÝÔó^§p¾êëd/ã}a×ÀpnÂ5¬Äͺ>¿sS¯ïtow¾çë!mãûóõð÷1ï×仫ÿ5¯;z>Óë÷Ï}ée¼¯êθF”¸S×—wîèõ‰îíΧ|=¡m|?Íc¾žü>æýŽ|wõ?ý§‡7ÿùÿø'øýŸ~¯ÐæBp³>ì[ó7ý3Ÿ§PÖ`ÕÅmþñmñ0 ßùó9Èyz¿†Ðôu’싳ι#ƒDsÖÜÆÏïÉø€9-c{V“1¡Hû ?ÕÛVýøó?÷#üË-©Ðÿó8÷>}hŒ›²Ì{ÊØ÷üÉÏ;ec+Ï£ÎçÁjNÿ`êŸOÈFÔ éêP#cÏà3|œ< ³èæ½Ð7Pw‚}}ÌT¯û°ðûžåâ-?ç4üûÙ¦çîþ¤|v'èP·Ô§4¶õt¾&ßð}9×VÇ>ýº¯l#à\ÿ—'ðƒ zj<ì!ò=€¨�p’¹ëù’NÏKº{÷myÒ¿VrŠ‡ð|Öú-”xùut7T±jå³Ö<F4¦±OߘÇØÛzËŠYWÇddñç~?N5ùx?裟ʸlDË ›�ä´ñóiØøðfµ%þ±{Yaîº9,Äâ›ÜTþígÿ?øtZ¾:6(ˆçÓz‰ç“k÷Ó¨~›ëóo|D(¢\ú|r-F;Tß” }6îÁípa$Þ[Âoø!öÇk/+Šüâ 36E¹Œ3>éëK‡9†&m‹aŒ&öâV¢$'ÅKÒrõD!XëaNË·_l÷³[I_Œ¨Ç¤‘í$lDÇkz~öçb,DeX¼,ÿªûO¤sã0SïŒ9u?;Œ_6ÖÏní;4UtëmGó¶Ú +ʘ=@�ðÄr 磧ÛÆG°ð8~öÎÛó9É©C ö.^ÖŸÊÚFõláªI™ûŠÇÏš}c@þzØx¤¬©öyö‡0Ì,sÕ€�#Š!ý˜JØZö3B¬Äî6O0,bÿ\mlç ïà™ñÏÔùú Ì£€ŠÍÕo<C1aŒW{áÙð·µÐ"þ‡8ÀäYð�yo;Çþ±|à>ŸÚås€gD–Ì9ušÛº<”<›ŸG«XçÙøøy²ÿ±h†ý¹Ÿów°Ð«¡ø”T=Ò,òëg˜‡ÆÇ®Hò÷Æܸü/Pdº·Íè(`ãˆã7ó³gà[úÝŒ1=ÿ`óçò‘?óÍø&£]�¾lÕ¶¦†_i6·˜ƒYX+cîše~îÎÆ."1+Æv†ÆæO&o¦=vñP¬cs#HÎÖ\÷ØþÄØžPéëMWô˯Ÿöå‚ÿð3f¢ß?Îë¿Œ{ê¤Ì‡e^%0 Ú|ˆ'æ¹Ï}œ¿tÓyr ç˜\9£ü!Ìiø鳚^ÆgU¿Sm<%Œã‰yüé~³iÎ%¶5¶-ŽZõ-~áwéb<è—pˆ�ð©1�ÿ£Í³'æ³"â� cŽOƒ°æŸ=nÜh¡W¾¶þƒÍö8¸M]ÊÇØöàÆú[ÙGnšídΫíSÛÛæ=ŽÎcL9Æa ™þ1Œ‡>n)q5>ƒ‰¹üg/!® ]‰žqýÜÂüœÉês/dì+¦.lqV5?ø�„ÏØœ{l›·Ë™ç>�ª«lämÿÙûѳZ=öUèOüÁæô$/6èÚXŠ?èñäF hÔ•âÍ„9‡Äz«'P½Fþö³gpûñst®c á*p{w¶åq{l¿0TØ\b‘ÉV6ÚsÁöXóK~àˆ+fwã0v;‚DPþìœo€Î¦fÆEÚŒÌæ2c1ö£Íž÷ažûÅìO,þyˆŸ=®°4À®|)3O¿˜�ÖîuêÄâñÇ0?u\ćð±a|ú·Ÿ=n\aúêû+>«{µª%•ŒÛ±^üјàâÈø\/2¹n2'g#Á>Àþ¾òŸð‚~þÄΗ@X¢_ä˜@¾¼ßš@¾éÿåß¼íë¸ÿËçÿοçxˆZÓÛuùƒÍ¹i’„yrr!¶{_Ç‹±ô±â“žæ›þú6wô&Õ¶iä}C–mOžþ¥Ôc¼AÁΡ°{⑱¡-º~«ØIt3kÜe˜k+&€^6¦8�_[|ŽëÑjæó=}|¶ä[Ùr,çzb�ú¬ÇÃM£âÛ>¶÷A9¹Œ=Þž6[þù ôZ_´‡W½e>¿;§çþÎ ö@HcÒ2ŽîÁç…Ÿ6F�& ð§$ëŽzÙA%�$üCZ;Â8÷ΡíŒÏåG›ûŒså´èôîw6¯ö½±µ¼ëõCn+Ωôâ+¥Ó$ãçR|Q¹íÝ?÷'žHÌ)IT0 ‘ÝŸLº^*F-Îﯽ®î}_VÝ_Ý!ߪYö(¿ÂøYÛ¬kË8n~b’†Æ\B÷r._,ÅDmyJ¡ùz/_‚¦3fË´ÐzŒ¬Dºò�hòTã~'¯f*I˧žO2VÇ¿@ÏLkà³ÄÙSsëÞ6z£§04ƒ—ò™Z¾…Wž÷>nCùyoI½ŒÛÃ-0—-¶-ö‰€J‹f?rðË2ª–&`¨å8z%þ¡¶·ì½î䤛ˆWRw¶N5†ÐÕƧ?é2Æžg?šÏ…ùº@T¬>D¸u�Ö>{Áá´öëd:n¿^ûž5E¢yW»À·</‡"~070_F¼ãz=Ð#l?Í°µîO“¼³èw¶ÆvÐæôuíØ Ì>è‰g$áž¼áþ–Ö˜ç°uìo)nÁ/ôÙ×?ú<û×æÖ‹·=1y®%¼åê1•Ò÷N”.Ö¢u¯“ðÂÈ#f¶=õ¥ý%xôÉ~n÷6—2óa2’ÓêÏÎÇE í`ŠÁ÷3Í”ø@žˆ™ñ‚5%kZãÔŠW¤CGþ`æ:t\W{| r?FPSuÁy/ÓÛšáR×w¬�êW&I¹¤í—%>rµfÄcR¼Ê@Bµf�ɘ÷`1ghŸ…Ï>@8‰,®p"GÚ0f»0·í1®*êÉßä‰ÖNCìªOmdE°Ø‘#æ‘ŽLæÞ?ý0—ÆEt‡Üó ‚s6>17<Ã/tA§Ñý–!"ù£ÍgÕ:˜‡pL’ïX‰K5>”µØ–@ˆ/â3KäØ}éŠ0q»˜E>§•côÀî;µ4²cÓk˜øÌØ,ö,äb¸Ò›ŒnîßWlû<s;ˆš…Ðßc‡û&*Ct�Ä"«o"¹?ÚšZ÷{K§ +Æd\•Ã€2>ª5‹ÛוÄi³78ã�ÏA[Y3°£Ÿã{Â@kÎÖ÷hûÄ{„Äe¼1\®ÚâyqÐð¶;Yû3öqÃÉðbRÆVÚžEü<±„çÀ.9ûuîÁäÔ8±²§œÙ#žär”/YèŽ!:º›[wÉKÈK¥¹-‡ +cÚ¾½˜‹–dðŽ—O-¡í€Ã)Ò¸ªë^¯<MO"ÇÌÑ#f~s$fF—¯ zúþr9ˆ¶¸á¬¶áœ¾r„ûÔÃQ•Q¿@žµÆÒÀ´g-û@Co·ºÃ¿“±<ñÒÕÕ°ÿ^ÄdŽ~P{Ó‘Rì’HsÅØýˆµîlŠ[³ä~îT'…¶ñõ×sUÎo½†p ¥÷°Ìø¬{QŒÀ>@›ñfp%cMs6û�µŒÛ™‰Ô±oV‹eÔ‘=œ`|—°¡õëc¿!f1@[\ÁìûÆbÜ!ÞØm.ù‰5+ÖÔa~RÞ~’&Øìs×!y€gSÈçûˆÇ€F1ʼnÑ}ùò°ú[…oëË[˜ùã¬ÂgýÉ ‡iñ<'»ëhñâ4‹=ý!sÍ{DÃô£ÍißĘ aÌ_c:蓧lŽ»C‚é| +ñóižpÇŒ2^äO#"h¨cL‡¶ºÃ;Y˜m^·8„“Wbkd Å(d53>ÃpzRR—D?¨pëÑ:Ç>Â^yr7Q?�õJ9æ½�ÏhWÇUÞÄæ-ƈ�Á³®Pššë @:q¤þï3ÅååìøùÓkßjþ½ßëgÿ8†¼±G7Å<°ív×Lq€Übxæ»xJŒ®9+Àð8uqOF cwxÖþ!ŸËs<DÏ96í{Ó¥9 +}ž˜§Ÿ±1t:=ïj‰ßzì°áY8jšÛÿé1—°cyÌÔkùd±*Š•j„ßþrxÀ¯²'™¾8ƒ¸,4þ‹µZßa“猹Y"§ß*~:ûžN—mm« ÎzQÕHÞ‘z(ⵌY‡ùŠKXW"®ëºÝe/,íìØØöBeÄzà ½ÆªßsôßÜŸÏEÆî{•Ñ/"€É&Â|ºGãÇÏÇ›[ë^c^ÖþÈoÏ}·žûï`Fëuë®J¬'žÛUšhÜ(#Úv«¤As°CFòhNkÏ;E’*tvÏv(V&kÖî=[ÆÓœAcÓ×c¡”^½vĶ¦HàâCÚ«ºYº·íµï¸…u7ø’b-Á˜é9ÀY6ølÝ]åø¦6îRÏíì¿"V\Dúíèº +†{Ÿ=ï=ØËFßo´6Iç¼òþ#ϱúµxþöÞµ¹[ÝŸo•þCWʽÎÜÝx5º“š–{¼ûÚN&»æL©(ªeqL‘:$åÄùãçã¾XXh>›²%‘ +óÙ‹�X�ÖÀJy µ©ÐO–í¢"²iáÎN4Q]/ôû’‚ùó°ºü»*¶ÿRg+#–¹P™Æ ËV&ö ÊS<5xÙ´º¼ÃZeÈ„‰l]N ˜TVT\–õA¨VðFnÓ‚/5€Ô=aÌXHR*Üàn"’—ñ.9j ýq„¤²v1puó€ÆRàB?ÅŠÜà_�WQ²ƒŸö^èêEF)i�éa7íT½¯È´‹¹ÆS&š@-e˜0%Âò„üÙ„ÍŽL•ò.uÌ~t–÷³(šÈÉæ%¼iH¨C ÛI�G–C{5KÒIJ;Tš€2ɣ˽`J*òm"ž Á$N ÷¦_!xŸ‰ ²…Àà·UD“@�Û<tÄá—P–8ÑÜs'¨‚bʽ”ˆ—êú’Æ”ü2¼Õó!P2﯂ï”dí ;ËÁå +¬Ža“å‰KOáŠu¤Ÿðà‚üâ¼ùÂùÀ!òîXÓJqý¨¿ÊƒN ÁÁ7¢ASï– ‚@UAt² )€ë˜kÑK?¼*°m¹Wpø’ÁoÞ„mfš$„�£Ñøã +2ÐGŒO0ïÁÑíÙ,᥄@ôA fK‹06œ +eIŽIHy¼™PD}ñ’4,xk˜ÀÞ 8*ðtðh-ÏôåféÈ?m¡œ(_Y£”,hÛCÙàRT '‚Ÿ_Zœ€œLt�¹ojU*‹Éäɼ.¨ŠÄ©�Ýh}†<) +Rò!Pj’q$yœÖ” +Ak .Š`!"<Y5ë/‰Â=LyÑဠË#rª˜b”ѹPø[I<P3å”× 3¨hå`'@^^¡ç€‚[ñ~€"�%ŸT4,è |²Ê`¸ô'-”d#2Þ¸Ä‘•–ì–jÙÝœ|RKAH†U+MÛª²:ú¤–Á©0÷š¦ž®èîÄ2O‰³26†ýͱ,_ä’€šy^™6 Yøáð+s'E 7Ü€ªH ‡ÜÔ@nØÕC +n@‘˼ÑÁa¿bñÙõUJò@©|d¸›ã$€"Rî}•h,ñqŽxÊ�Tf§}j7ÚÅPf¦¢~βgKâ~[%¦*t}ñÀœ{``¢ûm©ÉyAŽƒÿ.Y!€!øÖT^Ä@¿f,$6£…q ä¸ $¿¬RÄtJÉÙ²H„«“°1r²´DY¼É”笒ŽÛAiÍP:<ÁÞbBë©Âû°[ˆa.(¤¡À<!¡líJÁÕ.M¡S8��ƒR¶+aÁ&ÆUqDQ2í>–Ö÷ÅÓyKçÜ�/s£Áçºðy¯t*AYùf:+HN�°%Rɾ—©Í“¾j6š’ÁB³|é %”µ’ uÁ@6[(xàÁј‚Ç� ðˤJ°ÁÝïð¡3U2u¢pÊËJpKIn›¨º9D72«hߤ +ÃKb)ÈÏ«Rp8kþ‹Ê2%‚c•¿;*œ7’\Õ¤V´ISØJ1¿SH.ʔʔѫLß�Ä<H>l$•%.£„<¾e¤ß†+½M"ECq%‡yÃÒàŠh]s©CQr‡…ó¾ FÝF¤y-ËØ·™iç@ŽhýS:`Â÷ˆHé‡÷[Q»ìµ/’“)pœV$¦3¼ ç8Ä1U9Q´*Æ“¡†/,‚JrxWT± É$4À>ÌŽÏŽý†ÔHyBgYE"¤!X9i+¸~Ô1`ÖtXà_¡_ªZ<µa¹HZ˜x&ÄåB'úR<„’LªŒa:§H¦’ƒdHËœêÊ-‰¢Q†V·Q$Î(®¨‹Ê’Ç¥*¼_‰Ë&™¨À2&9"CÓ@Ìü‚0°i5õßı–Á+¡Ñhå}€“`2î¦÷À’÷Œ†¬zäK¯¾ÙOË’€EÅAkÑ‘T{«ŠƒLê;fX;œ{sŽ/K®KàBDÔt¹·‡úh·D0Ò +j–Ìæ +¬#8ÆLPX”ñþ½7ü¸2‰‚e8ÊÈ‚>…Ȥ ¡*Ö°£Tî/œZr¤/4I5@éZt„S°5!Šæ¶ðê%0–Kö‚Q,÷®á°²Š‡›,ÿh.b–Pƒ·œ…3”C%˜ók‘TÝÐy+§·h +zYÅq+Êhj@ûtžÈ ÈPÇH)…,Ë{¨U‘S’¦xÚ’"rï§X·’BEÔ@ÉaZ’9·"§¢hÒ +ÜkA[õLÌÔFuÀId½Áˆ_f–+Šs§ !ÀX¢h†DÞÀù.]0°ûÁN]ðqÂÀ×ǘ<²ûK‚ëˆÕc™—-4¡ÉV9#‘ìzA¾¡Hô< RW0B¦A{hÐ$ÜJIÑ\ÏÈ‘ l¯qCZ$k6Ld)Û_ÅG±ØR[*[a5ÚRèXóE©´G ’ˆ÷+á|¦Š ½`%%·šô€Ã�1¨é$€UNô]k©]¦kÀ……’Lt™´«Xv”§,%Å)áãŽé`É!ˆÈpÄOÄXFhUr·|È!ôŠI{¢½‘ì‚3CV•4¹Ä¨.ŠÊ`AòQB¢bYlÕ¾KnU”<¹Qñš5,[Å8ϨhÁw!(ŒêKmÓ]êáÀ0AkE@^öŠØrPUš÷£Œú +CªBH¨?b ´0±[Aȃ ºYZÚ¤’€RÑ’“Q‡¥aFù0% ÀÅSx4‘[ÞLÊPPɨ"ö3逸æËÄz±õÄ–šæðRìÈ,Þëásï‰Hú,òKʽ†‚Ôl1~^ZÅzºHâiùl.Ç·o×Â-ƒ}`É¥“û€Š˜NÁf1ÐVÌ° «!c˜»ÛI6�mEZ'õ–Ü@ݪ‚[Z¯Ç Çœ n‘e/gÛ¢/[D"Š%™ch5©EeEHÌbó%‘Q&H<ˆ Ú@e´U²X ªYË”œt®FÒ©H{¨LË<D‡—¥wN‰›…Ú-KŠ¬+ØÆ—ÛúcÙTžG<D•u¤ÐÊÒyÞ!ø‰fáË”ö£ +;Ðy·JZ8ÐïóD’S�‚JIVƒ¼àC2¦ - ,²®ƒlÏ›®s°å#–,/(Úkó—MJºK8þ6ëóÏgèÙ6 Ý“4à1Ť›N…x(Îà`EyYwv,âd‡®‹Òü†ªÁž¨76ªtD~0T%Rh–e3<Ò(zg{µv]{ûV×y+½D3ÕÞÁŒž×¨R:ƶ®`"N=XïÿmÝQŠjY:Š•U×ÃP—¬‡€éÏ4ŠÞ™n¢°òñ:Ùe¿êj”Ý3µ½[««½ÿy;[È*a߈"KÍôõŽDýŠ–´——ªJxÝ a:Á™²Îô«rÕamõ4‚=í¹M7%&™"s[=ÑÔžf]ßþNí*k¯ç¼mKkŸcn‚Ž8y´/½AÑróÔK7/…E$0Ѳvæ%¥²÷mͼ¤ -ƒp7/ADçeÙ™—P×ÍÍKà•|š›—ÍÂ'Fó¹%xž›—¤å70_7ó1îK!.*Å™u ÜU¶÷ЬKd}¢tì¬Kä›"<6ë6é´¥Y—Úݺ–¹,µ¿uˆ" -m57óRˆ2÷·q ¤R…C»q©In^ -«©n;óïš„O7ó’,¢-ŠfÖ%,*Ù=vÆ%Yz댞3Û’,™·ÑMKò1-4 -vÓøAÂ)fY’*RÊ›–„oË@•]IÄlfÆs³ÒF ¹4«’옳£M‰¼o+¡Ù”Ðu"ݤ$Ͼ`gR -òT.)7)™®+€È®} ·å¬MJÊké%lŸsÍK³(…u%ìTkÝ¢$Ï•MY^ÙMJëlïb¼MXv&¥Ftk¦C]E6sQˆL=¸Ž&%ìVÂ_`´„¹Í+qÂhäéD3µjÜXÔž5š”Úõ«¼^ÏyÃF^-òв3)u¢™‚ÀÓ¶6[‘Èœ›Úv%pT„ûWÍúÐ^O'š%¨×c¶¢þ´Á¢Ô^©]äïܪ9kÙ_ºAéÓµ{Yà±’™qîõH•¥L]s#ÈÆ P©‚N°¡u5Ë1TŠ%R3OÛït´HŠ¸mMfžäV,Wȶá³ÿø³ -#if|Q1¸…È[ÇÐj‡€^úE°¬ák5¿‚¶Mëoöw±æŒ—”ÍL8ÎFÂŒ±1m\mƒKØ/k}ÌD}Ù›gÆ2«}›€Aj‡êTaŠ"Ã/jÅ¥ç Fs€/æ5tŠöœ)×Eõu9ÅŸéfk£sɵº ;qôÚ3¢wú»µëz«¼®‹vþ(¢N3òCÎÍy[ö¾4¨(äÜÍ™†ëD›/Ý›Ùt]³ûÅÌ&;µˆ€¸Óýi¢ÝË>L›l+"߯{e¼Ä':³ÎÝæSƒæ b‘¯sªAÅ͓Ƚjàn|·æVÞÔ-\îWÃÖ0¥›gMäü´v׬�2Ù}ÍsmLÄÁÒk²äá\ƒ~ ,(‹ ÷me¶6¸‡*“<jt±%uíì|l”<×%6'\[‹<¹yÙEeïe£r 5¤yÙ zÊn7Û‚1) ûÙdÓ¹£-`•Ñj®6šÖà:óµ¡áêSqgÔó-b~»» 8/ÎþÜßFõfCÝáçñrë7a¢"ù؆Ô\n‘.’ºÏw¢½ÍéËj›=îtCuµÄܽn°SRIi~7ÙÚDP3Os¼ÅPvÈæy‹àŒN5çkaÖ¹¹ó½Á$D1ÓoP.éïÃåÂ|Äý†ï¹¬^ï©U6æ¸ulLs‹5ÊÎ 7\g¶¡®F±gîq`u¥ó×ê‚"Ko{f£ì|qÃuíý[]çí¼pÇEéªU:ms¯9¿b¶„î"sÂÎ!ׯ²ýg¨¨Qì;—Fx…Ü«‚Zâð@#ì|rýªöæ¢óþÿVˆ -)¨¹2$m:c7¤^‡¯E;ÄÎ:ÃHõ[úš,íͤ÷#ÅMu°eÄëP†¾Àæ"œBç¢<J ~NQ)©G¯_—Åxp”uC4žV°^¿S´»S6$>SîœÌ60’b?ºhæ™” OÁF¶Î};¨A7Ô‹4¬°[ s‡fJ§¨f"‹'Íy¸N8O…š×«ê”¹3šN•&èöÝêZ„Ä°ÏtÊsI¾Z¿Ìß¾UuÑÊÇe›/áç…ÿ†s`çè…WÇ×=½0ãÏðà4WoA¶‚½¯—–bÞén\0 e’ÖaN5êâsÊݽquÎèîÞFÙ¹{ûuîÇ\i¤¤Ò'U§b(×ÑÁ‹]l^mŒö=ôˆÏ7BFNÿ×{*|�1w¯oÛ1ÝÛ;Ïo¿Ì½º½ªN±GÜX©À·º Ó²ætÂÎ<\ÖÞ¾UuÞÊÁ~%|¡îµÄFu-±Y]KÄ´ QeÔÁ=DÔMK„Bª0A×aq ½pԛϵÄfŽsfè’cÙi‰ÐýæA•„‰l‘ÉìJ¢uD§5fêÿ^ÓýèñK[Þ눰b•ïÖ®k=ç:âe_žÛ‘²Z,v:b§º^G³fUÓýðGNkÙ눴ú¤%×…ª6¿^W£ŒúÚ@5½®×åº_æ¨#öwë×µVµºÎÛyÝ¡ü9¦ðe5X -Ïpú¾ÞS‹)=ËâN¬VÕ™¥QÜNçpvt¸æz]bÏtæaÔͬ.Ùˆ„‹åá™Nqcº¹*Ûuíý[]çíüQ¼Ëë”îYÙ(ÞSjµa+„Eb¢%»ÐÌŸ* \¼þÝØ×!“ƒ¾(ÔcP¶©"‡t°hI‘`…-Fm,msrˆp>b3V[aXpP¹0 ™j—Ccl¶&àT¶¨il¢®ŸSÑ;Ë–zWièE¿JgÙœ†ŠŸÐ*Ù÷U«’G4tø¨ÝB”臦݉ -'›F ó[´3å?n~ -À1ævHaÁŒ�¶ -{µ(Ýl�vžJ—cÆ"ªŠûÌTØ2«~¬Z³Tkl€ÂWžLÏ-à°§‰Ô™htHÉ5ß•¶ÿ…¯Uu$ÅP(Tò|œiv1+~w,e1xs§ºÙ�³††^é“`=µSuÅEçHR<ÎplŠ¡®c]bÏÔ;5üµ×u«žûæ9¼[»®½«ë¼?ŠWÌ¥K -¯:•á%<Η †‰„õfŽæâÀ„ªvVØRÅÑ«L8û}Pé¥Ic6µˆ‚jnpíjˆëÆÑ•ƒ.Â÷‚‰Ú¯+›C7}g¥B¶Q,gTpB확*¯6Š,›&vjI.cÒw¿3rËDN{Å!ÖQD.C±O_6ûËÊúÈ:[3⼡ì¨j/Ä{a ÎëÚí ܇/ñ]›¹Ù �r¡ƒ2{€°äÏäüž—ªö ¹Kù®ŠøÑÖ/ØhŠ+M„4húÊFŠhæ° ÍѺ#¯n]Y]Œ]/¥Íj@�/MìÁµF°S ìê<_v14 uHZãÚÌŽ6E/çúkÁ” ¡éìõž*[K]Ôä‘—ªcµÀæˆÍA»Þ)º¤£xg¿®¨/u¨«QÒ`®ëÔG]…ÃP¬BÀÈ÷gEïlïÖ®kïßê:ogs¸É´¥wó[Õë=uS3&À*t‹Á~°Ò“‘†$ÞÅ(ŠtŠÝ®“õ×]]bÏô;ZÌÂÕê‚¿¦ÎþL§èþnýºöþ®óv¶ÙVl¹¢ü–øzGÅÖ\h®ŸÝ^‚‘ä^X‰€h_ñ3Ýÿý²ÉæÒPU£ø#õÎF…øCŸ¡×(E ý‰öY…¿—_Ôäõ\4Ñ{k%ê¨îd׺@úU¨ž“êh d ³h¬©tŠò˜4`"w*A]|-¯k Ø3õÎF&Øõºà€ë¡?Ó(ÏímíÝÚuíý®Ëv¶HpïFÅ3‰âbþ³F…} B88ጙ'Ë¢À¿iÞB§<7±„.þá:À àlU5Š?ÒE£šÕ¢×%¬hÊþH#¨‹À^Ì/ê òz.šø#èó ÃŒ‚¯¨[Uf.QGucÊ+Eë†I"U·¿;°‚¾zÙ ö -;[ƒvGÖ†6€ -AÒ„läØnt”:4Ü+Óê>wӲ䥣»)ä�vÒàÝà§i;ƒw£e,5|7ìbö óÎ9߇?¨í ÞÐa’ª.©æN liC^7Êsïvðûá:Ãpu9ÅŸéjQ«öb«JžDh¤S\ÔWë×µFyUç¼®ž ¼7½^ÑÑžª(®Æœ’ɳuv£¨¹Â ÚÃu†æîU5‚=QolTÙÅ3aµªbvàþÈ2˜‹û«µëÚÛ·ºÎ[Ù¸L·pöAmNaØ‹Fj"EÈ*jéæCœgÿ¶±Âf[–œ‡ëÒl@ÍVS£ø))&6 ¼z]˜PË6>Ó)*Ö雵«Ú»·š.Úø£˜&¬kˆPêúNYŒ&CǾc¡¬‰^.¿CÇé!Ž~§', Áß!çl%ÆŽoo�ß/sl;„m³;e£¾cTòRÈà O¡QÕCÁƒ…6ÙºÁàá,WÂáíè}J’a`ð;U¤™9Ò§a0xà{è¦o0øFQñÇ`ðý:‡·ÇbHƒNq³ƒNF 7; ->Ò͈€£àÌÉíe7„ÚÉ÷B*yí(xè]ùp<Üì„O4<uŽSÇÁ£ö¦|4<P´·8#@¾ÚpðØH8Ç$ÂCÏu�Âc£â;\NÙ3;°£Ä1ˆÁ¯÷TQÁptqCœ³ÍÛ€…w‚Oâ×ûUq*j{ Þب®Øµª�œŠ#ú¾QôN±~]{ùV×y#›¤ïqÀ¼–àŽ_oÔqÇ짳d ¬CÈG§ÂpÇ_¯‚6a?í™FÑ; ¾>\g÷¡®FÙ=³QÛ»µºÚûŸ·³õ€ÃÅ1wÊâÖëNF ŒÏE€½™ ¯v|z£8k"Œ½_çH÷^W§Ø3ŸO"žº )½®ÙZÖŸi]ííÝÚuíý½®‹v>.ñ~ \ü,æÀø†kÈø†kÐøV¬aãV¬ãV¬ùÃvX±oX±†oX±ßaÅB¾aÅD¾aÅ#¿ƒŠ5|ƒŠ5˜|ƒŠ5ÿÚ*Ö`ð *Öò *Ö¯¡bÍ=ךÐàò +ÖðòR¬æR¬#æ+Ö ó#V¬AæVÌ!ó *Ö0ó#R¬æ(æ¨ù†sÜü'æÀùsä|C‰9v~sð|È9z¾AÄ>¿ˆ5ü|ˆ9€¾áÂ~ć5}Ç5}wc;ˆ~‡s}ƒ‡5}ƒ‡5ýÖ€ô Öô v¹Ï} 9ßáêaºx½á¾Æ}‡kPø~£å{]2`µªaºZ] ÷Õž¹Ã‡µw®kïïu]´sdþô$íðaÕ`]ewàWû𰆊ïWn~¨§Q´Ö@5TW¯Ê€_ý<¬½U»¨½w«ç¼}×ÔËîI„¹MX„Ù{–„¢RÖJ†R½aÖ—¸¢ê¿sù~p©´„±®F±g6ÃReE•uÙ–?<s†wóëúû{]ílëásì³”MÔêҢƙ‚ÿzO e[Lbƒ5'v¹Û7ŠaL™j׺ôªÅùÜvFM¬:Ôµbo_ÇgEïôWk—µ·oU·²÷å§ë—ðÎEu‘MíTض˜¼HsìÐ�˜Sð_gS%¢š—'êh×1¤nÍC]bÏTŽîÔmVèo¯K(e£iÏtŠ>Óß_çïßë:ogcHK5IÊë=½kè³m]-uÌAÏAÚ:EÛ<Lãu²ÓÐ`Úëj{¦ïiZ3!|^,hux¢~Ö»ü½üš¡=VËy¿È"ç‹P$0õ¡%½ÞSŠ‚º »)=§K°Ä á`°T:¥¥ãx¼@t@†ÖÕ(öL7û4ª&ÉjU-Œž¨_ööb~ÕÐ"缉½#?C€?ãfª¾1 -ÓB_ï©€œ%oÖXtÖo>•s -àNQemVF»¬:þµUÕ)öHwþUôª@9Ç«‚™ÕD�{¢Qž›ŠkoÖ®koߪ:oå2)a!ŸXDde4Ç’Ý¥àã©[ -(Uu&rZû¬mY¯ÈóÚ5Y]8½'Ø£\9W¢,ä…Np¯¦h¸DV"µÛªðW¶z.Ö]©Quà -îGlDé9«ó3Ey 6©C•j¬”±nªÀ¶«�G¨ªh=`OÓÛœˆÉ–ÔêÁúÙ¶áiFp׫¾S»ÊßÚë9oÛ±ü¸ÍBdºA¯Ñë=ò]¶P™G•9ª4¡™Ñœâ|,§”ÆëÐúmëj{¦ó1£…tuU+ú3kO¬1¼[»®½«ë¼_Bœ8ë˸ªšò6Œ£¯wT[à†‚¶ÄYÍf”¯£›WŒ '\hË6\5«·l¨È)þ@½±Q#[rèUÑŽ“êðD§èþbýºÖ¤V×y#Œ3[˜à‘NŒj€³–hÁÏJN *\ºA–þñ2¬1fõhU5Š=Ñ•?£Â5BŒc«ÉKCi½±½Y»Ì_¾ÕtÖÄ/?!iƒ™-žZˆcƦUå-©Cí¼å–r§h«˜?w¯›i¾ªr‚=Ñï›}BÎDzEB zèï}±~]{ùV×y#¿ÌÖ -dOÒÐW†%¾Þ«'%Èf>d¬Ï¢ö\$ëï.ÏÄ×®)I…†ºÅév¥JŸ1—Z¯+ÎøÓŸé”çö²úný:{ý^ÕY#½ë¾XX×ãáZ_Êghd2‹oC3øµ`Õ9˜Y:à|ËPÖ -V7B™+b/êÚ‘Ì…®ÔÌ£‘ö0f™û"ÄŽbFúÆ -ƒƒ˜3r0Õ<`˜¶•1<a†¡t.µ#˜á„(%íÌ0;ÏŽlb>^BS‡/¯ ïÁËò°™#íØe†GÆܱˀ꾻\àZ:t¹l²n‰e6ä2Edà2L¸[YrG.BéP5'"‘2yÛöØe e"lÑ]†,¶¤\¾í½Å±Âè64–;Ñ,ØÈ»ÈQt02BºS {Ìr oXäÝ*V¯§ðp'Ƹ×c0äþ´Üßɯjomõ\´íqÿÊg¡9⥂”!Î7pr]w°äÂX‘ÔPÉŸ‘§a’™G&îÉð˳G@2Dç2ÆÌF#YÖï»w#&¤ˆðÅ::à §‘2wàñ¼GÏjpÅŽeHãýãgºcŒ£½†#‡‘4)ç=¾xa–ºNCÂôhØR‚‹«d„ºŸWíÓ)d€Y;79æ_Y—Ž'®ö&Ž&Æ<šS؃‰Kµ…mXbôˈ$f¾Ù¼ÇYC(FcpÎD\‹ßðzíp]9„˜3ÎÑûé·_Û`9‹9¿n¸ êËCÀ9Ìø3Œ¹¹ÔX€ƒ¡WÓ x· ãÛë1p{Ø�îodÄþÎVÍEË¼á° ëº -w¢c{i™Ð¿�â—3Œ°›%l#DXvÑ<ÖÒ;€°Óëõ4د=l¶rZc«å¢]ÞàĈߤûz$:–k‹lÃá¾ Y{KÞ£‚aõ -u¸;Ý”^F„n'׫1¤o{Ô�nïã×´VxçÍòö"S˜·=¸ ½‹~#ìweìá€øå¬?õE¿ -®Ij•^O#€ÜN4Ün¯Ç ½ýi¸¿“_ÕÞÚë9o›7fž•ù>ôo#:bWÇ–˜ÇÆ@½0=z®ì¯0³%–÷&Ooõ8aâv¢áu[=†èmP¿íüšÖ¯ä¼aלapzGžpÁNuâJÃâ¡Á�Êî‹óºöxAøC‰X‘^yp‡0B÷Ñ~¶§HÁþRNí/î5]6ð‹kŸœ,â‘7X¿øÕ›÷WÁ¯gÿôꅾȯß>ÿú¿¿ø“ֽ·_üöųkG“ܽ|ýõo^¼{þâÍûáúÇžñ›w/þõå‹ûú·oÿí;k^‚7ItÛÇÀ3Oþë‹—øãûG;Ä/}ûí×Ò‘ïÞ¾ùÁkýâŸß?ùb4Rzåå‹ï>¢§·¯¼Þ•?ÜÆxùÍû?^Ë{=#çþÍ7vßÕ3sþÛË}ñóIQ¿Ê:?3c¾¡dlUQÓ±†4]=/GÒwlŽ=Ê+n¥ÝãxîM£¶×úu¿ÿmw÷ŸãÔš’eG˜qìp\pÊ4‹â¬gG?“xÙ%SY5W/R.žDˆ—ÈÞT– $À…®ê8,üsU‚câ³A‹•–ÔÙê®ÈQ¥ö(m^•æ4©=R¹€$.t/&dq*ÈÂ�¥^¶åó9áÅmUH(ˆ›@H–ŒC;žˆj·øˆLcëªè¥ÂP’i{€L&!ÅÖ2Móž`¹‘B€ÇM¹wÒ|§€ì©l˜ìÇÛ‰TÚØzÀ0¡=mLš”ÀŒoP¾@ŽÔ%½1-›RVŽÇ,GÖLƒ[¿sÜ“¢tuPÞqÝjYšQµ/ÙFùÁu€3ŸV ¦±¹&²æð¢ò'¹ ˆ‡ "€¬NY„ò²0'‘VWEUg ~aY(Éü9ÛéuÍÁ¬«La0Ãñ¦aØz–ðÁÓnf@×Î3º‚©õà^©‹Q¥ÀËÒî\h 8Tl1ã33#µÇ3™Jtc$¥ì:q´Ñf�: Ee¹™]xþ‚ãy‚ÉòÈ…Æ ’UåBw,‘Š\¶üg³ÙÂ8w€`,IÇ7Õªåê‚!a.RXiJv”[‰ðÍ-?U"¤ &fÝTÚ)\–Õ–)Ù_P9»oå5š¥µ¯«‚[O -e½† ˜0âÕŽšŒp†;îìjíKº\{òÑJ7&ŠW„^š‘§dƒc]ÁcD "ÊÉй)N`Ø"ÒnÖ�ŽkT§$“ŸWh°™<¨ucZ§{3T<~^ÜE 0pŒ2V] òÐmL›ªi -5q'¾°±c¶„°GyˆWevVI¥R öž$i«`à‹ Ê*–Á"Ã<ÂjŠt(9ôp&â@D’=ù\à=G5‚°$ÍêëœBƒcVræ4'ƒè#1[eVá@—p5K8€¶,‚�õwf¼ZÕk`•¨@[Òõ:$s±i™u‘@#6Ì+Àè³e%„ìÝ1#¤^¾1Ùm¢,ÃmU3txÅÏóe«¦E8` 1²y•‰ó^Y @Ë~ÙTÙÓ–}ZAÄJ4T't8+⬈Îëàø³çg‘Ö�ýpÙl{—„gªÉ‡õ€0ÜÅì•^Rµ�Q Á5©ZÔ_Åq[Øm¼að2Göa·†ºñ¤‰E×鄇Ã%;©àÜ< -p†âÃVWxV³¤„¡¶1.£ÌÅ%k_ÓŽõx8ÑÑ‹A§7ppfcëkDÚVsÖ|’¸#ðipéØø놖ò;S™ƒ‘Ú,¹"ª¨&XªVÒÈ@0ÂH\±õn귕ힻ҇³Î«Â £Õvåb³&Ü0é츶<tË\dznCÈ]Z÷ÿ £U‡Èò¼1|cXÏå>sÌBH] ‚õ4p0~žu¤eõ)Šy-„ŠC²[UÈ…^?]e½1S©¾ò&:š ºÝ¢í’ÕùÁLÁ…Ö½ á’Æ�®2åsÎ-¼l[p´Â(<«Gƒ¹¢ -ØCÖ$-;époê£�ÄS€¥ÛX46/iÊ=n� d£×Àin‘ù c“%4$Xx%¸6 €Å#i…%À•=T*>MrØ«z)f.…åºÉ‡™Ú¸ž›0Ÿ°ÀÚUH¹Ï$›+xnÕ0º&ix°-‹kÑZ›.n‚»‹Æû n‹PšÓŸ-“2©™Ø1WÆ>µÏÁ{‹š§\ZÑHQÈEE¯ÒØTžÑ¢rO\Û"<wuÐaÖPú «êN鼊Ãgœ Ö&©BÒZ ]F5÷áœYdþÁU£Òžûgf}ÅD4,mk4kR¡‚@›Ä$Œîš=5=ÜpBsݘ‘‹ç.àœšMÌ/-ºj»ªú•1ËiÎZו˜Þ8KTç)Öq-]r۸ͪG1ÈJsi†Ø[¹YÒ[á7ñµóæíˆ<ôŸ×¬¸†9µ@˜›ì]tJ!/ù -ÆIĤé¯IùŠXÕ:}2‰= ÏV*AŠ_!=A‹$[²¿Èj În›5RŠA20%.BÃâ¬Y}uõµƒ>w{¢@,´=U ÝaÅ´OpRb·ÄœM¡Ý6œŠ‡v3�+W¼ºÆ…ˆ«eÖ¶)ÖÛYuˆeÑDËp¨Ö¬ç¿±‹°ø¶ä|ÌÀúÜ#@Å^QôMËV·âôA#ðY²7„œ¶«_Šý‰Ü‚¶>øf±§ð#•¡áâ�;Àv¾¬¶í1'TäiÉ%|Ê &$[C<×â"ƒ{8´2—vSâ-‹,°±_‚&¹c¼)Õƒ ‚Ê\+s'¯4 R§ ƒ ‹;êÉ7àÅPÂØ‹";³¸â”¡Y«.@r/ÔvÕæ'“O7ôÆcå³@ãRDN,ªg¢yÝoß bœžÓjWDˆÐÜlÆç꽈üàg˜¹Ð(1®Ì -sšòK' (ØwÔF¬¦þ1.�›åLùA[*égÀ&*µkLE¡Ï\dNàÑ'þeDØ# h¶R©zZÇò6@¬J?¶dCj!ª×PTÂ’qP-Ä`K!6ƒÁ ?0îQ—wM$gÕêôˆÙb>˜¹Ú±8WÚ]„ ª5©ºFÜ#V# nò]cVÈÑ�aNÙ9ÂG $êE* 30¥d²YÁºfd½¾™mV!ïk4‰Ë‰\ˆ–ÖäX^²[¢+r$AgKH‰Û6ÞÏ›&.1R1݈ßBúñ º7î‚ág}µp[ZêVqèJÐ&‘³/+¾K›å.Çc¨ IŠÅå² R!Ž£ š´”›-OJÆ…ç›m±$wDGš¢Ô#¾�Ú!2˶³QcˆGÎk8�B/èUÜqi¾Só'PŠJš÷KŒªçq’3Ÿx 3S<{&ðó–1ý;‚æŠf½)Ywö¹q'"l]ñŸ5aº Ã1)ªßà¸úÆð9‰Š˜-˪æm,Æ)AФT«òÛ(íkîËËPÿb.ö>&w*œ<€’L²;Y�#¨„[ÓEòŒà?„=BõóSã=öiU¤ê:°nŠçevx'¸jCËe¿jSSl)ê±5b¼VëkD˜DWM%(;_RgÚ™Ý\ÊHܤIà’N9ÍÙî]!Ó -„pråIxZåéòE9�SVU–fσ bPÌ2k>uD2;ÿjç ÄÚm| æ5(ëÏè/PVaGp,Ä!!&3 €2û‘†ü“yÙßÉŒ÷ú„ªwF=É a¶@øéEW•%Àh1ì~{0ÇD·‚å``+Sµ8]$¬ÜôÄ:- Iã…[,šÊºjM|"˜ -Ýælc8CÊôÜŠ„7O&˜8©+LàÊŠ–4é¹(ÛR‹ïžý‰Š7ÍÊßqYâÌà»BBˆi²Ó›h_Ñ;ƒJM*.¬Œ K·%;N<Q`…¬¨°Ï¸¶üŸÉÌ¢X˜ŒÀ3o7Ò£›‘U•ÆZäÓuó'âìôh -°ý…±¬›Fº€Bá pµ<3ùzî!/jNuÉCS*Z±n -;'¤jé~'¥>P× ùEQLb¡ªQ|œ™‰G0x²=`4k&ñ¸FKµCƒ7çXÖ¼@8€Ÿ±ÿÚV6 aÍ‚§4`‚ÓšX!4¤ÕòÜÌbj¬ Ùp?ÐŒ(òL>6æ»Â„Wc¿oѤ½4{ñ"×Àd£å}¤ ºêJpû‘/ƒðÐ<MrSfAâó¸ó`)djæ*¶xÌ –‰1ŠË•1ÂÁV<*Ýb'cfØ)bƒB’tcÖÇP2´kfh~O¹(¸^)çn&GqK/«Q8…!¥o¾{ÁOB.\Ð}¢Þ î‚`$•ÁÍtîÓ1Îv¢õkU?Dšg½SóAÏ&áÀ F{«ô�nÍÊVqîæFsì‚Ì‹µ1jbØøæky¶ä3š!SF-´�tfÙ& 6ÏmÚÀ)€šV• -Š+a3ƒeL=“c“WkR@3áË<«yó1Ï9Ô@R2{"ÉœÅÁÂ(ýˆŒ_«F‘ÛéQÔ¾H@FDèË<C"qØÕ˜´ KÞâïó¢©\¶¹%„¾˜êª‡FÇ:kãà¬ØÌ9ÇÀ¬™ ` 3°`©æ¼2ÜG°qÖÈ4 Ö#˜…%©¢K~U% @æõBDjÑÏpÆ1¦®ÆûÁTÈ:K1¡2žfèðºh(>MH³ÐÌÒçš:´#8B5S ƒaf¦`'èN‡Ìr¨Ã|Yì”kîg0p¦Õ¶%,`>Ë}¡€€8ódœ¢¶�¢›ù±ÀÓïcê7QÀ(<e@ýo2AhÏâùÌBä{.L=Xõ´"cò-šIgcxÈ°á“H¼~ŠNÕcN‚\y ó‰ D€¨ -òvn0y:«m;$«A¸%' B¤·:„üaø6rµÄÂ,]›šÚhÎO”g˜hKzŠ=UÍßHò:33sä&¾U“‚ÞètZÝLbEbfW8GVËP¼mê-"€ÎÐâú,ip÷ÃʽU3]õÌ8µ”œí˜_a„Þ²`eH–iძTؘΌçAsŒ›9¢Ì‘.2¬\Üdw—² ó-AÅ�zÜŸÝj;J'2×¼’Â+/#Œ¾WX I`˜H ” ¶ûìôÎY´¬‰É3ÁËØ5x"££AiO„õB³™@?ÃÊ^\` ¾<jnm¦ÊÚªZ!U¢[uŠ£‘Ô`ô©MÓšBÊ €!Õ™2<Úz8Âd±z`2DðžƒD³æª )e…÷óñV=÷ç°V=;KÓ~ó:£M7öÑnÔsP `z¢ «¤@¶K±¾ üàÚ‹+¼–":|€DÄ€ÀƒÕD6œ{ïEF�§óì âoÊÙñŽ<`ÎnâvBÊ©ÝEh/ˆÁ¶fQ5´r~¦›*wU…©àC‡‘fMêÔp‡Ee+:àäêÄcŒM¡ý•¦Ÿ`‡¸_†=Ádu[â�òŸ˜×T¯BöôE†”«ÁGîGúõÙ— ¢[×YÁ®pa*®³Úiáq›Ÿf_¢nõ§A¯D5ŸÙEt«ÁÕ„JL�™Ø }�˜I‹/³Ïªšf'DÅb¯°Ï*ã؉w~ óÜ�¦,¢Å Pë¼' Þ -p‚b -œõÔa ˜hÇîAØ‘V$€ëabrŽn[·ÖëJÃŽ^4pŠ@R€}¢"ëi\¶æá«´ÕåLh -·Ce@@㜟y¸-SßÌæƒz—͈È]äoØô¶nh®‹záA¤› ¹Ï¯.²a=sUÐ�P$äÅM! Ô:…§B˜VöRü8•Bù÷ Gdf^D›ñ p\ì<DJKà·™Û5šÿ°lêXã†ô‰Ám³w~Qabœ‚`Ë`’UÔCKyfí¦Ð—“ÍÓ!ú¬YƒRTD ›¬g;Àt±x¿ìQ‡€D0ï@Ñœ5IÓqë7Ñ/ËwÈ^D÷;“xéGaÔ¬´ûì²&IɬKðIé³ÀóS´O9ÊÐSÝûèÒCÑ=”- ýG‹>MÞ·mô÷ø+R°g3eu.Ï´rK+\È‚$1ÁÛYÜ ‚M }"£@€(ª¡0ËXÏJåPŸfnL¸øÖM³vÑë3÷å?�fV+Çz£+ý†ÓßÓBN`nÒFÐu>É$ŽvÕVTC«µjMªL²Ë”äAºa:UÏ?#NùÕ*xà¦>n±î„Þ’furµ£;iæG&3ºª6;h=Qîw~s3[5¼§šoàÜ4$7œ-¥Ù¡´Í€‚Ô*çp)Aw„¢R*�\÷LlfYTÄ7´<.ôèð¤ìÝ4‚Ö>WN¨f˜Ÿõ$´Ä.ê£Ä]sKRŠ8›VE…™ÙxÙ=?'&‡“Ù[{jSî0¢¨QÁòŽ1¯G)*Zq¦âùÖÖ²Š›Ê–S•:4‡Ê3^4cm~â3©àê¤ ©Z*š¾D(TC¡î(lz‚/g ¯"'„}„€¥hpC¸¬çäOCÜÚÊø2çhN'‘Ùh?¼hNÓ£©µeLCÕD 8*}ÖxÒGš#œ<S -9,]6ã}Ž„¢!ypñÍv$8‰ô:fÃ(ÑŽxUç¥}®¶®å¡d^,ó1«NÒ¬ =…X覾Uûá]˜³ÊtLDcQBOväÖ2Jq¨ÌBZPƒI—f%˜ÑÒ.£ýpQ+ Rÿɪá³!d%7P» `0ÔM0VÐìu4ÍB¼†— n˜§[»Læ„œ¢M=ÅFd€™@¾=×YáHÄ~ÁÏ0¼óø±byxdò¦ÊïÊ@õD³ÊDf{Ù®›!H�¯€rÎ.†n†{ºˆzƒ¡‘™(Š¦Û¢%ë.8>�ö0ÚiµdÀE¯B6óZ -&L¢ÀoÑõ’L(‡¾•Õa£aÖlNÄ®,ÝÜÃì$\“‹f÷ªzb§.|^>9Ñs¿ð™Ù`‘ÁŒªè¾e±§ƒ\ã¢EGǨù —y~/š½#.¾oÚN¶Sph%Ø6^HšTE6IÔ ŒL|éM™ÜÊ]«†v*`@™y0n ùé, -JÝØ"™ú‘È €3g˜ìÈYCè3S½!›oѧÿ!ªe‚aö<q6)"”„Ä´ÚÚÑ~ÝÄX¬h¦Ýd\j0ø -Œž°ì²ndÖ -FšOmFðN1ËÖã¼vÔÝ3iÖ,´bis;cV„•qfÚmØÎ�ºšUU!(1“^HÜ3…Sà!ÂcK@@…OOøšl–(‡Y×Æs¤á»\Õ¿XÅ -‚·ÞvøÅ(V-øQ© ®ŠhS¼g0I¹èm4Kà -È~ VKÊMa.'ó‹�IŸÀI—IWd\Éu‰#tþ"æ¤fê¿¥!¸ÌµmU2ÐP¨(ºnaÄ=N€øÀû¼wÇiEj 9 Ÿ7~VÔK¶8ÜTnÕ›’ºL€<, -z"üx¼MøTÔzä13x_Tůí‚þ åQŠn¸+¹–k,AŸµ.ÐT&„ð -2h;¯T¬sÕåûÜFš«€`ûgÛ•�&Ö yVœTw8ã «Â"³^C¯bƒI‚P®¼ÎíH§ÙTôË}£VC v6*,UÓ8¬›Ú&ThT*›uQOƒ 3+¸’h\(†`©¹OVE®‚Ѓ†S”ðt0Lè�Áí¾3@•ò¾ Ñ 4›•ÕT;Œ)ûÃr;TnS!0_´Ö»v&׃6;Ú®œó2P{ßêVWGš¶*n&˜UëÖÔötθÝ{Öüd !-^ƒAË«K-Q]ÙfØígàSruñ«kå\ÈŽã‘¡< rŠ©¥@¨Øm½*¼@!�†„MóQŸ‚ÑGÛÃÓª¦ðÜfˆÊÃtäVNˆH³SB*¨@pNcrÚà†�‘•'Û¾VÓÞ/„?·«] »úÙW̘'£þóÃ/~÷þÝË78üìx¼}þüû׿}ûþ®ÝÅ[ÙI$z€UVŒ×FŒÃ³ËPŲî„YQ}˜.–SïÐTF¼¨uQA‚Wy1\>¥UF·„ÎÝ+âB[;ŸÉ(¨„›ùÔçh'<1q¿nÓéÎܪ4¹# -Ç™3uÆ‘mPm¢‹'«‚Õ«áqÓpÝœ¢«[A'3ŒUc*‚QˆC>»qÖ]TâiHY³Z-H"hà(4A¸®¦áLUÁÃx{ -ŸpFbÖùg�ËÁP\Î]ਯÄ#i–_Bjà[mã=ÊMSyõlèJ"q| `°ñ9ب2B w-ËÚîJÀ92õÞ¢w�~ ß@»zF[M.ð¤Á¢-Kjô(ns§‡ÅvÕ`Ä\Í\œºò*r˜¨f=Ë‘-}I“"ñæ êÔ¶&°žLi‘0lá -ßݨ¬roX•}3[R=,RYtÆž\{Í–ä…ÇA[6 ñVh`ž¿tºßÅD5LÙKg#cZh�0 -&σµ;Ê8ÏÆ!öÁ‚«8ŠôG$|®³§% –*ìoó¼Ø‰+·XÒX$á´az×l}½š.-T±�!Ò43s�b\ÍÁ¼„OnÁ›ò<5Uo -ÆDsÂf¸ut>NÝ@|H»»jLg¡\$8Ÿ —c"‡]Œì+pšéÞŠœñs_æ HêlõÕA˪˜+šçÑlŒÁíø*dÊÁ*‚‘š{ €à¤„uÖz4PVEÀ=‡L±ìO4S %¤¦2«dŸ`A=H±>›N7‘±°>¤åê%[ªJ 3 k<ÇuQW4¶$•!)K`5—ÌWZpN,2Æf¡«–D…ñª‰ -hÒfÅ‹¦I iAo[•¯1'ºX6Øï!ËÓ…ãi’ÑÛœ˜Lç_,´§C�þ‰ÁV\t‹/LŠBY»ÊÏŸ/×Ö€pOW)XW5ÙGº æ¢îzÌ~ŸpGl~0,€ðˆ§…¬<k^4ˆ‚Œì‚î€7©Ù9ë.é�è2†.«XFó]ie帵8ÎvœÏŽºx‰,ŽuŽºˆÄ˜5n…¾ÑG¼øªRîìú<D,¼Ví“ ´HPÁ˜±b6E½IWSª÷»i4 ò¬=¸ÄÙ$F_Q¨’.ã‰"ÝÚ-®:R)ª¬Š€j€.rroFñ‚¥ôsÑ£Ö1ñà¡#hKöy…‰žª&Êhú†Y3Ò‘dÍ„Lé3¤UOºâ¦#5$eW›bn¶j«€.uG#†=›oªçI4)V%„’ªÓQ݃ôOCÏ!ð<8¨]_cm5ëuQÁ}U5_RØÄd‘,¤t�Lb¶éqÃ)˜ƒ}E¤[³îèŽáH42ˆq'€¢ó=9x‰Qà -?t`7*ât -ê8!AýïáÂûô K9'•Ã{õ2k&û:€¢=:+Ç#¥ÑŠá¥…MS™’S0ÿŠªQ=r±¶ÝT#Íaec›€i#îà@KJÏÌÈNh&1ÇýªÙ €¼e¤@/Øjk4j¶xUL;ÀS‚– ²í^îþ’²=ö<P¦êdÖdjAC½ ã2Ž(c‚’yÃpÆs‹fZ¢º§±XXc/Âãa¨Ý@·¬zÒ:·~eô~vEÖY4–PÓÒÓ5sÝ0«!ô/ÍÚM[¦«Ço*šüÏ«VÂLN“ù,:?¢gZ -ûì‘þ0rÒ¨ýŒ-ܼòÐu›Ã!UVLx"< ð•ÌÍÃg1xnã+¶Œ‰<?2qaGË+Ç5‘Þx±š;*ÌŒacê8º¢¢º»AèŽÔƒ&ñ¬7_¢©×åÔß°Zê²Y@¼[¨†>)Ò4²ßãçúO?p-âæ{œÄ²YLÐ8Yè4Ú©pÍÆ4Wø]‹¥â‚íÖ¤—x…R1Ú…sÅaüf:…ĶÄX~õ×ã.²-^“¤çƒŠž„”v/\®yA27;P -Âð‘Çsi!p°œAÿj¾Ñshq÷y„ By¬^˜<-·¯„RæbF6³dAj’a‡^ë‘d<ØLaˆÖcÊŠUÑ7$,<nX§~[BMÏÈ´T‡ì¹ªež°”¢ÍÆá,žŸ"ªÇðyæYm*D7¨=qá\ÑrZBÕ‚-X@5wÏvkìn€Kšj¾q ô¨T…>“�u9Žðèg„Ø"=ò‹iDÀ°‹íÅ9™–¢¼ÑC·yx¨¥ôä¶lÇ-!«ˆóã“#XÂ4B’È’d†Qz¹aðM±k¼ô©¼ "ƒŒèyOt®Ð¨À€LÃ9MÍ:X… ¦¨Á…-Î;¹]¶XÊiÐgHPcmÊ–ë«Åæ&Õ–4FR˜YÓÙ¶eS´Y`(,ïA2É"jɬqØà<÷,!éJz1¶ïdª¯�vˆÉÒÎû³ŒÕiS¼1+gJ¹Íòw ~W\Ú4D³oCBJØ‚£¶Œ²P2×CÁ«º�ˆ¦ÒQ‹ê1æ¢vÈ6VÚj1í�bêaIÖÙ™AV yc°²d……¬HááXÌkƒ+ÖÛmkƒ¨Ñ9U¿ª‹ŒŸa€X‹ ô.1„1„kð§‚,<Íby‚ -Q\Ç+NIáEØ›hdÅÞ”]®klðp³0ífQ• -@`Øp·€à¦0)h .F#vOüiŠ+ -!|n;!ÕÅ©3ª&)×yU™[„€Cð«d9xW`>r%&CêÃ:ÇlC[µÏ±s¥y@D¤‚Ô‘@ÈVñpP¸úá*º‚õ¶¢ p¬]µÜÛ4Ì1++9³ž¹Â0áÙøD\y[™æ2ζ9'kÍ -¿È-)Ü`цcu3I.égõZá3'uP×›ßÅ3$¨ÇÍÕTúoýD4R² 8]‚¢‰ XDÆð¬†�Š–E(Z¸•ûÂ\(cÚ†èT“I+O½V×'ѱ3‰Ã, ΰˆîší�>ÆåE¢0î:ᎴŠ2ÐÊÕÌiø}«…,IÍŽám£ü$R؃bá‹yiš”7€¤bYÖ‰=›1:<–cI1oÕ° -ôí°ÀMÚ†TKïNlæi…ÞaÍÄl´ƒ°CgU”DZ³mŠ›ágæ;ªºîü®….`EÑó3O€óÔOçø•îÁ‡±È¡:§è§PÊìÂDâ ˜Y½˜ÜcËꉬf ®š¥@™ü¬òìxŒP†’r^4š©°1Té)«Æ¢å{ ¡u¯N omíê ꦛçy¶à-`.x"ƒ¦qDß1(ô6fM‹Æöò¸ApLØSâj¹tÕÙÆÏꀛ›¯W/ÚŠuˆ“êÑ/xxP»íTĶ£à*LbXè (.œ%ܤ�€è-¨f_‡÷9»ŠpTã€xÒ¨€ÓyάÅR§0o/¶˜2æR)UšvŒÀ<Lb'Ôe¼ÍˆÌ›} êö <ŸW;È *»UµŽ·«¶YÍúa„t#̶ՈճøÂ0 -ÀOM&_UˤQãà¡I9De: -KK¬-%ëA×®;±4i]œ_ "ÙVô¶fÃÆ+1{ˆ€Ä1ü‘Ä<i9> îjnNG$)Ê4Ñi>™-iJÖt£ªC”* òB"†ˆ‚2paãT2l¤Ôƒgˆyî}ynɼÆ}D5Â#ˆÏÌY¸%Å® š–VÉÄø|˜0ÙƽU«íz›WÚN¡‡ùXW5"y¤£Ž0yF5FUsréã‚Z]ªmè¼ ˜Ð¡·‚@°ZµßFß2ˆðÀ2 lf_¯ŒKŒCÂÌnkwFعÉKãÍãݕر</Ueµi–BTUp6W®@¡Q㈦ -GëkÕÍUÝäÌ#@Jå[D…ÁÒª±5wXÔ=9DÍ£ž¨9j@j«)ê&Öw* ˆ–;~%nƒDRW¬´}ÁM Y°�Áφ£ƒuÆyNQ¦P,1c».¨tˆªª†á=[À ÁÞ‹ÿì½ÛÎ.IržwsëÄ€-`¤Ê}æ¡Ô–aÙ-Z,[‚ats$ÑàŠ2á»÷÷n"3ë_Ý”h¶`耜þcUÕWÛÌȈ7žÐ -š‰žª*a'¸gT}õ<ÅÄZF`<c2K6:A€¯±È6ÏKqƒj¯äkdÖKËè¥:\~KºjŽ1‹‘>„ùA‚•WDár‹ -D7xS‘Ë*{©‚µäÊ…i®_cœsÌ£òq¹w5!ë"áÙ/‘–äŸ0ÛPQ~Jõü‚1’F¯pö—ƒ¦¢í5¥ˆæ -—Õ—ªœQùÉY™2*‚7ž[\Ÿ$÷ÇçuÏ5y3¡÷“À†¼a»ùX’LŠ¥Yt®9©vµ¸H#™@ÁÃ)=œö$Õµ_÷å-Co}ÅÍBJæÓÃÁfž—S‘ÄWa¨[ÝU#_}£~EÇëïýÂùo} ÿïaÔ_h»ÿï8»_û¹uuÿ¾©»øRÓ˜º›Ù’ªlæ.¾hru#wËRz1»h:Š÷?ˆ»}Dú ÜÅZopðv±"ýüîÆíb 5ÕRpÓv3kZê†íâoœj°vñw¡w£v¹Oj›´‹ãŽ±6h7³fý…Ù…BÑH?&gEô\ÝfåÖÅØ…fš.°»(”D@%»ÕŠ¨`÷6’¯[‹á×EáÛ]·)ù7\$w.¢‚[ý~¡u™dË#ÈºÕ -ƒu›§Ñ›«I¥Ø¯ÆêëlSu±ÑAuµÈe¦.{óÌuºLÆ—ò&ê6‡l n+ÒÚmž. ½½qº˜³4]'ÏÃÒm‘½Pºh‰#rHºÐ?¦ðÒÅÊL(…‹£Ëôgé£Ë‚¡q º}†„ébèÂã/,qîCšÓ èbÁÿèrªîõðsY¹¨b|bQßõ¢çFÅ’ñ¹(›‡Ë?]˜»£óðn•÷49a4ƒœ;*CD76w8RÔ\ô:ÀLÐ\$ÙQu3s—k2w%fJ˜‹?9\`4ì²jÐrWÒübX.Ü'¬NnVîìÊC*_0VAÊÅyWí»A¹g!žœ\–ÄâS N.g8BÜnâ0§½:6'—³ž‰·ääZDV^œ\jÈð‘›“KY’RëI¨_œ7¼ªkmœ\Ü÷ÇÚÐGpæ—/Jîr— äê3V*V pFFpëÆäÊ8צÙÂ@5xßtGƒÛÉå»B¹µ1¹ôV(ȺvcäñÆä.Óƒ’vCÒ'A*ôûM®ÍÈ]Y¿ˆ\/€»¦õS6|LÇETµÛAÇÅi´r³q‘qg¬Dh\¼úJÝ+Är´0îBU[K›‹Ë—§s%V||R·÷ax¶-9XAÄm‡Î¶G fÝ_ðpÁ,À·IñwÃp›Â^ÂE}/~%H¸ø›¿r‘ô €X88¸=š9g¡Œ‚Ûݨ'¸Ý‰Á@à"ÞWæ&ಖ¶�àBä×^³ZRïÆßV—òýœ3êû¿ÿ®¼Ø·Õx‘`ßVW©úår“o÷q¾e‚²gokU1üͽ-{‹(t-=¨·ð¡ÚÓ_Ô[®ˆV èmîzîÁ¼ýêšE8R"`Lγ¼‘·(Š@hÊÄ[Ð"šø¶Þ6w¼y·„C<sãn›Ë•‚v‹}2E¶§p+ µ‡ë¿ÓÙÉ]Û–µ.¸@·D#\4Üj:n`n‘§Fäé¢Ü¢Î¼Œº!·¨ØfüØŒÛè,v#nðÄ+e¢ms³Öó'…r7ßãrè¶-;{i¸-þf óŶÎ/Ú–ß'ŠºE¶Ý^`Û:•„°íg¡¤ÂWÃZš+n¬-rÛ {Ö¶¹† ¨¶ðBq×o¨-ܘ^7Ò# “FÚ⟛8¸›h‹S!OÎ@[$ÊP�<ÛVË»i¶0ñ‹2Îã®ÍÃä7Ìá fÙBŒ‡0K°lUi‚ªïÉ9G²"ÙB›ˆÀD€lI¿,õű¥’ás“c[Š-À³œoˆ-ŠÂ¶:§[(ù!_�ÛÂ~"yók žü¼¯Åßi•½6/ñÛ^›ütm&4ü®-nlnmaú*olm¡24¿¨µH™e=±¢f—T?°ðõBÖ"‘ÅŠ®êXI‘ž/`íç}Å£6°sœž§zTã×7¥mX-\ÿgVí#ùùUÔÚ‡T‹›sqjs7¥j1ƒRÉcQ;BÕ¤±ýQÔ,æ…¨EZBYj—°B/@-2gÏØ€Z”Å:m¶ïžR‘ÂL¢ŸRPÀmJ>hÚ¥¨/4-²Æ(ä 2-*ÚÚ:`ÚøûæÒ†-°´KkygÁÿÄû‚Ò¢¢”c:ÿu#i÷ß‘6l¤E½Žºy´~Íníb¹xÝ4Z”ÏÃE íÃ%°`[³¸uEA£…¼ƒ0‹ Ñ>ÔŠ•7_'E"A£ý-ÓJX‹ŽöaŬXÀ{ÀAùg/^þT[×g~³hA6HÈ(ÚÏËÂ1p£h©r,o-fé'm-p6ñË�Ñb„`äѲ{úœDû€þŒÈ|h±*ÆÀxƒhEÑJ‡Cû˜ZYÊ|Qh2FT) ´É<ƒãÎ3òA‹¥£®ÔZ@X63•òâÏ榡ßüYV6«x™™vü=ÅÝß©&¦´±á³È)$dÍfShçBÏÂë*Â%·‰}—fÝàYˆ„¹¹³aì,¤!s¦Må !zãèÄ!0»ÌYH0rÿÎîq¶ÉÞ;’´×qoöÜ^´YäÙÉ”5l¶,ÃMÍšÃÖ•Ë»Š¯Z¤YŒl\D!ÛŠRõ7g;âuaCüŽ:Sfãï2»mfÌ¢9ïÃ$®Þ£¯.k8´›Êu!fÕcô˜MÕÅT1)‚pX‡0›Š³¸›0‹„µ˜ß7`–ÖtQban4ø²‰m¼ù²>°ûÚ³‹æ¿ù²´Ì\Þ|YòÅÍ—,t•Ã—•¦|Ì.^œÀ`†»dç%0KtêHó ˜¥UÈQfñÌinÀ,ÿƒé¥›0+°l™‡0Ë«CtffùOÉHÞ ±ÊÓÕsA˜eö‰/FfùhI» ³H)eÂ,îÓSg9„Y=y&¾.Â,óbŒa–lST•b– z†.oÄ,~�e/›0‹óQ~,³<$ï7a–Â&Fƒ0K~vßbÉ,³‰_/¬$Qý�fi`ç�ÌÂ".ÑM˜%œ•ùË Ì"V©¸oføS†ñ"Ì23¦É„YÆx–ï«×Vdç˜sAdñeÁ@$0;ð²hT¥Vi^vµ¨.5_–[C—Åa–Óž.‹ l°e˜RQ…Ù²¸*‘^lÙµü%Zv%ñü6YÉTß\YÄ Õ>ÌXÙY„ÛTY°Þ|AegŽ¦ifÊ * ‘²Ê^”7Q%Ú*5P–á3dí7P–ùü6Æ(ËKÎO?@Y>:~…”qÉ›'»\‹hœ,bUþ›&‹¿k¿Y²°PVb”,ð(ºF’,a›ŸïéÉ&fÝSÚ$YÅÉd`f?a/’,1˜ƒ$Ë›^õªˆÓ€…QýFÉ2 >ÔØ(Ym”, &Ðn”¬r0-o”¬Ò$sl”¬ò/k¾P²8eÊÃ%ËrÖ×F£G”›âû¸Y²lq� A°d1´ó[3K–÷„µrK–FÄÏÍ’efè`ÉÂÀ$ÂÍ’…1´dÉÒ€¸J°di`[²‹%KÉ#55†É²#¾þ€Ébø âà¦ÉJ™ç¦Ér+Ì^A“MÙ9‹›&#ÓA“ÝbIÑdá=£½h²0Ò—š, ãM–6‡¹h²µIÉ5LVDÿ•‚&ËÖÞ°nž,Œ,“ l"5´Ì ”¥UÜPVF$+”åqXph ,d¹ß@YvB@¶=€²*–È+€²ìÊwøʪ6hVeÑ®†“ve¡|¦°õ&ÊRmŒ4‰²©ík¢,ÿæ;}!ei„D ²RUgeˆÈáâ¯Q›t#e%£ÖwMÿ,Õ’(»Ò7Q–n]Ëä$ð‰ŸÎLe!¢Ò ,Œ‰ÅA”…ÅSÔ=àëÉ3n¤l:팔å±Ø3"²ÅSeùBÊâågR–ó±´&´Á½_ˆ²T:±¼,ˆ²ØOmA”ÅÙà&ÊBÂnª»‰²x±øQP65wŒ|eY.CEH�eÙ…K©Yeé‹teSd¼7PV–ƒ“ýÞ…ßÎ=ÆÒGJñ“$!oš,ÆVJ£M“Õƒ_é…“¥¾Xàdqh -˜ƒ'g¥›'Ë4ù'Ë¿1KOV†¾^<YüÒÈ“å÷ €$ý(ÌF‘m¹òk(Q œ,ó’©oN,F¡Ùæ&‹ñÌ™EÚz´ÖJ¶c€yæ‹$ÛcæëÔ&Ä”ˆ#uî|QdÙ‰îsÛ"Û]èMð'†„!ÛÝÒ5²ÀF= - -#F„V±˜.~,a¬«†‰½^[ßôØøû‚Çn“Ù±ÓsnPaÁJe‘ÎEŽMQã½M $À±ñ÷ÅÝ&cc?çN£©±ó´ê‚Æ-7˜±óÑÐÈØù¸aÔEŒÅ>&¿263- ^ì|ôêÞ¸Øá8A‹enL!*ÒbA 7ï‚Å"ZæfÅT4P±@‚>¥�ÅâoäBƒ;Dn½)±ÃR¯€Äw/ F,ƒÔ¹¿±ÝB bñ¹M–ˆËƒÑ-à"Ä6*�±hxƒlfða{VòþÂÃÒTò¦Ãb" ‡ô‡Ð‡«Œ†E2)g‘aÃb?²úÊo±Ø'¸°HÌR®b,ìðšð¦Â²)+L…íZã¶úway"uó`ÙfúÐ`;Ã^õƒeqÞD³`»‰‚݇8 Øîü^p`‡“&ÏþˆE•¡@`1&¥ù:£MÆ…€…Ž‹«“Øfi¹�X’®ˆv=üW+PC¦Tþì¼G¢¿Nënúë4h6à¯P»³zÉìW lQ¦w‘_C»eƒ_±ÚdƒÇßöu›L}×¥‹ì7¬ã:ãf¾.CaùŠu?×@¾oÐÔ,j#_a”¢X+ê:<QºÒ5•_ÄW‘†âò' ·¢–ÔÈWnA¹é…|ÅÆQ;¯p(Ëæ½Î¢'~ã^±LB¥Ð^y66RÅ/ü„iD뮀«€+ Ü«ÜArÕ¦+¹Sì{µ«P6îŽf{¥åËî•~OܸWâ0ôïõ;—ã‡ßügå½2„†ÏÍ{¥QÆà½*¬Vò¼2ZFºûE|eP“ ¾óÀƒ‹øºªÞ…øŠæê<€¯{!ÀW„½Øßó¾ªõ¡_iÀ9×ÐërêÏ¥"€¯Š¨õ¶¯¬é#©ý¾2°ô8™%YQ—€<ˆ¯Œ_0[}!_·chä+ß?TOWúùzsOŽ€ò•H‡¦4ÍF¾RhK _a»9oä«¡å…|¥Bz�#_Åke#_ñ¹È¹‘¯(ÏÀ2ˆ¯(+"2YÕ¬ËM5nÞ+4I†JÓk†OŠQ p¯ŒUuùÛ¸WF;º‹?ð¸Ogà^ihªÌ;µ/4Ö¾q¯<"œ{å¯åù¢½2FÇÞȦ½r9XYÁz>F˜H<°W„aܧ™ÕA`6a¨W–Näú"½¢hˆÐXƒ^Ç·-8¯ÃEZ7涢ŠDªÚ‡ëEò:ü5ÜWèÒ–™®BŠ–„×Ñɹ¯£¹ÚÞ|×1T„jº+B,d•_pWôkÀ˜p×¾ÜÝÒl×îXÛvsA£ »vEð‚ëJFÑh/¬+›‡ 3%ª+Ž€7, ®ì‡<Æ‹éÚ]}e¬èa‘U¹Îš5œ9ÖÛ7Ñ•ý‡kÙ@WZç¼y®`EÁÉ»q®py³Î‰É2t ,ºÂ\««�o–+ÖŽn^O³Î €eÈÿA®lh>ò渲WN.ã -�)”+7Åõt¹ qmMÛÃʬo„+lpåá -ELz•«I(fLkÛÕã*!�×V%‡½öaÑoE=8KÞͬ'<ð¨%ÁüyÓ[šÀï¼µÍÝ“–c>ª`HֽذáÓ tkóôäVœG1!.rµ#Ôfp+Šã¨û@(ÏnL®t¹V�àR,nXNofët#ùÙº¼º dërŸž ¶BÓKÄÛl…`”EŒæµ²„fk…>¸‹Ö*ófµ.‡±ÕŠ¿ãW‚ÔÊÀ<\í µF=@¨ëáæ´¢FkOcZ—1~Ai]ŽçÞVäôfD@ÙÛ!VÍ)¤•Fb…-ŸJÄhæº!gÃW½!lpÐ_@Z1±HFkŠö£õÉŒVˆ F+ÕûJÜŒVx1ñB(Mœ½³Íhujv½ô¼ØúÁŒVf 1ë£õ;‡-‚U¿£u¹eËÑŠ¨+…þAhEÔ5Š¸žÁ”žLlÝr–EJ™¡.`P!¨é¬Ø ”ÎÊ¢DyÕD³®à«qUá²Õª×¾Kc3tmš^›°0þäu.0+ÝpæëÌÊÅSËfeÏ5|¯Ê0k#Íeåy¡VzsYéà’¼õuÇ^¥³W›cVÄÌñmcYia'ÖËÊXc,+/“‰±¬ûïËÊp.«õeUeî¬ËÊü«.,+ƒßl7B¶öHÙ\Vz¾Y€ÕSSÏ)§eEìEG¦²òß‹°›ÊÊ3Â*kŠ>Ae¥xƒèMe¥‘µ©¬4pH1••ƒjn*+½=œwPYa`ulPYa Úü¦²rQɱ_TV*–BFúuŒS ¡Meå"w-°¬x¯!Ú*«r‹¥¾¨¬äI�iTV%¸SßTVÄæ9¦ÜTV=š «Á؛ʪˆ¾Æ«Me¥Š¢ ²ÒPDaE�‹{UnNE;4Q¼×¦²’K—ÌB¼%Ý ›Ê -ÁB}ee®m&+t0ZÜLV𴘞Þ[Ás pÁPV¤=ø~ÜPVÙœUPVÀ€è”éFˆn(+ÙcXr”zle¥RéÊJ@ëù e±çs7ÊÊÝXërAYS³›PVÔµrYPV5ïCø@Y™¶b½‰¡¬<é*_€PVàÛ -¸˜¬°é·ÌdM$ÕÔº™¬4 nr3Ya$v,˜¬ÜŠ×o&+œÄ‰ßLVäÿÄ©0“O–øª`²nÃÍd=F3Yqp$‚¶š¨/ÎóÅdEÆ”N×Þ*kHÖý÷Ed [�Y!]"Ⱥ_ÆÈÊÌ'ê²ÈÊRa$§ÈÊ4– ø§»;ŒK`$±°* +“Qú{×9ðE¯ºùM%ÈxD4à_±~¼y¬Ä[5ùÊ—`½•!œyóX‰|²$5CŸ†ªâƒÇÊÉÉã«ÃD•k`+þîHàz:7FêƒÇJƒ›‘’ÇJããÔód¥IMdev•"§ ²B¯Æ’¸‘¹›³N &+ø‡úÈJù!•:,º¾h¬Ÿ•Í5o;?½ˆ¬°’¼‰¬´à‘l$+-´ÝHVÎÉJÅ«RÉ -ãV’•&³ŸF²’`5¨> -rH2)òb²nÛf²r2¢.3˜¬¼W³|²ÂªWÊPV¸ØßPVnBÍÌ e¥•O( ¬Â cZ…ëÌñ^PVŠè³–ºfή¡bCYÉ(P:ÿ‚²2`Ëú䀲²’Z5ãVùÖóº/(+-éØVôBà6ÜDÖc4h-,D 1õ;ûWuã?w¢ -3qp¬ª*O›Æ -o+¬€±"’Ûë›ÅŠ ËkbíRWoëT ûÄú± ST…lÁÂ�±bÕŒ=7‡ë¸~ï2 NÜVë=_VÔ¢HÀV´×‡DVÄ+[ª/�+$ר°7¡/ÔÌÝXYÈ?nü*l“HVÑW¤{æf¯BUb™½ -u6 -,½Š¿Bü&¯âo”÷ÞäUÂk?BW¡=‡‚aŸD¶\”“!p‹…]…ººàkwi¨t7è‚®ByC¼´Ô²4¾rµt¶Ä¾x«ð 2–Ʋ÷ÚS6mT»úÌ7lµé6kZðF$«K"`@Ñ‹´ -#$£Z-$ÜçÃY-ˆ¨•òƬ–%%))«È„’©é©f¶H¸«Õl¹@¬2¶Æ&¬bÁÎuíXEt‚<—ˆU=¦¯Ú-²ºéª°Qgd¸*öYÊL*Rú˜?p¡U›%NAVmn?`ÕSÍ«BuÂ@ºÁªDà=5VÎáH/¨*¡Lp™©:Œ˜ ¤ê`¡ß¨Šx-•<Õa´OàT±7MJæ¿SÅlþ²Yªa±NáB©âò0II—ϪÓ"ÔzsTxƒn10ªÌV‹œÈl]W¡þÍPíæùB5J„ƒ Ú]ÿTÙð ¬ÍOÝEŸÆ§–&§=µšyðT@>‘3;µ•ÜèT‚$rÝäÔæ¶BNmV)ÞÜTØŠ�¨TÕ’*Ñ󦦶"ÐüMMØ4^»¦9y†ê'öô»©Œ²‰© uàÃ10w�JÊ›— -Û³úÆ¥¿8%¾!-µ0õ‘^°Ô@©+µ°ü:*f\ÕEJÅÝx$"(µàÕÉ„ þÂÊüò¤¢ê‡u_*¬(YÓG@RQSD®ëÅHe @n‘*òÕÚ„Tä)ûxñQsW‘eàQñ7 !AGÅßO]/8jFäi‡ -²:L6…üÐo2*鶌 -r|FÅËš8Ý\Ô´Ñs°¨˜áñ¡G,Õ E]¬O‡‰ZYqy¨·ô"jîfQ“§LQñ*Ôô¡⠂»4Tè&‘¾*fE^îC%ú‡`¡"€¨%&dÙóøBB…z¦*Öìú’_Øz³ä7õób6±)¨Œn*t½µ¼¨?”z¨˜:Ê "Ùú›ŠèóšŠW•mL?ýLüU‘~Zä¼û4{fô)Ëzñ]äSˆ+úØÜS, HÂì)Jžô…z -�|ÝÐS$ʹT:¹t¡ZöbžJªÀÆì’Ä"†èVËRŽ<,u•C¹¡§ˆ¦‹mê)BÃÎóŸûk:Ñ6‡×§=…*�Š«`ž:)§È]MQJ7ñ+qÈ xŠ’gE‚wJâ@]/Ü)F!ø -¦6“vŠ¿Ç|¡N›3ÜA:Evq÷�’ïÅ9mM´‘‘o#�¦�~8?µ)§3í(mX,ó¨jh¬ÆoÄ)l¸‘A8]Æìp -2¤þuãMÉƬtSTÁ0°åm8Cféf›Î©¶ž6 °g0KÇTºâ›"¼ÿ"l}JXÓøû¦š†- ¦Ã³kàJG×"òfšBaY$ߢm&…Vƒhºÿ¾€¦až)¬«nœé0BᦙBbJ’‰a¦�š!Ð0SÎòx±L‡{ÑÊtXëàR¼Ú%È0PãO)ôš¦yÆJ· vÅñµ¢x!cü»Š)ãˆéÅ0†ÌÂtºÕNLÝØöæ—2fÙjàK™ã9‰sr õ†—µ'Ø¥sºL K§?¾¹t2)ý–‹’XâàRü.ÞÜRÚÒÜØR°^!Zj)êSàƒÝÐÒu:†±²‹(Ø‘‚YÊ*ü"–„(P�KñÎI7o^i´þ}áJg�ƒVºbµ°R–]µùf•šD»I¥8ŸÕ§E'¬Ä»1¥UyŸT–Ò}„Q:#‡hBétŠ%x¤ñiß|RÈE?žt&ݸղ›NÚFdZˆß4›”êáYßhÒá¦Ô›LJ.F/L:žSÒÞñœ -T¡Õwö*éÇ ºÌJÚíÝLÒþDá¤Ën·á"’›€¤Ý€– ÄYå=/)%+õÛ¦‘¢¬$0nt*ª«Ÿ^,Òº¢2Ø(RêÓ{t\’²<Z<íœ!²;©(¨cÏ ï™ªQø~AH›õ›AŠ¤Vk›@:‚‚{H‘?„Œ<ø£\ y#Ô†’€h*Z¨(PTºcymÍR1möhÍêiñBV,®dŠ ƒj¢M–óÝàQ4¼ÓY;Ù¹žÀŽ~uN~øŸÿBý©£ì¿D‘FÒÏ+ÉliîNKª]OnË´´_Q¬$/§!$ÁÐfÍéîî„è>qü©Õ°ºBô®®%¡Ö"ÉåapšZHëÎ9ƒ7Ö{ÿÄ¢ÒçÐfË!X¨ñËú.@ª}Ívö|°%&+®(M.OcÊ"œór/®²¥©3™`é2ŒÕGâ;Q:(òºP‹ŸPËG·È,lÅ] x¨í³Š7[’£ƒN¶§Éý±frRs %,¬g¦•Ð,XJ:{"Gkë" »oÖ¤¸`X(ãDz˜¿¹§4›¼bÙ˶í‹g‹õ<íFM6”ü{¯Ê§²5+çYÈ”ÔA÷37¶'“ýä¢x‰=Æ;˜GXÖPÅoFWb²FÙ‡Êw |b¡¤6=ÕÖáþ:LºÀ‚Ð%ÿ®ú»d‘Æ©†Úrº›kÁÒ[4üAd™–^NsxÚ ¡¥– -\m˜q@Sw^]{FNŒË‹¤ív€"6³C6¯³UW®/A†J¡ç�a¨|L]£ë€Pj˜~ˆ/˜.Ã-äãV‚ÁbPÞXµ¨Ž”"ËouúS¢%ÅÙÂëó~È|ào¥ðø¬þ‡<,)°ønYM'îãw–á(x ªOI™Ç%áêêiv Æç¥:ÝLK]ì¨ì¾PølÆôd +´‚èGËà/t"«h€SYQ±›>*…†•¦¬"~Ša¿ü¸Ç¥,Qé½\à «´q$šš®¯q\t[Y²Ç+žAãxê‰X [`TÎêJÍæè`ºï[K+˜£°òuá{Ö̋-»]¿ÈmG!؛݇ÂPÜNhüBâ×$}LcžQ„œQü̾Òw@¼O§rð†«€€ÑA×Yˆuc÷Ôn`Gm6 ãcåw°T€¢g²¤áJ\ð$w¤&/šý-¡þNqwkm!»ÞO˜“ØÏUõûÈ?ùyPôÀo -Ïw·‚À‰ÒïY–§¹„YÒ&ÿ –·d8±fdéŠß"° �Ïç7?ɯ äV~üþqÚƒNìIzÁu¬ÇU±l¯I”¬Èûá7Õ~r0“]h‘IÍÙŠ=³ñPb±ÇØ*õƒYËÞ\³X2)Y©qË]8ð’)YÇb»¡® ‡q^ÍA[¿F<X©xlävãoæòQº¥¿´”˜¢Q»Èu H²w7vã‘"ä<¿XÛг’e‰>3¿·–cO¬L)B¬ -o+Å|F—ZÝKØ/€ ݦ‡þ9ÒâOê½CÌ�òÍíÃo9êìõçÃC1[ŸQÔ³½ü ¬<P-4Æ…å3òëôÉNaß·Õõ0IOdÍägŽÿ€áñ[ð¹¡U–Ä—½0¼¹Ò‡ƒ²7¾š¸puóÙ³T,1¶å‹„ _oO2|£ZΛ|}Eö¨©B$ÿ.%—%°²Ž–”åd~†7}9£•”—nEVK+2ü~o£”"°N¼d&f-©u¬Ý]°ûê^^ŠúðÂJH,¬®‚Î,ô{‹ nÞ³ C¯•sR/&±‚>këÕ‹üw>±E.8*3_Û!„Ê÷·TÓ¢›!ùm„ëØÜ€X[[4’ÉÙó+»ITGP”å}PAòÅ„ÎŒO¨ªæ¶ ¦=c'±K¡öØtUEáœÿ’›ÅX%Οù¯Ÿìèbž@ÎoÄN=ÍÏË2…†™¨ -|<Ôj¶èØŒ5se+Å¢ª²6f¨ÄºÛ’ ÷b-üž/,¤zuwMâŽñ ±Þ†í‹’9´_¸îÒ?ulY-°[ì£Agpù)ðÏjyº8’çT÷è¤I½fø[R–lÖ™M.$yÕ½ŸÎŸäðGÇïs¹çËT¿NJTii{ 0üÚ±pê‘@‚`t¬©¹jlROíîÓ^=P<ªw«ª¹‹ÅÙH…ã!»m.I=Ÿ>ì¬"ù¸uÚ"Á‰ë¦¬.9}skI“Qo!dö_2:¦Cd'»ý©eP™ C^[¨6-MšŒ†'5ùn¶Ê@÷d‘1"Ùû#©)A÷ʆtS~ˆ¿bZ³ïYGà)�0Å¡ÎĥLJ¬1’9(諨bÞeŸªR÷g;¬ª8¦SE°ôþôË]µìs¿—?%D‘èHP]InuŸ¢³ÄçŒTe�¨Œà¹UÃX˜ü#q(åØ•²÷”úŽÐ§YÓx‘*ñ,`Ã-YèðkO{P¢äÇ% ¬½�ï ³vÄux-¸Zä}¥„«¨ OI:> ný£`#Ë”éì!aÉðšÁz¬ Ïs*^ûâ3P©Q奌jîž"DîN·]Â7Ò¬‹ÒŽÝƒ"¥�“Ï[à)Sç9lxÆÐs¬Ó‹VD]9ŠÎÏizIy„¶èEŸílçÕ&ä/e%Þ1Œ‰ZL,�Ÿ:¼ûu©N„ž$‚ñ8YöÑmâìtJb³!FIù¼_m—¿³°M÷,âËSÔõ#9e©ƒÇVõH{Ž§éÑRU@KívþöhÒmJاªÜl™ŠøU10)Õèá†\8©nP“éËšêbR¸t`‰‡0mwˆß#}†6X…èB`Z¼çÇ+ÒæY±4áp])ÉG Jà°#cKdìï -# -å“HÓlbÚíX¥ÇqýA—˜–XtPR<ü~ØELöS!èoû²'u†JÔ·!lLI5:ßhäG€š÷ŒÎ)¿@1b’ -¶˜Qyd-ÙÑ#ÂÛ7“\–Ý©-ÐÃ:ª}>¶ä-~{è>òaµƒÏLãùãa†Â§*8ëü ÎG£Ûè{àÙVR("Eì 7*Íw¬DªgD¾e°>n¯.vu’IKK&âóc|þdÝ49Òº,šÙY6AbèÕ㇯8ovj"‡õBÕ1^;ôÇŽó -hš‹)Õ4ÛÐðè>?UZRÌs;ÙAK¬Êv“5o·S'ƒaçË)ßêáOn+âÃô|†‘.¨äËøÕÉ5@FtEu<„yx'Õ"™'öbï -€å ˆeL˜·³¾ÁÅm8EsÙ^sËÅ2Œl{Ñôš~¾ù�¹ÌÝ„±‹Žñ 8+䔨ֆŠ Õ—+µè¯É@ãñ“þÎTÀm =-ÏòvÊNÀÛ½2ÊRã"à|#LÊ™„—(ÖàfðhyA&e*–ð“Å-Çy -ÕIX…`à ¦F.Ûƒí`A+v/¨§ðŽñpèV\ºÒ™~¨° &€Ù¬á/2`^š¦lÇîT:Wüo•æËÀ‘vtižwKnÂÛ¥ês@MŒß1°DŒæžDQó’’^Çœ«P - -¢sPV*W¹c¿|³D#XJEðÉ,>ÁGîtF=Ãî#«Sú°*–+Ü°(ŽŒ>+(ÁÀŒ�•öŽt*suC -GXXxÈŸLË˯25©8Åš”¶f$Á~¾dåUHãN³Z„üö‡4¾Pœàh"Ã*R,Ã2V ö‹ÃÔ(»{˜.("åq3>ËGÝÎaè¹îýfoŠæq†ÅA P`X‡K&E`ÒŸ (êS 8ñÒX±Nbšï%ñ°œqçÙFÙja4„T[FœÝxª„Gß$#E²ý-±C°pↈô"øÊ%XÊÐA“‘é{³Ý±0XÜé ù†¿BEÂFâYˬ,¶íPª¨°ñx— -(ÇHÌËÄÅ,üOÍÚSŠåǪ>Y©Æw´pÅL}TŸW§€:üqõ¢Å« ÏnÏ°Æì§ -ey,¼1`D“Ú¡s¼<lû°½¤Á»R#ç„q†/yExFU9lƤBZ¸®<Іña=òUY1Ö¡‹#ß9´9¹UûÎíHïR2CŠVrÔqe‹™“Ç°µÇD¶ÌnxcؒϧžؼK9-çWtSY«bÄÍ‘„Û;áåG%cü$Íb~.ñ¸=l$J¾rtâŇ–ÜÍ9cô·(e”ü^+“CPÑE{�µ´NuC¦ò·h;¶á6Œ| {ãÅC@·xEo(aš[Žå`èíÆ6&У„¬ží²›ÀQ™Pîáè-'ºâüq'rŠ1ª -act,Ñb¨aQ×,§ºVy"Sê˜L¶»hïŸ$ „-³{ÌÎlsJ9"ÞOø[Sœ‹ˆŒHQæ5B>«ÝÐ-‡}“£&ø5{ØkxKai¶é¡—uê–±Ó5º,ãð{è×ùÅ*Á'S+á½Eȇ# - åtuVĹs¹JS‘¦àÎd¢ïD6ÈÒ€’"’ë,]ã ¦`YÏtry5l³š'—xs„ÿg6ÈrV°cÁKïNOS©¬=¯„•][pM$yqĪ¤˜eã+iç¼#B¡ž ¦æ$…8 }#Œ$ÈfdD~ÚÐdÐóîM¢jÌÊô¾¦ZöÅ€¡1O»n >z’ ¥¤æ‘§©G‹8þb¦+B8±ü€œ!«é*Íïf)™ ©º‡W„RåÌ‚I#º,©Ùç†î29ZøÅ ~Î!ãÅÀTÁ[¶xK¹(ߘŻŒò×´ÀØ&|UT=dfQ×ÃÍl*V‡ej(²¶k|ËH`š²|–úÉ÷ª`¯0Ø×½´þ¼Ê\/ Ê©º¥4{ÆÁBÜ¢úrúsgÚ¦«"PCvrCÏÑ='$V#áo[ÃÀéŒ[Œ±ö~œZ›g¡å¬?4(u×Ïš;RˆÀp÷jJœ*aÁ&^LW?oTצȩ™’2¬ž”ˆf}7wÔQÂÁØ©¼ƒ‡lVÙæØnÔ¸7h£ƒxÈ0ÅŒÂqWXy¯Q–½8ÄÉ<²´n·VNµjÀG$Á®í˜Ëb®?z’Ú³™(ñ9#ØŒE8MA1`)9ß„EŽT‘ós¶[Í ¨?ø·ðš0¶c}ÜEfy~g}9O¼.šÃ¢{[¨?›e÷5¨QÛ¸-Œœ>àX+Û#'~}fƒMîçt�µÍ“"Vž“#·€…ݘ§PŠÎäCD’O„hF÷\Ä—»·cßEXØ臹û•ÃQôYM¨iKz˜‡€j@4+B^‚ð<¡™§a4©†Zg`™>YÖb1ŸÏDÚ”û-XúVñàÐ ŽùK†Â!ÛÁD”v^ÔÂ…ó–ØÆ×MÏ•tÕƒéG’½ŠÎU]%p¬¥!—…*²ü™CEˆ©t9š¸j~âäú -›ÒHeýÞ#äsüXÅÛ’ãyLìÂnGŶ&(…‹©n…¡\;*à +BC¤7Ô'Õ<°°Qzüfw#äZcƒåäT•G»Á1ú‚ä@osJaõv^ÄÑ2“ÙYòe@‚˜eZ™MCh›,¬æîË€¢DJÃ*-Ï«´;´”¨ðçÛz* `¸í(òM#r`t2Ò=‚„…—ɤ“Û´$mgd†�ŸG¢š„CIX4‚¤{¶[Ãu±¤lá, ”Y›Õö e\~Q&‘qð4ºJOí±#QDbÄsyY¢§Lvr}Î5Ü&Æ,´0àr€dd¯ÚÙWfr¹ ÃFñ˺¬údã‘9æ-š‚FÄoŸîš4Lh"M 7š¨/J(bÒÆtE.cIå;òÁb‚¸Â¢T/¶©GENGÇ ïlj…Ž$3ï¶ÛˆŽ±Ô=‡úLR0Ü@– ºg®QžßÇÍær7šq`¸59©«nWqÛnyá¬T¯òþ(x£K=jȨÓR„½ì=Uk]ôFÑÀÑñtJͲţÔÔ?ù¸Q}¢Ã›órU>ó½Ý¬~óŸòË@$™ËlGj ÊÖv‹ÊžLÉrâPä<ÇUB*HOŸ®èŠµpSôJoØ/Ù]“éØ•) ìÇAWpKåžµ|ÎDtùb'\TëÃtá"»!RÍmÇH«›öŠ‘V…¢¨5bg@ü�Å(ÂEÆ-—(³‡¥?'Ô)Q«““Ü^ÖH ”½q!ªþÔ”Y¬}‘á³s.£Ékð 8(d7ƒN,ìNs¿9¶NMI´0ã�ëËóc=5-eì=UQ‰¢8—6Hžçj„aqù—y…ê$鳡˜‘@>T8ä%·k?l3C‘‘Y¯�™ÑZ¬pØF8Os½ÃŽC‰§„Tö‚kâîD–>™GEƒ’õuâè cã‹÷8{Z<ZpŽ`DlÏ!s¿±ÇjØä¨2“ųù'9 Ã2bÕÈ°èЉ0ʘ"´tF®†ñÜ3t¨ò—N…Äð„¹¨ÆÍhµh—æž6œ)QZÈöa%:Í •<˳Š›âªZ€®|B‰¯®¶j2.R=‹¦öŽL®š£!fõ]V~¡À¬º±eÁIÈ*=4ÞüØSÉw–P4Ò„êMÌ›TÍê¢c@BdÉÒtœš¬‡ -—0y$g©*uâ«¡ -6?#uì’À¥£c©°hžÙâUÌ9<4X9O²º\R¡ÖÎL$qaÙ Ã1ì¬"s˜-Re{ä9+9T¨}–=ñ$!zcŽ?ÉUAüÜš+ÿùòd³Fþ$¬Í2EeA‘jdPŽrX§ôÕ{– áàAñb¶î“&%³ hmBÉlè²±Þ�Ç«gJþ(̵,J5„!&Ãè:§›b}Å5Œ:ÒWŽëƒš4±ˆeéZýtc<l£n†%ƒÔH8ž¨ÈñÞ‘A4¬I¨¦öl÷žì…¥ƒo™«8؉%p\á{mÂÌ-U#ÃÓºzVÄr+ù©oäÂÝ-@è‡c -b8„±¡Oþ'¿ú()Çùô˜ô(G~«‡n}ÛÉä÷®fƒÃ¡ -NÔTslu,,úö.—ŠJ`L+úm9‰7®·&¤{‘wÇ×KÃá°+†t‰-f“ª–Bm®t¡aOòqx¹2g.‚§@Ö#…7s;²l¿7Ú3¡9�ckSÜŽ9Î"þI€bdf¾•Ëc¦="[’¬ª„Z³IºÃ¡¶»€rP<Ñð²'Åï8Gñµës�àtêê;q€Ì9±ÃqjP9¦&ûŸœiQeé°Rî;ÄóéÊí»éaåÐhªª±1]€h"ëBñl)L؃¾#/×ñšº3Tø4}ƒäIaúÏŠ- ¸”Lˆ -Xé¨3W>¥_ŸÉ±¡l²xj×<Àƒ¤(sþB‰É±;Lñ½7ñÇ_aLç¤0½·ù½S…>+<¸¡å1-½:<OþöeãˆLoåÇžÙãr9ìÜ\ÝAï™ÕSm×Été5õÀ™I.Tʼ…ƒ6'{h‘Ó‚ò¶ÜïíŒAf˜v;Ó‡`+\PPËšóBøHõŠ+AÌ -Î:åÇŽ÷;dût¶©iç¹ z¿#‚±É Þ{>Ni&ëšha£ -äÊUs“\”Øwx/&]27¤ 翪Ó£궰|ÐjYì(P"2c\¿$뚘&]~šCuDC‘§xš\Z³ˆªfå9øÐah~¼*…ÃŽ³§½#{ÎÑšœ ‘ãÆ[¿¨†;õKºÈbŽ \>]dqHgF¤GdŒ%¡œ¡*+åºbZ#¸KÁûÙQ�Ešõ®/7"„…Khºýž=Cri9¥z”KCí«ÒI`$¡ôlºWø±ÚîªHML›ewB´d¢¦D‰h«JbGÈ£sWÙ]_iølTQ<!p·s%tæ°r…¨ž!ñøá2«£èX¡œ€‘á9Ì‘ø `¢1’È#ÑGAÿ~ÑË÷¿z}”£|ªdÄ©™á C)îc˜(D!ŠÆrÈOà_*ß@&I1ž°(“D‘äµ²:=)ï <:¼ìêâí'e2¯1£#}ð%5ÇЛ¨©º2‘Ø< .%\‡¯øzÁ@ÓG8,@_j¡WW86öTDõõœLa!TmWÖ±ôÎÂòÌøMø‘¬¯Âº?°”ä‚ÃMß ùWñ9FWê‰w–åSºðK¬<¤Z©\¹aÆâ›Õ%ð+F3P°…jLCœ®3«*H …¡&º1ÓÕ":-¬LŒr3ÞŒª�ª*P¢›(c,#œòC¦?@Ý@žlæP¨I;nkvà¢F‘x;P´æšŽ@~—.Aµ$ïooWb•6ÉÁ¨·UɱüÝÖÕ”íÈìOH¡ÁR%÷~e™Z+-ÒÑUd¡×l®³®¾s¼V•a§vªê…&”ÙÏâG¢OŸ-aì�>ÚoŒ¦G¹‹“øMÌ¡'Â3,«6¹œ™RX¨ý„÷ºG<jзí!G -s3cÉ€ÜÌÌ°ó�?ø%`ͦIRʼfDùyáIÂ^lÁ:«UªFTì,ÉBWKŸ‘C2¶‰¤pë¦Ç¬2,kIÁ)ŽøUñ¸H)‡–•šÌhàÁ ð5ûQ}-¢¾±€¡º2ÔŠAþ™ìå/tƒÇ È™o= x+º3 %9 >•IˆXu êv·ŠÁÚôÂ*C+½@‘ºy òØ;JMNbÍ©¥:ý9^equ·‰¦áôp¯ÑdG·KÍÂpÙ,¶£ø‘J1º 1ölk²ª†º¡R}j|’ÔËÊuß"ÿL¹î–šrÂq:œ!VŽ¹¬¾£.°š|NPæa¥€û¿!‚EŠ/DÄ(šËWM!už,~'/7éŸ9ª`žZ‡då<)ŒÅŠ8¦h±öâE}œ2.ú$žÔ¥@FÆË÷=ë²R)#¥k¡àXòT˜V{nkw¥5T7iH» wñ;Oÿ×\M°òB°¢©÷š”ìRÓDš<¼F5zvzzm*°MŠ¥gv[¶@€èuª-H-JmºÝ‰ä ‚Ks"‚ÝîXõµ«‹4LÆp˜nÚ22$ŸŸý†zìãËò¨·Ü ó•JZ`#<KM{×,².•$0&ÈkD~„ÙvjúÕªÇóPPŠùÔ©9jتyþY'õ¨)^)†ª %MŸµgs/;]Z$ð6Ф±k3¯p„°¿ÈÊ,ü·‘Xíœç´_ò³áÿ½;ˆlÒT¸Ô¨ªv³v0@ßõR•d–Êã©àÀ -ÙîMüI¶q`T¬¦qj”(KÉä�T–tgbé“3–Ê$@ D´ghb`CV…´Ó£¸!·á[X:å}òM‘Nd¤?À8,ħÔdºV;a¤MqJX©^”;¥¸ýÕ½ºM‰ÇSêÆŸ¦’wÕ\‰nMâdµ£¾gù(}õq½>M™‡…bXx¶¹)R{ -c¥Idî¨Ï-x&SävAI!ú@dOÏx¡%;óŠ¢4rš¦7~¬H(^Zõ=à{QzÎÀ’S -ù?þÜ!´ß±DTw*y™$O€V„´6à³x„õå®"¸‚r"U³j;Õ§>à¸Ü“ïpa”(¢æÈUtÕP»z¹¨Óq"v÷QU2ʤÎð³Té>"±¢7Ru˜"†¹k>ËsÅS™ÍʹHÿàœS´jteŽëþ ae7�¸ª~AeB5ÑÃZÎû“ž˜ôƒSSžµ†SÑ.sq^×ÉÚ>܆ú(ÌƆL¢ô?¹V\Ã>êyëÍßyTTE¼$3øV¯¹ 5¼”“F›Æ¥‡4lÔ¦óø¬ù¤€T·bÃî -âÂXSªºH:Züf‡kš?NLå bN3;-ÏŠÇ"þ‘>ÌìˆFùrvÑía¤{u‰º¥Ä§ß-âa%SÕ}R~{® ànž¬ªð -ŠDw‚‘FQúPE{¢Ñã—»Tw dÿjHjJPÔ„•€f´°h®gâvœóTv©2?ñ>®|ò›\'Á:»¿d:p®¬¦ã·m–G‹(¬ôhhe!{©Žï¢±‘~ÑJÁ!éOžeµœ%Dãñl¤×nZÕƒx¼jü÷D,JÕ‘Ãò¢¤ÊÞ7uU5Ju<,vT¿’¨ä”@©ÉâZet -doè«×žÃ`ˆ¥ñÂBÆÊa -¯Çc¯ç‰W¢]ùKåïG™eZlKõب%ʯ»µûÈNG\ˆ7ч•ÄLmP²/¹c0çµg_dŸÓ$¯ ‡š*/dv‡rŽ”l‰R“œ,CQÒHÅóIu<É\9Šù"‘>¡¸C¬ÿZªÛ.tXÆ¥ WÂz¬ŸöÌ…i<WU„¶á‰ù®5¦j“=ÚU}«&\˜LMÕzñ±’ {ê I˜Öû*帡#EÊÅsØŒCÉ,rŠØéú7p7É(÷)ŽÕP3 #ÚT=ÅÌúžeYg”EQr®æþNÌÀ³^šµÃpL·Ÿ†0ïôlLu:Ýù®2xº+4P¶ËÖ…®ƒåqª´•ÏYûnað«.;$×ô¨n“IX¾a§ñ$‚‡ìœ¡qO¨”«Èš0ûŠY>–¼ÊÞXEïšaÙ\ Jè -Áص×Á±–ñoÎJÖ³Ã/H`V•æX¥¾h=œÑ= -C$Ä´m7žšžqÄEO½.~Ed)Sx8+îÖˆ{ãg¬(¿\Ö‘ò”Ó¿ÏOØŽï8¢¥jOá)`ÙΚRrº^EGúTAGoG‡!=D%¼\!M¯kqÊ#N#‡;ĺt DÄ@—vmÇVÐ,óY–"l¢cgÏåkÙ‡S.‚³Y9^-ßÃ"ßq*mp¶cx¿)ÍÒêý÷s¤wÛÊ«åÄ™7Z]Ò¯›A—YùÊ{»›Öâ²£îÍD=4:°^îq1Ñîîí$âZÉüäðž;¨ODÛp¢WÉ(5ĉ2”%ËI#¾$2+)"S0‘W–�”¯1G+²Òcú^A›l¬ê·ÑÝ¥1xz.yè?ù÷œ_ -iòf2 -‹1\RaÇ1gM€pâð± nÖMR2‹Í -B«ƒ0~S`l×3² -Ž%J‰¬¶d=Ìr’P?™,ž_ö¸'õ5‹Šä.×ÿÇŽJÛ#Ó0–Ê©Ú`3c[±f‰Çný$[ÙQ!ÄVámB"EDŒÓ9¬v4˜â¬ÆzÞáØò*es,Mb'Ë„úVÓëÌíg[—%9ܬ<ߨˆÎѤ)öä,+uÒ´‰NL»Ä4Ž5ãƦÙèú˜¼³œc!3}¿?¶E—™Óa¹6·Ãgú(p(?iîæ>¶hø†©îí0Ã0ÀO”Î8µÿ]þ]éņ[¡ú}'|”q„¬p?À[Š?O¼Ö4ü˜œ&³ÈÒÕ†s›XXÄ`hqU‘Vþ¬ßvñÿ±ä»XåX“„¬Ôâ;ÎK¢Ž½íÒ¯6·:ˆp&¥ÉiêùÀBå5—U2j›ÖQ]™TP BÁ*MÔÕªÆ÷,Ç{{Ú{*Akü‚ȯÙ$"n£öPE]ÈbnVü>#é€by><)Îꔸ5Õ^í‚Œd$*AœCšÁñ™Í‡ð'B‘"°2.yí¸tä¾R9¸W‹Äkª†Ô‹ÚóQŸÈóÚcnÃðݬ‰¥D!<®ôâ4ô3K8\“Éz€¯~Ö¿¢÷_8Ú#G;*^mDÉÒP›FÄ´1DÑlF<n†vYμCTøÕU¾Åb -¸»¤Ëßm”g²ìÉ�íè<µùÙX®±ÿÎÏÎK ÓMÏ&3†3Ô¡/17;›»%Uª0.‡ƒûÄä¥bµ››]Ÿ@k›È³AÍnÖϽ ÙÑ—f3³I´w†“›j=Ú‹˜}ŒfW7Íܼl “¸qÙ@Õ"66§âZ´bÛ°ìjåÀ‹•ÍdcVu2ŠŠª e·˜o/P6d°â9;È�ÁÉf‰@á7 -òÛp5v@²Q,Í5Ù”2”òFd7mB6z«eóÑù«¨nñæc³ýšÚ2ã y8v³|ïÅÆ&�®•ƒÆFüI-õLÆÆêoø7&–¹àÒ›EgÊÍ1Øg(Æ.(6úÝËÃ8³‚NûUû0®†)š¼í›ˆÍ‰¼“M 6ë'¾.Ê_8ì¨zÛ<lB†¿m6ÿ\z6ØŒª2%€ÂYYt’°G åæ`‡I6û³¢aòkS°—{û½ ØX-°#b0°—š{%-_�l -j´Ý+™¯]Я—û ¿à׳;+ìk�":ñÜF_%æÖ‹|½¦zoð5«ÎJV ¼l(!âÍg›‰*±8éH˜ -_mð5,ÊnÜàëD:…¨”.¢KL€¯i‘ tÞl·îep€¯±~~B3Œì=LAÞØëUVì5úqh³À^³!co7÷ZÖ©zW%lžd±ÿ0„îqÅãͽ†uHAoî5Û„t—5z?ÅJoîõ2Ï}c¯£‰PP¯Q¯Ñ¼–ÛÐkÌË+{œ½®ÚÄë5C¸v¯ad -4x׈kŒœ¿mÜ5ΦIý·+™ÑàYa³®×0Y4tÊk8ùp“®±Öej'@׳©F60×(Û5”sC®»Û4mÆu[òØ6âº]ŒÃ=t5+3 ¸ƒ?|ë&Eæ‹nÝ—¶u›¦‹Ú†ýK‘uE:†rï�[GÃÏàZSç¨OiS™› NÑPëYÓ`Z·áWêFZ#¤•³"Ѐí/„“crŠóæYרü -œu}Bƒé¬=Ê!›‹86̺º³aÖ5j˜‚e ÃhãÛe}Že’5ó¿C_U¿,‘aåüYcQ7-6㢹Dc gìcû) "Å:s"“']ÍWO0B©ÒrcÆgùbX£>†kÇ@X’ÒÌ«&Á3<#7ÀšD”GqtÒCZ»¾º5çoz5V9Dʼ¿Æ|j0©ÙÅ/½ÉÕ„‚Ü€ëÄëàVGÙ¶)¥tM®+Ââ†V#ÇXçͬ›o^�ªqJÍ8Ç0HÇx«,/:ËñwÔ´2߃Šð/Xu<}°ªqœ,U}©š‘5Ru‹>öªnQHrsª[t« -Nu‹R’ÀT7wû)Õ,ù‰‘p¬þ”¶1£(ÿz!ªqF¼kA¨Y‚Uê¨nU±ÈO ›>Dó©aмa<5!Jln:5¡$ÄøN Ñ$Cϧ€HUM›)ZÝFS×fk©ñA3Swƒ©©y”eCuÐbc©KL³7•Iø›I]#;Hêtò›H]B[@j4 Ué¢yÔìHjáÁÆQg”¡$í&‚‹Zõmu^ŠÝ$ꄦäéô& -3{ªÓað¶“{/5ÊåA7…:ïâÊ€Kf“Ö·ƒº;ﶇ+Ì,lƒ×ÄÈhºëÁ!PsyÖºGŸøÓv/ü´kS}úqBjç1¾×ü…=ýˆéwÐÓÏ߃§áW¥7vs zoìteSVéèUõX•»½™Ó“Aèöí0§a±rz9ò"N/'ƒ8ÍõËÁMãÏ1Ó{ÏÖ€oØ4·*ùbM£{¤qÔ‡5í8ÝFMw•Òô6Ü émÎôrh"ðѦq<ÇæðëÞÊŽñfLÃALo[¦ó®úÀt¼Š7_Å�4bᥱTb{¡ K?ŒE¦ú¦Kã¹xia -j>xi|Ðì¢üÂK?„4–rðÒ¿eÒötøÒ ŒiÞ÷±à|tæñ/mpĦKç Vßpi¬²™ª¶ô¢¯Ú¾[#Ñ,ßÞhix¬h7YúáOV«à¢|üs~Þ1ÈÒðŠêœÁeøL†ºØ‹s£¥åH´ÉÒ(–ñ€¥q«’åŠ>ªÍ_Xél"Á¦J£!ýÓŠ Á�ÖES‚‘î^µ!®3VC•WÍ(Mþh·SúoU²mž4”ƒÜ8i«4¹QÎ#Gß¾—$·9Žu³¤áv÷Æ V…åáS×Ê*@B_GþöIocp¤¡ˆ`=q`¤y‹R}S¤‰9)ã@¤‹‹’6C[0à{#¤aäC ‚4„Ϙ ³·6e—8â84=º,!Š7<šê6ú”‡]C›èhMpùDhЄ(‡¸ÁÑXcDWLûchdÀJ·á¦F£¡ÑmY}Ìèïœêð¹1“w1£Õ—gôÃŒ¦NŽe{ÁŒ¦B2ù•±€ŒÆf"‡Â -cÆz.b4éâ>ëåÎk£PÛx£ñ~‘#píØÕÄÀhþ=Í'~n}HºÑA*—Àh‰‘Êb4¡,* b4%•.1šPæÐob4b›ÍÇ3z;ÄhJW˜w»‘ÑT«´272šJ†£ÍM’Û‡y=ÃÅŒ¦Rõiu#£¡ÂµðFFS×.°‘щl_wRäÛMa3ƒ¤Œ†…„͌ɤìÓ/0©¿ÒFFC}¤Ìa £©fìùFFS]Æk £Ù0ƒñU#£iàk~#£%Kë‡M–l› ë_Èh\’ ÎŒ†P[1ï@FSŽ¤Üë…ŒfsÝøŽXkÍØ•2‚FF#.ÑŒ© µ<gŒá0z5 ]7/möÔôñð¢W‹2f£¹Ñ8¸h…@Ï›½f<Wâpcä7`ѸŠ¾^°hE”¬htr'_3PÑäíª'@шˆª¢9ѳç·1ÑÔ¾d…™7%}ºÕþÑhÄè4#»Uc¤7";)›Í Õ Aˆf“oæ oB4¯8?Jj('õ¸GÔ&D£êµ×ñíˆ^®lÝ|h¶ÖvÞƒ Cvý½yáa+®h&‡QHXhhö„¼2t¢8!Ç &4AA 4´fwDÜhhqàŠû‘²ÛyKÇXÔŽí7V@› Mš½š†€Jo64¬M -64 Î AÃgBkÍo/64Îãm64KTÐ ¨jæsáYNAsÀ¡Q¡ |WÀ¡yƒTeyÁ¡“Šß×· ‡f¿màÍÚ†Çt˜ ‡fuÉÆJMã@‡¦E/84•¨R)™ÍžBÍ5•’e€Ñ]F¸ñÐR§’œn<4·#Ÿ(ðИŽÔÞûÆCÓ«Q«Cã¡Š5ðÐ°Ô <o<4¬r:Œ‡¦ÑÉÀCÓ¢æSš±8V…šÎ– ݃0·ÍÅ"AˆN„þƒ/NLs+ô!ZV~º&DóXª_!us¸ Ñl‘BÑB¢µ03ZKá2C}¢U<Õ¤«›*é)žëÍËtÑÿFDS¦-ž¼ÑTrë³0"š}�#šVŠ.‚-©|6 zf¢Áň–0^‡ÓjþÈ2‰žˆèx!¢é²s ¢qË$(D´¢_ÑŒh¨¶Öˆh†38Å#ZŽn|G0¢ÓigbF´£#ó0¢Q™ïØ¿ù¹JùiÁˆ¦¨äv¬X1¿~EDc1 !Ip$Yi£"P"¢IfKÑüªËƒÑxÍ BtjÑ.÷"D³|Š*› D³5 4B&DÓ“Ï©¾ Ñi‚-ËáC¿ØkŒ¾OÈýƒ$ Óv‡N$_<É¿Ä·›M+¥ÁæCãø’œ ÉÒo@4¬’3›MƒÒ‚DË„׈Æ/²5U𡑘d> ðÐÈä¼oã¡™‡d™Rð¡W·Þ1°Ïâ" ¶éУDFÖƆƒ ÝQ-îìFCÃø˜ÝÌ™¡v††”z*‚µ]{¶Ó¤ÎÚT襦±U¯Î`ÝLèîÞ× =’VAzF_mN17šDåU‘½±›ôáÄAoÃMƒ>Fà §çó yÌI\ -z4‡Å÷VEØ›M‚Þ†}Œâ@nõi` A• Øí¦@o$v@ zfJ(Ð0¨yÝ…€ÆnÁqfðh†v'�Ðóñë~óŸG´Ø -ü3 .êhü3¨%¢S^ôg¢ c<e³€ƒý<’Šù¦eÙ!@0ÔhéeÂ|cŸÇé\SŸ‡"mè3¬½™ÏÝ~Èf>#�Ê@>øhòy#Õ‚ø(ÓÂ|'t³°KLc‘‘ yì&¨iσ8…7í¹'å}ÍzF@–iý@=ë‚e¸sªÐ3ÒÝêÇeÎóð*õ…yfßçUå¹kåµÏ= ›7♧Tà7˜0Æ;ãïbï¶}„ù ¸s¤n°¯£l²sÌh€G¤‚â¼Çë`¢ÊxMuƘ—n„óŒ^‰7Óyv‹Ñ÷VËÈö :CÊ×Lj 3ñ–³ž3Ý7‘8ç’ç<ƒ4gÔ9090g«ÙóB9/F²Ë!9c©Ì¼—AÎûï›ã|ŒÆ8éý…Y¹5‹‰}7Äy')ÎXK꫆s¢¶ÝÍì6ÃV-`"êFõ Iš;¯Žå‘áÌ»…/¤MR–Á:‚`8s~è‡áŒTÓC0œÑàÝ¥ºHócMÃâæ7.\‘oæ)ñî¾™ý3xË»ˆN#/:øͬ蟆`«³`Š®Û7¿™Ï’…æ7ó•hDK¼œ¬f|ñ›Ù&2®@¡nxzÊpþÞúá7ÿYÎŒ’ruœi¥Ä!�Ί–|€ÍªYÄ…pf¸Šú @8ã¹úŒp‘/ÈMpÆ•«À0Îg5g}ÓSè ̲ã«}(eÖrÔ_¶³ìvFÚ+f)Ë&8à Õ@œY<ªŽÁW)uZœñÚ Úg¸v”ÝçãÁÙ¯gH5Dx “b(…µÎ—Õgvïeè?ΰHv3œ‰{ â(ΉXmWЫ—8µ^n†3ÞX«1Ìp¦.OÕ¯f8ãùªùf8£:D¯@8£TK¸tX/7øyœ¡.¾<=~¸Ñ:‚ߌ÷„ë“›ßÌ�‡ëà73À#.GZšk@OµníK'Å"éà7ó'³„;ßÌ@e4£WÉÙó( -¸ñÍkcûЛQN#¼²áÍshµ»ÙÍ,¯á™_èftƒÚäfH'Y©àæ•7·ytmQ¼ÔæÏEmÆÂfÑÌ È0Ù6Í çqÞ¿‰Í£AÂÀæ1\m\3aÒZ3ÚÆphZ3e,ù7¬¹;øøb5ƒÒŸY š{q냚‰õ*‡Þœfv:z„sæeá0|ƒÒÌîóCÉä–ëQ¥ÕûÂÀºH\E}ÄH؈fvy¯ú¬€B¢ŽßR�šA]£z󙑽#9ðÌ€0&tæå§7œ²©QB™_x…f&†a…ºÓ¢aè}X`f¶úÊåp™Á¦ºèÆ2£WkS™[óVeƺˆ%†7“F.@‚ÉéR3G™«fˆ›DJ¼Ì˜&¦"s«.¬½vSEëÍcæRŒ�s[öº!xÌP–p–¾q̸þZИÛ<ݽ9™ ®JíÆ܆¿´`1·˜½ÅŒó)f4î$8f˜‰SѸDmºÛÅa†ó®å¿)Ì85A"a†Èi¦õb0¯X¤ƒyµè½góêN_fh‰UHk�óêþñà/Ú†¹uÂjædøòr.`³—aˆßÚèe&:¸6ôr$#6y"/R?nðòÑQÁÜå€ÍÀ.¯„_Ôe$ZôÞô‘æ@¨™¹þ¡þ¦.Ó*š¸ep‰\+îì=VsLnê2¬‹ÿA]&#Êï…» Ê ]¾gè2,B7t9%º½ ËZù¬u ËÌ7SvÐe¬,;|zøvt™i^Îi]þÞƒŒ Þ¯]^n6õb.¯%ÀÂF.£jžõ1A\†óŒ`ÞZ#¤c˜2 -Þ2*M6n»1AuÓ–Y[ky09Ê -(^ìe½Ïi²ä56÷‘Üà -_‰³‹´Ì¥uAZæ‚Œ)ü -3ÌéÒKf¨Sàiƒ–yfê’7NTÓh»/{vCyÕ?ýŒ(ñÈ.=¹8ˬçP½•9˼ìÁú*s–·åæ,cG‘M‚³Œ/’tÿÍY†WUUµrq–aU;ßà,ÃB)ï-Óç#ºAËôÒ²6c‚”•¹ ³Ì øÈnÌ2OŒ‘äÀ,§Ý“$0Ë,á {a–i¬î š,š„Yæ Çb”³L3[¨_´¢H*ÙÞ˜eXT¦pc–¹ÖœaÌrb!\‘®W'±ƒ¥7f™‹bꡃ³Œ•,k@³¬¤n©oÌ2ã&$uf™K$u‹0f™l´jÙ牸çÐJf™l´éÍøhsPÀnÌ2Õ$ŒŽ³LC1T™<î(Ôó…YFÆÒ÷ߘeÈAÔ¹)0ËØF7ìÆ,Øcˆgªs9\¾‚Í´ƒ¹!ˤi±²foך…öAYƺQ/ÏMYf|™¬Ç ,ÃÇ”£”eÄ»)ËâÍq(ËÔþé4e™Jéoʲ””}ʲW„‰˜²Ì=UfuQ–"Øö¢Ô=yµ”e.$¿(Ë’O®y(Ë<ý(Z%e,á/.È2ŒþEA–æÒ‰²LB7dV±þYæfº†,óØÉm%6d™«±Y‚qY–Ñp†,à Y¾¬†,ãe x2ÃEJà_e,åÝíí²—VÁX>†±¼AXæzN¹z–÷ûú",3õLÂ@–YòNÕ@–™<ŒÖ[/Ië²/¨¯ÙC®–DXf0þŒâ)Õý4Ìulβ`™ÛpÅ{–%Hžé–䘇°ÌHÕüX&¶óÉÑ® 9/DäC�–ùõEFÿêfSíx`–^¬ µU¹S/À2cC$`™Íc,Ó ¡ÁEXæígÆ:ËLuS°ˆeTÉy#–‰¶rwRm¡2ëêhÂ2Æ:µ7» ËÔuähžÀQ�®²ë&,3fRR~#–a%|#–iáC -Æ2-(ÞŒeªœ`,3r¢òê—éžc™mv/ ÇÌÝÙe&ÚˆÞ1ôlk@–9Ã^d™÷Œ½åoÊ2¬zÑ‚²‹”RAYæ6”@Ý”eZù¨‚²,ÂÞ臲L¡zy\%o”F²ž:(ËPîpXÙ”efgèÐÞ”eFYq”eðRôd¸lqö¢,så”.ã -5F@9·áF,£ITè#^ŽËßyõ¿ê·ûi£†5CáÍMß6^O¸L=bÑ•»»½àÊÝÌÕÍVîo´ò4ªáEVžŽn@²ëÔYyÆ;wƒ•'#q÷^bânªòtyɪŒ¢1*ŸÌTæÒr •¡a¤ú&*èv•¡Ýâ âìú×›§Û4cYMºø;Sfi•7K9»rf³”a`;@)SSïø†¡‘NUŒPÊèˆ1VºNpÅÚ÷)£p`Øà(ic”K4z¾)ÊN1Deêƒë<eà“Ö \Z8‘æ'—hÊød&˜œ�Ýôd¤¡•2<ÍŒe†õŠi7:6Òø‚œ\Bèàdä¤Myq“Q -}s9½"Õ Œ£ß ˆ}A“k°ƒ™Ì¨Þ™½³Ä71 zÝL†¥Û‘§¤¨[;÷Â%÷'Hˆ¦%c7FÆ–Œ34w³’›%k•Ü¢çf’›g©)-î"±@R24,Lõ™“ŒüóпïÙ”«¬GßV¿Ã$¦`$£«zWX|WL`Ù—C¶…e˜‚µùÈØ‹ýPn<2.Ê šŽÇ€ö€#C_§’–‹Œkí®… $••¦€:U0À|ƒ‘U1V¿m.25Nó0óÙ®xA‘{´ &ò.$r7ãEDfË@äS¬lrqì‡\4dz™jr+ô,d‚V¸bQE~‹¦gABn¡V½AÈ0âŒÍA&{…ëcñ[lKqc«‹16^š:C:ÉÜõÒÒk3‘Å`^8È Úð;r‰¶ë7�¹ìæ}æ£BC$MãI33ÃxÓ7Œ(àÇeÄÔçÔµÞèc¾v–†q^[Žòí�oÞ÷Í=FM™ê ]”S²§%Q3RF6_Í…§ -æ1ò²Í[©—_‹óç.UÿæÃ@ˆ¾pÇ9cÞ´ãÏ4ÏêÂ;®&Cë¸q@UßF³µB1b~`‘kŽñNgãŠ7踡Òí©§¬Ãæà'dÌ1¢KùÈ›r¼˜Mß6为“÷f•€¾ÇŸ sYð&Äqò´„cëL_|ãÉe”˜¶$ÙY²I°¯“v±.L$-)ª 7ž^ÈÜ8âäo´±t_‡l<¢UÁÆ9Zܾ¸Æ]Uklaâ¦3 2Å5fÒ#ª±ø5ttñV$ƒ6Ð%aË\òŒñ>{!¢¯„cŸÖ4›f\ì5Ì8‡,cÖ¨{Ä ”1êݺª-é)aQÃWrsŒQpf”ò…1¶¤;(ÆA‚t Æ\U±Lõ†KA2Ê#‚úY§õC1¦œó KÈž¨íXC�K.ãƒûÞÿþ5½{Œ¾#Ò¦×醓1VÙf·RÚaŒ�B1u’^5pTóÀ˜ŽjCHå¼P“ຂª½¸egò.vqmÑÅH·Rïäbä(¥¿ÀÅßãØ9Ô¢ôpL$FÿáHì¶x¦H.ËFDlZ¼’/f1Œ¬šdñŠþA,ÈÕl}%Ï©+F1–‚wÞ -ÿÀtÜ +žÓ-‘ƒU¼é¼ š‚îåM*=š0B(Ì\\pŠ·áƇqSŠ‡gðM†ˆ—«ßRñ96Îd8©ÅçÏ‹PÆ (&\yÕÃ'¹ñÄ#‹d:ñhÎX†ižîñJ£×w°‰G¨“D<šs˜7™Ü©@ãõžý.1>›Þ ,ñlv¦KLC¹°ÄŒ_§7”xÉÉLâév`$ŽÖá7Fe§Í#†&“‰F㈡¾ä=¼iĘ0b"™3‹xúC}¡ˆQª”LÒ951 1ÙÑó "¦3QpˆÁt¢‚ÄâUì�Þâu·E„ÇBÔóHBÌ’»üFÏÅWˆ‘¾W¥†ÄÑlýÅžÁQ üðò²jÓ‡Y%Hñ›5½ÑÃ8¡ÕxxIv_Üa|n,–ìðŠR˜ _‡ÙÌá Ù@O§¦6_8†pjWÍ9¬‹#<ªÇÒ7܃ýFdëØ05ç³¾YÃH =n:ŒPþNO 0\6}†‘˜ŠÒiÑ%6f)®æ^u[ËÓèÞá…eÁÞ†1|Œ&wÃ6ßKÚdšíŠO|®$(h -ô"=•ê¢¼\ä(µ›-Œ€•Fc-”Ó,ŒÕT*ýp…±æ -ü0¿²j1Á‹*Ü,ÊØPa`†Z;HátëC† ‰HÉ� -smæÒ6–5“\Zæ'Lo,µCÖJ¶˜0׺#¿YÂX/£‰y«aPA¿QÂÕÊÌI�©8o~‘Ûᯎο¢õÿ?Œðwxà_8rýöþÉþê>0ôÉÿù“ÿãϧøñ/~úãÿñwÿ·ŽÝžoÿàŸÿîOþügöúoÿì÷üÏ~÷—?ýîumÿK¿ñÏþòwÿןýî¯ÿøŸÿÅ_ÿ{Ó£ná—~àþ³Ï)ý÷¿û³óoÿêyɱé_ü»?þÜ ÿî/ÿâÿÑmüÝ¿þ«ÿäq‘Ÿ»òg¿û÷‹küá/þ|_#ªº?ÃâßxÿëŸýé_ýÛŸ}–ÿø7ÿÕ?ü'åÿñþÔûáÿøþâÿìó’ýÕç=ûíoeþG¿û7Ÿëºþá7ôïð/Sÿòþò?üûÇù¯ÿèwýÍ|KÿÍožoÿðóÿò¯ó~óC?ßþ‡ÏüŸÓ_«ßþé·ÿí¾ý)¶üç¿ùíXÃñÿ~¿ÿxšˆ|?ÂB¥Ø¿lþìòã}œó‡Ï±ÿ§ßÀ¹f‚ëþ,ë?°ü„4@¹ÐgÉ÷Yyá?>ãp§…±¹ù'<&©IàÙ&v»:KRaÒm†q -{õ1¢Ú ±=ê÷Óo^f‰ãó¯ƒÒñù=¯#€%1–úïm“bO¯£ãë.ó>ÙsÐ몾¿?ýæ_ÿX¥LQfà í)˜XÉ -ÿ8ÚŸÅ/òà(?Z(áüÜÕô|û§û°q¥–JºµþÀƒ>f±¾®¼³æ¡·±)ùÁ+»ÌUŒˆ÷Qá>}^÷ØøÓÏŸØŸ®8þáãy|dÄèıËmöY°øn!€Ö{úblRí3¶¹±Ü¿½ -JD)ßÞg`ãO?b>ãÿòúþÒë[gͦ¤MFQ>knàkPHPñæ~Æ�‚�û3W'8�…Æ°Á‘Áÿrc‘vG]Òë’—C÷¹^¶û²Žùºç ×Í:'ðº±(qÇ’ã½-Læ—ǵïG{Ìç-ؽ_—ïîÀßq\ø-Ïdˆþº«8k(5^¿ÿ8sŸèe»¯é˜¯ë?½îÔ9×]Å/Àg~oÇ3y]ñý\ù¼û ÷»òÝøu^WêÔÚב+Sk~›«‘ ”×Èuï‘ë2Ÿ‘ë:ê¹®3¸G®Ü¥Ä~o;Phóõ¨Çø:ƒc¾Îöõº®ïîÁO$“kH¾ÜÌOùrL•ŸÇõs—ñ>µË|.ã:ê¹àë¹n ÈøÚµýXx½ŽzŒ¯38æëlÏQ¯ëúîø朻öš¥Ï3¾féó6\³ôe¼géË|féë¨g–¾Îàž¥Ï3¾·ÝoÃ}Ôc|Á1_g{Žz]×w÷à»7çusÎ3¾rÞ†ëç.ã}j—ù\ÆuÔsÁ×Ü7ç<ã{Ûý6ÜG=Æ×óu¶ç¨×u}w~úê{®öëaëË ¡e|5>Záq=0-"ŠþögÈœ[_f~¿¸÷¶Ç8G=Æ×\æs¶ç¨ç²¾»÷ òLº÷==ÂùñãI\gyï+ºœ‘sõ—+sîÓ5éß÷ôr®m'q=©m|?Õc¾Þ€}ÔëUùz~•éñ̺÷m=ÂùýãJ\'z¼‘s._æܪkÖ¿oëå!\ÛWâzXÛø~°Ç|½û¨×ÛòõüÝ_Õóöヱ¾?Ÿj˜_5É¥öŽñøãË�À–LÏx�Ù"é÷÷gã—àÞö|Ôç¨Çø:ƒË|Îöõº®ïïÁ¯¼øxÝÚóÅ^§p¾íëd/ã}a×ðpnÂ5¸œÛu}†÷½¾ØkÛóm_lß÷˜¯aõ~e¾»¿æòãu_Ï'{ýþù¸¯3½Œ÷U]ãù×èrîÕõÞ÷õúd¯mÏÇ}=m|?Ùc¾Þ‚}Ôû}ùîÄt^U˜ðÅ×)Öü|hA ;xy—ñö4.óñJ®£ÿå:ƒÛ×ùþÄ"øñÝz‡‡-_Ö;<-Ž“|o‡ú2çû:êqÓËwK×ïâÿ…ªÿøú -ªþ§ÄZËß-ÖÊ;ö5ÞzªxÁ~Áè]üz¬sý;Ç{µqÚÄøóòì‰#+¬g³' )½®N_lBNîiCV®ÖGýö:&×õ3{ý~÷´±Æø²Ý¯£ã}—uŸê9æuMß_ÿ¯6iàß¿ÜÖdÒÅëènðñžs½l×UëuÎ1¯[u~ÿu[å˜ä/ÛfiÑÞk_ÏõXÏ°y¿*ß]ÿ¯2a°,ãË=}\Bóú}^^y¿ª—íº¤c½®þóºOç÷_÷?P{ÿ²mV6ôý¤¶ñõPõ<þ}Ìû=ùîúµhÊž<\–ubóo5ÄæQcô.㋱)=½c6WUƒ¼Z¤m|ŸA ¬ôoõíüîm‡¤®ï£ãëŽù:ÛsÔ뺾»WÌ¡ÉÕ½o'Ïöå œ'{zÿÜe¼Oí2ŸË¸Žz.ø:ƒûæ`ªŸs}ÙÖõ^ï£ãëŽù:ÛsÔ뺾»¿ÂÒz¿{©r,œáßoK¸¯gÆ/o˽í~®ƒ[ûú¦~,vgÎÚÿ±ìc'výè¹_¯<÷öÞv?…ë ÇÖ¾¾->Á_ñ£_ûòчùu{x «~1úr¿Üʸ5>ƒ¯F=Æ/F=²û¨Çø:ƒc¾Îöõº®ïîÁwýë朇}ä<šëç.ã}j—ù\ÆuÔw Ñgð5ШWèK ±~½9—ñuÇ|í9êu]ß݃¿ûGOǶ|w_‘{%nêþ}diñb¿Îô2ÞWu™Ï¸ŽúÎAû¾æ ß'vå Gßúþqì”o³Ï¢ÏöP/ã=ø^æ3P_G=Cúu÷ðÿý‰ý*ÃÂñ†åé}]Øúòðéÿ9öŒöÿ¾¬ä«î(²WöjßÞ¸_V÷¶ÇÅ?G=Æ×\æs¶ç¨ç²¾»¿NY®ð}O×~~ü¸÷×Y^ÆûŠ®Â¹úkyqîÓåŠß÷ôrÛ¯m=©m|?Õc¾Þ€}ÔëUùz~(²½áû¶Çýüþñ𯽌÷E]k„s®Æ¹U—7~ßÖËs¿¶=.þõ°¶ñý`ùz öQ¯·åë øu¢È=Âls¤ï¾ÿ0¿>êâÆo#bm~�Ø -c–÷�À0Û—¯¦/ÿÙî|ÎçxÇøúíË|Îóóº¢ï¯þW¼nêùV¯S8_õu²—ñ¾°k`87áVâf]Ÿß¹©×wº·;ßóõ¶ñý@ùzøû˜÷kòÝÕÿš€×=Ÿéõû烾Îô2ÞWu ç\#JÜ©ëË;wôúD÷vçS¾žÐ6¾Ÿæ1_O~ó~G¾»úŸþöáÍñ‡?üÉï÷§ßÆ+´ù·nÖ‡}`kþ¦ÿaæóʬº¸Í?¾Í þôãû ¿`>ùOïך¾N’}qÖ9wdhÎÀšÛøù=0§elÏj2&iÿàô§zÛŠ¢£þç~„ù±%úþçÞ§ÏqS–ybO{âž?ùy§llåñyÔYâ<XÍéLýó Ùˆ$]*cdLãñ|†s€tÁ|â¢úêN0 /£™êuÞaß³\¼å眆?ÛôñÜ}ß”Ïîê¶àú”Æ6¢žÎ×äþÀ¡/çúÑêا_÷õƒm¤œëÿò~УA¯õ‚B‡=Dž¡G�N2w=_Ò©âyéC×bï¾-ïCú·ÀJNñžÏz@¿…/¿Žî†j#Vüb֚Lj†Ã4öéÛ�ó{[oY1ëꘌ,þÜïlj¡£&ïç�}ÔâC—hd€œ6~> Þ¬¶ÄÁÿ!v/+Ì]7‡…X|“›ªÀ¿ýìïÿGŸN«ÓWÇñ|Z/ñ|rí~Õo3°c}þE”Kÿ€O®Åh‡ê›á²¡¢ÏÆ=8°.Œ„Â{Kø ?ÄþxíeE‘_tƦ(—±qÆ'}}é0ÇЄ m1Œ±ÓäÏ^@ÜJ”ä¤xIZ®¾•(k=ÌiùVâ‹í~v+éË‚õ˜4²„è8#cbMÏÏþ\Œ…¨‹—åã_ußá‰tnfê½€1§îg‡ñËÆÚâÙ}‡¦Šn½íhÞöA[A³(�žx#CŽÄã|ô´cÛøÇÏ^Ây{>'9uÔÞÅËÃúSYÛ¨ž-\5)s_ñøY³/cÈ_”5Õ>²Ã~f€™e®`D1¤S [Ë~Fˆ•øÑÝæ †E쟫íô}<3þ™:_´“yP±¹úg(&Œñj/¼3û�þ¶ZÄÿ˜< ïmçØ?–¯ÜgàS»|ðŒÒ’9#§Ns[—‡’góóhë<?Bö¿3Í°?÷sþz5?’ªGšE~ýóÐøØIþÞ˜[—_ãŠL÷¶lñcüf~ö|‹@¿›1&°âïmþ|A>òg¾ßd´À—ÚÖôÑð«# Âæs0keL Ð]³ÌÏÀùÀØED£#fÅøÂÎÐØüÉäíôÇ.ŠÕclnÉÙšëÛŸÛ*}½éŠƒ~ùõsþ\ðïÆŒAô;ãÇyýWqÏA”Ùã°Ì«Ä�D›ñÄ<÷¹ó—n:Oäá“+g”߇9 ?}VÓËø¬êwª§„q<1?Ýo6͹Ķ£Æ¶³ÅQ«¾ÅïÏ üŽ!]Œý�>5æ@â´yöäÃ|VD aÌñiÖü³Ç{-ôÊ×Ö¿·Ù>·©KùÛÜXŸ@c+ûÈM³Ìyµ}j{Û¼ÇÑyŒ)Ç8¬!Ó?†ñÐÇ-%Î Æg01—ÿì%ĵ¡+Ñ3®Ÿû}˜Ÿ3Y}î…Œ}ÅÁå€#îªæ€ð›smóv9óÜ@u•¼í?{b?z–@«±Ç¾ -ý‰ßÛœžäÅýBKñ=ž\èÁºR¼™0çðX/"cõ„�ª×Èß~ön?0~ŽÎu4\nïζ<ní† -›K,2ÙêÁF{.8Àk~ÉqÅìnÆnGÊŸ½‚ó ÐÙÔ̸H›‘y¢À\f,Æ~´Ùó>Ìs¿˜ý‰Å?ñ³Çõ–Ø•/eæéÀÚ½NX<þ槎ë‘ø>6ŒOÿö³Ç+l@_}…Àgu¯Vµ¤’q;Ö‹‚?\ŸëE&×Mfàäl!ØØßW~âñ^ðÃÏŸØùKô‹È—÷[È÷/ý¿ú›·}÷ùüàßûÜQkz».¿·97M’0ON.Ävïëñxñ1–>V|’ÃÓ|cÓ_ßæŽÞ¤Ú6¼oȲíÉÓ¿”zŒ7h!Ø9vO<26´E×o;‰îb&c»s`ÅÐËÆàËbc‹Ïq=ZÑ|¾§Ï–|+[Ž%à\O@Ÿõx¸ rT|ÛÇö>('—±ÇÛÓfË?ÿ€â�”^ë‹öð -£·Ìç×cçô\ÃßÔ aLZÆÑ=ø¼ðÓÆÀ$þt€¤•`ÝQ/#¨€„HkGçÞy"´ ñ¹ühsŸq®œ}€ÞýÎæÕ¾7¶–÷a½~aÈmÅ9•^|¥tšdü\Š/*·½ûçþĉ9%‰ -¦!²û“I×KŨÅùýµ×Õ½ï˪ûk¡;ä[5ËåW?k›umÇÍO¬SÒÐøƒK¨ñ^Îå‹E£˜¢-O)4_ïåã+CÐtÆl™öZ‘•HW�MžjÜïäÕLE iù´Ø÷IÆêøè™ií|–8{jnÝÛf@oô†æ`ðR>SË·ðÊó>ÀÇmˆ!£1ï-©—qc¸æ²Å¶Å>Piñ¬âGÞaÙCFÕÒµg@¯Ä?Ôö–½×}€œtñJêÎÖ©Æú±:Ãøô']Æ8ÀóìGó¹0_ˆŠÕ‡·ÀÚg/8ü‚Ö~]Bƒ¬@Çí×kß³¦H4ïêq£ó–çåPÄææˈw\¯z„íg ¶Öý)bòwýÎÖØÚœ¾®„Ù=ñŒ$Ü“7ÜßÒó¶Žý-Å-ø…ƒ>ûúGŸgÿ:ÂÜzñ¶'&ϵ„·\=f£Rú>À‰ÒÅZ´îu^8�yaÄ̶§¾´¿Ïƒ>ÙÏíþÑæ’b@f>LFrZýÙù¸È¤Lñ ø~¦™È13^°¦$pMkœZñªƒtèÈÌ\‡Žâj¯AŽãÇjª.8ïe:`[3\êšãŽ@=ãÊ$É¡1—´ý²Äç@®ÖŒxLŠWH¨VÂŒ ó¬#¦ñí³ðÙ'"‘ÅNäH{Ælæ¶=ÆUE=ù›<ÑšÃéqhƒ]5⩬;rÄ<Ò‘ÉüÁû§±æÒ¸ˆî{TpÎÆ'æ†gø….è4ºß2D$´ùŒ¢ZóŽIò+ñc©Æ‡²Ûè�ñE|f‰»ï/]&n³Èç´rŒØ}'£–FvlÚb Ÿ›Åž…\÷@z“ÑÍýûŠmŸgnQ³ú{ìpßDeˆ€XdõíB$÷G[Së~oéTÁ˜Œ«rPÆGµfq»ãº’8mögàÙ#h+kÆöbôs|OhÍÙúmŸx¸Œ÷ †kÀU[</>Àv'kÆ>n8^LÊØJÛ³ˆß‚'–ðØÂ%g¿Î=¸ƒœ'Vö´ƒ3{`Ä“\ŽòE#Ý1DG÷qs‹ã.y y©³4·åP!cLÛ·÷sÑ’Þñò‰¡%´p8E—@uÃ땧éIä˜ù1zÄÌcŽÄÌèò5AOß_.‡@Ñ7œÕ¶"œ“ÁWŽ`Ÿz8ª2êïר³֘áAC˜ö¬eßhèíVwøw2–'^º£öß+˜ÌÑjo:RŠýOi®{�¢±ÖMqk–ÜÏý‘ê¤ÐÖ"^£ãz®JÃù×´ô–Ÿµq/ª‘Øh3Þ®±d¬iîÏf –q;3q€:öÍj±Œ€:²‡Œï6´~}ì7Ä,h`‹+˜}ßXŒƒ{"Äû£Í%?±fÅš:ÌOÊÛOÒ›}î:Ä#0ãlb -ù|ñÐ(&¢81z /Ÿƒ@V«ðm}y«3œUø¬?¹á0-žçdw-^œ¦`±§#d®yh˜~´9í›4ŒùkL}ò”ÀqwH0O!~>Íî˜q@Æ‹üiD¤ µsŒéP‚ÀVwx'³ #àÀë‡pòJl챡x…¬fÆgNOJê’èn=:Cç8ÀçAØ+Oî&ê •A¢^)Çœ¢àYíê¸Ê›Ø¼Å xÖJXSsH'Ž4Ãÿ}¦ø¯ü±œŸ"zí[Í¿÷{ýìÇ7ö覘¶Ý®àš)[Ï|·â�O‰Ñ5gž§.îɨaìÏÚ?äsyŽ‡ˆá9Ǧ}oº4Gá Ïóô³"6†N§ç]-ñ[6<«GMsû?=æv,™z-Ÿ,VE1£RðÛ_ïøUöd 1óÃg—…ƱVë;lòœ17Käô[ÅOgßÓé²m5ÁYo"ªºÉ;R¥B¼–1ë0_±c ëÊBÄu]·»ì…¥Û^¨ŒX<�´×Xõ;pŽþ›û3â¹ÈØ}¯2úEÄ0ÙD˜/B÷hü¸ãù˜@`sëqÝkÌËÚùí¹ïÖ“cÿÌh½ncÝÃU‰õÄs»Jed@Ûn•t!hÖcÈhC¾Íiíy§HR…ÎNãÙÅ -ãÑdÍÚ¡gëÏx`š3hL`úz,”Òk¡×ÃŽØÖ \|H{U7K÷¶½ö·øØ{×æ6r$Qt?Ÿý‡Ú8Ñ÷ºçŽè«P5s",¹íñ®ºíkõkbvBAQ%›cŠÔ!)w»ÿøù¸™@&P|eK"Õì‡ÈJ( $òàw;‰d ԙƢØznW‰¼i�²J©&Ög¦#.Èüýº{ÌùÜË¡V�|ÃÕ&"öKò^$;GU$Â@¬”Z› -ýdÙ.*"›îìô@SÕõB¿/)˜?«Ë¿«bû/u¸2b™U‘iÜð°leb¢<ÅSS€—]A«Ë;¬U†L˜ÈÖåÔ€I`EÅeY„jßjä6-ø2QHÝÆ…$u¡RÁ=�î&"yï’£‚Ñ'AH*kçWw0h,õ�.ôS¬È þp%;øiïõ‡®^d´‘’VÖxÓþHÕûŠL»˜k<e¢©ÔR† S",OÈŸM˜ÑìÈT)ïRÀìGgy?‹² ‰œl^ÒxÁ›†„:Ô°pdy0´‡ÀQ³$M,[±C¥ (“<ºÜ6¡¤"ß&â™Lâzoú‚÷™*[È�~[E4 °MÁó@G~ -e‰Í=wâ*(¦ÜË@ùèx©®/iLÉ/ûQýp11%óþ*øŽAIÖ²³\®Àê6Yž(°ð¨Xg@ú .È/Λ/<"àŽÅ0×ú«<è”|# -4õhÙØ TD'š¸>€¹ ¹ôëۖ{‡/ü&áýAØö`¦IBøa0j?® }4ÁøóÝž}Á^JDj¶´céP–䘄”Ç›¹¡EÔ/IóÀ‚·† ì ‚£OÖÒú,ÌaP~a–ŽüÓʉò•9z@É‚¶=” .Ez Hñù¥eÀ ÈÉDû¦V… ²˜L>�™Ìë"ŒªHœ -ÐÖ7`È“¢ %¥&G’Ç©aM©´Öà¢Ö"É“U³þ’è!Ü#À”¾�º<"§Š)F…¿•Ä5SN Ùx=Ð0ƒŠVväUàz(عï(PòIEÂҺPÁ'«†»€AÒBI6"ãKì>Ê*YiÉn©–ÝÍÉ'µ„aØQµÒ´*«£Ojœ -s¡Éaê銞áþ@,ó”8+!caXÑßËÒøE. ¨™ç•iš…_¿2÷wRzà ¨ŠÔpèÀM ä†]=¤à¹Ìö+Ÿ]_¥$”Êg@ö¨»9NØ*"åÞW Æ爧@hFpÚ§v£]efj úççÜ*{¶$î·UbªB×̹–Á!ºß–šœ·Ñä8øï’Õ‚oMåEÌ�ôkÆBb3Zˆ·Ð@AŽJòË*EL§Ôš\-‹D¸:©[#'KH”Å›LyÎ*Éด֥Ãì½!&ıÞј*¼»…æ‚B -ÌÊÑ®\ÍáÒê0…�0(ua»lbQw@%Óîàci}_<·tNÁ ðB07|®Ÿ÷J§”…o¦³‚ä�["•ì{™Ú<iá; f£)Ùê,4ûÀ—žPBY+™Pd³…ò)xl�Ð�¿LªÜýñ:S%#Q' -w¡¼¬÷·”䶉ª›CtÓ*ñŠöý@ªÐ9¼ä –‚ü¼*UÑ -‡³æïT–¹($«üÝQἑäª&µ¢Mš:ÀVŠùBrQ¦T¦Œ^mez€ø æAòa#©,qq%äñ-#ý6ÄXém(Š£(9dÈk–WDsèšKŠ’;,œ÷5ê6"ÍkYƸ…ÌL;rDëŸÒ+¾GDJÇ8$¸ßŠÚe¯}‘œLã´"1á9Ç!Ž©Ê‰¢U1ž5|aT’û¢ŠM&¡öav|vì—0¤v@Ê:Ë*! ÁŠÈI[Áõó Ž´¦Ãïø -ýRÕâ© ËEÒÂÄ3!.:™Ðâ!”dRmd“Ð9E2•$CZžàTVlIô2´º"qFqýè@]T–<.PáýºH\6ÉD–1É’˜bæ„i„M«©ÿ&Žµ^ F+Ùp7½–¼g4dÕ#_zðÍ^ÈxZ–,*Z‹Ž¤Ú[U<dRß1ÃÚáÜ›s|Yr]"¢†¤k̽íð8ÔG»%‚‘VP³d6ÇP`Á1f‚¢Œ÷ï ¸ äßÀ•I,ÃQFô)D&MU±†¥rádhÕ’#}¡IªJ_Т㠜‚ Q4·…W/y„q°\²Œb¹w͇•U<Üœ€dùGƒp°„¼å,œ¡*ÁœXsˆ ê†Î[8u¸ESÐË*Ž[QFS2اóDAæ€:FJ)d9h\ÞDŠœ’´h4ÅÓ–ì‘{?ÝÀº•êˆ(¢JӒ̹9E“Và^Úb¨gb¦6º¨fHZ ë Fü2³\Qœ˜; ÆE3$òÌw!è‚Ýv"肾>vÀä‘Ý_\G|b˼l¡iÍ%H¶Ê‰d×ò Eâ àIº‚2 ÚCƒ&áVJŠæ¢xFŽ `+x’Ð"Y³a"KÙØþ*6 8ŠÅ–ÚRÙŠ«Ñ–BÇb˜/J¥=j@Ä@¼_ ç35Pí�+)¹Õ¤ˆAM'¬r¢—èZKí2].,”dŠ ˤ]Ų£<e))N wLÓHAD† ~"Æ2B«’»åC¡WLÚíd윲É%FuQT^�’òËb«–ð]r«¢äÉŠ×<x¬aÙ*ÆyFEC¾AaT_j›îR† Z+ò²WÄ–ƒª¢Ð¼eÔ_PRB*@ý¥…‰ ØŠBeеÈÒÒ&•”Š–œŒ:, 3ʇ)Ix�®(ƘÂë ‰ÜòfR†€‚JF±ŸyG-(5_&Ö‹¥¨'¶Ô,0‡—`GfñfXŸ{ODÒg‘_Rî5¤f‹ñóÒ*ÖÓEOË·`sa8¾}»nì�K.Ô؇�TÄt -6‹¦°b†] ÃÜÝN²h+ÒÒ8©·äbèVdØÒz=N8æu‹,{9Û}Ù"ù°P,ÉdC«I-*+Bb^›ïÀ(‰„ˆ2A:ØàA Ð*“ ’ÅJPÍZŽ ä¤ p5’NEÚCe"Xæ!:¼,½sJÜ,ÔnYRd]Á6¸ÜÖ˦ò<â!ª¬#…VFλðqÀO4o]¦´UÐØλ ¸UÒÂ~Ÿ'’œlU‚H²äÇ’1UPh1Çá€F -ªð>u¢šV’ù'7‹+˜pûÁÌõ b™Dmi4±¾ÈvC.@àD¬ž2 ŸZcÌÙÀ„(ÏcÁEÉy0˜}ž³ô§ÁòôÁô‚e ×ká0ŒPPz} -EnÀPÎÜlëÊC¥õ!Ø�rz "ÑÐGíqžÒ>¬h ¸4’€qÏ•˜LÂP6Š ÎÀ²’ÓN,NQQh:<¼§ ·;zm…÷SIž±89šXjì"k&ž9~1ËÐ-ÍZÀŸ€0E<¾ -2§=MBªp[{X”ƒ¥ÒI�6ºrx`Øp7¸„}E¾…¨hvm0 ™˜fÁ‡Y Ð(Z31ó”õž¨tçàI�!©·kŒd’â-N`¿6’KÊØ®á4è/@íÉÀ!-‰“î¼¼„0«Hñ·Èþ³ ÝÂ(4e2NkÙxæ:|¶oàÞ@A¸)ØZž³ú|$%Ì°–Í`ðáÆÖrÙ’,h£Ø èf'†~´µ¦H¸eI‡!èèÈ xyÌ “€Câ�j¢«¤¸]”$ÀƒmI›Œ,‡à5ÁQÐE`q+›ÐUÜÄÔ@Ù¼3)– ®yð² ΃Ûo]Í"o’¬`Kß!ö_Æ=¼ÑÄËKMÎÄ#0Ô�äƒÌG^©…á䡬5ðÄ(ÙMÀææ‡(u*ÈFT•‰†½o¶¤ã Vu ÔTŽQë/þŽ¼�Õ&M}<0è¾qb*–91˜q…¨ -’YÙשô.Ó~ÏQ.)*¦làX x½,áJ+[UùÎ}ÑE¥"v'&x;TÞ¾ëD”+ŸJ5ìD^œ¤l -k Óªâ`† Ð 0iõ#›„ ðBÞåñôe®&ÝE”n�”$©GÿªH®„÷W”$©¤©©86÷)�‚›%FBæ”ÀÌ aéI�Åû6¸Éæ9©Q,òR9‡Hà„SðIJk^6±2yêº Ãh)ÂŒÀÈSÆpE�ÌÍäyÊVœmêáʬEÎ.§0‚ŽwF–䪒¢<¸ÔÔ/+)¨&W” -^'}üøCæ”G’;#Ü\®Xê‘ä|©¼¡8ìG[’ŸeÌàP÷ON™ã:i ¤ÝàNoM 0OXØ0cŠ",ŒÏås¼?sÎV«qŒÑ†åS‘Oé’ÆÒÆ%/nõ'ã"©rEÉ=¹¡DÒW²¬-¸®·?XØ„÷ Í )iq‰û’á.‚õü8xÛGh\H¹ûJ6èÂ’»ï¼6ÑZæ9;7kvÀÊiÂ,D_ñÙÎÇ6Ñx“w(ˉ³BŠ#Ì\Í%9^(/“,¥{Á&flcykÖñ’O‚Éù„RVùV9…ê‚+8[ãr+£×·öþˆH5ÖN GvièÆŽÈ•½Œ2�e¨(ˆ6$¡¦"í‹ñiêп^æL94Ç-ÀR#°wme90û?…²š&¨|Îü‚ôh5ñ@-HLV¶¤x�á·vXµ!Kxmjyqþf8·”o@ˆD˜‡Ðvh€uí°ˆ°`夶ä5 ù?%«•w<Áe?ÑXbìB΄ݨ?ˆÅ5 -6š ɇð¡x7(Šµe$ö«ªÈH’L£’LxbìJvtÏ9üN�UeŠ�Aj¾]0Õn«pb •ƒ -URFI>H}261:J)ó‚+ÎOUIM½ÕI9ïQ.@"“ -´Ã+V® ÷8T·lìÌKO0$Ž ’âÁZŠháíUé,L(Yb °,hb\”ø 3qí0 -ð©„Wq`´Ëi2}^DŒÃ¡èÔÜç‡ñÀ˜A¶ã³²PáYìßU°åÛC`úv‡x!“ðSa?—Þ1ÍÓžBRj«p pFÌ$A.˜UÎeÒŠ‹Ö„ˆ>�Ò"drR‘†]5œ‡‹H\„0Ñ@Îý8Äp…18Õ)ÃៈØ>ZN&@ÉD–§UæD’QˆódVæÉ’ž‚‚–2,b\ ×,Ã5‰hÉ:(ây`ˆ·G¹âM g3ë…0V±¸„|n� -:Ö¿)CЛ® -ÊUWZBz…Ž P2R0æRñ¥)nR’ÒŠ¥äh9ÿ�ûv!/!½Î[ýâ‹šZ ‘(6Ó2–ÀÎÑLzm1’XQ…ÐJ¥R^ð8„$F²‡Áù'…Dþ!†ZK©gSe�ëÉ0Ç!VSpZM4>‰[PHj5ž‹šKiˆëpÅÑ¢†—eå†|…tJ“ìO´˜ŸPª¡&¼Ëè>$ÆÆJÁV ‚gÌ&úDJú"-EIû%Êѹ’Óæ®ÉA»ÐMŒÄQ[ͬtLäå‘S4³ˆÜ~AÏÙ_å~ï(ˆª¥Ž™êJ±5ÏT~¿‡`óàK àÊpÙ’b¯Qð1쬒@ÇjÀ–÷6¼Lqb”!�貸j¨¾¢ÈLÚ”@hâ$%d�wÁë^л‚FÙ` ç@œ^EDAéÄ@I™ Ë‚‰3då*’„ŽèÚrL‰XIH¼$…0H‰"böÒ"˜(<˜É-ú -ú~YïµíG¡¼„¦ |›æÖ‡‹)Pª”¼èhë¹’Á9ÇŸ»Ò’E1aBl}™fYáÏ -8pÒöÁ˜%VNKd’vzàk0Ã2N™OÜâèxI–tåÁvl9?#d! -@Cê)2é<â 芓Àªð~-”Ù®´ \*8œˆD$~Jx®CKJ²‹Ë>¼_RÜ*É6¾™z˜ò$€£*¬B†�²<òg°Šµ¢ÐWÈÚ™[sã4�²,K92\ƒkÐ+M[Ñ•%u‘÷´DPtYÀüLhØ4Š/¢êšW&&dŒÙp8oÈ) ÀœíoFQ_KkSyË·«)¿&›\¨£LñÔ Ï³}&fùÑ”íñçU%åG’$)Ó:±gEÎÀ,óµ¹õ†D�dª‘`Ö‹²‰ÊL>DÌ·Òƒ6©OE’€YÅX)Js¼bVSþ¤œ rÔ@LI‰‡ºJˉ9uIª<ò¨eìAÓ*â/Lˆô…’̦ɘÈP:äEB¢‚’3Ro=Pf4s/¬Xy[æœíI3£I¹Ž -ÞóèòÃÕ%Yé0.ô$€ã™€¨�d*IôÉCúä†*ÍíZ¥™ÿµT–ˆž )¿ŠÄ†ÂÙÜ Û[@ˆlkËœfcõ ˜ãW}uÐÒÐÞB»ž—i ³ Äô�¶¼9ã»+” -A} -˜K›êKfKÍe›fmRÄo%TÀÄR2B�êè `£*=¨B"-[$Œ;e„ü3/[ÊdUTl.§<Ð*ëú8Ì -Ù"“\Y–ƒìrŸ:0 ° ñ‹ †#ñì£Úñ ªÇªËT—T*NíÆ—àé¾’|¾ñ|ª(i]Ô:”ëôRìЩ1 뇱H-¨lÅŽf¤É`ô™àÄÞÐ@Ô?Ò^ŽÇåÆiólœXfºMN™«’³�rôUD]éÜ‚l~»ÉPu‘87æÖÅ&Or½4œÉsMY…LNÙ¥pia0˜.…ÄJSRQö�¤ä‰*u¢à�Fq fT8Ð6 ýF0^ÌÀ2¤%µ†lHÔi¼>$(Î<+`Ré‚<6Ù¡2Ð�Vš»2MZ¯8îG¤°p´\Gt÷Prð(ò’ÁÖf•¨pRlF4!W‘_Õ¬%^À4µ$àÐVü‡×c{Ç)ê@á—·×.F [XÞ¨*§)#õ:âŽÆ´¢VÍ'mœ"3 *Ÿ)ò -çÑçÇ´)¢51;…HÐ+•ŸŒ±`Sô§!(^Ñ3– ˜î!Ê˾¬ä¨¥œÓ{Bf -IëNJü@)SWá%:Ì5EêGÊBDÉýÙü²ü�¥8™j8'1uȇQˆ$WYæ ã(¯P”0x„“ÀøI`ËÉb0ãxD.%6)Ì …˜ÍKæýÂy8INÌ拆t“…à«lbB_£(±ª cñƒ”Ë ÝøOØòØlîõW((–ÒHBɘȳ$a¢ÞæaàšÖh’3ä©…pŒ½å´fh¥ˆ,<û°âTÑAØE+@Ì(HB4® Jiª½�ä|¥*¨UÅ1Vd,<4E>Ù`¨Åó€Ó«Ø1ÖiÂQº£`qŒjÔƒƒwMÈÀh–߈Áé ˆ—5¥·†ûáæ!Ýr™¤ÎÂø†ã@¿ª@d+G`’ 3Hö�©Â¤ÏšÀä²à,ÁP´YSünEx‘¸@™âIŸfÁ„’gø$þ€ŠâdK–µMôBÌ‹`Z9‘L© ¨KÎAiul@óÞEu£Æh2)p¢VÑ÷Ñ7`Híî©Õ·1½_†xŒQ†'a9ß²Ï/NÖæWœ1i–XãY<c’4œØ+j G–’PœsÆÖ%çË•ˆ=ˆÑ~˜ýÁ“ÜUš—œƒ¥ÐÄϤ²ÁL·¡¬ œ"䯂LâgÑ3œ4<Ü¢%c¾é¹ôä?¸<ÙóÀ¾Fª¬á¤¼Z�f©(–r°ŠrIÛ&Ç‹Ff]¼°í0•ŸŠºG ðð’²1ú6iuf!{= -Œ´ò0hï*€--kJ"kÈ/‰·hŒ%£,S¸o ŒX–’¼H)¸Õ"i£CÙœF@…nq¨¬Ò–˜Íú…àå98 hÞªŠ4¯d - kk|À®²Â3«Ï5àØàËrfMÁRæ|‹âp¨È!·Îy &Ñ™4Ê$®³R¥ Èù—±›¯,§Îà�ó§ò°¶çDÎ+³sox²¶6¸+�P7<wXb‹7¥•5¾Œ¼‡È#h¹È'™G#à -½,ÊZ–—H²ˆ`+ùe,2é8„Y±›.„›‰ËX}]Ÿ"<E'h0€r8¥äH…AóÁ1[‹÷*˜†`ÁEá#—AÓÉ¢XyÅàù,ÆErÁ²—'‹Û8á+Þf’NÐoªâíœ÷I'0S{�r"t•äœ [¡¨¶\Ÿ3¿PèÆ‚¬téÛLºôÍ0›¡*r,wà˜¾‹òYÚ¥0Xˆá’b-G>‡Âƒ9Ù—¢#-K§DÂV$Gˆ™ÿTð-ÇúœD r‘6Ðì×I¼ -©™Ë®B¢@c�rhü4»h‚Y -Û¢ðuà:ʉ¼R(8´rªÊ¼"çÛ¹lr—!b&OÔU�[!¤U‚">`BrNcù%yy -È…\~«8ë ºž,|r“MØeÒ{ÕÆÛœ(;"ieéRŒåy)‘|€À")y¸øÆ›…Ý¢9–IÞU JèþÏœ¯4ðçª1áĦº‘UA‰™dˆ®dÂ~Rù÷ÓnAVŒÓÒ ºV i¥zYԘØb�ÒÂ6”¯A$Ù1èþ‚E¯‹÷äΔç~pv^ Áh™M¢4úA/Œù²1WõšZšùö&Áɪøž¹¹VãR…Žr¬ˆ·J,Aaj-¾ ÒPn(¤“ÔóK;ß,½Oû”Hþ‡‚®Oµ+žo#-ùr¼’…NŸÞ·Ì#¡L§«:sFѱ6MLïïZÔ1êqáw€?8sî±!£Û”? R½J1â¼…5W!A!4 Yµ‹þ¯bà]j8¥VSþÌu,ž4Et/ÓJòIü¤ÙøÊF±¡4:Ñi¡ÐIaÙáÒ{¦x ;bUºÌv€x%ë7¹f}ãO€‹9¡øÊè`Y¶_„Ï·K/¬¼k©?ó -ºF³ÌU¼ûTŒZ,9C‹·ˆ,j„¨gž8¤Ûó-€s³õEk=2ô'‹9áÛó"ljY%éΰúV‘K!$VÑ\-èJ<‘“?ºÞ,l–®ŒT”òš´ÿW¬ùú‘5œ ÙŒZk‰€=h›,r(mÁá&Bl•ã0Cjäùª;F]p¼õCÂÈ3$^CŠ.Ä'‹9Áëë«ìÉ×Ù/?7¾-»ÒÞ�ðìûÑð͸?œö‡ï=oºO8øþ~¹ÿéô§—/ú×ÌÁSþšýåàé/ß|?º¨áëó~oÚ »ãO«~ø&{òÛÕ`è~:tÝ÷Ïo¦õäëìÏOŸ endstream endobj 202 0 obj <</Length 43317>>stream -ÇÝ™½÷ýÁŸÂï2{új8¿ÁŸé§ë~{âx’¯¾Îžþ8ì÷øÔµ;|×,ú±;¸ñeí_L߯.<ì^aYוPúÏÛ<¢÷uÿÝûië!Qñ{Ó³WgÏ×ï»g¢íÈú®äšá@™{Êèü_uoz4º^¸¾~k;¢KÜ:®ètÒzÂuî}¨í×á§Ö#ú´ÕãX3™É8~£ÏÕÝÝ29½Ÿßêa¯n‹ -_µ%6è=÷<ªáètÚŸöÖÐô8¦ –þ¡?¨ÛoÁF{¡l;´áÍÕëÞ´ûqƒ‘¥Uî}`° ÛŽm\OníO9*~ÿt¦“›¶c:ïNêãú߸=ÙžzÎÔjC–D¬Èâƒ79ÉêZ’“Øõ“qϳԶ£Ñu=îNGãÖÓ+lõ~êו”Ç‚²÷>šÓÑ͸W¿w¯ß÷{퇵Á¨pó®®G“þtƒ½sý@Ö²mž>¯/³oö"àöhçD@½÷"àöŽãÑŠ€—ã®ãößú“½¸SB`kŠ¹·AlãÜË€{p/îeÀ½øù“~t2à#Ú!ð¨þXNßw/F¿>cà¡|,Ò&#y´"Òùàf 5Ü=~´µð0™^<¯?ö»Ð¡ £´Òñ¨WzlÂËîÍdÒïÖ®Émd°G——“zº¾ï»·Ÿ6¡¯µm¥ í¯‹‡8½Ú¤ýÙuÑòðº“Ýÿ÷ÏîíûÉuÝ{}³¦ãûMÿ›~�Ì?8€öFƒÑø/¿¾_+…¦<§A{…p(}ï#lí„1¹_v{õi¯»É¨•À6Øztn/Þºão» ëaûm6_ñþG¹é GÃÉ´{‹AÆŠ»$©8qÍýÓI¿·ÆÊï!zŠMƲåb´Ù`(_\Ž¾Väͨ?œžl¢`º]e}vìI8ÀöÜÑ–pGÓšr+ݶU6\»¢,¹…9e[h ?}Óí¯c\v(tÇýéû«zÚÞv·KÄaã}´í„á~¬Û*E|h?=bvÚDµˆz€´æ?¬Qé¥Ñ[=5s—D<’#twäèÍí»Â}WßÕ€ÉÇÏ=â)¹»~ì¾ÌÉ,öŽG;áxt< ŽÆuý{kcÇÖzýâO7XŒÛ®n=Gë_Õ^‘vÑþDˆØz »¢¹èºíÍÀ»¤©¹±û>¡;ÓBŒ»ý›öÄžŠ?‹<_¿ FïZóí[ÚÇ^l9u{t1Y—ºíiÚž¦Ý))Ø,Fc›‰Zë‘ì -UÛ Öo»÷þáÝù!?ЖßU÷ÝÇš#à¼õá²ídìñg;hí½»kÙÚ/Â]9òöLÛÊu°µLÃ®Ø v9kÃùç†Ý¡âíG²+¤`ƒvë}¡îp×ßóHZ/³Éf!0ûò¬µ)èø}w8¬§õ îm¢Ê™¯xïƒ|ÛÚLtÛAÎW|°ãèyr=èöê«z8ý®{½{gÒU×5ÕÚ�»²Òf ·ù”m=’9eÛs@[~2åý›Í}¯mGŒßÚ‹‚Tü.£ñw-ÈÇ6’½óÖRúÖ‰Ö#Ù"Ñ>vv3¾lp:}y‰|[vßåF~l—ýÁ`w¯ÁLë ?¬»}°øÑûnÔÞ6©°½êÌé¨=g8z€t¿v?9_ÄrÚoD-}ù{׸F ¤íÀºýiÿcûµ+lïIp9]µ'Xø,Ãö“ÔëÝ\ݬwúH§)©rÿD¢õ¾ºhŸ Ì—½ÿÐÈÖ\E2_ôúï±÷m§¬Yëþe˜Ö³v7)¶·zøÒ$™t‡ý« 6ÎŨìvú»Þ£q›i?’]ÛL¹w›ÙŽíþXÝfz{·™q›iŸn×üfÚ¯Â]9‚à¢ÈeöŽ3÷0Æq¦ýHv…lpÆn½ãÌîú{IkÖzï8“ígà8Ú;ÎlŸ´ôhgÚdgNÙÇë8#öŽ3;DözÆq¦ýHv…H<jÇ™ N§‘È¿°‰hwÜ6 !;2•;œ¬pOÈýdìn:ŒÝ™‹»ëÇÃöáѤŒ|öêì9&¤9ÛL-ÛŠ ÜSìñ&åy”¹ÔÛ+Þÿ�éyöô}+öômOßv„¾µ^«{ú¶§oߎà;Հ‚=uÛê¶çÞöÔmCêö‡fÞöÔm—¨ÛžwÛS·ÖÔ-5mæ²ñȈ\ëÁ{çNY ÷›hƒMdÿÈ›¨õà÷›h¿‰š›èMÿ·zðfÐýt¶Y¸è6z™<3=Îü,¾ÝÀé,©qïC{Èë¶v‡Žë«Ñº¬»•“Fdâ™g¸¿yæþÿÆ}wŸß¸²;w®¼ï¬ ׂ§í¨v)Ï>oGÃåyÌ©^Dû¬!ÛŸë¥åA¾Oô²x\œèåžÇÓ^Ô—ýáÚ˾S²x]w§Ï7XI]Id³-¬Ôù&בoy”À&cÙ•8ûùÄ@p·÷eî”c[¨Botu=š8šýúfÍÙ½µný¡lmÛå¿Ññ´#¤á˜6×nÓ…G—¬;îOß_ÕÓöûg÷Ćgí¶“‡ÛœSÛî`Ðz_}h?;brÚdÇX:õ"y묱r§Ñ[=5s—D<’£twÌ·:…w…;ÚG!>rûófy>·QÏ´·?/æÞþ¼5[oÆ% h™³ÑòÞ›óã½ôeosöhØÛœ÷6ç/=˜½Íyf|{›óÞæüÙÓ³·9o·"|osžYƒ;¢:Ùm›óEÿòò¦ý&ÛN6ήІ;5ÈÞ·ÐÛšÎÝŒ/(rºYþõF¥íµ¾„…z<:IoØ~ ÎÕÛÞ!úݲÙô5êÜûÐ>ÕƒÁè׶ãôß½Ÿºß{®¸õg«íUp©‚óSþÍ»q]¿qd¶þƉ1ýw£o>öGƒzú͸¾øf4î×Y%öº¹™qíus{ÝÜ^7‡æcºûw“Co¯ Û+èö -ºö9nZ›ÿê{ØHý“Ô¸úW¶X÷÷þÕÍtÍž)… ò¦ýyÞG9ìÈâûÎ<÷¢áI л·&×uÏÒãGþð˜8âQkpœÀwï -€íÀ°#¿ýíÚ1訩æ+>€I|ÓQn¬Œ›¯¸Wæ<¤2'¨n¼2'hvP§³WæŒöÊœ%Á^™ó¥‡¶Wæì•9{eÎ^™óGVæÖ+vÇ«b¯™Úk¦>§+§ANÚ«¦¶P5õ˜3s<²Àû[¬Â]ñ¢ÜáôƒþôM·¿Nm´{„áqgæØÔñuë‰Ã£¼÷£}î„-OËÑ~ û´[æÇúGLËñ@Gè>»ÕN¡·âG·ýÝ”Ûö#tŸÙj„>ø@þ€Gèî8l|úîŠRaŸÕêQfµ:}ß½ýú®TÚç}ú£û·NǶöߪe·ƒýG——“z -}×ÍÏ®ì«ÇägÝúòÖ‹ÖwcÑ-Èš0ÈoH^ã>úCÉ·'»BÚo!,lËäÜégwæe/Äm¹'tþUÛuúkÿb¿«Púþ•“ªýˆÞ×›ødqñ{Sµw?{ôCŠÚ÷<ÔCaZ/ÅöœãC0Ž›Œ¤=ëØ’sÜZùÕÅ^ý±“¼Ø^ý±Ýûê1©?ÊÇ¢þh?½úc[á½úc‹éú^ý±Wì”úëiw§À½X½ÓìËq·7í¾õÛøÊ-1Coºçqõ6Óµ¤¶±Ž‡£ÓiÚ[£gLåR(ýC°ArFûWP¶vÖÞ\½vËõãCK«lñ*Ü1.ï´ÎÐtÞÔ/Æõÿ¾©‡½örÐLûŸ²‡t5Ü–Sáñå_z¼YˆòNëëY¦£öÇö膲O¨äÑ°C •68.Ç£«öd?�³õxóC=¦ôPð»žjŸMiAïH“ôÃÍøüfàÖÔª÷ÉRv&ŽsåÄŽ¨‚o¶WîT‰<:/´ F´C^hñÄ8[Ú»W™V©Ìï[ni½·Ûý8Ú´%Ó¶[ŒÇ¯öoí|²kZXOïŸß·âÿXÙ½¸—·ŒHì¥Àú±—÷Rà=Ž©)¶>%÷Rà^ -ÜK_Õ‘íñËs0ìåÀm[O×^Ü‹{1p/îÅÀϚ̣7щ?FïÆÝöäw/>¼x(‹¸ÉH¸Qœù–‡þ<ÆüŇÝͯñHÃ}C†ÇBöùBv)_È>]êª<Š|!÷íA¼ÉØÛNÌ6̮ЯËýíå9t{¾É<htÝíõ§Ÿþ²&u2ý4ho¨¥lO½€aîÞ–š`>ÉãÇ´±?—ð85ÝŸ“ÒiÛÞ›\;"íðý†›^6»å$oÃáì -{LÒPk©ÉÍø²Û«O{ÝM¸ŸF¥û·l´–üB= 'Óîº+Sqi¶ÞöÑï–ͦ¯QçÞ‡öëû ¬`hr¿¶8Ò’ÎVÛ%å:öýÑdÖ*Zçªîa#EtRãþ7¨jMb»¿÷¯n60sùcµž÷‘îlb¾£lÏ=)> z÷x¿[\’¼g˜öÓ#8r·6Ã!mÉo» ë øÂùŠÛËR_7f~ç+î÷´gžöÌÓžyº¬OÃVÞsO[È==Nµú£t ¿Å*ÜkÕï᨟¾éö×q6»GºãþôýU½Áý�»D 6µ…l=q¸ÄûAk;í§çÃCÌNû¬I-–Dmõ@Ö¸¼¤ÑÛ,Á~XS2ˆØ¡û#ôr„ÞŠÝöctÓ¥¸í'h{2·å'hûìOÐmÈðÝUõþRÉGÄ=â)¹»~ìÞ²Øg@ -,èÎe@z¼àµÍ¢³{bÜýçÃÝkÉn4»œÛéªëšjŽcèûKWu²Þei÷HÄæÄoëYþ]ô!m‡‹ßÚŸdTüeÁÁhü]‹ ¸„ã1‡þ’Š<ʃx·SŠ¼~ôáµ÷¢�ºï,YùömÏÆq¸ODZ%”�”Ä°W~x„§/àíi÷ö›+7¨v…]Øao†”B´ Ü!Ú_¾‹øm¨û®l©ÝæÀaf~¹¬Ç/úãG§=Ú*¾-ó<íž·ÇÃ.è<eÖÚäƒcÿi3MY£ÎÃ%»öÞîQyt‹c³<ûc,·—ûåöðËMüQˆÛÑ;ª <ÁÞ?Œ»ÃÉeûÛ.¶gõü‚û1òpSwr˨¢mW›ÜF˜Ø1o‡5'è÷l0¸sÚ°;âÐíˆæ®¬Õu½‹>Üæ -«¯ž½ùÙ·Ã¾Ê -@ g߆o\˜çЃêwýaúÃÁ÷×؆ö?~º: ž<»¸È^t?ŽÆ@Dòì™ûÿ—_nÜ¿yöú ï•uRmGèR[ïÒEnKí¾67eé¾”e!É~éDÇ‘_>¹‡ÿp_þå@¿f"ϾËþñÏ<»€7¼=8Ì;Z²¬2):¥Ñ&»:8EGT¹v…;ÂJÝ1•*3(-EéÞq( TTÙaÕ)D)Šìø „ìen³“¨jMåªÊ¼“çºÂ/Òø¢:yY¸æ…í¨B*„¨¢Yû`l€…FM§”…ô×U„M„@½¼S•R'¥ªŽÔEï“)²C×L^ÂûEÙB+è9cáPˆŽ{mẮ;•(L,vrPv4èÛq/Ê«\Å íÆ•¾¹wà@•‚wrãf«”qTn˜º¨d:tQ¹o€lÂû,k# -a:Œ’ÏÇ¢é8A®p†L!ŒÄjÊȵ[1�07•ë Û©òÞÕQ¹)°ªSUºHA -ÖšrMÃ䖶ʔè([¹±[‡”¢(@ýQRJè"ƒ\¯«Riߎ[¼e´HT~ÜÒ&ÏUÊÍšÃ[¢*¤•›!X¦°Ð˜ ô\¿òB™R›,̪ɒ5à&¸ -†výÑ%•‚ñUy®ªØN\„ñe°xÁI)×!lì4,«Üªd`°W”&ŽþpVHt¨dÜcqd!Ûí;W³p(™¹o ps¸à†‡K}t“ï -c3YººE¦;….Ý’…Û1á…ÛÚ˜Ìmó\ié*0Ä!Wð^×_·)TqûQT•”�*…k¶¿„fÝšQiGˆ\üx€Äëâ Èž|ýòóÁWg‹H•ƒÞ’X¹šÈ@oG°|OnC² æmˆVŠ‘„l}u6O¸¾:Û˜t}uv+âåªÝ†|}u¶€€yàÆ$«Í1œ'c_ÝŠ¹jó¤ÛÚœ˜9|݆œ}uvK‚æÍHš_Þ· j~G݆¬¹š@oAÚÜüoJܾ:›'onºæÜWg·!q_ ÷úäÙp4Ì*Y Ìž«^Uªr¨ììx:lÌ!Í—¢¬€úÄMi¥î~GÜŽ‹@TïÙI·XÔ"lò -‰Õ›‡ Î,ò¡óX'¦g_?;¶“ÅGÀ< -",±›¥y4D`| LÝ*`ìr¬½‡û³–ÖGK„¥™GM²t/?:ˆ§ ÙØ"{z4 \ÁWB½q2f=~;õîË›þ…—5]óA‚Jýv=ObR(·ùªL»S8²ªÛÆØq©¥—Fž¾»ï»í*4Z«N}Ÿ�Õ‰?/Çý‹ÿ¬?ùvÍü«ß:¡h2£/B쀻Î*Z,yÙi4ut3Ž†g£N¼K…©?Ý8¼=›l‰€¤›òQž½;p#Ïœ±°çJü’ sdFúßýI!óÎ$x°žAË<S&3üZó•à䯀B;| -`Áðó„މߡ¤;5Üwªo2lÑñÔø†“zmå¤ÃPº“ô˜ªÜ ^ Wñ ->Ülwš;¢\8Ìs*î¾ùŽäa˜á´Ð×ã\Ç6 -8t°Y©ðÂ/ð«‘6㪎ÑÉ<ÞÂ+±iîfîÅ ì<Q#ð -ßò±ÀÉÁÑ9ì‡ ¡_dïÆÝ‹~í“ú'õ°‚ I…ÈŽÞœ—Ã?ÀÔ¸Þ 4#À½ÎVlCøåªQÐ,.è¶ýQ¯e‹GZtG—k¦éèèàO?ºïŽ—i‚¦«yáËáÂo)æsBø<mLçÜ\ûUp—Ãü'ÁA²¤â:+„H:µé”'ƒì-›dÙz’]!Çé50-aJÌì$«ÅÝ4ÍLòòZµè&?NòÊ-¾åÖYáâ˜Ø-$ÒÇãú¢?ÍŽ»ã‹¥DúÎÔ^²Àýêf,|ó[EV(øIOºð¡„D-…,¿rŽW(·àn,|FÝ»$p–þIý–TñÍxÚ[o¼9t(|¡V’þ‡QÑw‡·+~…ŸÖí5ÇnÈð)*(ìþ#.Ü@Eüñ0©sèÛ’UÚ·¹'ìÛe(æ;}ž -jB£ôßVà'âè;“þœÖ$/9i¼ºàÈèݳGŽ3ÊœH Än³çÝiý¢_.æÙ!¿ÅŒ(4n2„vüeò%·F»cΕɄºèî9·Ûí:‹¬ÇaáÏ7Á°,}Xœ0ט5ª€ nd¡ @:ÎØ±äŽ -t¬²ÒÌïw'ÃAë6Ã%fý1SЇ_‘Ž»;€Ó×w_ŸÀUþ(–³fåÉã~€“Ëdñp¿„ãAÀ“ƒ<b–”0<V¶q´¦<9[p<W<<øÔ~|:ŽöV\ÔŠ.æk‡©×3_7LU%üÁ‘g~ )°£aÄô)–µ¨â`õÂÁ–°$rx½[~T‹~ÀR¥?è2Œl¾ÂÑ -*/÷‹ô£~¹ï{ø«Gàè¯Ù| ¿"T³€«³¢âì Œ”ñƒ ->V,A”ú¼!3CÒm‡T¬’ -ËM„å&Â2SñóK-7.7Û„k3?®¶™ò³ƒ~Ò!÷=_p±ée;F/Ù1zÙŽY4o®ô‹Kdýáã‹-.½n¿è%ûE¯Û/sCÊýÚ’~ I¿¢rþøRëJ¤“¢›p-ç"Ò9™)?Ó‰ÝGîWSþ~Á%%–ì -±dWˆ%»bAïQ«Š+Gfçþï[KbÙvK¶ƒX¶æzôçê èqõ_`íøxû‰™�•ŸÅ¾‡7ûkÇàJ1¸jTøûåÖN³÷z¦÷ó+¿Ù{½²÷{ïyHsÿ÷K»Ãü,P°ðw*)…`XV„ܱÝ=G4³]éNaLxvÞµ†§Ì+tÊú$¨‰ìÙ5¾ZgÌÔƒ<U,ñ÷)cØý%øµ«ùõª,l“×´~MÌ2È–.(jJÏÚ¶ku–ãXÖª¬Ö닾˜(«\/DNTÇ+·L ®/F¿.Pï£î(‡E´–_–U¬CÔWs†_P‰V[êNcÑDCõP‚�Ç`]ö¾7ÄÚP†[€+fbÛRĶ»¹ -ÄMÑëªP†ûD�tïÀ—TÜ Ž 4zjue €Z¸dŸ�Ѷ¹Š¯£ŸÞÑѳ^ïæêíhÊÁ¨a} ¡–<C€˜ÜTƒî|Û)ðÄ1(™ÅƒŠˆß°û&ƒ§¬dÔqî©!¨'ý”這ŠêCÃåì -:>(ç–AhÔ(²`¬ó˜fqÓN´‡ÿ‘‹B•¢S¨(ªò"H©‘¨Ñc¹7](ÒJpï’e•r÷"‘—I- š›¾é¨Å›Ü¡ØxI ¢_bAþi )nßLÕ9{úýhú¶îÆn²þŒ4}éÔÌÒããg¯^†éýár4¾¢ZØYG/FçõÙ³WÕ™ëîéôÓ >‹¯nì1Öv·nä-TB¯d§Ÿµ[Í.𫃹]×<ï“™}4·×R*÷ßBØüfžÝîs$a ™Hë -¡925»]îàÙm©Aæ Å,ùmcA[Oì²½éù”‚ö¦N¨€Xº7±R®™ -è„ -lø¦£oÒºù’/Cvlû®6™6¶o”Àþ¦K° J€¥p2�jdM© -?ÄÿçÍo($Ð&a9•v²à}•¯‰åªœ,g"ÂTçhö[[;¥µà…>r0W„íã£_ôW3ì3³Ð+8çY›°ÎBK¥3œÇhht’OG–àA@'_ÐÇò„+.�ÅŠ—È΃c`^•ÈÑÉB¢!‰@@ö´ÀÚ¢S‚cî<„ª-eŒtØ!zá‘e¬ÎàË(¼KKѱªDÏ÷pIuBµ#O"©Pna:ÑÍQB ÷We:Jj¹¸ªEŸ?p¨dG™¥>p¯-ÁÄk:ZZ³ä®kee€Õ1îQ®sŽ*ÚŽ-D…‡—*/—T•Ð°Dõ%!P³]Ýò. -ãíV¹ã± »/Øs%’%{îéwÝɇæî;é?Ô~-ÿòW÷çÆýA4n¥Ö¡\Ão»Œ¼9s/qTï%Òãúcã&?e¿|ï�ÿàé;Dí,þù'X×h&y¿¼€|9ÿ_™¬¡vºóöåywÚý‹ÛÒüòêüÛgÿóþ{é?ÿ~_þóÿ÷ýü¾¤ãûß÷¿ÿÛ6¬ÏÕ¿¯Û_Ÿ÷wìQ�:ö7"[ÆDëûµ|H•½¸ùý÷OPÉätÿêÈ)Ÿñg¿üžO¿LgháÕðc=ž5eðñ }Ý‡Û àçý p;‘åtÌæÌ«=ñ“@m×ñ Ÿíg9‰n òºÁÑ?»ÆN½Æ¿ï�4ÇV@Âc‘�>"V_L«_bsìEŒì„÷ùn²™Œ¯Î›£Ú”ÑpœæY Ç‚ÞžÙ€p‡[³r[†£m¯±_½Àå‚òêd–1Tíx†g¯²g7ÓQæ7dÿ÷:Js2×ëóI=þX_œ9†üÌš$Û"FpT!‚#*¡söbÌ•Æ}‘&/‹äØY48†Î~nÃ+@@ƒx'÷EÊÊÅXžuî³Ìý/u‰Þ¶ÂÿB€cÏQçJGØ Â¤Ð:èVM©Ë¤í€ðM˜ì˜¸“&LYThSãî‹ÑÖ·å»@hKð{äõÙ~8±"˜O Ø…ã¸òF0Zð~+t¬rÕ„ù†Aß"LúrÛ)1Ä)é´ÛÆUQ–^ƒf¨(ÓáVaUIã)„zaÜë,Ìchœ'Š»L1õ4™aWŒCm§�šá9\¡Ï§v¿ëB40˜Âü µ#¿Ú¨è¶ šŽ)«]' ™Ûâ(Z:ï €È ˆ¿„Cä†üú}ÜÍ<®O„¿9L!þ`©C4[Š¿–vG”´“Âòw(usßÀvsc¢cm²TÄ¢~*¶žBƒQ˜Âp˜Ü8c‚»RêjJeh@‘Êð ‰Ê$�¦2³ØÊ9…)Ç訌(M‚Á¶Œ?GbÜiÔ$<9DR6p -ž©R•Én@þ㯃!ÆÆ ±ÜÓˆ> âx}ËésÀÝ–�uî�®Š&êRϸLŠ)w]4¨Ÿv‡^.mŠ9冒«qªShðjå†S@@[1ÖRÛ¥±ó»#ʸ‡e< -ÅqúvÓ瀲9ì�ÊJG¤i)GV&¤Ç^º&EQ¦(³©¬J1æø+iÓ£°è”¦Ð&¶›Æ"ˆ1–‚`dÜ. ^Æý‹ã1(ŽÒ7›>„ÍáO[áCn„¥ ˜ñèöÛS8αlön`Þ¬R"]Ã0in8ŒEc,Áи];¿;Ù–ÔÈ2Wãq†v“瀲9ìøS!°-˜å ´)‡W9–±|�²DUÇñedðè9áï”°w±V`Òb»@ïN˜; -›òvB’ØvŸÚ†_N€ÈØ$áëb-9·øîãyì ʈ=IPF q><øÀ%(#*A1Z\‹X1n—� ÊQ–€üШa<½<AYèa‚2×â‘S» €P6‹ï– Œ@<4bvxðÄ%8#Æ)ÁqW\-°_ÜnxN0Fˆ°ñã¢Fyäôâ_Ô½a4®Æ㦆�!l7 f-Ý–·O8gãìO‚0â’„+ÅÕˆÙ↠ŒAg ÈæÑÓËÓ}º˜nÌ0Œ¸1iì¼1#€7æ~Rî,âL2†üȈ›¡¡ÃÆlQDóNbe@DX1ÂRŽ‹¦‘óË#¨‡_4‚Ȉ>l5yÈšÅKÊŽE\„Elš8ˆ+b‡"ªˆc"qTÔ&=G<1„Ñ”@p<Ô&—ÞqD=‹8¢¾„GÚLžŽfñ‘ò_G¡ñ”Löýx‰¹‰8 -PD±H!Šš¤çˆ"†0Š‡Ú¤á†—FQ¿"†ÊH¸Âc M&ÏC³ØH®ˆ!‚ÐpˆQáx™ˆ!bx"Šˆ'â:gâ6ÃsDCE Ä«eC›4^zk²ÓBÏ"Ž¨ï\‡FKmÆ瀣Y|¬mk«Ì½û‹™,óÿü"]U¾ØdÉe�äËù¿-L–nŽ>×b¬*ôßÇçÏýñßšÿÑ·ý?ûøŸkèß¾Ìê[þãmÿÙÛ7³¢Mp‘acÚÚ´¬y3Æ ½…yÃWœ5pÌ@70q@Í9#‡ëmÌ‹pçGÁü’ͪȶW0€¸ŠL 3ÐöFWqÄAoiÁšs¦h{cŽkÖ‚ÀÛDán9ÒJf ˜J\ÍÆ„ÞÂ\‚õf &M`{“ jÎh‚ÐÛ˜Man–˜Sf T ™á¼I¡·2ª`Í9³Ê´½a6gZAèmŒ+‹°·ÓŒ.M`k³$à›7¼`Z¾[™^ æ¼ñeÚÞü9 ç00ÔÍM0°¶ÁL3M`kã¸*Ï™g úï¨6g¢iÛi`4sf�nn¨Y€åˆ]`Ài[›pÀ fÖˆƒ©Z77ã€;Îœ!§ liʱÌs�¸¹9g®Vpófž&°µ¡ÇU›7õ pscV›5÷4m >8šY“76ú,ÀÖª3mΔ�70%<qTë$,ñ&&¡„õê&°µY(2ÃQË“ðÂbÓÐl@ì¼É(n`4JØÞboc8J˜Ûboc<Šün±·1 -ÀV^·ØÛ˜–>·ÙÍÍK‘m õ&¦„Ám õ6f¦¸jÁÜ6 Á-P cÛ@ëmŒP ûÚÀìmQ GÛ$·0F-À×zn6Åìæfª„“MÑz+SU¯¦h½•¹*²°)V77YÍãi=ûšbtscVd]S„nnЊjŠÌÍZ‘gM1¹¹ak?ëùÕ“››¼˜WM¹¹Ù+²¤)"76}E&5Åãææ¯yì¬gPS<nn‹ÌiŠÈÍc‘M¹¹,r¥)&77’Íãg9&—eC¸s¯ûrUᦱ]Õ³©ˆg<ùï*±Ò«ðš%*Ì–+eUp3 ^ÃbÐ¥€@pk‰VkW¨å ¸k"/0å†IûT -:ü;Qÿ§¤Þ9¸êH7ŒKù¬ÆÒ1<Òs 90&)[ƒTå<�kåÄm'-ÏŽ}Cr_ .O@4P*…�89ˆ¹¸‡eHR¾�ÄÕ±åR-€�ÕkCg4 '»Ù -Ó‡ÅR3}¼¯,Ãpå#k7¨È´íXÜöSma€ù›î°œF“Ú_Èðz>aÓ¦w2p¶¦§ -Tn‘€¢>ó‰^«àç/bªð?xÄÛf : ]ñ|Š`LÐá¡XSe>‡‹wÆõew’ÅïÐ^åS'oJÞ˜t”²q—˜È¬t¥ - ð©!›‡ƒ—Ð?øÀaü0>,ñ>ÏÛ ~ÂOÒßäã+øKÇa‰ç_’ -¥ÇG¹*…Zë„Ï<ÞH`†9>õl®}±¸`1—=my‹GZ”Åü… -6.1ÄÏÜÀ÷!"<¢5 éÐã)~ð”$Õ˜Áôo,+ú©ôí…ùLÞ›t'Læç^‡�ymeÞÄÔ©Ù$wÕâ‚…œ¢å-µjÂä!ô©�?;ýˆì”êh70’ÁŸUKÐ…Òoè"YÊ -/ò‚Üý迹_”›+ôçk6µ2)‰-;ˆZ%%9¤éWüªýYÐëXh®©}ĸOQéÏIœòÅÎ6Èô-ýÑŸ“vPÜê4Û¡ÞÝq=ºþñzÅÍI›&Väì0 -³QŽ³ÿøL—ÈH©øUò×äġ*;6ܬ¤!%å!_Ÿä½g6|E_gü¯_ÂÊx+4‰— Ñ·î–pEáZ%÷Ðh#4}|@¯;9Húo¨]LJg= àPUØÊUø.H¯ñ:H¡Èõxà%I2| Hò×úøaäEXëA›%1áµÐî—€y0k£¿¦‡‘3Žrš¡øÍwƒ;w’Lmî‘(øæ&t…†}Lù2÷7•|9�0?eøYrƒÓâ¢ïpZÚêü-N‹‹.ºÇ)a;R¤]¥ØLp'#™£ˆkB5M)My\h33‘ÎQÒ‘Ïg.àf¤æ _VÊ£®qÛ$5Ç«¶Õ\Ý•-µn¹qóRÜbW3{of_òÒ=äµ;»ÏÒ¦ë8ÙÉ>L¦{ ÂÅg\n%òþ¾Íe…m±áK[>jÝráŸÅÌɧ¶‹Ÿ`Xׯ^ Ž•½ä,Ògðo¸¥F& jžý…»ßüÏ—q&ñîM®&3=;ç—wžxNu*ëè“ãÎfõ6òŽÃœ®f(îNµd¡“¸ò÷êÀ§7)܆+«ŽÊJ\6‡ë>áÎ)úŽW¡…†€Ò,, Xo·ˆ!#-Ü -‹7?ƒz&,“Âë»iÙ8®Á ;*;ye¼^®*¬W¸a‘9�µqâóÞ6Þr8ÛÃÙ®Îç0°×þ5r˜¢ë0ÅdÏß~æ$ ƒ"0\Zf:Êêìïþþ³ÒßÉËmB–Nô‚+èëqYx¤Æ/zä±Ô,¦ïH^»åïS£þ¦CùX5‡`kПÇ1wªPH”kô¥ -†Hëuã'óÕ|ÜÃÞ_1§Ñ[žÖä9™Ž%�jódî-Hþ L|íaã™ÚåTðKgÓæàJ¸H^x -Óa¡bP/zæÒ‡±!|è*‚‚^ô˜xWµS†#µ@ågu%VŸi9¾õø>/ƒÓƒFø^•j•³oOOô8œšwIˆáB/·ßP±U©2$†ñ ·]5aŽØXeÐNV¢M´a•@S®ô0Q¾E,R+-7B�zQï€A®}£xh:P -ßC€Þ÷…ËPo¹‘Ùõ–)\žþòÝɯžgÉžôúãÞ >Sg_gRáfÊ•w?6¢*Ül8úT +-F`bø0ÐH¡QÞ§NTÓJ2ÿä‚âfqSn?˜¹T,“¨ -#&ÖWƒÙnÈœè‚ÕS¦ásAkŒ9˜åyl ¸È"93°Ïób–þ4Xž"˜^°¬ááz-†jJ¯O¡µÈ ÊÙ€[€m]ya¨´¢>Û�CN´¡Qd!ú¨Ý ÎSÚ‡ wƒF’0îù£“IÊFÔXVrÚ‰Å)* +M‡‡÷ôvG¯m£ð~*É3'GK½UdÍÄ3Ç/fº¥YòP¦ˆÇWAæÔ §IhBnkë€r°T: ÀFW׀¡¯È·pÍ® &4Ó,ø0Ek&f^€²Þ‚îá< à ¤#õàv‘LR¼Å ì×FrIÛ5œfý¨Ý ¹8¤%qÒ——f)þÙ6¡[B…†c£LÆi-Ï\‚ÏöÍÜh"7[ËsV_ƒo¤„Ö’¢þ1ÜØZ.[R‚m{ݬsâÄУÖÁ ·,é0//‚¹`r�pHÜ@Mt•·‹’x°-i“‘å¼&8 +º,neºŠ›˜ˆ"›w&ŲÁ5^Äypá‹¡YäM‚5l)ð;Ä~á˸wÁ#šx9p©É™x†€|ùÈ+µ0œ<”õ¢ž%»ÉàØÜü¥NBÙˆª2£÷Í–t¼ÁJ¢”šªÓ1jýÅß‘ Ú¤©òÝ7NLEÀ2'Æ3®PUA2+û:•ÞeÚï"Ê%E¥À²• «"Ï£·•%\É`e«*ùo º¨TÄÎàÄo‡ÊÛw=ˆråS©†È‹³‚”Ma tZUÌ&~d“°>BÈÛ¡¢¼3>¾ŒÃÕ¤»ÈƒÒ €’$âÈ Uâ_É•ðþŠ’$•45‡Àæ>@ðb³ÄHÈœR¢�˜¹!Œ = `£xß7Ù<'µ#ŠE>B*ç œp +>ÉAiÍËÃæ!V&OA@äa-E˜yÊ®à‚¹™</CÙŠ³ ÁB=\™u¢ÈùÀå´FÐQãÎÈ’€Ü@UR”‡—šúe%ÕäŠ2BÁë¤Èœ²ñHrg„›ËK=’œ/•7‡ýhKò³ŒŠàþ Â)süB' ”´Üé©æ fLQ„…ñ¹|Žƒ÷gÎà +r5Ž1Ú°|*ò)]’ƒÂXÚ¸äÅ¡þ¤¢u\$5@®(¹'7Ô@ “HúJv€µ÷Àõö¿6á=hsCJZ\â¾d8…‹`=?Þ¶ÁRAî¾’ º°äî»0¯…M´–yÎÎÍš°rš0ÑW|¶³Ã±Mt'ÞäÊrâ¬â3WsIŽÊË$K)Ã^°‰ÛXA^àšu¼äS„`r>¡”U¾UN!…ú£à +ÎÖ¸ÜÊèõ½?"R`E „5‡S#È‘]:…ñB«ãre/£@Y#* +"‚ I¨©Hûb|š:ô¯—9SÍq°Ôì]ÛBYÎ@Ìþ/¡¬f« *ƒ3¿ =$ZM<P“•-)@øVmÈÒ^¤D^܃¿Î-å"Ñæ!´`];,â�,X9©-yMCþOÉjDåÏEpÙO4–»3¡Cwj Ä¢„Gq‚M…&Hò!üA(Þ Šb-d‰=Çj€*2’$Â(…$“ž»’Ýs¿@U™"@šoLu„Û*œXB%Æ B•Ô€Q’RŸB€MŒŽRÊ|…àŠóSURSou’DÎ{”„HŤípÀŠ•+hÄ=Õ-;óÒS‰#ˆ¤x`°–"Z8„G{Uz�ÊFÖdžX,š…e+>ÈLBE;Œ¼D*áU˜�íršLŸãp(:5÷ùa<0fPD†í8Äì„,TxûwìÆCùöG€¾Ç!^È$üTØÏ¥wL󴧔Ú*œ�(œ3If•sE™´â¢5!¢€´™œT$†aW çá"!L4s?1\!CÎEuÊpø'"¶Ï†–“À‡‰P2‘åi•9‘dâ<™•y²†¤ç„ ¥‹WÂõKãpM¢A²ŠxâíQn§xÈÙÌz!ŒD U,.!Ÿ€‚Ž5ÇoÊô¦«‚rÕ•–†ÞD¡c”ŒL‡¹T|iŠ›ƒ”¤´b)ù„ZÎÿ…À¾]ÈKH¯óV‡xÄ¢¦VC¤�ŠÍ´Œ%°s4“^[Œ†$VTá�t R©”<!‰‘ìapþI�G!‘ˆ¡–ÁRêÙT€Á:F2ÌqˆÕœV“ƒOâÔ’Zç¢æãRâz�\q´¨áåEY9¤!D!Ò$û-æ'…j¨ ¯ÁA`Á2ºO‰±±R°¨à³‰>‘’¾HKQÒ~‰rt®ä´‡9‡krÐ.ô@S�£qÔV3«yyäÍ,"·CÐóDöW¹ß; +¢j©c&¤ºRlÍ3•ßoÇ!Ø<øR¸2\¶$Øk|;«$б°eŽ /Sƒe�z£,®ª¯(2“6åš8I ÀÝEðºô®`àÇQ6È9§WQP:1PR&Ȳ`"ÁY¹Š$¡#º¶S¢V/I!LR¢ˆ˜½´& +fr‹¾‚¾_Ö{mûQ(/¡)ߦ¹õáb +”*%/:Úz®dpÎ…Äñç®´dQL˜[_¦Y–Cø³œ´=¤…A0æE ¤•ÓR ™¤øZÌ°ŒSæ·8:^’å]y°]�[ÎÏYˆÐzJ‡Ì_:8ºbÆ$°*¼_‹Ä�%B¶+-(— +Î'"‰ŸƒžëÐ’’ìâ²ï—·J²o@&‡æ‡< à¨J+«!€,†ü¬b(ô²¶pæÖÜx €,ËRŽ×`ÅôJÓVteI]ä=-]0?“6⋨ºæ•‰ c6ÎÂrJ0gû›QÔ×ÒÚTÞòíjʯÉ&Wêè�B<5ÈólŸ‰Y~4e;AüyU dù‘$I +´NìY‘ó0‚Ä|kícn}«!Q�™j$˜5ä¢l¢²“ó-ƒô MêÁS‘d`V1VAŠÒ/‡˜Õ”?)gB€5SRâ¡îÒrbN]R«*<j{ÁÄt@«Šø"}¡$³i2æ2”Ny‘€¨ äŒÔ[Ô‚ÍœÄK�+VÞ–9g{ÒÌhR®£‚÷<ºüpuIV:Œ= àx& *�™J}rÀ¾¹¡Js»Viæ-•%¢gBʯ"±¡p67ÈvÅ"ÛÚ2'†ÙX=(f@ÅøU_´4´·Ð®çÁeÚCÃl1=€-oÎø.Á +¥BPŸÂÅ&äÒ¦ú’YÁRsÙ¦YÛƒñ[ 01‚”Œ€:zÂÄبƒJj ¤HË ãNa�ÿÌË–2Y›Ë)´Êº>NÀ³B¶È$W–å »Ü§(,Hü"ˆáÈE<û¨v<ˆªÀ±ê2Õ%•ŠS»ñ%xgºo $Ÿo<Ÿ*JZµNåú½;´pjÈzÇa,R*[±£ir�}&8±74õ´W ãq¹qÚ<'–™n“Sæªä,€}QW:· ›_Án2T]$ιõG±É“œÅD/ gò\SV!“Sv)\ZD¦K!±Ò””G”=�)y¢J(8€Q¨Î�4¤MC¿Ñ�Œ3°Ì�iIáu¯ Š3Ï +˜Tº Gv¨´€•æn…L“Ö+Žƒû)l�-ÁÝ=”<J£¼d°5¤Y%ªœ›MÈUäW5kk‰W0M- 8´ÕÿáõØÞqŠ:Pøåíµ‹QÖ7ªÊiÊH½Ž¸c‡1¨UGóI§ÈL‚ÊgŠ¼Âyôùð!íBEŠhMÌN!ôJåçc,ØT#ýé_ŠWôŒe ¨¦{ˆò²/+9j)çôž™BÒº“†?PÊ”ÀUx‰sM‘ú‘²Q2G?F6¿,¿�@)N¦ÎIÌÅãGòa"IçU¤yÃø#Ê+å�á$p ~Ør²Ì8‘K‰ÍB +3h!fFó’9F¿pNA’³ù¢!Ýd!ø*›˜ÐÆ(J¬*ÈÂX@ü årB7þ“�¶<6›{ýUÊ# +‡¥4’P2&ò,I˜(‚·y¸¦5šäÁyjA!co9G)"Ïþ�¬8UtvÑ +3 +’+ˆRZ j/�9ŸC© +jUqŒËM‘O6jñ<àôãDÁ*vÌ„5Ašp”î(X£õàà]20šå7bp:(âeMéá~¸yH·\&©³0¾á8Я*ÂʘdÂ’=�Cª0é³&0¹,8Ë_0T�mÖ¿[Á^$.P¦ødÒ§Y0¡dÅ>‰? ¢8Ù’em½Pób˜VN$Sjê’sPZмwQÝè1ÚŸLÊ‚¨Uô}ô R»{êFõmÌAï—!c”áIXηlÀó‹“µùgLš%ÖxϘ$ 'öŠˆÁ‘¥ä眱A†u@ÉùÄr%bb´fðÀ$w•¦Dà%ç`)4ñsF'©l0Óm(+(çŸù« “xÁYô' ·hɘoz.=ù\ˆìy`_#UÖpR^-�³T”K¹�XE¹$†m“ãE#³.^Øv˜ÊOEHÝ£xxIÙ}›´:3„½FZy´wÀ–ƒ–5%‘5ä—ƒÀ‚Ä[4 Æ’Q–Î)Ü7F,KI^¤Üj´Ñ¡lN‹# B·8TViK ÌÆfýBðòœ4oUEšW2…�µ5>`×Ya‡™Õçð lðe93‚¦`)s¾Eq8 +TäçCç<P“èLe×YH©ÒäüËØÍ×–Sgp�ÈùËÏyXÛs"çÙ¹·¼Y[Ü�¨ž;,±Å›R‚Ê_FÞCä´\ä“Ì£‘a…^e-ËK¤VYD°•ü2™t¬ØMÂÍÄe¬¾®O‘ ž¢4@9œRr¤Æ ŒùàŠ˜Å{ÌC°à¢ð‘‹ ÆŽédQ¬¼bð|ã"¹à ÙË“Åmœðo3I'èŠ7UñvÎ{¤˜©=�9ºJrNÐ-‹PT[®Ï™_(tcAÖºôm&a]úf˜ÍP9–;pLßEù¬�ÈíŠR,HÄpA1–#ŸÃáÁœìKÑ…‘–¥S"a+’#ÄÌ*ø–c}N"9‚Hhöë$^…ÔÌåFW!Q 1€ 9´F~š]4Á¬Æ …mQø€:påÄ^)Z9Ue^‘óí\6¹‹1“'ê*€-Ò*A0!9'Š±ü’¼<äB.¿�áUœõ]O¾?¹É&ì2é½jãmN”‘´ ²t)Æò<Š”H>À`‘”<\|ãÍÂnÑË$彩%tÿgÎWøsÕ‡˜p +b +S]†Èª ÄL2Ä +W2a?)Èüûi· +Æié]«†´ˆR½…,êÌwQRl1�iaÊ× ’ìtÁ¢×Å{rgÊs?8;/ +wÜ΄€à�´Ì&Qšý Æ|Ù˜«zÍ-Í|{“àdU|ÏÜ\«ñV©BG9VÄ[¥ +– 0µ_i(7ÒIj‚ˆyˆ¥o–Þ§}J$ÿCAקZÈÏ·‘–|9^ÉB§Oï[æ‘P¦ÓUŽ9£èÆX›&¦÷÷ -êõ¸ð;Àœ9÷ØщŽmÊP)Ž^¥qHÞš« ЬÚÎEÿW1ð. 5œR+)æ:Oš"º—i%ù¤ ~Òl|e£ÎØPè´…‰P褰ìpé=S<±*]f;@¼’õ›\³¾ñŠÀ‚'ÀÅœP|et‰°,Û/B‡çÛ¥VÞµÔŸy]#ŒYæ*Þ}*F-–œ¡E†[D5BÔ3OÒíy‰À¹‰Ùú¢µú“Åœðíy‘ãĬ’tgX}«È¥«h®t%žÈÉ]o6KWF*JyMÚÿ«�V†|ýÈ NlF-‚µDÀ´M9”¶àp!¶Êq˜!5ò|ˆGÕ‰£‹®8Þz‹!aä¯!Eâ“ÅœàõõUöäÛì×4¾-»ÒÞ�ðô§Ñð͸?œö‡=oºO8øé~¹ÿéÝ//_ô®™ƒ§ü5ûîàé¯?žü4:¯áëó~oÚ » endstream endobj 265 0 obj <</Length 43348>>stream +ãÏ«~ø>{òûÕ`è~:tÝ÷Ïn¦õäÛì¯OŸÇÝ™½Ëþà|\áw™=}5œÆßàÏôóu ¿=q<É7ßfOö{üε;üÐ,ú©;¸ñeëŸO/Wv¯°¬ëJ(ý×mÑeÝÿp9m=$*~ïczöêôÙàú²{*ÚŽ¬îJ®”¹÷¡ŒÎþ]÷¦G£›á¹ëÛÑè÷¶#ºÀãŠN''¬QçÞ‡Ú~~n=¢Ï[=Ž5“™Œãwú\ÝÝm!“Ó›ñÙÍ ö궨ðU[bƒÞsÏ£ŽÞMûÓÞšÇ4ÁÒïûƒºýlÔ¹÷ʶCÞ\½îM»Ÿ6YZåÞ²íØÆõäfÐþ”£â÷Og:¹i;¦³î¤~1®ÿ÷Û“í©çL6hÉ@ÄŠ,>x““¬~ß’œÄ®¯˜Œ{ž¥þ°í®ëqw:·žžXa«÷S¸†¬¤<”½÷Ѽ݌{õËq÷ú²ßk?¬ Fõ€›çxtu=šô§ì»è²–m»ðôy}‘}¿·oD;'꽸·wV¼w·?øiÔŸì…À[S̽¸ B`kç^ÜË€{p/îeÀ/—˜ô£“7ÑÉ€Gõ§zðî²{>úíåc6É£‘ü‘ƒjŠ;;p¶Uv˜Lϟןú]èÐrQZéÞw6¸Ysz}ùá8„—ݛɤßã62Ø—Ýy{²xþt±ý@ÚSÅóß·|¯l;Q]\Lêéú±»»ÿ5Žp÷ö½È[Ÿ7×uïfÐÿðûõhXÛÏÍ|ÅûçÍ7äñh8™vo1ÈXñÞ9�!E{£ÁhüÝo—k¥Õ”™ø<h¯8¥ï}„5&7ã‹n¯~×ën2ªF¥=½ÿ‚±Ànx}³f÷ܱß:ëÄ5÷O[„üÑ<„è)6Ë–‹Ñfƒ¡|u9úNX‘7£þpz²‰‚ént•õ»p&ž„ƒi÷¸£Çiv¸•ÖdÛ9ûôAÅ¥[˜S¶…&´–%>¶ß2bÇ´ˆj?õ�i}~\£J¢·z kæ.ˆx€tÇýéåU=moÞ¥ósã£fÛÏÎû±Üß»:dú¦Û_§ÂÙ¡íf`[NßÍ5É»âaòc=þP&w%Út«=â)¹»~ì¾×+öŽG;áxt< ŽÆuýGk#ÆÖzý‰âO7XŒÛ®n=Gë_%:ãÙÇÝóþMûUJÅï}ZÏûƒn{»è.‰¥Ð®õ@v%ؤýÌœ·Ÿ™ó‡d‘GãëËÑ`ô¡51ß±eOÝvˆº=šöèèÚ‡0íiÚ=ðßÅ‘wƒÈ¸-ßð m;³ã7Ú-¿«î»5GÀ+lËwÿãÏvÐÚ+wײœµv„pçí%ž¯”ë`k§lWN¦]ÎÚð¬µ&øø²;Öƒwõ îm"ÎW¼÷%÷¶µ–ø¶ƒœ¯xïƒ\ã–_›…\<T¬E{2±õÎ;‡U:k½Êvå¼m?¢]9Žž÷'׃n¯¾ª‡Ó»×»w&]u]S °» +åý›Í}¯mGßÚ3éT|›·×¶“¾Öj»!}›¥ ÝÒwaµ?¶ ÛHö6˜Ž-ß*íc¹w1AJkeÊÎÐÖ#º:°-»ïb#?¶‹þ`°‰»×à¦uÐÖÝÖ>ØNÌëý8jïG›TØ^uætÔž3=À@ºƒßºŸ×pq z2íŽ7"(¾ü½k\£Òv`Ýóóþ´ÿ©ýÚ‹¶÷l»®Ú“,ü�–aûIêõn®nÖû®¤Ó”T¹"Ñz_·ÏæËÞ8[k>)™/zýOØû¶SÖ¬uÿ’rëY;ƒ›Û[=|é’LºÃþÕçŽbTv;ýÝa¹w›Ù29¯÷èÜfÚhWT"{·™eÿè‚7Xa[¾û¿ÛLûÌ‹»æ7Ó{„~3÷~QäÖÎÙ®œM{Ç™½ãÌòµ\±Ž3‰wœy<ÌRïÑ9δѮG{Ç™“–ÖxË<bÇ™ ¶×¶“¾Gç8Ó~D»BúvÚqfƒéØòò¨gzÎq¦ýˆv…|eÑî¸ÿl0•›ÒšÊNV¸CÚ~2v7«ÇîÌÅÝõãaûðhRF>{uúóêœn¦•xdN¬í•LûdIПO÷H¯â¾Mzž=}kEߊ?3}k=ø=}ÛÓ·=}Û)úöÃØöìÛ£"o5Ì鞺í©Ûžº!uÛ3o{궧n{êöب[j6:ÝÌ8þȈ\ëÁîNY ÷›hƒMdÿÌ›¨õà÷›h¿‰Òï<3ý°ßnà˜Ô¸w–Ìч7ýßëÁ›A÷óéfAŠˆÃ=ç!¯ÛÚ:8®¯Fë²bìVNšþð¼¾è×^‰šú‚]×Ýéó R4$5î?QÃ5dÝi;¶]ʹ³OUãÑ°C©jsvÑ>QÈö§wiÉŠìs»,çv¹ï5˜‰ïež ãþæ™ûÿ{÷Ý}~ï~Èî<åAÄ–Ùl+õo^¼_)ù¾]€7¸>~WÂ6ÓŸ4`àÞÅ‘½ùfg‚Á7Ú>[N»{£«ëÑĉÁ¯oÖ®¯@æˆ4Ów.´V°}l¿i>>Äži?5¾Gé@ÔCȲƗDoõ@ÖÌ]:ñ�éŽûÓË«zÚþˆÙ½3tCyaÛOÐÛœ:»t’Þ}:ÊGp”îŽùãVS»3nHû(ĽýyGíÏ›%"ÜÛŸ÷öç½ýù~Æ÷xï|ÙÛŸ=ööç½ýùkfožßnØŸ‘ݴ̿߈õÜÛœ·W‡´ÝÚ–½ÍyosÞÛœïÇ$sÞ¿¸¸™ÔÇ£¡ãM‡í×Ú\½íµ:ùmñn£¼ê:÷>´Ïõ`0úíøý—S÷ûaò«¶âlµûç,Z“ù›ñ…“^6›Áf¥í&‰[~‡½þØN ‡õˆ¯%Þ«àö*¸½ +n¯‚Û«àæÆ&Ó ¿›pŠ{=Üvéá¼Lðý‡q]¿wÜeý½;ãúFßêõôûq}þýhÜ®³³ït÷‘¨µÆ´¸‡tYIû§Œeëuÿè_ÝL×Üá™Ò*ÿ`ÚŸç}Tkœ�Á|`ß™ç^L9 ´{÷6€h/è_×=wÐøýÚ±h£æ+>€nÓQn¬s›¯ø�\ì)x÷ÕR,×½^êAõR´¶#¼e[Èí^™³Wæì•9{eÎ^™³àhß+söÊœ-PæÕWæÍêtöÊœí–e÷Êœ/Qæ<…|l~I[¤™zä¯ÝUM=æÔ,¬øÂþ^ñ¨bŠ·6‡Â–§çh?}zŽ-s]ݧçxÈstSÁ?CïçÊ•{çò§oºýuf´ýºÍQÛ~„î3\mÛºÏpµG褶m?F7=qvåÝg¶zT™6žÖ}V«[ôãaûðh²Z={uúî²{>úmïÐÏŽ¼O0qAë”eûÄÛÅ ìv°ëë@Ï[ßF‹Eï}‰µÈ’šä÷-ß+ÛNÔF“z +;c\ŸoD®w +¼Æ‘þ©d„ÛOî#¶er÷ é{!îÑ qBçß´]§¿õÏ7p"¥ï_ñ¯Úè²ÞÄ'‹‹ßû˜¢¨½O±ü%¢ö=õP˜ÖK±=Ÿÿlþ&#iÏèÿ¾W<°¤PìÕ»)øì¶ú£|,êöÙ«?v@BÞ5*°WìÕÛD×÷ê½úc§Ô XO»xríÅê¶`_Œ»½iwðÓ¨ßÞIÜWn‰zÓ=«wwC÷žÌàÝ´?íÑ3¦‚)”~ßlJݨsÿ +ÊÖŽ°Ã›«×n¹~Ú`hi•û_…µ“»’p:ï´N-uÖÔ/Æõÿ¾©‡½öRëL-ž²}2í}þ¥}þ¥{ 8ïÒ™ŽÚ³%£Ê>•”GÃ¥’Ú༻®Ú“A,ü�ÌäãÍŒõ˜cmÀ;}õ¼X¢MÚ8›Òh’ÞߌÏnç;¨jÜçٙ໠dŒQß":m¯†]©yt^hŒh‡¼Ðâ‰qº&l~¯2R™ß7_ßz1n·Zûq<Z/´iK¦m·_íßÚUh×´þ° ŸÞ?¿oÅÿ±²{p/n‘ØKõc/î¥À{SS +l}Jî¥À½¸—¿ +«#Ûã—[gÌØËÛ ¶ž®½¸÷bà^Ü‹_*4™G'n0¢ÿ1wÛ“ß½øð2à¡x,Rà&#y´rࣼ¢5ϽÏJ±bÒFÙväÖ¾Ýΰ±O0ºj û_È/݆ác£i_-_È}k»NÔð·fw6èö>~ŸyÐèºÛëO?·žn2ý<h¯¥ïßgz“ÂweSm4¨]ÙS/`!îÞ–zœJÓ/É´íºÓÍvÏžƒx`b7Á„Ç‘äýî77‰†xy{{Ùb¶Þýk›7ÛIïzÝ ø¡F{Úo—d4„;î[Îd„³Õî?°·5'{3¾èöêÍ&°Yi/ÁX6¼lxW®MïP~¼yaŠÖ™šê{ØHÔ¸ÿBµ¦1Ý?úW7˜X¹ü½ +éöCf3ºVëyÙˆ“MŒÂw”-๧'á|ÜAÞ¯õv¦;pøýz4¬7àþæ+n/ûG}ݘů¸g÷ŒàŸ˜¼Å•Ùw˜i|[Èíž{Ú5îiÏ<Ýóô.ˆÝ垧ÁàQzYßâ<Ú±~™ÇkÕ[ŸôÛo±sÚdMú£t j«²Æq"ˆÞfqöãš’é@Ĥ;îO/¯ê îšØ¥stS¥ñÖŸ¡Ò±zП¾éöשzöGè6¦·ým?ýºmÙ¡x„ÞJjÛöctÓg‚>žtwTÕûK%·˜3ºs²;SrwýؽeñX3 =Â[æR§Ç{§_ÛÄ@»çç¸Oñ»TþªëšjŽcè»Èòðï¢oi;düÖž–Pñ #Û~ª½tU'ë]®vYŒÆ?¶Ø€ÛH8!õ¨Ó¢Ük(àm¨ÝN)rØš]Úöœ"‡&©È½¨¬îyL¯ï?4øèÁ®¦ãxœ®€·_wÛo†Ù˜WÝv"v +˜ª÷÷‘túØbv`z¶}ɉöwcï"žNYë0Ê]ÛR»Í?J*þëE=~Ñoƒe[æyÚ=k?Ç» ó”YkûŽý—Í”š:—ìfØ{»{DåÑ-¶ŽÍòìϱÜ^î—ÛÃ/7ñg!nG쨂òdUx?î'ío»ØžÕÿ85'·Œ•Øv¥Ém¸Ó]à¸ýtm Ͻל4'½ñž [05Û‚’ÛÙ½è-úñ°}¸ÍVß<{%òÓ†ç|•€@N ߸&0‰Ï¡ÕúÃô‡ƒŸ®± íz÷ùêl48xòìü<{Ñý49ȳgîÿ_;¸qÿæÙ냼STÖIµ¡Km½ÏNG¹-µûRØÜ”¥ûR–…´&ûµ{}|~ýìþÓ}ù·ý–‰<û1ûç¿òìÞðöà0ïh]Ȳʤè”F›ìêàPQåÚî#tv(uÇTªÌ ´¥{Ç¡4PQe‡U§¥(²ãƒ²S”¹ÍN ª5•«*óNžë +¿Hcà‹êäeᚶ£ +©¢ŠJd=샱5RÒC\W"´6õòNUJ”ª:R9¼Ov¤È]3y ïeG 猅C!:îµ…ëºîT¢0±ØÉAÙQÐ oǽ(¯r_$´WúæÞU +ÞÉeŒ›RÆQ¹aꢒéÐEå¾² ?î³,¬(„é0JF<0ˆ¦ãAºÂ2…0«)S ×nÅ�@ÂÜT®3€4l§ÊKxWGå¦ÀvªNUé")XkÊ5 “[Ú*S¢£låÆnRŠ¢�õGI)¡‹r½®J¥};nñz”!Ð"PùipKC˜<WT)7k?nuŠª@Vn†`˜Âz@c&Ð;pýÊe"H9\o²0«&KÖ€›àB(\ÚõG—T +ÆW幪b;qÆ—ÁâE'¥\„°±Ó°¬r·ª’Á^QBš8úCÀY!MDС’q!Äu’a„l·ï\Í¡@td^ä¾ÂÍàFT€.õÑM¾+lŒÍdéê™îºtHnÇ8„nChc2·Ís¥¥«À7†\Á{]ݦP ÄíGQUR¨®9ØþšukF¥! +t|pqðó¯óƒ"{òmöë?¾9]Dªô–ÄÊÕ\@®�z;‚å{r’5oC´RŒ$dë›ÓyÂõÍéƤë›Ó[/Wí6äë›ÓÌ7&aXm–ˆ9à<ûæôV„ÌU›'eØÖæÄÌáë6äì›Ó[4·hnEÒüò¾Qó;ê6dÍÕ\@Ø�zÒææSâöÍé<ysÓ5Gà¾9½ ‰ûætè¸×'φ£aVÉi\`ö\õªR•Cµ`gmÇÓacin½eÔ nJ+p÷;:àv”X¢z'ÈNºÅ¢`“WH4¨Þ<qf‘7=˜‡ÄZ8‰0=søúÙ±,>æQaɈÝ,Í£!ãK`êæP‘�c—cíE°8üØŸE°´î<Z",íÌ<j’¥ƒxùÙAœÐ8mÈÆnÙÓ£Ñhà +¾ê“1ëñð‡!¨w_ÞôϽ¬éšTZè÷ëÑxú>ˆQH¡Üæ«2ívNáȪ6ncÇ¥–^yú¶î¼ï¶«Ðhz7èû¼ŸNüy9îŸÿÏú³o×Ì¿úŠ&Ó1:%Ä8±ëô ¢UÀ˜—HSG7Óéhx:úäÄ»T˜úËÃÛó°É–Hº)åÙ‡G1ò\À{®Ä/ Ùð7Gf¤ÿýП2/áL‚ë´Ì3e2á5_ Nþ +(´Ã§�?OèøJºSÃ}§ú&ÃOo89 ×VN:Å¡;IÏ©ÊÝà•p¯àÃͦq§¹#Ê…Ã<§âî›ïH†¾@A=p=Î%Pql£€C›…‘ +ß!ü¿i3®êÌã-¼â›ænæ^ÜÀþÀ5¯ð-ûœÁøyúyöaÜ=ï×n1©oqR+˜`‘D»ˆìèÈy9üLëMB3ÜëlåÀ8„_¯Íâ‚nÛõZ¶xÔªEwt¹ašŽŽþò³[ñî81q™&hºJ‘¾.ü–b¾1'„ÏÀÐÆtÎ͵_Çq9ÌÒÚ$K*®³°Bh¤S›Ny2ÈÞ²I–'Ùrœ^Ó¦ÄÌN²Z\ÐMÓÌ$/oñ¨U‹nòã$/¡ÜâkQn)Ž‰ÝB"}<®ÏûÓì¸;>_J¤ïLí%ܯnÆÂ7¿Ud…‚Ÿô¤[�Š@ÈAÔRÈòû'÷àxµðˆr~áÆÂhÔ½Kgé?‘ÔÑoIߌ§í±õÆ›C‡Âj%é}wx»âWøiÝ^s솟¢‚Âîï1âÂ}TÄ“:‡¾(Y¥}›{¾]„b¾ÓWá©ð¨Fá!4J_ðm~"Ž±3éÏi½ÐÚñAò’“Æ+¡ŽŒÞ={ä8£Ì‰Blá6{ÞÖ/úõà|žò[̈Bã&ÓJhÇ_&_rk´;æ\™ÜI¨‹¾àžs;°Ý®³Èzþ¼q‹Á҇ŠsY£ +ØàFÚp¬ªãŒKî¨@Ç*+Íü~w2´n3\bÖ3}ø鸻8}}7ðÅð \µáb9{aVž<î8¹LGðK889È#fI ÓÁ“aeGkÚÈ“³ÇsÅÃOíǧãhoÅEèb¾v˜zí0óuÃTU2Ìpæ‡ ‘€‘;FLŸbùX‹*V/l K"‡×»ågAµè ,Uúƒ.ÃÈæ+-¬ Òùr¿H? +é‘û¾‡¹zŽþšÍ‘ð+B5±j0+*ÎÊøA?¨0!ácÅÄA©/R13$ÝvHŪ!©°ÜDXn",3?¿ÖrÓér³M¸6ó£Ñéj›)?;éÇ ýrßóðñ›^¶cô’£—í˜EƒðæJ¿¸DÐ>¾ÚâÒëö‹^²_ôºý27¤Ü¯-é—ô+*篵®D:)º ×r~ "“™ò3ý—Ø}änq5åáïW\RbÉ®Kv…X²+ôµª¸rdæqîÿ~µµ$–m±d;ˆeÛa®÷H®ù1üWÿñÖŽ?籘˜¹PùYì{x³ÿ°v®ƒ«F…¿_oí4{¯gz?¿ò›½×+{o°÷ž‡ô8÷¿ÖÚ¹;ÌÿÌßy§’R6A€eEÁÛ-ÐsD3Û•îfÁ„gç]kxÊ\ѹB§Œ I‚šÈž]ã«uÆL=ˆÁSÅŸ2öÝ_‚_»š_Ÿ¡ÊÂ6yMë×Ä,Slé‚¢¦ô¬m»Vg9ŽeÊj½¾è«‰²ÊõBäôGu¼òqËÚñèú|ôÛõ>êŽrXDhùiùQÕiÀ:dÐJ}59aÈaÑÑø%•hµÕ¨î4MÔ:T%p|�Öeï[PqC¬ e¸¸b&¶!El‹`±›«@ܽ® +e¸O@÷|IÅÍÐàB£§VgQ +¨…Kö m›Ûªø6úé=ëõn®ÞŽ¦•Ö’ê`É3ˆÉMU0ÈáΗ±`@샒YŒ0¨ˆØñ »/a2xÊJF}çž‚zÒO™˜©¨>4\ή ãƒrn™„AÒ(Æ:i7íD{ø ±(T):…*€©*/8¡‘*ñ‰m0–{Ó…Âá gð.YV)w/y™Ô¢¹é›ŽZ¼ÉŠ—*ú5ä_–Ↄröô§ÑômÝÏÝü)õR„ÏRÙãg¯^†I{1_Qf,ì‚£«ç£³úôÙ«êÔuâÝôó >¯ö¥6Þc¬ínÝÈ[¨„^ÉN?k·š]àWs» ®yÞ'3ûhn¯¥T4î¿…°ùÍ<»ÝçHÂ2‘Ö &Bsdjv».ÜÁ³Û<R‚ÌŠYòÛÆ‚¶ž +Øe{Óó)íMP±tob¥\3Ð ØðMG-Þ¤uó%«¨À£Ý¾«M¦í¥°¿él…`i+œ€YSªBÀñÿyó + ´‰DØDN@¥,x_åÀkb¹Á‚*'Ë™ˆ0Õy+ݹµµSZ^há#sEøØ>>úEp5Ã>3½‚sžµé�ë,¸Tº1ÃyŒ†F'ùtd TtAð},O¸âP¬xì<8æU‰,$’dO¬-:%8æÎC¨ÚRÆH‡¢îYvÀ꾌»´«Jô|q/�—T'T;ò$rÚ +å¦Ý%ÔÐIpU¦£¤–‹«ZôùJv”)Pê÷ÚL¼¦£¥5KÞêºVVXãÎå:稢íØBTxx¡òrIU KT_Â5Ûõ×-ï¢0Þn•;ºû‚=W" YÆ&ýØ|lÊ®¯†Nž›ÖçßJÀǃþõun0m€Ÿ÷'°CCé_ÿæþܸÿ1èÆìú;zÀ5ÿ¶;ÁHS×)G%_"¥¯?õ1ŠôsöëOðOžîCÔæâŸ5^&ó×Ëåe�äËùÿÊdýèµÐo°/Ï»ÓîwnI{ðë«ÿë?¾øŸÿóßKÿù?ðûòŸÿû¿ïç÷%ßÿ¾ÿý?¶a}®þ}Ýþú²€,¸cˆÐ±¿Ùr0&Z?å[ªìÅÍ|΀ª&ÜÀ7§@~™'8ýõÿõ|Çx<W¨…“þð#ÑÒï±ÁÓ™¦<1“@=×ñ ŸíŸg9‰n Ú¹Á¾<»Fÿÿ~�Ð[QsŒELøˆX}!0~M̱ 0²Þç»ÉbDXd2¾9ulŒjSFÃqš·f5z{fÂnÍn@<ÊmŽ¶½^Är|sú—Ês¨“YÆpPPµãž½ÊžÝLG™ß`ý?ê(=ÌIg¯Ï&õøS}~êòS_h’l‹ÁQ…Ž¨„ÎÙ‹1W÷Eš¼,’/`gÑà:û¹Q¯� âÜ)+oO`9xÖ¹Ï2÷¼Ô%zÛ +ÿŽ=G+a'“Bë´¢[5¥.“¶�vÀ7`²#`âNš0eQ¡M»/F[ß–ïA -ÁïA×gûáÄŠ<bn<`ŽàÊÁhphÁûбÊUæ}‹0éËm§Ä§¤ÓnWEY6z š¡¢L‡[u„µV%§êu„q¯°0¡qž(îB2ÅÔÓd†y8\19´h†çp…>ŸÚý®ÑÀ` +óƒÔŽüj£Dh Ú6Ph:¦¬Rt`$dn´:ˆ£hé¼'�B ƒ"þ‘f,ðëôq7üñ`¸fph<þæ0…øƒ¥Ñl)þRXXÚQÒN +Ëßu¢ÔÍ}ÛÍŒ üIˆŽµÉRu‹š¬Øz +!FXDa +Ãar㌠îBJe¨«)•¡E*Ã&*“�˜ÊÌbp(ä¦ ££2¢4 GØ2þ‰q§Q“ðäIÙÀ)x¦JU&[¸ øK`Œ¿†',Ä.DüqO#úx4Šãõ-§ÏwsXÔ¹¸*š¨KA8<ãZ0)¦Üy,tÑ ~Úz¹´)æ”J®Ä©N¡Á«•NmÄXKA04n—ÆÎïŽ(ãF”ñ(ÇéÛMŸÊæ°(+E¦qd¤ Y™J{éšE™¢Ìv¤²*Ř㯤M¢SšB›Øn +‹ ÆX +‚‘q»4tzuD÷/"ŒÇ@ 8Jßlú6‡<m…¹M–‚p`BÄ£ÛoOá8Dzq<Ø?º1x³J‰ t ä¹á0AŒ±Cãviìüîd[R#Êx\ÇÚMžÊæ°ãO…À¶`–ƒÒ¦^åXÆ2ðÈUÇ”‘Á£ç„¿#PÂÞÅZI‹í�½;aîP@*lÊÛ IbWhØ}j|9"cG„¯‹µhäÜnà»ç±ƒ(#ö$AxhÄùðàw” Œx¨eÄhq-bŸ]$(cPDYòC£†yðôòe¡‡ Êh\‹GNí&�BÙ,v¼[‚2ñЈÙáÁG”àŒ§gÄ]qµÀ~q»á9ÁA"Â"Ä‹å‘Ó‹|Q÷„Ѹ›N�„°YÜ4˜µt[PÜ>áœ,°? ˆKJF¬W#f‹&@‚2Eœ% ?6j˜GO/O÷eèbº1Ã0âƤ±óÆŒ�Þ˜3øI¹³ˆ3Éò##n††NOD³EaÌ;ˆ¹+j–aÄKA8.n˜FÎ/£F|Ñ"#ú°Õä9 k/);qE±14jât"®ˆŠ¨"Ž‰ ÄQQ›ôñÄFSÁñP›4^zkÄõ,âˆúNmh3y8šÅGÊE„ÆS2Ù÷ã%æ&â(0@EÄ"„X(j’ž#ŠÂ(J 8j“†^1DýŠ*#áF54™<Íb#e¸"†BÃ!F…w\àe"†ˆá‰("žˆëž‰ÛÏEa%¯– mÒxéÉN=‹8¢¾s-µŸŽfñ±:Pô®l•¹×x5“ežáŸAd¬Ê›,¹€|9ÿ·…ÉÒÍé—Z,ƒU…þûïøü¥?þGó?ú¶ÿgÿÿ³` ýÇ×Y}˼í?v» Ú6f MÁš7cÜðÐ[˜7|ÅYÇtÔœ3rø±ÞÆ̱w>qœ;d³*²ƒí ®âÈ´½ÄU\`qÐ[B°æœ)dÚÞ‚ãš5‡ ð6‘E¸[ŽôE†’è¦Ws±¡·0—`½YƒIØÞd‚ƒš3š ô6f“E˜[åæ”èHf8oRAèŒ*Xsά2moXÁÍ™VzãÊ"ì-Çô£KØÚì øæ /˜–ïV¦¨9o|™¶7¿@È9us̬-GðÓLØÚ8®Êsæˆþ»…ªÍ™hšÀ¶FÍœ™€›j`k9bpšÀÖ&pƒ™5â`ªÖÍÍ8àŽ3gÈi[šr`,sÆ�nnÎY€«\ż™§ lmèqÕæM=ÜÜ؃ÕfÍ=M`[ƒŽfÖäƒÀ>°µêL›3%À ÌA OÕ: K¼‰I(a}£z§ lmŠÌpÔò$¼°ØÀ4´�[+;o2J€¶·ØÛŽæ¶ØÛ"¿Û@ìmH°Õ‚×m ö6¦¥„Ïm`vsóRdgh½…‰)aph½™i®Z0·MBpTÂØ6Ðz#T¾60{CTÂÑ6IÁ-ŒQ𵞛M1»¹™*ádS´ÞÊT•ð«)Zoe®Š,lŠÕÍMVóxZϾ¦ÝܘYס›´"‡š"ss£VäYSLnnØšÇÏz~5Åäæ&/æUSDnnöŠ,iŠÈM_‘IMñ¸¹ùk;ëÔ›Æ"sš"rsãXäASDnn ‹\iŠÉÍdóøYŽÉ¥ÙîÚë¾\d¸iDìßGWõl*âOþ»ÊG¬tÇ*¼æE‰ +³åJGYÜL‚×°t) ÜZ¢äÚj9îšÈL¹„aÒ>•B‡ÿNÔÿ))¤w®:Ò #ÃR>«±tô\CŒI +ÃÖ U9ÀZ9qcÛI˳cFßÜWƒË ”J!�Nbnîa’”/�qµCl¹T ÀpåÃÐMÂÉn¶ÂôáG±ÔLï+Ë0\9äÈšÁ *2m;Ö@†·ýT[`þ¦;¬§ÇƒÑ¤ö2¼žOش霩À©•†[$ ¨Ï|¢×*8Äù‹˜*üñ¶ˆNBW<Ÿ"tø_¨–ÀÔG™ÏÀáßâq}YÇdñ;´Wù”ÁÉ›’7&¥lÜ%&2+])B|jÈæáà%ô>p?Œ…K|§Ïóv‚Ÿð“ô7ùø +þÇÃÇqXbçù—¤BéñQ®J¡ÖúBá37˜aŽO=›k_,.XÌeO[ÞâQ«e1¡‚Kqã3$7ð}ˆh h:ôxŠ<%ÉD5f0ýËÄŠ~*}{a>“÷&Ý “ù¥×!@^[™7ñ„uj6É]µ¸`!g§hy‹GZ„ðÁy}*À/N?";%Æ…:Ú ŒdðgÕt¡ôºH–²ÂË‚¼ w?úoîåæ +ýùšMLJbKã¢VII©AzÁ¿jAô:škjE1îSTúK§|µ³ 2}Eô—¤·:Ívh€ww\®¾^qsÒ¦‰9;ŒÂlT £Áì?>Ó%2R*~•üõ0)q¨ÊŽ 7+iHIyÈ×'ùGï™ _Ñ׿Åë—°2ÞÊMâ%Hôí„»å\Q¸VÉ=4ÚMÐëN’~�Ã*BÓÒY8T¶r¾…’ðk¼ŽR(òE=xI’_’üµ>~y@VÄzÐfIÌGx-t…{À%àFÌÚè¯é!d䌣œf(~óÝàÎ$S›{$ +¾¹‰G]¡aSG¾ÎýM%_�ÌOY~–Üà´¸èÂ;œ–¶:‹Ó⢋îqJØŽiW)6GÄÇÉHæ(âšPMSJSÚÌL¤s”täË™¸©y—•ò¨kܶIÍñj‡Å…m5—EweËG[nܼ·ØÕÁÌÞ›Ù—¼tyíÎî³t†é:Nvk²…“é^‚pñ—[‰|Â…¿osYa[,DøÒ–Z·Ü@ø1s²Äi…íâ'Öµð«WÂ…c%A/8‹tÀün©‘Iƒšgá®Ãßã7ÿóEœI¼{“«‰ÆLÏÎùÅ'žSÊ:úä¸s‡Y½¼…ã0§«Š»SYèä®ü½:ðéM +·áʪ£r—ÍáºO¸sŠ¾ãUèEa#ä„! 4KÖÛ-bÈH·ÂâÍÏ ž ˤðúîcZ6Žk°èŽÊN^¯—« +ënXd@mœø¼··Îöãp¶«Ç‡óã9LìµM„¦è:L1Ùó·Ÿ9Ià —–™Ž²:û/ÿYéïäå6!K'zÁôõ8Œ,<Ò@ãÀ=ráØjÓw$¯Ýò÷©QÓ¡| +¬šC°5èÏã˜;U($Ê5úRÈ C¤õºñ“ùj>n‹‹a﯂Ó胃-OkòœLÇ�µy2÷$P&¾ö°ñLmÈ,*ø¥3isp%\$/<…é°P1¨Ž=séÃØ>tŒVAA/zL¼«ÚÆ)ÇŽ‘Z ò³†º«Ï´ßz|Ÿ—Ái‡A#|¯JµÊÙ·ïÞ5èq85ï’Ã…^n¿¡b«ReHãAn»j8±±Ê ¬D›hÃ*¦\èa¢|-ŠX¤ +VZn„�ô¢Þƒ\ûþFñÐt "¾‡�½î—¡Þr#³#ê-S¸<ýõÇ“Ÿ_=Ͼ˞ôúãÞ >U§ßfRáfÊ•w?6¢*Ül8úT 4éV+¼A#ï¨R8v‰ahÛÑi…Îs4¹èxWÝq Ð`å&LË '®s?„ßr\Y¼ü‡ €Ó¢ÒÞ£°0ðSûÇéƒØ=ˆ§- -or}%jÔ*ð4ÈàÓZPžx:Íäxnh@i*¸:½”ÉpÝÆuj’RŽVU±,p¶!Ó¸wŒv¿ÙB¡T¡Á`v_˜2ôÛÃ`ø‹ä…#ž…ÂåcÉéÀŸî…7-7;t<׿ݗ#(.YeÚƒ´}‹Š¤ª2åR–Óº;î½_YøŽ©‹;º`‹fÜÆöi“Jw¶Vh¯Œ*ïB#ø ¢£³;\µðÖo!Œ'.Bë\óJZ ©[Çà…�îu«*ò +or}%jÔ*ð4ÈàÓZPžx:Íäxnh@i*¸:½”ÉpÝÆuj’RŽVU±,p¶!Ó¸wŒv¿ÙB¡T¡Á`v_˜2ôÛÃ`ø‹ä…#ž…ÂåcÉéÀŸî…7-7;t<׿Ý×#(.YeÚƒ´}‹Š¤ª2åR–wuwÜ»\YøŽ©‹;º`‹fÜÆöi“Jw¶Vh¯Œ*ïB#ø ¢£³;\µðÖo!Œ'.Bë\óJZ ©[Çà…�îu«*ò �^÷gä¾sûË£H£ÜWáö%¤w1hFú[åÝ>Õ2ì«r0„WB¥ -÷Nšq+™,×S[Ðo!Ã!v’+«Í…ÏoXY7<¸µ@Ooð<“pñíÌ`g€Kw.(«J³djôa®¯½Óf ÞWs3ÀÍç½+ggÉ»1n:O®ÖüL¡¯Úæså]gf+$§Üt¾`Ú‚ÓåGœœœ¯Îâô|Æ´¸!8¢NÔV³Ï+"é¡2䢌7Ly—HJ½Y(¸9c€Í&—Á.Q¦ü˜øuØMñOwM6LG ¡ÐífZá±cL.cæÞ!àF¼GVxtÀµMŽ…rÄ´Àx9‘Då(^åØë]càŒá,£¥.}Y¸ãRÃ}ÆÞ{’E{>D5¸…—<cÚ8s ";ŽÓ`> +÷Nšq+™,×S[Ðo!Ã!v’+«Í…ÏoXY7<¸µ@Ooð<“pñíÌ`g€Kw.(«J³djôa«¯½Óf ÞWs3ÀÍç½+ggÉ»1n:O®ÖüL¡¯Úæså]gf+$§Üt¾`Ú‚ÓågœœœoNãô|Á´¸!8¢NÔV³Ï+"é¡2䢌7Ly—HJ½Y(¸9c€Í&—Á.P¦üœøuØMñ/wM6LG ¡ÐífZá±cL.cæÞ!àF¼GVxtÀµMŽ…rÄ´Àx9‘Då(^åØë]càŒá,£¥.}Y¸ãRÃ}ÆÞ{’E{>D5¸…—<cÚ8s ";ŽÓ`> \Šîܲ0Y®ÛRŠB¼}´{l.¼=£2^fpKM Üþ”wa—ƒa®‡JTˆ¹¥j`‰¢çzŽø+s˜;>xâ|üAy_ã+wÖºþâÞîZ«øJkw;º(Pô,tò¸‰Å 3³´ƒQX;D1¹í¯á·t ;SŽT%ìT'*8¼€±štÛ ‹ÌÜ3 *4 ¸µdØö”vG¿ûH@{'„T<ôœ@^ºEÁXÕESQlÚR£÷N¸eÉM·Tf ]ù4¨•á~£|J[Gˆ<oŠž)®Úé¼/¿ñîb¾¼0Ç ‡zWyG.È�!c’áz ˜!¡=¨ðĈ327iÇóó¸ÚÓìžn¢dBmaSÔx¯ÛÌñsǬ”ãÛ}sÒ™ªÜ -Ñàëm¼†@šm¼¼ûôý³³ãîxþìÎUg¢ã]AÕt ¹ð—|å’´ p!‹ýÒz§2jÝMkб - ^®�1B§2xÒ¤D%êÑaÝ3ŽŸ³ÆA,z¸w¹I“Ux†óÄñâîÅ -k� $;ó#ÈI)üeh$0ËrWöTFzÝvµTVvC5° jš}·µJP¨²Kðßp-W -$�Þrƒì&ƒ\€€Äf@ñì›ñ¯¢g¯ÉóÃÐüö�MNxô¡GšÂQeÂC¦�ùAá(aLx¤UãÖУCwèF�„nºâäž‚¾´w@Ïîí•ýÊi,£cŸª’ -évîY ðÂq’(8²vÜz5ÞËCpŠJ¼Q–êÍC¸% REe©Ü_[V"©!Ž½,sŸ&1TúÜñ:)Œ+‚N¬ãc6}Õp¶»öËК;VE¯@ÅÎR½yµD¹þðŠÝgl+×j²–%:1¦›16?×R à‡eØÈÒU*þ6è \¾“¹Ýf<o³ÆE�”ô†Ð�®~d4ü+Â3ª,äF§˜_pÑäßAêEh‚:93о¸ÊÖ$sU+•s`ªÝìPƒôHo¤çÐ%ªºÚæÕ Ô¦ ¾‚*Ó#µMÏáÕT9t¬ÙïÞ}(Ü«¤ã¼Œã¦,h¹“`rÔYZ“Ë-< èžuLJÓîù¼ƒÊ&N)hº«ç•ÿŠ&qäJº‚JÈx_�ø‚F¤×øˆ¶=<=èj™Ò?ºyôE©Q¾©ð&ROº¥YÁ*ÉcéLhRzŸ°³roð)é,>ÃY “ﮪhý¡6ñÁwñÐSn>YÌÌSèÖóµiïÁ!BÇM`4ã;!Úú1Ûÿ¬9[âa庚E…ûrƶ½Á[nóÖù›æfü?+âê`~Å4ÖSºÖæV"¯QoLoc]›8·…6¿ucé}¾‹![-@YÉÈÖóS,¤Y]³°‹¦xƒ·ÝæóSüUp -dº«Ãú÷-Ñ3¹ÊA3Ö€wGÈ«ù5A3qµ`ßÅ[x©ô<$Ö¸ôïPóï ZW3ÂS9×â<$Ö¸ÏÇäãÙ„Ÿ DÛôä¶^ª÷CýÛôÙ¸îž]Žz7“™ --loA^+‹ïTw\².‚Ć®1Ž»Ñ±YJeTö˳ŇÜß"”£sg›./HwÌ'áá0<Í?„ï\6E|%ËÒ-Ý_,8ÙèpnƇ“ðpžæÂ÷ɯ6`ÇÀ -8«@†Ì1ÃL™oƒ ³½}?¢;Œ{ÍááAL™þpðý5üRú_ÞnÜß×çÿª{Ó%—o&ï³ïºÃî»zœ½_�?´ò·ÌÿxÜúŽ’_¿ï÷BÉòŸf*»žv²·£›áÅÓù²_g‡OšD¾²F³°É®± WáÅ ;¥òn1¼:¤¾o>~ß÷FÝAv˜½©‡½þ€Šc¾h£BwúÿNÜ÷á»›šÊ†©šm›€*h†<ý:ëxT»¹i úOØ\¯Ý”¤Ýv©3ÿ¿‚óäfp‚Éž½:;»57¨±…“þ¹Û=gǧ®dq=ý£Õ= iÉd»‘¤KaàþÿÈ0ä«úz«W«™7;A¬ñÞüŽÞkð½0øZ'Wá‹*ü¯ÅK¿äÄ,ÚU°Üf·•ƒ9ªšgŸfô/ÌÏÓ,¸OÆ#Hð·˜ÀûÍ’Œ#ò›8ŒãûúW*œ‰æ£š{„a›iå8 Ü;°ßŒ{à!Ê\UÒã _Šƒ/;£•ÿ…®yž<ýÏáè×!>¸ƒòɳÁ§É¤{öòôëìé÷nÆÜ¡óô™;I?ÖTäéñèê–þ‹þÀ *¹Iï3_ÀC=óþ4ù³ã]ŸþÔŸôÝq ηp:íö>lÐÂQwÒï¥ÕÇ£uûú¼‡Š®ÅUWm?õŲֺí`{xú¼¾Ì¾É²'I;pœ“ák³o²§oºãé‚‘†7ýi›Ah»vWá‚uC?Nêo?ÖÃט»ñôšVÒ×óë9û‡�õ”ÿ¿{P#ë„"ÇÎY©Šf×›\-šˆæÞ´Dó Nß¼ÔèÕî¹ -ï”7Vøû -½ŽIwâ5ÞæWVZ8†sÓÊÆXY £A=¼øBzŠm¼›â8bý¥9xúíouïú€?`Ý9b7sá6Ó¹ÏïÃÌ<úã.½×——“zú5NÀ’ú¡Â«Áà…‘Ñ¸Ó½vlöSAú€¾'F³‡ÊìÛËKwP¹Ò?ô§ÛDxŸ¼¾™NœØ—X‘Ÿ÷'׃î'ÿøuº}]?¬WC_QÙµ=ó¥¡/¾x‚J£DUe™0hwJ„Í*zDcj}šdƈí>QöçÁƒ;ËË;QUBàÅÑÒ -ïé£ËªŒõœêŠ4{õó¨J%‹í¦*{>u‡éÒ®í›=ŸºˆDß•ƒæž}cÚ䨱wyÔ,$óhIÉŽGãa=ž|)2?Ó(“ö•s!§c¤·áfOÀåf²l™ïµØ]‹}[íyØ…„¥Ünv¿·{7““+naî‹49ÚEè -§12ûùPÒ¨?©Ò»¿Ì¹ö¢îN߶ÛhÌeJ:ÑÞ®<Ñþ@´¨ÚÓ¢=-Ú)Î`kèI ñ£{zèÉÑà¦Î¾¯·ÝüÀ<’•ÌýU1ÂJ[§ñèŽl„kQ¢§ÃŒ_²pÓ*Ð/¹0ó>ÉâóIÑCàÄä…'óŽ´²,|zq‘WèIQا1D2@ª¤(–¢F<&ÔE—M¸ucÚ'Ê¡ÄßgH·e+ø¶'#ñ± Ä–®Ž–xƒFÐò¡#? ”|°†lj¾¥(\!'¥UªèV™W–Â]Š‚•Û^Ò˜¥¸Ð__\1ö ;NF¡W¸Qx/-Ä)yBÝQ~IA`|¡-’ip^•K{7+ì.Y7È;`"Ù1…*+X*Wã9l6.AL»€*`ä#Z¶:Š\Òì—Ǻå¡uYÂ%Á±Ý¯ C'vþ`i¯—Y²4ì..;]{‘y¯Lçñûñȉ™ë¿{?pÿOwJîÜýêH«•š_ KCáN·¿X¯2ßøíýKªœ.φïübÚ9‡õdÒ€b¹Ÿºã>çÄÊ)Ä~y^_»Õ8y¿ªô¼ïúŽ¨œ)þ¶taiý0Âýòõù¿Þºµù—, IËÖaõi½‰iV–I;íÝ—†/çR‹ -÷äf§IcLOö{£‹z•û ≧¡Ú|µ³S23‡gŒê6Z~ð3/$†½§Cïax]#s·mUáÇÚI¡ÐËtÀïÍÌì—åË’+m¾(ïEèôû78ÆA$ä—Ò17šl§g¦Pü §×€�Èü §ÃŽ]N¦�Ö¸ô¯Zî‹=ñOèˆÜJâ6N¸Zeé^R…,‹=‰¿/Q½[ï½Ë4+ò-q-8:w;nA¶£<_™ï�m£¦læÚ¯’»]%ᦴ\$æ^=ÁwwŽUù§ø¦y>]g§ï»£_wJ-²÷ïÙ²íü`þ=¼J‚¾ÜR!¤¹Úù¿~ô|0D´Ðso2î5TE烛q(àÑy3©ßœž0f•"Qíº‹uYv{?ÿŽ1s|ÑXâñ¹AºÃÛ:yNzƒq£ƒëñ´1¸ën߶ Á'ˇeßþvÝu´ô¨¾ëì§z< ÜýÕ'ê?¹Ý§Ú“àÏM!ëha!H7Bâß<SZ 9ÚE¥Œê¨*ÿ#ärô¯B©¼’Þs£ª -¸U�ÇÝ)‹ò|ßqºŠ?m{}]9ý -ù&wËú¶§q[FãŒÍŒ«ø³¹Ì´©ÍTûÄd~Sù°ãžlE3ÿá Ý›ÁôŸ µ<í_]˜Z†TK|Ö‡ûÔ?ß¼h€"LçGŽ§I¯1=æ·Ã‹˜sm†Í7ÝA=ÖØ÷7ç{ûäivç~£þå÷ƒYøÁ›Þ<Zžüü¾?ýoí»›LwvP‹sZ=yûò({[_„¦ó/"ÅÒ…ºd>ŒÊþ½À¶÷Åi4D¥•{9®ëa(f„|ZõŽFyWw”>þÔ¥Âe© -t'´E%Š$/,†ð‹PX•ûƒCRzÑ(ü]÷]=œvCyÇ=¹ÂèlYYdŸ¤•‹V‡ „¢DWXAÑ Âû¿b“uìföò¯ªÊŽþª ¡-wUŸ>]Kí+‰·Þæy^aÂÇ -Ãl 9\$‡eô’óÍJ‡ —•¥kV<eÖU8³Ei}dž?×äí¬¸›öèå_«<iê:Ü¢×x×»FJS˜I9çí+pÜÜôO¸¿®Á<6(…F}¸9æÁ -å½Ô]ÛZá…[–U‚nš è tø详¢µ*ôG‰²Ô¡¥àí^)ø—"“Z’€:…¸S4Óp³^é¦Ð{Õ-lå›KJ´i¡‹sÍ œ 7IsB4„ÕP~áT¹*ý¢6!øÔæ²rSÑ‚Ñ9´‚îÔžÕ…ðêq×Åå�BT˜MÉûÑÂ=fa¥HAßžÁ‰(…kÎjÚ4…‚Tª°T „Hø,MnÀ>ªÄXipõHŸÄ7„ÝÒ€ÿ‚ðïÆÛC) —¡Ò0m«Ûhyaü¼‚„HŸ§4i,œÚÖm5ã;àÖ®-=òÍ!Î/dߌÒ<8!¸¡RkŒ“©ò{¥5èœÐúnqPQ1×6«0–¨ÖfYS\+Ú/Uè•”´›JkâÆÈB³©#q¡0„Ø¡ #eIØ®Üfñ»Ûh|}®t¥½>Þ·Á £s¸L'3ô¬píjŸöCríæËí/ÜsÚHlQP¤HN«^ùêÇEäì’´HÄN82!ÂfªüR•}~u¤Žà;ãCPüªÏaSº žÑDêÊìƒy…N5°›r?`•¢k!ì‡v“%ò+4í&G~ 9”•9.W{ÿôªÈÑq ïýÎiiÀÞ/ÿ -#®˜h·Ò<u%ý5-¥•¸TØ÷}¾D4$á¯Êã‰kñþ—.¥ÏO^ÁÖOz(œ)蔓%ì=·{µDú ׳úSÚÒò(à¤�üñð6aÑ–¸öSŽ*kÜt®MåW¯®‹¢ôáõ…‡"Áаh÷Ž>¡4îNˤQù‰sƒÛaÛï0GÇ*¤Û|T!WéQ·/»£ -¦´äFAFÄ5¦6ê°_b[î�ÖØÓ´0!ÒPð¿k´„®âŽ-£±°žº•xO'F¿x*Š˜‚sPƒ–Éì�w0n"šJ˜ -U1º¥'ÜÊ^¸|ª²Bw2Êí¬=YÞ»føˆ(`<rJIÍRùõouŽÍ–:wßñ„(N6<ŠÎÚpv¤'<Lü”¿ãEŽHpè„{°1è‘掰¦Dsº`‰â¹Íœ…›#‘åÚö¨uKßóU)pq1ìL:Æt[)¢¶xÄ^µµžZw~ZÛ²p{Ñ(©¯‚¶Uœñ°UÄ«Bªë7“·À"7ýçÌ³Ç ¯½ÈòÚ,Û8ýðimU(k¼÷Þ÷/ÖV -ÅB=bÞãKo®®H<\õ^_la/Gƒ‹z˜½EG§5í¤e¡±åÚÙ¤ÐÂú‚XeUNø™J¡¨?Åž¼w?af¨7ï6züY”Ï1iüf†k±ãŽÜïNnðÎÀ`‰_Y†u$auòñ_TÚ(åãuÝ~Æ-oœü"|RÌ$9&ðmÀD H†{a”ÅCòiâêÎPt2u„ÉwLQf¿øF-îE`Ê-“NG|‘™0ˆ|ÉÅƤ;nñ4ÓüzZÃ_ lDÜ¡¯‘q©Lú%·&úÔÙ/¡a‰å÷—v¶t”‡©méÉ¡;=Œ?p«Ùœ‚ÿo>F5Ï3'¶!a•Nî*<ÃãæÚË –º4û%´hý ‰¼„%ªãŽ—û&€³øŨ ¾–üX¹Æc·ûKRL©Må“ü…ëÌ1϶r õeö1�9 -3°~e´n•Å6äK4L¬ûK{ëçú<; Fc'§n®y—…Åì(´¦Ð7f»J²B1‹-™Ñs?·¤FÀ}|N8¨-±Ò·HKųPxf[æ¡Ü0žG… -ʆeBª1sBªïƒŸÉ -fT†&ÜÉ‚œb*€ø&$GÅN¸Íh½ÙEI‘mžGô·©Q˜[£×©¥$ÝN7¸ª¤dÁë[&ŽÂåF3बâú¾±7G¬£"UÔ&׿œô'ÓT=×ô˜7v¤é.D"EËoz‘Ìœ^ ßz›ËkDžÞ„Íü›ëÑÍt:†ÛZçïo».ïÉ›Ñõ×ÍZ0j7b~~ÓÖƒ³ãÁhRû‚¯C¹î´~ѯTðEpå>ÞžÂOë®;®1ãú¢?…Õá~¨™ÖŸüÍ! ïQ»È^t?ŽÆ¨Ì{‚CýzöJ7?Æå¸ -óùÜ íªN]ÿºpÿ=gÁ§DGÏ¿|wòýè¢^øã7Ù“ß®C÷óaw:÷ÏÝ -—ã=}6v§ð½4ñÚOJ9jp1®‡¾YèWø3åûõžü?ÃÉÙÇîxòM’s7-ú±G_à“%åÀÏ=™4žv;çýá…ªh‡ÄÓzú=¢a=†ÒÒ~Ø1GÃe]NÇ7õ>ÔmÆF%¿ÐôæèÅÊÑ·š×>Ü›Ùfá¯ÉÞèî@˜Ž®îj«ïûËÇÖƒƒ¢í—òÝÿLº`B„3Ï‘Ž¶ËñÎ÷Å)dªßš®<†]:¹üu‹OãÞ¸RxÇg¹Ðì ¼l˜¿ö/0vtí䆂K[è}’7¬•|Ø!:){ݘ>µÎ§‰¹×ä·Vdä¡ÂnRˆq>r²ëÕI}9}=î;1±Í¨æëlÁYDîtt3îÕGàùEèÝnKbo¾)õ‹Ñøª»Œˆ¤¼ìê•…k -ý°K<_ðk:®iwü®ž:>T"“WÏÛŒn¾ÎÎËåk)ÁtÜN®»®¹^+"Ý,ÿàk`õàúÃi=t{í¤ñ´ô–l8ú.Gå|›¡5Ë?°ú?_à?-ˆÓÕFƒ¼Úš!®¿KôÙm·,cÙ-8o×.÷&Ë6©õC÷ft=í_õG÷Üm铺Wõ´{Ñv?·Õgöã^ÃG›—ÆÊÿø®¾èß\eoëÉhp³¹™g¯„ÈØ®âæþæóÇLëa=ÎÞŒkHpõ×"·>{UeßÕ“÷ÙÛîÄmñ°z’×ø*oÔx}3½¾™®©Ãyztî¤;|wÓ}WgoF×7×\Þ¿áhP×Àäÿ±G‹àx<ºƒ™gšgfH¬TžYðí¶ߌܓõäíÍ §B„âd7˜`ç»ôëPÿl<=uÇ™OÇ“à”zÿæÙ[1¹ÍÉ«ßÖƒFoýk±oF“>ô•$Ìfyë:b†Çz5¡î»é÷³RÇ,†Ê¢ÈliÅ—ÀP¹!†Ü[£è¾†œ\è»Ã‘ÛT—Ö×1§Xåpݽ¸˜9u¯ðŒhr=šÎ€ºƒ~88-æ×ýŽi -o ÆLž½ÊžÝLG¼õfO{ÜlD;²ÃQïÃÈíÔwÞybEѾۼÝiCXMÈ-Õ(\e×ÝkGM&ý«›A7nsÉÛ¼ÊRÎܽ³áJSÔ²LÊviÑôнCº7Ïnöùb-›z‡1íÊ2[StbYI‘tpmѤkËrD¡JÅ%‰bw‡»“SÆ£hÌÒöñÇ:O‚ìÛ‹þ´{Þô§aÍrHÚËÁè¼;x[_ß&)…N(î[Ðä%$·ùë£ëä7G$òì’š1.ËÃuoêÆæÞØö¸¹C“ç³TæM=ž\×HÌ_ºõrFùÜ^F£ñOÝaòÞ-F,ï›AÏœR‰bmK0œ7®õq=|ûÛ”S:˜–×À6DãéÔmŠðfHØiÁ“ºõ›ÒÒ®Cè·Ýº#Tx¥mŽfbCmÚX„@[™v„x3üÅãÕð¢þí´î†›ÕyÑOÖ¼—ÆòiZV‡óy“ËÍÜrn¹þÜÔZ+ÚMgæg6¥é¦¼&~A×à¢3Y]¡7è_;òÌßyzçÉw³Z¥†¼wZþÖ:Âu2êupªNÒósqÙW òxõ<-™þüØ -áÍC(iàpÍøÿoº0¡ÙIý±Ì"Bžº³ÅòïFÄÝÉ;yÂExöêÅÍ`@„7Äƺ_ÑC?} ITÒveyÏ„•èhá1³°è[::"C¿°ÜëënÏmV–}ÑíÕœËsUiX†³…Ë¥ýø©_ÿê°ì˜Çi<ZïØ©ÄÎG7Rˆ£V3ƒE[ Ë5Ð(—´ø‹„²€˜ÃåÔ(Y¦¬J±¢èQz*óž-’=ÛNû™ÛÝɺ¡ ù$ÉšA‡ûí½à¸¬(œÇ£ž¥mBÁÈ̘åczì¬(CJ‹.#lŽô‡u6Á“yŒ.*<uœUÜ+&‰—‘\Žü¿Ó>þ-1›B¬ÁºåïÈ)ïÇÒ.[T8_-ȌѦÍEìHß›îاyüü¾ß{ÿf<KËÖŸfPÚ( -Y@ÜéYJ±¨Áo¯Îë‹v ¾yþÚt»=ec“ù<}ñsvçÓ£Œ„´%gÓÌsÞläo?|w’‘š,ûqRŸž.nhöí£ëOÙQ·÷„ªá¬àç˼ö7uöËwoÂiÓ¿ê¾k¸B„‚�ÎNoÎ/!‚eœ5Äå´E×ÁÙÂz‹) <J37ï¿-ìnZè;Ÿ»be™ŸûËѯÑMe®Äìì…“J=¿¹ô{ jB¢_é¨~ßýØ-‘ÔNÁÞšTÆL4Caôfÿ•ç&,îMëé[ÖS¡^¹a½ ÎÕ†õĬ‚Eµ@ÁÚU™d‘D³¾ô’i“Í—¹vë~iËÅÈ_SËÞªVq«Zf!×TÒ‹çxM-Õ$Ïí*…å$ój‰E›t]¥ÜWj;¨Åëiyñ™’X$†y5I:RËïº× Œ,ÒJ/¯ñCj»^Zú‡ç?ƒ;Wz”¯jüÔ±\x^O?4Ï}Ì×y9:qg6‘ÔÁâ“afþäqu®"&Wö³É¤zý(3íZWqâÔÔÑýÁÌÜ6Ê.9Ñ -kfþñΣëì;[Ô£þ¾‡%“<ÛpÖT0Ì¡?žÎÏ&s¼Á7Ëšn›‹¥¶’ä÷™÷~ûÛõh<6ˆ4 ¦ÊqŽ…áækò¶ó`ß@qNÉ4ƒùÙŒM3v#!³g¯²—”’JyCÒ*Ó‘¯tlµcÞ°*.g+5ß$²oßœnü*_ký»6µSÑ)ÒL‰%Gõv:DÀ -Û\S¾u?vÏ@°c|*Þ`{È…ÍÛTa3WôujN—‰@R?°ì“j|±ˆ·@<ýÉ«zRU¯˜)úzFïÔÆš s×MPx ž|‹íåË®ÅT³ØbTù2ípÚ[®¤«²á(*ñ²þ•t`êªPÎû7¼ëitÛxú¯Ñy›ëdš˜ÌÒѹ -nKŒÝ֘òvW—š|è_Ÿ;Œ|hnÇÙbãÚ |RÃhÆ«KöFƒSë'ó&ÉÙò4ìdDß°yý£óWÃËQÕk½¬gçýéUæYä‰VZüúÝÕ‡Î9hG——ïøÊüç’âWÝñ‡ÉlñEho6~3©ÙC&oÐ`Í~®ÏŸþÔ¿¨GO¿9™®þçjtêkÄLCëÀd:è\øWà"¡)]3[P-”Þmê\_\¹ŸÃÖº¾hݸÓâ‹æþúzŠ˜W&¼=è»*³p¦]¹$Ž ÔrY©Ô7_”ËJ¡b¢3¨/[–œŽÂ9h¬]]r__æbuÙtÅ>q‹ÏQÔ‹ìüSö|܇`æ•“�Ó“aþE½¬-/ô¾ÉÎ/kj”hEW46SlnÒ±ZÍW“´‹zÒ7\`u_Hrσúª± jäZ”ëN<åjMRÓ1?êÁ¸sņ˜e%z£!亷‰c’|$žû<9xË…¥Ç'º@¢Åyp¶à¥cè:�4¥/,u\MV|ë»ÎÊÅÊ|œcågKM@Lm-÷qõ'½ëAïÓrªäËô†³FÙÙ2Óþ uY2¾àÜ|½¡ÜŠ¾ã VÁ8¸ŠîB© åˆ]»r±¸§Óqc´©ã–ü’‡žÀmÜËÎhGâ]lÒ¢ôš2½ñèzM`ÖúŽ}YSlœ$w]÷R‰Ï»ãÉŠyl²ñxiQx:šõ\^69cZðE±- -s7Z”§æœy¬]§‹Áj’çË\/Gsj›Ùb'Ï“¡mÑMÜ@çìà3%ÎûÀ¼®˜èIgX¿ëF/Ë%…z³ ¥åÜq3\ÝÖ@ôPÕ5'ÍÏ”›¼ï:! ^%(TOÁ–G÷O&þ‡3›¥ì":ÿÛu§áË„][Tj<ËÛ£"cQÉw¤€EåÂ)‹æ3–ó–ÍÕ%ý$Ã�Sr·!H/)8ºî *X`²bƱÀÅÍJÀ -Ê몯f3œD7YF`©Ë›aoÅ*ñe‚6‚VÊšƒët‡Crú\,Mc©u¢Aï*a—žüØ9íd>/–“r/²ÿzrúóë7ÿõuöQ®Î®7—°|‹xHWÄ«Ô§hQr)ê]}Z!¶'GÓ÷uêÅʲõ3*žHש.ÆD•Ü›þoõàM=†<öA?ê“þìôøÕ«Ò<¯aôðã¿ÿû¿{S½ù£³ÿûÿú_êùÓ×ÿ—½ïJpÇ<ïPrÎVpÎ9çœs,ç´³Óïj{œ½Æ’’lK²$ËvõßNOWË -� ‚ �DÒå‰T'_¸2Ï)²„' §Š¨ÉrÐ]^\«x®û³Ðº.ãêDöðÏ?ÿ ˆnE½FŽ Ú´\¦rÚ²±Â?ÿ,<•R¸PžàÏjÈÑ[lÀ…ªþȉpp– Û£^Âç¶`½wÔ†üNRiøÓCþNO�þ,P/WÛ7ü9!†œ%â�.´rÛrçàJçƒ?«2UBcÁµ¾$/'Të<®Œyøu,²:W-ð'ÙP[Ô\6Á… #ŸÆ#³Óþ¬ÁŸ¦ØÐÔ‹øã²…ñåøDþ$ûâ-³Û¶çñȼçûÇÞ¶–±q•Ç½ÑkÈLdz"l1CÕãY…õ8 µ¶+Ýè\“TE3W¢O’Œ$&!S‘Ä7„ȦˆUvÜè°Ž•ÿùG}Pž‚v{zµ°WM6CLaËrë7ÜÆC¦‚É!†ƒW›Óƒ§_·©›Œ§Ê Bél7Á×àvtS“éƒÛëÕí]¹ŽNa�ž¤ÊÖ:Hn —*'ÑÍ›±D¸Õ.‡ÊÓ€:³(¬°=ZóâØ7Dýk_L½oêá®}^»§Æà±µ -3Xéµ�øÂetª^CÛýâ÷ÆS»=3©GV¾¤ÛËe±à10qbÙxÞN(¯“þ±¬ÓÄà¿œ4…viw¨bî"«Åô"S9¶]¿9:;±ö<ºó¿kKfn°:¶¬ÆiMΓ:'±1j¼†2-ÅŒä¯!lr•:ÑÔ4¥‘©Â›à†olª±Ãa9ωÐi’ÂkWNy) 0g÷¡ÊYÂ1|ža'“!ÑŒCN“Y›ºD4œËù¹CJå?$ÿƒ(t˜ Q�™‚ȧÉ_‰6¬€gO ¤/°rz¬túžÑå›GDïvéI'ǼAÏXmþRĵ{'ú½aÚ‚gÝ ™ o#jD®î¹…1šG”¸aŒ¨`êª}à}M ÚÀ¦ƒèb•=¢Ïẍ¡$#Æz¿Ž˜º±_Ä<6éËbåCÐm±„`gÇ!%B\kvĦö¦»QÑGØà„8ƒ9qÅIÄ]Cúˆg2#„øÔ â÷§H î[ Áf@Ân}‰t$¦>)‘xñD’ªCI -$cº†ìH5@òƒ)ªí)¤4J*gEjh³†Ô¯¿r¤¹7ÆöÀ·XºÍšé—6]dXµ‘q½\A¦Íƒ™OýYd dF“ÈÖÝ:"û‚9'#r1âI9’]åŠC8'W‡j¹vÙ¬É ‘�*7UC9šyä–ÛÊTrÛ¯;-wæ5Z¹Ç½ëÊýš‘W<µŽòȲ\‘Çû«<ÕKmäÙn² /LsVyySÚÉk—zUÞBœnh#—*È@>ÞÌsO -—¯j�ÀVqèÉEg -`¹hjv…¼rR*ÔÖÀR¡[ -SÅžT`DË©°© ƒÂ¹Þ¡g®–ÛŠh>]P$+h\‘m¬}Šb·dUT}&EK¡Ó(z®ƒ\1*ŽNŠÙ¢²Uüâ™_™J±+G–Š³:´PʹRcŒ,”†~b©D=™_¥ ©m•®îà¨ôgˆ2Å4Ê$2)s††MY6ž}ʆÙPv-õ¢räVt”ó\f©\ÏWåá’0«ÏÕ'S©ÔÍ|Ve¸jº*,?Ú©ì—AåÍ«ýª0:¯¨ËÒR•ËøtªŠÃTµä—¦ª¿YUÓß•]õ;U‡ùd«F¦#«Z³ž–Ôfõö ¶:äµ»ˆuÔÁUH+S©özFk®wêªÚèS·K‰±z„®¬êÅÌÖQï¢ ³újÒ54êsä1Í,MµÞ3k<%OWÎìšT¡2Õ»þ€¦±Ò4ýë2§™Û[Í6›h.ë`�È?߇hÍsWSkwÙÝZ߯ó¢Å=MmHEmuWQk»ÝÑD;M²ÚMµk/áŒ\§ Ï&:KÄPÔ9²Y¿.Ð?›u‰cô¬+š×S]3iè†{$£[ù«�‹î¸qÚôªèÑ 7«; -½½=êIëZŸ$”3}I½é[ûY_?ÞŒºúõª×Ñ_öƒŽA§[ô¸s?0x’ò±!:D熼1º14rÍ“a$?«¿9§Ùp‘—2•Q;P„x<•7zMûŽ1vŽ¯Œ…ÉYalõŠ„q2$bÆíxÝ0ÉwյɤòL·)d -å Sf3ß›ê¶.av9ÓÚ\^š®‹6j6„;9³]=Þ˜ƒËÀbÎÔµ s=ëUšG™ZÒ¼Iï6yšðZLåòØâœ*l–È5Ù·ÜÂÒ®¥ûÀˆ6˱أZmÈ‹5Å ØFq4})*Ðú"Ú@Ç%†î�^L•Òfe*Ëë,˜¯¢[b©šÃj{Ž±ÈÛ%‹u\u\…pܧ1àþ}lƒg"ýÞÔ›8Ð-ø1«ÐºheGغ!± kDÑN=—2HüfN«¼Q@e*«å1X}^‡ÚšnäÖ¦^y±ÎZʳõL(Ï6ÃZ±¹¹-‰¨l5KAg›˜¨íhÔ;ìz}8`wbä=¶TìÕre`o´ûÑÕR;ô]«ÝáÒMã`=Kô3MGݯÓÓ^ï8OáÚ’+4œÞdòàÌDÂVgÛïÉ;W™à¯KQâ.|–)ºÂêúÁUŠ-½®áL æ»ÓktëW’Û—#@fîÖlyp¯ª¾¨LåQf6{5’ˆ{¢QÍÙSö²ži#ñ\FhËj6o0ò»ò—“”wäìê¼Çy{è3ZŸ_?Õùò£åÄ7¨+3¾CÚFø‰ÌÉï‹Ž{þ|FŸòÚ90úþÃê ˜L‘uÀŸ?õ…C¶ÅÑÀé0r-…„%rš`E«B‚ÓíúBú½uˆuV¡Ø´µ5yèW3Z†5ÞõoØUºnÙz -÷à Eøpšdªˆ9¯'"!<ëT.—td>NÔ£Êæuuòçhº`6G{e(zæ*1‹Ú¿Š…z]¬ÖEB±•~ÛŠk¿ç¸Ç²tÅó³u->.\Î Äó%l&g?‘Òå–DO5É%ŽÝ)‰º2‘d´xZ'›Ë˜?¹Õo)c5ãO…tºßT3‰¤~]‰SZwÅóiÿLaHWªË^zYŸù3ÚBçœñµûõ0Í\@^®.YóÔÊúxX¦ÊV4!}vYïüætRÏùWáH®Z[á¹ß°É‹e>duò ›"Ÿßz»Ñ‚9÷¢}/täWcá[kŠør¤(¦Ýkqpé_JHo~-9ã{y©àÒªdªÒÜ`וµ–"Z¿ŽrÝi ”·ùZºb™©k•„¥<®ôºC‘w Ug5àÝÚBuq™kúI]Qw2îZ»,ÕNUϺnëû°znéÏÕçêØoC®XeªFh1¯5ÚN•¼qšûcM{²÷Û,´žæb›´C¥£íÕÆ^w¶‘ÑjÞv/³vÕèÞ··1]¶ƒÍÏúN†Xô;ÓþØßÕù&H7¢Zµ»ÝñÁßCzfµLÕóäÝã^TÉööÕ£oÙýÒž÷W}m`®Õbƒ”s&Í¥a¨³¦®ÃÈ[ûËd¤L»£@°ÞµƒÅÊèš*–Æžr±8®OëÅñI?.OœùK]¦šTÎXg²Ï¤FS»qñ;-MÐÓt[ïèfÖ4j›}íðlñ”çDò8™Íë|='R‹BE=X¬Ï{dI”vžeѲ/7ëÓieíê<«RÍÝYíòY }þÚ‹“Ôo¥kØþ)ßÚ¥ÞL×õhȱ>ÿFo¬äÜ´®Øl+onýÛ ·²Ýöñxz§Ñº4»˜ëî&Ô·7:Ì—}:I4ö˱ß{ÀÑ‚âP¬†‡½IËTGçÐo;6R#ù !̳SÐÜ«ŸzGâ¬SÍ]ÿã¿Ûµ8Ã^¥ŒíŸ(™|Î2lŸ¼w#nzæÓ+Ëý’«©´~m'µÙ\IwîþôèpöæÞ-¯ëZïÅh|@eÄOûmètùÏþ´.¿pÆ -~X½¹Z1^ÇÚí»GÆ$ìx¸}@TŸŒyßÛÄ 3¯È˜”ü•’óå1OÜï%dèó9j$§u ÐP,¿D>¡l©ß‰û<orË€ MNûñè’ýwvo#N}FNN2\òL¦mVba·ïÈpÀél}ç3`l_V;:‰éñÉ"Ï×y©q·o)Þ "‰îô‡0`SÆVçgߦ¦ «ùJbÄÇ -]zð¿Œé&Â<I|G¯g¤3²ÊØÄc¹dÓÑeV]^·ãÝhµç7ìÎ7ÑývÔÁ°™Õ-:”‡@à3î¬Çq¾í -É�ÕÐxÿ¿Â]üSFv£½o|E§eÒmµ½D`ÆÊt‚Óè¿ïS“ýÕ{Ädû-á—o“’óÑ”„_J'dn¿ÛOÈZ |ä´Š’~+L«$¬¼„CZ¤â¿àñ#8}¡-÷ÛGÕÓj¿hÌ>UQ²â[Ç‚ß…MüÛ†b#!q•g-„Íž$Zdt N…XÍÄv9¥Ÿå ¶Ò ¬7ÌUOTeX³1L–"o(æ´~ ùÆâŠF¯6ß$ÅV˜ -!<>`z¤˜qÂ\t?Iê»åAk¬—«¢ñ¬WÃ/IÙ ^Ýbx^µ’ºjúè=ú5ÓU.£Ýôž *¶Ö[àp¸a×V—`Îü�Ëà粜ýÐá—?ç[êÊ–³ÝÏ™J<í~˜6iÙÎð6U_�¿Ÿ¦c&B.$p6°ÿî¯?0“~€ -?£f'‰š·v0¬›ÈøÝ?ÝÂý\öÄdö³"cÀG?›Ñá!? cdf%4Î×É6/µ‹’¡ƒ0¶ö+hÝ~þ@¿:ÿ\wkXÛ,Y-œV‡‡x&0¸OF‘»9É1lC©ÊèÍr€Ð+ áBì˜s탘[µ'Qœ¹‰éýø§@=bdˆí [uÇàmø4žQÓ˜&ÔS8xJl—îÅIÇ£VYÌg¥½–ŒÙî`-áÏYîlW“ž®G<†çœ*ÌjU è9ú]QeÐÓ7ëƒ^ãá<gp‹Lôd‘Óí¥ô%¼H–²A¯uV‰¬|þIÔlÖ,žPe§-€Ï«ÜŽvâýí…m“1´ÝgÏ€`—¥ÁoW\ãQ«²þÝh2UtŽ¦Ç¼À”×ÜQ/uº¡jÄ\FÊ|ÏÝz×ñ^Ð}6o Q£ê×&¦s™Š$V|¤ztÞk8àV_Ó=//‘¥£±È1TG'Xöô4 -hò9Ò_ô÷àJ}„»…HØäüU†*&ÅŽjCs4½ÊT®_a›ØJÚÈÒ:ðxC*BmçC¸MX‹GfW½¿žV,=“Éh ¯V†Ø<»¤0c¨eä8”C÷ªŸž†7ª€Æt2t¯¡lE}„í×=é%!SÙ=õ^0´›h¶_Îcql»¾kÇÒÝ!N¢ésÍ¡™9:u¯"–_,çÓšŒ³ðÆQÜR=heUÁHÊ«hÄŒ.ÛŒKªcWø‘}ßàO;n|¬è‘`ý;èß®WÀ!éØöÒÒÉ^ëì&š5ëÓ,Šõ¹¨eäUÇCû±Øáƒ> …|E¦BÇò”•¼6øã^úÊÛˆe¨×#Æ؆·ð`Ý&jðûcF<Xøh8 Ÿ×3ýÍ÷É‘¼7À+„m4ðR8}o@ïÑ�Lë+×fVòž G$©á¦²ÕÞ¶ÿNBÕè¯!:·dŽ±ÑH£Ûǵ’7øCÕåä**'¹P'À臽–|3mÇšÃÀõN"ŠkYlÚ_?€97æSò6`}t^‰MIz°#Á¯ð4¨‚eªØ�3ÔÃÖf:<–5«;×#ä´Nv0xz£!¼wõ¹¤dwœI÷¨… d*ÁwÕÆ£,Œ¦mnð'®(8~ûxôT/òP5}¹>“’3’ºß¾yBà½*cGó*Ä¥ÓµìšÅµêƒ.²´—Û±1êÕGg§“}ž{C(r܉‘M„iŒä6¯i‡35cŽ¦~#jîSꬷ™P¡ÎÅ#ó´Å2ãi<2ݶHáÉ3‰ðÆîk<`Û/Y_;œ¬*|œ6ÈT ³B4±VÍ�ª’—&@çîÆþ¹µÜ÷&àÊxIäc—Ëà±æ9ñ¤Îûydu^Ù¡´4uŠ¸N‘J>z噹Õ[0“Ë:È^9ƒ/ÝNß.º@Žà©*«O\Óm¨2LG-+Ÿ6N˜k’öP5·_ëÕÔ(s–š2•×€ÆºwrbÆ}«íî&ó«+6YÕ7äÙŒ(Á¬îh²@<ú4¡òæ g¾W%øÓXå¥ÞÊ´*;™Š!ÂoÏÁªC]ˆdUŒµdèÕÑyHÓgåx| C–d7€ÌÝÍÀ”²9OéчÏ׬•†ñµ,¢‰}ÌXø�K 0±›Jƒßg'ȧtÀɪ4…]Cà+Õh&“4Ž1›Ž| -û²Ðï¨×«¹ *¼I£f8VÇüt8+½5XŸ¡[{WC3Úmü™†Ñ6 QWé–Ï®š~podÞÃa -ßÐoŽè3ÚEäöá/¸Ò¹Šä7·¯oÈ{Ôí!Þ”ÁÕo”z¾±`‡³yð%&Ë6ÊÁhüý‹ôz¥[C5 6@!±M!»IB„?uá -uFöŠÄ¿æ’ˆnò3Ò¬—¤ ÄBBÔvŒ¯Ó—‚¼T€?“”ÔËýàŠÞƒ=Ûšü J?tïk D†öàÙ—û@àHâF,ÐPúõŽÿF'9¨÷?)~!9bfµìË},Ù}‘2$d¨«[¯è§ÌŸ�‹c¼b‹6’eöêÁ*Ï<±‹¢7I‰9}†/ó•ä FŸñ'ót“ú†ÆwÁn ó[²»?)„’ãr'……=ªí Dª€|S…¦;üN�&“R}!G|þ©¥ñIò¦ŸädÐ9ú›ûÀ?¾¡¦á"ò’<MÎJ·Î^¸]‘‚Ý z -ætf(þKÐëž+´•ç‹P+3΂ªÖ3»xÃÖ2UB•�µÄ¦µ3t“kIå.U}Ѓ‘‡!B~]˜tJ…*DÂÅ»²±|è–…Å$+`O™”ŵ‰ï甚–jÄÃY¨¼ÓE"Ó“¿úrò±@;<í,ý`qç±è -¬•uªÖ5ÚDÌßO“Š²ÏÃyÞlF!{£ÓsGÓ>DÉ1ÒžIrtI¸Vò¯â`rTœž2L3,<^DgúXYh!�&åbØÚÀ=7ËÂo·›vm6xÆî¥ã¯Õf¨]°çEm–©8ŠóMm&»F»hÛ®š·UdžZ¯;¨QZÝÓízH4.i8«ÏÄ£ºiæA%`ï߀}`ÉIµãÀ¸|aÉIµãdª»%gzh…R-’Ýh&l×�ÑI¶Gñ@BC²=}Ö)ò·§ -]d±Œižoã NC\ëYÆÆ”ôhi>¯©Öô�¦Ðù…Œ -FC‹ÉMýa'�s5¼Š,;`>ÚsÃg°—b\WÜxâQ[7øCÍc(¶/!ÚLÔÒLÀ£’‘Pç%úé^:Ö×qÍfÆ ¸L¸à¼ò Ï0¼ÙÕ#èÜIÝGÿÚÂìN†×0Škgä6Azf0.~ÈåɘîîÌî:UýÓÚÊ°/sɨŽ7(Uô\eZrÀýKäÎYnèP)„*‰é/ÐÛ}'<XC\dC½F¥¥ãÓ^ñ0ìÔsêA`y¾’4&s̨¸HjÛλr˜Ä,SñáþkÌ2Õ÷%ía�§k¾#pÄû=½"Û]‡¸Êµu>`;“l:\*ÉØÚæiO -R¾R'YŽ|@ZI·•7¹÷‘TtÓÜQ2…ª‘Z-6.†X½™¼ÉûÄ%Ѷ÷qm&±‚ŸFÓ±c¶†xHgÚZ®lzô¬Dq{H[g>Žq™üó ÛÃ&qöÊTŒ5Ptþ‚n$MÑôI?|={ ³7ÖÊjnj�R×³ƒ%ï 6Dè<Xtíá{s§q“––9{M2IOÊzµ)Q>Çzûü±D™ƒp?XW^.óù2ÕcÔ',f,Y7ÂWª€0fËe—›¹&W‹œ¤µÌ[ä^0÷ÙŠ‡-5Ú n̉äãºVñÂ\±SCè£çV#T®º±¡ýpW¿LP”Ħ¬o0_î>‚à§ù‰¹vÓob“’ν -#ðÍØžŠ:W[òä½ðÆ©Ñ1Гî›XTG�& V£ésÉ(SyæÉñ"ènX€]èaþ‡Ž¡ªPŠÝ« žL®+P66 øJ16®jô<·�¥$ ts•h¢œË¿ŠÉTa“{v¸«7vJ“¨ª••ø@¡îƒaÙž‘¦¯Qsyj"ÓTË+»<¾‹Ðž^ú–¦cÅŒVºF#I…êñÈ´÷±ûHgë+9~`Tu‹Èb±‡ˆRtÁsר÷€>F¾iuyw‚/Q¯Øí!Ï+®ðÆ‚X ÆQÊpÏH³îÆäa«Í}¤çþCÂ<sÜ0LVpÒxccKûÀÃ@™Œë5 öb¨àŽe‚žð¡ÞÖ,bÔ=½Z�3íŸÇÀ¥|Rì½v¤ãI8‰ê] ¦Ñ¹ -bCÓb™Œ9ÖUŠÐ`ðõA.BH¦sÚNž¹õbØ›‰H>RÇš7Í«Õ°…Kd²5�ÖÑŠÎç%œ‡žDÐkBpÝ/¬ëPºØÌÒ}€¯R÷Ægi§ÕK(™ôÌ `¾Ôë ׈ÊT@„yœ±ödÜf´·+ä`ÍAÇm$BËœ5ŽèÖÞWœKO3‚Õ¶ç»ç‘"¥kŠUCWðXŽ¿¡L#œã€�Ì¢èÀÏ…·¿MZOi5 e(–öáNÔfó‚%²è^߆)i -Ö3ÍÕà -wg"LþãL³3Ðf,¤škÈ9>,sýªã”Ó:ª˜ž`ß—!Thª“ðÒ_Ó -;EwÝüêŠïä5¶¼Fײ«8D3éù:éëZq¿Àµ²¤]…Š7T¹V¯´ªf/¡±ÉÄ…7¿Óõ}@¡Ê&h \g$gî€eI;°>ó~Û§¦‘”¥¨Œ>{åࢠz}ë*àþ€Ó®”[T®ßã¨×Ô!4lf¤Ë9vQ§Ø¡+T¨%ã¡òÞ7ÙRž1¹7õ0�eªàÎIØ«Sª&@5DÕv¥bLÄ#¡Þ" x쌹xSƒì�‚2ÆÏ.\¿'M“|iGmáøâ»ÏÓ„u::Å€&1øž‰¥X‡lÉ^ -nð¢½UKÁ‡%§ U¬ƒ„�õ%TQDÒ¡]RŒ{㓳”™ -Ùþnñ‰2>†¶ŽPຨͅI#Pwãì7šéU‰¸v_˜/»B[ÀC %ŠôÓS˜ñ¨ -Ô€vQºšvÆêÝj#ØgS4•j*¡)±‰Î¼}y¨¤·Ô(\* ’„ÙvKôÖS¦GƒÖxpák’ü31—íÚ Šë؃!–òh,uÚZ´'!§ Ó°4%dýØ㻯/–"j°8ÁòW®y˜Z9\¶Ú°…öx,WwŠi�º0³_ü*0Üw⨃›"5e4]ð¸„ßœÕïK0${”½[Íň$åQ…‡¡ƒsM£“Û¼ãö.(f;g :¡jUUº¯È䌷‘|¬´¯s%´É5¸NÙ÷²$lEÚXÕ„œÆT®®¸b@ ½VG\š]0¦6GØnÈ>0[¡-ö¬¼òj°´B=²sH¨âÕCx³Ý;ÙâxnYÎúCÎ|¸÷¥¨6øBM/f²;öÔ&M¨ŒœH°X)]cö”´Éj9’žÛpq{2Êh7©ÓAo2bfc)u`Y;Ø3Eá¤Ò?ËÐ -ÄÚü*ï,j_7êÞGSÓÒ%šÖjãäîqt†ŒPOoñªÁƒ“}Ðx/ПZµ‚cÛU¥~M~צFÍàY×”ƒõ…è!>0'!˜(´„¹Å¶£:¸î ¸òE6»Ük¼vWvÿQãJ¯»àºË¬Û*MË©3mF‚±©|A‡<JF€¦ô"ŽÊtïM”}ÓÃ5èžN'U7>ÒÃVM4ÛÍ]t^º„îIê•||{×%™¯MúBH±EQÌn?b® -Ðf*ñx½Œè¤l‹©èTÓ†vãÅCAaAìãÛxd q”4¤ÖC[ÿJʱ–Š)-éçÀШ9ªÚ¹ÖÁß,è÷¶Á2™!‡ Ðsõæç,ɸa· -$Œ~e™� !†³ BT¯BûeAÿ˜>B”¿ vÄ€Jž„ -™äª>-Hœl°^éF•ä±IkÖñŒûߨ%ö:éÚ¯býæ²ÌS‹Õê塽VèüRKB5ïr`?^Ó]<ûØÄ®³…s:ÝʱK•ÏþkJÔkÀŒW¶c¦–s¶6côW}ãʳÞ~ÌŒ`6Í´@ü{1n_îpô>Ïؽö=–mG}“Sj»ÅØM¾ J‘ep -VÀM¤Ú‡æZV4ÔC�ÛÆ=£ÿ,3Ú]šØä*_=Ì¢Ç^=sÛ Dt¬È¤Õrsʶ]ÁFÉ &wØžn7° ¡]�)]¯‡ÃÉЦ‘9Êh {Ð÷¤ -ɲÝݬA_fq`#§Î½a²-/ÒèªK:€ kbôÔîVô$…Ù\C,gpYg0‚9TšRlâš·§¦>(]µXGéZ4N eI+T÷ûTøh#+éŒ÷È7s8\¬³x™o=Âà Ðdæ[O lW?8÷tµ[oÎóäQFûÿÏÿ0¤¿9ONóÓ‘}jLj·þÉ®Îöq1tã]Üó›£Ýì~âøSs=p¸±Ýôö$¼‰aƒðl±ÚÁC}oÏdd`*óoŒ¡Áo:€^6¶ CÎò¯p«·ä&îJ÷+ò‡T/áèÜ•XCoÛ(:G[þûSÜà+Û—ˆŽHú“ES–©ƒíEtù¶1.WàÑpnFWw1æšQÄ„æpÔâkiIô6$¢+YÏø9][…¡Ÿ; '˜‚Û6÷CΕÇS49˜EdªÓÉ‡|:˜qýΤ·aŽïÛÖzìÔm£Ñv¼UûB¾ T…P–“¾ðeíBÝ¥:d&².% ØÓKÙóéä9Wc -µX+T7-;;ã—:Þ߯ÕèT‘˜°§zöØΫÁŸ@ÔdÇÉq‰®Í–³3au=¿àgb¾nEÙH»§^®[âGšpômîTßÌ‹´¯Ì„ƒöÔ¾Ê$TüH½ˆötÆT'~¤E¬k•ãný©Lõ@{Ös&¤¶¥v¤iÅø‘Zu]ƒ_ð÷Tïí@Q;l²|}EãáLP�©]¡Üt>¤>Ÿç+¤dLîmñª±ô Ê‹4‘Ä«‚äÅÛþêD -xqcipr÷êÏB´ºçQÕ¶ˆÎÓ¤Öý+eÑ0´¨ÑpÚlÛÁáôÁÉÚÁ©·ÜUGvG\‰ñ"í†e!¤`ÝVZO—¿¯^¤wV,ge~¤¥ˆÎTn³|H žÛÿ@ -Æ…ÍJú@;XàGjmµÐ¸Íó"•Çey‹øÊTh¼×‹ôÕ®Pw¹ˆÒš0ëüHhH3Ó:Z$R¸«É&ðEaÐH[&-‡À¼ÕG“7Ö]ÇYHÛ^4ë0a©žƒT¦:Ë“³½½<2á�ãÀåßl§=@jW8ÖÓx_iÍé{.)ä1N_SGwð÷”/ó"x4„ Ò̬B |H¡ä·vLhe “óõõ,Ï$gùN[§åEZ×ì‚H+ËÒpL"•©žûÚI õÌÁË4K¨jñ ×Çô–ó!2¢ò‹�;´ÈDù‘æü±A¿Ôëñ"íÖ))\_žûúÛ²MãH»N´wÞ˜ø‘æÛ‚ËIp,$ÚAÊ´$ðIU1 H[54¶Ú¦y‘:ó&9와hÝGé˜Ðq&®éI¤¸Æ¯M²{šE‡zw"5>,-�û{¼ }߉‹ô¼Wûh¤—€ÓS¤;êè(¤á–bBãé\ó#�@k~–J)ÙW€4ry…I¹BÀ2&Ž 4¬yj¥!”îH†D -±Ðh•§Óh¼ƒHQÒÓ)4Ûßø7pžm¿nz¥ ¸KfyåûÙ°*£õ‡Ùh`g7*YS÷÷nÁ§¶=]¢É¡êúxú$ù誾c 6Dníú98OíNlP¥Ÿž×ΧYiß-åM¾ç”P,¦Ü]Á§N\_ -?]Žúš;ÅžŸ‡pu{"ø4kØpá§ãÂÜóxÊ¡˜]QOÆI¯IuÒ[;SO皣‹ómÍ°º)§sLî~¢Xmœ®ìøžSR.jXŸŸ6Tc"ü´uûnãy>TõJÁ§¿—â!)øt]ÇÃ¥ÇÓ'Šm×q_èkФ’Ç&ø4[ýMaŠ©&»q%+ôµQ§ºzÁ§±Pn<|šÆrL˜b!WêÜOmI4æÓßúìÖz8O ÕÒ9@?˜½ÜY™¬úÐã¹õl5–ÙXj:ZþUøô@›£ñ=áý9O]±ä~QB3‚˜Ò®°0«ðÞ‹#Æh9ÿ4Hûín½Q2‚Æ7*‡o’ï$Ç5¾¢‰–çÀÎaéc~¡¦·äÜ€–cFXrÎرÍ+r5À7÷Þñ),+ßX¤“<vºÍ&–¸=ÉeªZÒÒ@jW@;§ÃÔÚj"‹È/ÆÑǘ}%-A¤pÉ›!2‘Z+ÀFf uæÃÒ©Zx %µÿ;R‚C^¨ýß{šØ°êZ¤õÊDË"°DJjÿH=´ÿþ)諯=A¤€Àg«0R¨ý"•© þ¿äï«1‹!Íj‘’:Å)œû,´P§¨²Fu溡'¯èÐEÚÓ”÷ú×íŽ9÷Þ´+ŽýX³ðò=Û’æ;ZZ„AŸ»!ZZ>MÝ¡v©Sf8hüñë‰.êJ3ã-+…Ûøøã?h§UÚX‡2‰²÷ý÷p‡¨%Aø]Iå/Ù -¿+щÁ5ŠAÌÄC4Ñèý1ýǘÛÓHø†à®[‚ö€ÎùÔKï{aËrUÝÿ”™3í3+Ü_ŽB, fw‡é�íSM®Á 5Th¯úu(½ÇŒÕlÞ=n ÁhÚ¦R‘ C6ØV_£Ö®§QÌ& ®Àº9#® ?ÇH’HËÞ5œyEtø‡n<eÌóôOƒöO¦zôü#8‚·ñ«È_ŸâÞ?=Íc|=„ÊkM„XÒÇoOò'eYH$–0Lþ‚’Ia÷±<¦·8ëÁW¬™â¬D÷ø>åyé”›6ÍÉ_S·]iqºË„‰Å=ºgÑÓ±E!(zd¯X7ÖM˜¼7™E@5%zøi×A†&°@{Œ1#õ‡¦¶ã§]Ë„Šm¡YIúãx»Ö’¿ß5æ*FvŽÔ«¹W¤NdÔônoC¢N¯˜«£W³¢YMþ“,õý[â“0€w€9×dÐö> ™|>Ô©AãšQa2°‘R“$Û@ùù?$*¼J/÷ßsœL:uøaRñ"éÎØåÑ?Ï»Q\꼟u`É›WѱT`Æf„:Æ&Å[�ɨeø†PŒ9 ðЇ#ú™7@ÿîRð™7 -¥{“í"ûrIð¶ÌŸŸ…:Dg—šåI{’‡Å—3<É4ñJ“*zÖγL%¸0IÐ/m¦s\–dªwÆ7i’|_{â›ûÓ[Nó+·,¼"MºÒ‚ke¡L·GŠJš$¬Ð݆N¦’6‚ÀÊU,^éü¬Ü©D‹7Æ/QÜ>@Qœü°ÊNB»`^‘`ìåÝvÝvxi`-q#æN2µº¯)68ý!ÅØíÍvØ~˜¡ãôd¸^üçµcÖþhO’ÏRhyh<Ü\"/äCÁ柕—€üÏfe¸yT¾g(Sû±O#™„[&Ùm %þ>uZrµTãã®[r©ã?ß—å—n~Å0É -¼óåõ0ùÏâ&§!4'?7å…ÔŽnùM^L{FC(Ù °D-’ÐuÝyÃ&§6%ÙAF÷ؼw›mp•‚<{€Sh‚ˆˆÃ+>&HJ\í©Þi”âCÀ––pÊõ.*ñeYª�H=€T{_¸ $—I#:KWxíÏàjò_ßo -nê5þ‚©¢,Ö;'’ÇkøØä€÷—„Tþ¤w¬Äˆ%}Šš=¤•ˆõægë>ÅÉ/¥kmaOð4ì{ŠóZݯ½K€kåÒ<$b¾„4×%Ëm˜K–ã!٦ټ€QüÚ%ºÆ˜Hôè¿í&Iø„œT÷ÆÝJâ6%}e/˸7�q²Cd¤ÊÓhI+Κ*à÷‘©Ä¼tÛ4ÜÜm}å÷dyíë㈠¤Ž]'3ä&ËÓp`©ÒÁ+W•| ìL¤e²eR9ÃU¥ß¡¥‘íQ‰·GªÔG0l±·ÂGþl¾¸K:ñ®½æóÌcñ»¯/x£îº'Ô!™J„Óï°½O@ ¦²É^Œ¹4Â^8éeœ¥NH—Ôá,t¯Ö!¦.Kõ…±ÔÁÍ* 3~ö -ܓ‚³ŽÁÉÐó{>ïç>7+|«{WTò$�&äoåó¶R–…¿{còñÛK`ÒÈT_oR£&¾äÉ$Ãa’﵆ާà|;)(wkòå&“ßóþºw·÷y€±vß[DÙûƒR»0jÙg„Sý“†|*S½ž†–7¿½Ç' DÀXN½$R2ÔO÷‘µŠq%Úy{’hç5wO‚DãõD�a‚Ço%Zí!ÑnÖë;<Øk‰&“¸ƒ}.Ñî³2QßÿD£Æ'ÑÞžû�ÎûíÉwAÁù^¢A(ßï½’pDvƒŒaí}Ç"Sñi¬E¨¾³ ™[‡ü:ŠÕXfÇ[›çÉ7ï}»{[_暣°’¨™EÀ</\ø&3åOÌ`uä-!+S ŠÙ£Ø“¹NÚÒ,KüŒ'¨IH¼†#Mµ„Búa�œïC H(5gçý5ö¦»D÷2Ïn ì/|ÕÔZúg€Ú{5wMßè÷&ÉËç¯-¾fCª7‹á»\ oé÷â>Xì{ý¾{ä[ß]Å਽ïÒz^Å œoô{”ûZøù*FÂáÑïù ÜW8RWCñµ”0Ýã׫!k-p÷‰I,à#AùÇE¯•¬à©G† .08‰ “”F »oÍæ7¾jŽŸ�ûvv3ÚÅ3·ÅcE(&Iݽ$Ä"d±4Kšç"»§@ϺEÄs%!œŽÓ$AŽ c{^N/îÂ1›ž–¥ˆÙ"É®”°0ááæT0<O8rMÀÞ-Ã¥‘RÂäŸÿ.Ú�Ü»¹{{¤Ô`„Ò“Éþ…‡PÌñžŠ!ƒGr`–䃥€ Lö–hð-Ų›ÿ^R£$rÄÓä¢Wdjê>Ö3¿-·ãµ,è1 ³åÎÄ´+ c½CL!¢óæb|tÔÉ-ßçÐ1W±ç:NÆÐÇ9tât¤Lþƒ:A¤d`¶à›9tâtÌlÁorèÄ3èXZß9tât¬lÁ/rèÄ3èD²ßÊ¡Ï #³ÿ ‡Nü=:·ú뺧‰ËÊ »[_æЉgБúØë:V@²H†YQçÓ¶…cà…38Á.šÄëé¾ÜÖKË—Šsläƒa£\í—Ç9 ÕÓÛ‰²Wû÷†Ž±Çål|L'žÅ®ì\Ñû¯•’6ûÕ_9QØ{|bÀÄã°¤õôõ½Êœ“Ü?Žçêy¾H'ºåý& d>¾ð\‰5‰/eöå¤9I²&Æ yÄö¼—@uy+„Šã yßm,ä4&OûÚ_Õ2)Ä»&“˜ìÆŽ„|×1Hr2óo=ÆT²›Ð¶ ÛJz•ì&lŸŠo80¤eL4„eš¾2CbœlV¦°4`ì,ìyÇfŒ_e>J“Y£ø[F/9+…ÌÞ1!BùVŠ)™û–“˜uøÚ¶ÄâÛ˾ëcÏ®³WŽÃµóÀq“€ok¼A³ìX%Õ.Á,0†¦ÄÍ{©vIÎ㻾Š#oü*ÿEÁrZ §¦ 'Áˆ«ÒÏ1ðßR!Ô¨ _Š¦ðø½Œ—E0M°=˜¼ã'5Ïyz•#ÆìètìÏ2DO¡Ì”w€½æxéc;X¿¤ØË4Qé|H´(ÆvüâáfËÄtJrëy2¹¤é²O>ßg3ë>ÕËü~Kñ|9�k9{Eæ1Äûü3ÝI ÆÞÝâ{aì-’’=!�ÜÅ@¼:ŒóýT i©rÐ�}½¾ÜTþiSÜ^;d¢.i˜•&`Ä=±½XŽœìEš³„-O²CâGžÈžÌ+=Ò}~ -å×F/HÎØâäßÔ{îS‰Ò”^$È=Iጨïjþ>–’:ãó]PûM½çÞN³ãF}L§åOƒŒcJ³À›V“XùÈ Qø;î‘&±'óëUL„NV©MN'Ö$îÙfŽÿ—JIúLšôÈ|¥4a¥½Ç÷"=Gé6«¿ñÈ0ìýô÷�@+ÝñFÚ'™§lÁï=20 ã‘ÊH}•Ÿg}Ë#ÃëçOKHÏ‘–œSôÀ„{ÍÉÒÂ÷`©”,gʲpܸe™Ô - Ì ž“xÈüM$wIó7NÐ5·öEL¯”4´Ø™ëL ö.½‘>öºÀ›-ø*¯îí ÙçU2¯Nb¼žh^#uT$Søµ4#zHcö2tKÑP½âóY¤ðžÄ…î–ó.˜ô7ùpË_ÄÔ‰çýþØ'ùp|QÐÅí_çÃ}‘gñF>œX„êßåÃA¯õ—3PB>ω ‚I\Ÿçñ¢¡nßhþ:Ž{î(•÷×ùp/O ø“|8ÖŽ•„PËÏòḶ˜Ð¶Ìdû>³.p @±c"…tK)1‘õ½¤˜ÈWsÿ¼&¾U"d€Ä÷Ùè$ã«Ñ—GJ‰ J#áüA&×S$ƒHük‰“ë„bÏñÎŒZ6Ïš£þ)âYs|1œI(èíiÖ¿™†ä#†WáÛi€‰+Ã'ǧaë uŠhãÞïÙ‹¼Œö7§“pÞ›>ùÈ�Ο$BF-ÒV±—p„8MK(ÌúùHà—§¡±½ÒœÓuÆgL>?Øé¥A}ÏHÅ䟈0ú,t°ðG©#ù@B©ÄŒÔ‘|,Åeð"ÕïO2R»Ç¿ÉH…pþ"#æ‹}Ÿ‘ -¡üEF*„#íhŽIÌ×GNáCSß2Ò™èÑgOÃæ×Ó“ -Ç/Çþ:ŽŒçèù‹T8ÞqùóT¸Ïý–lŠ‰ÛîoØ•_¤Â1Ï "“áþ•T8¯Â¿ -Çï“hŸµÄC¦(`žŸ,–ø´ŒU•r"<[‹˜_˜ER½ (›$¢2&|²Ý›:ÌÓ!Ãïn.0²Ñ[·pÄN碜oÉ{`yÜÌÍ«ë -‡Ã]nÞQžåá1aÕ8#>zÈ—þÂ2±©QÅô‹»”Á~¼ê/Æ‚–‹Hþx5àh‘eãíØ)JÚ«éHØ<‰D–,BP9Ü–#Õ†ÝdÚãÄÎÅâË:ƒV£ÔÎ;s–ÜE&{±“Ý<“BŽé|f µ-õ*/²Ê°³¶šbÉnS‹ R4^ ‹eØ© -«ÜHéPiÂäb åæb¹ g†Ž›ìfm.³÷Ê„œ0¹V,Ù 3s²ëñy¶Bvv…âh¿v…’Ý:bYg[ñ»}µ*ˆT-§BHgâõøJMa¤±|'!H^åŽð„–Øv䨂 K÷š¼¢ùÜ-ñ=ß{”Wõ¦µ›•Ñª+RïÑKgÖΣˆæoV’?~ÝpT1ß±„[¶kØQ}aíÕû¿Iíy¡Êõš×±:Jhc_L¤Q¯‚S_ÅyPÖë_V’ã+;Âs¦Šï’X%¹·¼p¨äÉÙä™oÄõ½*"'×'Ÿ^‘ì_Ý·WÅF¤öïuÉDUg„s–Úõã¤Ï—ÄL¸‘`¸«ÔtâžÞO²é>óü›MÇgÜjqþ]6Äóa¾Ì¦ãó rçË÷Ùt|¹tŸf> -gÓñùâù#í¿É¦c‘…ž³¼ç}•MÇêÅ !dÓ}¸"¿™MÇ·Os_+ÿ,›Ž/—ŽiïÿM6_.ÄØž7²éø|í· -ì—MÇ7º¤§÷O³éø”fìèßdÓñåÒ œ6ÿE6Ýs“– -aMéÓl:>åT¦úël:¾ñ㉆ú2›ŽêeMá²é„t˿ͦ“N±o²é8 ¸{â”M÷ÅÞΦͱú³l:þÜê¿Î¦ã�°üq6ßn 'þ²éøÄÛzý‹lº;#”M÷z}ù‹l:>b<´ñ¿Ê¦{•Éõ7Ùt|¹t‚õø¾7�MU_죛„«x=©äÖæ˜øt|1ÙYÄ·î…jÙ|^¯î©I¸Ëó×õꄵitº4oÑéA%V$$ÌÉ|©XHdV‚‚@Ö³P£8M’* -$T—coL}Ô$H1Ш·Ê.‹5‰?BPˆÐI¤ì²€È„«Û" -`é3Ç""”®Ã‹Âæâž¹{µ,±Bw_—¹cœs%Q%ÿ¤Ì`u¹Œ¤\%‰eî„2¹¤%ÒI -O~ºûn¬ƒ”*3¢^*Ieî^z!a¾.sGë0â…î¾.sGå¾½(t'móèùƒs®ˆ@ Déy™?Q:d*÷ǹ< k>TþÜåê^ƾâO˜FgQ¼¤D:)Ͳ׆ÂA’ó‘°Ã7‚È u]lN–Va`Vh¸ùDðÐTÁ>ó %´ß“(n?LìbEC¦z.9 -€z?&9 -�“Ñ-ØLʾ?É|ü~+V9œ}‰p$ÕvåƒÂˆìªüÅ$¡<e²óf -¿Îe'IJ¬ªÁM¬ìžk+»¿;û“BÆ$ÖJf̵K”U>R¾¬÷*CÞÒ…™xÏÔ¢–¸Põì¼þ“Ì”ûÉÇïkÏ ²×¿ª`…·ˆ%ÏýÚ[…ª…vß`áµ¯Õ -ŠXTçpþà”� -ηժ)(·IÈwÂá{±ª5 ‰oíðê<Ó°.!‘A’þë -w·üJ¡wLCžàŠOëV¿WáN,óñ‹ixc4ºÂÝŸTÊ{™O$RÞ·ùD÷JyßOC‘ -wì¼$)ù!ŸT¸«÷ -kܽ_áNê©æ0ûéûÄÚîñ¡æY¯’k°×jŽLŠ¢CÕ¦û,±–›ùhûÖós¼éÐïsEÂù@n>áüI>g•f‹½„#œËIb’½:f‚,—÷N~;_sW -ãÓ4tk_„¿Öî›Ä4&)IL_Ÿk‰2V1)iLìN¾ð>@ÝÇE0É•”¡.j¶ßg¥[+eVJIbÒøv\åûS»²ùV“P¬(²Ò¾§6éÞ/Nåç(†<‡%6[T ˆ¿Èq˜…OƒöË»éÞ*÷H’RXkýÝÑT-r÷ír\[‚GS½¯ÃŒÏo•{|Q)ÏòaŽ+c~ÞÃ0$d=¿ÎqM’œõ,–ãJ{€à@düønªÌxKúªÑ5 [Ò¨b–®ÈTÑ€¡Rõí‡;¸JÉì¾x³Ÿâ¿<J-<¤k—á;¦¯XIxù@™‰”•'SõV‘éªb×asG:-|8pÞé:tcl™ÌIÃCõB¹v…ÒQÖõ„’ðº‚HA_äñ!ØW4¡hבjRcóB¨›îôžÉõ pц3²SÓ·úQGàd9ê´Î†©L Ì9ÇJÃqsÿ˜äÍx‹Hí -•5>|°ÜŒ¸Ò„Ò.Œ4QR´ù’ußœIVj%iY¬Ž`¦.Œ4«ÅY‘]�>7Þ¯è$Ì«Þga¾À{D|™_‰õîˆ÷þ{,“ Ï-+Wé¼oÖÐÞöâñß:‰a“€¨6¹Äªbö:pRÂÚ`û¸‰M/=$Â)IÏ¡U‚M‚œ,ܨˆ”Ԧ׉M翪ÌB:t_Tf‘êIŠŠ‡V ÝSe€ òNšXÖçäÉ/²Ò^DhRT’Iã'Φ׻ý»{aÞÝÛUšô¥Å/’‰þV”–L%Ö(a?ñ{MÒR8N‹nÏSl,G\ź~={ó:ö\3å3SÀNI8úú…¶û«Ã[&DÚ ‡²‘DÝËRwyú±oN¢}ä$>÷Q²ÿ–õ[çZ÷cz–Ù§hÂ,Ào¡å;+N0_ì•Õò|VœˆÄïcðl±ŽâoÕ;–0ñ?³‘Gq®„ùt×›J¸šÇäŽÕëòu¬–qýü¯]vd=>A¯Šõø@°vžÞ×Gj?i|MáÍÁ÷ÉžêY|Q–M<“é+×[ç0šÄÉ™&Ä|Ç/µqV“¡úôn5cÖ¾™ -¸VJHådžs%’ -øª¤ñ‹ñ{ì¼O¯u$3§®1o•™7€½ª¢£áf׊�ã¬*ßQìe.ôN²w.¿¤ØËz:oQ,kí -�{JæÓiŠ}˜(5Pò9$B b’r�E¢Ó%dJÍ|ö'¿“(5yÂáûY€Rs�I¯õÇY€,V±0¹q°ïeJÍ„û<ðAOq¹Áαz7PjàÝFþ(P IO9€ÌýJª=Ͻú¾(ŸôŠlßåcôå_,Ê÷äUøWŠò½ªÈö7Eù¨œqåû¢|2VøçEùžë#ÿEù„ë#ÿeQ>Iõ+¿)ÊÇô*ÀFÙE“èUj°pU¿ïφJÿÅÙPëúI:êëº~Œ®ýÁÙPBuýÞ‹Sú´®ŸxU¿Î†â©ë'îâ·Ä߯ëÇÏ|¢gC}P×ï5'ÿE]?ñÈ»çê˺~¯2¹þÈ¡+ZÕO¦zË¡+X×O¼kßÅÇuýX yªê÷AÞº~ââ‹Pý¤®o:¢Ø©æÒ #9S–÷,èêú‰Ÿüußÿ²®ŸèB!W±?¨ë'î~ë*‘º~â¦.oôuýøÒ$Sï»z|óþV]?q(ÐÏÿuýÄ7Td’á|“øÎÍHý´®ªÉ¨êǬ΀~Q×3 QvU?Ö™]o§§ ÷º~/ó^ÿ¤®ŸxU¿;'Y×O<àš‘‘úU]¿Gþ/rιú¸®Ÿ8I öêú‰Ìµóšø£z|zq(’ëñ½(''¹ßWuýîPx§Ï»ÙOuýDò^FÛÎÞë'®ÉÃþ¢®ŸÐ^ÞIü,K‚:ÛI|5 _ÕõßofG|^×Mm®µøi=¾÷‚4„ëñýÁô¹Wõû¾Ÿ”$¦W§7<Çj¼WŠ›‘ú]]?–cû©ª•1ô}]¿{ª”X]ѯëú‰«9<öv]?ñª~_ŸÚD×õûÒ×'±®Ÿ„¼×?¨ë'^Õïíz|eár¤ås]¿Ï“áUýX¾ªë÷ìJfVõ:åìݺ~âá]œUìãº~âNŸÒÇuýxÆ…QÕOü\8éuý>÷[²)ö~Γ€]ùE]¿‡àâ«ê÷qô §®Ÿ(G0*€|W×O\1¤¬×ïëú‰'ÄÒ+ò×uýØäVõ{ÒÇ$ŸdÅ®ë'¬Q:Ì‹“¬$Öõ“¤Ã|]×9’Ï8"Ùµó“¿®Ÿøâ šÅùg ±ÔºoáYÚb:Z¡ÆñÁ=WjI¨ÈY+Á]a×®xà='m‘ÅM7{ìÞø}f<团QiY+¤yÿ j)ÌìwzæY–hösßðóËJ1tòJÔÒ\;¨—`>¢ÌùSfT»C,“ÎÁJœ–é¸Ós•jzi«Ó„a4¹È‡ÇkØŽtGS\ ƒ*›Ó“Tç -Dzí¸nud*‡Íl8sñ¦9c>!¶lÂ:—×µÀ´’³7–ÕYÞv¬kgse#¤³FåÕrfíÞx›ûY@»;GÕ)¸³ç‘F> QÚ„]5ï¤RºëRѱî»37=÷ÉÜNZ©#fC?ˆà‹cÝà%4A4΄Ñø|’Fvuùtº´§³³‘:+úöñÙ6îï™–UƒÏbj˜‰¬K~K{ûµœÎÝ=,6çRP¹ÕÏ2„•_êig®Ð¤t€õ½$¬'yb*}(˜Mó‹$èîE Ç…P"‚}%3µ#ͬ¨¨·«~åîd‰«qëâªØL‘)Ì$Mß’C‘«ñ`ÍÃxµÜŽÌIDBñjU…*gSÒÞ/îÙ*û3}@׊FÒÜÃßÊèk|tðÛU‘«LmÇgM²€f¤—(7íùÈT´\¼é å<õÄ]Šu1Ö}@¶?±©7»¡¤8õã ,U>S‹Ö˜ÊØê=YäDö*´ÝCNe!Vo&áèpqc†I»Fʬ÷ÛZ'ÒrB--ŒF\(Il±™5·+LKúŽE;ðÓ¡'³~ÀIÀOŸ‘”0 - XÅ:'p#b¾}·ÄcxÎ À&QCÔ¨ºÆµÉT -3j–ÛØd}t¡¿CG66®‡é#˜'²Y0ðÀg`<)#>™êö(bz<ÂÃíZàö uÇ—aâ3)SËaò: 2ök,‘•î÷—e*,Ñ7OîL8‰ƒ…÷,´~dË£0Ëh‹%íYþÄ)Øã¾ê»d ^0¨¡—L¬×øµ0ܪd¦^šØ#N …Áa'l’,?i°“v£Çª7Xr•5žVäS\gwOoH«æT§t¢ø¦¢Š]:Àh]É´÷‡Zz[Žb†'ÿíò-³óÀcÇK‡ˆ2 bÅÙk¨yNvÍš9zS-œua\×® $«@Šµ:ø}à‡„ÒëƺN×]§ë[×ÆÇ€áѤòtÃL‘(ÚNap!WâÑIÁF_mj8}uíôiÝéFú -_Ø bÐBˆm3Ì×ØãƒM¥¾\Ë4ì¡®yç¶6ÎhÍÐ3ý%k[ï³rÌèË°DàJãa -åðƼЇŠ“y6šI!•‡ ¹oæDîÎ5ÃçðØIªkjvkOÏBvƒPã5+ÙZBíéØè«èhu ß«oCÜÖ"Õ^<º‘OBåjW#SÅƦ`.Ö^2žžû—ƒš‹lÕ½ ¬fÉÍ»X{–›·UJNŽÜt÷ -{m¬Î¥ÃºÍ R`O†c¨¹ú,7¹e‡5dÇXs’GÔêî{|@üÓÝh® Ô¨†›ý3jYËÍ–•¼¨&”®íEµæ3-Ç€´$ÁI+øiÕ‘iÎX¬„?ݬ~(¡|ø.ø¦EJÒLêu0ôÆLz" ‚ž†¤EÀ§”DyF>ÈhaìëæY »ám@3zJ†#ªñýž‘¾Wà Og�o8êÉÈpš²¤jEmãˆÆ”†á£Ô“(û�‚Öž\Z`×»!x»©gYM‰DÜD¾,¹òüÌZn°¡,…²ô!¬)ÉúDªI2+QÞÓí]á¨%Zû,¿´ŸŸd4t&·Yj%yžZPB§ª]¼~20Õ„7Pa�Huf6€¥¿6ÐSq}åT0k¬ƒ$²gxOî9¯”–©nãi†ªM©]ÞBì ôàJ�}¡@$ÕI¦ÖxÞ�OD Ç�(ây¦·‚…ɘ4À+óýžå~Œ‹±r„úÁ‰bvÀömÆ*¦~è^°föð¦bùð›v”²±²Ü -ƒ5ÁM/°CÔq.äQ;Ö"G¨“(Z¤žI×íÞÔòL,ô¸„uÃíl‹dÏ,ÿâ�©ÙDNëçC/èßÅGaMk½ø{(¼d±ph6Èoaœ¢g s"ÆŒ#Hî$ÐEÚÓ>™aGÁlbL®£ˆÐg_”H"Àm& 8¥ËÁŒàQOœM„‘7ÿ ÑÙ`NF1«Þylf"¥ÿž ¸u«Íîo"{KŒ"Â)ÜêHãòh~’±¯Èƒ2b=wÔw"4Eø�Xz£b—•<â”Zqn|Å‹ÐK,Ô8_¤tcpú°7 éŽø®KÞÑxŒ5+źQì¾ãéâàx—–Ò(@ÌÎâÝ��ôJ’“o ‘ãžb¼nƒ¨t:ÉI�$ÅZÛ4™kM˜o¶ºwþm1÷’lŸKqû5‘ÇÇc³Ë7 �€ ò5Õw_òXk/Äc’AŒO¯¤ÍⱧn,¿$eq}}ðØg Z ÓµyóöðƒË>im˜1HIQìÝÑh-_Ïxf@_žZ±þr4Z»+‡”7ŠIïÆéÅÜàk+7Áߺʿcì¶BñzEÆÏÝDS_V˜ ÆãO×€ûŠ<ž_QâE–ó´!-Å(1^Ÿ¿•–ãÝEÂJ$²Wñ6¼––ã+Âü9QÈY?ÕŠ›§3IÙp[ÎÅp{k;z+}ã`ÚDŒÇC1æšJ ß<<eMhñÙ¦O1»¤^z÷áôÖäH¹íR¯e£ò^¡Õ=0B[ÅtóVvÏðçÝ—Ôܯ´”a7;¯¡6ž¤ì]¸ño$núgÄl¦Ìí[L/´°ïæ8¨Â7³×ª½;uLç¥ërwîeÌYÃÝm˜1±<ŠÆ¾ãî‚É<ðõ¥gºá+`ÂÐ.Š„Oÿ¸ÇôŽ&"FÆ–w4‘2CçЮk líÞùðN¢Œ‘?‰@ ?‹Áìí¶(ÆIjë½0“fܧVBÖ ´ö ΗbÁ}F€à¨?k$X=å±;ÄÝ3i0ø^|j�Ì@iie®Ûá ËÐØÞ6E-#¯Ú½Øij2Uܳþ2Üë”ó=Ñ,1·ßo{ð÷Ý"hã.‘§ôâí¤K¢.í,¹œ‰xP3«FSSB[Õ&vc•*Óá§ÛÀZI{ˆZ#ë½ë#€åâ¢l\ ]"FÚ½>®Yh'︉bãlJ®:í÷q¿+…ƒ±ˆÛÕÔJyàôЮË$D¹E~6oN¹u½]õÜ6Æ5¬ŸnÍzJ0ôb@û%sGÕ½/ë´Úˆ°“pzf}Ý<²´ÇáSáäó´Pzü¡"¶®šKÓ|G:!#î ³\ú(–À‚Zp5ÂnWÓ‡xB;‘.¿Ö§ÖØ.õ¸^ç÷8ê&y.>Ì©\”3T=8;ÐtÂ`#ç~ÏNÏÅ&ª TqÿàûÞÁ;ÅÞð¾ïä;¯ï•ð}ï ¤Ø»þÁ÷½ƒ'¿çdzCÿã—9\„í‡üc)_7³Sá´Z¬v?F™Gf ¥0¬¶›îã§Ù¬:ûß—è~rÝÎv—÷%T‰¤RN[t6ÙOg?d0“m踋 Í43·´Y.FÒYŽÎ]‰uRQö¢s´ågLJK9Tˆqù›ªab&WÕbÄãD›<áϵÊSDâÝX%¥’^Âט!—mpv HgŒkXM€å!ÖÏÊAËyáµ$CíL´¯W‚–º¿9á~&+z€±ëͳI™‹ÑyóVÄdÑÔáfyôEuZ£.„wÓˆ¡$ÏÃþåáƒ�b -S¨5$ýQÔ²ÑÑÉjÜ@O¹ÇRnÃ]Ü“bVFícÆÅÂOnÐòN?r'ã6ý,äOÒ¨¥¯~g¤r £µÍ–IèŸn‰Rd(§3<!†1¯¹/·™œB»L9þÆVæc#S¦ÜÊ|<øZM ¶ûLÜÿ‚š@†åъ¿§&ÈTâËúߨ ”k[2ÄÕ èÜ…OM€ŠÎMQø÷ÔЗ»¢ðï© Œù2ù÷Ô™ê¡(pÕñˆ: -1ëZhñ¯ïůДZþSªÞ¡Øh"º|[KËÍ«»EjÈÒ@Ñ6~Ä´+u¡,uÁuAÉ5¯¨óµ(Q&MHKN¸Ç¦få@¿4:šnVí#ðã«¡¡¬? - ´´„;,iI/å\Dzä°Ci1ÉÓ§ñÞÕ›²¬š3¥x¬Œn¶äX,Í—tì®|†3úðA `qœ¢•’c=z -pä*D*l™ng¬Ãù.Î6¾Ð‡Ã4önä©Œ -¨“ÚÍÇ5ó®ÅÐ*Qba…Ë›iD´DÓÞ= -àPJx2$v¢†“þY=÷0ÖÇN$æÕ—dħûþ?§¤*–ëÛ8›ƒ°<jÑÄÜ_œ83œýE¹hïþ³sñiѪO˜ÉÐm»Í·¿•nbm„šr \ëj¬P»Q…•Ñˆ‰úi'5la�ÀâÍFnøÒ ô´œNªì–•¿#•Èh~’Ïo÷êÇÛ½Öɲ*ì@’åXê>íZa»¥ºüH;Dï{ÒÇëëƒ ýè¶IêÑôî›LÅÝ„$OEÿ|RÇ·û]B’÷ß°¯]ukçáF„ Á ¹+LÁjy¶fÍØ‚$OÒ"ÁÍ…p¯w7"è9[¦/·¢}—Çö¼t·+ƒîâEÂV4bÈ·M'ST$÷ùXId7›N‰�ÀèKäÆ'dQ7im BsžA©¾éÀ›RŒ-í7ºQs[Þ -xž•F×Eÿ OC“ÚÀ@SL*% nzÕç}f’f<DPÞnH$%¡ÄH�gy"6ÜKyÈT0àáÈx˜ý:úÍø/fà)úAóùh ù’Ç€‚¢ýŽÇ²Vó€ ‰‚èÑoyL³Ô~ÇcèN'Àc’Ad Æ—Â@v‚Íc}‡ù›Ñ�ö¼ÏÂ�ð˜T‰¬üõtå@‡±B…O²ìãoCßÌOJØòPò—£Ì—3^¬ 0ˆùàþn4 V+NJr}ëFÒon<µÁžÅ 6þÅÜHÊø‹6œüŒ±"'sÍË�1[ƃá¶"‹¶B¤ L˜©8m ç>·¥ÃôGLL>ówAf0ÀwŠ¶áYZN©�óg²dþ,ÕBtt¨ Ó’å£XÙV§ ™X£Ã ½ŽÙH/M4P[ðæx¢vÒ[vX»p¦…„<:Éÿ›L y /¬L‹»÷ô»]LÎ&Ë!²¸?âl@k^ϼWÓÞ÷òF情õžÀ�Mk`R9Äa¥ d|rÛ`ONlø³Ä„ &¤l‰¶ÓÇ»iÓĘ#7ÓÉ!ß•,tÆE Eù“K4XÀ@$X‚á”LNô~´Îd…ÌY51wùA„ˆ}Ò«ÀˆÙÚ³¹ý¸.÷¾À,Dô±”õ=¶&l—¢r–赋Påª\ÅÚÓ"ÜfªbþÅ{×~v`´úÄÝoieù-£ÇY&:É¢b¨a¹1~À÷ }ÚÀn®¨¹¥�·ÄýÊJˆy¶vð³MZIdÎÅ„øö}׿ޯ0f~Þ¿'0´ æƒèZysIþÚn}iÛ?K’yüᦴô̤„ZW€Dí?†–ÚnÄÈkx…3ßÌ-¬ðž•'ŦÖ[‘¨Á©‹Çc¹ºóæ ÝÚÐÙØm‡üi¾;5Ú”Þ!Õ5ø¡cʱ7\ƒ:eï¹?tÊTo¹?tB¯‚D×àþü2L·)±Ý”¹E)S©ÀÊìr=Àlƒðl±ÚeGÿdØõ -þÿÅmpþý±Á›Ù±LK¾úƒë~²;™j` .ÑÕä²ÚïF§ÿþ¸Á-ìÇÞï7?ÚPªoüÄþ÷aºüPŸÕWçÕx3û©î"•Šn,Í\¶–Šþ¸(Ø�Û¿ÆЀQï‰ÁeÂÈПø·ùЧÐ\d(Ý1p÷¿àG\ü‚[ÿùÁПÜO§‡þLáe™Íý˜lûÏVf²»¨Ë,yi·‚øø~A?mm·mgÓŸÅi4]ÁÝ`¡#š\(ƒ®ÔßðBfBÍ(øîü1Ùäµ ^f—Ëeû¹?´9ˆ°¹¥? là'æt ½ìÄmÄOxò&ü°død§ü9 W8ÌÏä �ÚïÀ0 -$¬VHSŠl˜Ãìp’Ú0œº Z4I#2û¸&e¼B Éísò„¡ÆÊ~*|î¹}zh'."ƒX¨¼!¿`³n‘M´C ÷vÿÿ1c’L¸í>¼V–À¬?VÜA]ðp=¨™ÃjÆYCzÿ„üaM¨!u¸È7é@' ðŸ‰ìœ¾Û«÷ÖLþÿ ‰Z6L-�`9 …¨ÉôbA èÅ�.O‚í_\l¹ ÷ÁŒvtÎ위9Á…ÓI.xÐÚá"ï€qòßæHúbuÚ͸‹€\h3 Ù–qÀÌ8a“ð+ê„wP§Ã‰«ÝjvÚÀ›0ð²p: —Ûpð`Ìî06Ð`+a5c.¾f-s�–·b˜ÙîÀg`„ÍìtÁéAØT—‡2„oû!Àk¨r›7;q\â|t:±Ç‰'P³ÝæÀo)êĬð;«ÙF`ÄæÂÌ6» t9Ì.ua‰þØqÐ,Ðx„&f·™íV;ø̺cwØ~`ƒ68Éff…ÒØP -�¬VðÅ$îr€wéOK.pœ�¯`@î;A?·› Œ$”3;¬„ã§.ߣäÔÇœ�¸ÓŠlfÜI€~à8f&œ.;ãÎm`&2Ö=«L2òŽÓNݱÙ�tòŽ‹¾c·ãØí»Û[¶4€}Çå™Øœ.³‹�Tº·›Àq³Íúèau™mN0à‘a¶Ú ¼QÉ -D C€NwRZ€©Q'þ ·ÕŠ›í(à‹ºì1*‘ì6;ÍÛÈYq0¾.H¨ûøZ1€Çà�?Ø�X+ î¼bÅœf«ËÊd©û-ÀŒwλß|ð§%Ì8b6&à±&°`ÜÙLW3j…ì~›”ƒÜÁ˜:è‚Ý x |y›`ÄÁ} -ý¿Z¬¦µˆþÿ‡½ÒCI£ÕJÇRšk{hhnÅPã»ø£ýû}3»+ðâà…áEIofžžÖDHiÕªcŽ*L2)HîIv ŒQƒR8U()®km`Á~C«Í¨;ƒCŠ˜dpÌç•ÚxEǃÃešAj²!±0Dp`CT9=x¢’C÷®Ë BãʪBU8œÕújœÄ9Û3„ H>Ja{Ï BVP +o 0èMh“#ôž¿ -ƒ’íZƒp܆\?z4B5 LÉHa<ä't¸ç\ƒßDèT0uŽ‹„ÐGD<-8ˆ¾Œ’öÈ?<ÖEE`óÆ:…(z&,³ˆ»£Mi®gròqõøVj/ø)wßGœ*IØü«¡ØIãBhE1âŒÔRB[u¤ Ö}Pé“æÐûÜÉ9T¦1-cžÅÝR¡–ºdH¯7A˜Xö•Ç•Íç`ׇä†îž¤1ž¬Bóð®yþRg9©à;YÁÜe¼`âRf0u97ëï{1Gòözø°?ì\BÏe¡ñ¡wLà^R¤*pdõÙɳ,3…ºB¶¢”à€4Y³qŽ¬ ål -œ8PÁ&¦Ô¢…Sµ¹<®œ G»>éj›%¦‚ï¤s“ƒ¹ËéÁäåý‡’c¡Åí+f8a{˜ ªš“/•`lÍ«Åþ}ˆšU‹SÂ(VRΦÀ‰lbJ-Z8U›ËãÊ r´ë“Þ*¹Yb*øNj0w19˜»œL^NÐ’{ºq妑ÇKõLWì2¬¸üÃгåjcþlaëpË‘oÜb€&P ~ÅD66Å�xß[1@ï<ŠƒQß8ÖGöDÖµ¾‡Íí½lˆÛzŠl‚¸höú-äÈ7ð6b'ßówã}š5N3þj΅͹µW7çý®="‹/Á¯u½øæ(Ž3ÁyáE &jÀ‰æO;‰äý[Æ!1ü†QÑ2á׉QMôv=Ì}YÙì¶_›Ÿ¿¶ÇÕî´ù³m6ûýá¼9oã?Íî¸=Çmsz9üeS¦áëõ§Ï«Ná‘ø endstream endobj 185 0 obj <</Filter/FlateDecode/Length 983>>stream -H‰ÄVËŽ1¼ÏWä’±çueAœZq€ûˆÇ$X ‰¿§ìtº{@nìjvÛé<\å*g®¯ÂõÕ…gÏÂåë……ÂâŸoï/oÃ^_¾¡ðñé)~¤‡XÕŸµ÷|ìS¤”4Æ(Ì-”VÃíóåÙ»p}ó‰ÂÓ§ðâ]x¼¼x…3¯3ž<z+ƒxJãú€$nO8 ã#þ O·/{v_KŸƒN22R¨©Va;ÛÞØ_ÑÄ„œ[¸ÚߢpÒÜBí©Žn—˜5 õÐ[½! ñEL%Qe,ÖT%0¤ª6Ÿ¹'ØwÔ¹•$sª¤BG䂇²`‘1Ts=ÍÁ"m�I8W†¦&-piž eF†Éæ Y,”ªb—†¬É8H3&tLÏNY“Öà`Gí à -Þÿ°÷¸°$ã˜f不ÑZ9 úŽ) Rk©àôDrNCû’Ÿ6Ÿ!¦õŠÔbáºâlqÞÒ;f((;mP”ÏaÅQ§P¤2€xå+È'9Ò O4O -&Äȹ'“¤s¹#jy’0IŠ"¨Ô‰ÈhL h ‹lÔw¤Ì€·ê¹Ž$PÅ^´È¢èqU³ µ‚ Vñ1’ûȦ}ÄtµÉ蘵”MjÝΛbŒŒÔhˆÚäM¯Í„µÉ9m͇Þ#RFˆî†¸í^ ”V¬ž;ë´×Ã^÷bíÑVÌ=¶bÓR¹4>ÀÞì×{ÖÈètfPÝZÕñ̘ئ¥hæîsæÔªYjROvŽþ -ŠIÇ£;0eóÌŠ:PL‹ÛØŒÉ6«%Å ˆêÓtIVd-˜ÂÓ‡½ëpMWcz*ÜfÑI†‹Ôw+r܆g†}Èå2`HkŒ´Ø—¡`ÍüÅ-Âœy€FÊÚúyd§!þJU<X<*ñ[#=Õ£g¬Gyƒa§SE¢‰³m*Éd.h¦6ÿÏ{l¦CÒY€ÜÍŸkƒ-ö®±=¯WÛÒ»=y…ÆŒŸ½Å´–à,}±T)Çâ•?Àä1~#÷`î¡@îaȆízÇþÓ.Výý?‡ÿÍ”Üüü©°2¤^䀷lJËŸ2ÑfΆî÷<"nøOn§¶åMÅ/å:;³Ú2/n¸8ÛËóF(¸Ô£}w“›aÓÌÞ,wË[çE—Ü[B®°ô8º®œÙÆ·¶b7yïŸm‡!‡l²YO7ow4¿@øˆ5²†üð «¡E»±…AuíÕ[ÞœPÈÓ[ëÏF÷¯Y—Ÿ�qäÎ endstream endobj 143 0 obj <</BitsPerComponent 8/ColorSpace 144 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 64/Length 677/Width 64>>stream +Ñàëm¼†@šm¼¼ûÝåJdÇÝñýÙ«ÎDÇ»‚ª7èrá/ùÊ%iàBû¥õNeÔº9šÖ c@¼\.b„þNeð¤H‰J0ԣúg+>gƒXô6pïr“&«ðç‰ãÅÝ‹Ö�@Hvæ;G“RøËÐH`–å +¯ì©Œôºíj©:¬ì†j`@Ô04ûnk• P#d3–à¿áZ®6H�¼åÙM¹‰Í€âÙ7ã_EÏ^“燡ùíšœðèC4…£:Ê„‡LòƒÂQ˜ðH«<Æ¡G‡îÐ�Ýt;ÅÉ=?*|iÝÛ!…+û•ÓXFÇ>T%Òíܳà…ã$Qpdí¸õj¼;—‡à•x£,Õ›‡pK@¤Š ËR¹+ ¾¶¬DR3B{Yæ>Mb¨.ô¹ãuRWXÇÇl:úªálwí—¡5w¬Z‹^Š¥zój‰rýá1»Ï ØV®Õd-KtbL7cl~®¥@ÁË°;‘¥«Tülи|'s»ÍxÞ„g[ Š�(é ¡\ýÈhøW„gT9XÈN0¿à¢É- ¾ƒ Ô‹Ðurf }q•IæªV*ç*ÀT»Ù¡é‘ÞHÏ¡KT9t9´Í#«¨M@ |U¦Gj›žÃ«©rèX³ß½ûP,¸WIÇyÇMYÐr9&Á䨳´&—[x¾ïžuLJÓîÙ¼ƒÊ&N)hº«ç•ÿŠ&qäJº‚JÈx_�ø‚F¤×øˆ¶=<=èj™Ò?ºyôE©Q¾©ð&ROº¥YÁ*ÉcéLhRzŸ°³roð)é,>ÃY “ﮪhý¡6ñÁwñÐSn>YÌÌSèÖóµiïÁ!BÇM`4ã;!Úú1Ûÿ¬9[âa庚E…ûrƶ½Á[nóÖù›æfü?+âê`~Å4ÖSºÖæV"¯QoLoc]›8·…6¿ucé}¹‹![-@YÉÈÖóS,¤Y]³°‹¦xƒ·ÝæóSüUp +dº«Ãú÷-Ñ3¹ÊA3Ö€wGÈ«ù5A3qµ`ßÅ[x©ô<$Ö¸ðïPóï ZW3ÂS9×â<$Ö¸ÏÇäãÙ„Ÿ DÛôä¶^ª÷¾þ}úl\wO/F½›ÉÌ …¶· ¯•Ewª;.YAbC×ÇÝhŒØ,¥2*ûõÙâC îoÊш¹³Í‚‰¤;懓ðpžæÂ÷ .›"¾Èeé–îoœlt87ãÃIx8OóáûäÎW‹�°c`ÐœU Cæ˜a¦Ì·Á‹ÙÛN Ñƽæðð &|L8øé~)ý/o7îïë³×½é’ËŽÆ7“ËìÇî°û¡g¯ÇçÀü-ó?wƒ¾£ä×—ý^(ùÞ!ÿi¦²ëi'{;ºž?/ûmvxð¤YAä+k4›ì›p^ºS*ïÃë¡Cêe£ðñewÜuÙaö¦öú*ŽMœû¢ +Ýéÿ3q߇nj*¦j¶ylª vòôÛ¬ãQíæ¦è¯<as½vS’vÛ=BæM`Ìüÿ +ΛÁ &{öêôhìÖÜ ÆNúgn÷œ¿s%‹SÀè)ìÍîiHK&Û$]ðkÿóÿG†!_Õ×[½Zͼ٠b÷æwô^ƒï…™À×:¹ +_Tá-^ú5'fÑ®‚å6»ÌQÕŒø;û4£a~žfÁ}2A‚¿åÀÞÏh–ld‘ßÄa?Õ¿QáL4ÕÜ#üÛL+ÇIàÞýf܃'Q檒ùR|Ýü/t!ôäàéÿŽ~âƒ;(Ÿ<|žLº§/ß}›=ýÉ͘;tž>s'駚Š<=]]ÃÒѸB%7éýaæx¨gÞŸ†"u¼ëÓ_ú“¾;n¡ÁùÞM»½´pÔô{iõñècݾ¾Ä¯Ç¡¢kqÕ¥ÜO}±€¬µn;Øž>¯/²ï³ƒìIÒçßgøÚìûƒìé›îxº`dÇ£áùMÚfP+ZÁn€ÝU¸`ÝÐÏ“ú‡Oõðõ9ænE|F½¦•ôíüzÎþ)@=åÀoäÔÈ:¡È±sVªâ_Ùõ&D‹&¢¹7-Ñü�‚Ó7/5zµ;A®Â;åþƾÂ@@¯cÒx·ù••ŽáÜÄ´²1VV èhPÏ¿†žbcï¦8ŽXé@žþð{Ý»>àXwŽØ Á\¸ÍtîËû03þ¸dïõÅŤž~‹°¤~¨ðj0¸Aad4ît¯›ýÔŸDS> ïI£ÑìÄ¡2ûáâÂT®ôûþô6„—÷’/î›~5œ8‰ fþÉ뛩ÿÎÆàçýÉõ ûÙ?~û°´{×öÌ×>„¾úâ}*zU•e Ý)~4«è©õi’#¶ûDÙŸ{^~sVU¨B¼8ZZá=}T`Y•±žS]‘&cÏ£~U©d±ÝTeϧî0]Úµ}³çS‘è»rÐÜ3°`L›5ö.š…d-)Ùñh<¬Ç“¯EægeÒ¾r.„ãtŒô6Üì ø¢ÜL–-ó½û±s¾·EО‡]HXÊíæa÷»q»w#09¹²àæ¾H“£]„¾ p +#³Ÿ%ú“*½ñëœk/êîô°ÝîDƒ`.SÒ‰övå‰ö'¢EÕžíiÑNq[COJˆÝÓ“@OŽ7uöS½í†ä&(à‘¬dVÚ*8Gwdk$\‹=fü’…›V~É…™÷I_NŠ'&/,8™w¤•eáÓ‹‹¼BObˆÂ>!:jT%E±5â1¡¦( +¸lÂcÐæ€8Q%ø>Cº-[Á·¥8‰%¶,pmt´Ä4‚–ù% äƒ5dPó-E ä +y48)R¥@·Ê¼²îâP¨Üö’Æ,Å…þ:ˆøꊱÙqª0 +½ÂÂ{i!NÉêŽòK +ãm‘Lƒóª\ŠØ»YawÉB¸AÞñÈÖˆ)TYÁ:P¹‚Ïa³ùs bÚÄP“¨ ѲÕQìàêf¿<Ö-Ë( Ží~m:±ÈðKÃx½Ì’¥awqiÜéÊØ‹Ì{ez8/Ç#'fþ½ÿáràþŸî”ܹ-úÕ‘V+5+¾–†Ân±^e¾ñ/ò/ÁðP´iëÉäy}íVÓä5f»ÊIó¼ïÞíúüKwÜç\Xü+Wžý›¦º–+®üløÁ/ÜùæP,·ðøK£u3Ûï¹âoëA–ôû”—¯ÏþýÖí‰ï²4.[7›OÓ¨)Hˆf㯈ºìéÏÃ~ot^·wÑyÛ>iu.µ¨rìØ™ÃÞÓ¡÷0¼®‘9ŠÛ¶ªðÖcíf[(ô²ð;A33ûeù„Cr¥¯3ÝwDƒcDB~-s£Évzf +Åÿ÷pz €Ìp:ŒÑÅd +`M€«Aÿªå¾Øÿ- þòÿ°½Ã0Kw¼*dY쉗¨€Þ-‰÷ÞešùÀ–¸¹•¿ ÛQž¯Ìw„ €¶ÑS6óNíWÉÝ®’pSÚ.s¯žà»;ǪüŠSügÓ<®³w—ÝóÑo;¥Ùû÷lÙv~0ÿžÆ +^%‰@A_n©ÒÜ íüßâÀ±7>.*ûá÷ë®#GõÅh\g¿ÔãI`ïé&ä³Áð<}îMƽ††çlp3<öo&õ›w'GŒI¨H²»îb]õ.Gã?°1–3λãKD7ÈŽx[ŸÐIo0ntðS=ž6wÝíüÐ}@2üŸŽÜîSíI𗦂u´0$‚!ñož)-‹Ž†í¢RFuT•ÿò9‚V¡‡T^Iï¹QUÜ*€ãî”Ey¾ï8]ÅŸ¶½¾®¿Œ~ƒ|“»e}ÛÓ¸-£qÆfÆUüÅ\fÚÔ0™r†Éü¦òa9Æ?+?øOíÞ¦ÿJ¨å»þÕõ€©eHµÄg}¸OýË ¬‹(Âü¼qäxšôÓcþ0<É1×fØ|ÓÔÓi}sÖº·Oþ™fwþ×·8ê_ÿ8˜…¼éÍ£åÉ?.ûÓÚÿÖ~õºÉtgµ¸0§Õ“·/²·õyh:/ð"R,]¡KæèìÕØö¾x!mƒ¨´¢r/Çu=ÅŒ°•O«ÞÒ(ïêÎCƒÒÇŸ»T¸,U¨D‘ä…åÂ~ +Ë¢òqpAcHJ/…ì~¨‡Ón(ï¸'7B-+‹ì“´còÂê”P”è ++(:AxÿWlòoŽÝÌ^þMUÙÑß´!´å®jáÓ§k©±}%ñÖÛ<Ï+LøXAc˜!‡‹äÐ Œ^r¾Yéôòo²tͪ‚§Ìº¢ +g¶(‚Ìsáçš¼w³Ñž½ü[•'íA]‡[ôÏáza×Hi +")ç¼}Ž›Ûƒþ ÷×5˜Ç¥Ðè¢7çÁ<X¡¼—ºk[+ü±p˲*ÐCPÀMó¡A„ýÍTÔ 6B…þ(Q–:´¼Ý+ÿà2BdRKP§wŠfnÖ+=Âz¯º…¼csI‰6-tq®93á¦1iÎ@ˆ†ð±Ê/œ*W¥_Ô&ŸZÂœCVn*Z0:‡Vн‚Ú³º^=àBˆ +³)y?Z¸Ç,¬é1èÛ38¥pÍYM›¦PJ–ª Ÿ¥É ØG•+ ®é“‚ø†°[ð_þÝ8p{(¥á24@¦mu-/ŒŸWpƒÐ€éó”&å€3C»Âºf|ÜÚµ¥G¾ 9äÑù…ì›Qš'7Tjq2U^b¯´±3`Zß-**æºUÀfÆÕÚ,kŠkEû¥ +½’’vSiBÜYh6u$n!†;"t¤, Û•Û,~w¯Ï•®´wÃÇû68at’ cãd†ž®]ãÓ¾cH®Ý|¹ý…{N‰- +ŠÉiÕ+ßbXõ¸è\€]’©‘Ø G&DØL•_ªR¢Ï¯ŽÔ|g|Š_õ9lJ7!Ð3šH]ƒ}p#¯Ð©vSîìc òCt-„ýÐn²D~…¦ÝäÈ4‡ƒ²2Çe à*pïŸ^9:.á½ß9- ¸Âûåß`Ä áVšG ®¤¿¦¥´×ƒ +û>¢Ï÷ˆ†$üUy<q-Þÿ’á´â9àÉ+xÁòI…ó r²„½çv¯–H¿ázVJ[Zœ€?žÃ&,Ú×>cÊQe›Îµ©üêuãÀuQ”>¼¾ðP$ ãÞÀÑ'”ÆÝi™4*?qCxp;lûæèX…t›*"ä*=ªàöewTÁ”–ܨ5Ȉ¸Æ´ÀFöKlËÀcš&D +þw–ÐUܱ…a4ÖS·ïéÄèÏAåB`@SpjÐ2™ â¦ÀmBDS S¡*FW¢ô„[¹Ó—OUVèNF¹µ'+Ð{×lcGN)©ÙB*¿þαÙRçî;ž…Àɦ“GÑYÎŽôäÁƒ‡‰ŸòwüB€¡È p6Ý!œñ֔hN,Q<·™³psä#²\Ûµné{¾Ê!..†I§cØn+EÔV€X«¶ÖCëN£ÂoB+p[no#%õUжʃ3¶ŠxUHuýfòXä¦ÿšyö8áµY^›…cï>~^[ÊįǽËþùÚJ¡X¨GìïÑ%¾ôæêŠÄÃUïõÅ6ñr48¯‡Ù[ôqZÓNZ[®M�-¬/ˆUVå„Ÿ©ŠúSìÉËq÷3f†zóa#¡ÇŸµ@Aù“Æof¸ö1îøÁýîäïÜ –Xð%eXGV'ÿE¥=R>^×ígÜòÆÉ/Â'ÅL’cßL„Šdˆ°FY<T Ÿ&¨îE'SG˜|Çõgö‹oÔâ^¦Ü2étÄ™ #€À—ÜZlLºãO3Íÿ§§5üÂFÈú 9—ʤ_rk¡OÝšý–H1Q®qigKGyq˜Ú–žºÓÃø·*‘Í)øÿÆácTó<sbVéä®Â3<n®½Ü`©K³_B‹ÖŸÈKX¢:îx)°o80‹_Œ +âkÉÿ‡u‘k<öp»¿$Å”ÚT>É¿P¸Îól‹ ×P_f¿£0ëWFAëV9pPlC¾DÃĺ¿´·þQŸeÇ£ÁhìäôÑÍ5ï²°˜…ÖúFÂLÂaW)CV(f±%3zŽâç–Ô¸/Ï µ%6@úi©x +ÏlË<”¦ÂóÃá¨PAÙ°LH5fNHõ}ð3YÁŒÊЄ€;YSLß„„á¨Ø ·7»(i!²Íóˆþ65 +skôAâ:µ´•¤ÛéW•´€,x}a‹ÀÄQ¸\Âhœ”U\_Â7öæˆuT¤ŠÚäú—“þdšªçš>óÆŽ4ÝÅ‚H¤hùM/’™Ó«á[osyÈÓ›ð ™ÿp=º™NGÃp[ëüýs×å=y3ºþùºYFíFÌÏoºÃzpz<Mj_ðu(×Ö/úõàœ +¾è®ÜÇÛw0äwu××€˜q}ÞŸÂ…êp?ÔÌëOþî†÷¨g/ºŸFcTæ=Á¡~;{¥›ãr\…ù|î†vU§®]¸ÿŽž³ïð)Ñ/xViɯ»ÞJ‘Ü�|…™f Éõh:êúá=KÚúóë~ǃ49…Œ¼ü›ÓïᢻìÙÍt”½íNÜëÿQÏ´èÐ ²sÆÇá¨÷qt3Í>x +µ¢h2¸YÊÎ@w|·…«ìº{íVõ¤u3`Gõôî¿*›Ž»ÃÉuw\{ŸÝ;ûç®4uQ$åÜ„žÜ,g= Ÿþw'b»nY™LºžÝÔ-‹~@Åi»²nÍù’ŽÈ*³¼¤H:°¶hÒµe¹Ž4;®ŒJÒZ<î?u'ïR<&ó÷f\Oêñ§:ƒíšýà¶O÷¬?èOÃýˆOþù£ÛR7WÙÛÚÍïMКs6el‚ý»zzs~ýÓzèfÛžf`y¯Ž®D0’ëÉ%/D\Ék| •7j8ºxíVãê:y¼Óq®s'Ýᇛî‡:sĈôÜ>}6v\/~uæ]=ø{wêš9õºËu—uï¯Ç¯ž§%ÓŸßÃý—ðÖæF…ìvÿ¿›.LDvRª³{@ÈÓwŽ ÿðãè< ø‰Ðw>&3ôñÙ«7ƒ¡!˜÷ܯŒ+Ý£A]ŸÍ½ú¥ËëÔ´… ï|ãª^×hk‡+4OßÂÑó2®Ó|U¹£…KaÑ·´œãbYXîõu·ÇëT›•e_t{5Ó¬*}R_Ì.—öã—~ý›ÃòswXt‡½P¾„°BTaa-¼µ/$ýnŠë7\ë¸Ý/£Ñø¨ÕÌ`ÑhÄr 4Ê%-Æ{P·(ô’R€¼dA˜²*ÅŠ¢q0é‘RdL@ºîÄÍÜ&èNÖ ÚkŒdÍ Cb{O”–=®ƒãÑ ÏÎÒ6¡`$°fù‚ÁÅøÃïntÓµeaHiÑ”nç ’Üñ<èël‚ΓyŒ.*<uÔ>îÇ“ÄËH.Gþß/õÇhø÷Ú‡Åûή_þŽœò~,í²E…óÕ‚Ìü<ìO›‹Ø‘¾7ݱr›üã²ß»|3]ô5ßþË(m÷wrMø@‹üáê¬>o×à›ç/ M·ÛÓ£5™Ïw/þ‘ú×ÙûÜï‰Çû’³iæ9o6ò÷÷?žÀIŒê$ûyR;yaC³o]ÎŽº½Àè g™Q_æÕ°7¸9¯³_|N›þ•;J' ~�8{wsvª«qÊ�4[tœ-ܪ·èËàQš¹yÿ}awÓB?z/”•eþÑ:Qd’pÊ3%fg/œÄPêùÍõ ßö<t|¥£ú²û©?Z2"© àÕIetAߤ7û_Nf‹{Ózú–õT¨WnXOüTÖ³Ì[‹j‚µ«2É"‰þ~}é%Ó&›/s3ìÖýÒ–‹‘¿¦–½UâVµÌB®©¤ÏñšZªIžÛU +ËIæÕ‹6éºJ¹¯ÔvP‹×Óòâ3%±H(N{‚š$©åÝkFI<ËkDN¬(ýþù?úçÓËô(_Õø;ÇráYx=ýLÐ<÷1_çå®þ!’:X|2ÌŒÁŸ<®ÎUÄäÊ~¡Ù‹Ñøª;'c-E`c¦ÝAë*Nœš:º?˜™ÛFÙ%'Za•ÂÌ¿#žÂ^;ìëÏž±³Eý1ê=,™äÙ†3@æ9p.Oçg“9ÞàûeM7‡ÍÅR9<ù}æ½?ü~=O bÆÅF58Ù1ê�?9Ð å¬;ˆXžÒ,ç?)Í2˜¿t‡ýÉ¥ëW"¡¢¼T¢XÛl–7®5ì”g_)c t)E¾"™ !mµ^„Œí¼]§]o+ƒÆ¼ìŸ¶QX×4Ô¦E´•i‡@46ÃßÍ ¿÷?ô‡¯†çõïïêÞ(áZ[ÕyÑOÖ¼—ÆòiZV‡óe“ËÍÜrn¹þÜÔZ+ÚM-4±hf—ɢפM5ý5hÌ'«+ô@êéÀ%ù÷l\p’jDÍ_C˜r’‚Ý_8:=yG Ë^MU–ï9kˆG×`”ð1#s:¼¥rÇ« ÉeÁfe[©Üͧ2³ÈL\P pÖÌqòcˆ¦t‚5¬ßlF”†ôðgoI!b2yµ#kïGoýkýœŽ&}Ö3vêŒmë"å+%³U*‹"³¥[n·ÁP¹!†Ü[-6ÆPQe…¾ŽàÐÝMUÅ¿þxò“ëõÂ…æªü~5ºŸÝÖ÷Ïn¦¤ÊI—ç7ñÚOJõ.ûƒóq=cæ¡_áÏ”yÒ'ÿ÷prú©;ž|ŸhÒ¢Ÿâ^FødI¹!¯…ГIãiG±sÖG›šh‡DÇbù-±Ci鯴Ho;Æ¡“ZŒo0ê}äú±Qɯ4ý_8z±rôæµf£6íLîÒFÿîSëExÃðz7Ço=,%»»uøݤì¸<8ÒÑv9Þù¾xöœéÊcØ¥“‹ß¶ø4~àm0ÅñŽÏ2óîËy†‚#ÚV“¾~–çë<,E.4†Ë†ù¨<ÛŒ-Üú]õíú]&ŠÞ‡RЖés›á|=Që¶#qbãšüÞŠVnÅYDîÝèfÜ«@¹ûUèÝNKbù‚_SŒM»ãõ”tܯž·™ëù:Ìþùé¥Ôd<Y»HÀbeáÆ`ÓÒ;/—¯=@SÖVK¡Qþa—A¾np}prt{í¤ñ´ô–l8úôÓÁú¶~hÍò¼yÿÇü§ÅƽÚhW[3ĵów)[Ú-ËXvÎÛõ„÷ÞdÙæ¡ôн]OûWÁß{[úäÄã‡îÂU=ížw§Ý/íGõ…ýøÒfÇ%…ÂÞ·/£³îàm}}3ˆ®—M£^°4§~ÃɯïG×ÉoßÃoœ’i†DÍfljè ³g¯V74˜!μ—Ÿ÷2‡Ã¤fPl½>ƒýómÃþ9[ôupÝ}·ÌÏ·Qê=;ø¦XÄGO<ýÅ{N¥žb¦èë3n›pÞ¼k&(¼O¾Åvˆòe×bªYl1ª|™v¸ +í-·yWÙpmâYˆ6o0 ’ÝeõêŒ(~Ï¥§ÿu®»jÇ4~˜éÔ\1xow0X]jò±}æ†#Ï×n$“º7^]²7Øñáɼåv¶<Å6m0"ª’:a\ ú?Gg¯†£,ÆÚ¬Aô²ø·MÎúÓ«îuëáÓU?×no0î\Î×”è†ç‚ÿ&«Kòú:ó)pEË…¥ÇçÑÒÞ/p"œ-xáv¥‚Fr½°Ôu°†Ïæù·~è\¶(9‰Èl© „P[kË}Z=ÆIïzÐû¼|Áù2½á¬ÃÐl™i†>.ß'„®×ã!”[Ñ÷ëW;îx=ÔçkJM(àÚ•‹Å½ ¤õöuÜ’ŸBÊи¸uÁаèy}´7Q¨.íøœíkÊôÆ£ë5E€Pö-XSlœä\÷R†ÎºãÉŠyŒ#]\tõÅ´uái2¤ueÇQ‹[,-}Õœ4»Ñ¢0w£EÙq�4µ‹á´s>XMò|™ëñÅhÎÑw¶ØäæŒö£Z4G7йÈÉ™g}8 VLô¤3¬?t£³Ø’B½Ù˜¡¥å†SôsXQf z膶˜´¹r“Ë®;€ëX‚Bõ¼íèÊ°ÄEj¦`³”]Dç¿î4ül±k‹JÇ3!¹ø»¨ä‡Ù’KÊ…S0†-šÏXÎÇÂ.9è¯ ®�v\é’‚£ëÞ +ª‚&+fœß¬d°WP^W}5›á¸©Éú3K]Ü{+V‰/X{Z)k¬Ó)uÁbNKù#gÅ!|•°KO~î¼ëd>…Šã0ϳÿõäÝ?^¿ù_ßfŸäê¹f®}Ø^SÙ4Sô•©¿ë¢2äîÚ»ú¼‚eN +Ž¦—ëXfÏb.ØëÎ�oxmM«Óâ‰c£ñ›Iý|ÔC1›EÁàç “ðô—þy=zúãèÌ¡uÍ‚™ F¼á·9×Ét�l¼¹ZBÜšÕBù¸/ÚÔ¹>‡Õ5¶îÔõyëÆýÒæiõõxí€2áí¯³X®\ÂZ•Z.+•ÚE¹¬Æy&lú’Ì3kW—L8†2_|4qÙtÅ>q‹ÏñçÙÙçìù¸IaV󧮕™\ÀrÏ`my¡ËftÔ²¦FIùŠÆfŠÍ“(…†¡Õ„㼞ô?$VY(Ëž{îZ¡7¡”MÙúN¤ëTcbÌÏ›þïõàM=†|ó C@y=¼®é%ÝÄÙè}jUÉ@|¥Pà<ûJ˜Âd¶RóM^S³é«|õïú¢Ì#í”Ðô›ç/N_t'SGx!ÅrzA…)¢ýÙxÅ:£ÂïÇý+p¼_±8¨èÛúCË’h8:Je¥¥Eß8$½JµùCE9Ò£mÙ·k6n£ðû•X£èњôÙá>)Ø–ÕP”ŽÛõ²ÞqeQ EßMÝÚåäKfAúUн¾¦·?yéø—¬;®3ÇÀdáÊ& ùÛe=Ì&>–µ;Lo¦Î€zdÝ €ý®qNÕÁÃ)6Þlìóè&»v¢F6fÓZ†Wûæ>À}.ýÆ‹þš¹—qÕ¡C\6A½:ëÿÿì½W‚òÊÎ(:æð™œq�“sNMÎ95ÐätÏù÷ÙÚÎƲ±mLÓûíìµW/ã U©T*I%•(ëäßvò?ð,+Ð1*Yžt¹ÍV°yÙ}‚Ÿ04¶=v ûü;|?Я/ÿnû ,´`—_tî´ gçõñ!'DÕ3v8©õ u>ìÀtý_‡ó¦ú¸—üe`LÔP»÷Ȩ¢ª^ÏPÆ»_ +Vxßz€„YfÔ†ÁC5”°ŸÅ‘ÿÂïœ?%1™”¥°IÐPî„ø¤Î{Qú¼ ÍJaÆb‰Î·éäZ˜üÏâ,ßFœþŒÒ¨„핦šŒcõþµ>Ä)ãýÏÀÌ¢9FéñÉ\äë/¥¦Âý[š÷@Àc:ýK°„Çuþ»o³sÐŽõ÷Z¡‘t‡ÂT=ùÎt{¡FŽA‘[B€l§4Å:Ç).ÇriȦÀ–¯¯n»é~²ÞÊóÛC¯H�QL'%ä×÷,`q“ÄgÂYãbî/‰©ùèôp÷’¯>åœ/Äiï_1Ã1mu½D`Q{:GQtΓÿyŸšü¯Þ#&ÿÛwh ¿|›”‚Þ $üR9!‹‡ýaFÓ*FN§,9á·Ò$q*Â*JY›v™@uþqRˆÔŽÐTh-~«¢ä·"$¿ã*ÜÆWá䔼zÓ %îΖQ…ÚoAå´5I+¶ñÉ‘>ss½ó¾+?ÿBnÅ”X·¸«'0óÁ›´géIJ{^ÇäÿY¥×€Qþ&¼ñ¡êÓ`àÖàR€/ šÜaú¯D?âD‰8bë»UųY+±€c :Ã%}Ïh þIÛš#ô%[,rNïV¾åÉ¥«Ñ_Oì-ÙÈ$I/ÒH‡ŠÎ°¯Ð7#çÛÌJâEs:5(zIü$–VTñíæHÀz¼D.yÜ¡ÒEüä|)w-3•B$à\Ôâë`h–°Û Ë'T…yàs'R:Ÿ»›¾&~1g×fî… Øue ‘š[*áÔ¶b?[CK¥K|£¹©(0ÛûínVzýh=noJ#å¾çD›Ô â»Øw–„UwKÓóo•Ž"Vj?ñ=h¹cÛȶíûŽ®ñ•»‹ñÈ1Ö'fXá „ -hò%>\àJJdçY$fóüh£5›fO·¡=™ßT:ïÑ2KÎ\c|åùQ¡·Ä¾¬cK$nh¤â‹›9ÔÌiVþÙl²WkKò»°¢1c¨câ>¯µcßz˜›Ç¶º°Áv¶ôoÑBM‚í7Eü¹¡Ò‘þæ ÝÏ;K°èw¸wýàÚív\¾‰èy–Å,ÆBœ%r—& ›Û°p·tî[Ç0¾X1h´Y±»¼£{Ð)è"ñl@ÓJZ½®—lÔ„ÜñÃÐhÎ{>|ªP`C{èPˆ4kàôÈYÙC:…bicX³9/ Ø@SL8&} +±tÏ )(Ô+*:UgÔµ%” +0WV2O¿·&Ç40¼ƒgë¶QK(”´â‰ð2ÈÀiþùÏ×I¶Á�^)æb°€—b9¶ƒG0c° +_Z8©{.$–Q¤ŠqØIvÉŸY´žø±$¾ùSr21hcä´Q d£P´¾š]£eí¬ãý¨{ÐÑ€oæÝd{¾±$¢¹–ǦÃ͘gk?gîÖ9$¾kÉ9EO�vb²„4þ=B²J—a–fÌÙÎ¥"çóªáô[aj„<®õ™ƒg¶ZbïPHJ~ǹt¿Ó‰XJ¥ó[‚7c*±ÅbhÎåÒ蚆"§‡ˆ¿~UGë¹ëí™”‚‘äÐý>ðí3ïÕ;Ù×Q!nUï"eÔMñYí&§hÀœXœÏVtQúÙ†Ðä`‰QHGG9Œâ¶€mœ‚35oOdÜzîÓê©vùhi+¦âß9Šå§óT|¾ëPÂSdÒ±-l=`“×B°ËÔ5AAT:ЊE)‘Þè�U%�%~ûZ‡çÖ +ß›+ë5}TO½^‹ßù% ˆ?{9|Ç×—5 ¥¥WÆMšlæÑ+ÿ§ߙ\5Aö*Z‚¹nîŽtÙrŒ�Ousú:šï¢µq.áX)À·!CFëÅÃ2Ò¬g'©¤§ÒVé4ÙgÉqLZ_xJOúÚ`ÌoÞälsÒßPd;¡³¾g(�ñ4D«Û£™û^e’âÏàtWWf{4ß©íU:Ž¿?Eên})^8Õ1Þ’aÖ'¾£†!o ¨¦R#²¢ºdî~¦”k*xÊŒ>|¾á4œ¯Í`M’Öú,¨Xi‰ÝÖZBA’ žFkÖÈ>¾^Wæ°k|¥žÈç3¶T é2QOa_–æ=ýz½ÑŶ9ÔǪ÷˜ŸnOxmvFšÔíêîhÞ¸K‚?óšÇæQú*× zÁU;îM"Ü{Ø2¤åãæÍ óaÞ¸Œß?üW&o™úæþõuþc<¦À{á*¸úIЯÀ—!ì˜ä6¾Ä…CaÙ%„ 8g¿Èmæ ¦5t“`ã� +Õª›DøÓ«Ñ÷`T¯(,ðk!‰˜&?#-(Ú@,Dc/Ìù:w-ÀK0øÓ‹rII¿<ŒÜ©¨pH@Ó³køºCFÙ¾ðJfhßÁ0P}aGÒwb†2¯÷Bw:ñÈA¿÷øIóÅ93¯ T_رä÷EÉP= ¯î½bžr,RŒñŠ-ºHÛ««<ó,Ä"I,šÞ%îäàô¾,JTŠ78}>¦îœ,ÒMú‚ßî·Tw{!R ¥Æ…%…?ª4í Dº€bS…¡;üN�.“Ò}¡Fzþ©•ñEòvˆâdÐ9ævàßÐÓpÿR<MÍJ +·‰,ݯ¨ÁnÐ=s:8V€�ÿ!˜uÏÝG«ßË<P+óGÁ‚7óûTÃ6*]Z—µÄe$9ºÉ¢¤F׺9âGËÈá¾N,m¦0B•â±2«lì$ߺei9+HØS6íCAñnS‡oZÍKµ…cÂa±Ñ"ZÝ›âñù9Ô}5óX ÝþnŒ~Ô °ø¾°Ä¬•Í ª‰4 ÆtÒòu˜g4Õ _ð4¶ÝN¢d«7ð%rAD+0ÒÜþY£u÷¸VŠ¯â`rÔO‚žrL3,6]&ædUj!�fÕrÌÙÂýwË"D’À¦ÝØ-þ©oåþkµj<Åù¿¢6«tÅù®6S]£]?´m7@ÍÛé“c·Q×=Ô(¾ùn3¦Ç�—Œ +\0çS Ó<ÿ °÷ïÀ~aÉ)µãÀ¸|`É)µãT:Ö’³=´B¥–N™~"# €ALSŠíQ<œ6PlFŸ7šüݹÆ_®’†ç»xKÐïf‘wq¥�3e†Ïº 3€©�t~)£‚ÓÐrfÛ|Ø À\ã«^˜dqüöZN™Ê[*áêâ–PzlcxÅ–êD›O8Ú™0xT±ú¯V…yzУîÍmZFùé..9¯ühØ?Žm÷Í8úígÙÑ¿u€0;Æ21ç-†bÖƹOŒKoõúó6öË족Û]7/À0mœkñz´W,áæät‡RwCÏU¾£Ü¿BXÎòA‡J)ZKÏ€Þ<ã‘⥰j½ ñ†/€a§ÿ¦„W—EcÊ:ǬƸ—¢¶ë²¯Æ(Ì*î¿Æ¬Ò=pßY’Œ8};‹ÀÌšTrã:ïÎó€íqÏ +¹X¥&cg÷ÅxRàT¾jMŠå¨”•t_ùp›ïÏ&¶mÀ[´o4’“ñÒbI6Û™»¼O_Ó]Çø2æÓk8ð94—<Åakˆ‡tf¬åÚvÀÌJ'£úÄÔ¹¨‰qŒ×úŽðý0\` +g¯JÇYeç/èFÆ–ÈÍã׳—Ó8{ã`¬ç uCÞD¬0Z¡©~„àC„΃eï1Ѿ7_·`¹³×Ö«Rô¤W'ÕKÒb&¿K”í8Š #MíõJ3_0_?%)ÂaÇ2M+|¥cwð\vÅ…wvs¨):Ñ˼C�sŸ¯x¸R +iñaä+eꔯܫ5wp„>zé´¢Õº¥Ÿ“Ç+¼úá‚¢%6m}ƒùÂú²€Ÿ¾Ïܵ›yÓ’œULAèU˜€o¦>”ð×ô‰”ÞñEÝ‹m==å¾I&L`ÒH=‘»T¬*ÿ;3]F|-°ãKsÔ=Xš8ª +½ cälóÞ€²±mÁWÊÉiÝ`i¼(%�¥_¬%ÒÈ7°üë˜J³ùGV½!iM¢®×ÖR#~†1êzFš»%ìÕ¹-âûúÙp–78V¤:µ3ž^æ–¶SÍŸŒV¹%âîñÈv”1v¤õ•?0ª¦e|¹\N£Ä)ºƒ…à¹kô{@£Þtz{É—èW\éîXäolë@Pãhexà¤Lº@w“ê˜Óå;1sÿ!až¹î@Xfk8iÉ©£{á LÆ XP²-ù’ùˆ?väh‡÷õ‹[Mÿ QÀl‡ç1🔇‘�‰ôüiQg•`f=ëØ$9¶-·`‘ÉÛ“ÃIí�1Zä"„b:ëìoQ[/d˜l§ã_ñ&öм^]ê6€-¼j “aÀ°îNâû»‚‹Ð“ˆlÈ®û¥MJX/ŸYú°àõp–m|qZݹ„–IÏæK3¼‰BÇ„JD˜ß“ìΦ]NkqR£sh±Œ¸¯h+])Ĵ鉾âYùÛq¬±»°žGš”ÞM4Yº½UÀc`9JÿDóXQ�0‹¦¾Û•B.e=eÔ<>”1 X.ˆ{P—+�–Ȳos¦Œ-ÒÌ·×w(܉sA„N;0Í–Häž-xH ·¨gz\>æ=úu÷¹hô¤uI3Á!0OèÐl/`¾fvš¾/t; +ékÁsÀÚ X½«¾æ˜Èç¾7™`߉ø®•ã:Zî…úÑÚ~cT5²‚&g³ÛþÌ7ì€z¢µmÄ-y—žxÑÞË’qä|æý®NM+%K!P'}þÊÁÕ 7uÀýa©U;tÞŸÓ¤ +×Ô14l”Ë9yÕg‘;ر7ZjdRÑê!8Šº²þ)µ7õ0�UºàÎI,`Òêf@5Dõ¤V3%Rñè`™Š‡ý$g.ÞÕ ’£`A�@PÀø¹Ñ¥÷çlh‹c/íé-œ`jß™c†¨»¦Ï%¾£I I|‚ÏÄÒl¢®Ì 7xJ‰Áº£ÃR4FkÎQZ„þiâ¹è>c>¥©ÙEÉL…lÏZ|²Œ¡¸^zsaÖ +7}ø¸Häu"e<T0îËÞèðPK˨"Ãܬb@3m�í¢r³íuÖj£œØ["›mk¡)±M,Cu´bv4(\i ’„¹öGâÞS®ýNDœ©È2ئøgã.Ûo€*eâ2„X!¨~ ±4k‘Ìh¢fàiJÈæ±ÇÇ®/4–&aqxÀòWmXE˜F5\¶º°…d*Ylzä4�SH˜Å~“nV§8™à¦HC›È•ü^é÷�g À{Ä +ÉåïVq§ãuBãçèàB`óÄì>ï„=…ŠÝä+Zˆ^´^×UØ™šñ®Í)þ•¬,c›¢EmrnÒ< [3ƒ6Ö Q5‡«ëî‚XPÂl41A×vŒ©Ë#-…f'´Åž•WQ –‘ u¨GöŽi]ª~Œmw_;V‹áX0ؾ”õ–`´d$m¤û@oÒD«È™"•r nÿ(I›©Wã_‰K.1^›è'RQ}.ÈÄí|,•¾,Ë1{¶œTæçq;Xû>F«{‡>ØOø‰ì¼rMäŒÆµ{œX G+Âó{¼€nôàä 4>�ô§N£äÞ &u¥_SߦŒÙI;r1µÕ`}!@ÅŽÜI& +#aî†A¹ë®n{(®‚‰¥‹T¬·þšÌI¡ôb+³î«4#§.Œ ÆB¥FÜêQ�š2ˆ»kóC }Ôm× o>ŸÕ}øÄ\ŽmmX=Ýî¶÷‰ïÊ5öpOÒ¯| §·Ôxp[Áå¡ÄM1’<aÞÐfj©T½N€¨°«ô²µ�Æè~º|((<ˆC|—Š‡ NÜ- ÍhÍ5¼Qr¬£ãJKæ904îúƒvÞMä§�ú½kñLfHãq(†GôE_GŽs–bܘ!PƼvÌ€†ÁÙ!ê×Ñêd~L)Ê߇Q;’@%Í¢¥|fUŸ¤N5 Öï¦UQ'gEÏ?i~Žäè¤÷°NÛ«0gl^è—Çd£Ôû¡—„z!ÕÀ~¼(fºúÉirÅŠ&ÓÚ½ÏV,ÏþkZÔÀŒ×v“¶Žgs¶gô×CëÊ‹™<å'a0›F þ˜°/,sÐ?õm‚e[�ÇÝÜÀ”Úí0~“Y�D%¾ŠÌÁ +¸·¢‡è·‘ õ�å®õÀé?ÏŒ&¡‹ÂœÝÔë‡YôØ«çaîz€ˆÎ€™²ZîNÙ®7ÒªXôTàßÓíô5º#e ë p8ú‰òrÇÀ ýÙR¦JúÚ)èË"läìe0NCVcäE]BuÉômœž’>Í@Q¸‘Ë;²$‹/˜u+˜Cu )%g! yûú£ÖÛHö´ÞeëZ–qBuH‡Ï€6þŸ›XÇ…KPçzQÑ€n/ï\&î[hT4™ûÖ#ùŽŽòã¼ú‹´³õ~³½\í³G5\ãÿ÷ÿþ¿ò1–Ì7—Ùùû|âgf÷›…õåÊI¼×™,L.×{8áý,TnéwAZÝq²¿ñ 3ˆ Hòæ-çb#¤ + G)ãõ§&ºs0Vû.j +„ÿAÎ-Ñ;3Õˆ¯¹zשbÿ?žRç¶JéÓ…ãþó1b6¨Ä˜3Üã*$Kÿyü`Aðȹ’ÅÀ…öÖ¡e.tðGíIÇ"‹4Õý +>wEšƒ“ \ÔÏäx–ÍÁŸ~êgŒðøÃðg‰~¹ÞùàÏõ3ê©GpaTCب§üó ®LAøHÓ´Áµ‚k3|I]Më6_¸²~Á¯“@ŠÔð'ÕPÐmpa觩øâ|‚?ð§-9Œðbþx]1|5=S?©¾xAËH×îñ,)ƒà€p8®ÀÌGÕ©@âµ…°™ˆ9låhýtÂ6fƃäTëëÁ`]"#†É(b‚•š"¾%ªAVx"Kñ„¶çCÇM¬úŸÿ€©uŽdn½$ë¶NO"¶˜cµYîã¡ÒÁ¿ÔÃÁk|3ƒgÞt雜§Ú3 F élQ7Á×àvtÓ‚Û›õý]µŽNižd«Öº)n‰UjaÑÿ²céX§[Vça},éÐ8a{ŒöåihI„6Á¤þÐ6§c}rÛøæÖÈ©³ŽqXéµøÂåt®ßœÀ"²¼Í$["Éüˆf|@0hÅ»-ÉBê‹$´·ÙþãØäòˆ%t=» +ís>&¬g9¿ªt@¦…ìP�º“ÝïTŒrÐ9òߧ{×ÂÖôÌ”€p·Þ¢ùŽ0§KÌæô(½ZU@3‰m]º)OLzpz¨+9€¹p�å±$þŽbg2*‹O$bÅbH8¤ôXþ‡âáÿ fC4ŽÙQÏ3?’h9ÏžãÎ]a;ÕÌX™Ì5bújŸ³Ïk¦xœWð3cø¬ú²eÛZ€ò¸ôÀG6ÈÛˆQë>DcM|!ZÜ2Etn0uõÁ’ð¾Á‡¦cxÛCLÉÚ1çývÄRQÇksØDlýäbŸÚLˆc¹"è®\A°‹{š«!n qé9„´j†ˆO¤H Þ”3ƒøÈñÏf`„ ¾åFB¡\ 7ƒK$²Ç,HÌgN ñžf„$õg-’*Ÿ"HFwì#ÙÒQƒäm·(R˜èFÈWØbBÊz2‹T¦Ñ5RËHm7æíG´Ö$ÒW�K¿Ýp#ÃʶŒë.+2mVkȼ}Ô"ßóPY&Wd£G3ÈÎ×9!‡’=œfrµâ5’ÜÔšc¬¨ÖÇ4zµqÕn¨-ñ0ª¶]tc5ZœøÕVÜ©tj×/§ö|Œj¿oßW‡“€:rîœÔñUµ¦N óNuvݪýLI]šê궲W7®Íººƒ8ýèVÕ‘zº˜¿ýY\½n��;Íq >–=Y€åjhuí¬Õèá•Æ´ž¶4¶0¢1¢ãѸô„EãÙM.šÀØÿ‰TºšÄW®¤ÉÔД¦ÐÚ5å~Å©©ÿmšŽÆdмGµfRžœ5‹em§ùÁó?*f_¯4}t©U—ÂßZƒ5¾ÔZ†é•õç´.¤±Ózû£“6”?"Úx3h3DÔ¦-ZZ.mÕz j[v_ZÛw4ËÚ‰OÓÓ~ó+íf|¹i×´]‡øoA`«èÛ_åf� +ï×d¯#¯Q‹.ð¥ébèwM—^UVºb>hÒÕÜöˆ®£¾¶uÃí椛ÿ¬IÝÏh\Ö¿g;=2Ÿ8õ†Í¼¢·ëwG½Óöë}e¬§¬£@ÃÓ§Éf^_loöúºÞÔw+é©~‚®úåÂÕÓï-»þf3µúKËf°-mƒ³9°üßËœ†l©67”û¡°¡µ6 ÃÛªhø&;î®›HÈ?C(ˆíßÞ¶‘ô’>cðÇs5&Sþ¶±¤¢±¾¯éýþdfœçŽã6†’Æk,¯6b‹™É·”MîB!d +/vSú”¸˜ÊöÍÜÔÎÅ[¦ñɛ֡:Àb:m=.³.q²˜íúžÆL's8ãܘ3„va®èsç°š§ÛIß¼YzæëaÔ³˜LË÷FF=µ$Æè·åËšØZZÅöÙ2Q_t–Ÿ¢Çn¹ª«n•ÎjibV<•ý²l‡ž5yI¥ÙEcíÊ„u6&’ÖÝtÓ²©÷õͦYlnŸ-j‹~Z¶üöû`kºú„mÜom{ue»-»¨Ýëí¤~ºµGVG€Åžo[öf! µOòŒ}›ÛoêpتթÃ3׸ñ[fè(ù®„£ÛÈ €]ŽSy8EÆh�%š vMRhîZÖ Íe¢…N+„ݼ˜.kV7†}™X°fZaÙ ZÄ7ŽM±øÛgÊM\wZGq<h°à¡Cr‹çãÃÞ6ÛÓ8ÐüÜø© 1¦DmONÓ˜ˆ»Æ ¢ìŽãÛ«?…¥Ç©n•P•Îé¸Æ-Î`Àwæ:µ³mÖ^‹Žöâ¼Ú‹Ë²1_]Þ–[íJÇã:WÃQ2¹f¶%ê:YÍnÒlŽ…I6Ω˜£FÖ«µ9Ý·äÉÛÑ»Í}'éöšæ@¿w§‡ù¶»Â7îùù`v_æpm)–Zž@&sôäã1§§òyÖùÈWSŠà^|‘/{cúæÑ[I®ÞñBæ»'`õ™×ŠÏ—R#@f…Ó¾ÎbuôëÁ°"´ùíÁSþDÂpñ׃‚ÞÊü× Ú + F+‰ÿ¬åÕ,˜xú¦Àé»;ÚÂx0dž›‚_“Õ,8jjóÁcÎE„¬éü9LL¡¯¼9u‹`ôCÇõQ¶Ùâ›pèë<—Ž…rx’²&ÂçãÄq”ÒŽHÔM"5£‰Ìw›c6QbÒ[G“óÎ2ÚZ¶¾£?†É +Ø›Ÿ˜·rÛÅòGôÆÒšØñ<³¨tqû—™ˆGñB(^»^sñïiº™Ð¶oó„»ôuIäJv{bÐZEÇq±–tèCëdÌc6%}$š\›w”¡õsIù+oêk±i¤¦¥ë%øLÁ´Ë榳¦/€%=ÐÍŠé“ÅtÎ Þ|<“(Ÿ7™ö*ÊìÌÛeÖZχ²Q“é'ÛèÍâÙoúœ3Ýð¯\h¡±äjõÕ ·j.Byc©wÉ»Ãf¾º˜x¼\_FϹSŽð˜JW¨¢æªÙû)š0¤Ycñb½±Æ‹?1?òeq/W_Q2Ùûj¹4__»@?Q²SþRbˆâ¥žúf-’C_M4ål¸+®Ãk|ß*žÔA])y:•®òm!MU££ŒVÃÄ»Úô8ÂÕÝW#Ws,ôZÚQÖ†%Ó±Ž¨û–º§ÔË>c©¾¼~OæYSÓˆõò¾F·©4Îuÿ¦é±fq*6¿õÉŸ–)Vsªtèò»ÑêztêÖù;”l“™ÁO»d1úÛËMqÖ±ŒµîNbИv=ÜÓE&ëï®oUwëVß¡»Kš +=ìûbîå‰å°7NC}Sp†ôãºu·ßŸCd`׫tÿ—o:hTj…Á¡¾uR3,!ÝïáÚmnŒìFr”5bîѬ½²ŒMÎìmßc›ñ°wM´ÙiŽ4[“n¤\›Ü²åÊÔ_-—§Íy³<=›§Õ™çëÚTéfµÖ›òÙÉœ´.æ•zžïš=Ó™C]‹r°[lãþê7‘9;Köí{ó!–Nd—¥š~´Ü\ÈŠ¨ìý«²c×\m7çóÚÙ7ùו†¯·Þ€öùC–gÙŸZß²û9.³ÁW¿oš‰¨{sù9N¶dųíÜ°ÅNÝÞ…v‘@m·â©ÜÞ`ôöIÖßÏhð`uÛ¯‡\†hVÓPàˆ£%ͱ\’SéNžqÈuje'ê3BØçˆ}Ð<ÌîôŤûöòLú'3üa׳‡å«îÖö“£ Ýîé•ÕáeÖsö`ž'#Þ=CÞQr?¿·�"†71l[,×{x‚Íý™ŠJSäÞµ¢-!×Øm 7§Ôa)Ú,áÕ•€W¸3Pñìƒ +{E=ðáú5–øö¦70e’øF;!ö)n VÉb"2AÄæ0Tj m@gïzëj ¿N}óÕk±@lhGÁŽ‘BïB⦊ó‚_Š q‰3\‡ˆ˜‡ð�Ûs×¥²a(Òã)š-â*ÝÛiÔzüÊEòÞKÈ“ ´ì©C×ÙLžû]4ÑMuê©`48ÃÌQ÷žÁBh+–¸Í\ø +¤Twé[׫{z©p9Ÿý—:@bÍ¢gîÆ£eOêÚć iÏõ…¹ô�{ —�€í¹YBiDOuœ—ÄÆî¸xÒNÏÉÿ~¦·àëN‚´ûq¤i÷ÐåËí¢H‡Ú/ #Ð>’ë|Z'Ž4€ÏLwGZÆúN5î3?E{1X‹6 ¤®•qbè$Å‘:M}K�_Š÷X@²jÇmA¬¯h*–H %5ÚýÙ”@Ú¢©ï¯Ú)•©Ê¢M#=–ÕE‘¦3x]’¼x7TSH/N“ü1mNîßBˆÖô<ªÆÑÛb&€Ôyxb¥c– R—k7:>>8™F;:VûºÒÈ„t§´˜(Òax\•BšQé´„Ñßïk�\4«EUi%n +´»‚R‹ë=‚qá³’9ܔđ:;4åE¿D‘ªSK·¶ºÃKbHU:45¤$úJjt›}1.…t‚¦ã¦8Ò45,Œî…Æúò |ÕXÃÒŽÍ( pøËdÈ›ìoR<¤Ý�ZpÛ0ˆÔ,@ªÒ]ԙŬNl8@ë> +ù·ÐëN$’÷fžJ!M EóÀK!…<&èköä‹üœ¿ª¢Hk~!‰4¿¨¨R(ù=Z™Ôb}½¨ó™ÅW¯k2Š"möKI¤µUe<¥‹ê©¯½4ÚÌâH„®‘Š‚âH9µR “!Úæ(¾J¸WB[á|Bi1” +ƒ(ÒAi“¥Âõ幯?×<%´ïA—Mé×ÏqWòzR€…B;ÊÚö’>ëjDi§&×»œ(RÏ—MD6 Ç�ZßI8in#÷ˆA:%L‚Icê&f +)n3üžÐ±Ù…H¤�DÀþœîB?x"½ôAé5lôéOz&i¬ƒeù‚Ðz¾4BÀÐÚŸ¥RÖFõ _ŸDaFMÒHÃXÞ&„Ö£ó‹^i/ž§B,Zíù<™î!RT€ô|Ž.wþÍ!¤×Yi¾Š]@^õa1®«ýa1‘üFeúáÁ'ù´SÁvM©§+43ÖÝOŸ$?½ ½Ä×`ô–ø½]?·à)éÁFuæéeãyš•ä~¥n‹=§…b9ëëK>õàæêXúéj24°{~ÅõÝ™äÓ‚eÆ¥ŸNKßþÇSÅHMI=›f$¾ödô™@ãB?ý6œ¼‚o–õ]9ýÆÔ¾'Š5¦¹Ú^ì9-å–ÍYòiK7u ÒOû _ðN1‘çcÝЕ|ús-3’O7M<Vy<}¢Øn“ + ¥¾Mªø]’Os¸3Ô–¦˜n¶ŸÖ +R_ë}¶o–|šŒ§É§9<¬Æ¤)EpÉ'ñÔ•A“Aó½Ï>£_ðÔR¯\ÂÌÓ¸= œ•™ú8mŽ>ž;/Nk•oÅѹ¡gäÏX·…OŒ9š¹hÑ;\¾è+žÃ¯ZhaÆ[ÎÛæOþ±Ã{)Äš¨ÆáŸe¿±Ö-#|“jì.ùÎjÜ,Ûyìž>ÒðanGÍ hépf„£èـ۾ѪÖ|ߟƱNM@:©“çÛØnã‰Û³Z¥{ ¥, ¤¤Ú9=q¤ÎNW)XD~0>Æí+eéH"…KÞL +霋ÔY62ç+Vã ëõšRJûg‘òBíŸíizËCjêPÖ+-ÀA\)¥ýK ö Ðþ‡¤ /¼¾$‘_œÒH¡ö/‰T¥ƒúÿJ¼¯Ä.‡´`DJé¤pîóÐB¢ÎÕ…÷ŽžºbÂïÎwJÞÞv{îÜ—x“Ôœ†Évéå{®ÃwŒ´ˆ>÷£Œ´|šºcãR§ÊqЄR·3#\ôµˆ`Æ;ÖŸõñ't4Î댱em¦À‘…h¤@„¼íÕŠ7ÝK�Á5IBÌÄC41èCIóÇZ<0(øŽ€Õ-A{@ç‚Gú%÷ ˆ½˜cµHèØ?U®ÆÌøÌJìË ˆ%Ííî8f|J É2¸¡‡ +íÍ|§·3â˜Óƒ²žO@ÖãŒæ\:õ2d‹o%‰5jãÍ +ÅmÒèf�¬[´â†0Êñ£ ÜÉ´ÜbùWD‡˜ÆÓƼHÿˆdÿTºG©?’#x¿šúõøiØþ™ë!T^2ÄR>~Š?iËB!±d€aæØOJ”J »ß‰å·½ÅY¾âÈ4g¥û§÷)/Jw ÜtNþ˜òx¬ëÍÉÓ]%M,¾è1=‹ža’/zIÑ£zźÉ~öÌ% Ûdõ´è§Ý0 u†Àí±&ô†vØ^œv")¶¥f%åíZGý~׸«Õ9"ܬ_‘:×3» ¢ IX½â®bœ^-Êv=3úOb4 °4ouHLÂ�Þæ\›C[vrù|l҃ƵÃd=b!Cµöóÿ’0¨ô*½:X‚wÎáp2åÔ†)&Š¢;g—Çü<ï&)¥óN~Öµr¢nßdÇRƒY˜þéY8›Ol$£1™N@1î€Â?`@ŽègÞ�ýc¥à3o”*l“8í¢úrM‹¶,”ž^¤:A׆ãI{’‡ÅW´<É<ýJS*z6ž‹J'¹0)Ð/m¦w•\–TºwÆ7 i’y_{›ûó4_N‹«xx,¼2Mº†s’ke©Ê´G‰Jš$Ð݇N¥S6‚ÀÊ—U,^éü¼Üëd‹7Æ/]Þ=@Ñœü°Ú^A»àiJ€ñ”wÛußáe€uä˜w:ÉÕê>¦Øèü‡ãK´7ÛuäûaÆîó“áz ]~©óö_@{2bÆ ”B+º@ã±ö +y!Ç8 +¶ø¬¼†Õ6+cí“ö=C™Þ}ÉÜ2)<h-ñ÷©ÓQ땬n)¤NèÂ.Ë/ÝâŠaF DçËëa +]äM<ACN~nÊ) ¨!Ýòw4y1í9 ¡md‹ÄµÌ@×uï ›œÞ”ä±±=øà2µsÚà*y>ù §ÐFT|HL¬¼Ú¡Ò½Ó(Í/�_ZÂ)7¸êä—e¥ û�Jí}éþ\¥Œè<]áµ?C¨É?|}?Y¸©×ú¦J\±äà’~H^,œ¨á#a“Þ_Jù“Ù±’#–ò).iöPV Ö›SœG,vŠS_ZïÆÁŸà9Øþµº_{—�ת•yHä| 9¡KVØ9—¬ÀC²Ëñ5x £øµKt3‘˜ÑÛM’ƒq E¥î ÖJ6%wã/Ë¿po�>8áT‡¨H•§ÑR>V‚5UÂï£ÒÉyév9¸¹ÛùÈïÉòÚ×'þHR'sä&ÏÓpä©Ò‘›P•| íLdd²eR9/T¥ß¡QíÑÉ·G©7ÜGpl±·Â¼@þÝ|ñULò]{ÍçùÇâÇ®/¿ðFóÂuOªC*§Þá/z¿�á†Î¥z1æÊ3zá¤W –:)]PG°Ð½Z‡¸º,ÝÎR7«Üø Ø+pO 3HÎ:'ÇA{ìïù¼ŸûÜ®‰vü]QÅ[�˜”¿UÌÛJ[RþVìÉ'n/I£Ò}¼IAšü’§R‡oH¾×fOœ†ó餡°ÖäÊ]&¿çýuµ÷E€ñvß[DùûƒJ»°ùgœ +Sý“†8|ªÒ½ž† +–·¿½Ç'¡DÀXN³"RrÔO߉·Š %Úecz’h—pODõÄa"§O%Zã!ÑîÖë;¼Øk‰¦R¸ƒý^¢±³2Ý<üD£&&ÑÞžû�ÎûíÉwAÃù\¢A(Ÿï½Rpdvƒ¬1#»‹ãPéÄ´Þ"Ô<ÈYÐÜCqÅiòã-Íóä‡÷>Ý€½¯/߆“´R¨™ÅÁ</]Å&3íOÌ`Mä-!«ÒIŠÙ_F?ð's“²¥y–øo0j‚ &) óŽ2Õ^ +å‡p> HÔ‚÷×pø›î +ÝË"» °¿ðUÓk!èŸjüÕܵ}¢ßs˜t¢®^>¶øÚ-¥Þ,ŽïBr5l½¥ßËû`!°ÏõûþIl-|wƒ£ö¾Këyƒp>Ñï9Pصð÷«GD¿ƒÂZ¯p”®†òk!%aú§WCÞZ8îSXÀÝ? G‚òG4‹Y+yÁS0I]`t–.) +vßÚíO|Õ??�öéìæ´KdnËÇZËPL‘º{IˆEÊ"ciW4ÏevO〞M‡ŒçJA8 I’AÅö¼œ^Â…)n·=-Kq»C‘]©`aÂcí¹dxžtäš„½Z†+#¥‚É5½ü]´-�&¹wÃz{”Ô`„ÖŸ/ü…‡PÌýžŠ!ƒGrdW䃥ILöŽlð-ͪ»ÿ^Q£rÄÓäbVdzê>Ö³«¸µ,˜1 ²å.KĶ¯Œày†IÄ%†0o.)–AGŸÜòyw{Î dý:‡N>ƒŽ’ÉC'‰”Ê “Ì|3‡N>ƒŽ›-øI|Oëû ‡N>ƒŽ—-øA|L¶à[9tòtT¶àäÐÉ¿ÇäVœC÷4qyt¬eña|¥½Î¡ã$Ëd˜• )1m[:^:Hì¢ I¢žÞÄëÀm³²|©”ÀFþu0lB¨ýŠ8”zz{ þjÿÞÐqöø€_ÓÉoæ±+?W”]ãJ’Á?‹æ+' +O˜|–²þQ¾¾W™sŠû'ð\=ÏåDw¼ß$‰ÌÇž+¹&‰¥ÌÁ¾¼•4§HÖ$¡ Øž÷¨®o…‚Ðñc¢Á ﻥœÆÔÉ`û«:6|×T +“Ýø‘ï:)Ncþ©Ç˜Nv“Ú¶á[I¯’ݤíSù Ž´LʃðLÓWfHRÍÀËVŒ‚…=ïØLñÓ«ÌGe2k’zËè¥f¥”Ù;%¤C(ßJ1¥rߊ +³_Ûö€Xb{Ù¬>öì:{å8ÜxŽ7 ø¶!4û‹«´¤Ú%™ÆÑ”„y`/Õ.Åy|·W1ðoäñM_å¿hxN+éÔ4é$yUú9Þ\i¤KÑ”¿—1ðŠ£æi¾Stü”æñyίrbä˜ýY†èù±ó!•™ò°×¯œb|ë‡{™&ª¼“‰ö+Šñ¿x¬Ý±ñ2‚Àz‘L.eºì“Ï÷ÙÌb§zUÜo)Ÿ/'�!`£æ¯È" ÆøƒÆ²³;£ÀØc-¾ÆÞ2£ØØ“ ŒQüˆWG£€qfOÕP–*÷«¡¯×—»J#>-`ŠÛk'ƒJÖ% ³Ò$Œ¸'¶—Ë‘S½HsV°åIuHþÈÕ“y%£Gú.O¡üÆÄUÉ9;#Rœü“}Ͻ#b*ÑšÒ‹¹'©#u]Í¡e•ÎøÇ|—ÔÇ~²ï¹w¤Óì„D¿¦Óê…§A%0%¤YàM¯I¼|dÐ(ü÷‡L“ø“ùõ*&C'§Ò&ÉG§¿NŠ“k’ðì»ÀÿK§$ý…G&Gyd>ŒRš°VG†Ùã{‘ž£õÙõŸxd8ö~îs�`”‰îx# í7™§lÁÏ=20 Mà‘‘ÊH}•Ÿç|Ë##êçÏ)HÏQ–œSôÀ„{ÍÉÊÂ÷`©”¯,çʲtܸe™7,Ì Ÿ“xÌÿM$_Åð7NÐ5ŸñEL¯’4´_°sט@&í]z#}ì)tA4[ðU^ÝÛA³ÏªT^Âx=Ù¼:Nê¨L¦ðk'h^ö*Îìåè–²¡zåç³Há=…Ý=ç]*0éoòá –¿ˆ©“χ{ÿü±ßäÉEA—w÷AžÅùprª—½ÖÎ@ùp"'‚J&qý>Ž uÿÆð×ùpÂsG錸¿Î‡{yJÀŸäÃñv¬„Zþ.Nh‹ImëÀL¶Ï3ëá÷g1‘�?&RJ·TÙ<(Š‰|5÷/âS5 NH|žNÁ±¾}…p”ä‘HB¡õ1 +Îdr=E2ÈÄÀ¿–h0¹NÚ!öïÌ©e#ñl8™Ÿ"ž §!˜„’Þžvó“iøH>âx>†�˜ì±2brLrvŽJ§¡Œ6éýž½(Êhs0ç½é#‘àüI"d¡l{ GúH`‰Ó´¤Â¬Ÿ~yß+-8Ñd}öaÁä3ùƒ^ÔlF*¦þm€§ÏRÿ*#u¢)H"U˜‘:QO•¸^¤úýIFjÿô7©Î_d¤Â|±Ï3R!”¿ÈH…p”-0‰Åâú¨ "}hêÛAF&3úüiØþx +RáÄåØ_§ÂQñü²=‘ +':.ž +÷{¿%Ÿbò¶ûvå©pÜ3ˆ¨d¸ÿJ*œˆWá¿ +'îShŸuäC®(àžŸ,—ø´’ŒUUr"<_‹Û_˜EJ½ (—"¢2&}²Ý›:ÌÓ!Ãïn.p²Ñ; +·päNç¢\lÉ{`yÜ,Ì«ëK‡#\îÞQ‘åá1aÕ8«>f¨—¡Ò*½mNF Íü–Lyµ‘aª*'#Ž«HþT=ìîPeÃÝä9Íõ\<fŸÅã1G!¨ïË‘nËo2ãqâçb‰eA+‰ÉQêIçy*¾2—½øÉnþY©Èu>sºVf]�9HeØ9;m¹d·¹C)šªÇä2ìt¥uq"…t,ƒ4mór +s±|–Ç'Lvs¶W¶2¡ Lm”KvÃì¤üz|þT†©ÑœÈ[_*Ù'—u¶“Ï°;Ôë’Hõ…Åj.…t!_¯Ò–Fšüê¥%É«Ýþ‘Ò +?ÃŽU0a™^SWŸû¾ç{ö*ðÞtöŠ :Meú=fé,"Šè×ÝJ +¥n[á‚*ç;VrË×`-{º/¼=¢²þð7©=¯#T…^é:V'Mâì‹É4êUpê«8ÚzýËJrbeGDÎTQà]’«$÷–®—P"ù"’:ò¸¾WEädãú”óÓ‹"r’ý«ûöªØˆÒþ½®5 ˜è¯êŒÎRû ~œòù’^H"’wUZ€NÞÓû›lºßùaÞͦ³îµ8ÿ.›Náù0fÓ‰ù…óåól:±\ºßf>JgÓ‰ùâÅ#í?ɦ㑅™³¢ç}”M'êÅ !¿È¦ûåŠüf6Ø> »VþY6X.×Þÿ›l:±\:…±=odÓ‰ùÚïØÿ.›Nlt)OïŸfÓ‰)7ÜØѿɦ˥“8mþƒlºç&4ÒšÒo³éÄ”S•î¯³éÄÆO$êÃl:!¨—5…•M'¥[þm6rŠ}’M'�%Üÿ£lº_Qìíl:Ù«?˦Ïþël:1��ËgÓ‰í–bàÿ ›NL<ð׿Ȧ{±3òGÙt¯×—¿È¦#ÆCÿ«lºW™\“M'–K'YïsÐö0�yõÅÞ:ºIºŠ×s‘Jam…‰O§“G|çAª–ÍïëÕ=5é +wyþº^´v¡ŒNW‹á-:=¨Ä‹„„9™/…,ÀKPÈz–j” IJE‚êrü©_5 R4ê²ËrM¤”02t’)»,!2á*Æ·ˆÂXî"°ˆ÷ø¢°¹¼gŽ–%Wèîã2wœs®ªä¿)s'Y].¯(WIa™;©L.e‰tŠ$äã“…î>«t稤ʌ¬—JQ™»—EH˜ËÜ1:Œ|¡»ËÜѹo/ +Ý)Û<:æÿàœ+"ÜÀäQyžEþÏB”Žù‡Êýë\е I)JîòÀu/c_ñ'L£ƒÆ³¬^Q"’ˆfÕëCé Åù…�‹LØáAd:’®?>'+«°0kÂ|"xhªdŸÅΆ’ÚïI—w¿LìâEC¦z®8 +€z?¦8 +�SÑ-ØLɾ?É|ü|+V”9œ}…pÕvƒÂ‰ìªýŤ <e²‹f +¿Îe§€)J¬•ª!L¬íŸkkû¿;û“BÆÖ*fܵK’”u1R¾¬÷*Cm~ÞÒ…™xÏÔ²–¸Tõâ²ù“Ìöäã÷5‰gP…Û_U0ÊÒ[ÄŠç~ãBÕR»o°ðÚÇê E.ªó 8pJ� çÓjÕ4”û$;áð½XÕ†‚D†·vxM‘iØTÈ Èÿq…»{~¥T»_LC‘àŠßÖ~¯Â\æãÓðÎhL…»?©”÷2ŸHY¥¼Oó‰ØJyŸOC™ +wü¼$%ù!¿©p'WïÖ¸{¿ÂÒSÍaöÓ牵ýÓCÍ‘²^'Ö`¯Õ•E‡®M÷»ÄZaæ£ëSÿÌ/,Š¦C¿wÎçróéŒçOò9‹¨2[ì%é\XA“êÕ1T¹¼wòÛÅ’˜¸»¢P@XŸ¦¡Ïøb øµîuߦ1)Ib2‡BK”³Š)Icâwò…ïôŠÉ4&ŸQQ†º¬ÙÎÎJŸQɬT’Ädî…Ê÷oíÊö[ILRD°v¢ÌJûžbØfrx?8•_ Š–ØîÐ5 þ"Ç5n—>UÚ/ïV¤{«Ü#EJi}¬ówGSu¨Ý·?ÊqíHMõ¾3½¼UîñE¥<Ç/s\9ó“ ÃPõü:Ç4IqÖ³\Ž+ã‚Qp‹ã»«~0ã-¬'6X<æȵšE®¦Ò%–Z=x[Hp•.SÙ}©v?5Ç !u‚^x(×.ÇwÌ\ñ’ð¾ÂU.R^>œJwÑ4;e®«Š_‡Íïu$òáLÒIxçÛ؇ñe² 5Kåþ‘»jH%áõ%‘‚¾¨SGB²¯hZÓmH"5d§ö¥T6Ó)›Éõ pÙ…sòSÓ.·þQGd9šŒáÞV©J ,¬9ÇKÛsÿ¸äÍÊHIÎù•?|°ÂŒ¸‘Ò´–”Fš®hºbH©ºož/µRˆ´*WG0ß”FšL6R¼È.€VŸ[Ù+& óf:ø£/ñG%ßãæW¢c³/ª�¢Åw¸&Ë$èsÇ)T:ÙÍÆÛÃ_<ã2~bv¡S6 ˆê2Q»A¼*f¯'¬Í�vP˜ØôÒC"’ôZ%Ù$ÈÉÒŠ+ImzØtù«Ê,”C÷Ee¥ž¤„|h•äÐ=Ufjï„ ÉeÝ Nžü +íE„&M%•2~lz½Û?Ök óîÞ®²(Ѥ§(-á|QLô·¢´T:¹FIû‰ßk–ÒqZL{žbcâ*Ù™ù›×Éçš)¿3%�쬂£¯_ø`‡É¿:¼±cC”p¨ IÖ½¬t—g˜üä$ÚGNâÓ‘q¿Jvß²~ë\ëaò—žeþ)š0ðÓChÅΊ“Ì{eµ<Ÿ'c�‰ûÇøA#"[¬“Ô[õ¤%LêÏläIJ(a~»ëM'ÜIÍcjÇêuù:^Ë„~þ×.;ªŸ¤WÅyz + ØxÎïë#µŸÁ¶ôæà{‰dOõ,>(Ë&ŸÉôVŽ•÷s8Mä¿ÌÓr¾ã—Ú8¯IœP}f·š3kßLÜh¤rrϹ’I|UÒøÅø=vÞçé׉:Š™AP×X´ÊÌÀ^UÑ1³ke€ V•Ï(ö2—Gy'ù;—Rìe=·(Vpö%€=¥‹i‡Å~™¨4Pñ9$R bŠr�e¢Ód*Í|ö'¿“¨4{ÂáûY€Js�)¯õ¯³�y¬"ca +ã`ßËTš)öû,À=åå?ÇêÝ,@¥9€¬ü«,@‰&=å�r÷+éö<÷êó¢|Ê+²}R”Ó—ÿbQ¾'¯Â¥(ß«ŠlS”ΑWP>/ʧ҉h…^”ï¹>ò£(Ÿt}ä¿,ʧ¨~å'Eù¸^Ø(R²Q‰^¥KWõûül¨Ü_œ ¥°®Ÿ¢³¡>®ëÇéÚœ %U×ï½8¥ßÖõ“¯ê÷«³¡DêúÉ{…Ä-ñ÷ëú‰3ŸìÙP¿¨ë÷š“ÿ¢®Ÿ|dë¹ú°®ß«L®?rèÊVõSéÞrèJÖõ“ïšÀwñëº~¼†<UõûEѺ~ò‹PýM]?ÑtD¹SÍ•Fq¦¬èYп¨ë'ò»'þa]?Ù….NbP×OÞ-üÖ T2uýäM]Ñ(è_ÔõK“|L½ÏêñýAÎû[uýä¡@?ÿ_Ôõ“ßPQ)†óIâ»0#õ·uýDTMNU?nuôƒº~‚iˆò«úñÎìz;=eëú½Ì{ý“º~òUýXNþ°®Ÿ|À5'#õ£º~ü-1^œsõëº~ò¤4Ø?¨ë'3×.âêñ™å¡(®Ç÷¢œœâz|Õõc¡ˆNŸw³9žêúÉä=¼Œ¶]¼[×O^“‡'üE]?©5¼ù¼“ø»ü-êü}'ñÕ4|U×O~¿™Eðûº~|jÅßÖã{/HCºßL¶ªßçõø”$1½:½á9Vã½R|ÂŒÔÏêúñÛOUý茡Ïëú±©RruE?®ë'¯æHðØÛuýä«ú}|jS×ïC_ŸÂº~ +ò^ÿ ®Ÿ|U¿·ëñý*W -Ÿëúý>žSՃ壺~Ï®dnU?©SÎÞë'Þ%XÅ~]×O>ÐIàSúu]?‘qáTõ“?Ny]¿ßû-ù{?çI®ü ®ßCp‰Uõûuô ®Ÿ,Gp*€|V×O^1¤×ÏëúÉ'Ä2+òÇuýøVõ{ÒÇŸdůë'Ñ:Ì‹“¬ÖõS¤Ã|\×;’Ï82ÙµóS¼®Ÿüâ ›Åùg ±ôºïYºr:Z©!ñ!<WjEŸ¨(X+Á]i×®|འm‘ÇMw{ìÞ„‚Gn<í›bPy+¤ýð ê(-H–ž_<K´p¹oøe…€e%‡Xz_ZÔÑÞ¸é—`>¢-†²vÔ¸G³ÞÑIœW¹Th;ðVf£mg2ÄN14³üŠjN·‰ô's\#:—ÇŸÑK§ªë´éôT:·ËîœyŠ©¶=o?#®BÚ9ŽU7ð¼V$[«úâËujßÚVÔäLü¨ëÕüÆ· ´‹°q¹OºsdO~!¯°AKӤ͚n+MÏyè/|Ìܧr;Cz‰Ø-Â/OMK€0DÐT,CSß³š&õÕóyì5ž/žVö¢’Ó‹kÚ+³™–uKÐakÙ‰‚W}O{ûqœ/ý,6çÕйÕÏ2„—_êïFÞè¬r„5[Ö“¼19)äĈEt÷ª‡ãBhɾRƉaQÖ4»õvv¤ô¸syÓlçÈf’æîÉ¡ÈÍzt~ÁxµâžÊID¢©z]‡jsÊÞ/ø*ûQ0}@×ÊqNÒÜÃßÊékbt‘ºøM¥KtS‹6U@3>HWÛäW|®Ž8®\Äq™ûS^ͦœlEˆ! Û>”Þ6Ûýh†D¦�NótK—Ï4b–¦2v†9S½Šî“£ùVkdI6Ûx:\ÞÚaÒ®•6ëC®Î™²œPÇÕ£FWZ;\vÃý +3R¾c@÷üt›©¬_ p²Gð3h¥$ŒÆ�V±Þ܈Û囹$^ô�°Ô’°ên)c&›Å¬†Õ.9Ûœ¼¨#ä6Q …`æ8æ¯'<Z8&ÚxP¥»?ŠÛðX·¾?Ȳøò\|6mvu'Ì— ˆŒÃKÔöžåñ²J‡¥‡öûÈÆ“>úPxÏÁèG®/fí°YÀáOœ†=êXØýÊôˆA ½bãø`µ¸!d„áV;ýÒŒŒC8‡±Y¦DýdÀκ=Œ«NÊâ(Ö6xZ·ROqé›ß‘Öíw,¨IëAñmM—´zM€;Ц–kï̶ÍOþ#Æå :hfÇWå@ÄšKÀÒðŸÉPÃùuæF8ëb¸©[C(VëôpvàÇ„6§F¦^7Ýæ›{×[ÖÇ€á‰LòtËN“(ÑÍbp!×â‰YÉÅ\m8suë ÝOš&#æ +_º bÔ@ˆ];Ì×8à£m¥¿Ýªì±©Ír[ç´fìŸÿP(Šu쬜rú2n!q¸Òøa˜B5¶µ/ÍÑòì»Èg‘ÚC°›9qÖ9 çø;‰1BwË.îí8¨nz¼á¤ZKèý=s•˜¬Ù÷æ½æ.*lM)^¤[õ,Z÷ *]rj‹´àb âÙ˜¹=’ô\ä«üM`=On²bíYnÞW1(9rÓ7(ŒÉV¬˜‹™¶gxH™‰%Q{ýYn +˨Ž±æ¡Ž¨5±{|@ü3Ýho,ô¨ÆÚÃêب펵º¬'´ÞÝEö#Ç€´¤Á)+øé4QiÎX²?}¬!(¡|ø>ø¦ EJÆNéu0ôÆNy" ‚ž†ŒC§”AEF>Èaìë æY ûñ}@ófZ†Xãº){ÏÊÜk`§ó€7ÜÍL|¼‰ÎyRµ€¢®iDãJÃ؉¤ôäe Ê>€ s –Øõ~ÞÃîêYÁÍP"²Q¯�K®z?Ž;l(Kak€,}kZò¾�‘jSÌJ´†÷´ÃÀxW„j©‚ÖAÇãç§ ]¨]Ž‡ZI݃§TйnŸ�¯Ÿ-\5‡×8�²}«`jŒÌt\_õ +Ìï ‰ÂÞÓ€{žeê»xŽ£jÓjW ”dTžÜh� /4ˆŒ>ÃÕzÏ[à‰Ô�Eü‡é`a²f,ðÊÎÞs°÷À¸Xk'¨œiflßå¬bú‡îkfï*V¿kW@)›j«} 08ÓšÑÌ‚;D7áEµ£a-r„>‰¢Cé™LÝîmã‹kƒ€¥“—˜)o¹Ÿm‘ØÕ? ÐK + µÛ¨iý|è“á{§á.m¿a…—*Íõ½5œ3@ÌôÎÄ”s KS¼;Rvì6¨ä:šC.ðe…"|Ðå’@PºÌø õÄùD˜¾D z[ÌÃ)f5¸Lí\¤Œâ?$°nµýÁýmäàHÒD8Ç:=e|@ÍO1ö y@¥Cœ—žž%B[†à¥w*öÅXIÀ#N©s”çÆW¼½ÄRm€óEI7Fç_vãî!¡ÜŸuc%:± g¥\7Êýãg<]Xi)�¡Œ�Äâ"ß �À¬¥8ù"?x Èë6ÈJ§³š@Q¬³{€@3ÅÎŒûf§Ïòo‡3ðhjáû\Ê»yŒ:ü3[\?�l‘y¬¹ÿÇ:)Sbz~Í ]=ucõ!)˛ۃÇ~¢3R0]Ûwo8ˆ©´ìSÖ†‡”4ÅÞÎêõŒç¶ôå©›G£³¿ Hy§˜ònœ_Ì ±6ðrB›ú3Æîj4¯WdüÒ€@ÍUb:ýíÀ®ÈÓÅé%^´a%1?A8ÒRŽÓÍåSi9Ý_¬D2ëÐôt“oÃki9½!ÜŸ3š÷S¯¹{:3´ ·å¼··±gv‚Ñ·ŽæmÄz:k±]¢•@ðÍÃSÖ†É1ͨxŠÅ5â¡ôRÖ‡3äX“í®O{@ÁŽ‹Î{…V÷È +mÛÝ[Ù¿ÀŸ¬.c`¯Œ´a·¸l 6ž¡í]¸ño¥¬nægÜn§Íí{L/´°Ysœ7±»Ùë4²ÎD×y齲ν¼…û `a݆yÏ£hºYLþo@hýËè_ {†qQ¤ƒæÇ=®w4·rð¼£é¬:‡Ì€v}mk.?€wÒUŒúI„øYŽ<`·E9EQÛì…EŒ2à> ´ + µ—Îp¾”KèÛ°'-øÙ Àši—ˆ£Ü#XϤÅÒ4ð© °¥¥Sx¸nÇw,c@c²kK8&½o¹74TºT éüá¸×iç{º]án¿ß÷àÙÝ"/hã>.Q§ôâý¤K +¢)ç©x=éTÄ°¨'²ó ÂXÕ6vg•:×ágÚŽÀZÉxˆ:'Ûõ Àrõ26-Q.+ã^Ÿ6Œ“wÚF±i!kW=ŒñGM‡xÈ›ÅÁXM'Äýjî¤=ðVfh7U +¢Ú"?Ûw§Ü¦‡Þ¯†n›â†p!Ä´f3'8†1bü’Å“ŽíËfGRVóÿbhúŽ¯ÈT)¶õh<bžºC?tÄöÃUsmÛY¤3*â2Ëuˆbi,bWì~5¸€gŒéúã|jëÚL™M!¿»iSSã¢ÎK;Cõ£‹Í¥-.jîHf.¶Q e¤Êûß÷²{Ã?ø¾wPì¼¾WþÁ÷½ƒbïúß÷ÒœüžëŒþŸÊí%\ÿ¨?Žêm»8—ÎëåzÿϪò«Ñ,†5öóCê¼XÔÿûš8Ìn»ÅþúÏ÷ÏųY+±˜æ‹T0“kìfņáV†¿¹[Ú<#å,%¾½éMFS Nßh'Ä™´–r¬Ÿëê'TËÌNª=ÄŠ§jˆ1s±ÂŸz•§‰$º±JI%³&±8ÇnIK±ÐìPÎ︞ËC²[T#ŽË2àÈD»ùD7Õ¬EWôpwÂýL^ô�g×[d“(2W=b +|9›ÃЄ›å ÐmÂã@¬¦HÞÍ!–Šúöï>#¶(1‡ZC1Ÿ4@-›œ<\Q¡Ç-Ì”{,u©Ñè>Üå%fUôþ1f].CÔ¶#/áô£v2îÓÏAý„!FæêgA)&F0œ` ™Œ…ùé3ÚhE†v:Ãbß ßõ>“³èc÷‘+ÇßØÊ|ldªt’[™« ô6ð‹û¿ &PayŒ¢ðßST:ùeýoÔÚµâ/Õ è°ŠÂOM€ŠÎ]Qøï© /¬¢ðßS8óeößSTº‡¢ Tä#B˜(Ä‚Ojq`Ä¿yºASjõL©æ0 „b«˜¾ºFFnÞ|e(R3@–†ëˆi½ !¶}¥e©®Z¡yEX°C‹:0i¢FjÂ=65kGæ¥ÉÉvüpl¬†¶þ€´´0Òî°p¤%³”pCPÃ¥eÜn¥NŸÆ·@Ö±n_í´â±¶ú,TØcÉœXÒ9°»¾ò‚ч�‹ûü´0S@ W©h RaËŒp;cÛª÷)¾ñ…>t®±—ö™ o)e„R@=ôn>–n=¬Ã¨Dé¥RìËÎh$Úˆ#‘P�§„Ò“#±Ó œðÇÂÉêaÃX;‘@˜?V_ŠŸ4ØýAIU:,-9t 6ayôþ¢»¿8óäû‹r5²þ³KùiÑiNÛ™è}»-x¸—nâm„ÚŠ Üèí¼PRƒèbÚÄÄLÿ´“sp�`©v£6|™€fÚN§TvÇ:ÔHRÊd´Åç÷{ÍÓý^çìX—ö–G År<uŸqðÝŽJ]~”ƒbö=™ãõÍ‘–yrß‚¤ôhf÷M¥nBR§¢ÿ~Ò$¶û]BŠ÷ß°]uÏñN„Á!µ+ÌÁéx¶fÃÙ‚¤NÒ“"ÁÝ…ömöw"˜[¶·¢ƒ×Çö¼r·+‡Â¾òUÁV4b(¶Í$ÓT¤öÅXIf7›I‰�Àè+äÆ'TQ7em CsžAP©>éÀŸRœ-í7ºÑð9Þ +xž•VïÕü OC“Ú"�ÀPL)% n{Õç}n’f=ÆQÑn($%¡Ä(�u:³°¥<T:ðpâ¼ Ì~óf곈ý`ø|22|Èc@A1~Æc§ý@’ÇdA#è§<fX?ã1to’à1Å +ëKá :Á籡ÛþÉh�{>è�xL)ˆtAýzºŠ`ÂX¡Â§Xö‰·ah'%lu(ùËÑ� +æË/×Ä|ô}6P«•'%µ¾Èu#cK½77žÚ@0¨072á*þ¢ çã¬ÈçÕÞp@L‡ºÏÖ€éÒb¹¯È²iÓf*A˜¹/lÅLë¶}Ä3[ÐþYpâ’mx––³p6Ìý™)E¸?+(êÂŒ”Fù(VFµÕcCfÎDØ2j'n“t!>ÈQ ´‡Á¹;žèÜŽÖ.i¡ Ï‚Iòÿ$ÓBAžè/Ó‚õž~¶‹)ØÃäc9Æ—ì#Á�ô·~™¹÷FváËÊ}°t² д&c@ÑöPš@Ƨ¶ ÔĆ?+\Ø`¢AÊV;p¼1M¬Ej3=™ò]ÅÁd\„³´?¹Â€D%8NÉÌèÌìG›lNÈœuw—/ñ+ˆØ§¼ +œ˜ý§=ÖèÇM™Tàí�n!¢gˆ•Bð±5ẖµ‹ô ëYFk7í:Ù—á6S{ð/>¸ #Œ£3$X¿¥“ç·L„Ý,³´lL’E%ÅPËqgü€=@û´…Ý]Q-jKn=´öÊIHúw$øÙ¥¬$*çbF |—Ýõï¢ìÆͯÀ‡lC—à>Hl´w—äëÞ—.ù»$™ÇaJËÀþ@JèM%HÔøÓiéíFŒº†W8÷ÍâÒ ï9ERl*©q³OX<¦T*YlzîžÐ]L}$äO;ëÔèÒx·R×à/ƒPŽ½áü¥cPõžkð—ŽA•î-×à/ƒÐ« Ð5xø?!•_¥ƒÛ”£ä~ÎÝ¢TétàNmq½á®Ql±\ï“ÿYœUØ?úüÿ‹»à(ü?úÏo¦*#õê?Üô¯°WéFŽèùšXÏ®ëÃ~rþŸ>pûçˆÛÆh¶–jýKþïãá|ýGÖ\_ÖÓíâ_ýð/^«™àöèÈÑ.ÙÄ?ß?öÀöï1t ƒGô{rp¹ð@ÇG*ô_üÛþ_ OÔŸèü,©P¦wàÑÿ€9pñný¯ú¯ø¯7@ÿÍágU•Ëý³¹Üä¿ÊFzéËuI:Á|Ì^0cS€ÇØØï'»Åüßò<™¯á–0i¢ðÙ¼(‡¶ôßØReCí(øîùg#Ôµ^v¯×ëúÇ>t¹ ˆ¯½c> \àæñJ½ìÁ]Ä¿ØìMø1Åð©>ø߀\±˜8#PH¿ÿCjîÿKNšLN'$'M1Ìmw{5]N_PðœN†šqÉÒÕ†¡œWèѸNý‚pãô0‘÷QrÁçЇûÇ s$5fqÄBÞ9ø›uÿˆj" ²íþ¿Ãûrxq;¼N–Àœÿœ¸›¾ àá.fPg*·ÓŽó†”ý„úaÍè!u{©7™@' 🙊ÎßýU¶5³ÿ;h2ƒVˆÑË)X\©%Éf{±¼ÌÒ +Ù§åÕõ_\^]¹¼¢ìÊjdz{'apáñ„Þ´v{©;à_œú·=Q¾;=¤÷]v‚�4Ûqî˜'\`r�~E=ðê±c8ñÏI:ír^& r¹oÁH·p; §ó¢ð5h™°¼Ã줜.»Ç§A¨^/e ßõ�¯¡$ä6/n÷à^¨0ùèñ`;3N vÒåÆ9o)êÁœð;§ÝE`Ä?Ì‹Ù]¤ ôºí^õa‰þ8hh¼B#]vÒI‚ÏÜ ;¤Ûõ6Øã‚“ÜcwcN(ÝÀ¥�Àê_üƒd½nðŽ"ý×Q'À+ûÐOÀív£Ebv·“pÿkªÀ÷(5õ1�îqâ�›÷ 8ŽÙ —äܹÌLÅ»çt‚IFÝñô—@§îx™;$‰c÷ïîo¹Ý|ØÐ�þ¯@æbóxí^P‰m7ãv—óÑ7Âéµ»<`Àã +^ÂîtA x§’ˆ†ºXR:=€©Qþ ·Ó‰ÛIðESõÈH¤‹£y9'Æ× ÅŽ¯qðƒ À@µ’�²€å'æ±;½N.K±·�3²œÇÞ|ð§%ì8b6&à!1°`°ì¦«uBv¿Ï ÊA7îæLtô�^_Þ'Á"`'! ꢔ7U™1âÝ£F’ºã¡×j°ù7Žàߤ‡Šb®gÙ�6%‘QFºÐBHJ@I¨Æ€^Q°ót…ÌÈÞtžÁH/œþÐSŒôpnQó͇½Ià`ŽûXh@Ü€[à½Vö{ôsòÞC Ã17¼€€!ŒÀºp�íº \€ áM'JÚ½8f +¨èr0¦ËŽpíQw3š€ @þxQŠ“Àû@ÈxI0pD½àzÀ§„‡¬@€ÙBð3¢z‹bS'eÈÖ�/wÐxÃ9w8ä¹ßc©V»×Epi-2&qUŠÀø‡¶ÜÞ^[p@9Ž°ð‚&î¸7ÁÜøþá$iG1ÀX 'Äÿ_‹ë4aø úY"Á@Çnb°Â@E7‰¨ ¡¥-¼>ÿ¹µ}V¬JµÄ€„þú.öŸóùs*i°Oj$“¨‡Ã0eø°û˜v¥Oå÷@„yMQã@å‡D¨˜µ©%ž“æåÇ…ÉûdËEúâßØòß¾¯Úâæ¶Ø¾âÐNzÉWº‚Ø<_˜ëBó½)ßF:ð{?Ncæoí9fBŒìp^´´c˜©L<»@½¶±W,ï+t)"K%h¦Fåã„>5ˆ,(amLt°dÎ)öÐà)›œVà³-Wz©Ú’ÆDò•Ö 6ÛÄæÛƒà|ƒþ¡ä¨âôU‘³L<!:€ƒŒ6'm-b_æ¯ZÍ]X%xæ*SÂÚ˜è<`ÉœSì¡ÁS69?.¬Àg[®ôRÉ%‰ä+Al¶9ˆÍ·Áù](¹ÍÊœÝ:F77#Û–j€x¶ÿàðïŸ*íÿ"„’˜ øVÓ¹`ƉfèÞ¡ RÌ´àÕ 373©OÐcEº•¥‰oDS©`Ú);!RD¥¤&j-÷7Ø(T8Åà}ɨ•2IJ°RŠ¨Rä• ´Ç-yZ¬{×LT–tµ¥GŠÃ[ Äž§×IcŒ´7Ö0/†n,›7|ùbØVqo=õ‘¢|îwÃËÜ~ ój·ï†¢ÇéІoüRìæa˜æ¡ØL¿¤ Ä /ˇ§ÇÕ!Xâ endstream endobj 251 0 obj <</Filter/FlateDecode/Length 934>>stream +H‰ÄVKŽ7Ü÷)tiøÓo›I•^ä�NV ` ·OQjµúÙ0œ1螦$J¬"‹z/¿½†—w¯~úù5¿¼ÃëeñútPÈ,ã‰þúüñø=ü}¼¼~ ðx”Ox{`âWLüùv| +¬s’®ArI¥‡Ç_‡Ïø[,1iˆ5aÜüCN¦5”–JïáqDµ$ÔB«©·Š0d81åD…ál©H`îÉÌ|=sKÔ-ðØÑBäš“(ÖI™:ŽÐŒ| ÀIrNEËm œ¬v�$á\é–ªÔÀ¹Ž�=2rL¾Á2€¨P*†]*à£8ÈʈÎØ’•à;`Gk à2æÿõù\pQS}^Z굆®)Õ?X*±–’r>,KÄA5uk—Iã´ù œ)2·…˲Õm=ÃÛ+”Ý6ÈÆw³à¨ÛHRî@¼b‹ä“ìð#èÓIÁ„Y[b®“ƒÈ VÕIÂ$)Š S7"£3% 4,²‘ßž”oå#réIPWÒ"gEWf± +¥–±ÁJ>F4ñ9+äñº:Ëh¯Z•½ÔšŸ7‹12B£.îu–kôz^Xg9G -ºë="d˜ðjˆçŽà…R³çób®|à*W².ëLæe{²iUÒøãxpð¿!Ü-X'£5Щ ºÖb[±Ì(1ñLK +ÐÚ]ÝËfåT‹Kê²ìòŽþ2’Iûs(0©kf EëH¦Û€í¬ÎdÙ’<ˆìv¯i’<É–±„§[vÖ¡šfÎ:µ”¹Î<¢“ôQ ¾y’3ÊÈ°r餷FX<Ü°êúâŽáÊÜ ²Õv¹hˆ_R7‹;_5Ò[>šÂéõJ„n&VßT’—¹ ixµÿ|Ù.:¶W�rs}® N{tó{M®O{ò2™qöiÓrÛà6E_ÌEò÷±ŒÌo0ÚûW`äÌ3” ä†Üaø®Ï0pìÿÁáµ@‘}GûIÁáßF3Kn>ßjlŒRϲá-™ÒÒ§ÌFtŠ³¢ƒ{‘!èOn§zÆMy\Êevfód^ÜP±úsïóFȸԣÿv›š!SåÑ,/É{çE—¼Z‚Hºï®+g¶ñ³ø C£÷϶Ã(õ²Y_Ñîhþ€#ÞÈ*â3Bä<{ 0¨.Œ–7dá-ÿ»ÐǬ÷Ç�®øÍ% endstream endobj 143 0 obj <</BitsPerComponent 8/ColorSpace 144 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 64/Length 677/Width 64>>stream 8;Y9N_3)VX$q5pboO:S*XkZf?Wh9[pEB=P!#Q\rSiNQpYnTp=h^*K5=p=rj61g>-l F3A#,[q#H`\'F?-Z$U8U%nccCHaL0f39.+/YP?=9>12o#eBXraB,*c8hTo4&U/^er krIOKkCXBjK/"UM!erHAW\@9bMD^NIe/=-#<oB^15O\Ae#gbQn&ha#.o1Ao4BV\OH @@ -1073,17 +1044,17 @@ E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn 6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1 VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH< PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O( -l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name(Layer 2)/Type/OCG/Usage 19 0 R>> endobj 6 0 obj <</Intent 20 0 R/Name(Layer 4)/Type/OCG/Usage 21 0 R>> endobj 7 0 obj <</Intent 22 0 R/Name(Layer 3)/Type/OCG/Usage 23 0 R>> endobj 8 0 obj <</Intent 24 0 R/Name(Layer 5)/Type/OCG/Usage 25 0 R>> endobj 33 0 obj <</Intent 42 0 R/Name(Layer 5)/Type/OCG/Usage 43 0 R>> endobj 51 0 obj <</Intent 60 0 R/Name(Layer 5)/Type/OCG/Usage 61 0 R>> endobj 69 0 obj <</Intent 79 0 R/Name(Layer 2)/Type/OCG/Usage 80 0 R>> endobj 70 0 obj <</Intent 81 0 R/Name(Layer 5)/Type/OCG/Usage 82 0 R>> endobj 90 0 obj <</Intent 100 0 R/Name(Layer 2)/Type/OCG/Usage 101 0 R>> endobj 91 0 obj <</Intent 102 0 R/Name(Layer 5)/Type/OCG/Usage 103 0 R>> endobj 111 0 obj <</Intent 125 0 R/Name(Layer 2)/Type/OCG/Usage 126 0 R>> endobj 112 0 obj <</Intent 127 0 R/Name(Layer 5)/Type/OCG/Usage 128 0 R>> endobj 135 0 obj <</Intent 149 0 R/Name(Layer 2)/Type/OCG/Usage 150 0 R>> endobj 136 0 obj <</Intent 151 0 R/Name(Layer 5)/Type/OCG/Usage 152 0 R>> endobj 159 0 obj <</Intent 172 0 R/Name(Layer 2)/Type/OCG/Usage 173 0 R>> endobj 160 0 obj <</Intent 174 0 R/Name(Layer 5)/Type/OCG/Usage 175 0 R>> endobj 174 0 obj [/View/Design] endobj 175 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 172 0 obj [/View/Design] endobj 173 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 151 0 obj [/View/Design] endobj 152 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 149 0 obj [/View/Design] endobj 150 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 127 0 obj [/View/Design] endobj 128 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 125 0 obj [/View/Design] endobj 126 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 102 0 obj [/View/Design] endobj 103 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 100 0 obj [/View/Design] endobj 101 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 81 0 obj [/View/Design] endobj 82 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 79 0 obj [/View/Design] endobj 80 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 60 0 obj [/View/Design] endobj 61 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 42 0 obj [/View/Design] endobj 43 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 24 0 obj [/View/Design] endobj 25 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 22 0 obj [/View/Design] endobj 23 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 20 0 obj [/View/Design] endobj 21 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 18 0 obj [/View/Design] endobj 19 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 184 0 obj [183 0 R 182 0 R] endobj 203 0 obj <</CreationDate(D:20150714152851-03'00')/Creator(Adobe Illustrator CS6 \(Macintosh\))/ModDate(D:20150811224720-03'00')/Producer(Adobe PDF library 10.01)/Title(Web)>> endobj xref 0 204 0000000004 65535 f +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name(Layer 2)/Type/OCG/Usage 19 0 R>> endobj 6 0 obj <</Intent 20 0 R/Name(Layer 4)/Type/OCG/Usage 21 0 R>> endobj 7 0 obj <</Intent 22 0 R/Name(Layer 3)/Type/OCG/Usage 23 0 R>> endobj 8 0 obj <</Intent 24 0 R/Name(Layer 5)/Type/OCG/Usage 25 0 R>> endobj 33 0 obj <</Intent 42 0 R/Name(Layer 5)/Type/OCG/Usage 43 0 R>> endobj 51 0 obj <</Intent 60 0 R/Name(Layer 5)/Type/OCG/Usage 61 0 R>> endobj 69 0 obj <</Intent 79 0 R/Name(Layer 2)/Type/OCG/Usage 80 0 R>> endobj 70 0 obj <</Intent 81 0 R/Name(Layer 5)/Type/OCG/Usage 82 0 R>> endobj 90 0 obj <</Intent 100 0 R/Name(Layer 2)/Type/OCG/Usage 101 0 R>> endobj 91 0 obj <</Intent 102 0 R/Name(Layer 5)/Type/OCG/Usage 103 0 R>> endobj 111 0 obj <</Intent 125 0 R/Name(Layer 2)/Type/OCG/Usage 126 0 R>> endobj 112 0 obj <</Intent 127 0 R/Name(Layer 5)/Type/OCG/Usage 128 0 R>> endobj 135 0 obj <</Intent 149 0 R/Name(Layer 2)/Type/OCG/Usage 150 0 R>> endobj 136 0 obj <</Intent 151 0 R/Name(Layer 5)/Type/OCG/Usage 152 0 R>> endobj 159 0 obj <</Intent 172 0 R/Name(Layer 2)/Type/OCG/Usage 173 0 R>> endobj 160 0 obj <</Intent 174 0 R/Name(Layer 5)/Type/OCG/Usage 175 0 R>> endobj 182 0 obj <</Intent 194 0 R/Name(Layer 2)/Type/OCG/Usage 195 0 R>> endobj 183 0 obj <</Intent 196 0 R/Name(Layer 5)/Type/OCG/Usage 197 0 R>> endobj 204 0 obj <</Intent 216 0 R/Name(Layer 2)/Type/OCG/Usage 217 0 R>> endobj 205 0 obj <</Intent 218 0 R/Name(Layer 5)/Type/OCG/Usage 219 0 R>> endobj 226 0 obj <</Intent 238 0 R/Name(Layer 2)/Type/OCG/Usage 239 0 R>> endobj 227 0 obj <</Intent 240 0 R/Name(Layer 5)/Type/OCG/Usage 241 0 R>> endobj 240 0 obj [/View/Design] endobj 241 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 238 0 obj [/View/Design] endobj 239 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 218 0 obj [/View/Design] endobj 219 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 216 0 obj [/View/Design] endobj 217 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 196 0 obj [/View/Design] endobj 197 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 194 0 obj [/View/Design] endobj 195 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 174 0 obj [/View/Design] endobj 175 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 172 0 obj [/View/Design] endobj 173 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 151 0 obj [/View/Design] endobj 152 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 149 0 obj [/View/Design] endobj 150 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 127 0 obj [/View/Design] endobj 128 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 125 0 obj [/View/Design] endobj 126 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 102 0 obj [/View/Design] endobj 103 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 100 0 obj [/View/Design] endobj 101 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 81 0 obj [/View/Design] endobj 82 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 79 0 obj [/View/Design] endobj 80 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 60 0 obj [/View/Design] endobj 61 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 42 0 obj [/View/Design] endobj 43 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 24 0 obj [/View/Design] endobj 25 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 22 0 obj [/View/Design] endobj 23 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 20 0 obj [/View/Design] endobj 21 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 18 0 obj [/View/Design] endobj 19 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 250 0 obj [249 0 R 248 0 R] endobj 266 0 obj <</CreationDate(D:20150714152851-03'00')/Creator(Adobe Illustrator CS6 \(Macintosh\))/ModDate(D:20151115140912-02'00')/Producer(Adobe PDF library 10.01)/Title(Web)>> endobj xref 0 267 0000000004 65535 f 0000000016 00000 n -0000000399 00000 n -0000047530 00000 n +0000000495 00000 n +0000048002 00000 n 0000000009 00000 f -0000194280 00000 n -0000194350 00000 n -0000194420 00000 n -0000194490 00000 n +0000172712 00000 n +0000172782 00000 n +0000172852 00000 n +0000172922 00000 n 0000000011 00000 f -0000047590 00000 n +0000048062 00000 n 0000000012 00000 f 0000000013 00000 f 0000000014 00000 f @@ -1091,14 +1062,14 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000016 00000 f 0000000017 00000 f 0000000026 00000 f -0000197190 00000 n -0000197221 00000 n -0000197074 00000 n -0000197105 00000 n -0000196958 00000 n -0000196989 00000 n -0000196842 00000 n -0000196873 00000 n +0000176774 00000 n +0000176805 00000 n +0000176658 00000 n +0000176689 00000 n +0000176542 00000 n +0000176573 00000 n +0000176426 00000 n +0000176457 00000 n 0000000027 00000 f 0000000028 00000 f 0000000029 00000 f @@ -1106,7 +1077,7 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000031 00000 f 0000000032 00000 f 0000000034 00000 f -0000194560 00000 n +0000172992 00000 n 0000000035 00000 f 0000000036 00000 f 0000000037 00000 f @@ -1115,8 +1086,8 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000040 00000 f 0000000041 00000 f 0000000044 00000 f -0000196726 00000 n -0000196757 00000 n +0000176310 00000 n +0000176341 00000 n 0000000045 00000 f 0000000046 00000 f 0000000047 00000 f @@ -1124,7 +1095,7 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000049 00000 f 0000000050 00000 f 0000000052 00000 f -0000194631 00000 n +0000173063 00000 n 0000000053 00000 f 0000000054 00000 f 0000000055 00000 f @@ -1133,8 +1104,8 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000058 00000 f 0000000059 00000 f 0000000062 00000 f -0000196610 00000 n -0000196641 00000 n +0000176194 00000 n +0000176225 00000 n 0000000063 00000 f 0000000064 00000 f 0000000065 00000 f @@ -1142,8 +1113,8 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000067 00000 f 0000000068 00000 f 0000000071 00000 f -0000194702 00000 n -0000194773 00000 n +0000173134 00000 n +0000173205 00000 n 0000000072 00000 f 0000000073 00000 f 0000000074 00000 f @@ -1152,10 +1123,10 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000077 00000 f 0000000078 00000 f 0000000083 00000 f -0000196494 00000 n -0000196525 00000 n -0000196378 00000 n -0000196409 00000 n +0000176078 00000 n +0000176109 00000 n +0000175962 00000 n +0000175993 00000 n 0000000084 00000 f 0000000085 00000 f 0000000086 00000 f @@ -1163,8 +1134,8 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000088 00000 f 0000000089 00000 f 0000000092 00000 f -0000194844 00000 n -0000194917 00000 n +0000173276 00000 n +0000173349 00000 n 0000000093 00000 f 0000000094 00000 f 0000000095 00000 f @@ -1173,10 +1144,10 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000098 00000 f 0000000099 00000 f 0000000104 00000 f -0000196260 00000 n -0000196292 00000 n -0000196142 00000 n -0000196174 00000 n +0000175844 00000 n +0000175876 00000 n +0000175726 00000 n +0000175758 00000 n 0000000105 00000 f 0000000106 00000 f 0000000107 00000 f @@ -1184,8 +1155,8 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000109 00000 f 0000000110 00000 f 0000000113 00000 f -0000194990 00000 n -0000195064 00000 n +0000173422 00000 n +0000173496 00000 n 0000000114 00000 f 0000000115 00000 f 0000000116 00000 f @@ -1198,44 +1169,110 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000123 00000 f 0000000124 00000 f 0000000129 00000 f -0000196024 00000 n -0000196056 00000 n -0000195906 00000 n -0000195938 00000 n +0000175608 00000 n +0000175640 00000 n +0000175490 00000 n +0000175522 00000 n 0000000130 00000 f 0000000131 00000 f 0000000132 00000 f 0000000133 00000 f 0000000134 00000 f 0000000137 00000 f -0000195138 00000 n -0000195212 00000 n +0000173570 00000 n +0000173644 00000 n 0000000138 00000 f 0000000139 00000 f 0000000140 00000 f 0000000141 00000 f 0000000142 00000 f 0000000146 00000 f -0000192896 00000 n -0000193716 00000 n -0000193766 00000 n +0000171328 00000 n +0000172148 00000 n +0000172198 00000 n 0000000147 00000 f 0000000148 00000 f 0000000153 00000 f -0000195788 00000 n -0000195820 00000 n -0000195670 00000 n -0000195702 00000 n +0000175372 00000 n +0000175404 00000 n +0000175254 00000 n +0000175286 00000 n 0000000154 00000 f 0000000155 00000 f 0000000156 00000 f 0000000157 00000 f 0000000158 00000 f +0000000161 00000 f +0000173718 00000 n +0000173792 00000 n +0000000163 00000 f +0000048443 00000 n +0000000164 00000 f +0000000165 00000 f +0000000166 00000 f +0000000167 00000 f +0000000168 00000 f +0000000169 00000 f +0000000170 00000 f +0000000171 00000 f +0000000176 00000 f +0000175136 00000 n +0000175168 00000 n +0000175018 00000 n +0000175050 00000 n +0000000177 00000 f +0000000178 00000 f +0000000179 00000 f +0000000180 00000 f +0000000181 00000 f +0000000184 00000 f +0000173866 00000 n +0000173940 00000 n +0000000185 00000 f +0000000186 00000 f +0000000187 00000 f +0000000188 00000 f +0000000189 00000 f +0000000190 00000 f +0000000191 00000 f +0000000192 00000 f +0000000193 00000 f +0000000198 00000 f +0000174900 00000 n +0000174932 00000 n +0000174782 00000 n +0000174814 00000 n +0000000199 00000 f +0000000200 00000 f +0000000201 00000 f +0000000202 00000 f +0000000203 00000 f +0000000206 00000 f +0000174014 00000 n +0000174088 00000 n +0000000207 00000 f +0000000208 00000 f +0000000209 00000 f +0000000210 00000 f +0000000211 00000 f +0000000212 00000 f +0000000213 00000 f +0000000214 00000 f +0000000215 00000 f +0000000220 00000 f +0000174664 00000 n +0000174696 00000 n +0000174546 00000 n +0000174578 00000 n +0000000221 00000 f +0000000222 00000 f +0000000223 00000 f +0000000224 00000 f +0000000225 00000 f 0000000000 00000 f -0000195286 00000 n -0000195360 00000 n +0000174162 00000 n +0000174236 00000 n 0000000000 00000 f -0000047984 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f @@ -1245,36 +1282,33 @@ l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <</Intent 18 0 R/Name( 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f -0000195552 00000 n -0000195584 00000 n -0000195434 00000 n -0000195466 00000 n +0000174428 00000 n +0000174460 00000 n +0000174310 00000 n +0000174342 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f -0000052463 00000 n -0000052537 00000 n -0000197306 00000 n -0000191843 00000 n -0000052961 00000 n -0000049561 00000 n -0000052847 00000 n -0000049415 00000 n -0000048365 00000 n -0000049598 00000 n 0000049814 00000 n -0000049695 00000 n -0000052729 00000 n -0000052761 00000 n -0000052611 00000 n -0000052643 00000 n -0000053037 00000 n -0000053238 00000 n -0000054233 00000 n -0000082884 00000 n -0000148473 00000 n -0000197341 00000 n -trailer <</Size 204/Root 1 0 R/Info 203 0 R/ID[<D66DB9F6794B485686BE511CE008EC9C><1297730D06D3463C93340FE671760224>]>> startxref 197524 %%EOF \ No newline at end of file +0000049888 00000 n +0000176890 00000 n +0000170324 00000 n +0000052998 00000 n +0000050312 00000 n +0000050198 00000 n +0000048811 00000 n +0000050080 00000 n +0000050112 00000 n +0000049962 00000 n +0000049994 00000 n +0000050349 00000 n +0000053074 00000 n +0000053275 00000 n +0000054267 00000 n +0000061334 00000 n +0000126923 00000 n +0000176925 00000 n +trailer <</Size 267/Root 1 0 R/Info 266 0 R/ID[<D66DB9F6794B485686BE511CE008EC9C><F02F34907B944F28AFBF9514F1FFE5CF>]>> startxref 177108 %%EOF \ No newline at end of file -- GitLab From c0025aa7f0c959cd9f37fed2500b9c6bb59d33f6 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 16 Nov 2015 18:32:39 -0200 Subject: [PATCH 0451/1338] Fix mobile problem --- packages/rocketchat-ui/package.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 6c7570eabf1..b7fef9bb438 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -23,7 +23,8 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib@0.0.1', + 'raix:push' ]); // LIB FILES @@ -94,4 +95,4 @@ Package.onUse(function(api) { api.addFiles('views/app/spotlight/spotlight.coffee', 'client'); api.addFiles('views/app/videoCall/videoButtons.coffee', 'client'); api.addFiles('views/app/videoCall/videoCall.coffee', 'client'); -}); \ No newline at end of file +}); -- GitLab From 2892be621b22b0fd907e18346a8612c4342bf58c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 16 Nov 2015 18:38:15 -0200 Subject: [PATCH 0452/1338] Keep cordova autoupdate but remove loop --- packages/autoupdate/autoupdate_cordova.js | 3 ++- packages/autoupdate/package.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index 2cc2290db91..ba9e0d502cc 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -302,7 +302,8 @@ var ensureLocalPathPrefix = function (cb) { // the cordova.file symbol is attached, properties like dataDirectory // still can be null. Poll until we are sure the property is attached. console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms'); - Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20); + // REMOVED to prevent loop in new app + // Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20); } else { localPathPrefix = cordova.file.dataDirectory + 'meteor/'; cb(); diff --git a/packages/autoupdate/package.js b/packages/autoupdate/package.js index 9d81493e206..8895552bf35 100644 --- a/packages/autoupdate/package.js +++ b/packages/autoupdate/package.js @@ -29,7 +29,7 @@ Package.onUse(function (api) { api.addFiles('autoupdate_server.js', 'server'); api.addFiles('autoupdate_client.js', 'web.browser'); - // api.addFiles('autoupdate_cordova.js', 'web.cordova'); + api.addFiles('autoupdate_cordova.js', 'web.cordova'); api.export('Autoupdate'); }); -- GitLab From d60ce82a5f5ba9c9ce2ff96df63fb89288da84e8 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 16 Nov 2015 20:50:21 -0500 Subject: [PATCH 0453/1338] trying to fix broken velocity after Cordova merge toast verions file --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6b7015ad45e..2d8c09aae3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ script: - cd .travis - sh ./namefiles.sh - cd .. +- rm -f .meteor/versions - meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter - ./node_modules/velocity-cli/bin/velocity test-packages --ci - ./node_modules/velocity-cli/bin/velocity test-app --ci -- GitLab From 26f12f68ff92bee5dc480a1f4df0be8412650851 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 16 Nov 2015 21:28:15 -0500 Subject: [PATCH 0454/1338] trying to fix broken velocity after Cordova merge restore versions file ; eliminate liveChat --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d8c09aae3f..0264797eef6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,8 +34,7 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- rm -f .meteor/versions -- meteor add rocketchat:livechat rocketchat:hubot sanjo:jasmine velocity:console-reporter +- meteor add rocketchat:hubot sanjo:jasmine velocity:console-reporter - ./node_modules/velocity-cli/bin/velocity test-packages --ci - ./node_modules/velocity-cli/bin/velocity test-app --ci - meteor build --server demo.rocket.chat ../build -- GitLab From ba8ce1857c523545aec7ac6358c2620523c72fda Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 16 Nov 2015 22:43:54 -0500 Subject: [PATCH 0455/1338] trying to fix broken velocity after Cordova merge disable velocity to let builds continue - until a fix can be found --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0264797eef6..960e2ffb372 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,9 +34,7 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- meteor add rocketchat:hubot sanjo:jasmine velocity:console-reporter -- ./node_modules/velocity-cli/bin/velocity test-packages --ci -- ./node_modules/velocity-cli/bin/velocity test-app --ci +- meteor add rocketchat:livechat rocketchat:hubot - meteor build --server demo.rocket.chat ../build - cd .travis - sh ./namedemo.sh -- GitLab From d540455c70cd0c769e92c53de8752ad8ff5ae17f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 17 Nov 2015 09:37:15 -0200 Subject: [PATCH 0456/1338] Fire global event onNewVersion when new version of cordova is available --- packages/autoupdate/autoupdate_cordova.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index ba9e0d502cc..5cf39ace8bb 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -208,6 +208,7 @@ Autoupdate._retrySubscription = function () { var checkNewVersionDocument = function (doc) { var self = this; if (doc.version !== autoupdateVersionCordova) { + window.fireGlobalEvent('onNewVersion', doc.version) onNewVersion(); } }; -- GitLab From 5889c62083c18c5b56f137a23d95c536ffc5d2ff Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 17 Nov 2015 09:37:15 -0200 Subject: [PATCH 0457/1338] Fire global event onNewVersion when new version of cordova is available --- packages/autoupdate/autoupdate_cordova.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index ba9e0d502cc..5cf39ace8bb 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -208,6 +208,7 @@ Autoupdate._retrySubscription = function () { var checkNewVersionDocument = function (doc) { var self = this; if (doc.version !== autoupdateVersionCordova) { + window.fireGlobalEvent('onNewVersion', doc.version) onNewVersion(); } }; -- GitLab From e0e9b5949ab2285992df5d48bb6cc4aeff3c2c3b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 17 Nov 2015 15:10:40 -0200 Subject: [PATCH 0458/1338] meteor update --- .meteor/versions | 2 +- .../app/.meteor/.finished-upgraders | 4 + .../rocketchat-livechat/app/.meteor/packages | 1 + .../rocketchat-livechat/app/.meteor/release | 2 +- .../rocketchat-livechat/app/.meteor/versions | 124 ++++++++++-------- 5 files changed, 77 insertions(+), 56 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 3bbb02db1b0..d670b9baf4b 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,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.0 +cosmos:browserify@0.9.1 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 diff --git a/packages/rocketchat-livechat/app/.meteor/.finished-upgraders b/packages/rocketchat-livechat/app/.meteor/.finished-upgraders index 8a761038c51..61ee3132307 100644 --- a/packages/rocketchat-livechat/app/.meteor/.finished-upgraders +++ b/packages/rocketchat-livechat/app/.meteor/.finished-upgraders @@ -6,3 +6,7 @@ notices-for-0.9.0 notices-for-0.9.1 0.9.4-platform-file notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes diff --git a/packages/rocketchat-livechat/app/.meteor/packages b/packages/rocketchat-livechat/app/.meteor/packages index cbcb892d50a..b5196ffad92 100644 --- a/packages/rocketchat-livechat/app/.meteor/packages +++ b/packages/rocketchat-livechat/app/.meteor/packages @@ -33,3 +33,4 @@ momentjs:moment mizzao:timesync reactive-var accounts-password +standard-minifiers diff --git a/packages/rocketchat-livechat/app/.meteor/release b/packages/rocketchat-livechat/app/.meteor/release index 315c635bf30..3a05e0a2f70 100644 --- a/packages/rocketchat-livechat/app/.meteor/release +++ b/packages/rocketchat-livechat/app/.meteor/release @@ -1 +1 @@ -METEOR@1.1.0.3 +METEOR@1.2.1 diff --git a/packages/rocketchat-livechat/app/.meteor/versions b/packages/rocketchat-livechat/app/.meteor/versions index cf86c29e008..c8184d77242 100644 --- a/packages/rocketchat-livechat/app/.meteor/versions +++ b/packages/rocketchat-livechat/app/.meteor/versions @@ -1,58 +1,74 @@ -accounts-base@1.2.0 -accounts-password@1.1.1 +accounts-base@1.2.2 +accounts-password@1.1.4 arunoda:streams@0.1.17 -base64@1.0.3 -binary-heap@1.0.3 -blaze@2.1.2 -blaze-tools@1.0.3 -boilerplate-generator@1.0.3 -callback-hook@1.0.3 -check@1.0.5 -coffeescript@1.0.6 -cosmos:browserify@0.5.0 -ddp@1.1.0 -deps@1.0.7 -ejson@1.0.6 -email@1.0.6 -geojson-utils@1.0.3 -html-tools@1.0.4 -htmljs@1.0.4 -http@1.1.0 -id-map@1.0.3 -jquery@1.11.3_2 -json@1.0.3 -kadira:blaze-layout@2.0.0 -kadira:flow-router@2.3.0 +babel-compiler@5.8.24_1 +babel-runtime@0.1.4 +base64@1.0.4 +binary-heap@1.0.4 +blaze@2.1.3 +blaze-tools@1.0.4 +boilerplate-generator@1.0.4 +caching-compiler@1.0.0 +caching-html-compiler@1.0.2 +callback-hook@1.0.4 +check@1.1.0 +coffeescript@1.0.11 +cosmos:browserify@0.5.1 +ddp@1.2.2 +ddp-client@1.2.1 +ddp-common@1.2.2 +ddp-rate-limiter@1.0.0 +ddp-server@1.2.2 +deps@1.0.9 +diff-sequence@1.0.1 +ecmascript@0.1.6 +ecmascript-runtime@0.2.6 +ejson@1.0.7 +email@1.0.8 +geojson-utils@1.0.4 +html-tools@1.0.5 +htmljs@1.0.5 +http@1.1.1 +id-map@1.0.4 +jquery@1.11.4 +kadira:blaze-layout@2.2.0 +kadira:flow-router@2.9.0 konecty:nrr@2.0.2 -less@1.0.14 -livedata@1.0.13 -localstorage@1.0.3 -logging@1.0.7 -meteor@1.1.6 -minifiers@1.1.5 -minimongo@1.0.8 -mizzao:timesync@0.3.3 +less@2.5.1 +livedata@1.0.15 +localstorage@1.0.5 +logging@1.0.8 +meteor@1.1.10 +minifiers@1.1.7 +minimongo@1.0.10 +mizzao:timesync@0.3.4 momentjs:moment@2.10.6 -mongo@1.1.0 +mongo@1.1.3 +mongo-id@1.0.1 npm-bcrypt@0.7.8_2 -observe-sequence@1.0.6 -ordered-dict@1.0.3 -random@1.0.3 -reactive-dict@1.1.0 -reactive-var@1.0.5 -retry@1.0.3 -routepolicy@1.0.5 -service-configuration@1.0.4 -session@1.1.0 -sha@1.0.3 -spacebars@1.0.6 -spacebars-compiler@1.0.6 -srp@1.0.3 -templating@1.1.1 -tracker@1.0.7 -ui@1.0.6 -underscore@1.0.3 -underscorestring:underscore.string@3.2.0 -url@1.0.4 -webapp@1.2.0 -webapp-hashing@1.0.3 +npm-mongo@1.4.39_1 +observe-sequence@1.0.7 +ordered-dict@1.0.4 +promise@0.5.1 +random@1.0.5 +rate-limit@1.0.0 +reactive-dict@1.1.3 +reactive-var@1.0.6 +retry@1.0.4 +routepolicy@1.0.6 +service-configuration@1.0.5 +session@1.1.1 +sha@1.0.4 +spacebars@1.0.7 +spacebars-compiler@1.0.7 +srp@1.0.4 +standard-minifiers@1.0.2 +templating@1.1.5 +templating-tools@1.0.0 +tracker@1.0.9 +ui@1.0.8 +underscore@1.0.4 +underscorestring:underscore.string@3.2.2 +url@1.0.5 +webapp@1.2.3 +webapp-hashing@1.0.5 -- GitLab From 0ee79d40a3d16ee9801e9e4e5e4677f1c226355c Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 14:38:00 -0500 Subject: [PATCH 0459/1338] Update README to include oschina.net coverage minor edit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a07134a1840..1529c385dd6 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,9 @@ It is a great solution for communities and companies wanting to privately host t ##### [JavaScript Weekly](http://javascriptweekly.com/issues/234) > An open source Web based, channel based chat system (a la Slack) built using Meteor, the full stack JavaScript development platform. +##### [Open Source China](http://www.oschina.net/p/rocket-chat) +> Rocket.Chat 是特性最丰富的 Slack å¼€æºæ›¿ä»£å“之一。 主è¦åŠŸèƒ½ï¼šç¾¤ç»„èŠå¤©ï¼Œç›´æŽ¥é€šä¿¡ï¼Œç§èŠç¾¤ï¼Œæ¡Œé¢é€šçŸ¥ï¼Œåª’ä½“åµŒå…¥ï¼Œé“¾æŽ¥é¢„è§ˆï¼Œæ–‡ä»¶ä¸Šä¼ ï¼Œè¯éŸ³/视频 èŠå¤©ï¼Œæˆªå›¾ç‰ç‰ã€‚ + ##### [wwwhatsnew.com](http://wwwhatsnew.com/2015/05/30/rocket-chat-para-los-programadores-que-quieran-ofrecer-un-chat-en-su-web/) > Para los programadores que quieran ofrecer un chat en su web -- GitLab From 53d1280f356c2c23cf8e597d0b875951c40014a5 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 17 Nov 2015 20:06:34 -0200 Subject: [PATCH 0460/1338] meteor update --- packages/rocketchat-livechat/app/.meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/app/.meteor/versions b/packages/rocketchat-livechat/app/.meteor/versions index c8184d77242..6240ee123eb 100644 --- a/packages/rocketchat-livechat/app/.meteor/versions +++ b/packages/rocketchat-livechat/app/.meteor/versions @@ -13,7 +13,7 @@ caching-html-compiler@1.0.2 callback-hook@1.0.4 check@1.1.0 coffeescript@1.0.11 -cosmos:browserify@0.5.1 +cosmos:browserify@0.9.1 ddp@1.2.2 ddp-client@1.2.1 ddp-common@1.2.2 -- GitLab From f61557e222bc30b2d4957cadae45fe424a58d282 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 17 Nov 2015 20:27:48 -0200 Subject: [PATCH 0461/1338] Improve avatar cache --- server/startup/avatar.coffee | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 387fed26d88..18b65368737 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -42,7 +42,14 @@ Meteor.startup -> if not file? res.setHeader 'content-type', 'image/svg+xml' - res.setHeader 'cache-control', 'public, max-age=31536000' + res.setHeader 'Last-Modified', "Thu, 01 Jan 2015 00:00:00 GMT" + + reqModifiedHeader = req.headers["if-modified-since"]; + if reqModifiedHeader? + if reqModifiedHeader is "Thu, 01 Jan 2015 00:00:00 GMT" + res.writeHead 304 + res.end() + return colors = ['#F44336','#E91E63','#9C27B0','#673AB7','#3F51B5','#2196F3','#03A9F4','#00BCD4','#009688','#4CAF50','#8BC34A','#CDDC39','#FFC107','#FF9800','#FF5722','#795548','#9E9E9E','#607D8B'] -- GitLab From 4fde9f9f743a2e1144539bf5e879b52c74211492 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 17 Nov 2015 20:36:54 -0200 Subject: [PATCH 0462/1338] Add cache-control to avatar headers --- server/startup/avatar.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 18b65368737..05801d949bd 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -42,6 +42,7 @@ Meteor.startup -> if not file? res.setHeader 'content-type', 'image/svg+xml' + res.setHeader 'cache-control', 'public' res.setHeader 'Last-Modified', "Thu, 01 Jan 2015 00:00:00 GMT" reqModifiedHeader = req.headers["if-modified-since"]; -- GitLab From f42c45f0ac2211f4b9c2338ccd1bcd6b3d4c36cb Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 17 Nov 2015 22:41:50 -0200 Subject: [PATCH 0463/1338] Fix problem with usernames being converted to object id --- packages/rocketchat-file/file.server.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 926a2aad351..00aa21319db 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -5,6 +5,9 @@ path = Npm.require('path') mkdirp = Npm.require('mkdirp') gm = Npm.require('gm') +# Fix problem with usernames being converted to object id +Grid.prototype.tryParseObjectId = -> false + RocketChatFile = gm: gm -- GitLab From 7a1a51906311a234731beadca57e199cd3664791 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 18 Nov 2015 00:06:47 -0200 Subject: [PATCH 0464/1338] adding graphicsmagick by default --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index be972ce9ac5..741983cc810 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,8 @@ FROM node:0.10 -MAINTAINER buildmaster@rocket.chat +MAINTAINER buildmaster@rocket.chat + +RUN apt-get update && apt-get install -y graphicsmagick RUN groupadd -r rocketchat \ && useradd -r -g rocketchat rocketchat \ @@ -20,7 +22,7 @@ RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz WORKDIR /app/bundle USER rocketchat -# needs a mongoinstance - defaults to container linking with alias 'db' +# needs a mongoinstance - defaults to container linking with alias 'db' ENV MONGO_URL=mongodb://db:27017/meteor \ PORT=3000 \ ROOT_URL=http://localhost:3000 -- GitLab From ebfe842568fc7eabf44c722516e8c5b3717a7f7b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 18 Nov 2015 00:16:01 -0200 Subject: [PATCH 0465/1338] adding graphicsmagick by default --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 741983cc810..73c1043a70b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,9 @@ FROM node:0.10 MAINTAINER buildmaster@rocket.chat -RUN apt-get update && apt-get install -y graphicsmagick +RUN apt-get update \ +&& apt-get install -y graphicsmagick \ +&& rm -rf /var/lib/apt/lists/* RUN groupadd -r rocketchat \ && useradd -r -g rocketchat rocketchat \ -- GitLab From ece32dc68d4668d79b0aea432279b858a1685896 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 18 Nov 2015 00:58:45 -0200 Subject: [PATCH 0466/1338] Remove default value of Accounts_AvatarStorePath --- packages/rocketchat-lib/settings/server/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/settings/server/startup.coffee index 09e68acfbec..0c7bb1e88bb 100644 --- a/packages/rocketchat-lib/settings/server/startup.coffee +++ b/packages/rocketchat-lib/settings/server/startup.coffee @@ -9,7 +9,7 @@ RocketChat.settings.add 'Accounts_ManuallyApproveNewUsers', false, { type: 'bool RocketChat.settings.add 'Accounts_AllowedDomainsList', '', { type: 'string', group: 'Accounts', public: true, section: 'Registration' } RocketChat.settings.add 'Accounts_AvatarStoreType', 'GridFS', { type: 'string', group: 'Accounts', section: 'Avatar' } -RocketChat.settings.add 'Accounts_AvatarStorePath', '/var/www/rocket.chat/uploads/avatar/', { 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' } -- GitLab From 589133d2ca99139dac43914ba78e71048a9d30fe Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 18 Nov 2015 01:04:37 -0200 Subject: [PATCH 0467/1338] fixing default path for avatars --- Dockerfile | 9 ++++++--- docker-compose.yml | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 73c1043a70b..8b3c4650794 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,8 @@ FROM node:0.10 MAINTAINER buildmaster@rocket.chat RUN apt-get update \ -&& apt-get install -y graphicsmagick \ -&& rm -rf /var/lib/apt/lists/* +&& apt-get install -y graphicsmagick \ +&& rm -rf /var/lib/apt/lists/* RUN groupadd -r rocketchat \ && useradd -r -g rocketchat rocketchat \ @@ -21,9 +21,12 @@ RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz && cd /app/bundle/programs/server \ && npm install -WORKDIR /app/bundle USER rocketchat +RUN mkdir ~/uploads + +WORKDIR /app/bundle + # needs a mongoinstance - defaults to container linking with alias 'db' ENV MONGO_URL=mongodb://db:27017/meteor \ PORT=3000 \ diff --git a/docker-compose.yml b/docker-compose.yml index b59ddd46332..38498e85b0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,10 +8,11 @@ db: rocketchat: image: rocketchat/rocket.chat environment: + - ROOT=3000 + - ROOT_URL=http://yourhost:3000 - MONGO_URL=mongodb://db:27017/rocketchat - - ROOT_URL=http://yourhost:8818 links: - db:db ports: - - 8818:3000 + - 3000:3000 -- GitLab From d81ac64e1a8a0ba17ff044f673ad3e4271ddd678 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 22:31:07 -0500 Subject: [PATCH 0468/1338] Build only on develop branch - for now temporary until we update the shell scripts for dual-branch builds --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 960e2ffb372..a7f417e0c6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ sudo: required language: node_js branches: only: - - master - develop node_js: - '0.12' @@ -50,5 +49,4 @@ deploy: local_dir: ../build on: branch: - - master - develop -- GitLab From 400aaeeeec241084c06fb07883e354a59aac8e90 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 18 Nov 2015 01:32:20 -0200 Subject: [PATCH 0469/1338] added VOLUME directive --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8b3c4650794..a1424718203 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,9 @@ RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz USER rocketchat -RUN mkdir ~/uploads +RUN mkdir /rocketchat +RUN mkdir /rocketchat/uploads +VOLUME /rocketchat WORKDIR /app/bundle -- GitLab From ae1e7acca8be8ae7727af79639bebe0af1dcb974 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 22:58:32 -0500 Subject: [PATCH 0470/1338] fix permission problem --- Dockerfile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index a1424718203..2df807acea3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,8 @@ RUN apt-get update \ RUN groupadd -r rocketchat \ && useradd -r -g rocketchat rocketchat \ -&& mkdir /app +&& 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 @@ -23,10 +24,7 @@ RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz USER rocketchat -RUN mkdir /rocketchat -RUN mkdir /rocketchat/uploads -VOLUME /rocketchat - +VOLUME /app/uploads WORKDIR /app/bundle # needs a mongoinstance - defaults to container linking with alias 'db' -- GitLab From 9c697950fec305de2f92dfb8e8eb22c8c48fd4d4 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 23:36:20 -0500 Subject: [PATCH 0471/1338] fix default avatar upload path even though default is GridFS storing to mongo; for some reasons, many docker users still insist on changing it to FileSystem --- docker-compose.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 38498e85b0e..b781f873145 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,19 @@ db: image: mongo # volumes: -# - ./data/runtime/db:/data/db -# - ./data/dump:/dump +# - $PWD/data/runtime/db:/data/db +# - $PWD/data/dump:/dump command: mongod --smallfiles rocketchat: image: rocketchat/rocket.chat +# volumes: +# - $PWD/uploads:/app/uploads environment: - ROOT=3000 - ROOT_URL=http://yourhost:3000 - MONGO_URL=mongodb://db:27017/rocketchat + - Accounts_AvatarStorePath=/app/uploads links: - db:db ports: -- GitLab From 10c2ef5b99b360feed10a13d055897205779abd6 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 23:38:57 -0500 Subject: [PATCH 0472/1338] fix default avatar upload path correct typos (in commented lines) --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b781f873145..72830939db6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,14 @@ db: image: mongo # volumes: -# - $PWD/data/runtime/db:/data/db -# - $PWD/data/dump:/dump +# - ./data/runtime/db:/data/db +# - ./data/dump:/dump command: mongod --smallfiles rocketchat: image: rocketchat/rocket.chat # volumes: -# - $PWD/uploads:/app/uploads +# - ./uploads:/app/uploads environment: - ROOT=3000 - ROOT_URL=http://yourhost:3000 -- GitLab From 5bbbf3e1ac6d285bdc9ca7253dacc1ac53caf30a Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 23:57:41 -0500 Subject: [PATCH 0473/1338] add default avatar upload path even though default avatar upload is GridFS, many docker users continue to change it to FileSystem --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2df807acea3..19967653150 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,8 @@ WORKDIR /app/bundle # needs a mongoinstance - defaults to container linking with alias 'db' ENV MONGO_URL=mongodb://db:27017/meteor \ PORT=3000 \ - ROOT_URL=http://localhost:3000 + ROOT_URL=http://localhost:3000 \ + Accounts_AvatarStorePath=/app/uploads EXPOSE 3000 CMD ["node", "main.js"] -- GitLab From 30171f20a94e13e614c2826d903cbb7c166813de Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 17 Nov 2015 23:58:39 -0500 Subject: [PATCH 0474/1338] fix default avatar upload path moved to Dockerfile --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 72830939db6..d30c0c0d1ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,6 @@ rocketchat: - ROOT=3000 - ROOT_URL=http://yourhost:3000 - MONGO_URL=mongodb://db:27017/rocketchat - - Accounts_AvatarStorePath=/app/uploads links: - db:db ports: -- GitLab From d4839952f8067e0301e1efe12c5b95a9742d6e80 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 18 Nov 2015 20:54:01 -0200 Subject: [PATCH 0475/1338] standardising docker deployment links and DB name --- Dockerfile | 4 ++-- docker-compose.yml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 19967653150..386758a3f39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,8 +27,8 @@ USER rocketchat VOLUME /app/uploads WORKDIR /app/bundle -# needs a mongoinstance - defaults to container linking with alias 'db' -ENV MONGO_URL=mongodb://db:27017/meteor \ +# 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 diff --git a/docker-compose.yml b/docker-compose.yml index d30c0c0d1ba..07624dc9669 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ -db: +mongo: image: mongo # volumes: -# - ./data/runtime/db:/data/db +# - ./data/runtime/mongo:/data/mongo # - ./data/dump:/dump command: mongod --smallfiles @@ -12,9 +12,9 @@ rocketchat: environment: - ROOT=3000 - ROOT_URL=http://yourhost:3000 - - MONGO_URL=mongodb://db:27017/rocketchat + - MONGO_URL=mongodb://mongo:27017/rocketchat links: - - db:db + - mongo:mongo ports: - 3000:3000 -- GitLab From 2863307e71727a25ea268fe2a0709042c2966c55 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 19 Nov 2015 16:22:56 -0200 Subject: [PATCH 0476/1338] Fix error with autoupdate with the new mobile app --- packages/autoupdate/autoupdate_cordova.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index 5cf39ace8bb..d929936e246 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -81,6 +81,9 @@ var updating = false; var localPathPrefix = null; var onNewVersion = function () { + if (!window.FileTransfer) { + return; + } var ft = new FileTransfer(); var urlPrefix = Meteor.absoluteUrl() + '__cordova'; HTTP.get(urlPrefix + '/manifest.json', function (err, res) { @@ -95,6 +98,9 @@ var onNewVersion = function () { }; var downloadNewVersion = function (program) { + if (!window.FileTransfer) { + return; + } var urlPrefix = Meteor.absoluteUrl() + '__cordova'; var manifest = _.clone(program.manifest); var version = program.version; -- GitLab From db28fcaad6721de37da3998cb9e40353b1af8a7d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 19 Nov 2015 16:23:13 -0200 Subject: [PATCH 0477/1338] Send the original host in the push notification --- packages/rocketchat-lib/server/sendMessage.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-lib/server/sendMessage.coffee b/packages/rocketchat-lib/server/sendMessage.coffee index 0d4f33fe6f1..ed0159147b0 100644 --- a/packages/rocketchat-lib/server/sendMessage.coffee +++ b/packages/rocketchat-lib/server/sendMessage.coffee @@ -70,6 +70,7 @@ RocketChat.sendMessage = (user, message, room, options) -> badge: 1 sound: 'chime' payload: + host: Meteor.absoluteUrl() rid: message.rid sender: message.u type: room.t @@ -143,6 +144,7 @@ RocketChat.sendMessage = (user, message, room, options) -> badge: 1 sound: 'chime' payload: + host: Meteor.absoluteUrl() rid: message.rid sender: message.u type: room.t -- GitLab From eef7838f57fa3dcc9c30ab9e58837db1526b31e5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 19 Nov 2015 16:23:50 -0200 Subject: [PATCH 0478/1338] Fix Push configuration in the new raix:push version and save the android sender id to pass to mobile apps --- packages/rocketchat-ui/lib/cordova/push.coffee | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee index f8485d4716c..be482f6dd7b 100644 --- a/packages/rocketchat-ui/lib/cordova/push.coffee +++ b/packages/rocketchat-ui/lib/cordova/push.coffee @@ -36,10 +36,16 @@ if Meteor.isCordova Tracker.autorun -> if RocketChat.settings.get('Push_enable') is true and Meteor.userId()? + android_senderID = RocketChat.settings.get 'Push_gcm_project_number' + if android_senderID? + localStorage.setItem 'android_senderID', android_senderID + Push.Configure - gcm: - projectNumber: RocketChat.settings.get 'Push_gcm_project_number' - badge: true - sound: true - alert: true - vibrate: true + android: + senderID: android_senderID + sound: true + vibrate: true + ios: + badge: true + sound: true + alert: true -- GitLab From 733f7ea494c7d0afced6ff4972e9101508c95331 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 19 Nov 2015 18:00:42 -0200 Subject: [PATCH 0479/1338] new apis for roomTypes --- client/startup/defaultRoomTypes.coffee | 52 +++++++++++++------ .../client/hasPermission.coffee | 3 +- .../server/models/Permissions.coffee | 3 ++ .../server/startup.coffee | 9 ++++ packages/rocketchat-lib/lib/roomTypes.coffee | 31 +++++++++-- packages/rocketchat-livechat/client/ui.js | 19 +++++-- packages/rocketchat-livechat/permissions.js | 33 ++---------- 7 files changed, 94 insertions(+), 56 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 0bba73ffdef..89e21852c76 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,19 +1,41 @@ Meteor.startup -> - roles = ['admin', 'moderator', 'user'] - RocketChat.roomTypes.addType('starredRooms', roles); - RocketChat.roomTypes.addType('channels', roles); - RocketChat.roomTypes.addType('directMessages', roles); - RocketChat.roomTypes.addType('privateGroups', roles); + # RocketChat.roomTypes.addType('starredRooms', roles); - RocketChat.roomTypes.setIcon('c', 'icon-hash'); - RocketChat.roomTypes.setIcon('d', 'icon-at'); - RocketChat.roomTypes.setIcon('p', 'icon-lock'); + RocketChat.roomTypes.add 'c', + template: 'channels' + icon: 'icon-hash' + route: + name: 'channel' + path: '/channel/:name' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'c', params.name + link: (sub) -> + return { name: sub.name } + permissions: [ 'view-c-room' ] - RocketChat.roomTypes.setRoute 'c', 'channel', (sub) -> - return { name: sub.name } + RocketChat.roomTypes.add 'd', + template: 'directMessages' + icon: 'icon-at' + route: + name: 'direct' + path: '/direct/:username' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'd', params.name + link: (sub) -> + return { username: sub.name } + permissions: [ 'view-d-room' ] - RocketChat.roomTypes.setRoute 'd', 'direct', (sub) -> - return { username: sub.name } - - RocketChat.roomTypes.setRoute 'p', 'group', (sub) -> - return { name: sub.name } + RocketChat.roomTypes.add 'p', + template: 'privateGroups' + icon: 'icon-lock' + route: + name: 'group' + path: '/group/:name' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'p', params.name + link: (sub) -> + return { name: sub.name } + permissions: [ 'view-p-room' ] diff --git a/packages/rocketchat-authorization/client/hasPermission.coffee b/packages/rocketchat-authorization/client/hasPermission.coffee index 8efa87d4977..9d636b9552e 100644 --- a/packages/rocketchat-authorization/client/hasPermission.coffee +++ b/packages/rocketchat-authorization/client/hasPermission.coffee @@ -28,8 +28,7 @@ hasPermission = (permissions, scope=Roles.GLOBAL_GROUP, strategy) -> unless RocketChat.authz.subscription.ready() return false - unless _.isArray(permissions) - permissions = [permissions] + permissions = [].concat permissions roleNames = Roles.getRolesForUser(userId, scope) diff --git a/packages/rocketchat-authorization/server/models/Permissions.coffee b/packages/rocketchat-authorization/server/models/Permissions.coffee index 727b6b69eb3..0db22472da1 100644 --- a/packages/rocketchat-authorization/server/models/Permissions.coffee +++ b/packages/rocketchat-authorization/server/models/Permissions.coffee @@ -9,3 +9,6 @@ RocketChat.models.Permissions = new class extends RocketChat.models._Base roles: role return @find query, options + + createOrUpdate: (name, roles) -> + @upsert { _id: name }, { $set: { roles: roles } } diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index c7cd71d4072..f27b9b10303 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -77,6 +77,15 @@ Meteor.startup -> { _id: 'bulk-create-c', roles : ['admin']} + + { _id: 'view-c-room', + roles : ['admin', 'site-moderator', 'user']} + + { _id: 'view-p-room', + roles : ['admin', 'site-moderator', 'user']} + + { _id: 'view-d-room', + roles : ['admin', 'site-moderator', 'user']} ] #alanning:roles diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index 891ec9d27ea..c5fe9fb993d 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -1,8 +1,24 @@ RocketChat.roomTypes = new class - rooms = [] - routes = {} - publishes = {} - icons = {} + roomTypesOrder = [] + roomTypes = {} + + ### Adds a room type to app + @param identifier MUST BE equals to `db.rocketchat_room.t` field + @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 + action: route action function + ### + add = (identifier, config) -> + if roomTypes[identifier]? + throw new Meteor.Error 'identifier-already-set', t('Room_type_identifier_already_set') + + # @TODO validate config options + roomTypesOrder.push identifier + roomTypes[identifier] = config ### Sets a route for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @@ -39,7 +55,12 @@ RocketChat.roomTypes = new class roles: [].concat roles getAllTypes = -> - return rooms + typesPermitted = [] + roomTypesOrder.forEach (type) -> + if roomTypes[type].permissions? and RocketChat.authz.hasAtLeastOnePermission roomTypes[type].permissions + typesPermitted.push roomTypes[type] + + return typesPermitted ### add a publish for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index 78c60da223b..d24a82d39f4 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -1,8 +1,19 @@ Meteor.startup(function() { - RocketChat.roomTypes.addType('livechat', ['livechat-agent', 'livechat-manager']); - RocketChat.roomTypes.setIcon('l', 'icon-chat-empty'); - RocketChat.roomTypes.setRoute('l', 'live', function(sub) { - return { name: sub.name }; + RocketChat.roomTypes.add('l', { + template: 'livechat', + icon: 'icon-chat-empty', + route: { + name: 'live', + path: '/live/:name', + action: (params, queryParams) => { + Session.set('showUserInfo'); + openRoom('l', params.name); + }, + link: (sub) => { + return { name: sub.name } + } + }, + permissions: [ 'view-l-room' ] }); AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index 4c4c84f3ff4..8d14854de3e 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -1,32 +1,5 @@ -Meteor.startup(function() { - var i, j, len, len1, permission, ref, role, roles, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - var permissions = [ - { - _id: 'receive-livechat', - roles : ['livechat-agent'] - }, - { - _id: 'edit-livechat-settings', - roles : ['livechat-manager'] - } - ]; - - roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); - - for (i = 0, len = permissions.length; i < len; i++) { - permission = permissions[i]; - RocketChat.models.Permissions.upsert(permission._id, { - $setOnInsert: permission - }); - ref = permission.roles; - for (j = 0, len1 = ref.length; j < len1; j++) { - role = ref[j]; - if (indexOf.call(roles, role) < 0) { - Roles.createRole(role); - roles.push(role); - } - } +Meteor.startup(() => { + if (RocketChat.models && RocketChat.models.Permissions) { + RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager']); } }); -- GitLab From 4048ddb611cdf0b0c30f3af7af95754a1da3b300 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 19 Nov 2015 18:17:27 -0200 Subject: [PATCH 0480/1338] new roomTypes API --- client/startup/defaultRoomTypes.coffee | 1 + packages/rocketchat-lib/lib/roomTypes.coffee | 70 +++++++------------ .../rocketchat-lib/server/models/Rooms.coffee | 7 ++ .../rocketchat-livechat/server/startup.js | 4 +- .../side-nav/chatRoomItem.coffee | 2 +- .../side-nav/sideNav.coffee | 2 +- .../rocketchat-ui/views/app/roomSearch.coffee | 5 +- .../views/app/spotlight/spotlight.coffee | 5 +- server/publications/room.coffee | 2 +- server/publications/roomSearch.coffee | 2 +- server/startup/roomPublishes.coffee | 8 +-- 11 files changed, 45 insertions(+), 63 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 89e21852c76..e027a74625d 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,5 +1,6 @@ Meteor.startup -> # RocketChat.roomTypes.addType('starredRooms', roles); + # roles = ['admin', 'moderator', 'user'] RocketChat.roomTypes.add 'c', template: 'channels' diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index c5fe9fb993d..9b9c5b24504 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -20,39 +20,15 @@ RocketChat.roomTypes = new class roomTypesOrder.push identifier roomTypes[identifier] = config - ### Sets a route for a room type - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param routeName: route's name for given type - @param dataCallback: callback for the route data. receives the whole subscription data as parameter - ### - setRoute = (roomType, routeName, dataCallback) -> - if routes[roomType]? - throw new Meteor.Error 'route-callback-exists', 'Route callback for the given type already exists' - - # dataCallback ?= -> return {} - - routes[roomType] = - name: routeName - data: dataCallback or -> return {} - ### @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param subData: the user's subscription data ### - getRoute = (roomType, subData) -> - unless routes[roomType]? + getRouteLink = (roomType, subData) -> + unless roomTypes[roomType]? throw new Meteor.Error 'route-doesnt-exists', 'There is no route for the type: ' + roomType - return FlowRouter.path routes[roomType].name, routes[roomType].data(subData) - - ### add a type of room - @param template: the name of the template to render on sideNav - @param roles[]: a list of roles a user must have to see the template - ### - addType = (template, roles = []) -> - rooms.push - template: template - roles: [].concat roles + return FlowRouter.path roomTypes[roomType].route.name, roomTypes[roomType].route.link(subData) getAllTypes = -> typesPermitted = [] @@ -66,38 +42,42 @@ RocketChat.roomTypes = new class @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param callback: function that will return the publish's data ### - addPublish = (roomType, callback) -> - if publishes[roomType]? + setPublish = (roomType, callback) -> + if roomTypes[roomType]?.publish? throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' - publishes[roomType] = callback + unless roomTypes[roomType]? + roomTypesOrder.push roomType + roomTypes[roomType] = {} + + roomTypes[roomType].publish = callback ### run the publish for a room type @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param identifier: identifier of the room ### runPublish = (roomType, identifier) -> - return unless publishes[roomType]? - return publishes[roomType].call this, identifier + return unless roomTypes[roomType].publish? + return roomTypes[roomType].publish.call this, identifier getIcon = (roomType) -> - return icons[roomType] + return roomTypes[roomType]?.icon - ### - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param iconClass: iconClass to display on sideNav - ### - setIcon = (roomType, iconClass) -> - icons[roomType] = iconClass + getIdentifiers = (except) -> + except = [].concat except + return _.reject roomTypesOrder, (t) -> return except.indexOf(t) isnt -1 - addType: addType + # addType: addType getTypes: getAllTypes + getIdentifiers: getIdentifiers - setIcon: setIcon + # setIcon: setIcon getIcon: getIcon - setRoute: setRoute - getRoute: getRoute + # setRoute: setRoute + getRouteLink: getRouteLink + + setPublish: setPublish + runPublish: runPublish - addPublish: addPublish - publish: runPublish + add: add diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index dddc8f8c021..6d03db06da6 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -106,6 +106,13 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @find query, options + findByTypeContainigUsernames: (type, username, options) -> + query = + t: type + usernames: { $all: [].concat(username) } + + return @find query, options + findByTypesAndNotUserIdContainingUsername: (types, userId, username, options) -> query = t: diff --git a/packages/rocketchat-livechat/server/startup.js b/packages/rocketchat-livechat/server/startup.js index f9beb312b1c..90644834099 100644 --- a/packages/rocketchat-livechat/server/startup.js +++ b/packages/rocketchat-livechat/server/startup.js @@ -1,5 +1,5 @@ -Meteor.startup(function() { - RocketChat.roomTypes.addPublish('l', function(identifier) { +Meteor.startup(() => { + RocketChat.roomTypes.setPublish('l', (identifier) => { return RocketChat.models.Rooms.findByTypeAndName('l', identifier, { fields: { name: 1, diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee index c1482357b98..12767b5eabd 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee @@ -33,7 +33,7 @@ Template.chatRoomItem.helpers return true route: -> - FlowRouter.path RocketChat.roomTypes.getRoute @t, @ + FlowRouter.path RocketChat.roomTypes.getRouteLink @t, @ Template.chatRoomItem.rendered = -> if not (FlowRouter.getParam('_id')? and FlowRouter.getParam('_id') is this.data.rid) and not this.data.ls diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 66d6bbada55..7c9d2574f8a 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -96,5 +96,5 @@ Template.sideNav.onRendered -> lastLink = $('.rooms-list h3.history-div').get(0) RocketChat.roomTypes.getTypes().forEach (roomType) -> - if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? + if Template[roomType.template]? Blaze.render Template[roomType.template], wrapper, lastLink diff --git a/packages/rocketchat-ui/views/app/roomSearch.coffee b/packages/rocketchat-ui/views/app/roomSearch.coffee index 25a18fe420b..5e880050085 100644 --- a/packages/rocketchat-ui/views/app/roomSearch.coffee +++ b/packages/rocketchat-ui/views/app/roomSearch.coffee @@ -3,10 +3,7 @@ Template.roomSearch.helpers return 'icon-at' if this.type is 'u' if this.type is 'r' - switch this.t - when 'd' then return 'icon-at' - when 'c' then return 'icon-hash' - when 'p' then return 'icon-lock' + return RocketChat.roomTypes.getIcon this.t userStatus: -> if this.type is 'u' diff --git a/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee b/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee index f52ba4fa767..07825b6684e 100644 --- a/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee +++ b/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee @@ -35,10 +35,7 @@ Template.spotlight.events FlowRouter.go('direct', { username: doc.username }) event.currentTarget.value = '' else if doc.type is 'r' - if doc.t is 'c' - FlowRouter.go('channel', { name: doc.name }) - else if doc.t is 'p' - FlowRouter.go('group', { name: doc.name }) + FlowRouter.go FlowRouter.path RocketChat.roomTypes.getRouteLink doc.t, doc event.currentTarget.value = '' diff --git a/server/publications/room.coffee b/server/publications/room.coffee index ef32aecaf2a..960f1c40de9 100644 --- a/server/publications/room.coffee +++ b/server/publications/room.coffee @@ -10,4 +10,4 @@ Meteor.publish 'room', (typeName) -> type = typeName.substr(0, 1) name = typeName.substr(1) - return RocketChat.roomTypes.publish.call(this, type, name) + return RocketChat.roomTypes.runPublish.call(this, type, name) diff --git a/server/publications/roomSearch.coffee b/server/publications/roomSearch.coffee index e5d9a2ae375..c499c1a89f7 100644 --- a/server/publications/roomSearch.coffee +++ b/server/publications/roomSearch.coffee @@ -24,7 +24,7 @@ Meteor.publish 'roomSearch', (selector, options, collName) -> self.removed("autocompleteRecords", id) if not searchType? or searchType is 'r' - subHandleRooms = RocketChat.models.Rooms.findByTypesAndNotUserIdContainingUsername(['c', 'p'], selector.uid?.$ne, RocketChat.models.Users.findOneById(this.userId).username, { limit: 10, fields: { t: 1, name: 1 } }).observeChanges + subHandleRooms = RocketChat.models.Rooms.findByTypesAndNotUserIdContainingUsername(RocketChat.roomTypes.getIdentifiers('d'), selector.uid?.$ne, RocketChat.models.Users.findOneById(this.userId).username, { limit: 10, fields: { t: 1, name: 1 } }).observeChanges added: (id, fields) -> data = { type: 'r', rid: id, name: fields.name, t: fields.t } self.added("autocompleteRecords", id, data) diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index ae5cdd0225f..409131cc9b4 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -1,5 +1,5 @@ Meteor.startup -> - RocketChat.roomTypes.addPublish 'c', (identifier) -> + RocketChat.roomTypes.setPublish 'c', (identifier) -> options = fields: name: 1 @@ -9,7 +9,7 @@ Meteor.startup -> usernames: 1 return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options - RocketChat.roomTypes.addPublish 'p', (identifier) -> + RocketChat.roomTypes.setPublish 'p', (identifier) -> options = fields: name: 1 @@ -20,7 +20,7 @@ Meteor.startup -> user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options - RocketChat.roomTypes.addPublish 'd', (identifier) -> + RocketChat.roomTypes.setPublish 'd', (identifier) -> options = fields: name: 1 @@ -29,4 +29,4 @@ Meteor.startup -> u: 1 usernames: 1 user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 - return RocketChat.models.Rooms.findByTypeContainigUsername 'd', user.username, options + return RocketChat.models.Rooms.findByTypeContainigUsernames 'd', [user.username, identifier], options -- GitLab From 971029cbcbefee9a51b291aadd6d4208ae47172b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 19 Nov 2015 19:13:43 -0200 Subject: [PATCH 0481/1338] Do not init push, only register --- .../rocketchat-ui/lib/cordova/push.coffee | 58 +++++++------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/packages/rocketchat-ui/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee index be482f6dd7b..e5c73b4b524 100644 --- a/packages/rocketchat-ui/lib/cordova/push.coffee +++ b/packages/rocketchat-ui/lib/cordova/push.coffee @@ -1,38 +1,21 @@ if Meteor.isCordova - Push.addListener 'token', (token) -> - Meteor.call 'log', 'CLIENT', 'token', arguments - - Push.addListener 'error', (err) -> - Meteor.call 'log', 'CLIENT', 'error', arguments - if err.type == 'apn.cordova' - Meteor.call 'log', 'CLIENT', err.error - - Push.addListener 'register', (evt) -> - Meteor.call 'log', 'CLIENT', 'register', arguments - - Push.addListener 'alert', (notification) -> - Meteor.call 'log', 'CLIENT', 'alert', arguments - - Push.addListener 'sound', (notification) -> - Meteor.call 'log', 'CLIENT', 'sound', arguments + window.addEventListener 'push-notification', (evt) -> + Meteor.call 'log', 'CLIENT', 'startup', arguments - Push.addListener 'badge', (notification) -> - Meteor.call 'log', 'CLIENT', 'badge', arguments + notification = evt.detail - Push.addListener 'startup', (notification) -> - Meteor.call 'log', 'CLIENT', 'startup', arguments + if notification.additionalData.foreground is true + return - if notification.open is true and notification.payload?.rid? - switch notification.payload.type + if notification.additionalData.ejson?.rid? + switch notification.additionalData.ejson.type when 'c' - FlowRouter.go 'channel', name: notification.payload.name + FlowRouter.go 'channel', name: notification.additionalData.ejson.name when 'p' - FlowRouter.go 'group', name: notification.payload.name + FlowRouter.go 'group', name: notification.additionalData.ejson.name when 'd' - FlowRouter.go 'direct', username: notification.payload.sender.username + FlowRouter.go 'direct', username: notification.additionalData.ejson.sender.username - Push.addListener 'message', (notification) -> - Meteor.call 'log', 'CLIENT', 'message', arguments Tracker.autorun -> if RocketChat.settings.get('Push_enable') is true and Meteor.userId()? @@ -40,12 +23,15 @@ if Meteor.isCordova if android_senderID? localStorage.setItem 'android_senderID', android_senderID - Push.Configure - android: - senderID: android_senderID - sound: true - vibrate: true - ios: - badge: true - sound: true - alert: true + if window.pushToken? + data = + id: localStorage.getItem 'push_stored_id' + token: window.pushToken, + appName: 'main', + userId: Meteor.userId() + metadata: undefined + + Meteor.call 'raix:push-update', data, (err, result) -> + console.log err, result + if not err? and result? + localStorage.setItem 'push_stored_id', result._id -- GitLab From f59b59867c7b5a0e463044adac4cc0c5f9a1e5cd Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 19 Nov 2015 19:16:19 -0200 Subject: [PATCH 0482/1338] Remove log --- packages/rocketchat-ui/lib/cordova/push.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-ui/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee index e5c73b4b524..3d0d64299c3 100644 --- a/packages/rocketchat-ui/lib/cordova/push.coffee +++ b/packages/rocketchat-ui/lib/cordova/push.coffee @@ -32,6 +32,5 @@ if Meteor.isCordova metadata: undefined Meteor.call 'raix:push-update', data, (err, result) -> - console.log err, result if not err? and result? localStorage.setItem 'push_stored_id', result._id -- GitLab From 8c97f09be2cb82206f32865257e0d21cdf7f1505 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 19 Nov 2015 22:08:31 -0200 Subject: [PATCH 0483/1338] storing settings value source information --- .../settings/server/methods.coffee | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 20939369bc4..9adf17b8ba9 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -10,28 +10,29 @@ RocketChat.settings.add = (_id, value, options = {}) -> # console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments + options.packageValue = value + options.valueSource = 'packageValue' + if process?.env?[_id]? value = process.env[_id] + options.processEnvValue = value + options.valueSource = 'processEnvValue' + else if Meteor.settings?[_id]? value = Meteor.settings[_id] + options.meteorSettingsValue = value + options.valueSource = 'meteorSettingsValue' - updateSettings = - i18nLabel: options.i18nLabel or _id + unless options.i18nLabel? options.i18nLabel = _id - # default description i18n key will be the setting name + "_Description" - # (eg: LDAP_Enable -> LDAP_Enable_Description) - updateSettings.i18nDescription = if options.i18nDescription? - options.i18nDescription - else - "#{_id}_Description" - updateSettings.type = options.type if options.type - updateSettings.multiline = options.multiline if options.multiline - updateSettings.group = options.group if options.group - updateSettings.section = options.section if options.section - updateSettings.public = options.public if options.public - updateSettings.placeholder = options.placeholder if options.placeholder + # Default description i18n key will be the setting name + "_Description" (eg: LDAP_Enable -> LDAP_Enable_Description) + unless options.i18nDescription? options.i18nDescription = "#{_id}_Description" - upsertChanges = { $setOnInsert: { value: value }, $set: updateSettings } + upsertChanges = + $set: options + $setOnInsert: + value: value + createdAt: new Date if options.persistent is true upsertChanges.$unset = { ts: true } @@ -51,16 +52,16 @@ RocketChat.settings.addGroup = (_id, options = {}) -> # console.log '[functions] RocketChat.settings.addGroup -> '.green, 'arguments:', arguments - updateSettings = + setting = type: 'group' i18nLabel: options.i18nLabel or _id - updateSettings.i18nDescription = if options.i18nDescription? + setting.i18nDescription = if options.i18nDescription? options.i18nDescription else "#{_id}_Description" - upsertChanges = { $set: updateSettings } + upsertChanges = { $set: setting } if options.persistent is true upsertChanges.$unset = { ts: true } else @@ -87,7 +88,10 @@ RocketChat.settings.removeById = (_id) -> # @param {String} _id ### RocketChat.settings.updateById = (_id, value) -> - RocketChat.models.Settings.updateValueById _id, value + if not _id + return false + + return RocketChat.models.Settings.updateValueById _id, value Meteor.methods -- GitLab From 3b368dcec1cc028ffcb841aec565c90d2451188b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 19 Nov 2015 22:25:59 -0200 Subject: [PATCH 0484/1338] fixed syntax --- packages/rocketchat-lib/settings/server/methods.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 9adf17b8ba9..7589508e307 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -23,10 +23,12 @@ RocketChat.settings.add = (_id, value, options = {}) -> options.meteorSettingsValue = value options.valueSource = 'meteorSettingsValue' - unless options.i18nLabel? options.i18nLabel = _id + if not options.i18nLabel? + options.i18nLabel = _id # Default description i18n key will be the setting name + "_Description" (eg: LDAP_Enable -> LDAP_Enable_Description) - unless options.i18nDescription? options.i18nDescription = "#{_id}_Description" + if not options.i18nDescription? + options.i18nDescription = "#{_id}_Description" upsertChanges = $set: options -- GitLab From ffc0e17efd9421e5bfe254abcb27b0a8c95dee54 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 00:12:35 -0200 Subject: [PATCH 0485/1338] remove old files --- packages/rocketchat-webrtc-ib/i18n/ar.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/de.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/el.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/en.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/es.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/fa.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/fi.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/fr.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/he.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/hr.i18n.json | 4 ---- packages/rocketchat-webrtc-ib/i18n/hu.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/it.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/ja.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/km.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/ko.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/pl.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/pt.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/ru.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/sv.i18n.json | 5 ----- packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/tr.i18n.json | 6 ------ packages/rocketchat-webrtc-ib/i18n/ug.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/uk.i18n.json | 1 - packages/rocketchat-webrtc-ib/i18n/zh.i18n.json | 6 ------ 25 files changed, 97 deletions(-) delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ar.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/de.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/el.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/en.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/es.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/fa.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/fi.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/fr.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/he.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/hr.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/hu.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/it.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ja.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/km.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ko.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/pl.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/pt.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ru.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/sv.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/tr.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/ug.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/uk.i18n.json delete mode 100644 packages/rocketchat-webrtc-ib/i18n/zh.i18n.json diff --git a/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ar.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/de.i18n.json b/packages/rocketchat-webrtc-ib/i18n/de.i18n.json deleted file mode 100644 index 332a0f2d96e..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/de.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Video-Chat", - "Remote" : "Entfernt", - "Setup" : "Einrichten", - "Stop_Video" : "Video stoppen" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/el.i18n.json b/packages/rocketchat-webrtc-ib/i18n/el.i18n.json deleted file mode 100644 index d4fd3d2608d..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/el.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Συνομιλία μÎσω βίντεο", - "Remote" : "ΑπομακÏυσμÎνο", - "Setup" : "ΡÏθμιση", - "Stop_Video" : "Σταμάτημα Βίντεο" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json b/packages/rocketchat-webrtc-ib/i18n/en.i18n.json deleted file mode 100644 index 84f089985d2..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/en.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Video Chat", - "Remote" : "Remote", - "Setup" : "Setup", - "Stop_Video" : "Stop Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/es.i18n.json b/packages/rocketchat-webrtc-ib/i18n/es.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/es.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fa.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fa.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/fa.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json deleted file mode 100644 index ab7aed7ca7b..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/fi.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Videokeskustelu", - "Remote" : "Etä", - "Setup" : "Asennus", - "Stop_Video" : "Pysäytä video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json deleted file mode 100644 index 41647a551e7..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/fr.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Tchat vidéo", - "Remote" : "À distance", - "Setup" : "Configuration", - "Stop_Video" : "Arrêter la vidéo" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/he.i18n.json b/packages/rocketchat-webrtc-ib/i18n/he.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/he.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json deleted file mode 100644 index 524e429ddff..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/hr.i18n.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "Video_Chat" : "Video Chat", - "Stop_Video" : "Zaustavi Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json b/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/hu.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/it.i18n.json b/packages/rocketchat-webrtc-ib/i18n/it.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/it.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ja.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/km.i18n.json b/packages/rocketchat-webrtc-ib/i18n/km.i18n.json deleted file mode 100644 index 98eedeb7c4d..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/km.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "ការ​ជជែក​កំសាន្ážâ€‹áž‡áž¶â€‹ážœáž¸ážŠáŸáž¢áž¼", - "Remote" : "ពី​ចម្ងាយ", - "Setup" : "ការ​ដំឡើង", - "Stop_Video" : "បញ្ឈប់​វីដáŸáž¢áž¼" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json deleted file mode 100644 index 36785947aeb..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ko.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "í™”ìƒ ì±„íŒ…", - "Remote" : "ì›ê²©", - "Setup" : "ì„¤ì •", - "Stop_Video" : "í™”ìƒ ì±„íŒ… ì •ì§€" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json deleted file mode 100644 index ac751a74fe7..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ms-MY.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Perbualan Video", - "Remote" : "Kawalan Jauh", - "Setup" : "Persediaan", - "Stop_Video" : "Berhentikan Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json b/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json deleted file mode 100644 index ff189e84d63..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/pl.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Chat wideo", - "Remote" : "Zdalny", - "Setup" : "Opcje", - "Stop_Video" : "Zatrzymaj wideo" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json b/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json deleted file mode 100644 index f9378d46d17..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/pt.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Iniciar Video", - "Remote" : "Remoto", - "Setup" : "Configurar", - "Stop_Video" : "Encerrar Video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json deleted file mode 100644 index ebedecb615d..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ru.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Видео чат", - "Remote" : "Удалённый", - "Setup" : "УÑтановить", - "Stop_Video" : "ОÑтановить видео" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/sv.i18n.json b/packages/rocketchat-webrtc-ib/i18n/sv.i18n.json deleted file mode 100644 index cd7a07141b6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/sv.i18n.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "Video_Chat" : "Videochatt", - "Setup" : "Inställningar", - "Stop_Video" : "Stoppa video" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ta-IN.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json b/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json deleted file mode 100644 index c1fcf250151..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/tr.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "Görüntülü Sohbet", - "Remote" : "Uzak", - "Setup" : "Kurulum", - "Stop_Video" : "Vidyoyu durdur" -} \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json b/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/ug.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json b/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json deleted file mode 100644 index 6f31cf5a2e6..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/uk.i18n.json +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json b/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json deleted file mode 100644 index efbd1904e4b..00000000000 --- a/packages/rocketchat-webrtc-ib/i18n/zh.i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Video_Chat" : "视频", - "Remote" : "远程", - "Setup" : "设置", - "Stop_Video" : "åœæ¢è§†é¢‘" -} \ No newline at end of file -- GitLab From f248957732d7fabf9a4c9ee265e1616b41e93b15 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 01:15:43 -0200 Subject: [PATCH 0486/1338] re organising files --- packages/rocketchat-lib/package.js | 3 +- .../server/models/Settings.coffee | 0 .../settings/client/rocketchat.coffee | 3 +- .../settings/lib/settings.coffee | 21 ++++++------ .../settings/server/methods.coffee | 32 +++++++++++-------- 5 files changed, 30 insertions(+), 29 deletions(-) rename packages/rocketchat-lib/{settings => }/server/models/Settings.coffee (100%) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index fde76ff1f86..6e2e0481357 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -99,6 +99,5 @@ Package.onTest(function(api) { api.use('coffeescript'); api.use('sanjo:jasmine@0.20.2'); api.use('rocketchat:lib'); - - api.addFiles('tests/jasmine/server/unit/models/_Base.spec.coffee', 'server'); + api.addFiles('tests/jasmine/server/unit/models/_Base.spec.coffee', 'server'); }); diff --git a/packages/rocketchat-lib/settings/server/models/Settings.coffee b/packages/rocketchat-lib/server/models/Settings.coffee similarity index 100% rename from packages/rocketchat-lib/settings/server/models/Settings.coffee rename to packages/rocketchat-lib/server/models/Settings.coffee diff --git a/packages/rocketchat-lib/settings/client/rocketchat.coffee b/packages/rocketchat-lib/settings/client/rocketchat.coffee index 4fff6096b2d..6db18f21080 100644 --- a/packages/rocketchat-lib/settings/client/rocketchat.coffee +++ b/packages/rocketchat-lib/settings/client/rocketchat.coffee @@ -6,8 +6,9 @@ settingsDict = new ReactiveDict('settings') RocketChat.settings.subscription = Meteor.subscribe 'settings' + RocketChat.settings.get = (_id) -> return settingsDict.get(_id) RocketChat.settings.onload '*', (key, value) -> - return settingsDict.set key, value \ No newline at end of file + return settingsDict.set key, value diff --git a/packages/rocketchat-lib/settings/lib/settings.coffee b/packages/rocketchat-lib/settings/lib/settings.coffee index ce9ea416307..2077f3b4f4c 100644 --- a/packages/rocketchat-lib/settings/lib/settings.coffee +++ b/packages/rocketchat-lib/settings/lib/settings.coffee @@ -4,29 +4,26 @@ else Settings = RocketChat.models.Settings initialLoad = true + +Meteor.settings ?= {} + +process?.env ?= {} + Settings.find().observe + added: (record) -> - Meteor.settings ?= {} Meteor.settings[record._id] = record.value - + process?.env[record._id] = record.value RocketChat.settings.load record._id, record.value, initialLoad - if process? - process.env ?= {} - process.env[record._id] = record.value - changed: (record) -> Meteor.settings?[record._id] = record.value - + process?.env[record._id] = record.value RocketChat.settings.load record._id, record.value, initialLoad - if process? - process.env[record._id] = record.value - removed: (record) -> - RocketChat.settings.load record._id, undefined, initialLoad - delete Meteor.settings?[record._id] delete process?.env?[record._id] + RocketChat.settings.load record._id, undefined, initialLoad initialLoad = false diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/settings/server/methods.coffee index 7589508e307..dc7c3e29f21 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/settings/server/methods.coffee @@ -5,11 +5,11 @@ # @param {Object} setting ### RocketChat.settings.add = (_id, value, options = {}) -> + # console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments + if not _id or not value? return false - # console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments - options.packageValue = value options.valueSource = 'packageValue' @@ -49,21 +49,23 @@ RocketChat.settings.add = (_id, value, options = {}) -> # @param {String} _id ### RocketChat.settings.addGroup = (_id, options = {}) -> + # console.log '[functions] RocketChat.settings.addGroup -> '.green, 'arguments:', arguments + if not _id return false - # console.log '[functions] RocketChat.settings.addGroup -> '.green, 'arguments:', arguments + if not options.i18nLabel? + options.i18nLabel = _id - setting = - type: 'group' - i18nLabel: options.i18nLabel or _id + if not options.i18nDescription? + options.i18nDescription = "#{_id}_Description" - setting.i18nDescription = if options.i18nDescription? - options.i18nDescription - else - "#{_id}_Description" + upsertChanges = + $set: options + $setOnInsert: + type: 'group' + createdAt: new Date - upsertChanges = { $set: setting } if options.persistent is true upsertChanges.$unset = { ts: true } else @@ -77,11 +79,11 @@ RocketChat.settings.addGroup = (_id, options = {}) -> # @param {String} _id ### RocketChat.settings.removeById = (_id) -> + # console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments + if not _id return false - # console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments - return RocketChat.models.Settings.removeById _id @@ -90,7 +92,9 @@ RocketChat.settings.removeById = (_id) -> # @param {String} _id ### RocketChat.settings.updateById = (_id, value) -> - if not _id + # console.log '[functions] RocketChat.settings.updateById -> '.green, 'arguments:', arguments + + if not _id or not value? return false return RocketChat.models.Settings.updateValueById _id, value -- GitLab From fea4d7eeaa9259f1543a82dddad81f9d3705d3e6 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 01:30:16 -0200 Subject: [PATCH 0487/1338] re organising files --- .../{settings/lib/rocketchat.coffee => lib/settings.coffee} | 0 packages/rocketchat-lib/package.js | 6 +++--- .../server/{ => functions}/sendMessage.coffee | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename packages/rocketchat-lib/{settings/lib/rocketchat.coffee => lib/settings.coffee} (100%) rename packages/rocketchat-lib/server/{ => functions}/sendMessage.coffee (100%) diff --git a/packages/rocketchat-lib/settings/lib/rocketchat.coffee b/packages/rocketchat-lib/lib/settings.coffee similarity index 100% rename from packages/rocketchat-lib/settings/lib/rocketchat.coffee rename to packages/rocketchat-lib/lib/settings.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 6e2e0481357..672a9c11f3f 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -24,6 +24,7 @@ Package.onUse(function(api) { // COMMON api.addFiles('lib/core.coffee'); + api.addFiles('lib/settings.coffee'); api.addFiles('lib/callbacks.coffee'); api.addFiles('lib/roomTypes.coffee'); api.addFiles('lib/slashCommand.coffee'); @@ -35,12 +36,11 @@ Package.onUse(function(api) { api.addFiles('server/models/Rooms.coffee', 'server'); api.addFiles('server/models/Messages.coffee', 'server'); api.addFiles('server/models/Reports.coffee', 'server'); + api.addFiles('server/models/Settings.coffee', 'server'); // Settings - api.addFiles('settings/lib/rocketchat.coffee'); api.addFiles('settings/lib/onLoadSettings.coffee'); - api.addFiles('settings/server/models/Settings.coffee', 'server'); api.addFiles('settings/server/methods.coffee', 'server'); api.addFiles('settings/server/publication.coffee', 'server'); api.addFiles('settings/server/startup.coffee', 'server'); @@ -63,6 +63,7 @@ Package.onUse(function(api) { // SERVER api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); + api.addFiles('server/functions/sendMessage.coffee', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); api.addFiles('server/methods/robotMethods.coffee', 'server'); @@ -72,7 +73,6 @@ Package.onUse(function(api) { api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); - api.addFiles('server/sendMessage.coffee', 'server'); api.addFiles('server/Notifications.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee similarity index 100% rename from packages/rocketchat-lib/server/sendMessage.coffee rename to packages/rocketchat-lib/server/functions/sendMessage.coffee -- GitLab From ad43d4fbab8da29cdefa90caa9d218096e27f0da Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 01:49:32 -0200 Subject: [PATCH 0488/1338] moved publications to /publications folder --- packages/rocketchat-lib/package.js | 4 +++- .../publications/settings.coffee} | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename packages/rocketchat-lib/{settings/server/publication.coffee => server/publications/settings.coffee} (100%) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 672a9c11f3f..83d304b031d 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -38,11 +38,13 @@ Package.onUse(function(api) { api.addFiles('server/models/Reports.coffee', 'server'); api.addFiles('server/models/Settings.coffee', 'server'); + // PUBLICATIONS + api.addFiles('server/publications/settings.coffee', 'server'); + // Settings api.addFiles('settings/lib/onLoadSettings.coffee'); api.addFiles('settings/server/methods.coffee', 'server'); - api.addFiles('settings/server/publication.coffee', 'server'); api.addFiles('settings/server/startup.coffee', 'server'); api.addFiles('settings/server/updateServices.coffee', 'server'); api.addFiles('settings/server/addOAuthService.coffee', 'server'); diff --git a/packages/rocketchat-lib/settings/server/publication.coffee b/packages/rocketchat-lib/server/publications/settings.coffee similarity index 100% rename from packages/rocketchat-lib/settings/server/publication.coffee rename to packages/rocketchat-lib/server/publications/settings.coffee -- GitLab From 39944acf5119bdd5da842f4bca280d5cd8ea09bf Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 02:29:08 -0200 Subject: [PATCH 0489/1338] moved sendMessage method files to lib package --- .../client}/methods/sendMessage.coffee | 0 packages/rocketchat-lib/package.js | 47 +++++++++++-------- .../server}/methods/sendMessage.coffee | 0 3 files changed, 27 insertions(+), 20 deletions(-) rename {client => packages/rocketchat-lib/client}/methods/sendMessage.coffee (100%) rename {server => packages/rocketchat-lib/server}/methods/sendMessage.coffee (100%) diff --git a/client/methods/sendMessage.coffee b/packages/rocketchat-lib/client/methods/sendMessage.coffee similarity index 100% rename from client/methods/sendMessage.coffee rename to packages/rocketchat-lib/client/methods/sendMessage.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 83d304b031d..e3f28075109 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -22,38 +22,57 @@ Package.onUse(function(api) { api.use('check'); api.use('arunoda:streams'); - // COMMON + // COMMON LIB api.addFiles('lib/core.coffee'); api.addFiles('lib/settings.coffee'); api.addFiles('lib/callbacks.coffee'); api.addFiles('lib/roomTypes.coffee'); api.addFiles('lib/slashCommand.coffee'); - // MODELS SERVER + // SERVER MODELS api.addFiles('server/models/_Base.coffee', 'server'); - api.addFiles('server/models/Users.coffee', 'server'); - api.addFiles('server/models/Subscriptions.coffee', 'server'); - api.addFiles('server/models/Rooms.coffee', 'server'); api.addFiles('server/models/Messages.coffee', 'server'); api.addFiles('server/models/Reports.coffee', 'server'); + api.addFiles('server/models/Rooms.coffee', 'server'); api.addFiles('server/models/Settings.coffee', 'server'); + api.addFiles('server/models/Subscriptions.coffee', 'server'); + api.addFiles('server/models/Users.coffee', 'server'); - // PUBLICATIONS + // SERVER PUBLICATIONS api.addFiles('server/publications/settings.coffee', 'server'); + // SERVER FUNCTIONS + api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); + api.addFiles('server/functions/setUsername.coffee', 'server'); + api.addFiles('server/functions/sendMessage.coffee', 'server'); + + // SERVER METHODS + api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); + api.addFiles('server/methods/robotMethods.coffee', 'server'); + api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); + api.addFiles('server/methods/sendMessage.coffee', 'server'); + api.addFiles('server/methods/setAdminStatus.coffee', 'server'); + api.addFiles('server/methods/setRealName.coffee', 'server'); + api.addFiles('server/methods/setUsername.coffee', 'server'); + api.addFiles('server/methods/updateUser.coffee', 'server'); + // Settings api.addFiles('settings/lib/onLoadSettings.coffee'); + api.addFiles('settings/lib/settings.coffee'); api.addFiles('settings/server/methods.coffee', 'server'); api.addFiles('settings/server/startup.coffee', 'server'); api.addFiles('settings/server/updateServices.coffee', 'server'); api.addFiles('settings/server/addOAuthService.coffee', 'server'); - api.addFiles('settings/lib/settings.coffee'); - // CLIENT + // CLIENT LIB api.addFiles('client/lib/openRoom.coffee', 'client'); api.addFiles('client/lib/roomExit.coffee', 'client'); + + // CLIENT METHODS + api.addFiles('client/methods/sendMessage.coffee', 'client'); + api.addFiles('client/AdminBox.coffee', 'client'); api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); @@ -62,18 +81,6 @@ Package.onUse(function(api) { api.addFiles('settings/client/rocketchat.coffee', 'client'); - // SERVER - api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); - api.addFiles('server/functions/setUsername.coffee', 'server'); - api.addFiles('server/functions/sendMessage.coffee', 'server'); - - api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); - api.addFiles('server/methods/robotMethods.coffee', 'server'); - api.addFiles('server/methods/sendInvitationEmail.coffee', 'server'); - api.addFiles('server/methods/setAdminStatus.coffee', 'server'); - api.addFiles('server/methods/setRealName.coffee', 'server'); - api.addFiles('server/methods/setUsername.coffee', 'server'); - api.addFiles('server/methods/updateUser.coffee', 'server'); api.addFiles('server/Notifications.coffee', 'server'); diff --git a/server/methods/sendMessage.coffee b/packages/rocketchat-lib/server/methods/sendMessage.coffee similarity index 100% rename from server/methods/sendMessage.coffee rename to packages/rocketchat-lib/server/methods/sendMessage.coffee -- GitLab From 9f29fe65fdeca0d22755249ac39e5b29320cecc8 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 20 Nov 2015 00:03:12 -0500 Subject: [PATCH 0490/1338] fix delete msg with oembed problem - closes #1429 view renders oembed in msg - even if msg type is 'rm' --- packages/rocketchat-lib/server/models/Messages.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 49ed13ec71a..ff9d345f4f9 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -140,6 +140,7 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base $set: msg: '' t: 'rm' + urls: [] editedAt: new Date() editedBy: _id: Meteor.userId() -- GitLab From 3baf314533380a6e92d1537ac3c97d02dbc0be22 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 03:13:56 -0200 Subject: [PATCH 0491/1338] re organising files --- .../lib/settings.coffee} | 0 .../{settings/lib => lib/startup}/settings.coffee | 0 packages/rocketchat-lib/package.js | 15 ++++++++------- .../functions/settings.coffee} | 14 -------------- .../rocketchat-lib/server/methods/settings.coffee | 12 ++++++++++++ 5 files changed, 20 insertions(+), 21 deletions(-) rename packages/rocketchat-lib/{settings/client/rocketchat.coffee => client/lib/settings.coffee} (100%) rename packages/rocketchat-lib/{settings/lib => lib/startup}/settings.coffee (100%) rename packages/rocketchat-lib/{settings/server/methods.coffee => server/functions/settings.coffee} (85%) create mode 100644 packages/rocketchat-lib/server/methods/settings.coffee diff --git a/packages/rocketchat-lib/settings/client/rocketchat.coffee b/packages/rocketchat-lib/client/lib/settings.coffee similarity index 100% rename from packages/rocketchat-lib/settings/client/rocketchat.coffee rename to packages/rocketchat-lib/client/lib/settings.coffee diff --git a/packages/rocketchat-lib/settings/lib/settings.coffee b/packages/rocketchat-lib/lib/startup/settings.coffee similarity index 100% rename from packages/rocketchat-lib/settings/lib/settings.coffee rename to packages/rocketchat-lib/lib/startup/settings.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index e3f28075109..2205d4ea6a6 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -43,8 +43,9 @@ Package.onUse(function(api) { // SERVER FUNCTIONS api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); - api.addFiles('server/functions/setUsername.coffee', 'server'); api.addFiles('server/functions/sendMessage.coffee', 'server'); + api.addFiles('server/functions/settings.coffee', 'server'); + api.addFiles('server/functions/setUsername.coffee', 'server'); // SERVER METHODS api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); @@ -53,22 +54,24 @@ Package.onUse(function(api) { api.addFiles('server/methods/sendMessage.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); + api.addFiles('server/methods/settings.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); + // COMMON STARTUP + api.addFiles('lib/startup/settings.coffee'); + // Settings api.addFiles('settings/lib/onLoadSettings.coffee'); - api.addFiles('settings/lib/settings.coffee'); - api.addFiles('settings/server/methods.coffee', 'server'); api.addFiles('settings/server/startup.coffee', 'server'); api.addFiles('settings/server/updateServices.coffee', 'server'); api.addFiles('settings/server/addOAuthService.coffee', 'server'); - // CLIENT LIB api.addFiles('client/lib/openRoom.coffee', 'client'); api.addFiles('client/lib/roomExit.coffee', 'client'); + api.addFiles('client/lib/settings.coffee', 'client'); // CLIENT METHODS api.addFiles('client/methods/sendMessage.coffee', 'client'); @@ -79,14 +82,12 @@ Package.onUse(function(api) { api.addFiles('client/MessageAction.coffee', 'client'); api.addFiles('client/MessageTypes.coffee', 'client'); - api.addFiles('settings/client/rocketchat.coffee', 'client'); - - api.addFiles('server/Notifications.coffee', 'server'); api.addFiles('server/cdn.coffee', 'server'); + // TAPi18n api.use('templating', 'client'); var _ = Npm.require('underscore'); diff --git a/packages/rocketchat-lib/settings/server/methods.coffee b/packages/rocketchat-lib/server/functions/settings.coffee similarity index 85% rename from packages/rocketchat-lib/settings/server/methods.coffee rename to packages/rocketchat-lib/server/functions/settings.coffee index dc7c3e29f21..024d3f8af51 100644 --- a/packages/rocketchat-lib/settings/server/methods.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -98,17 +98,3 @@ RocketChat.settings.updateById = (_id, value) -> return false return RocketChat.models.Settings.updateValueById _id, value - - -Meteor.methods - saveSetting: (_id, value) -> - console.log '[method] saveSetting', _id, value - if Meteor.userId()? - user = Meteor.users.findOne Meteor.userId() - - unless RocketChat.authz.hasPermission(Meteor.userId(), 'edit-privileged-setting') is true - throw new Meteor.Error 503, 'Not authorized' - - # console.log "saveSetting -> ".green, _id, value - RocketChat.settings.updateById _id, value - return true diff --git a/packages/rocketchat-lib/server/methods/settings.coffee b/packages/rocketchat-lib/server/methods/settings.coffee new file mode 100644 index 00000000000..b2775cb055c --- /dev/null +++ b/packages/rocketchat-lib/server/methods/settings.coffee @@ -0,0 +1,12 @@ +Meteor.methods + saveSetting: (_id, value) -> + console.log '[method] saveSetting', _id, value + if Meteor.userId()? + user = Meteor.users.findOne Meteor.userId() + + unless RocketChat.authz.hasPermission(Meteor.userId(), 'edit-privileged-setting') is true + throw new Meteor.Error 503, 'Not authorized' + + # console.log "saveSetting -> ".green, _id, value + RocketChat.settings.updateById _id, value + return true -- GitLab From 6324e2bf04703ac1b2fb557c52e25038a79c8c63 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 03:27:55 -0200 Subject: [PATCH 0492/1338] re organising files --- packages/rocketchat-lib/package.js | 2 +- .../server/methods/{settings.coffee => saveSetting.coffee} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/rocketchat-lib/server/methods/{settings.coffee => saveSetting.coffee} (100%) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 2205d4ea6a6..d7b956828b9 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -54,7 +54,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/sendMessage.coffee', 'server'); api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); - api.addFiles('server/methods/settings.coffee', 'server'); + api.addFiles('server/methods/saveSetting.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/settings.coffee b/packages/rocketchat-lib/server/methods/saveSetting.coffee similarity index 100% rename from packages/rocketchat-lib/server/methods/settings.coffee rename to packages/rocketchat-lib/server/methods/saveSetting.coffee -- GitLab From 9682c27e687198da2afba0017f6f1bb6a03e9005 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 04:00:25 -0200 Subject: [PATCH 0493/1338] re organising files --- .meteor/versions | 2 +- .../client.coffee | 3 ++ .../package.js | 5 +-- .../{invite.coffee => server.coffee} | 0 .../client.coffee | 3 ++ .../rocketchat-slashcommands-join/join.coffee | 36 ------------------- .../rocketchat-slashcommands-join/package.js | 15 ++++---- .../server.coffee | 31 ++++++++++++++++ 8 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 packages/rocketchat-slashcommands-invite/client.coffee rename packages/rocketchat-slashcommands-invite/{invite.coffee => server.coffee} (100%) create mode 100644 packages/rocketchat-slashcommands-join/client.coffee delete mode 100644 packages/rocketchat-slashcommands-join/join.coffee create mode 100644 packages/rocketchat-slashcommands-join/server.coffee diff --git a/.meteor/versions b/.meteor/versions index d670b9baf4b..01da5f996c9 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -25,7 +25,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.1 +cosmos:browserify@0.9.2 dandv:caret-position@2.1.1 ddp@1.2.2 ddp-client@1.2.1 diff --git a/packages/rocketchat-slashcommands-invite/client.coffee b/packages/rocketchat-slashcommands-invite/client.coffee new file mode 100644 index 00000000000..8ddab57f6f4 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/client.coffee @@ -0,0 +1,3 @@ +RocketChat.slashCommands.add 'invite', undefined, + description: TAPi18n.__ 'Invite_user_to_join_channel' + params: '@username' diff --git a/packages/rocketchat-slashcommands-invite/package.js b/packages/rocketchat-slashcommands-invite/package.js index 8e8b9ea0d6d..a73b9e87f4e 100644 --- a/packages/rocketchat-slashcommands-invite/package.js +++ b/packages/rocketchat-slashcommands-invite/package.js @@ -6,16 +6,17 @@ Package.describe({ }); Package.onUse(function(api) { + api.versionsFrom('1.0'); api.use([ 'coffeescript', 'check', - 'tracker', 'rocketchat:lib@0.0.1' ]); - api.addFiles('invite.coffee'); + api.addFiles('client.coffee', 'client'); + api.addFiles('server.coffee', 'server'); // TAPi18n api.use('templating', 'client'); diff --git a/packages/rocketchat-slashcommands-invite/invite.coffee b/packages/rocketchat-slashcommands-invite/server.coffee similarity index 100% rename from packages/rocketchat-slashcommands-invite/invite.coffee rename to packages/rocketchat-slashcommands-invite/server.coffee diff --git a/packages/rocketchat-slashcommands-join/client.coffee b/packages/rocketchat-slashcommands-join/client.coffee new file mode 100644 index 00000000000..dec6e33938b --- /dev/null +++ b/packages/rocketchat-slashcommands-join/client.coffee @@ -0,0 +1,3 @@ +RocketChat.slashCommands.add 'join', undefined, + description: TAPi18n.__ 'Join_the_given_channel' + params: '#channel' diff --git a/packages/rocketchat-slashcommands-join/join.coffee b/packages/rocketchat-slashcommands-join/join.coffee deleted file mode 100644 index 9c28036121e..00000000000 --- a/packages/rocketchat-slashcommands-join/join.coffee +++ /dev/null @@ -1,36 +0,0 @@ -### -# Join is a named function that will replace /join commands -# @param {Object} message - The message object -### - -if Meteor.isClient - RocketChat.slashCommands.add 'join', undefined, - description: TAPi18n.__ 'Join_the_given_channel' - params: '#channel' -else - class Join - constructor: (command, params, item) -> - if command isnt 'join' or not Match.test params, String - return - - channel = params.trim() - if channel is '' - return - - channel = channel.replace('#', '') - - user = Meteor.users.findOne Meteor.userId() - room = RocketChat.models.Rooms.findOneByNameAndTypeNotContainigUsername(channel, 'c', user.username) - - if not room? - RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { - _id: Random.id() - rid: item.rid - ts: new Date - msg: TAPi18n.__('Channel_doesnt_exist', { postProcess: 'sprintf', sprintf: [ channel ] }, user.language); - } - return - - Meteor.call 'joinRoom', room._id - - RocketChat.slashCommands.add 'join', Join diff --git a/packages/rocketchat-slashcommands-join/package.js b/packages/rocketchat-slashcommands-join/package.js index 5dbf26d4f4b..04690ded85c 100644 --- a/packages/rocketchat-slashcommands-join/package.js +++ b/packages/rocketchat-slashcommands-join/package.js @@ -6,21 +6,20 @@ Package.describe({ }); Package.onUse(function(api) { - var client = 'client'; - var both = ['client', 'server']; api.versionsFrom('1.0'); - + api.use([ 'coffeescript', 'check', 'rocketchat:lib@0.0.1' - ], both); + ]); - api.addFiles('join.coffee', both); + api.addFiles('client.coffee', 'client'); + api.addFiles('server.coffee', 'server'); // TAPi18n - api.use('templating', client); + api.use('templating', 'client'); var _ = Npm.require('underscore'); var fs = Npm.require('fs'); tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-slashcommands-join/i18n'), function(filename) { @@ -28,9 +27,9 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', both); + api.use('tap:i18n@1.6.1', ['client', 'server']); api.imply('tap:i18n'); - api.addFiles(tapi18nFiles, both); + api.addFiles(tapi18nFiles, ['client', 'server']); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-slashcommands-join/server.coffee b/packages/rocketchat-slashcommands-join/server.coffee new file mode 100644 index 00000000000..96ada8b2f91 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/server.coffee @@ -0,0 +1,31 @@ +### +# Join is a named function that will replace /join commands +# @param {Object} message - The message object +### + +class Join + constructor: (command, params, item) -> + if command isnt 'join' or not Match.test params, String + return + + channel = params.trim() + if channel is '' + return + + channel = channel.replace('#', '') + + user = Meteor.users.findOne Meteor.userId() + room = RocketChat.models.Rooms.findOneByNameAndTypeNotContainigUsername(channel, 'c', user.username) + + if not room? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Channel_doesnt_exist', { postProcess: 'sprintf', sprintf: [ channel ] }, user.language); + } + return + + Meteor.call 'joinRoom', room._id + +RocketChat.slashCommands.add 'join', Join -- GitLab From 0d7f4746f4e78c2976ef79749d5c4915c4489342 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 04:00:56 -0200 Subject: [PATCH 0494/1338] re organising files --- .../server.coffee | 84 +++++++++---------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/packages/rocketchat-slashcommands-invite/server.coffee b/packages/rocketchat-slashcommands-invite/server.coffee index ee18862041b..36ae07981e5 100644 --- a/packages/rocketchat-slashcommands-invite/server.coffee +++ b/packages/rocketchat-slashcommands-invite/server.coffee @@ -3,48 +3,42 @@ # @param {Object} message - The message object ### -if Meteor.isClient - Tracker.autorun -> - RocketChat.slashCommands.add 'invite', undefined, - description: TAPi18n.__('Invite_user_to_join_channel') - params: '@username' -else - class Invite - constructor: (command, params, item) -> - if command isnt 'invite' or not Match.test params, String - return - - username = params.trim() - if username is '' - return - - username = username.replace('@', '') - - user = Meteor.users.findOne({ username: username }) - currentUser = Meteor.users.findOne Meteor.userId() - - if not user? - console.log 'notify user_doesnt_exist' - RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { - _id: Random.id() - rid: item.rid - ts: new Date - msg: TAPi18n.__('User_doesnt_exist', { postProcess: 'sprintf', sprintf: [ username ] }, currentUser.language) - } - return - - # cancel if the user is already in this room - if RocketChat.models.Rooms.findOneByIdContainigUsername(item.rid, user.username)? - RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { - _id: Random.id() - rid: item.rid - ts: new Date - msg: TAPi18n.__('Username_is_already_in_here', { postProcess: 'sprintf', sprintf: [ username ] }, currentUser.language) - } - return - - Meteor.runAsUser user._id, -> - Meteor.call 'joinRoom', item.rid - - - RocketChat.slashCommands.add 'invite', Invite +class Invite + constructor: (command, params, item) -> + if command isnt 'invite' or not Match.test params, String + return + + username = params.trim() + if username is '' + return + + username = username.replace('@', '') + + user = Meteor.users.findOne({ username: username }) + currentUser = Meteor.users.findOne Meteor.userId() + + if not user? + console.log 'notify user_doesnt_exist' + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('User_doesnt_exist', { postProcess: 'sprintf', sprintf: [ username ] }, currentUser.language) + } + return + + # cancel if the user is already in this room + if RocketChat.models.Rooms.findOneByIdContainigUsername(item.rid, user.username)? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_is_already_in_here', { postProcess: 'sprintf', sprintf: [ username ] }, currentUser.language) + } + return + + Meteor.runAsUser user._id, -> + Meteor.call 'joinRoom', item.rid + + +RocketChat.slashCommands.add 'invite', Invite -- GitLab From 58f7c0208aba7e5b55a371dfcfcab74a737b27fc Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 04:19:45 -0200 Subject: [PATCH 0495/1338] re organising files --- packages/rocketchat-lib/package.js | 6 ++--- .../methods}/addOAuthService.coffee | 22 ------------------- .../server/methods/removeOAuthService.coffee | 22 +++++++++++++++++++ 3 files changed, 25 insertions(+), 25 deletions(-) rename packages/rocketchat-lib/{settings/server => server/methods}/addOAuthService.coffee (68%) create mode 100644 packages/rocketchat-lib/server/methods/removeOAuthService.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index d7b956828b9..24c6d5fdc85 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -48,13 +48,15 @@ Package.onUse(function(api) { api.addFiles('server/functions/setUsername.coffee', 'server'); // SERVER METHODS + api.addFiles('server/methods/addOAuthService.coffee', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); + api.addFiles('server/methods/removeOAuthService.coffee', 'server'); api.addFiles('server/methods/robotMethods.coffee', 'server'); + 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/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); - api.addFiles('server/methods/saveSetting.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); @@ -63,10 +65,8 @@ Package.onUse(function(api) { // Settings api.addFiles('settings/lib/onLoadSettings.coffee'); - api.addFiles('settings/server/startup.coffee', 'server'); api.addFiles('settings/server/updateServices.coffee', 'server'); - api.addFiles('settings/server/addOAuthService.coffee', 'server'); // CLIENT LIB api.addFiles('client/lib/openRoom.coffee', 'client'); diff --git a/packages/rocketchat-lib/settings/server/addOAuthService.coffee b/packages/rocketchat-lib/server/methods/addOAuthService.coffee similarity index 68% rename from packages/rocketchat-lib/settings/server/addOAuthService.coffee rename to packages/rocketchat-lib/server/methods/addOAuthService.coffee index 9ce3c9ca140..bf10e8f8907 100644 --- a/packages/rocketchat-lib/settings/server/addOAuthService.coffee +++ b/packages/rocketchat-lib/server/methods/addOAuthService.coffee @@ -20,25 +20,3 @@ Meteor.methods 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'} 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'} RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_color" , '#13679A' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Color'} - - removeOAuthService: (name) -> - 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' - - name = name.toLowerCase().replace(/[^a-z0-9]/g, '') - name = s.capitalize(name) - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_url" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_token_path" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_identity_path" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_authorize_path" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_id" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_secret" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_button_label_text" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_button_label_color" - RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_button_color" diff --git a/packages/rocketchat-lib/server/methods/removeOAuthService.coffee b/packages/rocketchat-lib/server/methods/removeOAuthService.coffee new file mode 100644 index 00000000000..60d94fef7ee --- /dev/null +++ b/packages/rocketchat-lib/server/methods/removeOAuthService.coffee @@ -0,0 +1,22 @@ +Meteor.methods + removeOAuthService: (name) -> + 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' + + name = name.toLowerCase().replace(/[^a-z0-9]/g, '') + name = s.capitalize(name) + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_url" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_token_path" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_identity_path" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_authorize_path" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_id" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_secret" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_button_label_text" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_button_label_color" + RocketChat.settings.removeById "Accounts_OAuth_Custom_#{name}_button_color" -- GitLab From 7f914e3227d409f132a72d27d63f5ad9b4f69263 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 04:22:44 -0200 Subject: [PATCH 0496/1338] fix typo --- client/methods/updateMessage.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/methods/updateMessage.coffee b/client/methods/updateMessage.coffee index 378bb0c9bda..116f9fd0d54 100644 --- a/client/methods/updateMessage.coffee +++ b/client/methods/updateMessage.coffee @@ -33,7 +33,7 @@ Meteor.methods message = RocketChat.callbacks.run 'beforeSaveMessage', message ChatMessage.update - _id: message.id + _id: message._id 'u._id': Meteor.userId() , $set: -- GitLab From 97f04ecc2cc942e3d27d5d2885efa72a05631f1a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 04:42:35 -0200 Subject: [PATCH 0497/1338] re organising files --- .../startup/settingsOnLoadSiteUrl.coffee} | 0 packages/rocketchat-lib/package.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/rocketchat-lib/{settings/lib/onLoadSettings.coffee => lib/startup/settingsOnLoadSiteUrl.coffee} (100%) diff --git a/packages/rocketchat-lib/settings/lib/onLoadSettings.coffee b/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee similarity index 100% rename from packages/rocketchat-lib/settings/lib/onLoadSettings.coffee rename to packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 24c6d5fdc85..f5c0be2fee1 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -62,9 +62,9 @@ Package.onUse(function(api) { // COMMON STARTUP api.addFiles('lib/startup/settings.coffee'); + api.addFiles('lib/startup/settingsOnLoadSiteUrl.coffee'); // Settings - api.addFiles('settings/lib/onLoadSettings.coffee'); api.addFiles('settings/server/startup.coffee', 'server'); api.addFiles('settings/server/updateServices.coffee', 'server'); -- GitLab From 0bac65c89f1595620225c9f569653028617d0569 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 05:02:13 -0200 Subject: [PATCH 0498/1338] using onLoad --- packages/rocketchat-lib/server/cdn.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/server/cdn.coffee b/packages/rocketchat-lib/server/cdn.coffee index d41fcbd5d77..259fb10a78b 100644 --- a/packages/rocketchat-lib/server/cdn.coffee +++ b/packages/rocketchat-lib/server/cdn.coffee @@ -1,4 +1,3 @@ -Meteor.startup -> - cdnPrefix = RocketChat.settings.get 'CDN_PREFIX' - if cdnPrefix?.trim?() isnt '' - WebAppInternals.setBundledJsCssPrefix cdnPrefix +RocketChat.settings.onload 'CDN_PREFIX', (key, value, initialLoad) -> + if value?.trim() isnt '' + WebAppInternals.setBundledJsCssPrefix value -- GitLab From 4063ed880d745b09d7735303d0e1101971c5e4d2 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 05:20:06 -0200 Subject: [PATCH 0499/1338] re organising files --- packages/rocketchat-lib/package.js | 4 +++- .../{cdn.coffee => startup/settingsOnLoadCdnPrefix.coffee} | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename packages/rocketchat-lib/server/{cdn.coffee => startup/settingsOnLoadCdnPrefix.coffee} (100%) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index f5c0be2fee1..457c210612f 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -60,6 +60,9 @@ Package.onUse(function(api) { api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); + // SERVER STARTUP + api.addFiles('server/startup/settingsOnLoadCdnPrefix.coffee', 'server'); + // COMMON STARTUP api.addFiles('lib/startup/settings.coffee'); api.addFiles('lib/startup/settingsOnLoadSiteUrl.coffee'); @@ -85,7 +88,6 @@ Package.onUse(function(api) { api.addFiles('server/Notifications.coffee', 'server'); - api.addFiles('server/cdn.coffee', 'server'); // TAPi18n diff --git a/packages/rocketchat-lib/server/cdn.coffee b/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee similarity index 100% rename from packages/rocketchat-lib/server/cdn.coffee rename to packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee -- GitLab From f71c0fc14249c5f5b04b5863444cbb6d71be4674 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 05:35:34 -0200 Subject: [PATCH 0500/1338] rename updateServices -> oAuthServicesUpdate --- .../rocketchat-lib/settings/server/updateServices.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/settings/server/updateServices.coffee b/packages/rocketchat-lib/settings/server/updateServices.coffee index da290e2d081..0c126b370d5 100644 --- a/packages/rocketchat-lib/settings/server/updateServices.coffee +++ b/packages/rocketchat-lib/settings/server/updateServices.coffee @@ -1,5 +1,5 @@ timer = undefined -updateServices = -> +oAuthServicesUpdate = -> Meteor.clearTimeout timer if timer? timer = Meteor.setTimeout -> @@ -51,12 +51,12 @@ updateServices = -> RocketChat.models.Settings.find().observe added: (record) -> if /^Accounts_OAuth_.+/.test record._id - updateServices() + oAuthServicesUpdate() changed: (record) -> if /^Accounts_OAuth_.+/.test record._id - updateServices() + oAuthServicesUpdate() removed: (record) -> if /^Accounts_OAuth_.+/.test record._id - updateServices() + oAuthServicesUpdate() -- GitLab From 5e25c7d107d87f19150a693dd93cc95636c32a79 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 05:45:34 -0200 Subject: [PATCH 0501/1338] re organising files --- packages/rocketchat-lib/package.js | 12 +++--------- .../server/{ => functions}/Notifications.coffee | 0 .../startup/oAuthServicesUpdate.coffee} | 0 .../startup/settings.coffee} | 0 4 files changed, 3 insertions(+), 9 deletions(-) rename packages/rocketchat-lib/server/{ => functions}/Notifications.coffee (100%) rename packages/rocketchat-lib/{settings/server/updateServices.coffee => server/startup/oAuthServicesUpdate.coffee} (100%) rename packages/rocketchat-lib/{settings/server/startup.coffee => server/startup/settings.coffee} (100%) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 457c210612f..98b1adcf584 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -46,6 +46,7 @@ Package.onUse(function(api) { api.addFiles('server/functions/sendMessage.coffee', 'server'); api.addFiles('server/functions/settings.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); + api.addFiles('server/functions/Notifications.coffee', 'server'); // SERVER METHODS api.addFiles('server/methods/addOAuthService.coffee', 'server'); @@ -62,15 +63,13 @@ Package.onUse(function(api) { // SERVER STARTUP api.addFiles('server/startup/settingsOnLoadCdnPrefix.coffee', 'server'); + api.addFiles('server/startup/oAuthServicesUpdate.coffee', 'server'); + api.addFiles('server/startup/settings.coffee', 'server'); // COMMON STARTUP api.addFiles('lib/startup/settings.coffee'); api.addFiles('lib/startup/settingsOnLoadSiteUrl.coffee'); - // Settings - api.addFiles('settings/server/startup.coffee', 'server'); - api.addFiles('settings/server/updateServices.coffee', 'server'); - // CLIENT LIB api.addFiles('client/lib/openRoom.coffee', 'client'); api.addFiles('client/lib/roomExit.coffee', 'client'); @@ -85,11 +84,6 @@ Package.onUse(function(api) { api.addFiles('client/MessageAction.coffee', 'client'); api.addFiles('client/MessageTypes.coffee', 'client'); - - api.addFiles('server/Notifications.coffee', 'server'); - - - // TAPi18n api.use('templating', 'client'); var _ = Npm.require('underscore'); diff --git a/packages/rocketchat-lib/server/Notifications.coffee b/packages/rocketchat-lib/server/functions/Notifications.coffee similarity index 100% rename from packages/rocketchat-lib/server/Notifications.coffee rename to packages/rocketchat-lib/server/functions/Notifications.coffee diff --git a/packages/rocketchat-lib/settings/server/updateServices.coffee b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee similarity index 100% rename from packages/rocketchat-lib/settings/server/updateServices.coffee rename to packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee diff --git a/packages/rocketchat-lib/settings/server/startup.coffee b/packages/rocketchat-lib/server/startup/settings.coffee similarity index 100% rename from packages/rocketchat-lib/settings/server/startup.coffee rename to packages/rocketchat-lib/server/startup/settings.coffee -- GitLab From 552cc0f68407b7ae92de7d9efbab5a2e8f612f91 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 06:02:39 -0200 Subject: [PATCH 0502/1338] DDPRateLimiter.addRule to updateUserUtcOffset --- server/methods/updateUserUtcOffset.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/methods/updateUserUtcOffset.coffee b/server/methods/updateUserUtcOffset.coffee index a116647e1c2..9712ad9b5e7 100644 --- a/server/methods/updateUserUtcOffset.coffee +++ b/server/methods/updateUserUtcOffset.coffee @@ -6,3 +6,9 @@ Meteor.methods @unblock() RocketChat.models.Users.setUtcOffset @userId, utcOffset + +DDPRateLimiter.addRule + type: 'method' + name: 'updateUserUtcOffset' + userId: -> return true +, 1, 60000 -- GitLab From 3f059a25dfee1915db57ceb518b02fc8e5c9cfaf Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 06:02:39 -0200 Subject: [PATCH 0503/1338] DDPRateLimiter.addRule to updateUserUtcOffset --- server/methods/updateUserUtcOffset.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/methods/updateUserUtcOffset.coffee b/server/methods/updateUserUtcOffset.coffee index a116647e1c2..9712ad9b5e7 100644 --- a/server/methods/updateUserUtcOffset.coffee +++ b/server/methods/updateUserUtcOffset.coffee @@ -6,3 +6,9 @@ Meteor.methods @unblock() RocketChat.models.Users.setUtcOffset @userId, utcOffset + +DDPRateLimiter.addRule + type: 'method' + name: 'updateUserUtcOffset' + userId: -> return true +, 1, 60000 -- GitLab From a3bc930fc84f7a75eeb6768f5edcb40ea4ec5336 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 14:53:26 -0200 Subject: [PATCH 0504/1338] adding missing indexes --- .../rocketchat-lib/server/models/Rooms.coffee | 15 +++++++++------ .../rocketchat-lib/server/startup/settings.coffee | 5 +++++ server/startup/settings.coffee | 4 ---- 3 files changed, 14 insertions(+), 10 deletions(-) delete mode 100644 server/startup/settings.coffee diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index dddc8f8c021..b0c0d46c3e3 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -3,6 +3,9 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base @_initModel 'room' @tryEnsureIndex { 'name': 1 }, { unique: 1, sparse: 1 } + @tryEnsureIndex { 'default': 1 } + @tryEnsureIndex { 'usernames': 1 } + @tryEnsureIndex { 't': 1 } @tryEnsureIndex { 'u._id': 1 } @@ -124,15 +127,15 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base findByTypeAndName: (type, name, options) -> query = - t: type name: name + t: type return @find query, options findByTypeAndNameContainigUsername: (type, name, username, options) -> query = - t: type name: name + t: type usernames: username return @find query, options @@ -291,11 +294,11 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base return @update query, update setTypeById: (_id, type) -> - query = + query = _id: _id - update = - $set: + update = + $set: t: type return @update query, update @@ -304,8 +307,8 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base # INSERT createWithTypeNameUserAndUsernames: (type, name, user, usernames, extraData) -> room = - t: type name: name + t: type usernames: usernames msgs: 0 u: diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 0c7bb1e88bb..d9dd9f60896 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -118,3 +118,8 @@ Meteor.startup -> 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 } }, { $set: { hidden: true } }) + diff --git a/server/startup/settings.coffee b/server/startup/settings.coffee deleted file mode 100644 index 83132ad9a0e..00000000000 --- a/server/startup/settings.coffee +++ /dev/null @@ -1,4 +0,0 @@ -# Remove runtime settings (non-persistent) -Meteor.startup -> - RocketChat.models.Settings.update({ ts: { $lt: RocketChat.settings.ts } }, { $set: { hidden: true } }) - -- GitLab From 91e9f16be6c4d768f77ec668e1c4818faa40ed17 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 15:18:45 -0200 Subject: [PATCH 0505/1338] fixed typo --- .../server/functions/settings.coffee | 21 +++++-------------- .../server/startup/settings.coffee | 2 +- .../startup/settingsOnLoadCdnPrefix.coffee | 2 +- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 024d3f8af51..18bb2f6548e 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -12,6 +12,7 @@ RocketChat.settings.add = (_id, value, options = {}) -> options.packageValue = value options.valueSource = 'packageValue' + options.ts = new Date if process?.env?[_id]? value = process.env[_id] @@ -30,19 +31,12 @@ RocketChat.settings.add = (_id, value, options = {}) -> if not options.i18nDescription? options.i18nDescription = "#{_id}_Description" - upsertChanges = + return RocketChat.models.Settings.upsert { _id: _id }, $set: options $setOnInsert: value: value createdAt: new Date - if options.persistent is true - upsertChanges.$unset = { ts: true } - else - upsertChanges.$set.ts = new Date - - return RocketChat.models.Settings.upsert { _id: _id }, upsertChanges - ### # Add a setting group @@ -60,19 +54,14 @@ RocketChat.settings.addGroup = (_id, options = {}) -> if not options.i18nDescription? options.i18nDescription = "#{_id}_Description" - upsertChanges = + options.ts = new Date + + return RocketChat.models.Settings.upsert { _id: _id }, $set: options $setOnInsert: type: 'group' createdAt: new Date - if options.persistent is true - upsertChanges.$unset = { ts: true } - else - upsertChanges.$set.ts = new Date - - return RocketChat.models.Settings.upsert { _id: _id }, upsertChanges - ### # Remove a setting by id diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index d9dd9f60896..ffc4406ce92 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -121,5 +121,5 @@ Meteor.startup -> # Remove runtime settings (non-persistent) Meteor.startup -> - RocketChat.models.Settings.update({ ts: { $lt: RocketChat.settings.ts } }, { $set: { hidden: true } }) + RocketChat.models.Settings.update({ ts: { $lt: RocketChat.settings.ts }, persistent: false }, { $set: { hidden: true } }) diff --git a/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee b/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee index 259fb10a78b..f8cf5970cb5 100644 --- a/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee +++ b/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee @@ -1,3 +1,3 @@ RocketChat.settings.onload 'CDN_PREFIX', (key, value, initialLoad) -> if value?.trim() isnt '' - WebAppInternals.setBundledJsCssPrefix value + WebAppInternals?.setBundledJsCssPrefix value -- GitLab From 430e0b012c106bfaee9e3c6c271e4f63eeeda1cb Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 20 Nov 2015 15:40:20 -0200 Subject: [PATCH 0506/1338] support roomTypes with no permissions --- packages/rocketchat-lib/lib/roomTypes.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index 9b9c5b24504..f81ec0444f1 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -33,7 +33,7 @@ RocketChat.roomTypes = new class getAllTypes = -> typesPermitted = [] roomTypesOrder.forEach (type) -> - if roomTypes[type].permissions? and RocketChat.authz.hasAtLeastOnePermission roomTypes[type].permissions + if not roomTypes[type].permissions? or RocketChat.authz.hasAtLeastOnePermission roomTypes[type].permissions typesPermitted.push roomTypes[type] return typesPermitted -- GitLab From 7ba66cde82a72fc733e2e1c3ac3ceeed68ccd14e Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 16:16:52 -0200 Subject: [PATCH 0507/1338] split server and client settings initial loading logic --- .../lib/startup/settings.coffee | 22 +++---------------- .../server/startup/settings.coffee | 19 ++++++++++++++++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/rocketchat-lib/lib/startup/settings.coffee b/packages/rocketchat-lib/lib/startup/settings.coffee index 2077f3b4f4c..2d485274080 100644 --- a/packages/rocketchat-lib/lib/startup/settings.coffee +++ b/packages/rocketchat-lib/lib/startup/settings.coffee @@ -1,29 +1,13 @@ -if Meteor.isClient is true - @Settings = Settings = new Meteor.Collection 'rocketchat_settings' -else - Settings = RocketChat.models.Settings - +@Settings = Settings = new Meteor.Collection 'rocketchat_settings' initialLoad = true - -Meteor.settings ?= {} - -process?.env ?= {} - Settings.find().observe - added: (record) -> Meteor.settings[record._id] = record.value - 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 + Meteor.settings[record._id] = record.value RocketChat.settings.load record._id, record.value, initialLoad - removed: (record) -> - delete Meteor.settings?[record._id] - delete process?.env?[record._id] + delete Meteor.settings[record._id] RocketChat.settings.load record._id, undefined, initialLoad - initialLoad = false diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index ffc4406ce92..687fb6df216 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -113,12 +113,31 @@ RocketChat.settings.add 'Layout_Login_Terms', 'By proceeding to create your acco RocketChat.settings.add 'Statistics_opt_out', false, { type: 'boolean', group: false } + +initialLoad = true +RocketChat.models.Settings.find().observe + added: (record) -> + Meteor.settings[record._id] = record.value + 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 + RocketChat.settings.load record._id, record.value, initialLoad + removed: (record) -> + delete Meteor.settings[record._id] + delete process.env[record._id] + RocketChat.settings.load record._id, undefined, initialLoad +initialLoad = false + + 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: false }, { $set: { hidden: true } }) -- GitLab From 5866043c1e8fdbdf731c1aace53511a7e2741733 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 20 Nov 2015 17:50:37 -0200 Subject: [PATCH 0508/1338] split server and client settings initial loading logic --- .../rocketchat-lib/client/lib/settings.coffee | 26 ++++++++++++++++--- packages/rocketchat-lib/lib/settings.coffee | 6 +++++ .../lib/startup/settings.coffee | 13 ---------- packages/rocketchat-lib/package.js | 2 -- .../server/functions/settings.coffee | 21 +++++++++++++++ .../server/startup/settings.coffee | 18 +------------ .../startup/settingsOnLoadCdnPrefix.coffee | 7 ++++- 7 files changed, 56 insertions(+), 37 deletions(-) delete mode 100644 packages/rocketchat-lib/lib/startup/settings.coffee diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee index 6db18f21080..fdbfa3c26f6 100644 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ b/packages/rocketchat-lib/client/lib/settings.coffee @@ -3,12 +3,30 @@ # @namespace RocketChat.settings ### -settingsDict = new ReactiveDict('settings') +@Settings = new Meteor.Collection 'rocketchat_settings' RocketChat.settings.subscription = Meteor.subscribe 'settings' +RocketChat.settings.dict = new ReactiveDict 'settings' + RocketChat.settings.get = (_id) -> - return settingsDict.get(_id) + return RocketChat.settings.dict.get(_id) + +RocketChat.settings.init = -> + initialLoad = true + Settings.find().observe + added: (record) -> + Meteor.settings[record._id] = record.value + RocketChat.settings.dict.set record._id, record.value + RocketChat.settings.load record._id, record.value, initialLoad + changed: (record) -> + Meteor.settings[record._id] = record.value + RocketChat.settings.dict.set record._id, record.value + RocketChat.settings.load record._id, record.value, initialLoad + removed: (record) -> + delete Meteor.settings[record._id] + RocketChat.settings.dict.set record._id, undefined + RocketChat.settings.load record._id, undefined, initialLoad + initialLoad = false -RocketChat.settings.onload '*', (key, value) -> - return settingsDict.set key, value +RocketChat.settings.init() diff --git a/packages/rocketchat-lib/lib/settings.coffee b/packages/rocketchat-lib/lib/settings.coffee index e43641e8c1d..7f3694134de 100644 --- a/packages/rocketchat-lib/lib/settings.coffee +++ b/packages/rocketchat-lib/lib/settings.coffee @@ -35,5 +35,11 @@ RocketChat.settings = onload: (key, callback) -> + # if key is '*' + # for key, value in Meteor.settings + # callback key, value, false + # else if Meteor.settings?[_id]? + # callback key, Meteor.settings[_id], false + RocketChat.settings.callbacks[key] ?= [] RocketChat.settings.callbacks[key].push callback diff --git a/packages/rocketchat-lib/lib/startup/settings.coffee b/packages/rocketchat-lib/lib/startup/settings.coffee deleted file mode 100644 index 2d485274080..00000000000 --- a/packages/rocketchat-lib/lib/startup/settings.coffee +++ /dev/null @@ -1,13 +0,0 @@ -@Settings = Settings = new Meteor.Collection 'rocketchat_settings' -initialLoad = true -Settings.find().observe - added: (record) -> - Meteor.settings[record._id] = record.value - RocketChat.settings.load record._id, record.value, initialLoad - changed: (record) -> - Meteor.settings[record._id] = record.value - RocketChat.settings.load record._id, record.value, initialLoad - removed: (record) -> - delete Meteor.settings[record._id] - RocketChat.settings.load record._id, undefined, initialLoad -initialLoad = false diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 98b1adcf584..e103586f041 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -67,7 +67,6 @@ Package.onUse(function(api) { api.addFiles('server/startup/settings.coffee', 'server'); // COMMON STARTUP - api.addFiles('lib/startup/settings.coffee'); api.addFiles('lib/startup/settingsOnLoadSiteUrl.coffee'); // CLIENT LIB @@ -77,7 +76,6 @@ Package.onUse(function(api) { // CLIENT METHODS api.addFiles('client/methods/sendMessage.coffee', 'client'); - api.addFiles('client/AdminBox.coffee', 'client'); api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 18bb2f6548e..eede3324732 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -87,3 +87,24 @@ RocketChat.settings.updateById = (_id, value) -> return false return RocketChat.models.Settings.updateValueById _id, value + + +### +# Update a setting by id +### +RocketChat.settings.init = -> + initialLoad = true + RocketChat.models.Settings.find().observe + added: (record) -> + Meteor.settings[record._id] = record.value + 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 + RocketChat.settings.load record._id, record.value, initialLoad + removed: (record) -> + delete Meteor.settings[record._id] + delete process.env[record._id] + RocketChat.settings.load record._id, undefined, initialLoad + initialLoad = false diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 687fb6df216..f1985261ece 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -113,23 +113,7 @@ RocketChat.settings.add 'Layout_Login_Terms', 'By proceeding to create your acco RocketChat.settings.add 'Statistics_opt_out', false, { type: 'boolean', group: false } - -initialLoad = true -RocketChat.models.Settings.find().observe - added: (record) -> - Meteor.settings[record._id] = record.value - 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 - RocketChat.settings.load record._id, record.value, initialLoad - removed: (record) -> - delete Meteor.settings[record._id] - delete process.env[record._id] - RocketChat.settings.load record._id, undefined, initialLoad -initialLoad = 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') diff --git a/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee b/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee index f8cf5970cb5..98100d83666 100644 --- a/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee +++ b/packages/rocketchat-lib/server/startup/settingsOnLoadCdnPrefix.coffee @@ -1,3 +1,8 @@ RocketChat.settings.onload 'CDN_PREFIX', (key, value, initialLoad) -> - if value?.trim() isnt '' + if _.isString value + WebAppInternals?.setBundledJsCssPrefix value + +Meteor.startup -> + value = RocketChat.settings.get 'CDN_PREFIX' + if _.isString value WebAppInternals?.setBundledJsCssPrefix value -- GitLab From 1c023137cd9e652a3a34c721a6eb376f05a1ed68 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 20 Nov 2015 17:58:41 -0200 Subject: [PATCH 0509/1338] add starred rooms back --- client/startup/defaultRoomTypes.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index e027a74625d..c7546e4a884 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,6 +1,7 @@ Meteor.startup -> - # RocketChat.roomTypes.addType('starredRooms', roles); - # roles = ['admin', 'moderator', 'user'] + RocketChat.roomTypes.add 'starred', + template: 'starredRooms' + icon: 'icon-star' RocketChat.roomTypes.add 'c', template: 'channels' -- GitLab From a84e4638f7cbf68ab4d2a4e5c9b2da408d65afa9 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 00:29:12 -0500 Subject: [PATCH 0510/1338] build with branch name --- .travis.yml | 2 +- .travis/namedemo.sh | 4 ++-- .travis/namefiles.sh | 4 ++-- .travis/setbuildinfo.js | 8 +++++++- Dockerfile | 2 +- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7f417e0c6a..dea9da73a3a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- meteor add rocketchat:livechat rocketchat:hubot +- meteor add rocketchat:livechat rocketchat:hubot - meteor build --server demo.rocket.chat ../build - cd .travis - sh ./namedemo.sh diff --git a/.travis/namedemo.sh b/.travis/namedemo.sh index 67663a3497f..2c32f690d7f 100644 --- a/.travis/namedemo.sh +++ b/.travis/namedemo.sh @@ -1,5 +1,5 @@ cd ../../build FILENAME=demo.rocket.chat-`cat version.txt`.tgz -mv Rocket.Chat.tar.gz $FILENAME -ln -s $FILENAME demo.rocket.chat-v.latest.tgz +mv Rocket.Chat.tar.gz "$FILENAME" +ln -s "$FILENAME" demo.rocket.chat-v.latest.tgz diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 6f56508c24e..7122c54414f 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,5 +1,5 @@ cd ../../build FILENAME=rocket.chat-`cat version.txt`.tgz -mv Rocket.Chat.tar.gz $FILENAME -ln -s $FILENAME rocket.chat-v.latest.tgz +mv Rocket.Chat.tar.gz "$FILENAME" +ln -s "$FILENAME" "$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index ffef83bd3bc..6387fecef4a 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -8,11 +8,17 @@ var lr = new LineByLineReader(BUILD_INFO_PATH); var firstline = ""; + if (process.env.TRAVIS_BUILD_NUMBER) { var transformVersion = function (firstline) { var versions = firstline.split("."); + var verstring = versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BUILD_NUMBER + '-' + process.env.TRAVIS_BRANCH + '\n'; + if (process.env.TRAVIS_TAG) { + verstring = TRAVIS_TAG + '-' + process.env.TRAVIS_BRANCH + '\n'; + + } - return versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BUILD_NUMBER + '\n'; + return verstring; }; diff --git a/Dockerfile b/Dockerfile index 386758a3f39..d43c1d2cd2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ +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 \ -- GitLab From 4a3152397747bf4713a8f3bf9bee9ed6844e5082 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 00:34:03 -0500 Subject: [PATCH 0511/1338] trigger build --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1529c385dd6..74cd0a3e905 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The Ultimate Open Source WebChat Platform -## Demo +## Demo Checkout the latest version at [https://demo.rocket.chat](https://demo.rocket.chat) -- GitLab From 02805f7a38702c3a54560d364a1a48c669a6e81b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 00:53:19 -0500 Subject: [PATCH 0512/1338] add master branch and fix version number format --- .travis.yml | 2 ++ .travis/setbuildinfo.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dea9da73a3a..19d07ea5649 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: node_js branches: only: - develop + - master node_js: - '0.12' addons: @@ -50,3 +51,4 @@ deploy: on: branch: - develop + - master diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js index 6387fecef4a..4b05518c724 100644 --- a/.travis/setbuildinfo.js +++ b/.travis/setbuildinfo.js @@ -12,9 +12,9 @@ var firstline = ""; if (process.env.TRAVIS_BUILD_NUMBER) { var transformVersion = function (firstline) { var versions = firstline.split("."); - var verstring = versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BUILD_NUMBER + '-' + process.env.TRAVIS_BRANCH + '\n'; + var verstring = versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BRANCH + '.' + process.env.TRAVIS_BUILD_NUMBER + '\n'; if (process.env.TRAVIS_TAG) { - verstring = TRAVIS_TAG + '-' + process.env.TRAVIS_BRANCH + '\n'; + verstring = TRAVIS_TAG + '\n'; } -- GitLab From d7761114f799645b8b5474b6790dd61144f5ee74 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 06:50:01 -0500 Subject: [PATCH 0513/1338] add docker tagging --- .travis.yml | 3 ++- .travis/builddocker.sh | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .travis/builddocker.sh diff --git a/.travis.yml b/.travis.yml index 19d07ea5649..238266b5b9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,8 @@ script: - sh ./namedemo.sh - cd .. after_deploy: -- "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" +- cd .travis +- sh ./builddocker.sh deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh new file mode 100644 index 00000000000..cec3db23b27 --- /dev/null +++ b/.travis/builddocker.sh @@ -0,0 +1,5 @@ +if [ -z ${TRAVIS_TAG+x} ]; +then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': \'$TRAVIS_BRANCH\', 'docker_tag': \'`cat ../../build/version.txt`\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': \'$TRAVIS_TAG\', 'docker_tag': \'`cat ../../build/version.txt`\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +fi + -- GitLab From 2ee6c44044dd68ab47083b266f3db6350e44c4af Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 11:17:04 -0500 Subject: [PATCH 0514/1338] add dockerfiles --- .docker/dockerfiles/develop/Dockerfile | 37 ++++++++++++++++++++++++++ .docker/dockerfiles/master/Dockerfile | 37 ++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 .docker/dockerfiles/develop/Dockerfile create mode 100644 .docker/dockerfiles/master/Dockerfile diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile new file mode 100644 index 00000000000..d43c1d2cd2c --- /dev/null +++ b/.docker/dockerfiles/develop/Dockerfile @@ -0,0 +1,37 @@ +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/.docker/dockerfiles/master/Dockerfile b/.docker/dockerfiles/master/Dockerfile new file mode 100644 index 00000000000..32770f2b470 --- /dev/null +++ b/.docker/dockerfiles/master/Dockerfile @@ -0,0 +1,37 @@ +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/master.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"] -- GitLab From c23be4c49432bf50249c84f07614a0838e30b0c8 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 11:59:06 -0500 Subject: [PATCH 0515/1338] default to latest build --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 07624dc9669..84e3a13dd78 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ mongo: command: mongod --smallfiles rocketchat: - image: rocketchat/rocket.chat + image: rocketchat/rocket.chat:develop # volumes: # - ./uploads:/app/uploads environment: -- GitLab From e025e941396377378673032f5f2500fc29861d91 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 21 Nov 2015 14:07:25 -0500 Subject: [PATCH 0516/1338] fight travis glitch --- {.docker => .dockerfiles}/dockerfiles/develop/Dockerfile | 0 {.docker => .dockerfiles}/dockerfiles/master/Dockerfile | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {.docker => .dockerfiles}/dockerfiles/develop/Dockerfile (100%) rename {.docker => .dockerfiles}/dockerfiles/master/Dockerfile (100%) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.dockerfiles/dockerfiles/develop/Dockerfile similarity index 100% rename from .docker/dockerfiles/develop/Dockerfile rename to .dockerfiles/dockerfiles/develop/Dockerfile diff --git a/.docker/dockerfiles/master/Dockerfile b/.dockerfiles/dockerfiles/master/Dockerfile similarity index 100% rename from .docker/dockerfiles/master/Dockerfile rename to .dockerfiles/dockerfiles/master/Dockerfile -- GitLab From 2b99308a3dfb1cfd9d591b7ccb0221171a67e8ab Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sat, 21 Nov 2015 20:25:41 -0500 Subject: [PATCH 0517/1338] fix drag and drop upload - closes #1439 Missing dependency from recent 'refactoring' of UI into packages --- packages/rocketchat-ui/package.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index b7fef9bb438..34ddea1afb0 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -24,7 +24,8 @@ Package.onUse(function(api) { 'coffeescript', 'underscore', 'rocketchat:lib@0.0.1', - 'raix:push' + 'raix:push', + 'raix:ui-dropped-event' ]); // LIB FILES -- GitLab From b563982d5647756e1c179cb4956f64691963c62c Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sun, 22 Nov 2015 12:07:05 -0500 Subject: [PATCH 0518/1338] fight travis glitch try a local fix prior to availability of travis fix --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 238266b5b9d..1f3e1c34cd6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ script: - cd .travis - sh ./namedemo.sh - cd .. +- sudo gem install mime-types after_deploy: - cd .travis - sh ./builddocker.sh -- GitLab From 7e5bccaa92d539fcbb1f6ccf15e4fd792c856518 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sun, 22 Nov 2015 12:45:00 -0500 Subject: [PATCH 0519/1338] fight travis glitch try local fix before travis fix become availalbe --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1f3e1c34cd6..68f7d0fd516 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ addons: before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' +- gem install mime-types - mkdir -p node_modules - npm install phantomjs - npm install velocity-cli @@ -39,7 +40,6 @@ script: - cd .travis - sh ./namedemo.sh - cd .. -- sudo gem install mime-types after_deploy: - cd .travis - sh ./builddocker.sh -- GitLab From 44602cf4ae1d04d973f60345178aa8407f118b1b Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sun, 22 Nov 2015 13:03:40 -0500 Subject: [PATCH 0520/1338] fight travis glitch try local fix before travis fix becomes available --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 68f7d0fd516..32924fac3b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ addons: before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' -- gem install mime-types +- gem install mime-types -v 2.99 - mkdir -p node_modules - npm install phantomjs - npm install velocity-cli -- GitLab From da7b8289b4fea02fb2f8ee0b6c415903562b06cd Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sun, 22 Nov 2015 18:39:19 -0500 Subject: [PATCH 0521/1338] Add support for mobile client for server binaries add support for mobile client for pre-built server binaries tgz --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 84e3a13dd78..73f149c5479 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,8 @@ rocketchat: - ROOT=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: -- GitLab From 14b502de5b30c011068124aca754f4cbaf7e655b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 10:09:33 -0200 Subject: [PATCH 0522/1338] configure room routes from roomTypes API --- client/routes/roomRoute.coffee | 40 +------------------- packages/rocketchat-lib/lib/roomTypes.coffee | 6 +++ 2 files changed, 7 insertions(+), 39 deletions(-) diff --git a/client/routes/roomRoute.coffee b/client/routes/roomRoute.coffee index 96ecb33cede..395d387d46d 100644 --- a/client/routes/roomRoute.coffee +++ b/client/routes/roomRoute.coffee @@ -1,42 +1,4 @@ -FlowRouter.route '/channel/:name', - name: 'channel' - - action: (params, queryParams) -> - Session.set 'showUserInfo' - openRoom 'c', params.name - - triggersExit: [roomExit] - - -FlowRouter.route '/group/:name', - name: 'group' - - action: (params, queryParams) -> - Session.set 'showUserInfo' - openRoom 'p', params.name - - triggersExit: [roomExit] - - -FlowRouter.route '/direct/:username', - name: 'direct' - - action: (params, queryParams) -> - Session.set 'showUserInfo', params.username - openRoom 'd', params.username - - triggersExit: [roomExit] - - FlowRouter.goToRoomById = (roomId) -> subscription = ChatSubscription.findOne({rid: roomId}) if subscription? - switch subscription.t - when 'c' - FlowRouter.go 'channel', {name: subscription.name} - - when 'p' - FlowRouter.go 'group', {name: subscription.name} - - when 'd' - FlowRouter.go 'direct', {username: subscription.name} + FlowRouter.go RocketChat.roomTypes.getRouteLink subscription.t, subscription diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index f81ec0444f1..7ae907bdfe5 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -20,6 +20,12 @@ RocketChat.roomTypes = new class roomTypesOrder.push identifier roomTypes[identifier] = config + if config.route?.path? and config.route?.name? and config.route?.action? + FlowRouter.route config.route.path, + name: config.route.name + action: config.route.action + triggersExit: [roomExit] + ### @param roomType: room type (e.g.: c (for channels), d (for direct channels)) @param subData: the user's subscription data -- GitLab From 9ef9607ed39d435b2a15dce3225a4636a638931b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 10:09:55 -0200 Subject: [PATCH 0523/1338] roomTypes NEEDS to be declared before startup --- client/startup/defaultRoomTypes.coffee | 79 +++++++++++++------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index c7546e4a884..c50823a9910 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,43 +1,42 @@ -Meteor.startup -> - RocketChat.roomTypes.add 'starred', - template: 'starredRooms' - icon: 'icon-star' +RocketChat.roomTypes.add 'starred', + template: 'starredRooms' + icon: 'icon-star' - RocketChat.roomTypes.add 'c', - template: 'channels' - icon: 'icon-hash' - route: - name: 'channel' - path: '/channel/:name' - action: (params, queryParams) -> - Session.set 'showUserInfo' - openRoom 'c', params.name - link: (sub) -> - return { name: sub.name } - permissions: [ 'view-c-room' ] +RocketChat.roomTypes.add 'c', + template: 'channels' + icon: 'icon-hash' + route: + name: 'channel' + path: '/channel/:name' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'c', params.name + link: (sub) -> + return { name: sub.name } + permissions: [ 'view-c-room' ] - RocketChat.roomTypes.add 'd', - template: 'directMessages' - icon: 'icon-at' - route: - name: 'direct' - path: '/direct/:username' - action: (params, queryParams) -> - Session.set 'showUserInfo' - openRoom 'd', params.name - link: (sub) -> - return { username: sub.name } - permissions: [ 'view-d-room' ] +RocketChat.roomTypes.add 'd', + template: 'directMessages' + icon: 'icon-at' + route: + name: 'direct' + path: '/direct/:username' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'd', params.username + link: (sub) -> + return { username: sub.name } + permissions: [ 'view-d-room' ] - RocketChat.roomTypes.add 'p', - template: 'privateGroups' - icon: 'icon-lock' - route: - name: 'group' - path: '/group/:name' - action: (params, queryParams) -> - Session.set 'showUserInfo' - openRoom 'p', params.name - link: (sub) -> - return { name: sub.name } - permissions: [ 'view-p-room' ] +RocketChat.roomTypes.add 'p', + template: 'privateGroups' + icon: 'icon-lock' + route: + name: 'group' + path: '/group/:name' + action: (params, queryParams) -> + Session.set 'showUserInfo' + openRoom 'p', params.name + link: (sub) -> + return { name: sub.name } + permissions: [ 'view-p-room' ] -- GitLab From c25b78c3c88c823be0cc117dd41ccf9af0fdbec3 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 10:10:49 -0200 Subject: [PATCH 0524/1338] fix redundancy --- packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee index 12767b5eabd..6b0aa396d44 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee @@ -33,7 +33,7 @@ Template.chatRoomItem.helpers return true route: -> - FlowRouter.path RocketChat.roomTypes.getRouteLink @t, @ + return RocketChat.roomTypes.getRouteLink @t, @ Template.chatRoomItem.rendered = -> if not (FlowRouter.getParam('_id')? and FlowRouter.getParam('_id') is this.data.rid) and not this.data.ls -- GitLab From fc410257075fda0633356e81ed8a8e8cbea7359d Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 23 Nov 2015 13:21:05 +0000 Subject: [PATCH 0525/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 66 ++++++++++- i18n/cs.i18n.json | 46 ++++++++ i18n/de.i18n.json | 3 - i18n/en.i18n.json | 110 +----------------- i18n/fi.i18n.json | 3 - i18n/fr.i18n.json | 3 - i18n/hr.i18n.json | 3 - i18n/km.i18n.json | 3 - i18n/ko.i18n.json | 29 ++++- i18n/ms-MY.i18n.json | 2 - i18n/pl.i18n.json | 2 - i18n/pt.i18n.json | 3 - i18n/tr.i18n.json | 2 - i18n/zh.i18n.json | 2 - .../i18n/ar.i18n.json | 1 + .../i18n/cs.i18n.json | 1 + .../i18n/de.i18n.json | 1 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 14 +-- .../i18n/es.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 1 + .../i18n/fr.i18n.json | 1 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 1 + .../i18n/ko.i18n.json | 8 ++ .../i18n/ms-MY.i18n.json | 1 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 1 + .../i18n/ru.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + packages/rocketchat-chatops/i18n/cs.i18n.json | 1 + .../i18n/cs.i18n.json | 1 + .../i18n/en.i18n.json | 5 +- .../i18n/ko.i18n.json | 3 +- packages/rocketchat-gitlab/i18n/cs.i18n.json | 1 + packages/rocketchat-hubot/i18n/cs.i18n.json | 1 + packages/rocketchat-ldap/i18n/cs.i18n.json | 1 + packages/rocketchat-lib/i18n/ar.i18n.json | 1 + packages/rocketchat-lib/i18n/cs.i18n.json | 1 + packages/rocketchat-lib/i18n/de.i18n.json | 4 + packages/rocketchat-lib/i18n/el.i18n.json | 1 + packages/rocketchat-lib/i18n/en.i18n.json | 4 +- packages/rocketchat-lib/i18n/es.i18n.json | 1 + packages/rocketchat-lib/i18n/fa.i18n.json | 1 + packages/rocketchat-lib/i18n/fi.i18n.json | 4 + packages/rocketchat-lib/i18n/fr.i18n.json | 4 + packages/rocketchat-lib/i18n/he.i18n.json | 1 + packages/rocketchat-lib/i18n/hr.i18n.json | 4 + packages/rocketchat-lib/i18n/hu.i18n.json | 1 + packages/rocketchat-lib/i18n/it.i18n.json | 1 + packages/rocketchat-lib/i18n/ja.i18n.json | 1 + packages/rocketchat-lib/i18n/km.i18n.json | 4 + packages/rocketchat-lib/i18n/ko.i18n.json | 4 + packages/rocketchat-lib/i18n/ms-MY.i18n.json | 4 + packages/rocketchat-lib/i18n/pl.i18n.json | 4 + packages/rocketchat-lib/i18n/pt.i18n.json | 4 +- packages/rocketchat-lib/i18n/ru.i18n.json | 1 + packages/rocketchat-lib/i18n/sv.i18n.json | 1 + packages/rocketchat-lib/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-lib/i18n/tr.i18n.json | 4 + packages/rocketchat-lib/i18n/ug.i18n.json | 1 + packages/rocketchat-lib/i18n/uk.i18n.json | 1 + packages/rocketchat-lib/i18n/zh.i18n.json | 4 + .../rocketchat-livechat/i18n/cs.i18n.json | 1 + packages/rocketchat-mailer/i18n/cs.i18n.json | 1 + packages/rocketchat-mailer/i18n/ko.i18n.json | 8 +- .../rocketchat-message-pin/i18n/cs.i18n.json | 1 + .../rocketchat-message-pin/i18n/de.i18n.json | 4 +- .../rocketchat-message-pin/i18n/en.i18n.json | 8 +- .../rocketchat-message-pin/i18n/fi.i18n.json | 4 +- .../rocketchat-message-pin/i18n/fr.i18n.json | 4 +- .../rocketchat-message-pin/i18n/hr.i18n.json | 4 +- .../rocketchat-message-pin/i18n/km.i18n.json | 4 +- .../rocketchat-message-pin/i18n/ko.i18n.json | 8 +- .../rocketchat-message-pin/i18n/pt.i18n.json | 4 +- .../rocketchat-message-star/i18n/cs.i18n.json | 1 + .../rocketchat-message-star/i18n/en.i18n.json | 3 +- .../i18n/cs.i18n.json | 1 + .../i18n/ko.i18n.json | 5 +- .../i18n/cs.i18n.json | 1 + .../i18n/ko.i18n.json | 4 +- packages/rocketchat-theme/i18n/ar.i18n.json | 1 + packages/rocketchat-theme/i18n/cs.i18n.json | 1 + packages/rocketchat-theme/i18n/de.i18n.json | 1 + packages/rocketchat-theme/i18n/el.i18n.json | 1 + packages/rocketchat-theme/i18n/en.i18n.json | 68 ++++------- packages/rocketchat-theme/i18n/es.i18n.json | 1 + packages/rocketchat-theme/i18n/fa.i18n.json | 1 + packages/rocketchat-theme/i18n/fi.i18n.json | 1 + packages/rocketchat-theme/i18n/fr.i18n.json | 1 + packages/rocketchat-theme/i18n/he.i18n.json | 1 + packages/rocketchat-theme/i18n/hr.i18n.json | 1 + packages/rocketchat-theme/i18n/hu.i18n.json | 1 + packages/rocketchat-theme/i18n/it.i18n.json | 1 + packages/rocketchat-theme/i18n/ja.i18n.json | 1 + packages/rocketchat-theme/i18n/km.i18n.json | 1 + packages/rocketchat-theme/i18n/ko.i18n.json | 11 ++ .../rocketchat-theme/i18n/ms-MY.i18n.json | 1 + packages/rocketchat-theme/i18n/pl.i18n.json | 1 + packages/rocketchat-theme/i18n/pt.i18n.json | 1 + packages/rocketchat-theme/i18n/ru.i18n.json | 1 + packages/rocketchat-theme/i18n/sv.i18n.json | 1 + .../rocketchat-theme/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-theme/i18n/tr.i18n.json | 1 + packages/rocketchat-theme/i18n/ug.i18n.json | 1 + packages/rocketchat-theme/i18n/uk.i18n.json | 1 + packages/rocketchat-theme/i18n/zh.i18n.json | 1 + packages/rocketchat-webrtc/i18n/cs.i18n.json | 1 + packages/rocketchat-webrtc/i18n/en.i18n.json | 8 +- .../rocketchat-wordpress/i18n/cs.i18n.json | 1 + .../rocketchat-wordpress/i18n/en.i18n.json | 8 +- 121 files changed, 357 insertions(+), 228 deletions(-) create mode 100644 i18n/cs.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ar.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/cs.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/de.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/el.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/es.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/fa.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/fi.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/fr.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/he.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/hr.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/hu.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/it.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ja.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/km.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ko.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/pl.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/pt.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ru.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/sv.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/tr.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ug.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/uk.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/zh.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/cs.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/cs.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/cs.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/cs.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/cs.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ar.i18n.json create mode 100644 packages/rocketchat-lib/i18n/cs.i18n.json create mode 100644 packages/rocketchat-lib/i18n/de.i18n.json create mode 100644 packages/rocketchat-lib/i18n/el.i18n.json create mode 100644 packages/rocketchat-lib/i18n/es.i18n.json create mode 100644 packages/rocketchat-lib/i18n/fa.i18n.json create mode 100644 packages/rocketchat-lib/i18n/fi.i18n.json create mode 100644 packages/rocketchat-lib/i18n/fr.i18n.json create mode 100644 packages/rocketchat-lib/i18n/he.i18n.json create mode 100644 packages/rocketchat-lib/i18n/hr.i18n.json create mode 100644 packages/rocketchat-lib/i18n/hu.i18n.json create mode 100644 packages/rocketchat-lib/i18n/it.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ja.i18n.json create mode 100644 packages/rocketchat-lib/i18n/km.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ko.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-lib/i18n/pl.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ru.i18n.json create mode 100644 packages/rocketchat-lib/i18n/sv.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-lib/i18n/tr.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ug.i18n.json create mode 100644 packages/rocketchat-lib/i18n/uk.i18n.json create mode 100644 packages/rocketchat-lib/i18n/zh.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/cs.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/cs.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/cs.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/cs.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/cs.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/cs.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ar.i18n.json create mode 100644 packages/rocketchat-theme/i18n/cs.i18n.json create mode 100644 packages/rocketchat-theme/i18n/de.i18n.json create mode 100644 packages/rocketchat-theme/i18n/el.i18n.json create mode 100644 packages/rocketchat-theme/i18n/es.i18n.json create mode 100644 packages/rocketchat-theme/i18n/fa.i18n.json create mode 100644 packages/rocketchat-theme/i18n/fi.i18n.json create mode 100644 packages/rocketchat-theme/i18n/fr.i18n.json create mode 100644 packages/rocketchat-theme/i18n/he.i18n.json create mode 100644 packages/rocketchat-theme/i18n/hr.i18n.json create mode 100644 packages/rocketchat-theme/i18n/hu.i18n.json create mode 100644 packages/rocketchat-theme/i18n/it.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ja.i18n.json create mode 100644 packages/rocketchat-theme/i18n/km.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ko.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-theme/i18n/pl.i18n.json create mode 100644 packages/rocketchat-theme/i18n/pt.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ru.i18n.json create mode 100644 packages/rocketchat-theme/i18n/sv.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-theme/i18n/tr.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ug.i18n.json create mode 100644 packages/rocketchat-theme/i18n/uk.i18n.json create mode 100644 packages/rocketchat-theme/i18n/zh.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/cs.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/cs.i18n.json diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index 861332c202f..eca96366ccf 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -1,6 +1,68 @@ { + "Add_users" : "إضاÙØ© مستخدمين", "and" : "Ùˆ", - "Email_verified" : "البريد الإلكتروني التØقق", + "Cancel" : "إلغاء", + "Channels" : "القنوات", + "Channels_list" : "قائمة القنوات العامة", + "Chat_Rooms" : "غر٠المØادثة", + "close" : "أغلق", + "Confirm_password" : "تأكيد كلمة السر", + "Conversation" : "Ù…Øادثة", + "Create_new_public_channel" : "إنشاء قناة عامة جديدة", + "Direct_Messages" : "الرسائل المباشرة", + "edited" : "عدلت", + "Email_or_username" : "البريد الإلكتروني أو اسم المستخدم", + "Email_verified" : "تم التØقق من البريد الإلكتروني", + "Enter_info" : "ادخل المعلومات الخاصة بك", + "Error_changing_password" : "خطأ ÙÙŠ تغيير كلمة السر", + "Favorites" : "المÙضلة", + "Forgot_password" : "نسيت كلمة السر", + "Hide_room" : "إخÙاء الغرÙØ©", + "History" : "تاريخ", + "Invalid_confirm_pass" : "تأكيد كلمة السر لا تطابق كلمة السر", + "Invalid_email" : "البريد الإلكتروني المدخل غير صØÙŠØ", + "Invalid_name" : "لا يجب أن يكون الاسم Ùارغ", + "Invalid_pass" : "لا يجب أن تكون كلمة السر Ùارغة", + "Language_Version" : "النسخة الإنجليزية", + "Last_message" : "آخر رسالة", + "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" : "لا يوجد لديك مجموعات خاصة Øتى الآن.", + "Password" : "كلمة السر", + "Please_wait" : "يرجى الانتظار", + "Private_Groups" : "مجموعات خاصة", + "Quick_Search" : "بØØ« سريع", + "Register" : "تسجيل Øساب جديد", + "Remember_me" : "تذكرني", + "Remove" : "إزالة", + "Reset_password" : "إعادة تعيين كلمة السر", + "Room" : "غرÙØ©", + "Room_name_changed" : "تم تغيير اسم الغرÙØ© إلى: <em>__room_name__</em> بواسطة <em>__user_by__</em>", + "Room_name_changed_successfully" : "تم تغيير اسم الغرÙØ© بنجاØ", + "Save" : "ØÙظ", + "Search" : "بØØ«", + "Selected_users" : "أعضاء مختارين", + "Send_confirmation_email" : "إرسال رسالة تأكيد", + "Send_Message" : "أرسل رسالة", + "Start_of_conversation" : "بداية المØادثة", + "use_menu" : "استخدم القائمة الجانبية للوصول إلى الغر٠الخاصة بك والمØادثات", + "User_added_by" : "تم إضاÙØ© <em>__user_added__</em> بواسطة <em>__user_by__</em>.", "User_joined_channel" : "وقد انضمت قناة.", - "User_left" : "العضو <em>__user_left__</em>يقم." + "User_left" : "غادر القناة.", + "User_removed_by" : "تم ØØ°Ù <em>__user_removed__</em> بواسطة <em>__user_by__</em>.", + "View_All" : "مشاهدة الكل", + "Welcome" : "مرØبا بك يا <em>%s</em>.", + "Welcome_to_the" : "أهلا بك ÙÙŠ", + "You_need_confirm_email" : "تØتاج إلى تأكيد بريدك الإلكتروني لتسجيل الدخول!" } \ No newline at end of file diff --git a/i18n/cs.i18n.json b/i18n/cs.i18n.json new file mode 100644 index 00000000000..ea6cb524892 --- /dev/null +++ b/i18n/cs.i18n.json @@ -0,0 +1,46 @@ +{ + "Add_users" : "PÅ™idat uživatele", + "are_also_typing" : "také pÃÅ¡Ã", + "are_typing" : "pÃÅ¡Ã", + "Channels" : "Kanály", + "Channels_list" : "Seznam veÅ™ejných kanálů", + "Create_new_public_channel" : "VytvoÅ™it nový veÅ™ejný kanál", + "Direct_Messages" : "PÅ™Ãmé zprávy", + "edited" : "upraveno", + "Email_verified" : "Email ověřen", + "Error_changing_password" : "Chyba zmÄ›ny hesla", + "Favorites" : "OblÃbené", + "Hide_room" : "Skrýt mÃstnost", + "Invalid_room_name" : "<strong>%s</strong> nenà platné jméno mÃstnosti,<br/> použijte pouze pÃsmena, ÄÃslice a pomlÄky", + "is_also_typing" : "také pÃÅ¡e", + "is_typing" : "pÃÅ¡e", + "Leave_room" : "Opustit mÃstnost", + "Members" : "ÄŒlenové", + "Members_List" : "Seznam Älenů", + "Members_placeholder" : "ÄŒlenové", + "More_channels" : "DalÅ¡Ã kanály", + "Name" : "Jméno", + "New_messages" : "Nové zprávy", + "New_password" : "Nové heslo", + "No_channels_yet" : "ZatÃm se neúÄastnÃte v žádném kanálu.", + "No_direct_messages_yet" : "ZatÃm jste nezaÄali žádné konverzace.", + "No_favorites_yet" : "ZatÃm jste nepÅ™idali žádné oblÃbené.", + "No_groups_yet" : "ZatÃm nemáte žádné soukromé skupiny.", + "Powered_by" : "Běžà na", + "Private_Groups" : "Soukromé skupiny", + "Quick_Search" : "Rychlé vyhledávánÃ", + "Recents" : "Nedávné", + "Room_name_changed" : "Jméno mÃstnosti zmÄ›nÄ›no na: <em>__room_name__</em> uživatelem <em>__user_by__</em>", + "Room_name_changed_successfully" : "ZmÄ›na jména mÃstnosti probÄ›hla úspěšnÄ›", + "Save" : "Uložit", + "See_all" : "Zobrazit vÅ¡echny", + "See_only_online" : "Pouze online", + "Selected_users" : "Vybranà Älenové", + "Send_Message" : "Poslat zprávu", + "Showing_online_users" : "Viditelných <b>__total_online__</b> z __total__ users", + "Start_of_conversation" : "ZaÄÃt konverzaci", + "User_added_by" : "<em>__user_by__</em> pÅ™idal uživatele <em>__user_added__</em>.", + "User_left" : "Opustil(a) kanál.", + "User_removed_by" : "<em>__user_by__</em> odstranil uživatele <em>__user_removed__</em>.", + "Welcome" : "VÃtej <em>%s</em>." +} \ No newline at end of file diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index e4307a71625..0040d1a3823 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -89,7 +89,6 @@ "Custom_oauth_unique_name" : "Eindeutigen Namen von benutzerdefinierte oauth", "days" : "Tage", "Deactivate" : "Deaktivieren", - "Delete" : "Löschen", "Delete_User_Warning" : "Beim Löschen eines Benutzers, werden alle seine Nachrichten ebenfalls gelöscht. Dies kann nicht rückgängig gemacht werden.", "Deleted" : "Gelöscht!", "Desktop_Notifications" : "Desktop-Benachrichtigungen", @@ -102,7 +101,6 @@ "Duplicate_channel_name" : "Ein Kanal mit dem Namen, '%s', existiert", "Duplicate_private_group_name" : "Eine private Gruppe mit dem Namen, '%s', existiert", "E-mail" : "E-Mail", - "Edit" : "Bearbeiten", "edited" : "bearbeitet", "Email_already_exists" : "E-Mail existiert bereits", "Email_or_username" : "Email oder Username", @@ -194,7 +192,6 @@ "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_AllowPinning" : "Erlaube es Nachrichten anzuheften", "Message_AudioRecorderEnabled" : "Audio Recorder Aktiviert", "Message_deleting_not_allowed" : "Nachrichten löschen nicht erlaubt", "Message_editing_blocked" : "Diese Nachricht kann nicht mehr bearbeitet werden", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index eb98ef0d128..dfd7f8334f8 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -2,30 +2,19 @@ "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Accounts", - "Accounts_Description" : "", "Accounts_AllowedDomainsList" : "Allowed Domains List", "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains", "Accounts_AllowPasswordChange" : "Allow Password Change", - "Accounts_AllowPasswordChange_Description" : "", - "Accounts_AllowUserAvatarChange": "Allow User Avatar Change", - "Accounts_AllowUserAvatarChange_Description": "", - "Accounts_AllowUserProfileChange": "Allow User Profile Change", - "Accounts_AllowUserProfileChange_Description": "", + "Accounts_AllowUserAvatarChange" : "Allow User Avatar Change", + "Accounts_AllowUserProfileChange" : "Allow User Profile Change", "Accounts_AllowUsernameChange" : "Allow Username Change", - "Accounts_AllowUsernameChange_Description" : "", "Accounts_AvatarResize" : "Resize Avatars", - "Accounts_AvatarResize_Description" : "", "Accounts_AvatarSize" : "Avatar Size", - "Accounts_AvatarSize_Description" : "", "Accounts_AvatarStorePath" : "Avatar Storage Path", - "Accounts_AvatarStorePath_Description" : "", "Accounts_AvatarStoreType" : "Avatar Storage Type", - "Accounts_AvatarStoreType_Description" : "", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", - "Accounts_EmailVerification_Description" : "", "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", - "Accounts_ManuallyApproveNewUsers_Description" : "", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", "Accounts_OAuth_Custom_Button_Color" : "Button Color", "Accounts_OAuth_Custom_Button_Label_Color" : "Button Text Color", @@ -37,53 +26,30 @@ "Accounts_OAuth_Custom_Token_Path" : "Token Path", "Accounts_OAuth_Custom_URL" : "URL", "Accounts_OAuth_Facebook" : "Facebook Login", - "Accounts_OAuth_Facebook_Description" : "", "Accounts_OAuth_Facebook_id" : "Facebook App Id", - "Accounts_OAuth_Facebook_id_Description" : "", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", - "Accounts_OAuth_Facebook_secret_Description" : "", "Accounts_OAuth_Github" : "OAuth Enabled", - "Accounts_OAuth_Github_Description" : "", "Accounts_OAuth_Github_id" : "Client Id", - "Accounts_OAuth_Github_id_Description" : "", "Accounts_OAuth_Github_secret" : "Client Secret", - "Accounts_OAuth_Github_secret_Description" : "", "Accounts_OAuth_Gitlab" : "OAuth Enabled", - "Accounts_OAuth_Gitlab_Description" : "", "Accounts_OAuth_Gitlab_id" : "Gitlab Id", - "Accounts_OAuth_Gitlab_id_Description" : "", "Accounts_OAuth_Gitlab_secret" : "Client Secret", - "Accounts_OAuth_Google_secret_Description" : "", "Accounts_OAuth_Google" : "Google Login", - "Accounts_OAuth_Google_Description" : "", "Accounts_OAuth_Google_id" : "Google Id", - "Accounts_OAuth_Google_id_Description" : "", "Accounts_OAuth_Google_secret" : "Google Secret", - "Accounts_OAuth_Gitlab_secret_Description" : "", "Accounts_OAuth_Linkedin" : "LinkedIn Login", - "Accounts_OAuth_Linkedin_Description" : "", "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", - "Accounts_OAuth_Linkedin_id_Description" : "", "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", - "Accounts_OAuth_Linkedin_secret_Description" : "", "Accounts_OAuth_Meteor" : "Meteor Login", - "Accounts_OAuth_Meteor_Description" : "", "Accounts_OAuth_Meteor_id" : "Meteor Id", - "Accounts_OAuth_Meteor_id_Description" : "", "Accounts_OAuth_Meteor_secret" : "Meteor Secret", - "Accounts_OAuth_Meteor_secret_Description" : "", "Accounts_OAuth_Twitter" : "Twitter Login", - "Accounts_OAuth_Twitter_Description" : "", "Accounts_OAuth_Twitter_id" : "Twitter Id", - "Accounts_OAuth_Twitter_id_Description" : "", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", - "Accounts_OAuth_Twitter_secret_Description" : "", "Accounts_RegistrationRequired" : "Registration Required", - "Accounts_RegistrationRequired_Description" : "", "Accounts_RequireNameForSignUp" : "Require Name For Signup", - "Accounts_RequireNameForSignUp_Description" : "", - "Accounts_Enrollment_Email": "Enrollment E-mail", - "Accounts_Enrollment_Email_Description": "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Accounts_Enrollment_Email" : "Enrollment E-mail", + "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", @@ -94,14 +60,10 @@ "Allow_Invalid_SelfSigned_Certs_Description" : "Allow invalid and self-signed SSL certificate's for link validation and previews.", "and" : "and", "API" : "API", - "API_Description" : "", "API_Analytics" : "Analytics", - "API_Analytics_Description" : "", "API_Embed" : "Embed", - "API_Embed_Description" : "", "API_EmbedDisabledFor" : "Disable Embed for Users", "API_EmbedDisabledFor_Description" : "Comma-separated list of usernames", - "API_Gitlab_URL_Description" : "", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", @@ -124,7 +86,6 @@ "Busy_male" : "Busy", "Cancel" : "Cancel", "CDN_PREFIX" : "CDN Prefix", - "CDN_PREFIX_Description" : "", "Change_avatar" : "Change avatar", "Channels" : "Channels", "Channels_list" : "List of public channels", @@ -147,7 +108,6 @@ "Custom_oauth_unique_name" : "Custom oauth unique name", "days" : "days", "Deactivate" : "Deactivate", - "Delete" : "Delete", "Delete_Room_Warning" : "Deleting a room will delete all messages posted within the room. This cannot be undone.", "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", "Deleted" : "Deleted!", @@ -156,14 +116,12 @@ "Desktop_Notifications_Enabled" : "Desktop Notifications are Enabled", "Direct_Messages" : "Direct Messages", "Disable_Favorite_Rooms" : "Disable Favorites", - "Disable_Favorite_Rooms_Description" : "", "Disable_New_Message_Notification" : "Disable New Message Notification", "Disable_New_Room_Notification" : "Disable New Room Notification", "Drop_to_upload_file" : "Drop to upload file", "Duplicate_channel_name" : "A Channel with name '%s' exists", "Duplicate_private_group_name" : "A Private Group with name '%s' exists", "E-mail" : "E-mail", - "Edit" : "Edit", "edited" : "edited", "Email_already_exists" : "Email already exists", "Email_or_username" : "Email or username", @@ -178,20 +136,15 @@ "False" : "False", "Favorites" : "Favorites", "FileUpload" : "File Upload", - "FileUpload_Description" : "", "FileUpload_Enabled" : "File Uploads Enabled", - "FileUpload_Enabled_Description" : "", "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", - "FileUpload_MaxFileSize_Description" : "", "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", "Fork_it_on_github" : "Fork it on github", "From_Email" : "From Email", - "From_Email_Description" : "", "General" : "General", - "General_Description" : "", "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", @@ -214,9 +167,7 @@ "invisible" : "invisible", "Invisible" : "Invisible", "Invitation_HTML" : "Invitation HTML", - "Invitation_HTML_Description" : "", "Invitation_Subject" : "Invitation Subject", - "Invitation_Subject_Description" : "", "Invite_Users" : "Invite Users", "is_also_typing" : "is also typing", "is_also_typing_female" : "is also typing", @@ -232,21 +183,14 @@ "Last_login" : "Last login", "Last_message" : "Last message", "Layout" : "Layout", - "Layout_Description" : "", "Layout_Home_Body" : "Home Body", - "Layout_Home_Body_Description" : "", "Layout_Home_Title" : "Home Title", - "Layout_Home_Title_Description" : "", "Layout_Login_Header" : "Login Header", - "Layout_Login_Header_Description" : "", "Layout_Login_Terms" : "Login Terms", - "Layout_Login_Terms_Description" : "", "Layout_Privacy_Policy" : "Privacy Policy", - "Layout_Privacy_Policy_Description" : "", "Layout_Sidenav_Footer" : "Side Navigation Footer", "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", - "Layout_Terms_of_Service_Description" : "", "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\"}", @@ -276,50 +220,34 @@ "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", "Markdown_Headers" : "Markdown Headers", - "Markdown_Headers_Description" : "", "Members" : "Members", "Members_List" : "Members List", "Members_placeholder" : "Members", "Message" : "Message", - "Message_Description" : "", "Message_AllowDeleting" : "Allow Message Deleting", - "Message_AllowDeleting_Description" : "", "Message_AllowEditing" : "Allow Message Editing", - "Message_AllowEditing_Description" : "", "Message_AllowEditing_BlockEditInMinutes" : "Block Message Editing After (n) Minutes", "Message_AllowEditing_BlockEditInMinutesDescription" : "Enter 0 to disable blocking.", - "Message_AllowPinning" : "Allow Message Pinning", "Message_AudioRecorderEnabled" : "Audio Recorder Enabled", "Message_AudioRecorderEnabledDescription" : "Requires 'audio/wav' files to be an accepted media type within 'File Upload' settings.", "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_KeepHistory" : "Keep Message History", - "Message_KeepHistory_Description" : "", "Message_MaxAllowedSize" : "Maximum Allowed Message Size", - "Message_MaxAllowedSize_Description" : "", "Message_pinned" : "Message pinned", "Message_pinning_not_allowed" : "Message pinning not allowed", "Message_removed" : "Message removed", "Message_ShowDeletedStatus" : "Show Deleted Status", - "Message_ShowDeletedStatus_Description" : "", "Message_ShowEditedStatus" : "Show Edited Status", - "Message_ShowEditedStatus_Description" : "", "Message_ShowFormattingTips" : "Show Formatting Tips", - "Message_ShowFormattingTips_Description" : "", "Messages" : "Messages", "Meta" : "Meta", - "Meta_Description" : "", "Meta_fb_app_id" : "Facebook App Id", - "Meta_fb_app_id_Description" : "", "Meta_google-site-verification" : "Google Site Verification", - "Meta_google-site-verification_Description" : "", "Meta_language" : "Language", - "Meta_language_Description" : "", "Meta_msvalidate01" : "MSValidate.01", - "Meta_msvalidate01_Description" : "", "Meta_robots" : "Robots", - "Meta_robots_Description" : "", "minutes" : "minutes", "More_channels" : "More channels", "More_groups" : "More private groups", @@ -371,29 +299,17 @@ "Profile_saved_successfully" : "Profile saved successfully", "Proudly_developed" : "Proudly developed with Meteor", "Push" : "Push", - "Push_Description" : "", "Push_apn_cert" : "APN Cert", - "Push_apn_cert_Description" : "", "Push_apn_dev_cert" : "APN Dev Cert", - "Push_apn_dev_cert_Description" : "", "Push_apn_dev_key" : "APN Dev Key", - "Push_apn_dev_key_Description" : "", "Push_apn_dev_passphrase" : "APN Dev Passphrase", - "Push_apn_dev_passphrase_Description" : "", "Push_apn_key" : "APN Key", - "Push_apn_key_Description" : "", "Push_apn_passphrase" : "APN Passphrase", - "Push_apn_passphrase_Description" : "", "Push_debug" : "Debug", - "Push_debug_Description" : "", "Push_enable" : "Enable", - "Push_enable_Description" : "", "Push_gcm_api_key" : "GCM API Key", - "Push_gcm_api_key_Description" : "", "Push_gcm_project_number" : "GCM Project Number", - "Push_gcm_project_number_Description" : "", "Push_production" : "Production", - "Push_production_Description" : "", "Quick_Search" : "Quick Search", "quote" : "quote", "Recents" : "Recents", @@ -415,21 +331,11 @@ "Rooms" : "Rooms", "S_new_messages_since_s" : "%s new messages since %s", "SAML" : "SAML", - "SAML_Description" : "", - "SAML_Custom_default_button_color_Description" : "", - "SAML_Custom_default_button_label_color_Description" : "", - "SAML_Custom_default_button_label_text_Description" : "", - "SAML_Custom_default_Description" : "", "SAML_Custom_Cert" : "Custom Certificate", - "SAML_Custom_default_cert_Description" : "", "SAML_Custom_Entry_point" : "Custom Entry Point", - "SAML_Custom_default_entry_point_Description" : "", "SAML_Custom_Generate_Username" : "Generate Username", - "SAML_Custom_default_generate_username_Description" : "", "SAML_Custom_Issuer" : "Custom Issuer", - "SAML_Custom_default_issuer_Description" : "", "SAML_Custom_Provider" : "Custom Provider", - "SAML_Custom_default_provider_Description" : "", "Save" : "Save", "Save_changes" : "Save changes", "Save_Mobile_Bandwidth" : "Save Mobile Bandwidth", @@ -458,19 +364,13 @@ "Silence" : "Silence", "since_creation" : "since %s", "Site_Name" : "Site Name", - "Site_Name_Description" : "", "Site_Url" : "Site URL", "Site_Url_Description" : "Example: https://chat.domain.com/", "SMTP" : "SMTP", - "SMTP_Description" : "", "SMTP_Host" : "SMTP Host", - "SMTP_Host_Description" : "", "SMTP_Password" : "SMTP Password", - "SMTP_Password_Description" : "", "SMTP_Port" : "SMTP Port", - "SMTP_Port_Description" : "", "SMTP_Username" : "SMTP Username", - "SMTP_Username_Description" : "", "Sound" : "Sound", "Start_of_conversation" : "Start of conversation", "Statistics" : "Statistics", @@ -555,4 +455,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index f72c176ffe4..06ba09ac2fc 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -102,7 +102,6 @@ "Custom_oauth_unique_name" : "Mukautettu oauth yksilöllinen nimi", "days" : "päivää", "Deactivate" : "Deaktivoi", - "Delete" : "Poista", "Delete_Room_Warning" : "Huomeen poistaminen poistaa kaikki huoneessa olevat viestit.\nToimintoa ei voi perua.", "Delete_User_Warning" : "Käyttäjän poistaminen poistaa myös käyttäjän kaikki viestit. Toimintoa ei voi perua.", "Deleted" : "Poistettu!", @@ -117,7 +116,6 @@ "Duplicate_channel_name" : "Kanava nimeltä '%s' on olemassa jo", "Duplicate_private_group_name" : "Privaattiryhmä '%s' on olemassa jo", "E-mail" : "Sähköpostiosoite", - "Edit" : "Muokkaa", "edited" : "muokattu", "Email_already_exists" : "Sähköpostiosoite on jo olemassa", "Email_or_username" : "Sähköpostiosoite tai käyttäjänimi", @@ -224,7 +222,6 @@ "Message_AllowEditing" : "Salli viestin muokkaus", "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus (x) minuutin jälkeen", "Message_AllowEditing_BlockEditInMinutesDescription" : "Syötä 0 poistaaksesi muutoseston", - "Message_AllowPinning" : "Salli viestien kiinnittäminen", "Message_AudioRecorderEnabled" : "Äänentallennin käytössä", "Message_AudioRecorderEnabledDescription" : "Jotta tämä toimisi, WAV-tiedostojen lähetys tulee olla sallittu", "Message_deleting_not_allowed" : "Viestin poisto ei sallittu", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index a32780abcc8..bab470be4b3 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -85,7 +85,6 @@ "Custom_oauth_unique_name" : "Nom unique OAuth personnalisé", "days" : "jours", "Deactivate" : "Désactiver", - "Delete" : "Supprimer", "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", @@ -99,7 +98,6 @@ "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", - "Edit" : "Modifier", "edited" : "modifié", "Email_already_exists" : "L'adresse email existe déjà ", "Email_or_username" : "Adresse email ou nom d'utilisateur", @@ -182,7 +180,6 @@ "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_AllowPinning" : "Autoriser l'épinglement de messages", "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", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index c881293a275..39dc2a776e5 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -63,7 +63,6 @@ "Created_at" : "Stvoreno u", "days" : "dana", "Deactivate" : "IskljuÄi", - "Delete" : "ObriÅ¡i", "Delete_Room_Warning" : "Brisanje sobe će obrisati sve poruke u toj sobi. Ovo se ne može poniÅ¡titi.", "Delete_User_Warning" : "Brisanje korisnika će izbrisati i sve poruke od tog korisnika. Ovo se ne može poniÅ¡titi.", "Deleted" : "Obrisano!", @@ -75,7 +74,6 @@ "Duplicate_channel_name" : "Kanal s nazivom '% s' postoji", "Duplicate_private_group_name" : "Privatna Grupa s nazivom '% s' postoji", "E-mail" : "E-mail", - "Edit" : "Uredi", "edited" : "ureÄ‘eno", "Email_already_exists" : "Email već postoji", "Email_or_username" : "Email or username", @@ -143,7 +141,6 @@ "Message_AllowDeleting" : "Dopusti Brisanje Poruka", "Message_AllowEditing" : "Dopusti UreÄ‘ivanje Poruka", "Message_AllowEditing_BlockEditInMinutes" : "Blokirajte ureÄ‘ivanje poruka nakon (u minutama - 0 kako bi onemoguÄili)", - "Message_AllowPinning" : "Dopusti pribadanje poruka ", "Message_deleting_not_allowed" : "Brisanje poruka nije dopuÅ¡teno", "Message_editing_blocked" : "Ova poruka se viÅ¡e ne može ureÄ‘ivati ", "Message_editing_not_allowed" : "UreÄ‘ivanje poruka nije dopuÅ¡teno", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 4bbd96dbedb..682995e7985 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -99,7 +99,6 @@ "Custom_oauth_unique_name" : "កំណážáŸ‹ oauth ឲ្យមានឈ្មោះážáŸ‚មួយគážáŸ‹", "days" : "ážáŸ’ងៃ", "Deactivate" : "ធ្វើឲ្យមិនសកម្ម", - "Delete" : "លុប", "Delete_Room_Warning" : "ការលប់បន្ទប់មួយនឹងážáŸ’រូវលប់ចោលទាំងអស់នូវរាល់សារដែលបានប្រកាសនៅក្នុងបន្ទប់នáŸáŸ‡, ដំណើរការនáŸáŸ‡áž˜áž·áž“ទាន់បានបញ្ចប់ទáŸ", "Delete_User_Warning" : "ការ​លប់​អ្នក​ប្រើប្រាស់ នឹង​ážáŸ’រូវ​លប់​​គ្រប់​សារ​​របស់​​គាážáŸ‹â€‹áž•áž„​ដែរ។ ដូច​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ធ្វើ​បាន​ទ០។", "Deleted" : "បាន​លប់!", @@ -114,7 +113,6 @@ "Duplicate_channel_name" : "ប៉ុស្ážáž·áŸâ€‹ážŠáŸ‚ល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "Duplicate_private_group_name" : "ក្រុម​ឯក​ជន​ដែល​មាន​ឈ្មោះ​, '%s', មាន​ហើយ", "E-mail" : "អ៊ីមែល", - "Edit" : "កែ​សម្រួល", "edited" : "បានកែសម្រួល", "Email_already_exists" : "អ៊ី​ម៉ែ​ល​ដែល​មាន​រួច​ហើយ", "Email_or_username" : "អ៊ីមែល ឬឈ្មោះ​សម្ងាážáŸ‹", @@ -211,7 +209,6 @@ "Message_AllowEditing" : "អនុញ្ញាážâ€‹áž±áŸ’យ​មាន​ការ​កែ​សម្រួល​សារ", "Message_AllowEditing_BlockEditInMinutes" : "បិទការកែស្រួលសារបន្ទាប់ (ជាចំនួននាទី ឬ0ដើម្បីបិទចោល)", "Message_AllowEditing_BlockEditInMinutesDescription" : "បញ្ចូលលáŸáž 0 ដើម្បីបិទការ Block", - "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​", "Message_AudioRecorderEnabled" : "ការážážážŸáž˜áŸ’áž›áŸáž„បានអនុញ្ញាážáž·", "Message_deleting_not_allowed" : "ការ​លប់សារ​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážáž·", "Message_editing_blocked" : "សារ​នáŸáŸ‡â€‹áž˜áž·áž“​អាច​ážáŸ’រូវ​បាន​កែប្រែ​ទៀážâ€‹áž‘áŸ", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index f6e1c8fe9f8..ad3d826a915 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -2,6 +2,9 @@ "Access_online_demo" : "온ë¼ì¸ ë°ëª¨ ì ‘ì†", "Access_Online_Demo" : "온ë¼ì¸ ë°ëª¨ ì ‘ì†", "Accounts" : "ê³„ì •", + "Accounts_AllowUserAvatarChange" : "ì‚¬ìš©ìž ì•„ë°”íƒ€ ë³€ê²½ì„ í—ˆìš©", + "Accounts_AllowUserProfileChange" : "ì‚¬ìš©ìž í”„ë¡œí•„ ë³€ê²½ì„ í—ˆìš©", + "Accounts_AvatarSize" : "아바타 í¬ê¸°", "Accounts_denyUnverifiedEmail" : "확ì¸ë˜ì§€ ì•Šì€ ì´ë©”ì¼ ê±°ë¶€", "Accounts_EmailVerification" : "ì´ë©”ì¼ í™•ì¸", "Accounts_ManuallyApproveNewUsers" : "ì§ì ‘ 새로운 ì‚¬ìš©ìž í—ˆìš©", @@ -21,6 +24,7 @@ "Accounts_OAuth_Github" : "Github 로그ì¸", "Accounts_OAuth_Github_id" : "Github ID", "Accounts_OAuth_Github_secret" : "Github 암호", + "Accounts_OAuth_Gitlab" : "OAuth 활성화", "Accounts_OAuth_Google" : "구글 로그ì¸", "Accounts_OAuth_Google_id" : "구글 ID", "Accounts_OAuth_Google_secret" : "구글 암호", @@ -70,6 +74,7 @@ "Chat_Rooms" : "채팅방", "close" : "닫기", "coming_soon" : "곧", + "Commands" : "ëª…ë ¹", "Confirm_password" : "암호를 확ì¸í•˜ì„¸ìš”", "Contact" : "ì ‘ì†", "Conversation" : "대화", @@ -82,9 +87,12 @@ "Custom_oauth_unique_name" : "ì‚¬ìš©ìž ì •ì˜ OAuth ê³ ìœ í•œ ì´ë¦„", "days" : "ì¼", "Deactivate" : "비활성화", - "Delete" : "ì‚ì œ", + "Delete_Room_Warning" : "ë°©ì„ ì‚ì œí•˜ë©´ ë°©ì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì´ ìž‘ì—…ì€ ë˜ëŒë¦´ 수 없습니다.", "Delete_User_Warning" : "ì‚¬ìš©ìž ì‚ì œì‹œ 사용ìžì˜ ëª¨ë“ ë©”ì‹œì§€ë¥¼ ì‚ì œí•©ë‹ˆë‹¤. ì·¨ì†Œí• ìˆ˜ 없습니다.", "Deleted" : "ì‚ì œ!", + "Desktop_Notifications" : "바탕화면 알림", + "Desktop_Notifications_Disabled" : "바탕화면 ì•Œë¦¼ì´ ë¹„í™œì„±í™” ë˜ì—ˆìŠµë‹ˆë‹¤. 활성화 í•˜ë ¤ë©´ ì„¤ì •ì„ ë³€ê²½í•˜ì„¸ìš”.", + "Desktop_Notifications_Enabled" : "바탕화면 알림 활성화", "Direct_Messages" : "ê·“ì†ë§", "Disable_Favorite_Rooms" : "ì¦ê²¨ì°¾ê¸° 사용안함", "Disable_New_Message_Notification" : "새 메시지 알림 비활성화", @@ -93,7 +101,6 @@ "Duplicate_channel_name" : "'%s' ì±„ë„ ì´ë¦„ì€ ì´ë¯¸ 존재합니다.", "Duplicate_private_group_name" : "'%s'는 ì´ë¯¸ 존재하는 ê°œì¸ ê·¸ë£¹ìž…ë‹ˆë‹¤.", "E-mail" : "ì´ë©”ì¼", - "Edit" : "ìˆ˜ì •", "edited" : "ìˆ˜ì •ë¨", "Email_already_exists" : "ì´ë©”ì¼ì´ ì´ë¯¸ 존재합니다", "Email_or_username" : "ì´ë©”ì¼ ë˜ëŠ” ì‚¬ìš©ìž ì´ë¦„", @@ -101,10 +108,12 @@ "Emoji" : "Emoji", "Enter_info" : "ë¡œê·¸ì¸ ì •ë³´ë¥¼ ìž…ë ¥í•˜ì„¸ìš”", "Enter_to" : "Enter to", - "Error_changing_password" : "암호 변경", + "Error_changing_password" : "암호 변경 중 오류 ë°œìƒ", "Esc_to" : "Esc to", "False" : "False", "Favorites" : "ì¦ê²¨ì°¾ê¸°", + "FileUpload" : "íŒŒì¼ ì—…ë¡œë“œ", + "FileUpload_MaxFileSize" : "íŒŒì¼ ì—…ë¡œë“œ 최대 í¬ê¸° (ë°”ì´íŠ¸ 단위)", "Follow_social_profiles" : "소셜 프로파ì¼ì— ë”°ë¼ì£¼ì‹ì‹œì˜¤. Githubì—ì„œ í¬í¬í•˜ê³ , ìš°ë¦¬ì˜ trello ë³´ë“œì—ì„œ rocket.chat appì—대한 ì˜ê²¬ì„ ê³µìœ í•©ë‹ˆë‹¤.", "Forgot_password" : "암호를 잊었습니다", "Fork_it_on_github" : "Githubì—ì„œ í¬í¬", @@ -153,6 +162,7 @@ "Layout_Sidenav_Footer_description" : "바닥글 í¬ê¸°ëŠ” 260x70입니다.", "Layout_Terms_of_Service" : "ì´ìš©ì•½ê´€", "LDAP" : "LDAP", + "LDAP_Description" : "LDAP는 ë§Žì€ ê¸°ì—…ë“¤ì´ í†µí•© ì¸ì¦ì„ ì œê³µí•˜ê¸° 위해 사용하는 계층ì ì¸ ë°ì´í„°ë² ì´ìŠ¤ìž…니다. 여러 사ì´íŠ¸ì™€ 서비스 ê°„ì— í•˜ë‚˜ì˜ ì•”í˜¸ë¥¼ ê³µìœ í•˜ê¸° 위한 기능으로, ìžì„¸í•œ ì •ë³´ëŠ” 위키를 ì°¸ê³ í•˜ì„¸ìš”: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP", "LDAP_DN" : "LDAP DN", "LDAP_Port" : "LDAP í¬íŠ¸", "LDAP_Url" : "LDAP URL", @@ -175,7 +185,6 @@ "Message_AllowDeleting" : "메시지 ì‚ì œ 허용", "Message_AllowEditing" : "메시지 ìˆ˜ì • 허용", "Message_AllowEditing_BlockEditInMinutes" : "ì´í›„ë¡œ 메시지 ìˆ˜ì • ì•ˆë¨ (분 - 0 ì€ ì‚¬ìš©ì•ˆí•¨)", - "Message_AllowPinning" : "허용 메시지 ê³ ì •", "Message_deleting_not_allowed" : "메시지 ì‚ì œë¥¼ í• ìˆ˜ 없습니다.", "Message_editing_blocked" : "메시지를 ë” ì´ìƒ ìˆ˜ì •í• ìˆ˜ 없습니다.", "Message_editing_not_allowed" : "메시지 ìˆ˜ì •ì„ í• ìˆ˜ 없습니다.", @@ -186,6 +195,7 @@ "Message_removed" : "메시지 ì œê±°", "Message_ShowDeletedStatus" : "ì‚ì œëœ ìƒíƒœ 확ì¸", "Message_ShowEditedStatus" : "ìˆ˜ì • ìƒíƒœ 확ì¸", + "Messages" : "메시지", "Meta" : "메타", "Meta_fb_app_id" : "페ì´ìŠ¤ë¶ APP ID", "Meta_google-site-verification" : "Google 사ì´íŠ¸ 확ì¸", @@ -202,6 +212,7 @@ "n_messages" : "%s 메시지", "Name" : "ì´ë¦„", "Name_cant_be_empty" : "ì´ë¦„ì„ ë¹„ì›Œ 둘 수 없습니다", + "Name_optional" : "ì´ë¦„ (ì„ íƒ ì‚¬í•)", "New_messages" : "새로운 메시지", "New_password" : "새로운 암호", "No_channel_with_name_%s_was_found" : "<strong>\"%s\"</strong> ì±„ë„ ì´ë¦„ì„ ì°¾ì„ ìˆ˜ 없습니다!", @@ -226,6 +237,7 @@ "others" : "다른 사람", "Password" : "암호", "Password_changed_successfully" : "암호를 성공ì 으로 변경하였습니다.", + "People" : "사람들", "Please_wait" : "ìž ì‹œë§Œ ê¸°ë‹¤ë ¤ 주세요.", "Please_wait_activation" : "ì‹œê°„ì´ ì¢€ 걸릴 수 있습니다. ìž ì‹œë§Œ ê¸°ë‹¤ë ¤ì£¼ì‹ì‹œì˜¤.", "Please_wait_statistics" : "통계를 ìƒì„± 중입니다. ìž ì‹œë§Œ ê¸°ë‹¤ë ¤ì£¼ì‹ì‹œì˜¤.", @@ -263,6 +275,7 @@ "Room_name_changed" : "ë°© ì´ë¦„ 변경: <em>__user_by__</em>ì—ì„œ <em>__room_name__</em>ë¡œ.", "Room_name_changed_successfully" : "ë°© ì´ë¦„ 변경 완료", "Room_not_found" : "ë°©ì„ ì°¾ì„ ìˆ˜ 없습니다.", + "Room_uploaded_file_list" : "íŒŒì¼ ëª©ë¡", "room_user_count" : "%s 사용ìž", "Rooms" : "ë°©", "SAML" : "SAML", @@ -294,6 +307,8 @@ "Silence" : "무언", "since_creation" : "%s ì´í›„", "Site_Name" : "사ì´íŠ¸ ì´ë¦„:", + "Site_Url" : "사ì´íŠ¸ URL", + "Site_Url_Description" : "예: https://chat.domain.com/", "SMTP" : "SMTP", "SMTP_Host" : "SMTP 호스트", "SMTP_Password" : "SMTP 암호", @@ -354,6 +369,7 @@ "User_left_female" : "ì‚¬ìš©ìž <em>__user_left__</em> ë– ë‚¨.", "User_left_male" : "ì‚¬ìš©ìž <em>__user_left__</em> ë– ë‚¨.", "User_logged_out" : "사용ìžë¥¼ 로그아웃합니다", + "User_not_found_or_incorrect_password" : "사용ìžë¥¼ ì°¾ì„ ìˆ˜ 없거나 ìž˜ëª»ëœ ì•”í˜¸ìž…ë‹ˆë‹¤", "User_removed_by" : "ì‚¬ìš©ìž <em>__user_removed__</em>ì„/를 <em>__user_by__</em>ì—ì„œ ì‚ì œë¨.", "User_Settings" : "ì‚¬ìš©ìž ì„¤ì •", "User_updated_successfully" : "사용ìžë¥¼ 성공ì 으로 ì—…ë°ì´íŠ¸í•˜ì˜€ìŠµë‹ˆë‹¤.", @@ -371,10 +387,11 @@ "Welcome" : "환ì˜í•©ë‹ˆë‹¤, <em>%s</em>.", "Welcome_to_the" : "ì˜¤ì‹ ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤", "With_whom" : "누구랑?", - "Yes_delete_it" : "넵, ì‚ì œí•©ë‹ˆë‹¤!", + "Yes_clear_all" : "예, ì „ë¶€ 지ì›ë‹ˆë‹¤!", + "Yes_delete_it" : "예, ì‚ì œí•©ë‹ˆë‹¤!", "you_are_in_preview_mode_of" : "#<strong>__room_name__</strong> ì±„ë„ ë¯¸ë¦¬ë³´ê¸° 모드", "You_need_confirm_email" : "로그ì¸í•˜ë ¤ë©´ ì´ë©”ì¼ í™•ì¸ì´ 필요합니다!", - "You_will_not_be_able_to_recover" : "복구 안ë©ë‹ˆë‹¤!", + "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/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index cb00194771e..52e0cc33ed9 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -79,7 +79,6 @@ "Created_at" : "Dibuat pada", "days" : "hari", "Deactivate" : "Nyahaktifkan", - "Delete" : "Padam", "Delete_User_Warning" : "Memadam pengguna akan memadam semua mesej dari pengguna itu juga. Ini tidak boleh kembalikan asal.", "Deleted" : "Dipadamkan!", "Desktop_Notifications" : "Notifikasi Desktop", @@ -93,7 +92,6 @@ "Duplicate_channel_name" : "Saluran dengan nama '%s' telah wujud", "Duplicate_private_group_name" : "Kumpulan Persendirian dengan nama '%s' telah wujud", "E-mail" : "E-mel", - "Edit" : "Sunting", "edited" : "disunting", "Email_already_exists" : "E-mel telah wujud", "Email_or_username" : "E-mel atau nama pengguna", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 9c5ca9b4252..2e0271c4960 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -58,13 +58,11 @@ "Create_new_public_channel" : "Utwórz kanaÅ‚ publiczny", "Created_at" : "Utworzono", "Deactivate" : "Dezaktywować", - "Delete" : "UsuÅ„", "Deleted" : "UsuniÄ™te!", "Direct_Messages" : "BezpoÅ›rednie wiadomoÅ›ci", "Drop_to_upload_file" : "PrzeciÄ…gnij, aby przesÅ‚ać plik", "Duplicate_channel_name" : "KanaÅ‚ o nazwie \"% s\" istnieje", "Duplicate_private_group_name" : "Grupa Prywatna o nazwie '% s' istnieje", - "Edit" : "Edycja", "edited" : "zmieniono", "Email_already_exists" : "Email już istnieje", "Email_or_username" : "Email lub nazwa użytkownika", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 69fd6340f1a..15ad47a5d25 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -94,7 +94,6 @@ "Custom_oauth_unique_name" : "Nome exclusivo para oauth customizado", "days" : "dias", "Deactivate" : "Desativar", - "Delete" : "Deletar", "Delete_User_Warning" : "Excluir um usuário irá apagar todas as mensagens desse usuário também. Isso não poderá ser desfeito.", "Deleted" : "Deletado!", "Desktop_Notifications" : "Notificações Desktop", @@ -108,7 +107,6 @@ "Duplicate_channel_name" : "Já existe um Canal com nome '%s'", "Duplicate_private_group_name" : "Já existe um Grupo Privado com nome '%s'", "E-mail" : "E-mail", - "Edit" : "Editar", "edited" : "editado", "Email_already_exists" : "Email já cadastrado", "Email_or_username" : "Email ou nome de usuário", @@ -198,7 +196,6 @@ "Message_AllowDeleting" : "Permitir Exclusão de Mensagem", "Message_AllowEditing" : "Permitir Edição de Mensagem", "Message_AllowEditing_BlockEditInMinutes" : "Bloquear edição de mensagens após (em minutos - 0 para desabilitar)", - "Message_AllowPinning" : "Permitir Fixar Mensagem", "Message_AudioRecorderEnabled" : "Gravação de Ãudio Habilitada", "Message_deleting_not_allowed" : "Exclusão de mensagem não permitido", "Message_editing_blocked" : "Esta mensagem não pode mais ser editada", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 8c154fde9d4..71b54e53e54 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -51,13 +51,11 @@ "Create_new_public_channel" : "Yeni bir kanal oluÅŸtur", "Created_at" : "OluÅŸturulma saati", "days" : "gün", - "Delete" : "Sil", "Delete_User_Warning" : "Bu kullanıcıyı silerseniz tüm mesajları da beraberinde silinecektir! Bu iÅŸlemi bir daha geri alamazsınız.", "Deleted" : "SilinmiÅŸ!", "Direct_Messages" : "Direkt Mesajlar", "Drop_to_upload_file" : "Dosya yüklemek için sürükle", "E-mail" : "E-posta", - "Edit" : "Düzenle", "edited" : "düzenlendi", "Email_already_exists" : "Bu e-posta zaten var", "Email_or_username" : "E-posta ya da kullanıcı adı", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index f8091f5d049..c80457321d4 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -56,7 +56,6 @@ "Created_at" : "创建于", "days" : "天", "Deactivate" : "ç¦ç”¨", - "Delete" : "åˆ é™¤", "Delete_User_Warning" : "åˆ é™¤ç”¨æˆ·å°†åˆ é™¤è¯¥ç”¨æˆ·çš„æ‰€æœ‰æ¶ˆæ¯ã€‚è¿™ä¸èƒ½è¢«æ’¤æ¶ˆã€‚", "Deleted" : "å·²åˆ é™¤ï¼", "Direct_Messages" : "直接å‘é€æ¶ˆæ¯", @@ -66,7 +65,6 @@ "Duplicate_channel_name" : "é¢‘é“ '%s' å·²å˜åœ¨", "Duplicate_private_group_name" : "ç§æœ‰ç»„ '%s' å·²å˜åœ¨", "E-mail" : "电å邮件", - "Edit" : "编辑", "edited" : "已编辑", "Email_already_exists" : "邮件已å˜åœ¨", "Email_or_username" : "电å邮件或用户å", diff --git a/packages/rocketchat-channel-settings/i18n/ar.i18n.json b/packages/rocketchat-channel-settings/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ 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 ba1d6c016df..3d4dda12e16 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,8 +1,8 @@ { - "Channel": "Channel", - "Private_Group": "Private Group", - "Room_Type": "Room Type", - "Room_Settings": "Room Settings", - "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>" -} + "Channel" : "Channel", + "Private_Group" : "Private Group", + "Room_Type" : "Room Type", + "Room_Settings" : "Room Settings", + "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>" +} \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/fa.i18n.json b/packages/rocketchat-channel-settings/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..dc45aca964f --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ko.i18n.json @@ -0,0 +1,8 @@ +{ + "Channel" : "채ë„", + "Private_Group" : "ê°œì¸ ê·¸ë£¹", + "Room_Type" : "ë°© 종류", + "Room_Settings" : "ë°© ì„¤ì •", + "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/ms-MY.i18n.json b/packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/cs.i18n.json b/packages/rocketchat-chatops/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/cs.i18n.json b/packages/rocketchat-github-enterprise/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/en.i18n.json b/packages/rocketchat-github-enterprise/i18n/en.i18n.json index dac5ec52b61..6bd78273fc7 100644 --- a/packages/rocketchat-github-enterprise/i18n/en.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/en.i18n.json @@ -1,10 +1,7 @@ { "Accounts_OAuth_GitHub_Enterprise" : "OAuth Enabled", - "Accounts_OAuth_GitHub_Enterprise_Description": "", "API_GitHub_Enterprise_URL" : "Server URL", "Accounts_OAuth_GitHub_Enterprise_id" : "Client Id", - "Accounts_OAuth_GitHub_Enterprise_id_Description" : "", "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", - "Accounts_OAuth_GitHub_Enterprise_secret_Description" : "", "Github_Enterprise_Url_No_Trail" : "Example: http://domain.com (excluding trailing slash)" -} +} \ 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 06dd996c99c..bf2ee2cce6a 100644 --- a/packages/rocketchat-github-enterprise/i18n/ko.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ko.i18n.json @@ -1,3 +1,4 @@ { - "API_GitHub_Enterprise_URL" : "GitHub Enterprise" + "API_GitHub_Enterprise_URL" : "GitHub Enterprise", + "Github_Enterprise_Url_No_Trail" : "예: http://domain.com (마지막 슬래시 ì œì™¸)" } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/cs.i18n.json b/packages/rocketchat-gitlab/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/cs.i18n.json b/packages/rocketchat-hubot/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/cs.i18n.json b/packages/rocketchat-ldap/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ar.i18n.json b/packages/rocketchat-lib/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/cs.i18n.json b/packages/rocketchat-lib/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/de.i18n.json b/packages/rocketchat-lib/i18n/de.i18n.json new file mode 100644 index 00000000000..b0d162a99b6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Bearbeiten", + "Delete" : "Löschen" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/el.i18n.json b/packages/rocketchat-lib/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ 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 9c76e8e402a..b0e165dc996 100644 --- a/packages/rocketchat-lib/i18n/en.i18n.json +++ b/packages/rocketchat-lib/i18n/en.i18n.json @@ -1,4 +1,4 @@ { - "Edit": "Edit", - "Delete": "Delete" + "Edit" : "Edit", + "Delete" : "Delete" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/es.i18n.json b/packages/rocketchat-lib/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/fa.i18n.json b/packages/rocketchat-lib/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/fi.i18n.json b/packages/rocketchat-lib/i18n/fi.i18n.json new file mode 100644 index 00000000000..f283462d8f2 --- /dev/null +++ b/packages/rocketchat-lib/i18n/fi.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Muokkaa", + "Delete" : "Poista" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/fr.i18n.json b/packages/rocketchat-lib/i18n/fr.i18n.json new file mode 100644 index 00000000000..6fcd2330c33 --- /dev/null +++ b/packages/rocketchat-lib/i18n/fr.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Modifier", + "Delete" : "Supprimer" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/he.i18n.json b/packages/rocketchat-lib/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/hr.i18n.json b/packages/rocketchat-lib/i18n/hr.i18n.json new file mode 100644 index 00000000000..247eb268a3c --- /dev/null +++ b/packages/rocketchat-lib/i18n/hr.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Uredi", + "Delete" : "ObriÅ¡i" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/hu.i18n.json b/packages/rocketchat-lib/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/it.i18n.json b/packages/rocketchat-lib/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ja.i18n.json b/packages/rocketchat-lib/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/km.i18n.json b/packages/rocketchat-lib/i18n/km.i18n.json new file mode 100644 index 00000000000..0db86550f90 --- /dev/null +++ b/packages/rocketchat-lib/i18n/km.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "កែ​សម្រួល", + "Delete" : "លុប" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ko.i18n.json b/packages/rocketchat-lib/i18n/ko.i18n.json new file mode 100644 index 00000000000..b454f6fb4a3 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ko.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "ìˆ˜ì •", + "Delete" : "ì‚ì œ" +} \ 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 new file mode 100644 index 00000000000..1c06d12d0c6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ms-MY.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Sunting", + "Delete" : "Padam" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/pl.i18n.json b/packages/rocketchat-lib/i18n/pl.i18n.json new file mode 100644 index 00000000000..f0a5a7f12d2 --- /dev/null +++ b/packages/rocketchat-lib/i18n/pl.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Edycja", + "Delete" : "UsuÅ„" +} \ 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 a5227168f1f..7c1bc08766f 100644 --- a/packages/rocketchat-lib/i18n/pt.i18n.json +++ b/packages/rocketchat-lib/i18n/pt.i18n.json @@ -1,4 +1,4 @@ { - "Edit": "Editar", - "Delete": "Excluir" + "Edit" : "Editar", + "Delete" : "Deletar" } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ru.i18n.json b/packages/rocketchat-lib/i18n/ru.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/sv.i18n.json b/packages/rocketchat-lib/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ta-IN.i18n.json b/packages/rocketchat-lib/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ta-IN.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 new file mode 100644 index 00000000000..230736a8535 --- /dev/null +++ b/packages/rocketchat-lib/i18n/tr.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "Düzenle", + "Delete" : "Sil" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ug.i18n.json b/packages/rocketchat-lib/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/uk.i18n.json b/packages/rocketchat-lib/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/zh.i18n.json b/packages/rocketchat-lib/i18n/zh.i18n.json new file mode 100644 index 00000000000..4a3796cadc9 --- /dev/null +++ b/packages/rocketchat-lib/i18n/zh.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit" : "编辑", + "Delete" : "åˆ é™¤" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/cs.i18n.json b/packages/rocketchat-livechat/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/cs.i18n.json b/packages/rocketchat-mailer/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..0b3dccd1255 100644 --- a/packages/rocketchat-mailer/i18n/ko.i18n.json +++ b/packages/rocketchat-mailer/i18n/ko.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Email_from" : "보내는 ì´", + "Email_subject" : "ì œëª©", + "Email_body" : "ì´ë©”ì¼ ë³¸ë¬¸", + "Send_email" : "ì´ë©”ì¼ ë³´ë‚´ê¸°", + "You_are_not_authorized_to_view_this_page" : "ë‹¹ì‹ ì€ ì´ íŽ˜ì´ì§€ë¥¼ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤." +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/cs.i18n.json b/packages/rocketchat-message-pin/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..b8e3131562d 100644 --- a/packages/rocketchat-message-pin/i18n/de.i18n.json +++ b/packages/rocketchat-message-pin/i18n/de.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Erlaube es Nachrichten anzuheften" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/en.i18n.json b/packages/rocketchat-message-pin/i18n/en.i18n.json index 834bea1c96d..f9e7c28102c 100644 --- a/packages/rocketchat-message-pin/i18n/en.i18n.json +++ b/packages/rocketchat-message-pin/i18n/en.i18n.json @@ -1,10 +1,10 @@ { "Message_AllowPinning" : "Allow Message Pinning", - "Message_AllowPinning_Description": "Allow messages to be pinned to any of the channels.", - "Message_AllowPinningByAnyone": "Allow Anyone to Pin Messages", - "Message_AllowPinningByAnyone_Description": "Allow anyone to pin messages to a channel, not just administrators.", + "Message_AllowPinning_Description" : "Allow messages to be pinned to any of the channels.", + "Message_AllowPinningByAnyone" : "Allow Anyone to Pin Messages", + "Message_AllowPinningByAnyone_Description" : "Allow anyone to pin messages to a channel, not just administrators.", "Pin_Message" : "Pin Message", "Unpin_Message" : "Unpin Message", "Pinned_Messages" : "Pinned Messages", "No_pinned_messages" : "No pinned messages" -} +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/fi.i18n.json b/packages/rocketchat-message-pin/i18n/fi.i18n.json index 6f31cf5a2e6..80cefc15549 100644 --- a/packages/rocketchat-message-pin/i18n/fi.i18n.json +++ b/packages/rocketchat-message-pin/i18n/fi.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Salli viestien kiinnittäminen" +} \ 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 6f31cf5a2e6..19f10ea3b8a 100644 --- a/packages/rocketchat-message-pin/i18n/fr.i18n.json +++ b/packages/rocketchat-message-pin/i18n/fr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Autoriser l'épinglement de messages" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/hr.i18n.json b/packages/rocketchat-message-pin/i18n/hr.i18n.json index 6f31cf5a2e6..d15da785f43 100644 --- a/packages/rocketchat-message-pin/i18n/hr.i18n.json +++ b/packages/rocketchat-message-pin/i18n/hr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Dopusti pribadanje poruka " +} \ 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 6f31cf5a2e6..4b0abbe9742 100644 --- a/packages/rocketchat-message-pin/i18n/km.i18n.json +++ b/packages/rocketchat-message-pin/i18n/km.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "អនុញ្ញážáž·â€‹ážáŸ’ទស់សារ​" +} \ 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 6f31cf5a2e6..4feeebeb4f0 100644 --- a/packages/rocketchat-message-pin/i18n/ko.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ko.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "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/pt.i18n.json b/packages/rocketchat-message-pin/i18n/pt.i18n.json index 6f31cf5a2e6..d607988686f 100644 --- a/packages/rocketchat-message-pin/i18n/pt.i18n.json +++ b/packages/rocketchat-message-pin/i18n/pt.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Permitir Fixar Mensagem" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/cs.i18n.json b/packages/rocketchat-message-star/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/en.i18n.json b/packages/rocketchat-message-star/i18n/en.i18n.json index 756eaee93e8..7377102ab14 100644 --- a/packages/rocketchat-message-star/i18n/en.i18n.json +++ b/packages/rocketchat-message-star/i18n/en.i18n.json @@ -1,8 +1,7 @@ { "Message_AllowStarring" : "Allow Message Starring", - "Message_AllowStarring_Description" : "", "Star_Message" : "Star Message", "Unstar_Message" : "Remove Star", "Starred_Messages" : "Starred Messages", "No_starred_messages" : "No starred messages" -} +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/cs.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..79dc107036c 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "User_doesnt_exist" : "`@%s` 사용ìžê°€ 존재하지 않습니다.", + "Username_is_already_in_here" : "`@%s` 사용ìžê°€ ì´ë¯¸ 있습니다." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/cs.i18n.json b/packages/rocketchat-slashcommands-join/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..061624dfd78 100644 --- a/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/ko.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-theme/i18n/ar.i18n.json b/packages/rocketchat-theme/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/cs.i18n.json b/packages/rocketchat-theme/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/de.i18n.json b/packages/rocketchat-theme/i18n/de.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/el.i18n.json b/packages/rocketchat-theme/i18n/el.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ 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 31987697d1d..1cac00320b1 100644 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -1,45 +1,23 @@ -{ - "Theme_Description" : "", - "theme-color-blockquote-background" : "Blockquote Background Color", - "theme-color-blockquote-background_Description" : "", - "theme-color-code-background" : "Code Background Color", - "theme-color-code-background_Description" : "", - "theme-color-code-border" : "Code Border Color", - "theme-color-code-border_Description" : "", - "theme-color-code-color" : "Code Color", - "theme-color-code-color_Description" : "", - "theme-color-content-background-color" : "Content Background Color", - "theme-color-content-background-color_Description" : "", - "theme-color-info-active-font-color" : "Active Info Font Color", - "theme-color-info-active-font-color_Description" : "", - "theme-color-info-font-color" : "Info Font Color", - "theme-color-info-font-color_Description" : "", - "theme-color-input-font-color" : "Input Font Color", - "theme-color-input-font-color_Description" : "", - "theme-color-link-font-color" : "Link Font Color", - "theme-color-link-font-color_Description" : "", - "theme-color-primary-background-color" : "Primary Background Color", - "theme-color-primary-background-color_Description" : "", - "theme-color-primary-font-color" : "Primary Font Color", - "theme-color-primary-font-color_Description" : "", - "theme-color-secondary-background-color" : "Secondary Background Color", - "theme-color-secondary-background-color_Description" : "", - "theme-color-secondary-font-color" : "Secondary Font Color", - "theme-color-secondary-font-color_Description" : "", - "theme-color-smallprint-font-color" : "Small Print Font Color", - "theme-color-smallprint-font-color_Description" : "", - "theme-color-smallprint-hover-color" : "Small Print Hover Color", - "theme-color-smallprint-hover-color_Description" : "", - "theme-color-status-away" : "Away Status Color", - "theme-color-status-away_Description" : "", - "theme-color-status-busy" : "Busy Status Color", - "theme-color-status-busy_Description" : "", - "theme-color-status-offline" : "Offline Status Color", - "theme-color-status-offline_Description" : "", - "theme-color-status-online" : "Online Status Color", - "theme-color-status-online_Description" : "", - "theme-color-tertiary-background-color" : "Tertiary Background Color", - "theme-color-tertiary-background-color_Description" : "", - "theme-color-tertiary-font-color" : "Tertiary Font Color", - "theme-color-tertiary-font-color_Description" : "" -} +{ + "theme-color-blockquote-background" : "Blockquote Background 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-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-primary-background-color" : "Primary Background Color", + "theme-color-primary-font-color" : "Primary 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", + "theme-color-smallprint-hover-color" : "Small Print Hover Color", + "theme-color-status-away" : "Away Status Color", + "theme-color-status-busy" : "Busy Status Color", + "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" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/es.i18n.json b/packages/rocketchat-theme/i18n/es.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/fa.i18n.json b/packages/rocketchat-theme/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/fi.i18n.json b/packages/rocketchat-theme/i18n/fi.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/fr.i18n.json b/packages/rocketchat-theme/i18n/fr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/he.i18n.json b/packages/rocketchat-theme/i18n/he.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/hr.i18n.json b/packages/rocketchat-theme/i18n/hr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/hu.i18n.json b/packages/rocketchat-theme/i18n/hu.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/it.i18n.json b/packages/rocketchat-theme/i18n/it.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ja.i18n.json b/packages/rocketchat-theme/i18n/ja.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/km.i18n.json b/packages/rocketchat-theme/i18n/km.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ko.i18n.json b/packages/rocketchat-theme/i18n/ko.i18n.json new file mode 100644 index 00000000000..eae4ba0da58 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ko.i18n.json @@ -0,0 +1,11 @@ +{ + "theme-color-blockquote-background" : "ì¸ìš©êµ¬ 배경색", + "theme-color-code-background" : "코드 배경색", + "theme-color-code-border" : "코드 í…Œë‘리 색ìƒ", + "theme-color-code-color" : "코드 색ìƒ", + "theme-color-content-background-color" : "콘í…ì¸ ë°°ê²½ìƒ‰", + "theme-color-status-away" : "ìžë¦¬ë¹„움 ìƒíƒœ 색ìƒ", + "theme-color-status-busy" : "ë°”ì¨ ìƒíƒœ 색ìƒ", + "theme-color-status-offline" : "ë³´ì§€ì•ŠìŒ ìƒíƒœ 색ìƒ", + "theme-color-status-online" : "온ë¼ì¸ ìƒíƒœ 색ìƒ" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ms-MY.i18n.json b/packages/rocketchat-theme/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/pl.i18n.json b/packages/rocketchat-theme/i18n/pl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/pt.i18n.json b/packages/rocketchat-theme/i18n/pt.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ru.i18n.json b/packages/rocketchat-theme/i18n/ru.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/sv.i18n.json b/packages/rocketchat-theme/i18n/sv.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ta-IN.i18n.json b/packages/rocketchat-theme/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/tr.i18n.json b/packages/rocketchat-theme/i18n/tr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ug.i18n.json b/packages/rocketchat-theme/i18n/ug.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/uk.i18n.json b/packages/rocketchat-theme/i18n/uk.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/zh.i18n.json b/packages/rocketchat-theme/i18n/zh.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/cs.i18n.json b/packages/rocketchat-webrtc/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/en.i18n.json b/packages/rocketchat-webrtc/i18n/en.i18n.json index e88088a6e9e..c52ef5d8daa 100644 --- a/packages/rocketchat-webrtc/i18n/en.i18n.json +++ b/packages/rocketchat-webrtc/i18n/en.i18n.json @@ -1,9 +1,5 @@ { - "WebRTC_Description" : "", "WebRTC_Enable_Channel" : "Enable for Public Channels", - "WebRTC_Enable_Channel_Description" : "", "WebRTC_Enable_Direct" : "Enable for Direct Messages", - "WebRTC_Enable_Direct_Description" : "", - "WebRTC_Enable_Private" : "Enable for Private Channels", - "WebRTC_Enable_Private_Description" : "" -} + "WebRTC_Enable_Private" : "Enable for Private Channels" +} \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/cs.i18n.json b/packages/rocketchat-wordpress/i18n/cs.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/en.i18n.json b/packages/rocketchat-wordpress/i18n/en.i18n.json index 129f9acb958..06727b945fe 100644 --- a/packages/rocketchat-wordpress/i18n/en.i18n.json +++ b/packages/rocketchat-wordpress/i18n/en.i18n.json @@ -1,10 +1,6 @@ { "API_Wordpress_URL" : "WordPress URL", - "API_Wordpress_URL_Description" : "", "Accounts_OAuth_Wordpress" : "WordPress Login", - "Accounts_OAuth_Wordpress_Description" : "", "Accounts_OAuth_Wordpress_id" : "WordPress Id", - "Accounts_OAuth_Wordpress_id_Description" : "", - "Accounts_OAuth_Wordpress_secret" : "WordPress Secret", - "Accounts_OAuth_Wordpress_secret_Description" : "" -} + "Accounts_OAuth_Wordpress_secret" : "WordPress Secret" +} \ No newline at end of file -- GitLab From 23e877d15a6c5db7c06930516520ee6d94b09a67 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 12:18:50 -0200 Subject: [PATCH 0526/1338] added order parameter to roomTypes --- client/startup/defaultRoomTypes.coffee | 8 ++--- packages/rocketchat-lib/lib/roomTypes.coffee | 29 +++++++++++++---- packages/rocketchat-livechat/client/ui.js | 34 +++++++++----------- packages/rocketchat-livechat/package.js | 2 ++ 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index c50823a9910..558121b5d3a 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,8 +1,8 @@ -RocketChat.roomTypes.add 'starred', +RocketChat.roomTypes.add 'starred', 0, template: 'starredRooms' icon: 'icon-star' -RocketChat.roomTypes.add 'c', +RocketChat.roomTypes.add 'c', 10, template: 'channels' icon: 'icon-hash' route: @@ -15,7 +15,7 @@ RocketChat.roomTypes.add 'c', return { name: sub.name } permissions: [ 'view-c-room' ] -RocketChat.roomTypes.add 'd', +RocketChat.roomTypes.add 'd', 20, template: 'directMessages' icon: 'icon-at' route: @@ -28,7 +28,7 @@ RocketChat.roomTypes.add 'd', return { username: sub.name } permissions: [ 'view-d-room' ] -RocketChat.roomTypes.add 'p', +RocketChat.roomTypes.add 'p', 30, template: 'privateGroups' icon: 'icon-lock' route: diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index 7ae907bdfe5..e2abeba2f5c 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -1,9 +1,11 @@ RocketChat.roomTypes = new class roomTypesOrder = [] roomTypes = {} + mainOrder = 1 ### Adds a room type to app @param identifier MUST BE equals to `db.rocketchat_room.t` field + @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 @@ -12,12 +14,18 @@ RocketChat.roomTypes = new class name: route name action: route action function ### - add = (identifier, config) -> + add = (identifier, order, config) -> if roomTypes[identifier]? throw new Meteor.Error 'identifier-already-set', t('Room_type_identifier_already_set') + if not order? + order = mainOrder + 10 + mainOrder += 10 + # @TODO validate config options - roomTypesOrder.push identifier + roomTypesOrder.push + identifier: identifier + order: order roomTypes[identifier] = config if config.route?.path? and config.route?.name? and config.route?.action? @@ -38,9 +46,10 @@ RocketChat.roomTypes = new class getAllTypes = -> typesPermitted = [] - roomTypesOrder.forEach (type) -> - if not roomTypes[type].permissions? or RocketChat.authz.hasAtLeastOnePermission roomTypes[type].permissions - typesPermitted.push roomTypes[type] + + _.sortBy(roomTypesOrder, 'order').forEach (type) -> + if not roomTypes[type.identifier].permissions? or RocketChat.authz.hasAtLeastOnePermission roomTypes[type.identifier].permissions + typesPermitted.push roomTypes[type.identifier] return typesPermitted @@ -53,7 +62,12 @@ RocketChat.roomTypes = new class throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' unless roomTypes[roomType]? - roomTypesOrder.push roomType + order = mainOrder + 10 + mainOrder += 10 + + roomTypesOrder.push + identifier: roomType + order: order roomTypes[roomType] = {} roomTypes[roomType].publish = callback @@ -71,7 +85,8 @@ RocketChat.roomTypes = new class getIdentifiers = (except) -> except = [].concat except - return _.reject roomTypesOrder, (t) -> return except.indexOf(t) isnt -1 + list = _.reject roomTypesOrder, (t) -> return except.indexOf(t.identifier) isnt -1 + return _.map list, (t) -> return t.identifier # addType: addType getTypes: getAllTypes diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index d24a82d39f4..c5a58fe2b41 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -1,20 +1,18 @@ -Meteor.startup(function() { - RocketChat.roomTypes.add('l', { - template: 'livechat', - icon: 'icon-chat-empty', - route: { - name: 'live', - path: '/live/:name', - action: (params, queryParams) => { - Session.set('showUserInfo'); - openRoom('l', params.name); - }, - link: (sub) => { - return { name: sub.name } - } +RocketChat.roomTypes.add('l', 5, { + template: 'livechat', + icon: 'icon-chat-empty', + route: { + name: 'live', + path: '/live/:name', + action: (params, queryParams) => { + Session.set('showUserInfo'); + openRoom('l', params.name); }, - permissions: [ 'view-l-room' ] - }); - - AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); + link: (sub) => { + return { name: sub.name } + } + }, + permissions: [ 'view-l-room' ] }); + +AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index f02fe7245eb..0672e0e91b5 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -21,6 +21,8 @@ Package.onUse(function(api) { api.use(['ecmascript', 'webapp', 'autoupdate'], 'server'); api.imply('alanning:roles@1.2.12'); + + api.use('rocketchat:lib', 'client'); api.use('kadira:flow-router', 'client'); api.addFiles('livechat.js', 'server'); -- GitLab From 498678528890e34df1d239ce2c892f4917db2402 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 12:19:33 -0200 Subject: [PATCH 0527/1338] send permissions to client before startup --- packages/rocketchat-authorization/client/startup.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index ded8f7799ff..84ab0f39dca 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -1,2 +1 @@ -Meteor.startup -> - RocketChat.authz.subscription = Meteor.subscribe 'permissions' \ No newline at end of file +RocketChat.authz.subscription = Meteor.subscribe 'permissions' -- GitLab From 4e365171d42b97ed31b7ec469238007a33d27490 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 12:19:41 -0200 Subject: [PATCH 0528/1338] added flow-router depedency --- packages/rocketchat-lib/package.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index fde76ff1f86..3c0cb5dd996 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -21,6 +21,7 @@ Package.onUse(function(api) { api.use('service-configuration'); api.use('check'); api.use('arunoda:streams'); + api.use('kadira:flow-router', 'client'); // COMMON api.addFiles('lib/core.coffee'); -- GitLab From feb29a40a598a6c9bd4ff1378745f5490a43911b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 12:20:09 -0200 Subject: [PATCH 0529/1338] random code cleanup --- packages/rocketchat-ui/views/app/room.coffee | 18 ------------------ .../views/app/spotlight/spotlight.coffee | 2 +- .../views/app/spotlight/spotlight.html | 4 ++-- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 2aa4d409355..17b46c0d0c5 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -91,24 +91,6 @@ Template.room.helpers else return 'offline' - autocompleteSettingsRoomSearch: -> - return { - limit: 10 - # inputDelay: 300 - rules: [ - { - collection: 'UserAndRoom' - subscription: 'roomSearch' - field: 'name' - template: Template.roomSearch - noMatchTemplate: Template.roomSearchEmpty - matchAll: true - filter: { uid: { $ne: Meteor.userId() } } - sort: 'name' - } - ] - } - isChannel: -> roomData = Session.get('roomData' + this._id) return '' unless roomData diff --git a/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee b/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee index 07825b6684e..f5d78489505 100644 --- a/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee +++ b/packages/rocketchat-ui/views/app/spotlight/spotlight.coffee @@ -7,7 +7,7 @@ $('.spotlight input').focus() Template.spotlight.helpers - autocompleteSettingsRoomSearch: -> + autocompleteSettings: -> return { limit: 10 # inputDelay: 300 diff --git a/packages/rocketchat-ui/views/app/spotlight/spotlight.html b/packages/rocketchat-ui/views/app/spotlight/spotlight.html index eb36d46f036..b15eba116e6 100644 --- a/packages/rocketchat-ui/views/app/spotlight/spotlight.html +++ b/packages/rocketchat-ui/views/app/spotlight/spotlight.html @@ -2,7 +2,7 @@ <div class="spotlight hidden"> <div class="spotlight-input"> <i class="icon-search"></i> - {{> inputAutocomplete settings=autocompleteSettingsRoomSearch id="room-search" class="search" placeholder=tQuickSearch autocomplete="off"}} + {{> inputAutocomplete settings=autocompleteSettings id="room-search" class="search" placeholder=tQuickSearch autocomplete="off"}} </div> </div> -</template> \ No newline at end of file +</template> -- GitLab From 289dc349783b1ec15221206bc57ffd1d5130ebee Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 23 Nov 2015 12:20:21 -0200 Subject: [PATCH 0530/1338] fix spotlight error --- server/publications/spotlight.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/publications/spotlight.coffee b/server/publications/spotlight.coffee index 3a1231593be..9921d4987e4 100644 --- a/server/publications/spotlight.coffee +++ b/server/publications/spotlight.coffee @@ -1,5 +1,5 @@ Meteor.publish 'spotlight', (selector, options, collName) -> - unless this.userId + if not this.userId? or not selector?.name?.$regex? return this.ready() console.log '[publish] spotlight -> '.green, 'selector:', selector, 'options:', options, 'collName:', collName -- GitLab From 9ae9d2ed54f89c989b900e1617b15a3bf0544dc0 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 23 Nov 2015 14:40:21 -0500 Subject: [PATCH 0531/1338] Evolve the call-to-action for devs Add immediacy from recent discussion(s) --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 74cd0a3e905..63d41649053 100644 --- a/README.md +++ b/README.md @@ -250,12 +250,10 @@ Performance monitoring provided by [Kadira](https://kadira.io) ### Contributions -#### We Need Your Help! +Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors community. A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it! -So if you'd like to be part of the project, please check out the [roadmap](https://github.com/RocketChat/Rocket.Chat/milestones) and [issues](https://github.com/RocketChat/Rocket.Chat/issues) to see if there's anything you can help with. - ### Branching Model The [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branching-model/) section below is derived from Vincent Driessen at nvie. -- GitLab From 5dee90d3a3485067f482e9d9c915afb2a24a6466 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 23 Nov 2015 17:47:34 -0200 Subject: [PATCH 0532/1338] using replicates on mongo image --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 07624dc9669..c32830def05 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ mongo: # volumes: # - ./data/runtime/mongo:/data/mongo # - ./data/dump:/dump - command: mongod --smallfiles + command: mongod --smallfiles --replSet rs0 --oplogSize 128 rocketchat: image: rocketchat/rocket.chat -- GitLab From f4b856f2b67e08c3a4308e1f3d354abe021f6c61 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 23 Nov 2015 17:50:42 -0200 Subject: [PATCH 0533/1338] trying to fix cache issues --- server/startup/avatar.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 05801d949bd..71aafd60613 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -42,7 +42,7 @@ Meteor.startup -> if not file? res.setHeader 'content-type', 'image/svg+xml' - res.setHeader 'cache-control', 'public' + res.setHeader 'Cache-Control', 'public, max-age=31536000' res.setHeader 'Last-Modified', "Thu, 01 Jan 2015 00:00:00 GMT" reqModifiedHeader = req.headers["if-modified-since"]; -- GitLab From 16b2c9fa0e4d4c7924092b0a3e93e18da7463f15 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 23 Nov 2015 18:19:57 -0200 Subject: [PATCH 0534/1338] trying to fix cache issues --- server/startup/avatar.coffee | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 71aafd60613..b97040ef457 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -41,8 +41,9 @@ Meteor.startup -> res.setHeader 'Content-Disposition', 'inline' if not file? - res.setHeader 'content-type', 'image/svg+xml' - res.setHeader 'Cache-Control', 'public, max-age=31536000' + res.setHeader 'Content-Type', 'image/svg+xml' + res.setHeader 'Cache-Control', 'public, max-age=0' + res.setHeader 'Expires', '-1' res.setHeader 'Last-Modified', "Thu, 01 Jan 2015 00:00:00 GMT" reqModifiedHeader = req.headers["if-modified-since"]; @@ -92,8 +93,10 @@ Meteor.startup -> res.end() return + res.setHeader 'Cache-Control', 'public, max-age=0' + res.setHeader 'Expires', '-1' res.setHeader 'Last-Modified', file.uploadDate?.toUTCString() or new Date().toUTCString() - res.setHeader 'content-type', 'image/jpeg' + res.setHeader 'Content-Type', 'image/jpeg' res.setHeader 'Content-Length', file.length file.readStream.pipe res -- GitLab From 8fc19db68b69025e71c4aaa9eb47c48f1ebdcad4 Mon Sep 17 00:00:00 2001 From: Jason Paryani <github@jparyani.com> Date: Mon, 23 Nov 2015 12:40:31 -0800 Subject: [PATCH 0535/1338] Add spk generation to travis-ci --- .travis.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7f417e0c6a..615c142d526 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,16 @@ before_install: - export JASMINE_DEBUG=1 - export VELOCITY_DEBUG=1 - export VELOCITY_DEBUG_MIRROR=1 +- export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") +- cd /tmp +- curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - +- export PATH=$PATH:${PWD}/sandstorm-$SANDSTORM_VERSION/bin +- sudo mkdir -p /home/vagrant +- sudo chown -R travis /home/vagrant +- sudo mkdir -p /opt +- sudo chown -R travis /opt +- cd $TRAVIS_BUILD_DIR +- cp -r . /opt/app script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - cd .travis @@ -33,11 +43,18 @@ script: - cd .travis - sh ./namefiles.sh - cd .. -- meteor add rocketchat:livechat rocketchat:hubot +- meteor add rocketchat:livechat rocketchat:hubot - meteor build --server demo.rocket.chat ../build - cd .travis - sh ./namedemo.sh -- cd .. +- cd /tmp +- spk init -p3000 -- nothing +- export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) +- cd $TRAVIS_BUILD_DIR/.sandstorm +- sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp +- ./build.sh +- spk pack $TRAVIS_BUILD_DIR/rocket.chat.spk +- cd $TRAVIS_BUILD_DIR after_deploy: - "curl -H \"Content-Type: application/json\" --data \"{'build': true}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" deploy: -- GitLab From 984fadb8e2771c063610a4c67e85bf52d1ec4ac0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 23 Nov 2015 19:39:11 -0200 Subject: [PATCH 0536/1338] Separate CORS in a standalone package --- .meteor/packages | 1 + .meteor/versions | 1 + .../rocketchat-cors/cors.coffee | 0 packages/rocketchat-cors/package.js | 21 +++++++++++++++++++ 4 files changed, 23 insertions(+) rename server/lib/_cors.coffee => packages/rocketchat-cors/cors.coffee (100%) create mode 100644 packages/rocketchat-cors/package.js diff --git a/.meteor/packages b/.meteor/packages index 164b3e945ae..f3b3486dc9f 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -3,6 +3,7 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. +rocketchat:cors accounts-facebook accounts-github accounts-google diff --git a/.meteor/versions b/.meteor/versions index d670b9baf4b..2484f271cce 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -125,6 +125,7 @@ rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 rocketchat:channel-settings@0.0.1 rocketchat:colors@0.0.1 +rocketchat:cors@0.0.1 rocketchat:custom-oauth@1.0.0 rocketchat:emojione@0.0.1 rocketchat:favico@0.0.1 diff --git a/server/lib/_cors.coffee b/packages/rocketchat-cors/cors.coffee similarity index 100% rename from server/lib/_cors.coffee rename to packages/rocketchat-cors/cors.coffee diff --git a/packages/rocketchat-cors/package.js b/packages/rocketchat-cors/package.js new file mode 100644 index 00000000000..ee7a5bf3f28 --- /dev/null +++ b/packages/rocketchat-cors/package.js @@ -0,0 +1,21 @@ +Package.describe({ + name: 'rocketchat:cors', + version: '0.0.1', + summary: 'Enable CORS', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'webapp' + ]); + + api.addFiles('cors.coffee', 'server'); +}); + +Package.onTest(function(api) { + +}); -- GitLab From ad8716630c497809471f93da3645337a9b9ff45a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 23 Nov 2015 21:46:15 -0200 Subject: [PATCH 0537/1338] Try to fix problem with CORS and header X-Rocket-Chat-Version --- packages/rocketchat-cors/cors.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index 52cdcc879a3..ac45ef8e0ca 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -3,10 +3,12 @@ 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"); return next() _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware WebAppInternals._staticFilesMiddleware = (staticFiles, 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"); _staticFilesMiddleware(staticFiles, req, res, next) -- GitLab From c765669600da8b2d64e26558f0711bab05950c3d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 23 Nov 2015 21:48:05 -0200 Subject: [PATCH 0538/1338] Remove ; --- packages/rocketchat-cors/cors.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index ac45ef8e0ca..f360cd65014 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -3,12 +3,12 @@ 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"); + res.setHeader("Access-Control-Expose-Headers", "X-Rocket-Chat-Version") return next() _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware WebAppInternals._staticFilesMiddleware = (staticFiles, 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"); + res.setHeader("Access-Control-Expose-Headers", "X-Rocket-Chat-Version") _staticFilesMiddleware(staticFiles, req, res, next) -- GitLab From 2aed2c189bda3e4a919fb10fd4a51c585bd7b666 Mon Sep 17 00:00:00 2001 From: Jason Paryani <github@jparyani.com> Date: Mon, 23 Nov 2015 16:57:35 -0800 Subject: [PATCH 0539/1338] Show more clear login error for Sandstorm users Fixes #1328 --- .sandstorm/launcher.sh | 1 + .sandstorm/sandstorm-pkgdef.capnp | 3 ++- packages/rocketchat-ui-login/login/form.coffee | 8 +++++++- packages/rocketchat-ui-login/login/form.html | 6 ++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.sandstorm/launcher.sh b/.sandstorm/launcher.sh index 9f62691ffee..f94956f58d5 100755 --- a/.sandstorm/launcher.sh +++ b/.sandstorm/launcher.sh @@ -1,4 +1,5 @@ #!/bin/bash set -euo pipefail +export METEOR_SETTINGS='{"public": {"sandstorm": true}}' exec node /start.js -p 8000 diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 2c0b0f50c61..7d5e7251399 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -91,6 +91,7 @@ const myCommand :Spk.Manifest.Command = ( argv = ["/sandstorm-http-bridge", "8000", "--", "/opt/app/.sandstorm/launcher.sh"], environ = [ # Note that this defines the *entire* environment seen by your app. - (key = "PATH", value = "/usr/local/bin:/usr/bin:/bin") + (key = "PATH", value = "/usr/local/bin:/usr/bin:/bin"), + (key = "SANDSTORM", value = "1") ] ); diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index face5c303d9..8b1d253db51 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -29,6 +29,9 @@ Template.loginForm.helpers showBackToLoginLink: -> return 'hidden' unless Template.instance().state.get() in ['register', 'forgot-password', 'email-verification', 'wait-activation'] + showSandstorm: -> + return Template.instance().state.get() is 'sandstorm' + btnLoginSave: -> switch Template.instance().state.get() when 'register' @@ -114,7 +117,10 @@ Template.loginForm.events Template.loginForm.onCreated -> instance = @ - @state = new ReactiveVar('login') + if Meteor.settings.public.sandstorm + @state = new ReactiveVar('sandstorm') + else + @state = new ReactiveVar('login') @validate = -> formData = $("#login-card").serializeArray() formObj = {} diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index c1247d08a25..c5514e2f0fa 100644 --- a/packages/rocketchat-ui-login/login/form.html +++ b/packages/rocketchat-ui-login/login/form.html @@ -1,4 +1,9 @@ <template name="loginForm"> + {{#if showSandstorm}} + <div class="alert alert-danger"> + You must login to Sandstorm (on the top right) in order to access this chat. + </div> + {{else}} <form id="login-card" method='/'> {{#if waitActivation}} <header> @@ -47,4 +52,5 @@ <div class='login-terms'> {{{loginTerms}}} </div> + {{/if}} </template> -- GitLab From 088d9a9ba20e7b3b9c6ec5e12ae111321f98dfc4 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 23 Nov 2015 20:51:44 -0500 Subject: [PATCH 0540/1338] Deploy Sandstorm SPK with every Rocket.Chat build Yay! --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1ecc185b684..62371ed3a30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,7 @@ script: - ./build.sh - spk pack $TRAVIS_BUILD_DIR/rocket.chat.spk - cd $TRAVIS_BUILD_DIR +- mv rocket.chat.spk ../build/rocket.chat.latest.spk after_deploy: - cd .travis - sh ./builddocker.sh -- GitLab From be844100a78df067262a4b9af93ff2c6574cf56d Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 23 Nov 2015 21:23:33 -0500 Subject: [PATCH 0541/1338] Announce availability of updated Sandstorm SPK minor edit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63d41649053..2f1789ac87a 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ Host your own Rocket.Chat server in four seconds flat: [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) +_*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat.latest.spk) for testing on your own server. + Also available as FirefoxOS app: [](https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29) -- GitLab From 343b674103a9dbca9f315339fcdde2cad44986cf Mon Sep 17 00:00:00 2001 From: Jason Paryani <github@jparyani.com> Date: Mon, 23 Nov 2015 22:03:06 -0800 Subject: [PATCH 0542/1338] Fix wrong PGP signature for Sandstorm spk builds There's a bug (feature?) in Sandstorm that prevents spks with an improper PGP signature from being installed. This change produces an spk without PGP signatures, and the future `spk repack` command will allow you to add/change the PGP signatures in addition to changing app id. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62371ed3a30..60d42d8a5e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,9 +55,9 @@ script: - cd $TRAVIS_BUILD_DIR/.sandstorm - sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp - ./build.sh -- spk pack $TRAVIS_BUILD_DIR/rocket.chat.spk +- sed -i "s/\spgp/#pgp/g" sandstorm-pkgdef.capnp +- spk pack $TRAVIS_BUILD_DIR/../build/rocket.chat.latest.spk - cd $TRAVIS_BUILD_DIR -- mv rocket.chat.spk ../build/rocket.chat.latest.spk after_deploy: - cd .travis - sh ./builddocker.sh -- GitLab From 114302664950ec57bc6dfb4885f29afb10aa11ee Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 24 Nov 2015 09:07:38 -0200 Subject: [PATCH 0543/1338] Fixed vulnerability issue with file names --- .../flex-tab/tabs/uploadedFilesList.coffee | 2 ++ .../flex-tab/tabs/uploadedFilesList.html | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index b522c02106a..d46b484db5d 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -17,6 +17,8 @@ Template.uploadedFilesList.helpers if this.type.match(/^image\/.+$/) return 'room-files-swipebox' + escapedName: -> + return s.escapeHTML @name Template.uploadedFilesList.events 'click .room-file-item': (e, t) -> diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html index ba76402103e..f50af8c5ad9 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html @@ -9,7 +9,7 @@ <ul class='list clearfix lines'> {{#each files}} <li> - <a title="{{name}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> + <a title="{{escapedName}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> <i class="{{getFileIcon type}}"></i> <p>{{name}}</p> </a> @@ -24,4 +24,4 @@ {{/if}} </div> </div> -</template> \ No newline at end of file +</template> -- GitLab From 4f45796719436431d5a4c1f5cccfffcecee37614 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 09:37:42 -0200 Subject: [PATCH 0544/1338] support `null` as roomType identifier --- client/startup/defaultRoomTypes.coffee | 2 +- packages/rocketchat-lib/lib/roomTypes.coffee | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 558121b5d3a..fa00955642f 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -1,4 +1,4 @@ -RocketChat.roomTypes.add 'starred', 0, +RocketChat.roomTypes.add null, 0, template: 'starredRooms' icon: 'icon-star' diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/lib/roomTypes.coffee index e2abeba2f5c..969afaba192 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/lib/roomTypes.coffee @@ -4,7 +4,7 @@ RocketChat.roomTypes = new class mainOrder = 1 ### Adds a room type to app - @param identifier MUST BE equals to `db.rocketchat_room.t` field + @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 @@ -15,6 +15,9 @@ RocketChat.roomTypes = new class action: route action function ### add = (identifier, order, config) -> + unless identifier? + identifier = Random.id() + if roomTypes[identifier]? throw new Meteor.Error 'identifier-already-set', t('Room_type_identifier_already_set') -- GitLab From 5c7a1bbec4b807f442b93a0d62c628ccfb9eb9b9 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 09:38:25 -0200 Subject: [PATCH 0545/1338] missing translation --- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e4b831f67d6..b8e6df84ff8 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -266,6 +266,7 @@ "No_favorites_yet" : "You haven't added any favorites yet.", "No_group_with_name_%s_was_found" : "No private group with name <strong>\"%s\"</strong> was found!", "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_user_with_username_%s_was_found" : "No user with username <strong>\"%s\"</strong> was found!", "Not_allowed" : "Not allowed", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 69fd6340f1a..1c196f88697 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -237,6 +237,7 @@ "No_favorites_yet" : "Nenhum favorito ainda.", "No_group_with_name_%s_was_found" : "Nenhum grupo privado com nome <strong>\"%s\"</strong> foi encontrado!", "No_groups_yet" : "Nenhum grupo privado ainda.", + "No_livechats" : "Nenhum atendimento.", "No_permission_to_view_room" : "Sem permissões para ver a sala", "No_user_with_username_%s_was_found" : "Nenhum usuário com nome de usuário <strong>\"%s\"</strong> foi encontrado!", "Not_allowed" : "Não permitido", @@ -413,4 +414,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} \ No newline at end of file +} -- GitLab From d16372af0a0c369c97881f22bc76b6ac2ece13ca Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 10:13:25 -0200 Subject: [PATCH 0546/1338] roomTypes splitted into client and server files --- .../{ => client}/lib/roomTypes.coffee | 30 ------------------- packages/rocketchat-lib/package.js | 5 +++- .../server/lib/roomTypes.coffee | 26 ++++++++++++++++ 3 files changed, 30 insertions(+), 31 deletions(-) rename packages/rocketchat-lib/{ => client}/lib/roomTypes.coffee (70%) create mode 100644 packages/rocketchat-lib/server/lib/roomTypes.coffee diff --git a/packages/rocketchat-lib/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee similarity index 70% rename from packages/rocketchat-lib/lib/roomTypes.coffee rename to packages/rocketchat-lib/client/lib/roomTypes.coffee index 969afaba192..c3cdfc84c9d 100644 --- a/packages/rocketchat-lib/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -56,33 +56,6 @@ RocketChat.roomTypes = new class return typesPermitted - ### add a publish for a room type - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param callback: function that will return the publish's data - ### - setPublish = (roomType, callback) -> - if roomTypes[roomType]?.publish? - throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' - - unless roomTypes[roomType]? - order = mainOrder + 10 - mainOrder += 10 - - roomTypesOrder.push - identifier: roomType - order: order - roomTypes[roomType] = {} - - roomTypes[roomType].publish = callback - - ### run the publish for a room type - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param identifier: identifier of the room - ### - runPublish = (roomType, identifier) -> - return unless roomTypes[roomType].publish? - return roomTypes[roomType].publish.call this, identifier - getIcon = (roomType) -> return roomTypes[roomType]?.icon @@ -101,7 +74,4 @@ RocketChat.roomTypes = new class # setRoute: setRoute getRouteLink: getRouteLink - setPublish: setPublish - runPublish: runPublish - add: add diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 3c0cb5dd996..122f05d9cef 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -26,7 +26,6 @@ Package.onUse(function(api) { // COMMON api.addFiles('lib/core.coffee'); api.addFiles('lib/callbacks.coffee'); - api.addFiles('lib/roomTypes.coffee'); api.addFiles('lib/slashCommand.coffee'); // MODELS SERVER @@ -53,6 +52,7 @@ Package.onUse(function(api) { // CLIENT api.addFiles('client/lib/openRoom.coffee', 'client'); api.addFiles('client/lib/roomExit.coffee', 'client'); + api.addFiles('client/lib/roomTypes.coffee', 'client'); api.addFiles('client/AdminBox.coffee', 'client'); api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); @@ -61,6 +61,9 @@ Package.onUse(function(api) { api.addFiles('settings/client/rocketchat.coffee', 'client'); + // SERVER COMMOM + api.addFiles('server/lib/roomTypes.coffee', 'server'); + // SERVER api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/lib/roomTypes.coffee b/packages/rocketchat-lib/server/lib/roomTypes.coffee new file mode 100644 index 00000000000..eb2b751d10a --- /dev/null +++ b/packages/rocketchat-lib/server/lib/roomTypes.coffee @@ -0,0 +1,26 @@ +RocketChat.roomTypes = new class + roomTypes = {} + + ### add a publish for a room type + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param callback: function that will return the publish's data + ### + setPublish = (roomType, callback) -> + if roomTypes[roomType]?.publish? + throw new Meteor.Error 'route-publish-exists', 'Publish for the given type already exists' + + unless roomTypes[roomType]? + roomTypes[roomType] = {} + + roomTypes[roomType].publish = callback + + ### run the publish for a room type + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param identifier: identifier of the room + ### + runPublish = (roomType, identifier) -> + return unless roomTypes[roomType].publish? + return roomTypes[roomType].publish.call this, identifier + + setPublish: setPublish + runPublish: runPublish -- GitLab From 2a5551fb07457ce40d92bd69a95722eb80669f6b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 10:20:03 -0200 Subject: [PATCH 0547/1338] creating roles and permissions --- .../functions/getPermissionsForRole.coffee | 2 +- packages/rocketchat-livechat/permissions.js | 40 +++++-------------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee b/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee index aa68c55f26d..7023d120265 100644 --- a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee +++ b/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee @@ -4,6 +4,6 @@ RocketChat.authz.getPermissionsForRole = (roleName) -> roleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name') unless roleName in roleNames - throw new Meteor.Error 'invalid-role' + throw new Meteor.Error 'invalid-role', "Role #{roleName} not found" return _.pluck(RocketChat.models.Permissions.findByRole( roleName ).fetch(), '_id') diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index 4c4c84f3ff4..0239df4a1e2 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -1,32 +1,12 @@ -Meteor.startup(function() { - var i, j, len, len1, permission, ref, role, roles, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - var permissions = [ - { - _id: 'receive-livechat', - roles : ['livechat-agent'] - }, - { - _id: 'edit-livechat-settings', - roles : ['livechat-manager'] - } - ]; - - roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); - - for (i = 0, len = permissions.length; i < len; i++) { - permission = permissions[i]; - RocketChat.models.Permissions.upsert(permission._id, { - $setOnInsert: permission - }); - ref = permission.roles; - for (j = 0, len1 = ref.length; j < len1; j++) { - role = ref[j]; - if (indexOf.call(roles, role) < 0) { - Roles.createRole(role); - roles.push(role); - } - } +Meteor.startup(() => { + var roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); + if (roles.indexOf('livechat-agent') === -1) { + Roles.createRole('livechat-agent'); + } + if (roles.indexOf('livechat-manager') === -1) { + Roles.createRole('livechat-manager'); + } + if (RocketChat.models && RocketChat.models.Permissions) { + RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager']); } }); -- GitLab From 6f3a5546ac4ffc8c61eb9104aaffc7b4422f2587 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 10:24:02 -0200 Subject: [PATCH 0548/1338] initial docs for rocketchat-lib package --- packages/rocketchat-lib/README.md | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/rocketchat-lib/README.md diff --git a/packages/rocketchat-lib/README.md b/packages/rocketchat-lib/README.md new file mode 100644 index 00000000000..32ddd189ff8 --- /dev/null +++ b/packages/rocketchat-lib/README.md @@ -0,0 +1,49 @@ +## Rocket.Chat main library + +This package contains the main libraries of Rocket.Chat. + +### APIs + +#### roomTypes + +You can create your own room type using (on the client): + +``` +RocketChat.roomTypes.add('l', 5, { + template: 'livechat', + icon: 'icon-chat-empty', + route: { + name: 'live', + path: '/live/:name', + action(params, queryParams) { + Session.set('showUserInfo'); + openRoom('l', params.name); + }, + link(sub) { + return { name: sub.name } + } + }, + permissions: [ 'view-l-room' ] +}); +``` + +You'll need publish information about the new room with (on the server): + +``` +RocketChat.roomTypes.setPublish('l', (identifier) => { + return RocketChat.models.Rooms.findByTypeAndName('l', identifier, { + fields: { + name: 1, + t: 1, + cl: 1, + u: 1, + usernames: 1, + v: 1 + } + }); +}); +``` + +### Functions +### Methods +### Publications -- GitLab From a19f784fd213035e805a11993d9910ef6febd1e2 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 10:35:09 -0200 Subject: [PATCH 0549/1338] added javascript syntax do code blocks --- packages/rocketchat-lib/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/README.md b/packages/rocketchat-lib/README.md index 32ddd189ff8..93e67d06b9b 100644 --- a/packages/rocketchat-lib/README.md +++ b/packages/rocketchat-lib/README.md @@ -8,7 +8,7 @@ This package contains the main libraries of Rocket.Chat. You can create your own room type using (on the client): -``` +```javascript RocketChat.roomTypes.add('l', 5, { template: 'livechat', icon: 'icon-chat-empty', @@ -29,7 +29,7 @@ RocketChat.roomTypes.add('l', 5, { You'll need publish information about the new room with (on the server): -``` +```javascript RocketChat.roomTypes.setPublish('l', (identifier) => { return RocketChat.models.Rooms.findByTypeAndName('l', identifier, { fields: { -- GitLab From cb82b51836d4453852c12530682a1433414bb168 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 24 Nov 2015 08:27:09 -0500 Subject: [PATCH 0550/1338] travis notified fix of glitch test to see if glitch is fixed --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 62371ed3a30..8018f2ad403 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,6 @@ addons: before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' -- gem install mime-types -v 2.99 - mkdir -p node_modules - npm install phantomjs - npm install velocity-cli @@ -41,6 +40,7 @@ script: - npm install - npm start - cd .. +- meteor add-platform ios - meteor build ../build - cd .travis - sh ./namefiles.sh -- GitLab From d7a10a365445f71b86b223a9bfdcc5eed32e2b30 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 24 Nov 2015 08:34:32 -0500 Subject: [PATCH 0551/1338] fix typo remove old add-platform --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2877df50774..b557eb7006d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,6 @@ script: - npm install - npm start - cd .. -- meteor add-platform ios - meteor build ../build - cd .travis - sh ./namefiles.sh -- GitLab From 1a03d1fec5c8288b2539cfe39da9a247455f1ad5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 13:27:29 -0200 Subject: [PATCH 0552/1338] using es6 both on client and server - fix broke build --- packages/rocketchat-livechat/package.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 0672e0e91b5..ca8eb3627d0 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -18,7 +18,8 @@ Package.registerBuildPlugin({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use(['ecmascript', 'webapp', 'autoupdate'], 'server'); + api.use(['webapp', 'autoupdate'], 'server'); + api.use('ecmascript'); api.imply('alanning:roles@1.2.12'); -- GitLab From e30fdc732cdbed3ffe2cec33abc55421a36a2973 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 24 Nov 2015 13:42:17 -0200 Subject: [PATCH 0553/1338] Adapting #1145 for merging --- client/methods/saveRoomName.coffee | 3 +- .../server/functions/setUsername.coffee | 7 ++++- .../server/methods/setUsername.coffee | 7 ++++- .../server/startup/settings.coffee | 3 ++ packages/rocketchat-mentions/client.coffee | 6 ++-- packages/rocketchat-mentions/server.coffee | 6 ++-- server/lib/accounts.coffee | 2 +- server/methods/createChannel.coffee | 7 ++++- server/methods/createPrivateGroup.coffee | 7 ++++- server/methods/getUsernameSuggestion.coffee | 24 +++++++++++++--- server/methods/saveRoomName.coffee | 10 +++++-- .../publications/channelAutocomplete.coffee | 8 +++--- server/restapi/restapi.coffee | 28 +++++++++++++------ 13 files changed, 89 insertions(+), 29 deletions(-) diff --git a/client/methods/saveRoomName.coffee b/client/methods/saveRoomName.coffee index 659b8a35a8e..d2f6ff68477 100644 --- a/client/methods/saveRoomName.coffee +++ b/client/methods/saveRoomName.coffee @@ -8,7 +8,8 @@ Meteor.methods if room.u._id isnt Meteor.userId() or room.t not in ['c', 'p'] throw new Meteor.Error 403, t('Not allowed') - # name = _.slugify name + if RocketChat.settings.get 'UTF8_Names_slugify' + name = _.slugify name if name is room.name return diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index e5f4af3db7d..409fb6d161a 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -3,7 +3,12 @@ RocketChat.setUsername = (user, username) -> if not user or not username return false - if not /^[0-9a-zA-Z-_.\u00C0-\u017F\u4e00-\u9fa5]+$/.test username + try + nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$' + catch + nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$' + + if not nameValidation.test username return false # User already has desired username, return diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 4df9f4b8d63..6fed25d40de 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -13,7 +13,12 @@ Meteor.methods if user.username is username return username - if not /^[0-9a-zA-Z-_.\u00C0-\u017F\u4e00-\u9fa5]+$/.test username + try + nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$' + catch + nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$' + + if not nameValidation.test username throw new Meteor.Error 'username-invalid', "#{username} is not a valid username, use only letters, numbers, dots and dashes" if not RocketChat.checkUsernameAvailability username diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index f1985261ece..4bff3c27114 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -54,6 +54,9 @@ RocketChat.settings.add 'Allow_Invalid_SelfSigned_Certs', false, { type: 'boolea RocketChat.settings.add 'Disable_Favorite_Rooms', false, { type: 'boolean', group: 'General' } RocketChat.settings.add 'CDN_PREFIX', '', { type: 'string', group: 'General' } +RocketChat.settings.add 'UTF8_Names_Validation', '[0-9a-zA-Z-_.]+', { type: 'string', group: 'General', section: 'UTF8', public: true } +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 } diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index 6bb5a982dca..7a480267454 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -10,7 +10,8 @@ class MentionsClient mentions = [] - message.msg.replace /(?:^|\s|\n)(?:@)([0-9a-zA-Z-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> + msgMentionRegex = new RegExp '(?:^|\s|\n)(?:@)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + message.msg.replace msgMentionRegex, (match, mention) -> mentions.push mention me = Meteor.user()?.username @@ -33,7 +34,8 @@ class MentionsClient return match.replace mention, "<a href=\"\" class=\"#{classes}\" data-username=\"#{username}\">#{mention}</a>" channels = [] - message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> + msgChannelRegex = new RegExp '(?:^|\s|\n)(?:#)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + message.msg.replace msgChannelRegex, (match, mention) -> channels.push mention if channels.length isnt 0 diff --git a/packages/rocketchat-mentions/server.coffee b/packages/rocketchat-mentions/server.coffee index 04c42e511fc..75f364f3f77 100644 --- a/packages/rocketchat-mentions/server.coffee +++ b/packages/rocketchat-mentions/server.coffee @@ -7,7 +7,8 @@ class MentionsServer constructor: (message) -> # If message starts with /me, replace it for text formatting mentions = [] - message.msg.replace /(?:^|\s|\n)(?:@)([A-Za-z0-9-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> + msgMentionRegex = new RegExp '(?:^|\s|\n)(?:@)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + message.msg.replace msgMentionRegex, (match, mention) -> mentions.push mention if mentions.length isnt 0 mentions = _.unique mentions @@ -25,7 +26,8 @@ class MentionsServer message.mentions = verifiedMentions channels = [] - message.msg.replace /(?:^|\s|\n)(?:#)([A-Za-z0-9-_.\u00C0-\u017F\u4e00-\u9fa5]+)/g, (match, mention) -> + msgChannelRegex = new RegExp '(?:^|\s|\n)(?:#)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + message.msg.replace msgChannelRegex, (match, mention) -> channels.push mention if channels.length isnt 0 diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 4a62d083d86..6489faee0b3 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -88,7 +88,7 @@ Accounts.validateLoginAttempt (login) -> if login.allowed isnt true return login.allowed - if login.user?.active isnt true and login.user?.active != '1' + if !!login.user?.active isnt true throw new Meteor.Error 'inactive-user', TAPi18n.__ 'User_is_not_activated' return false diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index 9dd9a22f8a4..3c8319079d3 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -3,7 +3,12 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', "[methods] createChannel -> Invalid user" - if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name + 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.authz.hasPermission(Meteor.userId(), 'create-c') isnt true diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 6994f4b1b34..22080081372 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -8,7 +8,12 @@ Meteor.methods console.log '[methods] createPrivateGroup -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments - if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name + 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' now = new Date() diff --git a/server/methods/getUsernameSuggestion.coffee b/server/methods/getUsernameSuggestion.coffee index f9732af56db..927adb09aad 100644 --- a/server/methods/getUsernameSuggestion.coffee +++ b/server/methods/getUsernameSuggestion.coffee @@ -15,25 +15,41 @@ usernameIsAvaliable = (username) -> usernames = [] username = undefined - usernames.push user.name + if RocketChat.settings.get 'UTF8_Names_slugify' + usernames.push slug user.name + else + usernames.push user.name nameParts = user?.name?.split() if nameParts.length > 1 first = nameParts[0] last = nameParts[nameParts.length - 1] + if RocketChat.settings.get 'UTF8_Names_slugify' + usernames.push slug first[0] + last + usernames.push slug first + last[0] + else usernames.push first[0] + last usernames.push first + last[0] if user.profile?.name? - usernames.push user.profile.name + if RocketChat.settings.get 'UTF8_Names_slugify' + usernames.push slug user.profile.name + else + usernames.push user.profile.name if user.services? for serviceName, service of user.services if service.name? - usernames.push service.name + if RocketChat.settings.get 'UTF8_Names_slugify' + usernames.push slug service.name + else + usernames.push service.name else if service.username? - usernames.push service.username + if RocketChat.settings.get 'UTF8_Names_slugify' + usernames.push slug service.username + else + usernames.push service.username if user.emails?.length > 0 for email in user.emails when email.address? and email.verified is true diff --git a/server/methods/saveRoomName.coffee b/server/methods/saveRoomName.coffee index 02425c803f0..16756afec35 100644 --- a/server/methods/saveRoomName.coffee +++ b/server/methods/saveRoomName.coffee @@ -12,10 +12,16 @@ Meteor.methods #if room.u._id isnt Meteor.userId() and not hasPermission throw new Meteor.Error 403, 'Not allowed' - if not /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/.test name + 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' - ##remove name = _.slugify name + if RocketChat.settings.get 'UTF8_Names_slugify' + name = _.slugify name if name is room.name return diff --git a/server/publications/channelAutocomplete.coffee b/server/publications/channelAutocomplete.coffee index 7cdd182e69b..eebbea4bc8f 100644 --- a/server/publications/channelAutocomplete.coffee +++ b/server/publications/channelAutocomplete.coffee @@ -13,12 +13,12 @@ Meteor.publish 'channelAutocomplete', (name) -> limit: 5 cursorHandle = RocketChat.models.Rooms.findByNameContainingAndTypes(name, ['c'], options).observeChanges - added: (_id, record) -> - pub.added('channel-autocomplete', _id, record) if _id? + added: (_id, record) -> + pub.added('channel-autocomplete', _id, record) changed: (_id, record) -> - pub.changed('channel-autocomplete', _id, record) if _id? + pub.changed('channel-autocomplete', _id, record) removed: (_id, record) -> - pub.removed('channel-autocomplete', _id, record) if _id? + pub.removed('channel-autocomplete', _id, record) @ready() @onStop -> cursorHandle.stop() diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index eef079bc8e0..24931bdd942 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -20,7 +20,7 @@ Api.addRoute 'rooms/:id/join', authRequired: true, Meteor.runAsUser this.userId, () => Meteor.call('joinRoom', @urlParams.id) status: 'success' # need to handle error - + # leave a room Api.addRoute 'rooms/:id/leave', authRequired: true, post: -> @@ -60,7 +60,12 @@ Api.testapiValidateUsers = (users) -> if user.name? if user.email? if user.pass? - if /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/i.test user.name + try + nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$', 'i' + catch + nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$', 'i' + + if nameValidation.test user.name if /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+\b/i.test user.email continue throw new Meteor.Error 'invalid-user-record', "[restapi] bulk/register -> record #" + i + " is invalid" @@ -101,7 +106,7 @@ Api.addRoute 'bulk/register', authRequired: true, # restivus 0.8.4 does not support alanning:roles using groups #roleRequired: ['testagent', 'adminautomation'] action: -> - if RocketChat.authz.hasPermission(@userId, 'bulk-register-user') + if RocketChat.authz.hasPermission(@userId, 'bulk-register-user') try Api.testapiValidateUsers @bodyParams.users @@ -120,7 +125,7 @@ Api.addRoute 'bulk/register', authRequired: true, body: status: 'fail', message: e.name + ' :: ' + e.message else console.log '[restapi] bulk/register -> '.red, "User does not have 'bulk-register-user' permission" - statusCode: 403 + statusCode: 403 body: status: 'error', message: 'You do not have permission to do this' @@ -132,7 +137,12 @@ Api.testapiValidateRooms = (rooms) -> if room.name? if room.members? if room.members.length > 1 - if /^[0-9a-zA-Z-_\u00C0-\u017F\u4e00-\u9fa5]+$/i.test room.name + try + nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$', 'i' + catch + nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$', 'i' + + if nameValidation.test room.name continue throw new Meteor.Error 'invalid-room-record', "[restapi] bulk/createRoom -> record #" + i + " is invalid" return @@ -143,7 +153,7 @@ Api.testapiValidateRooms = (rooms) -> @apiName createRoom @apiGroup TestAndAdminAutomation @apiVersion 0.0.1 -@apiParam {json} rooms An array of rooms in the body of the POST. 'name' is room name, 'members' is array of usernames +@apiParam {json} rooms An array of rooms in the body of the POST. 'name' is room name, 'members' is array of usernames @apiParamExample {json} POST Request Body example: { 'rooms':[ {'name': 'room1', @@ -173,9 +183,9 @@ Api.addRoute 'bulk/createRoom', authRequired: true, # restivus 0.8.4 does not support alanning:roles using groups #roleRequired: ['testagent', 'adminautomation'] action: -> - # user must also have create-c permission because + # user must also have create-c permission because # createChannel method requires it - if RocketChat.authz.hasPermission(@userId, 'bulk-create-c') + if RocketChat.authz.hasPermission(@userId, 'bulk-create-c') try this.response.setTimeout (1000 * @bodyParams.rooms.length) Api.testapiValidateRooms @bodyParams.rooms @@ -188,7 +198,7 @@ Api.addRoute 'bulk/createRoom', authRequired: true, body: status: 'fail', message: e.name + ' :: ' + e.message else console.log '[restapi] bulk/createRoom -> '.red, "User does not have 'bulk-create-c' permission" - statusCode: 403 + statusCode: 403 body: status: 'error', message: 'You do not have permission to do this' -- GitLab From 4e05fb4bbaecbb29b92833dfc3318a7983467a70 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 14:18:56 -0200 Subject: [PATCH 0554/1338] fixing remaining conflicts --- packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee | 4 ---- packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee index fc7a6533c65..6b0aa396d44 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee @@ -33,11 +33,7 @@ Template.chatRoomItem.helpers return true route: -> -<<<<<<< HEAD - FlowRouter.path RocketChat.roomTypes.getRouteLink @t, @ -======= return RocketChat.roomTypes.getRouteLink @t, @ ->>>>>>> develop Template.chatRoomItem.rendered = -> if not (FlowRouter.getParam('_id')? and FlowRouter.getParam('_id') is this.data.rid) and not this.data.ls diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index c92a094126d..513916bd038 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -98,8 +98,4 @@ Template.sideNav.onRendered -> # @TODO validate role/permission inside roomTypes object RocketChat.roomTypes.getTypes().forEach (roomType) -> if Template[roomType.template]? -<<<<<<< HEAD - # if RocketChat.authz.hasRole(Meteor.userId(), roomType.roles) && Template[roomType.template]? -======= ->>>>>>> develop Blaze.render Template[roomType.template], wrapper, lastLink -- GitLab From 88008195980bcaebef6eb4a64cba0cdaac379f1d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 14:20:05 -0200 Subject: [PATCH 0555/1338] remove comment --- packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 513916bd038..7c9d2574f8a 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -95,7 +95,6 @@ Template.sideNav.onRendered -> wrapper = $('.rooms-list .wrapper').get(0) lastLink = $('.rooms-list h3.history-div').get(0) - # @TODO validate role/permission inside roomTypes object RocketChat.roomTypes.getTypes().forEach (roomType) -> if Template[roomType.template]? Blaze.render Template[roomType.template], wrapper, lastLink -- GitLab From 60aa04e9700d6b893a9fb9581b3f937766315669 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 24 Nov 2015 14:54:45 -0200 Subject: [PATCH 0556/1338] Fixed mentions broken with latest chinese support --- packages/rocketchat-mentions/client.coffee | 4 ++-- packages/rocketchat-mentions/server.coffee | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index 7a480267454..b61ca51c479 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -10,7 +10,7 @@ class MentionsClient mentions = [] - msgMentionRegex = new RegExp '(?:^|\s|\n)(?:@)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + msgMentionRegex = new RegExp '(?:^|\\s|\\n)(?:@)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' message.msg.replace msgMentionRegex, (match, mention) -> mentions.push mention @@ -34,7 +34,7 @@ class MentionsClient return match.replace mention, "<a href=\"\" class=\"#{classes}\" data-username=\"#{username}\">#{mention}</a>" channels = [] - msgChannelRegex = new RegExp '(?:^|\s|\n)(?:#)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + msgChannelRegex = new RegExp '(?:^|\\s|\\n)(?:#)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' message.msg.replace msgChannelRegex, (match, mention) -> channels.push mention diff --git a/packages/rocketchat-mentions/server.coffee b/packages/rocketchat-mentions/server.coffee index 75f364f3f77..4af2adca7ae 100644 --- a/packages/rocketchat-mentions/server.coffee +++ b/packages/rocketchat-mentions/server.coffee @@ -7,7 +7,7 @@ class MentionsServer constructor: (message) -> # If message starts with /me, replace it for text formatting mentions = [] - msgMentionRegex = new RegExp '(?:^|\s|\n)(?:@)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + msgMentionRegex = new RegExp '(?:^|\\s|\\n)(?:@)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' message.msg.replace msgMentionRegex, (match, mention) -> mentions.push mention if mentions.length isnt 0 @@ -26,7 +26,7 @@ class MentionsServer message.mentions = verifiedMentions channels = [] - msgChannelRegex = new RegExp '(?:^|\s|\n)(?:#)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' + msgChannelRegex = new RegExp '(?:^|\\s|\\n)(?:#)(' + RocketChat.settings.get('UTF8_Names_Validation') + ')', 'g' message.msg.replace msgChannelRegex, (match, mention) -> channels.push mention -- GitLab From 235d9fce93755a838a77033ff745827624db5286 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 24 Nov 2015 15:06:42 -0200 Subject: [PATCH 0557/1338] Removed moment chinese package --- .meteor/packages | 2 -- .meteor/versions | 1 - 2 files changed, 3 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index db134d87ce6..f3b3486dc9f 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -122,5 +122,3 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter -rzymek:moment-locale-zh-cn - diff --git a/.meteor/versions b/.meteor/versions index 4c7d02feb91..ae9dad63301 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -161,7 +161,6 @@ rocketchat:ui-sidenav@0.1.0 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 -rzymek:moment-locale-zh-cn@2.9.0 service-configuration@1.0.5 session@1.1.1 sha@1.0.4 -- GitLab From 22dc7d43e309b63955fcc11b2c3e6ce667f55be1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 24 Nov 2015 16:36:17 -0200 Subject: [PATCH 0558/1338] Disable auto update for cordova apps --- packages/autoupdate/autoupdate_cordova.js | 484 +++++++++++----------- 1 file changed, 242 insertions(+), 242 deletions(-) diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index d929936e246..51425b89274 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -24,167 +24,167 @@ Autoupdate.newClientAvailable = function () { }); }; -var writeFile = function (directoryPath, fileName, content, cb) { - var fail = function (err) { - cb(new Error("Failed to write file: ", err), null); - }; - - window.resolveLocalFileSystemURL(directoryPath, function (dirEntry) { - var success = function (fileEntry) { - fileEntry.createWriter(function (writer) { - writer.onwrite = function (evt) { - var result = evt.target.result; - cb(null, result); - }; - writer.onerror = fail; - writer.write(content); - }, fail); - }; - - dirEntry.getFile(fileName, { - create: true, - exclusive: false - }, success, fail); - }, fail); -}; - -var restartServer = function (location) { - log('restartServer with location ' + location); - var fail = function (err) { log("Unexpected error in restartServer: " + err.message) }; - var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate; - - if (! httpd) { - fail(new Error('no httpd')); - return; - } - - var startServer = function (cordovajsRoot) { - httpd.startServer({ - 'www_root' : location, - 'cordovajs_root': cordovajsRoot - }, function (url) { - if (Package.reload) { - Package.reload.Reload._reload(); - } else { - window.location.reload(); - } - }, fail); - }; - - httpd.getCordovajsRoot(function (cordovajsRoot) { - startServer(cordovajsRoot); - }, fail); -}; +// var writeFile = function (directoryPath, fileName, content, cb) { +// var fail = function (err) { +// cb(new Error("Failed to write file: ", err), null); +// }; + +// window.resolveLocalFileSystemURL(directoryPath, function (dirEntry) { +// var success = function (fileEntry) { +// fileEntry.createWriter(function (writer) { +// writer.onwrite = function (evt) { +// var result = evt.target.result; +// cb(null, result); +// }; +// writer.onerror = fail; +// writer.write(content); +// }, fail); +// }; + +// dirEntry.getFile(fileName, { +// create: true, +// exclusive: false +// }, success, fail); +// }, fail); +// }; + +// var restartServer = function (location) { +// log('restartServer with location ' + location); +// var fail = function (err) { log("Unexpected error in restartServer: " + err.message) }; +// var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate; + +// if (! httpd) { +// fail(new Error('no httpd')); +// return; +// } + +// var startServer = function (cordovajsRoot) { +// httpd.startServer({ +// 'www_root' : location, +// 'cordovajs_root': cordovajsRoot +// }, function (url) { +// if (Package.reload) { +// Package.reload.Reload._reload(); +// } else { +// window.location.reload(); +// } +// }, fail); +// }; + +// httpd.getCordovajsRoot(function (cordovajsRoot) { +// startServer(cordovajsRoot); +// }, fail); +// }; var hasCalledReload = false; var updating = false; var localPathPrefix = null; -var onNewVersion = function () { - if (!window.FileTransfer) { - return; - } - var ft = new FileTransfer(); - var urlPrefix = Meteor.absoluteUrl() + '__cordova'; - HTTP.get(urlPrefix + '/manifest.json', function (err, res) { - if (err || ! res.data) { - log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content)); - return; - } - - updating = true; - ensureLocalPathPrefix(_.bind(downloadNewVersion, null, res.data)); - }); -}; - -var downloadNewVersion = function (program) { - if (!window.FileTransfer) { - return; - } - var urlPrefix = Meteor.absoluteUrl() + '__cordova'; - var manifest = _.clone(program.manifest); - var version = program.version; - var ft = new FileTransfer(); - - manifest.push({ url: '/index.html?' + Random.id() }); - - var versionPrefix = localPathPrefix + version; - - var queue = []; - _.each(manifest, function (item) { - if (! item.url) return; - - var url = item.url; - url = url.replace(/\?.+$/, ''); - - queue.push(url); - }); - - var afterAllFilesDownloaded = _.after(queue.length, function () { - var wroteManifest = function (err) { - if (err) { - log("Failed to write manifest.json: " + err); - // XXX do something smarter? - return; - } - - // success! downloaded all sources and saved the manifest - // save the version string for atomicity - writeFile(localPathPrefix, 'version', version, function (err) { - if (err) { - log("Failed to write version: " + err); - return; - } - - // don't call reload twice! - if (! hasCalledReload) { - var location = uriToPath(localPathPrefix + version); - restartServer(location); - } - }); - }; - - writeFile(versionPrefix, 'manifest.json', - JSON.stringify(program, undefined, 2), wroteManifest); - }); - - var downloadUrl = function (url) { - console.log(DEBUG_TAG + "start downloading " + url); - // Add a cache buster to ensure that we don't cache an old asset. - var uri = encodeURI(urlPrefix + url + '?' + Random.id()); - - // Try to download the file a few times. - var tries = 0; - var tryDownload = function () { - ft.download(uri, versionPrefix + encodeURI(url), function (entry) { - if (entry) { - console.log(DEBUG_TAG + "done downloading " + url); - // start downloading next queued url - if (queue.length) - downloadUrl(queue.shift()); - afterAllFilesDownloaded(); - } - }, function (err) { - // It failed, try again if we have tried less than 5 times. - if (tries++ < MAX_RETRY_COUNT) { - log("Download error, will retry (#" + tries + "): " + uri); - tryDownload(); - } else { - log('Download failed: ' + JSON.stringify(err) + ", source=" + err.source + ", target=" + err.target); - } - }); - }; - - tryDownload(); - }; - - _.times(Math.min(MAX_NUM_CONCURRENT_DOWNLOADS, queue.length), function () { - var nextUrl = queue.shift(); - // XXX defer the next download so iOS doesn't rate limit us on concurrent - // downloads - Meteor.setTimeout(downloadUrl.bind(null, nextUrl), 50); - }); -}; +// var onNewVersion = function () { +// if (!window.FileTransfer) { +// return; +// } +// var ft = new FileTransfer(); +// var urlPrefix = Meteor.absoluteUrl() + '__cordova'; +// HTTP.get(urlPrefix + '/manifest.json', function (err, res) { +// if (err || ! res.data) { +// log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content)); +// return; +// } + +// updating = true; +// ensureLocalPathPrefix(_.bind(downloadNewVersion, null, res.data)); +// }); +// }; + +// var downloadNewVersion = function (program) { +// if (!window.FileTransfer) { +// return; +// } +// var urlPrefix = Meteor.absoluteUrl() + '__cordova'; +// var manifest = _.clone(program.manifest); +// var version = program.version; +// var ft = new FileTransfer(); + +// manifest.push({ url: '/index.html?' + Random.id() }); + +// var versionPrefix = localPathPrefix + version; + +// var queue = []; +// _.each(manifest, function (item) { +// if (! item.url) return; + +// var url = item.url; +// url = url.replace(/\?.+$/, ''); + +// queue.push(url); +// }); + +// var afterAllFilesDownloaded = _.after(queue.length, function () { +// var wroteManifest = function (err) { +// if (err) { +// log("Failed to write manifest.json: " + err); +// // XXX do something smarter? +// return; +// } + +// // success! downloaded all sources and saved the manifest +// // save the version string for atomicity +// writeFile(localPathPrefix, 'version', version, function (err) { +// if (err) { +// log("Failed to write version: " + err); +// return; +// } + +// // don't call reload twice! +// if (! hasCalledReload) { +// var location = uriToPath(localPathPrefix + version); +// restartServer(location); +// } +// }); +// }; + +// writeFile(versionPrefix, 'manifest.json', +// JSON.stringify(program, undefined, 2), wroteManifest); +// }); + +// var downloadUrl = function (url) { +// console.log(DEBUG_TAG + "start downloading " + url); +// // Add a cache buster to ensure that we don't cache an old asset. +// var uri = encodeURI(urlPrefix + url + '?' + Random.id()); + +// // Try to download the file a few times. +// var tries = 0; +// var tryDownload = function () { +// ft.download(uri, versionPrefix + encodeURI(url), function (entry) { +// if (entry) { +// console.log(DEBUG_TAG + "done downloading " + url); +// // start downloading next queued url +// if (queue.length) +// downloadUrl(queue.shift()); +// afterAllFilesDownloaded(); +// } +// }, function (err) { +// // It failed, try again if we have tried less than 5 times. +// if (tries++ < MAX_RETRY_COUNT) { +// log("Download error, will retry (#" + tries + "): " + uri); +// tryDownload(); +// } else { +// log('Download failed: ' + JSON.stringify(err) + ", source=" + err.source + ", target=" + err.target); +// } +// }); +// }; + +// tryDownload(); +// }; + +// _.times(Math.min(MAX_NUM_CONCURRENT_DOWNLOADS, queue.length), function () { +// var nextUrl = queue.shift(); +// // XXX defer the next download so iOS doesn't rate limit us on concurrent +// // downloads +// Meteor.setTimeout(downloadUrl.bind(null, nextUrl), 50); +// }); +// }; var retry = new Retry({ minCount: 0, // don't do any immediate retries @@ -215,7 +215,7 @@ Autoupdate._retrySubscription = function () { var self = this; if (doc.version !== autoupdateVersionCordova) { window.fireGlobalEvent('onNewVersion', doc.version) - onNewVersion(); + // onNewVersion(); } }; @@ -228,95 +228,95 @@ Autoupdate._retrySubscription = function () { } }; -Meteor.startup(function () { - clearAutoupdateCache(autoupdateVersionCordova); -}); +// Meteor.startup(function () { +// clearAutoupdateCache(autoupdateVersionCordova); +// }); Meteor.startup(Autoupdate._retrySubscription); // A helper that removes old directories left from previous autoupdates -var clearAutoupdateCache = function (currentVersion) { - ensureLocalPathPrefix(function () { - // Try to clean up our cache directory, make sure to scan the directory - // *before* loading the actual app. This ordering will prevent race - // conditions when the app code tries to download a new version before - // the old-cache removal has scanned the cache folder. - listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) { - // Couldn't get the list of dirs or risking to get into a race with an - // on-going update to disk. - if (err || updating) { - return; - } - - _.each(names, function (name) { - // Skip the folder with the latest version - if (name === currentVersion) - return; - - // remove everything else, as we don't want to keep too much cache - // around on disk - removeDirectory(localPathPrefix + name + '/', function (err) { - if (err) { - log('Failed to remove an old cache folder ' - + name + ':' + err.message); - } else { - log('Successfully removed an old cache folder ' + name); - } - }); - }); - }); - }) -}; +// var clearAutoupdateCache = function (currentVersion) { +// ensureLocalPathPrefix(function () { +// // Try to clean up our cache directory, make sure to scan the directory +// // *before* loading the actual app. This ordering will prevent race +// // conditions when the app code tries to download a new version before +// // the old-cache removal has scanned the cache folder. +// listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) { +// // Couldn't get the list of dirs or risking to get into a race with an +// // on-going update to disk. +// if (err || updating) { +// return; +// } + +// _.each(names, function (name) { +// // Skip the folder with the latest version +// if (name === currentVersion) +// return; + +// // remove everything else, as we don't want to keep too much cache +// // around on disk +// removeDirectory(localPathPrefix + name + '/', function (err) { +// if (err) { +// log('Failed to remove an old cache folder ' +// + name + ':' + err.message); +// } else { +// log('Successfully removed an old cache folder ' + name); +// } +// }); +// }); +// }); +// }) +// }; // Cordova File plugin helpers -var listDirectory = function (url, options, cb) { - if (typeof options === 'function') - cb = options, options = {}; - - var fail = function (err) { cb(err); }; - window.resolveLocalFileSystemURL(url, function (entry) { - var reader = entry.createReader(); - reader.readEntries(function (entries) { - var names = []; - _.each(entries, function (entry) { - if (! options.dirsOnly || entry.isDirectory) - names.push(entry.name); - }); - cb(null, names); - }, fail); - }, fail); -}; - -var removeDirectory = function (url, cb) { - var fail = function (err) { - cb(err); - }; - window.resolveLocalFileSystemURL(url, function (entry) { - entry.removeRecursively(function () { cb(); }, fail); - }, fail); -}; - -var uriToPath = function (uri) { - return decodeURI(uri).replace(/^file:\/\//g, ''); -}; - -var ensureLocalPathPrefix = function (cb) { - if (! localPathPrefix) { - if (! cordova.file.dataDirectory) { - // Since ensureLocalPathPrefix function is always called on - // Meteor.startup, all Cordova plugins should be ready. - // XXX Experiments have shown that it is not always the case, even when - // the cordova.file symbol is attached, properties like dataDirectory - // still can be null. Poll until we are sure the property is attached. - console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms'); - // REMOVED to prevent loop in new app - // Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20); - } else { - localPathPrefix = cordova.file.dataDirectory + 'meteor/'; - cb(); - } - } else { - cb(); - } -}; +// var listDirectory = function (url, options, cb) { +// if (typeof options === 'function') +// cb = options, options = {}; + +// var fail = function (err) { cb(err); }; +// window.resolveLocalFileSystemURL(url, function (entry) { +// var reader = entry.createReader(); +// reader.readEntries(function (entries) { +// var names = []; +// _.each(entries, function (entry) { +// if (! options.dirsOnly || entry.isDirectory) +// names.push(entry.name); +// }); +// cb(null, names); +// }, fail); +// }, fail); +// }; + +// var removeDirectory = function (url, cb) { +// var fail = function (err) { +// cb(err); +// }; +// window.resolveLocalFileSystemURL(url, function (entry) { +// entry.removeRecursively(function () { cb(); }, fail); +// }, fail); +// }; + +// var uriToPath = function (uri) { +// return decodeURI(uri).replace(/^file:\/\//g, ''); +// }; + +// var ensureLocalPathPrefix = function (cb) { +// if (! localPathPrefix) { +// if (! cordova.file.dataDirectory) { +// // Since ensureLocalPathPrefix function is always called on +// // Meteor.startup, all Cordova plugins should be ready. +// // XXX Experiments have shown that it is not always the case, even when +// // the cordova.file symbol is attached, properties like dataDirectory +// // still can be null. Poll until we are sure the property is attached. +// console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms'); +// // REMOVED to prevent loop in new app +// // Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20); +// } else { +// localPathPrefix = cordova.file.dataDirectory + 'meteor/'; +// cb(); +// } +// } else { +// cb(); +// } +// }; -- GitLab From 4b08779a9e1c27717f74e355e0d506ed307684f1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 24 Nov 2015 16:36:28 -0200 Subject: [PATCH 0559/1338] Re enable push notifications --- .../rocketchat-ui/lib/cordova/push.coffee | 87 +++++++++++++------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/packages/rocketchat-ui/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee index 3d0d64299c3..c5d7574e093 100644 --- a/packages/rocketchat-ui/lib/cordova/push.coffee +++ b/packages/rocketchat-ui/lib/cordova/push.coffee @@ -1,36 +1,69 @@ if Meteor.isCordova - window.addEventListener 'push-notification', (evt) -> + Push.addListener 'token', (token) -> + Meteor.call 'log', 'CLIENT', 'token', arguments + + Push.addListener 'error', (err) -> + Meteor.call 'log', 'CLIENT', 'error', arguments + if err.type == 'apn.cordova' + Meteor.call 'log', 'CLIENT', err.error + + Push.addListener 'register', (evt) -> + Meteor.call 'log', 'CLIENT', 'register', arguments + + Push.addListener 'alert', (notification) -> + Meteor.call 'log', 'CLIENT', 'alert', arguments + + Push.addListener 'sound', (notification) -> + Meteor.call 'log', 'CLIENT', 'sound', arguments + + Push.addListener 'badge', (notification) -> + Meteor.call 'log', 'CLIENT', 'badge', arguments + + Push.addListener 'startup', (notification) -> Meteor.call 'log', 'CLIENT', 'startup', arguments - notification = evt.detail + if notification.payload?.rid? + if notification.payload.host is Meteor.absoluteUrl() + switch notification.payload.type + when 'c' + FlowRouter.go 'channel', name: notification.payload.name + when 'p' + FlowRouter.go 'group', name: notification.payload.name + when 'd' + FlowRouter.go 'direct', username: notification.payload.sender.username + else + path = '' + switch notification.payload.type + when 'c' + path = 'channel/' + notification.payload.name + when 'p' + path = 'group/' + notification.payload.name + when 'd' + path = 'direct/' + notification.payload.sender.username - if notification.additionalData.foreground is true - return + host = notification.payload.host.replace /\/$/, '' + if Servers.serverExists(host) isnt true + return - if notification.additionalData.ejson?.rid? - switch notification.additionalData.ejson.type - when 'c' - FlowRouter.go 'channel', name: notification.additionalData.ejson.name - when 'p' - FlowRouter.go 'group', name: notification.additionalData.ejson.name - when 'd' - FlowRouter.go 'direct', username: notification.additionalData.ejson.sender.username + Servers.startServer host, path, (err, url) -> + if err? + # TODO err + return console.log err + Push.addListener 'message', (notification) -> + Meteor.call 'log', 'CLIENT', 'message', arguments + Tracker.autorun -> - if RocketChat.settings.get('Push_enable') is true and Meteor.userId()? + if RocketChat.settings.get('Push_enable') is true android_senderID = RocketChat.settings.get 'Push_gcm_project_number' - if android_senderID? - localStorage.setItem 'android_senderID', android_senderID - - if window.pushToken? - data = - id: localStorage.getItem 'push_stored_id' - token: window.pushToken, - appName: 'main', - userId: Meteor.userId() - metadata: undefined - - Meteor.call 'raix:push-update', data, (err, result) -> - if not err? and result? - localStorage.setItem 'push_stored_id', result._id + + Push.Configure + android: + senderID: android_senderID + sound: true + vibrate: true + ios: + badge: true + sound: true + alert: true -- GitLab From 8dacdd3776fd7dc985fd71734e61d00986ed4019 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 16:59:37 -0200 Subject: [PATCH 0560/1338] fixes #1481 - not showing user information on dm --- client/startup/defaultRoomTypes.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index fa00955642f..832cbd2f21c 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -22,7 +22,7 @@ RocketChat.roomTypes.add 'd', 20, name: 'direct' path: '/direct/:username' action: (params, queryParams) -> - Session.set 'showUserInfo' + Session.set 'showUserInfo', params.username openRoom 'd', params.username link: (sub) -> return { username: sub.name } -- GitLab From 75eaad4b68cb7d225de2c759025fa79537c16c91 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 17:25:40 -0200 Subject: [PATCH 0561/1338] route options to accountBox --- .../side-nav/sideNav.coffee | 5 ++- .../side-nav/sideNav.html | 2 +- packages/rocketchat-ui/lib/accountBox.coffee | 36 +++++++++++-------- packages/rocketchat-ui/package.js | 2 ++ 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 7c9d2574f8a..227023ce43f 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -36,7 +36,10 @@ Template.sideNav.helpers return RocketChat.authz.hasAtLeastOnePermission( ['view-statistics', 'view-room-administration', 'view-user-administration', 'view-privileged-setting']) registeredMenus: -> - return AccountBox.getOptions() + return AccountBox.getItems() + + itemPath: -> + FlowRouter.path @route.name Template.sideNav.events 'click .close-flex': -> diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html index 605c277d14e..69de45698bd 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html @@ -21,7 +21,7 @@ <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> {{#each registeredMenus}} - <a href="" class="{{class}}"><i class="{{icon}}"></i><span>{{name}}</span></a> + <a href="{{itemPath}}" class="{{class}}"><i class="{{icon}}"></i><span>{{name}}</span></a> {{/each}} {{#if showAdminOption }} <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index c575f1760f7..a83288bfe3d 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -1,7 +1,7 @@ @AccountBox = (-> status = 0 self = {} - options = new ReactiveVar [] + items = new ReactiveVar [] setStatus = (status) -> Meteor.call('UserPresence:setDefaultStatus', status) @@ -30,20 +30,25 @@ ### # @param newOption: - # name: Button label - # icon: Button icon - # class: Class of item - # roles: Which roles see this options + # name: Button label + # icon: Button icon + # class: Class of the item + # permissions: Which permissions a user should have (all of them) to see this item ### - addOption = (newOption) -> + addItem = (newItem) -> Tracker.nonreactive -> - actual = options.get() - actual.push newOption - options.set actual - - getOptions = -> - return _.filter options.get(), (option) -> - if not option.roles? or RocketChat.authz.hasRole(Meteor.userId(), option.roles) + actual = items.get() + actual.push newItem + items.set actual + + if newItem.route?.path? and newItem.route?.name? and newItem.route?.action? + FlowRouter.route newItem.route.path, + name: newItem.route.name + action: newItem.route.action + + getItems = -> + return _.filter items.get(), (item) -> + if not item.permissions? or RocketChat.authz.hasAllPermission item.permissions return true setStatus: setStatus @@ -51,6 +56,7 @@ open: open close: close init: init - addOption: addOption - getOptions: getOptions + + addItem: addItem + getItems: getItems )() diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 34ddea1afb0..bff71ffe618 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -28,6 +28,8 @@ Package.onUse(function(api) { 'raix:ui-dropped-event' ]); + api.use('kadira:flow-router', 'client'); + // LIB FILES api.addFiles('lib/accountBox.coffee', 'client'); api.addFiles('lib/accounts.coffee', 'client'); -- GitLab From e247839a713cf252e29765755965fdf87fe2cc29 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 24 Nov 2015 17:25:58 -0200 Subject: [PATCH 0562/1338] using accountBox route options --- packages/rocketchat-livechat/client/ui.js | 21 ++++++++++++++++--- .../client/views/app/livechat-manager.html | 4 ++++ packages/rocketchat-livechat/package.js | 2 ++ packages/rocketchat-livechat/permissions.js | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 packages/rocketchat-livechat/client/views/app/livechat-manager.html diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index c5a58fe2b41..b969bb08e6f 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -9,10 +9,25 @@ RocketChat.roomTypes.add('l', 5, { openRoom('l', params.name); }, link: (sub) => { - return { name: sub.name } + return { + name: sub.name + } } }, - permissions: [ 'view-l-room' ] + permissions: ['view-l-room'] }); -AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); +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: 'livechat-manager' }); + } + }, + permissions: ['view-livechat-manager'] +}); diff --git a/packages/rocketchat-livechat/client/views/app/livechat-manager.html b/packages/rocketchat-livechat/client/views/app/livechat-manager.html new file mode 100644 index 00000000000..75e0725e696 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechat-manager.html @@ -0,0 +1,4 @@ +<template name="livechat-manager"> + <h1>livechat-manager</h1> + <p>Example</p> +</template> diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index ca8eb3627d0..049d7317e8c 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -35,6 +35,8 @@ Package.onUse(function(api) { api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); + + api.addFiles('client/views/app/livechat-manager.html', 'client'); api.addFiles('client/views/sideNav/livechat.html', 'client'); api.addFiles('client/views/sideNav/livechat.js', 'client'); diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index 0239df4a1e2..3bb95672689 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -8,5 +8,6 @@ Meteor.startup(() => { } if (RocketChat.models && RocketChat.models.Permissions) { RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager']); + RocketChat.models.Permissions.createOrUpdate('view-livechat-manager', ['livechat-manager']); } }); -- GitLab From fc96977443a611c1333cbd8c1ce8fc51024bda5d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 25 Nov 2015 09:33:50 -0200 Subject: [PATCH 0563/1338] Fix error in method getUsernameSuggestion --- server/methods/getUsernameSuggestion.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/methods/getUsernameSuggestion.coffee b/server/methods/getUsernameSuggestion.coffee index 927adb09aad..84275b48ee9 100644 --- a/server/methods/getUsernameSuggestion.coffee +++ b/server/methods/getUsernameSuggestion.coffee @@ -25,12 +25,12 @@ usernameIsAvaliable = (username) -> first = nameParts[0] last = nameParts[nameParts.length - 1] - if RocketChat.settings.get 'UTF8_Names_slugify' - usernames.push slug first[0] + last - usernames.push slug first + last[0] - else - usernames.push first[0] + last - usernames.push first + last[0] + if RocketChat.settings.get 'UTF8_Names_slugify' + usernames.push slug first[0] + last + usernames.push slug first + last[0] + else + usernames.push first[0] + last + usernames.push first + last[0] if user.profile?.name? if RocketChat.settings.get 'UTF8_Names_slugify' -- GitLab From d63f0192557fd941a05b8aaf90cbc48952c25187 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 25 Nov 2015 10:25:52 -0500 Subject: [PATCH 0564/1338] Promo availability on FreeBSD announce status = available --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2f1789ac87a..a542145fb5a 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,10 @@ Host your own Rocket.Chat server in four seconds flat: _*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat.latest.spk) for testing on your own server. +Or run solid five-nines deployment on industry workhorse FreeBSD server: + +[](https://github.com/RocketChat/Rocket.Chat/wiki/FreeBSD) + Also available as FirefoxOS app: [](https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29) @@ -174,16 +178,9 @@ Checkout [Github Wiki](https://github.com/RocketChat/Rocket.Chat/wiki) Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker). -### FreeBSD - -Solid five-nines deployment with industry workhorse FreeBSD (coming soon). - - - - ### Ubuntu Software Center -Easy one click install right from your Ubuntu Desktop (coming soon). +Easy one click install right from your Ubuntu Desktop (coming soon) []() -- GitLab From df525d6d5bf90578b754be6f891234dbe7a452a2 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 25 Nov 2015 17:10:58 -0200 Subject: [PATCH 0565/1338] Fix Rocket.Chat.Cordova issue #15. --- packages/rocketchat-lib/client/lib/openRoom.coffee | 1 + packages/rocketchat-ui/views/app/room.html | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 545dce131b8..4a45b3a480e 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -36,6 +36,7 @@ currentTracker = undefined if roomDom.classList.contains('room-container') roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop + RocketChat.TabBar.setTemplate '' Session.set 'openedRoom', room._id Session.set 'editRoomTitle', false diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index 919ef914666..c85eea27f69 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -81,8 +81,10 @@ {{> messageBox}} </footer> </section> - <section class="flex-tab"> - {{> Template.dynamic template=flexTemplate data=flexData}} - </section> + {{#if flexTemplate}} + <section class="flex-tab"> + {{> Template.dynamic template=flexTemplate data=flexData}} + </section> + {{/if}} </div> -</template> \ No newline at end of file +</template> -- GitLab From 73ee9209c38006bd13a5a0d918a459cc416df3ea Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 25 Nov 2015 18:45:44 -0200 Subject: [PATCH 0566/1338] Init push gateway --- .../server/startup/settings.coffee | 2 + server/lib/cordova.coffee | 79 +++++++++++++++---- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 4bff3c27114..8c11d40fc55 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -95,6 +95,8 @@ 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', false, { type: 'boolean', group: 'Push', public: true } +RocketChat.settings.add 'Push_enable_gateway', true, { type: 'boolean', group: 'Push' } +RocketChat.settings.add 'Push_gateway', 'https://push.rocket.chat', { type: 'string', group: 'Push' } RocketChat.settings.add 'Push_production', false, { type: 'boolean', group: 'Push', public: true } RocketChat.settings.add 'Push_apn_passphrase', '', { type: 'string', group: 'Push' } RocketChat.settings.add 'Push_apn_key', '', { type: 'string', multiline: true, group: 'Push' } diff --git a/server/lib/cordova.coffee b/server/lib/cordova.coffee index c8b966982fd..ccd906e83ac 100644 --- a/server/lib/cordova.coffee +++ b/server/lib/cordova.coffee @@ -7,32 +7,77 @@ Meteor.startup -> Push.debug = RocketChat.settings.get 'Push_debug' if RocketChat.settings.get('Push_enable') is true - Push.enabled = true Push.allow send: (userId, notification) -> return RocketChat.authz.hasRole(userId, 'admin') - apn = - passphrase: RocketChat.settings.get 'Push_apn_passphrase' - keyData: RocketChat.settings.get 'Push_apn_key' - certData: RocketChat.settings.get 'Push_apn_cert' + apn = undefined + gcm = undefined + + if RocketChat.settings.get('Push_enable_gateway') is false + gcm = + apiKey: RocketChat.settings.get 'Push_gcm_api_key' + projectNumber: RocketChat.settings.get 'Push_gcm_project_number' - if RocketChat.settings.get('Push_production') isnt true apn = - passphrase: RocketChat.settings.get 'Push_apn_dev_passphrase' - keyData: RocketChat.settings.get 'Push_apn_dev_key' - certData: RocketChat.settings.get 'Push_apn_dev_cert' - gateway: 'gateway.sandbox.push.apple.com' + passphrase: RocketChat.settings.get 'Push_apn_passphrase' + keyData: RocketChat.settings.get 'Push_apn_key' + certData: RocketChat.settings.get 'Push_apn_cert' + + if RocketChat.settings.get('Push_production') isnt true + apn = + passphrase: RocketChat.settings.get 'Push_apn_dev_passphrase' + keyData: RocketChat.settings.get 'Push_apn_dev_key' + certData: RocketChat.settings.get 'Push_apn_dev_cert' + gateway: 'gateway.sandbox.push.apple.com' Push.Configure apn: apn - gcm: - apiKey: RocketChat.settings.get 'Push_gcm_api_key' - projectNumber: RocketChat.settings.get 'Push_gcm_project_number' + gcm: gcm production: RocketChat.settings.get 'Push_production' - badge: true - sound: true - alert: true - vibrate: true sendInterval: 1000 sendBatchSize: 10 + + if RocketChat.settings.get('Push_enable_gateway') is true + pushGetway = undefined + + Push.serverSend = (options) -> + options = options or { badge: 0 } + query = undefined + + if options.from isnt ''+options.from + throw new Error('Push.send: option "from" not a string') + + if options.title isnt ''+options.title + throw new Error('Push.send: option "title" not a string') + + if options.text isnt ''+options.text + throw new Error('Push.send: option "text" not a string') + + if Push.debug + console.log('Push: Send message "' + options.title + '" via query', options.query) + + query = + $and: [ + options.query + { + $or: [ + { 'token.apn': { $exists: true } } + { 'token.gcm': { $exists: true } } + ] + } + ] + + Push.appCollection.find(query).forEach (app) -> + if Push.debug + console.log('send to token', app.token) + + if app.token.apn? + pushGetway.call 'sendPushNotification', 'apn', app.token.apn, options + + else if app.token.gcm? + pushGetway.call 'sendPushNotification', 'gcm', app.token.gcm, options + + pushGetway = DDP.connect(RocketChat.settings.get('Push_gateway'), {_dontPrintErrors: false}) + + Push.enabled = true -- GitLab From 48d7c9451e32e2dc0533f93142ccba0d47d4cd51 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 25 Nov 2015 20:01:38 -0200 Subject: [PATCH 0567/1338] Fix identation --- packages/rocketchat-ui-admin/admin/admin.html | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 868662ba7e7..46162c41d4e 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -33,33 +33,33 @@ {{/if}} {{/if}} {{#each settings}} - <div class="input-line double-col"> - <label>{{label}}</label> - <div> - {{#if $eq type 'string'}} + <div class="input-line double-col"> + <label>{{label}}</label> + <div> + {{#if $eq type 'string'}} {{#if multiline}} <textarea name="{{_id}}" rows="4" style="height: auto">{{value}}</textarea> {{else}} <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> {{/if}} - {{/if}} - {{#if $eq type 'int'}} + {{/if}} + {{#if $eq type 'int'}} <input type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> - {{/if}} - {{#if $eq type 'boolean'}} + {{/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> - {{/if}} - {{#if $eq type 'color'}} + {{/if}} + {{#if $eq type 'color'}} <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> - {{/if}} - {{#if description}} + {{/if}} + {{#if description}} <div> <small class="settings-description">{{{description}}}</small> </div> - {{/if}} - </div> + {{/if}} </div> + </div> {{/each}} {{#if section}} -- GitLab From f2fec7066e55ec6e964168e6119b2c6365f332cc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 25 Nov 2015 20:02:01 -0200 Subject: [PATCH 0568/1338] Do not render description of settings without value --- packages/rocketchat-ui-admin/admin/admin.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 1f048328ca5..7bcfda28b35 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -29,8 +29,9 @@ Template.admin.helpers label = @i18nLabel or @_id return TAPi18n.__ label if label description: -> - description = @i18nDescription - return TAPi18n.__ description if description + description = TAPi18n.__ @i18nDescription if @i18nDescription + if description? and description isnt @i18nDescription + return description sectionIsCustomOath: (section) -> return /^Custom OAuth:\s.+/.test section callbackURL: (section) -> -- GitLab From b3c67f3373367284382b36a4f41d7e8b00797df3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 25 Nov 2015 20:28:32 -0200 Subject: [PATCH 0569/1338] Change the default gateway to https://rocket.chat --- packages/rocketchat-lib/server/startup/settings.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 8c11d40fc55..0e2ed32b3a8 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -96,7 +96,7 @@ RocketChat.settings.addGroup 'Push' RocketChat.settings.add 'Push_debug', false, { type: 'boolean', group: 'Push', public: true } RocketChat.settings.add 'Push_enable', false, { type: 'boolean', group: 'Push', public: true } RocketChat.settings.add 'Push_enable_gateway', true, { type: 'boolean', group: 'Push' } -RocketChat.settings.add 'Push_gateway', 'https://push.rocket.chat', { type: 'string', group: 'Push' } +RocketChat.settings.add 'Push_gateway', 'https://rocket.chat', { type: 'string', group: 'Push' } RocketChat.settings.add 'Push_production', false, { type: 'boolean', group: 'Push', public: true } RocketChat.settings.add 'Push_apn_passphrase', '', { type: 'string', group: 'Push' } RocketChat.settings.add 'Push_apn_key', '', { type: 'string', multiline: true, group: 'Push' } -- GitLab From d42839c20289d5fdfb70790e91a3d6e72e22f1b0 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 25 Nov 2015 17:55:56 -0500 Subject: [PATCH 0570/1338] Attempt to fix SPK path problem best effort attempt until jason becomes available next week --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b557eb7006d..ca3d4efa5b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,8 +55,9 @@ script: - sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp - ./build.sh - sed -i "s/\spgp/#pgp/g" sandstorm-pkgdef.capnp -- spk pack $TRAVIS_BUILD_DIR/../build/rocket.chat.latest.spk +- spk pack $TRAVIS_BUILD_DIR/rocket.chat.latest.spk - cd $TRAVIS_BUILD_DIR +- mv rocket.chat.latest.spk ../build after_deploy: - cd .travis - sh ./builddocker.sh -- GitLab From 93a971bb28a224069f94e7badea5a93e45c2bd6f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 26 Nov 2015 09:08:32 -0200 Subject: [PATCH 0571/1338] Fix flex being opened on joining channel --- packages/rocketchat-lib/client/TabBar.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/client/TabBar.coffee b/packages/rocketchat-lib/client/TabBar.coffee index 237024dbdd7..a75bce80044 100644 --- a/packages/rocketchat-lib/client/TabBar.coffee +++ b/packages/rocketchat-lib/client/TabBar.coffee @@ -12,7 +12,8 @@ RocketChat.TabBar = new class setTemplate = (t, callback) -> return if animating is true template.set t - openFlex(callback) + if t + openFlex(callback) getTemplate = -> return template.get() -- GitLab From 705c96b5b1d89440af2a571d63171e39f49310d5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 26 Nov 2015 10:27:34 -0200 Subject: [PATCH 0572/1338] created a page container --- packages/rocketchat-livechat/client/ui.js | 6 +++++- packages/rocketchat-ui/package.js | 1 + packages/rocketchat-ui/views/app/pageContainer.html | 13 +++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-ui/views/app/pageContainer.html diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index b969bb08e6f..823f9e46ecb 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -26,7 +26,11 @@ AccountBox.addItem({ path: '/livechat-manager', action(params, queryParams) { Session.set('openedRoom'); - BlazeLayout.render('main', { center: 'livechat-manager' }); + BlazeLayout.render('main', { + center: 'page-container', + pageTitle: 'Live Chat Manager', + pageTemplate: 'livechat-manager' + }); } }, permissions: ['view-livechat-manager'] diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index bff71ffe618..d40700b3519 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -76,6 +76,7 @@ Package.onUse(function(api) { api.addFiles('views/app/audioNotification.html', 'client'); api.addFiles('views/app/burguer.html', 'client'); api.addFiles('views/app/home.html', 'client'); + api.addFiles('views/app/pageContainer.html', 'client'); api.addFiles('views/app/privateHistory.html', 'client'); api.addFiles('views/app/room.html', 'client'); api.addFiles('views/app/roomSearch.html', 'client'); diff --git a/packages/rocketchat-ui/views/app/pageContainer.html b/packages/rocketchat-ui/views/app/pageContainer.html new file mode 100644 index 00000000000..d10012d7627 --- /dev/null +++ b/packages/rocketchat-ui/views/app/pageContainer.html @@ -0,0 +1,13 @@ +<template name="page-container"> + <section class="page-container page-home page-static"> + <head class="fixed-title"> + {{> burger}} + <h2> + <span class="page-title">{{pageTitle}}</span> + </h2> + </head> + <div class="content"> + {{> Template.dynamic template=pageTemplate}} + </div> + </section> +</template> -- GitLab From 15bf0c96e7af45f66281573a14eec6b2e20e0cc3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 14:39:55 -0200 Subject: [PATCH 0573/1338] Fix the setting UTF8_Names_Slugify --- client/methods/saveRoomName.coffee | 2 +- server/methods/getUsernameSuggestion.coffee | 10 +++++----- server/methods/saveRoomName.coffee | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/methods/saveRoomName.coffee b/client/methods/saveRoomName.coffee index d2f6ff68477..0885fe433ce 100644 --- a/client/methods/saveRoomName.coffee +++ b/client/methods/saveRoomName.coffee @@ -8,7 +8,7 @@ Meteor.methods 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' + if RocketChat.settings.get 'UTF8_Names_Slugify' name = _.slugify name if name is room.name diff --git a/server/methods/getUsernameSuggestion.coffee b/server/methods/getUsernameSuggestion.coffee index 84275b48ee9..e5c2aa9c5e9 100644 --- a/server/methods/getUsernameSuggestion.coffee +++ b/server/methods/getUsernameSuggestion.coffee @@ -15,7 +15,7 @@ usernameIsAvaliable = (username) -> usernames = [] username = undefined - if RocketChat.settings.get 'UTF8_Names_slugify' + if RocketChat.settings.get 'UTF8_Names_Slugify' usernames.push slug user.name else usernames.push user.name @@ -25,7 +25,7 @@ usernameIsAvaliable = (username) -> first = nameParts[0] last = nameParts[nameParts.length - 1] - if RocketChat.settings.get 'UTF8_Names_slugify' + if RocketChat.settings.get 'UTF8_Names_Slugify' usernames.push slug first[0] + last usernames.push slug first + last[0] else @@ -33,7 +33,7 @@ usernameIsAvaliable = (username) -> usernames.push first + last[0] if user.profile?.name? - if RocketChat.settings.get 'UTF8_Names_slugify' + if RocketChat.settings.get 'UTF8_Names_Slugify' usernames.push slug user.profile.name else usernames.push user.profile.name @@ -41,12 +41,12 @@ usernameIsAvaliable = (username) -> if user.services? for serviceName, service of user.services if service.name? - if RocketChat.settings.get 'UTF8_Names_slugify' + if RocketChat.settings.get 'UTF8_Names_Slugify' usernames.push slug service.name else usernames.push service.name else if service.username? - if RocketChat.settings.get 'UTF8_Names_slugify' + if RocketChat.settings.get 'UTF8_Names_Slugify' usernames.push slug service.username else usernames.push service.username diff --git a/server/methods/saveRoomName.coffee b/server/methods/saveRoomName.coffee index 16756afec35..888d0c74b51 100644 --- a/server/methods/saveRoomName.coffee +++ b/server/methods/saveRoomName.coffee @@ -20,7 +20,7 @@ Meteor.methods if not nameValidation.test name throw new Meteor.Error 'name-invalid' - if RocketChat.settings.get 'UTF8_Names_slugify' + if RocketChat.settings.get 'UTF8_Names_Slugify' name = _.slugify name if name is room.name -- GitLab From 100f87b715446ae2f61e6abd132151d7fa347df3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 14:49:45 -0200 Subject: [PATCH 0574/1338] Add button to deploy the branch develop to heroku --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a542145fb5a..e457f071dbe 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The Ultimate Open Source WebChat Platform -## Demo +## Demo Checkout the latest version at [https://demo.rocket.chat](https://demo.rocket.chat) @@ -203,8 +203,10 @@ Host your docker container at [sloppy.io](http://sloppy.io). Get an account and 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) - +Branch **develop** (Newer but unstable): +[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) ## Development Installation @@ -249,7 +251,7 @@ Performance monitoring provided by [Kadira](https://kadira.io) ### Contributions -Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors community. +Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors community. A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it! -- GitLab From ee00885e52a162d44eec56673424145a892e3a17 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 15:22:55 -0200 Subject: [PATCH 0575/1338] Update README.md --- README.md | 211 +++++++++++++++++++++++++++++------------------------- 1 file changed, 113 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index e457f071dbe..1273760626c 100644 --- a/README.md +++ b/README.md @@ -2,51 +2,124 @@ The Ultimate Open Source WebChat Platform -## Demo - +* [Live Demo](#live-demo) +* [Mobile apps](#mobile-apps) +* [Desktop apps](#desktop-apps) +* [Deployment](#deployment) + * [Development Installation](#development-installation) + * [Heroku](#heroku) + * [Sandstorm.io](#sandstormio) + * [Sloppy.io](#sloppyio) + * [Docker](#docker) + * [FreeBSD](#freebsd) + * [Ubuntu VPS](#ubuntu-vps) + * [Ubuntu Software Center](#ubuntu-software-center) +* [About Rocket.Chat](#about-rocketchat) + * [On the News](#on-the-news) + * [Features](#features) + * [Roadmap](#roadmap) + * [Issues](#issues) + * [Integrations](#integrations) + * [Documentation](#documentation) + * [License](#license) +* [Development](#development) + * [Branching Model](#branching-model) + * [Translations](#translations) + * [Community](#community) + * [How to Contribute](#how-to-contribute) +* [Credits](#credits) +* [Donate](#donate) + + +# Live Demo Checkout the latest version at [https://demo.rocket.chat](https://demo.rocket.chat) -Available from the AppStore: -[](https://itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) +# Desktop Apps +Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron](https://github.com/RocketChat/Rocket.Chat.Electron/releases) -Get the app for your Android phone: +# Mobile Apps +### Available from the AppStore +[](https://itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) +### Available from the Google Play [](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) Now compatible with all Android devices as old as version 4.0.x - [download here](https://github.com/RocketChat/Rocket.Chat/wiki/Build-the-Android-Cordova-Web-App-and-connect-to-your-own-Rocket.Chat-Server), even on BlackBerry Passport! -Host your own Rocket.Chat server in four seconds flat: +### Also available as FirefoxOS app +[](https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29) -[](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) -_*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat.latest.spk) for testing on your own server. +# Deployment +`Host your own Rocket.Chat server in four seconds flat` -Or run solid five-nines deployment on industry workhorse FreeBSD server: +## Development Installation +Prerequisites: -[](https://github.com/RocketChat/Rocket.Chat/wiki/FreeBSD) +* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [Meteor](https://www.meteor.com/install) -Also available as FirefoxOS app: +Now just clone and start the app: -[](https://github.com/RocketChat/Rocket.Chat/wiki/Native-Firefox-OS-app-%28hosted-webapp%29) +```sh +git clone https://github.com/RocketChat/Rocket.Chat.git +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 +``` + +## 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) +Branch **develop** (Newer but unstable): +[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) +## Sandstorm.io +[](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) +_*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat.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) -Try it on Ubuntu: +## Docker +[Deploy with docker compose](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-with-Docker) -[Deploy on VPS or standalone server](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) +or -Try it with docker: +Use the automated build at our [Official Docker Registry](https://hub.docker.com/r/rocketchat/rocket.chat/) -[Deploy with docker](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-with-Docker) +[](https://hub.docker.com/r/rocketchat/rocket.chat/) +``` +docker pull rocketchat/rocket.chat +``` -Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron](https://github.com/RocketChat/Rocket.Chat.Electron/releases) +## FreeBSD +Run solid five-nines deployment on industry workhorse FreeBSD server: -[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=49QX7TYCVZK8L) +[](https://github.com/RocketChat/Rocket.Chat/wiki/FreeBSD) -## About +## Ubuntu VPS +Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) + +## Ubuntu Software Center +Easy one click install right from your Ubuntu Desktop (coming soon) + +[]() + + +# About Rocket.Chat [](https://travis-ci.org/RocketChat/Rocket.Chat) [](https://coveralls.io/r/RocketChat/Rocket.Chat) @@ -58,7 +131,7 @@ Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](ht It is a great solution for communities and companies wanting to privately host their own chat service or for developers looking forward to build and evolve their own chat platforms. -### On the News +## On the News ##### [Hacker News](https://news.ycombinator.com/item?id=9624737) > Yes, we made it to the #1 @@ -124,7 +197,7 @@ It is a great solution for communities and companies wanting to privately host t - Sandstorm.io instant Rocket.Chat server [Now on Sandstorm App Store](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) -### Roadmap +## Roadmap #### In Progress - Support multiple teams on the same instance / same VPS infrastructure: [Issue #658](https://github.com/RocketChat/Rocket.Chat/issues/658), [Issue #630](https://github.com/RocketChat/Rocket.Chat/issues/630) @@ -145,11 +218,11 @@ It is a great solution for communities and companies wanting to privately host t - File Sharing via P2P and Scalable Multicast: [Issue #369](https://github.com/RocketChat/Rocket.Chat/issues/369), [Issue #370](https://github.com/RocketChat/Rocket.Chat/issues/370) - Anti-virus checking on file uploads: [Issue #757](https://github.com/RocketChat/Rocket.Chat/issues/757) -### Issues +## Issues [Github Issues](https://github.com/RocketChat/Rocket.Chat/issues) are used to track todos, bugs, feature requests, and more. -### Integrations +## Integrations #### Hubot @@ -168,71 +241,37 @@ Integrate your application with fly-in panels today! Early access is available We are developing the APIs based on the competition, so stay tuned and you will see a lot happening here. -### Documentation +## Documentation Checkout [Github Wiki](https://github.com/RocketChat/Rocket.Chat/wiki) -## Production Deployment - -### Ubuntu VPS or server - -Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker). - -### Ubuntu Software Center - -Easy one click install right from your Ubuntu Desktop (coming soon) - -[]() - - -### Docker +## License -Use the automated build at our [Official Docker Registry](https://hub.docker.com/r/rocketchat/rocket.chat/) - -[](https://hub.docker.com/r/rocketchat/rocket.chat/) - -``` -docker pull rocketchat/rocket.chat -``` - -### 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) +Note that Rocket.Chat is distributed under the [MIT License](http://opensource.org/licenses/MIT). -### 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) -Branch **develop** (Newer but unstable): -[](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) +# Development +## Branching Model +The [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branching-model/) section below is derived from Vincent Driessen at nvie. +See also this [Git Workflows Comparison](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for more details. -## Development Installation +## Translations +We are experimenting [Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard). +If you want to help, send an email to support at rocket.chat to be invited to the translation project. -Prerequisites: +## Community -* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* [Meteor](https://www.meteor.com/install) +Join the conversation at [Twitter](https://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) -Now just clone and start the app: +## How to Contribute -```sh -git clone https://github.com/RocketChat/Rocket.Chat.git -cd Rocket.Chat -meteor -``` +Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors community. -or use docker: +A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it! -``` -git clone https://github.com/RocketChat/Rocket.Chat.git -cd Rocket.Chat -docker run -it -p 3000:3000 -v "$(pwd)":/app danieldent/meteor -``` -## Credits +# Credits Thanks to [Aaron Ogle](https://github.com/geekgonecrazy), @@ -249,32 +288,8 @@ Emoji provided free by [Emoji One](http://emojione.com) Performance monitoring provided by [Kadira](https://kadira.io) -### Contributions - -Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors community. - -A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it! - -### Branching Model - -The [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branching-model/) section below is derived from Vincent Driessen at nvie. - -See also this [Git Workflows Comparison](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for more details. - -### Translations - -We are experimenting [Lingohub](https://translate.lingohub.com/engelgabriel/rocket-dot-chat/dashboard). -If you want to help, send an email to support at rocket.chat to be invited to the translation project. - -### Community - -Join the conversation at [Twitter](https://twitter.com/RocketChatApp), [Facebook](https://www.facebook.com/RocketChatApp) or [Google Plus](https://plus.google.com/+RocketChatApp) - -### License - -Note that Rocket.Chat is distributed under the [MIT License](http://opensource.org/licenses/MIT). -### Donate +# Donate Rocket.Chat will be free forever, but you can help us speed-up the development! -- GitLab From f4cc6ec2c9c23bd494fee4b0cb2075f21f461009 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 15:24:45 -0200 Subject: [PATCH 0576/1338] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1273760626c..db9a23a86ce 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,11 @@ docker run -it -p 3000:3000 -v "$(pwd)":/app danieldent/meteor 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) + Branch **develop** (Newer but unstable): + [](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) ## Sandstorm.io -- GitLab From 288fed5ff5015bbac000289fa0542cf863dbaa3d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 26 Nov 2015 15:33:19 -0200 Subject: [PATCH 0577/1338] permission protected routes --- packages/rocketchat-authorization/package.js | 1 + packages/rocketchat-lib/client/lib/roomTypes.coffee | 12 +++++++++++- packages/rocketchat-ui/lib/accountBox.coffee | 12 +++++++++++- packages/rocketchat-ui/package.js | 1 + packages/rocketchat-ui/views/app/notAuthorized.html | 3 +++ packages/rocketchat-ui/views/app/pageContainer.html | 4 ++-- 6 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 packages/rocketchat-ui/views/app/notAuthorized.html diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index d9cb3f71561..9d349afef96 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -10,6 +10,7 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use([ 'coffeescript', + 'underscore', 'rocketchat:lib@0.0.1', 'alanning:roles@1.2.12' ]); diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index c3cdfc84c9d..b991b6a09f9 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -3,6 +3,16 @@ 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' + 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 @@ -34,7 +44,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: config.route.action + action: protectedAction config triggersExit: [roomExit] ### diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index a83288bfe3d..e2dec7e7e70 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -28,6 +28,16 @@ self.box = $(".account-box") self.options = self.box.find(".options") + protectedAction = (item) -> + if not item.permissions? or RocketChat.authz.hasAllPermission item.permissions + return item.route.action + + return -> + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: t('Not_authorized') + pageTemplate: 'notAuthorized' + ### # @param newOption: # name: Button label @@ -44,7 +54,7 @@ if newItem.route?.path? and newItem.route?.name? and newItem.route?.action? FlowRouter.route newItem.route.path, name: newItem.route.name - action: newItem.route.action + action: protectedAction newItem getItems = -> return _.filter items.get(), (item) -> diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index d40700b3519..97aa9cda834 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -76,6 +76,7 @@ Package.onUse(function(api) { api.addFiles('views/app/audioNotification.html', 'client'); api.addFiles('views/app/burguer.html', 'client'); api.addFiles('views/app/home.html', 'client'); + api.addFiles('views/app/notAuthorized.html', 'client'); api.addFiles('views/app/pageContainer.html', 'client'); api.addFiles('views/app/privateHistory.html', 'client'); api.addFiles('views/app/room.html', 'client'); diff --git a/packages/rocketchat-ui/views/app/notAuthorized.html b/packages/rocketchat-ui/views/app/notAuthorized.html new file mode 100644 index 00000000000..0fca8b8efd4 --- /dev/null +++ b/packages/rocketchat-ui/views/app/notAuthorized.html @@ -0,0 +1,3 @@ +<template name="notAuthorized"> + <h2>{{_ "Not_authorized"}}</h2> +</template> diff --git a/packages/rocketchat-ui/views/app/pageContainer.html b/packages/rocketchat-ui/views/app/pageContainer.html index d10012d7627..7c8af10e1c4 100644 --- a/packages/rocketchat-ui/views/app/pageContainer.html +++ b/packages/rocketchat-ui/views/app/pageContainer.html @@ -1,5 +1,5 @@ -<template name="page-container"> - <section class="page-container page-home page-static"> +<template name="pageContainer"> + <section class="page-container page-home page-static page-list"> <head class="fixed-title"> {{> burger}} <h2> -- GitLab From e000c185b927a172324abc7c095934c38127f406 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 26 Nov 2015 16:09:47 -0200 Subject: [PATCH 0578/1338] added some translations --- i18n/en.i18n.json | 4 +++- i18n/pt.i18n.json | 2 ++ packages/rocketchat-lib/client/lib/roomTypes.coffee | 1 + packages/rocketchat-ui/lib/accountBox.coffee | 1 + packages/rocketchat-ui/views/app/notAuthorized.html | 2 +- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 4d02048519d..65f227d3a5e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1,6 +1,7 @@ { "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", + "Access_not_authorized" : "Access not authorized", "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Allowed Domains List", "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains", @@ -271,6 +272,7 @@ "No_permission_to_view_room" : "You don't have permission to view this room", "No_user_with_username_%s_was_found" : "No user with username <strong>\"%s\"</strong> was found!", "Not_allowed" : "Not allowed", + "Not_authorized" : "Not authorized", "Not_found_or_not_allowed" : "Not Found or Not Allowed", "Nothing_found" : "Nothing found", "Notify_all_in_this_room" : "Notify all in this room", @@ -456,4 +458,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file +} diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 9ee0d172ae0..ccff59f961f 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -1,6 +1,7 @@ { "Access_online_demo" : "Acesse o demo online", "Access_Online_Demo" : "Acesse o Demo Online", + "Access_not_authorized" : "Accesso não autorizado", "Accounts" : "Contas", "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", "Accounts_AllowUsernameChange" : "Permitir alterar usuário", @@ -238,6 +239,7 @@ "No_permission_to_view_room" : "Sem permissões para ver a sala", "No_user_with_username_%s_was_found" : "Nenhum usuário com nome de usuário <strong>\"%s\"</strong> foi encontrado!", "Not_allowed" : "Não permitido", + "Not_authorized" : "Não autorizado", "Not_found_or_not_allowed" : "Não encontrado ou não permitido", "Nothing_found" : "Nada encontrado", "Notify_all_in_this_room" : "Notificar todos nesta sala", diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index b991b6a09f9..f292dceba09 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -10,6 +10,7 @@ RocketChat.roomTypes = new class return -> BlazeLayout.render 'main', center: 'pageContainer' + # @TODO text Not_authorized don't get the correct language pageTitle: t('Not_authorized') pageTemplate: 'notAuthorized' diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index e2dec7e7e70..ee12f6afec5 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -35,6 +35,7 @@ return -> BlazeLayout.render 'main', center: 'pageContainer' + # @TODO text Not_authorized don't get the correct language pageTitle: t('Not_authorized') pageTemplate: 'notAuthorized' diff --git a/packages/rocketchat-ui/views/app/notAuthorized.html b/packages/rocketchat-ui/views/app/notAuthorized.html index 0fca8b8efd4..9d4c6db2bf5 100644 --- a/packages/rocketchat-ui/views/app/notAuthorized.html +++ b/packages/rocketchat-ui/views/app/notAuthorized.html @@ -1,3 +1,3 @@ <template name="notAuthorized"> - <h2>{{_ "Not_authorized"}}</h2> + <h2>{{_ "Access_not_authorized"}}</h2> </template> -- GitLab From 1ed9834d9024fe67b85802a63239964d6cb823ae Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 26 Nov 2015 16:53:21 -0200 Subject: [PATCH 0579/1338] Revert "Fix flex being opened on joining channel" This reverts commit 93a971bb28a224069f94e7badea5a93e45c2bd6f. --- packages/rocketchat-lib/client/TabBar.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/client/TabBar.coffee b/packages/rocketchat-lib/client/TabBar.coffee index a75bce80044..237024dbdd7 100644 --- a/packages/rocketchat-lib/client/TabBar.coffee +++ b/packages/rocketchat-lib/client/TabBar.coffee @@ -12,8 +12,7 @@ RocketChat.TabBar = new class setTemplate = (t, callback) -> return if animating is true template.set t - if t - openFlex(callback) + openFlex(callback) getTemplate = -> return template.get() -- GitLab From 432fb74c81b77d0c46f0ab8d8ef783185305a587 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 26 Nov 2015 16:54:21 -0200 Subject: [PATCH 0580/1338] Revert "Fix Rocket.Chat.Cordova issue #15." This reverts commit df525d6d5bf90578b754be6f891234dbe7a452a2. --- packages/rocketchat-lib/client/lib/openRoom.coffee | 1 - packages/rocketchat-ui/views/app/room.html | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 4a45b3a480e..545dce131b8 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -36,7 +36,6 @@ currentTracker = undefined if roomDom.classList.contains('room-container') roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop - RocketChat.TabBar.setTemplate '' Session.set 'openedRoom', room._id Session.set 'editRoomTitle', false diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index c85eea27f69..919ef914666 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -81,10 +81,8 @@ {{> messageBox}} </footer> </section> - {{#if flexTemplate}} - <section class="flex-tab"> - {{> Template.dynamic template=flexTemplate data=flexData}} - </section> - {{/if}} + <section class="flex-tab"> + {{> Template.dynamic template=flexTemplate data=flexData}} + </section> </div> -</template> +</template> \ No newline at end of file -- GitLab From 53e0f4012688848cd0d7eb7e9d84edc56a58780f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 17:12:23 -0200 Subject: [PATCH 0581/1338] Create one package to generate info about the compiled version --- .meteor/packages | 1 + .meteor/versions | 1 + packages/rocketchat-version/package.js | 19 ++++++++ .../plugin/compile-version.coffee | 45 +++++++++++++++++++ rocketchat.version | 3 ++ 5 files changed, 69 insertions(+) create mode 100644 packages/rocketchat-version/package.js create mode 100644 packages/rocketchat-version/plugin/compile-version.coffee create mode 100644 rocketchat.version diff --git a/.meteor/packages b/.meteor/packages index f3b3486dc9f..a473551da44 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -122,3 +122,4 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter +rocketchat:version diff --git a/.meteor/versions b/.meteor/versions index ae9dad63301..2231d744104 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -158,6 +158,7 @@ rocketchat:ui-login@0.1.0 rocketchat:ui-master@0.1.0 rocketchat:ui-message@0.1.0 rocketchat:ui-sidenav@0.1.0 +rocketchat:version@1.0.0 rocketchat:webrtc@0.0.1 rocketchat:wordpress@0.0.1 routepolicy@1.0.6 diff --git a/packages/rocketchat-version/package.js b/packages/rocketchat-version/package.js new file mode 100644 index 00000000000..54e3893c767 --- /dev/null +++ b/packages/rocketchat-version/package.js @@ -0,0 +1,19 @@ +Package.describe({ + name: 'rocketchat:version', + summary: "", + version: "1.0.0" +}); + +Package.registerBuildPlugin({ + name: "compileVersion", + use: ['coffeescript'], + sources: ['plugin/compile-version.coffee'] +}); + +Package.onUse(function (api) { + api.use('isobuild:compiler-plugin@1.0.0'); +}); + +Package.onTest(function (api) { + +}); diff --git a/packages/rocketchat-version/plugin/compile-version.coffee b/packages/rocketchat-version/plugin/compile-version.coffee new file mode 100644 index 00000000000..fc68ef3dbb6 --- /dev/null +++ b/packages/rocketchat-version/plugin/compile-version.coffee @@ -0,0 +1,45 @@ +exec = Npm.require('child_process').exec +os = Npm.require('os') + +Plugin.registerCompiler + extensions: ['version'] +, -> new VersionCompiler() + + +class VersionCompiler + processFilesForTarget: (files) -> + files.forEach (file) -> + output = JSON.parse file.getContentsAsString() + output.compile = + date: new Date().toISOString() + version: process.version + arch: process.arch + platform: process.platform + osRelease: os.release() + totalMemmory: os.totalmem() + freeMemmory: os.freemem() + cpus: os.cpus().length + + exec "git log --pretty=format:'%H%n%ad%n%an%n%s' -n 1", (err, result) -> + if not err? + result = result.split('\n') + + output.commit = + hash: result.shift() + date: result.shift() + author: result.shift() + subject: result.join('\n') + + exec "git describe --abbrev=0 --tags", (err, result) -> + if not err? + output.tag = result.replace('\n', '') + + exec "git rev-parse --abbrev-ref HEAD", (err, result) -> + if not err? + output.branch = result.replace('\n', '') + + output = """ + RocketChatVersion = #{JSON.stringify(output, null, 4)} + """ + + file.addJavaScript({ data: output, path: file.getPathInPackage() + '.js' }); diff --git a/rocketchat.version b/rocketchat.version new file mode 100644 index 00000000000..3c91ff93c46 --- /dev/null +++ b/rocketchat.version @@ -0,0 +1,3 @@ +{ + "version": "0.0.2" +} -- GitLab From e302e6dc44f8909b70d356585cebd612d328d4bf Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 17:29:26 -0200 Subject: [PATCH 0582/1338] use nodeVersion instead only version --- packages/rocketchat-version/plugin/compile-version.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-version/plugin/compile-version.coffee b/packages/rocketchat-version/plugin/compile-version.coffee index fc68ef3dbb6..a857ae0f703 100644 --- a/packages/rocketchat-version/plugin/compile-version.coffee +++ b/packages/rocketchat-version/plugin/compile-version.coffee @@ -12,7 +12,7 @@ class VersionCompiler output = JSON.parse file.getContentsAsString() output.compile = date: new Date().toISOString() - version: process.version + nodeVersion: process.version arch: process.arch platform: process.platform osRelease: os.release() -- GitLab From 131b1c57c0f53f21dd2205336df9e5fe53ff221c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 17:29:37 -0200 Subject: [PATCH 0583/1338] Update project version to 0.7.0 --- rocketchat.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketchat.version b/rocketchat.version index 3c91ff93c46..f9a62bc59fe 100644 --- a/rocketchat.version +++ b/rocketchat.version @@ -1,3 +1,3 @@ { - "version": "0.0.2" + "version": "0.7.0" } -- GitLab From 5994bf3a251c45101d81ef122dd17e7e31d52fa0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 17:29:55 -0200 Subject: [PATCH 0584/1338] Create route /info to get RocketChatVersion via rest --- server/restapi/restapi.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 24931bdd942..efedcf3786d 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -1,3 +1,11 @@ +Router = new Restivus + apiPath: '/' + useDefaultAuth: false + +Router.addRoute 'info', authRequired: false, + get: -> RocketChatVersion + + Api = new Restivus useDefaultAuth: true prettyJson: true -- GitLab From 9b0112bb6691c76b96b1d2896ca2196471a7b374 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 17:32:48 -0200 Subject: [PATCH 0585/1338] Sort packages --- .meteor/packages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index a473551da44..5dd240ea647 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -72,6 +72,7 @@ rocketchat:ui-login rocketchat:ui-master rocketchat:ui-message rocketchat:ui-sidenav +rocketchat:version rocketchat:webrtc rocketchat:wordpress #rocketchat:chatops @@ -122,4 +123,3 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter -rocketchat:version -- GitLab From 2023c4d3216114d72f9c822b65a441107c60290b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 17:37:12 -0200 Subject: [PATCH 0586/1338] Change from /info to /api/info --- server/restapi/restapi.coffee | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index efedcf3786d..27ca22936a4 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -1,16 +1,11 @@ -Router = new Restivus - apiPath: '/' - useDefaultAuth: false - -Router.addRoute 'info', authRequired: false, - get: -> RocketChatVersion - - Api = new Restivus useDefaultAuth: true prettyJson: true +Api.addRoute 'info', authRequired: false, + get: -> RocketChatVersion + Api.addRoute 'version', authRequired: false, get: -> -- GitLab From b8a53c91210bd358cc7c92bf686074eb18a6f20a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 26 Nov 2015 17:58:35 -0200 Subject: [PATCH 0587/1338] CSS for inline forms --- packages/rocketchat-theme/assets/stylesheets/base.less | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c8a913a1aa3..b98b198610f 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -460,6 +460,15 @@ input.search { } } +form.inline { + input[type='text'], + input[type='number'], + input[type='email'], + input[type='password'] { + width: auto; + } +} + .search-form { position: relative; } -- GitLab From b86f4614777d5adc5bf49ab84d7ff81b8a02fa79 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 26 Nov 2015 18:01:24 -0200 Subject: [PATCH 0588/1338] livechat manager --- packages/rocketchat-livechat/client/ui.js | 19 ++- .../client/views/app/livechatManager.html | 71 +++++++++ .../client/views/app/livechatManager.js | 135 ++++++++++++++++++ .../rocketchat-livechat/i18n/en.i18n.json | 7 +- .../rocketchat-livechat/i18n/pt.i18n.json | 7 +- packages/rocketchat-livechat/package.js | 18 ++- packages/rocketchat-livechat/permissions.js | 3 +- .../server/methods/addAgent.js | 21 +++ .../server/methods/addManager.js | 21 +++ .../server/methods/removeAgent.js | 21 +++ .../server/methods/removeManager.js | 21 +++ .../server/publications/livechatAgents.js | 31 ++++ .../server/publications/livechatManagers.js | 31 ++++ 13 files changed, 397 insertions(+), 9 deletions(-) create mode 100644 packages/rocketchat-livechat/client/views/app/livechatManager.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatManager.js create mode 100644 packages/rocketchat-livechat/server/methods/addAgent.js create mode 100644 packages/rocketchat-livechat/server/methods/addManager.js create mode 100644 packages/rocketchat-livechat/server/methods/removeAgent.js create mode 100644 packages/rocketchat-livechat/server/methods/removeManager.js create mode 100644 packages/rocketchat-livechat/server/publications/livechatAgents.js create mode 100644 packages/rocketchat-livechat/server/publications/livechatManagers.js diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index c5a58fe2b41..491a92fc746 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -15,4 +15,21 @@ RocketChat.roomTypes.add('l', 5, { permissions: [ 'view-l-room' ] }); -AccountBox.addOption({ name: 'Livechat', icon: 'icon-chat-empty', class: 'livechat-manager', roles: ['livechat-manager'] }); +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: 'pageContainer', + pageTitle: t('Livechat_Manager'), + pageTemplate: 'livechatManager' + }); + } + }, + permissions: ['view-livechat-manager'] +}); diff --git a/packages/rocketchat-livechat/client/views/app/livechatManager.html b/packages/rocketchat-livechat/client/views/app/livechatManager.html new file mode 100644 index 00000000000..fc90993a0c2 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatManager.html @@ -0,0 +1,71 @@ +<template name="livechatManager"> + <h2>{{_ "Livechat_managers"}}</h2> + <form id="form-manager" class="inline"> + <label>{{_ "Add_manager"}}</label> + <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> + <button name="add" class="button primary">{{_ "Add"}}</button> + </form> + <div class="list"> + <table> + <thead> + <tr> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> + <th> </th> + </tr> + </thead> + <tbody> + {{#each managers}} + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + <td><a href="#remove" class="remove-manager"><i class="icon-block"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> + <h2>{{_ "Livechat_agents"}}</h2> + <form id="form-agent" class="inline"> + <label>{{_ "Add_agent"}}</label> + <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> + <button name="add" class="button primary">{{_ "Add"}}</button> + </form> + <div class="list"> + <table> + <thead> + <tr> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> + <th> </th> + </tr> + </thead> + <tbody> + {{#each agents}} + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + <td><a href="#remove" class="remove-agent"><i class="icon-block"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> +</template> + diff --git a/packages/rocketchat-livechat/client/views/app/livechatManager.js b/packages/rocketchat-livechat/client/views/app/livechatManager.js new file mode 100644 index 00000000000..49ba4e4896f --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatManager.js @@ -0,0 +1,135 @@ +var AgentUsers; +var ManagerUsers; + +Meteor.startup(function() { + AgentUsers = new Mongo.Collection('agentUsers'); + ManagerUsers = new Mongo.Collection('managerUsers'); +}); + +Template.livechatManager.helpers({ + managers() { + return ManagerUsers.find({}, { sort: { name: 1 } }); + }, + agents() { + return AgentUsers.find({}, { sort: { name: 1 } }); + }, + emailAddress() { + if (this.emails && this.emails.length > 0) { + return this.emails[0].address; + } + } +}); + +Template.livechatManager.events({ + 'click .remove-manager' (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:removeManager', this.username, function(error, result) { + if (error) { + return toastr.error(error.reason || error.error); + } + swal({ + title: t('Removed'), + text: t('Manager_removed'), + type: 'success', + timer: 1000, + showConfirmButton: false, + }); + }); + }); + }, + 'click .remove-agent' (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:removeAgent', this.username, function(error, result) { + if (error) { + return toastr.error(error.reason || error.error); + } + swal({ + title: t('Removed'), + text: t('Agent_removed'), + type: 'success', + timer: 1000, + showConfirmButton: false, + }); + }); + }); + }, + 'submit #form-manager' (e, instance) { + e.preventDefault(); + + if (e.currentTarget.elements['username'].value.trim() === '') { + return toastr.error(t('Please_fill_a_username')); + } + + var oldBtnValue = e.currentTarget.elements['add'].value; + + e.currentTarget.elements['add'].value = t('Saving'); + + Meteor.call('livechat:addManager', e.currentTarget.elements['username'].value, function(error, result) { + e.currentTarget.elements['add'].value = oldBtnValue; + if (error) { + console.log(error); + return toastr.error(error.reason || error.error); + } + + toastr.success(t('Manager_added')); + e.currentTarget.reset(); + }); + + // console.log('valor ->',e.currentTarget.elements['username'].value); + + // Meteor.call + }, + 'submit #form-agent' (e, instance) { + e.preventDefault(); + + if (e.currentTarget.elements['username'].value.trim() === '') { + return toastr.error(t('Please_fill_a_username')); + } + + var oldBtnValue = e.currentTarget.elements['add'].value; + + e.currentTarget.elements['add'].value = t('Saving'); + + Meteor.call('livechat:addAgent', e.currentTarget.elements['username'].value, function(error, result) { + e.currentTarget.elements['add'].value = oldBtnValue; + if (error) { + console.log(error); + return toastr.error(error.reason || error.error); + } + + toastr.success(t('Agent_added')); + e.currentTarget.reset(); + }); + + // console.log('valor ->',e.currentTarget.elements['username'].value); + + // Meteor.call + } +}); + +Template.livechatManager.onCreated(function() { + this.subscribe('livechat:agents'); + this.subscribe('livechat:managers'); +}); diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 3e0c8629995..ede2e4fc396 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -1,4 +1,7 @@ { "Livechat_title" : "Livechat Title", - "Livechat_title_color" : "Livechat Title Background Color" -} \ No newline at end of file + "Livechat_title_color" : "Livechat Title Background Color", + "Livechat_Manager": "Livechat Manager", + "Livechat_managers": "Livechat managers", + "Livechat_agents": "Livechat agents" +} diff --git a/packages/rocketchat-livechat/i18n/pt.i18n.json b/packages/rocketchat-livechat/i18n/pt.i18n.json index cec5df03770..63cef7b9c19 100644 --- a/packages/rocketchat-livechat/i18n/pt.i18n.json +++ b/packages/rocketchat-livechat/i18n/pt.i18n.json @@ -1,4 +1,7 @@ { "Livechat_title" : "TÃtulo Livechat", - "Livechat_title_color" : "Cor de fundo do tÃtulo do Livechat" -} \ No newline at end of file + "Livechat_title_color" : "Cor de fundo do tÃtulo do Livechat", + "Livechat_Manager": "Administração Livechat", + "Livechat_managers": "Gerenciadores do Livechat ", + "Livechat_agents": "Agentes do Livechat" +} diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index ca8eb3627d0..0d5ca884cc5 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -20,9 +20,7 @@ Package.onUse(function(api) { api.use(['webapp', 'autoupdate'], 'server'); api.use('ecmascript'); - - api.imply('alanning:roles@1.2.12'); - + api.use('alanning:roles@1.2.12'); api.use('rocketchat:lib', 'client'); api.use('kadira:flow-router', 'client'); @@ -35,6 +33,10 @@ Package.onUse(function(api) { api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); + + api.addFiles('client/views/app/livechatManager.html', 'client'); + api.addFiles('client/views/app/livechatManager.js', 'client'); + api.addFiles('client/views/sideNav/livechat.html', 'client'); api.addFiles('client/views/sideNav/livechat.js', 'client'); @@ -43,6 +45,16 @@ Package.onUse(function(api) { api.addAssets('public/livechat.js', 'client'); api.addAssets('public/head.html', 'server'); + // publications + api.addFiles('server/publications/livechatAgents.js', 'server'); + api.addFiles('server/publications/livechatManagers.js', 'server'); + + // methods + api.addFiles('server/methods/addAgent.js', 'server'); + api.addFiles('server/methods/addManager.js', 'server'); + api.addFiles('server/methods/removeAgent.js', 'server'); + api.addFiles('server/methods/removeManager.js', 'server'); + // TAPi18n api.use('templating', 'client'); var _ = Npm.require('underscore'); diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index 0239df4a1e2..98bf89e1be0 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -7,6 +7,7 @@ Meteor.startup(() => { Roles.createRole('livechat-manager'); } if (RocketChat.models && RocketChat.models.Permissions) { - RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager']); + RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager', 'admin']); + RocketChat.models.Permissions.createOrUpdate('view-livechat-manager', ['livechat-manager', 'admin']); } }); diff --git a/packages/rocketchat-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js new file mode 100644 index 00000000000..f843c151e5f --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -0,0 +1,21 @@ +Meteor.methods({ + 'livechat:addAgent' (username) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + if (!username || !_.isString(username)) { + 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', TAPi18n.__('Username_not_found')); + } + + return RocketChat.authz.addUsersToRoles(user._id, 'livechat-agent'); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/addManager.js b/packages/rocketchat-livechat/server/methods/addManager.js new file mode 100644 index 00000000000..43d2d5f9459 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/addManager.js @@ -0,0 +1,21 @@ +Meteor.methods({ + 'livechat:addManager' (username) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + if (!username || !_.isString(username)) { + 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', TAPi18n.__('Username_not_found')); + } + + return RocketChat.authz.addUsersToRoles(user._id, 'livechat-manager'); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js new file mode 100644 index 00000000000..bc054e8d56e --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -0,0 +1,21 @@ +Meteor.methods({ + 'livechat:removeAgent' (username) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + if (!username || !_.isString(username)) { + 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', TAPi18n.__('Username_not_found')); + } + + return RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-agent'); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/removeManager.js b/packages/rocketchat-livechat/server/methods/removeManager.js new file mode 100644 index 00000000000..c02941a892c --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/removeManager.js @@ -0,0 +1,21 @@ +Meteor.methods({ + 'livechat:removeManager' (username) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + if (!username || !_.isString(username)) { + throw new Meteor.Error('invalid-arguments'); + } + + 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', TAPi18n.__('Username_not_found')); + } + + return RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-manager'); + } +}); diff --git a/packages/rocketchat-livechat/server/publications/livechatAgents.js b/packages/rocketchat-livechat/server/publications/livechatAgents.js new file mode 100644 index 00000000000..b68dba1459c --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/livechatAgents.js @@ -0,0 +1,31 @@ +Meteor.publish('livechat:agents', function() { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { + 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({ + added(id, fields) { + self.added('agentUsers', id, fields); + }, + changed(id, fields) { + self.changed('agentUsers', id, fields); + }, + removed(id) { + self.removed('agentUsers', id); + } + }); + + self.ready(); + + self.onStop(function() { + handle.stop(); + }); +}); diff --git a/packages/rocketchat-livechat/server/publications/livechatManagers.js b/packages/rocketchat-livechat/server/publications/livechatManagers.js new file mode 100644 index 00000000000..639c1305c6d --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/livechatManagers.js @@ -0,0 +1,31 @@ +Meteor.publish('livechat:managers', function() { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { + 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({ + added(id, fields) { + self.added('managerUsers', id, fields); + }, + changed(id, fields) { + self.changed('managerUsers', id, fields); + }, + removed(id) { + self.removed('managerUsers', id); + } + }); + + self.ready(); + + self.onStop(function() { + handle.stop(); + }); +}); -- GitLab From 3a35260b2486a34b8291c7b09a8f95c116c92dfa Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 26 Nov 2015 20:00:38 -0200 Subject: [PATCH 0589/1338] Prevent duplicated CORS --- server/restapi/restapi.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 27ca22936a4..36324fcb3da 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -1,6 +1,7 @@ Api = new Restivus useDefaultAuth: true prettyJson: true + enableCors: false Api.addRoute 'info', authRequired: false, -- GitLab From a0b8cc3ebc64bad1cd0a368e57b94ad0ca0dd3ff Mon Sep 17 00:00:00 2001 From: mapk0y <mapk0y@gmail.com> Date: Fri, 27 Nov 2015 21:48:32 +0900 Subject: [PATCH 0590/1338] fix typo in docker-compose.yml --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 33ff050156a..be58250aa93 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ rocketchat: # volumes: # - ./uploads:/app/uploads environment: - - ROOT=3000 + - 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 -- GitLab From 5001e2d14b82eecfc8c60b35380278cdfbfef442 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 27 Nov 2015 11:26:01 -0200 Subject: [PATCH 0591/1338] AccountBox initial docs --- packages/rocketchat-lib/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/rocketchat-lib/README.md b/packages/rocketchat-lib/README.md index 93e67d06b9b..b00630727af 100644 --- a/packages/rocketchat-lib/README.md +++ b/packages/rocketchat-lib/README.md @@ -44,6 +44,30 @@ RocketChat.roomTypes.setPublish('l', (identifier) => { }); ``` +### AccountBox + +You can add items to the left upper corner drop menu: +```javascript +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'] +}); +``` + ### Functions ### Methods ### Publications -- GitLab From 98f255ba3c939e6006d2f8f4df83b96c92b9d7cf Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 27 Nov 2015 13:27:20 -0200 Subject: [PATCH 0592/1338] Hide hidden settings from admin settings panel --- packages/rocketchat-lib/server/publications/settings.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/publications/settings.coffee b/packages/rocketchat-lib/server/publications/settings.coffee index 3b2aa1c8dda..c3d5beb0a4f 100644 --- a/packages/rocketchat-lib/server/publications/settings.coffee +++ b/packages/rocketchat-lib/server/publications/settings.coffee @@ -18,7 +18,7 @@ Meteor.publish 'admin-settings', -> return @ready() if RocketChat.authz.hasPermission( @userId, 'view-privileged-setting') - return RocketChat.models.Settings.find() + return RocketChat.models.Settings.find({ hidden: { $ne: true } }) else return @ready() -- GitLab From e76baf592d441faf14a4d89d1414a40776ae4c60 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 27 Nov 2015 15:00:45 -0200 Subject: [PATCH 0593/1338] Allows for select input as admin settings --- packages/rocketchat-ui-admin/admin/admin.coffee | 4 ++++ packages/rocketchat-ui-admin/admin/admin.html | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 7bcfda28b35..f74cc51206a 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -37,6 +37,8 @@ Template.admin.helpers callbackURL: (section) -> id = s.strRight(section, 'Custom OAuth: ').toLowerCase() return Meteor.absoluteUrl('_oauth/' + id) + selectedOption: (_id, val) -> + return RocketChat.settings.get(_id) is val Template.admin.events "click .submit .save": (e, t) -> @@ -53,6 +55,8 @@ Template.admin.events 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 } diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 46162c41d4e..f612c6034c4 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -50,13 +50,18 @@ <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> {{/if}} +- {{#if $eq type 'select'}} +- <select name="{{_id}}"> +- {{#each values}} +- <option value="{{key}}" selected="{{selectedOption ../_id key}}">{{_ i18nLabel}}</option> +- {{/each}} +- </select> +- {{/if}} {{#if $eq type 'color'}} <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> {{/if}} {{#if description}} - <div> - <small class="settings-description">{{{description}}}</small> - </div> + <div class="settings-description">{{{description}}}</div> {{/if}} </div> </div> -- GitLab From fd12bcf2cad7ff98c9eec5f7eb96704c402d3766 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 27 Nov 2015 15:23:53 -0200 Subject: [PATCH 0594/1338] sets a livechat-agent as operator --- packages/rocketchat-livechat/package.js | 26 +++++++++++-------- .../server/methods/addAgent.js | 6 ++++- .../server/methods/removeAgent.js | 6 ++++- .../server/models/Users.js | 14 ++++++++++ 4 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 packages/rocketchat-livechat/server/models/Users.js diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 0d5ca884cc5..4bca67e8944 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -21,7 +21,7 @@ Package.onUse(function(api) { api.use(['webapp', 'autoupdate'], 'server'); api.use('ecmascript'); api.use('alanning:roles@1.2.12'); - api.use('rocketchat:lib', 'client'); + api.use('rocketchat:lib'); api.use('kadira:flow-router', 'client'); api.addFiles('livechat.js', 'server'); @@ -34,27 +34,31 @@ Package.onUse(function(api) { api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); + // client views api.addFiles('client/views/app/livechatManager.html', 'client'); api.addFiles('client/views/app/livechatManager.js', 'client'); - api.addFiles('client/views/sideNav/livechat.html', 'client'); api.addFiles('client/views/sideNav/livechat.js', 'client'); - api.addAssets('rocket-livechat.js', 'client'); - api.addAssets('public/livechat.css', 'client'); - api.addAssets('public/livechat.js', 'client'); - api.addAssets('public/head.html', 'server'); - - // publications - api.addFiles('server/publications/livechatAgents.js', 'server'); - api.addFiles('server/publications/livechatManagers.js', 'server'); - // methods api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); api.addFiles('server/methods/removeAgent.js', 'server'); api.addFiles('server/methods/removeManager.js', 'server'); + // models + api.addFiles('server/models/Users.js', 'server'); + + // publications + api.addFiles('server/publications/livechatAgents.js', 'server'); + api.addFiles('server/publications/livechatManagers.js', 'server'); + + // livechat app + api.addAssets('rocket-livechat.js', 'client'); + api.addAssets('public/livechat.css', 'client'); + api.addAssets('public/livechat.js', 'client'); + api.addAssets('public/head.html', 'server'); + // TAPi18n api.use('templating', 'client'); var _ = Npm.require('underscore'); diff --git a/packages/rocketchat-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js index f843c151e5f..d1d9f8710b3 100644 --- a/packages/rocketchat-livechat/server/methods/addAgent.js +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -16,6 +16,10 @@ Meteor.methods({ throw new Meteor.Error('user-not-found', TAPi18n.__('Username_not_found')); } - return RocketChat.authz.addUsersToRoles(user._id, 'livechat-agent'); + if (RocketChat.authz.addUsersToRoles(user._id, 'livechat-agent')) { + return RocketChat.models.Users.setOperator(user._id, true); + } + + return false; } }); diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js index bc054e8d56e..264e838daa4 100644 --- a/packages/rocketchat-livechat/server/methods/removeAgent.js +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -16,6 +16,10 @@ Meteor.methods({ throw new Meteor.Error('user-not-found', TAPi18n.__('Username_not_found')); } - return RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-agent'); + if (RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-agent')) { + return RocketChat.models.Users.setOperator(user._id, false); + } + + return false; } }); diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js new file mode 100644 index 00000000000..adc6863d011 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -0,0 +1,14 @@ +/** + * Sets an user as (non)operator + * @param {string} _id - User's _id + * @param {boolean} operator - Flag to set as operator or not + */ +RocketChat.models.Users.setOperator = function(_id, operator) { + var update = { + $set: { + operator: operator + } + }; + + return this.update(_id, update); +}; -- GitLab From 6214124bad29ffbeebbdff70856d4022ab988bd5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 27 Nov 2015 17:16:14 -0200 Subject: [PATCH 0595/1338] fixed translations --- .../client/views/app/livechat-manager.html | 4 ---- .../client/views/app/livechatManager.js | 18 ++++-------------- packages/rocketchat-livechat/i18n/en.i18n.json | 16 +++++++++++++--- packages/rocketchat-livechat/i18n/pt.i18n.json | 16 +++++++++++++--- packages/rocketchat-livechat/package.js | 6 +++--- .../server/methods/addAgent.js | 2 +- .../server/methods/addManager.js | 2 +- .../server/methods/removeAgent.js | 2 +- .../server/methods/removeManager.js | 2 +- 9 files changed, 37 insertions(+), 31 deletions(-) delete mode 100644 packages/rocketchat-livechat/client/views/app/livechat-manager.html diff --git a/packages/rocketchat-livechat/client/views/app/livechat-manager.html b/packages/rocketchat-livechat/client/views/app/livechat-manager.html deleted file mode 100644 index 75e0725e696..00000000000 --- a/packages/rocketchat-livechat/client/views/app/livechat-manager.html +++ /dev/null @@ -1,4 +0,0 @@ -<template name="livechat-manager"> - <h1>livechat-manager</h1> - <p>Example</p> -</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatManager.js b/packages/rocketchat-livechat/client/views/app/livechatManager.js index 49ba4e4896f..173cb633a50 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatManager.js +++ b/packages/rocketchat-livechat/client/views/app/livechatManager.js @@ -36,7 +36,7 @@ Template.livechatManager.events({ }, () => { Meteor.call('livechat:removeManager', this.username, function(error, result) { if (error) { - return toastr.error(error.reason || error.error); + return toastr.error(t(error.reason || error.error)); } swal({ title: t('Removed'), @@ -63,7 +63,7 @@ Template.livechatManager.events({ }, () => { Meteor.call('livechat:removeAgent', this.username, function(error, result) { if (error) { - return toastr.error(error.reason || error.error); + return toastr.error(t(error.reason || error.error)); } swal({ title: t('Removed'), @@ -89,17 +89,12 @@ Template.livechatManager.events({ Meteor.call('livechat:addManager', e.currentTarget.elements['username'].value, function(error, result) { e.currentTarget.elements['add'].value = oldBtnValue; if (error) { - console.log(error); - return toastr.error(error.reason || error.error); + return toastr.error(t(error.reason || error.error)); } toastr.success(t('Manager_added')); e.currentTarget.reset(); }); - - // console.log('valor ->',e.currentTarget.elements['username'].value); - - // Meteor.call }, 'submit #form-agent' (e, instance) { e.preventDefault(); @@ -115,17 +110,12 @@ Template.livechatManager.events({ Meteor.call('livechat:addAgent', e.currentTarget.elements['username'].value, function(error, result) { e.currentTarget.elements['add'].value = oldBtnValue; if (error) { - console.log(error); - return toastr.error(error.reason || error.error); + return toastr.error(t(error.reason || error.error)); } toastr.success(t('Agent_added')); e.currentTarget.reset(); }); - - // console.log('valor ->',e.currentTarget.elements['username'].value); - - // Meteor.call } }); diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index ede2e4fc396..6de6b790589 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -1,7 +1,17 @@ { - "Livechat_title" : "Livechat Title", - "Livechat_title_color" : "Livechat Title Background Color", + "Add": "Add", + "Add_agent": "Add agent", + "Add_manager": "Add manager", + "Agent_added": "Agent added", + "Agent_removed": "Agent removed", + "Enter_a_username": "Enter a username", + "Livechat_agents": "Livechat agents", "Livechat_Manager": "Livechat Manager", "Livechat_managers": "Livechat managers", - "Livechat_agents": "Livechat agents" + "Livechat_title" : "Livechat Title", + "Livechat_title_color" : "Livechat Title Background Color", + "Manager_added": "Manager added", + "Manager_removed": "Manager removed", + "Please_fill_a_username": "Please fill a username", + "Username_not_found": "Username not found" } diff --git a/packages/rocketchat-livechat/i18n/pt.i18n.json b/packages/rocketchat-livechat/i18n/pt.i18n.json index 63cef7b9c19..1782d554f8c 100644 --- a/packages/rocketchat-livechat/i18n/pt.i18n.json +++ b/packages/rocketchat-livechat/i18n/pt.i18n.json @@ -1,7 +1,17 @@ { + "Add": "Adicionar", + "Add_agent": "Adicionar agente", + "Add_manager": "Adicionar gerente", + "Agent_added": "Agente adicionado", + "Agent_removed": "Agente removido", + "Enter_a_username": "Nome de usuário", + "Livechat_agents": "Agentes do Livechat", + "Livechat_Manager": "Administração Livechat", + "Livechat_managers": "Gerentes do Livechat", "Livechat_title" : "TÃtulo Livechat", "Livechat_title_color" : "Cor de fundo do tÃtulo do Livechat", - "Livechat_Manager": "Administração Livechat", - "Livechat_managers": "Gerenciadores do Livechat ", - "Livechat_agents": "Agentes do Livechat" + "Manager_added": "Gerente adicionado", + "Manager_removed": "Gerente removido", + "Please_fill_a_username": "Por favor preencha um nome de usuário", + "Username_not_found": "Nome de usuário não encontrado" } diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 4bca67e8944..50bad731694 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -23,6 +23,7 @@ Package.onUse(function(api) { api.use('alanning:roles@1.2.12'); api.use('rocketchat:lib'); api.use('kadira:flow-router', 'client'); + api.use('templating', 'client'); api.addFiles('livechat.js', 'server'); api.addFiles('server/methods.js', 'server'); @@ -60,7 +61,6 @@ Package.onUse(function(api) { api.addAssets('public/head.html', 'server'); // TAPi18n - api.use('templating', 'client'); var _ = Npm.require('underscore'); var fs = Npm.require('fs'); tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-livechat/i18n'), function(filename) { @@ -68,7 +68,7 @@ Package.onUse(function(api) { return 'i18n/' + filename; } })); - api.use('tap:i18n@1.6.1', ['client', 'server']); - api.imply('tap:i18n'); + api.use('tap:i18n', ['client', 'server']); + // api.imply('tap:i18n'); api.addFiles(tapi18nFiles, ['client', 'server']); }); diff --git a/packages/rocketchat-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js index d1d9f8710b3..e94c5bee12f 100644 --- a/packages/rocketchat-livechat/server/methods/addAgent.js +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -13,7 +13,7 @@ Meteor.methods({ var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { - throw new Meteor.Error('user-not-found', TAPi18n.__('Username_not_found')); + throw new Meteor.Error('user-not-found', 'Username_not_found'); } if (RocketChat.authz.addUsersToRoles(user._id, 'livechat-agent')) { diff --git a/packages/rocketchat-livechat/server/methods/addManager.js b/packages/rocketchat-livechat/server/methods/addManager.js index 43d2d5f9459..6519a406bf3 100644 --- a/packages/rocketchat-livechat/server/methods/addManager.js +++ b/packages/rocketchat-livechat/server/methods/addManager.js @@ -13,7 +13,7 @@ Meteor.methods({ var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { - throw new Meteor.Error('user-not-found', TAPi18n.__('Username_not_found')); + throw new Meteor.Error('user-not-found', 'Username_not_found'); } return RocketChat.authz.addUsersToRoles(user._id, 'livechat-manager'); diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js index 264e838daa4..bc6dd5bd4c9 100644 --- a/packages/rocketchat-livechat/server/methods/removeAgent.js +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -13,7 +13,7 @@ Meteor.methods({ var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { - throw new Meteor.Error('user-not-found', TAPi18n.__('Username_not_found')); + throw new Meteor.Error('user-not-found', 'Username_not_found'); } if (RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-agent')) { diff --git a/packages/rocketchat-livechat/server/methods/removeManager.js b/packages/rocketchat-livechat/server/methods/removeManager.js index c02941a892c..43bebc3e8cb 100644 --- a/packages/rocketchat-livechat/server/methods/removeManager.js +++ b/packages/rocketchat-livechat/server/methods/removeManager.js @@ -13,7 +13,7 @@ Meteor.methods({ var user = RocketChat.models.Users.findOneByUsername(username, { fields: { _id: 1 } }); if (!user) { - throw new Meteor.Error('user-not-found', TAPi18n.__('Username_not_found')); + throw new Meteor.Error('user-not-found', 'Username_not_found'); } return RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-manager'); -- GitLab From c68fa0eb34c068a49f3ce74a14dc43f171c6e6a7 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 27 Nov 2015 17:17:17 -0200 Subject: [PATCH 0596/1338] fixing translations --- i18n/en.i18n.json | 1 + i18n/pt.i18n.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 65f227d3a5e..5016fad9864 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -451,6 +451,7 @@ "Welcome" : "Welcome <em>%s</em>.", "Welcome_to_the" : "Welcome to the", "With_whom" : "With whom", + "Yes" : "Yes", "Yes_clear_all" : "Yes, clear all!", "Yes_delete_it" : "Yes, delete it!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index ccff59f961f..b08892268d4 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -1,7 +1,7 @@ { "Access_online_demo" : "Acesse o demo online", "Access_Online_Demo" : "Acesse o Demo Online", - "Access_not_authorized" : "Accesso não autorizado", + "Access_not_authorized" : "Acesso não autorizado", "Accounts" : "Contas", "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", "Accounts_AllowUsernameChange" : "Permitir alterar usuário", @@ -407,6 +407,7 @@ "Welcome" : "Seja bem-vindo <em>%s</em>.", "Welcome_to_the" : "Bem-vindo ao", "With_whom" : "Com quem", + "Yes" : "Sim", "Yes_delete_it" : "Sim, exclua!", "you_are_in_preview_mode_of" : "Esta é uma prévia do canal #<strong>__room_name__</strong>", "You_need_confirm_email" : "Você precisa confirmar seu email para logar!", -- GitLab From 2551ebe94bdaa696ade6d93093700f7c079f2c5c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 27 Nov 2015 18:02:06 -0200 Subject: [PATCH 0597/1338] Block user registration and services registration --- i18n/en.i18n.json | 7 +++++++ .../server/functions/setUsername.coffee | 2 +- .../rocketchat-lib/server/startup/settings.coffee | 10 +++++++--- packages/rocketchat-ui-admin/admin/admin.html | 14 +++++++------- packages/rocketchat-ui-login/login/form.coffee | 6 ++++++ packages/rocketchat-ui-login/login/form.html | 4 ++++ packages/rocketchat-ui-login/login/services.coffee | 14 ++++++++++---- .../rocketchat-ui-login/username/username.coffee | 1 + server/lib/accounts.coffee | 5 +++++ server/methods/getUsernameSuggestion.coffee | 2 +- server/methods/registerUser.coffee | 3 +++ 11 files changed, 52 insertions(+), 16 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 65f227d3a5e..372f4d797a0 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -47,6 +47,13 @@ "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_Registration_AuthenticationServices_Enabled" : "Registration with Authentication Services", + "Accounts_RegistrationForm" : "Registration Form", + "Accounts_RegistrationForm_Public" : "Public", + "Accounts_RegistrationForm_Disabled" : "Disabled", + "Accounts_RegistrationForm_LinkReplacementText": "Registration Form Link Replacement Text", + "Accounts_RegistrationForm_Secret_URL" : "Secret URL", + "Accounts_RegistrationForm_SecretURL" : "Registration Form Secret URL", "Accounts_RegistrationRequired" : "Registration Required", "Accounts_RequireNameForSignUp" : "Require Name For Signup", "Accounts_Enrollment_Email" : "Enrollment E-mail", diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 409fb6d161a..af8a0ad2def 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -22,7 +22,7 @@ RocketChat.setUsername = (user, username) -> previousUsername = user.username # If first time setting username, send Enrollment Email - if not previousUsername and RocketChat.settings.get 'Accounts_Enrollment_Email' + if not previousUsername and user.emails?.length > 0 and RocketChat.settings.get 'Accounts_Enrollment_Email' Accounts.sendEnrollmentEmail(user._id) # Username is available; if coming from old username, update all references diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 0e2ed32b3a8..fec49f16d2d 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -3,11 +3,15 @@ if not RocketChat.models.Settings.findOneById 'uniqueID' RocketChat.models.Settings.createWithIdAndValue 'uniqueID', Random.id() RocketChat.settings.addGroup 'Accounts' -RocketChat.settings.add 'Accounts_RegistrationRequired', true, { type: 'boolean', group: 'Accounts', public: true, section: 'Registration' } 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_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' } @@ -129,5 +133,5 @@ Meteor.startup -> # Remove runtime settings (non-persistent) Meteor.startup -> - RocketChat.models.Settings.update({ ts: { $lt: RocketChat.settings.ts }, persistent: false }, { $set: { hidden: true } }) - + RocketChat.models.Settings.update({ ts: { $lt: RocketChat.settings.ts }, persistent: { $ne: true } }, { $set: { hidden: true } }, { multi: true }) + RocketChat.models.Settings.update({ ts: { $gte: RocketChat.settings.ts } }, { $unset: { hidden: 1 } }, { multi: true }) diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index f612c6034c4..f8152fc11a6 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -50,13 +50,13 @@ <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> {{/if}} -- {{#if $eq type 'select'}} -- <select name="{{_id}}"> -- {{#each values}} -- <option value="{{key}}" selected="{{selectedOption ../_id key}}">{{_ i18nLabel}}</option> -- {{/each}} -- </select> -- {{/if}} + {{#if $eq type 'select'}} + <select name="{{_id}}"> + {{#each values}} + <option value="{{key}}" selected="{{selectedOption ../_id key}}">{{_ i18nLabel}}</option> + {{/each}} + </select> + {{/if}} {{#if $eq type 'color'}} <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> {{/if}} diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 8b1d253db51..27055085b1a 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -51,6 +51,12 @@ Template.loginForm.helpers loginTerms: -> return RocketChat.settings.get 'Layout_Login_Terms' + registrationAllowed: -> + return RocketChat.settings.get('Accounts_RegistrationForm') is 'Public' + + linkReplacementText: -> + return RocketChat.settings.get('Accounts_RegistrationForm_LinkReplacementText') + Template.loginForm.events 'submit #login-card': (event, instance) -> event.preventDefault() diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index c5514e2f0fa..ff4d59f903f 100644 --- a/packages/rocketchat-ui-login/login/form.html +++ b/packages/rocketchat-ui-login/login/form.html @@ -38,9 +38,13 @@ <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}} <div class="forgot-password {{showForgotPasswordLink}}"> <a href="">{{_ 'Forgot_password'}}</a> </div> diff --git a/packages/rocketchat-ui-login/login/services.coffee b/packages/rocketchat-ui-login/login/services.coffee index fb491b8a994..27ad1757ed4 100644 --- a/packages/rocketchat-ui-login/login/services.coffee +++ b/packages/rocketchat-ui-login/login/services.coffee @@ -53,8 +53,11 @@ Template.loginServices.events serviceIcon.removeClass 'hidden' if error - console.log JSON.stringify(error), error.message - toastr.error error.message + console.log JSON.stringify(error) + if error.reason + toastr.error error.reason + else + toastr.error error.message return else @@ -64,6 +67,9 @@ Template.loginServices.events loadingIcon.addClass 'hidden' serviceIcon.removeClass 'hidden' if error - console.log JSON.stringify(error), error.message - toastr.error error.message + console.log JSON.stringify(error) + if error.reason + toastr.error error.reason + else + toastr.error error.message return diff --git a/packages/rocketchat-ui-login/username/username.coffee b/packages/rocketchat-ui-login/username/username.coffee index 2e91ce948aa..eef6c844c90 100644 --- a/packages/rocketchat-ui-login/username/username.coffee +++ b/packages/rocketchat-ui-login/username/username.coffee @@ -35,6 +35,7 @@ Template.username.events Meteor.call 'setUsername', value, (err, result) -> if err? + console.log err if err.error is 'username-invalid' username.invalid = true else diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 6489faee0b3..f140d164c4e 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -106,3 +106,8 @@ Accounts.validateLoginAttempt (login) -> RocketChat.callbacks.run 'afterValidateLogin', login return true + +Accounts.validateNewUser (user) -> + if RocketChat.settings.get('Accounts_Registration_AuthenticationServices_Enabled') is false and user.services? + throw new Meteor.Error 'registration-disabled-authentication-services', 'User registration is disabled for authentication services' + return true diff --git a/server/methods/getUsernameSuggestion.coffee b/server/methods/getUsernameSuggestion.coffee index e5c2aa9c5e9..ef51bc33dd4 100644 --- a/server/methods/getUsernameSuggestion.coffee +++ b/server/methods/getUsernameSuggestion.coffee @@ -9,7 +9,7 @@ usernameIsAvaliable = (username) -> if username is 'all' return false - return not RocketChat.models.Users.findOneByUsername({$regex : new RegExp(username, "i") }) + return not RocketChat.models.Users.findOneByUsername({$regex : new RegExp("^" + username + "$", "i") }) @generateSuggestion = (user) -> usernames = [] diff --git a/server/methods/registerUser.coffee b/server/methods/registerUser.coffee index 4a73cd73167..08513c97b3a 100644 --- a/server/methods/registerUser.coffee +++ b/server/methods/registerUser.coffee @@ -1,5 +1,8 @@ Meteor.methods registerUser: (formData) -> + if RocketChat.settings.get('Accounts_RegistrationForm') is 'Disabled' + throw new Meteor.Error 'registration-disabled', 'User registration is disabled' + userData = email: formData.email password: formData.pass -- GitLab From 7e0d8e06711a1c1ea7f6d253feef6cb3cb3f25a4 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 27 Nov 2015 20:23:58 -0200 Subject: [PATCH 0598/1338] meteor update --- .meteor/versions | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 2231d744104..44db73cc5ff 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -7,7 +7,7 @@ accounts-oauth@1.1.8 accounts-password@1.1.4 accounts-twitter@1.0.6 alanning:roles@1.2.14 -aldeed:simple-schema@1.3.3 +aldeed:simple-schema@1.4.0 arunoda:streams@0.1.17 autoupdate@1.2.4 babel-compiler@5.8.24_1 @@ -58,8 +58,8 @@ jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 jquery@1.11.4 -kadira:blaze-layout@2.2.0 -kadira:flow-router@2.9.0 +kadira:blaze-layout@2.3.0 +kadira:flow-router@2.10.0 kenton:accounts-sandstorm@0.1.8 kevohagan:sweetalert@1.0.0 konecty:autolinker@1.0.3 @@ -75,6 +75,7 @@ livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 matb33:collection-hooks@0.8.1 +mdg:validation-error@0.1.0 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 -- GitLab From 2d1d2e6a6fdafb6f2a687ca64b1c65c558f6693c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 27 Nov 2015 20:55:58 -0200 Subject: [PATCH 0599/1338] fix bug emergency --- .../rocketchat-lib/client/lib/roomTypes.coffee | 18 +++++++++--------- .../rocketchat-livechat/app/.meteor/versions | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index f292dceba09..2e3773a8122 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -4,15 +4,15 @@ RocketChat.roomTypes = new class 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' + # 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 diff --git a/packages/rocketchat-livechat/app/.meteor/versions b/packages/rocketchat-livechat/app/.meteor/versions index 6240ee123eb..2ca4cd982ac 100644 --- a/packages/rocketchat-livechat/app/.meteor/versions +++ b/packages/rocketchat-livechat/app/.meteor/versions @@ -13,7 +13,7 @@ caching-html-compiler@1.0.2 callback-hook@1.0.4 check@1.1.0 coffeescript@1.0.11 -cosmos:browserify@0.9.1 +cosmos:browserify@0.9.2 ddp@1.2.2 ddp-client@1.2.1 ddp-common@1.2.2 @@ -31,8 +31,8 @@ htmljs@1.0.5 http@1.1.1 id-map@1.0.4 jquery@1.11.4 -kadira:blaze-layout@2.2.0 -kadira:flow-router@2.9.0 +kadira:blaze-layout@2.3.0 +kadira:flow-router@2.10.0 konecty:nrr@2.0.2 less@2.5.1 livedata@1.0.15 -- GitLab From 60bef0aa625f2262db74ca37ad2c51902b14149f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 27 Nov 2015 21:21:25 -0200 Subject: [PATCH 0600/1338] fir broken migration --- server/startup/migrations/v19.coffee | 3 +-- server/startup/migrations/v23.coffee | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 server/startup/migrations/v23.coffee diff --git a/server/startup/migrations/v19.coffee b/server/startup/migrations/v19.coffee index db336f08249..9450ed37095 100644 --- a/server/startup/migrations/v19.coffee +++ b/server/startup/migrations/v19.coffee @@ -20,9 +20,8 @@ Meteor.startup -> # Add 'moderator' role to channel/group creators rooms = RocketChat.models.Rooms.findByTypes(['c','p']).fetch() - _.each( rooms, (room) -> + _.each rooms, (room) -> creator = room?.u?._id if creator RocketChat.authz.addUsersToRoles( creator, ['moderator'], room._id) console.log "Add #{room.u.username} to 'moderator' role".green - ) diff --git a/server/startup/migrations/v23.coffee b/server/startup/migrations/v23.coffee new file mode 100644 index 00000000000..aaed69fe4dd --- /dev/null +++ b/server/startup/migrations/v23.coffee @@ -0,0 +1,6 @@ +Meteor.startup -> + Migrations.add + version: 22 + up: -> + RocketChat.models.Settings.remove { _id: 'Accounts_denyUnverifiedEmails' } + console.log 'Deleting not used setting Accounts_denyUnverifiedEmails' -- GitLab From 471166515868ca24f2ad262eb842cf1c7e57467c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 27 Nov 2015 21:35:28 -0200 Subject: [PATCH 0601/1338] fix broken migration --- server/startup/migrations/v23.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/startup/migrations/v23.coffee b/server/startup/migrations/v23.coffee index aaed69fe4dd..303f024acca 100644 --- a/server/startup/migrations/v23.coffee +++ b/server/startup/migrations/v23.coffee @@ -1,6 +1,6 @@ Meteor.startup -> Migrations.add - version: 22 + version: 23 up: -> RocketChat.models.Settings.remove { _id: 'Accounts_denyUnverifiedEmails' } console.log 'Deleting not used setting Accounts_denyUnverifiedEmails' -- GitLab From ddd1794df04e31fa7f94b4796acb4339f1b57fdd Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 27 Nov 2015 22:00:47 -0200 Subject: [PATCH 0602/1338] fix broken migration 19 --- server/startup/migrations/v19.coffee | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server/startup/migrations/v19.coffee b/server/startup/migrations/v19.coffee index 9450ed37095..8658bf3f740 100644 --- a/server/startup/migrations/v19.coffee +++ b/server/startup/migrations/v19.coffee @@ -23,5 +23,10 @@ Meteor.startup -> _.each rooms, (room) -> creator = room?.u?._id if creator - RocketChat.authz.addUsersToRoles( creator, ['moderator'], room._id) - console.log "Add #{room.u.username} to 'moderator' role".green + if Meteor.users.findOne({_id: creator}) + RocketChat.authz.addUsersToRoles( creator, ['moderator'], room._id) + console.log "Add #{room.u.username} to 'moderator' role".green + else + RocketChat.models.Subscriptions.removeByRoomId room._id + RocketChat.models.Messages.removeByRoomId room._id + RocketChat.models.Rooms.removeById room._id -- GitLab From 7ec70185cb777f70fe5066db3ff50ae59c1c4235 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Sun, 29 Nov 2015 00:32:23 -0200 Subject: [PATCH 0603/1338] permissions manager page --- .../client/route.coffee | 7 +++++++ .../client/startup.coffee | 6 ++++++ .../client/views/permissions.coffee | 21 +++++++++++++++++++ .../client/views/permissions.html | 20 ++++++++++++++++++ packages/rocketchat-authorization/package.js | 10 +++++++++ .../server/publications/roles.coffee | 7 +++++++ .../server/startup.coffee | 3 +++ 7 files changed, 74 insertions(+) create mode 100644 packages/rocketchat-authorization/client/route.coffee create mode 100644 packages/rocketchat-authorization/client/views/permissions.coffee create mode 100644 packages/rocketchat-authorization/client/views/permissions.html create mode 100644 packages/rocketchat-authorization/server/publications/roles.coffee diff --git a/packages/rocketchat-authorization/client/route.coffee b/packages/rocketchat-authorization/client/route.coffee new file mode 100644 index 00000000000..a6afb9ede6a --- /dev/null +++ b/packages/rocketchat-authorization/client/route.coffee @@ -0,0 +1,7 @@ +FlowRouter.route '/admin/permissions', + name: 'rocket-permissions' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: 'Permissions' + pageTemplate: 'permissions' diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 84ab0f39dca..133b0380927 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -1 +1,7 @@ RocketChat.authz.subscription = Meteor.subscribe 'permissions' + +RocketChat.AdminBox.addOption + href: 'rocket-permissions' + i18nLabel: 'Rocket_Permissions' + permissionGranted: -> + return RocketChat.authz.hasAllPermission('access-rocket-permissions') diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee new file mode 100644 index 00000000000..b556665fc40 --- /dev/null +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -0,0 +1,21 @@ +Template.permissions.helpers + + role: -> + return Roles.getAllRoles() + + permission: -> + return ChatPermissions.find() + + granted: (roles) -> + if roles? + return 'YES' if roles.indexOf(@name) isnt -1 + + +Template.permissions.onCreated -> + # @roles = [] + # @permissions = [] + # @permissionByRole = {} + + @subscribe 'roles' + + # ChatPermissions diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html new file mode 100644 index 00000000000..e39ac39d72c --- /dev/null +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -0,0 +1,20 @@ +<template name="permissions"> + <h1>permission</h1> + + <table border="1"> + <tr> + <td> </td> + {{#each role}} + <td>{{name}}</td> + {{/each}} + </tr> + {{#each permission}} + <tr> + <td>{{_id}}</td> + {{#each role}} + <td>{{granted ../roles ../_id}}</td> + {{/each}} + </tr> + {{/each}} + </table> +</template> diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 9d349afef96..1e5ff91393d 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -15,6 +15,9 @@ Package.onUse(function(api) { 'alanning:roles@1.2.12' ]); + api.use('mongo', 'client'); + api.use('kadira:flow-router', 'client'); + api.use('templating', 'client'); api.addFiles('lib/rocketchat.coffee', ['server','client']); @@ -23,6 +26,12 @@ Package.onUse(function(api) { api.addFiles('client/hasPermission.coffee', ['client']); api.addFiles('client/hasRole.coffee', ['client']); + api.addFiles('client/route.coffee', ['client']); + + // views + api.addFiles('client/views/permissions.html', ['client']); + api.addFiles('client/views/permissions.coffee', ['client']); + api.addFiles('server/models/Permissions.coffee', ['server']); @@ -35,6 +44,7 @@ Package.onUse(function(api) { api.addFiles('server/functions/hasRole.coffee', ['server']); api.addFiles('server/functions/removeUsersFromRoles.coffee', ['server']); + api.addFiles('server/publications/roles.coffee', 'server'); api.addFiles('server/publication.coffee', ['server']); api.addFiles('server/startup.coffee', ['server']); }); diff --git a/packages/rocketchat-authorization/server/publications/roles.coffee b/packages/rocketchat-authorization/server/publications/roles.coffee new file mode 100644 index 00000000000..4b2dc50d8ae --- /dev/null +++ b/packages/rocketchat-authorization/server/publications/roles.coffee @@ -0,0 +1,7 @@ +Meteor.publish 'roles', -> + unless @userId + return @ready() + + # @TODO validate permission + + return RocketChat.authz.getRoles() diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index f27b9b10303..149b63b2f1b 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -86,6 +86,9 @@ Meteor.startup -> { _id: 'view-d-room', roles : ['admin', 'site-moderator', 'user']} + + { _id: 'access-rocket-permissions', + roles : ['admin']} ] #alanning:roles -- GitLab From db30aa7e2a9cf44a21d78611b7815e907508659d Mon Sep 17 00:00:00 2001 From: programster <stuart.page@irap.org> Date: Sun, 29 Nov 2015 16:47:07 +0000 Subject: [PATCH 0604/1338] * Removing --replSet rs0 which causes issue as described here: https://github.com/RocketChat/Rocket.Chat/issues/1472 * Updating the mongo database datadir location so that if somebody decides to use volumes in order to maintain state, it works. I'm guessing mongodb changed it's default location from "mongo" to "db" and nobody noticed. --- docker-compose.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index be58250aa93..bab5c04da7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,9 @@ mongo: image: mongo # volumes: -# - ./data/runtime/mongo:/data/mongo +# - ./data/runtime/db:/data/db # - ./data/dump:/dump - command: mongod --smallfiles --replSet rs0 --oplogSize 128 + command: mongod --smallfiles --oplogSize 128 rocketchat: image: rocketchat/rocket.chat:develop @@ -19,4 +19,3 @@ rocketchat: - mongo:mongo ports: - 3000:3000 - -- GitLab From 8dd046b5a5184adbdb6da8f59533785133979e87 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 30 Nov 2015 01:22:36 -0500 Subject: [PATCH 0605/1338] Fix place holder format for SMTP sender address Most SMTP servers will only accept valid email address for sender. #766 --- packages/rocketchat-lib/server/startup/settings.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index fec49f16d2d..71c8244136c 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -71,7 +71,7 @@ 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: 'Name <email@domain>' } +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' } -- GitLab From 388f27271aa0771472cd913fd73dbf75eac88cd5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 09:44:12 -0200 Subject: [PATCH 0606/1338] new route to edit roles --- .../client/route.coffee | 16 ++++++++---- .../client/views/permissions.html | 4 +-- .../client/views/permissionsRole.coffee | 25 +++++++++++++++++++ .../client/views/permissionsRole.html | 3 +++ packages/rocketchat-authorization/package.js | 8 ++++-- .../server/publications/usersInRole.coffee | 7 ++++++ 6 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 packages/rocketchat-authorization/client/views/permissionsRole.coffee create mode 100644 packages/rocketchat-authorization/client/views/permissionsRole.html create mode 100644 packages/rocketchat-authorization/server/publications/usersInRole.coffee diff --git a/packages/rocketchat-authorization/client/route.coffee b/packages/rocketchat-authorization/client/route.coffee index a6afb9ede6a..1006cc9aff2 100644 --- a/packages/rocketchat-authorization/client/route.coffee +++ b/packages/rocketchat-authorization/client/route.coffee @@ -1,7 +1,13 @@ -FlowRouter.route '/admin/permissions', +FlowRouter.route '/admin/permissions/:name?', name: 'rocket-permissions' action: (params) -> - BlazeLayout.render 'main', - center: 'pageContainer' - pageTitle: 'Permissions' - pageTemplate: 'permissions' + if params?.name? + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: t('Role_Editing') + pageTemplate: 'permissionsRole' + else + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: t('Permissions') + pageTemplate: 'permissions' diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index e39ac39d72c..fab27a68a6f 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -1,11 +1,11 @@ <template name="permissions"> - <h1>permission</h1> + <h1>{{_ "Permissions"}}</h1> <table border="1"> <tr> <td> </td> {{#each role}} - <td>{{name}}</td> + <td>{{name}} <a href="{{pathFor "rocket-permissions" name=name}}"><i class="icon-edit"></i></a></td> {{/each}} </tr> {{#each permission}} diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee new file mode 100644 index 00000000000..9cfda004f95 --- /dev/null +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -0,0 +1,25 @@ +window.rolee = Roles + +Template.permissionsRole.helpers + + role: -> + return Roles.getAllRoles() + + permission: -> + return ChatPermissions.find() + + granted: (roles) -> + if roles? + return 'YES' if roles.indexOf(@name) isnt -1 + + +Template.permissionsRole.onCreated -> + # @roles = [] + # @permissions = [] + # @permissionByRole = {} + + console.log Roles + + @subscribe 'userInRole', FlowRouter.getParam('name') + + # ChatPermissions diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html new file mode 100644 index 00000000000..94523a43e58 --- /dev/null +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -0,0 +1,3 @@ +<template name="permissionsRole"> + <h2>lero</h2> +</template> diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 1e5ff91393d..07d12fd426b 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -31,7 +31,8 @@ Package.onUse(function(api) { // views api.addFiles('client/views/permissions.html', ['client']); api.addFiles('client/views/permissions.coffee', ['client']); - + api.addFiles('client/views/permissionsRole.html', ['client']); + api.addFiles('client/views/permissionsRole.coffee', ['client']); api.addFiles('server/models/Permissions.coffee', ['server']); @@ -44,7 +45,10 @@ Package.onUse(function(api) { api.addFiles('server/functions/hasRole.coffee', ['server']); api.addFiles('server/functions/removeUsersFromRoles.coffee', ['server']); - api.addFiles('server/publications/roles.coffee', 'server'); + // publications api.addFiles('server/publication.coffee', ['server']); + api.addFiles('server/publications/roles.coffee', 'server'); + api.addFiles('server/publications/usersInRole.coffee', 'server'); + api.addFiles('server/startup.coffee', ['server']); }); diff --git a/packages/rocketchat-authorization/server/publications/usersInRole.coffee b/packages/rocketchat-authorization/server/publications/usersInRole.coffee new file mode 100644 index 00000000000..1fbdc57cad5 --- /dev/null +++ b/packages/rocketchat-authorization/server/publications/usersInRole.coffee @@ -0,0 +1,7 @@ +Meteor.publish 'usersInRole', (roleName) -> + unless @userId + return @ready() + + # @TODO validate permission + + return RocketChat.authz.getUsersInRole roleName -- GitLab From 377c4a0e68a6da19e601bed1a4b6095519e03616 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 10:54:13 -0200 Subject: [PATCH 0607/1338] editing roles --- .../client/views/permissions.html | 2 +- .../client/views/permissionsRole.coffee | 70 ++++++++++++++++--- .../client/views/permissionsRole.html | 45 +++++++++++- packages/rocketchat-authorization/package.js | 5 ++ .../server/methods/addUserToRole.coffee | 17 +++++ .../server/methods/removeUserFromRole.coffee | 16 +++++ .../server/methods/saveRole.coffee | 9 +++ 7 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 packages/rocketchat-authorization/server/methods/addUserToRole.coffee create mode 100644 packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee create mode 100644 packages/rocketchat-authorization/server/methods/saveRole.coffee diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index fab27a68a6f..7a966a0ac89 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -5,7 +5,7 @@ <tr> <td> </td> {{#each role}} - <td>{{name}} <a href="{{pathFor "rocket-permissions" name=name}}"><i class="icon-edit"></i></a></td> + <td title="{{description}}">{{name}} <a href="{{pathFor "rocket-permissions" name=name}}"><i class="icon-edit"></i></a></td> {{/each}} </tr> {{#each permission}} diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 9cfda004f95..95886e01153 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -1,17 +1,70 @@ window.rolee = Roles Template.permissionsRole.helpers - role: -> - return Roles.getAllRoles() + return Meteor.roles.findOne { name: FlowRouter.getParam('name') } + + userInRole: -> + return Roles.getUsersInRole(FlowRouter.getParam('name')) + +Template.permissionsRole.events + + 'click .remove-user': (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 'authorization:removeUserFromRole', FlowRouter.getParam('name'), @username, (error, result) -> + if error + return toastr.error t(error.reason or error.error) + + swal + title: t('Removed') + text: t('User_removed') + type: 'success' + timer: 1000 + showConfirmButton: false + + 'submit #form-role': (e, instance) -> + e.preventDefault() + + oldBtnValue = e.currentTarget.elements['save'].value + + e.currentTarget.elements['save'].value = t('Saving') + + Meteor.call 'authorization:saveRole', @_id, { description: e.currentTarget.elements['description'].value }, (error, result) -> + e.currentTarget.elements['save'].value = oldBtnValue + if error + return toastr.error t(error.reason || error.error) + + toastr.success t('Saved') + e.currentTarget.reset() + + 'submit #form-users': (e, instance) -> + e.preventDefault() + + if e.currentTarget.elements['username'].value.trim() is '' + return toastr.error t('Please_fill_a_username') + + oldBtnValue = e.currentTarget.elements['add'].value - permission: -> - return ChatPermissions.find() + e.currentTarget.elements['add'].value = t('Saving') - granted: (roles) -> - if roles? - return 'YES' if roles.indexOf(@name) isnt -1 + Meteor.call 'authorization:addUserToRole', FlowRouter.getParam('name'), e.currentTarget.elements['username'].value, (error, result) -> + e.currentTarget.elements['add'].value = oldBtnValue + if error + return toastr.error t(error.reason || error.error) + toastr.success t('User_added') + e.currentTarget.reset() Template.permissionsRole.onCreated -> # @roles = [] @@ -20,6 +73,7 @@ Template.permissionsRole.onCreated -> console.log Roles - @subscribe 'userInRole', FlowRouter.getParam('name') + @subscribe 'roles', FlowRouter.getParam('name') + @subscribe 'usersInRole', FlowRouter.getParam('name') # ChatPermissions diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index 94523a43e58..57a65990a65 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -1,3 +1,46 @@ <template name="permissionsRole"> - <h2>lero</h2> + <a href="{{pathFor "rocket-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> + + {{#with role}} + <form id="form-role" class="inline"> + <label>{{_ "Role"}}</label>: <span>{{name}}</span><br> + <label>{{_ "Description"}}</label>: <input type="text" name="description" value="{{description}}"> + <button name="save" class="button primary">{{_ "Save"}}</button> + </form> + {{/with}} + + <h2>{{_ "Users_in_role"}}</h2> + <form id="form-users" class="inline"> + <label>{{_ "Add_user"}}</label> + <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> + <button name="add" class="button primary">{{_ "Add"}}</button> + </form> + <div class="list"> + <table> + <thead> + <tr> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> + <th> </th> + </tr> + </thead> + <tbody> + {{#each userInRole}} + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> </template> diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 07d12fd426b..2f03cc224ca 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -50,5 +50,10 @@ Package.onUse(function(api) { api.addFiles('server/publications/roles.coffee', 'server'); api.addFiles('server/publications/usersInRole.coffee', 'server'); + // methods + api.addFiles('server/methods/addUserToRole.coffee', 'server'); + api.addFiles('server/methods/removeUserFromRole.coffee', 'server'); + api.addFiles('server/methods/saveRole.coffee', 'server'); + api.addFiles('server/startup.coffee', ['server']); }); diff --git a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee new file mode 100644 index 00000000000..442f8f4ea9b --- /dev/null +++ b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee @@ -0,0 +1,17 @@ +Meteor.methods + 'authorization:addUserToRole': (roleName, username) -> + if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-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 } } + + if not user?._id? + throw new Meteor.Error 'user-not-found' + + # return Roles.addUsersToRoles user._id, roleName + return Roles.addUsersToRoles user._id, roleName, Roles.GLOBAL_GROUP diff --git a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee new file mode 100644 index 00000000000..bcb603d6dd9 --- /dev/null +++ b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee @@ -0,0 +1,16 @@ +Meteor.methods + 'authorization:removeUserFromRole': (roleName, username) -> + if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-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' + + user = Meteor.users.findOne { username: username }, { fields: { _id: 1 } } + + if not user?._id? + throw new Meteor.Error 'user-not-found' + + return Roles.removeUsersFromRoles user._id, roleName, Roles.GLOBAL_GROUP diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee new file mode 100644 index 00000000000..6c4e16e954f --- /dev/null +++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee @@ -0,0 +1,9 @@ +Meteor.methods + 'authorization:saveRole': (_id, roleData) -> + if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + throw new Meteor.Error "not-authorized" + + console.log '[methods] authorization:saveRole -> '.green, 'arguments:', arguments + + if roleData?.description? + return Meteor.roles.update _id, { $set: { description: roleData.description } } -- GitLab From 91125cc356a676651987c8bf2c8bcc9eec992536 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 10:54:23 -0200 Subject: [PATCH 0608/1338] authz publications security --- .../rocketchat-authorization/server/publications/roles.coffee | 3 ++- .../server/publications/usersInRole.coffee | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-authorization/server/publications/roles.coffee b/packages/rocketchat-authorization/server/publications/roles.coffee index 4b2dc50d8ae..6a2c35852d4 100644 --- a/packages/rocketchat-authorization/server/publications/roles.coffee +++ b/packages/rocketchat-authorization/server/publications/roles.coffee @@ -2,6 +2,7 @@ Meteor.publish 'roles', -> unless @userId return @ready() - # @TODO validate permission + if not RocketChat.authz.hasPermission @userId, 'access-rocket-permissions' + throw new Meteor.Error "not-authorized" return RocketChat.authz.getRoles() diff --git a/packages/rocketchat-authorization/server/publications/usersInRole.coffee b/packages/rocketchat-authorization/server/publications/usersInRole.coffee index 1fbdc57cad5..089cea8e671 100644 --- a/packages/rocketchat-authorization/server/publications/usersInRole.coffee +++ b/packages/rocketchat-authorization/server/publications/usersInRole.coffee @@ -2,6 +2,7 @@ Meteor.publish 'usersInRole', (roleName) -> unless @userId return @ready() - # @TODO validate permission + if not RocketChat.authz.hasPermission @userId, 'access-rocket-permissions' + throw new Meteor.Error "not-authorized" return RocketChat.authz.getUsersInRole roleName -- GitLab From c8d3fda1d227f4cb0e175b1b267140d736308fd9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 30 Nov 2015 11:12:48 -0200 Subject: [PATCH 0609/1338] Fix registration when allow registration from services is disabled --- packages/rocketchat-lib/server/functions/settings.coffee | 2 ++ server/lib/accounts.coffee | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index eede3324732..02ade134fca 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -13,6 +13,7 @@ RocketChat.settings.add = (_id, value, options = {}) -> options.packageValue = value options.valueSource = 'packageValue' options.ts = new Date + options.hidden = false if process?.env?[_id]? value = process.env[_id] @@ -55,6 +56,7 @@ RocketChat.settings.addGroup = (_id, options = {}) -> options.i18nDescription = "#{_id}_Description" options.ts = new Date + options.hidden = false return RocketChat.models.Settings.upsert { _id: _id }, $set: options diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index f140d164c4e..a6d678fcb4a 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -108,6 +108,6 @@ Accounts.validateLoginAttempt (login) -> return true Accounts.validateNewUser (user) -> - if RocketChat.settings.get('Accounts_Registration_AuthenticationServices_Enabled') is false and user.services? + if RocketChat.settings.get('Accounts_Registration_AuthenticationServices_Enabled') is false and RocketChat.settings.get('LDAP_Enable') is false and not user.services?.password? throw new Meteor.Error 'registration-disabled-authentication-services', 'User registration is disabled for authentication services' return true -- GitLab From e44f81858d871dba9f99225848a6cb9d1fa09e1f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 30 Nov 2015 15:12:04 -0200 Subject: [PATCH 0610/1338] Renamed RocketChatVersion to RocketChat.Version to comply with standards being used. --- packages/rocketchat-version/plugin/compile-version.coffee | 2 +- server/restapi/restapi.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-version/plugin/compile-version.coffee b/packages/rocketchat-version/plugin/compile-version.coffee index a857ae0f703..89a87d1bab1 100644 --- a/packages/rocketchat-version/plugin/compile-version.coffee +++ b/packages/rocketchat-version/plugin/compile-version.coffee @@ -39,7 +39,7 @@ class VersionCompiler output.branch = result.replace('\n', '') output = """ - RocketChatVersion = #{JSON.stringify(output, null, 4)} + RocketChat.Version = #{JSON.stringify(output, null, 4)} """ file.addJavaScript({ data: output, path: file.getPathInPackage() + '.js' }); diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index 36324fcb3da..a91245053c6 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -5,7 +5,7 @@ Api = new Restivus Api.addRoute 'info', authRequired: false, - get: -> RocketChatVersion + get: -> RocketChat.Version Api.addRoute 'version', authRequired: false, -- GitLab From 300feb7ad9e95690de3c7d111fbd402b5ac62f32 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 15:23:37 -0200 Subject: [PATCH 0611/1338] role creation --- .../client/route.coffee | 32 +++++--- .../client/views/permissions.html | 6 +- .../client/views/permissionsRole.coffee | 23 +++++- .../client/views/permissionsRole.html | 79 +++++++++++-------- .../server/methods/saveRole.coffee | 12 ++- 5 files changed, 99 insertions(+), 53 deletions(-) diff --git a/packages/rocketchat-authorization/client/route.coffee b/packages/rocketchat-authorization/client/route.coffee index 1006cc9aff2..bdc42a4d818 100644 --- a/packages/rocketchat-authorization/client/route.coffee +++ b/packages/rocketchat-authorization/client/route.coffee @@ -1,13 +1,23 @@ -FlowRouter.route '/admin/permissions/:name?', +FlowRouter.route '/admin/permissions', name: 'rocket-permissions' action: (params) -> - if params?.name? - BlazeLayout.render 'main', - center: 'pageContainer' - pageTitle: t('Role_Editing') - pageTemplate: 'permissionsRole' - else - BlazeLayout.render 'main', - center: 'pageContainer' - pageTitle: t('Permissions') - pageTemplate: 'permissions' + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: t('Permissions') + pageTemplate: 'permissions' + +FlowRouter.route '/admin/permissions/:name?/edit', + name: 'rocket-permissions-edit' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: t('Role_Editing') + pageTemplate: 'permissionsRole' + +FlowRouter.route '/admin/permissions/new', + name: 'rocket-permissions-new' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: t('Role_Editing') + pageTemplate: 'permissionsRole' diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index 7a966a0ac89..a7bdd5eff07 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -1,18 +1,20 @@ <template name="permissions"> <h1>{{_ "Permissions"}}</h1> + <a href="{{pathFor "rocket-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> + <table border="1"> <tr> <td> </td> {{#each role}} - <td title="{{description}}">{{name}} <a href="{{pathFor "rocket-permissions" name=name}}"><i class="icon-edit"></i></a></td> + <td title="{{description}}"><a href="{{pathFor "rocket-permissions-edit" name=name}}">{{name}}</a></td> {{/each}} </tr> {{#each permission}} <tr> <td>{{_id}}</td> {{#each role}} - <td>{{granted ../roles ../_id}}</td> + <td><input type="checkbox" name="perm[{{_id}}][{{../_id}}]" value="1" checked="{{granted ../roles ../_id}}"></td> {{/each}} </tr> {{/each}} diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 95886e01153..cf30e0a7e54 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -2,11 +2,18 @@ window.rolee = Roles Template.permissionsRole.helpers role: -> - return Meteor.roles.findOne { name: FlowRouter.getParam('name') } + return Meteor.roles.findOne({ name: FlowRouter.getParam('name') }) or {} userInRole: -> return Roles.getUsersInRole(FlowRouter.getParam('name')) + editing: -> + return FlowRouter.getParam('name')? + + emailAddress: -> + if @emails?.length > 0 + return @emails[0].address + Template.permissionsRole.events 'click .remove-user': (e, instance) -> @@ -40,13 +47,23 @@ Template.permissionsRole.events e.currentTarget.elements['save'].value = t('Saving') - Meteor.call 'authorization:saveRole', @_id, { description: e.currentTarget.elements['description'].value }, (error, result) -> + roleData = + description: e.currentTarget.elements['description'].value + + if not @_id? + roleData.name = e.currentTarget.elements['name'].value + + Meteor.call 'authorization:saveRole', @_id, roleData, (error, result) => e.currentTarget.elements['save'].value = oldBtnValue if error return toastr.error t(error.reason || error.error) - toastr.success t('Saved') e.currentTarget.reset() + toastr.success t('Saved') + + if not @_id? + FlowRouter.go 'rocket-permissions-edit', { name: roleData.name } + 'submit #form-users': (e, instance) -> e.preventDefault() diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index 57a65990a65..60e31198358 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -3,44 +3,53 @@ {{#with role}} <form id="form-role" class="inline"> - <label>{{_ "Role"}}</label>: <span>{{name}}</span><br> - <label>{{_ "Description"}}</label>: <input type="text" name="description" value="{{description}}"> + <label>{{_ "Role"}}</label>: + {{#if editing}} + <span>{{name}}</span> + {{else}} + <input type="text" name="name" value=""> + {{/if}} + <br> + <label>{{_ "Description"}}</label>: + <input type="text" name="description" value="{{description}}"> <button name="save" class="button primary">{{_ "Save"}}</button> </form> {{/with}} - <h2>{{_ "Users_in_role"}}</h2> - <form id="form-users" class="inline"> - <label>{{_ "Add_user"}}</label> - <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> - <button name="add" class="button primary">{{_ "Add"}}</button> - </form> - <div class="list"> - <table> - <thead> - <tr> - <th> </th> - <th width="34%">{{_ "Name"}}</th> - <th width="33%">{{_ "Username"}}</th> - <th width="33%">{{_ "E-mail"}}</th> - <th> </th> - </tr> - </thead> - <tbody> - {{#each userInRole}} - <tr class="user-info" data-id="{{_id}}"> - <td> - <div class="user-image status-{{status}}"> - {{> avatar username=username}} - </div> - </td> - <td>{{name}}</td> - <td>{{username}}</td> - <td>{{emailAddress}}</td> - <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + {{#if editing}} + <h2>{{_ "Users_in_role"}}</h2> + <form id="form-users" class="inline"> + <label>{{_ "Add_user"}}</label> + <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> + <button name="add" class="button primary">{{_ "Add"}}</button> + </form> + <div class="list"> + <table> + <thead> + <tr> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> + <th> </th> </tr> - {{/each}} - </tbody> - </table> - </div> + </thead> + <tbody> + {{#each userInRole}} + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> + {{/if}} </template> diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee index 6c4e16e954f..0b6ae516bc9 100644 --- a/packages/rocketchat-authorization/server/methods/saveRole.coffee +++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee @@ -5,5 +5,13 @@ Meteor.methods console.log '[methods] authorization:saveRole -> '.green, 'arguments:', arguments - if roleData?.description? - return Meteor.roles.update _id, { $set: { description: roleData.description } } + 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 -- GitLab From 273d9b80c34a25f0eb1f31a781ef58e159a1751b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 15:24:02 -0200 Subject: [PATCH 0612/1338] users in role pagination support --- .../server/functions/getUsersInRole.coffee | 6 +++--- .../server/publications/usersInRole.coffee | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee index d5193830a0a..ee416c3e902 100644 --- a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee +++ b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee @@ -1,6 +1,6 @@ -RocketChat.authz.getUsersInRole = (roleName, scope) -> +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) \ No newline at end of file + + return Roles.getUsersInRole(roleName, scope, options) diff --git a/packages/rocketchat-authorization/server/publications/usersInRole.coffee b/packages/rocketchat-authorization/server/publications/usersInRole.coffee index 089cea8e671..64ff46b0c11 100644 --- a/packages/rocketchat-authorization/server/publications/usersInRole.coffee +++ b/packages/rocketchat-authorization/server/publications/usersInRole.coffee @@ -1,8 +1,15 @@ -Meteor.publish 'usersInRole', (roleName) -> +Meteor.publish 'usersInRole', (roleName, page = 1) -> unless @userId return @ready() if not RocketChat.authz.hasPermission @userId, 'access-rocket-permissions' throw new Meteor.Error "not-authorized" - return RocketChat.authz.getUsersInRole roleName + itemsPerPage = 20 + pagination = + sort: + name: 1 + limit: itemsPerPage + offset: itemsPerPage * (page - 1) + + return RocketChat.authz.getUsersInRole roleName, null, pagination -- GitLab From e87095558c4277dbc68a219b32fe3656e1407e31 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 30 Nov 2015 15:28:22 -0200 Subject: [PATCH 0613/1338] Renamed RocketChat.Version to RocketChat.Info --- packages/rocketchat-version/plugin/compile-version.coffee | 4 ++-- rocketchat.version => rocketchat.info | 0 server/restapi/restapi.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename rocketchat.version => rocketchat.info (100%) diff --git a/packages/rocketchat-version/plugin/compile-version.coffee b/packages/rocketchat-version/plugin/compile-version.coffee index 89a87d1bab1..02b38e3de0c 100644 --- a/packages/rocketchat-version/plugin/compile-version.coffee +++ b/packages/rocketchat-version/plugin/compile-version.coffee @@ -2,7 +2,7 @@ exec = Npm.require('child_process').exec os = Npm.require('os') Plugin.registerCompiler - extensions: ['version'] + extensions: ['info'] , -> new VersionCompiler() @@ -39,7 +39,7 @@ class VersionCompiler output.branch = result.replace('\n', '') output = """ - RocketChat.Version = #{JSON.stringify(output, null, 4)} + RocketChat.Info = #{JSON.stringify(output, null, 4)} """ file.addJavaScript({ data: output, path: file.getPathInPackage() + '.js' }); diff --git a/rocketchat.version b/rocketchat.info similarity index 100% rename from rocketchat.version rename to rocketchat.info diff --git a/server/restapi/restapi.coffee b/server/restapi/restapi.coffee index a91245053c6..fa805884417 100644 --- a/server/restapi/restapi.coffee +++ b/server/restapi/restapi.coffee @@ -5,7 +5,7 @@ Api = new Restivus Api.addRoute 'info', authRequired: false, - get: -> RocketChat.Version + get: -> RocketChat.Info Api.addRoute 'version', authRequired: false, -- GitLab From 1c9da633e102aa9533b76dcefdec6d507acb56cd Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 16:40:33 -0200 Subject: [PATCH 0614/1338] delete role support --- .../client/views/permissionsRole.coffee | 14 ++++++++++++++ .../client/views/permissionsRole.html | 6 ++++++ packages/rocketchat-authorization/package.js | 1 + .../server/methods/deleteRole.coffee | 18 ++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 packages/rocketchat-authorization/server/methods/deleteRole.coffee diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index cf30e0a7e54..c079659410f 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -83,6 +83,20 @@ Template.permissionsRole.events toastr.success t('User_added') e.currentTarget.reset() + 'click .delete-role': (e, instance) -> + e.preventDefault() + + if @protected + return toastr.error t('Cannot_delete_an_protected_role') + + Meteor.call 'authorization:deleteRole', @_id, (error, result) -> + if error + return toastr.error t(error.reason || error.error) + + toastr.success t('Role_removed') + + FlowRouter.go 'rocket-permissions' + Template.permissionsRole.onCreated -> # @roles = [] # @permissions = [] diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index 60e31198358..1fb609282d9 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -12,7 +12,13 @@ <br> <label>{{_ "Description"}}</label>: <input type="text" name="description" value="{{description}}"> + <br> + <button name="save" class="button primary">{{_ "Save"}}</button> + + {{#unless protected}} + <button name="delete" class="button red delete-role">{{_ "Delete"}}</button> + {{/unless}} </form> {{/with}} diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 2f03cc224ca..7e1b6412670 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -52,6 +52,7 @@ Package.onUse(function(api) { // methods api.addFiles('server/methods/addUserToRole.coffee', 'server'); + api.addFiles('server/methods/deleteRole.coffee', 'server'); api.addFiles('server/methods/removeUserFromRole.coffee', 'server'); api.addFiles('server/methods/saveRole.coffee', 'server'); diff --git a/packages/rocketchat-authorization/server/methods/deleteRole.coffee b/packages/rocketchat-authorization/server/methods/deleteRole.coffee new file mode 100644 index 00000000000..0b991acd41d --- /dev/null +++ b/packages/rocketchat-authorization/server/methods/deleteRole.coffee @@ -0,0 +1,18 @@ +Meteor.methods + 'authorization:deleteRole': (_id) -> + if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + throw new Meteor.Error "not-authorized" + + console.log '[methods] authorization:deleteRole -> '.green, 'arguments:', arguments + + role = Meteor.roles.findOne _id + + if role.protected + throw new Meteor.Error 'protected-role', TAPi18n.__('Cannot_delete_an_protected_role') + + someone = Meteor.users.findOne { "roles.#{Roles.GLOBAL_GROUP}": role.name } + + if someone? + throw new Meteor.Error 'role-in-use', TAPi18n.__('Cannot_delete_role_because_its_in_use') + + return Roles.deleteRole role.name -- GitLab From adad9cca896786b803e373cbef289c70ad2463be Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 30 Nov 2015 16:52:25 -0200 Subject: [PATCH 0615/1338] New statistics: lastLogin, lastMessageSentAt, lastSeenSubscription, migration, version, branch and tag --- .../rocketchat-lib/server/models/Messages.coffee | 7 +++++++ .../server/models/Subscriptions.coffee | 12 +++++++++--- packages/rocketchat-lib/server/models/Users.coffee | 6 ++++++ .../server/functions/get.coffee | 13 +++++++++++-- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index ff9d345f4f9..3d05788863c 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -101,6 +101,13 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find query, options + getLastTimestamp: (options = {}) -> + query = { ts: { $exists: 1 } } + options.sort = { ts: -1 } + options.limit = 1 + + return @find(query, options)?.fetch?()?[0]?.ts + cloneAndSaveAsHistoryById: (_id) -> me = RocketChat.models.Users.findOneById Meteor.userId() record = @findOneById _id diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index f698bea6735..20910f4e03d 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -25,6 +25,12 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @find query, options + getLastSeen: (options = {}) -> + query = { ls: { $exists: 1 } } + options.sort = { ls: -1 } + options.limit = 1 + + return @find(query, options)?.fetch?()?[0]?.ls # UPDATE archiveByRoomIdAndUserId: (roomId, userId) -> @@ -195,11 +201,11 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @update query, update, { multi: true } updateTypeByRoomId: (roomId, type) -> - query = + query = rid: roomId - + update = - $set: + $set: t: type return @update query, update, { multi: true } diff --git a/packages/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index 38ed2b66880..f72dc4db343 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -99,6 +99,12 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @find query, options + getLastLogin: (options = {}) -> + query = { lastLogin: { $exists: 1 } } + options.sort = { lastLogin: -1 } + options.limit = 1 + + return @find(query, options)?.fetch?()?[0]?.lastLogin # UPDATE updateLastLoginById: (_id) -> diff --git a/packages/rocketchat-statistics/server/functions/get.coffee b/packages/rocketchat-statistics/server/functions/get.coffee index 378e4b1943f..d321b5fd48e 100644 --- a/packages/rocketchat-statistics/server/functions/get.coffee +++ b/packages/rocketchat-statistics/server/functions/get.coffee @@ -3,8 +3,9 @@ RocketChat.statistics.get = -> # Version statistics.uniqueId = RocketChat.settings.get("uniqueID") - statistics.version = BuildInfo?.commit?.hash - statistics.versionDate = BuildInfo?.commit?.date + statistics.version = RocketChat.Info?.version + statistics.tag = RocketChat.Info?.tag + statistics.branch = RocketChat.Info?.branch # User statistics statistics.totalUsers = Meteor.users.find().count() @@ -70,6 +71,14 @@ RocketChat.statistics.get = -> else console.log 'private group user statistic not found'.red + statistics.lastLogin = RocketChat.models.Users.getLastLogin() + statistics.lastMessageSentAt = RocketChat.models.Messages.getLastTimestamp() + statistics.lastSeenSubscription = RocketChat.models.Subscriptions.getLastSeen() + + migration = Migrations?._getControl() + if migration + statistics.migration = _.pick(migration, 'version', 'locked') + os = Npm.require('os') statistics.os = type: os.type() -- GitLab From 6fd70f9a14b1067c41bf42ded3012167f2672b13 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 18:04:28 -0200 Subject: [PATCH 0616/1338] adding and removing permissions from a role --- .../client/views/permissions.coffee | 38 +++++++++++++++---- .../client/views/permissions.html | 4 +- packages/rocketchat-authorization/package.js | 2 + .../server/methods/addPermissionToRole.coffee | 5 +++ .../methods/removeRoleFromPermission.coffee | 5 +++ .../server/models/Permissions.coffee | 8 ++++ 6 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee create mode 100644 packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee index b556665fc40..8d4d7dcbbe8 100644 --- a/packages/rocketchat-authorization/client/views/permissions.coffee +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -1,21 +1,45 @@ Template.permissions.helpers role: -> - return Roles.getAllRoles() + return Template.instance().roles.get() permission: -> return ChatPermissions.find() granted: (roles) -> if roles? - return 'YES' if roles.indexOf(@name) isnt -1 + return 'checked' if roles.indexOf(@name) isnt -1 +Template.permissions.events + 'click .role-permission': (e, instance) -> + permission = e.currentTarget.getAttribute('data-permission') + role = e.currentTarget.getAttribute('data-role') + + if instance.permissionByRole[permission].indexOf(role) is -1 + Meteor.call 'authorization:addPermissionToRole', permission, role + else + Meteor.call 'authorization:removeRoleFromPermission', permission, role Template.permissions.onCreated -> - # @roles = [] - # @permissions = [] - # @permissionByRole = {} + @roles = new ReactiveVar [] + @permissionByRole = {} + + @actions = + added: {} + removed: {} + + subs = @subscribe 'roles' - @subscribe 'roles' + Tracker.autorun => + if subs.ready() + @roles.set Roles.getAllRoles().fetch() - # ChatPermissions + 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] diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index a7bdd5eff07..0115efefdb6 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -14,7 +14,9 @@ <tr> <td>{{_id}}</td> {{#each role}} - <td><input type="checkbox" name="perm[{{_id}}][{{../_id}}]" value="1" checked="{{granted ../roles ../_id}}"></td> + <td> + <input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles ../_id}}" data-role="{{name}}" data-permission="{{../_id}}"> + </td> {{/each}} </tr> {{/each}} diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 7e1b6412670..dc48b5be582 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -55,6 +55,8 @@ Package.onUse(function(api) { api.addFiles('server/methods/deleteRole.coffee', 'server'); api.addFiles('server/methods/removeUserFromRole.coffee', 'server'); api.addFiles('server/methods/saveRole.coffee', 'server'); + api.addFiles('server/methods/addPermissionToRole.coffee', 'server'); + api.addFiles('server/methods/removeRoleFromPermission.coffee', 'server'); api.addFiles('server/startup.coffee', ['server']); }); diff --git a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee new file mode 100644 index 00000000000..db3901161a4 --- /dev/null +++ b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee @@ -0,0 +1,5 @@ +Meteor.methods + 'authorization:addPermissionToRole': (permission, role) -> + # @TODO permission check + + RocketChat.models.Permissions.addRole permission, role diff --git a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee new file mode 100644 index 00000000000..3289eb28f5d --- /dev/null +++ b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee @@ -0,0 +1,5 @@ +Meteor.methods + 'authorization:removeRoleFromPermission': (permission, role) -> + # @TODO permission check + + RocketChat.models.Permissions.removeRole permission, role diff --git a/packages/rocketchat-authorization/server/models/Permissions.coffee b/packages/rocketchat-authorization/server/models/Permissions.coffee index 0db22472da1..3e1c6eef96a 100644 --- a/packages/rocketchat-authorization/server/models/Permissions.coffee +++ b/packages/rocketchat-authorization/server/models/Permissions.coffee @@ -12,3 +12,11 @@ RocketChat.models.Permissions = new class extends RocketChat.models._Base createOrUpdate: (name, roles) -> @upsert { _id: name }, { $set: { roles: roles } } + + addRole: (permission, role) -> + @update({ _id: permission }, { $addToSet: { roles: role } }) + + removeRole: (permission, role) -> + @update({ _id: permission }, { $pull: { roles: role } }) + + -- GitLab From 7079306d91ce7b963b55d21c2ba8585cbd26728f Mon Sep 17 00:00:00 2001 From: Jason Paryani <github@jparyani.com> Date: Mon, 30 Nov 2015 13:27:47 -0800 Subject: [PATCH 0617/1338] Add missing meteor-spk files to travis Sandstorm build --- .sandstorm/setup.sh | 3 +-- .travis.yml | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.sandstorm/setup.sh b/.sandstorm/setup.sh index 49d12a211ea..fe1aebc12a3 100755 --- a/.sandstorm/setup.sh +++ b/.sandstorm/setup.sh @@ -3,7 +3,7 @@ set -euo pipefail cd /opt/ -PACKAGE=meteor-spk-0.1.7 +PACKAGE=meteor-spk-0.1.8 PACKAGE_FILENAME="$PACKAGE.tar.xz" CACHE_TARGET="/host-dot-sandstorm/caches/${PACKAGE_FILENAME}" @@ -44,4 +44,3 @@ cd /home/vagrant/ su -c "tar xf '${METEOR_CACHE_TARGET}'" vagrant # Link into global PATH ln -s /home/vagrant/.meteor/meteor /usr/bin/meteor - diff --git a/.travis.yml b/.travis.yml index ca3d4efa5b6..95dd325e4ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,12 @@ before_install: - sudo chown -R travis /home/vagrant - sudo mkdir -p /opt - sudo chown -R travis /opt +- cd /opt +- curl curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - +- ln -s meteor-spk-0.1.8 meteor-spk +- cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ +- cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +- cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ - cd $TRAVIS_BUILD_DIR - cp -r . /opt/app script: -- GitLab From ec396041264b2b414678232483701ffcf9cd6423 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 30 Nov 2015 20:52:04 -0200 Subject: [PATCH 0618/1338] improved permission check on permissions manager pages --- .../client/views/permissions.coffee | 3 + .../client/views/permissions.html | 36 +++--- .../client/views/permissionsRole.coffee | 3 + .../client/views/permissionsRole.html | 110 +++++++++--------- .../server/methods/addPermissionToRole.coffee | 5 +- .../methods/removeRoleFromPermission.coffee | 5 +- 6 files changed, 91 insertions(+), 71 deletions(-) diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee index 8d4d7dcbbe8..f8420e316e9 100644 --- a/packages/rocketchat-authorization/client/views/permissions.coffee +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -10,6 +10,9 @@ Template.permissions.helpers if roles? return 'checked' if roles.indexOf(@name) isnt -1 + hasPermission: -> + return RocketChat.authz.hasAllPermission 'access-rocket-permissions' + Template.permissions.events 'click .role-permission': (e, instance) -> permission = e.currentTarget.getAttribute('data-permission') diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index 0115efefdb6..ad9bc027f65 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -1,24 +1,28 @@ <template name="permissions"> - <h1>{{_ "Permissions"}}</h1> + {{#if hasPermission}} + <h1>{{_ "Permissions"}}</h1> - <a href="{{pathFor "rocket-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> + <a href="{{pathFor "rocket-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> - <table border="1"> - <tr> - <td> </td> - {{#each role}} - <td title="{{description}}"><a href="{{pathFor "rocket-permissions-edit" name=name}}">{{name}}</a></td> - {{/each}} - </tr> - {{#each permission}} + <table border="1"> <tr> - <td>{{_id}}</td> + <td> </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}}"> - </td> + <td title="{{description}}"><a href="{{pathFor "rocket-permissions-edit" name=name}}">{{name}}</a></td> {{/each}} </tr> - {{/each}} - </table> + {{#each permission}} + <tr> + <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}}"> + </td> + {{/each}} + </tr> + {{/each}} + </table> + {{else}} + {{_ "Not_authorized"}} + {{/if}} </template> diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index c079659410f..590b2cf58f3 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -14,6 +14,9 @@ Template.permissionsRole.helpers if @emails?.length > 0 return @emails[0].address + hasPermission: -> + return RocketChat.authz.hasAllPermission 'access-rocket-permissions' + Template.permissionsRole.events 'click .remove-user': (e, instance) -> diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index 1fb609282d9..5677bff22b2 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -1,61 +1,65 @@ <template name="permissionsRole"> - <a href="{{pathFor "rocket-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> + {{#if hasPermission}} + <a href="{{pathFor "rocket-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> - {{#with role}} - <form id="form-role" class="inline"> - <label>{{_ "Role"}}</label>: - {{#if editing}} - <span>{{name}}</span> - {{else}} - <input type="text" name="name" value=""> - {{/if}} - <br> - <label>{{_ "Description"}}</label>: - <input type="text" name="description" value="{{description}}"> - <br> + {{#with role}} + <form id="form-role" class="inline"> + <label>{{_ "Role"}}</label>: + {{#if editing}} + <span>{{name}}</span> + {{else}} + <input type="text" name="name" value=""> + {{/if}} + <br> + <label>{{_ "Description"}}</label>: + <input type="text" name="description" value="{{description}}"> + <br> - <button name="save" class="button primary">{{_ "Save"}}</button> + <button name="save" class="button primary">{{_ "Save"}}</button> - {{#unless protected}} - <button name="delete" class="button red delete-role">{{_ "Delete"}}</button> - {{/unless}} - </form> - {{/with}} + {{#unless protected}} + <button name="delete" class="button red delete-role">{{_ "Delete"}}</button> + {{/unless}} + </form> + {{/with}} - {{#if editing}} - <h2>{{_ "Users_in_role"}}</h2> - <form id="form-users" class="inline"> - <label>{{_ "Add_user"}}</label> - <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> - <button name="add" class="button primary">{{_ "Add"}}</button> - </form> - <div class="list"> - <table> - <thead> - <tr> - <th> </th> - <th width="34%">{{_ "Name"}}</th> - <th width="33%">{{_ "Username"}}</th> - <th width="33%">{{_ "E-mail"}}</th> - <th> </th> - </tr> - </thead> - <tbody> - {{#each userInRole}} - <tr class="user-info" data-id="{{_id}}"> - <td> - <div class="user-image status-{{status}}"> - {{> avatar username=username}} - </div> - </td> - <td>{{name}}</td> - <td>{{username}}</td> - <td>{{emailAddress}}</td> - <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + {{#if editing}} + <h2>{{_ "Users_in_role"}}</h2> + <form id="form-users" class="inline"> + <label>{{_ "Add_user"}}</label> + <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> + <button name="add" class="button primary">{{_ "Add"}}</button> + </form> + <div class="list"> + <table> + <thead> + <tr> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> + <th> </th> </tr> - {{/each}} - </tbody> - </table> - </div> + </thead> + <tbody> + {{#each userInRole}} + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> + {{/if}} + {{else}} + {{_ "Not_authorized"}} {{/if}} </template> diff --git a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee index db3901161a4..693a1b3e420 100644 --- a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee @@ -1,5 +1,8 @@ Meteor.methods 'authorization:addPermissionToRole': (permission, role) -> - # @TODO permission check + if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-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/removeRoleFromPermission.coffee b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee index 3289eb28f5d..8acad5b971a 100644 --- a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee +++ b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee @@ -1,5 +1,8 @@ Meteor.methods 'authorization:removeRoleFromPermission': (permission, role) -> - # @TODO permission check + if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + throw new Meteor.Error "not-authorized" + + console.log '[methods] authorization:removeRoleFromPermission -> '.green, 'arguments:', arguments RocketChat.models.Permissions.removeRole permission, role -- GitLab From 304a982b35f528d6b399308687bc95d150200dd6 Mon Sep 17 00:00:00 2001 From: Jason Paryani <github@jparyani.com> Date: Mon, 30 Nov 2015 13:37:32 -0800 Subject: [PATCH 0619/1338] Fix travis Sandstorm build --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 95dd325e4ae..71f682a1f79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,11 @@ script: - cd /tmp - spk init -p3000 -- nothing - export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) +- cd $TRAVIS_BUILD_DIR +- export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" +- export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle +- meteor build --directory /home/vagrant/ +- cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install - cd $TRAVIS_BUILD_DIR/.sandstorm - sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp - ./build.sh -- GitLab From 252fc9cdb7a2245212f865bb3fc9277cf1a9c444 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 00:20:34 -0200 Subject: [PATCH 0620/1338] fixed typo --- {.dockerfiles => .docker}/dockerfiles/develop/Dockerfile | 0 {.dockerfiles => .docker}/dockerfiles/master/Dockerfile | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {.dockerfiles => .docker}/dockerfiles/develop/Dockerfile (100%) rename {.dockerfiles => .docker}/dockerfiles/master/Dockerfile (100%) diff --git a/.dockerfiles/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile similarity index 100% rename from .dockerfiles/dockerfiles/develop/Dockerfile rename to .docker/dockerfiles/develop/Dockerfile diff --git a/.dockerfiles/dockerfiles/master/Dockerfile b/.docker/dockerfiles/master/Dockerfile similarity index 100% rename from .dockerfiles/dockerfiles/master/Dockerfile rename to .docker/dockerfiles/master/Dockerfile -- GitLab From 8665a1b20f191f0c32270a01b6cea225a64289f2 Mon Sep 17 00:00:00 2001 From: Nolan Darilek <nolan@thewordnerd.info> Date: Mon, 30 Nov 2015 17:19:32 -0600 Subject: [PATCH 0621/1338] Various accessibility fixes, mostly labeling controls and regions. --- .../rocketchat-ui-flextab/flex-tab/flexTabBar.html | 2 +- packages/rocketchat-ui-master/master/main.html | 2 +- packages/rocketchat-ui-message/message/message.html | 10 +++++----- packages/rocketchat-ui-message/message/messageBox.html | 4 ++-- packages/rocketchat-ui-sidenav/side-nav/channels.html | 2 +- .../rocketchat-ui-sidenav/side-nav/chatRoomItem.html | 6 +++--- packages/rocketchat-ui-sidenav/side-nav/sideNav.html | 4 ++-- packages/rocketchat-ui/views/app/room.coffee | 5 +++++ packages/rocketchat-ui/views/app/room.html | 8 ++++---- 9 files changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html index 60f0bde69ba..8a971f49990 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html +++ b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html @@ -1,7 +1,7 @@ <template name="flexTabBar"> {{#each buttons}} <div class="tab-button {{active}}" data-template="{{template}}" data-width="{{width}}" title="{{title}}"> - <i class="{{icon}}"></i> + <i class="{{icon}}" aria-label="{{title}}" role="button" tabindex="0"></i> </div> {{/each}} </template> diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index 9eab99a5bec..68b8c7ccb27 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -55,7 +55,7 @@ <div class="connection-status"> {{> status}} </div> - <div class="flex-tab-bar"> + <div class="flex-tab-bar" role="toolbar"> {{> flexTabBar}} </div> <div class="main-content {{flexOpened}} {{flexOpenedRTC1}} {{flexOpenedRTC2}}"> diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 3e1767267ba..b602ff943c3 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -9,8 +9,8 @@ class="time"> {{time}} </span> - <span class="edited" title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}'> - <i class="icon-edit"></i> + <span class="edited" title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' > + <i class="icon-edit" aria-label="{{_ "Edited"}}"></i> {{_ "by"}} <a class="thumb thumb-small user-card-message" href="#" data-username="{{editedBy}}" tabindex="1"> {{> avatar username=editedBy}} @@ -24,12 +24,12 @@ {{/if}} {{#if actions.length}} <div class="message-cog-container"> - <i class="icon-cog message-cog"></i> + <i class="icon-cog message-cog" aria-label="{{_ "Actions"}}"></i> <div class="message-dropdown"> <ul> - <li class="message-dropdown-close"><i class=" icon-angle-left"></i></li> + <li class="message-dropdown-close"><i class=" icon-angle-left" aria-label="{{_ "Close"}}"></i></li> {{#each actions}} - <li class="{{id}} {{classes}} message-action" title="{{_ i18nLabel}}"><i class="{{icon}}"></i></li> + <li class="{{id}} {{classes}} message-action" title="{{_ i18nLabel}}"><i class="{{icon}}" aria-label="{{_ i18nLabel}}"></i></li> {{/each}} </ul> </div> diff --git a/packages/rocketchat-ui-message/message/messageBox.html b/packages/rocketchat-ui-message/message/messageBox.html index 3b1113685e9..1d348834884 100644 --- a/packages/rocketchat-ui-message/message/messageBox.html +++ b/packages/rocketchat-ui-message/message/messageBox.html @@ -57,8 +57,8 @@ </div> {{/if}} <div class="editing-commands" aria-hidden="true" dir="auto"> - <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="">{{_ 'Cancel'}}</a></div> - <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="">{{_ 'Save_changes'}}</a></div> + <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="#">{{_ 'Cancel'}}</a></div> + <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="#">{{_ 'Save_changes'}}</a></div> </div> </form> {{else}} diff --git a/packages/rocketchat-ui-sidenav/side-nav/channels.html b/packages/rocketchat-ui-sidenav/side-nav/channels.html index 82f971c984f..ed67e5e4865 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/channels.html +++ b/packages/rocketchat-ui-sidenav/side-nav/channels.html @@ -2,7 +2,7 @@ <h3 class="add-room {{isActive}}"> {{_ "Channels"}} {{#if hasPermission 'create-c'}} - <i class="icon-plus"></i> + <i class="icon-plus" aria-label="{{_ "Create channel"}}" role="button"></i> {{/if}} </h3> <ul> diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html index 25060876e0d..4a45dae2fda 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html @@ -4,12 +4,12 @@ {{#if unread}} <span class="unread">{{unread}}</span> {{/if}} - <i class="{{roomIcon}} {{userStatus}}"></i> + <i class="{{roomIcon}} {{userStatus}}" aria-label=""></i> <span class='name'>{{name}}</span> <span class='opt'> - <i class="icon-eye-off hide-room" title="{{_ "Hide_room"}}"></i> + <i class="icon-eye-off hide-room" title="{{_ "Hide_room"}}" aria-label="{{_ "Hide_room"}}"></i> {{#if canLeave}} - <i class="octicon octicon-sign-out leave-room" title="{{_ "Leave_room"}}"></i> + <i class="octicon octicon-sign-out leave-room" title="{{_ "Leave_room"}}" aria-label="{{_ "Leave_room"}}"></i> {{/if}} </span> </a> diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html index 69de45698bd..888078c599c 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html @@ -1,7 +1,7 @@ <template name="sideNav"> <aside class="side-nav" role="navigation"> <header class="header"> - <div class="account-box"> + <div class="account-box" aria-label="{{_ "Account"}}" role="region"> {{#with myUserInfo}} <div class="info status-{{status}}"> {{#if username}} @@ -36,7 +36,7 @@ <div class="unread-rooms top-unread-rooms hidden"> {{_ "More_unreads"}} <i class="icon-up-big"></i> </div> - <div class="rooms-list"> + <div class="rooms-list" aria-label="{{_ "Channels"}}" role="region"> <div class="wrapper"> {{ > unreadRooms }} diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 17b46c0d0c5..f5d25405c69 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -18,6 +18,11 @@ Template.room.helpers return 'icon-star favorite-room' if sub?.f? and sub.f and favoritesEnabled return 'icon-star-empty' + favoriteLabel: -> + sub = ChatSubscription.findOne { rid: this._id }, { fields: { f: 1 } } + return "Unfavorite" if sub?.f? and sub.f and favoritesEnabled + return "Favorite" + subscribed: -> return isSubscribed(this._id) diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index 919ef914666..010ab8427bf 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -5,12 +5,12 @@ {{_ "Drop_to_upload_file"}} </div> </div> - <section class="messages-container {{adminClass}}" id="{{windowId}}"> + <section class="messages-container {{adminClass}}" id="{{windowId}}" aria-label="{{_ "Channel"}}"> <header class="fixed-title"> {{> burger}} <h2> {{#if showToggleFavorite}} - <a href="#favorite" class="toggle-favorite"><i class="{{favorite}}"></i></a> + <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> @@ -25,14 +25,14 @@ <div class="upload-progress {{#if error}}upload-error{{/if}}"> {{#if error}} {{error}} - <a> + <a href="##"> close </a> {{else}} <div class="upload-progress-progress" style="width: {{percentage}}%;"></div> <div class="upload-progress-text"> {{name}}... {{percentage}}% - <a> + <a href="#"> cancel </a> </div> -- GitLab From 465e179f650803ddd81778020b3e19c521fdd25f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 00:41:40 -0200 Subject: [PATCH 0622/1338] removing old files --- .meteor/cordova-plugins | 2 -- build-android.sh | 7 ------- build-info.sh | 23 ----------------------- build-ios.sh | 22 ---------------------- 4 files changed, 54 deletions(-) delete mode 100644 .meteor/cordova-plugins delete mode 100755 build-android.sh delete mode 100755 build-info.sh delete mode 100755 build-ios.sh diff --git a/.meteor/cordova-plugins b/.meteor/cordova-plugins deleted file mode 100644 index 78573be10dc..00000000000 --- a/.meteor/cordova-plugins +++ /dev/null @@ -1,2 +0,0 @@ -ionic-plugin-keyboard@1.0.7 -phonegap-facebook-plugin@https://github.com/Sing-Li/phonegap-facebook-plugin.git#667dda292cf70d8fb725f512cedef3fe0dd55ac3 diff --git a/build-android.sh b/build-android.sh deleted file mode 100755 index 1a943b296b4..00000000000 --- a/build-android.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -meteor add-platform android -meteor build ../Rocket.Chat-build --server https://demo.rocket.chat -jarsigner -digestalg SHA1 .meteor/local/cordova-build/platforms/android/ant-build/CordovaApp-release-unsigned.apk RocketChat -~/.meteor/android_bundle/android-sdk/build-tools/21.0.0/zipalign 4 .meteor/local/cordova-build/platforms/android/ant-build/CordovaApp-release-unsigned.apk .meteor/local/cordova-build/platforms/android/ant-build/RocketChat-release-signed.apk -open .meteor/local/cordova-build/platforms/android/ant-build/ diff --git a/build-info.sh b/build-info.sh deleted file mode 100755 index 44263a3b5ca..00000000000 --- a/build-info.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -DATETIME=`date "+%d/%m/%Y %H:%M:%S"` -COMMIT_HASH=`git log --pretty=format:'%H' -n 1` -COMMIT_AUTHOR_NAME=`git log --pretty=format:'%an' -n 1` -COMMIT_AUTHOR_DATE=`git log --pretty=format:'%ad' -n 1` -COMMIT_AUTHOR_EMAIL=`git log --pretty=format:'%ae' -n 1` -COMMIT_SUBJECT=`git log --pretty=format:'%s' -n 1` - -COMMIT_SUBJECT="${COMMIT_SUBJECT//\'/\"}" - -echo "BuildInfo = { - date: '$DATETIME', - commit: { - hash: '$COMMIT_HASH', - subject: '$COMMIT_SUBJECT', - author: { - date: '$COMMIT_AUTHOR_DATE', - name: '$COMMIT_AUTHOR_NAME', - email: '$COMMIT_AUTHOR_EMAIL' - } - } -};" > ./BuildInfo.js diff --git a/build-ios.sh b/build-ios.sh deleted file mode 100755 index 92c9444debb..00000000000 --- a/build-ios.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -rm -rf .meteor/local/cordova-build -rm -rf ../Rocket.Chat-build -meteor build ../Rocket.Chat-build --server https://demo.rocket.chat -sed -i '' 's/IPHONEOS_DEPLOYMENT_TARGET[[:space:]]=[[:space:]]6\.0/IPHONEOS_DEPLOYMENT_TARGET = 8\.0/g' .meteor/local/cordova-build/platforms/ios/Rocket.Chat.xcodeproj/project.pbxproj - -# Set some plist attr for new xcode compile -/usr/libexec/PlistBuddy -c "Add :NSAppTransportSecurity dict" .meteor/local/cordova-build/platforms/ios/Rocket.Chat/Rocket.Chat-Info.plist -/usr/libexec/PlistBuddy -c "Add :NSAppTransportSecurity:NSAllowsArbitraryLoads bool YES" .meteor/local/cordova-build/platforms/ios/Rocket.Chat/Rocket.Chat-Info.plist -/usr/libexec/PlistBuddy -c "Add :LSApplicationQueriesSchemes array" .meteor/local/cordova-build/platforms/ios/Rocket.Chat/Rocket.Chat-Info.plist -/usr/libexec/PlistBuddy -c "Add :LSApplicationQueriesSchemes:0 string 'fbauth'" .meteor/local/cordova-build/platforms/ios/Rocket.Chat/Rocket.Chat-Info.plist - -# Set buildnumber as cur date in seconds -DATE=$(date +%s) -/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $DATE" .meteor/local/cordova-build/platforms/ios/Rocket.Chat/Rocket.Chat-Info.plist - -open .meteor/local/cordova-build/platforms/ios/Rocket.Chat.xcodeproj -echo '- Change provisioning profiles' -echo '- Convert icons to use Asset Catalog' -echo '- Add more icons' -echo '- Add more splashs' -- GitLab From 39c92c79216f0660a43230cee9c5301a6f5cf20f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 01:20:59 -0200 Subject: [PATCH 0623/1338] removed dependency on "Roboto" font-family --- .../app/client/stylesheets/main.less | 2 +- .../assets/stylesheets/base.less | 5 +- .../stylesheets/utils/_fonts.import.less | 47 --- ...683d1de814a4d109387bb90bb82e0bb8aeb1.woff2 | Bin 63396 -> 0 bytes ...8fe3b2ffcb825efff40a8378f22125ccf88cb0.svg | 308 ------------------ ...d4ddc447af43a160ea7249c8a3b8db63b90c43.ttf | Bin 105920 -> 0 bytes ...39d23da3eaa8144f02e19043fab2b3f19a33.woff2 | Bin 63104 -> 0 bytes ...3c2ac98be5b4e0fb8a97e28dda99ae76b8c7.woff2 | Bin 63800 -> 0 bytes ...e0a3b2ecefc9c25ccefa511cf8a781c78799.woff2 | Bin 63156 -> 0 bytes ...ca32cc805ea3e480e6458ae7c3640d41f6c96b.ttf | Bin 105148 -> 0 bytes ...ef2c34858a412764dfd5efadf3e387c8d7402.woff | Bin 82860 -> 0 bytes ...b4436ba4c5c9b33f4fca42b43d99a703467f0.woff | Bin 82560 -> 0 bytes ...76a31e25af67e36a420aa2348874c5a8b5c9a5.ttf | Bin 104680 -> 0 bytes ...755b34719e3012d4ae9455615b1549fec1ca3f.eot | Bin 73045 -> 0 bytes ...65969dd0cf49f8408deff0aed2b9d6008a06d.woff | Bin 82320 -> 0 bytes ...1d8824866e60a2a2d327c6b6219939b259b57.woff | Bin 82804 -> 0 bytes ...a17a54541b34b38ef67cf919f1ac63b44a7454.ttf | Bin 106660 -> 0 bytes 17 files changed, 2 insertions(+), 360 deletions(-) delete mode 100644 packages/rocketchat-theme/assets/stylesheets/utils/_fonts.import.less delete mode 100644 public/fonts/roboto-0346683d1de814a4d109387bb90bb82e0bb8aeb1.woff2 delete mode 100644 public/fonts/roboto-148fe3b2ffcb825efff40a8378f22125ccf88cb0.svg delete mode 100644 public/fonts/roboto-15d4ddc447af43a160ea7249c8a3b8db63b90c43.ttf delete mode 100644 public/fonts/roboto-23d439d23da3eaa8144f02e19043fab2b3f19a33.woff2 delete mode 100644 public/fonts/roboto-5cb23c2ac98be5b4e0fb8a97e28dda99ae76b8c7.woff2 delete mode 100644 public/fonts/roboto-5cdbe0a3b2ecefc9c25ccefa511cf8a781c78799.woff2 delete mode 100644 public/fonts/roboto-8fca32cc805ea3e480e6458ae7c3640d41f6c96b.ttf delete mode 100644 public/fonts/roboto-922ef2c34858a412764dfd5efadf3e387c8d7402.woff delete mode 100644 public/fonts/roboto-9e2b4436ba4c5c9b33f4fca42b43d99a703467f0.woff delete mode 100644 public/fonts/roboto-b376a31e25af67e36a420aa2348874c5a8b5c9a5.ttf delete mode 100644 public/fonts/roboto-c8755b34719e3012d4ae9455615b1549fec1ca3f.eot delete mode 100644 public/fonts/roboto-cd565969dd0cf49f8408deff0aed2b9d6008a06d.woff delete mode 100644 public/fonts/roboto-d561d8824866e60a2a2d327c6b6219939b259b57.woff delete mode 100644 public/fonts/roboto-d9a17a54541b34b38ef67cf919f1ac63b44a7454.ttf diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 1573e9cc323..de53ed4ab8f 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -13,7 +13,7 @@ body { padding: 0; margin: 0; font-size: 10pt; - font-family: "Roboto", "HelveticaNeue-Light", "sans-serif"; + font-family: "Roboto", "HelveticaNeue", sans-serif; // font-size: 14px; color: @primary-font-color; height: 100%; diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index b98b198610f..7cd7c5427d4 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -394,7 +394,7 @@ html { } body { - font-family: "Roboto", "HelveticaNeue-Light", "sans-serif"; + font-family: "Roboto", "HelveticaNeue", sans-serif; font-size: 14px; height: 100%; width: 100%; @@ -3419,7 +3419,6 @@ a.github-fork { padding: 4px 8px; font-size: 18px; border-bottom: 1px solid; - font-family: "Roboto", "HelveticaNeue-Light", "sans-serif"; font-weight: 400; border-radius: 0px; &.error { @@ -3498,7 +3497,6 @@ a.github-fork { } } a { - font-family: "Roboto", "HelveticaNeue-Light", "sans-serif"; font-weight: 300; } .cell { @@ -3538,7 +3536,6 @@ a.github-fork { &:extend(.rocket-h3); } p { - font-family: "Muli", "Roboto", "HelveticaNeue-Light", "sans-serif"; margin: 18px 0; font-size: 16px; line-height: 24px; diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_fonts.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_fonts.import.less deleted file mode 100644 index 0a9424711e5..00000000000 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_fonts.import.less +++ /dev/null @@ -1,47 +0,0 @@ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 300; - src: local("Roboto Light"), - local("Roboto-Light"), - url("/fonts/roboto-23d439d23da3eaa8144f02e19043fab2b3f19a33.woff2") format("woff2"), - url("/fonts/roboto-cd565969dd0cf49f8408deff0aed2b9d6008a06d.woff") format("woff"), - url("/fonts/roboto-8fca32cc805ea3e480e6458ae7c3640d41f6c96b.ttf") format("truetype"); -} - -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - /* IE6-8 compat */ - src: url("/fonts/roboto-c8755b34719e3012d4ae9455615b1549fec1ca3f.eot"); - src: local("Roboto"), - local("Roboto-Regular"), - url("/fonts/roboto-5cdbe0a3b2ecefc9c25ccefa511cf8a781c78799.woff2") format("woff2"), - url("/fonts/roboto-9e2b4436ba4c5c9b33f4fca42b43d99a703467f0.woff") format("woff"), - url("/fonts/roboto-148fe3b2ffcb825efff40a8378f22125ccf88cb0.svg#Roboto") format("svg"), - url("/fonts/roboto-c8755b34719e3012d4ae9455615b1549fec1ca3f.eot") format("embedded-opentype"), - url("/fonts/roboto-b376a31e25af67e36a420aa2348874c5a8b5c9a5.ttf") format("truetype"); -} - -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 500; - src: local("Roboto Medium"), - local("Roboto-Medium"), - url("/fonts/roboto-5cb23c2ac98be5b4e0fb8a97e28dda99ae76b8c7.woff2") format("woff2"), - url("/fonts/roboto-d561d8824866e60a2a2d327c6b6219939b259b57.woff") format("woff"), - url("/fonts/roboto-15d4ddc447af43a160ea7249c8a3b8db63b90c43.ttf") format("truetype"); -} - -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 700; - src: local("Roboto Bold"), - local("Roboto-Bold"), - url("/fonts/roboto-0346683d1de814a4d109387bb90bb82e0bb8aeb1.woff2") format("woff2"), - url("/fonts/roboto-922ef2c34858a412764dfd5efadf3e387c8d7402.woff") format("woff"), - url("/fonts/roboto-d9a17a54541b34b38ef67cf919f1ac63b44a7454.ttf") format("truetype"); -} \ No newline at end of file diff --git a/public/fonts/roboto-0346683d1de814a4d109387bb90bb82e0bb8aeb1.woff2 b/public/fonts/roboto-0346683d1de814a4d109387bb90bb82e0bb8aeb1.woff2 deleted file mode 100644 index 45901ee1a5c953acfd55d535ba50cf76acbae5c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63396 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 P@^`)UC%xk$DF6Tf9FpUo diff --git a/public/fonts/roboto-148fe3b2ffcb825efff40a8378f22125ccf88cb0.svg b/public/fonts/roboto-148fe3b2ffcb825efff40a8378f22125ccf88cb0.svg deleted file mode 100644 index ed55c105d7a..00000000000 --- a/public/fonts/roboto-148fe3b2ffcb825efff40a8378f22125ccf88cb0.svg +++ /dev/null @@ -1,308 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg"> -<defs > -<font id="Roboto" horiz-adv-x="1157" ><font-face - font-family="Roboto" - units-per-em="2048" - panose-1="2 0 0 0 0 0 0 0 0 0" - ascent="1900" - descent="-500" - alphabetic="0" /> -<glyph unicode=" " horiz-adv-x="507" /> -<glyph unicode="!" horiz-adv-x="527" d="M347 411H180L167 1456H361L347 411ZM160 93Q160 138 187 168T269 199T351 169T379 93T351 19T269 -11T188 18T160 93Z" /> -<glyph unicode=""" horiz-adv-x="655" d="M277 1400L247 1042H136L137 1536H277V1400ZM547 1400L517 1042H406L407 1536H547V1400Z" /> -<glyph unicode="#" horiz-adv-x="1261" d="M765 410H501L421 0H278L358 410H119V547H384L453 901H195V1040H480L562 1456H705L623 1040H887L969 1456H1113L1031 1040H1235V901H1004L935 547H1160V410H909L829 0H685L765 410ZM527 547H791L860 901H596L527 547Z" /> -<glyph unicode="$" horiz-adv-x="1150" d="M856 375Q856 467 792 530T574 644Q361 709 264 813T166 1079Q166 1243 261 1348T524 1473V1692H673V1472Q841 1449 934 1331T1028 1008H844Q844 1149 777 1232T596 1315Q477 1315 414 1254T351 1082Q351 980 417 920T636 -810T874 701T1000 562T1041 377Q1041 208 940 105T655 -17V-208H507V-17Q321 0 216 115T110 429H295Q295 290 368 215T575 140Q706 140 781 203T856 375Z" /> -<glyph unicode="%" horiz-adv-x="1500" d="M105 1176Q105 1307 188 1392T403 1477Q536 1477 618 1392T701 1170V1099Q701 967 618 884T405 800Q275 800 190 883T105 1106V1176ZM243 1099Q243 1021 287 971T405 920Q476 920 519 969T563 1103V1176Q563 1254 520 -1305T403 1356T286 1305T243 1172V1099ZM814 357Q814 488 897 572T1112 657T1327 573T1411 350V279Q1411 148 1328 64T1114 -21T899 62T814 285V357ZM952 279Q952 200 996 150T1114 99Q1186 99 1229 148T1272 283V357Q1272 436 1229 486T1112 536Q1041 536 997 -487T952 353V279ZM447 110L342 176L1053 1314L1158 1248L447 110Z" /> -<glyph unicode="&" horiz-adv-x="1273" d="M101 391Q101 496 159 584T383 789Q286 907 253 979T220 1122Q220 1288 318 1382T584 1476Q734 1476 832 1389T930 1168Q930 1080 886 1006T730 849L623 770L947 383Q1015 513 1015 672H1182Q1182 417 1059 249L1267 -0H1045L948 115Q874 49 775 15T572 -20Q359 -20 230 93T101 391ZM572 131Q719 131 841 243L486 668L453 644Q286 521 286 391Q286 273 362 202T572 131ZM405 1128Q405 1032 523 888L641 971Q709 1019 734 1062T759 1168Q759 1235 709 1279T583 1324Q501 1324 453 -1269T405 1128Z" /> -<glyph unicode="'" horiz-adv-x="357" d="M253 1425L232 1057H103L104 1536H253V1425Z" /> -<glyph unicode="(" horiz-adv-x="700" d="M133 591Q133 817 193 1025T374 1403T623 1643L661 1521Q515 1409 422 1179T319 664L318 579Q318 193 459 -91Q544 -261 661 -357L623 -470Q490 -396 369 -222Q133 118 133 591Z" /> -<glyph unicode=")" horiz-adv-x="712" d="M567 581Q567 358 509 154T330 -224T77 -470L38 -357Q192 -239 285 9T381 561V593Q381 803 337 983T215 1307T38 1530L77 1643Q209 1570 328 1399T507 1022T567 581Z" /> -<glyph unicode="*" horiz-adv-x="882" d="M330 983L28 1073L74 1224L376 1112L367 1456H520L510 1107L807 1217L853 1065L546 974L744 703L620 609L434 897L254 616L129 707L330 983Z" /> -<glyph unicode="+" horiz-adv-x="1161" d="M670 781H1076V606H670V146H484V606H78V781H484V1206H670V781Z" /> -<glyph unicode="," horiz-adv-x="402" d="M134 -290L29 -218Q123 -87 127 52V219H308V74Q308 -27 259 -128T134 -290Z" /> -<glyph unicode="-" horiz-adv-x="565" d="M525 543H37V694H525V543Z" /> -<glyph unicode="." horiz-adv-x="539" d="M144 97Q144 145 172 177T258 209T344 177T374 97Q374 51 345 20T258 -11T173 20T144 97Z" /> -<glyph unicode="/" horiz-adv-x="844" d="M177 -125H18L626 1456H784L177 -125Z" /> -<glyph unicode="0" horiz-adv-x="1150" d="M1034 621Q1034 296 923 138T576 -20Q343 -20 231 134T115 596V843Q115 1164 226 1320T574 1476Q809 1476 920 1326T1034 861V621ZM849 874Q849 1109 783 1216T574 1324Q432 1324 367 1217T300 888V592Q300 356 368 244T576 -131Q713 131 779 237T849 571V874Z" /> -<glyph unicode="1" horiz-adv-x="1150" d="M729 0H543V1233L170 1096V1264L700 1463H729V0Z" /> -<glyph unicode="2" horiz-adv-x="1150" d="M1075 0H121V133L625 693Q737 820 779 899T822 1064Q822 1178 753 1251T569 1324Q431 1324 355 1246T278 1027H93Q93 1228 222 1352T569 1476Q772 1476 890 1370T1008 1086Q1008 871 734 574L344 151H1075V0Z" /> -<glyph unicode="3" horiz-adv-x="1150" d="M390 818H529Q660 820 735 887T810 1068Q810 1324 555 1324Q435 1324 364 1256T292 1074H107Q107 1247 233 1361T555 1476Q761 1476 878 1367T995 1064Q995 969 934 880T766 747Q886 709 951 621T1017 406Q1017 210 889 -95T556 -20T223 91T94 384H280Q280 269 355 200T556 131Q690 131 761 201T832 402Q832 529 754 597T529 667H390V818Z" /> -<glyph unicode="4" horiz-adv-x="1150" d="M902 489H1104V338H902V0H716V338H53V447L705 1456H902V489ZM263 489H716V1203L694 1163L263 489Z" /> -<glyph unicode="5" horiz-adv-x="1150" d="M206 730L280 1456H1026V1285H437L393 888Q500 951 636 951Q835 951 952 820T1069 464Q1069 239 948 110T608 -20Q415 -20 293 87T154 383H329Q346 258 418 195T608 131Q737 131 810 219T884 462Q884 608 805 696T593 -785Q472 785 403 732L354 692L206 730Z" /> -<glyph unicode="6" horiz-adv-x="1150" d="M847 1457V1300H813Q597 1296 469 1172T321 823Q436 955 635 955Q825 955 938 821T1052 475Q1052 250 930 115T601 -20Q392 -20 262 140T132 554V625Q132 1027 303 1239T814 1457H847ZM604 801Q509 801 429 744T318 601V533Q318 -353 399 243T601 133Q726 133 797 225T869 466Q869 616 797 708T604 801Z" /> -<glyph unicode="7" horiz-adv-x="1150" d="M1061 1352L458 0H264L865 1304H77V1456H1061V1352Z" /> -<glyph unicode="8" horiz-adv-x="1150" d="M1004 1076Q1004 967 947 882T791 749Q905 700 971 606T1038 393Q1038 204 911 92T575 -20Q365 -20 239 92T112 393Q112 511 176 606T355 750Q258 798 202 883T146 1076Q146 1260 264 1368T575 1476Q767 1476 885 1368T1004 -1076ZM853 397Q853 519 776 596T573 673T373 597T297 397T370 202T575 131Q705 131 779 202T853 397ZM575 1324Q466 1324 399 1257T331 1073Q331 962 397 894T575 825T752 893T819 1073T750 1254T575 1324Z" /> -<glyph unicode="9" horiz-adv-x="1150" d="M830 640Q772 571 692 529T515 487Q389 487 296 549T151 723T100 972Q100 1118 155 1235T313 1414T551 1476Q767 1476 891 1315T1016 874V820Q1016 395 848 200T341 -1H305V155H344Q573 159 696 274T830 640ZM545 640Q638 -640 716 697T831 838V912Q831 1094 752 1208T552 1322Q430 1322 356 1229T282 982Q282 833 353 737T545 640Z" /> -<glyph unicode=":" horiz-adv-x="496" d="M390 97Q390 145 418 177T504 209T590 177T620 97Q620 51 591 20T504 -11T419 20T390 97ZM135 980Q135 1028 163 1060T249 1092T335 1060T365 980Q365 934 336 903T249 872T164 903T135 980Z" /> -<glyph unicode=";" horiz-adv-x="433" d="M111 980Q111 1028 139 1060T225 1092T311 1060T341 980Q341 934 312 903T225 872T140 903T111 980ZM146 -290L41 -218Q135 -87 139 52V219H320V74Q320 -27 271 -128T146 -290Z" /> -<glyph unicode="<" horiz-adv-x="1041" d="M264 644L890 391V195L72 574V720L890 1098V902L264 644Z" /> -<glyph unicode="=" horiz-adv-x="1124" d="M986 814H152V975H986V814ZM986 399H152V559H986V399Z" /> -<glyph unicode=">" horiz-adv-x="1070" d="M795 650L134 909V1099L988 721V575L134 196V388L795 650Z" /> -<glyph unicode="?" horiz-adv-x="967" d="M357 410Q359 529 384 598T486 751L617 886Q701 981 701 1090Q701 1195 646 1254T486 1314Q384 1314 322 1260T260 1115H75Q77 1277 190 1376T486 1476Q675 1476 780 1375T886 1096Q886 921 724 751L615 643Q542 562 542 -410H357ZM349 93Q349 138 376 168T458 199T540 169T568 93T540 19T458 -11T377 18T349 93Z" /> -<glyph unicode="@" horiz-adv-x="1839" d="M1738 502Q1726 260 1618 120T1329 -20Q1142 -20 1089 148Q1035 63 966 22T822 -20Q680 -20 607 96T553 417Q568 582 628 711T784 915T985 989Q1066 989 1130 968T1274 883L1222 329Q1203 98 1350 98Q1463 98 1533 210T1609 -502Q1628 891 1465 1095T967 1299Q766 1299 610 1200T364 912T263 478Q251 230 323 48T542 -231T899 -328Q989 -328 1079 -306T1230 -249L1267 -364Q1205 -403 1103 -428T895 -453Q645 -453 465 -341T196 -17T118 478Q130 753 241 972T542 1311T971 1431Q1220 1431 -1398 1319T1663 996T1738 502ZM712 417Q698 275 738 199T867 123Q927 123 982 174T1074 320L1075 329L1121 832Q1065 861 1001 861Q884 861 808 742T712 417Z" /> -<glyph unicode="A" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538Z" /> -<glyph unicode="B" horiz-adv-x="1275" d="M169 0V1456H645Q882 1456 1001 1358T1121 1068Q1121 966 1063 888T905 766Q1023 733 1091 641T1160 420Q1160 224 1033 112T674 0H169ZM361 681V157H678Q812 157 889 226T967 418Q967 681 681 681H361ZM361 835H651Q777 -835 852 898T928 1069Q928 1189 858 1243T645 1298H361V835Z" /> -<glyph unicode="C" horiz-adv-x="1333" d="M1240 462Q1213 231 1070 106T688 -20Q430 -20 275 165T119 660V800Q119 1003 191 1157T397 1393T705 1476Q937 1476 1077 1347T1240 988H1047Q1022 1162 939 1240T705 1318Q521 1318 417 1182T312 795V654Q312 417 411 -277T688 137Q848 137 933 209T1047 462H1240Z" /> -<glyph unicode="D" horiz-adv-x="1343" d="M169 0V1456H580Q770 1456 916 1372T1141 1133T1222 777V684Q1222 478 1143 323T916 85T572 0H169ZM361 1298V157H563Q785 157 908 295T1032 688V773Q1032 1021 916 1158T585 1298H361Z" /> -<glyph unicode="E" horiz-adv-x="1164" d="M992 673H361V157H1094V0H169V1456H1084V1298H361V830H992V673Z" /> -<glyph unicode="F" horiz-adv-x="1132" d="M972 643H361V0H169V1456H1071V1298H361V800H972V643Z" /> -<glyph unicode="G" horiz-adv-x="1395" d="M1244 191Q1170 85 1038 33T729 -20Q551 -20 413 63T200 301T122 658V785Q122 1114 275 1295T707 1476Q935 1476 1074 1360T1244 1029H1052Q998 1318 708 1318Q515 1318 416 1183T315 790V671Q315 426 427 282T730 137Q838 -137 919 161T1053 242V569H716V725H1244V191Z" /> -<glyph unicode="H" horiz-adv-x="1460" d="M1288 0H1095V673H361V0H169V1456H361V830H1095V1456H1288V0Z" /> -<glyph unicode="I" horiz-adv-x="557" d="M375 0H183V1456H375V0Z" /> -<glyph unicode="J" horiz-adv-x="1130" d="M779 1456H972V425Q972 216 847 98T512 -20Q295 -20 174 91T53 402H245Q245 277 313 207T512 137Q631 137 704 212T779 422V1456Z" /> -<glyph unicode="K" horiz-adv-x="1284" d="M539 677L361 492V0H169V1456H361V736L1008 1456H1240L667 813L1285 0H1055L539 677Z" /> -<glyph unicode="L" horiz-adv-x="1102" d="M362 157H1052V0H169V1456H362V157Z" /> -<glyph unicode="M" horiz-adv-x="1788" d="M417 1456L893 268L1369 1456H1618V0H1426V567L1444 1179L966 0H819L342 1176L361 567V0H169V1456H417Z" /> -<glyph unicode="N" horiz-adv-x="1460" d="M1288 0H1095L362 1122V0H169V1456H362L1097 329V1456H1288V0Z" /> -<glyph unicode="O" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q533 -20 400 64T194 305T118 668V773Q118 983 191 1144T397 1390T703 1476Q878 1476 1011 1392T1217 1147T1289 773V681ZM1098 775Q1098 1034 994 1172T703 1311Q521 1311 -417 1173T309 788V681Q309 430 414 287T705 143Q891 143 993 278T1098 667V775Z" /> -<glyph unicode="P" horiz-adv-x="1292" d="M361 570V0H169V1456H706Q945 1456 1080 1334T1216 1011Q1216 799 1084 685T704 570H361ZM361 727H706Q860 727 942 799T1024 1009Q1024 1139 942 1217T717 1298H361V727Z" /> -<glyph unicode="Q" horiz-adv-x="1408" d="M1281 681Q1281 470 1214 318T1026 79L1286 -125L1155 -246L848 -2Q776 -20 696 -20Q524 -20 391 64T185 305T109 668V773Q109 983 182 1144T388 1390T694 1476Q870 1476 1003 1391T1209 1147T1281 774V681ZM1089 775Q1089 -1032 987 1171T694 1311Q513 1311 409 1173T301 788V681Q301 431 405 287T696 143T984 278T1089 667V775Z" /> -<glyph unicode="R" horiz-adv-x="1261" d="M703 589H361V0H168V1456H650Q896 1456 1028 1344T1161 1018Q1161 882 1088 781T883 630L1225 12V0H1019L703 589ZM361 746H656Q799 746 883 820T968 1018Q968 1153 888 1225T655 1298H361V746Z" /> -<glyph unicode="S" horiz-adv-x="1215" d="M598 649Q351 720 239 823T126 1079Q126 1251 263 1363T621 1476Q771 1476 888 1418T1070 1258T1135 1035H942Q942 1167 858 1242T621 1318Q479 1318 400 1256T320 1082Q320 993 395 932T652 819T936 707T1088 563T1138 -370Q1138 193 1000 87T631 -20Q481 -20 351 37T151 195T80 422H273Q273 290 370 214T631 137Q783 137 864 199T945 368T870 533T598 649Z" /> -<glyph unicode="T" horiz-adv-x="1222" d="M1175 1298H707V0H516V1298H49V1456H1175V1298Z" /> -<glyph unicode="U" horiz-adv-x="1328" d="M1194 1456V466Q1193 260 1065 129T716 -18L665 -20Q426 -20 284 109T140 464V1456H330V470Q330 312 417 225T665 137Q828 137 914 224T1001 469V1456H1194Z" /> -<glyph unicode="V" horiz-adv-x="1303" d="M651 255L1067 1456H1277L737 0H567L28 1456H237L651 255Z" /> -<glyph unicode="W" horiz-adv-x="1817" d="M483 459L511 267L552 440L840 1456H1002L1283 440L1323 264L1354 460L1580 1456H1773L1420 0H1245L945 1061L922 1172L899 1061L588 0H413L61 1456H253L483 459Z" /> -<glyph unicode="X" horiz-adv-x="1284" d="M644 898L993 1456H1219L759 734L1230 0H1002L644 568L284 0H57L529 734L68 1456H293L644 898Z" /> -<glyph unicode="Y" horiz-adv-x="1230" d="M613 725L993 1456H1211L709 543V0H517V543L15 1456H235L613 725Z" /> -<glyph unicode="Z" horiz-adv-x="1226" d="M313 157H1146V0H86V144L884 1298H99V1456H1114V1315L313 157Z" /> -<glyph unicode="[" horiz-adv-x="543" d="M523 1512H332V-160H523V-312H146V1664H523V1512Z" /> -<glyph unicode="\" horiz-adv-x="840" d="M40 1456H216L824 -125H648L40 1456Z" /> -<glyph unicode="]" horiz-adv-x="543" d="M9 1664H387V-312H9V-160H202V1512H9V1664Z" /> -<glyph unicode="^" horiz-adv-x="856" d="M426 1211L236 729H64L363 1456H490L788 729H617L426 1211Z" /> -<glyph unicode="_" horiz-adv-x="924" d="M920 -151H4V0H920V-151Z" /> -<glyph unicode="`" horiz-adv-x="633" d="M474 1240H315L57 1534H280L474 1240Z" /> -<glyph unicode="a" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141Z" /> -<glyph unicode="b" horiz-adv-x="1149" d="M1056 529Q1056 281 942 131T636 -20Q431 -20 319 125L310 0H140V1536H325V963Q437 1102 634 1102T943 953T1056 545V529ZM871 550Q871 739 798 842T588 945Q405 945 325 775V307Q410 137 590 137Q723 137 797 240T871 550Z" /> -<glyph unicode="c" horiz-adv-x="1072" d="M574 131Q673 131 747 191T829 341H1004Q999 248 940 164T783 30T574 -20Q353 -20 223 127T92 531V562Q92 720 150 843T316 1034T573 1102Q755 1102 875 993T1004 710H829Q821 815 750 882T573 950Q432 950 355 849T277 -555V520Q277 333 354 232T574 131Z" /> -<glyph unicode="d" horiz-adv-x="1155" d="M95 550Q95 799 213 950T522 1102Q712 1102 823 972V1536H1008V0H838L829 116Q718 -20 520 -20Q332 -20 214 134T95 536V550ZM280 529Q280 345 356 241T566 137Q742 137 823 295V792Q740 945 568 945Q432 945 356 840T280 529Z" /> -<glyph unicode="e" horiz-adv-x="1085" d="M589 -20Q369 -20 231 124T93 511V545Q93 706 154 832T326 1030T566 1102Q777 1102 894 963T1011 565V488H278Q282 328 371 230T599 131Q697 131 765 171T884 277L997 189Q861 -20 589 -20ZM566 950Q454 950 378 869T284 -640H826V654Q818 795 750 872T566 950Z" /> -<glyph unicode="f" horiz-adv-x="711" d="M231 0V939H60V1082H231V1193Q231 1367 324 1462T587 1557Q651 1557 714 1540L704 1390Q657 1399 604 1399Q514 1399 465 1347T416 1196V1082H647V939H416V0H231Z" /> -<glyph unicode="g" horiz-adv-x="1149" d="M96 550Q96 803 213 952T523 1102Q721 1102 832 962L841 1082H1010V26Q1010 -184 886 -305T551 -426Q434 -426 322 -376T151 -239L247 -128Q366 -275 538 -275Q673 -275 748 -199T824 15V108Q713 -20 521 -20Q331 -20 -214 133T96 550ZM282 529Q282 346 357 242T567 137Q742 137 824 296V790Q739 945 569 945Q434 945 358 840T282 529Z" /> -<glyph unicode="h" horiz-adv-x="1128" d="M325 951Q448 1102 645 1102Q988 1102 991 715V0H806V716Q805 833 753 889T589 945Q499 945 431 897T325 771V0H140V1536H325V951Z" /> -<glyph unicode="i" horiz-adv-x="497" d="M341 0H156V1082H341V0ZM141 1369Q141 1414 168 1445T250 1476T332 1445T360 1369T332 1294T250 1264T169 1294T141 1369Z" /> -<glyph unicode="j" horiz-adv-x="489" d="M331 1082V-125Q331 -437 48 -437Q-13 -437 -65 -419V-271Q-33 -279 19 -279Q81 -279 113 -246T146 -129V1082H331ZM127 1369Q127 1413 154 1444T235 1476Q289 1476 317 1445T345 1369T317 1294T235 1264T154 1294T127 1369Z" /> -<glyph unicode="k" horiz-adv-x="1038" d="M442 501L326 380V0H141V1536H326V607L425 726L762 1082H987L566 630L1036 0H819L442 501Z" /> -<glyph unicode="l" horiz-adv-x="497" d="M341 0H156V1536H341V0Z" /> -<glyph unicode="m" horiz-adv-x="1795" d="M314 1082L319 962Q438 1102 640 1102Q867 1102 949 928Q1003 1006 1089 1054T1294 1102Q1650 1102 1656 725V0H1471V714Q1471 830 1418 887T1240 945Q1137 945 1069 884T990 718V0H804V709Q804 945 573 945Q391 945 -324 790V0H139V1082H314Z" /> -<glyph unicode="n" horiz-adv-x="1130" d="M315 1082L321 946Q445 1102 645 1102Q988 1102 991 715V0H806V716Q805 833 753 889T589 945Q499 945 431 897T325 771V0H140V1082H315Z" /> -<glyph unicode="o" horiz-adv-x="1168" d="M91 551Q91 710 153 837T327 1033T582 1102Q803 1102 939 949T1076 542V529Q1076 371 1016 246T843 50T584 -20Q364 -20 228 133T91 538V551ZM277 529Q277 349 360 240T584 131Q725 131 808 241T891 551Q891 729 807 -839T582 950Q445 950 361 841T277 529Z" /> -<glyph unicode="p" horiz-adv-x="1149" d="M1054 529Q1054 282 941 131T635 -20Q438 -20 325 105V-416H140V1082H309L318 962Q431 1102 632 1102Q827 1102 940 955T1054 546V529ZM869 550Q869 733 791 839T577 945Q409 945 325 796V279Q408 131 579 131Q712 131 -790 236T869 550Z" /> -<glyph unicode="q" horiz-adv-x="1164" d="M95 550Q95 805 212 953T526 1102Q718 1102 829 973L837 1082H1007V-416H822V100Q710 -20 524 -20Q328 -20 212 132T95 537V550ZM280 529Q280 343 358 237T570 131Q735 131 822 277V807Q734 950 572 950Q438 950 359 -844T280 529Z" /> -<glyph unicode="r" horiz-adv-x="693" d="M663 916Q621 923 572 923Q390 923 325 768V0H140V1082H320L323 957Q414 1102 581 1102Q635 1102 663 1088V916Z" /> -<glyph unicode="s" horiz-adv-x="1056" d="M770 287Q770 362 714 403T517 475T294 547T172 647T132 785Q132 918 244 1010T532 1102Q716 1102 830 1007T945 764H759Q759 840 695 895T532 950Q431 950 374 906T317 791Q317 724 370 690T561 625T786 551T913 448T955 -300Q955 155 839 68T538 -20Q408 -20 308 26T152 154T95 333H280Q285 240 354 186T538 131Q643 131 706 173T770 287Z" /> -<glyph unicode="t" horiz-adv-x="669" d="M391 1344V1082H593V939H391V268Q391 203 418 171T510 138Q542 138 598 150V0Q525 -20 456 -20Q332 -20 269 55T206 268V939H9V1082H206V1344H391Z" /> -<glyph unicode="u" horiz-adv-x="1129" d="M808 107Q700 -20 491 -20Q318 -20 228 80T136 378V1082H321V383Q321 137 521 137Q733 137 803 295V1082H988V0H812L808 107Z" /> -<glyph unicode="v" horiz-adv-x="992" d="M497 251L765 1082H954L566 0H425L33 1082H222L497 251Z" /> -<glyph unicode="w" horiz-adv-x="1539" d="M1098 255L1306 1082H1491L1176 0H1026L763 820L507 0H357L43 1082H227L440 272L692 1082H841L1098 255Z" /> -<glyph unicode="x" horiz-adv-x="1015" d="M503 687L743 1082H959L605 547L970 0H756L506 405L256 0H41L406 547L52 1082H266L503 687Z" /> -<glyph unicode="y" horiz-adv-x="969" d="M494 271L746 1082H944L509 -167Q408 -437 188 -437L153 -434L84 -421V-271L134 -275Q228 -275 280 -237T367 -98L408 12L22 1082H224L494 271Z" /> -<glyph unicode="z" horiz-adv-x="1015" d="M314 151H947V0H88V136L685 929H97V1082H917V951L314 151Z" /> -<glyph unicode="{" horiz-adv-x="693" d="M632 -366Q455 -316 366 -202T276 101V300Q276 543 64 543V688Q276 688 276 930V1138Q278 1321 365 1433T632 1597L670 1482Q461 1415 461 1133V931Q461 704 294 615Q461 525 461 296V90Q464 -185 670 -251L632 -366Z" /> -<glyph unicode="|" horiz-adv-x="499" d="M324 -270H175V1456H324V-270Z" /> -<glyph unicode="}" horiz-adv-x="693" d="M19 -251Q222 -186 229 80V300Q229 531 410 615Q229 697 229 930V1133Q229 1415 20 1482L58 1597Q235 1547 324 1435T414 1137V927Q414 688 626 688V543Q414 543 414 300V98Q414 -90 324 -203T58 -366L19 -251Z" /> -<glyph unicode="~" horiz-adv-x="1393" d="M1263 777Q1263 619 1170 511T939 402Q867 402 803 428T655 529T533 621T454 639Q376 639 334 586T292 438L131 436Q131 596 223 699T454 802Q530 802 600 770T758 658T910 567L939 565Q1015 565 1062 623T1110 776L1263 777Z" /> -<glyph unicode=" " horiz-adv-x="507" /> -<glyph unicode="¡" horiz-adv-x="499" d="M170 684H338L351 -360H157L170 684ZM358 996Q358 951 331 920T249 889T167 920T139 996T167 1071T249 1101T330 1071T358 996Z" /> -<glyph unicode="¢" horiz-adv-x="1120" d="M586 131Q686 131 760 191T842 341H1017Q1011 215 912 115T669 -12V-245H484V-11Q305 23 205 165T105 527V562Q105 774 206 916T484 1092V1318H669V1095Q819 1072 915 966T1017 710H842Q834 815 763 882T586 950Q445 -950 368 849T290 555V520Q290 333 367 232T586 131Z" /> -<glyph unicode="£" horiz-adv-x="1190" d="M449 622L457 402Q457 248 395 157H1128L1127 0H95V157H172Q212 166 237 231T264 393V401L256 622H91V779H251L242 1039Q242 1238 364 1357T687 1476Q877 1476 988 1370T1099 1087H908Q908 1194 845 1256T670 1318Q565 -1318 500 1241T435 1039L444 779H763V622H449Z" /> -<glyph unicode="¤" horiz-adv-x="1460" d="M1103 112Q944 -20 735 -20Q528 -20 369 110L235 -26L105 109L244 250Q140 406 140 608Q140 814 252 977L105 1128L235 1264L382 1114Q540 1234 735 1234Q931 1234 1090 1113L1239 1265L1371 1128L1220 974Q1330 -811 1330 608Q1330 412 1228 253L1371 109L1239 -27L1103 112ZM311 608Q311 485 368 379T524 212T735 151T946 212T1100 379T1157 608Q1157 730 1101 835T946 1001T735 1062Q622 1062 524 1002T369 836T311 608Z" /> -<glyph unicode="¥" horiz-adv-x="1240" d="M614 782L978 1456H1197L779 736H1091V611H707V446H1091V322H707V0H514V322H136V446H514V611H136V736H449L31 1456H251L614 782Z" /> -<glyph unicode="¦" horiz-adv-x="491" d="M147 -270V521H333V-270H147ZM333 698H147V1456H333V698Z" /> -<glyph unicode="§" horiz-adv-x="1256" d="M1145 431Q1145 242 959 157Q1028 108 1064 40T1100 -128Q1100 -296 970 -395T612 -495Q500 -495 400 -467T229 -382Q90 -269 90 -64L276 -62Q276 -192 366 -267T612 -343Q748 -343 831 -285T914 -130Q914 -41 843 -11T563 126Q381 174 285 229T143 362T96 551Q96 737 278 825Q212 874 177 942T141 1110Q141 1276 274 1376T630 1476Q862 1476 992 1363T1122 1045H937Q937 1170 853 1247T630 1325Q488 1325 408 1268T327 1112Q327 1043 355 1003T450 931T661 858T889 782T1030 -698T1116 585T1145 431ZM602 691Q512 715 437 742Q357 723 320 673T282 553Q282 483 309 443T402 370T611 296T797 238Q875 258 917 308T959 428Q959 516 890 570T602 691Z" /> -<glyph unicode="¨" horiz-adv-x="856" d="M102 1371Q102 1416 129 1446T211 1477T293 1447T321 1371T293 1296T211 1266T130 1296T102 1371ZM532 1369Q532 1414 559 1445T641 1476T723 1445T751 1369T723 1294T641 1264T560 1294T532 1369Z" /> -<glyph unicode="©" horiz-adv-x="1609" d="M1119 597Q1119 444 1033 364T788 283Q631 283 537 388T442 676V786Q442 962 537 1067T788 1173Q948 1173 1034 1091T1120 860H974Q974 959 927 1001T788 1044Q694 1044 640 975T586 783V670Q586 550 640 481T788 -412Q880 412 926 454T973 597H1119ZM206 729Q206 557 286 411T503 181T801 98T1098 181T1315 410T1395 729Q1395 899 1316 1044T1100 1272T801 1356Q641 1356 503 1274T286 1045T206 729ZM91 729Q91 931 184 1104T443 1376T801 1476T1158 1377T1416 1104T1510 729Q1510 -532 1420 360T1165 84T801 -21Q604 -21 439 82T182 358T91 729Z" /> -<glyph unicode="ª" horiz-adv-x="915" d="M618 705Q606 739 600 777Q524 691 396 691Q277 691 212 753T147 918Q147 1029 230 1089T486 1149H594V1201Q594 1336 470 1336Q401 1336 362 1309T322 1231L161 1243Q161 1346 247 1411T470 1476Q603 1476 680 1405T757 -1199V883Q757 786 783 705H618ZM435 828Q478 828 522 848T594 895V1037H482Q399 1036 355 1005T310 922Q310 828 435 828Z" /> -<glyph unicode="«" horiz-adv-x="961" d="M536 804L794 407H653L358 795V814L653 1203H794L536 804ZM610 548L868 151H727L432 539V558L727 947H868L610 548Z" /> -<glyph unicode="¬" horiz-adv-x="1134" d="M958 375H772V639H127V800H958V375Z" /> -<glyph unicode="­" horiz-adv-x="565" d="M525 543H37V694H525V543Z" /> -<glyph unicode="®" horiz-adv-x="1610" d="M90 729Q90 931 183 1104T442 1376T800 1476T1157 1377T1415 1104T1509 729Q1509 532 1419 360T1164 84T800 -21Q603 -21 438 82T181 358T90 729ZM205 729Q205 557 285 411T502 181T800 98Q961 98 1099 182T1315 -412T1394 729Q1394 900 1316 1044T1099 1272T800 1356Q640 1356 502 1274T285 1045T205 729ZM653 654V316H512V1165H788Q941 1165 1025 1100T1110 909Q1110 786 982 721Q1104 671 1105 517V456Q1105 370 1122 332V316H977Q963 352 963 444T960 554Q944 650 829 -654H653ZM653 782H809Q881 784 925 817T969 904Q969 977 930 1007T791 1038H653V782Z" /> -<glyph unicode="¯" horiz-adv-x="938" d="M834 1313H120V1456H834V1313Z" /> -<glyph unicode="°" horiz-adv-x="765" d="M130 1216Q130 1320 204 1398T385 1476Q489 1476 562 1399T636 1216Q636 1110 563 1035T385 960Q280 960 205 1035T130 1216ZM385 1088Q439 1088 476 1123T513 1216Q513 1274 476 1311T385 1349Q330 1349 293 1310T255 -1216T292 1125T385 1088Z" /> -<glyph unicode="±" horiz-adv-x="1094" d="M649 854H1013V703H649V289H482V703H97V854H482V1267H649V854ZM970 0H135V152H970V0Z" /> -<glyph unicode="²" horiz-adv-x="751" d="M683 667H84V775L384 1057Q493 1159 493 1228Q493 1277 461 1307T369 1338Q294 1338 259 1300T223 1205H66Q66 1319 149 1393T365 1467T574 1404T651 1230Q651 1126 544 1019L460 940L284 795H683V667Z" /> -<glyph unicode="³" horiz-adv-x="751" d="M265 1125H349Q423 1125 459 1155T495 1234Q495 1279 464 1308T362 1337Q305 1337 268 1312T230 1245H73Q73 1343 154 1404T360 1466Q497 1466 575 1406T653 1241Q653 1186 618 1141T517 1070Q666 1029 666 886Q666 -780 581 718T360 655Q228 655 145 718T62 888H220Q220 843 259 813T366 783Q436 783 472 813T509 894Q509 1007 353 1009H265V1125Z" /> -<glyph unicode="´" horiz-adv-x="642" d="M316 1534H540L272 1240H123L316 1534Z" /> -<glyph unicode="µ" horiz-adv-x="1160" d="M339 1082V449Q340 286 391 208T559 130Q758 130 820 282V1082H1006V0H839L830 115Q737 -20 567 -20Q420 -20 339 53V-416H154V1082H339Z" /> -<glyph unicode="¶" horiz-adv-x="1001" d="M646 0V520H562Q332 520 200 647T67 988Q67 1201 200 1328T563 1456H832V0H646Z" /> -<glyph unicode="·" horiz-adv-x="534" d="M147 729Q147 777 175 809T261 841T347 809T377 729Q377 682 348 651T261 619T176 650T147 729Z" /> -<glyph unicode="¸" horiz-adv-x="507" d="M285 0L273 -52Q426 -79 426 -225Q426 -322 346 -378T123 -435L116 -328Q195 -328 238 -302T282 -229Q282 -185 250 -164T120 -134L152 0H285Z" /> -<glyph unicode="¹" horiz-adv-x="751" d="M495 674H338V1275L122 1218V1346L477 1463H495V674Z" /> -<glyph unicode="º" horiz-adv-x="931" d="M122 1123Q122 1281 216 1378T464 1476Q619 1476 713 1380T807 1117V1043Q807 884 714 787T466 690T217 787T122 1049V1123ZM285 1043Q285 943 333 886T466 829Q549 829 596 886T644 1045V1123Q644 1222 596 1279T464 -1336Q383 1336 335 1281T285 1129V1043Z" /> -<glyph unicode="»" horiz-adv-x="960" d="M244 949L539 560V541L244 152H102L360 550L102 949H244ZM593 949L888 560V541L593 152H451L709 550L451 949H593Z" /> -<glyph unicode="¼" horiz-adv-x="1500" d="M458 664H301V1265L85 1208V1336L440 1453H458V664ZM443 118L339 184L1050 1322L1154 1256L443 118ZM1318 299H1425V169H1318V0H1161V169H786L780 271L1157 789H1318V299ZM938 299H1161V588L1144 560L938 299Z" /> -<glyph unicode="½" horiz-adv-x="1589" d="M399 118L295 184L1006 1322L1110 1256L399 118ZM453 664H296V1265L80 1208V1336L435 1453H453V664ZM1481 0H882V108L1182 390Q1291 492 1291 561Q1291 610 1259 640T1167 671Q1092 671 1057 633T1021 538H864Q864 -652 947 726T1163 800T1372 737T1449 563Q1449 459 1342 352L1258 273L1082 128H1481V0Z" /> -<glyph unicode="¾" horiz-adv-x="1593" d="M570 118L466 184L1177 1322L1281 1256L570 118ZM1410 299H1517V169H1410V0H1253V169H878L872 271L1249 789H1410V299ZM1030 299H1253V588L1236 560L1030 299ZM314 1126H398Q472 1126 508 1156T544 1235Q544 1280 -513 1309T411 1338Q354 1338 317 1313T279 1246H122Q122 1344 203 1405T409 1467Q546 1467 624 1407T702 1242Q702 1187 667 1142T566 1071Q715 1030 715 887Q715 781 630 719T409 656Q277 656 194 719T111 889H269Q269 844 308 814T415 784Q485 784 521 814T558 -895Q558 1008 402 1010H314V1126Z" /> -<glyph unicode="¿" horiz-adv-x="969" d="M588 680Q587 574 567 511T498 388T358 233T255 37L253 0Q253 -109 311 -166T478 -224Q578 -224 640 -168T703 -20H888Q886 -181 774 -283T478 -385Q282 -385 175 -285T68 -5Q68 168 228 343L337 456Q403 534 403 -680H588ZM596 997Q596 952 569 921T487 890T405 921T377 997Q377 1041 405 1071T487 1101T568 1071T596 997Z" /> -<glyph unicode="À" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538ZM778 1550H619L361 1844H584L778 1550Z" /> -<glyph unicode="Á" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538ZM763 1844H987L719 1550H570L763 1844Z" /> -<glyph unicode="Â" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538ZM975 1572V1562H822L672 1732L523 1562H370V1574L616 1846H728L975 1572Z" /> -<glyph unicode="Ã" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538ZM1027 1814Q1027 1706 966 1639T812 1572Q771 1572 741 1582T663 1623T593 1660T543 1667Q502 1667 473 1636T444 1555L320 -1562Q320 1669 380 1739T534 1809Q569 1809 597 1799T673 1760T746 1722T803 1713Q846 1713 874 1747T903 1826L1027 1814Z" /> -<glyph unicode="Ä" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538ZM351 1681Q351 1726 378 1756T460 1787T542 1757T570 1681T542 1606T460 1576T379 1606T351 1681ZM781 1679Q781 1724 -808 1755T890 1786T972 1755T1000 1679T972 1604T890 1574T809 1604T781 1679Z" /> -<glyph unicode="Å" horiz-adv-x="1336" d="M973 380H363L226 0H28L584 1456H752L1309 0H1112L973 380ZM421 538H916L668 1219L421 538ZM887 1729Q887 1642 825 1584T672 1525Q580 1525 519 1584T457 1729T518 1876T672 1937T825 1876T887 1729ZM556 1729Q556 -1682 589 1648T672 1614Q720 1614 754 1647T788 1729T755 1812T672 1847Q622 1847 589 1812T556 1729Z" /> -<glyph unicode="Æ" horiz-adv-x="1914" d="M1879 0H996L981 353H417L212 0H-14L866 1456H1817V1304H1126L1146 833H1736V682H1152L1174 151H1879V0ZM518 527H974L943 1260L518 527Z" /> -<glyph unicode="Ç" horiz-adv-x="1333" d="M1240 462Q1213 231 1070 106T688 -20Q430 -20 275 165T119 660V800Q119 1003 191 1157T397 1393T705 1476Q937 1476 1077 1347T1240 988H1047Q1022 1162 939 1240T705 1318Q521 1318 417 1182T312 795V654Q312 -417 411 277T688 137Q848 137 933 209T1047 462H1240ZM751 -9L739 -61Q892 -88 892 -234Q892 -331 812 -387T589 -444L582 -337Q661 -337 704 -311T748 -238Q748 -194 716 -173T586 -143L618 -9H751Z" /> -<glyph unicode="È" horiz-adv-x="1164" d="M992 673H361V157H1094V0H169V1456H1084V1298H361V830H992V673ZM725 1562H566L308 1856H531L725 1562Z" /> -<glyph unicode="É" horiz-adv-x="1164" d="M992 673H361V157H1094V0H169V1456H1084V1298H361V830H992V673ZM710 1856H934L666 1562H517L710 1856Z" /> -<glyph unicode="Ê" horiz-adv-x="1164" d="M992 673H361V157H1094V0H169V1456H1084V1298H361V830H992V673ZM922 1584V1574H769L619 1744L470 1574H317V1586L563 1858H675L922 1584Z" /> -<glyph unicode="Ë" horiz-adv-x="1164" d="M992 673H361V157H1094V0H169V1456H1084V1298H361V830H992V673ZM298 1693Q298 1738 325 1768T407 1799T489 1769T517 1693T489 1618T407 1588T326 1618T298 1693ZM728 1691Q728 1736 755 1767T837 1798T919 1767T947 -1691T919 1616T837 1586T756 1616T728 1691Z" /> -<glyph unicode="Ì" horiz-adv-x="557" d="M375 0H183V1456H375V0ZM385 1562H226L-32 1856H191L385 1562Z" /> -<glyph unicode="Í" horiz-adv-x="557" d="M375 0H183V1456H375V0ZM369 1856H593L325 1562H176L369 1856Z" /> -<glyph unicode="Î" horiz-adv-x="557" d="M375 0H183V1456H375V0ZM582 1584V1574H429L279 1744L130 1574H-23V1586L223 1858H335L582 1584Z" /> -<glyph unicode="Ï" horiz-adv-x="557" d="M375 0H183V1456H375V0ZM-42 1693Q-42 1738 -15 1768T67 1799T149 1769T177 1693T149 1618T67 1588T-14 1618T-42 1693ZM388 1691Q388 1736 415 1767T497 1798T579 1767T607 1691T579 1616T497 1586T416 1616T388 1691Z" /> -<glyph unicode="Ð" horiz-adv-x="1373" d="M199 0V666H37V817H199V1456H610Q800 1456 946 1372T1171 1133T1252 777V684Q1252 478 1173 323T946 85T602 0H199ZM673 666H391V157H592Q814 157 937 294T1062 680V773Q1062 1021 946 1158T615 1298H391V817H673V666Z" /> -<glyph unicode="Ñ" horiz-adv-x="1460" d="M1288 0H1095L362 1122V0H169V1456H362L1097 329V1456H1288V0ZM1081 1814Q1081 1706 1020 1639T866 1572Q825 1572 795 1582T717 1623T647 1660T597 1667Q556 1667 527 1636T498 1555L374 1562Q374 1669 434 1739T588 -1809Q623 1809 651 1799T727 1760T800 1722T857 1713Q900 1713 928 1747T957 1826L1081 1814Z" /> -<glyph unicode="Ò" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q533 -20 400 64T194 305T118 668V773Q118 983 191 1144T397 1390T703 1476Q878 1476 1011 1392T1217 1147T1289 773V681ZM1098 775Q1098 1034 994 1172T703 1311Q521 -1311 417 1173T309 788V681Q309 430 414 287T705 143Q891 143 993 278T1098 667V775ZM812 1552H653L395 1846H618L812 1552Z" /> -<glyph unicode="Ó" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q533 -20 400 64T194 305T118 668V773Q118 983 191 1144T397 1390T703 1476Q878 1476 1011 1392T1217 1147T1289 773V681ZM1098 775Q1098 1034 994 1172T703 1311Q521 -1311 417 1173T309 788V681Q309 430 414 287T705 143Q891 143 993 278T1098 667V775ZM797 1846H1021L753 1552H604L797 1846Z" /> -<glyph unicode="Ô" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q533 -20 400 64T194 305T118 668V773Q118 983 191 1144T397 1390T703 1476Q878 1476 1011 1392T1217 1147T1289 773V681ZM1098 775Q1098 1034 994 1172T703 1311Q521 -1311 417 1173T309 788V681Q309 430 414 287T705 143Q891 143 993 278T1098 667V775ZM1009 1574V1564H856L706 1734L557 1564H404V1576L650 1848H762L1009 1574Z" /> -<glyph unicode="Õ" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q533 -20 400 64T194 305T118 668V773Q118 983 191 1144T397 1390T703 1476Q878 1476 1011 1392T1217 1147T1289 773V681ZM1098 775Q1098 1034 994 1172T703 1311Q521 -1311 417 1173T309 788V681Q309 430 414 287T705 143Q891 143 993 278T1098 667V775ZM1061 1816Q1061 1708 1000 1641T846 1574Q805 1574 775 1584T697 1625T627 1662T577 1669Q536 1669 507 1638T478 1557L354 1564Q354 1671 414 1741T568 1811Q603 1811 631 1801T707 -1762T780 1724T837 1715Q880 1715 908 1749T937 1828L1061 1816Z" /> -<glyph unicode="Ö" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q533 -20 400 64T194 305T118 668V773Q118 983 191 1144T397 1390T703 1476Q878 1476 1011 1392T1217 1147T1289 773V681ZM1098 775Q1098 1034 994 1172T703 1311Q521 -1311 417 1173T309 788V681Q309 430 414 287T705 143Q891 143 993 278T1098 667V775ZM385 1683Q385 1728 412 1758T494 1789T576 1759T604 1683T576 1608T494 1578T413 1608T385 1683ZM815 1681Q815 1726 842 1757T924 1788T1006 1757T1034 1681T1006 1606T924 -1576T843 1606T815 1681Z" /> -<glyph unicode="×" horiz-adv-x="1092" d="M89 329L419 665L91 1000L210 1123L539 788L868 1123L987 1000L659 665L989 329L870 206L539 543L208 206L89 329Z" /> -<glyph unicode="Ø" horiz-adv-x="1408" d="M1289 681Q1289 467 1217 308T1013 64T705 -20Q534 -20 403 62L306 -93H164L308 138Q118 330 118 690V773Q118 983 191 1144T397 1390T703 1476Q917 1476 1065 1351L1168 1516H1309L1150 1261Q1287 1074 1289 780V681ZM309 -681Q309 437 407 296L971 1200Q869 1311 703 1311Q521 1311 417 1173T309 788V681ZM1098 775Q1098 957 1042 1088L493 207Q584 143 705 143Q891 143 993 278T1098 667V775Z" /> -<glyph unicode="Ù" horiz-adv-x="1328" d="M1194 1456V466Q1193 260 1065 129T716 -18L665 -20Q426 -20 284 109T140 464V1456H330V470Q330 312 417 225T665 137Q828 137 914 224T1001 469V1456H1194ZM773 1550H614L356 1844H579L773 1550Z" /> -<glyph unicode="Ú" horiz-adv-x="1328" d="M1194 1456V466Q1193 260 1065 129T716 -18L665 -20Q426 -20 284 109T140 464V1456H330V470Q330 312 417 225T665 137Q828 137 914 224T1001 469V1456H1194ZM758 1844H982L714 1550H565L758 1844Z" /> -<glyph unicode="Û" horiz-adv-x="1328" d="M1194 1456V466Q1193 260 1065 129T716 -18L665 -20Q426 -20 284 109T140 464V1456H330V470Q330 312 417 225T665 137Q828 137 914 224T1001 469V1456H1194ZM970 1572V1562H817L667 1732L518 1562H365V1574L611 -1846H723L970 1572Z" /> -<glyph unicode="Ü" horiz-adv-x="1328" d="M1194 1456V466Q1193 260 1065 129T716 -18L665 -20Q426 -20 284 109T140 464V1456H330V470Q330 312 417 225T665 137Q828 137 914 224T1001 469V1456H1194ZM346 1681Q346 1726 373 1756T455 1787T537 1757T565 -1681T537 1606T455 1576T374 1606T346 1681ZM776 1679Q776 1724 803 1755T885 1786T967 1755T995 1679T967 1604T885 1574T804 1604T776 1679Z" /> -<glyph unicode="Ý" horiz-adv-x="1230" d="M613 725L993 1456H1211L709 543V0H517V543L15 1456H235L613 725ZM708 1844H932L664 1550H515L708 1844Z" /> -<glyph unicode="Þ" horiz-adv-x="1210" d="M352 1456V1163H631Q778 1163 888 1111T1057 961T1117 738Q1117 544 985 429T626 313H352V0H166V1456H352ZM352 1011V465H629Q771 465 851 540T931 736Q931 859 851 934T635 1011H352Z" /> -<glyph unicode="ß" horiz-adv-x="1218" d="M324 0H139V1111Q139 1319 242 1436T532 1554Q712 1554 810 1465T909 1216Q909 1091 845 990T781 819Q781 768 818 721T950 601T1087 461T1130 317Q1130 158 1029 69T745 -20Q664 -20 574 2T445 52L488 207Q537 -175 604 153T725 131Q832 131 888 178T945 307Q945 359 908 407T777 528T639 671T595 821Q595 910 664 1013T734 1201Q734 1295 682 1348T542 1402Q324 1402 324 1109V0Z" /> -<glyph unicode="à" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141ZM687 1240H528L270 1534H493L687 1240Z" /> -<glyph unicode="á" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141ZM672 1534H896L628 1240H479L672 1534Z" /> -<glyph unicode="â" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141ZM884 1262V1252H731L581 1422L432 1252H279V1264L525 1536H637L884 1262Z" /> -<glyph unicode="ã" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141ZM936 1504Q936 1396 875 1329T721 1262Q680 1262 650 1272T572 1313T502 1350T452 1357Q411 1357 382 1326T353 1245L229 1252Q229 1359 289 -1429T443 1499Q478 1499 506 1489T582 1450T655 1412T712 1403Q755 1403 783 1437T812 1516L936 1504Z" /> -<glyph unicode="ä" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141ZM260 1371Q260 1416 287 1446T369 1477T451 1447T479 1371T451 1296T369 1266T288 1296T260 1371ZM690 1369Q690 1414 717 1445T799 1476T881 -1445T909 1369T881 1294T799 1264T718 1294T690 1369Z" /> -<glyph unicode="å" horiz-adv-x="1114" d="M808 0Q792 32 782 114Q653 -20 474 -20Q314 -20 212 70T109 300Q109 469 237 562T599 656H779V741Q779 838 721 895T550 953Q451 953 384 903T317 782H131Q131 863 188 938T344 1058T561 1102Q748 1102 854 1009T964 -751V253Q964 104 1002 16V0H808ZM501 141Q588 141 666 186T779 303V525H634Q294 525 294 326Q294 239 352 190T501 141ZM796 1419Q796 1332 734 1274T581 1215Q489 1215 428 1274T366 1419T427 1566T581 1627T734 1566T796 1419ZM465 1419Q465 1372 498 1338T581 -1304Q629 1304 663 1337T697 1419T664 1502T581 1537Q531 1537 498 1502T465 1419Z" /> -<glyph unicode="æ" horiz-adv-x="1729" d="M1262 -20Q1001 -20 865 160Q800 74 687 27T433 -20Q266 -20 172 66T78 304Q78 461 191 548T526 635H749V720Q749 827 694 888T535 950Q430 950 360 895T290 759L106 778Q106 921 227 1011T535 1102Q650 1102 738 -1061T876 936Q939 1015 1026 1058T1218 1102Q1428 1102 1544 974T1660 612V497H932Q939 321 1026 226T1262 130Q1410 130 1531 206L1578 237L1642 101Q1484 -20 1262 -20ZM469 130Q541 130 620 167T749 258V495H521Q404 493 334 438T264 300Q264 223 317 177T469 -130ZM1218 950Q1103 950 1029 865T937 640H1475V671Q1475 803 1408 876T1218 950Z" /> -<glyph unicode="ç" horiz-adv-x="1072" d="M574 131Q673 131 747 191T829 341H1004Q999 248 940 164T783 30T574 -20Q353 -20 223 127T92 531V562Q92 720 150 843T316 1034T573 1102Q755 1102 875 993T1004 710H829Q821 815 750 882T573 950Q432 950 355 -849T277 555V520Q277 333 354 232T574 131ZM604 -9L592 -61Q745 -88 745 -234Q745 -331 665 -387T442 -444L435 -337Q514 -337 557 -311T601 -238Q601 -194 569 -173T439 -143L471 -9H604Z" /> -<glyph unicode="è" horiz-adv-x="1085" d="M589 -20Q369 -20 231 124T93 511V545Q93 706 154 832T326 1030T566 1102Q777 1102 894 963T1011 565V488H278Q282 328 371 230T599 131Q697 131 765 171T884 277L997 189Q861 -20 589 -20ZM566 950Q454 950 378 -869T284 640H826V654Q818 795 750 872T566 950ZM671 1240H512L254 1534H477L671 1240Z" /> -<glyph unicode="é" horiz-adv-x="1085" d="M589 -20Q369 -20 231 124T93 511V545Q93 706 154 832T326 1030T566 1102Q777 1102 894 963T1011 565V488H278Q282 328 371 230T599 131Q697 131 765 171T884 277L997 189Q861 -20 589 -20ZM566 950Q454 950 378 -869T284 640H826V654Q818 795 750 872T566 950ZM656 1534H880L612 1240H463L656 1534Z" /> -<glyph unicode="ê" horiz-adv-x="1085" d="M589 -20Q369 -20 231 124T93 511V545Q93 706 154 832T326 1030T566 1102Q777 1102 894 963T1011 565V488H278Q282 328 371 230T599 131Q697 131 765 171T884 277L997 189Q861 -20 589 -20ZM566 950Q454 950 378 -869T284 640H826V654Q818 795 750 872T566 950ZM868 1262V1252H715L565 1422L416 1252H263V1264L509 1536H621L868 1262Z" /> -<glyph unicode="ë" horiz-adv-x="1085" d="M589 -20Q369 -20 231 124T93 511V545Q93 706 154 832T326 1030T566 1102Q777 1102 894 963T1011 565V488H278Q282 328 371 230T599 131Q697 131 765 171T884 277L997 189Q861 -20 589 -20ZM566 950Q454 950 378 -869T284 640H826V654Q818 795 750 872T566 950ZM244 1371Q244 1416 271 1446T353 1477T435 1447T463 1371T435 1296T353 1266T272 1296T244 1371ZM674 1369Q674 1414 701 1445T783 1476T865 1445T893 1369T865 1294T783 1264T702 1294T674 1369Z" /> -<glyph unicode="ì" horiz-adv-x="506" d="M341 0H155V1082H341V0ZM615 1495H456L198 1789H421L615 1495Z" /> -<glyph unicode="í" horiz-adv-x="506" d="M341 0H155V1082H341V0ZM343 1789H567L299 1495H150L343 1789Z" /> -<glyph unicode="î" horiz-adv-x="506" d="M341 0H155V1082H341V0ZM556 1261V1251H403L253 1421L104 1251H-49V1263L197 1535H309L556 1261Z" /> -<glyph unicode="ï" horiz-adv-x="506" d="M341 0H155V1082H341V0ZM-68 1370Q-68 1415 -41 1445T41 1476T123 1446T151 1370T123 1295T41 1265T-40 1295T-68 1370ZM362 1368Q362 1413 389 1444T471 1475T553 1444T581 1368T553 1293T471 1263T390 1293T362 1368Z" /> -<glyph unicode="ð" horiz-adv-x="1200" d="M820 1301Q1069 1037 1069 628V535Q1069 377 1011 251T844 52T602 -20Q467 -20 357 44T187 221T126 467Q126 614 182 730T341 912T574 977Q737 977 858 863Q810 1058 669 1199L451 1051L378 1150L570 1281Q438 1372 -255 1421L312 1580Q551 1526 726 1387L915 1516L988 1416L820 1301ZM884 635L882 691Q849 752 780 788T618 825Q473 825 392 730T311 467Q311 327 394 229T606 131Q731 131 807 244T884 541V635Z" /> -<glyph unicode="ñ" horiz-adv-x="1130" d="M315 1082L321 946Q445 1102 645 1102Q988 1102 991 715V0H806V716Q805 833 753 889T589 945Q499 945 431 897T325 771V0H140V1082H315ZM927 1504Q927 1396 866 1329T712 1262Q671 1262 641 1272T563 1313T493 1350T443 -1357Q402 1357 373 1326T344 1245L220 1252Q220 1359 280 1429T434 1499Q469 1499 497 1489T573 1450T646 1412T703 1403Q746 1403 774 1437T803 1516L927 1504Z" /> -<glyph unicode="ò" horiz-adv-x="1168" d="M91 551Q91 710 153 837T327 1033T582 1102Q803 1102 939 949T1076 542V529Q1076 371 1016 246T843 50T584 -20Q364 -20 228 133T91 538V551ZM277 529Q277 349 360 240T584 131Q725 131 808 241T891 551Q891 729 -807 839T582 950Q445 950 361 841T277 529ZM681 1240H522L264 1534H487L681 1240Z" /> -<glyph unicode="ó" horiz-adv-x="1168" d="M91 551Q91 710 153 837T327 1033T582 1102Q803 1102 939 949T1076 542V529Q1076 371 1016 246T843 50T584 -20Q364 -20 228 133T91 538V551ZM277 529Q277 349 360 240T584 131Q725 131 808 241T891 551Q891 729 -807 839T582 950Q445 950 361 841T277 529ZM666 1534H890L622 1240H473L666 1534Z" /> -<glyph unicode="ô" horiz-adv-x="1168" d="M91 551Q91 710 153 837T327 1033T582 1102Q803 1102 939 949T1076 542V529Q1076 371 1016 246T843 50T584 -20Q364 -20 228 133T91 538V551ZM277 529Q277 349 360 240T584 131Q725 131 808 241T891 551Q891 729 -807 839T582 950Q445 950 361 841T277 529ZM878 1262V1252H725L575 1422L426 1252H273V1264L519 1536H631L878 1262Z" /> -<glyph unicode="õ" horiz-adv-x="1168" d="M91 551Q91 710 153 837T327 1033T582 1102Q803 1102 939 949T1076 542V529Q1076 371 1016 246T843 50T584 -20Q364 -20 228 133T91 538V551ZM277 529Q277 349 360 240T584 131Q725 131 808 241T891 551Q891 729 -807 839T582 950Q445 950 361 841T277 529ZM930 1504Q930 1396 869 1329T715 1262Q674 1262 644 1272T566 1313T496 1350T446 1357Q405 1357 376 1326T347 1245L223 1252Q223 1359 283 1429T437 1499Q472 1499 500 1489T576 1450T649 1412T706 1403Q749 1403 777 -1437T806 1516L930 1504Z" /> -<glyph unicode="ö" horiz-adv-x="1168" d="M91 551Q91 710 153 837T327 1033T582 1102Q803 1102 939 949T1076 542V529Q1076 371 1016 246T843 50T584 -20Q364 -20 228 133T91 538V551ZM277 529Q277 349 360 240T584 131Q725 131 808 241T891 551Q891 729 -807 839T582 950Q445 950 361 841T277 529ZM254 1371Q254 1416 281 1446T363 1477T445 1447T473 1371T445 1296T363 1266T282 1296T254 1371ZM684 1369Q684 1414 711 1445T793 1476T875 1445T903 1369T875 1294T793 1264T712 1294T684 1369Z" /> -<glyph unicode="÷" horiz-adv-x="1169" d="M1069 600H71V784H1069V600ZM461 1098Q461 1146 489 1178T575 1210T661 1178T691 1098Q691 1051 662 1020T575 989T490 1020T461 1098ZM461 281Q461 329 489 361T575 393T661 361T691 281Q691 235 662 204T575 172T490 -203T461 281Z" /> -<glyph unicode="ø" horiz-adv-x="1160" d="M91 551Q91 710 152 836T326 1032T582 1102Q692 1102 786 1060L859 1208H983L881 1003Q1076 849 1076 529Q1076 371 1014 244T840 49T584 -20Q480 -20 394 15L320 -134H196L296 69Q91 218 91 551ZM276 529Q276 335 -373 224L716 918Q654 950 582 950Q444 950 360 841T276 529ZM890 551Q890 733 803 844L463 156Q518 131 584 131Q723 131 806 240T890 535V551Z" /> -<glyph unicode="ù" horiz-adv-x="1129" d="M808 107Q700 -20 491 -20Q318 -20 228 80T136 378V1082H321V383Q321 137 521 137Q733 137 803 295V1082H988V0H812L808 107ZM673 1240H514L256 1534H479L673 1240Z" /> -<glyph unicode="ú" horiz-adv-x="1129" d="M808 107Q700 -20 491 -20Q318 -20 228 80T136 378V1082H321V383Q321 137 521 137Q733 137 803 295V1082H988V0H812L808 107ZM658 1534H882L614 1240H465L658 1534Z" /> -<glyph unicode="û" horiz-adv-x="1129" d="M808 107Q700 -20 491 -20Q318 -20 228 80T136 378V1082H321V383Q321 137 521 137Q733 137 803 295V1082H988V0H812L808 107ZM870 1262V1252H717L567 1422L418 1252H265V1264L511 1536H623L870 1262Z" /> -<glyph unicode="ü" horiz-adv-x="1129" d="M808 107Q700 -20 491 -20Q318 -20 228 80T136 378V1082H321V383Q321 137 521 137Q733 137 803 295V1082H988V0H812L808 107ZM246 1371Q246 1416 273 1446T355 1477T437 1447T465 1371T437 1296T355 1266T274 1296T246 -1371ZM676 1369Q676 1414 703 1445T785 1476T867 1445T895 1369T867 1294T785 1264T704 1294T676 1369Z" /> -<glyph unicode="ý" horiz-adv-x="969" d="M494 271L746 1082H944L509 -167Q408 -437 188 -437L153 -434L84 -421V-271L134 -275Q228 -275 280 -237T367 -98L408 12L22 1082H224L494 271ZM599 1534H823L555 1240H406L599 1534Z" /> -<glyph unicode="þ" horiz-adv-x="1180" d="M1063 529Q1063 282 950 131T644 -20Q447 -20 334 105V-416H149V1536H334V970Q447 1102 641 1102Q836 1102 949 955T1063 546V529ZM878 550Q878 733 800 839T586 945Q418 945 334 796V279Q417 131 588 131Q721 131 -799 236T878 550Z" /> -<glyph unicode="ÿ" horiz-adv-x="969" d="M494 271L746 1082H944L509 -167Q408 -437 188 -437L153 -434L84 -421V-271L134 -275Q228 -275 280 -237T367 -98L408 12L22 1082H224L494 271ZM187 1371Q187 1416 214 1446T296 1477T378 1447T406 1371T378 1296T296 -1266T215 1296T187 1371ZM617 1369Q617 1414 644 1445T726 1476T808 1445T836 1369T808 1294T726 1264T645 1294T617 1369Z" /> -<glyph unicode="–" horiz-adv-x="1344" d="M1421 651H419V802H1421V651Z" /> -<glyph unicode="—" horiz-adv-x="1599" d="M1737 651H401V802H1737V651Z" /> -<glyph unicode="‘" horiz-adv-x="409" d="M270 1555L376 1483Q283 1356 280 1209V1073H96V1189Q96 1291 144 1391T270 1555Z" /> -<glyph unicode="’" horiz-adv-x="409" d="M153 1046L48 1118Q141 1248 144 1392V1536H327V1406Q326 1306 278 1207T153 1046Z" /> -<glyph unicode="‚" horiz-adv-x="407" d="M141 -283L36 -210Q127 -83 130 63V181H315V81Q315 -20 266 -121T141 -283Z" /> -<glyph unicode="“" horiz-adv-x="724" d="M278 1555L384 1483Q291 1356 288 1209V1073H104V1189Q104 1291 152 1391T278 1555ZM593 1555L699 1483Q606 1356 603 1209V1073H419V1189Q419 1291 467 1391T593 1555Z" /> -<glyph unicode="”" horiz-adv-x="731" d="M165 1046L60 1118Q153 1248 156 1392V1536H339V1406Q338 1306 290 1207T165 1046ZM472 1046L367 1118Q460 1248 463 1392V1536H646V1406Q645 1306 597 1207T472 1046Z" /> -<glyph unicode="„" horiz-adv-x="705" d="M141 -301L36 -229Q127 -92 130 61V246H315V82Q315 -26 266 -131T141 -301ZM437 -301L332 -229Q423 -92 426 61V246H612V82Q612 -25 564 -129T437 -301Z" /> -<glyph unicode="•" horiz-adv-x="690" d="M138 772Q138 859 193 915T341 971Q432 971 489 917T546 769V732Q546 645 491 590T342 535Q249 535 194 590T138 734V772Z" /> -<glyph unicode="‹" horiz-adv-x="614" d="M286 550L544 153H403L108 541V560L403 949H544L286 550Z" /> -<glyph unicode="›" horiz-adv-x="614" d="M231 949L526 560V541L231 152H89L347 550L89 949H231Z" /> -</font> -</defs> -</svg> diff --git a/public/fonts/roboto-15d4ddc447af43a160ea7249c8a3b8db63b90c43.ttf b/public/fonts/roboto-15d4ddc447af43a160ea7249c8a3b8db63b90c43.ttf deleted file mode 100644 index c114ddd182987597e9e6003cd450985a91196bd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105920 zcmeFaXM9z~_QyRfA=HFkL<k)_f&_w!s1)fP6tGfNN<=Sq#fD-<Y_U+RG(kbHC?Z69 zF$4mJ;(-*Ba{?SrP6)vU+0S?8BoeⅆQ<%#q;Jl`}3QbJ-f}UwPwxQYi9NlQV3B^ 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 Yx?<(XIf|U2Xzb+htd<4({)T`516OpZcK`qY diff --git a/public/fonts/roboto-23d439d23da3eaa8144f02e19043fab2b3f19a33.woff2 b/public/fonts/roboto-23d439d23da3eaa8144f02e19043fab2b3f19a33.woff2 deleted file mode 100644 index 7e198edea70904f915eb9ed6a81e8293b80dfe81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63104 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 diff --git a/public/fonts/roboto-5cb23c2ac98be5b4e0fb8a97e28dda99ae76b8c7.woff2 b/public/fonts/roboto-5cb23c2ac98be5b4e0fb8a97e28dda99ae76b8c7.woff2 deleted file mode 100644 index 2a2edf6d02c9e57faac747841a634d043be04b79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63800 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 IWF@iSBVQmmQvd(} diff --git a/public/fonts/roboto-5cdbe0a3b2ecefc9c25ccefa511cf8a781c78799.woff2 b/public/fonts/roboto-5cdbe0a3b2ecefc9c25ccefa511cf8a781c78799.woff2 deleted file mode 100644 index 45e0bcd1ab18a298bc8baad1e9961ea27384255e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63156 zcmZU(V~j3L7c4rSXKdTHZQHiBXZF~(ZQHiJ$F^<TbKmcr+~g*Abtm2FpDUfJ%Bpfx z5N8Gg2KujFnt_o2J3#!8{=3Tpf&B07|6ka_qBsG?q_}mK5Qab{k^ot#AYLR`=&(A& z&;=3X2wPxw5K_=G08ElN5EvnN2qq*UY=DlAf<z)<ebn_ww51M&b;%BZxO1{J5xuD| z^t=I!(NDkbX<F~tD(wiw@lWV)$xWnd5bN&H^w01AYB$?Cyh_k5p!U(pM?;Y%jtiNX z_&HEpo=u4?X)v%dEu=ZJRB6dpaVeHvOCsZS(U4Qxm^Z_7WR$xZU1&IyWmbZT!SZmS z`MkRdW3p9CE;3k6SpV1t3CYA3axCHWJH}bI6}YN#Sl$)WlZO1_CqMJgR5e%N#CddW z?~?UuL{*GuO_n^wZh28FDm%ts{%cgX6jcwJ(uKfTjf-tn9ztX4>7}vHh-inHdun4% zbtwD?e~IJs_xZYGm_OfYA2>Tohj1mj<6syBnvhS+asgFCm<r_4#!2gk>SSufJLPKJ z*?aEcQ1T*Zy>%@VmBkx|<@#_bP|6{p;dgDAVle-z(O{Yz768`s<u606A5C}oA4`2l zs_l)*i`7~2w{D0-JHF7|5vy^@QIv&0)hYsKunej{Q=&UB35}0;ZLqaBte3}i^mpXm zSn|s+#tK40@rf`joO;Oe*dZNQF47xeU3X;k0(N2;e~em&l2=h=UE<9H%-%$1)eQ_s z^9ZF<)~`Nll-KZDcKcFj&tlPoc!{ZLw?;_)WSX)cOASh9h@;8z2|ffckV3kmD7Sn( z@F}VnKCvyX(WIvIm_(|k#FE`+ZLTj3@Eg0v*qbE69c%>@$(Dsq8oizp!@7G@hY5Pi zzVUN9oL)rw#rkX$R}z(D=mM+2O+N&mhF^Zw`Ct*5j?Jd8z0|k99YG8MSFQrx38rRK z6rw9QmrbrK)mM71WH!+!O}}Q-iZ7B_G)2Uy{{9MiDqi4wh>|W+cK-eSyRpfV@IfL+ z6ONKXo8YaHsa;*UUI=A9dM~Y@Wh~o7?WY>~${=801U2*K25PUrNJ;Eg6T}C2uCpic zC`-bDibQCSlixqne;gAY9R$XNxmCjQbkCt(qSpX5(v`nuDz~I4l;DYn6E3KYxLtzq zRHMOYslw0=Xu=(W)C!xkA#JclqpoX>v_5$G9WHG#up{n*qS4~@h$)ER;4p|mmKDiJ zY?!vTCd0^UYlb)(9M(Zfbc9NgYQgs_->1#Lm0+RN<B|IOK(N5NjKzokRO&<B<T91O zRO?dXu81@Em|$=$yqX#<PxEhd=fLxbt=v*di!OV=wdb>FjBaLkBrO~oUb7hJ%cnG3 zfRJpYelypgO;$zqG+_9CcJLf|j<zaHJQNsOVJIP3VPQm2r1+)LN~{DY3=DaP0vZm3 z+RGN&Uoio+hK9-5!u$%ccW^I1f3NRrbJB@G6fiLmC_tSXFN56Hr2@SPXe|oh4iMx5 zh)H3K1f2b{JNA4n{sLdmbO(Uz=STAx0Xq-_r;1`eL2clU#E7V`vri%*Sw<-3{j0(V z<9YXMdD^Yi5!_Z=-d2O-<f~4oNsvkvI0pwDBT_eeR#jsi0~Mq~(X`9NHmwn9g>Z%N zDsKQ6DRGF;E@dnNC}~5C-1FRlVM#&??Ao^RS!fzi-6(86H+vJa>I^{He2t><%0C%J z2*H5>`AgFVeF{M@q%5iVhUP*uHt4WRT2jmtoPTk3{x<6O4|yEKPF7Vx9;g~L`{z!Y z@wlM8_nPrOl{Cu=(@-s4VFe6B%~1wVwT<ao-NG_!*c=CDb+`dTo)tFm8ofTDK%wQU zRE()+N5WS@{=o#`sg$H`@mfOBMB{+|A+rSqcdye915Bd~^BY+jUyp=R>q3)a3?dvG zhN*rkqpzrE@q0Oirb|M4L`tLmGP-7r8obzec0|?6?LI%C1TJXBm?mc&kv;98jL)-( zb}Z&^vz1W#y3|@8MXMwjBN9#icu9>8PVlRzl2r$SaC5iVR=mpa_kjteQw#}fWCxvv zO7ZL{!IPlP4U5e)&iRxq;kZyKj2>)X>aka}VaBNe_L=bBU~)y<iJtI3%5b3Kz%yG+ zBOqDlKdn&rw2jbh(9fZEcdIICa(Nar7Rag83b(_?(>j`srkQ~Vj}IZIHS=kPQI!^s z!REyXw+K605;w$s7nI-hfSE$#Q3-@JCa6rQQ`A4xqchxSO60IozYMsms_H3*+p`c} zq0XE4+skmCf9sU1qz4j#+Q8P}I1RgoSoU@-xTTnHAlG=J_^8CLpon%~9bxV{yLjIO z{H*2Gs`~W`ND;t4DI((-8=Q1{B1P2)AH8J+id=G{*8RVY(VJp{BT${Cl6IO^@JMRd z*E?Jl?Qd8tRfKs#h+Bz%%u0LCr)VX;kuB;;-X)<+B%vGi?xJCi12u($*;%G@a`k{% znvRU%JRIC0?{Ej4N)6l?YP;NouBQ%a0e8|M?{rj`#JSNizErZk5y>=@IYb{@QN|v6 zAz!+oI7}+#x7gDIs$_Vrfy@xR;bH#$e!Jg(4|-wdS6U;qkv%khIm_>Ds1Ub?V}Y2k zhO#Iy{X@ULwSR6882$qOR&;+G6?`LNqz(M;s1lDCN0i#RBTuu!$C#&bvUak=Cx{-! zhl^qpvBj2_sM@=ogqctErYwR*w0LE9Tqr}!LYkVp_F4WD+xV`O;X@Ze!4y;)6yc1^ zyS96=oLH8_KgKW;q|EOAewtP!U#~l>bu)9gNmSCfnEU0*WaRu&uvp*un8l@PE=T+n zzWXSaEi08*vNG@OxjWU-vU$JtjMW6@f8b`_VWobq?M$OSS5DrK_3X|peLCvPN*JwM z`k^gh#s&h7e|d3U>Am?{`8?h@R$aFuC`%4y7Rmrh23o+j%bD*-wBb|;JCCr89Aiq5 zF;ogs6OG0wnF^1%5aLEp>~&D_O?DKGwg`UvV``8)=xH};`^bS6I7TQWjL5YG@;kk% zpT}crAcvRwjyQ;9&KQX(PxVaGtK;+is&v+M?%8KvE`|a@Rg8!PMNA|KV7`0}^3z#( z7`*blOUwh>1aVRAi!tERxe*KAd@MRTOo2s65b1td+yU=VR=TPHgF+?~3@7s4Ii;EQ zNNe{PFrPuBQSHTUh?^fL+?+tt(EPQfWCut}FNY_5G>mDxaI$=Myn26ng*{SIQd5R3 zl-ebd*E_vezKC#@?5@7+I~}2N7e<b#&!M|u0G-B|3RbPm>IB%81<3^Z(|E`Fe`dq( z5rOeW`%56-rQ_dm&T_h^o~}+dgSw}z;`C>2`oFr@`6D3T8G-Oi_ftT<*&@7kGwjLq z>KZJA_8vlB`~$psAiR|r9Jc-F{Bpo)4#i`fMeT_I90ZyRDAI=(_yIVY!z6!GV`(Lm zDKk;+BKeIl57U*UeF95p+42X>kV$c{1RG1Pl;x>ToqrKJfCCBxf@v8kY2VO-=Xi)n z%JJpS0Ow`?6Q5fvR*wDq88i39-cKZR9Nlc$k|q&t)VC3F>~p3tcCK^Bl)Kp$<KK@; zm5^5ol$pV<+#ceZ7C2s!Ec=-{ynsGplw-$wd^~aqy`d4w-3-gj^%E`Ia}Jss8Xf@f zl}VoN-K2ri5YXIzM4|_LT7$pY0W`mv*XIBkx#v&KbSEgD4m17;M)fP1Ol|j?<HH+} zujA0w(#C_h8=$UkTey<jkt|sSOVqJIUP<U%(8_vvhe$ym=WsX>g&=?m92g8hA(D>f zgtCm2N+h0+4N}EyxmdE9E0=0Q*E}Sb&1AM4t>$_}r`2x!y50S#WV>Xy-FO&k&GQYR zC<lo1o=J*xGb=?p?vN5URO~?23GGXwVh4@vLy0112$#%b$)aZs9p8fsC#*4eTHERh zA55)}SDZVsoLDeS={1|KN2=MZ+HYm|xp)c5cv-mF|L)zLy*=5|h9g(V)+$ym{rI96 z!uUj*YpSroP~32}IG=2Vq_o7;<j{C=-3R%OA$%f<5mQrP<s?Q9l<waJI~z~B)8tP4 z>|Pt;zje*-T*=!D2nKAi&-N1ZTs!s|8D+M|ubC-?oSo$2_=Dau^1nZ!MLjnqx=A%i z#`q+&m1SPwRZR8lOBD#aX6<oECP`CZkBAP*3!1g{95`M_Ae0YbI1i=NF@>sbIt&fH zg;P?i1bM<*&?aqC5q|Cv?ZZ|Oz)H^?OW4=GC&wAG%bpD@n5mVOq-S8RB&j>Ft^A#$ zu)xDY^?<10Iyc_FIjws;(-2S;yTN;%Ge&RgiL%#MK~hEjA$)n^72^Ot08<(bthm}D zQ6m^3>OixdGqSvbn}zK&eaf>ygH=pDvVVr(Bo`lD6sFZ%FvGDcek?xJ)BrkFs+|ub zi4l(j!t%N>tdUuO*8pLa>!&}vs$L_odhT5=UQxj&$#;f1f1GL{TfN4vHHMqmZS>64 z+Wo5`qqb~$HUu(g%GC_hDTL=7N@c-o!v3QPYXp5|1Ps9{#J7q&dJp5kgo1I6-pnyz zt%%gXbU%oG#iS{TUkx&%&omT*gv}OHn$)Vub?!()R(^>Xg>_|v4n3|ojURAM95{!0 z&ZZy1%x%5IG$(i|>x^Y+ZtA;NF?Pb$Bu9yU680dK&4}$_wGfC9`viC^jLC=333j<8 ztK8K<9<6Y}N=hBqUVa(wl*9IYliG|0^^C2+>2)MI{W%_`|DK)Jr2)W#K!yop?n#E{ z1r`;+(``D0rHLpGa0RxD+Rd{0ZMBb(=;yM)?^xNq6?6FLn=-=f!k*IfMTcIvlhh}Q z7%|rrCEj7{V^vgo=l9+t&6HA%Rz}d&KsA#s@H>^5yzu6raA}I9IH+P+(A9cw$+>Ia zweDZ`?~3J@Azkqh9>Hk(>jL7zjR}Eb;Q^8t)1nLz(*a0^B@ksxE#B^U*TlGTA7SG? z9yT4m6E#o=+h!1b-h}?|QUHoC*m*kSg9zWK5bHKJaP39euyt7{!-g^AH99<e?H^Qm znwo$~gq1-XAM9Y;R&b+D<ZyoQR(RqQ4T*TCslTY%PWWhPcB0d2e)%`GUT2=DY#;Nb zM4TU-9%$6zGJyMtFA}1TWGU~$tz}6+1?@4-G2Mg|Bl4qeIyO|(RIU&$_>pyTGJAQL zlH_<9t)BaLl(u&`CO-jr)EtvQ$9q%8C`t11Da29#r6EqMRE3%N)Ibq!XMA@bJ>*f* zqF{Bh@_p9w%ydEGCvezdSTm|d$*o{8NZvKXApmi#%NPhNBHpWp#9%J@9pys$1)%_G zE5u(b4m`elV%9}6?I*79=`j!E09B+_HKxi#o1vOP9J~sg$_*Gd<Gj%hl7vWNkk*;} zV$H~eQByJDKh|#Y6aJFP&_Z{CoV8;yhUk{4#!C4R^&m;~sI(h0BF@FMGcfa0#KfQ| zNP0X%AR+N8fy~_CuQ8#l2;66mIl0MNqU~v6OTk7U?z4(aLisogpG=(ixtwDPEW$a` zGA-i?>2V7n(vn2~)XkCM)KM&wGaADa?Kw##8(>0elvqhwQTS>RuffSsn5xa_4bz`S zl+?sHc{BM_=nus^Rjx%Bmyz8ACoUSQOf6Y7`w(Y<8VG<rD3^eD(IN)QZTCL29oSmt zZO;x?S*Q6E`UL%jb*5ECs*kIatV;;e{G(x4<uR0jlku%vZj3F%+UJC4=7v+%XFE0C z&>SSkg4FXW>lXX>Oe1J(Nbw3u(>gK&y4zYHu)D#r-mv6HU-+1f1Km|5#jU}}rfvME zLb4Jbf<fjr33P*;K??%3d3PEwFC4YYfzUj8`3N0xSs8^$dnkpNa|b-K_8-y*L#Ry= z6KkVK3^oFyf#A(816YfRdR|z$c(q0K6BE<3iAuKH1IVQ>w!mL$k+!X4NWXx{eiIe| zIMB@yHlRE5G4MUeuxat<LiYB8>?Cn_>W{MI{&<b7(&Cyvht>3H;mvDIx&6;GUx-ay z`iJ1vHl7O`Pl0W{FnHrE(6Mz~HkK`4E?l>fG1l@(R^dy6i1|kl7?Bs*s^WJoPz5B% z)6}&JMGA1Nx`JW-60LTL&d?VJh%85x68Xs(Ri0dQ-49G48jUuk<7vptkq*)|L)ri6 zK1V}MTG6DdR2t=`z2!bzrj}jgc8Ni&;N(cCT+;TS&b5H8V-oP(Vk{p_sswnXe>hS{ zYZBUf3Sg8nR<3M|@^jRyg`C2mja!HHq%{}VIw7M}<js~|%$?YYoRx1Gxt^z;Pw+rc zccc|sR4unXk%=d^<EQB9N;_NO7J*kII0dnC@07_EIAxg~u4P&26AW*$lVHmh!)#h_ z7|F8^s&!xX7)$2?Zq+F)<<}7t!vVz(ndxeX&^Rb9sDDK-ZaCU%=<LmhR9bz=>`D_O zti6_;^Hy%0eJcAjg1)hDxaGbu+fZ|#JYT>&1xPrI(BGH_^0K6VBvMDA5;!{w+KQ~T zon&y@EX!Opz@xaI#HQNYUy&C(%`c3kCt$D^y;#Vzh@ZSOI9Ud1r)#T5l1NKgkh8EO zMLPn88mFYjQ4L0|_Q1i{LY;qM*{EnDZ)vHRRe3!nMLm%`M4E?OhNc-T`I3qCRi(Ey zaS8=WW^nt=z}eI7SfpUa4^udk-4d%f*`VaAQ|Y%i<~0O0LV3px3b~f2-yXZc!$6kX z%0=W93L0QJnf9V9V=0yo@X}NEB%$~qib0hj;2~m`2Kv2a_-bB3frq6f6PFF!7&);n zT(P`x(y}|vGYLc3I{=eQ)=9`&x+)l<bCi7I^3cn3xW^lL^Z406_#xlJ<sIgO0Zugh z$I>ZfjXNB9)_85-NBM#k7W!tvH#pqC1fMeQ-@AwsQs*4?ICtQ}yu5>dH_#5C$?#J3 zV?Pbd&dJ~<Mt<H@*!2%V{$<rUMg*L@-f!e5y|Kq|V_!Q*8yP|4A4|?5q+_v_8bxP* zhI%~G`9fOLR!Bv$<8?k|4()I|9!!PMw4L;pLMrHYzr!F>N;-J8T-ewLH@B&Xpoqil zZib77QqHruPP<Db)2emKt~(yns8*}KSAT9?Q3PTBiL$7lRNow})M@>0wE2B&XZ<e8 zz1CZK(43BXYd+9<8!;g0d*8@>7LO>?e%L9|T+khz%1*V5R37>2Mm5**(Y`R0>MCg} zuB#CMHJ_6l9pjj?n5S!dw#xD~>qp`pZtS-=<<QqxW`L=SQ#ie!C&p;d7pk4+0GV zk6?_v)yh;XH~8QvRKcOGslB<u<Gwe=RUas)*+u!+GO>7^-NRXI;<wJcphAYmvfqS5 znSJz9Vv)TF7^PXl66e~EKGCdt2DDA$Qi8&o9G8=TLYu}_qmnn}DoY5jby6r`;a}#8 z#V@_|6f)!*G)CIQF}4UDK=<nOqi|dhDT2sYOtc-Z^PY=n227g=r}b({tL;22&vjx) zrl$gfnivIBE>GAsa{?My_)B^Yu2WNuTL|NLQ6lI9STFu;oe2(;ZFLck1D`i)b)Zw> zd2c+bP4ga^OeTfCDGuj^*r33;q@??V*larfU!hu_F&lsNb7MXX$*6ae=F24%B9V9? zDwnh>{{Dal81OsLwI)KuWBJ7RDf21mFr~=yHXV(NyZ#5kecg#YyVvT<+TYJtlv!Ev zI90kb#mZf-D($~9`S13{Y+x}nmCXh?`LcP~$$1uAbPrF|m)ab?>o2EXpZL4aM7>*& zfAj7G<WFFF4{$cWSo$u@ygmti58Hfi<9@pT9+>X_q&@D2*7Ihy?W?ly!4u&Nh3Qk{ z&?hUnC`M~aK3%0ljFex@1W_>T7>~&O?;B0+c%?^qheW32f+1rRkDX;G@zrm{U_MS8 zuh&rs24g}gA5kiK1Vb7idBcr9wJB+Qg9A`WHTwpbbsrBXroFXlE&9PC&~V_h!CjDt z+jim1TyDDG(fgXVFioPFMlnsI8dr_3%!VFHK3p~yBi6@pLQ~t3Io$7P^&xxl;OPFb z5oAQFwp@Hy-tTYHnV_%Or4l?pphi9Xlk{+h=Lil5BvH%gWt0y|gusK6OCF5WPefF` zVm=7=DG0EJfy<~H4@<=t=PU5i3T5zvhB`u-v__PiN^mx3G%2QDoHH4Z9ss}i7JK6p zoTB-H-1c0q)xiBX$v12O>MzU(1@aS67=|FEA~q{+E!H=fjv`@S@+YU;a6VhedNChD zOrUgB72v)%`Vc4I#|k^4JlS$8DlT;V?uKV@+IIO!27bu7IvA6Z-|i6j>2TEhb4g@) zmzn(zot)X~e#mcqYCHsWjze@h_%l(EEQ7@~?Q{6Q-hi^HFBOYr!RvVriYAxO3^w)N zEE-7rU^*NPS2+27IURRy#frdI@8L0BZvep)^^(ayy?ii`%E7LeeFwG+7P#=vW%(9H z;+EC$F~`HCPOo_Xj3LE-yI$Dp^WI_o>UPq%F~D&{#PL0+&dZN#hK-btaY89YWBar+ z!9^-9=ll<0;=aYd+b{_g<M&>y84SEgihFV}H;f?<$)r=M^-66!9?+=OE4y8yUC-w? zKiW7g+wHE7Q|<b$Hhwq%k#)d!#CTk#q$SL9_l6jJt(U=;#Fi}6`Oun}%TL4})uU5W zc1Y%>Ka0Snq6gAhQRHAUrP@!OH)!QO>S&WrGObeBO~f7MG<@%ag(H#(MdFfGj@BQ` z#%nh0_pjr_oep3m1LXI6=%N2Fa=eeDQE@!qV@I#m)4)r(&sRfs;n+%~WKzJ!$=xDC zCOgO5CU(VAKY-&vz@;geC}uSeVWOc+x(f#>Ic=N#;dMu^1KmFLygM4{>d}5};Sk=~ z9GFAr;m|KMtynO7>4=1Rheo4O+hJeXZoE#@`!vAAaBLVi;mbqb4HsZB(+~B_=2~)6 zHLXyt+9|>&czJ%*4y`ZFaYiQ@eSnLy^RZlvYZVXxCLWfICzgnqAmM!ju<t)dA%~Gm zW!feY)M_Tj0sPCOr|yH?a`{E11bS^bcKJ7^XWg|@F-B|-tFC+5{|EC~aMKX$gRKUx z*M2U#PWa;d0~|kNvI!N|%ahA*@u}Q7nr&LX-e3RDV4N|f5~o(Q)PaB?{$E!LALT&8 z_w1wM&t;_BKePk!mpli3F8yEC*XLEAuG^gBL7<%-+3l(0VT4wXp#O$CXLW-Gc2}#o z!*|c^4Y78fR`1DgVlqM{<B}(xuUKeQYCDxM)%Qj#McP*ZMKTueP#SJItJ!*~B$wB= zodkXLi&?N68UDkOaF8>34go^TU}fIqVl@*%SuglgRFKOmr^gC(GI95f8g(kNGwZeu zhS5x|jJ<|eUNN5^roJR9COIca_@C3$mL2wb<%h1;?!7<vklxRMRFSF~=s5_~rah)A zzS)&>9=>9f0_EM?n0aA5S0iF`=%id);}tad6cC?f@u!$gV;JUT{qF3Grnx3lLzz)M z9{yaBxRdr}Ghg?!C6|smkbQHS@Es#ikth{G?2$@MCl?(52j$mWZ@$5Hg+-(!q%b_6 zTE*tgs<<Zf;tFc`v^Kn4U$pwJ$&Wx`o|DUckQvk{w_h{rX?5kLh*pU$y;RVeHtMk7 z=lG%6yzQGx&@CetD_XpOjP$zyPFodd?bdl{huIk}rV?DXmb8buhBY^m^-hTB;Er%= z9a6F^huFNK$lY&%Zaui@tx|~BVAf>}mk!TxKAG@?o1~GS3=LtJclX-Jb(zRA;`dk` z%G;J(G=PC>E~|B>N0iPa5UX0vTWz0wn1mR0zxlDsc?+c>Hb;^k=8QQ_Gn#7ue)57o zHimNM7b#Hy!e+$1mc`7ls@x<hDcDfp7ZZ-B77KQejieSftW&I~7aCk;t}A^o2E}wH z&4z6G*2S--9jek)>VQfpGVeATw=P`fpS5Ddn4gONAa6@NUL$T1ixx-l2ocC|0Yr)? zHdbAi7>F)Relg_95tBxCO(T*t9S67lxFLBkzjR!O%Y~cZ@r(#%1;r5$giy9+nQ$Gs zYxyVR!%7nj<g}a5pSCpl3K3XNXpNz&tZo@$kqWh8ndJjX!6TE4VSONATg1x#(=-V~ zNqv413$uAl6T|aOgQ+6f=O!m3g`W1(&gva6T+?Kn3n%A-1`uPo=#9ftq>p7yLF(|w zV-YH+KX0cKE*&)pz(K2L^H@wK_ds5Le@|wG{|_0+&HM$I){rZkE5x8^81X+(_oKL# z_~7sh+q+JDAYYw}Laen|lHir+&cHc_XAy78AjI47(_Jm&`#bOOzm5(kWkQ8{Wj;5f zS|>}kSgR*ycDN$;a9K_3vTQi$w7Gde_D&|y&?eVrs&dG4BmH|Zv9P%F$jVlPS-AqQ z&?}o^i5+h;^fDcIiQ4W!3rVW^MqtHM^iNL_ADIQ|W!k=49OILlFO&<T@3BIFixMTg zC=2&#STp|Mk{e`!pJu9h{8!NMc>~o~r*`7h!%lMteyRRHO6oDC%Ytir&ao@WJGiaE zE&tEABcYJb`8>>{Sv_ur01j%KpnCkzGGWqBlhf$fS)G7WEvoyhCMmPcd%Yc8Er~7; zL^bSApK?y0MgBDNlW!jAhMEw0jpb;Dq@SQSVUu|FY%KEtcTA6!p0O4AmPuAZKPTKK z+f8Y4W#3YFO#zKXXqgP4QRH4puB+K<f5mazxZukRERlg44<#cEI2EFhT&U2J`cR)} zU^-tybf*E@t2a>TWIyb+ccZ|&pr2KlAjG|NChKvzhSM`RD$k`5C!aBLNu4aws90d4 zr+`l8Us>vFIeh1bE;>brc;p&bdWl5<K%cDLW;>q5{ijXSHn};GBE@Ph%0$v~7j&GG zsC~>694Viu;It8}co(P4|7my~U5v7cQbZd!!UV}(xgYf_44U6cF7QYt7Pm<+3<ef& z>fH-H4UMjS&QH!xRFVxqVpr=^Ia}VN4TWN|?g2H!R}=&?YkpM#fivC700~dhINY_m zG|maqF>qQgd%*&LaPtRNwIv`xNx($GEd|fDiLAvl8usWqrjl*^d4k^rVqXyvlkTdA z_`BI?z43f`=I&@Ifd$oEbl@wCIRBmuy0|pK_uoRG5rj_%%M_nsO&;iV!fHuUS~?yX z8B_JYL;1Taxc9;!=30Gn7nD>h7&2NM=DvB8cwK2}GNt;&0Uc|dTi`Xbc0)q*pHhUJ z(fKg@%=>n+VElAG^=&PID&C<nDQgnS_yWI)2#UJz*dx{n)F%}j8}TnH#46QUJqldF zeI=lDC4Zz%8SO*ptXsZ$K7aceY|e`{e&694E5@T?QsRsPU`Tljl%lPjP6v`O>>CdL zzXC#g;&P8zOnf%F0AKT3Jo?@I@6T4B&kg+S5kQ;*gbBHLOsVhzfWRLpXa9>6UdNpi zL0QLzcErI=5f=o0pU;Rf@)nZqn<WG20Z8t_100vS`#67Q013(3YkHHqIXDQpWw!XY zsv>gl4)n;v0HR>TPyY}IoQ-@ZonI7Jg`yoPKji-;j^Q^1Tw8>kd<K&SI{d>1m4MZ_ z+;rOUUkJm%|3hGb6UlYI{?iR%XJH`tZoY62fis{yGtCW+pr^OKpRgZl`pugaBp0I% zI<a-Y|FlNiUCU;|Eh+4&=0*@gumX;fzYg*Nc`$xfwewOUme@%@y^hFdZOV*)#wU9& z-6vbm2TrL2_6O}?Wuz!$`ip3PPV9f5F8&EP&h0N%vEM|z20k!>FZXWnQ)?hkbQwCu zc}DrBrorEy6QH=19t1~thMvx*XgBm|rOE?Y46~+h!L?x}|M2+%RePUf-VJ$j3K_r- z%K<Hn*Z(`_uEzNoWc7Mx@?Xs{N9`jRLcEXzQ*~=(eo)`zpZmgG?=Iw)fZ5eH7epF$ zOJ~^$U&cnH0s6qgQb4fKmKLE3e2w-9Xn#-5^!$uvrXc6MlKIDE3U|=2zhd!u>fa;B zR>*;kqi`8=6DU{&xwo=yfGc3DI1Eu@*wDrGMz&YHVx-+p?wM20;nlEI=Jox{wIJL~ z>Vbz>ArQB7M&_|^3#a(H>tJ-TFesklEYsVv-I~3OGJfkvcgTX^;Eg-Zkn`YWpE&H4 z)--X@cPY^2Vu$x;u_*>;A36@Mv05kJU{qxR(z4v-P~&PY90kLR5N6b5!+&09Tm3sr zZJUMiq8!ZiI3rlM=f^nR-tU4W&xA0Z0=>b<7M)(-3VC|623_RqTX8UtwZkp)M*K1= zzzq(oa;G^NY;9R+le1PWckp-*3FT!`fVX6V;qq6b&tR}+nT$l%37uBCSa>_B^nNbO z-23n!VZG^ax|P?<#O7mjV@QuQQj+3?TCH>o_HFlTz;M^g6^}!Cadly3X>CD8NlnqF zXWh@|dhugU){fI{iG){O&-_Z(&Z<&hT`z?WgeGGIprK1LzR0S%4g%prbwNbe{ayr# zWFQlcVaGc-0+~*{+FdHKL^34c8y5!Rn-2$elx-t7<T`Q#<1g}xc{*cJ3TLV#zMgeD zBS9Wv?h5Na#jPmm?jq$|@9Un+u=CRFSJjj6%DW#lAHhNE<eE%^o=1~PYl5tHLOYw# z3vX>Ue!lNaZCvTMl6W~Q)j}xN&wKlTz9ergpmf>dnT0>0o%g?5FJ?>_&jH$eB{ouF zFI^`TpJU&8x#&#YVY<4iOJw$bL+w1HK%SxZ;+{cRA|k?}b-uq)dO>SOHppJ}=6{7& zxbYKPW(nF|!uyQ3oq|a}sDJSbw10=oU+sk1aB5L;#<Af>DV<H?;^h#w-G{*#kz_%V z22ew6wT-g$C#L-~4AIl!PW(Fz@zW91DeF^8HY!2sNf7~HiK1c>5(XcCAU6wCH?<7A zEW5rzS}A(2RK{M?JR$c8Il<sX^5Wa=bY?sfNu?46b$|E|UfPfADU$nAj1=OWj`)Uh zi+X^5H9J=oAdqRi!O|N=n5k+{_ofUp%BtUy47o9=FC9VG(G&5=z1-p3aT~aRx#A|z z;mfQm%gi-2P}LQa&O*V`y}FC>k(aiFk5%>^kisaL8&W0xJ4T3A?*9vhr2-hBbeP4c zl1r4*<Y|Kx$>p@1%~Vo@s>4eUj_lp97;)9eG?v*iE2~E5!lJqTz@8$gVZ~Y^^q#A$ z&8_Hma9vvpT1b`xs*+0S^Z(fLIX{CutFUsue4$k*7)*>_WWC<nQ=i^1ut8e!FTV<W zl&g=di0^RA;T#eD3Dns`SnIN9ylHX9ORLzew%7xI!{`S44dO`EfGmeZg+GQv3VMUC zC!titCrSWxgCYmH2_fI%OF}0G91(&`LhV3S2wDpOSt{(6O2i6P#3iIcnL;EG!i+)l z1FZ|X#)EnT96@GDqAZ|NH`96EX{M<V(S*npu~ePPnN{`<zR64EW!yr=vXv4nVC5YC z6@3(U;>lX*_dYhucgefV37y6w{sC)%)+zyUMPpC2Vk#R{lv6k}&Q)WYT@;iyI7!Y% zGuL?xnnE}i<y}6i^vRCoFW}BYeFP$tRL0SnYExy})t+}lf7C<sQNZd;k6s`7YBVKF z5Oo|7yMFy1_$rFbIGb5B{;7oi%(4u&_`%+L`_aVhxDb%}-6QDn;}+og{kna<P>lMe zycO_k`?>6c^zg99{S44=`T~YHyMw3e1x*K5U{{qC`R>HU>~y36RTn3NM?s261y2+A zdJ1n|BALlSCd5_^CjW2hMiEBl@>=TRx@l|@3{yEP9~KAgEi6Q-eb0i?y0yP9G2xZ3 z9kZ1phxvdx)B2(oKGyZ&)=`((e+F*5#+Rz}TeuC-sqH7g7qfF3=|x9jLPBZSSGs8J z0TD>}5IsWiPze4O+X{R%YYqt)Gi1^PNewhJ<YK+;D)U;kyv@8^GD`Swk+^+HH=&el zN*$nb!p-<M?cs7F&<hUX<Kgjnb9iFzgx#Vqj4}K{ko!KUD;O}?!pr;~`7XGRi-aqi z&gOQyn2Jg(T5>am#@S?%82y1Cvxo4ynvo*Nn#B8CIx}SC9)~-IktXgt?^kTJ%XfYV zvzY+gi?wYuKfWkW+j2(1>|#u4cCd8Z>Wr2+%8Q7GhK3Wq7I<Ir*-etQJu{5`(d7v- zNX@i0V2B_S?IYv)Ky`VUV6_1eAL`SlU~K$Am8D;iCH9EV-WY<6F;8EB^F>z?hcFCz z&?n;8`F-@^5z_3m^hS}_=tJhJ=nxj->TIgc_)k9GHE3k90M6*%+fqUEi=~;4_6KJJ z3%xFsJ#6H%;M?flRR%A=7Y__yk@E>SXvqCA0P-ISlO)iM38EhHJTdY&(L6444$(Y1 zG9S@A93wIb)Bo8G7!U38pa&#m_#8*T9zy)_1fo<AVEOqZ*duo+u9$V0zJ=ijn)CUj zlyDQmT@tp0?1(%L7j(~7ihT3qWxU(yZk{38{PRE?;>r|$R1EMlrJK6VI8~r$<$|4y zz_0N{=eh9KIPV6$AZukri2te>_)Jv~yX>SVdk$R%Y5^$ngGanZV}U3Hb)r%UWrG&q zI7G~7CZl4(yl~>QTwePvmK6_bgXJ2aDJ5VFB!#G!%;qB_GWNrgD*4iM^5K(Ps!-#5 zj-C*bb#(<b0jfUJlbA$udapckrv0rrXK>R)FN!GXwk4VlD5T;E=qM|?@6bpzdIi=l zWV?9u5?JcI!&LL;6QMW)_9_)G=oLzR%OZQ@YB#|8$jRsK6RA9Y1qWu-FY+Sm2tn~- z@HqUI3#w<Hqp@K?M#!dA_xgwHLwl1Fad>_IOv@J@v-uPP2FWJWFM`OQ8Nr|#_xy>a zQn7u^aowSiiKJqg3D{_&=6>lh`A7xBQC%RWxE}uF-bUSHeyf0OAALjv#ttWu=9w)L z-<40}+t5=xUB10l%7LzZD2ph=hv>WA=iOoM%<{zX<_Cf{P!TFEznf}*Yh=I6y(EdR zszMuw*?LlklWOP8rg{6BnQ$&hloQhvSx&9{pSC+<TP4C%nOB>ZBy#)a^kSQ{KW?g( zE2>hJ@3BB3LzZKd{g$v$ROn#>ysI76e%OCfZw;JBPDryiy(w-xxBD=DI!><rKY8== zlqjxo`F{oS)L5~=;C1;lGfLn1?*j5TnVel-pI)A`7)=H;BbDc6a5)*w|8U3M{#HUG zl8UASlr-C4?{y>uMTNzM?0lwLW?cksUq$-R384OOaH5;*rZHqBrAoa{tIhW?^!t`i z6fSAqxMdwrK5g?bWgIQAT(yEtJ7>p`RV$sYrrOT-TCgJXPkQQgdoDq+Qg*SHezMwj zGu*f;ch)!?J6l_GYm1v?j$Z#z=0@j7=xFIl>PqWN>`d)V?oO{S3JVMk4$r@*zNDzE zu(UV>K}AVTQB_%8Vd+dO3<5owI57TC${oG8L6Xo!g5g`R#ouRDn}hJa_b8rL_xD=J zB`a4h$NqW!(-%vy@4)*~+*mG3x8B{bk9qFRu*DS~@xu}CF(va|y`!%nMK?#7Q)V}U zn4NC}h6+})bA*VHCPoLlID*)~&;YSWjzcmc$y8!BY+~ie{rz+6eKQJ+hFk+p1_tbc zZ8-{G9+&?zAOb(aof9;_b{tg1JJ_foLH$JTh+x4Oz`^l*Ov+<{Dqutj6GzY`(lzrJ zPY^}pwhbFs@MV+N_r|quTprR>&2Q%{=42(s(-~<QErb;I_Y21~t9EOs8;y1nMm7=} z3cLMtV{5}xI8H{q88atQ#}|vIzmya4wviR*E|b&l8MIB)Osl+)boFz@eQSTpOys-H zJgF<n66DGGuC>rRvdQn7pm~YoB=h&(o*uyo@qq^Nd4vF$au-l8L5}6VpT*Uc0!I}- z)&a_{=4CvT`w`6j3@>l2#>U)AI|~N_IQ4v_h}cUF$86(!Yo~?tyaQ!#-Ud%JJ|y;H z%IBsksuDeL><h+!W8D+(J$D1`=74kNT(&o9qJZN5G|=^u^&X||7FN%+@Fa86Skl?@ zX~OOOTL$wLw%eoN8SuRj>Q`_B`+~*nIV-bahj@bmO4F@2GKhmznTQBrtbW7u5Wbhj z@AL4x)~KZ~`V*~R=m9}48(h&0ZM`FyMRfF%Aj2QU`)slVF^XQaMZREVMa{SIZ}CBv zqo35VW&Q(1x;W>Q+pBM#dowbFF-?1LY?IK3Ak=9)7f|9+;+wX;>gck7PHfNR+};~K zq-tJxcYx3|y$WKprFqPHrrV>xT4M9S$#)v!Bpzuv>Jqizy%T>Yecd6RmB4;H&14=e z?5AKs(@F^M4n+W^gTW-Vmi7ZR%u5$C8q0E^i*!c_&?=6Ak#-FI25ysEG+g-S-T7Ap zdVL0tRYaYLA4>(QI0$f78~lbM#fqIT{mU|85^Rb&Ln0er$6qwO3{n?<$Ymj^^i1V+ zqAXnS7fFrOF@>fQs%!vx6Owq%z=mw|Smj)xw)A20ghYQ#9d7ytQL(@d%uVbxF~{KX zkD6wGWM-H<7&O0$5GkTa<iAnod?X3%@%-wXhza52fB&{&v*8$cdxDWL?>QmLxpX~J zv8fd-3(N4x(tJXvqvqls@CQH{ysdoi5$I5JI>5Y1G)ViV#Hf$~P<EZun7s@_vBkX$ z8lTz*kO@nL+Rl?!9eqY7&HfXLW+Nsl5Y}>)Lf6XoOT27r%A;O{F7qEZj*6FMs`6Ya zHn?c{?C(|O4awb&8wBaFh=Ut(yv{#UVOt68H+tZi)3!MqER6z<dZQQm8>0#5=E<}c z_#rgS?qQ6OSgG~+d4uS#n#Adz3Viodpih3`eH>=D0Z@&&9_0vw;Rp{z>s=>20%^Jx zccBdB08!#INopOeRil6#ZIiRCx`an2gpDc@?&cxx?mXL`BkwXi39&xb69|Z^uJiyu z2q%<j#k}K$3x#atYg$9Fm?U?h*f@T(Swuqwbpb_Rf=R=`2D0n2rX!t=1)4KEgY&9F zjQwy?R%0Z{dc(a&I|@n}n1#((Uv8F+Y2A~i_z_yOj&b&L^3|g(Srwp!Re4dj08IMI zGN~#b?1#`mdB_!#L|BCAS-cSc>^H@kJG2)#{}X0-0dZBF23~-F5^$|EogEq>%#u0C zZ~JlfrXb!}6wrs51nkiezM^6K`CnX2rXCw}|MU61B$~Z8VM4<EaaZ{U1pbS;+blbY zKaL2(=r6pm)E^DuBKoItiHVtshK{fuDb8KtBdj$G&1;VGFhj<#Vt_74FU1Blg9<g} z^uZOym}SxTL)okQvSim44^%}{lj+u-cfbJ2cmA7s>FrR0$!^T;Y@S+H)b<zx{aau` zznDKRnK(cxR4Ta;mu;^oW?0kLnT$Nc_M-`#Ml<etQsJj@fMzkB%ue4@|LMzqZMw$8 zT&T`2rAEF1nZReks^3ijuL>9S!6BFhgelw%chib~<}`@DfOQVRDF!(B5G5hYJfr0R z*VUT|o|LXYS)L+`7lyXee!69T1Tc~W*@%L;NEQ?lz*ddmNBb>=KfHZ(;|O<;`w;Av z^V2wUX;v2OX)`p?iV(^N6lCP8L8|y$-Bl>hQ?>&B;7%9^^1w)l0Q^8m_zL2f*ZEtn z`Agd?L(|`B!RFHK;gz)3&OR;1>x%!<$FX1p%<h$!T=)5#@lEmT7dND{mvU`@dpKR^ zM<;Fo4y5p1{6K{xoy99$KnYD;kSqlB1h=n5ER1LjM%HdgK&-n7{IhI#4+)V^a1+E# z8Gt(ne9nkid;;%}tq3PAgfs@}jtD{8xX7WmT9s#Z%a^BgqWE;i0v^!YPnxbGcYXEn zwAP`NW7pIA4;#bRJCEZ&=0LGB8LFkg7iRFN`NF>J!-ZwSit?#BIZRY(5gGr&sNISR z;T3?@n=Ij(e5F5F#3%0gS#>8;7qhfRyqUOcvr?<mH!vTQ#UA$1X1jfoez@s|%GxIC z4xq^HCgkGo>h#KX{HO*J*()qGAiksi{nhW~=3(3X)OPF+e6mMUM#~n4%XQo)+P;UE z5K)%!zOi&|i>{R3Zost%2df@*n^)u5ex7@rIjWh>nZBIiA{YR}Na=ez@O{>45!btL zOao4XgEaQC$tmE_TbnNT8s?)xhSv`$gzW&oVjH9DG)NrJFIJ)Il&RpZYu*%vI{Ufu zCV8!)y_|*snFNMLv+XYitDb|15;Qf@h1r@C&&m(P#<nDxCqbo14RbKhk(=E=K-#+N z&+<UO(~@PL8CLHrPUWTqYn*}>3ieEd7z`(j)Fl7svSIF(X|---G1DQMixYP8xAUAR z0(F5;1Y%v*%Q|iQg)q!JmaD+OP_*lbrM<ixR63UHf}@Y;COC<*DA7p##}QI(sqkRE zIviNhO~4I-H#)gf4a(zWAWJo3EUkn2X2Ffi$bo^b4*Yj`dh4m$7gG>#PG~QXo=A+U zKxQ7!Qlpaz*t#isUhd4OnS(Ddx0rQKMfFGViPbY>L85MsfKu&=+B3>Cc1Qd+e`v1j zOk@JvCzxMcB41%HEgAG9lA0i-S6o2l<_zPbvuM8Vj9~)dJLX5|U%uabwr2>s>JMjg z@~u*Vth6F^`qVvL5=)n~3A}&oKZHf)EVoys%1H41IVjEe5!BF;bAmHb+JQz@lu08G zXJqw$YgL}ALy9xh>HwDt{*|GRGge!Fy7D^Ph???u5A7}2CFV^N$jTKFiLXp;KYT3& zZcvJVnc)g77j*g)WNsWkbJ(1yIH-qQhJvTN6vaPp0=qNEuwq4)%hiP{Pu5Biz|Q<; z(4GDtg=3J*br5I5*5Nbf#@6ziTzbMe#LH@RMz2I?)*zr~+QNX&*ey^!1$;nfK(Nek zdRc^M9e;#p;2-jNWEu$4T>jZ~Qt8U{cvh)09m!DB2&{4PkUu0`i8QICaj2a+M=}AL zNy6BLJd#RvbX53-JW^71cvLE9^vd*T#tPI{;Wy-JyC;&BC80M&w_qgl#p?CW1O@sE z3zc(+M^ViY99CsSo`KF=uf#bEv$#HzEdDD7@j_UI7-RL(<1#G1(&XU_vOql`K*}%x zQpEgx4PXc;5O?t&2zNojzyQRX{MCRrV2`M-c<y*X;lBt^=<&jXg5+m*gpea!?v%iu zkT)<9U}%=CGa@jOsAq&k`4~^YjQ%b&GxtEY8)rrc!ioLBzBy0%`I5|FgtEJVV<HKt z;lkOzU=d;Qs`*4EdH7a>3xp(R2=U+@9xr2{PZX4b%msiCnB-tnA*|+>wIWbSK4+r! zIZzQnf<#cz0YyeIl#b*9)LbJ>UdUoZ^LU7KigJH&O(QT(lJQS(oV)(uJt+NRq@6ot zl>v+|NtQ3*0U|*xS`ebdbHteR7KZ@M;brY`1O+d6C`lvwV&a-*+w(C)ep6zY(fAnL zb*eEj{3SvHa2p9BqDVui5lSsSEGjXqTtO~tP0ZUn{a$GPJrdS^6n+6zLq!;ia*=OL zG}iotc}wBPA`rU%22$-^IldqUOB1Z-qUsq`?s+=BGof2*)wwWV&OsoE)dLjFK}Oqs z8gX+mfk>vcA&x0&hLasbvUIoc0`T@NC^}=c4V@uwnjwf8GiZ!A7Qeh-jNc;+`oANU zcLb}AQ8-%%(xAZA@<EvEtNEgxJ3b^q0X#9hl0=XYh{1yVIK@HC5A%q^NFTQlU<!m1 zp}WqNkG$DJzoeI|)`NRF@PTgqvuDMk=5Q0v&^d`YXRk(kQf2VW4KR3Ere*}(USC9? z3reA&XMv>6>J!dTc+&ySQte9=V*Wwr4E=Ry_WgC|X8w>pTkq7G6@7<@o(O^|Kft&J ztJtwi4Z)8GW*-<mF(%bREaVQ^E~tC%m*s2!<<^WTh~XP<#Jr6uGW^K@%#5#y44ki! z2(~r;;PVXeX5cx_h&mfvkdQYxA-1h`NUB}&no_y;dg%P+p|3x$-zOFb$!vS?<0l^~ z`BCV0>JV$$b4z8J<mwZkaUaMlsOx%Nz3w=XBQX01H;X{$-WONI#*v*g*DqB+{Oh9@ zHsAxfAA%sV#fSUwzSjf0smAc7j@$<WMYorHL=x>siShQUe;XB--OP;)PV1m+P7mkK z3Y`qp&WsAKz1JxCxK7Vi?GT!pMgEyX%fZ7Ah2Gof1tW_k9SyofH;eY4RfZT2y_uV< zoGgk;>*K7I3Kx=`CD3WJGaB?GrWKOvd9EyVlUxvQE+k81OF3+|Cq0-cb4wx?5hy31 zQ-eRXy~t`|(5fcyC<(L898OC(!pP1(L`2!0!PcC&j(d7B4-=ipRLJJb;1mFZ>{L64 z7xl=(P^AY<h6i3Yw?Jo+7(3T0<DV!y*}?Pn!8@pg^)rRF{ZJC#Z@?K}X0a<u_SBNv zfOzvB{^>oCzdhV9R|j<9rVbA`Cc!J+lonoAx2VO61q4Crevz-`5Y^+y$N$OW{8I<4 z_lc16HH&)>JQwE+BtjkE_LLUK1jb%4_>=?2du3>gj8tJ-t%*|SkBq`0sID^;((=|b zfKou6ZuyxI-Xt7}odAFlhmuuJ$qNY4`<NrIasmUlERNU>&><@gw>HxTt{6flund=0 z+t{Ov&lGhliCSTb5Wh<brXxsvHvv<)jDL?LQYNdeMf{PRi-F}e`$DVil%q-~?hn9I zl+Hk6IQbooCt;-6@x~>soFf?_6;<TkW~D%c1$fLUg^FfUvsl(M`^5wan%$uE7zgMS zwV|PgC*=LaAXSK4{~Q+kEuI;4Jffcb(qLa1wB7vH#k2qJlR%=X8oDMl{mw3Y-PfTu z!$zY028&+SY3DCm1-C)d&<>X+gP?FKwp>pS=|<S)*ho+UZO#h}2mo6dQ}EG<n4;(^ zE3|-h8ntGO6B$Z8N5S~U_KtSGLP=)#XA?^(&@JldY3`qKpK0g&5Qu=@aUjPKMb89l zqSRYh{)z8_QEzs-M`#n3u1ou;HPC@g^?@vyJXvrYqol2?ZD)GcB1}wl8ik(h3<`iE zB?I*%JYPcwQ>2dCF1c5egE3gG4rcyRPly{9yQvVUV?Aor;h9ivQmlU-Dp^AMdqQ~x zRX(v%IY$W`16A6~6)_kd^s0L&C%7;{gJ)Aj9GKfiHh(?n_on(orN9#H&=0SmY}Ck} znVK^}DVvwLv&W%Ze=9>9gEZ27TT^yM2CWPc=AxoTRNlHR!q6LSmt=m`V0BSC^7oE4 zoM!j-({<<cT(k4W>T0l1m>%t-nMT=$h+m=|-BCjuxYR!GqJx11C$+U80ZkjSP`<v^ zL=ZUBxZ0<0!9UU3^5(Ando>mTLi1naZ0iD;o~2H`e=0VrtyK{CG3A_#>FD?nEXam< zg|vpOX*~Dl7H>4!=0evL(3C<-AP%aLhkZ=|igT;}R6t_G^A1Bzo$UOPv@9+E1&(%d zV$F*f+Dvb_U1t5j`IO%4Hm$HoNL~_w&wf!|H-#3wYejmoaM<?w_u7KXV5daNF8|DQ zo&kscUmb??_U)6EQ((PH3}SOCzC&$Fgihp=#?83IB+IyQQyH$ZV<jKOD~&Mb67am! zuOvbws39@I*S&LK*gNNmIiiwG`3BY~SQ&rmlE{Mi-w|7$#6UE}+#x3--K^x%mVPP* zwaAZ^x_D&c3NacjE4K{1HkNX;i>YvZK@(8LRA30}ZH7|8Br8Mfk5e|g-r}CnZoy3* zs;eIZ2d&gqb&kK4wHDf{dhXAi;S9;=lOU5{6Km`}$uM60r{^X7SrzX~k^sjsJnNC; z3@l~Fw|W{n6VfSx7;>YISk+^$9n{*zDb`b(vQ>La670Nv5`O-{VhXf;$2;bh-pF8< zsjQ5A2&|NzYnBMKJTpnmv*ArSMNYWySxtJ9yJq|Gkizx9Y+EN@D3yCWVC6<GMlYE6 z=8hf<csTv8Ny$e56Dz<PfmwyDnE!|>J$GB{S0fdW6VUZ(KMya-(GLAtlhSC*IOv#C zzW(|0w|N{>5NcbGmdxuw&;J8EK*Yao1JzVh^)i}1qU_3Q`*JqaCk^NNydDSD{}-xB z|GO7{xBds|mR>Dh7v5ERFVlv*!P^&qNB&EhOi4JS=iw<!$ix!uz3?`?>0B(=E|mgl z{?qN)#S&u8k)}?miU38b2}*v=-b)Qd{2!H%xGsogHZt)dD2c&Nw6$o>Kv-W4!&_FO zQPZnV6{mGHeZL!EB;*&H#a`rd_+1bl@tLH0qCF_5);sXij4taAS+f4m@|P*)_bQcy z^3kG{jam9a?U?1jOJHttmj_i)Y*KJzRQJgKCmJ>LWED}JtBa<}nRmq=f`PEa>IxXg zU*ti`tZ1?ULkGm;rz};1j3mHg88k!n4b|8Td2o6PhmV8@P~xq&eTPrB=Nd)62}{De zE86cU+4CXc)FVIV%NTalnfcHuV~~Vp-kv1P0%ReXQo>i1U1}8CaQu@-T}KDZ=7c&m zqn!dl9bLM;^`w|c#o$W+DLGc@fwM3k-3@UQ9#u*})sUpv5S*yx8hy^F5i>g=kKBcP zU`xUPJhu<;YIXCjVijShJS1cT%HLMM1vJLM;Ks6&&lrnmP-~l=?I69soAJo+z?-N6 z35PW1xp~x%t~=Eo{FQRXIK$+*+Nw|ez;1bUMfx>I_rAs+Xt0Ep>#F+X_(Hq|f4rol zG6E<VA<!0Q#JZHHG_CY7;ECZ}J0qVv1Aaz+s~s${?V^<We^{O54G>KTw`#;;zyt7a zf?R8SLUv_SH9mU<4K(BtU22q)C9Ji~OBT9x(0poaPxg7?zR2J=)@H3r9T7pLCTpIZ zB9;#88hdH2)4+hXf|s}++9#O9lDZmif^9`Z;bC&aS27`;P^$m4+i(16-Q)5_3hzNQ zT#wMVZO({g@qJNU`X45`fJnW8{M%;H5b~TCrCA95c2iKsQYpz;`MrzPs;vspDleq1 zJqOHXV>^=}2*Q$qAHkkyb~krOK1%^cx=l@2+wifW3!sl|x~(?@vblZOg=R;6X(P6% zoPD_>E_6X5a&NNc!y^6f-QYEr`Tq#3r_1vHcRkO8cvU?7>?!Y3X2!CNX#kp?0xxR& zG*Yv&8`xHfm*or#+Qap{a_-R3txFKldY6HpegCd581A39Bbi_%K6HXA)k?ggkRT2i zQaVg<d&W9+8|p3?<y9z*>UJ24J1U2r24-_sBwi~TDUIN!9FoZIFz|LX%$CuCAAX>! zG?o5}U1JmS6<%`elNjLy>d?Gq)O(II-0*FhY+o;+B!Y%=H1~C%IR?)n@VzJxPZ!&b zU2pYjtu`x9(GV2buDx3eEvt4WEl@h-pU%pVwmxG>97t2<1P;l}dl?C7O!+tz(%v2O zW%h4Tjfk!HZnE3Zh_+4VN+aYxa3Fnop|<ZAv@hZ+H<v0e8`Kd=g^!&Dq;sf6is^^` zOhKVZ2n^0+mO6vAxhw_Lsiqzrba}48Bqf-6P=?*#merB$0=*ewU=*g`VNA#_JCVz2 zgcI})w&Z+;4sQ{rESGQ=1vL8#t<PcsS84mYS;17@vA^l-8a+1R@U=t_GL_#RxL|oi z@ANC<mSv8K#BN|ON^2S?jzkl&a6gf{%2EcWIWv78GXgwMSdAVeI9`n2z8Sv7e7yH} zBgd?!O<nAf1Tr-07X_3_LdJ@#0;C&%1NMe|z1*ToIxLs<cxF{-LkOQsIQN_dE3b)4 zr3i*(sDbrFQGN*iSc%dxOTtsFsT48lcvx%tx3$^HAl?edD8dDcWoR@vB}TOmcM$~J zQd%u%$qRefJ^YTQDtvuc$G}*?-Ru}(?yGTTqt%{g<rU3&N*Z70*<z>uhUL#<Q#oxo zKOg3%2UV7MN}V#+Rh;`BVCCV%K09z8WgalenquKBzl?Jv>w2E>CGb6OB~5pyYz!s3 zBlB-XH3Y|p-A)OUJ?hoWmDIgfD6;{q`rXZQ2{|1;j9-fk#sgt*$ovh=v_oz;mc-k& zqKEvbFBVI^WoU7;h5$LhReG)^N`4Q;AQ`m2KB@n}Rml>LgRYJCX=)Qo#}O;XO6%8n zH$3>$QI3HxJ3SFj9ddIAnL&jBn2?iVL3o{fTc`ItTcP6Z*5WIf?v!rq;2CJTuyQ@` zq;)IMurhycSoXhdv8CAU1kJTLqH(8Iq4AYn_I~8v<O7|1`#ZBTC=R&3q8nGWL#ehY z`_(UeYQOPb+L_ao#QfSWeS!JyZVv{gDEX0}oL7|j{(nbPryG5NnVFIX5#;Op!GMN@ z$5JP)9oW5wrS+-l_kwt2?|Ox@)X&SWuU8pSJ&N@bv<>s_W4(=1^cW62186dSfU$Vj zXX?9IZky|2M);r`^QcibP>A+pp;v`sc;?WuH|&(jN(Oy#mc?}FB-dr9ATOXP+>gMD zQQuD4y&?G<fIw1kty559dlV}Ke@&0uRBjXgqED~2ADsm|kNo|K@R<2~xs3_66(G!B zqa;Gvb>XOKc|RM-#Cgj1uKx#RbS0)Yj#+SIIIbe_U0J-a9b>(^n#knjMQjw|7xyt@ zms#MPl*s2CH2RBVW0Rg}wnU!;&Y}-YPS`~i`eO#3i=W<q?2Ozu96IH`*kzpY8__tJ zHc^OfMWZP9iW__^PI#A*To2)O9gYc|>UWns-mH$>S#$GfoRaWJDkM-+IS8j?qu0D- zbxogda~5usvS~#CVv=#Q7-QtAe=hQnal|58T%Pur!75*#mSOu8`I3bf;G-v(Efi$? ze&mfsVd#ei&m3XLW!Sqy;VggK#x?6sFe)=utf-${_40_)F+NREByh#tUrh(GAMn)w zzc!J3)4UKJ`a#7~r{Fe@H^ut2M^O!{9;0Ch!SUZ84%#?hvve1H_rZ_^0~$xx_H&D9 zzz(?+hZZ4tY5Jl|yB@8iIl5*y<<Lnh@u;VC|99x}h=wVRd62NM3<e8wHNJV4T|6pc z<UN?-V{(IHZs>01uvaqf+w?HNc<Jscw_SFkC3HG@hg{c=y{WxA_+4LH-u@alhQH@3 z79NBeFf%3hC@w@2hndfk%|1p)`FM-P*uEJm{I4?w!(i>$$*~+O=@oIBWqT7xv|Ws2 z^`BU30}MM&LKP^C^amxU%z)(;eskB?I3hQg($)pbsjvrJFK|Z7B7K|u*yAuLJeh=y z4EZy{Tor;^kzuV+fdqP%&nOvonespK1CPd>&6|#0t@9R<durq?vSayCK{a26F^@DN zvhu_`t4CO>ePmN4uJv1(8@6)IDoA~Y!(HRtG!}4y7Q0Bapj47bv%@^`vr$FTYyBs> z_9wfwn{aMa5^k*dsc;cEr|%P<Zo`BijJzu92#OwI=rcV3UCpxnPuCms{`e_xCyc$> zO}uJF|Lz<Rz2lO6Tak4j;YAR+Jp~Tnj^q9D4$2S+Ei%bKmWqJ(ZRSX+6d)Ey(kP;8 zq^2tHqspAJ+*{q@yLSO<SgKJT8P7={Zjb)CE?3EL(0Km!I&qiN+U!xAs2pM9O_)tu zxwC!UU{<G3v=w&C7piJs5p&ba-q+X4P=EV9AN=bfh2f6pEt*)YGjdFs4G=c;=q?%= z{(?(_18piNJ^VNO{sPJ{ym~BTsRcZ<+|w_OVKR6yfWEwiUn(ttD((J?s>;aSrz5}W z&(rPlTMQX+`2D^v-xutGtNq=J@>`1<Cof5ku?_$nFXA~etKM)Z9HWr~&2LIl(3L=z z1e%`^WP>R!`Wf(Vm#63Rb1*hC8gg}D=T~vnRn-7tZSih7G8`&5)-XJ!)ubJc?86$~ z;>P|n#&qt=JAPn~`0gF659hz<p1swEZvHl>^?md0=Wvm}<pR&;?foL3BYnr2xjg;Y z+|II(&eU82&vsa1nIe<4z@!^NE7Q2`+qqs?ld)3L0=d}q&{*Af32HL=$YpnFggbBI zG+=Yr5waP?lw%2;JfAUHWoV!y92x_Od7J?B^3yImoZJ}PkbA5_hS<v8Fu<ttbimVR z9yx`d9XZc1@?%?27&kWw-3T=BnM+7hF!hqMI{$mfv8v3RtbY7NfI&;nO*5h46tw>N zkJIyBw9BBP(GS4Hm99k+sSaAdDKHcBUsS9lzz`V{G=gF5d3pf%JS9#m{AKhX%w<Sk zLb`%to0vNM-NMIB#!aHYRc4t#K}xAz!o0zUYSd=Z|G;^gBx8FyK4S&;lzH@Ch1Z7l zfsD2z=*GMW4h|8#k1>vcGgA6eB2<fScuNit$7Z|$5nAa7jwN(QH=;r8xAe!>3C4Ow zmL>#Kt!#%3+z`v<q@^!3dxaH3nwHUdFtFimM$fW+VBNAFUC1&9p;SHkJZglCgKS%9 zs7aTdCrH=Y^r0nkZ&-E$43{CaGdCkOmLvVotcPSDH6>vyA24J)HCQ?#L$iU|)5N;Y zccVD=oa%}GEqpi8!f;=gPS(ViN7ku-x~`KTIxu5vDbC@sqWXfWLkVtjk@qCE0@~5* zl~HlwBWhfZ%#kp(n|H2Eg?v!t4Z27NKpxv6cj+)5ooFR64zV;GJ%E6&3-A~;sJ7$v z!P!kMjvP<#$Oxw3Hq;&Km22F}LCA_pz3RuZU}&^qSXSk0(W9qOnsCO$ALovhJUOZc z|L5p(0^JA(tz)WMY%(Wz2^sU^l8_vUY*ArrXa17=W=3?HL+?D_IDg(ZS<?o$ENfU1 zIhj3%jFD^-JTSLQLkYMH{5y`dY|<f!Glc;N9oo30M92tE@cAlyzce)TfHAmWlOYN7 zv#+i+tcaKNMcZsA&4P2qfu=O6`QLQ#V9qmX&~xgHZIIFLIivS#o6|eBP1qPEb_+_M z@_@!!4IN7Hki90W)Unm<cz%kx*Auf*D%WBp?&jqlMz$&eAAAq|I8A5!p$Tki0$D$c zIu{7ZOe<=b`cvl_?#)hY^gUx^frgf!@)cU-f8J%sf`T2rzPKpu$N^F_#v{K0Rq{0s z*72n6D93v*6+mv@x0sn({*{#C^&V7;jl-J!-dvc46NT`p+mX-;X+PgTBGj<#x-HF5 zvv63?A)jXp_Gm*Vn+e5Z5mu<R>L?Mc%`0#sw+jukqjBwTC#D6u7mcO2;@djSe5!of zOI&++j>k~Xx&xr4(4$jJDB)A)U%LZcQiIG0OuuN~k4zpV(_`u#us~hgIYQ47N2og1 z%AXtes2%%PLF1}mI;i+-)Ryz;W|=5s2}3(D=3{EbAQcK<?P#Cuu979Wyyo>`9?235 z+XP@LqA|-U-BVu!+uy)SM!a(Oa96-D?(mq#{4!oetmajN!H|0sWcTmF$0``n-eu7a zD~aFhYL8{NjBXp|eNFr{BLFPFS*GI5%$I@~e+gH*O|Kmhb_kA-=j$U(U50>;jO^rY z2ps!`4q*yh*JWU{;J@4NmF#!MH;K}rV+`mHx!XQV^Q`>*<;t8;@h^3(r|Az3gC>X* z26Db4DG5IrM;NZ%8B3s!Ttbtt$k({e#KtHZwb&?9^_?HP9j<@jlgdCv!5nn^z$356 ziiC`!OSZM_zwPhgN4bq&&erbPZ}`BL+B2H7@cIPVhj^v8x?oM-imPa@=W#eEunt#y z&VeqBc+ibgcE8<P4aG3X2Np+4A6K@<8k(#_U$G7tLPH<)+h0c*V0cW8Sz`rFYJ9#y z9uxJ%jNS6?*?Mq%^oU&cV;<vNUN)@T;>m&~*Bxoq*Nm+yI@g$d<_K2W{EKtM^p4UK zv67f8(=J<K4fH&0gdq<X%?MqWK-o;Wm?$S^J(0`o#9RGg;p~GO?%Uo%`+SH<vYVB7 z=H5Gp+`Y=7^BP-cn9@}+=4%SG&dZ3h-j~4k$9cj4fPqPP#qK8-ix8x^uwldF0EVEo z|4+F>O081yC*W?qQV%;y0*nsDA>^$`S>N7S_VoUZYnxa5P#n}p<>8iN{;O)yaJ~Eu zSevPJXUP2DmKCYYoIFTgxGoB{xub^g4^@GjR#0^r`%lsj(Do=8rhmgAyX!cWB^KpH zhuLbno3VUyj~?Ig=g{aW(&d3Qqd2I>o-}^b2@VM;CYPygMR>rPom}FjK1rpz0WDfg z`6CAJZ6Q)e$UWKj5whueUZ`~#P2P+_Z-E2>C>rr(LWu5j{D$z<s9hvCmU})#6kCSA zxl!>E#`6hAi(Pn3Lj%J2u!@2QZZ`$5h5x7kVHXvBTIAjJir;Wns_}Yz^8c;NP7}FC zH=857)5DMA-2xPH7q(d1A`fuQGh&!-J2%)y&Es;ssYpj6EumlChS>w`7ay@$#>G}1 z5*6DhiF`(C$>OwSB&>c!0+4t#0_Zhk9z;X#v@z@b3gbBaSPmTf_3iB{#`p)0epAtq zKeT<9H~kY=*Jix1`F5G;gj3Zt%Af<sv(IOs$xo*mMdz*JVI&{(dwfxBlUmNh=m|6J zs<r&UDTBtERsW`$o^6Y{6Z;}<!-tw_re6`uFWL7mGoe0JNXPq9;P8YMuZ8SJV25SR zr%P<Qu<fvwTE$H8old5Fx;*)S#0n4xSgO`R=k(2P7Rw%Ah;;R>e|(L7+t1{5?weWT zG4R0DrD|v%qFW>63DTevxK)LX$Ig%uQyzeLLe3L_kjUt5hX@Al)?<3<gHBN-^%PfW z6(7fPrQB?_H_#zc0%?F|GikVgPal}fb$-ZlOi1u@N_WCxlZdMQ+v&8Zl?dTH$i45D zM*)EQ+x}STffVKn`A&jHCsD9@p@^p=)*>jQwa_a1gGMXeWB*Zq8B=!hBkO1+^~%M` z9T{=!y2g}RCr4j7{jkZ(&-jPlW{Bwv5?OQjwAI-V{`|3%lq%BwezhB5q*^{;;$Fd+ zas`&s5JE4f(Xs~0bAS`q2(MD+=M*Cvs@QM4?dijk+Yk!il;cGZfS@5V*YI;CBa8~z z%aQ*%i?M5Iu8;ckqGH7=%r460tlwtNBYBkO6ztGk?aFy=whbv5H)rfFGooWokIv%0 zy3J%<_ii+UZ9Vp~S#pu0GajYC`Y<X4_6=0DX}AoWeqk65eiO(EpJ<i0<4K)zi74M; z-78`wQSGZp^l!(NjKoQbbbk*%4Nv7~CD2K`v;{>p3}jEN(4NTIR|DR<L??E(_HXV- z1`Vqhc78<J)h(_kN#nJg(V68>!g-RA+`xUtw>KzQJ;Vd&y&+v+gaEuKG?IR!2gsmH zruRlVU~>fG1Ab+P<3z5|>UJ1%k39#T#SW1j=u+^U5Jwb7!p<X5QPfZbyugrs)}9I> z=c_XQOwMR+6+{=LEF`dJuDHD{+5v7oL>g@Yw`rl7ffa)dD;OKrdd|1x#$W{lmgYG# zkTLO7zkc`5c@_}Eh~Rc)fEYd*Dpvej#_tIm4w}`Kn$=bhCiWKrQ`@>_Gps#1oMK`j zC&ydQP-@A_2YkfKrB=mv{>~w|)knnNXROo}x*AUX&Ir*cNh+hiA>8XLR*$g1{>jZ? z?3G+8qeVQOC?S`}_MUob)IG-Lw2$*t=E)01+xgFjn+a%ch@_;Dn^}eQVaz|l4*ARt z3^yuwbap_B6R&z8TqZdsi5#1$Nunk3N|Ml=Qp~j~9xoA9!oy+3Z>BJjuw*&`fhMpz z9gDL+?42}SEM8QEyH;@szDewsDmZ~bKw^?J5U^B6(wE;}avnlK-<?UBHQvHSP8dxD zZM`<#)ly99szl#U?F>lFK}X9?EAor}MHP+ySaJ47K+j)sxCXAzTu+P4XUt0QqU29{ z2{7%K&M#ZTanatsMiJ2&sR=kLw_0H;MK!PjSRpGWqaP!SK3j*FIm+4sRfCcYfK4cV zx6ND_)sa_aAwBrsn()k(2VvP?OvB8bczxljFOcJVChQys)m<=8qbto{+4>GhsTSTi zX6o7P8K`B~CuQ%F=h@@;@SJ=QMX6b55<|3c-IU9$q73neivKQ3_`A@yUNDLro>tV5 z>A|?DM$Ghv`bH^<=F=)zJbC=1pm}$7@yLF0UM9$B+&}i-h5fh7`Y^%oa?58A-Y*`7 zN;K=d51S^YCr*LOocov+95#6pwka{s9}kNzR_alg5W-b|=l3X08nzYGXNES=^6*eU z?9c4r`=>QCN}LhX^Hww&evNXFj1B?(ThlSY%8K7xT_bO2JDmcTyxk>^^2PYG|EL^b zxse~*g^jBr;F978QnNrDav%Ml0qVeA+}$33mos1c4xA2j57?>wHfu5cuFT54DJP<C z<E{AG`Z{#3YhzmR%c5dTYn-?ut135(S)Cji6R^`N;A3sU-WmAqpPSY~!g|}E%S^3r z-W?f-%l@a5dT;jbj`1X?kzgxA%n|l{<g1n@G9{z=W)uPLcocqGC&NTF`{pU>UVS&g zoQpT#r)o9g#NXAiiQj9jPs-acisqd^=eP2HMkx3&BjrOa?5F>qne`(zAqkb8uH<f( zSCbN!Uxiu95(SHM@qe6f{>rE|tyC4wdWgvi_-8OW`q>Y8>Yy4-&D|aQ@|@S;=dYCh zndJxD<B`jZ7m<M-d^$N@aGz8cKP-5=SC1vAy;KLD-7Zz;Win<0i5fL=^sQ?k!P-x| z6t>%TEn3@d+Xp`Jtxv$qQ>@eTvh&2*nMJuICCGl>)7UmKP*cS&@ymr{dj*EU`!6Vw zGxqJy*BQ0ORsEtsn})l{mdw}6Bl6`)wf1c9#4<Nbgg+Pgc6M;%vRJ)xa$L{Ni)Z`m zB6e-bd?&g(t&KlyI8y5na(zhG>6^n^El*~b4EbVX^sCQ5ZB{F|MvsE-5^ne0596}z z)3uI$3zil2e)N*O6k}Z%eSU9Wb@AS*>h9W|pTAct&jEOtg^!=Q1fD*FZf+u*x|Iac zpVc?#s&y`=^ruDb)VQ2u7uOxjkv96Z{%4D-7}>S0ad`+64GwDhB|}fDyy}e_lxj`5 z<KuKLrFl%@ig3`aRySIjvAZs|Uq89++C{^sfj)<^p=*D|8St)%^2^PoZxpw-KYl4s zgA$jZB@sIo3mDz7+04nO5n5rVliVr=>ouFg>{+*wMXhyMWNUdTYE^jMdf@OIHNR}5 zr`vvMObbpUS-X1V0kHmjbx#Lp?1VWiaZu3}TMl%wm)J+k1tBXTUABI071dFV3ZcaK z<=*)0*X2GzY%~rP(M|>;`F52rHGeov97`E}V;JgG==mzlX|R?Nx~mW#q`Qx?6mc@{ zCklL)%*OI*ZnpYUnzD275!{1Q6&;&$wO$uA^4OV!!zoK_d&xBMl0;Q?xm0o1IdIfz zBGY(RX?c}&G12H+I|%<q*}6RTU60q|do`hfRSn8R|DSgZ0W134*!fxhwEwB()*qw% z2mOT^SX5zdI?Nq~)t|e9K8Yl#4~8QB-m8#ddktPKT|&Gx)d4_8sM?Q4d6(ZcU&KXL z?Uu<Xt&;rtH-hCEOjbWi*EU;cB<1aaq}lA4S{9KCaJUfazA3Mb(8`rp7AWsRLk1(e zl8Y$xbY@I`T6a_q>(?mjiNGb5r>`mSkfz@FuH;TyA&nh<og79-i1e=lV&ok(!6uoW zUdXBHC14m3TfE2ec{c>IzScg+tf*ucmRB(64P*bOgV#=I^;MT@H7Lf<Z4B)0a4FY^ z|1BWP{_^m%RhRsOHR1OAm_=og4wbt^kkE0_$l3-x;Ea~rdp;f<pI%(^5Mu{FnOPhf zU-h-U8oe;5Y15`D&@7Bt&=t>z4(-eET|+4`KPM>K9R0fkKty-YA^{RDk#=ek)zx=b zNi_(dghcHKQN2Qr8letd`D)v0`Qhn!uIpt7&WH4nR449MFTa@&>MUz>-b&pmN7u22 z>Tx9iZl~UsULfFSRJ*}ccLd!cJKxnwKD=-}gWXQ|L%i|813TFLOq&fmAG$0`P3gzx z(azz(WXYI$00AJWz=pJyL$DS^Tjnsf>DJs+o0@ub_OQE@JfkCG=YvIry=X?{=6(;s z0cbJ{KF+0*8o$g-e5{i2YDw{K&KVGBxAyg0m^*&mJKk|Jph6$&F$GEqLb<g)tsnIM zwji3Rqbb$5hra4%mt&~o?i!%GD#+igC578d>4}qXx4|^;!Ha4|X|A=m{Ghy)+A(FH z&7iCTr7SCX{P@%y@4w2*h-HC4Lv5u-52Z5RoPJ8rVhH{s{&r_`qdNY#bGWM~AWkx3 zZqLMzlZo(EH*_+UD{e1OrBKrxxMgeY?{u;6nlr{ytL_YcvdJw?rH&`5S|5w*?zV%X z2B9G!%rQToSnK47QXg}yAT@&00NT*tb>ox}i#WLv1`Xh*eY>Ru(mxAJ%SPc>l{I+W z1B2Ld5<<D@<6kThyu?+E&3MG=nhKu}H{AI_U{omwBmBgT1267;JZ-h$BxY(LuR#N0 zPJ$A4ZPc#Ezw^64ylyn<-wuHzKu5r0QPBf^+Nd<JCOVB2|F?oAE-DJ#++`xat>Lm3 zR`UGE64di%@dWNdZ*B1c9$PePD)(6F&-$^h?x0|82*6vYk&NIq_IEwkLA1b|awjpx z)}3N^JIc^`69MLqKi(ef69j}v_{|H|$yh|7L?wE2@_!3HKW`Gvz1OB}*HVzec<Rel z&`Hs4g!BVgbiG;(aevX7wm2VK<|jOyNoYA9U4X4#X{u^oYa{V3%l#QFehMr)JK7-p zJpm_8X?tA>p?V*APC6?Q_6>f5?9wE<i3p-OkTj5Q90-Bh6m^?}Vv9?<((=2B-QpI0 z<+-_~mn!P}0FeM{`8N2}tUv_<SL5GYD)wA%Gr0n8Hc1Az?YlDiPY(VVa+ZRk8ycVs z6Q;OWUGpAmx1V|*Wzar-I!b%yLdCJW{xe<OX8l-q?se+}`M+x&cmHnTb@#gqtcp4m z700Z2Tc%5%i38uTg+#Zk=TV)GwP`}1eo~AiPoZ1;w6%9*D)Z_3cd)5)rS_DL_m&CW z<_q5a=?Bk7VC2Kb0?~WO0HU3&qI@}QgpgYLS#N#h&Od{@zMHTM6uLDJf#!+Nvhmm$ zZmnOf)Ya8`Psrpy!<v@`%ywAVyJ_Kb(nmp7(=g7m@p9GZ&n`>z0&3J;SurrB`jS#@ zKEpE7eMbBca`z78&ijjEvFG}TJKsX@YPEWIFKJKp|A(=84lR?ncU%$6NPe}jzyEHh zKmL5~#fSHRJOYN5)K?C4(vn!JV6Y_N17`<)?TeE&9loVS`PmipSS`2=qd4Y`XJOL# zC^HeAnwXM?e>^ZS5?Go=NleWmGa}B2n8;3Q5{5$eA0HHX6s8lCQVn21MS?3`ksDo6 zo|mKf-IoaI$v+d}edRKT&0gQJdG_eJSLNJ<m~xYKlfdG_si=~Wu|F1kQ{~k7#(n&6 zIGSs1Rc(+>j1R2VeHPxc6*PEOX<q~HHwZ-4QSva{Fj`u(*Ve^G?+z}xKTy?R2la`o zb)S~*U3mjvABAFPa&YOa5Jqe;rpCw$Gkc9k3n{lMO*2NCVf2yA*tkGUm9crE!U}{x z<f#pQ<>DSBJcjYiE(Z^LYs8kZ?+kOwSxiRjL}P%WeIl1tR!GirOHU%D=hjE_r9G4* znT%)sANC=CpK=96Z)&P6pJ!+(SB|k%IK$c@a|8Sb$nyyn=j|tj&F(ro<W^7j^|1!K zF7LG(+jv5GL`5_^e>!5pFQB$K79Hqcy!-KiL@b(~o?_@?iX|1gr#P!xf^dNQ(*EY0 z&_@wCNi_TNF4LO^b`+d<Kv|<~mEu9I@&kE$R9J&MKIkRfG3c8`#TJ!8WWE5p)IANw z%q!3y1q*?CRs7&JpdB;_feK?bl<4cQB)MN-B?2~qS9-2bR(p<jPCMBvyNmqyzNlJU z2v`jn6s(TsAQ9d!X~~=(zu_WgA~lgwq^f$VkZl?_pJT^yH+5yj`ff`;iHi>z5=>`H z(&M;UIXQUrVg}Jhx098GgoXL=?p&2X`neV`#-obsbCFrWu|%jzrwcJ>E~YM-8=E_P z>}F_m96Z$DYXH1ouhRW@O@^IpzfBk&04T5@2-~=rWy1#-X@!t$O0#dnuVrE3=tN4| z{3&@oJtcMXN)Cu&j%3|zkR-;5PlA^1>h-<5vgjj0t>QkIWPfj-e^vyVXy_|8<H3z{ zAq=5DWGBaMxTP~Ew?)9aKEfC3x2<yv#N288Bz(Gnh0eJ8!zWVnfX)!z(DY;maN;bb zijE1Stqt-D1bNJ29$rjjtqeAaruynC@+<v#P*nSZi9x)l2Ww=ChzAHIaSr&^dE+b| zrioUkGJP}4+)%&EmP~p<V=2M}j=;ds;zBqYj_8|y(4LLNs>43aYmH^7JGB0E;;Xg} zFMJg#?CI>7%t-?CZ!`|nxhR|Q!75(cw9bP&jfn--)!EZ{7G-D6Cq~MuW5^TtAnB;3 z-SP5WkL#A$-c**rc~AdP>)vgNBNSv&{qso$j1`r3TO;rI^`hGR*s@JCA!Pb0(YDrd zWT2+;&XFUJ-1>h?Ida;CN5KUksK>MJ)!#{L7_l*D=cL}&aY8>-#fz#lB0O?PC~7IE zGM-l~F59}~6=r2O`X?S!CcbTG4PCtJi;F-XyqA6XHSjicPW*F4JDG%xe|0%(2pP%i zHXpJue7P0|!TIA++2lZV;n2=f#WXX`@an7{Jtf00_;iQiu<co5O6q(9@<B>=;NK&O ziG@hM_h~$SHrt$W3YGM5`Q*96SEoNUv?iEmXeP<2$;O(K+t}?zcwQG_U`?ydHc^-F zZ#Tbkl86;dQ`G?z(ee0!ZkC<j>cZ`{G-3e772XlU`n8j8G#vfkDkj5=V29|8$=Dns zHJ|Bpc27RKY#v)Q>(S77kBeXQifZJ|L2glk^7P8$7ei-)Dm$4%cO8e88Zi}m&mvn0 zh`D=(dzXuNej{YLbJ5pOWx%&=|J8SN7kcwieE)Kn>`$H@FRG4sP3w|GzE$|#HuRxb zS}j<AM0Liaz%V+)JANVYOmr2V^RHtJ6#xXRx)jR0cxMmYD!gv%8qZZ9=cWLCY4dU< zf`nk5oX~@Vbxot-FmXArDOXVp^NyO-cYcp^FDqHRU3HWXcH!*@bZS*Y#{Xo*$pfV# z<qe8|GD~CTRIWB=P(jls1yp3s`K&$ZetZ263fI6fiOJ4)na)n5(*G7P>Daz7$qWeV zOo-<nZ~yFtjfvM3ic(r5auFqUNn24Pfzlb_jPpT}3ljW)TL_x+XK>j3>5)d(v$Rz9 zl*#vLw~T^q*uA?*QZj{A2~>Y>E4W~7V3bhkf9xLXR5M6j+9X!=0Uvg{dzqVdzW;b4 zdC2bX<2F)E(z#qC!=uxTl0^i`f&lBn#EVB9>hA|(RYi?C7nSa&E||*2vB^7dLkSYd zt88H#Sgv7eTG#>g&cLt1+VUj!X^<)+T?9tlCo+w8m6d<V&2`eWmnRolX&O2o0M6TB zu(A7X4V|8+26jU9W6XL-Q?XZfUUn;|XpfvytuNUgZHkuU1%I_*UmPKZh>8ufvp5P_ z*DPM&Qz1mob=mn7)nh`LP@sPUHgR87y^-<6Sn7O8Zpg~Yhnp$jJ{6vDDouf=b`~le zno$zCW4@$@c0u<!DOgN94r-ohFUfKLWXmY}Jd2M6jJ^4@6E-Sd#p=cIqjKTJjcCOe zgRYr{s+c`qeS3NMFkeaMkV{A<blEM1pa2Uz!>$sR^dBX!Z)8LTd!%{MHzLckWVzYM zo~!X_L>w9gbJChNE+s>m*u5;bD-x2(g`$Nh*-GATkp%CkXkQ-%C?hJy*H13it#mMm zm<&hzgb@43x)akf*~w|u^r&Djp&tu=fz|e|hiTyp7KaLbqcwe{jSlt&)DT-{ZgB<A z2=?iJL0P^Mj@P-_<C&qcZ<TFmNEn?8i=&be33N(wjD4i?5ABCf9<Wmg(}y>9@>et% z@k$Gf)xq9bfTq5~%ra$fZoH;<7u}N(j>07D0<Q8|Z>^Q+O0C}zQnm<3#0EB9aTE0R z&d7W!!164usG^U%?@YbCuS(E3sCclZf`)QCpxC<T`!C+z#ZFPW?=*%00f^;Wns&OJ zkc6g*(ZtRtUQ53yQB%`sz7C0^3<GeiU7BSYw~kg&7{N7JzcY1@Xt84!v`%CG(DfTE zVU&o4M!qZfji)D{&LrK!>H>tOq7j}=(+P2F-`mmFlL`g@h|pr~YVrtkfq%qMnC(w7 z6qo)huORdHZB<a!Sycey(|?L5Z{Og`piWsf*Ii;CI>)`bM%5H{NyAsSv4%STpM{?Q zV|VWMitD9vLeiqr5Bph6d7pKk?d_yo(0!UtB~Va4P1?a(w_jspchSvZJCU!2TY4Qo ze*_=rKg=*Mc)?iowv+gc=d1AAe+o-jzw;7y!|GA22)}IBUB;Td^iu;yNZd`()9ul3 z)zfr1Ig{gp7rV~xNv=!w4*C=;;{DAQGdoi&?kL-BR*O?e&turHiG=UwDj(5%>^uuS z<fl=?KMsc*BGP~119-K5vegkE`zp`c6kkpk0dST&+<M8ehMu4Jq><yNMxohCOT^jQ zDoSBaZN~M$S=@?R&;M=Wa#QEg!^|oi`V3e^F^EZK!Xh{-+K4Q?=V6ZM-9mEak~qiu zU2cm6aWBH!DW~ybo`N-i#pL(*V2bBrXzC`092vbe+g-%`e*Z*e?%$UFq3@V9{*bY; zJza+Ae8nB$|ENoZuC}=6@@gI;M>l&(D{sX-!U8c;$~>0k@f7_qik4{dNkzvvE(Hy| zl6$};kdA+P%D^+mAC;2nLF`RLWnPZ!`p=}K_Xem6EFBdw(AQoe0tW4|cj|nL%Iz!e z*`oARU~8ydIrRD6)%lM%V0yzB_pDZz-kHKqEgfMO+f4fs9f|w0xo=G8;g8IpaQtU* zBUMdgz$N1W@yP{Hl=Kl_Igp&BhOb=xFgEFCM+koBwe>Wp7Y=Kp9KsDPFwbt2J&_rs zDc5lN_pzquBY=>1JJ^vROxvY7-;;31DuPC70DJNZgIe?Cjfx!JYoW3s?CEP^IrvtY zO9!5KK08$n6=y+u1KSD*$j8E6<vq?LVDnmLpi?poG&Y!S6bOO(<T~NMj;J;^#4e$m zlO1<x{jotybPX6Euc~#N2@cZYuQ7w355*Ih?!&d0rII_lhBKDY;jJ?zcJ^0qw!L~< zUlmY|3arYRtJ{N+ajn*IvA|HVR*Y$jaC*`+8D;laH-i3iy+2^`aJKl{48{U>nEhXG zwvtl3?B9h{{G1fuKRH_X+qqO6AS<fR)jTqthGRY(EN2blu*^YAsgB9e9<;Z+HdkW2 ze@=<89Y{%g)Qzz)=me+w_9vG7Y=Xafi98c@OpOmN&2{!JgELu%zPdlQ-z<1l9U>l= z%&cPJq&6!W*0?)|yklbc@)dmI_l#2(PB`T-)a)_0t!t5kDCW$dOmJl1vj%nZYMpDf zh}Qvhr^ENuU<@Y+DSM&*zqD`>m2LhyL|E~Hy`v`8A_iP<CVu!ec*Dn)x4=8r;s+FZ z&iUr>9}S5g#_Z}!*`T5rJNe~}!NI{76G+MNow5|nk^eqaX%Ah#tHlE+wm$X^e!G~t zh6Qi8;&Nhy6`3^NGYw+eSymIDl3ydLb$WV@JU6kL-HKKB+R>dx5(ThEYpz^Avd&3K zfrITcHx4M<qh0F29bpF|oo+@uZ)j(PUQ5lvyOI&~!)(muvU5tUer0d<4i%Lz@4lQ+ z?TD-q_BrSRKtfoJ#d$OJ4S4mS)5d)#-ZaRTXp!jj6$_ta>Z2gFSp8iC`6rS;kR8{- zo*#f2xzr32NGKo|P_V~%x!q;t5Btzj>!jMI8!x8oOIKEJO0eVoG=mBa%R_e11z;Gt zmRxi5S@mh}doaACuRY-JML4e!yB64Kv{&oC{ee0nc$vW`Yr5t5|0Dfdz3Z&^6(fr# zHX}J9FBc1j8QV*YMRdA4KZ1ePwhrLe5}Y^h_q<k7<IZjT8|&1PPlyus;IJ^%b(X#^ zX5>KCx06}e(xh+%phlxPCEP=u0*gf2uoq>wdJiB*F~VE%unIozdOT(>Z>ZmX#ODd@ zc2m?1?ySK1N)ZE2eAc#TWl|HOdkJ{(5t+|A<zbk)2EhC%*<9wHr_Ao`$D`36dp`U? z^}WvjK2{{8oR&uu(73tOFFXINRWDExQ^+-B;k>In?yA%%1b&V@f5lZei=ii!<Gt3x zULSkm8M}FRuE!&2D!?0Hdn?lZv6-^(8P=902yLX{8T?Enz!1^EtjmOvV+GM4F-|?x zmFFrkxX9HE!%|!^Pc<RZUbwTZ@?8zyYp(7QZu1XKqe=Zpm{bkwLv?RIW~I)3>m8yq z*Tt%>G|K_^vMADA9#u{zvk=r4@kRet=~BC8ZYDk7qnZCk_*3p*=3Wht%&v9pdaQbE zaq9ZJfxhXtU5|*i{4v129HoC1(_KR~s_j&!@R6hC0i%GgCo`~>Fi;e>i%vJi85_#+ z6k9xWIM*q`l?OoMH<u|vo2|E1VL|h`TMZka80Ha<_!_>|-wp1r!yW-*G&#f+dumH4 zT_z56G`2SnM&O-N@P%=o4q5ZW1^1`&S96<K;eXp*KcB&>=#zsSNfm~F98tk_^Ky4o ztZ&~^gZ{!u^V0SEGy4g8u=3(h8kcn2ME~(hYiXW%KIxD||9Gq^SAE_XY&7YNR2w~+ zU3T`iN6_dU7gMg)mg4rtH%&>QtM@OwJU<JdyF`{hneF0KusyO#x~h~Tdb5<AF(<{k z_0(`X<$^oT#03`FTf%FMwy3w_IB`~X(A!HYshIr60>#R*GO^S02Ss#Nv+Ixn@8&B? z){Qi2iZ$IxT<y>`$LKq;a8*z!AfU%T9Zq|VKyAVQqzi|RZIs{)D%?@smv81a%Bv}U zRu<x>pi3LlSisbYlfPC(AgKu{V(B_+8mdG*KJ^ZD!a;k5s-tWT62#G*dgw@mI{q%> z*ao>qK`M(O_lR8~ysxWipDdtSq{y)L$0J+2URDTN)|>L1Z#4yF=Tx|$NgQ;6GOxcC zk)odrhU78S6uK{Xjm+*2rPjUT9qDp$rA%T}U@t;80F1_s1sQhgZO?pNh`2ssnx<{F zD*Z=g%<A$?4W{&$0T#4vQzgX6+Q9(}{$dKCv9Dv=mDj#bLunwyUUyeS9{WOJ<-U^; z$Gsb)>!zhJF49cc{sv8%v8J!=P;5tIJDce-)(4cu#ukL-R|1?Xb}Ed-twhT_QRq|% zuIo5|vTixCB?|mVDLFi<ayFh&gvL#*mthMNm1cOxUZHI&Or&-BFHc9o4pXJYj<0J8 zUkWo^oFNlD(WF9&E94v4KmZ2j<mq-7u0onNgp>F*-T<zlFJICg15UNF3+B7{0|mxk zeX>-%_&F3JSC9d8B%GBI4X{z21}>X3s$KT}arqA=9hQ|%<+9uU*kpx+Xs*lM`3eH{ zjk!49I%)Nvmy4=Bo6|fceN8ef3XLR}Nv=lOa(AfCNFs)(<QS#52y0Q&aVb)TdDv{| z@XCXADaEexdp$Kpi}(+LVHg%PTV+b^Z~34?rvp28*r#)`9s-tcXy?*W0s9~CdMsno zodU2{Fd{y;uZbkNcxP|cQ54g|Mw-RvwV$s6;?Ou%P?bh9tS93JC=d>knJ!oN`>=<A zM!xXVEP7F|Iyt@M^lGU*5{)F4Pb<&6xQWiUYEYYKAZ1UqG{R;|?ifvhRP&y2K;sGP zByG!S*$FC=R=r>lOPH0M$fq&@k%psRbFhrPb?Rdn3iTPkZ9w`&+DpfpQ*foDA9kM9 zm*{;c*-oSq%b+s-$nd4!{f-$}GnMXX;8-?6vA1VszRUmJJ)czn)TMj;6Vr1*=l(A3 zAb!28paK(PzoGrAsMb42Ru^kWBVIL_ukP=z?75%j*fCPn(Fs&7L5qOLQz4$gm9TH| zXCK>2$Z1R=z+>5&iwTBeO;o_iq3e@ljj(BSM^A^D$_xrAT~+qxiJ5e6aRxBhxDv8~ z=uFiSD=2@p<5rC+nA@x$LEx=3Wm)a&XQDW3cg<Qc?lu@GDO;{P^={@Vg{2$(aW8IC zMLnF+Ky4U1DM+N3{@^JrcaHhj&NzE6Wx2GmwUJ3}=-xA3UAD(e(d}&7(PM7(;^0eH zrE84X<%Bs0oNxZrp#4w5i8o+l6Ume7@7JnWrzq?~ZqS;~XtG*yhOkdRc_j-LttmkL zHFc2b<B>XFI%r|%3&@`bPFW1djs9$J5;ps~3kirp6?717lD+<<55r81QpYC?;-E8o zlN*nss%xFA6?gtL^X+bg4-Jivi!m*AXf6#)_fCM{KJsh8%#d>Y>4GJw<$gqyumnh| zVL#GpG!qq^LxNhZtYMO^u4wXunxwi^v}w)Qu-C$8QggJd-ONy?rBs3CW^CD6o36<H zagAkb28gc$1ImC|RczF{k8#`r2IFf_(cG8BX6qi87lwFLxL_7gBFU{a{dhJ1><Z&o z7QwO=_KaKMB#I3PqXC6!ky^$(=(Lo}GCdU(f`Q5V>n%$?9I9<vipvL{r8^INEWuf@ z#6<h+#-B;+p9W9q)AaS=qM-U2muD{;3^eh6X<n)Z%b{UZ<jU096=mKUFR4p!h8l6> zs50zC74~OX_KxlT#{PdJH&pTWCM057XNJm2*fyDD6zIHSrIS<G1Y<$k$da*o`7B4h z?(ynW6Om1YU4m{><f+W+2=*3GD*K&D-z28CRFkY2ySi|J%ElyPP{Z==2Nh?7v<-FU zj&1U^gl4s;25oWnOKEM;{qf$n%J`=mB%Xl1&JKHC{;A=sL_XRF^>99^xsol3-|M1u zZ`UZ$TXt9}RLQjRRJyllQFcAod+Ky~@=%LykTOuI`Ru^5;@rZ4Mhjo1-(ihs`<Kij zU9CjFmSu+i;m*uZy3lR-e{i#cHeFdVmG@Cct6H9Yo;H~3VoT7HjsJ^!!d$fBDQ8~8 zN7ScgzO)s(@dmMmcz%D%zpF0@%cCmNLNoFQ@CF#}useG_o*P@C)r1K(@#6iIurHuA zm+J!4J(-wob}Ao=anBy|^dkxvc~=}_W;^COwYoZHi^m+(k6$0KU`z-`;kZ-6j=5sm zU2<)VT@k4+#|ZHp`UH4-2<eIB+F0A-ww^n4J@Gu466;fm-)Ow^O;}gHD?)D>!!bW8 zgP^>!h8L5tJmY#=3tfBT%LDLvQZgGW&%;vY%(#q;hnh30yd(jwYg~NF@5XL?!ylWC z37Y?y1>c$RA*)?rL46sUH3XkJ8x|q*;W3D@SY?nxeNty$J4gIw28*lvyi#1{(Sq}+ z%AIY{Ebf|1g!v;<PV6a*F0`9FYBak-*i*VfIn4j+$1)#VY&XAped-nU)C`kZ&w);e zJa{z)0CqR<EeGb5Xetc@Jv=%N<$Hq!ZtDSjbs^zE!#Ga1+1g!YT`#VRyV3P{gU|$s z&Ymr*5mj&j0M{6;b0Yb@fj9ePC_9Pg<%Hs6LoKTs6tF2&VJ3m^8|~%6hEn-tc(^Fk zyK>)XvXhrEg0Y=nj+Z9~AIAJ)8i8AcjvG?HakJ1?I!k}bGgRQ#g^w~EEtaOvDQJsK zyw*sycr|Dl#7K*SD=sWTgsfL;Ue1n=cGx&M8AAFB8585Uad;C<GlRsOJ1h!gv`2dd z8h7Tf1ecu&)T>x|^gxWJqqjrI7aCK7%)e3Cz><1h#(Ypd`O5dqFRAy-Y@me)&6@0D zlO@SHc^RN{XeuMdB2SvfO6uh<JoL^CC|(yQuP`;ZptpO&cb7c`d6{XMzI0Jkpa~4o zPF`DE-)-z^{RbtVOK=81B(YxYeigk```-l=DZ$x}Eig5c*f|Ic3{H+T<U2}tJjwqF zdxOFCwHj>J+G?W&9cJL2Qf4FRjcltaq6Iyv;;x;9a#Xa|wEj79NVxqW{me1(k?@6y zUH}r%lrMLUoiw-ud=mUzb>vhxsneq(8qi~!G<6s{6eOXRSgq7hnt56tit_92(UDHu z!w<d!OTS@;`RrV}?Piqo#np0&F@e2=?b#7aAyU01Oum4<#5Q4IM|I}g>0>#<vFhoC z4cvM!=j)ECBZ~-(D64hl#<PB~z-HMgO1D;MyH2DOSr>N2wzu$DoEMebIxvf9V=-H6 z-fX;3ySrxC_-uJinC+#4WT4!)<Ig<r!~26Bam7+vrE2MuoX6W=;-4(P)Vtne255Vv zvrT1kJ(}c2m>M0%{*&;t*8ev*E7_&mT#Gf?I^4N%Xe)k&6sI=>9u~>vF)hdoS?7es zpRvdJYiuRQweojFe9ezB*Uk9+n+EhZ)icacmOu>(mzxhEW1E10(p?QE5j_z=A*7p< zi*7W6kjf^MPj@4MKxO*Wv(%r&>y=?DAv~_JSG=J}F#^z|lUQfSUPzq?n`K|y@{hc1 zOLabFy!mnX3_d@5Yo3oW)5mG0QqWbh{6Vn6RC!~^#HXD*GL5XYujrcLFbx{!ZqXlT ziq>>X@0rH9i2X(y8dz6SuQK;+0qr5CI2m-LS>ty}CTzET6sMGOck$au9rvzR%l5cF zE9~h>t=ZbOGNuq_dweX+v%mCX5Fbp*&UW_(y{+u)_4gbUGoQ+UwvUb>OxxdD!4ZJx zhJ@ee`^3Ee6a3h{4Q6E!1^wVq|9B6e>QI_-T4Qvz-XY^`S#-X>cgkn+?X>bt4p`d{ zRaQ*@N+h)-rhO<&(7jaO&=(5JBwrg!)EyPoEZF)EKD)HEhGwWsk}6(*(geTeoFmy1 z`7UC;eKg~p>BE^r-w@q%Lv$3lrW`x$3y4WyeJ1y7yQdQ@Io49<yk4F_2}1Jd(e(wH z$RRF)NuWOVIm1Twc>ux_K20k8T<h+V*<MMW_6Rtc#19@~#x@s{BJG0ki>VK_4D@`$ zPk$PswI+Eo*!y>P8SZ-RoJA9hoPc67v4D=sGs)Bb9^k`sm~*&WVs_sS5C92ogGH&c zFY{E}Ouf3*{M9?RUUw<x?{jWpQ2u5WCc__QXpydC+2k#^Qg(oj=@N7uNEwBHfkQ?& zY5{r=m-C<<uo(GeE(!Y;W~KB!I#2HA`%e<rVxF44v{aGNjw!m^ZdLimzc7~xW<^#0 z60scieFgj)>wojXW#I}Ou7kl5p#?zn@ZW;pts33nZ@2SSsl}`R-a0s7f-kQDk=78y z0B+k)L1St@FuWgzfzynq>W`w0<F();+n<|LV3<Hn)U}~!!(fIW68IY-3B_cQhFHdq zF4$rvjnQIpR1aS3{4=trq!7prt`<9^kfrq+b~@hwe9djy3?@-iLUN&PSjuF>u!24Q zxrbq;#JDzm1ZBMm$Xt8_meg)hXF4yyTrvr`Dt4RsaebiQGMD5+A8#g7SulKoP7K=y z818sv&Ou(J|7VNQ2AvFOsRbB0WeDC1c3c{VeC-8Od;d$PTWP$m5vq6f2bIJ&r|wdp zmz_<e7*63bycAwzv{|?9mbXGJ8c6qj)`pb+T-yX-tkGT7HY_q1Sq)|n!Ljg0<J)|I z&c*E_Xb&uk`ZkM7D}~oLN$?M}$6y`8toE!*ecjRjM<D~~`u{V~vimb3Di;`i#PCdI zMq9Pp@757W^|wFdTY2!>MhSjlvnpq24oMCCpjg$RE|t$+NU;OgSDTKPPlFRTVOCeG z!uU-fnFd3{==vjkom%~efQOLOs0)jJD%c7q-~$Zsej$i|Xg3*P2%~isS1c$9d}qoM zeVNALASbAMD<h<#GH1R{vutYa3iC7NMP>qXt=XBxPjHQFRKg8<8~W%BvyWw(OW=)- z5-nC{XE>hSIErt42BiSS13npy7k})O%N2(X#h5kjhJX9{2`YitHcK>HrL-Y`&#cZJ zq=v00;oJV$7l>V0>;8AsFB0$SDUY-J7R1vwZR4Qu^~V5EK(D`@=~+d>)F+~am~l{4 zD5?hQWAjZ7(hHzxx2+hO+9u9EQj5YQ!NE)EtJ<oh+bT{la;aJtra3H=wxLCszTFE( zu7D9Unoxj^<$0}mGcP!?R4wy~(w)V)s6lEE$c7Q^OS54Kk?HH8Wvwj!s27Y_2ctm{ z$B%J&;qsY&KF61~by7ZhjKt=%Gw2ylR8Kl@1ayz`Sp+IUnm{Lf8`4duNK<083K4eP zd@_m8p*W`G<)u@&+*G6A)oc1n6!d~wWA_J2qFGAO(w?ND{JtpqO-a0@XVibr3B911 z0QTha!I)QYN|Hg|_UxyR$Mn;E-n;es2mJG!7MB!aPZrJ&uch$ukKfH5$VS4C(D)T~ z9Y{Q3e-dbac(bCs&(X<<1GRtzFkP`APw)4ewu(YUnR*nWJ_}*6^==#1LI`l@_|4l` z`zBt$1vMSB^|-?n=VPbgsRgk^VvPg0h#HOdB`NBu*4?%R3(K@+5|4e;dFdzfjo{5J zZI-mCKB7|xMnrU+-#|UK?3hzY`;~OGt|vl#^f;V0KWoY9N!bWIxqT=gtAgTK3{j== z&(<DrNCcZ$c0%OlhYpp7R&l=gfZBRMCoT<7rKJ#(z`;`Uf~(dpcZ4B}WE%gt@GVU~ z^ifsnYE1lyEbNhV_RHg4jkL^=I|Bd3dr|XjdA&1iqFwc9A=fG?DfFeAdqgPF@*qul zu*Rxe*V8B^+2WLQd9*pj2s@fK`HvmpfU9N%@OB5KWf@b#1(=pV20PNhi;!6aKT`;Z z{S4KD!t$<i&^=I}F+{zyew-V|vIP}METvx<*zoSu#T>%c#vYOqW6(Htj?_>o;n;B} zs|Und<4el138|dn%i_s?YL6qI8k@AW|0bOdd_nEfqVJ}@^f`Z_u&kGz-gSwRoR+qL zSX0+04BuZd<m!L8tfMQuc&wmTspez-;)e^wn`DlFn18__*V%v+?KuQG(e@F4=kbCe zPv`{P9XOtJPO_rvcCH@ry?b3ca!@hTHSjW|4o437rIYmpu<stBN%M&fukAf>Z>M9* zK5(S~k)=5V4W#d3?gD4~p>7z1xa)nbA;|taxi;t&Xp}jM9c7Hp?%Y*67@QK{J^>Cf zx6qEn0d^)nekLy+uyk{)vI^)SMi-72VXw&<rO~p1jKBs1^Moj90t<&gqnXg~_;~P7 zEwfx2eNEV7gR0%*Z{NGna}~kqb`GE>zZ;G0F3;8x4hOySVf6bn1>JTvNy_{X^bqGA z@5ELcvkim}K5lv3V3@0HJI7ZQIt(>Kc}$4UE<m`Z=OibQvjI+a^gEl7R3$SEVpzZG zP`Yy?o4P?AMLz#n;l-C)arOGRI_yJJUTeDU=Ru~#4+GhKj|NG1<o-}v`f~7U=0<)b zkd{P*eP@QFpQk0QLy4CFbKksvQCXz1`Xj1LW@y3W&12Y~`D<2T84|q*=XH~dq*de? zC}bi+y?b_Q)U=;!mAKyHWXwshej{19o%kXP&*ZZdONU3&(wRRNFG|y!j(C&M*x_gV z!7!Z&SO5`WctErc8gmp)^K5ng#d$nqCoRP6#OX_Qjix=O=HB#l4V`UTFRKZgKG>WK zhQWsvvSWWNWneQuHr-O(KJ>m}`7EZ#|DfJ}D}^&LnI9T&AG)RZ)SNZ4P5RUY$klS^ zF(E50dIi&m)vWoaGM%wC+<C}}r&Y;aLWi!l>KC;f-exI0OLW54aTc2cnK|QyMa=Wr zdKq`M@|FNR+EPUu+tAv;H~|^7eCHy<rg}Y8!Xy!BVb_C#TA^z^%1(N6s&CS56c>F4 z0h-87zk{{)w`lncoe9x4*y>JzR`$pq6v8f1U4j(5RfX{09G$yT$&w-cEiU<+jrTA} zyxGOp%KpDmOr4RwuNt5Ij5tlmo}QAYlBbuWmJ|QqKS4-1D}ZZ1Dq?xTU>sl^dC8K5 zKD1|G9Jf~cqa*!oLGy+hdBwhbNmfp7`aR-enFT%?pi)oFrU;a9VZwK8HwP(vfu8`% zJDO@d+`@p^9M*mu_*naOqXd#{PWpY~lGdvtqbv(DfQB>-t?M`dD=#dg%m<N?KPtM3 z-I`xL5J6*>tTwAq(81a^mc#9Hrtad+P}}$Khf(<vYCjfefTF~eTq>%S*lH_a2^p!R zl(<kUM~8gNqJ)9c<A9B@j)gP9(%lVLe36q2_4RaF4MTdFS6xGp%*-+g&_P5kDavAr zs-qGdk2CmiR1)6WLP*JTU@J%^7J-67ijU>(_lttSQ#Eu9LoP&Tk#VUUES^HjawT|V zoH_g0Yf}`gR}Od$3<N%w1z9tSyf|CpxK<JtWa%+yV2YfJW8-mjb=mssLL=c+n4xeo z%s^-}eIb~NKNW1qpA0tO@9ye#@Wr|gg*o`V<@MV3dd>glwHN%)%iE?jf7^q#eDl}~ z{O55iG>*I*`u^MRnD&es9iJG?pH*`r)m$&<QOFtjX<*zh%4zQB-vm&}p+txmDdFP7 z;nIQY_5ai;f0&61^}-!h9o(hbS67ZE_0$8W!Lt81a2bm`g|0{#vER3FS;Xh52|pn8 zW~u7RMM8STvZ$(hnSk5MGxj}Ops1#bI+%*eR}s_s_5jje1>ne!v45hDhS#K4Mr!vN zi%2+3Wl+5Kb!t`|Sd8?r`^}+e5KqmC^(j9n`<)ZyF{N-E4X#XPg;3g0TZAKG<HLdm z6+yI`y0Nk4<6_M_`?Ia0{IK9?O*uO+4UE%Fa4iP4)ZVi<!w@iZM4-hjdSSPxMF8_@ zsfeMfmK@y(>t4HLL4gM4#kp9TStjU5TF@bGMX^rSk_-__><|%`D2RP&iw2-%)l0NY zn-P!7(RPSX1aw)(C4l)ycL~Ejs3I-A?4YEkUU0yS*6|ljOT4d|S;Fi&#nN!050>Cy zkAJYHw{il{d06N#hx*{a47Gqd2xWy|kkxlF)^amCVY!)5sh-^2dcLBq=eKe!fik{W zkb5V+B*lhdT+rz;JX_HRNRmZshRW!Kv+pJ1-}wb4;b+$n2aXEBNRaCL==h2}2i$xz z>dSU2ZRp#CGES+K*c4jY#~T1zolh`FsHyk>kUXJ*;646-c-$70X|*lNg-^J7W>(Jc z9u*jMwhlF24HWEEjmYiUN3f!^&<05XOYaFbpadm)YL=F9G`8Cq_xIhbPnukitA_|_ zj`hK>t#tJ(I?uL>Du#P)+MB0Yjkgi6b|znPGEuHS|BX$6;P&c}b)t&ES3ks-uzG=U zMO4!{*T~^J@>l|L9)}uuO+1wlsVGiI5?k>(FP6jsdfigK+q?%PKnK;zn|Fk^?yzqC zn$VJ|tV*-V!|a$WP*zM?AvmY5=uG;#YNBT?@^@P?iyhx5MsfVt%N+vv(l9E$A8(cU zAvcZip7-Oql**}Ylb)(+YF_a~?^XGujSyjS=xcv*>D#txwJfukT5l$;_K6svX%&le zn9hG^r*tDfnycCKT>0rP6oGU}soLup$~#p-{3bEI>asji*$BMF_H@MzEw5yv*UEHF ztqUTQPQ8Lk*WTS{ek9#bZ~W<Hv>%08?O*!FO3?R_jx@y)L2x_mQcqm3?GXJK$b(#) zd}RFU`&ejUN-$>8olyIzW4(G{RB^a~@7WjJ6j$+(7<pwg=?r_8kTZ2$c9J05_;X== zVrv4{sM@3x*^+=xN{=hjG2Hop#>|vtpzd=1zx3t`{$bs#`^iyS`?W$?#FT<*;iinX zjvH%5nbTaUXxfE9kam$Plu6A^&d#?q>h7i)_g=qy80XBtOTOM@e8-vs5gfHuv6Y1_ zD0(-h%a^%CrN_8dN?YkjS<K*-acTttms<uDB^KsX;0V+*FfUJB5Q~P_)pg>M;q_Nv zj{={W!1u$~XR+1*BjID*a^=2>F8L!gJfs@z=zo^A?x^L<bu;fLI~dMEERf~tn8@Oh zjFiafSPl09Dc1^P7&0aTm4HOdyVzA)CF#jPsOGL|2*foR5yD}5GLFZk>WwYF7(%>i z)3bE{iPZ*|6dA6GE*_Vuc9L(e;@P)%qkR1uqQv5$25?f&2vRrw=R_fB-+V>I?C$WA z(h5=6t*;ppA)_7=Ao3)nlskXp>$6)Y`F;ldw7&>Emr;bU#7)>Z*?4{;HkSj-zL?jf z;#}69<We}~=o%M>M`OZ5pWvgR2o%xhP-9F_jGj4__lfzYkc#Q6HZ*t)gMxt3NOABC zN>YryE!%@*HjdGmDc}tS&GekN26)jjxKo`D{usDHh%8nHZ0ZGuNkp3_)`msa_}|<> zJf+^+wG>$_NId9$PNv|?P|NK&P`*cuR%9qS7};^ZGHWPU1IdQu0zdndTQ^2!v+E;M z^;7C2E;AUh_1vBl7d-i)g@L7909qfay)Aj>iiV8=hRVrnk^6SHwGH@wdR)8;gth)H z`C0zU|Kme1Ke#Smfs5sXc%v|relDyGhipubrw^Vl7>uq01g_ETnwQdtR|qJ|@0Qmp zb=e%e_xidSa*hKC!1pc%AGi~_UtxL2+UrPz5>l$HYt7g6-qv>?Ew$glHx`ebhTjNc z%fC#m-(20YJdSZaaj1bZuEK1_e1U4W5MyEG%R9Nn3ac5bkn)m{WM;{c>3eB28G;xV zbMFMQf_tTJ8fh&7GYBVg6dt9~H~hY#seiBu3Sx_C6m|<73y<n_wm=3$x7>Zc2gtyq zVx%$mpvA9>#K*`0Za!OS=d3@-pJ5Yz3F=2$<XgDmUfO3Sl%1mrl7YHk*XgSWH<UWd zak1B)^LkWa&gC`ji{C?&Gbya6VNKwB=yGl`s!f$PRPZkcgdj!>>DY|h%eRka*!2ZJ zlF`(62h~g2d;bQ9m9I8r-IW1<%ig^l8dkV`CF`sFuFe@j>eDC5q3AjH(zzt6WJr$` zmu&wRU-gtrfHGQb{j2(%8Vk<)naa_B@RJ+3(;*;_DRcPQB`;MY?*8!p`hy*eyfQ(P z))0Ovj(O-bwW>DHK;v*1>(4j4ADlCY)DARIyX<KuKG^19>3*)=K6zJHM@8*xZ7Wnl z97kFiBQ0l;bx&b)Lzai#Dfa2#3opEeCCq%eHB0iB0;XQ}bb`}or6f7hA2iN0Ulal^ zz{|&+V7E_5NmA@4Y1$`%uXc)#RvCs=hGkIYfd%5IdUJIst39Wp>$hr93g@J<*37oh z$|rPEF)vRIyQA)dO<&j6?!&se*bndY!nxPRNXxppLvY0CGM3V#f&gu)oMW{^@SpXN zdSfrUxSSWgB5*oEMrCrVmYt_nlwL(mxJroIM$FvJme?ZhLpE`E6|j3;o;)aXR?(gm zmiWo$0(W7H{<w?2O%Hu|<iF`P?%H%F$(oyBZQ8$?CzG&A_4Xy)ayyJF{X>20<i{e) zy}Tw*7m+=$?a}a``sqj2M~0CmLlDAN?j)<rbV^+Z5CycnPl#9Gs%E<K!kq9zA|@Q% za=us*|Ja8AUL7#ly>sNHz-%T!yxX<0I<^zLs&-sa=b#)kZw<+=(wLz>@bmbAu1@WG z(CT20*<T`k8yl>V`e=u)xz9J+vXN<1MM!Uj(tECrf(fN?N)Mn;;)y~|9qEa6tBq}4 z7aK>W0jxU#A^IHm@u;xcWL|Hj(tDl_-X}xEnV{%g=54eKoH^6Uk#5|cyl&?(UTG?{ zJ`88lAr%4KbwQ21p0X;6!@C5ljs(e@0%{3tzIby7tsPNW&`FDH3e~GnD)T>046P|5 z;iutc5nt9*$fJKoRd9uLTzVi~RHeUj^6W25uBz{Ia>pw77tHTRP1<c+od8GPpx4-Z zO)of}04<-qS%Gb$8lJ)FWAxrwMgHFSgS}p-uKv8D%hMj;R`w%0o}s@hvMCJxDBMR| zYLv)bWxgx6$!?KKzy#CQ+fPYrhGE-lg97qR-;x_6joiLeHnMxm=>m7In=SLlEqrzl zi8WNH&T<Vfp@l~072V8Wrw1kg#_QJ3KCNG)YrSWvH);UIhtEggjm<;A*K-_=OAdPC zylvq%WMhKHxexSlpYsSwl2-Wl_#6cm_hk%W6p-U<0Fe|UVt&)k8YI5txR1E!Vph5$ zvv&1lbhSuDx7ES=E8U7RCG1^a$OoQ8?zX;Ij24Fgb<$7L4abFbR|Ru#&Z#5{(Ivgr zec-f$sHwY{?wBrS?M9@gynmCB{^Oo1JoN68prgsMM&p+AzLaB4$E9rbT8{|D%ILe< z2TQyighSssnIVVK^rVeFOty|tOo1waH3C6XHu2iNHi*k9FUfS3%tPH`#r8$dS}1dL z_diq2IS0N>W-1iMdT~X++GZcTJK82o8-@_~>)Z<JG9Twq>%D6dxc>O!*8BA$yQoF7 zE={VcyhC!*FQv3o;(eNAZAnXLO%Wxs9cHiFD(jT;wvQ_(p14(t!jZ@+McDK4$YD)3 z2`f*1&CJ%6hg!4E&C*4d`BygQRlep%_W1Wi4s09TTpV?d)KE=NHJ1T26|y4-{Rf#( z9=07z_w-jIw?O)>$8vA?wlz@c?TvW_hzFGHlq5<sk|)yYhL=mrOgA_jj{)O~3+rI@ z{CWXR@POZjx4(729W3TPA83PXKTrdYw|UDW7|hB@o>66Vl>P|!`(RqacwoAG0&7Zo zu<rgZJdhUg`hqDudqv*Wrxnb&%Z%cBv=0zmzmWx^FAM1G#l~B6hC8%c2m36ZI*#zZ zkKz+nTG)3ZxQzob!?>_-fZ8HfQ#6w{FPz=nTL`=<_ot4Z{^<4(1*FNx53NH!okCZP z2F|GX2F3it)V<Y(ttvhkP%iBJDR$O^sOCPyRoxwZe>cA(oiiPyV5e7@_kAEOu`_zZ zMe;EP`v-&{w-fF(@2{SnBeEOCmn;Q5b@+IpHzEp%kP9B2e@*E9DSXj_s4Q8+^K9Fd z7WVXYxAXM`J=;q~v;nO0qCYHQ6Q*8+$6-qn`NCd0D<W-QsXSQEemFEMUy*FHGpvs8 zN_F`5^LWodV5&mg(68Oio7KCYjvBcH#mL~TWDJjKFdII=B^JMdG=ZtQGs4y~EO|6W zcYQ={WgqOYR-<n0Dq!HsWS)iDp+g^!<Iy}9s+FEBVhG;qL&ey6KYEF=V^w)OixUzb zwwur__==W8bu(Ah#(5WWtjv!d{fgYunir_2D{*-Z@3jd}0J9Gf+7of;kR#{w<FEq? z{)ehgch(x=+4qVI@B!)X<(DpEHbIgM<?sjZl(}GRzX=Y!xoY^XdxU+<a%Hhhqj|~# z*ef<#c++O}K!s-W_zl2dJEFk<M^AdJ^jv!Ie;`+c#RK-GM6Q1_xYZQl(_-t62Vc8U zNdI?nl4aJ=gqd15dW3z;_QXQv9{$JY_jaJn4WRYV^TeS4+Y+h~tA2<V*ibCh&n$=x zsQf(`<E?G&kW`$TS=dPkR|ZK=j{Ck|U1_4#i0UHo(j<>_B4`Yw+UX{KUJ4)Lb3(*r z9W`pJTlN2h*l!2MJ%t)3?Uw4N`?+P!9D$(&I$Y7+P3^Y8Sv>LQW!i2WRrpNwyZ#9X zM5_A&Ek#6urkjbud--V`H?kAh3ptivJ<?=6S*r{VX{d0<?}85IGI0KEe=NJ#?hQ z0}ebll}>o%Gg`5Z=N7>5`YE@_d3dj?fn08{K?Dc#=I&dB!*j{PBL#Do+H2-FDCeFy z9-H_}v5^<{d^|S%J>mgKc)5^irc+UsA0FzMAoG3j%c<~@ZDMCPOOzGg(^*C?=)0lX zZn&Kqy|VK$P*J6%ky_dD7^p%z1GTG++?r*uS9qvlEjOon0UVO(uD|1#O6M15Flueu z=V|?i{hHw!SKvgK&F5fTG}Z6hZDUK<L(IxI6r_|-4>m-weaIU*1=NE0H?X8B_wD*K zlurhJIIyc|ZGD%$stb2MJF$~~d}X(ZQmSq&MBV8Fo(O(@wj+3&I(=o5={fxL%1_I; z6I=lQE%oiqHxw8<ee*VTj{lYd*T-P%QBy<C$HfJ2y3`cgfFBR@GMn!E=gMu_U+h~G z^17QqT95Loo2P?=A7tlCgyMTWmax@rMe65QedPA5ZVyxiWhp7&WYgV3(?mm#*Tm~> zp1*Gd_QcgZK_F1Yi@~9%-GUP#KWn|aqc?nXe1aQgum$Tv3QEE~d@|Z2)j<+*j(!!P z=`szQM)@}`1KBaFD1#h6&FtH!qjA{Dl&f1$*zti{x!&sTZ<84IHwYNq-Z&o7yJ0p( zLCF=~O!``2y`{6tm#s}4bN%kOjF}F0&r(vhR4sYYXU!nuRZeQ4FddR~C+xyRgSu7a zZ<LFYC<DBWU5Gf%&z_Y=`0d9iyjhLVVp`kNWb{H3t|4m5SLH}!-`|U`d{NY%B)pHd ziaNGuD5(R|q29$rP>~2M3SETM0%r?s@1=frqICkCXvQKzpecz<WJ#p(+i5*-nu<O1 zSn&ip2%VSf!5V+%?LVla{eu3FANKofTpljJ6O<m18+rLnDyfzJWy9^Ga$1u6`&RkO zOe#}ULEqqJQwt(1yxG~-o|fl==U^5n1uh&ExB6yXlhny#e(`7OXFZ7F<AhOw(AL_k zgq?(oS)^SXq)U+t?-64APm-G)FuMCy2A{k@?bx>QsZD8vV;baZ8BSLAxk*M1b1E3* zLwzb4ENUhx>X9SwONr8-ox0up*H`O|9ulIYnO90>9uiJ}NPAIAniWNE4GaL%DIVdl zT7=a1k7*jHtW@HviV9R37BKIF+*@OleA>n!*Ko7ctbPso5}MiUDOO>r3L4d?)i+(B zVJ)d3P_)d51NlFd85GptgO7&^M(SfVL4dsd04xdo?_bRcjAEtulA!$o%r7?1fUQi| zVr3&(aA*(&A2QcwIB&3h1UYJk!GSXa)1JvnpBn@LEwcn#UJ!r)GycD#KoZ^wzyfo5 zV9CnsAn^0q@%r^W*}K-%>s$KhI$)B2yW)z;`VNgR{P?`*;p}hu*S07itONlT_Xe=U zbuR$3ttdziyX`mS7MV%pJ+~e#^p;`H4JN>#?h2qi83$49?CgdXOf6Jo-}e5#EDe;8 z&f;k4x2FOc9-Bwdl5`lnn_a}Lk^jdWa7##5mj)8gH9jP(y6*_~Soy5B?#<UVc`tT# zS77gKIH)&w<(kF=SQ<es>F!jTX~Os;Rw%AZ`o(WhH8I7{R%fH0*9&@4FSV9WKzL|9 z-X6OHSiU>)KK)o-F^dK*M6FMM(iZGMW*~!#Xp&Xw$ZA7v))#aW{o@~ZqZ7H8n6sLv zVO@HNr#P93`s2Bz&bW#^^&Yu67P&Yb)2J7Cv$CqPibz%$WE#tp1sjGd7V0$UMLgu< zb>!kb<igKLLNN4cmMB2nePhh3;IdlpG&*CcEQt0>u{1pbjH!z4Efdgpd<MR4&uF5; z{KsAA_O*=P<F<a(Dj=iPsP7J|p)eq3OtdXIjS?X~$S3@N?oh{Cu4_&oIWmIRYqYhK z^((?R47tJ_hUnI>8t=)UM%iq7J02jp!U%?FM{*h^vsq3-A9FRl!K7DYAkwS`x;??G zvYkZ?7i~Ep)9XrY_s2LmLPCWxooe52nSj2;v+3m14R+c=w2keUOq%P3Ipe#FqJV=c zJ_0EnrbY@eR3tU(BMWqMf>_x)qA)<Q#Wap-apElnggB9mh+w?Cb9@5k?oa0K2?o^@ z#~&uecG|XuCAAPYQYV!b$kK0d1Ll;bY-Od-L$KjifO#s>Nqek8h*3#U$`w~w%9B=c z*@32oN}3IhCxHzjh+VmTaeSb}HjKT)#QWvlyyj>9GxFc(V2r$s<FlT2;_<H8hMa(3 zz<0Gya6}r1JaSL@{|@ta3F)j2AY+tjO>#tlb+Ap7%(Tk_SA&hU`hLgg)O7C#V`MZF zE<Bf$FPm;gL40$U_KC{5-mqSvXE1G73%(m10U^92CikU)f*zRr<^D$?r9~U>t71iV zA{zqTk|0^xp^C&&+0sA`@#CVU2=V=jEE*uh8<90l(X|IQ1{;(5jCaH+ZdMt!zQtn2 zD4`M?6PyA}r&`vj3Fw<WoqAGHj*%k+v-*3SNNHYH9XDo8iIqO~?2Xa73ybG~y*D9= zK9}BhGV0}U!bwLkxMF8YBj(PTWQ?)PMOf!*Lp=<9^PUvat#gQ!wh`puNSi_&9^&SS z>=5Gmxm*z9M{y_!@vVU$OM&_VKO@8jC6!1;Ew1U)U(=|YrH4XMM4J=KeN1Pacx0Ur zic!^z#qkN4%e>&Ns5Yc297+0tq6)hwI|<<!+$9DaPTQM?tQ7zIJUj|yTD}526}a_X zFa?V)EQVgW;*<=Fp?nK}79f_Dclir8U)1$oZU<GPXm7Pkj767u9mc!(?pO2(+@TJ& zs98C3qy-o_&N4L0gB9TrLoR-WtQOT|VRxocb1`NDhJr;G7DGw9_$`WwB|F4lO1I~@ zXv@LOk;?%mOHNNf-|hK5GjO5{V#M6=Z8NfdUQNCNU26HP*|$&GyD>AveRHE1bdrYs zd}s!?d`X+Xs_k$>-PB$ga2H!~GUvi&1|)4N1{`7+qMYF)Cf?VL@UZiL)sqCDd+PwD z?;CY%HpL|mklJJLdMG+R!ioLn?BE9~NpsLyMg=2^@wpw0LLyp4G;MWh_FLkw<$4c^ z1Kc&dmC4eTo;;ER(l(x&fWGq6i6H0$$-dc^KR(*89}NetV-%!8CoJ%uQ$DkFOAcH~ z1@j@UBOw-J!Pe*RJQt7W(we-X&tbg7_~g9eVGUmw*5a8V{|Y-`5_bR#t~~%|afJXD zJmI-8P%U_0g#yt+=&<)k0~S*0autHHcwZdQ7PIqX&&%x}3IUpd^TI9dGhN-i{R4wT zW7F&aw2dP?)(90xX+9k1WnHamCzIUupY9~(G*0qe@mXJ$hClu1CpQasVJjSiJ;lDx zstMqO>5V?#E3$rBP~hRC&sv8c#Wy$o+H{tT8Q5Yn$i;}>wh*A_C?T6k=Fj|KP*9D- z^7PznAqp%PFS*`cEM_DTi2IpGhU0fU$E|Ez$OM+YXmt^FbVg~tWCymrcK-+$$9o2f zMkfJw7VG_8*SX0AHhkyf-ooShepLti+F9^f*?5{VamzoeT5D4^x-_E!MKF3#oEnx} z1U4fS-yUUt{ZI<9zys!#?H<r<Uug<a^M!!8eP@Aslv9LtN$=y1<3nbT^TsvX(D9Tb z_7Q$D)Z^xrx~`dz0<CZeA6q|?(3}gqgi93dg<+~DHIct)w!bF>7D6b;kYYc!0GNYG zeyyMn2MUGVni%LuTB|JT(G_9wRk}Ni`RSVYyTjoilEsAJ<>&UdBX&8vb__Csi(m0I zo<7@U_Htu#GL-Zv*PPvVimIUI%Utuy2V~Lq8R=MXS=8(sjlPu$;5OL^1@7?ZD4Ehd z&IBV`N*yJtM(k^L?G$8!P<<^?zwF25Y?45v?lLt#7!BGuY^Uk2&-FL$tlu99UdTr% zv-MN=N(x%VuFV66)DOR@%)><huT>$!wEv6W*|UEfejEs33vb6>?wkBo9Imk?zCTKk zTfbLI0_J=ks>=E2#5Y}`Ro~T8*_DDisSgJ7$VMZy8Flr!k)R(sa8`<gG^F7<kY+vM zTbQih`aj97CIh^7kT%_ZZZ{eXecE`3UoJM}4<Ke5ZvT}PTf4|T(&FOsDYgx}8+{(6 z-fnnJMM=I5!+1;j^(~>!;bBQF&9PW(2b3mii+fEuQH_F4G;=@>=Hj&1snL$a@xp2c z9UHwIg)xk2Vae=UT%G{mv_DTknkD)_hle1|H~vq%Nov&6rkl_0MrnDNHs0cwiw*e$ z<TDL7|BB<@d~0@(G;gG~#qn!Xg2A>2jwjpdNYd{yiw2i0)(p6ayb#t#n*E@~S}#c3 z0%u0js7iS$_#4u8;|WN!AIsRn9DaS*e_pw;6B(pUx14ifH;hOdZ}rPu*a-n<8gBU& z2lMUWJ<_6)x-~WmS)#JM<Kb))+oiKIT3KmEf|1yJBP8hQ9U_En?wc$wPJnOMpN=yi z)Y*{75~O#yF?Hzard?^;nI|@l6j6zD+NCKq;@oKe&qccFtc+4tnv!6IjUCYrdTMP8 zTc~AmaRPjsKR<_?*SS4obKuZx-Q~Khz)-sy2MKy})MlWLX=X`yvq~!`BX+8P%T`uW z(o}*E78Mn<aby!P2h$&HvHdYA2g{1glcwmvr|7-i%~&K&Mx7_=SCaK%R*eUk_CxP& z=;$#2%^H&mZ)i73&K0J!8R9*HKOy*eB$JgoI6N}k7MXhn#O(u0_PPeSeWVazok6u~ zWns9O*I!rLO0@}VHZ79jtz*M%LzIJQLx>Vc#$NS1=@Yy};DtIlG=vEPd~e|RBfzeu z5w`fB4+T1bh1~)&fwHf=%K=bbD>`g5-BfAcJ};}p{64cOW4{OW(z<n4TQ0ao5LMX8 zYp%KycJVD5s}X{x6>riuIUY3RJy<9!Bt=-QB<#d@Sd<W7EoGDpwpxN5(`<@;@KYAw z{2nDW%p9Ts94ixeuQ>s$Rin1_iIm1}@5rhFoN%NPjm&{H?tEQ|>tSs|iaKT5E(?Ac z96_}kN3FX;=O@Sl%!x$f1kt+D%y!xUY!11kN3n2a3f3Ps2$c3y7mG${Rz`kUy;>|D z+Ua)7jf-=sO@Nls5gOFfmE(UUT@Gv+9KmI#AEQk9S?KBSEQc#;^SiA9eW5GH^69FD zxDz~5Tz40kvi;)Zp7qTNRaaRWY3|0P_PT1m^Xot^QB9O93w(<6&~>39iktJsw9?Kb zU3Ak+KZ6W0%EbEPz%~)luHDG4%_Q%RYf(565Rj27Bkl?U((|2rGbh-Eqd`jC%)Zr$ zZ5O-E?<~1-CSeG3%W+rZ@lpHnmoAF&UUrs7t&mG!{8y(~Me=dfpQMW}@rilPdI@fN zdM#hu3mQ>0<#<5=z~B#O|5v3=XC5Bihk^XLrz0It$sWO?4k?+3{ibmHIA-ynD&qM1 zYtO&`*RZDhf5E;m*DsfP{F|oPgFbwKN7l!j_Rwt<(R&|;k-1$5wteeKhxUIPnS_>- zkF*O6!9a8l(rPj+uY557;+U^iev!xJE8ta=xAD9PMt-h0nS+)(%+KBS&PS{7CvFm6 zR$HbFRrb=&@05V{Lf~m#3I$L-kqf{X&oIA#A121sXHD|cnhK#Oex$)LzVp;4kC05& zPXj(pE#+*cTpL@Y<FJQ}v{fC0eSdWQtuH5U&J_q;?0urp945gf0AN_OScHm9Gwmci z1!<8r*`tJyNR6rlX7PQR<h7szno&`PubqEMTuxfrvOclhprc1XcvfB(x|h4PpVG^; zwjYiaCs!;+XpAQu|27q(oHgC6U{mn#(oL*nF1-{1<&%8~`8<AoBKU1<A}o|HuRE}{ zR%e8=$f*$;!H7p2fBPYvFBrsy`Dsh04QYG4J7F$bw^yzJK&x2a1H79XqzkCshwV$* zXLy<g$I9%F7AN;O%?;88cvD~d1v}*0zEEPkzFgwT?ec;DK`Ff?A*<O(-af*)d87-V zujcgecwRa+qzgi4pWCm>gh55yHxhf;gKdE&p--DL@%EWJLym>^rNE8-1)TQw>Au?f zT7mwP#}0>kq3BiK%ic{3{G$_d0xr5M@|@9rqNUz@x!sZ9k@NeR6SS<`{rxYdH{G-u zF_-1^@1I<op#qPu1yGjRZ4*?;UiJbg`!rP)O5x}_Arx2so6)b{RQm_hzjrG;rq@@& z5eL`&#QY0}4^nSU&3yZWo`{61CDGH+@3!GxJ@t1B@dR8dz%cVvSt#L4hX(_*q&DPi zh#|FFupc3#q^1~f1b+V3+>~|*m^7Nz(F**6!wYVEP79xX`{!9PE!3Y65_950``@ZU zV5o*y6D$+}n8B+obrm3<`q2eo<J-r(-jsd&Zp{rBmvDEzn_hR9+|hzw7y=5X%cU*1 z)?@|aT&|2Fi`k1Y_^OoySAbFM-019YfP^jUtegGl?;&sTk3`Jz6n~#Jh&%=2vGk5G zI_Q0%Mre}@G{J~UN5>D?D`tVf6J`}spPPrje|b0TL44zaTU{6%pRA_0-{9P8-76az z?=|uQrF~o<0+=V^Oi)JG?AQ$f&t(uyoG8sEwE=irFmBg?ngXJbPj(t`rhu%K*rHXx zAr${Ibihh%%hU#v>gkANGUCxJ-!V^@Aqb}M3bHhcLv)(RPXKUb=^oO|#Q5T_MU@n& zepJ@zUQvL#Wjk|<i^^J0#AlmD0&FR;HTU;NaREokF*O6~NJ*VxCG*U5m{_uO`c1rK zKM7uv?Vd@^JLYap*h|JOT2eWV!_MFTd@_LOjhn>NCX~jjc1&o<k)IiJf!1Y=mOWRn zJM64H@v^BCYIoPqo&usqH($?)42_FXT#J3|H&6S|RN+4Ll*@<_+Q}X@iZH$)o2rGZ zEyE+t8nsL-BQMiqfp>cIjnG_I&Pf2gxU#*3S0#U;F=y8TtLn_F{JS#q;x4dT5r~eC zGD<{IjJu<P{b2CUn@4(A7(?qookA@DP?Er*xdLOsSOhKAnZnz{Z_)S_m6x!+RynTe z&urO~Ww+US(Z#;t7myjW7S@dx|61nIvP2;`P0&JyCEeb$z$3K~m|I(PgkH=&R@!B? zGV7=nK!v?EwU&vzeUETagqvK$o6o6n)_Z?FI?k}f$=pdwx0$ozNS5Rf<O)|cv@~a7 zRI6WG7l=cH0+8|J955+?3Dm%og0?gXzj{=%tKm~di%(dUI?iav`oyN`E!iWJof2v0 zw3Z9sMQ$jdQ0cR1+R{9|0~Y^l0&ooE&jY4k@(jlYvw|I&UC*HUQdyneNU!7-M*iI~ zo6Bj`_hHZ4f+{X6ver#;@aEsL3ymch?6x(9LFcasEbp&g3EUY!g6!If>}VO^wNq4j zX?HWuF=X8>@!T{~OU@(5&?4$tJ@m=avO4IQ-}Zqp7CAb%`r+fpQ>V3P+FC1W`c_LZ zn5JG%vRFVa<U6m8o}JM?)AZL8`0-m-@r#^~f%P5uL;AQ#N0%JfmvdwBY2_`}T3b=- z;Nr`fL0UZM(hQKZvtuOStl^A9Z#7EOLO}}QRpZHRJDyve6BvBDgOIk=iU=bVr2?V7 zd0+0vH<Izq=#7VA(6cykyZ~%2*FFT}QOjxVjoI<h7hJ_H$E6z{8+umKxryB!^<0UV z!tO%TZL|w_O-1SAiTVpf^Hqe#;<v1SMD~8PtED)Jw3e+~Dt&U+mD5r4ewbYa&exdz zdE57G7|bSW_)g{fT3l`+X5O2-NKiY9y34l#tR*eE1R!UU{)z%YE3+pb_Sbd>gRv@j zlW#E&wI?EQ29(9*?}ynWoiBBLJ8_$+`fC11+G}HS3%@7*SyZ&&ziTQ=7v~Fu(eBJI zIR5*=<%aS`7_Gn=-RwiJ`2{PM;RZtr_g$E0)Juc5h!$rV8^V{B@njz+_r~8+-tSL$ z=6uqEwrr{DLQ4mh^e4N5TF`xaHMCV}9LK>ZMLFwFXCJ#i`C$RLZL^~ojNs<*cF>f~ zNzKD4WejS3M8T4jOZ-<FbNfI<`@GmY9rMiRagjmKZI0@o9RC`XL3`lcP<G3!)U%71 z(Av_|m7QU;B9!-lJy~Arj&6poJQ`Ou)NyM|fw-Z?YF=BQS0NES)tYK)jt<Z~EBZB~ z>AC=aFgurer+`p;wQSM9piIg-tqndAUS-0&&0n!~4<_Xeh2iCIJd~2)Jfz&=>|tkq z9uNAd*((tM-aVero9O+Xof({WiWiWLO<rg&vT;$Ca7N}KX<+YkG?-W!>C~b#Q-nm) zxPO(zt~N<8h%um0+fr`_TXxm^NlP%zCqO)xQr;2}#0~>ns~szfR)D-w_Sc3}N`+d{ z(|NKheK6-jd!@&VmLMXn(6bfXh!J|Q_>U)}80dNyv_#cxYE#0sC=qFqqC#E|m?p_& z&CF==A}iPRhkT^V{b*bNBN<u**$uN*NJv+Gr{IJzbyZ{w8AB!!|FuAd{!VDU?NM|- zp;gtE8?^gCur4*m@R}c5@6ZceOz*YyPL0y&7nlSOq^)u2nec3mu;$PstkIN9npU%B zO~^cc(%a|G_|KLvj%Z!NSa}+3QTK34t5z{3=%vTgt%of)^|1T+&9CNihpe8}ss;EG zr2d&~2o1q7W-%+UwsEK|Wu&Z>K)=fb!{O*tE@86=(yYd7>K{xMh+e!g;Q9>vum0Qd z(N_>Qq|Q_-WYalOlW#if>Yq8PrGGvEXIuSyOSSnXFn<S6%2)qh{8`ToPWcw+y@60D zZ27;22tj~U9e#2)@qNedklN3{Z-X`)D#(wW7`PBcEv-i3!?4kpXHFR^&+HjsMZDaT zJQVQCiwIsHt&Cmq)mh~)lVyW-ILr2-K%!~juUgpJPXTQ9_LgAMB-mc|Br|ToCufPj z@>iHApU^_nEQUEnV7<4o0z=1JTupg6_0j+zP5Yjm^LgJh`aHT{&wftI{Jz`c#jpLk z=W;*HO%MLO49VGJ=x<-9*@?6`pEi?vxmvzX4<{P8&BsG#m3=gDtOjQiynh!<=n8kl zr<`{2Jz5fRf%^6ozO<&8fkEf_Afn8x(&Tsx2?Ta`pqTl-;6kc)a@wX|#|3@e(JUi! z!{lBKGb<!{6FwWmOzxaXz6DANw}ucUrXn{2R?4iDZBG)+Ax?RyvJ$VJr;XzP$WPCv zeiJk~s%7@~AbO7i-Xg0W*WUH<NXlHEx{^}}ZaZ5quEKRRpx2iud9|hyc_OkY_O8k) zOaXk83v9Go%Cy28k|PH3@mWkLLF8M&kai^$HJuW)JrT0(xSN7ZUsHzG5@AL$xQ~`b z(+FCF$QffrrhEo_iIaXKatsDhHzPlujf7>G^mcw}&D*Wr?_?s<R43Ejj_!J8VFKgt zUxdr<5Oj`-U--p_WZizkw>gT|cEKK~&NDOOC48y~U!j_~PuPIS5RkQdA}4AN$U&4M z^e(uZ$7VAcg}(?EM(1<tXgB!UqzHy_*5r?Q=gV^v`-pUpG^^}$l;s`y771TC#{LfC zG3*Xrmf)bgg|1%i>)=~%D1tka`Zb>i{Je@wD8776bj(&DxCCzW-m4m1DBJB6f}Z-Z zSb$J57`E*i;Ph2C*9NQE`{MNK6>e)jxqk?zEt8?k9Ykp2)HXU&rf?TuKa`fmcUL*b zRb10e<$TaW`@(2E4;~raobOV^tNEAZXK<hu1{KCJzy);QL#f+;@~yJbqbD#xoruMC zs2v-zMobW(m7bYo)Q*dUNVUeYcrQcX#J)|Vp?dgaU+8UL!}su0{1)=Z^}?6*I3D!U zzYJqhapk!;p7Uf<CUYvMX$Z|E=0^R3R6u$KRsmyX(IxRZ0Vrz4vZk*)sauPQ?yOXF zlN!`=iFINi;3dsusrI$3Po<PJWGq4ZwVD#=6OB%)_%QY$Uqu6hn1n^_69I+t!M7*R zG=5f<F>q#6LO@3B%%Cqynie6W`AS%{JdzWOgJz*8&7K=><6$?ISJCbZ@1b49@qP}E z=TC9c%L0X4I&pjJt$3Sqk8Qmltd(_m8HfhScUmt~d~^k>8cbwj3lh77hw-TRfUXeg z6w{nr5l&^Gu%X^T$q{F9hSYby+Z4lylrZJXTB>%+5N)8ruy{B_SVj*r%2Ip>KgO>? z?Ke97S=h;$n!!$;0RA=ADg<Z-x{a7bHNzBK*Xa8w(4t==NG~>2c=*-Vu4hfoWQg8O z%0Mwjhj(BCa1~)s0H=afUXeJniR*Egq^3Zt1pDI4ge#Z=BLTWDIwvW+y`I&rk=3hI zU}0B&HM0t$VV*vNk>r}?I)-I|&tJ$(o2G-FX<TiZPwO0iQVxg$B~j8D{2okB>MXZC zb+xP{Neis1{;Ph@x##;zA6$=x9L_a}@Z)lq2dUS)O+nq!GG~+t@m&JlXHh*ROH3v! zMryf|;4Z`tjzBmA<Lhm1zDu->ckQwQ5}SEnC<?ixqx%sz%n7_TGusN*E^Qch*v2Sr zrMkOLA<iNA`ttHNW9cx*gnEe}tq{Q5-40Pa%C%q%-PndPPcCL-g|i1%HZA+Q8&g=} z8OOuu1Mm3OunELH0MsCLUbnv=IKT>bj4d7b*`&l1^()536~Na5QqXU&6Jy9;3DWyt zKT@B>mDa3bhX_&8`J7LjCc@47-=W+_=M?15-|GcY-O}^4)Uu#x6*}t*ogzDaI2-)V z@A~3=<jvW#jJ$40YQ1V3p~{<tt;DWE8lL?09tbqz9VYwjPnT8^T}bU3Sgu8r6-3g) zIT%Ia1Z7NuHtd(P^TSoFLN#4CA#p_`*cN$qcEf;9N&EIHZ8}yH(WxcOtjRKCqaIa0 zpc+h-TtPm>6kzi2ieyi11}V7aHVIjGdoT-?TsP6Q7R|>c97u*S0kxsT9NLSHx>TCV z<q^6j$s^nedNm3TVQuOG==++VS@V=457L^#(qS&iWmA!AA9yw3b<*&n3#d%lrxSH) z11KwiwZ{>HqL8m-pez@01FBldv<olU>$XHqvMcau$4Ld&o|Ld<v0XLfTT_CFr)5*t zNL-1Y{ZNsr@Yt?wf6sVzn3dko{8dB#1FRe7X7P&=CL(XR1`-ZxSOJ4Y*Rmd1HgZ9i zk>F%}gCXP5b!mq`dUi#oS!W2{OG4nMrg`Y`2nBV?uD?3_+T>|SKK1_d-4ne&#?f!= zi|U<)V?Y8DSwBGP>gG)JhQ@IRaOZghmDsspA6s5{Al)!|-n~n{{L(I?S?7LAe2-gK zUWuyp<6_)5<l__+U2;zWbB7drE)i%-TQ;p_Dsif}E3@{M<HOa9UwbR#S+Gm8E?7Zc z<}AtS5?+z<-Ju8v*Q^i#K;ij$(>phwmkfs|->UEJMCS}V|7pQI!<#Zfpxcnm!re2U z^W9}4)V^q8|EzP?LH<Q>F(6O861HC!T_hET`u;~3p8hdZ^et{PZO6@=Q(+sqE;alX zF5rSe^3F=T*rI1wcdPqYFo>YumR?QSi+vyoF~~Ka{sat((2l?&D_?dD_H3MZ)F_3! z4;GmC9&*6o;)SA_*t-y_6=PQj2?Jer!JW-_xrL2=g#}$=b>8wv(b?d#<v$}BF=p?* zdu9>Q<AV<+jH$cA{qcwYObc)nN3w+PcCp^kAY%De6XkKLZib!jTcPM7XDYB<7>F3i zdDdKuCOOrTNiKt3BTVg(x@z^HT)O;G(X3Z^O1X{OEKENPy}M}_&;iy*cq9x4Xxl5k zt@6g`exe9onM6xxBpl8NpM*@97X!NCo^FBLtHVP+sc@(ZaZg*gYe1b#rV*1wgI804 zQ%rA3(luCVO59k%QCcA|aCV55$RrI+)?D@pP}Z@UoOT~zlRvLbD8vomS?bdNe^?z= zMcX&Vg%I?Eu}JUh46(27p2coO*yB!%gA@gqxJ19SD<pxcM_hiuY^!&bDdU(v`t3+n zL<dW=dhw<|*XBZnJbLPKujr3Fg}{ag7t7Bi$;{l!3`R$d;Hio7+^h}17#Xt!R~W-9 zNFw(JyOI-H+k~o!U{6u)#Z75c2por6e+2|EDdO^+30Mf}?I%ui^$5+{io0SBuD7V> zu0DC>bOeY!kebO_7m<C%{!CL_L)}(LRx)ci#HQj~Q~$N(+3FP-7$%=Ry?E1IGixX@ z{<>b*cC^XFABrqxy4XIq@|d|_6@q2=z&k@|><a?SA7&2WiZjrY!4c@2B)CK?X_;9} zmQDo~8Ix3Uh3zx>J3g)P4zT!+<+HMLPiWYr``>=|Q<1=<sU{cU9E!Uyo@nn+omfTZ z4AF;f+u#*>_Ep47kVZ+Tq=IngV){p@DwBxe)d1&YnwY{Z#-+0_F-i->>ExY5dzC?5 zCycULioUWcw$10&ftXVpp3#*Ln_Zv#FE11kPm+*{pKjDGf_FKOkp`yrTA;rFdN)rH zj+jSuKAb^YLzMA~HsT%t=MM3vF3tprpeH8efHLXJIKAZ-@s2MUe(QM5d;^7>dYZOr zBnY)pEOyLrbw3ARpp7|E1T3CQr&24b-ME4gM2_PS_pHsJlbBYuJ3=TQ$z@zbvR0~z zM`7n&9pYDlPW^ppleO>WP1MTM{xlNJM9#q3DVPcz+#0~eB{&Asy^b$#eqUhFs-+d7 zlQj2NfweB@Oz#*4^HCN;e`Ruta)R9Oj{NbDV$5tSH1>RqLNp-8YlTS?Q=up}{^--K zJfdwcRU!6;@S?evx)<Z{``SZoOhR`+`jd4ByoE@09i3c!VQLAPQs)1w7~k8deOxRF zy&8`94I!zBHTN~Ozld>-lNgW$Tl$ErSnhBl`YxPr(ijMVqb`-(?dxhg$sKiUr3Lny zre#`~Ttfk`E|caAc|7%nibOsY>(?}!$vE+IJ7-X(s-_)reKdM58w&XeE|{T70(v(# z<ky)O&STzOFK!dbe}EV=%;LMk#2_)CfjrvndOM<aVADQNgKvT-!J(Mu+o~kQTFo`5 za?~#sj4qP~Ll&3I4_d;w0BcFS%PG<%GtM}YM0GbhD~b9(is>lZLNX5Y&dERQEE+c7 z0iiA;sA2?TlanNI{Q&q9;sZ!(NH#NYnWcK1Hu4p(GD1m#a8+FyIT}Ijcsjf+3*tY# zLq0eRDgd<fG;fG5mnK(4^s?BWY!?R@VdFIiDrHkOqOSo6N-gH;u)ZxJlM3PHKT3FP zBimPQD(@<f6)RLNFC4RYR)3F_jb;{zJOL|BJRItXnAua(5O5vD0xx$Fb;c;tYS}Rh z-oGp~9vTjCiBZx^skx?-qtLS;?>=0*RO+E_AzRx80jema2k@X$Bz$v6$IT_mY1W*= z@bqbuLCZ}Wkcd=kM5#$y-v}bI&rTtgk)^ml$el^0J@RCRg(hE!M&@7-=sjRB7-mO@ z)7%3~3Wccp!V+DTi^QgIBzcLS4Wn=s{oD<1+^R<`P$v$_0USs|c{@1tR<H>S%!-#? z!E~@Zk;$O#%(at9b&SmHtX%&Y=Ie~-I9nmTHBFdQZ5bURW9&T0SnEZ#5l${Q8F)(x zfRIOw3uVm9o@|#)bE1vq4aY1-JI+0{WB95ZCiO~Xpxq!_+~<{&rLlaXxu=-&fzSyN z9C_j(^uj(fPnJ2iZsx{MWfC{)DCCfZh~{q9Uo#wsP+WW8z0nku_DmD&{PKQBTNz|a z66i?|64`t?D+6gN<`=st6RV}6aYhJ6NY8W5SzVhD9%0v4yzbF`$&)k)0uxR`9T8kf zSqqRmK<kVPdCT`N>G3RqcTh|p>+bxrXR{Hih@v+xVWPa9LBGBZ%XkvF9bpsppBLMD zGwl*Hq5U*d1=6z4jw8%5Rt_SD%q4*)y49l)I%=oc0GQy7Rqk1O-DHUfJ}7>p{meRz zcXkn8@YoQ^y-aYd|ATcIo$xkU?3hDzz=_!jixwRZ2FEb(PX>OJD;8TZriI9vx{v^; zPwpS;nydWN<TQ-LT=PKQf0~#;M3;^w_NY(lZaiJeO>m<c-D-s!PNtAA1L7^pU|qJ# z7^k_Wz{rIknkgfrXU;1FBuy^F$8$t&ew9FAeX)juf&;8g#26f%@L7}_9W_cJbpjsm zK_Giq1iI`v=_qN>DC26d6*>^N8`5PWOPxb<gDG|_ayF?WeNz|H%&3{Ghi50mt;a<* z8S@0Su@}Eb>Bv!1DoxaC13~r+#XX)YFtjYZbHu7kg>}TsWylZy=#MbB%}t#07Aw2; za)PG1J|ob+&_Oa1XJOcu1`eatl-L}*;4mn+2C(v)kOVeS>Ia=X^y_RjL~+B&iBUHh zF{#7}$#OUm{;5?xY=Bx>&+3x_u{BQ0tA>B)PIwVTDKu^vPQ{R{zsxK+fv3rgwyD}d z$BcKh6|Ax;v?ve`iZiXqxv&Xv<XH|wWdwY#i+ANRLx$~_`)*6Cz7dln%&vzXb`0#w zT3h`_#^iuhff+-|u_2&<;fvsqX!Oc)R4ZPl<(pX!2iHlS@~A~fvGp@BfP$m|l+H8z z3hw$MN26{bN*7#`Y%gF6u$S9Ka5GWR1VOoi`cf+hH~FEy34%_JmTyiMVoPBwLbF%* zR0);I)R<E^DHrS`%mkaw0+cqKm`kxJX<lubt1xF!{w}6&_W=u7aMu<c<?_o;)U)d# zCIv%#^+F>_nAip(!k@t-5_s<gBQH`ZvvsdxWU+WEmsmJehmqhsD#TDRFnu?}z}nr= z`we&TwwtOYD`e4;SMo0EIK-IJYR*q#u_M(ZU4P6B`XT-Cy%9SxRR8@MAJjYQ8}*yQ zWIj>Z2<wLlDKiEeU6xB}8bL)+>H@J)QE^X#4q^8pmvwNOfc+$?lVgN&{x=&^(WuVl zF)>V)>N``6G<KX2EG5><n#v9mWsN$3lw)RcK1%`u<G9lb-SV_qjx(;{t`G}=SC$32 zlJpuogtW#%RU?p~vf=|Mp#@k^I&=*@hh8xo1cNS^X`lqU{a-wQWuW{X0?0xm4*=nS zhJvZsOyIEH5&6tQi-&cIC?-vp78$9A8XiJ0z>zC56L$&;3t=%i(T9rBcUSI7i@o>{ z(k@GVxqi&4UX;n@qIG-h`eq9%SA!fwo5$%^vXSBFbSCG$d2EiOXw1ce{d(w%#w@ez zw$|pm)sJX50zdwZ?lTv(SSC5b<o?u_jnbw1Q*T0^AFESGjd^94vO>f#k1@U(aawS; zSK5b}UT;Y+@0?dd)HQGHdSyo9K-Y0UiID;!i%ZTHNoyLO*XXNJFOYzg1uGUR>sO1_ zGJhf7R)>j#*00vw7~s9*SV%42jQXMDg4GGSMV^NV6lh^ipL@AakCHH#CPNQthO?G* z1>EmrqiS{phRg@H3hsh8u_Jy0RMcoehLB)5(W@1R<1yS6i?`W0UKTeY(YxC$!s6}b z@DmzuE_IajDlS_(g>C-q2F<xpYb4o~j&lyOW2$VK^QV_xry2FldmegfE8FhfTrf^c zWzw+u(Dw_#6&7k*8IFw+CE*gEBGHF8OBnIOVw45M*^MXBzeg<@;Fb54zwcftgX%oR zc&iRa?@fXW<ZoC^j>;Erygn{s;P5043Ok4U=q<)1bL@5$55FgcsVycsodpJ4fp`EZ z$tS@bEFD;u@)mEe6EO}-!cIMkBx8A~5FnY9l!4|8F&Z{$E+p-&gg*@d9vPl999{YW z(&v`28l7TN1&sa|gkR=3<-HA_ylUE7cqc5s>eNNEYw~l#5a$68ae%8v1g|zTK3hhS z;gI+H2gc)3vCV<QVcCYmVW=PJ+mPg!VL($e*-*I#wE|C%K1B*A;p_uwvJ3~7r2G%9 zCVTM?Ex{&>=zw~@L3x5_Hsa9~QoZup4E8P2(NWt8b?u_^mNdu}CkcH<gZn$5n=<)N z%ef??{EA&%ctp*Po7_C4@EAi*=0_w)7`S}gQnL4qWR{1x4Q#7&q9)o6W3k}&k2LQU z1#8gHb$?IC=yv%!jq$Eq*51C@9lE`E-)ZgpK^N?@T_LxAv(puNUbOu-0c*o>b!<zj z3QtX3DJmc#q(?&8?$t1Cd{CD}%@tS_)Yd_$1i1>~1Rh?sGb)oNN-3zNOgkZt$Cc&) zrwoR>t=u7eiGz8A0J7W={~=lsY_2mwr#g*r;ZSm_g$rR-b{l6+M>xHVvY|K)BBvTL zPV}l5u7V*pxtt0%5=u8=9#H*C8-4kv?uIOA(;y2q0=h;TEl*4qvc{3MFfAdj;~H9I z-oOU((<O($If7s)m-n|-+r3f_a@42v$wfL^&F~5-<$Qm)hkX0i0Gj3{vztxAj>G=u zuRH4>{JCmI^gPh*m1HRQt-GbadDZUyEFg0d7F{a{R}0<21<q?X<FS2ExPH^>|06^0 zZ6GOIx((Y**amO)Bc)KCHT96SuB(MExXRO@=95S%vYcphcHp>Kp~8n<-i(_a1hgU4 zJt8@bWc*)^&cSMBqEeP?e&qLPW$D~yo5GV3LWGfrN?59PJY|e%u3Eu9+p_A;T{!9% zlF>#+7(`?DGmL<3CW?hS;`;0#0JIF`GQ9npkLnz#kxTn^B<by<;^zfJsO!a0bH-$Z zeP8GOV!qbn$-tmYDldkr-@>hKs$mOzCWN2i9mhD1iko7#mZ3^=OYz-#O4r6yoB6F# z)F3?6yQQP*$s1>F6dnr&KDF<Hf(c{ve4#E)SrciYFSN0iB3M$#3zzZ7t{)!#;Cc=K z6m+`{XIu)&@WducXz6aVPe!MfT2dy*c>E{2`w2J$r{a{+-N~O)c+mGJkMqCu>>7}K zI+=sPLC%0mi@9Mp9&d_!u6MUzgw5OiVP7e(-{|*>>$5X~PW#4E+Iu<Ot_^CI(<5&J z#zE@py9{L!$d~zJc0IHoW`o*oh<gkrcm-9J3|UH5Yn&Q)T@+_YZphBt>bwkr<hpp< z9$NR~x0##DfNUzH!uwW}c;lQLhsgx!0~XNZg5AOpr?r9FmKBIv4@DQt-3NL&X=xV= z&L6OwhvzgpgsD!}xHiY|Vmt3_1u=Het(cBdgV@_aE{w@$NVda6K_uz`9;$Q=yv<O* z_JcKF?eVM+lChI5xLX0B>-9uW*YnTO0`MgJ7QI?J*%UuL9!TrzrSf@l<nlxJf|rlr zsr(lDu4C_V?S18tWlvb;fB4n!vv&!N{XnZawh?s-Bw^&hORDnfvO_O2y2Ef<cR~kv z7;8xD>T~6fl83s5KDZ+9;p!7{3w`IY_k8tzM2pT@20JqqP_`j_&0+6@Y%ZaHbnT0` zLZv7=Sq(C~8P34v{86&kOLUq3B-v-*%Z@Ei`4(gFFe#{LfQ&G)29e87AEkm)o;U92 zkRwJLdY<RmDsQ2SE8yGJCRu?_ZG}IE8Uw~GaqYEW>yx{H8bx`MCn883<;#}KVdP$2 zMbcjr$MUkspP0H*-_1hjGcBNdP7z}EzVH1AA47P_cn+AlDV6Oae?N8ksrLi<(BrL2 ze9St%Jf_GeKj&@u%YM1+Q{?jw-s5{N;Z=Dv-u%7Di6I@?(rie~an@9KN#_eH8Ap@W zTEnsH1W-vjhcX{hDo`6#lGmUNoGY8kE0nQ#Yzk@b!e#UUr4YV=qd>!fj)T#9Q-y|5 zvoe*$QX&qVo*}vMXhO)J7pESmtsPM!eK-7zaX}LIlaTb8lQ<f=2zb~wKKC;;=LY66 z>xieNx)TI!EtriZ1}25`v04;kbKmPuIO-`IQNTfxE*9npJ5&R$1g^Psp?J~KTRT@Q zMqdIf!W%2Pfex{6&)Z}*(NHyzB^P8`NE(UD_tJM#;`#XXOKfg1QJ-fTpj}O&6UlCs z3#sWOJ9^;z$<U>V>RT<Ds)ITu_1(goKZPDG0XXH%FzqdrJr!ZM@`?$e8s20#wm&Gu zOA^=+D+z3f4>-Vq4RBx=t)7f<U5t2VhM+S8ln7%Hpf4T{cVHr_k%XvMRcgT7xf5Zu zc);*+X8Z)x{EB!4G^->+;SE=~s`++UKlzCseC!ER>Q7@PxZxuLQHW)3ccu<>c3g4i zA8e@H>*bEyyD88;zrVK$KG_JCD=NlrD9{KTFbc9{H$LB-Gl5p^P&Dj@Wq)^Fq6JrX zdA)*&_krW+xNJ3rqkzqol5VFy@Ha9+1O!4hXl|F0aj7<tximV6vooO$0;nn^2(sYt zYcVNWl%`!1lYth5;R3*bnkC|-I4wtHfvNzwMX=^iU4X+=9kHR&Qhg+uRT%^p7>wLy zHpEt9TuUoS$g9S#`D=C~3sYO3h`vX#qN<F7TU^dzBn>JlBX~`~HHKBcFxIWHHoG`3 zJBYDObg(q>KtoKc-*=^EuXe2G8J0_}I>alcD&v%4bz0316ph>IiDw9kvalTmZ-tA> zO?q1t92g=IQDL!+@r8d+hqcU>XsqR0<U>(G7wqiD5b-qZdF@QXaBXttzvag1DW$%8 zG>~#V`VW$sw=nn!642NAdB48<dF3e5jXHo$nN|;RO=AbVM#1rg6e~9#gyd|f5DGzQ z;CA2u?v~o_HtChodm&$&?U>xp2q|D*>1y|DNht9onKnz}-;MD<!iDRm#lcRIK;Z-C zs!2J-z`a+TUN!@Z+Dxz5Hdg))L#le9l|HSG{PtQ9rDOq14dD$G&M-3KYD7uMJgY)~ z)x;E{&NWb!h9Wl$sANXj*3x%|ONg{-i@M^q)&Y7}lj+8!5E30r$RcmmSD(wCDQtfX zac!&WDO$J(s8r6Bu})`4e3L2FC80O-BDRaQ=h>}jPnpJP-RTKqAqUS4_=CD=q-S*_ zl&MH4tVwOPZPU-IZZ9YWqo6K$2Q1;z=Yr3Q*IS(Pf^??6Fk8;3XzmeC{4A$UOK!~? zg^4_Opcyny2_n(%R#~JQ5f@u)F*@#|X>OWD&PK%^KoZWnDuECnuHN>D9yloHPUU8x z@P%^`3>1Qf0p_@5XHv#cn_)Ho@?P}xANo+Q_j!KM2m5fZZ`S%n$h^Iqd<0D1faK?a zfBddQx6e0e^lG0(vJ~Dy)FavEK^qGuR8i!D>?X_IL$Nf1EEH-4Stt%75J85;?3jT& zGrd8{SXQ$Q4dq*Z!gh51kPl<V89_HA2{p@5XC|CkXvCp<RIn=&9xkyG9EHvfCJSqV z>j4u*q(u(XGm7$Z*Sf$~XL+J0Iy|&V`5K!{MajwTOyRNd%;nm!ea`->Fl_q>@t`nJ zjrL(e*+BCD&~a~?r}RF3pE~#punC#cJDPNyHxFf=m6iQ8CZ#DvsiiD*(1{CHNZtY? zEC2JL0aIXJmMQ`0nyA)_j|wY{)s~GaH6i>%h|wFX8Wp@gL!l8R8rv>!TS|D}*cI+U z)m5WQzeIS}v+6qnz%%~eE#bi*0wL*E#~ZS>cR`QFevp47gVQKt25tRz4jEC@u;tvN z>u$;IThr}!Bqm!GWls@2jmJ+Oa0*_C$KWlkx4;kh;hhcqa6-{n7=?^dzC$&2kr|a6 zeJWCFu$cmfZKc`{Sj}z|QO4?9ADvtg*O2N{b!5&XP9qF-?!-P(n@f<q*ay$@6TYr} zLRSB$m2Q(y57P>8a(RP3Xf;~<yhtOM<Y5@!H#DX|yddbBz~o8par6dwqLb{8uFoea z^nB}@)S_16mkCVgtCLtM$^%)UX!}Pqf$asamT}dMLdfk%kUrS?<Fb{mG(+hM5l_B& zksDX*WuOw12_1(R!^zRtH7DnO<}1yF;X7j_#<3;VF*$Es_}%!<>k>L*FxQXBiLVoC z((79n-|K>&LI|Dj>N7d@rJT^Jh~j%pXGyaskDuZJJQPMg#g4wn{9QQ87jv3Gh^wI) zJAm<>4cR5OLi2(af;p$w@8MW7i|iU~GuE%dm0#`E@Rx_Gdr7v!(;(zcttsZO9_O@j z(6A`H@I!FuEZsp%5oUF28ScJsee>B{uYK9Y%WQuNx)@yVuSGu@()~TZ>`3k>j|SWQ zwqfDT{_LHe;NsM$^2G%pF-r?h*OzOof&SZb=!)k*Wf(y6WrIykyAhZ;4$vVlp_JmF zA8@XnrK)>Cy*KUKUI2qfnG<eUtZFY8q*C@Mn$06#vfF5J;+0zp!5WkqjkBnb<LTvj z-XpnnuM-JF)6wZ88DooyU^v(_)$WZl8>)wjReX)uWa1mH-gKE{oAQJ)WzGmek$P|q zo!u=K(gG*t;TIIqr@9i>OWGrRdwqt4YWuO5!C?NTy)m%RNQsop`}?juG#`3jdo<99 z5E~JD@5YPW*K6CoWwT4bW`dwSSXG;*O&6Cf`q~A(EEu`u((ls(zB3BZoz#|dE^fms zQ%F%nvbY}ddP%4G+?z5iRHN<e;P0AuYJX1X+{L6nV$mM~OTIrQj?_0sc;boqZp(bR zSGiZ7+~|(fslei3!xzPyx*VH%dN?QcyH}``R(_5WncZ?u3!LY!Q-o3i?xtW1WPlZr znwMPWp@NU;3YFJN@uU!cevgJ_0g+OF;xxK8RHU>79HM%eGC48-wo@_IM)(GfsPJVW z?yRP$U%T9FTS3S_TjZx2v{|C$;~X5MR|taMh;WrlMEV+t=f8Tc$6CmGYI`N0Ux-5Y zc^YM(3Xg!xmSF+*0>Cv+iv8ze0bYEYpvr}I(8_2;E~|S=dxclp3n>w*V4qaBwsvji zWznQ1$pL9lNRP-pc@5OrWL<QwwPB3ebF>Err}oO34u^%SaPQ42RxpI9{@M0iYwC!x zRd!*q;#IB36n-*P7D<U%2(yAQ$DrUQT<%E5y5=%btpkZ@Vox(cV5Cgx+v8iYRHg8> zP)1HOq`SpIMDZf<quLIXVI>?ud@ogaFO)n5asp7TGf$jq3r?FjGeZ^-I_F#SqN-`( z9RH7hID7C<oF{hn!m^GjYk_7uXd?<j@Y)@n$ZgF^*0}KZ=k~B?z?N@MmCiPv(ke;1 zx5({_I%Nqdp~;Eki$FwK2qm+5VRrytx_}mxh!Zso)x1R(e1FMu2We~n<mXDcpeZT7 zsNd3Q`5#{#FSfZa1cKetpCnu~0-o2-@n)7dgKbI(VnnwRWa#%MFyt8k-u?N@V<1B& zl7|&nqfS;cNxwm3Cd^o(*|JCX-sdmhOr&<v9~ZK+J95}WN679TtZ%ofo@mK@S8WU! z%N2o|!w|M>u2PaJ!~=;$8CgFMmGUcsc6O_ce^T``P+?|120k47TUEu#v!C3%mLWB+ zhY%J_x3Q;ul{!-m1B+&}cEY4ty_V1#w5&FI!jPGKs}@u9AD%E^HlmGdxk?iQ?fS}& z&a3Dln@`kM4QadD2ensE+F|*N3A$%}40y}HcQc-ji~Niwa%}Mj&=D^GT^_T*3|QE| zVJHTCj0A#o1o(L}s~c|yJC#d~pNBuq|GtJMCO~h&(K*3Y`Mj;pv@Ap&Tqs4l70!)B z=~g-8L3FVDb?f$q+OR=k(;oAKw5h^g%d8CQ@Q!WvwGNYF^2@{uGDt$OZtGrns|=1$ z%q}2k@1K_jC~nu8V_(Jdj>YtssXEP1?I1|k*W1SJnx!uH_8BOO6HWm}g`M;#62TiV z+<c$f&4Wx!W)!|0#6_t!bIho5>mKS3(gc6_Z7xVcN>;QaG97tU>~uk9vwn?qL-(P( zch&B~);9o^@{V}%Y^$DF!Bm-rIE^-yE|FTOS!>Um<RGq1Jl_NYAMpb-w_hv0(0l0Z zJ+-%}q*6wFnKU$64H9F;X?}HNU{PgKkrSdDlIyELJ<cLuxh$KDxzM6trW51!)0omz z<$(4&j9Q@41LPhmQ=!w8UzRGN$ty|Ajzy{yW&AQLx@$g#zOB{vUgrBbzk(ohanv4l z`pS>%VA9$@#%b-Y>I3Rc<Kd+t>#wU6MlPW5kV#BeMD^pGTpAB1;e8>HiWm_1q`rD= zy{2JYlqsDPq(O7o$X=U{J6DOubr4bT<=sIY8LKCMDkuw?S|jOer>>*IVJ{!A4KzK% zqme|6lzFF59^EfIgN9BcQ)crAdqQ#H4@baXda9Jc_^wH%rI!XD)*xXy4>KM7d{ge6 zaH4kk#wLBK#5viCBSpdA{amK6JPCE;+>2YX`hG@FZ(m64%?+ZQQTLA#a^uj7cK;+y z6rK_hD}6u1PlqwR6S_+-57d6FAPUzb%x$c;Q&%kEShRb098`o)cTTP-6G94B2M~J` zvE13KUF4%mJITGA=uX`u*ywYo7lEBcU^wZhx+IQ4=CsJn>NEM-%xr>l4=BmKdO6W9 zqQv&P$?Vnlr(HZLQz1b;5o5KHdl)xNtfzTb8C~0u7H|%uX@Mp%Q5?m(lcx=I4%@ID zi#%)?&N^vkW&FVSD&UEPy{C`}f2|X@e^GuldL4a^^~ll#K4P+^oFp>fX~WgN`N_y~ z4qYT>opK@fT*~x<!-f1)8`pezTH%)H+=H1F0ihZJRDU!$E7^gFy0h81_n1K|IuRw# zz~dYkwQ!vd?^&~az0PZQc3oGxi~Rbq-|)?Pv?w}5z^G1Hhl}~P$#~7`A9HX*kbAmK zGUc7a#O^}t{gjjgQnx~CK~!KnU|V=HEm7loncgsq<0u9Q<%E+wAR^(u^2+V0Y7Jq* zi{tR^b`gGoZeu$loZz5r%uck)E=Eu$V4?!QYi|JpanC|K<Z$cBQrJ8W=N{uX+0W<C zh;e1}{>gEcFY@2KSYn@VUB)|~c-slyd!<o(h3G`gKIe)n8lN`X4$33wY@OEl_-T!< zCwGp3Xg;isFI5pkZ=l118fOt?Oak#pHK{0sJtz_GD>>DdcH?KIYxVlV`jhlUIJ)1O zXzf7L``3hI{}IugrH*X^ja9H&1Pnq_6tc%(D`k>vtDz{*fU<g1gWSiz&Rs4M7YpaK z>JD8tvq~i!8&;jd%|#W9x|E|OAx<lhV{}b(bzfA^OWZ&HDR}CTz-pzXwOt0~Y^am` z1VkG1rkH!7{*;IAIg;p;<3#1!jG{CQku&o`0mEj{6I@tcR`Mn#+o`-LAS*oBj4z!w zu%A3a?>O5ko~2%xrf{cI-;QKO?TF+-U0UJEV}Q_DB^a=K0`|(CA_9DHXH(D|29e!~ z^J2gz(7!IJu`!C^J|=LS2a~o(TdwFjWDWERNGc(NEA^1AmQLF>Jn#B9P17S91R-}! z7EEh$S#nMmGs7Y(Y%(~qwP-MjG}aU@%*1E`4|0vU1k)?CGSIF~MLhGb#z}D6GFBYy zEieTTGnJ?uRJWC`T>)j@H!c~i(IghRYSm4lOYRLn=gMdHpD4NT)k`@RUk+Lwp40!j zl)Qhwi?aGb9H(~dQ&1}iKX>OcFLaZ#bIp%!A`IuDyUnV=R4*{RL5DC+EiCC2foq*u z<Z=(^((iutprlVTMc;(yht7c_k*%_g=W2=15GRWU%c<Z%l|s<D73)Q=GESH$?<YD` z{?nuk@@`I>inRDEEr5X;is}@Vb$GPLf|}||*x<StfMMdsg)1}J#MGTVBBpSzXW&|= z6$<*qNBp}&8&KH(b49z@+~}HSu8I9&E3l$T=eVs^?(Xqrc8pWC?#x-g+gW05w#%cj zF6#c`ZpVITF|?AzSYl2_5SUO4*Al>ievRn;kugr4y!4>dc_J6t^A-2I--1-DQ=krh zlBQ{~Y6gxrjjboe{2lbWx+!W>i7<x5$ylZ$f=vZ)fo<w(>cizo$!oi^>yY2ch+|!D z`;7Ezn?@e(t{{)3_Zq1)B7;9bL?+nR*bFZLZm#Ie8kAvJiAyh^sZ@9xa#uER(O?_c zf=ry!udYgB(Uf|q#NSvpFCp5E#SwZ{t=AB`|7thB^jZe8b6*hR<7A4rpK~w7GzDA5 z0u~x(6*yFjG+&dF6i;2OwQkQ>sa^09Mr@Qt@Rq4+(?SPBT#i(or4bIjkY&>u8+HdS zGo_qlP8RpyqFySrs19>dr(WrlHYKkFYYeh=kVAtO;!q{Z=DU7X__|E0APuT))H=z? zqopBwIm!+;vkBn>{>t5W_wCBdyp3q9XArh1WJsaa3A>)7r@nJdSx|x`SjZB?!O0DW zIXp9?kGO(XV_>o8D`er0(NK?VP0Tj$V?2GH+_R{I(Ogt?kV#1PC#@5QtPJE%t~II0 zLn=kdhJkN;>c+2PUC5*!ff*V=e1gwPn2{^v?QF>8uO8R8J!dCW(GfQEMTIw3+w=zD zUO8eRU`n5}^`@pGAtkhiwyJ|4w5D>X*&U9$5tnl*Q70iOU^6_xc7QbtNuA=N&|js~ zQ!$VziKCfN<chT!)TFe+T~2hzPDV6e!Pm%cWMOW+`Odr9LPt&P+p4tU&ATl5b}E&1 zE{XmuXC`!g;G3(a)@+UIaEsSC#BADmR=xtG*}tLaA@dD5u}_YANE$7A;;4-TV%Pbm z=$&X%Xwd9zwI%gv>7BZ?_-PJ-*u)x8Dgs@R9|a90?k`UuxDG!;r0ybr=P`SjgybRF z6AMI^KJC~YQ+VP^=uNt~JRm3<KD7;}NeuhWwh>$d0jL>de&X0I@8E@b)0!RHI`xAe z^{4xbW1_gNMFy4TkHBXkhPqNF`Sbkr(P31Kei`{)gM+d3hvgvO!~bmO$Tt5?lbZY2 zE{c>Nw<2=A0_-5Zp1H2wNpl$>oh)Yn7RqYLvR1as<mzac)O#vvhxS9;O@Tgcmi8)$ zL$qT&N1Dbo4DtvwALI!$LS9G<yyoUnw);ux4yyiFplr?P^e<@j0pkQc8)Rk}N5*+V z%3SlP$d<3EO(%55n>%GV#`1%RXdk30A7eBKdtx`?gi4#1FdA?{L5HV~H7tbZ9#otB zTgf#`vD*TT9k9(ce)Dr}mZcoLOIL(LzoM&ssp(~;);u<?%tTUBdwk_2Y8iP3B3Ac= z&Rb?eFrcm`*EjSR#<Qxza?c~J<)FyLvtKSZqC3k4i5f%zvyL2v`J|s|WiGwm0*b@T z2CNd}*e(YmybU2W?9Ev1E3vs%xT-+$SAT!37$+175FiMq^MHH}fgQ<eb|bceuao3! zBBE2!q?`oAJB~?ffI-a2AOJ>!#g@pgNj=sKaT@lM5LYC28O6>&X6juinIGY7udsGW z|B>TM9w}(YKdh5^72!Y?9l&Z(*kaK@V~4Iy^_&NsEVGetV0cw&J6;&mXd5xP9&Ad; z;KQ1Y3z?YILEZq#^ybXuHMIOMWI~igH{MvW6yc0vkf4hWS>NG#Gm?m4qKr*4Wl(Fa zaH5jzam8J}2(o@K5f(udl4<0^=6Gr}`&i0r<chH|f76k2++Dk;o|hb<cPq&af=DWM zK0RO(MR9kj|H>~gu3}SQJ+Zm1eN1Aw+|#%N-%@1NuVD$W{1b;%8e@*D{Cyb@Il~oB zgc0!{qM$yM%w4J!bBrhmWLYN(_&LXeTQ~+pNvL2uyHdvj+=cD?=QfR;LD~ZBG1iV+ zlvw+8q{mpM!l}Y?l0luL@UNp*Y7PQR*+uZ!WGlSdc>$CR9qgrGxv?I%G8w7kqnZ{^ za)aa^VZ&Wv_OWqkkhZF7vLnqMSRLVXkP4+EK46(lrQ*{K5!Q<i^HRWAUEz=i<Ea6r z2gSJylofyPHto1cU`;!wi{P<wVZd|);&#SIYq8kT@OnJTWF(Gz1_J<JIv63$X@wyV z#?kj@+Ef&)G&5Jfweqlq>nILbhF%{Yin<9~V)G0;9e5|cR>5ANB!{hJ(ych$p-ULj z{AuTo$0>ukX3cG}#c_0TK8yof?pR^C^s9yR)_qPGr@-t>Io_KKX06S5-gu++-RFim znHDF#^_j75pBdZZPu5jHDCwA{8wloXaFa4789)~gEKF-{uIiE{E(i1OaLcd%I`G!? zR{&d3i}mZ>HbwdD_3ha;oPLBvq5bnHljX;&IbW)q{XJd7cvuUhSD-AKp1Op=jh<I4 zIQjj3jAKT-;Vnz?i&pp4ZWB_qqi;^jQ9#)~?s(I|9I?nvO*ji8XgO07&1n6V!?Ch- zdZ>Z_`SAaUp#4_v`+UcyRHThsBsEDzCT%$sGE2>g%C5{{%YHN1uHV@5N<6TQ0AJQW z^nyfJ^G^?p&}+3Os!R(M!?8vNkiNGn3}UqCFqZ>CYK5RVH<ObGib-}O@>^+OHLlMe z5htt~zKWCApEUdVzo35M=wHa!e^Ysl`KI2ai}(3!*(V=?INJIo-nZ0dQma=t{YPb@ z@W%K!Y_d!U*QB`taH>phiz}gH5ZUVV&?OAZ(bHR7%Ughz`lDs+;2s&qMC(Cml@0s& zP%$Wz<DPe&R0S5*tDNM)B;P?hElj7GR193E<giKy90n_TGaoK*0YoWFj1I??+S;Mi zF@X)wSj<KpAo3hd9#N=_Rlmy~(pS&wnNDw|_q~dMEP!@wf+zNP;NI~-&J~tbe0{=x zshWH^zjaH0>?1}BJ?F~}WuC#kKF4j686%!47I@NneT-+r;gUzkCpLX7;o=$*N-i=P z%FuC)h35Jnl^38s2fRg$fu%AJ%#e=9$3ybYrCz@Fxfqjtae5yX^<`ZZuu_ly!TX}P ze$iVB@6FA-`4LUNb#r<tn7xJ@H)GFV_k*jx>)IpO8h+DWbG5a<pz(mqt4NY(WKJk7 zQ{h-)E1j2wT4G8U0mGG5CV$9y9v>}=$PI8~3Y&i|9plod1r?HMQxfWl8L7=CG8aXB zFpU)pYExCcRmmoxqU$J52aqmXIk60#@$k6U)Or9aM>fTvZKx1JIxFHe`=d_z!W1q$ zfhv;m>3Cc*vtm`0C&#;0+QCHmX8e?Q?qQt$^)~<(E}6qm=$6xmG#WYilD7lvdneo? z4Q-79#@qN1S>LKyIJ2oymhqe<-z-Yx`rPm69ywxfv4x+!U?}o6hyX5IkVxBj{)Dnh zWMt_cm2?u|O(;!~(~m4|e_VB-?}oK>^nP<J%8B5o7155nqFrF~0i9d9g`BgM31J&f zvBF-7!rl?9WW>k>@bI|jYlHT-Dh|O+Ru7tE7>fFl-L`jj-Vz3#w?h~OAS-9mJR~Q{ z*vnQ-<>TdB00s7E25`Y6P4D(^7eW00sj!<~3k9NAnT5Zn#ba&Dhpa3Jggznv4cX*} zv<3mS(`GVD$2OMv)Ef5kpRsfHaF`RjVP7)vCH|h`06#jNkrCE{&}Fi8+LK<Fj;h)% z2#tRU{S7BVMw`7>Gw{=+4#>&GU(<qW9q^LB-k4fCW@@lGP(oTj4U_~W6qJ)qzY_XA zf~f`@e^7!cBSKW~+W@a2;2{_xa1s}5x0_5!nm;-a4moy<&1TZ_28(*<yee?Bx#>)$ zl4zq9Bhkjq2z16K<*8BVWq2;c#1f)(-%?4T82~$0I^a$8c6bh#lCuRy2uNmK!f9~! z!&^;{l4&n^bH%@omJzQJJ3<(fsJ;-41qd9Ro2aPW)|>Dg_DQdSiNYsjk!_7x3V-kM z155BNRcKX~I4Rx&-b+Re;h}eMSMZ|5MG0<#uKW0H#Y4E+)<w$XMzDOgOO|+-$V(_6 zbE<X=GY`(8S~6d1<9eTQJgBoOgEv3<y_R1ksW3h`DJWS&Hk>x564E<dt2L;5_cB!C z+B8h<TZY0AtevS~v_qNCUJbPUQMe!cD?N{KYQe@(LM)+_5K8C<dGAY^N3l%B-WA)J zcBYN#srLAi6(`K>pkLp6VHF)j;;>#IbM~1&fN(|cOqZ%mClz~SMwZbApi)!pmga%a zM8adrf@!l&bHL8|Z@I@X9}AxpvX17UcaHh@TGG^w_^GSYz_5AA?6<q11#Vk)#N(_o z<Y_QTW<TS2@;?D;TNc|k51cuUYCO-<b-!B?04S(R#gm`zZ)fh`Jol^H8JD~Fw+{gs zk`h0)<lFWB-U33^Bu+1+qHR2hKOQ=F$-|5+?%BMST|DW;y(MlT)GKXjH#pb!N`FaY zZX;T7(r7MHg<SXy_~pLXK3L4#t$ob`cd`LRgXAJbS$K=2{?Qo2+f$)G8;$KtB?Vua zOd*wUg**XYKv;GY+9T}nWkH{ri=q9QN~R@4rGc@qJQ}Os*o<mMH<I{@aNEAbPctvk ziqy79s0NoQrDzJy(#bp@WfOIlOrz!&LQ8=_kNGktHKX2~X^$vO$5ZY#c~p(5cF+0X z2PDN(#J~hc^iIS@x{R?TM)_Ka253X;YubnGOIw~J1hWgtvmjEsFPT<~G^^&GmkT+K z=)rE?4_t8MM5o-;I+TTzhs72Tbz^t_AIm0)dVcMR-R8A+ckBFmLbp9ik@}W*-Yc(5 zIaDB|2eXb!U@C0`H{!V=o_Tb_%%qDL`kpb0RD^9tGp6#Yzf#<-^*9d?w^INKv&f%g zrBJ_A%11weuR>}0$qf8<$&VEfPjOjghqd+q0XZO7m;tRQfXQ>NpeV6e?B|+pm6<I2 z*On`2xtpCV5X4qQa<U}%9&^N#Do}Z+8V*FkyJW?G;I-^Kqb+G~3r@{wpVkhxe&1TU z7wTu{y?xTfgJBTJO*+XU1MX;f89<=n?~(p-W4QE38es1y5ZJgrfoMZZN4E;3&l`Db zsN2Ty2qIWQ`v1ap5uxk{oc^C3GO~R)B(%%R(XIDZ;K?xFdcodxzq<yc5Ck<C5AB&y zh0GCZ;(~0Bp}L`iN+Cs{%4FndjCFP}=Ti1Y!nwy$WJ#G7?-vD?NC~N*Sr=&1z@FGs z^oqhqj;vT(Poo_p3|nO0f(pW#x#hWlG-`vi`LMW{0U={48Xwa@<<cZ*sqd%rmm(@# ziRMHsk6t{$Wt5>Y^;+}r$iU6wk5~i}zoqOBr??G0GW}r8GcwWxWHT-AYiH0+W~tk} zo*TAQNf~RECW)g<+dk>4<DeCsdpUD*tvpM}i0-*VsoN5C^!fORP9c*t-tkrn!YH z-A6o9Q!iUY!u@JAX$YW&Xc}3k`L@V-Yu@?4zNvo6zkmlHAZI@DOT5|pzVg2M`Jta* z3+mekG+lzL|04r1cKu`lFjf1hTp*_?%M7?38*e;eLtkP#R*&aB#goLtfeBvg&yp_w zaUDAy^Tp~6O0%~ZVl<spu_GdN=xtfUbx|}z;VU?y1v0@8E6@modWCar?bM<nQ-iHT z_^f$A{pHskakcm>N<>UVhC)10t{URQod(MAisCFYa2BPN-T$y4ONj9hSEx^K<3e=M z(vJy>6lyV-R$<^I7;^>wS>|E3V^tL3&cSZ1#Q9D_@54h+WwpE_f#M(xixlS!DA*-& zIFil@-`QzLC&9`S!3z_Iv#2{6krCsu(})16wZJ*}ZFsyUu`t~JgZ7Zy5wh~dl5^@8 zh&SS8d4=<0sf$V^4WNEb{MjS(i`^#LtA;p@>@Fm@o3A>H^v>j5TS8gu94VvZq6sxk zG{1M04;9&;XcP%<mmyN8_AD_~gtig}^e9<z1N$3AHrK@koX>Rgwo4NjbEK#y8X@0a za>brY0etw;mNZ<F66ZayX18yN&a0^P{P#9doP#Zy*Ic9`NhWd1GqAd&i)nK&#R(+8 zH)&^!uGBRjP0b_E-EVsSYni9!gxQQR&##~n(zQGL=>M10UCrF#HPmE$s3{kZ@g0%& zoD`F36oJ@Ord4BN*rR8N2m)>10>wu(4jnw~`t%NqMDEG*2Y0F7=b{(QLYga9EF=#d zW;RpCl3Z*p_HIf{A>W0ns>`jOjIHS}1@o0t8>%P`!nvcgaDrFCgK5a@-dWVtcp7|~ z<zdLYUkS8-ql9m#aLHZmo=EVN#g=>@iiU;_SFNOa<!Ag%c~a!k1}j)86hx0Ii#^Jb zR}`!mEb|;Hqox)QVydJ5U|MLKKjJDXf=sBWNoZ8%we=Lo|K5$j9UYS1EkR=XuL}MW z$kY_KMU1+1xkdBW5fdnsUBTbi(CCgY9Vchq{vTY^9T(sMtrs=;A}Dc4h)@B;w@F10 zav}1|W=<_Jg2qrGaBWnWv1vMAm}jO>3jdjN9z$0u^g_gtu<_o>wppZtCnbc+=9XRB zcohj#biWCu!S*L0+%wxbG{mI7%OfMt#mB=w&X(gzEWcvfnv<uV=B1A6b9U-_sMbm2 z(?zp9tI6krrRi+lBGgD$xG|{FgD>EAspw0^_lnXITVk6x4kK4SN)A$0Z0#Fq07{r} zLB$sq-2fuM&w)2kC~&Ez90cVEO9f(Ny|0WdSGojw4lWX(oh&Ih(&m}cIg1LWOA1b^ zNMe~fqI>P;DOmjnNW1S;jJ@6{u+3%i=SY?<x#yT#QA6=f_T}>xx;AplP2x2+3*uq* zkQWl7${B6(`N{1uogdo!KsbcjVL2E(OXxRzo!LmzokR+sRgx-1pJGv0+bpENJCtjl z-#TQ9;I|3^?$Pk~B<UZR=bS3QT|99LIz^jsXkhcOf;16AJ`oO(@+o9L|9e+bbhzBI z3oW`RN;}g9iNdGd!AJV%nQg6$=h_=0+(3s&FpdzSx1qjj-~*mb;`!yk-)Jy^YA_Yb zv}Cm6cz&8~sB1wghXX~hQ5@XteM}yo2DeM_Q&rCqt#@$iF!O9?1O&{G2hDnGooRC# zy#_6g9zryzVH1JEPNagmXRQ-R$TK9}_Ge-(Yb%TubBrR!RLDn)<A4h_j^D=OEv>%{ zS5ErX_LCPVMv0h)>Fw`H?_fqoHTwu?@zNz7W=Y{((wr4mH%LDa!{{vDU#_JhLF(%p z<S1ImTtHk&JOR8R^w46G(~ZNzCHSkQ)hcWWhSFks9EX2aOD(o#<`|j0sqABQzelaf z$_R3hh7gZ9fQ1AS`3O>+t5%Y?=JLtKG?A=@eN!n<drPQgKD;Kbz`w-t1ZjDW02eO! z)U_N3)=~i2XApHqgYVE>33Tdzr_0)WFmSLlonrRRBN8k`hAC)1;v)vPhzXlABxu=P z!wU!6p~H+t875AFB3bRpg56Xf+$auyhQy)gvQP2$!-g0y<2+zT67hRZJZME2Xt`M5 z<P&;gqgo5~GL+C_`-L_Z6TrgZSX&CS8z?xEo>fNk5sV9!YD!&@+SgwDId{)V|8M@< zEKx7;SwXNCLn9nmvUzBEcTUKWQU)w1Pn4iGisd!uL{xC@7YlT~$q2wsqNSs-uR-w^ z^QIxO!1-C}9JD?h_08hM1F*0s6^0u|Caf&j$;1<E9oRTTeKbNy``(~mpocAmd@xQQ zqevTSJJ&`S12_%Zm<Z6t7ywCS<DpAP4FS~U7*M0#W{^tPh7WYQ{iS9bOYA3NYXUKV zhKm6D8Ut`5kk|tU>OJ(sAtFlUhaC5p()4ChoWy&2|B7J!W8dq^>Sa%Z5@0VH;bX2K zaQ^~x0V6HrbrPBZAGEKb4&I)iRn42(wBaz9VD;IT7vL?}7)7Tc#R9D=)C+y6a|pn4 z;Gfuso1wsg9o1Wd92MV6r`nRym@|nz8G0%U?vp^)U_*uXDWW+1jil3PS@TG&XJYS? z&^IxIYca=(r<iN>o8Uu3CU2z;wg=h)za_Luv?*FZyI;t~+Rk<A|IZZpQ!_3>_9?T_ zEaX$Q|K1}RwdY`|;ghI+LO!~7fi+}b!oXYH(aS;$P+y!vKZF$)A+#miZ{QqtH!<b| z?b~+tr2yD<;2F6L!?6AV?S4yIjptS9@YN!*NG(60>Xj-k0FU4mSv;r@=ftX}GPLR| zSKF2Fkc$e5TFE`<qC!kV;|NQzZ?t5V-nsyPb#y<5k3)<}oFE;TcQF^jV>IDN3SPbO z{;%<I0(P_hkGKo)txnDimPg64FXzOV#hmIh02&awy6y>*_biW{N}$sEDuwk%BTeO| zSc8^El>Pj|@vbj8V4B7r=59tqW#80-4X@x12Ifwjd_9X*8(p~oXHA}>u1Q>iugk7W z>kxJ`pk3nBHGr?MO8P(P+6Y-&^bZ&Rz{b{2`nrlkjrreytUUzOVs7WN7}$7W;X%^_ z?pT_;Eyc0ESb==Bks*=-ASKob*kZk`^|^GneQ%H&gJ1*~h)igAt<CSOKiXh(zZ6>a zBze6y2<ShRgo=S(-+CMXnuNn3==<%@1tU5k0Na31AY_FU2<Ilqf$fQ0dlJq~*2Vwa z6jjR4O*N<U+;mw1=VmGj@wr)Af;>0dz9@g)9NSV#fd@|kyg6~;=mjJ}C<4owNGd$0 z9JsP`Kd;7}4Zc8*D@Kv@HYlIu<Js|H$D1!Zw)p7rV0}rwfXsRhUUFr{n^8&N!wJe= z&fp6a;O0DTp;Nd*H{KBA^GHs9$_mm81XgUJ+)4r$NOZH;)5(`4uqm4vHwqkWF?@D; zCsu8e9JCIa0aF^B*zA?N_Ot-$<u?c`?>3a9b%7jDST;#Qd5Wh6JHXi4FL*-ZUk3fI z&Bv;a!RHL`U5Y<e@9li>)1XFy5-s}e78Wn?zg$R9-S#Ww7`*K!<%s}_AcB2V1QS0l zKE}B}5$9P3IW*`TH&$1LZnbsil-&5LJcemOccq^3cPuO;Z8eem7S<QSqx*gf+sbhE z32R~hy)~2wTR0A9q}LBDoIRNrrFSh{o1-l+iVNKDCfh|UJb#HXQN#SQjyYbZ4Kn#^ so|FZOL_`>ueWbQUX;hH-4ZKF+R!&L#uag3$c{YeYu$z|;;0*u(0Od$=V*mgE diff --git a/public/fonts/roboto-8fca32cc805ea3e480e6458ae7c3640d41f6c96b.ttf b/public/fonts/roboto-8fca32cc805ea3e480e6458ae7c3640d41f6c96b.ttf deleted file mode 100644 index 74d598d36fd0b5ab8311c2c0ec9ecfd6516df58f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105148 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 diff --git a/public/fonts/roboto-922ef2c34858a412764dfd5efadf3e387c8d7402.woff b/public/fonts/roboto-922ef2c34858a412764dfd5efadf3e387c8d7402.woff deleted file mode 100644 index 562fe18a08ff8a04d793c8a5863e80fb20bc978a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82860 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 diff --git a/public/fonts/roboto-9e2b4436ba4c5c9b33f4fca42b43d99a703467f0.woff b/public/fonts/roboto-9e2b4436ba4c5c9b33f4fca42b43d99a703467f0.woff deleted file mode 100644 index 2e069a916b0daab939d520689774205ca8e39679..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82560 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 b4IrXGgt2rJzYI_;Uxu+10O=YsZvX%QOejX{ diff --git a/public/fonts/roboto-b376a31e25af67e36a420aa2348874c5a8b5c9a5.ttf b/public/fonts/roboto-b376a31e25af67e36a420aa2348874c5a8b5c9a5.ttf deleted file mode 100644 index 5bea9f0e79e5791e316210067b30361f006950fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104680 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�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 diff --git a/public/fonts/roboto-c8755b34719e3012d4ae9455615b1549fec1ca3f.eot b/public/fonts/roboto-c8755b34719e3012d4ae9455615b1549fec1ca3f.eot deleted file mode 100644 index 5598f9ef4067950fd378f058fe1924813a8e10ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73045 zcmZ6x1xy@F)Hb@iEbi`Zi@WQ>0=u|-ahKv&pe*hbcXuc)QnWyEEp9~$ELJEKO0iO) z^uFJJznlEIb7Y<)Ig?B#nas%;(E|a=bU*;;KLP^)|LOm400HU1|G}EN|8M}P2xfpT z^Z$m*fB>fdfhT6%G5_oOza~6@KEMlL_n-LxCjbD!f3_pQ84v*Q0N4V2|MTzyjQ{ia z0{j53|7E=Vub41^A0YT23H?X^qh<b&?|+c!fBFCaiU5F;ftv3BwdDVSXuudOz*it( zX93U-CY$}9GG)K%jN>ZRFViQRMN*<qBT&sDY6zEv*Z~}-ROfNl7L}M+VNzN2jb!4b zN3x#&<WMVD#Al&tt`=6z45>$_hC1aG&(c0U8YjG!{P}nk$>Vmx_evh~^Dd(6qT4iq z!sB27XQp$PcAF9(##?7MA!0WP98RgWkn=aRqgA`=ZPy;N?7M$Qq~-}`T63vx<OFl* z$G#pqf9ZfcbZTEZpKAr2>!C%R496AsWH#qCC}`F!Cv22;b`v;%D_I`Y8aRHh_^(>+ zT3tEI#|bJnhP@ITDe1I8DM_Y03+F0Bz>y^KaP8Mc`6Hk4qr`7MBQzZkYxpyjvL^Rn z)w-4bJ}_+N>ZvXj>>f;SN<T6}Trz?onoIeU@8#e3kvA+b+cq4und}=z-SC>*{ltq2 zM$IdWe*M2JSV?2CsrPw6hw9nP^bIB_E-r$=w4)@JP_*iBjBe(7{7Z#M6&h0(GMfam zC@BuCZ&WOF$TOO#vJ4g*7lOfsmm(OcN%-hC@e)eqOR@p@KS7ICZ_919=>M+Uc@9C} z{TdJrPZ{ddrJ<doy>?Gub4KVz#t?YZj^{>?5*ng0XO_(o*GB(d@DPQsE=SynVRJV~ z#k%$yDYhbA?i&-t3=?epqm5uP$_sEKsxzU`N9PmDzttKM3rxc~pt!X1RQnUU`t_f? z{~}Yxe+{-)SK_e-vzzt-saW)OJcjp){x|@96GsEq<_dyclWzNRoG*L^2Mj_Ne730q zr*u;#+E4^@e{$l9Dwv@?L#7j4FDn1!WMgSY-qoMUmWW@UlrNp7jifI3<UX&v8;BqG zUD1a+M&<yE$z42SUy&sgf-=!khH3jC_52A<DrV>{;&o%>t-L}m*;<+G3#L~n?aJ4H zH<DXwdC;~U&zR349r(7d#|VPHg}<*2f@fH&Q1Gf?yhMHGyBj3NSTF$JTY`uhR;0Za zrAJ2nHT3+b3wWPhN@blsFsz@<)V}(?W8Nkfv=R<CM2~Li>b$pd$8Dy$YL<RBNvfte zHFEDz&da<ufnZds3nFoZtJKBwkEl3ptx4NUIxrf=v8>Lvn_ow|>0>fE^3l~}4axB= zH>hIivF+7;2j;jJ3}u$T>R^f|5mb4_lmR9x&6I`ML<>rw8}12SlM6<?j7Tib6rO(> zYVJ97Zk3o>Q{Z@>^-hGkEb8rw&J&<JbUa@=QmkHzsTutux6plkcSV*qzOIuI()fAF zRcgY$G)Y(Zqk6o$Sc~Sz{k)=m8x%Ndy{g8mH}qhTcg4#_#(s(vEA$X^uy+GJ)T}S) zM<y;W=O~ksD8B>Sa#XJkqt-Q`<9O7-UAxU3#-1&s>8BR8Lrj%O94`=@SErirDV2 z8|b_M-e38!OeJRorfbr85kE0edeMAJLaT|_(aUk?+x;rNy-s?`M&%b?+{S!4p+9!8 z%I8{M;6F)sg@Z-)mpx^LgS4j;R-15;^_Gm87mx|5`k{b>8P`oH>x^eNjAaxIWc(q@ z113&hH~Y<OW68@_;VF8j=WW|r-ci4ccM`Q-p4j<g{8MoX=E!~|G$B}%I0K6zkOm{U zi43CP`UmG$q|*&4nP8`V>F37==N^8@w}V<Q-5cjROi-KlRd(@Jb1~wGAFZ|I!8<Fd z5Tq1KpqPeJ$D0jzq7|%|k&WCcQd04)2yOXd4PKn(pcQdK8nmSpOZsjJa|^o({|}^W zvvS5d`7qUI4K8mTb;(I){js|T%9`lI&qDdJO`0yBNfsx>!*hj7Z2okdEU(*p_UkTd zA?OB-t1h6`+PSj%Rk`@Tet7xt>5izi^R12J&}Pe-!c%VdVG+3SG%q!T01%huIzDf5 z08cz4WRVVmG}h9jDh}5}v;(eOsz+5QzRA=RBM=F@Se&gyJW`eMbM`8PtW*i^&_`lG zDD(4}t;~rU$*xiq_iYlgaqOa1w;n3jI{0~wL*#yRLDRC8l`W%u-gor+hqX=Oc_Nw| z_}l1c6&<HI8{V2E)B}z`PD{1G(TS|blr=?_7GSpzMQdTVqw+BFNnN}>?@9S*AB;b@ z$=w0iZ@&vQroUsT<Y2RF{G<7LV>f%0bsjWI-ryoQWI9mAap`IVIgQF-BFlV796ifc zLeirp=Y#XN&U=*1Q)YLV)Z{tDjtGbCMU%{FV68IF2gIl?UZHj;*1N3w2jN+TPdl>; z0&;5l1~nu2qNks1YKsVC$d&^x(a7c)u_S9>UBsKa(J$d@xwkSS@?|_4L`>ADvlLHK z^<9;2<~i82v_S6Ef~sk4S$GdwT7y^BOOhPw6`OZzx$)YvnJ)SeRx_nUvC#|_np-x5 zjYyb5O1B;48QHf4dE}bO8b|n4>7Oy1+#D@iZ7{GcG9*c-8P2?{aTHG{$~L5|qRW-S z3umxA6#Ry+n|fPXGoAiMEV~X+CscJ{0Du=F!*nGwqsryer*VpI-Y%jC{S`3-MgNV+ zCcFK6U5EShf)7p8vS11A?XTf8;NOLF1;DX&D(;{}9|4?t7B%&R`EXgi0368pL#0bL zqX7lh+nEi^e@#NP`h%6Ul6#{_O!*uW5C^4$RYPl!vc0PV{4Z}El*e|O9<dZDhe}W1 zuU?@)0?^Z{R1l^n%cD(^E+3#79GVM`i~?6iF`CI9=U)iX!e8Rh450NN#o(DsCs1tx zWAGARE(?Cvs=xweUNEr;t5AMbd~g6H3kioJEjgWG)|A#2rlm@GShIFlot8?$_#WZy zET3JGB48s-=Cf6FLki<U<dGY<oA}Iz16F#7$j`#RHv*+`m$tR<Uy8=jnYysg{bE<6 zKXvE%!tPeB{wJ?qQ8ro6yMg8}op|1FHF*q&k8`4*5|dw0M>eL$ijg5-a7MXe69?3) z3&v6tSDyltm1sUWk})tvX0KT;<2fK(e{ua{^TV!H9)V!gHqFEeay>OvetavbDK0pu z&%Mx9J^B7NVzbiLqJFiX?eP*rgd7_uDTv(1x}NiwbV#wfaupc3a|4VDNgoD=LCGj= zV;h8%%Y%vDVxf|$d_lIPr};!dR9JRmFukCTamAHx+BXBK`kuU_!Et8eao#VL$@~R# zsXiP^bAOMlC=4fY-F}d!(lw@^ZKaTwVpv^c#>XGkx6f7uespui@MFknazW}_5BI$B zgWF=MyBAO~7Jn9NGr<!QNUf%)Ao-SluLI^<oIsp>9~i>A=BHdZBArYkJyr46L*E15 z!*07_4ldY~BZ+bbi(sZk3|Y%FU8_B<26Ax{#1a3f1aYmfeE{XBfsWQM$2IUpn$XK} z#d)ncQqf5cx2k^BPaPqqhDy^!Q!Sz&LhOc`Se$?mz~--)iW$NqBsd8n=`d9#9L#8? z-6Oo;`SMEfUB#>SbN4yt`CD;k&+E<SDf>9KF25WF$vmVB=8#V1WDR;0V$gT>Z#E?e z8vX$=U`pLUp5|umgU8@%DwadEZQ6<VL5R`DSh*3F<1piocI}^{w#jx!Gh(T#d&t$P z-XezY>60k7hm)P!Y~L(@;x4(l`Pos>Q~FH3i9@}Mxu~?Yo-K*PJZE5-G)7oNrjK1U z^wm8J9g(i20JEQG`V>F$A`?d`D)W+)Qn4i9@ZRRKZR@wK9t{EL`1g2Ry@Lb|sa^#x zmEbs%&z1?p&Bpv~Iyo+$#;X{D=NY2v-L_GYreRDpmc;$CiWnHTus-%Hl4>;U=!N0# zQ^DLH;{rFrpK!v2d4F6`&H;i23)t*}p30)QwqZgs;b|XrIV))KdVot)VK(adPFd-R zZNz72V7y2v@~c{GqkMKOEH=8vQ8&pEsjI<tWgPGOSVk04m9P>Y4Pi+AWR<E)UItcL z34ssnrSeb-A%>n5kFH0l&jG~59@qeP-<u=qVa6s%fdsW3WK$Pc{h3Cq#JxI3(_u^e z(VUI(ZYZ9Bb8xx>E{s;euyv)F7K-}CX&MU^lOFCh07_RYHcmS5X|f&af*%3!mLf|* z7WHutAE&{|IqZ7Wh_xCsEsjGs;Z-Y=kw<bs7=cz*DNNXT^&ug+3D(y%a?OX+W1KVt zytdh+nW>sRvS5SVb+aG=saU}z5FZwZzpv-yla79Z6?KM26268upr!{pJ`MDaLnCg- zU@68^E~iRF8le#hQ4s2nzc<F@HHP?IZZs_I#u1@Ks&sxL+XpS-M-rX)Jul-@{{U|* zO-|&sT4p3c*Qss;4yBn?Ns4L1aq|}S{0=+qf6IODxi__QHG3CTWx=27ortqwC2KNL z7%#Ajt?HTb<*oY8c#Z#}|9f&Iz#GNXzE^tlMc3c6B@e*ADflAi?Wa4H(aR}OR3Uhz z4MwJ?M?xtX_<c~dVesRW=W9!1plbs063Q7|@v4p=f1p2g=P@GkZ_(lsibn(4l!eY= z2|iof`QkV@lPBum)5ty>!f%(-Q|LJJCQq2aaw_xNv_^gbzn!U{_ejwhffLcU#Dv?Z zuTtBu)s^GuCcjFh$4FHxmtxSZyZ9k5N++aV{Y)~EHI)E{ZN(ngaaj;4t|z9ZFN3CJ zw)}Ov)G{~<Eq42kzNI?iD)Jy|xXs4hPnfS+5ZT$xB4v$r+SE}_XtvmB;hJZ&dDvGm zqs3IAZxSwSzOY)w*N0@s$@|U>eVXEE$V9}kU`acq7ye)e+v#c*V!Rzumi$#D`bZ%_ zcI;xMU#xPM^!@VKsj_jY2l1-f-(F<jG3Kj){$1kHMx`As{_O<YW}r%n)3uH6e7v#G zBw~6q!cqXX^@Z|rmi#^N2?waX$8tf?x>-;Fi;P@g)?00Kw5o~6UKvgzad&4NJN%rF zQ=C$;P?V1uTy@nhtEiP434N_;BnuTXd>~yRCNT8>`x3u5#0`#h?XCB%zHp{=I;y{% zGmEo69=E>2V4ZAKs8HL4lb#Ul_TMoLy-|*bN(D{udN_%@lI8a`O^owy%qkZHXIiek zPlElXcJXDZ;}&GM3EYR?GreLVppWQOegkf~BbWd29_?k=3B&9ojmwL~f*4{-nEazT z+`lpuswblqK+DBfI-8QZv{j9A1{U=t_vN#VPU(F~4w9Cjaeh%8nV%)CD>|4yOXHL? zA5cgs8aDKX=H@^$<@oLL?>E1fn$v$?TS@o**$NjlVS4XnX%HX2*Yq#^nCCe`qe`Pg z<5uH2=3p6VP~EW9u>Ad8>O!Qp4$9f#yjr>?_tCGX&3iBVL&Ny7lPv1gpYDNh_E`F9 zk83(e>Nzw*<$Umc;6$JVAv`r}PN8v`4_ek$wTIWuRUUlIcYD5{%D$&ONM=<qm#JN& za@k|cCTJ)6?%#%+O|(w-_7n5!LB3Z34buk|vpDaIlBhqg8jf(Mouht=t)KZ#G>f*m zs*0gTk=n@@4Ruy|M%s}S@Ttu9DF$kzAMeBwtn5PRBb*gdG%q>#@06!oj4)R<bIcmA zQ4wUk;(3{hqDk2N2!YHVeH#SPQZtEJX8RH-lcvF8iti>jJ5ux=|J6|q(;p5XkF=Sv z30d5{jk{<%7n8N}idBi-x6~&Do<aVD`_7|0D76eMfO`|`jPE=Se+|#u@|Fl0V~ups z+h0z-6fw96@R??<XBj%%v$?ta{(bE?RmaThLj31gwA_O{OaN5mEYtY#$4@M7F963e z5!j#}EFyw}%|~4l6_mXmz2`&u01j|#4oOJ?g;6Og5>PZ!RBH;UsLm(5Fp^rbI-YeR zA^8t$I$rrTg}U%}WHmmjS8-$iZGR37a`}!Vek?p@xfc}9KNiBf%F3|DQ(4^|Ru_wV z^h%xdTUn3xej`h1kLs95%O5Ny*{i(FPi^_Rj8G=xY<IH1c^Cos+9FA$x!hg6y8k^0 z1Sf`&(fSxhc;_jw6cs#myk=@Ep+J#bvEbRgqCfNoam#p!{*wDmjr`aPmucn>PYybl z%e5+E)oyAhov7UmLB#qPT6hWzRyDCU$&A1ZrzYnhw?iyLvtc2@_L6$WdQ6%KAUv=p zMq_+;V}7?wRz9IlV0CCmectBd-q*BOlwGB<3Iz<)B$P8i46_#KpMN%Qh6;90FAV8_ z+}6CnQDV{zS7&N6znFm@rdqn%!KJHRva^FnC3Mi8i~UP&D^=8CZg>KiGop{9Hjhd+ z=NS#T-0E6Nwc0rOrEZ5YDXCKG4jQhf7BGd#w`i}GxT7S{VdQX@^tVzucriOl6iN|M zzWSTYpC)Zjv13S2tWl}95#VC*I(8?1H8FrTPyL0&-Qsd|$F{<4QK0p9^NsS!a;J7o z2{JIRQhxpB`zmuGHnuY&v}@~S;^WKjU+M;6rKNJnNmCg>lqA;R&^UE-z}-poGA67a za;jNw_3?7DBUd}Dq>VLSfKzj*NBWA(L3Sz`LbpLIdan*01jp26tMLU<7HGs2y_>0y zt;yn74-s`t%==^@@+)IU+4rad;@K1SBHN?0zr%hFR%X_&<S4&CMpxL&J(3-0;it}w zLIZdMnJI}bUnwh1MrIIlqVAQv4-d+^gbujEI(_q%$7h(;g!OY*>;`7Q81^ArS0Ue6 z^Zs%0mey=;WbWwUrHHA!Sv5EIn#sQ6=Hj9MGGsDq-<X&~wu;#Zu2(R4UuUEuX3hP` zgKl`!@Z9py>Bb9JYpkV-<UUo#*K;cW_~R5ZspMt4-}35$hmJdK#per0V~8n6>u}{b z1S!q2*s2&iLOjh{Y^kTcFP+#D7Yic(s+RD?B0CyN`{WB2g%Gu5Kn^mKGr4}e)|)!G zezWp=k&{Jxf-EVVj?Lgcn^;n1mK+?REDFKPI`~7mtc0AuVCvqhdZMmSbW}>Nlnl;J z$krRPGaLmaC6i>)ld$uFD(U5pA^jk(%fP#UQ}nEWB%SvBzJM=^cu_3bW7I^&KJe;& zIzFEFmy)_w-xFug!3j6<yxm0Tl+*$2%6K}%N>t&hwf){d4arTjj(p^5oEuB!we@5* z33Oow^$93_=D58|s7x%CHRAFG4C2ieUvt=qt1)<Ep?KNSwi9qSuE>xJv{BQ$<G~?% zQ5*FSMtgcsVKKx_>884x2xPy}^g-(|bv+-r%lk2dz8TDsut705#FAUK$^G(7Qx&vP z&}t@RX`3`H*c*ht+-l(g>9;XsXki-25^fTc6cZNGSV&e14C3JG_u$Ensvy?{vFY&; zWIAfpNC~?cQ#)X!sAhw`ndG9JRLyuH1#wo)m|#+&A4CPXV~Q(j_76Um=iw1cv_e*G zy424W<ng$e;whbVa&TS(%6WZU*|yZ|IBKe>1E8YlzhZAbE$2T89BQx5Rmc<9UT+|2 z(2C#!Q^7idSHp=(su9#Mo5Z+4Cn{@^#e_ILYL&L*Ur8h6nv`Z}svIrR4umPA&Ralu zlVZ9vzmnmv(d!e5fCVLl+7g@A1__%;=%BU%{D?ZuAZg#v65SAP-t@;OSPwfPEwB=Z z$A^vnU}@gXf&j<FcxEKxV`9zR+op00;K`eg3d0G#4T~sv4Qz8DO_U7mmuA<v`B+Y8 zSTma~g)^r8<|*hY>z@S2Z0gh8aPO2#qlq!>v7rWJ>rDMB#AGp!M9)lyP;VweD^uRd zxZI8eb-9JV&<xsOu(ussr5zh?rBj=qp0NsoNYrW3W|nLypTB$9zdUf<5F%rb=|)k} zpVAQ5LV<gLqSDkSiuR<y03aV1HiG5g{)8E-(I*U`-ELgqLU~(MB{S^b;5~kOnjQDO z4^_gE9j%L0xej!jd__{PDKe7>ep*$62~#HGY9W|hQ`=M^)_hYm+(__-F!YSj#e0HW z8dB0)0uwczW#?26NcYQ>NfN~GjHji;5-O=-sZX}?fbgi<5yCI*>FWJp<-T1G7;DjF z=)|ug?KmeX%57k_XgI8pR76MtQ}-roLQDB?wMaAraV0mL9{4MffRWJh4|V`6H9<y6 zb|!*B>IO=p9Xv5V-rfTA)C_QB_lwWl5(4ODi*c}Q)gS@%I4bl*JJwl-gh(~4n2Y`W z-URY91G1<`kZFn?W}DV_6ULHS>l98JSS)=L(`BPG1>;tEgXEBKa+;M}I+6r)?H7r3 zt5pip=LSx628$(4C{|oVcgX~v7@}QPY(~B#5|!2)#VjwU3MWh;VG2$o6D6`xYd{}G zr0c;pLGY|90z@V!{3qJ-Ac3)_8B4-4hv*v;`*dM#eMrIs<|{?<N(d2wW)wyuACm_% zk^u&WU$@ifRstc^fTxwt>x5AJ5t`d-?2K$NuJ~Lvem4Wx3gW~t_Gi4`Mm&|C{{7ML z6UCrbyH`03G8FxOTOdWY6cPnt0@xc^>Do$>)%9De>#YV6A)IwbBl=2=j8>Z}VYW6X zUP(TW1uu9+vyg~NoncL)Lx`NmufgLeCn??(qpel52#8}7Jabf`tvVc(Y0Thw5CxtT zX61zzBfpDOzropzXU`b7&mmXgl!uCY+7LgsAscwMbZ?-<G>jphKssLlJob)<iYTmG z<Vb^3qO-YU_6JM_ck|ob2oVTc_Mhd_ttGma@%?q0UP%b~#f+7?`|w;*vn_%P(X}~f zb@!*^t&I7yTt#Z{OmbHB8#c!=!)dS&b%Lb2>FW;qP(0!{+{kT*w2xDAot+HgyWA|m zIDID5Z};!UiP>Xdfy5ZE`ET(C3m6P%4O4stR+%iwZM4r7W$T5E{4^`s93mGXhXhkR zr0t6S*;W@{<XYx)j9BtGW@yvOD=S4)DyVT-ZLfZ_B>-6qr2h7@HYHP(TCDu>3azY1 ztHc3E5%~)k954LF;FPw76!Ehm62JaU$oMv@noh}}-C(pe!$v+zAZ-b)N#94;-=A># z)267MFb##cj4aG0ZSrlEF2@i-V7zZ~Q?s~YVV#93WvO3W795;ylSEB_X7$E!2?AQ9 zqscLZsoOk)kbZ`%(>F1lF+7Ewx|4r0SOIa;qgx%V=MuiCdFt&-5dE%wdGU#w9v)#u z1`Le~xv!l5>B6B*>Lc|#tHIGdD2e=)al@3wcb%Wib^NsJsQ^qiyi8UV^dG@w0iNO9 z2`lV-Gzf8MA{B@$;DSJrn#3Pcyr^ygjGn=eYoWgR?aAR-5w*lcG$?~y%<e3&X)h*r zJ;`2)Aj!+0sf!^JDNfDQC@+5g>9<anG0g<W8}G(JecU4#gp$mCZ1MAFI06^I*xCj4 zh*}FoV8Chw33onSID3GCFVH<tZWv3T0o_43PZ_DzLUTCX%l{o*sTPBG<{;%ogt5c? zlSUDoDgp17W-A$<MIR-41syDyW||R_b~q(7Vv;@q6oTOPZAV(v(USMt)^BGO?NiIb zaq%$H$FOEv0axr;`N~waX6Pr2?5vG*Z`?A_E9Da&Ja`6&$XGZMxLKGwi1~2ZIQxV| z?XVp*Gh#YvhT5S9Ou|rI55t5pVjMPUSOb$Uw}TO}ETRC&lccwIt^|LSP3I8a*Hn!v zkl+<%syR?4AdVXxrqG}^A9>jkKUkm2-+-A(Nyk2nmm%oMrl_fpov<%Bis)e(4Scb{ zYY2fQKv}VA6ip*5L5J~E)I?MqghJnl#jqi40>PUs>ew_a<V;VR!3mMTE7ehkn2Cg8 zK1MZ-qV!1gkL}ptKS>50aY{`Nc<glo2I4e+mc4CyW8lK~zWTQ|W3HQQ_jKmLy1@w| zZe3!~#Nhcav2(Aed*4?#VqcZ_q)tAtu+KHWe04bSG9$}9l&K^k5}7DK%sMWMmyj>P zDyj}jh~@~6D=>A+(-r-AGQ&hLN+~bo+;>L;u{W_AT&*=`YcRNuZeOo9ob1-r&-8~T zkg`vgkNXI}Un0kszu#eJd88G3XbL_~%n6+|@SU*PiGzpZ6)%#ozy;Zg6DuK*d3QXO z#CNP>g?qFi3n3UCUB=*<53~fj=a}M++w95s>061JS=2(rf52yjyOnk}FzR$kCY>Zj zAxv=MkZ1W3tvkS1Exjq6rAHcumQ|~&o6;a1Q}hM;t<M*ZRV?*U>4MfG`bGjO>Myvs zsIw%j>fo<wLM#<eapE#o!^5ku`0~4AffL!Fk|`00szk_8(@FEr`0bK5F+r~@ny=|9 zJsMAY+!t4O@{AQWgVEAD4g^_X%A>F@r_n}SyFc%Xe9EA^&U@vPXjD~uDQpHC!@<XB zo$zyMWFyOHNt8%cg??J9i&C(y{sd*;i9Y}0bt?9<FqLy+0vcJh{|lelkLC+JBC?`v zj1^Nu!G-_Cw#*j1z|v2tg-=sQp8;9-$zutaL@DRtBkt$WvF3Ol!YI5hF=y;($?F6+ z61QGIE{9Nq>KoQ{cwOVWS%Xo(c1pqAceL6s3{O`2i48R$SaFm2Gy`^mp_yc`qgO*; z=Y3zrkO;9TAS7643iKf{|1~rbq25HWUnF=4xo(^#(Mdic3%1&?*jJD#0j76OBIQm@ zr9JF1f6y}=_OPVcqDU)S2sbB~V3bJt6p8{)p+dx#%^uU|_ov9)WU&<)kCAG-7Xg?Z z184QP=75A@Nh~hYWF%{=P~wA%x-I6gES#xr=r65yAv3MgcvoOYozQ(&_6ppQckDG? z%>vA{_zmWqrGGOx5iwTaHWwT@{qkzB`0v;tdBYn_NhTpv1QWoVyWAO@bo3eXj1~O% z3yj;bL((o5W5a<@h3`@E*@K3AH|&Me8Hi*J{T%`D)fxnO2@hd+C`@ULrWU*e;Q9Jx zV&H@e2{qDxUJlLcm`P$(d|ib>1yY{OAsOruAE<<`X@UP>IAn1?H&Ek7(`I_IVnqTO zNAo7?*i3ZX(l|q?s#6qMPj(ahkt5k^g3*FXREm2<EG!6O7C^oOj8t3`TYB<@1N<gQ zAn#r3?tMil<*#T^XqC!f;yoI_-Hxa*n(0?o(=7whlpD<js+>H$)QlOxKhT@{LMCEf zXazgydmg_z?$IE#@d~q__-Id&m@M`z>k8sK=T(T6o*n!OeR3EfLnRs{CYAM6c4$Ic z4YOsU7~4W)J!HhjB;K%v=C~QP=r;=Ie-`K;actzi9+mmn$ThynHLJ_S6m7WU)V_&k zaF~&)fX&4=B&-;LHb}gz%pfUF;}%?;WI-QS(pye@g9XQqmy6t{kv>7cgrU{r3erK* zfN=VBW+)gqNrHl*QD6&756*$h40mmabnT%OV5B@U8gK|MC$N!1_6mt;!@eyUEh{yZ zxh|Ir$_|~N1B6hpNOUk0x(zXteDU<TmZsciPfmT!goiA(l_+$mw16{Tyxxl{lbMuY zk@df}^&=*EFFvZ7PJfK4eceW4p5T|=Dzs^uT4U~(3A7{{Owu?42zm=*JJg<~=M`#f zRs(M^QO=a_?&?>tuS_rXLs;3B*~J(JhqSC?W_zS9ak#k(GX|9v)rLgTQV39aXvMS3 zCID7NDQL{9vh!xVmmx1kCO!_``$p1N14u&<7}O1BLzkq+g``_26CFtSTBW=@bJ<`! zkU}C@=3}+E(ntsCU&*AO-e1ea*|`fk3A=SAZ_!`~e*#i#G2?uy3J84q*Wye|-N$*e zVC1u07VNTm?Y_6fSpq~bn!AW9SxZhx_rgBVP(I<Smkw)G6?1KS=s1vHD{g4|Bz=2R zM6H&bo}MbJfL=qkw#%nc2{tT78^uRtsHV`=XnGKrs<P3&7Vdjn6VLIU`fcDJEgA4p zu%2m2|5fltsx|MVXJwnbX?&oDq{)zP4F-dAJ@E)&y8Re@SZ`d=>$~L?$K(~Jfho~i zzz;u?I$&!1tKM?)WdP1BUS4Apr1?+<*&g7dbz%MX6(l!l1jzg93a<a!cmr`$E2XLS z4Ns*U@b85)Mp>+c{dY%VQena{M%L^=5xCyz!k$GIF#%Vll&?ygW)8!OJLQ&mv-r13 z!8X@A__#2;Id(Vo51HZbj`5k_@^pd_ShI$ozJ9wl?DDw6)<YN{KKw9IY_qANpU}&o zvGyGc5{gxL+LjRU`z2+g>>5#Xhd*Nfbr$WH{7Qi3gbL2r^7KJAz+bg9iAsv<=i8(^ zkJDb6GP0cvezi|3&Z!(<ca#U|vZ^GwK1b~044Rx!-+!Kb|GD~Su7tfp07UAg?gxZ) zAtb0oQN-(5{j;B28e>y8SwY@z<y2n^WgB#qb2c>~+Lfb0J9TmFt)9PG3@AsXE$7@R zG=_qEElccY2%~D_kumMt7K{W?k9EjrQjEOirhP1SQwPOwVwsjq!XMfDPW`cozwqxd zebaYqr-dX3Z{)#9SO?tmbY=%CKUbKVU7ftndHazzsw_y^96n>YTqWXo8Kk6L$*2&k z*A?hX@z=s9&gA<%lKOZbQ|0(~=n)b2HbL?XCvm~zpFV$43orUJi{95{8xn6smVO2= zTT4o$H0rt5J5x|^hkT+C`S=jb{rkhmU*s1-R;+#eXJayv+rdliK~@oU+h4NG)B+A! z<hDaFskg&g?Ke)!O`6ooUwoGPPuNqnkFr9Qdz>NErmlSK=*K=Sbd)}-k61XTJzuUG zdsY@zEKg~2-v>Oan@F3ht<Kc~9sTM=S>F4%5t&Gz{^Kd}XEd5aMyMadz0{Ajo7w&9 z2y*;to^!nFw77TSo*iEG=j>k1x8z=pIp|(B#baKznjK!%Gylb1xp&R6)OQU)JmItX z^-3lIom3{bG*T?R+i%oXZ%^a*8@E%BL5<r<w-1fmu}LLHFIno~<VJC#i8)3ew-$_y z>C44L0*oAS1B~o>9F1&Z+ZsQt7B;qkXN}Al92%S6MRnMaX?Wxq7!)2EE(!M-i4HUx zX@%hA7-;$i7=EeMZY+cwG}acdH8wOUksGdYlN&B&fEr!56dMaeRJd#Ne{nZdV5v8{ zsgoOt0wayIbdim<edXi^1}JpHWyY&U7nVOpqRC;EG}xc?@R@-o9!bi?b$YQOdMdB2 zn3^H1KkZ_kH*{&+ws#80)WZ0Kb~t#uf}Gp5c6q>(y|d0%8v+hReMdRFA>o;{+nsPP z=QibFf+_qzfp91FwkgugX{Q_gY4=cBoSx2q+DToXM&pb+f_;p4@qTX8YRTPtc&Rg* zNP6Et#}MW|Fk1X@TNjy!*w2xVQQJqND_27B=y|V&)NEX(>EjX?e&BPWwML-P>y=Fy ze_IHsg1F3qy~R|?M3XA2C09g~+{8TpjVI&{E|LV(Q2UF1I5gEoc?97*ChJXb$<IZ< zmMSKFs0{fsopMZv$BU{y;3ydKBi>B&oLTTwub8Gz$1zUyU?@h7ZZkEc#bNgyV6ffW z`^aH5XRWwhg^{(F;V&?CBn0$;L8ODwmk*|aAY6k(S58pc8t|wX2wDJYQp+Tln7X-s z%x{o`eJ0s^3OCf&+2rJtzHk|png9h9mv2c~r#x9wzf)tt=1LtWPC3BJlZ?bJhI-5~ ztvC~bvfIX2{}MJY^*t$NIumhRCy;9HWB=I4u$M$q7DFithH2FYaBzw~+|KKiH8L7$ zZ&Mfy8EH>91{xW(<rs|6KLkix)fwP4pc?BOjbylXizQu-Q95SBpx53pR`<&5vVu^@ zi2O~H2N_LkEO~1z+n+J)0x@J;M{f<hG8=c3G`w;@T7=~oKj~|PwXk(f8F`Hv4Uij$ z86kebtA8Kphsl2sv_7_Hzl`a81oesMt%JKv8tOU5F5^h<m5joL04+9aQz7fpW&?MG z_|5~1`3lJxs}VQ#xW9*UmmWOB>c0RZSHqolFFo3r@f<I^=m)O%KK^X#f3jkZ$1Rz> zTq)X%oC@Pmw!733i<S{G7IDOPAI6@2CIfmk3AlAU#vvU46;p2h?RLx=xRIxQQ6M_C z?cI`Kf>-KB#23@$%y2PBm{R0+hV`_f_;BUdva;cJTHX?Ba@A*0_@t!p0`^RT^Q=Z9 zKVZcow&Kn#V~NKbuu`=BIt~}y@dV>}kN(1&N6I=+ha08w7u9T^$Do&!WAgpZ#5z;y z^vUwe{GsFFGqX_{3c>393!OVcrD*wnDqbN{RtH=$bLnxt;?#SjP~o06=*0F6zLjk{ zd}him8>P0AOBKvrai>VRH2+;Td#V(nzxf2wQpj?;dG_dY{+|9Z7$7DK;79}brvd&R zI-haKmkLZQkx?CKvF2E%86fDI4t@LUkL)Mn<{iro{C#7Hr_I$MvS~FD&2E^hb`+B+ zoCFkhiZ`Zm0)RXXaGeHtr3MI717PY60uxX`97*6A9Uw&wpqv7{d(-K-TBD~C7C?V@ z3z3T?y^uuvLI=!G1DL7-wCs_zE-1h}9bkI`z(YI;^zcSAp#xA&0L-0m+Gjkt-ie^| z2;C`Hggm5_^qb)UzPtw54O|*2Ts9Brv91;@EWZ`0P<HM7%-;0&bs@qnSafK%-wj_{ zegi`I!&%{xPa|vDJP%*iYJ(5+hk26EQGFeQXAxGDlZUA~IjK2==!;z@JwXs3Yz$XV zP*wo5Ju&!kNUZ0Q;7~6qa3hzo7e~LFgG+k{yXvYo`4Neu+rB{t{;F?KA*dg_4T(qb zCV_?9kRQH^)@??W4?u)HF1e@L(=oKlhWq~g7#nE+l(Tya=Z>|nFNc8YUljagZ2dNe zU|trD{_Q66&!2hVvMB<^6LD|NcvaIt*y{anL<{-~YDXPct>kv{&d`LW^&i4~g}20A zN&(T<jzTUy9AEkF>k7C&z2?m=8)WeKHY=s4_lBFBU9A!e<q~1XAStEom`pgSTXreX z{4DF)o`$oKc+PG1w{E}pe(Hj*x3210T<$sh1e<n&P<uZ89>kf;NRZWLe9INF2ArRc z8#wR!c~9mwoilI%N~ICdo^N@og8nnj95^Evco@%mZaXB_*P?{I@27wEIAy*Y`u*gf z=}oV?9A$PMC_M*I%ncoKmqwv;G<@#WI)}P$+SIr|8oN2A{+Nz5`$@Crp-Wz{ptt4% zO8EeFTk~kvR7bW=1)lM)<;MwWC}V&=NWV8Xir+F{@^diyhu(CCG>;f^w@2b^jaoF_ z^8-4cC^{wiJiPVSQ8ld<8un0|r$)0y!}eJH*`%6$?p%01;u%F0QNbTk&Jt1KJFt*2 zun=c`VrzX8_~EsP!yo2e?F%DL??&x!2kk#MO6npi5MLLnFKqOK1OWoyRoDraNduR> zg8^pGAmV5An|~l&uShH}WV#m;O=9r7qun1f{RW4mBS)2GWr;u2zPv!zFdUy5Kvo!z zxhA+b499E@pz;ZwF9mQNhHq8O72H`$NU>;O^a1748B{ga?z`x5Pu98qACq*h)7)Lf zRN)^vv3s_NS}1sYB)Z(>>s?kUxSBHK{h*SAv)SPR6zXeGUo!$aybaO0b(b*hHFM-) zpS@f<<CVDmgznB$Z`on>=zNOUH}7Ixt(!4&y;kDW$$J?6gI>FQ^s9BT8=c!?Sxh4| zk|!WnzpHvYcaJ8ge?)!T4%&H@A<cKmZf{T4q%a*DuWl@C$SdE0OPHwJa@#;b&uuDT z%h%1#V(N`t+70j~>*^(lwCRGq4Q(;~N~vzfR^!mL(Dc5wCgUfc*P==z^WNlFbY}A| zYfOqek~U+Kj@(n@Rxb0;nZ|90OkE%>?2o!l+u!sY6GNSym0P5{dU&*cusfSL@TgvM zw5t%kqZu~N{C|1mS6?UeU0+v`_E+?UcV+8^o7k7sFF|GJN7ZivuNJoXhAbod!(THL zt!o7E%H#iF@8tnRhhlr-;*9*K#iDC>hAsM9X1CTg!kR#;cO(<M+(pG)9J0*=&c-A| zysQ@M8sw%7|7on2@Z^B`7GeE~DGfSxi^J@$;OwpfE-!G+$IJ=Fm-$JL{%a)L>ew%9 zz+L)L77b9omGazEU5x+;^T%wWZFQ{w0uuVjH7~_W2_UGZA8orI*tml<^@4uwDvy(I z3d28Pz(1W>Z&&FGu6E#Dw~F5OQapW`5&O}s^SgBF5)W<lBXt`>C_^O0sXR{ffB9Qi zTz7vLVq8Rn#GZd~#)0mjcO7n@Iet0qYViuY_Z60#TP96mk+Ok-=dTAb)B_alyDZ@q zAm08cp)b-&TUuwtL|cr$fy;LJ4Q5o@e0hA&-z$3Cs_uXffA8pCCwa2skw(xumRtvu zuD?XhFd-3|wh`3l#<qP6)2NZk?l#ilFAnyiSd(riFH-JF(){S!{g8hzj8PMZ9oj#f z#gq6b;)p0x)?GSrC*nhUJ`}wi$5*`^S$t_^bm&EK^g<BH0LD#~dRT4hsZB@BcJHfd zZ+b9n!S2(y47|UN{lF^RF7cq1dsGUPcADvZtX|03__>Crt6R`sZub;kk-$nK`r0Gm zw`V}yTe9)J`%T-|Eo=vIIg(;&6j=B6zv<`o#|0dt&Eh$g`D?$~wF^~kDgGi^SjKoq zIDE)h?E5--WJY#!ZiJlh<qBTU%txJV3sI_}uOihxBU&QTgA{u?VmyaJINEW}d_bu^ z%fz0VT2535e(T`KOUqO$;+HhCA8=dL(rbWp%$4kgdEVc03JIXZ1w&tTvc)3>@Eg-d zq^<9jP@^n5l=W%68pXRp=!s@!eTgZGmSj4$2UL2J6<u`uGRf`<eLKO<afTM>E7b1; z=Gl(WeChv=4Be^G;d{RFD|#O2lVzCkIa|(~#(LH&{am(8f1{^hEU#{baZabRndS|d z{4OA5;XHow{t@diDlrWy)=u4uioP8F{N|QQpT7TIGOS{PS2^DS@4LfLptHhCgUytU z>jm^54*o|%11j<-*-nK-sEF2t+^2^fdB)&!`>NEs*L!9CU*aalA*{Hx@#i<TBG~^% zw#Xu)x;01IA{MS4X;IaCzTfNq5VG#iQ9SSsU;P7a%S!F%vs-U74ob~OCs^aX1%Cb= zFG|HOZILvASJrwp^vrqqW$-Y{<ZD<$g!{dcOtRKjubR=({sNo&aT*IBy0(?Pkbz7U zxHX#}@^kK;sD@BI^+DgSkiM4p_;BsNsaJ(8vy*{xh0SOkDO-%brbd0#`%YKMRKYrO z3i5$d<rOTu0s}DP7f0h%(XBGEH!~~~l^u>dqc4)1UhF>#U+9Jsv+&SJ=YJA&P#5~? zGF6pp8&*)+`Hk{3q!KhjOvZB=os_Q^6F{0JSbMvol)@Uvj36MB)FuY2z$u&5fS#?H zqgr+v68CX-*f<OVQ28W?Q3}Ghd0!*#-WTXId=lM`^OJ-h7jVyxO{K_ON164`La(@# zKqRYmPJ6jIrIZc;wqf{Uv&SlB9Pi<<tfVrP&cu(ZjYfh^fi{?eG*lU;|1h&LbkWOY zP`-fAKmf)HF^UoOCh{I<5Ra)Y`i_8zQBe%@PBaKZR~GdhbC*P-q(wpT8Hi$B&xk$6 zZ~-j{+o&Rgesi(;S<pMX&W}6V(v{OvXEVE-mj2S5+Gk+EV6o>&Lo$Bof3M)7M@bJl zz}sNFVB=i*M_hImFR3zuERc_nnjDj+H<wpKie~Xu+ji8Br4rpFww8j1HKzGR33O9t zMd8K26MPSueM<0&XCQO+K`bJXSCt~?1*-xwSULIAj?!+YXurTfS+PLF@{3==n7(gi zbKI`HPYId37G%^3nuqlZYsYBb2Tzv257dpThtjL~wPJaR@|1nT3LP05cymAUYxhSz zTl{Xr;Tx_H!ei@$dBR2*bNr3~m8`<k5mbChA@Kmuh3gbMI<P#!rrwhAl)U0D(oj^F zFD40{lL2W*s7T`-M)#NVv~=-NWBkolSmCdRV-<imq@0Ln0aps*eqbCYTCXdg6N}d1 z@hAB_lkgXd+FWX;ys7;qR%#Siy!;eti#b!^Axnzl_q|+9{lLNR6_}5|W1puKzvp!A z>q<VXVW6ZV|3dFw?t<P%uo&KFnrn^J#d45rxL~|<VMrpX(eXCZNtQLpH1(>i&I;3| z$pE!j6SD${i680d9B%VjG%-(Q-+$z{BUA2EUYAZ#!q6LP9J+AjT4*0-mmOWL(B?B< zNRYEs!>kqD$YoG=r{p;<`?7G2F<`{q9h*Ih6Z4NF7F;x4tuxKMqjes?9Exs8SVCML zoU`WFr=YD*DNm{X-KFneoX@^A^&Da1{0iRd)T4;@D<V}8hxt{25>C*1&xy3rAVbl3 zjBzB}+emXJ#G3k=peUz{3p<6Qo2-Wfkg2*KVN`&@E`<c@O|}+FRVHNBBa_k8`*jPJ zM2J)psdGQ^5T;^`rp(9SlrHU{F`BN)f2oq%$LeYCtVSxn+po>zSCo3Rak~M;SVyWu zc>R38duxWc(iLFE80l;lV8Xc{U<{*D{f-UQW+Z=XIqLWJ{o!EFfVM|Q@0)tMdbKpr z{m|UHa4y`DozO0^#YI$H9wfe6Pg6;dXh@?w)Jaz<E?QFz`p{*LLWy4F2Z5;2wP64` z)H~#3dq<%K!S<QsB9{d`Ng5IsMzybm=ZN8GGCWyE<jG3G=zo*1XlMS|IdAVdy_Ti9 zI_Un+vuta9nd#QQAjQbYz-VYk)zWS?-60JHH<?Qcf{HzpDW@B;ly5N?xK2mAkqSB_ zXIjOR5<>)Wr_mhiXIz2nd&a2Q>in^4l&$_SCB&E)FgU1-!HIU*TElQX9K_4**$x#3 zN-L7`aEs4Xd>fWTl?<Z}^afjw6Kuh?W*`MVK=!00wW4m5I}_!aeiScKdCfq1O_%k% z?-Ds0)#F>lp`u5vKynK8<|qW$>|4<p)NUopLr?oCU6;K+-}W--^?l0jCl&!~-m|XZ zmy;dEyxRM7e2M`i&V^r_K1mu`hkL&j^Bd)0j2tJ*!9w2gb!tQbmV&^5HX>W^`Bc5| zBX}8liK;r%Y*?~B29rcwCDnpbAeZ+)Cg|vhy{1}iuR-Xq`FDjig1<IWJltUpCr~Y7 zn%8Ub;W6>zz2rp3gh<*2XA2T#3;$N9+K97Ja)h{oh$agG+tt8?HUa};rFQKo6uIyw zO~z$SkwySp%ttF&DQI^A_~YxcN=<b=^D-svLqYzSu3|yjw`2aPD};aOuJDUMi#W?( z&d;%e?LJyiekQ|hfrFK=I?)xn1&*fYFvLp@M*Kz@WxtuSfTLxEyIvV>4h?7zz*E|Q zJmvdR;T%X=bpdd8FU-VZ#hvx#ax|Q_kxO;Nkn9G&YZ~N^S~j=#CQ-j`&&+3R9yCp7 zF#|08g5Q2cjPkcM7ebqvZl8MHTr(??9JzYJx<QH$K<!!fe%WW*pef98HNXMs_@gI< z9ldd!#F`o@1~$X-9*YkJ+Seb}Dx86@jO#0~bvL)%y|p~qkoHvROrvKFVkYSf4}$~J z-x{az=*MvYXR}pV%|az50Z8;%J+AUEY7J}Qb~2Kxm@a!xzALkb&7@CFe|q+g89oTm zQ>|G@k3Qyd%mqTR<_VZybikx}ooRRPoYKoMuZ5pA>OZEH5}IQ(6=>&{PCkQsCl=e9 zDOnFT{{%BB263<juB|bvu2Nbuhp?1PelN`9hVM|0i}D#RW7#BsD*RJ+H2}Y7{I1g- zoX=)tFnt1b)~$uQ9_?iN^~cGGyn3UHK-c~6$L_ukz<$1Wl?zZbzJwEZkZOcqTV8CM zhHQ#-HFR5jjmbk>G3i`x^0u|50<SqZ5@24n(<XMJj%{pF;DbB7C>X8jYJcI*<eN@D zdS)uQF&?QuYp+Q6piB}=56b4NDnJvCdlFs!7P=~5u@mniQ-|W5=nfY9zT10S__-^d zkYwe&<tw=_XX&#B<i|3xnmYEYsq2;62CRFTx^(rrB=d$%R`Qp7zf0H+ygh#QBd))^ zi8ZLVfw+9Q)nOmGkPbGh`$8?tx4-w3GFF!Ut@Y*CJ&||!0tfY6j2+=6&p+!#A2E*x zVhBh>I5)K2E|b5Mj{3crd@p@JHW5d+R}q(Tce5;`6i!OR^x}EV3f#(=@<c6UKT;;4 zHa}hLo1hW>stmH*MF8hi)fbL)#D%`B-?ePu$HCd+nD&p<M!RerA}P^}j_c%|U|VR8 z{zay+N{xo&ES>?4Q^D=-=1|!nBfCK*-)z|!&c~#|oNM#Z4SRr4oozu9ak#3+fNiwS zM?<IL72Kkg(^9&1(miDfsUDWtF0dpv3Q{bj<qM$`Jf;9oR?TW#RqK)oWgCH8vw1iQ z_p9@tiIo+T0L0Ljw9Os<UJV&=s=*aNXe~njgJ-#f;_Ju~Ts8qgQPH4{<5Z>aK=K>( zv5J$d&+)^2p}&6Ocsz~2hFtxPzXO}vqzl4xzI^ROnV~)yd5Q;@3=-P7DjfjdIGDu^ zAlXCj`E0JK*Jq_-2MJrAsd7vy-?pRgm|j0d0&fHW^M9J}tg!fo<#y3+EXF>8*17jy z<l#9L-|l{~RZU!2uz6-iImXXnP>GMvxeM+Z<@N<)9F*mEf-85hR7dN{%r6A|31INA zNN=};mR+fw;Cz~O3=a9$rwKNau>-S&N~J_PfK(JAMhY1bOH}SvckeP885MX(TIiQ1 z8d`VAWxN~Oc!qI$E&l=yTM~2duwo8d6L{EN;ih=_ByI5lQOz@atQM#jaU^2Qf}?l$ z&;G`W0)aaYQo12EPN7ly`x>r`xkRP}ijCG{(}@&~ZD>PwV!7b@(f@h(TVN8WwX^xS z20y3}IPzaV+w=5_;sob|i{czA2cm#xLEvxog%fK4^b6?QZLXy|+5(|uHp>HEqhB_x z#G0dw8=9cTc3?=;=&qhwOi*KNO35na2N*^RkqP<_yUL%o9?2U>eFuqm`b7G7Rj-p- zw_;^XJ{?afhUjuDB<&n5$ifYiW>hm?fy*KU=mA9p2~ES)#G#S`Wl<@avy==V0X;w| znyaa58;;cX&>PUw58bqxlTZFw=fpot2@KlRK4JVJLru}!V+K@1=e=8;zRmo$9!R#& zJ&SifmaN;Q9sb5>wn<c@F^?xR_2ymeZ~gv<u$?JTUeoYz(4Xq8v-LeH+~4WpYLW<Q zPR#GGy$isER&Ud9**ZA+yp<&-Uu_1;H<li0wEi}<Nh2ixGb6|r)jb?Uial$^rIr~U zBsV@$aN-@-v3&8xRZx(@{^;v?7Z$WHEXlpTYp5@X&eNuIdhqt@cTr$)#j7SKRHj`A z#_Cc~jjk!mCS^X`eygx&?c8#145xvBqhDz=z+L@TQdDfJ^5!2!1U{ppH7;9~Vjv3$ zM{9`Q1^976zG()+>}`Ww=y?ciN@yobw-~bIdEKhVbbw)rLDV0cwpWvWBX>ztJ{?Wl z<Nz<CzU=eT(vQ`Xh@MQ>j(QKOrf8wQP4JHnBh-~DpFyIvaHY5NU!pOsB9EKMtJ{d~ zv56LAdz(C_S|dl$;xNesUf3Kkr9)9VaV7XEJ1z3*`ovG5rb5)4#z8Jgb4)_JUrZ*~ zj|{M+<K`b;4j>y&Z|=i(@d2T?8RUS0b)CtX&A+jB%1NLBo8a_s$mTU}Hbs<foSc3! zZggnV2gDJQd`+xcOKI9zN%Eu9=QV&f-OML%UOL%=78GR<nN3mj<{>b4L1^w3ciM>c za4~50380Z6r!$!3?KIMbJog6KDMS+ZN~MU4XFnG0=qJV#(?$&P`w%-d1D-~z_+|)A zTWs{l>_JBHTrh`kb&U6Dn3O_vm5Ij$Ke{obzFv+zV`U`~=WruiF+Z0@mA%74j!Rei z{XYOVK*+y}watCn+&xzO5u1>uZ@`c^InupkCUs%;o_L^A&8#tyb_hvdvHEa-VIhka zX_0#b7AY8dWF3^&7Fjkz-{Qg@hid~UzpNG9J(xIQ2*c!m`o)8RLkOl2tn?p#v(V&3 z%d^hGiHGYdCkSFb&0_|lKh_NnY?u<+5M>B^^_15VW4((edstRP-3xWKh*k#-AKB>Z z49*Vr8D^`4{0{!G4RL0}6^3?FMgLjyavUw#k7ZLQzW8g9F+RYdpKO!eq3(XN48wN8 z(;{79s9^9<@KyMNY{izS7@*(4CO8Be`CfRmpc(qW`OcIx;XqeHu-VwxxD_xk>jc*( zz<*dexP}1y0!yBs{{Uj*-~Z_gK{Q?K^@Bs2Utg>RoDH+umYv-8zD(;9PJDdy6g@q- zmr0#sb;$>wNr7qV8Ndp-3+(-fyP9S#qsTL+iAGF)fpdfo&)E1l8L-{!4UPz#KUo`b zY-X9(22K%MKUu7DP-OJXYjA?o#d6AX*Oz{sWOIowo*kD{oh;6?YT$~(3<nVD0!07T z8yrDrez6kd#$W3tZbN1NXr81hSs?2+4oGGGu~z5OSK5qJL^~N32;$;LpNy&!sz2)h z+!L9>7aO@5u!Y+b9Oh&Bc+E}7xc@`G;MEVvhK_B^vT>4sI5|V`vq%#Ld1vjw%QP$X z-NQ2|q=PXyB(ji1nInQMKM5G85%U)#H75tz^vM@44U8o45|;>!)rVpesC;g)OBh$8 z>Sp1ElCi45GG_NMCpd#(>cCNg77_{~YECs^m1mWoRt`BJbmsYxW)2J*FmuZhu1VM> zvR=(|6AZFoaXMy|W+Yrou`*$qgS$7GWIe<y2Zm}G95FsJ?%{2jRKnVw!AX)4n*^bT zWGQdl@t|=f+JvxShKg7P@|G_|r_%wMVvrMD{<G1zA6#EB%*E><?El<O6X%)y&jSE< zLjwum1F{atGb1df5Ry;`l2Cr)8sc&f+ZV2RpnVVHkQN%WA}&OjPS(@Sz?g2z_QvJR z(*_XCcVQuzh_~cq=}%G{K$)b<&~1&GvdY^CTOoVrKO1Sv{$SkLBL!KBBYI_j8yVXT zvU(6(yD!WHoq@V-4q(i{M;idy<G>iUuk7Fu+xD<Jz>2rDVFsNhXr575;OCM?bSkmL zq4}{pG*|-`{Vayy2Mzj^bZG>|L$*qCv5macB`&~KY<glJU>~*yDE0({XqFcptLbcf zVw&&-H@i{pv(>q3k9gfS1E%%_8+wGk!1ZiINzSCJ71X5nUWK@$3~>MI+CYEQ2@7en z{;}h1YCY&a4f>c~pblG8u!5knQ~I3GdI^=kDbGPOY?^b>Bn_vBJp#S36u&kvsj&o~ ztbJP?7%fm;csfBz`T!-r@?M)Y0v&cs)qXbROa{;$+f$MB0v6)LeE|a5c1O?)+bziY z04~_VL(qI%-!oT1X3TN_A?PgG>d)8<L1#px<U`P1{7(<qOF(7=ZL$7<(i>%SCiDfc zUzK!CBWJS6VA;)Ze-m>~P>UXpA=Gb@OcxIWy!0({@ZG|}C!GNB`2J6#K{x~iaD-r> zQtZN^;2?NJA!HbsP7BFs&)8xf1LN;Tq9J{y(UCap?MoBMg2c$3NSx4x^G=(E0r0R_ z5QZ(_V2rP1QIJqIwzRL;vYjH-{-H=D#7G}4YI27EE>}`(m9v})Fq}6ORau>rRU?%) zh;_^a0%=;mh>9vCz=_$jQpk=`i%5t<G2))4q%~S+5mv2-i6~=oBAitb7}Aoy5ye;q z!~aBl1&x4(zqUedmVgZK<5O%?Nkh;|3@_1hQfzbj7e(6t?K-~W$5~c2(GXtPa=$gV z+>AkuP64BX4=Td>xYuYvdljv+618%E02~?_mde$Xvql58&b3*`<JY{^Z$xA~5cpE- zrI3`SvDO(-u1{fmJrS%e)&e-TF90ODP~LeOs#9<5<nExc(vV{su|ZNiykHWeKsL)T zsdP|-3>1(ARw^om9=w!w6_GsBi?`Z7!6zu!g&ONr7DS5yCu%`dl$FUT29i)Xiv$=1 z6_nV7G02OFNl=Cd3omFc0|td8kG1wA!Rhcp76CITkmiI;Qi2*FXj+qm)&m>bMwXyA za6%x3*&LH5UW}xdkkv|Fv3lGqYufw>mrJ=4w|F@MR=^BSS_Dyc10OnOM2HMw6|zD- zE1BkKps>NIE+7_AP9WJ*zDk7-!IxAaALQBMJqF=jR8kKEdFbidz)Dw6)bh|MmVeb= z^l%$tJHkGy&rMLYOqB+bnGb_-w8#llXU8Qf00E?Fhxn{Z5UeGKW+b9gt9;2bLU~+$ zB19Hwu|w)&<{qUJqU6d{KzzFsWlE%AY!xV%i+#y(G+e9%i7zGrbFe51$W<44XoOn9 zN)}Wo^aQB^Dgb~aDjW>J$0%Bo3+fI*Xc#N@;aq)0X0{fbt2bnkp9D!3c(7wIPXWq0 zVF(2oCsP$UUZT@NaCmq|kSaVn1cHY*EeoKv3Rf;(<F&LCVcamF5(0`xn9?pR+3cnl zbden3%KpeOfCfDeKxyP4vw)-A4o(I2C7=Qs+rdRLuL)A|09XMMZx+SY$_Nq4vs-|* zuMZ#Hm@FaH(HPJ;D8&wnppY#D2FyvmAV8AMCq$FSw2}0iS=Q<ZFJS6sI%L9_!##x( ziv?hOQjJ3vYYN%`1<I$5w3+{3s0j7vz!*}6NBXcJr37oP`WP~1dSflu!an=~V?x01 zt}e_~bmIh!E-=9}B{W|zsfQ+!!pCbtN+*aRZomRiQ9xigLQjK5<0BZTdGzQXqVxIe zSiy>*QQCb46H!><LgV;YnX6F}4NQ7iO4M{-p;L7we7(`kij`>;<*d;eB?g^Q+!Pj- zC^!VQ6v34TO~C_J8=Qi`?(BGB63JMFE}j_I1OqxYwMsoM)rWD3(KMoQEM+xO6JdDN z;0w$ds^yqe0*OeUt6_?2$W&BkLITmIHd74;=4h=gHVM;V5(5O7w;c@v0TB9Q-lz7R zz-5SO5pKTo)5}Zv?6(UGCtpeE4qzDur6IKR{|$^j^2H#tN=w2jXv2E=@rO70Gm1ef z24yT0GIhm3i&gqSVmD!dATxoYDm0n{3QEaP0t3+xHI$}2gl%BtI98SEOK*44SVa^$ zhg{kTT%?Qwp@k2YL~|k-&oUxu89y})&4Ca%Hq3--hst6lWiLNWg>VVnkA_q1lchFH z`I^*Ea^dRnlpXv_q<@L{sUBp|k`n+3gVpP0)0t&7CB@_IC~SYn2Spr#B7YFj5?Vnh z4?jxO(hn&n1`@yNUqwgiE(C(|py`tQ;FX+wYXu;v>YXo?Y2F&t5YIdxP-(^tgbzo( z8;DTTUUWa+XyUY_?ZS*gglv=XMU;d35Ofy{`yMavhw9oGBsUH}SBmTG;Xt7fN26fd zX8Xor$(A#Mi^p4uh%iQEmk-;{3lqL-h#2Q(lhp`1=M3R|nPuxw*!d5ScqDd#p2?Xk zY#Z98fV|s{2;%|()J_c?!CC=v9W6GC2do_-IZK5ZuFzD><7cef<TG`coLw_i7a^!{ za{=s-0hp(M^?bLBVEO(iZEm5xLmo%z(1&~2Y@6B0NPA37RtJWXVEkw>A`ipVYoHRA zrm`HPX0s2<>+|>RMl{~P)dxWEgfnkaMD-Tot9fpp-**Ap_8I$+D0&k1tXRL;q*d^J zphXWzBjoan2??=SmIrcPVbR@M*P(4h81UmawxnBML~4Vsu)8e;CEuY9&`me7QG7<x zt!U<0Olp+q#&e+(g8h!?(SSWz*IGwvGT~Kyf_#>?HdJtcAs$Yl3VQooN7sd7oY*0g z+Mqlah-_voj&ZNI%$d?(t9yR57~Slx(XwF1&AD(X5eOxah{V0|>_$17Pd~L=g%h=@ zbvl*i39$%*5uTv8GqwcV)F7=OgpGF;1J1d`ISx#MJNeUHMx)#g(pA3IRuJE*r99yk ze!(z79wB+Z+5`3pz2TPoMzpQDIW1R&NR>UuF~Lrz7>7I=m{gLafPP{(X$63XTo9dJ zJ%vPYS4oJjYT>}P;MbN5m9Ivj$YMJFt810^@ib9thz;u500>l}uUCyTY`kcd<ph5F z*n%dj0hXQh<;I`(Yr-VL>iIO5-g?W4oT2c&zcaW$^tJcZpbip%EmxMal<!&+7GhoA zYA5|**i=2335jidXexlNAc!LHsv7u9AyNvG?jLiuXrnabu!i^pUOLt*a(B}OxjD(X zo=;~n7b}rIC>IP8uz)=-QW%<6dw>MrXJK}rB2}SEM~lQuh-{Y^aZC^gUE9Rusk}%e zTY&33uoMHRzzD4E2U~$+4I*}-0X7vI@H)!AR}rY=%}HSHdH_2TndK2w4{02QI>Rw* z1mZWlF=Ul&6F3>TaZ4rV-N})^+<_pqQNKVcX>baI)Uh<OBx))J0OMV)0Y$M2T|3qn zPz^$vW7F2rCc%(AB4U&!1r=R992!D9TVNAJz+FJx%w{K}i<BmVuEA(dFF+Dxd8Nm7 zX39lc0!i#)Srk)ngdR@?N*BT?zL_}~0Jfe{6b{6fKo~v(0LC*2CyH<HYZLgVgAuDl zBQ5OIosur<HVTbV7KxbxO?vwNA(;qg2$IAw>}muH`33b~S(L$^NS%k(OE;z^g{D?5 z;bF&BdXZAXln3bWTTypxJ)@TedP*NeE1=BbRIeFd)+$XXwEidpl9z{AyTOZvF~}Tk zwyTWRP!N)6%Q7#rr<hu&;{#eL<H<P6mi**1rgt`#Xy9n~E2+42aO16+U4%GU;AL=C zVAfpkD~?oKY*siGD5u=q!EGcC;ROKRxBN>7)kd_OTP?XsiEouMc~rf|kt!!fh=}z9 z_a<u4)$-K#zgPoqK!NlpkS;Jqcip~c6jS;nKL{6f>g=!abA60_dsb$$!CCg=ictzq z-j6Eq;?t#s(R5bb-MA7u!khG#CN)Y`DvQm%zKji)s`R;+v1oN0wcx2*JFcM9uU&W2 znpIKz<mN0USA=IT84QlHs99<s$<YpO<byH^S^F%tbfp0V(h%D15shHLf)Yfs-?!>X z9ArJe*qA{qUC&=Fp@l0l*G!CUbsicHcry;&GjN0#QIJifgN;K`bem&AkY80rkV#86 zbm(YZtV`IQt-?z(k%Y09;wAw0Kq+;Si8Y<4gXy$<Dlkmb;M8-lTN5c{*fg?sk(w1N zdSxSA^`_~vvM!9us8fMAsVgy%ymwuK2i=yOH**82UDbEj(?;WRc5<;E+8qcmvZ}rB z1ZuTf6yqUJHNb^C(G=}lpn9-Vrk!3X1Fa&)Gr6dBbP1An7cVqxt-{=-3f>SD%5KvD z(?=J=COi8Ls#yLK3Hd`d!~4zwYYm}k9@!{nA1ZQM)@<H=B%b7ZPE8|q*I*ft4~Mg? zhq|7K9ew05t~Op!iCnb)T-nCpRKJQDtQ<tMHTX~vS$0*7?(yz9eJXeu3fyA+q$%I& zs(fJo2sF|>^;C3V^>zSM31At;2?}a61IV%hY38sl$}mwzDEpY18IVxAZA_@n?Z&Ig z#hHZasT39CPt6wIQMJgxCI;~9e-k5h0QpE`TPG2dax~jwV4i&RVu0`uEL#vwEKei3 zHEX+d1S3+}38#K>b?WsTW>TqXDOmvBglY+N!;QTm8_Ut@Cg5xlZb%t#;w!}KNVK^k zPKmvPR}USIry5bT6L9FF@g?U>?6rc*NhfA9_F)GphK!%3bQ_tp*diCX7|SJ%S%EmP zc-4bQjU_M%XvHubI@GYlL5VQk-wt>Sl2rfKG#U&&VXr{`Q2*HZWsJ2{X~2R|AZrZ7 zMmlKqkqE(Snqf0BT9ix1m}u@*lNjXu*?+{!Goo9Ga1;=t(PW?Q;BV8rd-Q+?7J-bV zs|j{#ngkzY4+>J&0woPl{uZP;I3Iq{a%2M(X=|F8r8?~y?YKbp=2YUR(<IzH`Jv2m z;YBg$ZSZ_b4}xpSu%37)1cPzlRN{o`#6i{!fEJ|vLmzU~bli61DWw(8!2D2jsWDzP z9JMsBhfJzznLuK0Pe4fLO#+^dazN<<A0&lT)t0s}oQ?-6oCx+o=3>z?r~!!|$PyI> za(ci323o9ZcyBpl+?p^_49{DsS$<HB>9lV(7-%Qt+i{PT>ywG>?Bp+E9RNIy-*MgM zN9AM3G9!8!(+0m(aoME5aXaLR-75ylW6hHjOx4H|#=hYqB+=0NRncfe-?n!*tNU^X z2tl|o%Zrj`)XJwbHWmQr)wX<S=7TnSo+|WbjFvK!c%HF)1-m|DIOCX&)WS9@fLEm6 zD66N88l}JvQ)X6ZvgHg|<bMr8O&wrZl23%xt0brJcHLS+nEV0qKr`oV40W3+RwwO` z4<pCttCrsP+L6|kalC?kJZPD6UNY{f+KrIZgI`*Z(%E!WgN;C-0091mlPC;HcczzH zrF~6OS~Crjy^WJ#%C-m)8MJJKX6$o&te0A$?x}$&NErj?(+dcw>36G4O?;fo1T26g zg^3s!bV^jGp-(&m>l54pVy%LuK|qpv60jOU3{!MEQg6DWJ}18%hj1XA*v^REGSDwS zH4`BNgHd5I3?-)A8t9S_2W_laX~?r85vmxV@97fzW6#N7ILn>4S|@=*<;{s(YvR^t z7=4}hZpeHmlat(M_MK;$efGQvbj)ZS7TQ#EBjso4Pdi1RAV>>{7n(Q5)HkU1O81DS zX%~1ft}+z=N>?MN@D+-VK}my6@Z+bG{>;0lo<g(uQqrF)+gKC0(Mpeu;(ZGu^hoS! zQ>#T|eJq-WiDwBjmN3&cEn!rEx!PB0?^)e$WF>K4G%L!;MDs*+!%Xw%9&uVOd~jyE z*Hh7$uNLbmCsKkMcVt7DYzxu&{9?`Md^<Eb<qF$OnVq<_8D#+{64cTu?%sDIrt^*; z6G?JxU8dqZm3V_-t?*IEc*U+&5s=ib{^6@Q6JO~8WA=VY{BB97tjNJOUv^pJ_AFvU zi6^H8rw>q#?j~d`%E^c$9;~yh7N(;v_;+V40ko9x(bcJe&SO#jxv!{&9^?!-Ur{5t zDU^gvOo`0y-Nu#jyp$dxjZ!Hbm&#<pQM!ICVp9k4$Mk_{R2M}vq6mzm84Pp@bEL&* zDRzHw^fnkYu3SAjXsUThs!3KS3wD_l<BNV5Y}8EeqSD>ybJVJ(5GME_NbxTWgCaH; z673<j)UoZDrbIs^SN{r}!*9b0xOZ(z(5V~WMobD}x8Rwt;WK|t;Sgv1>a!QTc6+8? z!Hh|33YzqGNPzfMwK(=JlbQpH%s(PJ1bPc6HlZk}GBdn(4WogQpw^m5!Q@}djv$2P zZ_d%UVi3&e7imCRgNCGV1{l@&Qa#2E7x9cDn8{hI%_SZhDUkU(57BwQlUb3PF=$q- zWKG1kU5hZ=l^-U7WEVV*{>Eoow~&OClZ(#lkB&xrV}Zl*X}1`Xse!bMjH;JAU)X~~ z?y2XtO1AvQKCS&>VLz2dV;}Eq7|eRpLI)8>l|1_^6efk59?`ToBjxa+i!>|OKT2E& zWgb64;o!CsF8*jNhD@iI%2_>TER;t0`f(164W;3Wxa73?VW~qkq#X=KXHa{-Kcs@p zsNv9GHoJPEMtuynV02opLg*u=my{_(ys6_zU~v_s#W<-rOUOXv%JBoRzd{jf*6KRA z=qsSm#SLMu@9FDBime7pwz-$89kp;Xpp=pK&s!o2pfFJmB+_GWW&}(OaBP_Y@*xc_ zqF8q*K<!6r{92U*<5DK!t^+7TAG(cHC+H<xO6PQk9W4xYZzt@Gr#W780-bT!op3-A zdUF5|tOf99KyspvV^q-1PPVg`Nyd2HA-`+x<9a$0WfpAFs&oRsl&u?NV(CFS@~T~D zr879m<q-xe2m*@F=zt;0HDOYJIreFj8GzP*6i1ApYyh>vB*h{u#jzLA(s0wo(8><_ zXr6kypF^<s-6NP@*{h^I!sl`=V?3eK2}t?0@KXYm;%|F53KqA$WZ(dGz%?z}j#hMB ziK+}C7zDB}C{oKqU2#0N1FrxUz58KKTO&-?)~!=wzXHj<0KV{ieqSTt=-6Vusz)oN zgO14no>qqa9s@ozXm?)M^D(KamuxA)+%7RCL6T`)sxnpG<!BzfYN{Hb5A0IQ#-LT) zf=CS?fU~gIy1AP}J;JMLsR0VLKj?(FvNmLc5H_H0GCZ|b(UfdoO3sbI9N$QhdjgW; zPMtV!2O)ND+S8~EDRW41{9e@ae!S91$fnJJIkH?{-mSsXe_=>v@V?1`>Sn#VIHm`5 zo|n%QIW1M_)L~&R0^_TTXWNAMO$VMq84=hL6mYeG_2?8ph~|nwEpOl?LUKo8U7#2f zbkBud3F?eQouLmE21Ee(N!3T<LoWTUM6iZ9ihCUaTSRuQ*qlc8j#IBR$L7Q{Wir$V z!tE;yOQBWvh_Zv0)O^T>^~(5yoLy)U$Eb^yIxRctNce`SV`kRo8&GwN2FC#(ursp) z8Be>Jl05&5=J=|RTQNN#TR|<8!lWYIq0N02_p4(ipJn2iLrH3ij!Ih19@{{^;YVaH zRmj7;CK#8oJ2mlVlSk0;vrp3YQwww<N;p`d1wEVB4`X!87xaKsz83`{FwuUJ7OPs5 zLpdf>D^L4QMe#VV5*O+tG)nNif{aiz3=GehfM>zb!@2lZb9nqAL-FWGSqor7@s#_R zy&>z0&*ylyv%9o2fIcpWIsbCuCs))++6hY1h7{+fYI7kS#}Lb;Z<BVy#eeMLkN6hG z>WOu&RbTnWhreWDl(0o=tJ<1fP0>XK^<%iz5^;Q?o;UlXnEdKf1)qtD>-6(9*yIvR zBFg^mwDY{`YqAx^ujT$!AMetO{Ia;-n68R4)+uQRg`;}9x@K012GPXugZ3-mPeA&N zF(qj$f{d0?t}pI0r~s?_QQAPb5Z}v`s8TYE*~phwc5r-F_rQ1Zklrx^e2}Ib=XeRW znf*KfGQC+JYrLncO6kdbRdr5kSTEM+Sxhp&or6UV%(d%|%)LmbPlH#(B&j#8kxP{- z{yLvYm}b-TaW(RjvnLcXqLWF;m_L2wS073{v9r<EY8<s&w|njh^Cd;K49@q<5pAYm z5=kZ4!SuYgodTP{*r@@tXP#_+P9s2!kaE-O%Hey0Dj2Z85^ki5)FNlF(J3!%Fb}$g zf<*P9KSe{dJ8J8TPR?XGxlV6{AHqGjgcyXjm%c~tc&%xB)Tx^FN2eGr2&cklsqT%& z^S&bD!cfq2K0mx@6Y`D;=sG&E`a=b;hcr;-gIegGq6{*s-A5&7<4W~UCC!9rw5t(g z;oRF#WJW}sLz^I0`jP3iL3qn4X%=LoKIS6V=F?iL@1vyCCdA!fYMZ-9mvPSfOuLQE z=kCO^f1*gYPhW``+pa@9g37eG(ma(Vljxg*N7d#LKFY=b7iW24?Y6Z$FCid~s^+dv z&)xq#?93+QCo^b}xJ3fiB;c7m8;L?$)%NTg?wlr$nzgg^SyNkH1ZrlZsR}MXamjpM zaH(Y_Lmf(wtguSjEMHnJ{#Tv6nuYwTBqtFiHCZ3{Qqb><ckBq?rwluaO-_a9jT|b& zyuVl%icw`f4KUiNCKBM>aHJ$?pN#dTW)l1<`o=3P(vY*k0-OV0@bx^b${lvPODm24 zG>u}Kxt#X_vi7QD9Z}3N_sw8KL2jqzOg(bd;2aY6Y3fL0jAPlb6OIunM(Lvmz>~M4 zQH?HE$CJx4kkkkG1G^#Taiez8KXEWPHd4d%O~V<ivoOXQz`w{(UP*I|=WxW*?W!2z zANNUp`DH+?I5XuP6RbOX3TMtqt)(ujU(li1VR{XRt?$eL^%YR;fn+Mt)#DJyh<?=f z{nVESs&DJ$H|t8P`NLCvd=*$QHO`gk=B@VFHDiV<SwPh_rt<(8q1rNa4H<NBR?2x{ zE6i}h=d{?t1hi^QL`dH86S)(!gkW_`bfEy4d4!}LeW41|>D=Z;7a2i6Ps1APxM~5s zHcV!i*Gv<p`Dri)hW1md@7Ky_M_K`+sot%)Rz87onPmuSGA3?n8s99)MOM8to<a6` z&^I4wwP{TkVnXtLc~18gY=QMM#SEfCtcpxI%%LF9DoS?F9B6p?jrHZCK}}Xg^6zz? zQ7CXiQ3kTX1jl9A!(p(-bSSR7owibgKcgF2k5*xxrrXIS!<$R7!&?AkoltAMqA=O= z!4zifjv71Fka&&Oqou-6D2y>qV*fa&9fot_gw@Emg2Z@VlVQ?P^ue{INvP3dYfwjV z?ueQtRKvP<?y;51fc4q8qfs|+ji)i1g|hT|q{d31CU<_HD(xs!tk9vJ*`m^kfpbx& zTyu7W=tLqpmSpdHXNvd<1FbrSd;NH%P5`zB3a(n|a_)`0yp(5GCrUEpt*01gQSHu= z$N&WRa8+fNXY!V^cab!vO2r$I1CiC4pD|HtUxIas_4)W%vlA^8n$xO060*Y5qZjr< zRQ3+db1XW_`r7N&fHy)_0cnb%6de&~$*|~P?2%7&Qy0(kR=AarI;mZhSsdV$0P)>b z4D_kn6}OVNSfrI^3E@}mltO6jb-^f`xV6%b=L#_(fbS}RmWy_T!zPBqwW?;ZEA#%r z$3i{M7A@MsivF=$i%rD(K#~CkFlyGca)pH!8I?Ya0WNEhlqLH;zHkOoh+V1hu2sef zvO>2PmdAD#Q%B_?Vya6RIB|qqhL!>lIC<s&iYl$mZPO4OU<u`MgwS0s>Hs2K9JY0) zoJ}-N#8#T7Xoy5d!{T@x>v7JOgz>WBlAcQ5OeOBMc1NYfA%?`rFIy(F4a3wBQApHS zOh%n$Wo=>WU`?6o$V|jD2-D=zFIA5Ew0COtui1cZJyHaGs_ogmGf;C!pAJLZphmz- z(57foz9`4zMAKhwAJm^?y7Qc17dX4b)gZZkwIt^VlNG2m9n2JB8$J$D0r+KlxLTdS zw-%(<?edp=nw)ZZU|!}Kn`{SKHft<XR`nolpA2gf)X505#Ywl6;jJDr1eXZSn?v5# z!kU|-2$U*wPcp(g)Oj2(wa{AD{Tv9lhr)n_3l>2MZrr=UFD7`h>|5E`!H4?;y}cg* zReKQ$hiegAKnzr<$aI25*K3L_iA`8UD;A7$lfkW=h@e&LowlJ=t8TV+S;~QuRuILA zx9tX%b|OWQHc6C2um&8xskKrQvMQy|WGIDG90X*l8BD4z4C=iga<!uJTi+LzQ2-jP z!GbGNK}1WXRKJHs`FskiMTR2Jua+2CTZcvB*(o#viLPn|SKQRewa#e(R0!&%AqE9# zq7263_Xs+-ay0#j_YsVuF)T0|qYA3vLkpqQb*O4@WJ5w}0YRz}ND5uxRbwqmhQ-QM zn$S*f05`5-(<C)Vp@=p;X{e-wFFGndnu;Ouo}TF~X2{&pky}+n+dx!(LKSK@VA!vT zL7|%f!>w*A=sIrHzG1{zhlMJUc>N27;@7@=Evo}9OxZe&@UjM0K+^XrJ}LyP#ah@- z8)S=Ehawfi3e55xxW`%|b+l^AF8x9(amvgTL<(1ew-Cpzp=jx&%6cUxY1fVrwG?1V zCZBaIip`lNT~gOrcy!CC{Rc?9kj5!1HLbf8WK5k@=y@8IkpZh8>j;W?{akcX(i-;D zTu5SGaj_`GCt77hzC;4gqtSiQfD0FrPj{O>xpbsO2JEy(1+2K%#|oIKzdHe|k56nY zn<Zvy_HHpMBY5_D(fSHqu^tNsG;Ms+)(`*{mkH|`Wb7XT=j5~NWkjSr&4x#;Wq|V~ zTGjuXd|jiq$ML6ZqG6PhG2|itkoeKG>|pjC^|#PyC^IDkor{Tpa`7t?5a-$Aa7IyX zh&PaXz>h<5-G)B-B%U7Ndn(rki6)&5jWtWN5vqBJG9y8&yJ6kk!`MhYR9WjHSm+gA z)IP1*-)ucK03}1DUO+CQq9j>1-JZzQXT{+J5<<z4P1O+2i9@XI;a)_hQP$cdSpX{~ z(V)so37ng2K(2wV#^eM7h_DM6b~(HT7oW7PxB#f>zUL$CMPP)9%eDs0jYmmRJ*EcK z47WLG*34}ow95ZBhi%GMRccl<QA8)NP6I%I3AIk}X?+$X?Ugn2s}XG0JBl{0MIA<{ zFK#oj+s_xH>ZU_2z%k<`ttXMAbH#5=rEyspaSS5;jLo!3Cftm~;t1eDmIHEa#~lvb zb?yJ5lIjW!5uuDG-h*K(!P5$XNd!}Qkasp%j-uq=39?lv<ofR^aN21WshGC6)@-P# z;Kq)r1U%VhDjccNC(W{PWd~0kFRqeBfB*!g^LADA_ywmkWeo9;Uj||c=Hs1em~z!^ zK)E8&c;~Hv8JpLzs6T+)BHSDzSzNj>pa3(M(P~jHnn?@WZXo2cL?^5p)G^$%V>qD{ z4HoNa1rvEqXz!Iy8`!ClNEz6u$`LMJ=&`!TJ|j_b?c-Ld>4(KT3Ill{XV`2kX;VHm zNvIQdj9krwyI<l$Ty*TCDf#w0M51{()`EJo3LgQ5$x5n>`A*e(ax6&%0BXN4UPs1& zs#sme1co4VU7{<J%(KtcW3?W;kK-{*dNSRpfDAGBX~#X<#S7)NUmY?hr2VZ{B-!3$ z1FTdprUtl+;@~AuOv%!_n>e=7lxo4s>Sz|oK^S(*f>$8gwSx?+t_tHmcFeT1b_>+G z^4Kw91uN$7j182)8$|JNvyRPWj-K(jMGfw#$<PjDbo+=3q1*__iRu@q!4nFgD_WFG z$FHu@tJ~?2B40X=v=?#&um^DpT(LN~(;0$9dj4}ycLM>W{281igDs3&DL#cgW34X% zba#N!!kGvg;rq6sJ%E%=DykHEYTO8QjTD;msFmh5Y3(eWjy259z|D{3msS<18!*Zv zAGP=-cfe>Ltrm*WEsz8Uu6*EHhpM2V0)-_+Cwd@Qv#y}fs2fKQTcFW*LUd!iFl>=? zl>kX4Rgt-(2}MViaR(AQo9M&|zBa)wm(CJ@n{z2x>>=swOKOUNWdSsBms+XLWH4K? z?e4T5-o!@Kv?0$K)f|(rSB7F+&te1R@jZOXo*tfR^*@WQN|r>MQkhA)qVQkh;FOh* zt42$Qg|L)#IU5~x>X?c~5HGCbFD$Kubh=flra@wou_x4T&&s%Qq#Cr5nrRoFFW9Lv z?`vpfvyLR;<Cu*A@@e&N#O%1|4ggBMt9If)Ro1C^6q`joqgiRC(gsITC&YU~3{+y# zq3z(mzyJBE@;Xt+<ZDIY5=BvuiVasoLirp((CT$WaK;YqWp)wle30}A6aPw)!92J0 z1#$_{(+S@9VXo1Lvub!ZBJB)oRD_0?ywE2;S6aO}o_SYGGH@ESc}pka63+3tbdIoD z#58{-4KNXV7oyXoZgE(lc`zdoo0*-sLgz(e_#;`?n~HVu0BnI44G~pjL}~hq1R7c{ zP7F!_wNv?R{SaNAa-G55<g?{SJdq`cvmksYk`Bqs+a2EWcuSmqFwahNxYf5ivT?k3 zCRPg{lQ7nZlcF$J1!;A*;VGE2A<=~<QouC+S4W#HymDqN>4BVW=O+GG`Og5|^-Rn{ z{F9bQTbZw~zmFs?LSqqhLjnwEen{@0;1WV$`BchuBn=4yF?QgaYT&KS8+d^bg!u#Y z!q9))pD?Y9xAOUk=wB^8U8ICX=@XPDKM6#x)`Q=7DL3(yjiVgA&E$PrHZaeHT@+Z? zHm~YAXn4rCG%N8+l88d|h}>)&+U=5*Z2!?UIt$}OvHzY0NV6TKMokgIxxku1j`}>| z#(TSU%iL5%hW<HwI6f`58%w-Qi@~h$HZ|Bx6?-TzYLU9rV&7`U&M`8=R~GqZmOp)_ z&%smH4kZlj$;+53WD;||CQ!wyi-%`BYV`Kn=i*ViIze_b4~p{qViwEwv2bk$EhfPj zgT8G&aLr7Q?Y?ayg<XEAeK<97kWI6)#v?nlNuPe|bLFcw%g?57|MCg9$+V1v6VzWk zLd;m!`-37Yd+pp!+h|z<py+kX_`+DJtm+=6{4s%N$uLO2N$ZuAGV0eC1c{H-K6ogR z5DazOg5$fj1__B~wse5;dJboW4Otlvt@h}{-NAX6OVpzAEq2;jU{l0DXw@R!SK%aL zC#i2+A(!J-R)I?txhU|hxYSfNmw?h4;i)X8im!^M7~=`ccZK$*7VCBb_;|p==xIki z>+#B+Ns^_aw)O6<mC+W5he%Sb=B*N$gs-GLHKK6>d3X)3Y4(!Hfp!bB8u@-R2TP5C zc<GN+s9E(nZv#|a+e%5w@$UrrwtCdj@h1_X^|bdlYU5QeQnozHoPYStUwxxqg#rQ1 zNvRVCl_6uOmwV@ksp_RKN*>Jd6}5tCmd-JKPr@<LZ(kNZm3b&WMFY5tX-)1rwidJk z56^*2VUFz+zmyKOY38jqSie%1By;LGs$0TXc2Rie+!`%z?~O#DOD{f1roNJ71IX~w zJ1^MYa+5O|`LZtI1lzM3g@%rkQ+7Q^%4WzY5li0E>Zn{T*CO4kJMblAE$?Q?fh-!X zn~-K&j$^vVWocriBy;1>S?LFsL=I)6*xgc68#4$7Ngvq0znEv=Lg`>@cD!<1OY?ub z?U-zDY2VD}ePs!!iCgO^%6SQj%E+dhS6XV;Qjk##q!7<v6Ii;JUevNHxqx1DYk7-r zBHUTPqC+wA>v`Z2@))d<>$)Lwr~B>Jsl|n7T9KC*BL9vUwcn}KRd&N|QD~$!2L{sv z5oR=km?L-mQD9quYBH~OAe0wG?^h{qM2d?GOJe;qgoR+3WGW!&85pD_SdUy0$hbdh znvBS%;;MZ;p>qvf8@mEBc?_3mMp-{5ES6L09UO<L*);d?(H(0+)<{k`hCwb&MZrXI z+0jv)T4R`nvizY$Or{d#Kxt}kmO06zU=~FEEp7s6j0v$>YVe0iOy(Yeij|CCmlHF* zj31ix&o<Lg+ETGIiiF~a0iho^F_}jb`-qhQe_~vBh+hWl2u+fnNvHR1&$QygQ!uPw z$FoIP;TuSfR_VU8n8eW+%$KgpC@uK(G@qspLqU<RxA^p&+9$<_6E6uNke90Zya}S3 z{t+RzdUevFa6E()z0)e>nYxt5=qUqK>nh0wO%=2lj7{uq{ROj1i5?Q_<0Cr>r`p#u zb`fvF$e2qX!mhuum2V==d{iq;Y2wC5KAup!A&pMFf4Il79>JW}h8Y*4KB&nAJ*R9) zB3$lHHW;8rMwMBBlAykkVRK*PWT$X15Ed?Ecnc4Us41tTGx>iyQuH>pY?cUFNKmXd ziLR5H=g6>C6Vn7-H`Yj?;XLX%6c~?(5V@X8(PI?*r^kKnzNB9=O<1%pP;cExdds`@ zW(@LnPSXu&5;7#VBil`q1ioNYv;OTPR0EcrZKV*}PiNa+1Qo~t`gNY_QfTvo#4a>o zuuoR|@CMVZt*v6wX})F}gy$PdXDb~)pGc)VV{y6f>P-UHF%xC7A>-Ay!lMV<i5++( z>ItY!{@<on=M6_Y!Xm(@4!QDV96e)~np|9c1-6eXp!;GpnO5mnoEysVd)m4?yY2!e z_|sJLo0+-;goP3-#4XmKdK;1X)CH~Vb#DPr90rp68Pa|V&3jpEmFbL&d^j9?tSdnX z&PY3Uc1|FOfl+Kp3k)2>d%BV!UbTZIi0t`N4Y_H01{1x%&GeCFO=o4240Uyh5cpZ{ zPyvawqt}VVCd|w3af4BFUN;Vl{=YjAz<|#6zi>sX2|Ct-aC-1~0XX3Rw2TCT$wl4X z=Hh*#a$6a|M?kfZzfTeqK1MlbmHw+Qp80XIe^DCkE=ClnX+a8pD-v8SstkA3DDpui z+Lj<T{Q4_XR{nl}`p_rt^^w*B!1U=U!7OPVc*v^?D+x7!8P2|?BE{wJXP$Y4K>fD9 zp~#G2F)!8UHXo&J(xWJVzZ$8D!RDU0+tD=FnXX2N<F&|Y(!x65q1>o7$hoKdIAIF# z=8(odsDn_8ufx|O&Fu8*LKcNi*fm=oc_J=$qS;)$MG}-j5)x;5`(Xvd;SG^z4F)V# zwq3<n+R&uMI!)IWXkmzhgRs`Xs0r!Zdo$Of{Jv`yAG#T;3^d`^mz>4sd76!;<h8V( z&BHB<yz<}TBjNrus4GGr(%3Dw*b?x~V*7R21?s~x&64%yz8nCRzpQSSW%6ongTv1r zHe;7bm0D_x9Lz=9n@WhVgVSIl=HX7N-sCscIOsz_>d$>K^acvw36vO!AICw9m4wF# z1T{VVqsu;j2>g-etPQYXm;6W7%z7MDz_7^;|DA!X`_kPoh3sY@^~w|qmGKMjfmZN= zB4E#H9dc}{NP=M+c4oK;0NK$k+;o;mIb}uv%+>OBEmNv31WA#d*kfp-{mgs>7en=9 zIZ1Y>{N_olejDJ_9S1&L*TFn)X6p@<K^Q@H$oY=#D62cRdm#Hu%U;2R-6Ez!`wO0% z9h%K#;ivIsU;EKJo5qJ{Uw^At2|w(H2G_lLPI|49K(B1YX8UMYwbKnK#Ae9;5C+;c z?O*+!xy(?jLCviL$xJV5i2T5ulT14-+eN4zEABo!lGv>cT0+;&^k}1Q)SE<T0jN?h z;Tv^8<3Z4`rh%HL{6=$(gGa=Ru{e_}_4;9PxfM|Fa<nZ|pCB?7?vkQN>t3C6h&68N zqiA&xn8*idI^m~w&PKy^Xrv*{>s8LLBTO{VrG0s1+I!VlswkGyH%SvdZ-Fcnlu6+9 zIt8p_0&4?}VAT28>pyU=C8L&2WA713!itR|2-u?D0dWeCv`qdHgX#wX<t}|n1@ep1 z^TZ3HCR#Kp&nf6TWZ#FE3hz*kFk~HHzpbp!FZDtuXZ#HfB-{QLinrtjnPv}9n5J;4 z;<M%~RGT~IEZ2{}%U7ea<eA%x4MhHJ*W~ipjvTSa3k>*qp*Uic1SHk4>wCx<303C9 zg-=Iuovrp3>(*p+>XG;#)A<j7y;l&&5FsQ+eh?~iaI)yc5mHXhm;<EYe*Z-5pdrf& z*Ci5G1mcgf#?L_v&|#4tz-SnmoSDekwp!4V6c4~&#(L`clSq01$ebw%u$Q>*(RwLt zljibdiQmyJMhyGaF`^?sXf(!{B_F$xpJ{MQ?OQgIj*+=lTl018I)Q38q*W7hw7vPK zPYuoj!$3H&0tSG~<EsRF0Iujjv|?JGw?_4@L%8Q@Xjj6ZzeYPN@ST9$Y%v4@&l<AZ ze&HZ~dZ=Jio`p>;)61pq?X*mt6GsHUyP=*4Rb7RwvWFuY;3ZI8uz4x5`VXSvyI74E zJvg8&%DB=?vdcMdF&1)H93xm@lIV(Q-VNt8=DiuvfpkNhJBCCIQg;GL&31m++b~jv zD(caaA-_O2uMdHsh6c5kM<R_H%Liy-I*KAi{Gbz~(%bCMH>}Q3C@v0+{yXXyW_^{Q z1Md5v#ZuQ4NCZvW>^{4DGE9S0;gzoo%Dx%1t&k@ODv^d2mx4Fia|eYh5o@0)mj8SZ zfEtq8=t-`NXLm;^iELu`c13CJ$vPU)+^Kk6%%QLl(BGBMM_y>I-NqpbkZ*_ll`)Pt zr>&4lZP!UOLqXyOqysB2fXb}(BblwDmX==GR2u(at01j;X#WzC(;{Vx#JuB<)|vff zhDPB${u+2>4$<QU?31G4-{C8}wm)f?QQ)Hu;A8<Gba`h+ekxRKRU7!JaBgE%_kiMk zjUWx!uGUZ{(mH<AYhXA8C9O8yD*uj=!)i}d^~NU|JG)b*;#jLjwBn_YY$XmA0sI;? z^aRGoM-*i>M|5i-=QOJ6i47@(gsT2X)h&EjdV)~g;u~QFJplpeo9x35Ht(bA5Ad-x z$;CrMb^67aoFgyt(2nyv{_Pxhk^w<RTl6RS_Ubr16WTu>(#AF)di=5~m`zi(X}L0< z@lr#Gsz~iOUV+KduP~gcJ)i~xE<zUIjN#XHWA5iVnUCjzIzV=$L^^XFJH6A~azmI9 zKG}tS>K*HUhYTU(WCQN<$ROBFrQR%=kYJj>0hMG~XQa*3<!btevPEut4{?_GY^&hJ z!@c|Rv9hG^J(6x5s}V-a@On|@>l2fdUmIMF%v$Y%XfIurEe(|4AFoB?B(a@p4(;x- z%#;HQ*o?D6-8=P+8qmESkY!F#RQThNz{77lWmf%fX0$p|la1!<wd!+Rhep9iS0#=e zFb_Q5D;Rn}8<o%i@YajNG)shLhaVOuiH#Li+*aL{NxSOC9eY*6fOz2`EqDv!#4NFQ zn^3W=yBtE#VhkKtbs%F3bK|Z8;QSOB3+g8#!l(gdo6e*`^3^U)KM+x#L)|K;#r)4b zb+YU)#?8cOk<Ox2^4wO!$h`9}MXAcEmN)G?Vg7I(Dh2$BaIE|-;duaKk5|?^<opc$ zx24vARC;D(cxXI+^w`GN{GcB?nT6F2e08+^Io!@H?3X#3fk}T|r9~))Rwlj=;7+T> zOnr5MeF%|#PJSvZ8-df`e^fxc-!7e`0f2;>T3h=MhsEJ+K8Yo%kJCgCQovQDs{4r? zIvoetF_rEdU-2mIH`%_^L`E3@uTijz%x2;k&Fs}A=Nt02kx~ILXnAIVG2*(Y9KaHT zh|&(jP&$KYonhu5=q$K`^1=fV`#c=SlBLbUQ9TG;h=B-s<TJx{&_gPK6n;DMNB_M< zC61z68dzcp#&D@j;=U_CV~Usq=z0-FtAWs^Im7C2(0D(uRf+|>#JYGS{4%vwsxIO> z@{H=W&TKP0-U|x@w$-DoI#y1=L-DLwRB}JH``<yVR8Ek1^M`0z2~=UzS=UvcXohI| zrDY3Mt%9WpmQ|;h5~?2b9~r2rGHy-zDG#C4B$2#>ghK69J+b|FP~UO#+JPc+(p;cP z6tvNWv;KHwN4Iwb^rnp!4d+Yn;T5j55u_or7lxYyXzAm%!3l`p_QWnJytzfMsc=yH z^nN51@ecTu&__;TP*MaZ6Av|@%?F8B!N`y_Ge-rM%elW^k2XtS)wV+CdV@U`ODWA` ze0LVqTD1Cw)-Xne?>r9DMiS}kL0J+Z$&aCpyKCpHo~WqI4I9^5)pm^DkO31xNs%0q zKw_%&hXshOQLgn2fP5liuqN@zA2v1eHRrAIek!&SVHkY`k{4j&DgN=*(6usGz^RZ% zJ3Q+^5+Ex`y&zC>ZdmbLJV^!`@e=~!(gJ}LQV@_c;`mj<V|Hh0uVB!)jE6YFwbdx^ zs7LM<sIT-+Sz`hfAk)H7FjQQ&86c$pJOY!;L|ONGPoh;(K>k8l#)%jYGtP{w)8V+V z;Uq3|j40cirO1=eF>{tqErlGg1KKH()*qEzq?Q5Vt3z0J!4Q=onHd)gUNnZ~Kml`A zs*BjWl2B2EmL)TR?EDLN1Z1KVhx)I@?y9DP{R7(lkcf*+@T&*nzrJH5vwGKBEo332 z$rg*4umAwgM19OtlQZR*Xzt)w(9tqZ?}b0gkWPgXZbGbxBLo7q@LJMo%(|g0)|;Wr zC2-E!LgMmin{IDEwld&JjNjJ=SOrES1=}i`r5<0RiPX?kK|ceDY_=s{q?REK4T*fX zU%Z=%)ugRAO60U#uo6f%lMMr3x4i14^mm=b2}}%eAAO+x>W`7o8c14_v&_B{3o-H? z1A<6-0vj-xQ{>ft;YejdWP@_p_re7ETFvetT~J-%tJ$-+yox46rcGb5Ufq{*8yveb zU1@xU3FBpONM6u^k94U)pKTz_yqC-rOh>v|owwRiV~*e~g1==fU?AX-D5n5dTndz} z5KvGA58p6RGOGNjeM3xNsI(@<r$iR<j1YETK|{&VoK;n0gJXxOV!`Xx#Cni31MN_B z2pCTBe7=awXH1GE3epdNk5uYMx)tIOE0)Qb90Er^xSs0=j?LhFc>)qt9r-FOnr6ep z1G~Cz;@OUa>PsC}(&d*Q$OaWIn^6R_V!ZIcF%i&*@h5sqEla1+s)C?#S@moWH16aM zQ7bM<U@xn_tE7v3d>=vfL?tK5pjS1FG*eZ{^3#N%TZl?k%qFyoFAS8yu_}@02n%bD z;=wa?q}*LJPddm(XS=E_l_}GuD8X2?-?MfgHKES4EBj}WU9mxD9KMIOj}!W!=1#N? zdEn1$@wdP2AcUW3QXD!awTJ8r0sqo%id?!PPy+BrV5hY*0bdJ%euYF3l3;SiVrUs3 zN9S)~3YPJDs47$-iw8q29<Lc}<W*R$hPd@oz^lY7#NfSXKemDiThpH{Ltmo;6_)(4 z2OBDkFdnheY-uty%VI;Kq*g27Wg7=9s~Z^%#lD`fKFb1uVH%bHR&FByFBh}3irY!m zssz0@AO$^yLw|2%6==24bI}Ar5Rfn#{hYA?!d6;B+E5^mz$L(4{3yGAK@H-S0?Edf z*%seU*><lp4pR74SQo&i*U!Icwv!@gYU^`Ns}qd@LturC0I}IUBEf+pVUu06{0r7a zZ&ZdUUXJ86Uq>72w(jIAIU@hWUuM|82c|AUKn<l=>)Bek6@tbM0hQ8z3#(7{op=;) zzK7N3D5w<?v3jU4Phvj+aeB}KyqI|cjr0maZ3>j&d;r;mvPv}QV}7{h_5fl*K9JLN z_(UZ{_F!Ax)f6?RaVG}q1=~0}tm*+#Z1j%E8J3Z;UwPXIU`I8PM6!QeCN%^inoi$= zeD(gjjR`?sL?CV$Bbg8LhE?}z44y4q03QWkDnuDZZhIo>a25Wnkn^S1*_iHVx}uHR zy*ap@sECr64?iE6454l>k1g`KF!PuqwoWgf|J_2eNVOO&cH(yh(Zj$-8Led<6sKXi z2=YWm9WM-~*^Yc|fvdH{8$!skn_?J}qC3ITD{vnlXW}ia9$zZ+{A2V`YJPj(!iYcG zqZLQ?SX=`ZXr7L4R{fQ4!!(Ds*iH`ji4t^|GQ*TOzl{I9N@2Bv90h9N06p>nM`H~O zL=ze%K$X|s@0dLTeBwhpAX3NxAGBAl0f~QCD^;z8iv<^0x!lsnoE%cJA}ttF0J=<j z@fcfyfija}5alb4rB-P#ynL(a?YT|45s$Vkuv{wpv3Fb!+YziY0=%;2v1U0$wVOo| zm~~!~oesoBt@!{hQ%}hyP$AV`h*D%CaD!sYfLUq<nAfa+D{uL6=2Hwt)mGnKmSEz@ zfi(%Tt!~DJPV9)Mf52d|dUA#P<;s}LG*$;nrI7$L{4Q9vm`Yr9Y>!W`LtDkB{mTu} zRO>I{Rj?Mk{pCkqotkapfZZD-5WHU+nv#$hq(USEt?BrYvy4O=Uz*4&Q|~r{h<&Mz ztQyfJ79vCw82)A2D&V^;K}{6|d~{_Ux(!W()}zR!G}+L%lnJtEl0nRMmlQd(u_n&U zGGl2Xfn1NO5t|oLS2WYh>7X?eBTK|@B~C(=-Y7W?gM*xK%%bcV_c%?#f`6SM-0yGU z-CUj(%W8x}@2Xr6BV_cKM#pov37*0^oJgT1+m(i}^;tD$cwC0dKH#*=7)Of8XbrN7 zj9NnQpAyN75T(xw_U~9$cUI9KJP0zX!WUaE)ZM?c#$0~s-g@CwVuEo)H;ARLIhj3e ztHK))!oU_L_`;p+CW8(W=9g`m1C?guq@1ZbV{$P8Wf)&Tb&Dd_Y**UozSVXSqd-MM zs<-wJNLlr|U(!TNen~P-I?|?Jcy^Fb@EajBq;`Uk1mnsT<FReH+`2ZZ49W1!V;uR} z7Cp;XSz0sJ=Fkmr+W-JXK)Szdm8d`<XH-0)sEV{Z5m9hHm2#sRGG}T=c+-}rje=(Q ztP=A_K490z&l;93d(}>h<GdT*_sR~jJMBkc#i68R<JH3c={|yLjRku%YmER7)lfjG z3jP=42gS?+Vu#wLN%4fL_b?>Me&Jm{28`88iig|M_7*gsf(?=}UCx2d$YWLGJ21nF z3C>P=^)0{x9x!F`Uj~_%%bqEdNxo{?ojU1mV`Au{ECV3%^1<Jk3gpj@oc`}|tMT<} zs*|E>7R*H4QJ7w_kIf!D79n@*jU+`%l$2AJ(S<8r0nh1?nux1oQ1V5{ZF1_ddnqK+ zaAnx;9T=!l@8@&<9>m&;B^7HvC0e|cvDV4FgeCy#uK+Y(_zTQ)CI^Wx_(XZR4shBD zrH;z~G-qGL_BjJ<n!tgXT^rTr0vLnQ*~J^1_$Q0wlN()(i{LJp)kbV={2NU#bPj(% zM<_Cue6?G6YE-(y5TR6-v4oX2gAW=*l~p}~*lNnq67edv2vM1sjKh^W`V#*D6VtW! zv!qlbV=YnzO3lu+5fCuwB@P^q-@4Dcpif>fXGJ*B=%1xkhkI5vPdlLE`l;M_%9%S& zIJ*f9@O6{+9tJK5;!+T2E=8Y@!Px+QUZh-W7gYgEC%{ZhU96dy(rM5;5S4*RMC!qt z&QE|6WKYU!u>qly9O?1s6sBgRdY*L?yMF}_Or@h}J2#tdfFM_<>R~bu<pA|Lt(HG% z1&B1f-i_OVq`NvF4y9I6JrmBw#B?3qeBbO4D;Z0Hsyt&4UM0ckZ|c^c<glW)OJJJ7 zpkA3z0B0qRxv&+rhC7)k|5rE8tP?ltpXdmvT(7;*g)f+-qY(i840W>lGRyT2%j;;K zBjZ%2+f%6vlKhXmiv?gnTm-~dkCH&(oa_P)k-zBL5NSyp3ww%8TQ*!Yw1@{5o}Ior zORk|c%S+1NtC)5IH$yo3g=LJdf@i}7<SD;1<%fc748Y=ps{SqL6*wG#im=OG%}@lK zz&|*YR;$aY-sq-wUaHM>t=yAIs9~PW`auU+_Oa=ToFCX`%p>K=`^k*V%^9o+i)jbZ zL+~qk4hwJ+J217tK*Kp7K{y6r$2=2}2OmrZWVY!3{T|4FOS5F({Zf0tb<|vJ1etS9 zCtxvihc5(y|HyYbLu+3EOf*yR7a!)mGVzT?%03m2e=~REj&btzV1<E9^=}q@Y}FDB z42Z^Fi{c)Xw4VEK_%UM49XT<XnAWh;RaBC1rHYg6hn!gi;b7wGcu=VUKq4}qx0u)a zLc8s+s$xgM1ciS5(q0s*?xSxfm&VtJHXKNtsjUS9$?c{p`ZIhgDkP72yo<Zgc@(*V z6{?bBcojbTU}fl^e@xr5IW?dYzJ7qY=iBq<s9!amdn6GNP9Rs&p811|&fxcG>NssR zVQ-`$Ip2U83+FH00b{k?)8UXLQFt2h;d`hsu_jPso>Vgb2NarY?*zpcpA5%=il7)K z;I7zB#u5<PXP!+T*GJnJgX{v30<nKZQb)_07XJ)dlQ6oYI-zV`UP1?I-kHsl`+8u5 zI$q*(rAO;p0H8!g%;?9peNx+wOVO5y%(<9+c2Z96U-%Wrpt5XBn{1&W6LQr+j~o1- zh47d}Nx`oB!_<izY@_g7nnR*7#ayW593NJi@tTN}_)5You=tE?hTQjlrg{@#)WJbC zdI%klLBGRZmgvBf2ZkvU6bc41z8?n?sx*0W8IMYzq3H2BN1;c2NRP8=N+qps*k4(4 zUDG&MWOPO(>fHaR1kN*AUz!%cLFia$L645-s(m<oIdv92OYq75kRN^$^p@!oVbAse z=6E(F7<uEtBwGNdWv)bdm&Fyf2ptI8R=^viL>&A`8W)U#K*X_nL%AF@jPmqD$u6&T z4C&-j<V#~maw0Jbrwkq157C0#NQ!e=K(V6qD$MFP63g!|-h=mqjWh^fFG#Cv40f|} zrM+OC(7%0Ol=6~u((lw!2&<O;{R_XpXT{&!9pL=+)zOho7Q6DzEvg8Yf9YQ<Y$d5w z=ptV<-vO*kJYMe0Tf`&melQFXA8tiK^&b&LD3Z8l(OTV^(Yp}@kI0e5`6mcl@o@Gq z7M8W(L`!?oJyj+~z9E1;*-Kcv_AXpF{YeuOv@w6M2f`@1JRT%(ABxN|f3s8r*4`dQ zZlzE(+ttA#T?Gcza&(uUrg@ryBduB}BNQWbT11E%M!=@U5Hx<D+KeC&(~r9n!k@My zCf|!nz;^5YEg{K~?MY+0QL&^wlgX*vQrIYOq#IU*gc3c*AiNdZ3u$icY#)71wr)mZ zqiu-H`5h)lq=w>Sn|H%!K??!z4@#^SynO_B>g;&30EY8?kz!1C&^j=)odk#-j40AK zT!sOo8w^jAMBNo{=h68W0iH3|fWb#g8!|B)vqHAjFb&Su$&r?Ex!;}t2F@}q%M4;_ z0GUDPU0)%+!gKh^q$U&nRRZ;SPoChH@;3cP(`V|)GiJkzx8LG1Waub@fDmqx5(z-T z7|~~2xi}Y=$Kv6rpdl2ixJm>Mfz_88qagsYnwb)YvouXgLx2IP5AbQJ=Dy!AbuF%E zxtdqSFz0O`PA9$)dxu*t0Fue{N(w~&Q)nke?8NX;G2uxIc8~Eh62*$F00N6!N6|Fv zGQ)esQ0!OQWeBI$_X)>l+gnm9NwfZMW$*E9Ljua&J2;$@M2XW29ZXfob^vfM6Ia&D zOhS96GeABPPRH5h*Lt&Lpg|i!Q-!GgIucu2hXgzAQv&=T4?x&K3vI`k625v5F<++9 zdCYJ$l|Ff4x97)lmHGhMlF9407Zusv2V>Cv@DGSBIb*Bi2k^6~gakPVKGQ3c#o&VS zCm<aK$*7G-qBs>jUidoI3&NleFG&@j+b3v(LrK8lW9Sq^sAYrKhfAaNp)nShKs{Y& z;1z(TqVi+}gIuOU>-`}3!Kk<h1fW90<gtjUkZq(uO!tB{%P1|dQAPkOzMX;9xDn4` z8NgR2W_*T6YDO<XQ$(uzTLg(sI~NAG_vFK!`1$~9*lR&7g*FBN`7Y3YX~2B+Dkud> z#^MSMX$~ggt)9WXM}X4#6RJ-~7EM;>a!z9o1<A>A=E@}qV8hu|6HG$^uqF1kUYR3z zb&3K)$|A+41y;y%Y%M|}Wq`W}kIUHwq!~;NG(B;8bvjs_<NyJWbR{!9iI<<<*4VPS zQ!g|nGYDGL?5@HU^O>PAn5DWuaZfC2dYdMNyE8AE8UMV!R8ToYH6?&jh^PBP%f~2K zcm$c+7QN1SJ!5kka|=diN={6aiy{abkX)uKg*B1B;@e&Jpdxwz9yHAu3Jj?T_r%a; za!|K?btDtC%;7uoc#HCh*0U#k2T6jV7)cN=-grC$9Dp|>QG(j2_dO9uB)U8#xR}PF zJ?^RiIzqV>+8z?F!5h{nFXD<LNpS!#C&WPPTLJeMueU`Ou&%5qR%9e9hX7W2+0JDY zkL-9V&TEr~26Q^wS9L0{75W;C?MXcNIKxcau3EN9+88u6o+36CQ~_)MWz|fw0yL!O z##2zl<~s>RdMyK&Y?}w(4>!}#lwQx=bb4$z3rqI-kNvcOvcfV}0vBmm?9I4ogJ0(c zMx4Uc(cD%cz@f_A&ye&N+}T%0+dPC%XCNfjHoN&SpK}zpUJ2tW@TkhJ>j4u9NCe<? zX9ip!UqM0mIGe!41A+)!e+ijleV`uX5z1eNk94ERy97@PF4#c?Vwgfp(0xi2vQ2!0 zrr#+ECP7M~SE01*{M;-eCJ-P9sEkdt%4UQX5_NKmj&Yqd!?wk?5LLs*hjcWjJtcap zC&0@(HdvseGLKelNL9%eF-WZL!(tHz+q<w+8@?W%+m~oCMcJ^VO>jB|Vn<#$>s-6; z&x{eSkx!Rd3-1VmmYiQ)1wT8O1inDAI{B!fv;#1Rh{be*+5}vnRCnQ^ykML3Oq`x* z<G6C;TW9fDa^NXf97rt0Ad4td?kjSy1SK2_;|a@7^D-y_zaZ=bt{UC6A!2pVG;|Ej zlgc{O`&bwjgGZ!N@Su|j>Uxk)J^~A{&dW%z>~w`5sn|SHhtTohUqNIX*fUTi<28W2 z3KCQRIQLRTgoG=0x<BDpMhia4M@4JEOM3sDFHX#u-Kc0Ed}HB6cdz_-XXt+3+bSiy zgECOi>q9O1B3@e!yanV}%m&-XfWAlph!73T;iHt*!il7A3t8kcImi`K#{*Xfgkjh* zUB71GWur>)QX8d|`k8L7JwV#_^K9%93<B%2>zY->fr<jiuEj)baAG`89X?PUXb%=b z53+vtLhWe4uqv9$)>j{CLIG^I{2?#D{ka}?!h-*jgb0)FZdCMVhKYqFAsvCe5Cvy= zWDXg1-VP)M429WR1BiHw32sPT{-9wNpcEi7q`m;_<G5#>K2G)1SMaQ%MjKi^u$`}) z$`P?N6v-Y)eWp>m_JEGM(JzXWO#+K<!amEDZ_;>|33TZP0OyWrgZdPg&eBPeyr81a zinPBHp2edQB8G||Tn~)~e17WCu18tW``zG57hxv=G$VdJ1onS1@U0Q}hAD{EvLCAy zwUXl)3d3L=XrZx_0Esv<qDna26oeG(YIFKakp636uuvIxH7f@KnWCoXsiD%Mf!O{& zx;9>TQZ*%MYbGQlaUokSoT1^M1;#-WfQLkr3;$3)WqUTVWWKhMXJ7#`L{vp<I`<!- zSR5avt{xC(>aOZyv~APx5!*Z*$ZYxbNaQGmn#<2l(jXY2um(E<m51<{5qF@?sfLxp za@xP`9sp7RaeBo6EWR<lWWk~+w{GveX9{RoN{%S!PyzA^ZRrKVb)Ct8ABK8{!c=f} zX~~pcK&|-U!H_g_BALjS?wEyx3EZvFNIuOXP9B<rsnqn`wzctA_SCRI>rE1sA#JS{ z#xNuI!X*Tjhhl>y!~k2YG(*#`Hc+RgLJvs_JnWi(LW?@X`wOxBJ{`^41{@8HzYQa8 z(;zOUCp0$J&(wv5MM8*_ZV9jny8AYtKT|At%=t4y0^^Z4k;Oxs@0xhMJ{%LytO~AT zI;wT{5962&W#!wFcr^}yVg4jJT!)y!{Q1L=`akvz1(4h?XdZ9P<0Uh5dc2%0pUEi( z4+ML{tzw~4VNzEZyKJrlK!+xojurKU0F5#)LCzRRUMAFiCo4Hk21N(q`K>_Oz(SN} z1_BaXY0WHR3KE*TCIaUrbp_Z|syq?mf*xaLabNZUGznZX^+pTPyUmR_Hg2k{8pwl> zt7eQx3=vq0yKZ_vQ#Nav+a`L2!aX_eLvRf(?ZC>cU5%5cp;a9=1oo^3Ygjyu+w?{u z*-kmCj=_y$yMJe=uVdU_HQX3+HZK$4q~JOx9EzD%f9r5&_ThlCR~-fj*uvu7AbhkH zK;3@*y^#+O=Y;Su2}T}IHuV`(%o_AI=D+Ja--Xz-G7NqSQXFzB(~PwSCJ0|p$Yg5x zAZT$R4?RaR??Z)TGP2T_v{S&yRl=!*f&0kA8tN7+%U;(*If`mf6IH>c$l{Eeq$G@L z?Y~LmMQZyae^Dt$o6ha3?2Y|JaY8nAy_*NfXQL(iUZV;7*~dw(3BZzOK9V;wiMn9} zBm#(5!x@yUay677g>0@4ira-ER*C8P2Wn8sk$M51P`<-aOl(ZhT}-f!_9hljjYNdZ zS3`Ft{K3m;+3hp5e9=1=_kE3mUQiE6`f!Fq?C7X`zY2yRdFedLOP&yvNij8&gGLiX zfewgCBH+>)#u#Kw1rmzlc@vAo{o&OJSCaV8<KNL{Q75O`Cn0p%Ac%ucv??_hLh!yx z9fN3#gbW%!U~CyFPXYhd1Lm9r>RW~cHFptnc4V_3RQ$;V4JAlg$e<BoA*Bhd71+%u zV;nF$Lv}j$Dh6SgvLImSkO=`|mHP*>2d~1JLe(aK#?g|Ko6n&O!b^DEK^2TSlt-)) zIOuIR(2sJ_98;NtM2_A1J;^#dlZ%UD;D$x?vfgS;K&bc-Hd6pu7;ZuhCB8rb=a;bB zgF^`J6RAKZ91Q`f7HKUU69}=>50R7=ryt4EH(666f$+p8Z4Ny|OeCckV#h4VvB9gH zR=9#99ljFK&wEpQ8;^|!!#BP)jEKk*MzMo|GenKo2^}<UEawxi6@pD<bZL|qKp5Z3 z=iNR+0Nia>YS=o5-y!;<g?Cz6i~#`%r6%G%E6xCTyF$i-`xpw)$to*Lz$6Z>q#_DQ zD#Sdz7@`rA<Qsr02wV!#N$~U|i3K%o;$4Rj8i*;31T>POSr`qe#%QqxawncE!iv)e z;dGe_gu-XgIW%d6#nwSol3+n40P<k~U@JjH0;<y#Xl*!%3?zZNvdc-ik`ls?4144P zai)dA<Aw^1$?`9;13vQXBsE3=<OPpA%Sr$TG*Ayf3V5o1OtU;?PRaBEW<&Vk#xle^ zL*>DuJabyKBNl`El4io;7#b(V4SRr@G8^vLXhW2Ag}P?!hc?Uo^;;$g+!+V4PH9Hx z19GAOc?FcxD>Ydwoe@ZOV1yNG1eaE$#D(@ZTt*Zm>>W<O-J&cGD8Mvux{aqR)59pE zqdsNUs)*m)2_Xhy6cJfvj1$80Q5pataXeQW698iH>}OdRXtv;5=q^W6^PNUm_E}_G zhhrCMjYwGrWfGG|bU|M*ra?%sAlf;R6(}ywmv=-cT{XY6L<!xHLIrG>WDH~}FD`@_ z0*FF!;h^Y(^fJZ*&@8&f1;Y{f9E_GU%O3`z!jL4eUjhb+C4FS)9RPw<AI`vqoe+B{ zEAaZhCFN$h@Yf9D-2~k`yJ3{j;awDB5I+@J-QxK5R$VQxsG<1;jhPSfTgN~TSJ%NS zJ3&%A91#yUA`;-Bk3V-EMTDI)sJRSgV6-&f!zWRQ2VodG1?w%qPq6I+cgW{J*O}|2 zg(LSTfD#M9qrm5o1VSf;J!}~Ua-z1j;4;$+c!3A%py5FngEMv@WCE}40+p=qrO;6b zx=jAp><HKLac7WN@1DcOo>j(85gH#*XJ1gOfOdH9{E_qG26I%NK~;uJ*EAZW{sD^2 zn1ON92=;`5cET<}S2)_ni=57(@b7P~c0A@(!>IvWrJvA2Gn5f&E#B1>3F)e2HN%Z* z80@lQ9|B<pa_JCBgcp+;xJ>0G4$K+wyRereh}t^QJ)W5Zt5CepC-etPC1JVE#Wd9< zKC{otVc^H5vk<?^no}bgwm}o*W?RU{fT1fZ3@fdgrA4JqlJ9Dj8A-(mS&m!>G_)-x z6}tg_!GE4ZfdlEZ14Qi<>0UFuQp5j<AErnRsru#WyLttRXg$wQ{v9&V1XV|ZhcNJb zyEE`)B-xwFsEkgNPD^sL2{Mq)FA}4)(dXv@R7QD7^}f%w-02Gk#%7!!i-2TSyM}M+ znC$@G7<zW2%_FPm^?@0(%BbD}V%Gxnd$V{>B;K8#8O0yEyuX+tcTwvrJ9A8oAg-Ry z8%%FiOwIXR34%C205}=r!&jcPR>={&$nCtdIWfAZms3{=a|AUZ@i7P{!z^H9FvP)* zQy^VFPp`UO=u&iSXGqZG1-CBi%eBUPTY>RtZ03OSH9}y_zk^UsqqdtEfkSO#CJW5k zo#8oXR?81Q5RW8d$*WsHh<@(bxXDUrD2*g2DbdzPqxv0JhR~oxZ`I5Y8?k!_me_X* z89xkQx}9d<*>zs2XA%Q3(`;6i53uWff9cve6Ip#%tlW~MejXq}L}aGxcIz(QPRU3_ zKgziihDE%xz_9G6oaI_rPCbW%Hi*VR%_clWK*p)1Xkeyqt_5_Lnv$rM;c&!iA>NAW zU|$3Vt?{BDGSG6`pq2{Zv0-dqO*VaL3|U{s;`p}(YZLzpe7M+LY4{a9Jye4`HXSCK zO!P)SdF-C@=Ce_p#^Y>SPWViogk=XiT(WVc!Pf>HO(+|D`y8EdmBH5m+-7VfP|xM9 z5b^!(ShYg%8XdTH;j+euZQCVlx<&@x>)R@5M%2RGlBNk+B*b^5^7njDg!p1Cm1xbE zrWtrLkm`h9p$#R<V{&0N9tkA9GNT{UN27y5Ur=UC78j<odgF+pR3Sqdc#de<m^{4d z<cdsBlZz*Tj;z$bUwNSBYJB(#c05jm7M4PRQ>Ky8^iX5vZpt&M5EIKWP%rQ@5)w?` zMMBmF0i*TFq3*d(<)BAt<nx~_IXf~q%Hs4(8n^%F2_;HOZ?No?IMJ|(CCXMv*yo$8 zXgO=`gqNtonob-J^1SjAilwh66wom<oF&Bm_%Vh~TE~+j5LQzq{tAYi1rOF|hQ<^E z-J;gcVA`eQlp=S?o7p2d81G3nTq3|2%_m;(fV7EG|Fhpv@8cmQ&sY$^bRoaErk%Wb zGGob`ykEG}5ixrDHyZ*_LlN@<DMo1O>mfK<+M#h~3a_S#C2y^P#<1|>dUHAPZX@%{ zx(~eNmum#GsK=IZ#kdNPyejOWeAT>Bj0pW@@HObRjDm2ziDagA`C%x?l*4#|@k}Co zl+5VPNzc)e2<l#k9jA>v+u#5+YYzr@<u#=!gqay@#FPU*xJ>fFtz^z!U;zRTp?(lN zM4Ci4o9Z?4AL+lo?ieWWScA5XO%4y*A>WiKo8FC}{9D5G<ijHfgce=h0H6^BcNmT) z8in4zgn*F|+`{&qA5Lw|688@bZS++OfK{otR)xg24x?O>O(=Dgxg!%oTYGDuw8-uz zuu3VTfucbARvdTcK|yh-<kL9_Vnpd_Z31=A3m;r@5q-${!iVC(G9K|*R7+OpWkFLm zT8|H3sem2&+RF;C+@8xpmxW(8FD8gO(NL?{x^EEk&?h(NSvViWF{>$$kk4lMnDl@& z5}yP>U5ycjSjmZdBthgiz3OT<k!FChgFywsQT$vHF-bawK?$De2nsf!EzR$0Nwzcs znTCZNoXQ%>0*a-HbT`UVS0;s#_4XCf5sCV^n>~#@;fEPl>{F$?sC}QukM!M9GYgk8 zUP5(ZEEgcP>};32{L-jbsn%vwH)>CS#Df-<Ml5qx2GY!z?W7?KSxk^r+&0Ys3$ve# zHYp5|HX1+$Z-YpwX2N0k_le4sy5u1x`0zXQxn#AWB2W8+IISP|84F+v0lBW~(63Zh zA=ll%yhG`YwI??I=#FuCw?afEOGJYU)XtEUELRt0pf@3;sz2N%5G4t~3{jU+OhY3T zyflTulsS;|llwfE34s6_#?$C!z<{gUwwDdfWkIswz-_=8oRTIZI4$tORk5=F7Yzg1 z>uyx$QvRZSJK(a8_07CMoxqxTzFuBrChk?P$OxZhR0azCcniv*jlOL0AXu*|J(MFA z`uI+upa}>U<UkVlmVe5E>c8Q;WR?nNfP$*57L&env!6+&ls1ps%Ps~H$h%R9xFj4w zV4#CBb|}OE!Ds9RFaV|vQ<%A_6d$bb8ajH?L}ez+)IjP|B6u}5BWkl4IVv7ZdQ^BT zmCqw7j1jtLK*Cd*oCCViZ^{5&0BF7gb39x^_}L)J#Dn{HddCBuHxUE^h^P=eWd?z; ziOfGEp$xiKHu6OS42l}lOdDPdxCapAL?gP{8^3q38~ZZ{3!2Dpm&m0LQcu$nbWk>C zdW`q7y4bGp6+p@gWMrUlXpql)!<Y!6Rs^2ilVXpRDZ3FD#04cDN2NH85PTbT#sn5b zcCca~o78xvLG-~u!k54x3?R`O@|4;_!zSRv{v3lh<Unaw!L21)1JVHu(#VSPL-p>? z1z~_3lq?>Iy!<x%z`&xBTJ-RSJQqNwg##~6(Cmw$*K8hN0i(|UJAb21Y;pNb(|vUH zK4%`gv~OE>+iKBG(DPbBeS+XeN})tCF%n?!7eBRnv{d%VJRfA1Y$x#C7nM90>>r0R zl!Xi4%$NOC@(o_#o;!4?t1DBYFAoS^<BI^m?*AF49x=CLb7r8E=9FbOd#+$@Q3Gm? zYC#-4y5xAgFfz2rFSb;l)s~V$5%Ne*lp2toj@WJ+L^ipKu<6FtUGrMzaHTomPAjcD zqZgO$cv^ft@ce*ksw=JS!^5#w*r-M?yWNmU($gC^21E;K27{OS4XBIC{kyO&fq*%V z+|(OkD09N1jNP|Y;lFvq?3sxTQY{|;du9@Jpi66{=K4~GKq7BgaoU7k^cq{MvWJbI zY@z6!oz+q5Y$`A-6p+8~*VV)HOw_BU;p6P~S{OYAT5cuBQ&{<nfDTc5HB~uyT(Xev zc-4k@83%4#MPlniCdxwDYAINs<-#i#QDC5Is`B7{i|$MpiQsxId!+bCK#hUXkp_U+ zBq5u?4=N!Cu_&yIO=t_Mlu+TYD4sXTkr_2JdF>7(Hy4mcZUr&kpoK{6H0$!yoaQ2$ zdvx}CKJ<xnh6<~KDo0&Xo+P!9z~|vIg)7UaPp1%E0Ky9`p}W=`jAR?n6Cz_ukQ3w8 z!{@I`vww=f$UgYDuP+D~0QZVQ3_1uvcq$4)4ad>?G&A@KR@xZQ&={w)uE&>TbLw7& ztjYn1I3R8iBJLV@@%Fiz1XaEYmhA_${?nrC25Pm2!InD*s`@>>v)o?D(1n3gnZxRr zin$wacz~3Rmv$=eOk}0E+er!a4ZViihN-Z*<N?F`1I7wO>bf36sm6Zy#8V~3$mtWa z%&i6v&<R2?(3&ZmBY+%gD2maRv*N%#N|eN)<%I(JRs%{%6cJH?(5hao=9z6=&u}6j zHWs=pCg2wn2Bjw>KnUATLqUo)*Lk|Sm_`F--g=8w1BI4=z%2GLA+RQ;XzLO22-O>- zneYp*E%1g<6t6aGB4DLklL&W39a}h>-|Ac>Ge{#^FoqR(t$a#R)Htn1+l2zUlexVr z0$m~_2#t0ZSDFHK>LL7Jw&kIWl*MEtbCMQOZ(MpZ5DHpgyI^)Z_ku;eNFMZwzkor+ zaf%1~2i4t-x6FD#YLn9c93u((*FdOR7H>-K1bpErp0vwU_}f*kD4f1@o5C@3iNb@v z6XQ$8WTSDd7b|U(b-a{&As#vsQPQZIV~I7mA`wwaBhIB;vySRs;fYWEOWfZ*7~e?t zfyEIud4_=1v>zT*R}gV1@DSiZJIWMujRz?RF50*kkl{Y$3aO-Y7NW54BZ;D^Tzvz% z6m%{W=Lx)mjPKqGaI!Qmghbt?07zL;8Khx?FGMIv;;(TwU80GC*2M#D)L6W=P*OMT z3{$*LJn^c&b}H_Gk0n%~X~47!8o4eTCK)a5vR>N+Q3HG#wNP}jUNQ@|YX#7QK~Ur? z_<3lSWQkqppTC^vM%0i+#X~QWc!maqu=}@AXe13uU{v%9o2c{^37!HFv`FHRthS3Q z=i&;J)4;W+UqEYs+fCxfVZ`wMbRRTu7=UeHizK`*xzra{M8|$FJk?z|8F3+(C1ZWW zr9idbG>lX&4%HRWQ}o+a#~#H|)+_jVSc(-{X+1fPj-yycLsI^KulIfBV!-hL@<IdX zx}SGo2l$_93CJ=QPD1a2vqgK)cvm|y7c|*-GRPLLrvA(WdcuwU%$rS<Md|D*ntICT zH56$98@=7q0k-ny9g71ugNv2Rg3C4`R0^-atV9UniZR?K2=BF5y0SJPFEhhiF(TAc z;~WH&QPSNc^*zx_N$MptXvy)YoP>z6So4N;c9M{UJOIug=p*s{hcr&`LTGB-afHla z=HC|*&*dW1?Z?x=*HSbhHj!0;;e-~1EVLH{Lue6btM_l#Ah<3V?*YI+&i1*IXtINn z`WY&)u2BW&ue%_&;?J;oMvRCiW8Zn6?Rm5M3aEWcD@HOQBoEdae#R8S05K);JcIad z%>Yf31+z&{Gp^}GX)4^ib}hG^CrPMSqOzRWeJDDnjW;W2NI6-~>v+ewT#7)<4DL<% z>g={mzNH9fb_7LE03&wPwbQzd3js)-;sl{YM2qAho04@zM>+D|A&D{qCiuXU8Eypl z$yC1H-j{$joi{UUs>ynDLI6ik?+n6ss44EYe<1A(8<AhIks0Gj?8M+Y94W>It&rm6 z-+RFU8bFN$@H|7Xv$14v9B2&*yRJTNY=8xKOdc43iEZyn>J?G1xOOl87n^w?T{0WY zFmaCugz$YUe#B9I^kcb0oP#%fdm2NBWQgemdhQ@%i6r;1q}Q_pE89{!5le_#CM{-D zt&-6tnZ)v^Jn+?MSwG_q1VAwE$B(RH970BKnK8VwJcsns+wzQZn;|IG8;3zZB|=<6 zh)Dj;CRZhs|B#H!=tB|Q4IxFDNyn80h*5kgf<#0U{1hhgjrN8Jjm1-aPCsRF1Pm2a zA#sZXfE7-!O^|bZb`uF`F2Sq)co<s`-olx|$4Gciz~fRj`UTLCu%`g;nKYMtLPnd8 z9_-X;)a~B+Rkk5!Q1226N>mE~$2uP+B8MUGP>0%B#SgH?L=JMTz2se=JaTjWW{kpC zcF&DeS3stFSIlBzdL1SO>_U7}1L@r^ub2DTpYgb%ya35QVBx>i5teuh&tov({IDsN zr2%wu0u_yVl(rJB__YxzK!IYR@+ye+a)=7>oR-%|Q<a;p|BNS1FAO=tSICqK@J2q| z;2>`YXrDw100uiT2Rz3MTY&^j0LOCMJ}@=G2W!!TLG~S`Zs?+ji9`bqpBX}q!AU)^ z^w;0ZS8V;&Kx3mDYQpMW%IAk1AJa$T{J>Qi=eUq7U%Ckp>3o_m1059mW2l@9Lv%u$ zYeFCpn}Fg%AdHF|yAXj1zg4%S&`aXWlEg7|mv_eI>5|d#spy0}1{{0_z;5KkA4aHO z7l7@&d_eNVA>ttV<B*Cf6L}gpC))z!R}{BcZs5RpjCewr!#KqK+k9PNcuSK1qIw4l z!aIw<FkgBr_Ygd}Y&Ez6oVY6RGuJ6=;lr=!L&knWZQ*;DF=BFf0uS{Au%$H&-#;vD zuGtxc&i*EAp_Y6?jaM5_0pMehm!i)?aBy|RVCy2B<R>;YXvu|Smd73-Jh?E2P(sQ{ z+z+CpOBt}VDIl%oGM2V*@Gzs8(+i6u8w9&}wwghvViL`{;KPN;0I`k`p70h2UQ+>M zjnEMz<q(#f3FZgZXcsKLa|ZV3^|Sgdn_BC}j^ZmaXbg5JvE>NLC-BsJ8uFf2Qe(lB zFcxg}6VL0Cg$?3S!H7~Pay*c%WnVS<_k(aZPMS@O=<%X`6b4}t@Wp3Na6lY15aU1` z1O}uQE=l%5U?B9eX+@qO<Cd@9tGkR>8^vmjQjZT$;K}U1SQw0w7{<xwpw7SL{v5Uh z+t>vQfI%uWUaN;HVGOb@ht48SS?rm1vqcll0SWOvGUyUaFrZ{A2~vkm%jP%uPT`j* zCNrBpMI?>Ks{uKX-J$O81O<5e4hf$tavQit9|1wq9{(C#Vo(4|B%VY7Kt*R5qFE$k zJKl`EJi<kunyV~l(hMikY(+vQh-Yc@%MYC-Y)hX;u!aUh$nr$-^6W_-QOd+P`%iqd zfsO9EiKcv@Fd(ewo*Hh*^zq&+`ryg!)@nJAuMyzlFNlX+87>+)PqGqwkv!>St;A5; z3+g%Z2#@gWGd)fC!dydFfp`Ey0dyxo#iovvKV8CGY4`ErQf;Y3R@$mc;XrF9S@4Ke zKZ;!Q6X=0}kmC!+ktX2rXY`mg?r54dNeeZci9}<+Ew_EZv|OXBnYt0=&$b;h??>;w z9Rnor53%rQ%Kx5|c_o54eF%iPIDMMKSzwo+5#yS=A*aMh0(^NYUs$Pk1Gr(<cqN_! zU6;a&#<RDG>r$!DANQz!pYe))IO>fjPo#5@MuftKfWG1!#*F?|%Va1V?shQa5CHp| zUiE%4*drg(n+%>@pfoF#hR|7WE1VIjlo=V$$==0y+09S{MvmXbMA*V+<UxO6^Os6N zt&&f!YDw(uFe&_3RL8jBZ}ALa>;(c0+It9|c(p$|k^uFP@&YiWaLbWU|DX>kmd;+k zsJ~NFzAUg89&YI1eO;KBOFJtUVVCa?dHl!KRUWDw)e=_a_qkc_xL#6~xJrOPzz>fA z0AGLt7$FPH+(t<RH>P8e9qN~l{OcCVXV|<T91oRsp%&(^@fH4{i~E`~nal~8UO=nd z(}v&qNKq7@@;e-NAD<H4#+BY-6Cg%v1etgpw+gCJ@*H9z&e8nET2F5T|C$!J*1Zx+ zN1)j?P?+bF*kTEwp<P--9tUXD35<DZq8UoFWUK(4U}Ki`RTZY+QnB$vIml$M^Z9xI zgJ%)v*)JLz@e~>eYF)Dm@sVkC7uWOyLC{i0#=g%6gRqgs3~5)%m#NzIk6n`ynR9?0 zKsOXF`6_R{k&h7r>drk|^v*7Zi{M2CAf*8<sUd+w3Z#IDGzvI%A>S_@yee<Fl?lJZ zj{wHhAznhhivBMF@lJ(`vs#4P+zA$lBP%}g?F3$1=Bm>+2(eC_4O!S)ft^t7)jwR3 zmc*PN55x;XWni!7@)<*@C`}->fbr#|Nc{AU(ecD&GOc(V7Y9kL>cZ7GNxX&z%A>re z^^my%PUANrH+8u{@Qk1;$E2JpegY?;uj^n0Yphm&7sanI!N}yH#D5ShW)mTf9Smdh zC=?+;(N3;DIy3OO4F_xbV7i>q6dDcbsMeBM%R|q8*<~^=XAF{^Ak@f*y8dqM;xm|K z$L|{cZdhJM^Z_%q{9_Lg0H4_C$g3iEQvHZ#Vn%96EImOBxt_l+g~AyRbkH_fwBQVa zEFwE?No?g%V<h;#2_X0IyX{k>##1D%h|!2!XGD!$XMa)dF#6u}oFs_WH=ZGt)A_-4 z@fp|vs*sbH<3v74Ou=S%vTLY^R@9!)deu$i^~yBbvHOG*%>f(HS)GNzFmng*g-3bv zAQ^9K$W6UP7&VEf-t+R_ApxE`5|}{7)vFT_0ep?Ysrsq@15{6?Rb8K!^i0js1{2JK zl}WEWX$?H_L85dguXd344F1IWo@Qov)|cl3gtcgQ|JGLu#7A_=Lkjii^m$P1>p7~& z8!~>qA)jJ0c7VHIlZbr<z-pD99n30v0srKzy*JLh+^J?PJJtXEUT7AfYs?peArc*8 zC`yRw(0pm<dmtRTCCipLkcx(<!_(@DpwuAkXGa{-T?LX+$yBCO8p=Uf2vDTvc+5XL zuWCR8#sL!{^Pw0Nwh2}n#Y#apNzm^|2KIw1K`$hfw%5Z4L$eIX%1jAb9@S5Z(ez@o zeo4R=%7$a?G7?)Qhy~<%)*qo|P!<I8WlEJOkj*+FV0A$4B+Q_ot`N0h;D*9$Yo=WT zgjEmu8#`f2A<zZmQVFL!=oSW?^&+Pn^e85#0LqiMR!<G|C1q<uiUBJrS73#LpOb@! z=rcFLpV)Z+JZd6~ORM3LN#G4^utq#>|FqSOB1_qw07eXn&<acDARthofMzm9K&u<| z$5LkF`)baf!m?qk{+W4gFw(Y}NKO%5dQsn}g!5VggJ3WCXbl>%-PYM^hZ`LjR-+(5 zRB4`s#nF1W$E+c)>_{v632=P1gfn{eYsqY-mZd|!2-)9)W2L9@-Nsf%_w6=GxX}}B z9B_w1{epX-vX>qX>A8PQINC@z-8Tqyq``2+@Vem&{~YH*RZf!Rk*w%&m{AVp5wY?> z6zv5(ZZpV^Jn-dmpc#~_;Ji4uJ;#_ZvpjZ~i3<14;NLt6GX{uUbb9ES;lE_G0Zkfp z0o273#yIpK7qk5ce3Jz<O6&oL^rMSTZGozo58@IXnZZJ-q)1l8e7zSCGP}YjHLXy7 zpWLL3w`38JMh<jC%)-?82OkO$UE82NM2&Wx5+Ln%Q6h{M5Bd;b!*KP6>K@gbwOz89 zc~f|*ouRyym%vMch;e6mDF&xF7Y<Wyqqq~6lC5!YL<qr6%n^{Fsg*o<krNBuU^~UE z066el;o<54e18Lmh?;*B94IyMNWrM`l5zfU*F4sPf1PN$%mARokVrmACjW^ddBub< zmW)8P;%k#?mvu8wPRJA-pedv;)BYLIB<<Slg<j3Q5<#kPq0cB<TK&(Eg-9s)y2nVY z95k})+VtH?bX9tgk_{tfPxqsoRQ%g^M0U{L#EX&r2UqcfP*skLP`&fnoF0LNFC|w1 zFq?REhgvuazd0qAYy`)OPO_0bv;mTHBp7VuNNt=x5wQFb+v2a7ZE2lU2`HOjhPVmE zjqbtVvYe!#;c>9qf~WRt_#d<?3BV47p6=knSuGUzZIvivj!6NA8;p~JhTA#PA7K`$ zng<zFBt>GhQR}B!%{h~z)iN{LXn*8u?3+VQr(rZsMQAcMc05Df#&VR=tMGQp4j2^$ z^M7HeWqeEX&L8?}+5l&b6nHWTlfb7Dlo{|GS<J|`3kVJG<AMMY7gRgPHC17<NB>?^ z^B5>b%N+@7*qWvU?Y~)Z;f_VTO)nOJtU$UtP3fr!uM1F#;@e(R<O$g^0>*C85gY@c zF2}?jgpX!17D+X+hEzPi-_`zU408Tix0RL<FUej0pkN>)X3&Klbx%gD252FKB@eW3 z)1v}`R`-R9QQe?2ch@s1^C>!MtP(urpYuBtbU?L{HP3HkMFDdz(%Q2-j;w8hsxi)@ zANxbcSi!HUi(x%6)Efsnc(6Oi1()hhdujMwv#x2uRJ{nk)0{Q9*N%`b$~x@RaMA&$ zXoCu&IIKV<#ZX08-YDcG<7Ni-wI6`RP&`0B3VZ`7LSQvf>w-9$zSFmZm3IFt4kw7I zIc9p0)CzlJ4f4$v71l)Cu%Y(lh4+r}S6mzAl+%#$iR2Yh9OjknX}P)NOi=)pLQ&n` zCRTt|K=BOn;%$*HaexrzYo{U<hA#Z1rh89b?PoJ1VfZK=CMf6u$RBEuaQr#vQUm3} zAk+@|KnOXg3qXasF{cDYUmVlpSmK`=oUO6S1I-l%(9A)N#T4o>n;&ZvE!)bV*tjpL zkbT8pc-(_E?xpQ^owZOSXWk0IPuN^|E4Ita4K$oU13PIY_OBaTxF%fn)j<TuSm#-J zbxHszuUQA(3QnuE9a#y4R0*X>4O}%%DTy!3hh`QG@hL*SJQs4kqSr3|r??6Tso*W% zCwu<_(PkpcQ{SlR68v^8Pezw&qllv(iqK2L$tx_hSJ`FrmNe2PRW%@1hb%2J4V!Ca zqO7?jG#<omQy!uUW7#dWTx*tE%L~DeBJwc$gpomktT!YNf#$G|ve}4SW|ILs;g?y- zj8}rhl$9@Beo*O(gW@`v$oXQyd{b{!V_+w_4YG_omk#VRHiZvSBVR5U`}oBSFj>+G z5kL4MC*sm^Ef6!vIEEz1N8{NEwKCcU4Wb52<;(<#S^)+FPP8rb<l@Odh{5sU;TLhp zK!C~JYk@fyjWDKRWiZq2Nw(7E(ExHQ79GXz1TX>(kpq5kE<R6htj?CxetuVpuZLkZ z@eg7OYgHDN!%+h=N@z6e82SrS6BujVfR5^G#f)2gshJD40}n-HYvg-gfFF}Z40l{p zFE04>ctBwFsGJ=-Rt()jJ*l=4sQY$Vq)S%NrldS(N=VbLVbvZ$@V5Xa>H<5$(Rhz* zt48QTom<f0WR&)J3*LZc7-p$1%3K~z$Dn|SLdOA(*f$mEW?Q8hGzrq3>XAAw$LySm z6fd%NnL7CW$dqduQ(^{XTOtiygbx){C!K>t{V_UO3l{-N)5wim)@>qFAbyeM#^CxZ zucDKk`N7w=-vf>;W!!;axGa>6B{`WxEw2y0=l$7WyaiRqn{61U6s*dwYO-xCcBM?) zXyf=5GhzHUors}BzWO$H>&9)9@;YiqvL=#HE5dVngM2)=c=ztGB?Xv}j2qP0F=Yrp z4ky{Ub6jd-co6cL41^^?kr$5ez>Ev@*7OzvNjEUw8(JiKMN}Q7f*8M|Ex1V^UK`Ya zq;>30#aIJ$?MDTSURdr5K~emM=MgwX$JDYOw4f9{mu{Nj*xkj(91q{GU^gNEgRcbD zfm$Cl4~l5Fn^MKRT#aW@eL6_&)>@&3PeHB{N<9&fz2W5KxokVG$ts;-z<iOUNW-W_ zO_cSTYS{e@LFLI(V{K?{aN6`h@K_t*#wj#j_+qXCyz<1hD~R`T)COMXD}b2zUkS9e z?y{)U%b9O2E5N6W2r)#!^xIV2k?=0~5VeA*>mQ&SmkU+qDCzq0<hs`zY&Y`lQLV+* zl59hB(r#i8<-vtxbEgA$KA<SuEgFXIM~!ZdY@C7(d-mcb7zvMO>R?wc2JT@JWLYQ; z5a9EV%2Q^Es|k8ZUcnO2=7WJg!AZTay>u6GZSNuhiHJg!Oi4QRA(0RW@7uF29<NrP zZhMn<Uqb5>DdEX|9(QA4;b_H8oRN*}=u%&;Aq4)0=U4gzATw984w#lwC}R^*HQhUF zLzE5QHM^~$2!!qCA+LztT&$v)+S<*QX%V|Z!K(e6h@?SHg==zr0g(#Ws{&yoQ%Jlm zSVoXqH;Qv;8GI}8en4A9;x7c@BT;DpcOA>Kxd{N8LvmPy7;0=vpoMx=wuc1m+|LVW zh?%4yktPjG=E8_&VdA0CXd0QjEwz(M7O`oeaFrtBRRNu&0etfkKVWGZTqfOM8B<zv z><v9yYOwOFqO5%IgpXI+ra<%g2scm|lXBtq1O$LYolv&nWw{+Vet|c30{_th0m5|i zthO`02gg&sOD1E=3K=}`hIly6BQ>yFW<wTs39^FP<>?*=J0ky26U}<pg@LR<<l=3Q zZE`|mZ;HA>>kNUVSqXYKBeGR8!R}h<o?Sno9bHjBc<IqRXFDE~C+2cxgWR#vJh%O4 zAbaz`YPv5g@6Q>|2dDjHq4Y@Ko_rEF1Qh%y02v4`OVh?Lgy03MCgAB7O=6UtuI+X4 zs4S2q)h?^Hs7ehiPVI3zX`?`>5J1tdN^{*oL8!3-qI(Jm=B#|jGnQs<r1?nr9zG9M zLArTBPHMOf2^I(h5s1Vg1Y$<%Bs~Z0h(a0f$TRP^5p|Kf*7pss=TMDl5S>|eS#jvR zgzmmh5iVd)4D!HwS!-xgT`d9b$TT4LWX;Q@;+ii#5}<Ba37SUg)B*H0Hsv;+ZAiPC zJj=H_cNQtRyW&`ellzQu7AH&bh4GDXVV@;J=~6O&5FZ9WD?AZhl01yGOLNkij>0BI zk(NM81U}_5Ne)L!E=kEvLt!=*G6m(<vgrXrWDp<7MNPS-w%$%mBL)#YWD~~oATWXJ zC4llmR&2jmd*=lOTa<w&<Pwx&hAK~iNHL0uys_X_ggLGYYdUBIhDg5GFZqdBSbX`l zM!~l)!ESj(sz!gsBuidkpjDjx-y(a7gtc8AF2{fghFBCCi53kdy--A;JW3d#(U1hG zmpMuVQf|`qkc=<*4I@nZfY2-_d8r0a)(~cU6le&VdqWJ;b4DKF^_IgU9Vji_nk#rG zGZRkb%oSB4B%>4IlSrR(<ZUwWjAJ1XwhKM;iwi`!gUhAPoc8R+q#Jq=&f6NvY}t>G zY-z#jiWlf5=jb0P1MVGNsfofjG+UZ2kZkD;<xMwjy0Z!Kw2c<5mzNCowoR;b$xT+| zl+{QDEjrDCd|2cZq$7Hu^Q?IU**Xc`;{P>#kfdz{DYTD8stW9TE79r?Ae!d5a>>q3 zEVT3GjHE_IwWbP(ax&dV(+rV<B8Hc*qzl>rMG@V-X`-l#W8-G}f%K6QzIihY;Wugr z(rg7K!*TM1iS*ckNRCs$jcEIF$H?hj1Z^Odm$;3c)teRmwDiHLJuzx*&PmIx9#;B; z>9CNp#e{gbr^>yGoHXcitKnQzNnk`gN>qe<a~~{6&57xWvz9w5q?Lz&oQHIk7^nGk zma1UsLwFv^(1J*E2o9(la})~{Egb~>O4;NQ3qi^6LP^)(PfQ-vTWRrjjQ2sJhpbFu ztr_SW;{Mn!nl&<U&GCNqLi{(2L`TbjXF3&cE;6ga^24<Qz`;W4&V^f~A{G-Ynt~*d z`@_kIE-H|+%DJwuiItkL5`p8|-7s2D49Z2?^~Tja``S@(90N*`{|gz#31VqqufDRe z?;isec67}koAy-I={L;lto5fV-ub%JNq7<$mj^|fV7~i^79|;lWJHh;xUHv1(<6mD z4aW$ggf=i8D@yoMIt@e|F}3pDX+%I#u6#~A46+(RN=G^-K@(_F9Jyj3^j^$EC-Php zL2GdVvr-ASKZ{s^1)>$P9s(fQP7Tvw<i+s|1;k}gY%QXAS|JoPssu=&AZ*ELjsa0T zicgT>yt+WBnGarqsuxL4848JNTu@>GNHX@c1hp}pK;*+hQy%_YagrGkC`yA}&B+Ww z0&F1kSt8gXP{RceEVh-148RtXLS9@nW+TA-q-V`KpXW0>5YLjyXYrAo;{MerCK5HV zCZv#jLVWTlvYz%nJm8T#b0t!RWWGxw2pLTf#3)eKHkL9!mK4KS&*(qu7wu>nDi<O| z=u&-$v4B^}j8)|l-);4(4h%?Y5=Im6v4JEDXqYS^^o!Aa8ZXzfwKCfwbO~wCgi7I5 zIh-QJRd5d~N_q|vX(XcV*y5zxakqxJqU`0bMYOn3?Yx*M3_}H&#X(4<eP?hHcKDQ_ zJl`k}Av*$6B$sL`^c1P&-lB{}r<OlIP{7%CD-i2bZ3Q81AXpucgKq?5^BN6>>Illf z10rrM1aJZqFDx+IK7T{k%_`Ln^mL^Ir8+v60XD`2-AX_kT}oB#Oa=%}C0xD@Aus_* zvJy*44d~JAb0h^=@L<rOV;k#fW_;6?{3dMScamxww<2>;BgJPHhev4+@j^=x$aMNh zmVi}OYm!V(PK$80G6QpnDdQXfHk)dNIwTGxFwFoC%?_zvWx^F0Tkl?T#o%Bjo=Fe` zN9OVd7H?|fHCcsQENn4r=jpN@DzbWlzqJ9(hi6)r5SY|Xl|gOj2aPD<ayD@ix~ZRy zF1?N{wG{%9IOeD%e|28R8`Rs0Um=L~Yg?4BSGBZjOPHbVke;l>J*k-m{!Gq?g)=-^ zHS{T6+{<=Nn%$l#9f43gSzs=5wf9y`-tfgWMHhmTa(Gv+DkMb8-nh>CV(|s@<8bqy z`tY7fag`Kc@mToLym^l#;zrr$x^W8*EU_#MyugdigTp@4Mr;(q)s6Wru(&wa(YW5l z+7WlLdfdh}$rJ8k-)Iu0Ne@Uak!QLbhyr7!^zr25jPP*}_Esk!nfSFtc=Fr8&zI); zaL}l~^047%wTE$)KVc-0>rXVIOu-6;&dDk4S??aKn=!UkGdS^FbYL(JZJn1$=GY9( zkIUW}U`d{s_<?}5D_M`CB;`XG3_W9I1Wxl&nsQk)F<~+}C&#i0KBkm%)^1eokqM2A z!!g@D+-}Qf<q=|Z4~`yDvBS#-lLOX2VU&-;^YiJBk<@Y-moBc$2jJgWl`5sXoF{SS zld*f)g|gW-$DkZ+msPYo20_g5nv2TBJ{F6Z1$<nHFM>!BKN1I#G3nseIN|J?O$Enu zY%7aQ?8L}Gb*NGFm?OcfB=X=sHZB5LAu(i#TQqTw%p7ILCVx|v|1g(=GHq$2@kGZy z-y#QPKN5~d?UG9RBolJhZswU4{wHANKSY4_5XTZccA%e;fRMA(B}=R_w258iQD5+* z%wI!@UHh$}8Bs6$cP<P+wm=GvJ93@EMPW?jM`yHWK$E5wK}Vu0(-aq7usC3GY>}zl zgFc(PBz>*7@*Ai|WM~Iwl5>0vZu+Z%Zzr_qh!1?cY~}YHAtA-{O<n-DChr4_krm0o z;6dKj3%ayEg!g9q1NH!ii5Tldk1kFEInG~e)q|FCG^lR81%V@M05d?$zubA2DhL-H z_Hl6Ah#0W-Hd~*^x8RUlf5lGB>nOlRs{%m}_z)gVQIkAyt1cVN+zyE@CEy|i^0ag4 zC^Bia2g^?Zw2MlXF@JoXC(^Kp4*Z7lrqzuECV#;#uXOY(mgW|5mn0F|2u|B^ZB1N< zNX_g<=V_qQwk{$iviUDfKC*-0&Zgevrts{{(ar!i3?(>z36?%rZ3ddqr>=3C|F(q1 z?9v4dT_LiE5kV%@j*4j-N3uufLy##LNaI8W3!9&yuH9NF!lPFjB8zo$n>#^i2Y%X? ze}q?~0Dtoyi!=C+Y`y%|tjz4KjQaT8806k%v|P3(M1&?6+@^6dF_KfKkZW*Zrh?-V z64S5K4w}X09EjXE8sqemJ#B{5OXeh5ikPEEd+DK)`!^tQS7?yCRY5ut>hPCEYdT9N zu`Bvm93FaF(lmTm#SpBPVUZV=+Xt*c3ts<A$h?;wz0}IL0Zi)LQ^G<i;U=hZWbTeD z2KgVVma@~xxCsRj^UwGO$|rp`Xp^C{zY7DzhEqmfiXlvU!F<3IVE2%3;A3k3204z+ zlE^mn42f@W!Kb%2lEP{94SY*C`c3;yQbw=MsnZKPhgx+^al<5pvD8nTKLIbHJNQYc zcRjJ}BDb+e$9oiOcXShNah6bND`zT$5zCX&xn(4+l#>v{kyYs3GMi#_%9jMTH1*7C zazFB=fIdEdR*JDUFb6?=J1J2~|8goeY2&-Hmys@Up)m*P=Dk9=eM$UcPPVa9I)zSR zHWfF(UgZMFsb7(T;FJkP3xqsXyOaxLeHwxp2>Zi4SrnO3NhlMIL4ziHa1AnxkQ_oL zd{IRAX~2LnWYlV2;#dLOfc4PnNHnlT=E98rAuWiN7HUE8CfS4SpeWG^B(>79@pG5a zv>F**{hQ$g({O@+BPFOx_sP){22Sz!qQDXrY;QpYuXHK~4Q%&d=$I;)=$y4SRK~=$ zwzAVJ0^9}wY`}|+>&??WJ~WKva!$qxeb3PmF_n&TgQj9(YEElDwh>6NNxT_Wa5t|c zDo^hQGx}Mkm(=IGu;?e8Lk`<{izjCu;@jombxQ)HdLo~_ppsZZZQHall?R%nqNU*^ zg-3>i!?M?T0eUFyX23G~6)iNdL@UupVy!Ru8mD$D6KBPgGf5IcMugmog9Q`cz+{zp zrI_$YhgF@?GQ3j6s##1)R2PS|avv0Fp!Avml2fuk8W_R>iM?hLC)xliz8#UxB#L-N zJ=@(_m8jDJ9KGwX2-Smc)iHHyWHR^M48$L;5oHL%ZebFbwHQ5Z23`e7N64gYXo)W) z5h!F+LZ*W+0%BTB;8x)L#tSb$CU7d9kP+LP$z?>}GJzG#IZ$=0VzuoopjAhSACc5G zm5}D3?-a@sB`vr~Ks=lW97B#3)z(9rgCtYR!B9%!N+abZCdO+kF-Dk1U^@r$K=`E; zoTZ`B(~QO{S`ftPMM2`VT-HiSQQ<XnSk1wL#*wo=DA{QXLxg6W5;jM3;*3mWi6oKK zN)3$os0e@iP~c_61!|_W^#jpzo1GM}pi9k)R*waTH%xdUJlLfZ1ny{2qeB}fshZYe zQIioIjO2|0gtaoJYaGs|hkj^b`k&PTMCX0pYxdZQPfW^=qOsqYGPI**0<!YdPidy% zZd(mT!#ykK#hGdr;qogb-Do9+3Is)K0U<D>5RD6fXNzrHYz$y*za}Y}eH{$bk_o_v zb{(Y(HSj6zj7eRyW34G|kJfz7rRHb`)?LRM(i6qG29Pa-pd**J`7Hzx=44T7&+TGR zX$}v;4yHvF!xNezSSH<v6yJ<0TCb5HBic~Z4egYVxEc2jDM&OEBq??T_LMaOa4@~l zCxY;{I!Cmu$1^p+BzWv}27<J?JER(1=szKb_!=AR%Xil$%V2dA1#al*bf8sGLmBvm zK%(odC{zk9Of~HTH6TP<XbrYz^Z1Fe3G#)Z<MC)GAgrK1FO)men3-*Sw}ZO)N-&1s z@by42OXU|_@j#;EsWf*I-73dwY8=aj0iE2m$Wb?+&PQL5nF+<oK9iJD0l?-{g)<Km zH$dNnue@uE2|&7irfB$f;AB{|dt_uansGRQR*S?;Xq{wZ`c(N6UvM%5#^i5j0HN9e zGm0ciG9mhFkc9TaOM~_p*jhbV4rR1ORp2SL^z#*0YZ36Z#B#`f8JQx~NMvzT+|@uP z6RaO7XNgcW#9&!s9qML^W|v8Z?9z;mg&IXZS`LF7v+^N6F?Qtp7|qNZWCw`BnUqtV zV7!l5IGB9M$|-ixWoD>Enk-?&%+x!n*prLNB+p2(ar;7uy=w@ySrQqW(6ht|aPgLy zE_X1>ZUiYgUM+(`<>qAZ1xc<M<FX9Z$UN>)ciK!Lpi+2?sX<Ge-n-02*&r<v5Xlt^ zLO5iRo9Q_ob#~ok9=ldZ2a=RRP^mIMdffVpyNb{Tz&nCwLIZ0xwgS?kN?648(*c2Y z%uqzpnpy!7k~9`VibX}OmX70a%P);GX1=Y8u_nJ{w<2*{FASyiO)4&_fLxhJWuy#I zM2&R4DrWR&AgMYg)nlS%TXQKM<O33*<i*R8j=scymH`Yl$6bS4%K(!6osxD^WfLOn z6}Ss!37;tv3^>79j>0BoCasLtsTw5~3uoXGCQ@qHpEgKQ&@Wp$evmVQ3#}Zrr4?Z? zCko3<Pc+}-EvLaz-oOy^6J~Sj(waRQ$i)l+hd3GymZxjr1P~tt7eMp`yuwU9a1}gC zdW4uiHT@SrNRowJCXHmT)HX{Dx7JXR`Kd01>+IzgLNH6l6{X*2&UdR}t+uX^9(#Dy zpgck#2f4onW8r3kR3CD0F={r-?zTd>AN>F8F@n9r)(8j;{3V@`mf7s?&;UbPh$U>H zLL`htsGmR()axVQ0RYPOw3Otq0Xa0EfUk!&YKb5N$`&3=XV3+FEiamJn>C%2-49%+ z^VJ<*^GxE%1bSQ_sSl;B=$Isxau%2ir4eEiUJ{xb@hhn;6`dZ`p12a8!yw_6x5ydF zM?{f5s<~{~Qb5nfS|f@2^+o6~<1}%ikQiWsve2|~mH5#}oDe}nMG{7KEr={#YZ66k z0l=l?O`|r-o=7Th#r*d1+gzS7l5d2~Hc|JsEhR|$W}XkSyN^`?7$$9#wwV->o9&tR zk1{4I0>uqd(WBpQ<8)vVe`vG|DPt&424e?s-E2Sopj#G|j`r20AbsK)&ewJnVL*-T zPzbsocUpJ^cCtJu_+l$|D-p?QU?erV;&?O&tZ6Q1!+_NX@)s0fB4nyPr5J+&wKOL0 zAix=xG?e`m!PdPitu@djfuzeXFBOVmWlECrc`7f_I1NyMFB9OjYgs5lUZMm*Ixom5 zF2d1aibr%7$LVTCsfBDO6TV6i2}jr0GEqEMDt-&=feUtt*LbcxAf^k(d0-Y~<*~RE zUkSXT$L344`UJo$6Rr<D4vipi?XoPiR*&-w=6Pl8YeNpAF&3p*wY~6uIeP(XIZznS zoyAa+!-eB8)~I3;nO1~WxGh*inXOQP4q20ItWF*Eqb&<bI{aTt>-sIYwEYNfhqRq_ zbTNns31G|0v9!7~Gc>`C#bC{GT4x(iCk});XjO{_J4*zTfowTv8nGb4pylv#*CZ`r z%8{KagI*&*pe12jP#rLfL|e&f5;=u2%F(=>n|0g}Gn!lzT&Nt{Q3Dgg(Y+`fdKAc} zLhfq{MWUc{Ejpc=MfiZM`LB0dLL=e=%SB+8Mv8R3(;<BUl-X3LcTh3f9`ge6BA49N zBx_V+v$Wm^FC3GMk&_39i$@xlghXnz<*&6yCNnPxj#~Fq3MJ9tD(Q*HX$U?5aULE@ zkxeHQR@Ge_!eusk0ke&kr_x|;qL^@XHn~)I4VI=fM5f|A1dQZzQ<NGi5vexXkg`>7 zAB4G+F{2MJJSG_c=>Xtu9tJ)pFL42?Ll(Z;R>Y1y#Eg8k0%Sjwh|3Wnl$k0fICe1- zRBi^YQXLFJt`+?l(L(izXO@UvIa{q1Lc%A);*SLNcW265igL(W(0tJ^`q-tKPH3X6 zd1$Tm1<91H(7b17Bu4o%lyL@Zw#G=`K#>8I3d6wIc}7UnfRQF790UPo5NNC*6mV1+ z#RSHRS${;@kZ~$-zzr`uB5xRWosnGSq^Te<@=YXJA2(X*lzmf}3X`3rco?-(jALe8 zU}LhukD0$MLNb@!K%-{$BU{ol{)>iv^vnZ!Xzq-4AL}nI0?e8<|DuNpM7MVSh{G)b zAI!Uxk+nNB(91zn1jbsLA{2b@b0^q)J2>SjQUs$WFkaDwET+Nrh~bwe=kBqkBF}Kx zV9bTRB11-J^oiL9dxr4*$Wni~Zs$0Z`NW%QtlRO;n^8ZmnB+=21mI{u=1`7NaDu|| zA<12Pi8Q%H-#CH2BV0>rZboZGqdqK;3AUq4uE@=?P}<;Ctg%md4w|A@Cj*Y$K`f<c zFe@A=Ohp$`kxPi4q(=<bnqsZmn<{3pjU=^#;nxV#QeG$uNdU>VzV0a{sWux}!2rqN z$T@mw?-nFp1ijJR5JZ~)Z$<2e;EIyLN_O0C()E23OaY2&)xq&_<nNb-mh%{r;jmr` zJkeih;<{>ksG_Ej><H#&p+3uepJ@)pdxzt#FZ4aMEt+{VIzizx9|2hHaiZEBGOa^0 znt&PB4+>u(couEURL<6cZ!BsnsUB;h_IEgjvH(DX&_M-1Xv9}335dPd2G{P){@L}o z>mtK)lPKhqP@c0On}fd4TqEG*r=Kr~I6LfF3&OgZB4Qn9zrj0Xo`4t_Brwl^hE@3; z4;sfghKv<dWkKEh)RleH(2e@}Pq8?tPRMtd6w^IeRnrZ-)FClmRUu2666rDDP}D6d zCZk|y5uw44!>0`$F1UPfu@5@rOG>&>+|thoXT&F1|172WhBY)9aCX`L-Rb@3=Fg5x z8?Tr129NYwhI;cI4~t$$ysoiM2o_>3kUztZD`ZzKmhu7R)s5HD!6BcQA1}T${ZIJC z^bg~w(!XmZFuaSjw;29wx0?@YyG-ppWGs=+!Xqgz>J?-Lly5qtC#O5S?ffCMy~1W} zL@@4khcOiekOT<qx{lI`vgJ--nYULe!#1!Uqjlv!Ai&Q@S5xkXohmrdBV#$j;oZm7 zV;RRb27A{gAx_@aKqS;nhU!@Q+vb9#C<QHt+sO{=2&1u!p0Nb#3*NHdiW_payM~Ic zTa|5(8xE^uDW$643sEnU$I7{f;@LN-Gmh<Tzb9`MHA3qUKoFfg^tB(5w$LGwrJ-r7 z7PxFccB9QNn(p!lz(SOfc2M4JNPx_dv07KhgA*kgCk&zxrx{Tsgt7vVXOV+6Lk6RT zOjv-Kn<Ir&zBy)yWVFL8R%jv6nccp*U;z#8!|Uv`8>|~v;&E}7-GxLx>dQ80Fg(Ju znKFK{Q<&N;=2SKV%sp2W4Cs9onWMJ6CeZPKFi1HmN}wY1%f+j?FI+DeTzt83YKUux zR~(QOs*4YQUG;brHi>C=94N?4gEes85g$bgRt_vaTfHY$Z1Mx3z)Bv0fPyb;qUdC0 zOfii`mIK0Lo~XOCvQlCpSu0YG+lxDvpj$;?>j8qU{oX6ARpP{wsk9!drnOIU*nOUX zkS8A$dBpN(^T9~=jbJN*GK;vBs2WZr0yCpMcW0+Y40ct*DZ(=*fPKWPyUA#N2&utR z8i$1mD$A_FeK{R0Wgsa_8ANoTc|bCTL9h{ClsBh`0+lu3rN%}yfmp%`O_<XIc4{<x zDK>&@<ogGiDX<D25f`g33PeX;ruW5F7dGrI$FS4ZC#IRRc>N}tJSdpT_EEpeak)h~ z0NG8%9x*lEgpBW(7f?%~M?NI;K{F`uFyXND5%?$L!<^NYeV9y_O#DOPhq?xaPh<;3 z0Smo73t1M&(w4i$JoK?3ibR!<q>-GIxBLQlAp8@9M-l$UIg=yV>8y$nd{Oo)L#+ca z#pFXV9i6a691xv?Du@bjfQtW+Adify(2$-yj5>^PaX)CA<O?Y6vBnIHM8b@(OTo9~ zPTb(_$b2V5_(Fmc=$r_)_cqxoHA{~*ltL4AntL<=Bz89*g3+gk)l+?1iW(kboi;AC zFj~VGXf)p23{9i(l&hD-!p@7E6i3ViT_!Iq6-8!>m_8RHukZ|9U}xLmJQ@4t^38%l zw0o0@+b{@VIfEQkNOKA12!u74y6lsX5N()35F?p*d!s4=6zG1|(G<n~lyTziQVRz? zt&4OBH05w2GV!Geh{5y)fJi81<E%HY=zKOl7EKRui#k%GQ^8F4Ty#Qa84R}VNEX0a zd~%qG00j+21ayjrD)Jq*DVI%C5;0YKvg|b|gg&(^6ze9&8xxeq$(5xsiRTA~6A&cw zODJ7fj6x9^yAh_<B;Hqk0#C&-hiPTheA7!b43enyK&pV`lPvrWCzW%3lPIAHgGvV^ zb@McuQeys0FUtgm2|<$rBx<G^I13D(vREIs2>{9=00B>dIq_z}b79q{L>@`Q;iRAN z3n%K`Q#)XkZ~)smDdJZInp%`(om_x~y@eNS3SuM$Q7L0hltzSs;Rj$wwOf1(Vurbr zcaTH|8n*}qf+dtmL6KxPArM3iWmQEW21b--Zn&|;_ZBRm$S}s*I1s`j-;zrY%@<_D zZZU~RkG~??M67Zk?E~ze$%k-7Mj{TzESgIeLLrL@#0W-8(tk0<`Fgy%%uv%1a#-|S zfjEjWz^>RXE!og=Ev;Ic2_}xF5bakz1mEHa*5Ni1TeE=gYeWpFGLl3(9yZ46HW&gq zwl<G2fQq~67Giaa{K`TUS`q13OUKkxhRT)^x}RlPX0UzKk!GjFFs!y=37mC!>$t(= zXyg&KM(eKoi!UQBhSLoP8ECR0P<!kf+a81__?PrQ+n*KwBe268sxM=KP!!=%%we=Z z<dJ<+IJPF_VDKB0&45B`48p5Lcm!7^1SO#&O*wh4fQ6nZasd$qW&%+O3_+yqcOxu- zfC4%Z1mK<<PBBq35F!YS&`juCnvli)CkRoqMdwlS=Ok1}y(kFC=)KL0G1D2gK-3Xv z=aVi*XBkDoV43LBQROd_q*0CdsY8X4FI}Y0G0;zQ83cn8(9lJRs8xkz9}2f{`?v{) zE9jyG*lH<k@DWn^K(BUoK$SVfJ}7|qD4HM$sU2XQP7I<X*>Hm~iX&wa@CZ0r7`cCd z5n##l%%CQ}VlQ*F9vNgG1Vw6=8X$y8sg@M_V?t=6u*Ud9)RZpGSSL%q8@W{rOeYiy zcLeTo3Z;spDRAonZ4gcYWBu`W9p+Fj54o+Mg#oW8)jvw&h%!n8K2N8<`vYuz3EIH( zx%f?g2DG0_7WotgALJ+216Y_o5?uU9d{G9YAh*Zgqq|uZf_AXH%6@iV!O9Pvi+rLE zFg)M&VCC|#B7>A_`i|xkLBy8+^S(?3IIT#40S#!okzem9ik~JMfqd~t?yKs|lMo<7 z4IqP6&E)0eALftc<{62_8eYV-^1zB3Krd4ZxJ>v7gn?1^x6E7BRI)Z9(TV8!V}A#y zNTjFmfP^LGg9J(+BYY=d=~MyGU}68q|0ZYE2554yNZf#`ObQ{4CHepOmSs2EC&WTq z<iQ9_;)5Cn{Qi;Mn3-G&8sx4Vk*|Cz<V^T0;BS!(xe(VbtVA~sT4$5@BG>8|S@VI2 z?}{$+W(#};`YdW}!gX`v5T^c5-q<|tz$Ly!7%uJmi6aMw5k<%Le)h-hgn}T&cMsH8 zRv}UpJ^+2f8=<d?j1`GG|2Bu$7CIGzvBf~tk?y{@J$BE}^1#>EH<Ho!gW?YlEUj&L zmafy%KvCY3V<!=N9+EB70q>!_3f~r7P<XMYwF0^;0-r?$gA{85xI$xNn6X4Iy3S#h zJ%_#^TP*^-h_O&DNQ){3xOp3)wTB!+0|Yo^0mfNL*WA~U#gHu>0tOvBtHa9H94GiF zWqSbP-%qvo0?8vwAu5he44NdEMYJMXr&SOG3n*!KtBM^5-BlEfx=y+R#X?x15ETa5 zKp;8=iHrxRONTG;;!q&b!*jUe8M+okU@g^K;{=bWHoAR)CEw@{Is`zI7)F4&XB^ij z(h^~684M60CZN^In>;iKrhXDcIFeWu8DNWAs6m35-slfX0=a1Fap`%1SJI>ZjHzzw zkV5=_fyjv?`hgHY$nFx~ngiKBM05wlNfGIU@}^MEA_n~N$4;WfTkDtL-mQByBb+m9 zj7Zvxn&Q4Gr*wmH8<6tC4``J(gFpE$1Tw?jYE3cMrh52omZaBE!1<1b()i0Q36_Hl z82{ZO1Rk%C0JK;pT#4Z;LRvf}WMIV}AQ+z!o8lxsVNgs44k0JNKqd=qA0aPJ4p)j9 zGKEcqtx;m!lCsBNlm|H<fF+XvN9}>X!1OM_G3*^q<sm#WGGJ4ZuScjPWJYtj{n`NZ zW-x!lX={CFgdsBC2}P;na#I}$eT)?&DZX|2J+rE>kafN%<)~4XB7C@s6R4D<m%@?~ z5^<|L<>&=!+=31d?kEAbgA4NeZ7oWG3!M`u7s-hlnC_Dm#PTRD-9`Ye@pXk`7l<!D zP;%gx5IDwClcNKoZ11CoeqrW;Cj<zLVLh`(6i_2x3)Dn=`Gj#$0wB5>G>Ae<omL3< zBD}OohGJGoIY5dZxh%OJ4q%7VR4p?EN^e-QYHyivy>?YOO2EID!B<bK3a4eP(R)E3 zV2kV1-lXPe)A7LBdM7f!MdnV^y+_wW4D*D$+1b-Kfg7}5+*e_6p$^CjHwcB|QlaJ3 zY1oz`v>^(;DVne`)Mr{K)rj3vLK%r#P;+IeU)y*&!p|_`*liT$w#ymx`lsU75)124 z^K1ts@DgZ1v;Pd|@~0N3lA4%E$8C0b34pACeh4+N7^RGh-w=MnSTfH7K)6~*Xd#9% z9EUU<HVSAUVPzTv56fo%MAk@58sr^=jOfpX83~YZpodom8EpmGhYZRZ{tYqJ=LS~9 zp&&LWVi+PLDh~+*tPlYaS?AX>uOQHpuPH_p2E~X4R$4d-XNu6+vMabepk$~Fh5_IX z$^yU^4lI7+*r8BeHv8n%-$`+W{+fq!eqCZiED6-YM>&kX3C;t75d&T}+1U_ptby{1 z<&3I~({;=2JLIbU|2cnW%$tdBUJ?|QdQV6KTa2^nOH$)Ks(l-H3Yispv2*jVYi~tb zB&BgZWZyagnZ|jL{ShM5XCC<lyA7va$|GRrI~}r-WfuZ(8!K)|$Sl%*A%m63#xs$o zo8qx5z9VX~M4Gz8TomHQdwog`@e0}jfg&qo7t@s$I5f01?{=ozIg|S1S5R%hHdzdz zTpLN3w2VN`z2){W2@hGF3l%^~TEMQ0;lgl|rr-bp%@fOH!67WTa(Q5$Rx6iFWWgCo zrbQ_lrU?zn0FanX5tBq_3#G%gL<-_KBsC$LiA1wBWE26Z0Ntx}0IdT@E{oE{Z8>0A z^5Uv-6?dpnQGjB-rsJl_MOPV-;yj31%G*cC^+4hixI+<(EPz0t5=l)|svFGc#LF!e z-Abl3Uuak&H@m6ZnO8;=H?NaUYofn6+My)_Fib@W{EM=!l7Z5W{8Nf;XS0(!k25?r zQKTX!Tq;%qY=w{|$KQ$k@(H0Qm?h50dmWR+jSv7Ggz5lNwUB!tKoV~I0xjd8a7Xz+ zH*tM@D>MQbQL{PRV*(NAIFfaDhXLQYLw6v|12PY?OSWK_T;2vY!<ZlprQ5(Zp>93k zFoOe&@VuD!Qra&L;Roa|08E`WZVDWwr%H$#oDX!l6)vc)awVcbl0DGqm=v;NYYel4 zFa2tE+J(<417)R4DK$s}4V45~#`!u;#0orDyl6TH;lx}>yiokG3cKncw4BY;yoy## zM#v>l_<4JM>8-e-q%V^km>AdEo2Uv_QFtaea1eN!sAdIe(vZd_wp0#U)|(bPotn;; zYF&0!3Iqg^Ow>g3_jGfGlx1a5_`M8?FwY~l9g)miShdwrX_b6Cs|#avz8|6GBVL6X z?Ekj<YE3_SuvZK?k6o6wPbuAXimKR5CyM%8W+dmDy6#+p!N2nZ#DDiSrw+5d2;n$m zA&7k%K?ail@ar@Q&Am*UF09a@g;FOY<z|#BRg-yTEDEd#Sc8cGF!(vE_H_jUWx%ny zgyQ6J4b+VIjPH-%FotFbHRu(!F_i7$#l%N58{lCN!76Am1TuRyL~pf=FoC8k5=Z&r zA3+8q6NiMbdI)tEGiZ6Q%6{s4@+5}27m_hrFVN@(P<{{{@_avljD@5hau%gb373I} zAMo}>S55<n-xVS3l)jLl2<9~8d;o1SCMLFVpHFB*Fc{S~4T=>swi!`VQ^Z<kGm<Nj zsJ9rw@J${9)Ir^OOsZ~{@UEr@0pn^2)v;C?p^4u^Wt=6(V5m2QHe3~Mx*$pL4qPHd zoRGrKMN%9B)m)#b(rlNP4{sS2D}z3%Ya0!i(VwNg7HK4i{?`5H8sBrhQ;u+qe8M_w zY6T~wvEI1_jr!I^9$>!?AY0LcM+;AfqlbNw^Q$zFNR_a`&YtjqXLb77kCmhA(bz(` zzMS@u4HAfq5)V8<=0L%*0vqT6H$|3!2Y1O%rz|J=s1gfu+DU0LjG)4HZt;^2&v%<B z;khoeO_awdra7c@53kT7ONJb?<>CY8jM*H4J^g;jAYSfwK?VWT`QNm~=OhQ;&iWAp zXi<tBLaRA$aELR+r#OzxW5nT=p3H=?NfxOwLLvDIa=jdJj>ce#!6`NrgY+h6ASkRB z;0A;dQit*BV64nR;whK}^$aRJ00AI&KHItqu-^>lS%=N96hr1#g77zDc#uZoc?Vgz zEhvL2qK3##K#Xfd`B4Pv%S_V`C})!y;)bSB1aTycPXO3RV9DE2PQ&7pG$tLd7|4_H zlz?J41nG8AFp??;)UUPiDs6zBGwg5F3y7F?AHu)8Lo^@LPb1hjAvqS%XI+sJ2+@-y z=!H~k31p`fF>ryw@ZJUJ(W){@1?baB%h<xei(7lU-$LDOzK7>vO{$JB+rTD>!L3e; zFQhE4DDG_3^H}?dZ<VQaCN{l`NLvQ*Pi9p$6+M}Ht2)1v-y%iP>DjXPnmTpow4G}D zdfHkrA>2|n=s2z-Q?X5+>(ia%LXzcD#=T|FOC=*`WlB>&AR+r7<XdOTFK;!|B_0ZJ z4JgcvfMK%ingO7A;np);15XV%;kw;L^cD~(@0H`9&S>Upfj1Z17&YjHbvrn$h&4oH zvTT;`We_1@W$EBR>u^}r5@d@&DqqkVwUO(A)J+V^{6Oog!C4R7l^iK%CKH%Aw`6Sp zdlVyOxWEZBfB>XrHUgGPfbOU3V(7OhR#(6|*23WQ2mDaHx)VQWf;TRd0$K2beg)!H z2@#?2ca6lMut}(yuTFy7U)0=_eKrsCfy@g%wfADI*hj3`U-rQJ3qddB0=#3+@1trn z1r5a{b&2L^?>r#NBXlSARraZ!w$?EM4kUpc6TNJgc=k^hXE4%?@vugo;ixV~*fb6^ zAV!A>O2U4V8`P+4bK4;j(iDTj*#>8#2qqREN?sB#8lRP9U@IdWLh?HB!lCp+BZwGL zWeq1=2C4pGV9Oy;?FJ!25Vl5Ol+{#R^<;|hLy!Mc#$1S(3Ru^I1+CB$S2sK;v$IQn z%{IM0wdRxNUFukSy%A(om;h-nB8bK695QSYUojof+_0nYr=Q+G9-sZ1g=}woXe>lC z2(aV|EeRv_Ad0D0yv0JN1N4XKQ@bLAfR4j4XpUX)%Bxrw))8&jD@+d2k%t8%7HwSA zx8ySs(&9EermzCEfS>hGoa4qZP?tFI7zB}IYg^wjSiDmaFcB>5jl9F~X$mCzy(EOs zq+LCW1wB#J$rTYIiDIDtNwY!?sC@A--x;>xfIVLg(p*#m^Ex<0fb%m+LDViWrDp?y z$p*8Vs+S8Gmk}_QVgayJ*~pQ!K^hhQfdw8`1B$D5nME_^E^U3SL@X1}MmJ<qDf}#i zF&LNBO%#X)3tH&3c;z<9?ZOZN5O5U^$A)nM;d-_`tbUWGY@-liWe+jxmWead$dlcP z00I&{LVblSOk+N6-*HHV?_AQdM1c>DY!f36t<J#31|@uvxFZp3pzgzJsl=Vopi9+& zs7`YlmB10|gj3~1k3{Rx<cQP?Rv)gU1S!kC?4d_fyO`P~i9H5rai3`8zu=lSRJynj z%>jTR5%+jyFW{V$rE?d&)?9%+k=?YzbT;vR3K5W%lkyPRM6vB!0wOn{MeOwGq5GyZ zzOH`Hg)~nQ1}R2=p!n{BVqG>&x1foBkmPZ?Wfpl+fd{;ddi=O`GbsT9Z@4^!tkM`J zXlIQ)ZXFKs5nNOU06!{z)6&T^2NalbU*Z~AS)DmwO77930;2%}cawSZ8$&f2J8dNb z!NI+xZh8}DAYc-+Oz6keLB;Z#CR<XSsskz*6ICh(P!T6M4XS^$>uw}O7D6KGYb5}J zQKo<t+hiv351eV3edyi;V+SO5t)w-*LKiFvffc%;Xwl5})pP)fuz6Y{cU~D_9}Ga~ zt{QQIG*|Y=C-;L!UJRIb+NyIN?XZ9|Iou6W(9U2rXrfuHquX)7V0(FaAMsL8=!wx+ zn`LLzTFEOC?%Y^0NLfVm8|fu?*oxl<2f$p!;O8)JVJC)GtH6LO6q!QCwq%qC@GqZV zAFk?A1HZ_ur2uRZN3#v591_*)Zorb#Vpbq2BU{*bqj5GVg=Eoe>F=ULa_(V?ZS^p< z0|BJk^o@k>*AY3a4@x^^h)BRizZn}CR1DkOG&`Vj_K=!L#WVt#>KKB0B#i4S7@zBq zK&giFLp+#=u#1e!%R*c4Lcm5c=)%quxulSp;qhNOBay|_61A5w4@P9907(lDSMht; z1D3y1m=QiefpPVlrH!$!G_EGV1~F8x08M^sqYa2`&q@mlRM_ri6>r(gV0iQ_4WnEc zM1+sR0YeVxK0{BC?FHLwI6EnL{fZ|E>EN+I{17ubPn|DI2vo#n)Qrbbo)NZP1dCo^ za$?{F`HGhAAqrvQL_pAL)hJQnN&gWvbVUVK49!JZHGOO2dRJU?UW)=GtCmoU8_63+ zASU2~y&<_8IF$%TX4TRt(0Xvq0W0FFG)d1x056odoj}ur8zHGdF*caq^`gv1|0)UN z5-2NT!-2-ryTQOk_<gNPmioH^zQeHk5FR1|+KzS@o$O-xe4i7ek(tSb4V!@=%0*rK zqq5!Q%Vg`81z<ezWjP4AjKf8oDfbo9W!#VsSDAt0T!WxPm7%H0?8psr8hmKgNf<pJ ztGpmGds2p5a3}Ry0B`&S)NGlh|2ph2`pr;~Z?mJxr~W4lvkH}nAWX10`ITAWZzIU8 zTOr#>(Y!U7PuY26EOM})<V6EtME<OZ^nei1eF3Di=XkS9(NuL|aWphGw9o^H^9Ic| zksCUjg;QWdz^S$Qg#%~e08&IEMf=gA)oP1fAPrftA?Dml9U~8e%pe!JfVoENN`Rdh z6}C0io~CCHWDNMDa|Po9_JJ#aZrk8=)sqY?P!y+>y_>e#u|aH8uOR^dL4S+ZRfLB( zX{H3KNddK|vxMAoK<yDHt%Due<A!Z8D{PFLg|KJk98ZT!D)Smd*S(h`EVKtseNEK$ z(3=vhDkNda16F7nP`nYj2vb&LF9D|kamLyf;5fbYTdSW2SCBA^Nv?fEjJqsiB+bQ! z;yb@Y57vbBsLh;&6O4`5B1s+O(IG>mp;liM=#9Q~>>?y|Mhc4`mnrQ1%S{+YW(o(v zlXY3YIBJIXq`^ZDc#B8BCe)o{pmCEGg|sqbb6qi@9bvhWgc2P9EyRL@IHfOCQe@mC z!ptIFkPx$D=5cwGRY3G<$nqR%I@c5sCpmjz2-dt-jKm=R8ATzPce8<Dn79YCCC6>_ zjue8OP;Iehh#vqS&523zVpnKiL6GQ=%=IC?3Y{KK3GxNb&#Md)j3)`yR1wjhBST38 z(r21Fw-f^|kHRh-CK;M^1V99e!V`PZ>xVR4><WRskFkn5Na);N1`CNBQ);<yBNv?U zQ-y3rU%5u0X$I+w<TVp*F#}1EAT+JhbVUnGA^71OrKO-$!vg6C(p<1L(N7AS>tbHp zJvW-mft<M%zrI4sjGKTLL(E{h0Ag>baiwBWghW_4^LZKx!M>=Js5+`NACsi4|Humn zo343)Jv!mKj@C5Eo}Znzd3gYA#Vx!BaeDb;ERUs8;cH|TfCL<6e0muUp`j8n7$ZKi z&;{xM{?IBZOhos+5iiNvej{daOpJWYM<Mb=OzXTVaXEDOi8jzw5CkL#4_1HBsgbA< zVg#6hvbKS&2q;4bCM5ICvJ{Q7q8Bru<ZFn$)<{!FN}eKiJ+6e9J%oOlz$C~sl<(!9 zXKfRHVeZ%QnyP=;lP3N)ME{yu#&07d66M6j4-aOoD@O40Ci5>N5y7kB#A-zyhpcMm z=9u#p0g?6M|Du!%2=t0(3#c)QT)RO0<1E*f2#7m%kJ*>$BH*Imfi?ViXujinpbkmI z5vczw5SE}Usy7dUzVZpj?+l3HH<5Q6cpOcIF~<y18i83zRHH`-&F`YP6yfNsbW?x? z2m(ZeNesn{F`U>%$t1$gGH|M}WX{GSNKbKlGC2WC=lDG{lnXNwS|<+!Jg1ihy%|X2 zZKX+7vIN~YZ6v!j-T*I$zDCXaroYsnCdL;UZU(2aPoX9#SC=<d-C$iL!6GwScwDY@ zP^_~7#8Rm_%vuJcjAG!`W5yn~fSY_VNFJV3EXke|#S{Zn(bt1+P}LA;WGdYZJp?lp zqeBdYwaziPJF&)OxeE(oCqeq8OlygZ@kX#hW+48#kC2=^%2<ik7Y)g|AD}dNpi@pF z<Y59ZX5$S!9HtOOlleaGN;2o6`UM(b^aA;0n#q<{(E_Jv+vrQk{9n_Guk9i{MjDZQ zGbf^_V6x<Gl9@PWkdLSkS`i02&k^w~SBaV4h=_D1=<ldmV>zNn1b~D$`4ztXlGH(! z!)ZAlu&Kt}cyqou8WVdYk_(#xFSHoLF?-2f9z_eC(DY3Qj|eGdwUjIr9j-I`6iHSg z<tT-hxc4;HRGW;8vNL;nXpoxCERZ96@H$I!6t^abg@G~a^Oh_Nb|wT}3Gm^ht0D90 zaZqHM2xN~z!JOFvyz+pgFhux1e5uTNadnJ9%l*)RRQ8sKhbfqQ>bVn0*^?qa5m2=k zqY))W#uC2H`7<N5vJbZq&sC!luOezk{`Sv7P2)q;nCtE>AVb3kM$#Dy!zvkzU<&SI zlS6iVvz5p`@fF*u1CYPEnjT+IWeaPm@b}<o8~bB14oF~&b>hVqci}^hWG`0p15sJb zGzC4ULIN1%Os>?Iii|J}tBTJ@yul4`S+Yy>a&f`U<30|6D{2t(F8XY@)4_3diH1ag zbvZGy04d+ORk(Hqm|9Q9XKnyC@3ic5aU9nN9fmeqV2wkvlMkT>aPR2s^Q1^K1cH-p z#T!(BVNl8<eJo}G_`-6GOwqt)iRk&U1F=&eEP%az4p*8$U@vtH{*!3|ywkw5O;00v z&q2VA@GS>ln}`EQ><!kMV-A8c7R&pLj0m)!L5D`Qa9PbW4C2;oZGcP<iyl*!THX^~ zv9OVfl#rQ0<mkxl_G%iV(}KeM50EHoDCWViYMOBJ0Fg-(xuIQ;VOpA;(vihf-zBm~ z3rr|&XJOzpjBo&EG^Qm;pq^VB7Sh~K4+X!hhIJZ(OoxyX`{K!{7o9+WYE#iA=@bc8 zLlD|MBXI^X1{*^OCS?Y<E9EXkz&a?_fT)0l<N64ui_;<Uh`Ne3oF3y=I(s(+yrzY; zl|j%7ma|DhCqDm8WZdy&h8h&^4v|AFgPf5#E+<0h7GtIuQnaZ1J)1GC5=<c+H(i4X zAepvs%ACNRz;lW>A1DE59_+>))BdoktCxd4D}A2zI{1w#mRO!p;6iaFKP&e8+If&J z>)qZVaFJ7b_?q+rT7lc91R>h~Z)|4RB}r0Kb}_edfgGgD<YE--h^l66aoFM_1R)%1 z*OE4jp_PAz09IPa9In^f0t78E<Q>ozQjmj0sOVKY0MunTCOHg~T_m})K8<nNLA+Xv z$>Ux?<HBSE{7xgv53cpq0iZ9$=S2<s&SQ#RQkFYlkZ-KhH#2h)(4#X&MTPWRu4t7~ z7}t5UG&cxESS^!imIz9lqdyX#6*sJD@FJ)&W911I2+i<Yxozh`kJ|-~*Rlp(qh%Q( zXoy<@uM=-cE-TwWV?pF7uq+94vnG)vSt_JG>Xvn6zCrE5WxwL`-fy%Sunw8>Dy)7j zFQ0GF1aq)pAcFmYnIJA<kgzReV3uMaqZok)CeGMDSqE4`90eIH(KzK8Cqm+YWdv3~ z!82!&VbY3`L{Fd<{26zpFUUqvo8kdt&Bp3BbX<4dGP$>eM-9Jp1W#gwDEr7M#DvcD zxrPl8g4%-e_cRuQuxxuI0&xUkk^vl|J|@cWEyOI_+gkV;DuXhfQ-K6D0xf?GL{U+c z%pE{vK3iiJU}tblJo6XAhDU2ClS%wgF*{)Mq;om|K>?I!JK%YK6WXH`fnG|WFM1HG z&C&o8Hf-}5Jp@OKICEZ!Vc8JyL%>Z5FGIXabO%8^!haW_h@6>anCwW-d9Bn0=0H=> z0EvH^uL_=^<+CAiv=;Q=&<+v11HBEV>E1R`A@b3nEoxiXo5gmGDPwPk#j@$7WAZW) zA&89x?FO0vph6(f$Td_69|7$6u2|8K6FFx&iRwi^njl|w7KHAhEsQb)0vefWmXOQ7 zq23E0niDf@+>m?b-T>X?+(VykKrBDCz62pCRVIq?#rB^jfXLJqwopKPxHt+RSsTCy zs9dckfFYVw3|n~tB69@f;|eAy{O0l$DDZ@W?p}dM7$^;fok@lS36TA?cD@LhO$k{M zbD1wq=zT&KV%k6q2%O0ZxLF{NL?`;dc1W^rY9LW=<5)=YZBMj<iUM*Ej~SQ?H6doh zOmMKpLXk#$S6|j&gYygpd2|VsEDR1m3_{_xs(_^kCNBYFi~=7L&~u_g8!S(~Jk~zM z1?-_?Hl|SvY~xo^S>Nk*0LdC^-WtDRNC!I#>kk8jDYOF`@#y&Uz8coYKMMCSHCo_t z43Z!fx5_g(6$)7?&uSBI8kOPan~7Q`qD=!B&`-grKv74VjVdf2A7;><C<JpP5kM*I z;1?mQW<#>Zf@(9Nrm-(F7T`c>+dx-Op2by<Pzf9u5{v@JfobC*jNp10Et1yZ@fG4S zVXq8gVh~#i)tJap9t6HX3NTKhqK{Dy+93c~222w*3{tag4wxVbjDXn!c#-6R30m8x zWx51V9|-b5P-a^t8jA)(jS`8_;~F6mQDD_@3|*u+aK(*H^$*DOf~9{clz4bwK1w|> z9}E7pSUEgkLSQDN0K$EFf<vTUo$Sz*1HocpG)bYecg2322KvLHfxZ~1_$5OolH1Ih zW2Y#Q5cB{Wagl(;Ft-R3Mi_qd!G`ZbL{d`45Ch1JQOjBj2qKO`ymyonuS9xeZVeLV zxU2hfj3|VISm^zy1a$HY1hL}?T{h;rQjg(C*iD6mF_o$NFNsNnq_@9aM;LgXZLv!? z%R+Qham@g-Vj~zKBm8VbtgvoJ+|&T#63#{oY(<ho%o0R`P}?LE7%dJ6flAW=wUe-r zh0BPgpkrdB41&usA;Tz8C=x<YD<B{s1aQ{tndTAsV~HEF`6aDf-Xol}L}vklX4XAN z>%<!R2ZK`h$7>J)zTvm4rHs1=CdP7l3pPbj2>_<>=t1DOOi3{#Pk`ZsGW9%BF@nU% zjbZnA=N}`WNbAGk23Qbd`!JZB86*S{vY@*LOe(_m{MYUI+@5%nv0(sExvJV=fVnJ; zqV(`x9)rQbzDDO29kLu+p}3bJ3>OTIPdTgwo>%cmuqK*hUh5OXb9qp9nIa-0C3Xe) zoUBdCWQa#%1#s`tY&e4T1-0JbwPDqh20VM@Kt+wrkw?5Y9|wS;Yv|QDefNq)n@B_# zMK1))0){8By(qaf93^&0PwXThKosmnLNwa(3;l<>^kZqRkf^X{_qhk^CO*h#oM?*4 z@gI#fh^q8;+#^q|dGVLRb<EwQP0&=cVxdtO`^?#K{wSjBXvst^I=UC6XweKPJfpTV zFpfOer^5c^u{Fm*xEehiQoHQ}j`0zn;<nNT@iU6(o^j#u%|>w8I+ith)D=90@HLU9 zEXA^rIP-w3t>klia48(#QfUkv7SU(O-iIpLDT+pG>!SboqWunu`!KP0k8w^TadDwC zFxR5wK;-;hMsILv$^@~I5uPt}v3}jmshU~6yDMy593Y2S-Yq9Sh9eAaEjVnhVRbMF zVK5nC>_c4`cAN}x5A1*6Ama2wxKEZ4UM;`gAuReqzn{C8_h>77-uVTLj)Uhx(L#wS z>`1lq*$t=%lBT$tMjVEL(MW0m`hGTi2)+}M%<P1j_<<YT$R69$M!!_*#+_Jo#=|P{ z57)6f>&g5-9(5VZ*}Ku*Xn4zkF|fkST0GgDaUdAUg{U-Z+vb%_mD%gYvr*hbVn8;b z4*5y_5ipKFmbfxiH9keY!F?wO!-uM6&JSeNCnu};@KSZxXW%t%M8o-;!+0?@XbUEb zg<QTFK1Y`-Gu_K}NmYSoy+K#D`Hz9Bu=~$idEJ^4!IQC##S89%lo>6z()r;v=qd;u zHu)+^-nPhTC%lPMV#Jn1+q;DycTcxYb0N;M-W!}Is^pD$S$zp55#Kroe#uIS;mEF| zsx}Nz*VIh-S>h7Ts`<v*#owvH^FJqm{72#{ue%#t^{X!5-g{V!IB&@<tO$&H`2v!R zypmg~>F(yw%1GP=%oo<VStos@{FK=z;!)8_7sP}KT)Sbwfb|kBk*teQI{SS3+VMGw zF5o#5Dwv5gfQAR;?RE`BSQ6$UUV?ZmvLpLQ_7G_WU2s#!p>ap6uDhWeI3;vM(6%O> z>PiV=U8+C#Qor|As1tM)c-jVRmk`D`+zKQ-hs$atf9ThmVa?S2`bZVHNV(0e$b5^z zzVgWYe#PVnnYY4CdY)oqtU^I#Ly-+c+Ax_CjAvP+4z88w(oJ(pF=Bm)=I}VG>^BHs ziQG=0(ifnO->hb2sQt$5RSDX<c+nTy2Yvu-#b#bm1Im)KuB!J|XKr?aRT)6mx2N9^ z{VI)FVZ&<1bPr$jwiQhYOA3^lKv<}eS}hnO4LYsJ7)8t&L|21k4}uuS!yf35fG*;W z;UD6XA2~8*h*eFbn=4c}KCnr%_B2SF@S)1mngTDev}E6fGz9fBG|{?Zh|<JJ0CT&# zS7FQ=0bqB9OsIr{jnxNadr<{QYVHN39~GzZy!&!n&SrgURWOPFxe^Z+gUd>^5HuZx z3g2wY$4(pT3KY$Zr5sjzA%?X-pR|15M2-MLCQg;@<Db#Vat37jS4fi;zX*&4IOHiq z5N^6`8POGoTp57z;JXzR!GOo^aOjdmK-rO!L|F#EtQIduoBVFNt=UX<`#~z=eG+{A z)OLY|LevbAc;5AioC~0T!oHH$;BA}>!9UOQLCyFuC(x|gTuNj!IARxKl}P&$7cX;y z9h}sIW^L$LG|)w(4HyB;5L_h1oG3NT^$02Crj47-+`etILM=X3*5N+rJU7k1Eu(-$ z$xC*O5rcqoe-H|yylRFuA2fPi(Z(M9No0K53Jz(5h)uH$ZefuGK~5fw4Zvu)@VG|t z7FF36Aji%JD{^d>B430$hpZ=9BZMzHutzKjzh+7|h_z)Q0kTa&v5Vl~nk5H*wh=Ri zbhE8KOdCKV6`xiip#l<%2+whin9nk!G(o&Hf-xg2YCY`C^V>0Y0xHRaZ_RL<Z}Gro zCRo$Bijy}9A~Xw{-vMnEF`&w<@>)_|xl2VI{B`yMC{k)Z(&vK_ejCgVN=-uZDPpW@ zwE7yQuuCe>&HFTmXCPuB2L_akOFqCVAUs&=NS!C-?p%F1v&dAq9Y~$V)Rz4)bih)? zN9P+{dL}f>5a9|K>H*Dm+(@_iXdiN3qF&<-`-od6rHsRQi#7H4W;*=^G#1G}6+;7B z3Uf=R9wE5FwCQFPFoKd*kYG?WmIP%t_MjyRFCdm->0jR%padgAMN|{)Z|BftcHf@I z@#G*X%(xQBz`pR8Cm~<JfwyCaTRCEL272!$hwl3t-%<yfV}hc2@nC}NIj|LuIx0Xn z;3ImDK|3h+x<2#<H;!0xQY5rs`Tqe4?nfHM8le1<IdCU_1kI@gi;$D0L3k8=3BB#^ z_eE~06PF_S86rp_bt!qKdl7_QltR~iXP2;^2^$e?Ng0Yn)}e=Ivk~}dt3YJ^DFrE( zNUGT-Q1QDHtlVLUD9heBia50I-)s#RwqYFShQqO&c$!X@<gY6OD-I$b+=@2oL$lZ! zB*r=7A5QFA;l!}ZY{y8+ztuHhmnF!OD6Ps;QshSI0-+i~Dfm~4c8XGlxKgkZBjoWi z2!|;y)F4Wq@=X+vII=nJJu|5^#SyzRmWK|6K#&$UBnk-T=RW$ICv_!Y$-i3=`r}I4 zThaHikI5rQ!GJ60kQ7+R;R1}j;dJzm&7+i$pwG0b$7Fp^lF<>ulL%}^VM&ONbufvL zbs>(?Tu`4+OyY(9C{Hq2s$zH0jZXnjM(hVBHbjYRavL1#Xz{@e|8$5<+~VRhZc{KY zyBrn``sLk9%-heQqI)a6K>-d4+mW{^IyCJa`*%eSV}rTVDTab>#;^-nYvmMlc4{IZ z*^J3{wENCT_ar+pDw%e8$q~ZKNuF`58bpDviEsxzzF`yWGU1PS*C(AE2>=<_cimVK z8YxF<pSlQuY=8y?b8zm68CpOeOu_SV9Y=P{g5G0C<TG@mFzsJ6<92Kk01=}t4LTE+ z@q-Xh#NA!XB3P(qKZYe>1ehj^dQEo=gP3S``~mbM_k)f!4zrr-0B8Z>l4M?h=E%gz zO#lwRT-(IckL*T@HH&|RCS;GZ$cb}XLFuzHV3^Hek;Nc7LZiG(lE|aA3M54g7NIO? zg_{7_F@S8RT<L&7+AtSrJit&-MdKXF9A&H1F#M~L9!No|3*n9@-hd{c&8sOMo~CF& zolp@sgV<A|1XxA{&|#twg*}}l82q=(LWEyWSTnBhRMAg0jcgHgk_Zh4nv+8`9%*zQ zX&3`E9%!^4Xpm`9#aYuc%BR~E6uc(gMZPhj>|<&@^cA|&8w`f)GC81#Et+YX@FN`* zZJ~Jaf17Yp&ribq=@4HG9t#<VBOLyINH}enKZN^bu)~=yMzDxE@;l*AAEc{!8UFao zaU5pdq+DsUtkIh%BbfQ0Ul_eQ@VH14t&E7-#|$)8?uFJC<4Yv}^?I$uW`a%%$kMX0 zojfi6IjwKx)6w|JW1#ZSWvR`aO{m*3*AYzD76j=oBy8zi!V-Oyl<2}@j#<nH&S*gs zJE#1y5d#=o3v{6f19P#ItWC#YZBMhg#Yc>#PzliYuTYrVSB`Q6J&9Iobv6zA26jEg z3G);SfX9hb`A#<*Pz|{!Vf-zcn|Td5-x8M>rvitEhb<X-O-$#2Y52G`r3Z8YpO)~` z0qLR-;r?hw`5+tKMuJzZ8N;-Xt^lHUP4Sg1zt~k01hDIXBC*P5A664M4Uz*a0UR9T z<Gc#3YJ$&eNLH;SHq&Bwro_toh-*8~p$LndHEIl(aipKMkiSBMxs0P-!>3riSXSl9 z^<`pUwB{KZg_mJ4eE2vCIT5YSh3D!Fb6$UFDWG#MWv~~Pgoq8rm9%wYUIn>ymsCez zvS)n95Z5=!knTv7_i{}2KX;r(D5q1KW*?LSF5{x1WMN`+MK0u)RfO!c%cbPv9)vMC zHMYGa4qf_ZBY$xt@!7h9C@ImE1ih962NYTaTp+kr0y#F%Y`uy`nzD%rIF6Jgw%BK_ zlW-Chr(L&LA(2S@6o;IrXN!2?jE!k03sBYil>vKbrP#<sR8M$>(uLti%ZT=3SQ6*@ zCgZr!HY-QNDycP$mJxy^U!gQTRqg$MV>Jk-QfL^CV~agrQ%9Qt14rGO90<_Mo*E!H zr)qRK_vGblz&1NjX_EkEPmFZwsVo(uH?96@U{F$j7}?V-4Akbra%o^Beet0sNk2l3 ziy6O><*xW2>16avZzU@wHF+o~iDAl=-k473q8g5vijBD4p=X9)`mrEVIcurswtFPS zi8T!-$O424SJAlUG%*DQq<V&_jJSyJ6vh=Wr=Z&H_b~R`(hFX%i?s%HNM5}Gv+8<h z{O3S;@wB99h>iv!*EUE4a&FP7lodL^MkW@-5mPS~d!x2DLMUN8PMMpKb?*itkiN^O zLe0?pA9TU(Yoe!)YI)*dny27M^#R`00T(?D8~J2gZLsXeDJBHzMV~jCKuY|eEVeIG zFpOmdA_!)o*86+b_8lpatjZx8%)X?}Lbr+s>Dq2)jMs0GJngwxD*@Sk3)|m<#j7o` zs?^P5x(o9us)PbEH~=sl!f6z+I<c`Jih_U@FmFu<2Zhww&?@y}iAsOX9GrO|)Wq&C zOIT&S{po2Por&=yc}5{5@2m}bA4ee1g7V89M7av8tm!eWd4r1PXYJ0XlUDN}glR$$ zg2#fD)p}xN@l=#A;F(UWv8Bb}PBcpm$8IZMk^Qp&j6x7E?xx?yc0^bZ4w*83+I0)$ zH!6W22%diSSmivnlps8xdlzIla0C>#U8|*Ya|fgg;|sG~D->g<8%FTaOlsBvo~a0? z1WJ$_Y2lvGM$Fda$;U^ytRU$5G4H5leE_@^G*=5iYh>d;lr*n~!4QvyW>eSQuwLg{ zly%1GK~X($oh_9%IoOPIb{En*IItOg(g5Ge)WpU`k>gXd&L}uaDYt4`kH})m3iMev zL@5HfX_+sswfJtQ1fZc8&BQQl>;k7KZ-}WXL9rOns|5mN%TS8UrvgE59$Uk{s_-C< zAh=$$e{4CB0sfSe(JAYb0s|-jT(eS711n@l*)DqkT_W9HsU5v<Mn6PU@lA~6ln)6^ zE{xzR1n!^~xwr&+65!kdv5sjn44C~x2$oqQi*8-dy@{ZSe2W5bGA3Bd^DRIsQVyhs zQ=KVFo&7wwQk9TmKoelV1Hxjoc1Lo-AzfsUZ7{!YoMb4L_CFA3IrF8qngl28#n1@v z%-hh`3g;3;g68{b0Tl%EY8|>=J#lz+a-=AQ7$jKry-Cs#h9sLrU~Bcs4WpDR7!f{W zaE_p!e#r@l*&6{uU=fgjUZPv2jJZ+?ijXSwgHny`jT@lOI!R=E(rDX-qoaby>-IYr z2>tvgZm8baqjKGjxV*kP$|X$)Bi8OwBzFVW9aRC_Es1D9a@ZD!O3F|bO^qf%%y}b? z2aNowtN@V2&3~j_AHd5tSXJ_|n0yvGt)9gYetS_f>_{N=e~a&b(BQAdy*Lp7gH#T! ze1$gXmPE5ff*ryxc?Yry-j2xi`1FT}x%=MIJGluvirVcX9irmELE@XzG2Q&#$qVNh z6EuktWAtAaVGJBDKtDY{q-o8LMKO-OjUvu$(WQ)bEM?s>63E!bLE&swAwl9TV2?49 zCRV<TxtZnCf;sKJJPL8Z6_kf$jvwx^ZYMTc+;g9@I3<-<DMMAQQSk#3Oox;LE)-8J z(*xp6hdqhD#lSZD!C6>l`ie52r-hW?mCdl4_6<GKG$g#S8Twc+{w>b~#xbPfzl>}# zx<<lAFoOMC|Fs(yqb769!yqhv{7OcP(2uu*9ZWOUu}0D47`2%%F&Ik72Y@hV>@sW! z3vbp`gCOXdNM2vk(J|N}Un>#Di8zvWz)CJhEC8|uNIME$^TcK`5JpvxJQ_Teu<}v} z*Qaz6J?~vKY13XK$C5JvP$+ookn)2HBSD6Hb`__8ax7l+kO%^KwT&W~okfl!o#y#= zGMHjU?{=Z0dih}pyMum<!y_8kAxZhMlObY+!G!n;<pe+^h1(z+O;MkH-M<t;gQavn zx6fYqgYYC1ZI*;@;W9yMC`VU0ou6q?gvo95L&8Yy$bbmM9VFy)j*q<B6kEugw{cCw zBOx_T7dzD9bu+P@rZKVaZUte_k=jfAw6{YNT?CQ<)XAg;7*tDK<%y(Ua~XFc7@f@_ zYKo6}pp7vg7$n(gYW32Qb+H1lSuKB&8f?g-hp@8=&gK<&hc(P+W12Y8^4Y*C_UbIo zI=z_%De@(Ya_RuM@pe;vy1E)&!?MF%5lDLx(4&H;!(fuae;r(&h@IBZUL^%pq?Xe= zWc(^Q^8#*ywaBz3jn>6xfn8JKQOL9Rnf1zQ5;<2Qc=ik@QbEZBkfsd|^`Uz3PUP4d z+A^s}Eu%=iWXDQFmSQ9*!b>33BQUjPh~gpw9EwL&(Agzt%REAs8yB@{xj>&<i8n<k z(oFex<=VUgz}tC50LwFA5dh>v^1y+vk#S<M4@M;Qem6#zi4kMI<sK+hQRVJ-a#ixp zSw2~$OI94<Ky62~r*pG|p+x@9zFC3Gcc&TLsuJahH2`b+&ygMXB8RPV#4MVZtodS^ zwKje`&)qX2)uGx$LbE`jZ$H8@HJ{z%e7U8bKF1dFHd(KEt`Sl6cXLG;6dQzsL#t$e z5nO(idQI)@Zsm9WtXaU`AzksZ5~Y4rwUHLFjE<Ub1F2(V)fPEQ2J(@&pci<VfC)Qs zMqCP5mabz%<UIBaH%5`&r((Z>jR&m9LJJxlDYr2Qc+l*;2qeW(%hEnfXnqCT2{`DZ zzuLT2D>Rtl)0AWREyV?InWS&nZ;8G1ys$0GJvzQ97UI~V<A|qg5D+d2h>HMMLTiK} z4eO&KD1?wO^tO81%Ap@{NO@64rZ~fpg9lT?al+@wV17C-X5=fW3*2sQHNID-OEI3y z0zMu%4Ahd3e*B=@h?mdc^WdW+E8dd6W>3R35pkO`<Bz7DkOJrm>X9D^rY}EvBAkFT zU|_>AQ46cn$-mlW6Z^s~fy`?pCCs+BVGP^+`*j;%1c;;{By6glgPrj@7=Nz-$w!he zXX057MVyfbkr<G{x)?!po<%`%g2#rYqu@ar+zPttjZHmDR2N;DpCig9Lx|VK+?U3X z&4`{c2?oT&LV*Z+e}({=+8!xMfX8r}4l6dq6Ar^q-(zPijs`e)*|U}pAHibBjIsxi zIqp88{AIFw<-sP|qw!@;@7MouSpFO;Qz<;^K*p?Jcdz$p@ToG9#&xF*LSyM-`Y$r1 zypT0TTSz5F_vUcKk21}^4?bq9HM+0<aAlUf$sR{l!KfM5-~bJvE0yz5GlGIMDUg*z ze&+hD1e^+2zIq%&)WF=WMc{RV@69!KjAg%sMhPf>8OXseW`4eO7j9d$!Sv;^tmufu zXWA$zqN^%}QsoFxq^cp&#o$!T?k{xOj-^DyP5g<mbe(`oul34Efn6%|NH|AQB!%N) zD&W;Yn|0_0UCZyxuvG$BOfX{19*;u2(b7cYi#C%M^~H>cE`G{jZ${%LZNFz1WVU*d zo=eEUzsPT3ztd#ALMZY)K2G!RKT^F3BZPdZ4LyjV<E-?w$;kYE8PAAVBt77-!V=&l zBAU>UsMm&tp6`z4Mgxns2&IXY+yKQH5h8>Gh!f27#KB%rkv$DhwlC0UK75%KIV*@* zPQ+1;ECe|qLRQd`&^Gy<;afE96BtE#r4b4gZRELFx3aK_Mgr776$pchYE=DbnAbe5 zrNr#3h8)5zYjURIR+=V%U}>RCRC23_{aqws+}Xn*kDkvR$ZPX5^)h5se9qJD*;UZ2 zl=Ua~)|qsgRNiWQ5OQwUX)>i?&nOKMH<`J02nyQU+6UMhg9J#`2pfe=Q6$8uFD!iN z5arZJq$Jsoj@hB{k^-GT+3?Tjrn6*>o3cOxAjYwRFB30ETnLkpj?qQ46jV~H{!*Z< zV`4bilo%?OL<~pa-|ApBIA1g4i4W+T;{;T&p?s!#QlU`J=^3@rM2YVYk`d%T^uNFk z83ZEOA06QTFI~sE5b$gt;f1l*T!31^6pi<^wr9B7CmV&pl9nHCvHi|OvHuA%orbFm zLR%?<oJll@AMw_fp?qZ(DTndffK@*!<Y2Ir%b65@RIAqDw(t=m<0#t2@M&6GYs?dG zEm1<Pj0A~s9%@_6bE2r|Q?96@a|=k&PK=FsZ1)KV2NovRt3)rl9|yvT+={TnLjJ}; zU7q@chhuC{LUF-Lx@C^Dd@g3m9mjB9^fUoM2`-Ro&q0W}mX~jtRb#P()8YCfDm5u5 zEY(<@mF_5YlupRNsc_P{=vo5->A$Cyhtir2q^1nuBg-z(n<-1}i2VCl6&n#5AKk<W zI%KJ2(8rn2ZXY8^sMvSGxykM_+aa1(#^ND*gG&-bsofp#l-3y{rEO{YY*IB;$<&aA z8ZkM%m?0#oSIL}aH1MosVc?9=kuyt`4^5bQY{LQJLWyMQ*04FL`ZDuQ-?%I7uvpwC zzN;%<W9%nGmLm#B$00|o0@KV-5oz;j8w-*!L|}nWiaA6kacnBCZ8SXxQ$Z<SjG>K6 zuuZ))KB-I6yXM&8!-PVC7$XZ&1KKttIyH!cbc|KSsQ6ckL%}Ohvgm=qo^HVTk&RGp z3Gw4)5<5E|yRd6LAslFEhN#VeNOtW&O=hVwbd{6I_(BLLZNUq{l*khH6~I-dsZ-Vl znJBX*tR(nNurx@Pi5XYH3Z;Z$n$R)?<x(sI201yPwJQR4hRjsC)>HY`Q2)TZU`Ag` zMKZ&610_w;UeKDk;Wim=fGuD)V2XY>Svc5RO)0btxHEtl@FyZ$q_J}xN32u_ew^XP z_p)|NUV3bntYx}rgB&>5dw}W4IkKsRCVTWl^Y6X(=ggrWR0p@80Ih)5no=MZO4?X& z`#TAk-?dt80WJhA3ax!Sxu58hp-e9H+YyCEEMWPhCD!tWuV5e-!HK1rxe%|?pob~` zWE3bUYsgi?^B>s}X^Pa@gR0(W8j_p;`8x(s&}cI9Zlp?VfRX{69znQr;2}uPwA?(9 zsuZyPK+UD-<1t{EGlhFmq3#MDqyPCG*av<yMc@ka2rDV6K>OG@B^=#bCEAU3p%d#T zxL*RR&Y3cYu*baN;|Dh=KOHWoaf7P8*GPsX-0w4AU5@dp7!5Lcpcn9L5e)_(#+Zfl zG^6@GGHPI%S=s^NM1g1;^m6a%!0KkFP~V{*Y6sA&UA=yq#ILw2BvE$vK$3X>xm+v> zUQRN?LI@=hNRD){mLh5c`G9PLbVLN>0WM$ZBP?P%t*}OlF92+bA(z+2z{o5bC1qyr zh-hf`hK-Jgdukw->$8B`#<&Y~Co4qso=5QpxGb$eAbR$Qs{k2@!W54KgQKhjDpn4? zLKs=q3FrkEg{@|6IW|vf6(=zwAV76C3k}-@Rd9^S?3k$3*eR(<T-CKCapbX6m7T^n z7kckQ2`o+_T+317=72qk2KZ7+003Hk>M`<?OV6PxMhLlTuy&8Cgv-%9lI&vBiy)Ss zOo^8}Mf<~xTJx-fsC83TVwY}Y6Gx6`mp0ak^nArEYP!T?^+6N85~QcZeM#af5;jJs zKz93H?0z?Shw5aU_Mah}j4~Gn>c!UGfh3{;CyTmk#-aF)spH&ZCaitV5n%R$BqHxG zLAhN<X&7_2?~Ro~k^<R}B-t%9kcNP(8gg@qt&7jOx&_tze=NSI@yzZqKsCiA&3+ro z53$zlqcYXfX7Z#Pqo6}qZfaRJOI9-njrI3%&&k4TF?fpsP!Tki2OP{FDw${Q{9#aJ z9e!tG?W@2R1|Jwdw)=UAc4TVw(m=(}We_6E!-*t`TmN&~GoBdDl@s{sy!ANb4l@S< zANzFef;+`0)%}~k2Lsjn%~9<N!YL8tN^}I3nI^J<Iqo3hfQiI35oQ_@{&EI^SsK)y zm++Gm=KjmbsApW;-0Ffb2ndv+TK=U%o5}vaHiiSVP88rF91sX2_i&7BybmV{Br2Da z#UrP<b8D8lFY|6U^*^)|^B6<e?<rGDxzj0#n>Xtr*nwf2_S&L*#1VVOTT5NO4R{od zBa?c3K?DjQn@}abpa;-0wDV1Gks>Mj&H9V(72}(GCJs_+|3R5r#HBhJK6bZl_W+cR zewSd8fkqe#?uaN=<xYZXfQ+Ii^I|~S$=GrBvn+zrh4rV!$aD+=h%-K9C5nbn08n}r z%wlj5MdLXHD9&~C%@+bta5Lrh;3tjXDIFpPq|7?ZfrTY{25M<hV#^r$-!0h%w3Io} zX_9J@fd#aq6yzIdwM}Ngf}=JDksRKt@OX7}L^#B|)SfWjP{iCvk=fnP?QemCbWbUf zw$Sa#f)o7EYzfRGutOFjFN!%b1cQX?t$O_Wrtvv9;LeM}VF^I{!EJA3pn620d;+Bp zFX>uZ@@C)v+SykO=JKo4@TN_pFMA86kA-5A|7mgOX+BY$r%c;O#vmX8CmVW}YDtFp z3<Oot_aQ{c3skit84iiMR0dwvD4&+7r^P&hr6F{7SRm35OQrORkT_Y^Y~V?F@T@$H z(Cvj_<g-52O5ie>KsJeOYd8loM?@MJ5GLpL)nJmYF**coyb@@Y^#_|FX1^6-^huF? zMwijV*!n5RWPNI=r}0cqNB<?3jZQ|SW0gtyidxbc3=9OpXaej)ayCJx!k2_-6Q%GS zMKKd<B*PO_s)J?>hw>zYY}Q0aMA<X3+s+jaSw|(Ea1Cp}CdTxqFktppTle1v_!_2r zIYcR*>PljKXd(x7ZPTe%C0GDRo}@Iavj{xPwz)M@O!6+{CB=YXgYCw`QLfwbwnNOK z9>C0zmV*HV7!4_)FpE7Qr->xg{B3n#FZd4OeTs{b{u99o&=-X-v#21130`2S`Y=4G zC36rRc2Z#Ew3*EQMskraFx9vuWm;b9P}U4#bb+nqM|KrT!m!0)ZuT_-qI|PzYKZ7A z=1VhwHV7YMQFf5Y<};IRJ0}?*9BRrtXt-3Js3iq{!bVAQvWj+Sm6&4+LMpFo#7%|A zM^dInXq;0$y$CbS^W9$57qdLfz9p&@Ml2ncN^)z|bD<OQVsZ?=OtXJ9AaFiFm{IbD z5I@7>A%F%2X1Osuf~|lVZwf<;j9vYfCod)<kfYWH1(XJ+Io?Yv(Jtpq+YO-!69lm8 zwM=;cxa);LKZZW)`5a$N<fjjz7rGeQNFXFSNP$|G;k<rRK4~iO1a+b1lRn59`o1U= znfk&igIW3&RX~JBp=boyPnuTH6wXB7zKv=D=oL~3IP?uF*iSGD-)Y5Z#r@d6bw+;b zo(PA2hT%MqJ5&7UB`p+iB>KZNFPW-WqDVxuC9*<z_B{340P~V?`t?wbkV3W%z=Fj0 z%@#y2o^s3i)cgvNd>N8W@HF(Ks1R21?LoIYRhCBhT{)NIB$$k`4Q7%$N=_jeiFTxC z%uEHM5bJ^;AxVaoy!=-T4;J~9gBk#d2ZV0fzzSA6k06fx5&I3&pnfI`V52Q0iSi49 zB7kfWZCkt^B#?pyB#^Sf##kPliclY5L{yR%$@+xh+MWZLwU%F2EFwp3<{?mK%K{L{ zwE+WLNT_lzbB4;HBVLi{Y9-Ad7iw!cH}0O^iGZ?cY&vld+Ia7bVY5RFq1?bHlVrP0 z^OL|I31HcvIAYrAT3XY#vzrV_b7iw$I)Gr7&9DepM8O|<iP@+VXgtgU?(d!$)>epm zHG`tT@n(!zdaLy;?>Ydq`va}NvN2)b*SHPp5*raF@6zHm{kxyc-eJ2BG<zF%071{O zyd!$bpew9%fTesMJ^fI#`h=B%2nmvP5ECTJbhLjf)<Pg#u*X|?zbomZ)r;|bw<iad z2MRZPZ{josQ5>6_zGKDRd02%#I}@&mfd)6DzVZ`R+svDSqp=|3b{zLl-MAy_J>pYi z0_bLQ?6F!XCI{oU;-ojt#2wNBBhFVjIOSbVk`k70qreWWe((GoeJ&G)oAtW|vI2-+ z`?UqGn-p)(!Ii^|QRjna+=V>y#c)2wXc4S;c-6LnLxIY<$lxB5-61%nYEx)l)5`qT zRdbEhAva>Q_=cQ6wgixNz6X{pjOUPo!h8F1ESun|ZW%751Ruyu3$72HAm_FYADYHJ z83h5zS-tpTlA(0Xg|P`3Ewze6&oh?992*Q>_#}a0zI)GoLXe8wgtlwr>fr}mGnjhI z2VB#5Cpp=w4RRF<LlDp!$0qJSwO9Z=ng@=ZzPtqi83g*m`QI!pG!pg)64o$u_M3Q8 z3||J~6knW`0jzc}Mrs(rb50uTpU@v5e+_zQ3v}UN?41nZO3eDV^)9b_u6`^mKqWeG zBrDRRnat$x8X8-se_3{jMavi?{K2eulq=4@VMu5*2DVBby>oqqx%j?*<O*RH%&mbM zc|efRlnDbbC=wC|K=1=JnmMIBh9NUt0a(Y_t60}}9?BF#DQn(shXQAagYvx|(%LTK z#s2FkRi7l#%>gr6RB1{AfdtzNDld4Z?dac3v>?_IWJmNq4PT$k9;&a>nYR@Ygk>?# zRE)!xI_;)+ARqP+P!dG{Y3Pu|t0Y&vGB)*mert|Uwm`9L_XBW~NK#JbU=BHs>cB-l zZpi_p^A-;0Yez)H;BYhF=YYroh;%2S0b4=BB8Ma<TLYb?H=xoTu``)Owi-N@13=Il zHXR$;@Yt6JfdD;&H|rzeGFJ`+bmY~CSwMU_lRdK;Vgm+1J`-X35#>8h-ab>XJB%PM ziP#s35W3rIwL6asQ})8IketyM$l$a^>WDFnxz}oOA|`Igqx+DLMz-Xj(>1oRZI-c; zlk#0w7K%{OZNh=mm_~)T1acO6`3LOaW0^D)$reaNE2v`|vJipz^>ne+EC`CMfB_Or zJ!I&SqiV6L1e0`XDkP(z>FZ)u)@lP?2$hscJ48w375_7kqd>_}7KXM!ucV?2MaQ+~ zDTtG;986qsRr}d0HdEI>ND9{7G6Vs!KuACswL{!CP>;UQd;xUk7~)m`zm0jSbr?$# z#a_INE_x{+_?JRgGPDNLY{57Thk{VF;CBzTfeL>AU>YhlqFF%t{n5JuGZ0E}`8Pgo z&CvF0UtaqP=<^&~0zV0REH5o23qTSOSXkhdnCAW~uLxX4mn4BiRpOxHbHnaw(Agzy YOjIp(#^{=ofae+GrjoSU=cEOZfa4`s!vFvP diff --git a/public/fonts/roboto-cd565969dd0cf49f8408deff0aed2b9d6008a06d.woff b/public/fonts/roboto-cd565969dd0cf49f8408deff0aed2b9d6008a06d.woff deleted file mode 100644 index 380c65bd763d9580167e97637fad6bdf27dd1f80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82320 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ªp=DEXi33CB}>dIaZ8-g?mft{^WnE$^OYDY2i+ zf+(;+Dp#W>i`h`0FBb<<MI?(ao{z*}MLl$Pq>eIi0MN3W9jo$Wk$7ZPHB}_ze=Duf zh?!;co9ZkDwl2Yd6K|_25)$Web#DdzYt$_LZp-W)d-1~+!pQF?2=l*6zcsgC=LO6A z?HitRYhp_3Y<q_lnbt{*GDa`*Yua!-taa+QP0+Ap5Po*^>}LFIp?_}}o?~D3W-9*S zO&(dEe|8T=9k$^&Em}a`M(BLv(WBF{&-{@%j%an^AQH@y#H!U49n_Kwite=%<Vgv? z|1f?fl<{+O#E<e-KEt{3D+krJm@4He<EGHBQ70cAHacqIGTR~JQfGrk3j2BGbE%G7 zJu4}5#&4<c_~MxHXV<l;H`uyy+T?AW+H^~@zZjaZB%yt$K5kL<7eFEVi!0Er|92Z& zT){SToBMMHoP3!FuJ#)DQ|mzZ-NduC$3xh2(YO1S(ftvM*DxHV0dxUm6BKhya{3GD z7F2hVp-@=zuYtp}c`%q7^B2(5rXU9g?#9F5>~y#lf5~W3l0ST<X%P=${D+_dY7`m^ z!pFs@`T0QZeEJz*<w4-iI=~_xTD~eUL;twQ4dNTq0$)R?@GaC_&dMSwaq+gf1$kL2 zjuta$FNwZ>j%ZU}eDh&AkrgFKr=^nUAn{mZeXdLn%TnE<SZ1^wgCQ0OEF)~$8=tj0 zJ$=KB_~#D<O%Cq0brpi0@J{CnXg6hWsp$0fA9Vc}m`&Tb7y#j{Sc|n$E4Pu)%;aF= zT<)0O1XvsOBzH{5r48!!jDanrpk2gesA{ip)*2t5aPg28rp--AiXpjVVeVTtXir{( zKKR~}Oc93RTOJ|EgSKxY0OEX24vVH~it-upP2vH<8VHo4HXa-vDAIu!Zeu>l&9>tQ zuTtfaP~70&aLLZ~HSN)WqUectb`FUxmH^>kpyVlYW_mJ20~c20hbKr66fA=eH#k8w z{hKd0AqC`ThD)K2g;bSN?XtrXcrmyp<0FP4N|_O17k-S7Enbz_uYcydg&3B!HF<mc z&ie4>b|0bst*;ONX@ren$+>!IQNno7knJ#FCEkj!#w~h)-=_4KC`6aP4_)!y`;5Vc z#Ev_#>dd7{Pod1?0T~v7b3OAt4Uvn&hD1o-Tozr3+*2+|!e9QZ2Vb~YLwUjEu9_(^ ziFbZ+-s-fYG&)S)L`P@*o}M&3ZejogJ5S%U*{-ebHNSSNN%+~+Lq2G_X0y+<my64r zm!)sAT=;-rK4@e<_)pU|HIECnGn?F3oC1ue>8!Yo?Z`fold{@9`Qz);xHLu)CKC=u zh%km84W1k@OXSJKL-JF$MNTORff4EHyHKeG_M1=-%OzjVgv$;*yoHIbWKTv}_Mr%0 z$In;1pBDG%(yeE#4m*A+{KfXDRRT(@brBpqkl&^p2++r*|BqEHRE#mehuJPV2ffc^ z;w?y}Z>Z9>JAF3{37NV`Kv&Nnrd8XwEk<AZ{CTq9S0j94N^G0Bes_L;I)LCXZYADh z%zNV{7seG>JZY37J2=QAtNv{ODxS-|yWnw%6sF4v`a(2}g(#WN=%ebFw`0x#mt;iM zEm%#6N?S9hW=#)TGSqf1jm%0Xw5_0;IeKC5r|5{Zk~!m)n8^2~XdXkceL(^<;}Mx3 zl!54+pe#fcb3~^J)k8GZ4ME4=Alb?<zBg1sx30;mNeU9z>C%g6>2kXHhrvo-6l%eg zb-qS4<$WnB1Ffi6k)I(RujLLDxNi<nH%BtauRC!nqPs&@kWv^rlq(kv^UFkU&#w#3 zmy50|mx<P#Dku%j6^wpAH@{FcfFPM@a_)=)c(9~lzC_-j<Kc;jbFL_KfEwhg$Pm3N zDnh%Hqv20+4c(ivreJ0}rYPZ|Fwh<@BqH48&ci%#Wy1F<>Br`;+P_^ILr6z^+206% zet+Ut;_(TYdpBk7-VWnvFYri)$_@a%3VPud!P$TxZMd7#a4$EcB;fh{`-W?^>Xz%n zNW=TuD++N4xA^tx@b9ON``(&*bkXVqcvU(vpJVLLobFy6b2KjD#Q2#9HqC||ofGo% zfFEwfJaOS9oe+R<_}hxcKnHh$IRKD%y~zHFC;bWskIJxj*Gy*bP6Bj2wgN!(BHwiZ z-k_Z%8hjKj+&!0<|GcvXKtTaK3!F;~I8s?el2l2;rBgZz(ws@X$t)~P$AQ0L8w9_@ zfq2QruL+H9Yt-+3J3?E08`=XAsg(BHE(8#04S?2-$&g^sP01q4(NPd459Q}&ht4S< z&&#LEx#UWEd9&#F?V+@f?&>Id=voMQyN*f`+F%+3L=|as(M>og-I_X86zh-jFN?%0 z(o?*6!`Fuh-SWvlAnCw<2v^M6vb#f0=R?0Fl3vW6vrAx=!|rL@YJEXTP>!5meo7rJ zeNI_5GCN2;zFY!$kxUhhU}oNL^{`7`>_y2>eox?7paOUZZvl4$S#hkpQD&14p-`<{ zPE09`!aUnaw~qgiZ0+B3{uWVaG}0U)h)>SmZJ6|eR1`yZyZyLuGpQ%mLxX&1`LOM1 z)Q1M+rlWg5ZM_e>9+-&p@Gs)!^HB3AY;)?(^NY7mHfA0xVl#hB=Cmy6tDvMlLJV7q zJSoNO`*I4!G+*jMU8qJc=kb<OAAnLoDcLDypdrg@`jC)nN`|1xi^4SISti}ql5U4v zsIGu>_H4t`a5hYS_<s7t8!*1p^lhThWVE@GAig}daJhEj6ts2#T(AIo_eUoWWgINm z2><;>Un_d`?e=?Jj*NSYuZkPix0<~aKu|I7Pm%J%lp*Jcg<&lK4@&0p9|bjIRWO}J z-?G6n<CSFOO#6~T!6(CwzN~|kVMD!US#Lr^E#yTOcCoO2>&P1Zwo!`-(*?0*T0l7@ ze!p`<x)xtTzl@r)a3X%8g@$9_AKQ(7XjvES%g$ciK0ErtGjUi(o5THtxGp_Mp}uJS zoXyQE@24}^2VW9yXm-&`7X=wt{t^5n78vYo62t!OB$gmiFLgy}I(z!?(8Ad>k@F)` zE{hcv8qU(m&+XlPc=r+f7YzFA?UdAv3_%>xym9kxV$H@om!o;{!XoIuDjr@qGjd<~ z;7$0)az3*<Z>e9^I<@ic)alD<e}>}kg={igL8L!HN`|s2qG(QzA9>=(`s3tRv_DR2 zbCwZ*vRy8DsrzGzBqvQ+NECze>PTR{pf7aVLe8RBv^*3(h+yQY@4h~s(6V8(u9{{c z5ZmFkc<nbAwei`D4mPZOVaTi=TWVJwJvMY~zsmrEhIx;4(PU4RBDywUOzvEKlJiya zg)NA6z<G8#Ct8qN084%z3PBRjm`jVcL{(wO2w8!MmAnu;+Rudev|lu#mL)E+mOfl4 z*T2WSO(JTP>R%p-&rYvgi%6hm1O6KSHdRc7nqkltdZPUwwv3+wAN;WWFWBdN0=DCu z`*P$H<B`^j%ug`wog*thpSa4eJf5nXNn$4zGKW*6%x)UFcU;;u?OVYSsbythgcdl# z=rv<;^{}|^9%eK#uJibXqS$04JtwXoSiFKIPXG3dCQcuIg-Y6kCQgOu)S->nVMob& z8{<QJSxwfwJGyYDFU^s>155B4Ef2loU7nvTVk5Z#qf8KHR#3&i`#qzm;#fbbw)-8Y zkF)%!+D>1H_KWpH`9Nbne9Pp5YC=V!fKf@@II!FNjiS&vHGod!8GPB(?wOvB{wCn7 zbz>%?``>SToIiO^a1?B4k0VNbN3@;xc@dF={$w5l!9oeJSo*&u_TsmnPEN?v5iMSq zp`%uoj^d_u6gREQ(ox*BZkLYYrgin`-7{UD4sir=erokzGUO-BDZOM46lDYoM1=5# z{VU>lZ=3=XI+6(&8Y>e%Z@Cse!i1;{8{s3nam)lV*V(@*b1fb`Oi@8ZH=akl#KEAM zvVM7q$NN>B`Mhv73_$W%LM<9fyX?hK?q*#+s!AmWM6`cR9>~muV9k~BWu~nC`o)W{ z*B=yxYNLaFporfYSHpl^P`e8TtZv=AG5+HrzJvcj(%NNL7G^cM@(e&QGVhUaim^5{ zmb{fSkvD=rPBSQpF5WD^fw#}Ysz+5NP1EHUqAI{x%NQ#YYWq&(J0cK@r*>S$?~*T1 zKJ;a&*x5_=R<7K;o$&MMVT-<8x`p7-OD=vtvtDeCHy28F-c*ON4TcbHq9luav?1)) z{=D5$Wb2@!q+2x5s|qK2BD#qRJdj!k4T)eaO4;+oadtZ#*ki#45z&o6l%g|>*EtcZ zqQA|1{ABbvH|I7?+&Z2qK>KKQvPOCL#HC`bkGInA|E`q<DgZo##|SfVG91)n+#+)B zj;v^g;*EU^*EtD4#KqYsO_+-I?^tpkE}K>7$5(P2=dj$4)1Vx%N?}Y#1>7OTS#Ug& zJ<~kH&CGlYCmx${N@O2S51H`TaI*6(DmB#-PCpzdf7q<fHzVCCsKlua4KAHug0D0Y zmW4GtO=ecK6S_URa^P{=#Jm;QhA%H&GGQqUf^g1@X=#6MJ^g#`w<nH$|0|q2d*j~B zu}25rJ~~wjFSl#R@gL$3j-0q@dFJ#i$hhngh^4t#np~h^I2h7DhKE!5(TN30hhL<S zGy_Yli8RVdH!x<(xZ}-mGU`#eRR?h%tZT#<V9Va=&8w82)Q(zQl~FsSNBe*lc!7^S z&qh1N>4Fbv3K!o1tuNK5uZ=}JHT%hH&EVp^Q2@lpvsXXEn}wAC01IdY%ICR5Eof98 z08dcg8IZpij4B~9rc!05mx;Y$b*(pW0tQmo+9ki*qtXL|S*v4c<fqNM2`R0#-jSoG zjT_oyEB$6&u@&^v0-z(`6r7ydH^l-tp1~qxmnS#tCX5nWRZX2dG44A6LD@V%U;~%P zxBMhg`IZy?J=J&3<hxPiyF;6GaDplKswSl@i^~NNbS1x7LHR{Mzst9k4Rf_>xk9(* zv$SC1<kYI;uf);O=qvU{RY)Jh;UGx94F>@m8_&jKE99!Bw(VdoeSI)^Pi<S$Mm_us zJO(;4V&w_y$4g;l(XcYcN?YA>i7r8Xj80s;X`k6WYkyZErDwA)g7taTv>EFr+!$YV z^h|OG=<cSN9hPI>iZ@IDZ9v|oI4(dck;D+(&Wc;Y{Z^PGd}oUgzUvQ1;TZsej<}at znMH@vKUK1X!!mQf?OALvO{)qLaf%a(A?aCasJ5U0Oo-B0rNJzCBUZ*uQgLUvh2B!( z5!{5_dcoCk!jJ^o`UKlNI(qX^AkqlyD3g;UczCjvAVlnTAwTz1z_0mrj7?^R&~#pW zhcDt$e20$l=y`O%-fhaX@71S0T>%^O-l9if1qcV;M!K%N;Vz)OE)Fkv-NIgH?+a0Y z{(d#o66``pfIxm9h?@N02Zg^+;C8!4k47z%ffjTpnsz)xOoxN2pdn}nI)Z}|>hvY~ zp3G!SuVvY_8oM@U*A8U8wP!HZf=tyS^+AMO^23r=V7zK_K?V~=xX}_P29uy<Ifs(k z=ZqkzoT!E&RW5i&1JE@{HX%)7$qCg<O+_^yLmM8yN=H_PJR8+1B{D2k8FHSwOT#_m z-!oXCS!lZ^tz&9%XnKdVwb|(%$Aku3JEX0%yRUh>CObWCz0fhP%a?HpUv`RzH{!Z< zii`iUW5S2337tE|C3fu4|4~bHwk3?4ur<12!{{wDnvLHU-Jn7AmT5xzgl*fVH5<2W z^9<YRnAFrhEqaYi>C-YMHKlLM-Xli#MGs=Esl8gnq>k?M;a(+iSS32MgTN+e6LNqS z=qWX(gmhXqOZ0$&p|Bc^ybpc);~UV@AC<@HFwFqd==XYqweW@VJ%+8;0p?R--!qbL z!VA!XZw!Dw__2_K#~JWsI0@3-SQn%U(V74t0B8D5_ES-0Os3IprP6lM75O<@fc9&) zKpp%E0JH!Y9MnPgT=_gtLo?A6&0$)rnX9q+=`t70rQoH;I(o4zZ_j+94nbv$(s>W| zqM<n@dHXw`@G<S74=HTdG0{9!vtxSGcKAHjLHpJ2E$u%FrD&Ua0U$PI6>nBbAu8_; zThW}MT%_hn*+8vQ7#^UHLy6>~L`p@_vUKUwtC46wBs10+WQ;HhF_Je@sqw1(PnzUY zn!#zq+39IEQBIL+kyJ6F)o<91!&IBe`{oez4_+^#hUkGUpiiW~4-$_Z(d^%&yLo8; zwX{X!$1Kpo1iV5Ed%~N8cXmrmbnn^niy>XNbo=q!C)ajQU9fxkkKMKa4dtWM3e27h zB9Ft#_#Bf;$hjpYsK1h4L)kTqUCZ*d8hLw<i%;``R=t~9rog5-bR^E?=@Ud^OSI!O zF`c}``OJfI>5mF5N*qWjX;{RVgT}a$F{Tt1M1ON*^@yC6nwCV(GLoBDC=5~9r^t<x zRM49xL_<z`QYZ>~g=#8YBmdIzW^73Nj{Hl5gW%6;wt8^$WPB4<hk85^NB{o2(Db4( zFaAtC1_;m_c}T3|+o+^%|Cuvq;$iC#FJT0E{Sb+cydWbP1j>N5QmCA%6iPwTDju~G z>WuyTWml3sDapYNi_}vr`7a95N+CX`qA}KzG~1Da*i8<62%%ijTAJ|B;6&tHRVc<4 ze3a(*TMb&5Y@~^3pEh)z>w_zQr@*e~UixgX-ulq~_NKjiH{2C|vPY0w%zeDFW}>Ty zu8Q^pnw+oqK_h;INAAd8yMvw``|=*^9y33Gbtc6+i|yEbC30!bMlBRrKzZ`K8mI+5 zrJA4DrhTbNB@?}dvTHcImS@)r>{_{K6+C`%%A;F+Njzsc5aO&PeMp`f7(*AOhC_Nd z^Y{~%`sdBK6?~XVVWMBi@nzRQ_IfaTy%c*~nmrC@kIS&f<=9{NELVz<f8K@mMye`5 z(a@YfsU~|uPX&@*Ko&JU8HhH|Zt}?>L>lOOA(l{0WK;;f!BDd~DvVxWq{X5WC&3k? z$By0kZ4C(UUo%Fn#9da8nu+h@8fUhT9h(MM%^UI*4yykM_j=j@FBOJ8jl#>I>0rg` zm27_=2&-5f2IfSDl@?CH$Ji(SW}N*l3Z%EVoALA&_}KQ{P5KWXTlw?d`SWl8gqrM{ zGlwDH0nm(PXv6?O5WF%@-^roU4Ih@~jWs^;S?%-Ecmbu_Cg9CW8B^;??VbXj4|)o) zV2+%iNAv`gnX^$y5r$31D^uW-6xeh6a3KY5$`NawI*+%*&I_}k?K4U&g#NHknzI1y zw)eO~86i6mOVgXkkT3vaK%BpjDY>d@^0NH8A~k!$d|mRHE>W>Nmob6RD-#&?on?tp z&nR*-!<QpoFtWwvO&1rVHYwQ3K&Yl1d3sRbstBR~36*iojWZ+TT}BLhhwlg{$Uj0; z)pxSX(7|V}!*w_Yu0xStH(!(*SQ3UqZ9v!c-Jl2jENF1(le^v410Ygap^2rkf@Q~i z22M%=tlE7}0A<Fa*Kl?%&s8sR<T7<tqu3;ua41)>p()oy*9q3b7@0kS*oo!z<$}vq zDksJ`xOxTdDAcK+<#;mY8?XEwDX<->lUaZ0pwZ8Sve(Pdp(_*-l%|5(=+wbYP4y61 z)k21?dRPcqLy$g#acO7CKlpst-6|*6Ice7%?TZ(}kuLUd^s5sI|Ly8=6=$Hm_SSIX zPc$h+XdJga?)Bv4xN;RMSmIv7trb7pUgp7c(Qcn9Di~;CpC(7OKX}>7Zw9{LtmyBm z;7l~C^)J8Z$<e=P*eNB_Q;I7<OFF9yCA$F{L!pKGVTgC1^1nod2n+D{qrJZl$@X}5 z0Y08>e-GEq+UspU973p$q!rgo3GFq_`sVcCb=tn)9VK*uS?T@L=4<*>UW2^X0<H8_ zl6Xo*x!N&bB9SAqHF#-cUJaViW{%ho%zAUMnW##>9HD@$T$$N)y0Y3^1};u*%vCay z3^E}>F5Ofbb*&$%q{d4=M=6+qCdBBfMO7m=8aOrTjO6B3#oJI#kY-@pmhx?XB>&Q0 zkbjpSK|z!JExxkB1#Rgus>j+MBYVKn_(<Z&#I=bd``ahNve0Qboy!3Lh(9t<Sq};L z`SV^Vhum9!V)@dvCRe5>nV3Ou;?NunU}yqf)EQz4XRP(eNS^2cvGmc;kDymd|M>kW zdoNj`;ja`S$%L2Un^&&AU65t6*#yCae|mZKG7N=@rVBt}BL9}<zyyJG2{2zN4N!kN zT|+Xtp`uAtB5h}mmR{-fxY85MHOMu>wVtaOqc*<{<V{An;>PDGae5ldzhbO<VM>x% z2)cpijJ`<z!RLQL!S)bOg+uWiIBMsKBkOS*?0|Q`4*eG<qBjq|z4!-QXy3AYQH}_J zNKv|)NzCRA1Cb2r>@Opo{b@=*y@s=E^;|$n4XUd`fgDSf?A=z(Tz6+dcEw0~&W<&S zg#jnQndyE^4G4^&wrp9>maU|=Wtpu?UCRX-lrpNV(3T}{n|V`~m}Y3+yb&YUWIvqW zyW6t(gtjeuK)*Gw*OC8wC3L2CDk){8YlY6X5}o@@-9EWl#?EQ|8gxwW)vQ}ur@HnY z6Sfi~m0YH2dRm!LI;!t|X67O4DG+LCoykfr1-eOYa(!ht85`~%;ec3hR}c%5mLtjF z@e4Zo<s5gO^hQHFtqrYKB}(CprQ{j3=R$RFxu0I>xO8+>#)RQ$+KBk^!nsXjQ{N;{ ztrt1P_~aK$x#Y^I@vc)FXGWaH^W*w%&p}PQz~B|ZgA?!rI`_K)(5=^;00Pj162Jo1 zNMVfqgUVURq^-!VigwO(O|e<$>_A5fPCgc?rI-^sI4GCa(}jW>&*UShMOT1ONb?X% zx11Cf6kgyHCsQ6QyDzvoCsVFeE+LAHZk~M`>SUj}8<v)KE?Af|Xjnp@5yLJf<L}4Y z+gQh=eWT#+-l*HsBZspS79TmhLL4@J+^GITCr%#zVX0D^l;k?l6JVgQSfmV`Zc5G; z-&uYq$iOu6M1n?beh}Fi%Jt~j3$%C<l;h>>AkgY}yDPq^9LVIdI~{J8>ja4cOS@wr z#Vh3OEn4RN?<G~2wCKKib+_giX1B<OQ#Dbz7u<xqB0u~E+-biDzsH}!@0-xJFC@Cy z9L6ah2>M7!&TvIV>k;q=n7^D*?@ypwf*K`fD4Z2zLC(ENP{n~5s$K@z5|A=+6H<i> z5@c|QSGZ_6aAfYQsdL^=ntW%HU<WD7PHo3?7LP`O!+Q=}3E})KC}hukIj1f@IApX? zZZv)bOD0pFFsVMjTC)OJ;179!qABD)9XtU5>fo<}I{-khq6K8B#^gKW^8V2_*X$*q zy$))k1@t>`gYuny^gDb2oqfkjz7wI@Mm~E3xS>VtJCl{~tf1fF;Zp2714-L%Yqpcm z{sJnX#q2x5%6Fna);55^01_{(qIpSXq#Wod8D+eXk=mc^<lyT+xEmD|mOE!;0bb25 z%2J0A_4-(%DAL(L&WwV<oH_sG^rk3bRDamXCSJeqX+NcvxkBnH8}xzce~_wh??(MN zf9>gS)^0r)d{MxCdO~klvuu@~C0gPy@TewV;UCt+l8^o7+)a<ax!-s116b~#ib=Bo z1UvKG8OB@(EHuQxZx)fBDUM04n*6+?`BuBDRrvFzw$8h6wCex__3%q^Ioo&DsLPgj zy$j^8a0qE9&g|6D-2<tE2tpb|gF=A)fN<`^deqInQS`H=qL!$k-5lRT0D>43Z}$Qa zY(P7O`+^S;fEQrr6DNGh#=CDjDl|en;{gQqm6(7FsL7{O^Qs%vu<A-Kf=1TfB^^(T zC6k0!i-dpqc*CXX*tOTorO#fpYbPEf*#+ZRU7!@=k$%Q-<ez~$z$)qL)?>1SnaVoq zg$BG2M9jCiy~)q9Xsu-Qc9FFfx?e-MN{?ls+H|VSA+T$4vAaS76Sj~FUCSo3#z*FJ zsb&dhf;X%xyVvQAW|^u;_bm0N$t&J{(c#Uqi};_^>yuZ!>CoZ*ib+3O(c8SvtNTy? zxt_M(&y!c2)K2fZGJfjMb#zX(uTNY44RT&!oBhLuOV?o3E5C)d+23Ef^!@DD^CD6& zj=1+-Im4No_Oq_3SCW4}VJ;VN^wx*-0On1{t<X@d5tu+737CC(tPF?3qljTAE(l^! zugd}eFeP9run}R|)w65V@~l+u#M%Y*o9nAY^%>NA%Ql}r`ZpT$+P#Ke?qe7WO&n}1 zdI*1!R#YH!rl}ag3~@R0Nl;=@)VOjX4>&-8z&ZFl@{Ke9Tyh#y>oF*Ts$wDJ0mr!I z&t*A<QMV6q0h8&eZZ^v{FYS#bTt{X_`1s2MDrGeMqUGxPEhi=jl}0yg+i+du=!WT) zoGXnbFK?{fyx`@gZOF?)zuJva=ocksj;-A|sACXnRUbdB-2{bp3Yf)S2}Z3N00<U> zrNVXb05E_kkYnH#VrGfx*wr(aT4Q?7Q|w8_BLnPMqKMctgpiw=n4BR(h;ZHhY)P~6 z*PwnEZUAj7n@zrlf6am4!?pNL*;@l(<pEG%_TB(|g`Ch$02HQ)6+k=)20iP8n#-V$ z#9vq2I{+sj1&J_*o#QD03g^TK@~Kj)PhC|$rKO(&i1Yynm&vZz0B2A`a&mE1d^OM! z+07wowLmVh2ILZJEPK{jgjajP6*#^Z?hDW3gRm7O@Ls#cUKU*^TFW+)5Bw$d2W|qJ zU?=e}8rK3QunX$Qy`R`pi9b01N+Ssfj6^HpJz`Y}KnFhKp$B}766xgtXnqjVKy@W@ zyWXb{)c5H_{>)0!o|V*6OU-Kus{(qGmy!gB=<j|Y>cwDDh;a<3o@mxY7{0%1pP{|# z9Ve}?2Y`5q?8R`<l6f&(qCj$ws5etstu?Y*NmC>zKYtD(|1rL~PnS#zatv~ESPMO$ zCYS4o{4a=bMl#c?V5566-#AS>xx07oSKFq{_8C3)jopqKTdl%ReUf$@|2&}@&Kumv zR)$qWpgk3Kk{+39?Pp&<p4Wko(5e;1AV&u_7cew%GL9ovWTrgb9Wus-B@(k9Fysy4 zoQ_)1Ct)Z=7+d%3f!mj*ze~}~E}51*g|wJ-V8;3#b>5c&h_+kvlFd*#uuJlmbrElc zi<qAYzSaltjW0`{l;xb1{Iu|}U-^lJJh9LxUXF8QV!47Qjti7l9$<c{kX$PG!ir8A z9R|k<BvZ&H@x`7!TNXF|+_}o<eTTqHY(B@Nzri>KM~c(gluq0zdG&K61EkEYeIOet z)%>z?DhskDA0;kU{P-{vsMwXtq2Ab&F!Cgf4N39KmTeVkCzN2L63T|eLU`CdF)GTU z@KP_95HEgE;P$0s-dWkI5wM*MjCxRJtlLS}i?V{`abcrEtcxTvDrLYt$w!5Q=C&-C z*UKi|5pc_I0gGM&Lh&&i(phzSp9(@prA9z5ts25dZY-=Cg{+<A@02JxcQI1zksrB9 z9R|;wDP^tPcOcz0UA~yrZ2y<H3c@xsr=y?xz!u*AW0ODBC!;fMbJs7*m&2p!NW>BT zy(*fgpd}b1`L=4!Mxu$VveqRXtIL7H^PjXJPg;Dm)=YWwq&$-yEtsj;gwqP@>URg_ zn~df4QWb}A71!r#dIqa1i3$-`qN$*ItVzkHDIFdzFB$oc0++Qxw=&B`X(HPskA^2t z{@y)4v|Ok)J9Si63jBO!>zmTiM^@dsDPxvp;ak~le%v&wcex$YHtwdQ)$D?6AFm~g z(a}CFpxC!V<NkezG>;wIzhnEZEjy0tIDP$rS^Y;2>DYBpo#<ih$89Pf*U`G{;NgY< zm_QdiO!r8$6SxC^vZkUy9nc800MXz}&<*qieLy@I0EU23U^EyDCV(km2AB<BO8Trh zN-bcJORoX!T8Uk2vuj;;ZOX1K*|i<Jc4pV^?An`M`?6~SyAEd8q3oK%u4(L=!LF0o zbsD?QBBx~?dA6I9nQKbz|FJEE@>1Gpa!Hv$E*Z7R#idSD#f#6JWOOZiP|6ua|4Cx- zn4F{tX;%_V-XEKkl$4Pq#MF1blJtAhv!uKv;wa1`@9gzV3Q9u5>O0f-vy!rt#9>l9 zZQ*Wcm!z2HCADh3GOX~KC&RFmB`we^Y?)OH->jpTYP+hQ<qXWFBhojQj$>_o&Y;|! z#N3>IxfFj=OP|vqH>asyYF7A-*jzHCbZlGFcXE2==Jd$T>5`k%DmSNvKBsLi)wJ8I z+air}DR`E`Ms~D5XL4>%8XMoS`kd*xIT>`6b0+9>GIR5tffjkKnhjo>feALTROB zm2WW8E5A-Md+J5lVkl^UoCVM;ghar@s!_TvXe3&GRf~aIipmYD9vjHJG{g(@y|3gJ zrg|(?AKx#292%P#Hx4!Ws?V^FRjTIVtd<Sxw`|$4ehcAnkN#hD861;Xw)(qM$)_}B z&L+Jb46B{eJciYiY(2&%^tk{{_U_PV?*V;~OX1_MVn)@f9b@}Dnf=q1N@D-u_kB{W zJx9i-TYKU?D6B=Bj=}CtD=df2o3w4)WGKDBXgsBDO#2SqtAA!Y2R}cboO~Xi)&{{6 zBerZAf$waw?cdVj3sGn}g8h3}L;m~1sdi;c;%m0C?`_6+W92&lG@yt52i<kzyca+q z2xc`4ngUAm7N%h7Xlk<T&vOTIAr%F?AO)fPtnHFP?yOoxgcMlPhvA%v&gd*?2m+L) zu~1u)gjVEf)Dq-IsFB5S=}q(%j@ug88jGGKOSkN?Y2lpJ=mM%$zGjV>?h)tDpKm3K zNEEeS*ecs93s?TGRm;~hwdJ_QGczKq)~^~{yFriE-M88aC*Ud(Ku`k!;eduBf2#0) z89wyJQ^5m4$sB;8%nNY9z9|)TvSA@ZGw}UF!q>xarntTEGqKYBK{!a4LM>$!&$g>t zkK)vEE{f}^R&P}~V6I#agRvkntR!bJhH|XnH2Et^S@%i;Yc-aF7*$xT*BJZao7=<O z<L+Pi;;TlbXRcnke#Eb1za4BnwDi}Q&bO8yLYDWi!v3`%-rTiSEZe=!(Sv=~WWLY7 z@aiml{o~8;0L;t8tzdaD6}W*gLe=XbOMVq0Cbg}d)xHj+w!oaO2Fs)D%$iZ|Wj;SJ z_5Oxkh6GO=t+_rMuY_8V1_a>Ed`E0m$w*x$*dn3UY9*ifjrujkTy#>q1GtkF*%i=$ zgG<2~qCkAz$u*yQ&y-7}G4)I&XzInh?0yXBQNl%C2suQn${oomP0tyw$a)lgRuR$R zlYvI;RdjN3#<<1tJvw#h(KohXaKsm-jFzZ|JsMXUR?5dxL$jf0N=na0ty(pD)2y3U zb=Sypo{f97bcret5SSs}MklndfGY?9O;{hC3R}R!ymFw3X#NU>)sRbVXm>XQBcUxk z@%`N?{(-eOm^GKWTrBd|iju1e7}1HP*tWE9@13!~!cMIdy6Gk_>fAw-(_`4M9u1qd zs1FBfLdu4ft<$<e^~Sm=*1F%(HEjx+VLhnLTIa0gM_6f;P7z<SZ@<2~r+bilgnK>r zX!lrmZH#IVX{#(Gn2N5gnK)@pLY&lh$l$Fcttoccu-L}UTh~8(neL>);$39Z(mfgo zrhy!oFDu1dKStpJ$UPwUf?gh@`mUbZAT2HX9<9~HNJuL%;YVCu<gI!x(JrwrNiG>K zni#p2`#n8_JR>}Xm;xsm6+kAfTH*97d}h)sx}-%H8W!oe0^|i?%Q*LK2K0^nzGI!> zh?b>HArbXE*Q{(UQz}BdyM6nE?`n53)NqfoxHst8B_dqzp|DT8oAl5J^ah{k8(a2D z51sRSDANA1V1iB#Cg_w=mz;F&jPFpZ%6g&HhXqYHv*jSK2Axr9vpD4jY*lx?X2i6G z;@!iCUyK;4DG}bLW&1`}&#IKeVy<|e%taT{QWwzcziz3Zl~Yv}Z<mgIMMu8kq|cun zPnRH<2p2j>nwWxyYDjJ)vSl7QG7Gwoz(?cuO%>1Y*zuy(J%B(D@tSZ>+gsHh21H_l zi2gVT0ui7d5M$`CBJz8P*5Z~+zG}%+Eo-riy=7~dHbNJqqlrY(I<iEZY1{lr<9w-~ zMnhW!Bgt*R2<SfR$dOERclv$;4}P&@2b_Hm{Fl3gA$^(7M|X)wkO!r_i}r~1D6&h) zbg6a;o;i4CTW*^`uvpv=n`+AfCs2as0`S;TYG^uU1-x%v9i>ER%U15wdHRIUC)2i@ z0T646nLtNIv#BaoE1<X<Ws<Wf6UuQlFI~j^6sy8IX^rg{($nG3!{Lu<b}PL5H;lsP z#LN%F;Y!pS2w)ii!ms4lJxDu(K$_$yN7nu5#L=slIy*hUF$dfi0wses)|Vur1o=kz z(pn?FvA!r-@>D0>vN|q+BNu@V#h$#B$}6&6R6x5L#_q#Hmce0{e~jxnVDgQx@fBEY z+M=wn_%L*tz5w6GZ^X<s3%g7%VO$=+VjHsHx+wz_Qc$migo_#g!Qi~-qMx`D1cJ7b zP@*Ky2o&JxC-ig`n9S#DaS0r|K%n3%k2CLv4-Ho-y-}i{@#VSi@w=3t=Y0FrX!Ty3 zz4_$v4Qn<SVA7#8u;hnvt6ok#cWB!DyB8;&{cF~2faqL^Mlu(!zzCX3t|mqI$T1c- z2Xq+SxQLXy<DfEBzg8!B<p<@L!9L4gO-GaeS^4Dd$$PiI5i=+Ky?F5Qzo#HE+*a@5 zh1hQ%0sz_C*vi_|N##ZhaLizE)rzd45ql|)0&(ys@#DTTj(U&XNaEjdwAA)oaI+6Y z4NzHJJ5J0@!2R>vv5~aH8PxyO{@}L+-vF&6dZXY6Q<Psb+8@y$>jWUMlC@Hftd(HU zLvjr%#jh2<>ujxvMc0bRt(9Q;Bf$|IJy4idrz{;%bmh?W4zZl2?bIW8@O|j?$Eint zDW;vXwx78wC2XsJ55N;MtA;m#;cv#ifWZehk4e9Me!`h2l`Fs!edN&+8?aex%gvg~ zzY|bwMv7dLE}aaduY`E^pMum)u|bNxSxO2zl!Dysuf$CIpC~}))rDorZwsJ=%Kz>7 zb25<-ENiurj{*oj&wDOJk%yju;KTG@{3#mX7|i2nFCx7--4Gp1y}0S{73-Yw$<xJ5 z+c&FD?pd3fGIJPE#-$GV6*tg9WpxCoU4xEGif1qbtP-RIoe;g#%FkSoLMp0bLlecq z3h=9KDJdJ_>BaUuRDJ=fnvDmNAtJez$L#Oyqm>mslC(tw$`rSvfqKQzRT~MtP(OQE zN*vi7N}n{{*y-I%f}Z-KBgfCdzbd#WLAlO^PQG(tca-pzva->P4g<M|QSc-@nVsT_ zYjnf4TvNzk`w91mRJn<QY@+aw{XPyAGnG+q%Jy!P;zpfYjofjJG=Q~+-O-hkk1P?J zrq~;jC3q}_=4y$VG+&F#)Ba=!*CRXF0|bJm%6Xq7P%X2VQ@^<5o@xc4@SF!`9p~H- z>*3e8e#bAZf6ToB-L<36?bvqi{Pvw^klSngGc5CN$ePzv@t@DUFW$R%HR-~```^hY zy+C#iZ~+F&3hrZ6xM1AWc4~klE4Zrw*=gg*3hvFbg6GRoCO8>Amsbkhb@uLW=kO_5 zV}AD9EPNJT!Ij0#6YJLRhw&LBMopu!(!5BrKUM;75KP9+iJg5^ODv(TtQ6q5a;VnM zu``t5qtyzjw|vqS9lJVXhW^$*uW^f;_;2WO^Jg-CDd%=<J@@VQU1a<=ziP0j#bqyO zd6)DLEL$*!7ay=OTmpb-QZ$!DNyDN&IU0v*U;)Ll^6Et-r+MtHr;pZil1p-B>)x^2 z7Yr#JUkXJnK>a1-RVi@gxjVCl!>Z%#sj&8h6>H|;>l6bdW`4DP__kmi;DTyR88C7R zq&v4IIrFZO(GCZFCB3B#pRFF?SSwfvr2c1u<_pY6^KlD6mAf9oKA98f07WVEEt?!Y z&?;Iaq1z<9bZdvlM~}U*ZqJ;#aUSfjqs!l4Px>j%dUWmVZ7`(kpzb}=I!@hsdRg+c zq1`(4|FY-AF0(dv${vz3HJSFRJOIK!OqZ?5%N~9bw0tI}Dh*Tk2Y;D@I}7K<@DD$W z;R!6S|G5ar-}C~tCDAcIi(8M5XB?*qLB$nQSn5Rt&o5qhDva8-c+pNs&X1@2f4H(& z@V7mkv0~{A!ASe#3xHUj{I(OQ%xz3n>Q@o@1Qkb>f-8ZMh(uOl(s*2XB(6N+hc2Ck zLm!5-v#|;Qn)l?9H|Wa!b*@XQm=-6)i`MrST$o&v@7&oP={9Wzxfp0uEOM>2*+F5@ zGYPtu4!Lc`r$*qrMkD@hIQ}LT1}~W{q}Zm;UM>v!FkINwsgtcMYiT*kUBz^Y4xB2= z=@k6n^MwEa6j|fsI{|3v9aS_~8=25#|3{(#_~jhj7w*Wy%kYZXa2xKOg|@;w_OI;{ zC1OTxQ9U{{WO_t5d1km4aWliWNNI%pdsK!+B0U^F9oMtshSQN3O1Jytu5dg00{}?b zx`ZE@+-eN?KlyP9UBIQNQ%A}qXN_$BM==Z(^<v*eFKi>xkM?>(kGQyw!qtTK0D;bV z|DYK{FmMNcRA%`HC^E}SjVdxb$}C!G2dU2ibHOtQ=e&_sQjkyGYG}rSNfQ^L`BSFO z@87jcPPZ<*VAIW8Hm{kpHYaDj+laK+3x<z<N5^0+x#S8apanHmvfJz^mP8Fy!2JR$ z=s04#fN6R<Vo1Z>0rz2J545;xw}Ajs#xb;<^w$K4ZRm&&GCNwCCe@z>CbobII5(Y; z>csY74mo;9f0+!p;?*{WGH|kwCkjE!?WbY=0qvtZ_w2vQHhWamZMeS`tTm)Xy*6E2 z44R!DA2&LRX5BX<GcuF3FdQUF!Seacw~(hQ^6<+iNT-d`6*kI+y+e((u)-I8!kG7{ zgdc4w%dbRgowmBF*^&9xNI5;1P)|YEFWbj{*}iqJ{wq_)&1>Cs?Wzgm*A3|3v2)Dj z7Vt1?Ub}9~mbH4NTjOi=^es0(K0PC$Zu`~^XHyO7b8^`)7=a7$0AHxYj@fa;KxdIP zp1A8^5R8BVaVH_QZ<JwYB_~&{ES<!{oJIl_vOt=~s6$a18U1mx2s4xLC>Rn14PA~L zX^4F77>=t#^M}buFA*p*cCh59vd-BaGdtF&LwfZp(;;^S(XEj^Z(i<nzcC;)Qdb)B zEBsENpS#RiW*~b~Cl4^&Dl81kMqZ~IR~cT$(@Qq&nLcms)Zxo?iMn1*cJ=Dkp-Ldk zgwwj;4WB-8bXHowCXM#A=^1PQ2=pSoSS*wP-XI8cmkhEO#XyHgC9TXwk}32OENqzu z<Wn;m3SOj&slR%47=wkvHdB=}N}%Pi^9dPI5dOxu)x;4q7o|^Lee>*;n*9w49a{D3 zDU|4nA9l}58L@2rjQUsq6!5~&BP#VAk`UcKmSt1}G+!_}L}bkTX~!ZmVqtTE$VFt( zd^|S^4#5Ga6Z*+s27T3);wGcXxXdT}$P7Y21&}N`%NRUohNW|6mGKIpLT1N2-15#w zwy(+)Q#7FPmxb~Hbh14I$}8$n5K@D1!w|26=Bqh$u=2Gaf#KAtn@?bSO&&lrrg@#F zomNepysBffI?d;fPMg;;acz9U`Z!~c=B>W$)}mz>)U-|yU;n<16Rg&R#{K;Ky4UG9 zDg{@n7u~jg;})&q)>^GweO|j+OUn0{_YRFCJvV?LkRUk)hba1VfSOg&>?p;NC!<b8 zWXqu-6oCZdFz1eW#4T;2a0jS+t8`Oga?piFMV1yQB9!&f$AnDH#*dtxJ$mYVbnSu> z8eo}?^<#~F+PCQ)3%hikKgzm#<GiL<e}rEmi0V{|955hhbsUuhW6)0YM=_XOl6trT z^`n?v0py4SQCsZ{^2ihTgE|aM&0Mf@B&ohvJrs>%5v7LBLfL2+a#HYXQZ#@u6i#EH zAtRReMZLbds)g%4N?zu4?%>&}=ev#W+OR?AF7+F9Yg{EPv`UqxRkbsYT&~x>Tm5>S zyVNaJwQ`sxvMODLwQ)<~1&Irm12sTXuv~I#)?As5%DMDfI~VY{m;wNmCxgPU96!$0 z>SVGg1xP%dOiCJCl*&UG<w;j)uoL@~iG%c#Ijddpj6!G{amW#qQcBoD)?}pI^Zdn2 zE(PTH<`Ae=RxKHjkWhikxe;D$>ydaQxpm_f<98oFKl$;zGmi)MZ5ZFF_g}kOH-;VT z6FLppxG-s7B7Sgb)27svjcdoGtrM>IoaNnpWp|$%EqX7W-f>mWm1DZht61^N!R;$7 z>SkJc%EwmHcU;SEgBm2&I)bM3&YYE~PneT61TgN+M`Bg6Ej#@NN+smAUV{3NK`{&| ze7y;d_0+|SNfi0c#3fL22BwyAX<GE&41o|S7($_}-B)8CH6gRgndyW@6W%&L?d!-2 zqk1QfvX@=IICXPy@aB|-n_=~Jo1x~<dX!gl%X(PTe%pQ*=3Tt=%Qw-NetQcLI1GSz zUbBlaqxP19m`zOS&c))Yck$WUzEEH;a^6u7d=>uCppV<`CXy^*HY(JMg@$~!H2Cbn zhZ$*aHBH7e+P)MIg>eT@>^g!o(H#3w&8~}QM(rzK3;#WDegoe|2ZqmDoVX}!)=J8Q z2Y~pBVfbTI#xX~J?3g~s6H#dq(*(4{(XXZ4cJu;O{ejxT;xv)@rD?#oX=!{_ot%QA zIuK+7ApE5T)E}p6QxHc`_sKSK1a<t#>Wa1mu9;!Aj)e>6;+F9C9OP;LTMKNX;3@2F z->ZzyVa6=fnx9s#b{;>+JTaTV^f`@u=L{6NsBS@xv@|!gb&b6$dXtS#+dn5m(G_iC zL!pet4y`X4i`M_!SOCQ-Dc`wh!AAz6jF;8w0xzw=8dP!-674pvudM^Tf|31{?2#}C z*EGXHc`#Hmd{)8HBf%$;@$|7m5OYuHo!S0y=1_8iI=M~?XN0j7HDC5)?g>_z+R;P7 zLT8RXitjha?YL0rq`0~>?$}?PlVaQkm!EFvPtGWGRE*!?^84>@M;9x;in0I*--;_i z5Yb8k*omd8iyYt>Z!77eRj@Na{7<wh?kuObBn>r6zVi2c)Cs;EZ;C>j5-z)DC`{07 z4ngm6oZ#FY9keZRsoPvD96KU99pAoVkM(}aXsrlWAyea5q~e4jcY5Q_X%`-zISK<d zZ(yuC{(yqQGl3Z_QJD2P^H?R>0*d&z-AruxLWN#}5EQ@|If7Z=;3)=)5yY<=EyjvT zVuqL{I>+p#Pe`CoBXX=0qMCKWnT~=wt6Mg|sp@Sc7iuTS|G`LPgu|!d5wJX717R<` z+KN}xJ6I8qoQCvhjD1*V)c(u7ye~U+MzizdLSva1y@~|2I-cn=;9nKo6UN%-r=Yvc z+eDe_3Oqgna3cOD4U6g0=A+zV0veJA$xdo@w1o6XXVJkBvHXW8@XE*#e?NQ(eJy7G z(7B6k7Z3{k)B^LkPF3-4L#F?j9R04GLq+hU{iTuaSb<Ui3b6uV<jfMX3+_lbR)`>X z(iH)6w4A)lR>w<JMwnilyIUA!zmI&ceZuE$j8FQ6*PHXE)sS>-WQ!S7-V)Uz`9zBh zg|Z`S*#t7C@XB~R*WZtZvxS45yHHK98M(A(^QQx@AWqV_xhpdW*)nv_1)q+Cslr_( zXA3Cwrxch#hEe3S5GQV`iQ|&o4D`OW?Sr6cV_%H=x1o>X;pup|FhPlglw-cpdJ=SU z=5rH@?Y(2JUPykfUOB5hHbt0|zj`6H?1iH&#??yF%6Kr|m&j>ZDgmxxS_+rFM+GdM zBZmw=R0l6Y4{c*9x17+*9t{&wE&N%0415Crib=pV=*k8_{D*mLeL)cDpP#L7WQSv5 zF5o?yyr0lZCns7;WIxLqhjOTT=5nc)^kh+0q0ccfx&e}n516z7lxdzM^by}YN!Ska zA+dC=7Cn3h1M!`wDUb1O82B^=F1T{~_z$)|*G_zsD~4%p*M7k7odyrqLUiMMyEf7O z&Gw^OyN~vCj`WQdJ<@&+0AzieB4+Z;3H+JE_e};91~>|AljvG3b3%1ilw7N0lwskh zpxhAJyK_ehOd5SZ_4acsls2Wp1zz_~!`k@k$Fr7r;_qNZ59nv3&oBJpf!+ZK#sMJq zC+AFQ(qdg$IM3S=z}ufZjR3PeISwJpL%>m(c(Ek7Qn{3SRyH#gu30ME!o%~=5b_eD zIb-PCMN`n3UE9x2UyghJJt!mfkGVIY=cwWT;MfsSPfkT1yZ_gjkZ)dpJ|eEE{Y2Q} zms9XhF9P;pTWe;8mLi;0u1vNKlyts+{Q1GjHlB{><7BVIgi~rr=6G;iT~2(RU4{KM z-w3T1Op3P!lUac)@nm5P9<^#y?jPTshCwUvsZCZAvPih>?a*O54=oj;|i{YRie zpag+Qk`Ns7KOj&f6MK<#Z*P_<+e8VcO%!osiZD^cjVacIlI3@j)kSs%^(K*mip8yv zUKRsgK>&k~!B_756mL-QD`5a=pNW}_qhpjLvVO8!$NZM(d&@^Oytq6Q7oI@cOOOdz z96IRh5OJj74upvBgLK7UU=^Li^1(#fXFq<0>tlCsueoa@Q0XBt?mp-ytoO|gdl+mu zZRwoJu-EEiNDRj%@o|jdpt~>x1>#CyeThA%j2b*ykYl%6%%U~{K$4)$6a}f*f?th% zmwC4z7q{_5s>(mo6>`~|1+yVTP{CnJ<sbPaGT|_S+)4GwJCcYLR-GKk9Uy#dHCM;w z>{WoY3Q>w)=8q2aLd#R=XwX5j$EBnQ-twrRVJLu%!WuF*3f|+qG9XISPvb*I#7L`$ zn9TgX<kd`$HttjV61gd^6|bV(kS}x=3OD9&!r!k5R+zPAm9hs1H#&A6OR(w6Ou7Xj zScbPU>FWxjCCGFF>d5+E@G%@mYXK>%0*fh!M_BQQ6tu>Qx56)pVsb;YDDnQsOfDNi zPf3uGT>`Zf_;Y|yL2~7bBfC1w8XuK>?tH2;H%_YAg-UqZOGvjb%%50v8(*iBiY2iO zUdSeuHk3^#_5=u2#k<8E7FqWpt@SpVlx##Xm*t-F;*KXMR|f}l)V0Q;ll9aF;AS-{ zifz$IxiqLDlI`6|RmXc7(B;Wi+XySXfi~bky*a+YPS^|n^x+0>1*7pnxKlWRGw?V7 z>8Yc6#a7=c3DS|}>{fOBfZLSC!YjE&O6*z%CLqP?sjjV$)sqbwq>s=evQ_oj<Qcz; zB`2l&9Se^bfWFWg4`oqK7+GMJ3#Z3e$KXNB;5T^4LO3AJnhpof$AjVN<;c%|kKLkC zUHePq&TePz+W`b^33}ihktY@+PeK_}46oJl*|#oSB8Aq)$cV)09U~HF9O6OY5#dOt z5~qhvcs99H=l1DC8Kbzrkr_lr2czK=;VM;X8#Qu+g}Un&PTFdHC0)8RBJtVlOQX+^ zup(*J`c3OsEzg3V3tbXNj_x%_+PtXu%+R_&tk~Ut@qhv2(*};}599L@Ty0oPwzULY zT#Fz9J{_m!BlJo^DQBRdW$EgJ)KMb*n37`uJSBx06gO-Z0tyHR5Ud73^k=&_o@QC_ zIv*ddFWzA#<~yunbudP;EB>?dYTc}ql$r40eC&&iE9rs|Gucu&ZQlvx^)J%XS5J{d zUfxAVh4))=urIPOIK9V}_eSOm(x|#9${_lrV0SOCIoVZFSgS88xR~iE5lLACOZcTQ z2nyZL?ng~%i-Ji$Dqs?_k)$>F@L9V2CUh*n1_c`a;DH+q!JsXu14o~IC=~^RXW>?L zGZPw?bT!ti-@QC;m<bPkIRfpseV!5H(py)zy|9y=`@6;C?A&i6IsdzJpF<3A-W{su zMhdFaexdVVTYGxi$J1j;Iqqeya$z?cfu@p&JOagFIye*5-3iF)Taw6|eEH}Vwxejx z(cM-i^-|E>O<i+pTj6^m@?cxMZ~2UJ0jRu!4op{Mo@@v6a`|6MKi<cs$UHUz?50Wo zP%;G`v%+I3@&M4AJn~v^hU)Ahx$3?C-N-YA{Xb5FoOaJo25ZWgh0a6X=gF;6&xt%Q z2vDN66LdtFWYfr!O+$4zen)ft=RnMK7pv-?xp9sZZ_X(oGqsaiN?J>S7>>a8@FI8{ zwm9<Rk0+-uo-+wcL|ws^&=Gv%Sih+wnFywg6U!7EIvhDs&IWi=xCnqslc31Kc9N5f z9CV^`hKE=37KM{WHt+c=a%{_cIcm?cdRVAAJf=DW(+Y8dtTxCxawbs-aa_LE06{FV zaa@^=Ger_U=1=7iZ6J{D3bkBv_6bx<<VQQl(%Sg3&Que2&UU71uX6;wW6zSME6y;P z<8b5b1U>yjG{7&*9x@9`ZeytI&r$+vmLClp)@(Y8A<R3uIeV>liubc~KSNO*@k{2# z7v3-_Yvx}+$9sNzcmA}!m+_s43sya!bYU-@fxPFM-$*|VAcRB`#ZsY)mE+6la_TS; zf66(|jhhqG;@yZ;aHHCVTdW(Ez;4<3ceML%5pL9z=LVD2*0)~oU<#Ei0$TM_M9Ig{ zmzv**7w<Rx_v@6D*93j}5%j7B0{a6ZZl1q^WgRiB?EoMM#!OmK0Q8o0W?#j7>66O= zri!a)>?Kpadqt>A>_Jx@`%Ao98wuseJyW)!fpj2*mJMtNEu%7s^?k&Or{L%1X3m9; z@zFV%$Twj5sMT8t9@&OPp~0}h@D%g;djcRlU~O(E0l5moCxtgXij_=SUb~|qYOMp) zl_IlgCNjfmqv5ZuuV16P_64tz$^H<T;*nPZ{*uXS<y`awlH|mYUMz)*UoHH;QAm4v zsG-AP^2k=RUc+)!$)YmTMP-gPQ<c>mVWzvtoK2po>%svYvq&@?--V88ubyU|ob4)8 z;W1??^dqXQ7y+#VhqS_jKBCT|j@S#ghS49>XsLdMcQe1R9!!?Vf>4hLx0#s9T<jo7 z9<Hq49;DwMq~A2Hi}ai3c+q})WP3RF+oMRo`A)LFAq_k{D5)L}S2Qv71vV)CQIs)7 zOPor2;R8lUPDYc1e^*U6<7nvdoT?hFvw{MO)le-_6QLnnKU)KnWs-08UU8DU>&c)J zBzC4~j1+#w8V}8#;_JWz3z+JN!|TR(B7pgEFX_;qvF|{BfBi)}Kv$&~0OD(A^G%R| zDwCk7s4gB-?W|RjaM<y!9OVwjH-I0Hph<4Pxj_GA(o+c}XUw$Xh49V{P6@We7ihr@ z_5VoISlj?ggDN0R@{g>_m=hV}dSO{lN5w+Hogk6!LaLkuD5S8G+o!xKrE{szq6}B{ zGlC-uwP;!WUy=aMIQ}R!A*wWcUd5aFK~0g+hjO-6Q^b;{@s-u%HsDA2^1DlD#l9E6 zb#02Do|1N-A2E2ybbIoQ*+WNXOddS}`PBLxM#GxMcd&H-C+GaI9X~K^g~=7}Lmjq1 ztF-~Y{n8(WZ+_jd;mh@P4qf=>Ak`!CakAm?D$^r=1HJGKis&VKE{g5B7)em}oGyY3 z6>@uyU$A`K5IVCd=cdvXIu~MltFisW1AO}>B{g+~_+k^J+e(e|EroY$zF}Hq56PL= zBH5w+?-fUmxX~q7F68c@NirW3(<Cc0)gDix&ZT_)o;sFn^?427Omu6J`Jy@L&&OGL zbz1KV6nBD-6DxYEhcZ=PiFjM`o&H{mzCU$h{MjR73QC(7KR1;q{573^_}=N*G1wmO zpEJuDYVik;YWbSK=)@v0P5%RCzG$gK;3PX0IU~#v>F9Y|W?j8Ou|BBJEfZ@RGml%V z<uj<q4FT7@r<z7A>#{WHCwa(~_dQtUeQss(gX8K6lpGh4<6`DHdObPbO;^fDMYkTP zrr-q3brFj?$PVp-iu+Z=g`v;!?ajLqN2Q8mZ%=;=ootJ)pEx${vpLwl{-PGWIO7ci z-jsLRyK-=bZt1g0_~k!CBTw9ljTt01yLU8v-#LIl&%CEJZp-S5_vGq|7c<6^n>?&; z4t2#H3W~cq<Q=idiQ=rM%~uMFSC66{Lp7d4zw|q^AK^E`0M?7S5Usx?+C9&REAbz% z$E^Bi26TNjtjgD<1A{*tlsmw@M^6Qk0}TAZAW0Jt=x7)I-&7IzRXw9%Pp%d>=Nk$k zrMLzANFhYPqc7fje{S@J;nXX%Vi(RCMz&lGPD1;atUua;ID;lnPJNOH1XYfg36um= zB_SwS@u>Rb(raLGxn7d5tDw$WmeZB@X8C3p+~ub-OILg$al>;uwh!l84=g54ObMqz z#r|+i6tkPCqHQ;!hg9iyNEaLHOw?>xTT3+VLad6485$I_zZC&;Xx&OGU@cEAjFFiE z>O0fOK|L4^S$zUXPJIr?q7&7N(3Ok&=@=waD-SN?M2B=nrBWr`7$(Lc*NE2pF_Mcm zAK?;3NqUN)Twpi28u!(}B{;#gDMPwcX{<Z;wdSiss1WOdHgryR?!3Eue7xuU0iB)G zJ2%QlyU?0qWF4oIQ3(ZGC704+bX2%wmsbr#O)}3p8I@2v>!GosL>I{jB}7j8(BM!M zqek{{!c379p^Wt`lnsV~4yYl*P|px;paW`vF=~c&o;1%u4?TLk2g{`l3hB@k_M*Z% zojSSrg%-E>Si7wEVE1AD&ph<rx@prE{i8E6<6PnguUPF4b8uTI!A)!T1jm=W`$Ol+ zoo_r0N(kP+sq<t2M0)n?Mu^!As~bdC&Ss^86lDm4x%4WstGAj<Jb$#xkSAq$S1K12 zb|e<pu`%&bu)TX}twb`AP*Bsk8U?kFB(UI_R7&<KTSCgn2~&(xTva8F<B{h`#ar6{ zKtc9((%gB{o~*fh2M>$yJ#u(l-{JUieom;p5Bz)4p#v*xFWt9)l{RVI*pYPxj~_qO zwnvpLia;3v#JWnva@<F&3IzO*RR!Ghs|rNB#=2_%Rb_!NiiRqzEMO{9Szso<VLe6u z!NXtu`qO^AmzGC^4W}%dKLPK#fB$}bd^{R{ZvDD5Lj1)!BSy{@SX~?9i#2Nj<CX6x z`N-1BM~*x>M-=Mre(E_dTBMMrRY<Od*%h3A98iRzm@syDF_ppF%OY#JvfolP4?Z*Y z&k=6%DZ_4^d1BqaeE90J71j+|asYW}<LTR%Xn}p@Zu~vY(_Va;JQ(}NCH}+eq2)am zZisD3A6iLz+6SKDke9Vw&`i(#$p&`E`Ag`46G0m3fj&;*fNG{~aUQN2c688nj7MD0 zl<qkVciNP(@$k|1Gl%tE*8`Tdg{*ix?fV@WEB?M5a`6#mpCYaNSxc*i1`v;kuN)cn zrKK2XVLXn2s+ja^jUXqM%XdYQlsv^04V}>hTU5==@k*WgWq8T}=MlF~yh=T=>}E{N zFDnip%Uc++1I4}v^Ebh2Z*}MYIR$OkUVTTbgrNYS5gJ-I)p(4qnr>v(lp*8o1wue0 zm5+<dt@U%X{Y>1VD9N=|p{Q1TZ{Ze#<j>#Rti|2Zf1f$yx3MVw){L1q$D)*;TLxt3 z#%}4Kor@|gd!IS|_2SQ#f0!}t^<vl2mxtTVnNzO}&pS)kH|`~xNJ~9IAQ&PUSpE<_ zaNX3Km?L-O=)XK2bpwr?Ocl=V=nmy4z@J;`h%9t^B$??#H|w~CZhC&=w^1qmJVxC9 z>XB>8p_M~cl`Fq`@Up|m`!&v8VgE_<Gg;`*9#lB@dO)20T}+?XGJjbw#$To<y%{L^ zv))iER^-NAy;Zrcc{<LBR&;0kR=(pmt$&gEF-K85jay8#N3ny>Pxy7XYk%vg>!<%t zJ+$n4uL{}yR~|$m8*H<-E_xr1!k58_*P3%Ljv(*e{cXzn5q=>3Fp(YGM{<@=9cQMO z@e{$b$pB|rFH?uN0f&O|0r|FOAZK(JK#fdlrJpKZ!CKTl>)v?l^>N?cwb_2%yfdTx zc>88FV++22z-Q{qMKzYb%6xybkMF@(Ngc+ctP+b3pQk+-gxd?>7cj|{mYL*A|9`?H z$E#BY{U?~@_(>Xc=lHGR?(q+<w9lziddj>N8;1XS^iJx=#W#DDTa~nE3krb<mfyGL z!?WA3%an?3d|-e7)v!#S?((BE@NMGYXA~z!ayZ^<PJ<xOR&ryKkT0&o?-TvUHwce5 zQs~gMVkoVoUX4{!7nL)X6;qedMsEY~pLcfPM=O^?pB;B#a6nq%57Nw^N2mQZbN7{! z@XYOZ`(W!!wJ*cg`)z+5IJy-7xx3Cz{O2m^YoN3{kJUNrA$f#b_)N_rr2xD&9!ln@ zkuz5cCqN4G&?u$QN~wi~j#0LhMwU<YgVDC+IoBUObIT!oeFIzqeRe(~_@K0sKkuIL z%jiij7EicZ29HK?hg-W!)xUz#xt8x>n?tuRu3Nhj-;qk~!@sR-RSjAb0YEG#;Wf)i zFcTZzQ)V~tq_Tu7fAQaP0g2wUa*e2CkRNXX*hAr#qj1SFSam1diZ7hRcc9N2oQY<< zU7^Xz!N<R?c>#YdAx*OnAq$}Uwt73Dejx$?(NWh#lGWk`LaC3TbQmuo<Rhqrqrc6a zvvx(ty5vYy4=_DZ5gTG18)DjEP2@8CXv-%2Xcb%mO`A4D;|e%>^v&s0eo2REH>XX# zk&e)@OL*Ur!?5MIwJyRoM-Jir7sQ>=f7J?nZ)@$H_^;JVpm_)DfivrY5rk8|3weh- zQNxC>0>+DKFLH2l)_W-51D!?}rsaBJw5WR#%sR1c0W@~P7dy4vj32LptDq0<$;#2` zzf7NeV=Nl|8`S@t2GOx!@b)f$w0ZA)2)6pR>LvKakt2B5C71(Cu3C=&+V=TQd~eM% z=(`KZ-e*L;&wK`F(NHeX<mYPh(Pa%u(neEL@ErJUknncx;PU{2i2#Vf;%eXvh+kL6 zx)u|-F4U|fWCkp_=Ou@CxT=S4K+fr6cXF1tI^S7gAB7=eux%zXcZgm%Y0;4s>(#Me zeSa3WL?_$B>n+E3N*=#``q1Np4ldcd2dC#}0+2I62dYTI$FbEsoLb;XgydWRt(7JN z4APv!eHfq`0#Ce7_>IMC$O*2*YTP0?XURvMBW_B;M>o#bqtUAe$xmZ0sH9|+-6Eob zaZms=Lb$z(&<ppx@-CAU*gk)?lyvyJw?AHNO`IZKaC5g;r`Nt1pU}PAofG@NLJa@{ zb@6_2wU}8Xue(^N6Yq^znEaT*D>-T1<h*Vq+h+=udo?+)TlnSlX{+rQ!7#)27R{;H zFAg7oEt-kVK3o@;M-!d0Ga|=`<{;F;?*TwdfI$UOqT9-g7{hX%<|SyqW`|Ozc}dYa z&C2Hnk-xWueeMSR+(+vG^&+2Htl39C^Rx1|_<|4y<!{v`zd4`%tzT4si?3Z2P5#z= z*8X4FXZ%!&%Jgpq<kD(EVai`@h32Ah?9(@uU*=Qm0+edgad@?06K8>vpqJ#Y)ExBW z{qE|ZxCVO4i6x#2a>!eL<jI*}I=*}$^ejwp7pg~9VQWjPT3f6rOje8_*n2ccx;Fmw zfbox)-`Z7f=Fhut9a`3ZQu#7)6?!@p>-(dTzh*6eJ!M$;gqL4!$gNa8isp&o{lW`& z(u4uhX6~>lj<ENIeQ7%CXS*(J7VEyZYLeq+t|o1=xDxn~@mL_4*my7-n)lxo7k%R7 zpQ~EpsT}QIoKQ4y)!z`O3b^n_R!E2@-#XM3aMfwTyuxH7QJZXUj91G(J=g)ArEGGP z$L_;j=!RdANV;C}=;;ZST|BPs;VPVQV<B`ZLx<vxqF!7B{DB3umrBVM-%3%B3LyRk zKCEHlys%o6hvMN2P*<tp6c!Ds5h)v6toh`bmk*Lp7(+oyIOzlY@!UUR?XQw2TpF63 zoAKv6Gy~%e^T!3GeK+nz*pbayhY!7iwV+4)F5~acod0+#{uRH(&#&TB+w1kJiNwiC zgZ}*M;r>l`0Rm%)CYDb6;{{3*iRv!Trn|yl$b&F>oxoU(Hv!4D%#>ng-h~hb?_lq0 zVtU4dMGGH|&v>wS;r(%f_4@8zH?G6@Yp9BZ-)3e)r<}68p;OijoVQK<$@byby5D0A z!S%enJOUnr<-}S*ODq2teGWDQ0E5L^NDF4M_uu2eFp@kEr_af!)*W+k{1lZ##O`@S z)^iAmmE4%stU5F}ObB0<k54`FGwK;H2ni5zyasM+byVKUg#R4o7nWzPvjPXZ1+M85 zH+}*Bt_L)Aoikwq9QD=l!G}BHAC8^<;b3~=<f=2r{G#m%Yb7k-WOqh?-?-MTH{R#8 zF>CwDYPA2AQ9GnZ`$*5c815(p0Pz=14)6pez(~ahLtUEMT<+*}R5vt0Q8!{mnl>!L zf}}yHg0bZCRvuptm1>oNN<|G>g*CFes0`Up1FgV99{sp)A6&c#24=6qe;f|M7oq1P zXu?l#;oGn(+8vLUuEV(}r+kC2u1CA=2Vi9=j{5*BLVK=5-x7=KjsP^Oq&q31F!N5$ za_LpHJL+vJ{J-rEfPnlH9%=yy03#$(snqMMI;cNd>%yBn@ur=O@FiXIq?Z71hUp35 z60DI%h9_|4vH*(>1W@&#A<(O<gN0h1QtE>y0QJL{K0i2k=T?{kQzs{FE1Pooa0=O2 z5Ad?y15TZ?*FtCK&Yn5S9w0u5-@O|^P!#}i0h^oFy#By@Wj$RG6N`>sSx@Gbb#bWK zqeknnh;O7Y_j%g8ci2Phh25VE4Q<DShVd}Fe}CK?K;V)07!A`zlhu(Sd6x|0b83~r zlmP}sSPfu)r6<TiZK1-N&8JfFXhNFfre%I&fpMj?5Ska&!Dx#eYpT#2{PNZ<7>MuY zmr)sta&ym~)kNb*eej!j{Qv9jJK(D*w*SxU-Q9$mgfs(*gqDOFArv9Br%{^N=pBR? zF*Ym+?@?65UMO}YF+i}O=rvMRdQ+qmY{c@cPw9w=NOu1-XHQP<+`aI7_1``v`OLZB z{qC8vQ_jqsQ-tAD9(h3AoG+?fClXy3E(9?D7L{#es8hru3i3pf$c6YY9|1L0e5(lP ziDE6H^)IHDhHlO1Lf9FBJ4Qn%Gr9z}i##89Z4C{KE<o<2Fz$qM+;L(2ZH!+a`ikz6 z@F}7Ahdn$*iLXRQaHae{C(i-hJ|e+fYi*M9OeKfEh;Q8Aq<p2sUlP?$%A0!S2(I`O z#A{JXxnz9kiQ?4==-L{(1EULJMFe!LhPD}9fas(!bYgk1ftS--5;YukY3XV1zRc|2 z=cVu#u`AP9-4OIdxDwI2*96-`yN*ORRhkpJ&>b0pJDSjkCAvqH&FBI|CxxMFaUH3g zp2QZ@#%nPmom&jgySdD#NsIQOs9cH8p_bl5^pI#h^m~0jnri4+1a!KF?!xFoa3i1_ zYUoCcE`bVhwM6U2wgwuyCZh|GJ1LAivpksNmC6E%Ux?pmN6Keck?UJ~#Ur~PJyHCK zXx#vkprKncx)4r9;7-!ez~}-*CxxNwl?O9XbG#k?W>iy&??SrF7wsgwZtki<?BnE2 zYpZoqqA#N_?h^os*2B{^_oIpXo(Sj`8u}EY3t?6SbSn*A&gc@5H&lG+mKu69qYIEb zDGZ%c9_*${h46NJ#xD@H!HR^xI23;s;<4v~Gwx<7AL--;wwqT<c@OHj24T;ImU=9i zUQ~|TD6ed$=ho;)PZW1VKsVITrx;xbGa{fHYv|34E<kir7`kbBupQ>q{YIi%TYpzG za_YIJxF?|+9uKpK^CbXrlrc6;Y=nqFHuq8cq};K7W|l%XN3z80(Hpss+5ljrTB{gc zfasbaks&?PJb=J<>wrXEOD*DIh}K3v#hF}{Z!;asv>(;LE&v}o-H)akm>dD!KtrEm zbRj$#0o_PLA7FF|+#f;jh8lV^qYIEbDGZ%e9&GEC%5$=Qx1r`kD4%;!7kw|Q4zl~v z6UAQ<t?yXJYv@yqE`*08a3^Z$&5SNUbW#|)Zh0`n(>&ej69}R%BS@F709wz)x-fb( zp=~JW%iOr~)46e`VV~rg$pqLc@*>W_xc9*JcNw7{f@-QoCuawnX>+4kW-NwJL|26| z<wbXmXFu^M%ySSRo|Y8N^g?H>`FAS_$xs(2mDa77N_&yX{wS+7ZpHX7oAE6~JXRDH z2$=y>Y~&OWwAhUoRgrX1h_)l!PUKK}=<QI&wg@y3#=Ayl{0+Saw9kq8)0I~b9eM53 z6*oR}uaWt)(bFlnf@iM2`i9p18}x56<myZAZ7-g5##_O&*91~j&c-=o1AELXp%rw5 z!qVhUxpct&qTONLD#z4}35~WHexFcz`k{lwXwogMnS3Fg^-B)*)La^06Sw=C$_>6i z=;AP2I{=syy2{VUB<F99b8^UHlj*JV<D`GE@WN@L>^dk+3S1Uzb=!FJy!9gL;AgWQ zo>nsX*jvl?1RBIv71?m-z~t4<KYnN1gJ#a?Ylpmff6>Y*ciw-`P;u|-WeXfAys{=2 z;h*k(=*}@mjJt0gHd)Pr<(I!Us<)a2)A#VL7zovrX`E+JBV`NQj^9iV!VCsbnAmKu zFJqo7n5Pg<NS=r@A!a;9j5ZWr&)*<_R}D4hTFg9OY+?;FG`<yzk1!os!%U5*7xNSe zQw$*<U9S_YSJ7V#VrdvMCtt1hvLMT2fn_33VT6n#O_-b1JkJ)80X=ctUJzJmT~j%q zx6kl=eu8|ecjT1?kD)7R47FjxlxX#yYFy^DK1gD|VpxZ|NUmUv#!{wO2=gcy#M3C0 z$3D$G^TopvRwaoV;|j${=>7o2*i>Oaz)IQQTw(<wRo()LBR{bGHKv6gM~?|NA!@Pu z>m{3HwaBg~v|uEOS}>A;vJS{&HY|`IYf5-@5?}XI8Lp(fVo)IFlB$ns=#>@Of&0&% zGF~&@t$1@he>vT!x3_{fR2;xl5zgayDk2lIVP<LLi(1o}f-L{32y(8L7;b@TQ4I}h zEzWa9A`v07U#;eulS|VAp~o7tBA=V6lgQpblI7-rmTUAd+dv+zHo86X)zrUyI(_qx zXV2~{9{ptJJ{_;^dOLT)S3I~X!FbquHQ}LOo^3ww%q-`ZpDs;a`RnC<JND0RGjgz3 zAR~qce&6y+t$CZOT4P&oMMdzT$n&+LIIR_(pjM>NPjS0!Oqe<HJKBeRN^|N{{-8cZ zTQ3nBPkCUU(#Pvlrh&Ga<uwE|H)rPJ%D$im^(o9(hJ1*D2f&~iXETkb7W2#(JH$ZZ zX`%6~P&|aW3V?Vns^oEU&3)D;<iQ?8Y;=xSK5LJyd{(Ry!=MvA+dSm!J&G&y7G5cd zB>sBY;UU`;a6TK=UZSt?(9lM7SB&x5!3#W$y9L0wJ}Qk@?<MYV(c5Pkh$8fh65ZL_ zP4j4lZtYftmpr4_OY|uF40BI#2SwmE3H^*jx3!iiZbG*}Zhb~?5&F19=R_qjcd>iD z$fH$6R7l>Utq&C=VLH3N=@`g#t{0=NAoAe;z(G?!dDa;#I$<64^`z?*cB5n&Z=dFO z&WCKjU4;AeeeNOaQ!5CFR*@Bq2B73m%XubPn?Q1-{7Uf=%6rK6bzf8i$=-_UcBN>p z?}YN29``*A%i1B)FM4RVllzH=P6@Rx$u{>R<}#bw+=JNW<~g~6Z)}kAt4JP)@*sd2 zK<mXtWG`wfF7R3PqKUm&Vva>kljy4n-B>)Vuh&q60BUd%z3EPT)AdfSXlMgIi*ok} z%2i8eyioWh7C@|Sg}|BkVgO^HEdUu1+0eQMY~}I<f7h7sn_OG50BqI!@bg#OK+mh+ zlPlg*zei<<*sHSHUNzB(7r8!rRn5?E4(CtTdT22ffM)SYA!TtAHEKg;@hR7ax7NRw z<lU8=G-$;d6p6N?tFO0>(KI-LEQp3eFgy+TtKXwAwm}$G>VvIoeJjQU&6Wjh%bEbE z#nsf0T&S%o)eNQ|VeWxwdaG`oOJ$y75iNQXkG}FPW1eD|&D!ghxXYPmkr*p_KuzRH zFGsIt%;YlDA~*=3P^NlYu#tya24KF2wcDQRYo5rZ_tmW`QDY(2=|B&IHY=P>@));F z*6Dj#r|qfk^0DqlI=RM^Sf>N2eSfdy^xjtd-Xd5ny870SX_fO?03(QXI?$V|{%+9w z;|VcX=JqDEe0HFG1Vs<unG71sRJ`@TJj~G`LJy2!;mOjtyD)blto<LkPZ75bg@5)j zGj_1k%arGK6f;@3O5L-H!|4&2hov@%<OAF@h|gubSISeJ<A~2?yeF@(<fM5g*1QPz zh~6~wXrbwQg7qz$WOxYHvaNjUQ&_hb6MF%&C(F9+WhtB8U{4Oqm0aTcGTzg^7y$8o zjVXjjIUGVc?v+I~Q+U#Ho#=GVwL-Go)q2|Q0sK}m#(I|Rw#jU_ErF9FPqzvCY$@er zOHt?tp_<Q5qgjyclgvE<j(VdlWQSRPRuQAZ%<ya+Hh(3gV=VI&gDbickFME%;!&8n z5Fj4iqJ10lED#e#clB)p_5gK4ELV1WVp6DRuoTKxeG(pIVy;fiwMYyVxx^)RmXfNt zPFXH<ErP=U#1&s2Oq3`Pu)ulPTxbQ+>v#f1A=HL%_6d*{djB;s+;f$gZ~>imtriIN zmXR737%9ruC;U+j8+(D0(xn?pbK#7s`8_LV`G3Ch2j`&m*S%u=9%)f&^6cMo`;Moz z&gfCrA72Izp3PkO(e~wm&q2U*($ey!*$L961*snAL$k1uQAH(qNRIJ)ji9UZ<j%^f z$_-FN*V4EP0nh&H2S^%(FW@pO{piHzq<4`20-HjNNd1hP4lh}1OgbaX%O+PDkY=>M zukgdo#=45DoR2;U#Qd>EwVf^i_HVcwl1uZfpG0o>tdy<1-2klh*qaR_bT9C)H4x2v zA<cO&q!5ClUF5wjwm6<*i(_G5zhxvbl-WMR%mv6?Q~p(BaIhMUc@lLyj%HnXFXr5H zl|d>_D2@Un3EjnSePuLq+b5WNzL<gB`r0F2<6c4B3VorEo6)3qE9NeO4Wg@$J4WOF z1-Y@u9vKK{W^5clRDIm}yq9Kgzn#b4F~B`!{}oH*0YX2gMtVGkaS6{pmY8Rv?vR-K z2xE)8wR)3`Jh}{V?=<V9t`Acg_jFy~OpDfrZkZQJ*2oa66<U1h4svgSY$$b8l#9s} zd8zfK6mk3Vn3Vb{*(oxtkE=visXt#S#3=daKg>k2;S|#j0I<cELqC&JjDBp#N$I<^ zE3g*QXx>CE#)p|G#xtgthKWZEegl)zw9=`^bxBz3cgB`X%+S^(3R_#le#6)T$(y9{ z@;L+6q91Fz08T-}Ncfac{7ni^yLI2V-$?n*PEX}8R?6R}k$<N9hm>PPUMz_<R9cIH z^T~&usZ4z6iK3r}<`&L5Wpq5Eu>`O4GslKvt#24xAhAhdSUzLm{v<IMqaGU&oi~G- z`O3LP%r8sCsSxbMW)iErkK?^Nb;j4S;|YsvSMW1O6Z%7mZe)GK=mJD1>FAJMJd9k5 ztz;|BY~F<otq%+>YrK(;dVfGQ^8@OlA7j1HkEWWL1!-ghs;^<<8B+*F5f~eUqLsFU zE`fQF;X|iu=x-QZfZR!8=#27U8?P)d1|#ablXCYZ>B48sxfk}MCyECVtzRBU(9rRW zE`(<ya3_VLt#24zfaoM0&8G^;{|V}{mvp%T*>z7RHMFn&WB%GFOvv!{A~iMa3I5iL z;T}j2*=NJp?$V~+-F*D~dua9kPwk-vjB(=QgsSP!=>C(uVDazDIPuE6W7Q03W_yvX z;>K6R8e?47^Jk5v`aYHF{d)UlOgv)>;VFOn)zMZNqvwl!X3WqSV;NHfFGISA;qL%r zs3T^zH>M9r*LPZ|@A{bgt_j03&fkMtCm36NW4gXqLWnX#D81YIdSsdxpijiH7*RbH z9`x^V)ceQxI8wbmj#L?(AT>MH_^<79U{LlB+Ac>?NQCy#T@Ei=JC7r=TxLagriYgY zuj4S<I<}E@)J6&;w2?-kXzK){i$m(av4$yQ%zSYxx1(m27$;Z7cvl!&`HsW&HbzcI zZPt@E@A$?`9s}J40LG=*<8B}u_QjCl8>^xST`1AH*2j#V;N~#eHwwBtBs#`A!RTW5 zQb-T8IM<N2<vjCo#Gq|?SLKP9Jgbby&-pccBO<r%Tv=ApnBR@GCg}o<=B_EBvZc#X z>w@pwM5R^_OKpydWsZHpW^cq!O!LjAqN_Mm+;fE`j=Gg4&vMW9IxO%7#Om#UMrB4) z{T5Wju@#m^ZPaEf^-N13%{OY-49U~w$hMXAxx+cmEV0Z|1Utdsiet3V^kW`PC&06i zL2WKg!<=ADF}%WUR~wb>RK_e4hSa?#^{O<R^5R}&4nLwCUM5kxrSUl@SH;Fw7|K_y zbDW=zMLB+(`IRG9Dm{sDsgZp<u@6Uf-l=6wJYj4oywN{iGuG*&;#?~%&16Tr4s*mZ zN71x&?=8GX)!fPD^@5j&B+LV@BkWj|<C8c0Yo-=+T*(~X+phq@vxwh$7EuCEL54O% z;a;23A2WIa%#vu$YDJh6j46hfAe}H8kKK<k3q&F`^v_**HKFhUJC*T^;0&bc79|xQ z+qoOPEvLiC()e&&kuL}do8=P2%qpQbw*&F1<mV$g5Narj4c{1!3Ja+Hb=7Y0ZLLFN zYyal_Hiox=^T!#Xfwo=Oi-e6WYB%*n*MV=|&(;x~(;<4V*Zzj3MVyy2*7}CA1rnR2 zV`Uu%FT@h}qCR8m-$$*#uYUyK-UHEA8KdWmRuRzgp=di6(b#TpN%vv3)9`j%I)84% zl4DZp&X>}c?RFq{%g3qKyu|q&gp|JtVD+=xOL+^D{|JVZtMRwgR^v=dlK&>9E`Z!o z1iP)2=Om!q?FfoLNAlD`c^AUpq~uT&z}$}VRfN9`@eAEk#wGTRQcG`?deg1$9)wiQ z_KWQ~R^1KJPP|z`!&Z5tU8%b;ox$l#Fx?c`ri1CO{QFT%x4^V2%_}k8l7IgZ)7h12 zI|tLP`S+8UZUejvWNnh^9R7VS{@%9As*dT4fh}m5?t<wKGW`~&JHx+njy<wPj__=2 z<2H)1HveizOT4%4SR(Fp%OF0)*|IEko-^Ml?ahC;qa=C_p_{q;w68^?xwkHI#su~w z_c}sf#@uYB<Qc(oS^o{tCgsgFmi)f<oIA%aN<BWpwz3VeZ#LnU!q|r8a$%${K(-`{ zI)Lfju6rDKPtUwkru$)ff%KNL4}ZT4(;4WKQKg4s`XZSw#q@B%-Abu%bKFm<v;bV< z9;E)XQF*YodMjzFP^4+Wh)PT|&puzN36@hoDyOb)8I7b3LUW9zvyCtb?phiVk_q#$ zv=hcy$0cTmhcQODs|l0!FW%@_CGnYPsSHvd#y2{6N04S@AiSL|YZGL`*wSiv16ALS z!$g`)q~Qg)YH1QtS{wfbt7*5}1EIbhN*ktC^J2i3HVF&#n2Dzu+xWsfD&G$r<nh>I zr}OxyMEu8dzMnpI`x~!pDHRWG%Xbd{?FGlZf65PQ7w;7Le|h}wJ_T>QvS-2vQ=VS- z^yFI~yYY_Vo8Q=d%a(gyD1FA)GyDr*W)E3|EAaVN*q&Bb_8j8ds-DJnC0{m`^mC%d zIqxiWkl*bNJZbU;%@7XoDZoU+oWF0Ry2W%bVqf{bOdrE{9H5=?ob%j?@%N0}v-*2R z%Kt(9eVMPP<kOOf&-C}4zMhg!A>;Ra8SwcoO!vZc2|(b0wNB>dD3#b8_XvF*m<NBK zfc~HiOsf-y!aJS$FL@4&jzynI=l2|DMDiTgV%lp_=s9fv?-TYsMvlW4yz|aAk55pJ z!?MmaE<W{uavb*azDB$L&O12RQ;qQTT<5+UQ4{CO?RdVp5FpUi`bwe>()ofP-Gjb8 zg6PowYAmTi-gzPb(Ftp>FP!_XLsHl|s+97e=~;Q7bNYyO`23Xso;GHp^`(6NSmg;| z_h;?v;QbZe!`jb#Sj7Va+Fl5cJG}Fj%{y;-Mr+^B8>4CG?IiEK<%u}}8v1<P6OGR! z+*(ZZa}&Cg?|ucNi5r-^0Cx<N!t_op4`yMB68mOiS9n?b8a{>bk#11s!RZLQhSj;m z`Bnp=p9bH)A+K*HnU{b%;blV&tle2=uJ{VmHm09<PX}t^DK!gMT9#U~(D|}}wT;i0 z6}eZqpNFlTx|)4NoZ=EU1NTc<2d$}8S8yHh7C76Go{{L8n2&1+z0-dNg>6U|I&-my zrJJ4bvKS5l)fYK)u`j|K5lRkgQT~tL?BxCz(FZ)VxSi2l18i;n$M0ToZ-`&_Q9|$L zubXFb%smCbs)c>+N-WdAIG0(~u}9gC=~Mu7xBZimAud3+*Uc{Qhjvc|XPta*p_;@C zYlFn6c=*8QZkfXKirL$T4JOkJ$>|f_T=u&-LxLz6VNUVJ6sJ$Mx_D|a$CFzH0EoZV z9ET@zK38%P6fe2Ur2IOkUtodRSIUo&yq&vTjWrU_H*rz^1>#3K*YZ6#PkybG`)BPf z<V<%XmdE=MR}sko_DLK`KckWKQyfWk=T<3IyXrRJNOhRd(o3|4PGPkEuK&o5oqzFG zbmY5;HIcJhd9ay6(atw&doS?bHjWz)z&URe_`Z;T=5E1Mxjs#|Kb38*Qm=1CJS6Gg zf5@HJ;gWMVYBUd^GL89~=gr`!gZ8v`kC1BG=9(@LyLeW}HLdJ#%@I#^9i+Ne_yO)g z4WFXn)eL1^R6T6jh=-+OAX@c8OZhtYa9{zp=OdoZy<LT=o*nGWds*1K*k`zRnIIa8 z-jRD3?k`HXznB2`x+i_-8xYMsm(AP-q8XP0bF1&WKI%g3L1r(2hqx5DH)4Fmd(3>+ zGKbf;5$+W7S<AM}b(char)C-=3Gi%$OxIWSFOo5hzefq#ev&9JNusl_Mq8E#J1RbU z-r6Ve$zIt{sZH-}Qyxt7Fpo>j2YBZ62jT=VNTCu!XJEI=mbVY}cRZ$BQTu4dRIUTC z7Qdi+`AGDpbwC|$Y+l8)p$V5)BSf6Gny{Ir0QSoIs)?9PKDid*E+Szv_}rSu)Sa0Y ziS}6Y`gy+#%7Y12obOsLav~nyhDz3WULn5$U_OufeNFnE_4I>K{cZsW6k#hmO|AYQ zl^0`_mBTt1rB*=SM+0O+OS6z_U@hsX-?9(3@}7GQz`6!!Bo&~Zd(3Q2&y9BvYR{!; z&vkJ6n0ryD&Nza+6?ny)lgoVnfF6K`dvfDFl;5Q49A`p3F`eb~v4-ID<sQy#<&8L! zw;w)#oOrXqn~`kOW+ZQzvL0|ovW;gXp1ga=Xz@1p@{7$6#9$gNwA=CaUFuoFJPc_O z?}<KN$s<-kxwsgTe5+Tgcg1Pu+oOn6;R{^{@%lY??3J1SS>|63+e9~QG$Q_Z51)!U z4<~+we-z9}{B1({e`5Y+urq@GHB~!e{qyX%h+pAnMbN)_d9ZaT|1RcVD!<eEk@yos zZ{9ym{0je=`+X$++aez8o&BRgrsp3;Q2j^tlR~Y6eG}kQvj7COj>tX=I4>(XFYmy1 z^)=EABX~h*4yGw?LOl*P%?G639T4T?TKNxgtvokZbO+`th27%PNNprJl=UpJD*POX zj#S3&Lv=mP{BKMCK2^G=gtD$?*0&{VY?ZDTht^jt*B8#x&RJizwffr6^@a1cbJkZ& zzS&WRb{(8kfkM9n)p3@*9W5j{dqVkiFnA8OLgDFqe_M>ClL|FMXI}P1^(<kgLTbd@ zp=r!h0?R~iIR9Mk05g{0U5yAUFXnzC>Lub<{l{j})n~_y(`>9m?2*K-@Uz_t#Ov(A zrXD^IbuVQ8<?xQU%*P+Y{aFl_$1viz#q#NaNbFgNM(uBkI?C+JU<GQgpDeA#y_wR! zgZ(D4EBuTI+Bfj#c3krNnSUuP6-^>(pG5qq{Zp*{(!0O&v-9jywI}u=1eu->Awlgb zvM(WOZS21TpPB(6sMVd*kH;p7IgV|yrPs~^gTzQWyI>OLc>uA+zJY8@3ey5&!!WCy zonj>4sFQCE3;|Qk#GEp|Q|HNB;<qtPexHX>o<rY;ODoGQXd%QoCCVRk&+?3PwZhZ) z@Vgl2yD6&OOTw?GAEEDs)QI<z79k_HSW!#l`DQ4MxXu;lNP8r5A|9TmHlq96z&6PI z3z>g8{2}`I_#3cqi3HSn81XCoeGu^Rr?WmD|F6uy3|!V<<8M->e`jpt{Rsac>#y-= zgz_I?{-tnMG?#e&zJGl$zg*@|5x>IEbiebL5BC771+X6`$n^X$32F(E{V`GdU>_;? z)Pn$m+Q~V6rOcFT)K_uzewM6GQKE~_K7eyAT45BUrRO;hE$##Gac7-_J5P*^z}++g zH=^P52;7+(_dCqJ*oqZHecV~0-1bD~UTi)FsXp!ujXQ<8OGJXW+{fKq)B6B(m%wbl zw;9gmOlO<*s-32|=_@`9$l|Owi_JF`3(22AzeWpWTUdy_M@N$XjQHo|c)Sf~;X_E? z1FCKUy{+(+(_><Aq?<`Ns~$p_`ykDKGs!xH7QpAJroXGQ0H(-XrFb@8W;8!To8AkA zzL#x!-pPy<M*F$*M6Sop{u@1yT9LW);8Wt(cIP$j70kWZJS;}~xa)>;+oOqFp&x-L zA2*_zJB_(Z;JE1RE0Z)$@2$kG&`-E0!^?!x3!JUiAv;=eQ+@vER(SPnerCR?SV-R6 z+r4*op&bxy<S1VP7OrYr;tmY1YL(oo<BnyU`s)f$IbAHSrL}mq(A7G&ixGtB0crYr zop|Dyrv%;<U47ooYHI8Ma$dKW^r@y{dB*|_^c*t721tg6@K|YjqsD5#Dm_*%@6kA+ z)yTQMfM+Ktub=8qvXMZcV?#Zg*Fw+cG5AlN=fHTdL0j`|D$fh0YY}lNG>sShGFkcB z#2BSjfojYdZ%wf7`0Bmy|F-_X9ge)KGwH3fV_$w&#jAPtRr9Aml4qBQmI7+aabk(+ zDLsOo-MH)MMj5r{u;(SgRXHc0DVgF+G2c)ts7v8BcO2A$(wH>mrB(j%N_DmKs8vJN zz4+F%4V#vGMD0{Lg=Raf`(vIwKqp6>LTjkPLkq(9M|p|FUyk@+2;Uv$ZKXW)erM1y z$s$k~ScLdrJ-L{H@(vQe74e;kXT4`>koW_LA5J{`QT~S1$3Xnog!lTuTO?04#GfX4 zpb~FBui+b2;sZsYc%vE0S4n&(;)9-CeN$ff1iB*rAj$8cd#Hs`4G{mCC%5a-H&$rZ zL;PV+ZY83;v2&?4+uA70zZ<>xWA|m(bx%3N%zkQyCc0Dk9Cz1L-atpo$`w*>xD^2A zWGe{q80!b{{4@ug;5`ezMW~u}d~9_Eiq~D(dP0Nz+y~<^h?$|eRIkonsri_68}F1t zgGyhvB90<+8DpI7;)bU`zr%69bJCYBn<Cmu!T8tKtbEzL-q|yD)%5jWnAhij`>kVC zJpam^M;03YzvV_ibMIsV)Pi2R&G_F5sofwXq;>;ima}Ne6Hf$gsi-A}85=9Q7#s7A z2XCnOhCCk278>^Ul>g-0$2lt|FI;H6Sn-AEB~Cfj#i@Mp<@L_PAlzR7tZ13{1eod1 zyH=H~ihlI6w$h8ER+naT=xWVPwv0^@C4(_)kx`>!RVZ5%!!^_qwK;k+Dy~%L7|IDB zO!@N5DWZn+>jop|#frtojOUHlD+ZXC=8Guj_k3rMF|VR+MJj-Be+3Afu|ekN?vVV{ z56w@?`STMSnxCbkYTx?rWd$23XGJV~Wb&FdlSM0M?{x9h9H+PVX0{Piaoqegf5V3S ziXySesZ+63?P)k0t+AD-VIb2x4I`o;*6i=@3*S%XJ=_v!qj?pbI>D#ZsT1{7pnHUq zb9|OYzUw+3E7Uvsx%-IiN**f|OE;8Dyj_g=)}Gv&gYwrT&ufT3K|C*@JWI+4BEFpD zJy704@?VYk<HY|bsimmg?}XYgq_jH6^VXXtuZ8rlq_$CmYES=4YF9d~u8z%>YX@sZ z{s}yFa>}pkoUFNGm010RleyNYTk(TYH$QOE*&pO--`yZ8cU>VChKH47<Y|g_5!@e@ zFeKcx5$y#+55}rUz*UMRcR<ye$#DGT&LdMrZqfy!{Z!|XFHGmp;>G;Hr)QT99vtX% zHVZ`M`6P&g8}+rKFP;<^mL6Ox&WnW`CtZ)lsk^W0k6wm=4L>e6SPlQyLRaJhLt}>& zWXU$M|0!p%GjOihzkQu^`IF)W@xqhN<!g+U6+Mlq6*G;M`NrIe=Zx_cw}7ZTEhP26 zEo@hV^-ejz-nB{ZrP*=a;$-yOTjTDQ|Fj7pLRk6IT9}Tgeb#<4>Tzegv;A=~;=@hO zipND`(fA2x#V&E$i5A<O_TqHDD0g~^6;9*I6RL8D--b0fOGr^MIkBZTqZ`NboI4;I z<m6LL<RoIc@usyrkN`czv+i90`T5=P_5^^Lg6EHtkmowddlJ*hn7$Oi?1TH*7hw8T zId4wFbP9Oqp?(cW`w`fXhUv%T?=>);kWl5ft2g`YnkWvj->xQ_->#Dq(}ys(u-`6P z$@=^N<%t53>$Abth~NhZ(Xj7aCydzMoymJcubY!aN6lhFdls>wCjbsB>onmzx^ARB zk!%k?8?BTrl^v1rV`xuDKMjL>i)<l2q%4SpZ{a#VJ0)9`-1ZW+8~Iy$_&^l#>)y!8 zPk~!Qq83?SvmNnuquf2=JEO*UvOwiXd=BaJ8rg_-FW|vOAr>gqzaQaSyG|qvS7Q%9 z6TR`M@^4T00TIeSrE*u<T?=45iTnd8zq2EhPb}N4(Mo~*9f`k~`PrKlpThCJfo)j7 zLkOSax;{_0e9Ff;geO|nN&j7R1E2|1?nm5(-(&`@n&+a;^+joY382@l%SryM`y1g` zBR-4d^AUfOw7%>^d{2_UO#Hc_c(Fi?B42j7jOUwr#DA1VTja6gk$;|37TAvXD~SIw zl>fsgb@`k72E7tqMd(rJ?@l6l?_;IgianuuZ~73%sb}2`_Jroi`@wM1n7xOgd^u`1 z%PA9W5q~vVv$Ihy@pca4TT>3#p!^vrpNZD&Ye>GY63@QCJb7I%5%vX!@14OVG8b)0 zZ7VI3eoy{<>l#nhqL=Lcgnq$2<=X+M&pxcm*oT$(&R6lB4>+H)4=XRP8BiO&F>PUQ zOdfs>d2iap-k3c3821dWv$yd&+mpXR>(OoON6F(qjq>^c<{q>^bt2o#M!)|+w!Ppj z0&A~C5A|#>U0k2-r8;5j%be~(O*)Y#8!)FCP8r@rKn|2&jPfqB_I^WrF4fX^DDUQ! zS?du$jO0B~K2-AGj`*&`^FGQ4N&dx%A4&4zO76%L*j5{Bw>n*Sxs;2cPGhLLt4<y? z@CMIE&KIuhJ^~Q<!AbymSGP0DosG`dQvQ;}PqXSs`FfIn>U=5XuLFobTX9mpf#lyI z&slj>tryBasP6H%L%9T*JyE`w@Dr6BGNt?uD^|*XA^d2kyi!kjU(Z&0(rwRjOuxtJ z#h6|Le5VT2`!J0+crm>m({BTarkLKqzjwj(rpmN66w_OPZ(y2*GW`L+?<D^IA+Qe< zOz!}`U54qsm~JN1ahTo%=k_^){^I%Mbi_MqK94+pj~j@w(Fa}4D$I1ez4o*3W@vQi z-A&Blc7F-|!y4yGmJayT#;S6~H*cahUkd(Pz<k!*J>=b$Gz8zO54AM2zlVRYMNG%^ z&;Axdn)StdnGT&d+zjcFZwva{gWjGZw-2)!{(jWgUf5#+;@|hRA76U`0awcT<A-J; zG=*nNn_$#_@Q1!jl8L04aMuvkV?%@Q+0_%3y*3N~1+(NrJWDRb>t|(W8Pc?nH7d)v zZRxD6m*l^Y`#GhtO|ld`F;<@9C{0bQ?j`gftsJQ{$BR&pe=yQhyPTw|*p)fyfvyXm zp1FAP$<iI)-Z}ng*|N!R?3`?rK34KdNzse5L~da4_=$fVJ-hVPXU06*sO$bYOKLfz z#DbWmj}_cI<;J^i5c!_JghF$P`8dSD?9xDNoL3&%dfi11)$cQK*YIpCHDpoLP@aqA zpQW>Eyi`M$fLlX)D~hQhZdcOVmdc3zQtJIE%dAGW{8!pd{cMI=w=r&Lj{GZaE#{KR zH&*nRG|5;s=_aR8j5TUj$d*v?y;1LvBOu^rXMk!6P#?yZrc!ieEx;eo5VerxzHHQ~ zZTsUF+j`t(n~W#6S22<9s9@aXl=!kGlh=GR>GRni97&v9XTeLaZdki${-Sts>+73p zIoFAz1d;a5eMP_A_u;CCp8Rh6%&k8>_C%y!uZDB2b*Z}JZ6uRjcb>b9zrBz7+nWH( z_}+ANtuK%mLy$KPL<HC)C9dndZ{|3imm8~{ms==qq4RQM`Mey;VGqqMZ|1W!9zKu8 z)<5%E8c!Yr2AwZx!;${ze8K+$6cI@7cma*h*8$u}494I!`2(c3{}Qi|)5tmd!;3We z^?H4Hz4G7n&g)fG4P$kO>Iz>}0a<ULg{%kY3YAKlqoFFb08Nug($y9W_53qwx|>vW zGBa6(1+buGw``Fjx9Upw>rp9GM1?@02@f5Z@%<j1MIGIp)fK`34CLd&fdO`5haK3n zeTf*^*%4k3gb*38xz2jU!6yhGSKpH(YIAXQ6;&Tz-A?M(-O%yF)twIWoMq6-rL#K- zyo;l{fEng>U7;#Bk`zD!6*7D_K!1@2jR69Lcw<*^5Re&#fdPd90dfI^!y^RxBUr41 zYK8U_fV%kw->Ms5B=TMIg<q=ACX}HlnwArOtWSK^C;8eAft+^b8@bhupXK1FBjm;} z4Tnyvtzfw-SO5)>G%!FF9^iT)kAzTFWamVxQ?)AyYOXg3shtwp1z`vLwmh+8@VEV_ zZt^dYCq#%5Av*&~<g_Ei!0_-1s>GJ>-b?L@*gzYzLj((iKrtLeLRA0~hp!X`>VKGB z8BzcM0096100IC2hvROMUk^O>02v4X00000#PAU=00000(A!Rq`XK$)2^t7<00009 z00IC200000cmZQzWME*=`NzY+z-j(V;h!s~6i@^Ousi|)Z4Lz{cmXt(bChM*(}tgO zcI|yS6LW0awi#>O?tE#CZ3aEI?TOK&*tTuk&i&qX*DrrO>pk05_13!AEhP^CAo}rt zJj<qd2rKLWm)lq-`Y$N4uPKg3GBsYt(s&CsT|QN95rd=a=n@a2W%LEBTvMuP|1@#C zxLV|h-r}HGAkG(sB0svBxzP%`Sb5Eru+Hi-%kAc}<O0T9O80!mG2e=XzAMLUnV6^X zG*<aT9E)r6l3hiAe~RYYb1ZzVwVOpDv+bL-PWR_fX7@1E9;1!##cunK>PZv2+9$NP zC#hghFg*H-J+3}2q`1pC-%TQl2Xd7SBu_DJvFePr2^3o`hR6HqZsYWw$JXd6)<rL+ zHoC9U--na(thao&+DwM0&rP8?zD?s($&Xi4UTYiO8`KLKbax-q!aYL`>6P(b`a}<N zyYwVKgH`%oY9p9xs~P2=phU4ZiSA~Hy+(l>&x(*wkt=1J+s8~B#jH@M`9ca^kXK!~ zEdH1wqJP|jSvHB?dgs#UH}=TW9L>*ho4MBQl%G#CF`PnPXvY+HBSVvcoM|l>m9F2t z9JO275FVEI2jt6A2I#I~HisR4Ar+#><>i&CXD7~$&!nQ?OqtfVCDSQR@)#YxzyZIB zS@HJNBYrK5YzD*p1a|ArjnT`grK;&jH;$dI52db1v1e1N8m^6JGC77WZl>lu)8a8~ zgTLR0e>O=EOG~89rCD*pW9}6;Mas<zIquic#OE-@H>ZzHXOep49%*-fjG=xxGu1=W zY(8V{9&U4A(nRr&uwkm@cMR0`c3VejT)+|aR7>}b>i-a})ARjxW`g#rNA<nM&tklK zaC+Ft^|pb<HYoK%7(@sEGwu8U7H5p7b;fQ^gs~d$Ra~Ci{FC%g%2D1PWVm|tZoi!d zns4uaV2Cf{4u2^(CjZBgq?99}W$M>(Gbij*Zr6Rwk^#J6A2U*MWh<XUE>rogr%k9$ z1@%^r&1J9E)!cmL{|1NBV<F!g$m6lLT;pDh3B%YMirDVUQ9H!iH$W)2Fkd>9QI?nb zRO6!XDs{rgIx{)-z3HB$5{JWjwpstwM@c<i^gprRo}sRFpkfmEI0T*ui`nK6usvfR zFC>NPjcQDC?=jlT54(n8_6=3s52XDu^-*$$?#yM`e|P&cSYXW+>jzvXfA@&F@_3Rs z0DsmH4NUL*)40<XvBh%a;XHY>o#XB=>F3;Gm#{lb;bPxk^*^05|D@t+z-{4q<@_Tv z?S7_&AF1s-QN>@tjaI-0>HbiTI(97eYx<53?Dl(9d-?9wzqW<(X_isZ4dP5&$KcSN zA>lpM?P6N{dNi{>@*rkhayPxgI9ex9aZlLFdi#OvtOAq$L2CNS^p=+^<0E9+Igrs1 z{?qulC<oC<P`!y;=zBNtf<WV5w2Xys$Bxj1*={FIqGEDHw<w#2(qVBPx$)KXi7%$1 z`lPol;Ieo<tKBa4`<m?MQ`#oaG9u2VSY*5Pbc;Wxvm33ttR^eeS5GYAc*bbTlIgSv zl~m)gT<T|2+kH-Jt1Rz&Qs`@`ejhT$9cM&_YHQz9<j-PVs7`Kpn|a}3riDU^Y?b!* z;%52N-Bz;CM$;o>5>w+Ob-iNCPyg1Jr?1sxs+FUCoNyo>!sO^PrrSe0GlUj4g6?65 z5O%M07Wn`f%@~@|mXYpHI@nY)qZd-kqO~k{J6PvtQ|cCo>6F+>l(@;MRmyRs)=HyC z*<hDa-ny{arfGd1o89N)ZH;ednn|NK)mKl^*@kL<H=F%0T6<p{;%e)GRI%r<QN9kc znl!d+<#BH+sD7=iBaN&!=UNR0#~*Q}m?MUW{-U!e7FnX3xKIpsS<H_2a;vqci`~Fj z--i>v3ir5g+2I>VUu8%7tsq|;Q_0<?81!B`9;sVHe|uQ5zE5YLsk!gPXUy}LQp=QM z(vG@GU*$1Ov1*_7)OQALLPhFYTQ0EA({nrR7LCuLhCfx~A@mOA*&MRcd(E%ZTx&6j z%rHPYhKsBUr-v(bCQoN?VyCalnf|!mzF7G$qEYCe_jQlh>{oNL;vJoSPjQ=aardep zRd3rw1Kqd9nviAF$&`2F)E~obisojMX|?n{j$%JjIqeeDxW|`Ck1)@@!cOg7n6Ala zPPeDiJ$<F<EQ&>z&>R<v!B!;inlUKcq8PU7o!^-qeUMrjy(08~7X5!G<^XF~6Gh>3 z`J=XN+YQS&jq9LpV<)w3+jfK6wxWi$ZBF-h-(Bg+G>=Jk*1MXSGqY#yZ@=^I8%ln_ zKk!VVXHbQ(c>);1>Ucr8B(s23;FM6nDFrMpMyt4A7B9spe!wT;fKOnMOam@qe?no; zaL=A$mFX>ulj0FSV3BaZA_ULC*uL^y%$J$MXO=6&cwW|#ox*UOYi0`H!C1CmXYDzb znVv9RX!_RltnFv5$R+o~^i*<ka4WVlSO5#c7VscUW_N10F~w@w&~zYb-nTWSn}V&J z1N-A^yuZ7_d9Y8u!jmvvTKlAR9E=I)Wvk>6EEv{<K`G9gbI7T}uy7<f!nuiM;YnZN zIyjDJNHN@KcbmY!@Wadk|G*zZVgBfznn!Lly<>4f-slIu7!G{VA3GfKVn6WZKOv8H zYb{n-T(Py}vse}K>^b<hg7p#pI`MD?{;H6#E3|$;@Oz#~ey>Q~m$z<BvVhweo#2ip zMg~Emp=*}t7UYi(aO>35a1S^i^)ckE-@lL>oGZNwzQNz{E6fU?z^d>l98PY+`t%p{ z7B<%nKI459R%K2&nOtN}#^laWZ<rq*)%y4z--lIM7wcqQFg0uA-m^Z|hCgtpVMXRs z&qQ9b7CwVn$$xq#e2KmZX5~A|WnY!s^qcgdvE{)M?l;`Sn&`LWPg<+i0q?`;Y3}^* z->yNA|5^nj;BS~&zQr8$0_+ET4pZ~D?|-^O@-Nts9){5GG&bvC4N`fBSXc_%!{6*X z&*>{Y0o+b60I##x>?ge_{R6!3uhY}=dYxy@-p@Ol7Ru~%+so5dkCvDou(O}x`>ChJ zGyPmWWH##iq<YTmRJrD>vFk8`J3_v44>(hDpZ-c`qO+26f5>^|hI$NYTKtjwN!WMl z*>{3OWA{EDbsv>4nu8ptpVL_@S2ZU-V7^&~p5U+lvy2P+TW>mD^;ESjbgr{A&d0U1 z`<O3O-^NGxxMLanXXEYs^#VWOPE+H_J*jH6>a8?gZ)fR_YHoakandz&qF)pF-wggG zl@F+nC3gQBm#Q7r-PA;Bw<=oFZHw=7KjM8|d+W7oiS4Nyc(Hh%x&X(E;qi5R8(yb| z@i)JLBk_NJ!~3c!aIwbbJE`$47?U{|7q(_>Y8m4*HoVK{yvH1HFu!9wSlz#4c28#f z2BEd*mH+?%cmX`Y1GF0m006M|*S2ljwync#+qP}nwr$(CZR>Ff005}-_f)`kpbNOE z%3F1+>H&xd@`KugrhwLgj)0zkeuFFE{@@FcJY+oNBeWiLG>i=E4I2)d3_AjQ4QIhS zBSeV$h|@?uvL$j2@-Zrh8jV_px{2nZgXl5n6BsF`E#?ANhn<N%jDzAVxZ$`9crf0D zuZ{17pN8L$zlHx!=t{UsR1=31Uy_2P-DD`)OCCx-MSe=DPFX_vMy*RdKm*ZQ()Q4y zbSr&0{Q`r=$TCJU7BKEHCCpmPtt<&^DC;>J$zILA#~H-=$whFb+>6}jJPoe}ZwFt^ zPw;2*kMds%)PjEna|9~{hXi*7--NY=$3<|_0MQk(SNu!TL9$=!k<OL@Wo%g!**e*4 zc~m}Mp-`Ms0+fxFXH<UGBGq?wHT4MfTMb7O)Fd@+G@~`gHQ%%@Z7c0s?J4bZ?FXG& zS6|mpH(U2W_d-w92lPkvpA1Pu7sCdl+}Pjv($vUw-HbI4H2<{ZEmN%wYs@;!hPTzX z?Xa`#9qe1|KO9XRN1R6I3K!JX-F4etai8?WJkvdwy;|=O?`K~--*Vq4ztg|g|16*l zG!JYDqJyo2+e3!X_AoU(JOYWRB7GwtqAj8eqn~5m*r3??I54h>Z;QW4m=bLg8<OZ` ztK`;{Hnky*PY+H1%(Tng&nB`1v(Iw5+}6A|f22Sz)GwSWdW!2x!qTd;t$e!jhc0*k zZ)6Ps0C=`-+qP}9sqICr*tTtRmCgTb+qP}vvu*~u{>u&Y26^MJn@u-gyrsN-?)Gy< zH;WQQ|1h>OE-*L@6C+W~EdHeAdP%%=QR#)!uF@yV7MC&0-Ywr%ZYqDjVsC||;+INO z)#|G5Do{P4y0qF|GrdMo^KR|&+F0F`y8gO%>i5;3tuLw%HH>M{G!AV<8((kQ+Z1h{ z)~sw9(^B0+wT^8qX?+zMcE{tOY0v^_HFN-CK%I~tN<#p86#5<B1zX^|;K$(C;BS$K zk@t~*&?)E&6h{AS^R#bj-`BCaL)$r}lkQsD<?i~eyRm0@Pkqnty|;Sl-WPkn?i<y& zq)**P^nKkwtbcd^a|6=`%mc3td^zwBa~Jb0vx8}3`dH&w^{hYHBF;EYij(5?@ZRB% z<Ma7R{)2)Qf(}7OxJ1|`yhk)jbWBt$3W#Tlo5VTsFOu~VrQ}J;C(=36aw%W>l5B#k zTo#oNkypr{l>e;Qrl?X-%E8Lb%6er^`L1fS%BA{PeOet>zofaMp)^lxXK5eRZPS@` z@9S6U>-AB?5`)4x)VSVQX?(*p-c)3go1QW6Hyh1=SZ-OKupY2JVw-KdWlPyd*xB|! z96KFC$1~39&Pz_6^Lf`i7vdUlJ?=i>zTY#?Q|kG|d&V2_jrJLQ9^X&?!+y2@`M`mI zD>x|F9U2-^hL?p6;a?+XBjHFoIy~AOeKxi^7LAXHBk}tZOA?YqE;%Z>Eh$SrpZqxa zdum*2QEE%-bgCqEck07*Rr-m{;>_yI=FINQvCO&5|MJ<DSylF@+|HaoSI9k|`wSa| z&B8We`><138P<s@umA?I7qHLqA^2>36Mhme#XE2X?#B!G^Z4h)U}6@rkvKt=5FLbq zun++P5HAp)lS9a9<Z^N!d6BFo2S_~`Bkw0)C%>acQ46V^)CH=B>Zg>Ho66=F=I_Zr zm;WIDJ3WbBLT{r_&^PG@x`UR}4mw5ON54vcUSJeHEc^k+gJob3I0s4r47flE+<*j+ zfqw~t2LLcu005w$vu)e9ZQHhO+qP|c3+KAJG~2d~_wJng3=)9spd_dbnt_gB1egLA zfbHNMAm9Rc4t~PeFgeTv%fLFY4IB)o!i8`xJOW*K9lnIWQDT%8l|Z#oTht$oM$^$c zv>&<XI(mm=;bb@y&WB6kI=C(FiHG8ecrM<84`2`9z^|;otRz-8tE5%OYHtm)F4$G< z*7hKKroG-iWC!*w`=b-j$?BAL8aZ8@(as|0xO2^U=zMl#yBXc$Zaue~JIEd9E_L^~ z*uCt&^#1kIctyP0UMFveH{09fo${pj$ouIh_w)Hx{AND(jsMjD9>fna1jT~tLAyW% z4}$L`KFLV(k}9M%8APU#`D80OLws_BJRv`6e433GqBUu2+LunCi|9JKpCWpZ-lgy8 zuP|AdDJ&V*4%>!9!x`a|@Hb1&^0BI{4I9M9vYBit+sO8^lgwea*dz9eePX|O44#0e z;2C%hUVxY26?hHafcM}N_;S9FJNznt&%a0iMscI0QQD|LR4Hl_b&Ezs3!?2JsYok| zin5}rXe0WGVPc$^CgzE)Vy`$V&I(5`ab8>(_r-JZUj8rR%jB|`93)4{xpIr#Bag^X z8u?WIRw-0|RZX>3L)BchMV(fbqUxf0tX}IFI=#-Vi|cy2s~)2l>(zR*KCQLBsh{eP z=5G_<q&AsNZd2IQG967%Guq5GTg?drjc;z6*MACv2SCSR005w8+qP}nwr$(CZQHhO zyKS7mF6_>>-gDwQNu4}S6{n5U-<jyFaP~Xb9qhbz{<(48q;6ifyxYj_;tq4CyQ|zi z?iKgBtK6?%3a^M)!K>pn@j7^Yyb<0MZ<)8lyWqX>UV<1P11JF+fF58nSO*S*E8sa$ z;5SSK^TG<SH5>*f!Fg~4JOpn-0zaYzC<iK!nxp<`I$DQLq9@2lAJJc&0H?t@aCzJi z_rw$NN_-IC#1wxb2}vGOowOrE$sDqooFWg2AU|kqnw(~)`DsPknD(L*=?c1^UZaq{ zWwBXumYL;erCD9po(*Gjcuby==jA1NRo;-d<vsaOK9SGmEBRJ_ke}r@`BP50<)8Sk zs2)-GL-9g&Lr49Tei6UE-`el)5BA6Vv;E~h3l|K}4V&=W@IR42q!1ZI4pBgq5EVot z(M60Fi^MK*Nx0&*j3qP4QnHckB`3*M@{l|yZ^>tp$v}Qq(NrRpP8C(vRb$m&^;W~x zWHn!{R@>D%^;A)1)hG2&C)8<m5nW3+)17obJxWj0i}X6ZOCQsh^gZorU%%F$^=}i) zBr>T?CX>q)GNnu<Q_D0mtxR7t-Yhhm&2DqpTr>Af$b2z>Y;2p@rnZG_DO<_bvW;vj z+sXE_gY4&^eQ-6n8#sXuz6O6I2_k7CIU+?O75)S1t3;Rp009611mXaX02TmQ00jU6 z0000001f~E0ssPX00sa7cmZ{ggKn)s6h_yz&3J<ATido7l*hKx7=4;Xjgvk>U#j>r znfy7-Xl?J=z&oyZ#Dm8#fMam{fbWtl^N_cc9Y3nlKd#~@{O8>9Q|T`qKVy<>$1iyO z;JM>he17oRvb6ks@Z0el4j-&Le#`EI3&-yjd+YcEFCV^Sh74KG$P*(%lp=<1I_c6f zERfNPkR&8&i8KM)MN=fT4BK8*!Ac>$A@Y=U2WgikgI}kpV_5aP<tZwW#7CZe8&i-q zL)zAFr_=S&r!(U9)LWgAw(5-4m84Za_%M?5dV_>W*;)yVJi>K<Yp<5-ECF$f8CA*K zyhYtU+o!E*d)NPM@9KvDAyL6jz)%tg#d+IHRHW&V#YX@u)y4eBw3vr}sg-4z4y}q^ z?f9y4waY(GMAl?=PMr=_Sz?Ac*4feB=5kg~&70*tFUDtxcmZQzW&nf#Sqv!*SO5Sj z9|6$-cmdnMqrHJan_&|pH<LEwCLTs0xt+(#KvPbLfkT^NJ7aF7tC1{_xt*ylJ-`CY zVlGSYHUqO*np6C&z${jGD~OiuY!l04tdv14cDP=SKqnJbaS)5sQeQ<%0L0>gtK){5 z$FPZ)mmTOF1=re4371V91R0Ar1qd>hY-#`z1%iyFoA_mcV)?R+r2wn|E0+KO6ge&| diff --git a/public/fonts/roboto-d561d8824866e60a2a2d327c6b6219939b259b57.woff b/public/fonts/roboto-d561d8824866e60a2a2d327c6b6219939b259b57.woff deleted file mode 100644 index b24493e50ee4292059f99ddfb9ddf4688af1becf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82804 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­ZzvY&aa*{J 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 diff --git a/public/fonts/roboto-d9a17a54541b34b38ef67cf919f1ac63b44a7454.ttf b/public/fonts/roboto-d9a17a54541b34b38ef67cf919f1ac63b44a7454.ttf deleted file mode 100644 index cc5227cd2cad63e84b2d36588c975215b62a6851..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106660 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 Dj5ZVI -- GitLab From 60038a8086fccd6e52c95e36b4c706f07dcbb20a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 01:30:30 -0200 Subject: [PATCH 0624/1338] removed dependency on "Roboto" font-family --- build-old.sh | 1 - packages/rocketchat-theme/package.js | 1 - packages/rocketchat-theme/server/server.coffee | 1 - 3 files changed, 3 deletions(-) diff --git a/build-old.sh b/build-old.sh index 0017dc40e43..f60192ddad7 100755 --- a/build-old.sh +++ b/build-old.sh @@ -1,5 +1,4 @@ #!/bin/bash -source ./build-info.sh export METEOR_SETTINGS=$(cat settings.json) meteor add rocketchat:livechat rocketchat:hubot meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 7a2d5830675..0cfa009d7ce 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -25,7 +25,6 @@ Package.onUse(function(api) { api.addAssets('assets/stylesheets/global/_variables.less', 'server'); api.addAssets('assets/stylesheets/utils/_colors.import.less', 'server'); api.addAssets('assets/stylesheets/utils/_emojione.import.less', 'server'); - api.addAssets('assets/stylesheets/utils/_fonts.import.less', 'server'); api.addAssets('assets/stylesheets/utils/_keyframes.import.less', 'server'); api.addAssets('assets/stylesheets/utils/_lesshat.import.less', 'server'); api.addAssets('assets/stylesheets/utils/_preloader.import.less', 'server'); diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 8958ab46563..71f76a317fb 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -35,7 +35,6 @@ RocketChat.theme = new class files: [ 'assets/stylesheets/global/_variables.less' 'assets/stylesheets/utils/_emojione.import.less' - 'assets/stylesheets/utils/_fonts.import.less' 'assets/stylesheets/utils/_keyframes.import.less' 'assets/stylesheets/utils/_lesshat.import.less' 'assets/stylesheets/utils/_preloader.import.less' -- GitLab From cb5c404f2657175e7d6fc8e50c8df9ffa1d44ca0 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 02:31:50 -0200 Subject: [PATCH 0625/1338] removing demo build tasks from travis --- .gitignore | 1 - .travis.yml | 15 +++------------ .travis/namedemo.sh | 5 ----- .travis/package.json | 15 --------------- example-pm2.json | 4 ---- build.sh => install.sh | 0 .../plugin/compile-version.coffee | 6 ++++++ public/buildinfo/buildinfo.txt | 3 --- 8 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 .travis/namedemo.sh delete mode 100644 .travis/package.json rename build.sh => install.sh (100%) delete mode 100644 public/buildinfo/buildinfo.txt diff --git a/.gitignore b/.gitignore index a342721459c..2ae4ddd56cc 100644 --- a/.gitignore +++ b/.gitignore @@ -46,7 +46,6 @@ .Trashes .wtpmodules \#*\# -BuildInfo.js Desktop.ini ehthumbs.db example.css diff --git a/.travis.yml b/.travis.yml index 71f682a1f79..19ee383ae76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,18 +42,9 @@ before_install: - cp -r . /opt/app script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi -- cd .travis -- npm install -- npm start -- cd .. - meteor build ../build - cd .travis - sh ./namefiles.sh -- cd .. -- meteor add rocketchat:livechat rocketchat:hubot -- meteor build --server demo.rocket.chat ../build -- cd .travis -- sh ./namedemo.sh - cd /tmp - spk init -p3000 -- nothing - export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) @@ -69,9 +60,6 @@ script: - spk pack $TRAVIS_BUILD_DIR/rocket.chat.latest.spk - cd $TRAVIS_BUILD_DIR - mv rocket.chat.latest.spk ../build -after_deploy: -- cd .travis -- sh ./builddocker.sh deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" @@ -83,3 +71,6 @@ deploy: branch: - develop - master +after_deploy: +- cd .travis +- sh ./builddocker.sh diff --git a/.travis/namedemo.sh b/.travis/namedemo.sh deleted file mode 100644 index 2c32f690d7f..00000000000 --- a/.travis/namedemo.sh +++ /dev/null @@ -1,5 +0,0 @@ -cd ../../build -FILENAME=demo.rocket.chat-`cat version.txt`.tgz -mv Rocket.Chat.tar.gz "$FILENAME" -ln -s "$FILENAME" demo.rocket.chat-v.latest.tgz - diff --git a/.travis/package.json b/.travis/package.json deleted file mode 100644 index 7abc9ca86ae..00000000000 --- a/.travis/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "setbuildinfo", - "version": "1.0.0", - "description": "Set the buildinfo.txt resource", - "main": "setbuildinfo.js", - "scripts": { - "start": "node setbuildinfo.js" - }, - "author": "", - "license": "ISC", - "dependencies": { - "line-by-line": "^0.1.4", - "mkdirp": "^0.5.1" - } -} diff --git a/example-pm2.json b/example-pm2.json index d1a4c2058d5..7e0d731a1bd 100644 --- a/example-pm2.json +++ b/example-pm2.json @@ -8,7 +8,6 @@ "error_file": "/var/log/rocket.chat/err.log", "port": "8080", "env": { - "CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net", "MONGO_URL": "mongodb://localhost:27017/rocketchat", "MONGO_OPLOG_URL": "mongodb://localhost:27017/local", "ROOT_URL": "https://demo.rocket.chat", @@ -24,7 +23,6 @@ "error_file": "/var/log/rocket.chat/err.log", "port": "8081", "env": { - "CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net", "MONGO_URL": "mongodb://localhost:27017/rocketchat", "MONGO_OPLOG_URL": "mongodb://localhost:27017/local", "ROOT_URL": "https://demo.rocket.chat", @@ -40,7 +38,6 @@ "error_file": "/var/log/rocket.chat/err.log", "port": "8082", "env": { - "CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net", "MONGO_URL": "mongodb://localhost:27017/rocketchat", "MONGO_OPLOG_URL": "mongodb://localhost:27017/local", "ROOT_URL": "https://demo.rocket.chat", @@ -56,7 +53,6 @@ "error_file": "/var/log/rocket.chat/err.log", "port": "8083", "env": { - "CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net", "MONGO_URL": "mongodb://localhost:27017/rocketchat", "MONGO_OPLOG_URL": "mongodb://localhost:27017/local", "ROOT_URL": "https://demo.rocket.chat", diff --git a/build.sh b/install.sh similarity index 100% rename from build.sh rename to install.sh diff --git a/packages/rocketchat-version/plugin/compile-version.coffee b/packages/rocketchat-version/plugin/compile-version.coffee index 02b38e3de0c..54e72fc2339 100644 --- a/packages/rocketchat-version/plugin/compile-version.coffee +++ b/packages/rocketchat-version/plugin/compile-version.coffee @@ -20,6 +20,12 @@ class VersionCompiler freeMemmory: os.freemem() cpus: os.cpus().length + if process.env.TRAVIS_BUILD_NUMBER + output.travis = + buildNumber: process.env.TRAVIS_BUILD_NUMBER + branch: process.env.TRAVIS_BRANCH + tag: process.env.TRAVIS_TAG + exec "git log --pretty=format:'%H%n%ad%n%an%n%s' -n 1", (err, result) -> if not err? result = result.split('\n') diff --git a/public/buildinfo/buildinfo.txt b/public/buildinfo/buildinfo.txt deleted file mode 100644 index 23bd41cc4c8..00000000000 --- a/public/buildinfo/buildinfo.txt +++ /dev/null @@ -1,3 +0,0 @@ -v0.7.dev -This is an unsupported non-production development release. - -- GitLab From f2ae31d34c2070178788691de538dd47bc1a5ca2 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 02:33:47 -0200 Subject: [PATCH 0626/1338] removing demo build tasks from travis --- .travis/setbuildinfo.js | 45 ---------------------------------------- build-old.sh => build.sh | 0 2 files changed, 45 deletions(-) delete mode 100644 .travis/setbuildinfo.js rename build-old.sh => build.sh (100%) diff --git a/.travis/setbuildinfo.js b/.travis/setbuildinfo.js deleted file mode 100644 index 4b05518c724..00000000000 --- a/.travis/setbuildinfo.js +++ /dev/null @@ -1,45 +0,0 @@ -var BUILD_INFO_PATH = '../public/buildinfo/buildinfo.txt'; -var PACKAGES_PATH = '../.meteor/versions'; -var BUILD_PATH = '../../build'; -var LineByLineReader = require('line-by-line'); -var mkdirp = require('mkdirp'); -var fs = require('fs'); -var lr = new LineByLineReader(BUILD_INFO_PATH); - -var firstline = ""; - - -if (process.env.TRAVIS_BUILD_NUMBER) { - var transformVersion = function (firstline) { - var versions = firstline.split("."); - var verstring = versions[0] + '.' + versions[1] + '.' + process.env.TRAVIS_BRANCH + '.' + process.env.TRAVIS_BUILD_NUMBER + '\n'; - if (process.env.TRAVIS_TAG) { - verstring = TRAVIS_TAG + '\n'; - - } - - return verstring; - }; - - - - lr.on('error', function (err) { - // 'err' contains error object - }); - - lr.on('line', function (line) { - if (firstline == "") { - firstline = line; - } - }); - - lr.on('end', function () { - var packages = fs.readFileSync(PACKAGES_PATH); - var verinfo = transformVersion(firstline); - var content = verinfo + packages; - mkdirp.sync(BUILD_PATH); - fs.writeFileSync(BUILD_PATH + "/version.txt", verinfo); - fs.writeFileSync(BUILD_INFO_PATH, content); - console.log('Version is ' + verinfo); - }); -} diff --git a/build-old.sh b/build.sh similarity index 100% rename from build-old.sh rename to build.sh -- GitLab From 2ff2e356feefb7dcd8b85732ae2421fca105642b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 03:12:37 -0200 Subject: [PATCH 0627/1338] added font-weight: 300; --- packages/rocketchat-theme/assets/stylesheets/base.less | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 7cd7c5427d4..72c726e9fb7 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -395,6 +395,7 @@ html { body { font-family: "Roboto", "HelveticaNeue", sans-serif; + font-weight: 300; font-size: 14px; height: 100%; width: 100%; -- GitLab From fa376c2b3270e3c48a18c40577de4fbda6afdca9 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 03:57:19 -0200 Subject: [PATCH 0628/1338] no message --- .travis/namefiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 7122c54414f..920028d1f3b 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,5 +1,5 @@ cd ../../build -FILENAME=rocket.chat-`cat version.txt`.tgz +FILENAME=rocket.chat-"$TRAVIS_TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz mv Rocket.Chat.tar.gz "$FILENAME" ln -s "$FILENAME" "$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" -- GitLab From 196ed94c80a1e6ed308e50189caed83474ed1eea Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 04:22:19 -0200 Subject: [PATCH 0629/1338] removed dependency on "Roboto" font-family --- packages/rocketchat-theme/assets/stylesheets/base.less | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 72c726e9fb7..29c1c47330d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -394,9 +394,9 @@ html { } body { - font-family: "Roboto", "HelveticaNeue", sans-serif; + font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; font-weight: 300; - font-size: 14px; + font-size: 0.875rem; height: 100%; width: 100%; -webkit-font-smoothing: antialiased; @@ -2314,7 +2314,6 @@ a.github-fork { } .message { - font-size: 14px; padding: 18px 20px 4px 70px; position: relative; line-height: 20px; -- GitLab From 9e16f994bcf5184dab53ba09416252718853c2ea Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 04:56:35 -0200 Subject: [PATCH 0630/1338] minor typo fixes --- .travis/namefiles.sh | 2 +- packages/rocketchat-theme/assets/stylesheets/base.less | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 920028d1f3b..03a03745e9b 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,5 +1,5 @@ cd ../../build -FILENAME=rocket.chat-"$TRAVIS_TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz +FILENAME=rocket.chat-`git describe --abbrev=0 --tags`."$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz mv Rocket.Chat.tar.gz "$FILENAME" ln -s "$FILENAME" "$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 29c1c47330d..0fce46b4c8f 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -395,7 +395,6 @@ html { body { font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; - font-weight: 300; font-size: 0.875rem; height: 100%; width: 100%; -- GitLab From ab3e95bec319ed962def6ab5bf377e6628fc9e7b Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 1 Dec 2015 02:40:11 -0500 Subject: [PATCH 0631/1338] comment off velocity crud for now attempt to speed up build --- .travis.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 19ee383ae76..fc781b524d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,24 +6,24 @@ branches: - master node_js: - '0.12' -addons: - apt: - sources: - - google-chrome - packages: - - google-chrome-stable +#addons: +# apt: +# sources: +# - google-chrome +# packages: +# - google-chrome-stable before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' - mkdir -p node_modules -- npm install phantomjs -- npm install velocity-cli -- export PHANTOMJS_BIN=./node_modules/phantomjs/bin/phantomjs -- export JASMINE_BROWSER=PhantomJS -- export DEBUG=1 -- export JASMINE_DEBUG=1 -- export VELOCITY_DEBUG=1 -- export VELOCITY_DEBUG_MIRROR=1 +#- npm install phantomjs +#- npm install velocity-cli +#- export PHANTOMJS_BIN=./node_modules/phantomjs/bin/phantomjs +#- export JASMINE_BROWSER=PhantomJS +#- export DEBUG=1 +#- export JASMINE_DEBUG=1 +#- export VELOCITY_DEBUG=1 +#- export VELOCITY_DEBUG_MIRROR=1 - export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") - cd /tmp - curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - -- GitLab From 3cd01a7aae1ff1eb3a5347b8786a789926d67911 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 06:57:40 -0200 Subject: [PATCH 0632/1338] minor typo fixes --- .travis.yml | 1 + .travis/namefiles.sh | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 19ee383ae76..ce0a128b569 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,7 @@ before_install: - cp -r . /opt/app script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi +- export TAG=$(git describe --abbrev=0 --tags) - meteor build ../build - cd .travis - sh ./namefiles.sh diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 03a03745e9b..517ec9d3ef3 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,5 +1,4 @@ cd ../../build -FILENAME=rocket.chat-`git describe --abbrev=0 --tags`."$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz -mv Rocket.Chat.tar.gz "$FILENAME" +FILENAME=rocket.chat-"$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz +smv Rocket.Chat.tar.gz "$FILENAME" ln -s "$FILENAME" "$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" - -- GitLab From dbefac03c765c694cc00066829698b3334221639 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 08:16:20 -0200 Subject: [PATCH 0633/1338] fix typo --- .travis/namefiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 517ec9d3ef3..4b0f3b12ee0 100644 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,4 +1,4 @@ cd ../../build FILENAME=rocket.chat-"$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz -smv Rocket.Chat.tar.gz "$FILENAME" +mv Rocket.Chat.tar.gz "$FILENAME" ln -s "$FILENAME" "$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" -- GitLab From 9b4f872d61495d1e2774c7061ccaa2e4ca6aae86 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 1 Dec 2015 08:44:26 -0200 Subject: [PATCH 0634/1338] better label --- packages/rocketchat-authorization/client/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 133b0380927..302da0a6431 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -2,6 +2,6 @@ RocketChat.authz.subscription = Meteor.subscribe 'permissions' RocketChat.AdminBox.addOption href: 'rocket-permissions' - i18nLabel: 'Rocket_Permissions' + i18nLabel: 'Permissions' permissionGranted: -> return RocketChat.authz.hasAllPermission('access-rocket-permissions') -- GitLab From 66c0768c593484b6af2e0cb8c8e861053a10e252 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 1 Dec 2015 15:08:57 -0200 Subject: [PATCH 0635/1338] permissions renaming --- packages/rocketchat-authorization/client/startup.coffee | 2 +- .../rocketchat-authorization/client/views/permissions.coffee | 2 +- .../client/views/permissionsRole.coffee | 4 +--- .../server/methods/addPermissionToRole.coffee | 2 +- .../server/methods/addUserToRole.coffee | 2 +- .../rocketchat-authorization/server/methods/deleteRole.coffee | 2 +- .../server/methods/removeRoleFromPermission.coffee | 2 +- .../server/methods/removeUserFromRole.coffee | 2 +- .../rocketchat-authorization/server/methods/saveRole.coffee | 2 +- .../rocketchat-authorization/server/publications/roles.coffee | 2 +- .../server/publications/usersInRole.coffee | 2 +- packages/rocketchat-authorization/server/startup.coffee | 2 +- 12 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 302da0a6431..1f05f78acbf 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -4,4 +4,4 @@ RocketChat.AdminBox.addOption href: 'rocket-permissions' i18nLabel: 'Permissions' permissionGranted: -> - return RocketChat.authz.hasAllPermission('access-rocket-permissions') + return RocketChat.authz.hasAllPermission('access-permissions') diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee index f8420e316e9..45ff2454ebb 100644 --- a/packages/rocketchat-authorization/client/views/permissions.coffee +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -11,7 +11,7 @@ Template.permissions.helpers return 'checked' if roles.indexOf(@name) isnt -1 hasPermission: -> - return RocketChat.authz.hasAllPermission 'access-rocket-permissions' + return RocketChat.authz.hasAllPermission 'access-permissions' Template.permissions.events 'click .role-permission': (e, instance) -> diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 590b2cf58f3..7dddbf14301 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -1,5 +1,3 @@ -window.rolee = Roles - Template.permissionsRole.helpers role: -> return Meteor.roles.findOne({ name: FlowRouter.getParam('name') }) or {} @@ -15,7 +13,7 @@ Template.permissionsRole.helpers return @emails[0].address hasPermission: -> - return RocketChat.authz.hasAllPermission 'access-rocket-permissions' + return RocketChat.authz.hasAllPermission 'access-permissions' Template.permissionsRole.events diff --git a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee index 693a1b3e420..a6d52621a7d 100644 --- a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee @@ -1,6 +1,6 @@ Meteor.methods 'authorization:addPermissionToRole': (permission, role) -> - if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + 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 diff --git a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee index 442f8f4ea9b..781aaad04ad 100644 --- a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee @@ -1,6 +1,6 @@ Meteor.methods 'authorization:addUserToRole': (roleName, username) -> - if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + 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); diff --git a/packages/rocketchat-authorization/server/methods/deleteRole.coffee b/packages/rocketchat-authorization/server/methods/deleteRole.coffee index 0b991acd41d..83f0d290094 100644 --- a/packages/rocketchat-authorization/server/methods/deleteRole.coffee +++ b/packages/rocketchat-authorization/server/methods/deleteRole.coffee @@ -1,6 +1,6 @@ Meteor.methods 'authorization:deleteRole': (_id) -> - if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + 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 diff --git a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee index 8acad5b971a..9efde6b9d17 100644 --- a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee +++ b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee @@ -1,6 +1,6 @@ Meteor.methods 'authorization:removeRoleFromPermission': (permission, role) -> - if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + 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 diff --git a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee index bcb603d6dd9..26d47a63b1a 100644 --- a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee +++ b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee @@ -1,6 +1,6 @@ Meteor.methods 'authorization:removeUserFromRole': (roleName, username) -> - if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + 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); diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee index 0b6ae516bc9..8df33ff81a5 100644 --- a/packages/rocketchat-authorization/server/methods/saveRole.coffee +++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee @@ -1,6 +1,6 @@ Meteor.methods 'authorization:saveRole': (_id, roleData) -> - if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-rocket-permissions' + 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 diff --git a/packages/rocketchat-authorization/server/publications/roles.coffee b/packages/rocketchat-authorization/server/publications/roles.coffee index 6a2c35852d4..6357a62510e 100644 --- a/packages/rocketchat-authorization/server/publications/roles.coffee +++ b/packages/rocketchat-authorization/server/publications/roles.coffee @@ -2,7 +2,7 @@ Meteor.publish 'roles', -> unless @userId return @ready() - if not RocketChat.authz.hasPermission @userId, 'access-rocket-permissions' + if not RocketChat.authz.hasPermission @userId, 'access-permissions' throw new Meteor.Error "not-authorized" return RocketChat.authz.getRoles() diff --git a/packages/rocketchat-authorization/server/publications/usersInRole.coffee b/packages/rocketchat-authorization/server/publications/usersInRole.coffee index 64ff46b0c11..90d7b841779 100644 --- a/packages/rocketchat-authorization/server/publications/usersInRole.coffee +++ b/packages/rocketchat-authorization/server/publications/usersInRole.coffee @@ -2,7 +2,7 @@ Meteor.publish 'usersInRole', (roleName, page = 1) -> unless @userId return @ready() - if not RocketChat.authz.hasPermission @userId, 'access-rocket-permissions' + if not RocketChat.authz.hasPermission @userId, 'access-permissions' throw new Meteor.Error "not-authorized" itemsPerPage = 20 diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 149b63b2f1b..a938b289c01 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -87,7 +87,7 @@ Meteor.startup -> { _id: 'view-d-room', roles : ['admin', 'site-moderator', 'user']} - { _id: 'access-rocket-permissions', + { _id: 'access-permissions', roles : ['admin']} ] -- GitLab From 640805a38f733174a80de643467e937e4dc6f4de Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 1 Dec 2015 15:36:11 -0200 Subject: [PATCH 0636/1338] route renaming --- packages/rocketchat-authorization/client/route.coffee | 6 +++--- packages/rocketchat-authorization/client/startup.coffee | 2 +- .../rocketchat-authorization/client/views/permissions.html | 4 ++-- .../client/views/permissionsRole.coffee | 4 ++-- .../client/views/permissionsRole.html | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-authorization/client/route.coffee b/packages/rocketchat-authorization/client/route.coffee index bdc42a4d818..fe115fedcff 100644 --- a/packages/rocketchat-authorization/client/route.coffee +++ b/packages/rocketchat-authorization/client/route.coffee @@ -1,5 +1,5 @@ FlowRouter.route '/admin/permissions', - name: 'rocket-permissions' + name: 'admin-permissions' action: (params) -> BlazeLayout.render 'main', center: 'pageContainer' @@ -7,7 +7,7 @@ FlowRouter.route '/admin/permissions', pageTemplate: 'permissions' FlowRouter.route '/admin/permissions/:name?/edit', - name: 'rocket-permissions-edit' + name: 'admin-permissions-edit' action: (params) -> BlazeLayout.render 'main', center: 'pageContainer' @@ -15,7 +15,7 @@ FlowRouter.route '/admin/permissions/:name?/edit', pageTemplate: 'permissionsRole' FlowRouter.route '/admin/permissions/new', - name: 'rocket-permissions-new' + name: 'admin-permissions-new' action: (params) -> BlazeLayout.render 'main', center: 'pageContainer' diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 1f05f78acbf..144f7ea88f9 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -1,7 +1,7 @@ RocketChat.authz.subscription = Meteor.subscribe 'permissions' RocketChat.AdminBox.addOption - href: 'rocket-permissions' + href: 'admin-permissions' i18nLabel: 'Permissions' permissionGranted: -> return RocketChat.authz.hasAllPermission('access-permissions') diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index ad9bc027f65..29a6b7e6946 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -2,13 +2,13 @@ {{#if hasPermission}} <h1>{{_ "Permissions"}}</h1> - <a href="{{pathFor "rocket-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> + <a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> <table border="1"> <tr> <td> </td> {{#each role}} - <td title="{{description}}"><a href="{{pathFor "rocket-permissions-edit" name=name}}">{{name}}</a></td> + <td title="{{description}}"><a href="{{pathFor "admin-permissions-edit" name=name}}">{{name}}</a></td> {{/each}} </tr> {{#each permission}} diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 7dddbf14301..18814d2a1a0 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -63,7 +63,7 @@ Template.permissionsRole.events toastr.success t('Saved') if not @_id? - FlowRouter.go 'rocket-permissions-edit', { name: roleData.name } + FlowRouter.go 'admin-permissions-edit', { name: roleData.name } 'submit #form-users': (e, instance) -> @@ -96,7 +96,7 @@ Template.permissionsRole.events toastr.success t('Role_removed') - FlowRouter.go 'rocket-permissions' + FlowRouter.go 'admin-permissions' Template.permissionsRole.onCreated -> # @roles = [] diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index 5677bff22b2..17a971a3952 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -1,6 +1,6 @@ <template name="permissionsRole"> {{#if hasPermission}} - <a href="{{pathFor "rocket-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> + <a href="{{pathFor "admin-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> {{#with role}} <form id="form-role" class="inline"> -- GitLab From 2a631f793f0e373978117af7bcc7a1b13fa2b0d4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 1 Dec 2015 15:36:20 -0200 Subject: [PATCH 0637/1338] removing old permission --- server/startup/migrations/v24.coffee | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 server/startup/migrations/v24.coffee diff --git a/server/startup/migrations/v24.coffee b/server/startup/migrations/v24.coffee new file mode 100644 index 00000000000..1d473a03d3f --- /dev/null +++ b/server/startup/migrations/v24.coffee @@ -0,0 +1,5 @@ +Meteor.startup -> + Migrations.add + version: 24 + up: -> + RocketChat.models.Permissions.remove({ _id: 'access-rocket-permissions' }) -- GitLab From fefab766bae52fecf20736852eccefbae6a021e9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 1 Dec 2015 15:49:04 -0200 Subject: [PATCH 0638/1338] Secret URL registration. Closes #1507 --- client/routes/router.coffee | 16 +++++++++++++++- i18n/en.i18n.json | 3 +++ packages/rocketchat-lib/package.js | 1 + .../methods/checkRegistrationSecretURL.coffee | 4 ++++ .../assets/stylesheets/base.less | 12 ++++++++++++ packages/rocketchat-ui-login/login/form.coffee | 13 ++++++++++++- .../rocketchat-ui-master/master/blankLayout.html | 12 ++++++++++++ packages/rocketchat-ui-master/package.js | 3 ++- packages/rocketchat-ui/package.js | 1 + .../views/404/invalidSecretURL.html | 8 ++++++++ server/methods/registerUser.coffee | 3 +++ 11 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee create mode 100644 packages/rocketchat-ui-master/master/blankLayout.html create mode 100644 packages/rocketchat-ui/views/404/invalidSecretURL.html diff --git a/client/routes/router.coffee b/client/routes/router.coffee index 951fba47212..a0c46837f1e 100644 --- a/client/routes/router.coffee +++ b/client/routes/router.coffee @@ -100,6 +100,20 @@ FlowRouter.route '/room-not-found/:type/:name', FlowRouter.route '/fxos', name: 'firefox-os-install' - + action: -> BlazeLayout.render 'fxOsInstallPrompt' + +FlowRouter.route '/register/:hash', + name: 'register-secret-url' + action: (params) -> + if RocketChat.settings.get('Accounts_RegistrationForm') is 'Secret URL' + Meteor.call 'checkRegistrationSecretURL', params.hash, (err, success) -> + if success + Session.set 'loginDefaultState', 'register' + BlazeLayout.render 'main', {center: 'home'} + KonchatNotification.getDesktopPermission() + else + BlazeLayout.render 'blankLayout', { render: 'invalidSecretURL' } + else + BlazeLayout.render 'blankLayout', { render: 'invalidSecretURL' } diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 786afad2d49..fd9b9d2b84f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -54,6 +54,7 @@ "Accounts_RegistrationForm_LinkReplacementText": "Registration Form Link Replacement Text", "Accounts_RegistrationForm_Secret_URL" : "Secret URL", "Accounts_RegistrationForm_SecretURL" : "Registration Form Secret URL", + "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_Enrollment_Email" : "Enrollment E-mail", @@ -168,6 +169,8 @@ "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).", "Invalid_confirm_pass" : "The password confirmation does not match password", + "Invalid_Secret_URL" : "Invalid Secret URL", + "Invalid_secret_URL_message" : "The URL provided is invalid.", "Invalid_email" : "The e-mail entered is invalid", "Invalid_name" : "The name must not be empty", "Invalid_pass" : "The password must not be empty", diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 82eabf20678..253ef074f5e 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -53,6 +53,7 @@ Package.onUse(function(api) { // SERVER METHODS api.addFiles('server/methods/addOAuthService.coffee', 'server'); + api.addFiles('server/methods/checkRegistrationSecretURL.coffee', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); api.addFiles('server/methods/removeOAuthService.coffee', 'server'); api.addFiles('server/methods/robotMethods.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee b/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee new file mode 100644 index 00000000000..a69c22fffe4 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee @@ -0,0 +1,4 @@ +Meteor.methods + checkRegistrationSecretURL: (hash) -> + console.log '[method] checkRegistrationSecretURL'.green, hash + return hash is RocketChat.settings.get 'Accounts_RegistrationForm_SecretURL' diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 0fce46b4c8f..bfa3d0bf261 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4055,3 +4055,15 @@ a.github-fork { .inline-video { max-height: 200px; } + +.attention-message { + color: white; + padding-top: 50px; + font-size: 24px; + + i { + display: block; + margin-bottom: 20px; + font-size: 40px; + } +} diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 27055085b1a..2a74b14ccfe 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -52,7 +52,7 @@ Template.loginForm.helpers return RocketChat.settings.get 'Layout_Login_Terms' registrationAllowed: -> - return RocketChat.settings.get('Accounts_RegistrationForm') is 'Public' + return RocketChat.settings.get('Accounts_RegistrationForm') is 'Public' or Template.instance().validSecretURL?.get() linkReplacementText: -> return RocketChat.settings.get('Accounts_RegistrationForm_LinkReplacementText') @@ -81,6 +81,7 @@ Template.loginForm.events return if instance.state.get() is 'register' + formData.secretURL = FlowRouter.getParam 'hash' Meteor.call 'registerUser', formData, (error, result) -> RocketChat.Button.reset(button) @@ -125,8 +126,13 @@ Template.loginForm.onCreated -> instance = @ if Meteor.settings.public.sandstorm @state = new ReactiveVar('sandstorm') + else if Session.get 'loginDefaultState' + @state = new ReactiveVar(Session.get 'loginDefaultState') else @state = new ReactiveVar('login') + + @validSecretURL = new ReactiveVar(false) + @validate = -> formData = $("#login-card").serializeArray() formObj = {} @@ -162,7 +168,12 @@ Template.loginForm.onCreated -> $("#login-card input.error").removeClass "error" return formObj + if FlowRouter.getParam('hash') + Meteor.call 'checkRegistrationSecretURL', FlowRouter.getParam('hash'), (err, success) => + @validSecretURL.set true + Template.loginForm.onRendered -> + Session.set 'loginDefaultState' Tracker.autorun => switch this.state.get() when 'login', 'forgot-password', 'email-verification' diff --git a/packages/rocketchat-ui-master/master/blankLayout.html b/packages/rocketchat-ui-master/master/blankLayout.html new file mode 100644 index 00000000000..a75928f8866 --- /dev/null +++ b/packages/rocketchat-ui-master/master/blankLayout.html @@ -0,0 +1,12 @@ +<template name="blankLayout"> + <section class="full-page"> + <div class="wrapper"> + <header> + <a class="logo" href="/"> + <img src="/images/logo/logo.svg?v=3" /> + </a> + </header> + {{> Template.dynamic template=render}} + </div> + </section> +</template> diff --git a/packages/rocketchat-ui-master/package.js b/packages/rocketchat-ui-master/package.js index 280af721a3f..506a740b7dd 100644 --- a/packages/rocketchat-ui-master/package.js +++ b/packages/rocketchat-ui-master/package.js @@ -25,6 +25,7 @@ Package.onUse(function(api) { api.addFiles('master/main.html', 'client'); api.addFiles('master/loading.html', 'client'); api.addFiles('master/error.html', 'client'); + api.addFiles('master/blankLayout.html', 'client'); api.addFiles('master/main.coffee', 'client'); -}); \ No newline at end of file +}); diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 97aa9cda834..55c85b1c1e4 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -73,6 +73,7 @@ Package.onUse(function(api) { api.addFiles('views/fxos.html', 'client'); api.addFiles('views/modal.html', 'client'); api.addFiles('views/404/roomNotFound.html', 'client'); + api.addFiles('views/404/invalidSecretURL.html', 'client'); api.addFiles('views/app/audioNotification.html', 'client'); api.addFiles('views/app/burguer.html', 'client'); api.addFiles('views/app/home.html', 'client'); diff --git a/packages/rocketchat-ui/views/404/invalidSecretURL.html b/packages/rocketchat-ui/views/404/invalidSecretURL.html new file mode 100644 index 00000000000..e3482d4500f --- /dev/null +++ b/packages/rocketchat-ui/views/404/invalidSecretURL.html @@ -0,0 +1,8 @@ +<template name="invalidSecretURL"> + <div class="content"> + <div class="attention-message"> + <i class="icon-attention"></i> + {{_ 'Invalid_secret_URL_message'}} + </div> + </div> +</template> diff --git a/server/methods/registerUser.coffee b/server/methods/registerUser.coffee index 08513c97b3a..d441143015d 100644 --- a/server/methods/registerUser.coffee +++ b/server/methods/registerUser.coffee @@ -3,6 +3,9 @@ Meteor.methods if RocketChat.settings.get('Accounts_RegistrationForm') is 'Disabled' throw new Meteor.Error 'registration-disabled', 'User registration is disabled' + else if RocketChat.settings.get('Accounts_RegistrationForm') is 'Secret URL' and (not formData.secretURL or formData.secretURL isnt RocketChat.settings.get('Accounts_RegistrationForm_SecretURL')) + throw new Meteor.Error 'registration-disabled', 'User registration is only allowed via Secret URL' + userData = email: formData.email password: formData.pass -- GitLab From e98ad59a7dbca6e15ec44218ea7c967756701edd Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 1 Dec 2015 16:33:30 -0200 Subject: [PATCH 0639/1338] Prevent message forced refresh when removing room --- packages/rocketchat-ui/lib/RoomManager.coffee | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index a9e8a7a406b..1f5f3f024cf 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -21,13 +21,14 @@ Tracker.autorun -> Meteor.startup -> ChatMessage.find().observe removed: (record) -> - recordBefore = ChatMessage.findOne {ts: {$lt: record.ts}}, {sort: {ts: -1}} - if recordBefore? - ChatMessage.update {_id: recordBefore._id}, {$set: {tick: new Date}} + if RoomManager.getOpenedRoomByRid(record.rid)? + recordBefore = ChatMessage.findOne {ts: {$lt: record.ts}}, {sort: {ts: -1}} + if recordBefore? + ChatMessage.update {_id: recordBefore._id}, {$set: {tick: new Date}} - recordAfter = ChatMessage.findOne {ts: {$gt: record.ts}}, {sort: {ts: 1}} - if recordAfter? - ChatMessage.update {_id: recordAfter._id}, {$set: {tick: new Date}} + recordAfter = ChatMessage.findOne {ts: {$gt: record.ts}}, {sort: {ts: 1}} + if recordAfter? + ChatMessage.update {_id: recordAfter._id}, {$set: {tick: new Date}} onDeleteMessageStream = (msg) -> @@ -149,6 +150,11 @@ RocketChat.Notifications.onUser 'message', (msg) -> return openedRooms[typeName].ready } + getOpenedRoomByRid = (rid) -> + for typeName, openedRoom of openedRooms + if openedRoom.rid is rid + return openedRoom + getDomOfRoom = (typeName, rid) -> room = openedRooms[typeName] if not room? @@ -205,3 +211,4 @@ RocketChat.Notifications.onUser 'message', (msg) -> updateUserStatus: updateUserStatus onlineUsers: onlineUsers updateMentionsMarksOfRoom: updateMentionsMarksOfRoom + getOpenedRoomByRid: getOpenedRoomByRid -- GitLab From 7c73cc4cdf04b54eb9123546c97942ac9c9bfe68 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 1 Dec 2015 16:35:35 -0200 Subject: [PATCH 0640/1338] Force deletion and stop computations of templates when closing room --- packages/rocketchat-ui/lib/RoomManager.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 1f5f3f024cf..db18da71d52 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -69,7 +69,9 @@ RocketChat.Notifications.onUser 'message', (msg) -> openedRooms[typeName].ready = false openedRooms[typeName].active = false delete openedRooms[typeName].timeout + Blaze.remove openedRooms[typeName].template delete openedRooms[typeName].dom + delete openedRooms[typeName].template if openedRooms[typeName].rid? RoomHistoryManager.clear openedRooms[typeName].rid @@ -163,7 +165,11 @@ RocketChat.Notifications.onUser 'message', (msg) -> if not room.dom? and rid? room.dom = document.createElement 'div' room.dom.classList.add 'room-container' - Blaze.renderWithData Template.room, { _id: rid }, room.dom + contentAsFunc = (content) -> + return -> content + + room.template = Blaze._TemplateWith { _id: rid }, contentAsFunc(Template.room) + Blaze.render room.template, room.dom #, nextNode, parentView return room.dom -- GitLab From 00a09c0bac78eb70be4cd9e663251db70a53b5ab Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 1 Dec 2015 16:38:33 -0200 Subject: [PATCH 0641/1338] Close rooms when more than 10 is open instead of closing rooms inactive after 10min --- packages/rocketchat-ui/lib/RoomManager.coffee | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index db18da71d52..ee2ad7308e1 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -44,7 +44,6 @@ RocketChat.Notifications.onUser 'message', (msg) -> @RoomManager = new class - defaultTime = 600000 # 10 minutes openedRooms = {} subscription = null msgStream = new Meteor.Stream 'messages' @@ -68,14 +67,16 @@ RocketChat.Notifications.onUser 'message', (msg) -> openedRooms[typeName].ready = false openedRooms[typeName].active = false - delete openedRooms[typeName].timeout Blaze.remove openedRooms[typeName].template delete openedRooms[typeName].dom delete openedRooms[typeName].template - if openedRooms[typeName].rid? - RoomHistoryManager.clear openedRooms[typeName].rid - ChatMessage.remove rid: openedRooms[typeName].rid + rid = openedRooms[typeName].rid + delete openedRooms[typeName] + + if rid? + RoomHistoryManager.clear rid + computation = Tracker.autorun -> for typeName, record of openedRooms when record.active is true @@ -119,25 +120,29 @@ RocketChat.Notifications.onUser 'message', (msg) -> Dep.changed() - setRoomExpireExcept = (except) -> - if openedRooms[except]?.timeout? - clearTimeout openedRooms[except].timeout - delete openedRooms[except].timeout + closeOlderRooms = -> + maxRoomsOpen = 10 + if Object.keys(openedRooms).length <= maxRoomsOpen + return - for typeName of openedRooms - if typeName isnt except and not openedRooms[typeName].timeout? - openedRooms[typeName].timeout = setTimeout close, defaultTime, typeName + roomsToClose = _.sortBy(_.values(openedRooms), 'lastSeen').reverse().slice(maxRoomsOpen) + for roomToClose in roomsToClose + close roomToClose.typeName - open = (typeName) -> + open = (typeName) -> if not openedRooms[typeName]? openedRooms[typeName] = + typeName: typeName active: false ready: false unreadSince: new ReactiveVar undefined - setRoomExpireExcept typeName + openedRooms[typeName].lastSeen = new Date + + if openedRooms[typeName].ready + closeOlderRooms() if subscription.ready() -- GitLab From 47778840564f855c0ed6ec70326c51957c6d69a0 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 1 Dec 2015 17:04:32 -0200 Subject: [PATCH 0642/1338] Fixed error: when allow change username was set to false, registration failed. --- packages/rocketchat-lib/server/methods/setUsername.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 6fed25d40de..2132d7edf5f 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -3,12 +3,12 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] setUsername -> Invalid user") - unless RocketChat.settings.get("Accounts_AllowUsernameChange") - throw new Meteor.Error(403, "[methods] resetAvatar -> Invalid access") + user = Meteor.user() - console.log '[methods] setUsername -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments + if user.username? and not RocketChat.settings.get("Accounts_AllowUsernameChange") + throw new Meteor.Error(403, "[methods] setUsername -> Username change not allowed") - user = Meteor.user() + console.log '[methods] setUsername -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments if user.username is username return username -- GitLab From 6f1e4dd1ae475f6ff464beb874c45ab7ff79ef60 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 1 Dec 2015 17:40:33 -0200 Subject: [PATCH 0643/1338] permissions manager translation --- .../client/views/permissionsRole.coffee | 2 +- .../i18n/en.i18n.json | 23 +++++++++++++++++++ .../i18n/pt.i18n.json | 23 +++++++++++++++++++ packages/rocketchat-authorization/package.js | 10 ++++++++ .../server/methods/addUserToRole.coffee | 2 +- .../server/methods/deleteRole.coffee | 4 ++-- 6 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 packages/rocketchat-authorization/i18n/en.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/pt.i18n.json diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 18814d2a1a0..95f5898ea40 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -88,7 +88,7 @@ Template.permissionsRole.events e.preventDefault() if @protected - return toastr.error t('Cannot_delete_an_protected_role') + return toastr.error t('Cannot_delete_a_protected_role') Meteor.call 'authorization:deleteRole', @_id, (error, result) -> if error diff --git a/packages/rocketchat-authorization/i18n/en.i18n.json b/packages/rocketchat-authorization/i18n/en.i18n.json new file mode 100644 index 00000000000..a33353406e7 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -0,0 +1,23 @@ +{ + "Add": "Add", + "Add_user": "Add user", + "Back_to_permissions": "Back to permissions", + "Cannot_delete_a_protected_role": "Cannot delete a protected role", + "Cannot_delete_role_because_its_in_use": "Cannot delete role because it's in use", + "Description": "Description", + "Enter_a_username": "Enter a username", + "New_role": "New role", + "Permissions": "Permissions", + "Please_fill_a_username": "Please fill a username", + "Removed": "Removed", + "Role": "Role", + "Role_Editing": "Role Editing", + "Role_removed": "Role removed", + "Save": "Save", + "Saved": "Saved", + "Saving": "Saving", + "User_added": "User added", + "User_not_found": "User not found", + "User_removed": "User removed", + "Users_in_role": "Users in role" +} diff --git a/packages/rocketchat-authorization/i18n/pt.i18n.json b/packages/rocketchat-authorization/i18n/pt.i18n.json new file mode 100644 index 00000000000..33a4b1e46a4 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -0,0 +1,23 @@ +{ + "Add": "Adicionar", + "Add_user": "Adicionar usuário", + "Back_to_permissions": "Voltar para permissões", + "Cannot_delete_a_protected_role": "Não é possÃvel remover um papel protegido", + "Cannot_delete_role_because_its_in_use": "Não é possÃvel remover o papel pois ele está em uso", + "Description": "Descrição", + "Enter_a_username": "Preencha um nome de usuário", + "New_role": "Novo papel", + "Permissions": "Permissões", + "Please_fill_a_username": "Por favor preencha um nome de usuário", + "Removed": "Removido", + "Role": "Papel", + "Role_Editing": "Edição de Papel", + "Role_removed": "Papel Removido", + "Save": "Salvar", + "Saved": "Salvo", + "Saving": "Salvando", + "User_added": "Usuário adicionado", + "User_not_found": "Usuário não encontrado", + "User_removed": "Usuário removido", + "Users_in_role": "Usuários no papel" +} diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index dc48b5be582..3496986fd32 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -59,4 +59,14 @@ Package.onUse(function(api) { api.addFiles('server/methods/removeRoleFromPermission.coffee', 'server'); api.addFiles('server/startup.coffee', ['server']); + + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-authorization/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-authorization/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n', ['client', 'server']); + api.addFiles(tapi18nFiles, ['client', 'server']); }); diff --git a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee index 781aaad04ad..98583682d75 100644 --- a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee @@ -11,7 +11,7 @@ Meteor.methods user = Meteor.users.findOne { username: username }, { fields: { _id: 1 } } if not user?._id? - throw new Meteor.Error 'user-not-found' + 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 diff --git a/packages/rocketchat-authorization/server/methods/deleteRole.coffee b/packages/rocketchat-authorization/server/methods/deleteRole.coffee index 83f0d290094..ab6e554c112 100644 --- a/packages/rocketchat-authorization/server/methods/deleteRole.coffee +++ b/packages/rocketchat-authorization/server/methods/deleteRole.coffee @@ -8,11 +8,11 @@ Meteor.methods role = Meteor.roles.findOne _id if role.protected - throw new Meteor.Error 'protected-role', TAPi18n.__('Cannot_delete_an_protected_role') + throw new Meteor.Error 'protected-role', 'Cannot_delete_a_protected_role' someone = Meteor.users.findOne { "roles.#{Roles.GLOBAL_GROUP}": role.name } if someone? - throw new Meteor.Error 'role-in-use', TAPi18n.__('Cannot_delete_role_because_its_in_use') + throw new Meteor.Error 'role-in-use', 'Cannot_delete_role_because_its_in_use' return Roles.deleteRole role.name -- GitLab From 12107cc8c8849d8441accc98cb965e37e5729baa Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 1 Dec 2015 18:13:22 -0200 Subject: [PATCH 0644/1338] improving permissions UI --- .../client/stylesheets/permissions.less | 19 +++++++++++++++++++ .../client/views/permissions.html | 2 +- packages/rocketchat-authorization/package.js | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-authorization/client/stylesheets/permissions.less diff --git a/packages/rocketchat-authorization/client/stylesheets/permissions.less b/packages/rocketchat-authorization/client/stylesheets/permissions.less new file mode 100644 index 00000000000..001db508e7b --- /dev/null +++ b/packages/rocketchat-authorization/client/stylesheets/permissions.less @@ -0,0 +1,19 @@ +.permission-grid { + border-collapse: collapse; + // td:nth-child(2n+2) { + // background-color: #FAFAFA; + // } + tr:nth-child(even) { + background-color: #EFEFEF; + // td:nth-child(2n+2) { + // background-color: #EAEAEA; + // } + } + td:nth-child(n+2) { + text-align: center; + } + td { + padding: 5px; + border: 1px solid #E0E0E0; + } +} diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index 29a6b7e6946..7bb56709b0f 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -4,7 +4,7 @@ <a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> - <table border="1"> + <table border="1" class="permission-grid"> <tr> <td> </td> {{#each role}} diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 3496986fd32..90a13112d92 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -17,6 +17,7 @@ Package.onUse(function(api) { api.use('mongo', 'client'); api.use('kadira:flow-router', 'client'); + api.use('less@2.5.1', 'client'); api.use('templating', 'client'); @@ -34,6 +35,9 @@ Package.onUse(function(api) { api.addFiles('client/views/permissionsRole.html', ['client']); api.addFiles('client/views/permissionsRole.coffee', ['client']); + // stylesheets + api.addFiles('client/stylesheets/permissions.less', 'client'); + api.addFiles('server/models/Permissions.coffee', ['server']); api.addFiles('server/functions/addUsersToRoles.coffee', ['server']); -- GitLab From cdab22da14b333ee447ce417116f2bd4ff806c33 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 1 Dec 2015 18:15:01 -0200 Subject: [PATCH 0645/1338] Improve message rendering removing MessageAction from render time --- .../client/MessageAction.coffee | 7 ++++- .../message/message.coffee | 2 -- .../message/message.html | 17 +++-------- .../message/messageDropdown.html | 12 ++++++++ packages/rocketchat-ui-message/package.js | 3 +- packages/rocketchat-ui/views/app/room.coffee | 30 ++++++++++++++----- 6 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 packages/rocketchat-ui-message/message/messageDropdown.html diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee index 3aec40bcb3e..43af02e4689 100644 --- a/packages/rocketchat-lib/client/MessageAction.coffee +++ b/packages/rocketchat-lib/client/MessageAction.coffee @@ -32,6 +32,10 @@ RocketChat.MessageAction = new class btns[id] = _.extend btns[id], config buttons.set btns + getButtonById = (id) -> + allButtons = buttons.get() + return allButtons[id] + getButtons = (message) -> allButtons = _.toArray buttons.get() if message @@ -50,6 +54,7 @@ RocketChat.MessageAction = new class removeButton: removeButton updateButton: updateButton getButtons: getButtons + getButtonById: getButtonById resetButtons: resetButtons Meteor.startup -> @@ -111,4 +116,4 @@ Meteor.startup -> chatMessages[Session.get('openedRoom')].deleteMsg(message) validation: (message) -> return RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid ) or RocketChat.settings.get('Message_AllowDeleting') and message.u?._id is Meteor.userId() - order: 2 \ No newline at end of file + order: 2 diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 2792c4cf8cb..b934b460ecd 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -1,6 +1,4 @@ Template.message.helpers - actions: -> - return RocketChat.MessageAction.getButtons(this) own: -> return 'own' if this.u?._id is Meteor.userId() chatops: -> diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index b602ff943c3..5768abe8696 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -22,19 +22,10 @@ {{#if private}} <span class="private">{{_ "Only_you_can_see_this_message"}}</span> {{/if}} - {{#if actions.length}} - <div class="message-cog-container"> - <i class="icon-cog message-cog" aria-label="{{_ "Actions"}}"></i> - <div class="message-dropdown"> - <ul> - <li class="message-dropdown-close"><i class=" icon-angle-left" aria-label="{{_ "Close"}}"></i></li> - {{#each actions}} - <li class="{{id}} {{classes}} message-action" title="{{_ i18nLabel}}"><i class="{{icon}}" aria-label="{{_ i18nLabel}}"></i></li> - {{/each}} - </ul> - </div> - </div> - {{/if}} + + <div class="message-cog-container"> + <i class="icon-cog message-cog" aria-label="{{_ "Actions"}}"></i> + </div> </span> <div class="body" dir="auto"> {{{body}}} diff --git a/packages/rocketchat-ui-message/message/messageDropdown.html b/packages/rocketchat-ui-message/message/messageDropdown.html new file mode 100644 index 00000000000..93468e4bd65 --- /dev/null +++ b/packages/rocketchat-ui-message/message/messageDropdown.html @@ -0,0 +1,12 @@ +<template name="messageDropdown"> + <div class="message-dropdown"> + <ul> + <li class="message-dropdown-close"><i class=" icon-angle-left" aria-label="{{_ "Close"}}"></i></li> + {{#if actions.length}} + {{#each actions}} + <li class="{{id}} {{classes}} message-action" title="{{_ i18nLabel}}" data-id="{{id}}"><i class="{{icon}}" aria-label="{{_ i18nLabel}}"></i></li> + {{/each}} + {{/if}} + </ul> + </div> +</template> diff --git a/packages/rocketchat-ui-message/package.js b/packages/rocketchat-ui-message/package.js index f06271a56d7..b62401731bf 100644 --- a/packages/rocketchat-ui-message/package.js +++ b/packages/rocketchat-ui-message/package.js @@ -24,6 +24,7 @@ Package.onUse(function(api) { api.addFiles('message/message.html', 'client'); api.addFiles("message/messageBox.html", "client"); + api.addFiles("message/messageDropdown.html", "client"); api.addFiles("message/popup/messagePopup.html", "client"); api.addFiles("message/popup/messagePopupChannel.html", "client"); api.addFiles("message/popup/messagePopupConfig.html", "client"); @@ -38,4 +39,4 @@ Package.onUse(function(api) { api.addFiles("message/popup/messagePopupEmoji.coffee", "client"); -}); \ No newline at end of file +}); diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index f5d25405c69..1b233b23076 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -332,9 +332,29 @@ Template.room.events instance.showUsersOffline.set(!instance.showUsersOffline.get()) 'click .message-cog': (e) -> - message_id = $(e.currentTarget).closest('.message').attr('id') + message = @_arguments[1] $('.message-dropdown:visible').hide() - $(".messages-box \##{message_id} .message-dropdown").show() + + dropDown = $(".messages-box \##{message._id} .message-dropdown") + + if dropDown.length is 0 + actions = RocketChat.MessageAction.getButtons message + + el = Blaze.toHTMLWithData Template.messageDropdown, + actions: actions + + $(".messages-box \##{message._id} .message-cog-container").append el + + dropDown = $(".messages-box \##{message._id} .message-dropdown") + + dropDown.show() + + 'click .message-dropdown .message-action': (e, t) -> + el = $(e.currentTarget) + + button = RocketChat.MessageAction.getButtonById el.data('id') + if button?.action? + button.action.call @, e, t 'click .message-dropdown-close': -> $('.message-dropdown:visible').hide() @@ -416,12 +436,6 @@ Template.room.onCreated -> @autorun -> self.subscribe 'fullUserData', Session.get('showUserInfo'), 1 - for button in RocketChat.MessageAction.getButtons() - if _.isFunction button.action - evt = {} - evt["click .#{button.id}"] = button.action - Template.room.events evt - Template.room.onDestroyed -> RocketChat.TabBar.resetButtons() -- GitLab From 5579e905b4cc5a36ade612ae32e3e1e07e09ea94 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Tue, 1 Dec 2015 16:01:00 -0500 Subject: [PATCH 0646/1338] Textarea theme fix for RTL These changes alters the theme of the text-area and the upload button to look correct with RTL interface. --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 9361458a437..1cd8ead2175 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -222,9 +222,19 @@ .messages-container { .message-form { + > div { + > .file { + border: 1px; + border-radius: 0 5px 5px 0; + border-left: none; + border-right: solid; + } + } textarea { padding-left: 38px; padding-right: 8px; + border-radius: 5px 0 0 5px; + text-align: right; } >.users-typing { float: right; -- GitLab From 167b0fe85f2578a9432e5acbce0dbe49bb84f3a0 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Tue, 1 Dec 2015 16:06:31 -0500 Subject: [PATCH 0647/1338] Update the flex-nav hidden element for RTL Updated the name of the flex-nav element for RTL from `hidden` to the correct name `animated-hidden` --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 9361458a437..7c8b179510d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -94,7 +94,7 @@ .right(0px); } - .flex-nav.hidden { + .flex-nav.animated-hidden { transform: translateX(100%); } -- GitLab From f427d5f67f5cfd2457dc29d51bb49cf27f600173 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 1 Dec 2015 19:20:52 -0200 Subject: [PATCH 0648/1338] Refresh the count of unread messages on scroll --- packages/rocketchat-ui/views/app/room.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index f5d25405c69..1e482e9ba36 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -526,6 +526,9 @@ Template.room.onRendered -> template.unreadCount.set 0 , 300 + wrapper.addEventListener 'scroll', -> + updateUnreadCount() + # salva a data da renderização para exibir alertas de novas mensagens $.data(this.firstNode, 'renderedAt', new Date) -- GitLab From d2bb907583c434f17d33860198ba729e0cf9af83 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 1 Dec 2015 20:00:25 -0200 Subject: [PATCH 0649/1338] Reset correctly all counters of unread marks --- packages/rocketchat-ui/lib/readMessages.coffee | 13 +++++++++++++ packages/rocketchat-ui/views/app/room.coffee | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/packages/rocketchat-ui/lib/readMessages.coffee b/packages/rocketchat-ui/lib/readMessages.coffee index 5dd3b704f48..f2988df8fc0 100644 --- a/packages/rocketchat-ui/lib/readMessages.coffee +++ b/packages/rocketchat-ui/lib/readMessages.coffee @@ -14,6 +14,8 @@ @readMessage = new class debug: false + callbacks: [] + constructor: -> @canReadMessage = false @@ -33,7 +35,9 @@ if force is true console.log 'readMessage -> readNow via force rid:', rid if @debug return Meteor.call 'readMessages', rid, -> + RoomHistoryManager.getRoom(rid).unreadNotLoaded.set 0 self.refreshUnreadMark() + self.fireRead rid subscription = ChatSubscription.findOne rid: rid if not subscription? @@ -58,7 +62,9 @@ console.log 'readMessage -> readNow rid:', rid if @debug Meteor.call 'readMessages', rid, -> + RoomHistoryManager.getRoom(rid).unreadNotLoaded.set 0 self.refreshUnreadMark() + self.fireRead rid read: _.debounce (force) -> @readNow(force) @@ -73,6 +79,13 @@ isEnable: -> return @canReadMessage is true + onRead: (cb) -> + @callbacks.push cb + + fireRead: (rid) -> + for cb in @callbacks + cb(rid) + refreshUnreadMark: (rid, force) -> self = @ diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 1e482e9ba36..015d6eed927 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -526,6 +526,10 @@ Template.room.onRendered -> template.unreadCount.set 0 , 300 + readMessage.onRead (rid) -> + if rid is template.data._id + template.unreadCount.set 0 + wrapper.addEventListener 'scroll', -> updateUnreadCount() -- GitLab From 3c43969791c5c52098aa8db97eaec8166b4329c9 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 1 Dec 2015 20:41:10 -0600 Subject: [PATCH 0650/1338] Attempt to collapse two builds into one Hoping to shorten build time --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06dbf2c2522..6bdaab1d9f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,9 +43,9 @@ before_install: script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - export TAG=$(git describe --abbrev=0 --tags) -- meteor build ../build -- cd .travis -- sh ./namefiles.sh +#- meteor build ../build +#- cd .travis +#- sh ./namefiles.sh - cd /tmp - spk init -p3000 -- nothing - export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) @@ -53,6 +53,9 @@ script: - export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" - export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle - meteor build --directory /home/vagrant/ +- cp /home/vagrant/* $TRAVIS_BUILD_DIR/../build +- cd $TRAVIS_BUILD_DIR/.travis +- sh ./namefiles.sh - cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install - cd $TRAVIS_BUILD_DIR/.sandstorm - sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp -- GitLab From 4db26f78e449a43293059fd02fb6f0857a485f4c Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 1 Dec 2015 20:57:22 -0600 Subject: [PATCH 0651/1338] Attempt to collapse two builds into one Shorten build time --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6bdaab1d9f7..db17bc6df43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ before_install: - cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ - cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ - cd $TRAVIS_BUILD_DIR +- mkdir ../build - cp -r . /opt/app script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi -- GitLab From 63db5f83a150ac315682986dafa4611295765c28 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 2 Dec 2015 01:15:54 -0500 Subject: [PATCH 0652/1338] Collapse two builds into one attempt to save build time --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index db17bc6df43..73add1c7f6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,19 +44,19 @@ before_install: script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - export TAG=$(git describe --abbrev=0 --tags) -#- meteor build ../build -#- cd .travis -#- sh ./namefiles.sh +- meteor build ../build +- cp ../build/Rocket.Chat.tar.gz /home/vagrant +- cd .travis +- sh ./namefiles.sh - cd /tmp - spk init -p3000 -- nothing - export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) - cd $TRAVIS_BUILD_DIR - export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" - export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle -- meteor build --directory /home/vagrant/ -- cp /home/vagrant/* $TRAVIS_BUILD_DIR/../build -- cd $TRAVIS_BUILD_DIR/.travis -- sh ./namefiles.sh +#- meteor build --directory /home/vagrant/ +- cd /home/vagrant && tar zxvf ./Rocket.Chat.tar.gz +- rm ./Rocket.Chat.tar.gz - cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install - cd $TRAVIS_BUILD_DIR/.sandstorm - sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp -- GitLab From e9220e32955d66c81f029c7cc75d0fb92553b6f4 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 2 Dec 2015 01:38:30 -0500 Subject: [PATCH 0653/1338] less verbose build output correct typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 73add1c7f6a..d7b0fd1c697 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ script: - export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" - export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle #- meteor build --directory /home/vagrant/ -- cd /home/vagrant && tar zxvf ./Rocket.Chat.tar.gz +- cd /home/vagrant && tar zxf ./Rocket.Chat.tar.gz - rm ./Rocket.Chat.tar.gz - cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install - cd $TRAVIS_BUILD_DIR/.sandstorm -- GitLab From 7623a9e17cae85f62001dfc629f9734efef56f64 Mon Sep 17 00:00:00 2001 From: wtsarchive <wtsarchive@gmail.com> Date: Wed, 2 Dec 2015 12:43:51 +0100 Subject: [PATCH 0654/1338] Reset avatar before uploading to prevent caching issues --- server/methods/setAvatarFromService.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index cb78e366d3f..4a13971591b 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -32,6 +32,7 @@ Meteor.methods throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> invalid content-type') ars = RocketChatFile.bufferToStream new Buffer(result.content, 'binary') + RocketChatFileAvatarInstance.deleteFile "#{user.username}.jpg" aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", result.headers['content-type'] aws.on 'end', Meteor.bindEnvironment -> Meteor.setTimeout -> @@ -46,6 +47,7 @@ Meteor.methods {image, contentType} = RocketChatFile.dataURIParse dataURI rs = RocketChatFile.bufferToStream new Buffer(image, 'base64') + RocketChatFileAvatarInstance.deleteFile encodeURIComponent("#{user.username}.jpg") ws = RocketChatFileAvatarInstance.createWriteStream encodeURIComponent("#{user.username}.jpg"), contentType ws.on 'end', Meteor.bindEnvironment -> Meteor.setTimeout -> -- GitLab From ec07b10cf34b01d1aefcc9133bbbcb69f24563f0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 2 Dec 2015 16:50:36 -0200 Subject: [PATCH 0655/1338] new styles --- .../client/stylesheets/permissions.less | 110 +++++++++++++--- .../client/views/permissions.html | 57 +++++---- .../client/views/permissionsRole.coffee | 3 + .../client/views/permissionsRole.html | 118 +++++++++--------- 4 files changed, 192 insertions(+), 96 deletions(-) diff --git a/packages/rocketchat-authorization/client/stylesheets/permissions.less b/packages/rocketchat-authorization/client/stylesheets/permissions.less index 001db508e7b..7a11a3e3e45 100644 --- a/packages/rocketchat-authorization/client/stylesheets/permissions.less +++ b/packages/rocketchat-authorization/client/stylesheets/permissions.less @@ -1,19 +1,99 @@ -.permission-grid { - border-collapse: collapse; - // td:nth-child(2n+2) { - // background-color: #FAFAFA; - // } - tr:nth-child(even) { - background-color: #EFEFEF; - // td:nth-child(2n+2) { - // background-color: #EAEAEA; - // } +.permissions-manager { + h2 { + font-weight: bold !important; + font-size: 16px; + margin-top: 1em !important; + margin-bottom: 1em !important; + border-bottom: 1px solid #EEE; } - td:nth-child(n+2) { - text-align: center; + + // a { + // color: #000; + // text-decoration: underline; + // } + + .permission-grid { + border-collapse: collapse; + overflow: hidden; + margin-bottom: 1em; + + td { + position: relative; + * { + color: #000; + } + } + + td:nth-child(n+2) { + text-align: center; + width: 10%; + } + + + td:nth-child(1) { + // text-align: center; + white-space: nowrap; + } + + td { + padding: 5px; + border: 1px solid #F0F0F0; + } + + td:hover::after { + content: ""; + position: absolute; + background-color: rgba(4,73,116,0.04); + left: 0; + top: -5000px; + height: 10000px; + width: 100%; + z-index: -1; + } + + tbody { + tr:nth-child(even) td:first-child::before { + content: ""; + position: absolute; + background-color: #FAFAFA; + top: 0; + left: -5000px; + width: 10000px; + height: 100%; + z-index: -10; + } + + tr:hover { + background-color: rgba(4,73,116,0.04); + } + + } + + thead { + tr { + background-color: #F0F0F0; + } + td { + font-weight: bold; + a { + white-space: nowrap; + } + .icon-edit { + font-size: 80%; + } + } + } } - td { - padding: 5px; - border: 1px solid #E0E0E0; + + .form-role { + label { + width: 150px; + display: inline-block; + text-align: right; + } + + .form-buttons { + padding-left: 150px; + } } } diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html index 7bb56709b0f..f95b309f24a 100644 --- a/packages/rocketchat-authorization/client/views/permissions.html +++ b/packages/rocketchat-authorization/client/views/permissions.html @@ -1,28 +1,37 @@ <template name="permissions"> - {{#if hasPermission}} - <h1>{{_ "Permissions"}}</h1> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> - <a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> - - <table border="1" class="permission-grid"> - <tr> - <td> </td> - {{#each role}} - <td title="{{description}}"><a href="{{pathFor "admin-permissions-edit" name=name}}">{{name}}</a></td> - {{/each}} - </tr> - {{#each permission}} - <tr> - <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}}"> - </td> + <table border="1" class="permission-grid"> + <thead> + <tr> + <td> </td> + {{#each role}} + <td title="{{description}}"> + <a href="{{pathFor "admin-permissions-edit" name=name}}"> + {{name}} + <i class="icon-edit"></i> + </a> + </td> + {{/each}} + </tr> + </thead> + <tbody> + {{#each permission}} + <tr> + <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}}"> + </td> + {{/each}} + </tr> {{/each}} - </tr> - {{/each}} - </table> - {{else}} - {{_ "Not_authorized"}} - {{/if}} + </tbody> + </table> + {{else}} + {{_ "Not_authorized"}} + {{/if}} + </div> </template> diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 95f5898ea40..28f81963983 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -15,6 +15,9 @@ Template.permissionsRole.helpers hasPermission: -> return RocketChat.authz.hasAllPermission 'access-permissions' + canDelete: -> + return @_id? and not @protected + Template.permissionsRole.events 'click .remove-user': (e, instance) -> diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index 17a971a3952..cdfc6badeab 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -1,65 +1,69 @@ <template name="permissionsRole"> - {{#if hasPermission}} - <a href="{{pathFor "admin-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-permissions"}}">{{_ "Back_to_permissions"}}</a><br><br> - {{#with role}} - <form id="form-role" class="inline"> - <label>{{_ "Role"}}</label>: - {{#if editing}} - <span>{{name}}</span> - {{else}} - <input type="text" name="name" value=""> - {{/if}} - <br> - <label>{{_ "Description"}}</label>: - <input type="text" name="description" value="{{description}}"> - <br> + {{#with role}} + <form id="form-role" class="inline form-role"> + <label>{{_ "Role"}} :</label> + {{#if editing}} + <span>{{name}}</span> + {{else}} + <input type="text" name="name" value=""> + {{/if}} + <br> + <label>{{_ "Description"}} :</label> + <input type="text" name="description" value="{{description}}"> + <br> - <button name="save" class="button primary">{{_ "Save"}}</button> + <div class="form-buttons"> + <button name="save" class="button primary">{{_ "Save"}}</button> - {{#unless protected}} - <button name="delete" class="button red delete-role">{{_ "Delete"}}</button> - {{/unless}} - </form> - {{/with}} + {{#if canDelete}} + <button name="delete" class="button red delete-role">{{_ "Delete"}}</button> + {{/if}} + </div> + </form> + {{/with}} - {{#if editing}} - <h2>{{_ "Users_in_role"}}</h2> - <form id="form-users" class="inline"> - <label>{{_ "Add_user"}}</label> - <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> - <button name="add" class="button primary">{{_ "Add"}}</button> - </form> - <div class="list"> - <table> - <thead> - <tr> - <th> </th> - <th width="34%">{{_ "Name"}}</th> - <th width="33%">{{_ "Username"}}</th> - <th width="33%">{{_ "E-mail"}}</th> - <th> </th> - </tr> - </thead> - <tbody> - {{#each userInRole}} - <tr class="user-info" data-id="{{_id}}"> - <td> - <div class="user-image status-{{status}}"> - {{> avatar username=username}} - </div> - </td> - <td>{{name}}</td> - <td>{{username}}</td> - <td>{{emailAddress}}</td> - <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + {{#if editing}} + <h2>{{_ "Users_in_role"}}</h2> + <form id="form-users" class="inline"> + <label>{{_ "Add_user"}}</label> + <input type="text" name="username" placeholder="{{_ "Enter_a_username"}}"> + <button name="add" class="button primary">{{_ "Add"}}</button> + </form> + <div class="list"> + <table> + <thead> + <tr> + <th> </th> + <th width="34%">{{_ "Name"}}</th> + <th width="33%">{{_ "Username"}}</th> + <th width="33%">{{_ "E-mail"}}</th> + <th> </th> </tr> - {{/each}} - </tbody> - </table> - </div> + </thead> + <tbody> + {{#each userInRole}} + <tr class="user-info" data-id="{{_id}}"> + <td> + <div class="user-image status-{{status}}"> + {{> avatar username=username}} + </div> + </td> + <td>{{name}}</td> + <td>{{username}}</td> + <td>{{emailAddress}}</td> + <td><a href="#remove" class="remove-user"><i class="icon-block"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> + {{/if}} + {{else}} + {{_ "Not_authorized"}} {{/if}} - {{else}} - {{_ "Not_authorized"}} - {{/if}} + </div> </template> -- GitLab From dfa0dd00279ff7aec9fcbe4ea8fdb7f320e0ec89 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 2 Dec 2015 17:18:36 -0200 Subject: [PATCH 0656/1338] notify when there is no users in a roles --- .../client/stylesheets/permissions.less | 4 ++++ .../client/views/permissionsRole.coffee | 15 +++++++-------- .../client/views/permissionsRole.html | 5 +++++ .../rocketchat-authorization/i18n/en.i18n.json | 1 + .../rocketchat-authorization/i18n/pt.i18n.json | 1 + 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-authorization/client/stylesheets/permissions.less b/packages/rocketchat-authorization/client/stylesheets/permissions.less index 7a11a3e3e45..9d2d57bfd23 100644 --- a/packages/rocketchat-authorization/client/stylesheets/permissions.less +++ b/packages/rocketchat-authorization/client/stylesheets/permissions.less @@ -85,6 +85,10 @@ } } + .empty-role { + padding: 0.5em !important; + } + .form-role { label { width: 150px; diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 28f81963983..078f5dbe619 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -3,7 +3,7 @@ Template.permissionsRole.helpers return Meteor.roles.findOne({ name: FlowRouter.getParam('name') }) or {} userInRole: -> - return Roles.getUsersInRole(FlowRouter.getParam('name')) + return Template.instance().usersInRole editing: -> return FlowRouter.getParam('name')? @@ -18,6 +18,11 @@ Template.permissionsRole.helpers canDelete: -> return @_id? and not @protected + hasUsers: -> + console.log Template.instance().usersInRole + console.log 'count ->',Template.instance().usersInRole.count() + return Template.instance().usersInRole.count() > 0 + Template.permissionsRole.events 'click .remove-user': (e, instance) -> @@ -102,13 +107,7 @@ Template.permissionsRole.events FlowRouter.go 'admin-permissions' Template.permissionsRole.onCreated -> - # @roles = [] - # @permissions = [] - # @permissionByRole = {} - - console.log Roles - @subscribe 'roles', FlowRouter.getParam('name') @subscribe 'usersInRole', FlowRouter.getParam('name') - # ChatPermissions + @usersInRole = Roles.getUsersInRole(FlowRouter.getParam('name')) diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index cdfc6badeab..a824390e886 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.html +++ b/packages/rocketchat-authorization/client/views/permissionsRole.html @@ -45,6 +45,11 @@ </tr> </thead> <tbody> + {{#unless hasUsers}} + <tr> + <td colspan="5" class="empty-role">{{_ "There_are_no_users_in_this_role"}}</td> + </tr> + {{/unless}} {{#each userInRole}} <tr class="user-info" data-id="{{_id}}"> <td> diff --git a/packages/rocketchat-authorization/i18n/en.i18n.json b/packages/rocketchat-authorization/i18n/en.i18n.json index a33353406e7..e390524161a 100644 --- a/packages/rocketchat-authorization/i18n/en.i18n.json +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -16,6 +16,7 @@ "Save": "Save", "Saved": "Saved", "Saving": "Saving", + "There_are_no_users_in_this_role": "There are no users in this role.", "User_added": "User added", "User_not_found": "User not found", "User_removed": "User removed", diff --git a/packages/rocketchat-authorization/i18n/pt.i18n.json b/packages/rocketchat-authorization/i18n/pt.i18n.json index 33a4b1e46a4..da82a048405 100644 --- a/packages/rocketchat-authorization/i18n/pt.i18n.json +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -16,6 +16,7 @@ "Save": "Salvar", "Saved": "Salvo", "Saving": "Salvando", + "There_are_no_users_in_this_role": "Não há usuários neste papel.", "User_added": "Usuário adicionado", "User_not_found": "Usuário não encontrado", "User_removed": "Usuário removido", -- GitLab From 1a64a4317e1e3c2a935b71d3ecb950dfe96c87f6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 2 Dec 2015 17:30:55 -0200 Subject: [PATCH 0657/1338] sort permissions --- .../rocketchat-authorization/client/views/permissions.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee index 45ff2454ebb..0e134582401 100644 --- a/packages/rocketchat-authorization/client/views/permissions.coffee +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -4,7 +4,7 @@ Template.permissions.helpers return Template.instance().roles.get() permission: -> - return ChatPermissions.find() + return ChatPermissions.find({}, { sort: { _id: 1 } }) granted: (roles) -> if roles? -- GitLab From ea738438f25632efc34c384ac3cea8495d56d21d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 2 Dec 2015 17:36:28 -0200 Subject: [PATCH 0658/1338] sorting users by username --- .../client/views/permissionsRole.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index 078f5dbe619..bb754ced89c 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -19,8 +19,6 @@ Template.permissionsRole.helpers return @_id? and not @protected hasUsers: -> - console.log Template.instance().usersInRole - console.log 'count ->',Template.instance().usersInRole.count() return Template.instance().usersInRole.count() > 0 Template.permissionsRole.events @@ -110,4 +108,4 @@ Template.permissionsRole.onCreated -> @subscribe 'roles', FlowRouter.getParam('name') @subscribe 'usersInRole', FlowRouter.getParam('name') - @usersInRole = Roles.getUsersInRole(FlowRouter.getParam('name')) + @usersInRole = Roles.getUsersInRole(FlowRouter.getParam('name'), Roles.GLOBAL_GROUP, { sort: { username: 1 } }) -- GitLab From a382a28b039811e2132f4da0a30bf1c1eb138dc4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 2 Dec 2015 17:37:22 -0200 Subject: [PATCH 0659/1338] cleaning up styles --- .../client/stylesheets/permissions.less | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/rocketchat-authorization/client/stylesheets/permissions.less b/packages/rocketchat-authorization/client/stylesheets/permissions.less index 9d2d57bfd23..1c3d293b0e7 100644 --- a/packages/rocketchat-authorization/client/stylesheets/permissions.less +++ b/packages/rocketchat-authorization/client/stylesheets/permissions.less @@ -7,11 +7,6 @@ border-bottom: 1px solid #EEE; } - // a { - // color: #000; - // text-decoration: underline; - // } - .permission-grid { border-collapse: collapse; overflow: hidden; @@ -31,7 +26,6 @@ td:nth-child(1) { - // text-align: center; white-space: nowrap; } -- GitLab From db807f12d95bdc682810f55649c6c9e7856feb83 Mon Sep 17 00:00:00 2001 From: Thomas Lutz <thomaslutz.de@googlemail.com> Date: Wed, 2 Dec 2015 21:14:18 +0100 Subject: [PATCH 0660/1338] Add hubot config to docker-compose.yml --- docker-compose.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index bab5c04da7c..7fc1a9f81e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,3 +19,20 @@ rocketchat: - mongo:mongo ports: - 3000:3000 + +# hubot, the popular chatbot (add the bot user first and change the password before starting this image) +hubot: + image: rocketchat/hubot-rocketchat + environment: + - ROCKETCHAT_URL=yourhost:3000 + - ROCKETCHAT_ROOM=GENERAL + - ROCKETCHAT_USER=bot + - ROCKETCHAT_PASSWORD=botpassword + - BOT_NAME=bot +# you can add more scripts as you'd like here, they need to be installable by npm + - EXTERNAL_SCRIPTS=hubot-help,hubot-seen,hubot-links,hubot-diagnostics + links: + - 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 -- GitLab From 2435165feffdcdcf9aed4c4357c2cf6ae4e255fb Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 2 Dec 2015 18:29:56 -0200 Subject: [PATCH 0661/1338] Create page to manage assets and change favicons --- .meteor/packages | 1 + .meteor/versions | 1 + i18n/en.i18n.json | 5 + .../rocketchat-assets/.npm/package/.gitignore | 1 + .../rocketchat-assets/.npm/package/README | 7 + .../.npm/package/npm-shrinkwrap.json | 7 + packages/rocketchat-assets/package.js | 28 +++ .../rocketchat-assets/server/assets.coffee | 165 ++++++++++++++++++ .../server/startup.coffee | 3 + .../server/functions/settings.coffee | 13 ++ .../assets/stylesheets/base.less | 39 +++++ .../rocketchat-ui-admin/admin/admin.coffee | 30 ++++ packages/rocketchat-ui-admin/admin/admin.html | 25 +++ .../rocketchat-ui-master/master/main.html | 14 +- 14 files changed, 332 insertions(+), 7 deletions(-) create mode 100644 packages/rocketchat-assets/.npm/package/.gitignore create mode 100644 packages/rocketchat-assets/.npm/package/README create mode 100644 packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json create mode 100644 packages/rocketchat-assets/package.js create mode 100644 packages/rocketchat-assets/server/assets.coffee diff --git a/.meteor/packages b/.meteor/packages index 5dd240ea647..e64873f3d2a 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -123,3 +123,4 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter +rocketchat:assets diff --git a/.meteor/versions b/.meteor/versions index 44db73cc5ff..8c88fab5cc1 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -122,6 +122,7 @@ reactive-dict@1.1.3 reactive-var@1.0.6 reload@1.1.4 retry@1.0.4 +rocketchat:assets@0.0.1 rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 rocketchat:channel-settings@0.0.1 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index fd9b9d2b84f..9dc586d6867 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -168,10 +168,14 @@ "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).", + "Invalid_asset" : "Invalid asset", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_Secret_URL" : "Invalid Secret URL", "Invalid_secret_URL_message" : "The URL provided is invalid.", "Invalid_email" : "The e-mail entered is invalid", + "Invalid_file_height" : "Invalid file height", + "Invalid_file_type" : "Invalid file type", + "Invalid_file_width" : "Invalid file width", "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", @@ -419,6 +423,7 @@ "Unread_Rooms" : "Unread Rooms", "Unread_Rooms_Mode" : "Unread Rooms Mode", "Upload_file_question" : "Upload file?", + "Uploading_file" : "Uploading file...", "Use_Emojis" : "Use Emojis", "Use_initials_avatar" : "Use your username initials", "use_menu" : "Use the side menu to access your rooms and chats", diff --git a/packages/rocketchat-assets/.npm/package/.gitignore b/packages/rocketchat-assets/.npm/package/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/packages/rocketchat-assets/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/rocketchat-assets/.npm/package/README b/packages/rocketchat-assets/.npm/package/README new file mode 100644 index 00000000000..3d492553a43 --- /dev/null +++ b/packages/rocketchat-assets/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json new file mode 100644 index 00000000000..f69e18d8fe1 --- /dev/null +++ b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "image-size": { + "version": "0.4.0" + } + } +} diff --git a/packages/rocketchat-assets/package.js b/packages/rocketchat-assets/package.js new file mode 100644 index 00000000000..e5f75eaf3d2 --- /dev/null +++ b/packages/rocketchat-assets/package.js @@ -0,0 +1,28 @@ +Package.describe({ + name: 'rocketchat:assets', + version: '0.0.1', + summary: '', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'underscore', + 'webapp', + 'rocketchat:file', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('server/assets.coffee', 'server'); +}); + +Npm.depends({ + "image-size": "0.4.0" +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-assets/server/assets.coffee b/packages/rocketchat-assets/server/assets.coffee new file mode 100644 index 00000000000..acf9d258456 --- /dev/null +++ b/packages/rocketchat-assets/server/assets.coffee @@ -0,0 +1,165 @@ +sizeOf = Npm.require 'image-size' + + +@RocketChatAssetsInstance = new RocketChatFile.GridFS + name: 'assets' + + +assets = + 'favicon.ico': + label: 'favicon.ico' + defaultUrl: 'favicon.ico?v=3' + constraints: + type: 'image' + contentType: 'image/vnd.microsoft.icon' + extention: 'ico' + width: undefined + height: undefined + 'favicon.svg': + label: 'favicon.svg' + defaultUrl: '/images/logo/icon.svg?v=3' + constraints: + type: 'image' + contentType: 'image/svg+xml' + extention: 'svg' + width: undefined + height: undefined + 'favicon_64.png': + label: 'favicon.png (64x64)' + defaultUrl: 'images/logo/favicon-64x64.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 64 + height: 64 + 'favicon_96.png': + label: 'favicon.png (96x96)' + defaultUrl: 'images/logo/favicon-96x96.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 96 + height: 96 + 'favicon_128.png': + label: 'favicon.png (128x128)' + defaultUrl: 'images/logo/favicon-128x128.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 128 + height: 128 + 'favicon_192.png': + label: 'favicon.png (192x192)' + defaultUrl: 'images/logo/android-chrome-192x192.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 192 + height: 192 + 'favicon_256.png': + label: 'favicon.png (256x256)' + defaultUrl: 'images/logo/favicon-256x256.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 256 + height: 256 + + +RocketChat.settings.addGroup 'Assets' +for key, value of assets + RocketChat.settings.add "Assets_#{key}", '', { type: 'asset', group: 'Assets', fileConstraints: value.constraints, i18nLabel: value.label, asset: key } + + +Meteor.methods + unsetAsset: (asset) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', "[methods] unsetAsset -> Invalid user" + + hasPermission = RocketChat.authz.hasPermission Meteor.userId(), 'manage-assets' + unless hasPermission + throw new Meteor.Error 'manage-assets-not-allowed', "[methods] unsetAsset -> Manage assets not allowed" + + if not assets[asset]? + throw new Meteor.Error "Invalid_asset" + + RocketChatAssetsInstance.deleteFile asset + RocketChat.settings.clearById "Assets_#{asset}" + + +Meteor.methods + setAsset: (binaryContent, contentType, asset) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', "[methods] setAsset -> Invalid user" + + hasPermission = RocketChat.authz.hasPermission Meteor.userId(), 'manage-assets' + unless hasPermission + throw new Meteor.Error 'manage-assets-not-allowed', "[methods] unsetAsset -> Manage assets not allowed" + + if not assets[asset]? + throw new Meteor.Error "Invalid_asset" + + if contentType isnt assets[asset].constraints.contentType + throw new Meteor.Error "Invalid_file_type" + + file = new Buffer(binaryContent, 'binary') + + if assets[asset].constraints.width? or assets[asset].constraints.height? + dimensions = sizeOf file + + if assets[asset].constraints.width? and assets[asset].constraints.width isnt dimensions.width + throw new Meteor.Error "Invalid_file_width" + + if assets[asset].constraints.height? and assets[asset].constraints.height isnt dimensions.height + throw new Meteor.Error "Invalid_file_height" + + rs = RocketChatFile.bufferToStream file + RocketChatAssetsInstance.deleteFile asset + ws = RocketChatAssetsInstance.createWriteStream asset, contentType + ws.on 'end', Meteor.bindEnvironment -> + Meteor.setTimeout -> + RocketChat.settings.updateById "Assets_#{asset}", "/assets/#{asset}" + , 200 + + rs.pipe ws + return + + +WebApp.connectHandlers.use '/assets/', (req, res, next) -> + params = + asset: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) + + file = RocketChatAssetsInstance.getFileWithReadStream params.asset + + # res.setHeader 'Content-Disposition', 'inline' + + if not file? + if assets[params.asset]?.defaultUrl? + res.writeHead 301, + Location: Meteor.absoluteUrl(assets[params.asset].defaultUrl) + else + res.writeHead 404 + res.end() + return + + reqModifiedHeader = req.headers["if-modified-since"]; + if reqModifiedHeader? + if reqModifiedHeader == file.uploadDate?.toUTCString() + res.setHeader 'Last-Modified', reqModifiedHeader + res.writeHead 304 + res.end() + return + + res.setHeader 'Cache-Control', 'public, max-age=0' + res.setHeader 'Expires', '-1' + res.setHeader 'Last-Modified', file.uploadDate?.toUTCString() or new Date().toUTCString() + res.setHeader 'Content-Type', file.contentType + res.setHeader 'Content-Length', file.length + + file.readStream.pipe res + return diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index a938b289c01..e1b57d541e7 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -89,6 +89,9 @@ Meteor.startup -> { _id: 'access-permissions', roles : ['admin']} + + { _id: 'manage-assets', + roles : ['admin']} ] #alanning:roles diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 02ade134fca..34f829a6d9d 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -91,6 +91,19 @@ RocketChat.settings.updateById = (_id, value) -> return RocketChat.models.Settings.updateValueById _id, value +### +# Update a setting by id +# @param {String} _id +### +RocketChat.settings.clearById = (_id) -> + # console.log '[functions] RocketChat.settings.clearById -> '.green, 'arguments:', arguments + + if not _id? + return false + + return RocketChat.models.Settings.updateValueById _id, undefined + + ### # Update a setting by id ### diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index bfa3d0bf261..a46ab872cad 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1729,6 +1729,45 @@ a.github-fork { width: 100%; padding: 0; } + + .settings-file-preview { + display: flex; + align-items: center; + + input[type=file] { + position: absolute !important; + width: 100%; + top: 0; + left: 0; + height: 100%; + opacity: 0; + z-index: 10000; + cursor: pointer; + * { + cursor: pointer; + } + } + + .preview { + height: 50px; + width: 100px; + border-radius: 4px; + overflow: hidden; + box-shadow: 0 0 1px rgba(0,0,0,.5) inset; + background-size: contain; + background-position: center center; + background-repeat: no-repeat; + + &.no-file { + background-color: #fafafa; + display: flex; + align-items: center; + justify-content: center; + color: #ccc; + font-size: 24px; + } + } + } } .page-static { diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index f74cc51206a..fe0aeea2948 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -40,6 +40,9 @@ Template.admin.helpers selectedOption: (_id, val) -> return RocketChat.settings.get(_id) is val + random: -> + return Random.id() + Template.admin.events "click .submit .save": (e, t) -> group = FlowRouter.getParam('group') @@ -100,6 +103,33 @@ Template.admin.events swal config, -> Meteor.call 'removeOAuthService', name + "click .delete-asset": -> + Meteor.call 'unsetAsset', @asset + + "change input[type=file]": -> + e = event.originalEvent or event + files = e.target.files + if not files or files.length is 0 + files = e.dataTransfer?.files or [] + + for blob in files + toastr.info TAPi18n.__ 'Uploading_file' + + if @fileConstraints.contentType isnt blob.type + toastr.error 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 + return + + toastr.success TAPi18n.__ 'File_uploaded' + Template.admin.onRendered -> Tracker.afterFlush -> diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index f8152fc11a6..a13f52cb1b0 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -43,13 +43,16 @@ <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> {{/if}} {{/if}} + {{#if $eq type 'int'}} <input type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> {{/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> {{/if}} + {{#if $eq type 'select'}} <select name="{{_id}}"> {{#each values}} @@ -57,9 +60,31 @@ {{/each}} </select> {{/if}} + {{#if $eq type 'color'}} <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> {{/if}} + + {{#if $eq type 'asset'}} + {{#if value}} + <div class="settings-file-preview"> + <div class="preview" style="background-image:url({{value}}?_dc={{random}});"></div> + <div class="action"> + <button type="button" class="button red delete-asset"><i class="icon-trash"></i>{{_ 'Delete'}}</button> + </div> + </div> + {{else}} + <div class="settings-file-preview"> + <div class="preview no-file"><i class="icon-upload"></i></div> + <div class="action"> + <div class="button primary"><i class="icon-trash"></i>{{_ 'Select_file'}} + <input type="file" accept="{{fileConstraints.contentType}}" /> + </div> + </div> + </div> + {{/if}} + {{/if}} + {{#if description}} <div class="settings-description">{{{description}}}</div> {{/if}} diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index 68b8c7ccb27..4219a22d722 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -13,18 +13,18 @@ <meta name="msapplication-config" content="/images/logo/browserconfig.xml?v=3"> <meta name="theme-color" content="#04436a"> <link rel="manifest" href="/images/logo/manifest.json?v=3"> - <link rel="icon" sizes="any" type="image/svg+xml" href="/images/logo/icon.svg?v=3"> - <link rel="icon" sizes="256x256" type="image/png" href="/images/logo/favicon-256x256.png?v=3"> - <link rel="icon" sizes="192x192" type="image/png" href="/images/logo/android-chrome-192x192.png?v=3"> - <link rel="icon" sizes="128x128" type="image/png" href="/images/logo/favicon-128x128.png?v=3"> - <link rel="icon" sizes="96x96" type="image/png" href="/images/logo/favicon-96x96.png?v=3"> - <link rel="icon" sizes="64x64" type="image/png" href="/images/logo/favicon-64x64.png?v=3"> + <link rel="icon" sizes="any" type="image/svg+xml" href="/assets/favicon.svg?v=3"> + <link rel="icon" sizes="256x256" type="image/png" href="/assets/favicon_256.png?v=3"> + <link rel="icon" sizes="192x192" type="image/png" href="/assets/favicon_192.png?v=3"> + <link rel="icon" sizes="128x128" type="image/png" href="/assets/favicon_128.png?v=3"> + <link rel="icon" sizes="96x96" type="image/png" href="/assets/favicon_96.png?v=3"> + <link rel="icon" sizes="64x64" type="image/png" href="/assets/favicon_64.png?v=3"> <!-- <link rel="icon" sizes="48x48" type="image/png" href="/images/logo/favicon-48x48.png?v=3"> <link rel="icon" sizes="32x32" type="image/png" href="/images/logo/favicon-32x32.png?v=3"> <link rel="icon" sizes="16x16" type="image/png" href="/images/logo/favicon-16x16.png?v=3"> --> - <link rel="shortcut icon" sizes="16x16 32x32 48x48" type="image/x-icon" href="/favicon.ico?v=3" /> + <link rel="shortcut icon" sizes="16x16 32x32 48x48" type="image/x-icon" href="/assets/favicon.ico?v=3" /> <link rel="apple-touch-icon" sizes="57x57" href="/images/logo/apple-touch-icon-57x57.png?v=3"> <link rel="apple-touch-icon" sizes="60x60" href="/images/logo/apple-touch-icon-60x60.png?v=3"> <link rel="apple-touch-icon" sizes="72x72" href="/images/logo/apple-touch-icon-72x72.png?v=3"> -- GitLab From fd88b2453d0cb66061795454f3bfa1660aac2766 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 3 Dec 2015 01:02:00 -0200 Subject: [PATCH 0662/1338] Initial tests with rate limiting functions --- .meteor/packages | 1 + packages/rocketchat-lib/package.js | 2 ++ .../server/functions/setUsername.coffee | 13 +++++++++ .../server/lib/RateLimiter.coffee | 28 +++++++++++++++++++ .../server/methods/setUsername.coffee | 14 +++++----- 5 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 packages/rocketchat-lib/server/lib/RateLimiter.coffee diff --git a/.meteor/packages b/.meteor/packages index e64873f3d2a..2eca93df9b9 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -25,6 +25,7 @@ meteor-base mobile-experience mongo random +rate-limit reactive-dict reactive-var reload diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 253ef074f5e..3d150e39dd3 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -8,6 +8,7 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); + api.use('rate-limit'); api.use('reactive-var'); api.use('reactive-dict'); api.use('coffeescript'); @@ -30,6 +31,7 @@ Package.onUse(function(api) { api.addFiles('lib/slashCommand.coffee'); // SERVER LIB + api.addFiles('server/lib/RateLimiter.coffee', 'server'); api.addFiles('server/lib/roomTypes.coffee', 'server'); // SERVER MODELS diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index af8a0ad2def..24209457efa 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -1,4 +1,10 @@ RocketChat.setUsername = (user, username) -> + unless RocketChat.RateLimiter.check('RocketChat.setUsername', user) + return false + + console.log 'RocketChat.setUsername' + return true + username = s.trim username if not user or not username return false @@ -44,3 +50,10 @@ RocketChat.setUsername = (user, username) -> RocketChat.models.Users.setUsername user._id, username user.username = username return user + +RocketChat.RateLimiter.addRule + type: 'function' + name: 'RocketChat.setUsername' + params: (user) -> + return true +, 1, 60000 diff --git a/packages/rocketchat-lib/server/lib/RateLimiter.coffee b/packages/rocketchat-lib/server/lib/RateLimiter.coffee new file mode 100644 index 00000000000..5ec8e453f73 --- /dev/null +++ b/packages/rocketchat-lib/server/lib/RateLimiter.coffee @@ -0,0 +1,28 @@ +RocketChat.RateLimiter = new class + constructor: -> + @rateLimiter = new RateLimiter() + + getErrorMessage: (rateLimitResult) -> + return "Error, too many requests. Please slow down. You must wait #{Math.ceil(rateLimitResult.timeToReset / 1000)} seconds before trying again." + + addRule: (matcher, numRequests, timeInterval) -> + if matcher.type isnt 'function' + return DDPRateLimiter.addRule matcher, numRequests, timeInterval + else + return @rateLimiter.addRule matcher, numRequests, timeInterval + + check: (functionName, params) -> + match = + type: "function", + name: functionName + params: params + + @rateLimiter.increment(match) + + rateLimitResult = @rateLimiter.check(match) + unless rateLimitResult.allowed + console.log @getErrorMessage(rateLimitResult) + return rateLimitResult.allowed + + getRules: -> + return @rateLimiter.rules diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 2132d7edf5f..e2f86b2c4bf 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -30,10 +30,10 @@ Meteor.methods return username # Limit setting username once per minute -DDPRateLimiter.addRule - type: 'method' - name: 'setUsername' - userId: (userId) -> - # Administrators have permission to change others usernames, so don't limit those - return not RocketChat.authz.hasPermission( userId, 'edit-other-user-info') -, 1, 60000 +# DDPRateLimiter.addRule +# type: 'method' +# name: 'setUsername' +# userId: (userId) -> +# # Administrators have permission to change others usernames, so don't limit those +# return not RocketChat.authz.hasPermission( userId, 'edit-other-user-info') +# , 1, 60000 -- GitLab From 85155645f83ce6a793ed8fbbea7f7b1078cb8258 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 01:02:36 -0200 Subject: [PATCH 0663/1338] bump version of sandstorm SPK --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 7d5e7251399..e3528fc7174 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -21,7 +21,7 @@ const pkgdef :Spk.PackageDefinition = ( appVersion = 1, # Increment this for every release. - appMarketingVersion = (defaultText = "0.6"), + appMarketingVersion = (defaultText = "0.7.2445"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. -- GitLab From 347bb74ec7f6a3f3304a299f6d242214a1888701 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 01:16:41 -0200 Subject: [PATCH 0664/1338] formatting rtf.less file to match base.less --- .../assets/stylesheets/rtl.less | 469 ++++++++---------- 1 file changed, 211 insertions(+), 258 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 7611f60fa52..6f72a6c62f1 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -1,259 +1,212 @@ -.rtl -{ - direction: rtl; - - // Mix-ins - .right(@right) { - right: @right; - left: auto; - } - - .left (@left) { - left: @left; - right: auto; - } - - .margin-right(@margin-right) { - margin-right: @margin-right; - margin-left: auto; - } - - .margin-left(@margin-left) { - margin-left: @margin-left; - margin-right: auto; - } - - .padding-right(@padding-right) { - padding-right: @padding-right; - padding-left: 0px; - } - - .padding-left(@padding-left) { - padding-left: @padding-left; - padding-right: 0px; - } - - .side-nav { - .right(0px); - - .header { - .right(0px); - - .account-box { - .info { - padding: 10px 18px 10px 0px; - - .thumb { - float: right; - } - .thumb:after { - .right(-14px); - } - - .data { - float: right; - padding: 0 10px 0 25px; - - .wrp { - text-align: right; - } - } - } - - .options { - .right(0px); - - .status { - .padding-right(38px); - } - - span.soon { - .left(-30px); - } - - .status:after { - .right(18px); - } - } - .options._hidden { - transform: translateX(100%); - } - - } - } - - > .arrow { - .left(8px); - } - - .arrow { - transform: rotateY(180deg); - } - - .flex-nav { - .right(0px); - } - - .flex-nav.animated-hidden { - transform: translateX(100%); - } - - .footer { - .right(0px); - } - - .rooms-list { - > .wrapper { - direction: rtl; - .padding-right(8px); - - h3.add-room - { - i { - .left(6px); - } - } - - h3 { - .padding-right(10px); - } - - ul a { - padding: 6px 6px 7px 25px; - } - } - } - - .more { - padding: 4px 10px 4px 0px; - } - .empty { - .padding-right(10px); - } - - ul .opt { - .left(0px); - .padding-left(10px); - } - - .flex-nav { - > section { - .right(0px); - } - - header { - .right(0px); - .padding-right(15px); - - > div { - text-align: right; - } - } - - .content { - > .wrapper { - direction: rtl; - } - } - .input-submit { - margin: 35px -4px 0 0px; - } - - .button:before { - .right(0px); - } - - footer { - .right(0px); - text-align: right; - - > div { - text-align: right; - } - } - } - } - - .side-nav:before { - .right(8px); - } - - .main-content { - .margin-right(260px); - } - - .messages-box { - margin: 60px 0px 20px 0px; - - .message { - padding-right: 50px; - padding-left: 50px; - margin: 12px 20px 5px 20px; - .thumb { - .right(0px); - } - } - - .message.new-day { - margin-top: 60px; - } - .message.sequential { - .info { - .right(-15px); - .edited, .time { - float: left; - } - .edit-message { - float: right; - .margin-right(5px); - } - } - - .message.with-thumb .time { - .right(4px); - } - - .time-single { - .right(-15px); - } - } - - } - - .messages-container { - .message-form { - > div { - > .file { - border: 1px; - border-radius: 0 5px 5px 0; - border-left: none; - border-right: solid; - } - } - textarea { - padding-left: 38px; - padding-right: 8px; - border-radius: 5px 0 0 5px; - text-align: right; - } - >.users-typing { - float: right; - } - } - - > .formatting-tips { - float: left; - } - .icon-paper-plane { - .left(10px); - transform: rotateY(180deg); - } - } - - q { - .padding-right(10px); - } - q:before { - .right(50px); - } +.rtl { + direction: rtl; + // Mix-ins + .right(@right) { + right: @right; + left: auto; + } + .left (@left) { + left: @left; + right: auto; + } + .margin-right(@margin-right) { + margin-right: @margin-right; + margin-left: auto; + } + .margin-left(@margin-left) { + margin-left: @margin-left; + margin-right: auto; + } + .padding-right(@padding-right) { + padding-right: @padding-right; + padding-left: 0px; + } + .padding-left(@padding-left) { + padding-left: @padding-left; + padding-right: 0px; + } + .side-nav { + .right(0px); + .header { + .right(0px); + .account-box { + .info { + padding: 10px 18px 10px 0px; + .thumb { + float: right; + } + .thumb:after { + .right(-14px); + } + .data { + float: right; + padding: 0 10px 0 25px; + .wrp { + text-align: right; + } + } + } + .options { + .right(0px); + .status { + .padding-right(38px); + } + span.soon { + .left(-30px); + } + .status:after { + .right(18px); + } + } + .options._hidden { + transform: translateX(100%); + } + } + } + > .arrow { + .left(8px); + } + .arrow { + transform: rotateY(180deg); + } + .flex-nav { + .right(0px); + } + .flex-nav.animated-hidden { + transform: translateX(100%); + } + .footer { + .right(0px); + } + .rooms-list { + > .wrapper { + direction: rtl; + .padding-right(8px); + h3.add-room { + i { + .left(6px); + } + } + h3 { + .padding-right(10px); + } + ul a { + padding: 6px 6px 7px 25px; + } + } + } + .more { + padding: 4px 10px 4px 0px; + } + .empty { + .padding-right(10px); + } + ul .opt { + .left(0px); + .padding-left(10px); + } + .flex-nav { + > section { + .right(0px); + } + header { + .right(0px); + .padding-right(15px); + > div { + text-align: right; + } + } + .content { + > .wrapper { + direction: rtl; + } + } + .input-submit { + margin: 35px -4px 0 0px; + } + .button:before { + .right(0px); + } + footer { + .right(0px); + text-align: right; + > div { + text-align: right; + } + } + } + } + .side-nav:before { + .right(8px); + } + .main-content { + .margin-right(260px); + } + .messages-box { + margin: 60px 0px 20px 0px; + .message { + padding-right: 50px; + padding-left: 50px; + margin: 12px 20px 5px 20px; + .thumb { + .right(0px); + } + } + .message.new-day { + margin-top: 60px; + } + .message.sequential { + .info { + .right(-15px); + .edited, + .time { + float: left; + } + .edit-message { + float: right; + .margin-right(5px); + } + } + .message.with-thumb .time { + .right(4px); + } + .time-single { + .right(-15px); + } + } + } + .messages-container { + .message-form { + > div { + > .file { + border: 1px; + border-radius: 0 5px 5px 0; + border-left: none; + border-right: solid; + } + } + textarea { + padding-left: 38px; + padding-right: 8px; + border-radius: 5px 0 0 5px; + text-align: right; + } + >.users-typing { + float: right; + } + } + > .formatting-tips { + float: left; + } + .icon-paper-plane { + .left(10px); + transform: rotateY(180deg); + } + } + q { + .padding-right(10px); + } + q:before { + .right(50px); + } } -- GitLab From 1eb3e6b0a666f7830731f4de366076e43061cfda Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Wed, 2 Dec 2015 22:57:49 -0500 Subject: [PATCH 0665/1338] Many fixes for RTL A lot of fixes for RTL --- .../assets/stylesheets/rtl.less | 212 ++++++++++++++++-- 1 file changed, 196 insertions(+), 16 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 6f72a6c62f1..2d21464f1c8 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -1,30 +1,37 @@ .rtl { direction: rtl; + // Mix-ins .right(@right) { right: @right; left: auto; } + .left (@left) { left: @left; right: auto; } + .margin-right(@margin-right) { margin-right: @margin-right; margin-left: auto; } + .margin-left(@margin-left) { margin-left: @margin-left; margin-right: auto; } + .padding-right(@padding-right) { padding-right: @padding-right; padding-left: 0px; } + .padding-left(@padding-left) { padding-left: @padding-left; padding-right: 0px; } + .side-nav { .right(0px); .header { @@ -79,6 +86,7 @@ .right(0px); } .rooms-list { + direction: ltr; > .wrapper { direction: rtl; .padding-right(8px); @@ -136,12 +144,25 @@ } } } + .side-nav:before { .right(8px); } + .main-content { - .margin-right(260px); + left: 0; + right: @rooms-box-width; + margin-right: unset; + margin-left: 40px; + &.flex-opened { + left: @flex-tab-width; + .flex-tab { + right: unset; + left: 40px + } + } } + .messages-box { margin: 60px 0px 20px 0px; .message { @@ -158,8 +179,7 @@ .message.sequential { .info { .right(-15px); - .edited, - .time { + .edited, .time { float: left; } .edit-message { @@ -175,14 +195,15 @@ } } } + .messages-container { .message-form { > div { > .file { - border: 1px; + border-right-width: 1px; border-radius: 0 5px 5px 0; - border-left: none; - border-right: solid; + border-left-style: none; + border-right-style: solid; } } textarea { @@ -191,22 +212,181 @@ border-radius: 5px 0 0 5px; text-align: right; } - >.users-typing { + > .users-typing { float: right; + } + > .formatting-tips { + float: left; + position: relative; + q { + padding: 0 3px 0 0; + border-right: 3px solid; + border-left: 0px none; + border-right-color: #CCC; + } } } - > .formatting-tips { - float: left; + } + + .account-box { + .options { + direction: ltr; + > .wrapper { + direction: rtl; + } } - .icon-paper-plane { - .left(10px); - transform: rotateY(180deg); + } + + .flex-tab-bar { + left: 0; + right: unset; + border-right: 1px solid #eaeaea; + border-left: none; + z-index: 13; + + .tab-button { + &.active { + margin-right: -1px; + margin-left: unset; + border-left: 3px solid #ff0000; + border-right: unset; + } + } + } + + .flex-tab { + border-left: unset; + border-right: 1px solid; + right: unset; + left: 0; + .transform(translateX(-100%)); + .control { + text-align: right; + padding: 12px 30px 12px; + > a, + > form { + float: right; + } } } - q { - .padding-right(10px); + + .input-line { + &.search { + .octicon { + left: unset; + right: 10px; + } + input { + padding-left: unset; + padding-right: 20px; + } + } + } + + .user-image { + .avatar { + &:after { + left: unset; + right: -12px; + } + } + } + .lines .user-image { + a { + > div { + float: right; + } + } + p { + float: right; + padding-right: 10px; + padding-left: unset; + } } - q:before { - .right(50px); + + .user-view { + .thumb { + float: right; + } + nav { + margin-left: unset; + margin-right: -4px; + .back { + float: left; + } + } + .info { + margin-left: unset; + margin-right: 120px; + } + .stats { + li { + border-right: unset; + border-left: 2px; + } + } + } + + @media all and(max-width: 1100px) { + #rocket-chat { + .flex-opened { + left: 0; + right: @rooms-box-width; + } + } + } + + @media all and(max-width: 780px) { + #rocket-chat { + .main-content { + right: 0; + } + .fixed-title h2 { + margin-right: 45px; + } + &.menu-opened { + .burger { + i { + &:nth-child(1) { + .transform(translateY(3px) rotate(45deg)); + } + &:nth-child(3) { + .transform(translateY(-3px) rotate(-45deg)); + } + } + } + .main-content { + .transform(translateX(-@rooms-box-width)); + } + } + } + } + + .burger { + margin-right: 7px; + margin-left: unset; + right: 0px; + left: unset; + .unread-burger-alert { + left: 4px; + right: unset; + } + } + + #swipebox-close { + left: 0; + right: unset; + } + + @media screen and (min-width:800px) { + #swipebox-close { + left: 10px; + right: unset; + } } + + + /* Overridding the icons code to suit RTL languages */ + .octicon-chevron-right:before { content: '\f0a4'} + .icon-angle-right:before { content: '\e914'; } } -- GitLab From 970cf1ea97096b48f530631327256b28a23c44ef Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Thu, 3 Dec 2015 02:51:59 -0500 Subject: [PATCH 0666/1338] Attempt to optimize sandstorm build Reduce build time --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7b0fd1c697..de0727cc875 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,8 @@ script: - cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install - cd $TRAVIS_BUILD_DIR/.sandstorm - sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp -- ./build.sh +- 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 $TRAVIS_BUILD_DIR/rocket.chat.latest.spk - cd $TRAVIS_BUILD_DIR -- GitLab From 28d20de10d11226ecdf20696430d1bb78b41fc02 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 11:23:56 -0200 Subject: [PATCH 0667/1338] remove default value of ROOT_URL at app.json --- app.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app.json b/app.json index d3622bda772..5bf31ee1de0 100644 --- a/app.json +++ b/app.json @@ -8,8 +8,7 @@ "env": { "BUILDPACK_URL": "https://github.com/RocketChat/heroku-buildpack-meteor.git", "ROOT_URL": { - "description": "IMPORTANT! Please replace <App Name> with the value provided on the top. This will be the full URL of your Rocket.Chat app.", - "value": "https://<App Name>.herokuapp.com" + "description": "IMPORTANT! Please fill with https://<App Name>.herokuapp.com. Replace <App Name> with the value you provided on the top. This will be the full URL of your Rocket.Chat app.", } }, "addons": [ -- GitLab From cd67413544d434fa89703d1bfa7bff08b6d7ee4f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 11:27:28 -0200 Subject: [PATCH 0668/1338] typo --- app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.json b/app.json index 5bf31ee1de0..7bebc1473a6 100644 --- a/app.json +++ b/app.json @@ -8,7 +8,7 @@ "env": { "BUILDPACK_URL": "https://github.com/RocketChat/heroku-buildpack-meteor.git", "ROOT_URL": { - "description": "IMPORTANT! Please fill with https://<App Name>.herokuapp.com. Replace <App Name> with the value you provided on the top. This will be the full URL of your Rocket.Chat app.", + "description": "IMPORTANT! Please fill with https://<App Name>.herokuapp.com. Replace <App Name> with the value you provided on the top. This will be the full URL of your Rocket.Chat app." } }, "addons": [ -- GitLab From c3729bb5eb584a839a94be2d7888a5f5eae37121 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 11:33:45 -0200 Subject: [PATCH 0669/1338] better message for Heroku app.json --- app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.json b/app.json index 7bebc1473a6..fa60f6fbab7 100644 --- a/app.json +++ b/app.json @@ -8,7 +8,7 @@ "env": { "BUILDPACK_URL": "https://github.com/RocketChat/heroku-buildpack-meteor.git", "ROOT_URL": { - "description": "IMPORTANT! Please fill with https://<App Name>.herokuapp.com. Replace <App Name> with the value you provided on the top. This will be the full URL of your Rocket.Chat app." + "description": "IMPORTANT! Must be 'https://<App Name>.herokuapp.com' Replace <App Name> with the value you provided at the top. This will be the full URL of your Rocket.Chat." } }, "addons": [ -- GitLab From 4bc2458fe914ca0565a52b49405db6c0e110b9c3 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Thu, 3 Dec 2015 08:37:00 -0500 Subject: [PATCH 0670/1338] Distinguish Deployment from Development Install Hoping to ease tedious support nightmares --- README.md | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index db9a23a86ce..677f275c0c4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ The Ultimate Open Source WebChat Platform * [Mobile apps](#mobile-apps) * [Desktop apps](#desktop-apps) * [Deployment](#deployment) - * [Development Installation](#development-installation) * [Heroku](#heroku) * [Sandstorm.io](#sandstormio) * [Sloppy.io](#sloppyio) @@ -23,6 +22,7 @@ The Ultimate Open Source WebChat Platform * [Documentation](#documentation) * [License](#license) * [Development](#development) + * [Installation](#installation) * [Branching Model](#branching-model) * [Translations](#translations) * [Community](#community) @@ -55,27 +55,6 @@ Now compatible with all Android devices as old as version 4.0.x - [download here # Deployment `Host your own Rocket.Chat server in four seconds flat` -## Development Installation -Prerequisites: - -* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* [Meteor](https://www.meteor.com/install) - -Now just clone and start the app: - -```sh -git clone https://github.com/RocketChat/Rocket.Chat.git -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 -``` ## 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) @@ -254,8 +233,34 @@ Note that Rocket.Chat is distributed under the [MIT License](http://opensource.o # Development + +## Installation +Prerequisites: + +* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [Meteor](https://www.meteor.com/install) + +Now just clone and start the app: + +```sh +git clone https://github.com/RocketChat/Rocket.Chat.git +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 +``` + ## Branching Model -The [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branching-model/) section below is derived from Vincent Driessen at nvie. + +See [Branches and Releases](https://github.com/RocketChat/Rocket.Chat/wiki/Branches-and-Releases). + +It is based on [Gitflow Workflow](http://nvie.com/posts/a-successful-git-branching-model/), reference section below is derived from Vincent Driessen at nvie. See also this [Git Workflows Comparison](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for more details. -- GitLab From 0b859f62f0c62de2f3983a4131b2b9a9f8537253 Mon Sep 17 00:00:00 2001 From: Kristjan Kullerkann <litewhatever@gmail.com> Date: Thu, 3 Dec 2015 17:11:39 +0200 Subject: [PATCH 0671/1338] Added option to disable "Forgot Password" link on login page. --- i18n/en.i18n.json | 1 + packages/rocketchat-lib/server/startup/settings.coffee | 2 ++ packages/rocketchat-ui-login/login/form.coffee | 3 +++ packages/rocketchat-ui-login/login/form.html | 2 ++ 4 files changed, 8 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9dc586d6867..ed6fdf939d9 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -57,6 +57,7 @@ "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_PasswordReset" : "Password Reset", "Accounts_Enrollment_Email" : "Enrollment E-mail", "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Activate" : "Activate", diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 71c8244136c..b5ac283749b 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -12,6 +12,8 @@ RocketChat.settings.add 'Accounts_RegistrationForm_SecretURL', Random.id(), { ty 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' } diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 2a74b14ccfe..52ef48d4bcb 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -57,6 +57,9 @@ Template.loginForm.helpers linkReplacementText: -> return RocketChat.settings.get('Accounts_RegistrationForm_LinkReplacementText') + passwordresetAllowed: -> + return RocketChat.settings.get 'Accounts_PasswordReset' + Template.loginForm.events 'submit #login-card': (event, instance) -> event.preventDefault() diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index ff4d59f903f..575459711cf 100644 --- a/packages/rocketchat-ui-login/login/form.html +++ b/packages/rocketchat-ui-login/login/form.html @@ -45,9 +45,11 @@ {{else}}{{#if linkReplacementText}} {{{linkReplacementText}}} {{/if}}{{/if}} + {{#if passwordresetAllowed}} <div class="forgot-password {{showForgotPasswordLink}}"> <a href="">{{_ 'Forgot_password'}}</a> </div> + {{/if}} {{/if}} <div class="back-to-login {{showBackToLoginLink}}"> <a href="">{{_ 'Back_to_login'}}</a> -- GitLab From 502b80d3d5535ad3e9f6b8fc58cc52cb9fad5d64 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 3 Dec 2015 14:24:32 -0200 Subject: [PATCH 0672/1338] new RocketChat.RateLimiter functions: limitFunction limitMethod --- .../server/functions/setUsername.coffee | 20 +++------ .../server/lib/RateLimiter.coffee | 42 +++++++++---------- .../server/methods/setUsername.coffee | 8 +++- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 24209457efa..3c9a8fd7665 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -1,12 +1,6 @@ -RocketChat.setUsername = (user, username) -> - unless RocketChat.RateLimiter.check('RocketChat.setUsername', user) - return false - - console.log 'RocketChat.setUsername' - return true - +RocketChat._setUsername = (userId, username) -> username = s.trim username - if not user or not username + if not userId or not username return false try @@ -17,6 +11,8 @@ RocketChat.setUsername = (user, username) -> if not nameValidation.test username return false + user = RocketChat.models.Users.findOneById userId + # User already has desired username, return if user.username is username return user @@ -51,9 +47,5 @@ RocketChat.setUsername = (user, username) -> user.username = username return user -RocketChat.RateLimiter.addRule - type: 'function' - name: 'RocketChat.setUsername' - params: (user) -> - return true -, 1, 60000 +RocketChat.setUsername = RocketChat.RateLimiter.limitFunction RocketChat._setUsername, 1, 60000, + 0: (userId) -> return true; return not RocketChat.authz.hasPermission(userId, 'edit-other-user-info') # Administrators have permission to change others usernames, so don't limit those diff --git a/packages/rocketchat-lib/server/lib/RateLimiter.coffee b/packages/rocketchat-lib/server/lib/RateLimiter.coffee index 5ec8e453f73..9ba6f7b92ba 100644 --- a/packages/rocketchat-lib/server/lib/RateLimiter.coffee +++ b/packages/rocketchat-lib/server/lib/RateLimiter.coffee @@ -1,28 +1,26 @@ RocketChat.RateLimiter = new class - constructor: -> - @rateLimiter = new RateLimiter() + limitFunction: (fn, numRequests, timeInterval, matchers) -> + rateLimiter = new RateLimiter() + rateLimiter.addRule matchers, numRequests, timeInterval + return -> + match = {} + args = arguments + _.each matchers, (matcher, key) -> + match[key] = args[key] - getErrorMessage: (rateLimitResult) -> - return "Error, too many requests. Please slow down. You must wait #{Math.ceil(rateLimitResult.timeToReset / 1000)} seconds before trying again." + rateLimiter.increment match + rateLimitResult = rateLimiter.check match + if rateLimitResult.allowed + return fn.apply null, arguments + else + throw new Meteor.Error 'too-many-requests', "Error, too many requests. Please slow down. You must wait #{Math.ceil(rateLimitResult.timeToReset / 1000)} seconds before trying again.", { timeToReset: rateLimitResult.timeToReset } - addRule: (matcher, numRequests, timeInterval) -> - if matcher.type isnt 'function' - return DDPRateLimiter.addRule matcher, numRequests, timeInterval - else - return @rateLimiter.addRule matcher, numRequests, timeInterval - - check: (functionName, params) -> + limitMethod: (methodName, numRequests, timeInterval, matchers) -> match = - type: "function", - name: functionName - params: params - - @rateLimiter.increment(match) + type: 'method' + name: methodName - rateLimitResult = @rateLimiter.check(match) - unless rateLimitResult.allowed - console.log @getErrorMessage(rateLimitResult) - return rateLimitResult.allowed + _.each matchers, (matcher, key) -> + match[key] = matchers[key] - getRules: -> - return @rateLimiter.rules + DDPRateLimiter.addRule match, numRequests, timeInterval diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index e2f86b2c4bf..3e6e88090e8 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -24,7 +24,7 @@ Meteor.methods if not RocketChat.checkUsernameAvailability username throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" - unless RocketChat.setUsername user, username + unless RocketChat.setUsername user._id, username throw new Meteor.Error 'could-not-change-username', "Could not change username" return username @@ -34,6 +34,10 @@ Meteor.methods # type: 'method' # name: 'setUsername' # userId: (userId) -> +# return true # # Administrators have permission to change others usernames, so don't limit those # return not RocketChat.authz.hasPermission( userId, 'edit-other-user-info') -# , 1, 60000 +# , 1, 1000 + +RocketChat.RateLimiter.limitMethod 'setUsername', 1, 1000, + userId: (userId) -> return true -- GitLab From 42a8d4bc6794a51a5f226826244e42137d6fecc7 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 3 Dec 2015 14:36:37 -0200 Subject: [PATCH 0673/1338] Removed commented code --- .../rocketchat-lib/server/methods/setUsername.coffee | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 3e6e88090e8..751d397d23c 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -29,15 +29,5 @@ Meteor.methods return username -# Limit setting username once per minute -# DDPRateLimiter.addRule -# type: 'method' -# name: 'setUsername' -# userId: (userId) -> -# return true -# # Administrators have permission to change others usernames, so don't limit those -# return not RocketChat.authz.hasPermission( userId, 'edit-other-user-info') -# , 1, 1000 - RocketChat.RateLimiter.limitMethod 'setUsername', 1, 1000, userId: (userId) -> return true -- GitLab From 99734329c03dcd889f2a890c97dcb1ced3c807fe Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 16:34:21 -0200 Subject: [PATCH 0674/1338] bump sandstorm appVersion --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index e3528fc7174..685352e67ad 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,7 +19,7 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 1, # Increment this for every release. + appVersion = 2, # Increment this for every release. appMarketingVersion = (defaultText = "0.7.2445"), # Human-readable representation of appVersion. Should match the way you -- GitLab From adcaa85f85213ec3c6c85fa6c0b842487d7186d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 3 Dec 2015 19:58:01 -0200 Subject: [PATCH 0675/1338] Allow packages to register files for theming --- packages/rocketchat-theme/server/server.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 71f76a317fb..1cb6a376e9e 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -32,6 +32,7 @@ WebAppHashing.calculateClientHash = (manifest, includeFilter, runtimeConfigOverr RocketChat.theme = new class variables: {} + packageCallbacks: [] files: [ 'assets/stylesheets/global/_variables.less' 'assets/stylesheets/utils/_emojione.import.less' @@ -71,6 +72,11 @@ RocketChat.theme = new class content.push Assets.getText file for file in @files + for packageCallback in @packageCallbacks + result = packageCallback() + if _.isString result + content.push result + content = content.join '\n' options = @@ -120,5 +126,8 @@ RocketChat.theme = new class return items.join '\n' + addPackageAsset: (cb) -> + @packageCallbacks.push cb + getCss: -> return RocketChat.settings.get 'css' -- GitLab From e46b2269437504276f05f82241d78634d3aa5b5c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 20:11:25 -0200 Subject: [PATCH 0676/1338] code formating --- packages/rocketchat-favico/favico.js | 439 +++++++++++++-------------- 1 file changed, 218 insertions(+), 221 deletions(-) diff --git a/packages/rocketchat-favico/favico.js b/packages/rocketchat-favico/favico.js index 03a68e54c0a..48874d41eec 100644 --- a/packages/rocketchat-favico/favico.js +++ b/packages/rocketchat-favico/favico.js @@ -28,15 +28,15 @@ 'use strict'; opt = (opt) ? opt : {}; var _def = { - bgColor : '#d00', - textColor : '#fff', - fontFamily : 'sans-serif', //Arial,Verdana,Times New Roman,serif,sans-serif,... - fontStyle : 'bold', //normal,italic,oblique,bold,bolder,lighter,100,200,300,400,500,600,700,800,900 - type : 'circle', - position : 'down', // down, up, left, leftup (upleft) - animation : 'slide', - elementId : false, - dataUrl : false, + bgColor: '#d00', + textColor: '#fff', + fontFamily: 'sans-serif', //Arial,Verdana,Times New Roman,serif,sans-serif,... + fontStyle: 'bold', //normal,italic,oblique,bold,bolder,lighter,100,200,300,400,500,600,700,800,900 + type: 'circle', + position: 'down', // down, up, left, leftup (upleft) + animation: 'slide', + elementId: false, + dataUrl: false, win: window }; var _opt, _orig, _h, _w, _canvas, _context, _img, _ready, _lastBadge, _running, _readyCb, _stop, _browser, _animTimeout, _drawTimeout, _doc; @@ -45,13 +45,12 @@ _browser.ff = typeof InstallTrigger != 'undefined'; _browser.chrome = !!window.chrome; _browser.opera = !!window.opera || navigator.userAgent.indexOf('Opera') >= 0; - _browser.ie = /*@cc_on!@*/false; + _browser.ie = /*@cc_on!@*/ false; _browser.safari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; _browser.supported = (_browser.chrome || _browser.ff || _browser.opera); var _queue = []; - _readyCb = function() { - }; + _readyCb = function() {}; _ready = _stop = false; /** * Initialize favico @@ -179,7 +178,7 @@ var run = function() { // apply options for this animation ['type', 'animation', 'bgColor', 'textColor', 'fontFamily', 'fontStyle'].forEach(function(a) { - if ( a in _queue[0].options) { + if (a in _queue[0].options) { _opt[a] = _queue[0].options[a]; } }); @@ -202,7 +201,7 @@ */ var type = {}; var options = function(opt) { - opt.n = (( typeof opt.n) === 'number') ? Math.abs(opt.n | 0) : opt.n; + opt.n = ((typeof opt.n) === 'number') ? Math.abs(opt.n | 0) : opt.n; opt.x = _w * opt.x; opt.y = _h * opt.y; opt.w = _w * opt.w; @@ -251,8 +250,8 @@ _context.stroke(); _context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')'; //_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); - if (( typeof opt.n) === 'number' && opt.n > 999) { - _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000) ) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); + if ((typeof opt.n) === 'number' && opt.n > 999) { + _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000)) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); } else { _context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); } @@ -283,8 +282,8 @@ _context.fillRect(opt.x, opt.y, opt.w, opt.h); _context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')'; //_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); - if (( typeof opt.n) === 'number' && opt.n > 999) { - _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000) ) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); + if ((typeof opt.n) === 'number' && opt.n > 999) { + _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000)) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); } else { _context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); } @@ -295,16 +294,16 @@ * Set badge */ var badge = function(number, opts) { - opts = (( typeof opts) === 'string' ? { - animation : opts + opts = ((typeof opts) === 'string' ? { + animation: opts } : opts) || {}; _readyCb = function() { try { - if ( typeof (number) === 'number' ? (number > 0) : (number !== '')) { + if (typeof(number) === 'number' ? (number > 0) : (number !== '')) { var q = { - type : 'badge', - options : { - n : number + type: 'badge', + options: { + n: number } }; if ('animation' in opts && animation.types['' + opts.animation]) { @@ -314,12 +313,12 @@ q.options.type = '' + opts.type; } ['bgColor', 'textColor'].forEach(function(o) { - if ( o in opts) { + if (o in opts) { q.options[o] = hexToRgb(opts[o]); } }); ['fontStyle', 'fontFamily'].forEach(function(o) { - if ( o in opts) { + if (o in opts) { q.options[o] = opts[o]; } }); @@ -331,7 +330,7 @@ } else { icon.reset(); } - } catch(e) { + } catch (e) { throw new Error('Error setting badge. Message: ' + e.message); } }; @@ -357,7 +356,7 @@ _context.clearRect(0, 0, _w, _h); _context.drawImage(newImg, 0, 0, _w, _h); link.setIcon(_canvas); - } catch(e) { + } catch (e) { throw new Error('Error setting image. Message: ' + e.message); } }; @@ -384,7 +383,7 @@ drawVideo(this); }, false); - } catch(e) { + } catch (e) { throw new Error('Error setting video. Message: ' + e.message); } }; @@ -418,15 +417,14 @@ newVideo.width = _w; newVideo.height = _h; navigator.getUserMedia({ - video : true, - audio : false + video: true, + audio: false }, function(stream) { newVideo.src = URL.createObjectURL(stream); newVideo.play(); drawVideo(newVideo); - }, function() { - }); - } catch(e) { + }, function() {}); + } catch (e) { throw new Error('Error setting webcam. Message: ' + e.message); } }; @@ -448,7 +446,7 @@ try { _context.clearRect(0, 0, _w, _h); _context.drawImage(video, 0, 0, _w, _h); - } catch(e) { + } catch (e) { } _drawTimeout = setTimeout(drawVideo, animation.duration, video); @@ -536,9 +534,9 @@ }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { - r : parseInt(result[1], 16), - g : parseInt(result[2], 16), - b : parseInt(result[3], 16) + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) } : false; } @@ -578,213 +576,213 @@ */ animation.types = {}; animation.types.fade = [{ - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.0 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.0 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.1 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.1 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.2 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.2 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.3 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.3 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.4 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.4 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.5 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.5 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.6 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.6 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.7 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.7 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.8 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.8 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 0.9 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 0.9 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 1.0 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 1.0 }]; animation.types.none = [{ - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 1 }]; animation.types.pop = [{ - x : 1, - y : 1, - w : 0, - h : 0, - o : 1 + x: 1, + y: 1, + w: 0, + h: 0, + o: 1 }, { - x : 0.9, - y : 0.9, - w : 0.1, - h : 0.1, - o : 1 + x: 0.9, + y: 0.9, + w: 0.1, + h: 0.1, + o: 1 }, { - x : 0.8, - y : 0.8, - w : 0.2, - h : 0.2, - o : 1 + x: 0.8, + y: 0.8, + w: 0.2, + h: 0.2, + o: 1 }, { - x : 0.7, - y : 0.7, - w : 0.3, - h : 0.3, - o : 1 + x: 0.7, + y: 0.7, + w: 0.3, + h: 0.3, + o: 1 }, { - x : 0.6, - y : 0.6, - w : 0.4, - h : 0.4, - o : 1 + x: 0.6, + y: 0.6, + w: 0.4, + h: 0.4, + o: 1 }, { - x : 0.5, - y : 0.5, - w : 0.5, - h : 0.5, - o : 1 + x: 0.5, + y: 0.5, + w: 0.5, + h: 0.5, + o: 1 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 1 }]; animation.types.popFade = [{ - x : 0.75, - y : 0.75, - w : 0, - h : 0, - o : 0 + x: 0.75, + y: 0.75, + w: 0, + h: 0, + o: 0 }, { - x : 0.65, - y : 0.65, - w : 0.1, - h : 0.1, - o : 0.2 + x: 0.65, + y: 0.65, + w: 0.1, + h: 0.1, + o: 0.2 }, { - x : 0.6, - y : 0.6, - w : 0.2, - h : 0.2, - o : 0.4 + x: 0.6, + y: 0.6, + w: 0.2, + h: 0.2, + o: 0.4 }, { - x : 0.55, - y : 0.55, - w : 0.3, - h : 0.3, - o : 0.6 + x: 0.55, + y: 0.55, + w: 0.3, + h: 0.3, + o: 0.6 }, { - x : 0.50, - y : 0.50, - w : 0.4, - h : 0.4, - o : 0.8 + x: 0.50, + y: 0.50, + w: 0.4, + h: 0.4, + o: 0.8 }, { - x : 0.45, - y : 0.45, - w : 0.5, - h : 0.5, - o : 0.9 + x: 0.45, + y: 0.45, + w: 0.5, + h: 0.5, + o: 0.9 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 1 }]; animation.types.slide = [{ - x : 0.4, - y : 1, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 1, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.9, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.9, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.9, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.9, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.8, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.8, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.7, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.7, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.6, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.6, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.5, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.5, + w: 0.6, + h: 0.6, + o: 1 }, { - x : 0.4, - y : 0.4, - w : 0.6, - h : 0.6, - o : 1 + x: 0.4, + y: 0.4, + w: 0.6, + h: 0.6, + o: 1 }]; /** * Run animation @@ -796,12 +794,11 @@ animation.run = function(opt, cb, revert, step) { var animationType = animation.types[isPageHidden() ? 'none' : _opt.animation]; if (revert === true) { - step = ( typeof step !== 'undefined') ? step : animationType.length - 1; + step = (typeof step !== 'undefined') ? step : animationType.length - 1; } else { - step = ( typeof step !== 'undefined') ? step : 0; + step = (typeof step !== 'undefined') ? step : 0; } - cb = (cb) ? cb : function() { - }; + cb = (cb) ? cb : function() {}; if ((step < animationType.length) && (step >= 0)) { type[_opt.type](merge(opt, animationType[step])); _animTimeout = setTimeout(function() { @@ -822,25 +819,25 @@ //auto init init(); return { - badge : badge, - video : video, - image : image, - webcam : webcam, - reset : icon.reset, - browser : { - supported : _browser.supported + badge: badge, + video: video, + image: image, + webcam: webcam, + reset: icon.reset, + browser: { + supported: _browser.supported } }; }); // AMD / RequireJS - if ( typeof define !== 'undefined' && define.amd) { + if (typeof define !== 'undefined' && define.amd) { define([], function() { return Favico; }); } // CommonJS - else if ( typeof module !== 'undefined' && module.exports) { + else if (typeof module !== 'undefined' && module.exports) { module.exports = Favico; } // included directly via <script> tag -- GitLab From 5299dc34ce8aaa54143e7397968e361dd8426653 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 3 Dec 2015 20:13:18 -0200 Subject: [PATCH 0677/1338] favico.js update --- packages/rocketchat-favico/favico.js | 68 ++++++++++++++++------------ 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/packages/rocketchat-favico/favico.js b/packages/rocketchat-favico/favico.js index 48874d41eec..17feff3e17e 100644 --- a/packages/rocketchat-favico/favico.js +++ b/packages/rocketchat-favico/favico.js @@ -2,7 +2,7 @@ * @license MIT * @fileOverview Favico animations * @author Miroslav Magda, http://blog.ejci.net - * @version 0.3.9 + * @version 0.3.10 */ /** @@ -68,28 +68,30 @@ var isUp = _opt.position.indexOf('up') > -1; var isLeft = _opt.position.indexOf('left') > -1; - //transform animation + //transform the animations if (isUp || isLeft) { - for (var i = 0; i < animation.types['' + _opt.animation].length; i++) { - var step = animation.types['' + _opt.animation][i]; + for (var a in animation.types) { + for (var i = 0; i < animation.types[a].length; i++) { + var step = animation.types[a][i]; - if (isUp) { - if (step.y < 0.6) { - step.y = step.y - 0.4; - } else { - step.y = step.y - 2 * step.y + (1 - step.w); + if (isUp) { + if (step.y < 0.6) { + step.y = step.y - 0.4; + } else { + step.y = step.y - 2 * step.y + (1 - step.w); + } } - } - if (isLeft) { - if (step.x < 0.6) { - step.x = step.x - 0.4; - } else { - step.x = step.x - 2 * step.x + (1 - step.h); + if (isLeft) { + if (step.x < 0.6) { + step.x = step.x - 0.4; + } else { + step.x = step.x - 2 * step.x + (1 - step.h); + } } - } - animation.types['' + _opt.animation][i] = step; + animation.types[a][i] = step; + } } } _opt.type = (type['' + _opt.type]) ? _opt.type : _def.type; @@ -101,7 +103,6 @@ _img = document.createElement('img'); if (_orig.hasAttribute('href')) { _img.setAttribute('crossOrigin', 'anonymous'); - _img.setAttribute('src', _orig.getAttribute('href')); //get width/height _img.onload = function() { _h = (_img.height > 0) ? _img.height : 32; @@ -111,16 +112,19 @@ _context = _canvas.getContext('2d'); icon.ready(); }; + _img.setAttribute('src', _orig.getAttribute('href')); } else { + _img.onload = function() { + _h = 32; + _w = 32; + _img.height = _h; + _img.width = _w; + _canvas.height = _h; + _canvas.width = _w; + _context = _canvas.getContext('2d'); + icon.ready(); + }; _img.setAttribute('src', ''); - _h = 32; - _w = 32; - _img.height = _h; - _img.width = _w; - _canvas.height = _h; - _canvas.width = _w; - _context = _canvas.getContext('2d'); - icon.ready(); } }; @@ -350,12 +354,14 @@ var newImg = document.createElement('img'); var ratio = (w / _w < h / _h) ? (w / _w) : (h / _h); newImg.setAttribute('crossOrigin', 'anonymous'); + newImg.onload = function() { + _context.clearRect(0, 0, _w, _h); + _context.drawImage(newImg, 0, 0, _w, _h); + link.setIcon(_canvas); + }; newImg.setAttribute('src', imageElement.getAttribute('src')); newImg.height = (h / ratio); newImg.width = (w / ratio); - _context.clearRect(0, 0, _w, _h); - _context.drawImage(newImg, 0, 0, _w, _h); - link.setIcon(_canvas); } catch (e) { throw new Error('Error setting image. Message: ' + e.message); } @@ -449,7 +455,9 @@ } catch (e) { } - _drawTimeout = setTimeout(drawVideo, animation.duration, video); + _drawTimeout = setTimeout(function() { + drawVideo(video); + }, animation.duration); link.setIcon(_canvas); } -- GitLab From 62afae5e2d410a7724a2c0cac44e4b8d0ca46613 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Thu, 3 Dec 2015 18:51:15 -0500 Subject: [PATCH 0678/1338] Better RTL support - Some bug fixes - Additional support --- .../assets/stylesheets/rtl.less | 356 +++++++++++++++--- 1 file changed, 296 insertions(+), 60 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 2d21464f1c8..0c8af2e4567 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -76,9 +76,6 @@ .arrow { transform: rotateY(180deg); } - .flex-nav { - .right(0px); - } .flex-nav.animated-hidden { transform: translateX(100%); } @@ -114,6 +111,7 @@ .padding-left(10px); } .flex-nav { + .right(0px); > section { .right(0px); } @@ -143,6 +141,23 @@ } } } + .search-form { + .search { + .padding-right(25px); + } + .margin-left(20px); + } + h3 { + .padding-right(10px); + &.add-room { + i { + .left(6px); + } + } + } + .unread { + .left(6px); + } } .side-nav:before { @@ -152,51 +167,51 @@ .main-content { left: 0; right: @rooms-box-width; - margin-right: unset; - margin-left: 40px; + .margin-left(40px); &.flex-opened { left: @flex-tab-width; .flex-tab { - right: unset; - left: 40px + .left(40px); } } } .messages-box { - margin: 60px 0px 20px 0px; - .message { - padding-right: 50px; - padding-left: 50px; - margin: 12px 20px 5px 20px; - .thumb { + margin: 60px 0px 0px 20px; + .new-message { + .right(50%); + } + } + + .container-bars { + .upload-progress { + .upload-progress-progress { .right(0px); } - } - .message.new-day { - margin-top: 60px; - } - .message.sequential { - .info { - .right(-15px); - .edited, .time { + .upload-progress-text { + > a { float: left; } - .edit-message { - float: right; - .margin-right(5px); - } - } - .message.with-thumb .time { - .right(4px); } - .time-single { - .right(-15px); + } + .unread-bar { + > a { + float: left; } } } .messages-container { + .right(0); + .edit-room-title { + .margin-right(4px); + } + .wrapper { + .right(0); + } + .footer { + .right(0); + } .message-form { > div { > .file { @@ -238,16 +253,14 @@ } .flex-tab-bar { - left: 0; - right: unset; + .left(0); border-right: 1px solid #eaeaea; border-left: none; z-index: 13; .tab-button { &.active { - margin-right: -1px; - margin-left: unset; + .margin-right(-1px); border-left: 3px solid #ff0000; border-right: unset; } @@ -257,8 +270,7 @@ .flex-tab { border-left: unset; border-right: 1px solid; - right: unset; - left: 0; + .left(0); .transform(translateX(-100%)); .control { text-align: right; @@ -267,18 +279,69 @@ > form { float: right; } + .more { + .right(0); + .transform(translateX(27px)); + } + .search-form { + padding: 0 0 0 4px; + width: 100%; + .icon-plus { + .right(4px); + } + } + .info-tabs { + text-align: left; + .left(20px); + } + } + } + + .flex-opened { + .flex-tab { + .control { + .more { + .transform(translateX(0)); + } + } } } .input-line { &.search { .octicon { - left: unset; - right: 10px; + .right(10px); + } + .icon-spin4 { + .left(5px); + } + .icon-search { + .right(2px); } input { - padding-left: unset; padding-right: 20px; + padding-left: 8px; + text-align: right; + } + } + &.double-col { + > label { + float: right; + .padding-left(20px); + text-align: left; + padding: 10px 0 10px 20px; + } + > div { + float: right; + label { + .margin-left(4px); + &:nth-last-child(1) { + .margin-left(0); + } + input { + .margin-left(4px); + } + } } } } @@ -286,8 +349,7 @@ .user-image { .avatar { &:after { - left: unset; - right: -12px; + .right(-12px); } } } @@ -299,8 +361,7 @@ } p { float: right; - padding-right: 10px; - padding-left: unset; + .padding-right(10px); } } @@ -309,15 +370,13 @@ float: right; } nav { - margin-left: unset; - margin-right: -4px; + .margin-right(-4px); .back { float: left; } } .info { - margin-left: unset; - margin-right: 120px; + .margin-right(120px); } .stats { li { @@ -363,30 +422,207 @@ } .burger { - margin-right: 7px; - margin-left: unset; - right: 0px; - left: unset; + .margin-right(7px); + .right(0px); .unread-burger-alert { - left: 4px; - right: unset; + .left(4px); + } + } + + .arrow { + &:before, + &:after { + .calc(right,~"50% - 5px"); + } + &:before { + .transform(rotate(135deg) translateX(4px)); + } + &:after { + .transform(rotate(-135deg) translateX(4px)); + } + &.left { + &:before { + .transform(rotate(-45deg) translateY(-4px)); + } + &:after { + .transform(rotate(45deg) translateY(4px)); + } + } + &.top { + &:before { + .transform(rotate(45deg) translateX(-2px) translateY(2px)); + } + &:after { + .transform(rotate(-45deg) translateX(2px) translateY(2px)); + } + } + &.bottom { + &:before { + .transform(rotate(-45deg) translateX(-2px) translateY(-2px)); + } + &:after { + .transform(rotate(45deg) translateX(2px) translateY(-2px)); + } + } + &.close { + &:before { + .transform(rotate(-45deg)); + } + &:after { + .transform(rotate(45deg)); + } + } + } + + .message { + padding: 18px 70px 4px 20px; + &.new-day { + margin-top: 60px; + &:before { + .right(0); + .calc(right,~"50% - 70px"); + } + &:after { + .right(0); + .margin-right(2%); + } + } + .message-dropdown { + .right(-2px); + ul { + li { + &:first-child { + padding-right: 6px; + padding-left: 8px; + border-left: 1px solid #eee; + border-right: unset; + } + &:last-child { + padding-left: 13px; + padding-right: 8px; + } + } + } + } + .user { + margin-left: 5px; + margin-right: 0; + } + .thumb { + .right(20px); + } + .info { + .edited { + border-right: 1px dotted #BAB8B8; + border-left: unset; + .padding-right(3px); + .margin-right(3px); + } + } + .private { + .margin-right(10px); // + } + &.sequential { + padding-top: 4px; + .info { + text-align: left; + .right(5px); + .edited { + border-right: 0; + .margin-right(0); + .padding-right(0); + } + .message-action { + float: right; // + .margin-right(1px); // + } + } + } + } + + blockquote { + .padding-right(10px); + &:before { + .right(0px); + } + } + + .first-unread { + .body { + &::before { + right: 20px; + left: 0px; + } + &::after { + .left(0px); + } + } + } + + .ticks-bar { + .left(2px); + } + + .fixed-title { + padding: 0 20px 0 10px; + .right(0); + } + + .list-view { + > .status { + .see-all { + float: left; + } + } + &.uploaded-files-list { + i { + float: right; + .margin-left(10px); + } + } + } + + .page-list { + .list { + a { + .info { + ul { + .margin-right(3px); + } + } + } + .user-image { + float: left; + .margin-right(12px); + } + table { + thead { + th { + text-align: right; + } + } + } + } + } + + .statistics-table { + th, td { + text-align: right; } } + /* Overridding classes from swipebox.min.css */ #swipebox-close { - left: 0; - right: unset; + .left(0); } - @media screen and (min-width:800px) { #swipebox-close { - left: 10px; - right: unset; + .left(10px); } } - - /* Overridding the icons code to suit RTL languages */ + /* Overridding the icons Unicode to suit RTL languages + * from _octicons.less */ .octicon-chevron-right:before { content: '\f0a4'} .icon-angle-right:before { content: '\e914'; } } -- GitLab From 868a09153b63fcc23623e0d401123483976ca53c Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 05:30:39 -0500 Subject: [PATCH 0679/1338] declutter travis.yml --- .sandstorm/buildrc.sh | 19 +++++++++++++++++++ .travis.yml | 16 +--------------- 2 files changed, 20 insertions(+), 15 deletions(-) create mode 100755 .sandstorm/buildrc.sh diff --git a/.sandstorm/buildrc.sh b/.sandstorm/buildrc.sh new file mode 100755 index 00000000000..63e515ed3c7 --- /dev/null +++ b/.sandstorm/buildrc.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -euo pipefail + + +cd /tmp +spk init -p3000 -- nothing +export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) +cd $TRAVIS_BUILD_DIR +export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" +export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle +cd /home/vagrant && tar zxf ./Rocket.Chat.tar.gz +rm ./Rocket.Chat.tar.gz +cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install +cd $TRAVIS_BUILD_DIR/.sandstorm +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 $TRAVIS_BUILD_DIR/rocket.chat.latest.spk diff --git a/.travis.yml b/.travis.yml index de0727cc875..9f0a20fd8fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,22 +48,8 @@ script: - cp ../build/Rocket.Chat.tar.gz /home/vagrant - cd .travis - sh ./namefiles.sh -- cd /tmp -- spk init -p3000 -- nothing -- export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) -- cd $TRAVIS_BUILD_DIR -- export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" -- export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle -#- meteor build --directory /home/vagrant/ -- cd /home/vagrant && tar zxf ./Rocket.Chat.tar.gz -- rm ./Rocket.Chat.tar.gz -- cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install - cd $TRAVIS_BUILD_DIR/.sandstorm -- 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 $TRAVIS_BUILD_DIR/rocket.chat.latest.spk +- sh ./buildrc.sh - cd $TRAVIS_BUILD_DIR - mv rocket.chat.latest.spk ../build deploy: -- GitLab From fd90a80baac2d873fbccd6b0d1b3a8780fdd817c Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 4 Dec 2015 05:38:45 -0500 Subject: [PATCH 0680/1338] declutter travis.yml fold away sandstorm pseudo build --- .sandstorm/buildrc.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.sandstorm/buildrc.sh b/.sandstorm/buildrc.sh index 63e515ed3c7..a9bc628bc31 100755 --- a/.sandstorm/buildrc.sh +++ b/.sandstorm/buildrc.sh @@ -1,6 +1,4 @@ #!/bin/bash -set -euo pipefail - cd /tmp spk init -p3000 -- nothing -- GitLab From 12053cc9658b7d2e534386bfd109e94fd82d2bdd Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 4 Dec 2015 05:57:16 -0500 Subject: [PATCH 0681/1338] fix buildrc.sh escape subst --- .sandstorm/buildrc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/buildrc.sh b/.sandstorm/buildrc.sh index a9bc628bc31..2a43b268fa6 100755 --- a/.sandstorm/buildrc.sh +++ b/.sandstorm/buildrc.sh @@ -2,7 +2,7 @@ cd /tmp spk init -p3000 -- nothing -export SANDSTORM_ID=$(grep '\sid =' sandstorm-pkgdef.capnp) +export SANDSTORM_ID="$(grep '\sid =' sandstorm-pkgdef.capnp)" cd $TRAVIS_BUILD_DIR export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle -- GitLab From 517bd04b3edd8627d8f3b04717ad5dece4f2fe97 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 06:16:35 -0500 Subject: [PATCH 0682/1338] fix buildrc.sh - use bash --- .sandstorm/buildrc.sh | 2 ++ .travis.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.sandstorm/buildrc.sh b/.sandstorm/buildrc.sh index 2a43b268fa6..159c8a83b02 100755 --- a/.sandstorm/buildrc.sh +++ b/.sandstorm/buildrc.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -euo pipefail + cd /tmp spk init -p3000 -- nothing export SANDSTORM_ID="$(grep '\sid =' sandstorm-pkgdef.capnp)" diff --git a/.travis.yml b/.travis.yml index 9f0a20fd8fa..3fe130b61d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,7 +49,7 @@ script: - cd .travis - sh ./namefiles.sh - cd $TRAVIS_BUILD_DIR/.sandstorm -- sh ./buildrc.sh +- ./buildrc.sh - cd $TRAVIS_BUILD_DIR - mv rocket.chat.latest.spk ../build deploy: -- GitLab From a5e239590c8ae8622f1ec61b236d97ac56560572 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 06:46:56 -0500 Subject: [PATCH 0683/1338] declutter travis.yml II --- .sandstorm/preprcbuild.sh | 19 +++++++++++++++++++ .travis.yml | 31 ++----------------------------- 2 files changed, 21 insertions(+), 29 deletions(-) create mode 100755 .sandstorm/preprcbuild.sh diff --git a/.sandstorm/preprcbuild.sh b/.sandstorm/preprcbuild.sh new file mode 100755 index 00000000000..0de70bdc50b --- /dev/null +++ b/.sandstorm/preprcbuild.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -euo pipefail + +export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") +cd /tmp +curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - +export PATH=$PATH:${PWD}/sandstorm-$SANDSTORM_VERSION/bin +sudo mkdir -p /home/vagrant +sudo chown -R travis /home/vagrant +sudo mkdir -p /opt +sudo chown -R travis /opt +cd /opt +curl curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - +ln -s meteor-spk-0.1.8 meteor-spk +cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ +cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +cp -r . /opt/app diff --git a/.travis.yml b/.travis.yml index 3fe130b61d9..6e4da387cea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,41 +6,14 @@ branches: - master node_js: - '0.12' -#addons: -# apt: -# sources: -# - google-chrome -# packages: -# - google-chrome-stable before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' - mkdir -p node_modules -#- npm install phantomjs -#- npm install velocity-cli -#- export PHANTOMJS_BIN=./node_modules/phantomjs/bin/phantomjs -#- export JASMINE_BROWSER=PhantomJS -#- export DEBUG=1 -#- export JASMINE_DEBUG=1 -#- export VELOCITY_DEBUG=1 -#- export VELOCITY_DEBUG_MIRROR=1 -- export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") -- cd /tmp -- curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - -- export PATH=$PATH:${PWD}/sandstorm-$SANDSTORM_VERSION/bin -- sudo mkdir -p /home/vagrant -- sudo chown -R travis /home/vagrant -- sudo mkdir -p /opt -- sudo chown -R travis /opt -- cd /opt -- curl curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - -- ln -s meteor-spk-0.1.8 meteor-spk -- cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ -- cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ -- cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ - cd $TRAVIS_BUILD_DIR - mkdir ../build -- cp -r . /opt/app +- cd .sandstorm +- ./preprcbuild.sh script: - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - export TAG=$(git describe --abbrev=0 --tags) -- GitLab From 84ba8f2aff5c40b7e85f70b90a5dceed2ee7ca4d Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 4 Dec 2015 06:53:10 -0500 Subject: [PATCH 0684/1338] fix typo --- .sandstorm/preprcbuild.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.sandstorm/preprcbuild.sh b/.sandstorm/preprcbuild.sh index 0de70bdc50b..b09a0156cb2 100755 --- a/.sandstorm/preprcbuild.sh +++ b/.sandstorm/preprcbuild.sh @@ -16,4 +16,5 @@ ln -s meteor-spk-0.1.8 meteor-spk cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +cd $TRAVIS_BUILD_DIR cp -r . /opt/app -- GitLab From 0af7464f2f43f634f734a77fe76cfb7556d26d99 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 4 Dec 2015 07:03:42 -0500 Subject: [PATCH 0685/1338] fix typo --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6e4da387cea..722b75720da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ before_install: - cd .sandstorm - ./preprcbuild.sh script: +- cd $TRAVIS_BUILD_DIR - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi - export TAG=$(git describe --abbrev=0 --tags) - meteor build ../build -- GitLab From 36bb64b00127874ac7630feff72ad23658fd7e09 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 4 Dec 2015 10:03:50 -0200 Subject: [PATCH 0686/1338] added livechat flex for more configuration options --- packages/rocketchat-livechat/client/ui.js | 43 +++++++++++------ .../client/views/sideNav/livechatFlex.html | 22 +++++++++ packages/rocketchat-livechat/package.js | 1 + .../side-nav/sideNav.coffee | 3 -- .../side-nav/sideNav.html | 2 +- packages/rocketchat-ui/lib/accountBox.coffee | 46 +++++++++++++------ 6 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index 920d8ca5c55..28591b5d046 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -17,21 +17,36 @@ RocketChat.roomTypes.add('l', 5, { permissions: ['view-l-room'] }); +// 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: 'pageContainer', +// pageTitle: t('Livechat_Manager'), +// pageTemplate: 'livechatManager' +// }); +// } +// }, +// permissions: ['view-livechat-manager'] +// }); + 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: 'pageContainer', - pageTitle: t('Livechat_Manager'), - pageTemplate: 'livechatManager' - }); - } - }, - permissions: ['view-livechat-manager'] + href: 'livechat-manager', + permissions: ['view-livechat-manager'], +}); + +AccountBox.addRoute({ + name: 'livechat-manager', + path: '/livechat-manager', + sideNav: 'livechatFlex', + pageTitle: t('Livechat_Manager'), + pageTemplate: 'livechatManager' }); diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html new file mode 100644 index 00000000000..815010b9fd6 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -0,0 +1,22 @@ +<template name="livechatFlex"> + <header> + <div> + <h4>{{_ "Livechat"}}</h4> + </div> + </header> + <div class="content"> + <div class="wrapper"> + <ul> + <li> + <a href="#link" class="admin-link">{{_ "Dashboard"}}</a> + <a href="#link" class="admin-link">{{_ "User_management"}}</a> + <a href="#link" class="admin-link">{{_ "Departaments"}}</a> + <a href="#link" class="admin-link">{{_ "Queue"}}</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> + </li> + </ul> + </div> + </div> +</template> diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 50bad731694..6c2e212dc27 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -40,6 +40,7 @@ Package.onUse(function(api) { api.addFiles('client/views/app/livechatManager.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'); // methods api.addFiles('server/methods/addAgent.js', 'server'); diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 227023ce43f..0b377ed7aab 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -38,9 +38,6 @@ Template.sideNav.helpers registeredMenus: -> return AccountBox.getItems() - itemPath: -> - FlowRouter.path @route.name - Template.sideNav.events 'click .close-flex': -> SideNav.closeFlex() diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html index 888078c599c..cb6d536bd67 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html @@ -21,7 +21,7 @@ <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> {{#each registeredMenus}} - <a href="{{itemPath}}" class="{{class}}"><i class="{{icon}}"></i><span>{{name}}</span></a> + <a href="{{pathFor href}}"><i class="{{icon}}"></i><span>{{name}}</span></a> {{/each}} {{#if showAdminOption }} <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index ee12f6afec5..801e5ee9504 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -28,16 +28,16 @@ self.box = $(".account-box") self.options = self.box.find(".options") - protectedAction = (item) -> - if not item.permissions? or RocketChat.authz.hasAllPermission item.permissions - return item.route.action + # protectedAction = (item) -> + # if not item.permissions? or RocketChat.authz.hasAllPermission 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' + # return -> + # BlazeLayout.render 'main', + # center: 'pageContainer' + # # @TODO text Not_authorized don't get the correct language + # pageTitle: t('Not_authorized') + # pageTemplate: 'notAuthorized' ### # @param newOption: @@ -52,22 +52,40 @@ actual.push newItem items.set actual - if newItem.route?.path? and newItem.route?.name? and newItem.route?.action? - FlowRouter.route newItem.route.path, - name: newItem.route.name - action: protectedAction newItem - getItems = -> return _.filter items.get(), (item) -> if not item.permissions? or RocketChat.authz.hasAllPermission item.permissions return true + addRoute = (newRoute) -> + + # @TODO check for mandatory fields + + FlowRouter.route newRoute.path, + name: newRoute.name + action: -> + + console.log 'accountBox -> action' + + Session.set 'openedRoom' + BlazeLayout.render 'main', + center: 'pageContainer' + pageTitle: newRoute.pageTitle + pageTemplate: newRoute.pageTemplate + + if newRoute.sideNav? + Tracker.afterFlush -> + SideNav.setFlex newRoute.sideNav + SideNav.openFlex() + + setStatus: setStatus toggle: toggle open: open close: close init: init + addRoute: addRoute addItem: addItem getItems: getItems )() -- GitLab From 3378bd78d0f1a01be8503b93e442c819565a7440 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 07:27:43 -0500 Subject: [PATCH 0687/1338] fix PATH env var --- .sandstorm/preprcbuild.sh | 2 -- .travis.yml | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.sandstorm/preprcbuild.sh b/.sandstorm/preprcbuild.sh index b09a0156cb2..e7ea8528c10 100755 --- a/.sandstorm/preprcbuild.sh +++ b/.sandstorm/preprcbuild.sh @@ -2,10 +2,8 @@ set -euo pipefail -export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") cd /tmp curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - -export PATH=$PATH:${PWD}/sandstorm-$SANDSTORM_VERSION/bin sudo mkdir -p /home/vagrant sudo chown -R travis /home/vagrant sudo mkdir -p /opt diff --git a/.travis.yml b/.travis.yml index 722b75720da..a2ab3dfa3b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,8 @@ before_install: - mkdir -p node_modules - cd $TRAVIS_BUILD_DIR - mkdir ../build +- export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") +- export PATH=$PATH:/tmp/sandstorm-$SANDSTORM_VERSION/bin - cd .sandstorm - ./preprcbuild.sh script: -- GitLab From acf71fe0dcecb3b31518d499de2f2371f4d32d03 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 10:48:49 -0200 Subject: [PATCH 0688/1338] Closes #1469; Remove custom oAuth record when removed from settings --- .../server/startup/oAuthServicesUpdate.coffee | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee index 0c126b370d5..eb796abc309 100644 --- a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee +++ b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee @@ -48,6 +48,12 @@ oAuthServicesUpdate = -> ServiceConfiguration.configurations.remove {service: serviceName.toLowerCase()} , 2000 + +oAuthServicesRemove = (_id) -> + serviceName = _id.replace('Accounts_OAuth_Custom_', '') + ServiceConfiguration.configurations.remove {service: serviceName.toLowerCase()} + + RocketChat.models.Settings.find().observe added: (record) -> if /^Accounts_OAuth_.+/.test record._id @@ -58,5 +64,5 @@ RocketChat.models.Settings.find().observe oAuthServicesUpdate() removed: (record) -> - if /^Accounts_OAuth_.+/.test record._id - oAuthServicesUpdate() + if /^Accounts_OAuth_Custom.+/.test record._id + oAuthServicesRemove record._id -- GitLab From 70b0e919e7e898bd641b2ed1f255261b706ab48d Mon Sep 17 00:00:00 2001 From: Nberton <eternal.pretzel@gmail.com> Date: Fri, 4 Dec 2015 12:27:40 -0500 Subject: [PATCH 0689/1338] Fixed Issue #1468 --- .../server/functions/setUsername.coffee | 12 ++++++++---- .../rocketchat-lib/server/methods/setUsername.coffee | 9 +++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 2e4d5982937..4396303f517 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -1,4 +1,5 @@ RocketChat.setUsername = (user, username) -> + console.log("In setUserName") username = s.trim username if not user or not username return false @@ -10,12 +11,15 @@ RocketChat.setUsername = (user, username) -> if user.username is username return user - # Check username availability - unless RocketChat.checkUsernameAvailability username - return false - previousUsername = user.username + # Check username availability or if the user already owns a different casing of the name + if ( !previousUsername or !(username.toLowerCase() == previousUsername.toLowerCase())) + unless RocketChat.checkUsernameAvailability username + return false + + + # If first time setting username, send Enrollment Email if not previousUsername and RocketChat.settings.get 'Accounts_Enrollment_Email' Accounts.sendEnrollmentEmail(user._id) diff --git a/packages/rocketchat-lib/server/methods/setUsername.coffee b/packages/rocketchat-lib/server/methods/setUsername.coffee index 4ea4a1cce94..1c71fddce72 100644 --- a/packages/rocketchat-lib/server/methods/setUsername.coffee +++ b/packages/rocketchat-lib/server/methods/setUsername.coffee @@ -16,8 +16,13 @@ Meteor.methods if not /^[0-9a-zA-Z-_.]+$/.test username throw new Meteor.Error 'username-invalid', "#{username} is not a valid username, use only letters, numbers, dots and dashes" - if not RocketChat.checkUsernameAvailability username - throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" + if user.username != undefined + if not username.toLowerCase() == user.username.toLowerCase() + if not RocketChat.checkUsernameAvailability username + throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" + else + if not RocketChat.checkUsernameAvailability username + throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" unless RocketChat.setUsername user, username throw new Meteor.Error 'could-not-change-username', "Could not change username" -- GitLab From b3bfaafe2126514b674aa9c6819e3a464fbcf88e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 16:46:16 -0200 Subject: [PATCH 0690/1338] Improve Settings layout --- .../assets/stylesheets/base.less | 67 ++++++++ packages/rocketchat-ui-admin/admin/admin.html | 150 +++++++++--------- 2 files changed, 144 insertions(+), 73 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index a46ab872cad..c877e67b063 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1721,6 +1721,73 @@ a.github-fork { } .page-settings { + .content { + padding: 20px 0; + background-color: #f8f8f8; + color: #444; + + > .info { + max-width: auto; + line-height: 24px; + padding-left: 20px; + font-size: 16px; + font-weight: 500; + } + } + + .section { + border: 1px solid #ddd; + border-left: none; + background-color: #fff; + padding: 20px; + margin-bottom: 20px; + + .section-title { + font-size: 24px; + font-weight: 600; + padding: 10px 0 30px 0; + color: #444; + } + + .section-content { + border: none !important; + border-radius: 0px !important; + padding: 0px !important; + + .input-line { + border-bottom: 1px solid #eee; + padding: 20px 0; + margin-bottom: 0px; + + &:last-child { + border-bottom: none; + padding-bottom: 0; + } + + &:first-child { + padding-top: 0; + } + + input { + color: #444; + } + + > label { + text-align: left; + font-weight: 500; + font-size: 16px; + line-height: 20px; + color: #444; + } + + .settings-description { + color: #888; + padding: 5px; + } + } + } + } + .settings-description { .allow-text-selection; } diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index a13f52cb1b0..a714a4463d4 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -6,103 +6,107 @@ <span class="room-title">{{#with group}}{{label}}{{/with}}</span> </h2> </head> + <div class="content"> {{#unless hasPermission 'view-privileged-setting'}} <p>You are not authorized to view this page.</p> {{else}} {{#with group}} - <div class="info"> - <p class="settings-description">{{description}}</p> - </div> + {{#if description}} + <div class="info"> + <p class="settings-description">{{description}}</p> + </div> + {{/if}} {{/with}} <div class="rocket-form"> - <fieldset> - {{#each sections}} - <div class="section"> + {{#each sections}} + <div class="section"> + {{#if section}} + <div class="section-title"> + {{section}} + </div> + {{/if}} + <div class="section-content"> {{#if section}} - <h1>{{section}}</h1> - {{/if}} - <div class="section-content"> - {{#if section}} - {{#if sectionIsCustomOath section}} - <div class="section-helper"> - {{#with callbackURL section}} - {{{_ "Custom_oauth_helper" .}}} - {{/with}} - </div> - {{/if}} + {{#if sectionIsCustomOath section}} + <div class="section-helper"> + {{#with callbackURL section}} + {{{_ "Custom_oauth_helper" .}}} + {{/with}} + </div> {{/if}} - {{#each settings}} - <div class="input-line double-col"> - <label>{{label}}</label> - <div> - {{#if $eq type 'string'}} - {{#if multiline}} - <textarea name="{{_id}}" rows="4" style="height: auto">{{value}}</textarea> - {{else}} - <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> - {{/if}} + {{/if}} + {{#each settings}} + <div class="input-line double-col"> + <label>{{label}}</label> + <div> + {{#if $eq type 'string'}} + {{#if multiline}} + <textarea name="{{_id}}" rows="4" style="height: auto">{{value}}</textarea> + {{else}} + <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> {{/if}} + {{/if}} - {{#if $eq type 'int'}} - <input type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> - {{/if}} + {{#if $eq type 'int'}} + <input type="number" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> + {{/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> - {{/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> + {{/if}} - {{#if $eq type 'select'}} - <select name="{{_id}}"> - {{#each values}} - <option value="{{key}}" selected="{{selectedOption ../_id key}}">{{_ i18nLabel}}</option> - {{/each}} - </select> - {{/if}} + {{#if $eq type 'select'}} + <select name="{{_id}}"> + {{#each values}} + <option value="{{key}}" selected="{{selectedOption ../_id key}}">{{_ i18nLabel}}</option> + {{/each}} + </select> + {{/if}} - {{#if $eq type 'color'}} - <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> - {{/if}} + {{#if $eq type 'color'}} + <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> + {{/if}} - {{#if $eq type 'asset'}} - {{#if value}} - <div class="settings-file-preview"> - <div class="preview" style="background-image:url({{value}}?_dc={{random}});"></div> - <div class="action"> - <button type="button" class="button red delete-asset"><i class="icon-trash"></i>{{_ 'Delete'}}</button> - </div> + {{#if $eq type 'asset'}} + {{#if value}} + <div class="settings-file-preview"> + <div class="preview" style="background-image:url({{value}}?_dc={{random}});"></div> + <div class="action"> + <button type="button" class="button red delete-asset"><i class="icon-trash"></i>{{_ 'Delete'}}</button> </div> - {{else}} - <div class="settings-file-preview"> - <div class="preview no-file"><i class="icon-upload"></i></div> - <div class="action"> - <div class="button primary"><i class="icon-trash"></i>{{_ 'Select_file'}} - <input type="file" accept="{{fileConstraints.contentType}}" /> - </div> + </div> + {{else}} + <div class="settings-file-preview"> + <div class="preview no-file"><i class="icon-upload"></i></div> + <div class="action"> + <div class="button primary"><i class="icon-trash"></i>{{_ 'Select_file'}} + <input type="file" accept="{{fileConstraints.contentType}}" /> </div> </div> - {{/if}} + </div> {{/if}} + {{/if}} - {{#if description}} - <div class="settings-description">{{{description}}}</div> - {{/if}} - </div> + {{#if description}} + <div class="settings-description">{{{description}}}</div> + {{/if}} </div> - {{/each}} + </div> + {{/each}} - {{#if section}} - {{#if sectionIsCustomOath section}} - <div class="submit"> - <button class="button delete remove-custom-oauth"><span>{{_ "Remove_custom_oauth"}}</span></button> - </div> - {{/if}} + {{#if section}} + {{#if sectionIsCustomOath section}} + <div class="submit"> + <button class="button delete remove-custom-oauth"><span>{{_ "Remove_custom_oauth"}}</span></button> + </div> {{/if}} - </div> + {{/if}} </div> - {{/each}} - </fieldset> + </div> + {{/each}} + <div class="submit"> {{#if $eq group._id 'Accounts'}} <button class="button secondary add-custom-oauth"><span>{{_ "Add_custom_oauth"}}</span></button> -- GitLab From 9901d07994919599218ae8fc4ca0764c2f846433 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 4 Dec 2015 17:02:40 -0200 Subject: [PATCH 0691/1338] moved accountBox HTML to new separated template --- packages/rocketchat-ui-sidenav/package.js | 2 + .../side-nav/accountBox.coffee | 62 +++++++++++++++++++ .../side-nav/accountBox.html | 32 ++++++++++ .../side-nav/sideNav.coffee | 55 ---------------- .../side-nav/sideNav.html | 31 +--------- 5 files changed, 97 insertions(+), 85 deletions(-) create mode 100644 packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee create mode 100644 packages/rocketchat-ui-sidenav/side-nav/accountBox.html diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index 8c51ef517ef..f0c3872b146 100644 --- a/packages/rocketchat-ui-sidenav/package.js +++ b/packages/rocketchat-ui-sidenav/package.js @@ -21,6 +21,7 @@ Package.onUse(function(api) { 'rocketchat:lib@0.0.1' ]); + api.addFiles('side-nav/accountBox.html', 'client'); api.addFiles('side-nav/channels.html', 'client'); api.addFiles('side-nav/chatRoomItem.html', 'client'); api.addFiles('side-nav/createChannelFlex.html', 'client'); @@ -35,6 +36,7 @@ Package.onUse(function(api) { api.addFiles('side-nav/unreadRooms.html', 'client'); api.addFiles('side-nav/userStatus.html', 'client'); + api.addFiles('side-nav/accountBox.coffee', 'client'); api.addFiles('side-nav/channels.coffee', 'client'); api.addFiles('side-nav/chatRoomItem.coffee', 'client'); api.addFiles('side-nav/createChannelFlex.coffee', 'client'); diff --git a/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee new file mode 100644 index 00000000000..b5e470d32de --- /dev/null +++ b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee @@ -0,0 +1,62 @@ +Template.accountBox.helpers + myUserInfo: -> + visualStatus = "online" + username = Meteor.user()?.username + switch Session.get('user_' + username + '_status') + when "away" + visualStatus = t("away") + when "busy" + visualStatus = t("busy") + when "offline" + visualStatus = t("invisible") + return { + name: Session.get('user_' + username + '_name') + status: Session.get('user_' + username + '_status') + visualStatus: visualStatus + _id: Meteor.userId() + username: username + } + + showAdminOption: -> + return RocketChat.authz.hasAtLeastOnePermission( ['view-statistics', 'view-room-administration', 'view-user-administration', 'view-privileged-setting']) + + registeredMenus: -> + return AccountBox.getItems() + +Template.accountBox.events + 'click .options .status': (event) -> + event.preventDefault() + AccountBox.setStatus(event.currentTarget.dataset.status) + + 'click .account-box': (event) -> + AccountBox.toggle() + + 'click #logout': (event) -> + event.preventDefault() + user = Meteor.user() + Meteor.logout -> + FlowRouter.go 'home' + Meteor.call('logoutCleanUp', user) + + 'click #avatar': (event) -> + FlowRouter.go 'changeAvatar' + + 'click #account': (event) -> + SideNav.setFlex "accountFlex" + SideNav.openFlex() + FlowRouter.go 'account' + + 'click #admin': -> + SideNav.setFlex "adminFlex" + SideNav.openFlex() + + 'click .account-link': -> + menu.close() + + 'click .account-box-item': -> + if @sideNav? + SideNav.setFlex @sideNav + SideNav.openFlex() + +Template.accountBox.onRendered -> + AccountBox.init() diff --git a/packages/rocketchat-ui-sidenav/side-nav/accountBox.html b/packages/rocketchat-ui-sidenav/side-nav/accountBox.html new file mode 100644 index 00000000000..2530e8c3c67 --- /dev/null +++ b/packages/rocketchat-ui-sidenav/side-nav/accountBox.html @@ -0,0 +1,32 @@ +<template name="accountBox"> + <div class="account-box" aria-label="{{_ "Account"}}" role="region"> + {{#with myUserInfo}} + <div class="info status-{{status}}"> + {{#if username}} + <div class="thumb" data-status='{{visualStatus}}'> + {{> avatar username=username}} + </div> + <div class="data"> + <h4>{{username}}</h4> + </div> + {{/if}} + </div> + <nav class="options animated-hidden"> + <div class="wrapper"> + <a href="" data-status="online" class="status online"><span>{{_ "Online"}}</span></a> + <a href="" data-status="away" class="status away"><span>{{_ "Away" context="male"}}</span></a> + <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> + <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> + <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> + {{#each registeredMenus}} + <a href="{{pathFor href}}" class="account-box-item"><i class="{{icon}}"></i><span>{{name}}</span></a> + {{/each}} + {{#if showAdminOption }} + <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> + {{/if}} + <a href="" id="logout"><i class="icon-logout"></i><span>{{_ "Logout"}}</span></a> + </div> + </nav> + {{/with}} + </div> +</template> diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 0b377ed7aab..1f6f5958a07 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -14,30 +14,6 @@ Template.sideNav.helpers return true if favoritesEnabled and hasFavoriteRoomOpened - myUserInfo: -> - visualStatus = "online" - username = Meteor.user()?.username - switch Session.get('user_' + username + '_status') - when "away" - visualStatus = t("away") - when "busy" - visualStatus = t("busy") - when "offline" - visualStatus = t("invisible") - return { - name: Session.get('user_' + username + '_name') - status: Session.get('user_' + username + '_status') - visualStatus: visualStatus - _id: Meteor.userId() - username: username - } - - showAdminOption: -> - return RocketChat.authz.hasAtLeastOnePermission( ['view-statistics', 'view-room-administration', 'view-user-administration', 'view-privileged-setting']) - - registeredMenus: -> - return AccountBox.getItems() - Template.sideNav.events 'click .close-flex': -> SideNav.closeFlex() @@ -54,35 +30,6 @@ Template.sideNav.events 'scroll .rooms-list': -> menu.updateUnreadBars() - 'click .options .status': (event) -> - event.preventDefault() - AccountBox.setStatus(event.currentTarget.dataset.status) - - 'click .account-box': (event) -> - AccountBox.toggle() - - 'click #logout': (event) -> - event.preventDefault() - user = Meteor.user() - Meteor.logout -> - FlowRouter.go 'home' - Meteor.call('logoutCleanUp', user) - - 'click #avatar': (event) -> - FlowRouter.go 'changeAvatar' - - 'click #account': (event) -> - SideNav.setFlex "accountFlex" - SideNav.openFlex() - FlowRouter.go 'account' - - 'click #admin': -> - SideNav.setFlex "adminFlex" - SideNav.openFlex() - - 'click .account-link': -> - menu.close() - Template.sideNav.onRendered -> SideNav.init() menu.init() @@ -90,8 +37,6 @@ Template.sideNav.onRendered -> Meteor.defer -> menu.updateUnreadBars() - AccountBox.init() - wrapper = $('.rooms-list .wrapper').get(0) lastLink = $('.rooms-list h3.history-div').get(0) diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html index cb6d536bd67..80b0454af9c 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.html +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.html @@ -1,36 +1,7 @@ <template name="sideNav"> <aside class="side-nav" role="navigation"> <header class="header"> - <div class="account-box" aria-label="{{_ "Account"}}" role="region"> - {{#with myUserInfo}} - <div class="info status-{{status}}"> - {{#if username}} - <div class="thumb" data-status='{{visualStatus}}'> - {{> avatar username=username}} - </div> - <div class="data"> - <h4>{{username}}</h4> - </div> - {{/if}} - </div> - <nav class="options animated-hidden"> - <div class="wrapper"> - <a href="" data-status="online" class="status online"><span>{{_ "Online"}}</span></a> - <a href="" data-status="away" class="status away"><span>{{_ "Away" context="male"}}</span></a> - <a href="" data-status="busy" class="status busy"><span>{{_ "Busy" context="male"}}</span></a> - <a href="" data-status="offline" class="status offline"><span>{{_ "Invisible"}}</span></a> - <a href="" id="account" class='account-link'><i class="icon-sliders"></i><span>{{_ "My_Account"}}</span></a> - {{#each registeredMenus}} - <a href="{{pathFor href}}"><i class="{{icon}}"></i><span>{{name}}</span></a> - {{/each}} - {{#if showAdminOption }} - <a href="" id="admin" class='account-link'><i class="icon-wrench"></i><span>{{_ "Administration"}}</span></a> - {{/if}} - <a href="" id="logout"><i class="icon-logout"></i><span>{{_ "Logout"}}</span></a> - </div> - </nav> - {{/with}} - </div> + {{> accountBox }} </header> {{#if currentUser}} <div class="unread-rooms top-unread-rooms hidden"> -- GitLab From f26aab2923f57484f60467fa493288d9cf7743fb Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 4 Dec 2015 17:08:44 -0200 Subject: [PATCH 0692/1338] queue open action to until SideNav is initiated --- packages/rocketchat-ui/lib/sideNav.coffee | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui/lib/sideNav.coffee b/packages/rocketchat-ui/lib/sideNav.coffee index d55a61c6b6e..b5d4f356a0e 100644 --- a/packages/rocketchat-ui/lib/sideNav.coffee +++ b/packages/rocketchat-ui/lib/sideNav.coffee @@ -1,9 +1,10 @@ @SideNav = (-> - + initiated = false sideNav = {} flexNav = {} arrow = {} animating = false + openQueue = [] toggleArrow = (status = null) -> if status is -1 or (status isnt 1 and arrow.hasClass "top") @@ -61,6 +62,9 @@ , 500 openFlex = (callback = null) -> + if not initiated + return openQueue.push { config: getFlex(), callback: callback } + return if animating == true toggleArrow 1 toggleFlex 1, callback @@ -90,6 +94,14 @@ arrow = sideNav.children ".arrow" setFlex "" arrowBindHover() + initiated = true + + if openQueue.length > 0 + openQueue.forEach (item) -> + setFlex item.config.template, item.config.data + openFlex item.callback + + openQueue = [] getSideNav = -> return sideNav -- GitLab From 8009147eaa9a89a85f9b67335b36562df0029146 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 4 Dec 2015 17:09:27 -0200 Subject: [PATCH 0693/1338] accountBox sideNav support --- packages/rocketchat-livechat/client/ui.js | 1 + packages/rocketchat-ui/lib/accountBox.coffee | 22 ++++---------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index 28591b5d046..c9144af815e 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -40,6 +40,7 @@ AccountBox.addItem({ name: 'Livechat', icon: 'icon-chat-empty', href: 'livechat-manager', + sideNav: 'livechatFlex', permissions: ['view-livechat-manager'], }); diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index 801e5ee9504..49c6a3c13d2 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -28,17 +28,6 @@ self.box = $(".account-box") self.options = self.box.find(".options") - # protectedAction = (item) -> - # if not item.permissions? or RocketChat.authz.hasAllPermission 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' - ### # @param newOption: # name: Button label @@ -64,19 +53,16 @@ FlowRouter.route newRoute.path, name: newRoute.name action: -> - - console.log 'accountBox -> action' - Session.set 'openedRoom' BlazeLayout.render 'main', center: 'pageContainer' pageTitle: newRoute.pageTitle pageTemplate: newRoute.pageTemplate - + triggersEnter: [ -> if newRoute.sideNav? - Tracker.afterFlush -> - SideNav.setFlex newRoute.sideNav - SideNav.openFlex() + SideNav.setFlex newRoute.sideNav + SideNav.openFlex() + ] setStatus: setStatus -- GitLab From 5e4b3514767f5b40527ede06e20da3d5d76869d8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 17:12:23 -0200 Subject: [PATCH 0694/1338] Collapse sub groups of settings --- .../assets/stylesheets/base.less | 19 +++++++++++++++++-- .../rocketchat-ui-admin/admin/admin.coffee | 8 ++++++++ packages/rocketchat-ui-admin/admin/admin.html | 9 +++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c877e67b063..fcf06ddf5a9 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1742,17 +1742,32 @@ a.github-fork { padding: 20px; margin-bottom: 20px; + &.section-collapsed { + .section-content { + display: none; + } + } + .section-title { + display: flex; font-size: 24px; font-weight: 600; - padding: 10px 0 30px 0; color: #444; + line-height: 40px; + + .section-title-text { + flex-grow: 1; + } + + .section-title-right { + line-height: 0px; + } } .section-content { border: none !important; border-radius: 0px !important; - padding: 0px !important; + padding: 20px 0 0 0 !important; .input-line { border-bottom: 1px solid #eee; diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index fe0aeea2948..1f8c90a7dd4 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -130,6 +130,14 @@ Template.admin.events toastr.success TAPi18n.__ 'File_uploaded' + "click .expand": (e) -> + $(e.currentTarget).closest('.section').removeClass('section-collapsed') + $(e.currentTarget).closest('button').removeClass('expand').addClass('collapse').find('span').text(TAPi18n.__ "Collapse") + + "click .collapse": (e) -> + $(e.currentTarget).closest('.section').addClass('section-collapsed') + $(e.currentTarget).closest('button').addClass('expand').removeClass('collapse').find('span').text(TAPi18n.__ "Expand") + Template.admin.onRendered -> Tracker.afterFlush -> diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index a714a4463d4..68df2179560 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -20,10 +20,15 @@ {{/with}} <div class="rocket-form"> {{#each sections}} - <div class="section"> + <div class="section {{#if section}}section-collapsed{{/if}}"> {{#if section}} <div class="section-title"> - {{section}} + <div class="section-title-text"> + {{section}} + </div> + <div class="section-title-right"> + <button class="button secondary expand"><span>{{_ "Expand"}}</span></button> + </div> </div> {{/if}} <div class="section-content"> -- GitLab From a8d07fad7d632897ccaf3b8e076c9e62f5b3499b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 17:12:46 -0200 Subject: [PATCH 0695/1338] Change translations in PT for False and True --- i18n/pt.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index b08892268d4..5d4d9e939cc 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -119,7 +119,7 @@ "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", "Esc_to" : "Esc para", - "False" : "Falso", + "False" : "Não", "Favorites" : "Favoritos", "FileUpload" : "Upload de Arquivos", "FileUpload_Enabled" : "Habilitar upload de arquivos", @@ -362,7 +362,7 @@ "strike" : "tachado", "Submit" : "Enviar", "The_field_is_required" : "O campo %s é obrigatório.", - "True" : "Verdadeiro", + "True" : "Sim", "Unnamed" : "Sem nome", "Unread_Rooms" : "Não Lidas", "Unread_Rooms_Mode" : "Agrupar Salas Não Lidas", -- GitLab From b805370589864b746a6c200786efde15264be9b8 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 4 Dec 2015 17:23:37 -0200 Subject: [PATCH 0696/1338] cleanup --- packages/rocketchat-livechat/client/ui.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index c9144af815e..ea863114c22 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -17,25 +17,6 @@ RocketChat.roomTypes.add('l', 5, { permissions: ['view-l-room'] }); -// 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: 'pageContainer', -// pageTitle: t('Livechat_Manager'), -// pageTemplate: 'livechatManager' -// }); -// } -// }, -// permissions: ['view-livechat-manager'] -// }); - AccountBox.addItem({ name: 'Livechat', icon: 'icon-chat-empty', -- GitLab From b463f4ffcbc37c23efb941ed6a0579a21525e254 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 4 Dec 2015 17:39:29 -0200 Subject: [PATCH 0697/1338] Departments --- .../client/lib/LivechatDepartment.js | 1 + packages/rocketchat-livechat/client/route.js | 21 +++++++ .../views/app/livechatDepartmentForm.html | 35 ++++++++++++ .../views/app/livechatDepartmentForm.js | 54 ++++++++++++++++++ .../client/views/app/livechatDepartments.html | 31 +++++++++++ .../client/views/app/livechatDepartments.js | 55 +++++++++++++++++++ .../client/views/sideNav/livechatFlex.html | 3 +- .../rocketchat-livechat/i18n/en.i18n.json | 19 +++++++ packages/rocketchat-livechat/package.js | 13 ++++- .../server/methods/removeDepartment.js | 19 +++++++ .../server/methods/removeManager.js | 4 +- .../server/methods/saveDepartment.js | 23 ++++++++ .../server/models/LivechatDepartment.js | 41 ++++++++++++++ .../publications/livechatDepartments.js | 18 ++++++ 14 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 packages/rocketchat-livechat/client/lib/LivechatDepartment.js create mode 100644 packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js create mode 100644 packages/rocketchat-livechat/client/views/app/livechatDepartments.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatDepartments.js create mode 100644 packages/rocketchat-livechat/server/methods/removeDepartment.js create mode 100644 packages/rocketchat-livechat/server/methods/saveDepartment.js create mode 100644 packages/rocketchat-livechat/server/models/LivechatDepartment.js create mode 100644 packages/rocketchat-livechat/server/publications/livechatDepartments.js diff --git a/packages/rocketchat-livechat/client/lib/LivechatDepartment.js b/packages/rocketchat-livechat/client/lib/LivechatDepartment.js new file mode 100644 index 00000000000..3a8d1777605 --- /dev/null +++ b/packages/rocketchat-livechat/client/lib/LivechatDepartment.js @@ -0,0 +1 @@ +this.LivechatDepartment = new Mongo.Collection('rocketchat_livechat_department'); diff --git a/packages/rocketchat-livechat/client/route.js b/packages/rocketchat-livechat/client/route.js index fb95d8c23c9..a2029900297 100644 --- a/packages/rocketchat-livechat/client/route.js +++ b/packages/rocketchat-livechat/client/route.js @@ -9,3 +9,24 @@ FlowRouter.route('/live/:name', { triggersExit: [roomExit] }); + +FlowRouter.route('/livechat-manager/departments', { + name: 'livechat-departments', + + action: function(params, queryParams) { + BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatDepartments', pageTitle: t('Departments') }); + } +}); + +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}); + } +}); diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html new file mode 100644 index 00000000000..5db5126701f --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -0,0 +1,35 @@ +<template name="livechatDepartmentForm"> + <form id="department-form" data-id="{{department._id}}"> + <div class="rocket-form"> + {{#if Template.subscriptionsReady}} + <fieldset> + <div class="input-line"> + <label>{{_ "Enabled"}}</label> + <div> + <label><input type="radio" name="enabled" value="1" checked="{{$eq department.enabled true}}" /> {{_ "Yes"}}</label> + <label><input type="radio" name="enabled" value="0" checked="{{$eq department.enabled false}}" /> {{_ "No"}}</label> + </div> + </div> + <div class="input-line"> + <label>{{_ "Name"}}</label> + <div> + <input type="text" name="name" value="{{department.name}}" placeholder="{{_ "Name"}}" /> + </div> + </div> + <div class="input-line"> + <label>{{_ "Description"}}</label> + <div> + <textarea name="description" rows="6">{{department.description}}</textarea> + </div> + </div> + </fieldset> + <div class="submit"> + <button class="button secondary back"><i class="icon-left-big"></i><span>{{_ "Back"}}</span></button> + <button class="button save"><i class="icon-floppy"></i><span>{{_ "Save"}}</span></button> + </div> + {{else}} + {{> loading}} + {{/if}} + </div> + </form> +</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js new file mode 100644 index 00000000000..eff4f358d9c --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js @@ -0,0 +1,54 @@ +Template.livechatDepartmentForm.helpers({ + department() { + return Template.instance().department || { enabled: true }; + } +}); + +Template.livechatDepartmentForm.events({ + 'submit #department-form' (e, instance) { + e.preventDefault(); + var $btn = instance.$('button.save'); + + var _id = $(e.currentTarget).data('id'); + var enabled = instance.$('input[name=enabled]:checked').val() + var name = instance.$('input[name=name]').val() + var description = instance.$('textarea[name=description]').val() + + if (enabled !== "1" && enabled !== "0") { + return toastr.error(t('Please_select_enabled_yes_or_no')); + } + + if (name.trim() === '') { + return toastr.error(t('Please_fill_a_name')); + } + + var oldBtnValue = $btn.val(); + $btn.val(t('Saving')); + + departmentData = { + enabled: enabled === "1" ? true : false, + name: name.trim(), + description: description.trim() + } + + Meteor.call('livechat:saveDepartment', _id, departmentData, function(error, result) { + $btn.val(oldBtnValue); + if (error) { + return toastr.error(t(error.reason || error.error)); + } + + toastr.success(t('Saved')); + FlowRouter.go('livechat-departments'); + }); + }, + + 'click button.back' () { + event.preventDefault(); + FlowRouter.go('livechat-departments'); + } +}); + +Template.livechatDepartmentForm.onCreated(function() { + this.department = LivechatDepartment.findOne({ _id: FlowRouter.getParam('_id') }); + this.subscribe('livechat:departments', FlowRouter.getParam('_id')); +}); diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartments.html b/packages/rocketchat-livechat/client/views/app/livechatDepartments.html new file mode 100644 index 00000000000..a334421e88e --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.html @@ -0,0 +1,31 @@ +<template name="livechatDepartments"> + <div class="list"> + <table> + <thead> + <tr> + <th width="25%">{{_ "Name"}}</th> + <th width="25%">{{_ "Description"}}</th> + <th width="25%">{{_ "Num_Agents"}}</th> + <th width="25%">{{_ "Enabled"}}</th> + <th>{{_ "Delete"}}</th> + </tr> + </thead> + <tbody> + {{#each departments}} + <tr class="department-info" data-id="{{_id}}"> + <td>{{name}}</td> + <td>{{description}}</td> + <td>{{numAgents}}</td> + <td>{{#if enabled}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}}</td> + <td><a href="#remove" class="remove-department"><i class="icon-trash"></i></a></td> + </tr> + {{/each}} + </tbody> + </table> + </div> + + <form id="form-manager" class="inline"> + <button name="newDepartment" class="button primary">{{_ "New_Department"}}</button> + </form> + +</template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js new file mode 100644 index 00000000000..274f1d1876e --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js @@ -0,0 +1,55 @@ +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(); + + 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:removeDepartment', this._id, function(error, result) { + if (error) { + return toastr.error(t(error.reason || error.error)); + } + swal({ + title: t('Removed'), + text: t('Department_removed'), + type: 'success', + timer: 1000, + showConfirmButton: false, + }); + }); + }); + }, + + 'click .department-info' (e, instance) { + e.preventDefault(); + FlowRouter.go('livechat-department', { _id: this._id }); + } +}); + +Template.livechatDepartments.onCreated(function() { + this.subscribe('livechat:departments'); +}); diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index 815010b9fd6..ae76e6746d9 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -10,8 +10,7 @@ <li> <a href="#link" class="admin-link">{{_ "Dashboard"}}</a> <a href="#link" class="admin-link">{{_ "User_management"}}</a> - <a href="#link" class="admin-link">{{_ "Departaments"}}</a> - <a href="#link" class="admin-link">{{_ "Queue"}}</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> diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 6de6b790589..374873a7ed2 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -4,7 +4,18 @@ "Add_manager": "Add manager", "Agent_added": "Agent added", "Agent_removed": "Agent removed", + "Back": "Back", + "Dashboard": "Dashboard", + "Department_not_found": "Department not found", + "Department_removed": "Department removed", + "Departments": "Departments", + "Description": "Description", + "Edit_Department": "Edit Department", + "Enable": "Enable", + "Enabled": "Enabled", "Enter_a_username": "Enter a username", + "Integrations": "Integrations", + "Live_sessions": "Live sessions", "Livechat_agents": "Livechat agents", "Livechat_Manager": "Livechat Manager", "Livechat_managers": "Livechat managers", @@ -12,6 +23,14 @@ "Livechat_title_color" : "Livechat Title Background Color", "Manager_added": "Manager added", "Manager_removed": "Manager removed", + "Name": "Name", + "New_Department": "New Department", + "Num_Agents": "# Agents", "Please_fill_a_username": "Please fill a username", + "Please_select_enabled_yes_or_no": "Please select an option for Enabled", + "Please_fill_a_name": "Please fill a name", + "Saved": "Saved", + "Theme": "Theme", + "User_management": "User Management", "Username_not_found": "Username not found" } diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 6c2e212dc27..4617b065094 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -24,6 +24,7 @@ Package.onUse(function(api) { api.use('rocketchat:lib'); api.use('kadira:flow-router', 'client'); api.use('templating', 'client'); + api.use('mongo'); api.addFiles('livechat.js', 'server'); api.addFiles('server/methods.js', 'server'); @@ -38,6 +39,10 @@ Package.onUse(function(api) { // 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/livechatDepartmentForm.html', 'client'); + api.addFiles('client/views/app/livechatDepartmentForm.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'); @@ -45,15 +50,21 @@ Package.onUse(function(api) { // methods api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); + api.addFiles('server/methods/saveDepartment.js', 'server'); api.addFiles('server/methods/removeAgent.js', 'server'); api.addFiles('server/methods/removeManager.js', 'server'); - + api.addFiles('server/methods/removeDepartment.js', 'server'); // models api.addFiles('server/models/Users.js', 'server'); + api.addFiles('server/models/LivechatDepartment.js', 'server'); + + // collections + api.addFiles('client/lib/LivechatDepartment.js', 'client'); // publications api.addFiles('server/publications/livechatAgents.js', 'server'); api.addFiles('server/publications/livechatManagers.js', 'server'); + api.addFiles('server/publications/livechatDepartments.js', 'server'); // livechat app api.addAssets('rocket-livechat.js', 'client'); diff --git a/packages/rocketchat-livechat/server/methods/removeDepartment.js b/packages/rocketchat-livechat/server/methods/removeDepartment.js new file mode 100644 index 00000000000..8fb2b620dff --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/removeDepartment.js @@ -0,0 +1,19 @@ +Meteor.methods({ + 'livechat:removeDepartment' (_id) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + check(_id, String); + + console.log('[methods] livechat:removeDepartment -> '.green, 'arguments:', arguments); + + var department = RocketChat.models.LivechatDepartment.findOneById(_id, { fields: { _id: 1 } }); + + if (!department) { + throw new Meteor.Error('department-not-found', 'Department_not_found'); + } + + return RocketChat.models.LivechatDepartment.removeById(_id); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/removeManager.js b/packages/rocketchat-livechat/server/methods/removeManager.js index 43bebc3e8cb..38e462d3f0e 100644 --- a/packages/rocketchat-livechat/server/methods/removeManager.js +++ b/packages/rocketchat-livechat/server/methods/removeManager.js @@ -4,9 +4,7 @@ Meteor.methods({ throw new Meteor.Error("not-authorized"); } - if (!username || !_.isString(username)) { - throw new Meteor.Error('invalid-arguments'); - } + check(username, String); console.log('[methods] livechat:removeManager -> '.green, 'arguments:', arguments); diff --git a/packages/rocketchat-livechat/server/methods/saveDepartment.js b/packages/rocketchat-livechat/server/methods/saveDepartment.js new file mode 100644 index 00000000000..88c60936332 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/saveDepartment.js @@ -0,0 +1,23 @@ +Meteor.methods({ + 'livechat:saveDepartment' (_id, departmentData) { + console.log('[methods] livechat:saveDepartment -> '.green, 'arguments:', arguments); + + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + if (_id) { + check(_id, String); + } + check(departmentData, Match.ObjectIncluding({ enabled: Boolean, name: String, description: Match.Optional(String) })); + + if (_id) { + department = RocketChat.models.LivechatDepartment.findOneById(_id); + if (!department) { + throw new Meteor.Error('department-not-found', 'Department_not_found'); + } + } + + return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description); + } +}); diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js new file mode 100644 index 00000000000..e6ae538b945 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -0,0 +1,41 @@ +/** + * Livechat Department model + */ +class LivechatDepartment extends RocketChat.models._Base { + constructor() { + super(); + this._initModel('livechat_department'); + } + + // FIND + findOneById(_id, options) { + query = { _id: _id }; + + return this.findOne(query, options); + } + + findByDepartmentId(_id, options) { + query = { _id: _id }; + return this.find(query, options); + } + + // UPSERT + createOrUpdateDepartment(_id, enabled, name, description, extraData) { + record = { + enabled: enabled, + name: name, + description: description + } + _.extend(record, extraData); + this.upsert({ _id: _id }, { $set: record }); + return _.extend(record, { _id: _id }); + } + + // REMOVE + removeById(_id) { + query = { _id: _id }; + return this.remove(query); + } +} + +RocketChat.models.LivechatDepartment = new LivechatDepartment(); diff --git a/packages/rocketchat-livechat/server/publications/livechatDepartments.js b/packages/rocketchat-livechat/server/publications/livechatDepartments.js new file mode 100644 index 00000000000..ab35d5dd88c --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/livechatDepartments.js @@ -0,0 +1,18 @@ +Meteor.publish('livechat:departments', function(_id) { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { + throw new Meteor.Error('not-authorized'); + } + + console.log('[publish] livechat:departments -> '.green, 'arguments:', arguments); + + if (_id !== undefined) { + return RocketChat.models.LivechatDepartment.findByDepartmentId(_id); + } else { + return RocketChat.models.LivechatDepartment.find(); + } + +}); -- GitLab From 527ffac1fd38728a29b7cae4b77e41b08bf0ecc5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 4 Dec 2015 18:45:00 -0200 Subject: [PATCH 0698/1338] Secret URL - Fixes #1574 --- client/routes/router.coffee | 22 ++++++++++--------- .../{blankLayout.html => logoLayout.html} | 2 +- packages/rocketchat-ui-master/package.js | 2 +- packages/rocketchat-ui/package.js | 2 ++ .../rocketchat-ui/views/app/secretURL.coffee | 21 ++++++++++++++++++ .../rocketchat-ui/views/app/secretURL.html | 11 ++++++++++ 6 files changed, 48 insertions(+), 12 deletions(-) rename packages/rocketchat-ui-master/master/{blankLayout.html => logoLayout.html} (88%) create mode 100644 packages/rocketchat-ui/views/app/secretURL.coffee create mode 100644 packages/rocketchat-ui/views/app/secretURL.html diff --git a/client/routes/router.coffee b/client/routes/router.coffee index a0c46837f1e..74873c70a05 100644 --- a/client/routes/router.coffee +++ b/client/routes/router.coffee @@ -107,13 +107,15 @@ FlowRouter.route '/fxos', FlowRouter.route '/register/:hash', name: 'register-secret-url' action: (params) -> - if RocketChat.settings.get('Accounts_RegistrationForm') is 'Secret URL' - Meteor.call 'checkRegistrationSecretURL', params.hash, (err, success) -> - if success - Session.set 'loginDefaultState', 'register' - BlazeLayout.render 'main', {center: 'home'} - KonchatNotification.getDesktopPermission() - else - BlazeLayout.render 'blankLayout', { render: 'invalidSecretURL' } - else - BlazeLayout.render 'blankLayout', { render: 'invalidSecretURL' } + BlazeLayout.render 'secretURL' + + # if RocketChat.settings.get('Accounts_RegistrationForm') is 'Secret URL' + # Meteor.call 'checkRegistrationSecretURL', params.hash, (err, success) -> + # if success + # Session.set 'loginDefaultState', 'register' + # BlazeLayout.render 'main', {center: 'home'} + # KonchatNotification.getDesktopPermission() + # else + # BlazeLayout.render 'logoLayout', { render: 'invalidSecretURL' } + # else + # BlazeLayout.render 'logoLayout', { render: 'invalidSecretURL' } diff --git a/packages/rocketchat-ui-master/master/blankLayout.html b/packages/rocketchat-ui-master/master/logoLayout.html similarity index 88% rename from packages/rocketchat-ui-master/master/blankLayout.html rename to packages/rocketchat-ui-master/master/logoLayout.html index a75928f8866..e1228b4a62f 100644 --- a/packages/rocketchat-ui-master/master/blankLayout.html +++ b/packages/rocketchat-ui-master/master/logoLayout.html @@ -1,4 +1,4 @@ -<template name="blankLayout"> +<template name="logoLayout"> <section class="full-page"> <div class="wrapper"> <header> diff --git a/packages/rocketchat-ui-master/package.js b/packages/rocketchat-ui-master/package.js index 506a740b7dd..7f1ca13660a 100644 --- a/packages/rocketchat-ui-master/package.js +++ b/packages/rocketchat-ui-master/package.js @@ -25,7 +25,7 @@ Package.onUse(function(api) { api.addFiles('master/main.html', 'client'); api.addFiles('master/loading.html', 'client'); api.addFiles('master/error.html', 'client'); - api.addFiles('master/blankLayout.html', 'client'); + api.addFiles('master/logoLayout.html', 'client'); api.addFiles('master/main.coffee', 'client'); }); diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 55c85b1c1e4..af4028150c0 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -82,6 +82,7 @@ Package.onUse(function(api) { api.addFiles('views/app/privateHistory.html', 'client'); api.addFiles('views/app/room.html', 'client'); api.addFiles('views/app/roomSearch.html', 'client'); + api.addFiles('views/app/secretURL.html', 'client'); api.addFiles('views/app/userSearch.html', 'client'); api.addFiles('views/app/spotlight/mobileMessageMenu.html', 'client'); api.addFiles('views/app/spotlight/spotlight.html', 'client'); @@ -97,6 +98,7 @@ Package.onUse(function(api) { api.addFiles('views/app/privateHistory.coffee', 'client'); api.addFiles('views/app/room.coffee', 'client'); api.addFiles('views/app/roomSearch.coffee', 'client'); + api.addFiles('views/app/secretURL.coffee', 'client'); api.addFiles('views/app/spotlight/mobileMessageMenu.coffee', 'client'); api.addFiles('views/app/spotlight/spotlight.coffee', 'client'); api.addFiles('views/app/videoCall/videoButtons.coffee', 'client'); diff --git a/packages/rocketchat-ui/views/app/secretURL.coffee b/packages/rocketchat-ui/views/app/secretURL.coffee new file mode 100644 index 00000000000..b50c21019d1 --- /dev/null +++ b/packages/rocketchat-ui/views/app/secretURL.coffee @@ -0,0 +1,21 @@ +Template.secretURL.helpers + registrationAllowed: -> + return RocketChat.settings.get('Accounts_RegistrationForm') is 'Secret URL' and Template.instance().hashIsValid?.get() + + ready: -> + return Template.instance().subscriptionsReady?() and Template.instance().hashReady?.get() + + +Template.secretURL.onCreated -> + @subscribe 'admin-settings' + @hashIsValid = new ReactiveVar false + @hashReady = new ReactiveVar false + + Meteor.call 'checkRegistrationSecretURL', FlowRouter.getParam('hash'), (err, success) => + @hashReady.set true + if success + Session.set 'loginDefaultState', 'register' + KonchatNotification.getDesktopPermission() + @hashIsValid.set true + else + @hashIsValid.set false diff --git a/packages/rocketchat-ui/views/app/secretURL.html b/packages/rocketchat-ui/views/app/secretURL.html new file mode 100644 index 00000000000..839eb6326cd --- /dev/null +++ b/packages/rocketchat-ui/views/app/secretURL.html @@ -0,0 +1,11 @@ +<template name="secretURL"> + {{#if ready}} + {{#if registrationAllowed}} + {{> main center="home"}} + {{else}} + {{> logoLayout render="invalidSecretURL"}} + {{/if}} + {{else}} + {{> loading}} + {{/if}} +</template> -- GitLab From ad5a35763ea2d782b25751e7839e458e28471805 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 21:02:22 -0200 Subject: [PATCH 0699/1338] Add new page container type, settings --- packages/rocketchat-ui/package.js | 1 + .../views/app/pageSettingsContainer.html | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 packages/rocketchat-ui/views/app/pageSettingsContainer.html diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 55c85b1c1e4..af3ee5f187b 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -79,6 +79,7 @@ Package.onUse(function(api) { api.addFiles('views/app/home.html', 'client'); api.addFiles('views/app/notAuthorized.html', 'client'); api.addFiles('views/app/pageContainer.html', 'client'); + api.addFiles('views/app/pageSettingsContainer.html', 'client'); api.addFiles('views/app/privateHistory.html', 'client'); api.addFiles('views/app/room.html', 'client'); api.addFiles('views/app/roomSearch.html', 'client'); diff --git a/packages/rocketchat-ui/views/app/pageSettingsContainer.html b/packages/rocketchat-ui/views/app/pageSettingsContainer.html new file mode 100644 index 00000000000..adb39f9b1a2 --- /dev/null +++ b/packages/rocketchat-ui/views/app/pageSettingsContainer.html @@ -0,0 +1,13 @@ +<template name="pageSettingsContainer"> + <section class="page-container page-home page-static page-settings"> + <head class="fixed-title"> + {{> burger}} + <h2> + <span class="page-title">{{pageTitle}}</span> + </h2> + </head> + <div class="content"> + {{> Template.dynamic template=pageTemplate}} + </div> + </section> +</template> -- GitLab From 96845c679176636235ff7158196d1094c6808cfd Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 21:02:49 -0200 Subject: [PATCH 0700/1338] Add new role, manage-integrations --- packages/rocketchat-authorization/server/startup.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index e1b57d541e7..905a43410e6 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -92,6 +92,9 @@ Meteor.startup -> { _id: 'manage-assets', roles : ['admin']} + + { _id: 'manage-integrations', + roles : ['admin']} ] #alanning:roles -- GitLab From 13a1b1694f28e3b50595fed169f87b31a284e704 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 4 Dec 2015 21:04:37 -0200 Subject: [PATCH 0701/1338] Init package rocketchat-integrations --- .meteor/packages | 1 + .meteor/versions | 1 + .../client/collection.coffee | 1 + .../client/route.coffee | 25 +++++++ .../client/startup.coffee | 5 ++ .../client/stylesheets/integrations.less | 42 +++++++++++ .../client/stylesheets/load.coffee | 2 + .../client/views/integrations.coffee | 3 + .../client/views/integrations.html | 15 ++++ .../client/views/integrationsIncoming.coffee | 8 +++ .../client/views/integrationsIncoming.html | 59 +++++++++++++++ .../client/views/integrationsNew.coffee | 3 + .../client/views/integrationsNew.html | 44 ++++++++++++ .../rocketchat-integrations/i18n/en.i18n.json | 3 + .../rocketchat-integrations/i18n/pt.i18n.json | 3 + .../lib/rocketchat.coffee | 1 + packages/rocketchat-integrations/package.js | 71 +++++++++++++++++++ 17 files changed, 287 insertions(+) create mode 100644 packages/rocketchat-integrations/client/collection.coffee create mode 100644 packages/rocketchat-integrations/client/route.coffee create mode 100644 packages/rocketchat-integrations/client/startup.coffee create mode 100644 packages/rocketchat-integrations/client/stylesheets/integrations.less create mode 100644 packages/rocketchat-integrations/client/stylesheets/load.coffee create mode 100644 packages/rocketchat-integrations/client/views/integrations.coffee create mode 100644 packages/rocketchat-integrations/client/views/integrations.html create mode 100644 packages/rocketchat-integrations/client/views/integrationsIncoming.coffee create mode 100644 packages/rocketchat-integrations/client/views/integrationsIncoming.html create mode 100644 packages/rocketchat-integrations/client/views/integrationsNew.coffee create mode 100644 packages/rocketchat-integrations/client/views/integrationsNew.html create mode 100644 packages/rocketchat-integrations/i18n/en.i18n.json create mode 100644 packages/rocketchat-integrations/i18n/pt.i18n.json create mode 100644 packages/rocketchat-integrations/lib/rocketchat.coffee create mode 100644 packages/rocketchat-integrations/package.js diff --git a/.meteor/packages b/.meteor/packages index 2eca93df9b9..551eb7d6b64 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -125,3 +125,4 @@ yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter rocketchat:assets +rocketchat:integrations diff --git a/.meteor/versions b/.meteor/versions index 8c88fab5cc1..068fe6f9dd7 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -135,6 +135,7 @@ rocketchat:file@0.0.1 rocketchat:github-enterprise@0.0.1 rocketchat:gitlab@0.0.1 rocketchat:highlight@0.0.1 +rocketchat:integrations@0.0.1 rocketchat:ldap@0.0.1 rocketchat:lib@0.0.1 rocketchat:logger@0.0.1 diff --git a/packages/rocketchat-integrations/client/collection.coffee b/packages/rocketchat-integrations/client/collection.coffee new file mode 100644 index 00000000000..dd1f798db85 --- /dev/null +++ b/packages/rocketchat-integrations/client/collection.coffee @@ -0,0 +1 @@ +@ChatIntegrations = new Meteor.Collection 'rocketchat_integrations' diff --git a/packages/rocketchat-integrations/client/route.coffee b/packages/rocketchat-integrations/client/route.coffee new file mode 100644 index 00000000000..e32f6d73e8c --- /dev/null +++ b/packages/rocketchat-integrations/client/route.coffee @@ -0,0 +1,25 @@ +FlowRouter.route '/admin/integrations', + name: 'admin-integrations' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('Integrations') + pageTemplate: 'integrations' + + +FlowRouter.route '/admin/integrations/new', + name: 'admin-integrations-new' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('Integration_New') + pageTemplate: 'integrationsNew' + + +FlowRouter.route '/admin/integrations/incoming', + name: 'admin-integrations-incoming' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('Integration_Incoming_WebHook') + pageTemplate: 'integrationsIncoming' diff --git a/packages/rocketchat-integrations/client/startup.coffee b/packages/rocketchat-integrations/client/startup.coffee new file mode 100644 index 00000000000..b1279bb0dfe --- /dev/null +++ b/packages/rocketchat-integrations/client/startup.coffee @@ -0,0 +1,5 @@ +RocketChat.AdminBox.addOption + href: 'admin-integrations' + i18nLabel: 'Integrations' + permissionGranted: -> + return RocketChat.authz.hasAllPermission('manage-integrations') diff --git a/packages/rocketchat-integrations/client/stylesheets/integrations.less b/packages/rocketchat-integrations/client/stylesheets/integrations.less new file mode 100644 index 00000000000..129cf9e9e31 --- /dev/null +++ b/packages/rocketchat-integrations/client/stylesheets/integrations.less @@ -0,0 +1,42 @@ +.admin-integrations-new-panel { + .admin-integrations-new-item { + display: flex; + align-items: center; + padding: 20px 10px; + color: #444; + border-bottom: 1px solid #ddd; + cursor: pointer; + + &:hover { + background-color: #fafafa; + } + + >i { + font-size: 2rem; + color: #aaa; + } + + .admin-integrations-new-item-body { + display: flex; + flex-direction: column; + flex-grow: 1; + padding: 0 20px; + } + + .admin-integrations-new-item-title { + font-size: 1.4rem; + line-height: 2.1rem; + font-weight: 500; + } + + .admin-integrations-new-item-description { + font-size: 1rem; + line-height: 1.5rem; + color: #aaa; + } + } + + > a:last-child > .admin-integrations-new-item { + border-bottom: none; + } +} diff --git a/packages/rocketchat-integrations/client/stylesheets/load.coffee b/packages/rocketchat-integrations/client/stylesheets/load.coffee new file mode 100644 index 00000000000..88d4bb35ad1 --- /dev/null +++ b/packages/rocketchat-integrations/client/stylesheets/load.coffee @@ -0,0 +1,2 @@ +RocketChat.theme.addPackageAsset -> + return Assets.getText 'client/stylesheets/integrations.less' diff --git a/packages/rocketchat-integrations/client/views/integrations.coffee b/packages/rocketchat-integrations/client/views/integrations.coffee new file mode 100644 index 00000000000..be6f7ccdc46 --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrations.coffee @@ -0,0 +1,3 @@ +Template.integrations.helpers + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-integrations' diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html new file mode 100644 index 00000000000..94402e8603d --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -0,0 +1,15 @@ +<template name="integrations"> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-integrations-new"}}" class="button primary new-role">{{_ "New_integration"}}</a> + + {{#each integration}} + <div> + + </div> + {{/each}} + {{else}} + {{_ "Not_authorized"}} + {{/if}} + </div> +</template> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee new file mode 100644 index 00000000000..2ce5018f126 --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -0,0 +1,8 @@ +Template.integrationsIncoming.helpers + + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-integrations' + + data: -> + return {} = + channelType: 'c' diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html new file mode 100644 index 00000000000..4b723e36d2e --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -0,0 +1,59 @@ +<template name="integrationsIncoming"> + <div class="permissions-manager"> + {{#if hasPermission}} + <a href="{{pathFor "admin-integrations-new"}}"><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>Post to Channel</label> + <div> + <div> + <label><input type="radio" name="channelType" value="c" checked="{{$eq data.channelType 'c'}}" /> {{_ "Channel"}}</label> + <label><input type="radio" name="channelType" value="d" checked="{{$eq data.channelType 'd'}}" /> {{_ "User"}}</label> + </div> + <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{_ 'User_or_channel_name'}}" /> + <div class="settings-description">Messages that are sent to the incoming webhook will be posted here.</div> + </div> + </div> + <div class="input-line double-col"> + <label>Customize Name</label> + <div> + <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> + <div class="settings-description">Choose the username that this integration will post as.</div> + </div> + </div> + <!-- <div class="input-line double-col"> + <label>Customize Icon</label> + <div> + {{#if value}} + <div class="settings-file-preview"> + <div class="preview" style="background-image:url({{value}}?_dc={{random}});"></div> + <div class="action"> + <button type="button" class="button red delete-asset"><i class="icon-trash"></i>{{_ 'Delete'}}</button> + </div> + </div> + {{else}} + <div class="settings-file-preview"> + <div class="preview no-file"><i class="icon-upload"></i></div> + <div class="action"> + <div class="button primary">{{_ 'Select_file'}} + <input type="file" accept="{{fileConstraints.contentType}}" /> + </div> + </div> + </div> + {{/if}} + <div class="settings-description">Change the icon that is used for messages from this integration.</div> + </div> + </div> --> + </div> + </div> + <div class="submit"> + <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/client/views/integrationsNew.coffee b/packages/rocketchat-integrations/client/views/integrationsNew.coffee new file mode 100644 index 00000000000..dfa96b39691 --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsNew.coffee @@ -0,0 +1,3 @@ +Template.integrationsNew.helpers + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-integrations' diff --git a/packages/rocketchat-integrations/client/views/integrationsNew.html b/packages/rocketchat-integrations/client/views/integrationsNew.html new file mode 100644 index 00000000000..5f256aa12f0 --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsNew.html @@ -0,0 +1,44 @@ +<template name="integrationsNew"> + <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="admin-integrations-new-panel"> + <a href="{{pathFor "admin-integrations-incoming"}}"> + <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 + </div> + <div class="admin-integrations-new-item-description"> + Send data into Rocket.Chat in real-time. + </div> + </div> + <i class="icon-angle-right"></i> + </div> + </a> + <a href="{{pathFor "admin-integrations-incoming"}}"> + <div class="admin-integrations-new-item"> + <i class="icon-logout"></i> + <div class="admin-integrations-new-item-body"> + <div class="admin-integrations-new-item-title"> + Outgoing WebHook + </div> + <div class="admin-integrations-new-item-description"> + Get data out of Rocket.Chat in real-time. + </div> + </div> + <i class="icon-angle-right"></i> + </div> + </a> + </div> + </div> + </div> + {{else}} + {{_ "Not_authorized"}} + {{/if}} + </div> +</template> diff --git a/packages/rocketchat-integrations/i18n/en.i18n.json b/packages/rocketchat-integrations/i18n/en.i18n.json new file mode 100644 index 00000000000..0db3279e44b --- /dev/null +++ b/packages/rocketchat-integrations/i18n/en.i18n.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/packages/rocketchat-integrations/i18n/pt.i18n.json b/packages/rocketchat-integrations/i18n/pt.i18n.json new file mode 100644 index 00000000000..0db3279e44b --- /dev/null +++ b/packages/rocketchat-integrations/i18n/pt.i18n.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/packages/rocketchat-integrations/lib/rocketchat.coffee b/packages/rocketchat-integrations/lib/rocketchat.coffee new file mode 100644 index 00000000000..c04702a3fff --- /dev/null +++ b/packages/rocketchat-integrations/lib/rocketchat.coffee @@ -0,0 +1 @@ +RocketChat.integrations = {} diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js new file mode 100644 index 00000000000..588673a00a6 --- /dev/null +++ b/packages/rocketchat-integrations/package.js @@ -0,0 +1,71 @@ +Package.describe({ + name: 'rocketchat:integrations', + version: '0.0.1', + summary: 'Integrations with services and WebHooks', + git: '', + documentation: 'README.md' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use('coffeescript'); + api.use('underscore'); + api.use('rocketchat:lib@0.0.1'); + + api.use('kadira:flow-router', 'client'); + api.use('templating', 'client'); + + api.addFiles('lib/rocketchat.coffee', ['server','client']); + api.addFiles('client/collection.coffee', ['client']); + api.addFiles('client/startup.coffee', 'client'); + api.addFiles('client/route.coffee', 'client'); + + // views + api.addFiles('client/views/integrations.html', 'client'); + api.addFiles('client/views/integrations.coffee', 'client'); + api.addFiles('client/views/integrationsNew.html', 'client'); + api.addFiles('client/views/integrationsNew.coffee', 'client'); + api.addFiles('client/views/integrationsIncoming.html', 'client'); + api.addFiles('client/views/integrationsIncoming.coffee', 'client'); + + // stylesheets + api.addAssets('client/stylesheets/integrations.less', 'server'); + api.addFiles('client/stylesheets/load.coffee', 'server'); + + // api.addFiles('server/models/Permissions.coffee', ['server']); + + // api.addFiles('server/functions/addUsersToRoles.coffee', ['server']); + // api.addFiles('server/functions/getPermissionsForRole.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']); + + // // publications + // api.addFiles('server/publication.coffee', ['server']); + // api.addFiles('server/publications/roles.coffee', 'server'); + // api.addFiles('server/publications/usersInRole.coffee', 'server'); + + // // methods + // api.addFiles('server/methods/addUserToRole.coffee', 'server'); + // api.addFiles('server/methods/deleteRole.coffee', 'server'); + // api.addFiles('server/methods/removeUserFromRole.coffee', 'server'); + // api.addFiles('server/methods/saveRole.coffee', 'server'); + // api.addFiles('server/methods/addPermissionToRole.coffee', 'server'); + // api.addFiles('server/methods/removeRoleFromPermission.coffee', 'server'); + + // api.addFiles('server/startup.coffee', ['server']); + + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-authorization/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-authorization/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n', ['client', 'server']); + api.addFiles(tapi18nFiles, ['client', 'server']); +}); -- GitLab From 073df1ae450e3a1cf8ffa610d1deccaafaaecda6 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 21:31:39 -0500 Subject: [PATCH 0702/1338] versions.txt has been removed, fix tag to restore docker image builds --- .travis.yml | 2 +- .travis/builddocker.sh | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a2ab3dfa3b3..cd98bfdaeb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ before_install: - mkdir -p node_modules - cd $TRAVIS_BUILD_DIR - mkdir ../build +- export TAG=$(git describe --abbrev=0 --tags) - export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") - export PATH=$PATH:/tmp/sandstorm-$SANDSTORM_VERSION/bin - cd .sandstorm @@ -19,7 +20,6 @@ before_install: script: - cd $TRAVIS_BUILD_DIR - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi -- export TAG=$(git describe --abbrev=0 --tags) - meteor build ../build - cp ../build/Rocket.Chat.tar.gz /home/vagrant - cd .travis diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index cec3db23b27..f542566d639 100644 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -1,5 +1,10 @@ +#!/bin/bash + +set -euo pipefail + + if [ -z ${TRAVIS_TAG+x} ]; -then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': \'$TRAVIS_BRANCH\', 'docker_tag': \'`cat ../../build/version.txt`\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; -else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': \'$TRAVIS_TAG\', 'docker_tag': \'`cat ../../build/version.txt`\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': \'$TRAVIS_BRANCH\', 'docker_tag': \'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': \'$TRAVIS_TAG\', 'docker_tag': \'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; fi -- GitLab From 8c5d3a245c86a400d8a0bbc64016a05d44dabba3 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 4 Dec 2015 21:49:28 -0500 Subject: [PATCH 0703/1338] fix unsupported option --- .travis/builddocker.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index f542566d639..8aa10fb6429 100644 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -1,7 +1,6 @@ #!/bin/bash -set -euo pipefail - +set -eu if [ -z ${TRAVIS_TAG+x} ]; then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': \'$TRAVIS_BRANCH\', 'docker_tag': \'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; -- GitLab From b9bce0b4e7741b59b0288d4a79728b671ea56edf Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 21:52:59 -0500 Subject: [PATCH 0704/1338] fail fast the shell script --- .travis.yml | 2 +- .travis/builddocker.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index cd98bfdaeb6..df91835e5a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,4 +41,4 @@ deploy: - master after_deploy: - cd .travis -- sh ./builddocker.sh +- ./builddocker.sh diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index 8aa10fb6429..8ec9dc48fe7 100644 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -1,6 +1,6 @@ #!/bin/bash -set -eu +set -euo pipefail if [ -z ${TRAVIS_TAG+x} ]; then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': \'$TRAVIS_BRANCH\', 'docker_tag': \'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; -- GitLab From 66030092adb19e11c3326448a5937a5a7924fcf2 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 22:08:15 -0500 Subject: [PATCH 0705/1338] fix permissions --- .travis/builddocker.sh | 0 .travis/namefiles.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .travis/builddocker.sh mode change 100644 => 100755 .travis/namefiles.sh diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh old mode 100644 new mode 100755 diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh old mode 100644 new mode 100755 -- GitLab From 67518129613300239bae9baa04611672b770d75b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 22:23:32 -0500 Subject: [PATCH 0706/1338] restore docket builds --- .travis/builddocker.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index 8ec9dc48fe7..fc50d402334 100755 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -3,7 +3,7 @@ set -euo pipefail if [ -z ${TRAVIS_TAG+x} ]; -then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': \'$TRAVIS_BRANCH\', 'docker_tag': \'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; -else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': \'$TRAVIS_TAG\', 'docker_tag': \'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH\'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': '$TRAVIS_BRANCH', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': '$TRAVIS_TAG', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; fi -- GitLab From 23ceece2c77047d2bfdf5a6cb71d8a22838e3092 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 4 Dec 2015 22:53:15 -0500 Subject: [PATCH 0707/1338] escape curl command --- .travis/builddocker.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index fc50d402334..cbf7da106a3 100755 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -3,7 +3,7 @@ set -euo pipefail if [ -z ${TRAVIS_TAG+x} ]; -then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': '$TRAVIS_BRANCH', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; -else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': '$TRAVIS_TAG', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +then "\"curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': '$TRAVIS_BRANCH', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/\""; +else "\"curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': '$TRAVIS_TAG', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/\""; fi -- GitLab From fc57cb20e40efa3498655e947a6ed9d4bb16c89b Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Fri, 4 Dec 2015 23:06:17 -0500 Subject: [PATCH 0708/1338] retrigger docker builds --- .travis.yml | 2 +- .travis/builddocker.sh | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index df91835e5a9..cd98bfdaeb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,4 +41,4 @@ deploy: - master after_deploy: - cd .travis -- ./builddocker.sh +- sh ./builddocker.sh diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index cbf7da106a3..fc464d8c96c 100755 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -1,9 +1,8 @@ -#!/bin/bash -set -euo pipefail +set -eu if [ -z ${TRAVIS_TAG+x} ]; -then "\"curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': '$TRAVIS_BRANCH', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/\""; -else "\"curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': '$TRAVIS_TAG', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/\""; +then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': '$TRAVIS_BRANCH', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': '$TRAVIS_TAG', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; fi -- GitLab From e36cf8da5be1fcd63ab346d764e43cbe2371b78f Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Sat, 5 Dec 2015 08:32:19 -0500 Subject: [PATCH 0709/1338] re-trigger docker build --- .travis.yml | 2 +- .travis/builddocker.sh | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index cd98bfdaeb6..df91835e5a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,4 +41,4 @@ deploy: - master after_deploy: - cd .travis -- sh ./builddocker.sh +- ./builddocker.sh diff --git a/.travis/builddocker.sh b/.travis/builddocker.sh index fc464d8c96c..14d59768cc5 100755 --- a/.travis/builddocker.sh +++ b/.travis/builddocker.sh @@ -1,8 +1,23 @@ +#!/bin/bash -set -eu +set -euo pipefail + +# TRAVIS_TAG='v0.7' +# TAG="v0.7" +# TRAVIS_BUILD_NUMBER="1234" +# TRAVIS_BRANCH="develop" +# PUSHTOKEN="secret" + +CURL_HEADER="Content-Type: application/json" +CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" if [ -z ${TRAVIS_TAG+x} ]; -then "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Branch', 'source_name': '$TRAVIS_BRANCH', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; -else "curl -H \"Content-Type: application/json\" --data \"{'source_type': 'Tag', 'source_name': '$TRAVIS_TAG', 'docker_tag': '$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'}\" -X POST https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"; +then +CURL_DATA='{"source_type": "Branch", "source_name": "'$TRAVIS_BRANCH'", "docker_tag": "'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'"}'; +else +CURL_DATA='{"source_type": "Tag", "source_name": "'$TAG'", "docker_tag": "'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'"}'; fi +curl -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST "${CURL_URL}" + + -- GitLab From 47bca49ae51adbee47204061bfcc6af334aad58c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 5 Dec 2015 22:39:16 -0200 Subject: [PATCH 0710/1338] Fix push notification for android --- .../rocketchat-ui/lib/cordova/push.coffee | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/rocketchat-ui/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee index c5d7574e093..659305fcf1d 100644 --- a/packages/rocketchat-ui/lib/cordova/push.coffee +++ b/packages/rocketchat-ui/lib/cordova/push.coffee @@ -54,16 +54,16 @@ if Meteor.isCordova Push.addListener 'message', (notification) -> Meteor.call 'log', 'CLIENT', 'message', arguments - Tracker.autorun -> - if RocketChat.settings.get('Push_enable') is true - android_senderID = RocketChat.settings.get 'Push_gcm_project_number' + Meteor.startup -> + Tracker.autorun -> + if RocketChat.settings.get('Push_enable') is true - Push.Configure - android: - senderID: android_senderID - sound: true - vibrate: true - ios: - badge: true - sound: true - alert: true + Push.Configure + android: + senderID: window.ANDROID_SENDER_ID + sound: true + vibrate: true + ios: + badge: true + sound: true + alert: true -- GitLab From 7a3f1812c9ec76fd4fa7b4facb80625328c0e757 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 5 Dec 2015 22:39:34 -0200 Subject: [PATCH 0711/1338] Enable push bay default and improve settings organization --- .../server/startup/settings.coffee | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index b5ac283749b..2421e30a7ec 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -100,18 +100,18 @@ 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', 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', false, { type: 'boolean', group: 'Push', public: true } -RocketChat.settings.add 'Push_apn_passphrase', '', { type: 'string', group: 'Push' } -RocketChat.settings.add 'Push_apn_key', '', { type: 'string', multiline: true, group: 'Push' } -RocketChat.settings.add 'Push_apn_cert', '', { type: 'string', multiline: true, group: 'Push' } -RocketChat.settings.add 'Push_apn_dev_passphrase', '', { type: 'string', group: 'Push' } -RocketChat.settings.add 'Push_apn_dev_key', '', { type: 'string', multiline: true, group: 'Push' } -RocketChat.settings.add 'Push_apn_dev_cert', '', { type: 'string', multiline: true, group: 'Push' } -RocketChat.settings.add 'Push_gcm_api_key', '', { type: 'string', group: 'Push' } -RocketChat.settings.add 'Push_gcm_project_number', '', { type: 'string', group: 'Push', public: true } +RocketChat.settings.add 'Push_production', true, { type: 'boolean', group: 'Push', public: true } +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' } -- GitLab From 22739812ac3605fa502a4209314497a6fb688472 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 5 Dec 2015 22:39:51 -0200 Subject: [PATCH 0712/1338] Add some translations --- i18n/en.i18n.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index ed6fdf939d9..6285218a57f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -96,6 +96,7 @@ "Busy_male" : "Busy", "Cancel" : "Cancel", "CDN_PREFIX" : "CDN Prefix", + "Certificates_and_Keys" : "Certificates and Keys", "Change_avatar" : "Change avatar", "Channels" : "Channels", "Channels_list" : "List of public channels", @@ -325,6 +326,8 @@ "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", "Push_enable" : "Enable", + "Push_enable_gateway" : "Enable Gateway", + "Push_gateway" : "Gateway", "Push_gcm_api_key" : "GCM API Key", "Push_gcm_project_number" : "GCM Project Number", "Push_production" : "Production", @@ -418,6 +421,7 @@ "Stop_Recording" : "Stop Recording", "strike" : "strike", "Submit" : "Submit", + "The_configured_URL_is_different_from_the_URL_you_are_accessing" : "The configured URL is different from the URL you are accessing!", "The_field_is_required" : "The field %s is required.", "True" : "True", "Unnamed" : "Unnamed", -- GitLab From 6f55db420310aa8d46d31da7f4a5e1ff81c93157 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 5 Dec 2015 22:40:11 -0200 Subject: [PATCH 0713/1338] Alert admin if configured url is different from current --- .../rocketchat-lib/client/lib/settings.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee index fdbfa3c26f6..579f7234991 100644 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ b/packages/rocketchat-lib/client/lib/settings.coffee @@ -30,3 +30,18 @@ RocketChat.settings.init = -> initialLoad = false RocketChat.settings.init() + +Meteor.startup -> + Tracker.autorun (c) -> + siteUrl = RocketChat.settings.get('Site_Url') + if not siteUrl or not Meteor.userId()? + return + + if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false + 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') + + return c.stop() -- GitLab From 6ff62d1ec5bb99cb36cd0c4f07cd9db16e963d80 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 5 Dec 2015 22:40:25 -0200 Subject: [PATCH 0714/1338] Translate section of settings --- packages/rocketchat-ui-admin/admin/admin.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 68df2179560..3375b44f776 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}} + {{_ section}} </div> <div class="section-title-right"> <button class="button secondary expand"><span>{{_ "Expand"}}</span></button> -- GitLab From 27029ac44cc0fa7c2cfd5be0463b081c9984ed01 Mon Sep 17 00:00:00 2001 From: ymegane <crybaby.sumire+github@gmail.com> Date: Fri, 27 Nov 2015 16:15:04 +0900 Subject: [PATCH 0715/1338] Add "Meiryo UI" to font-family --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index fcf06ddf5a9..016fb3f49ae 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -394,7 +394,7 @@ html { } body { - font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; + font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif, "Meiryo UI"; font-size: 0.875rem; height: 100%; width: 100%; -- GitLab From d467d29b9aaf63688dca578723447ca6073535ae Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 7 Dec 2015 10:33:13 -0200 Subject: [PATCH 0716/1338] fix livechat visitor can't chat after refresh --- .../app/client/views/room.coffee | 2 +- packages/rocketchat-livechat/package.js | 1 + .../server/publications/visitorRoom.js | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-livechat/server/publications/visitorRoom.js diff --git a/packages/rocketchat-livechat/app/client/views/room.coffee b/packages/rocketchat-livechat/app/client/views/room.coffee index 3ac81b7c284..f29371d9d73 100644 --- a/packages/rocketchat-livechat/app/client/views/room.coffee +++ b/packages/rocketchat-livechat/app/client/views/room.coffee @@ -38,7 +38,7 @@ Template.room.events Template.room.onCreated -> self = @ self.autorun -> - self.subscribe 'visitorRoom', visitor.getToken(), -> + self.subscribe 'livechat:visitorRoom', visitor.getToken(), -> room = ChatRoom.findOne() if room? visitor.setRoom room._id diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 50bad731694..0cc296524de 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -53,6 +53,7 @@ Package.onUse(function(api) { // publications api.addFiles('server/publications/livechatAgents.js', 'server'); api.addFiles('server/publications/livechatManagers.js', 'server'); + api.addFiles('server/publications/visitorRoom.js', 'server'); // livechat app api.addAssets('rocket-livechat.js', 'client'); diff --git a/packages/rocketchat-livechat/server/publications/visitorRoom.js b/packages/rocketchat-livechat/server/publications/visitorRoom.js new file mode 100644 index 00000000000..52b4fab49f6 --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/visitorRoom.js @@ -0,0 +1,14 @@ +Meteor.publish('livechat:visitorRoom', function(visitorToken) { + console.log('[publish] livechat:visitorRoom -> '.green, 'arguments:', arguments); + + return RocketChat.models.Rooms.findByVisitorToken(visitorToken, { + fields: { + name: 1, + t: 1, + cl: 1, + u: 1, + usernames: 1, + v: 1 + } + }); +}); -- GitLab From 9e8b3a550c517821b275596062131b0264c1d19e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 7 Dec 2015 10:59:42 -0200 Subject: [PATCH 0717/1338] fix can't send msgs to new livechat rooms --- packages/rocketchat-ui/lib/RoomManager.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index ee2ad7308e1..a0c0a3c1c87 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -94,10 +94,10 @@ RocketChat.Notifications.onUser 'message', (msg) -> query = t: type - if type in ['c', 'p'] - query.name = name - else if type is 'd' + if type is 'd' query.usernames = $all: [Meteor.user()?.username, name] + else + query.name = name room = ChatRoom.findOne query, { reactive: false } -- GitLab From 0f72396e9f82ae041ecbc763eba0e7dc798d7dc5 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 7 Dec 2015 14:43:24 +0000 Subject: [PATCH 0718/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 81 ++++++- i18n/cs.i18n.json | 2 +- i18n/de.i18n.json | 27 ++- i18n/el.i18n.json | 1 - i18n/en.i18n.json | 5 +- i18n/es.i18n.json | 1 - i18n/fi.i18n.json | 1 - i18n/fr.i18n.json | 1 - i18n/he.i18n.json | 1 - i18n/hr.i18n.json | 1 - i18n/hu.i18n.json | 1 - i18n/it.i18n.json | 1 - i18n/ja.i18n.json | 1 - i18n/km.i18n.json | 1 - i18n/ko.i18n.json | 1 - i18n/ms-MY.i18n.json | 1 - i18n/pl.i18n.json | 213 +++++++++++++++++- i18n/pt.i18n.json | 3 +- i18n/ru.i18n.json | 1 - i18n/sq.i18n.json | 77 +++++++ i18n/sv.i18n.json | 1 - i18n/ta-IN.i18n.json | 1 - i18n/tr.i18n.json | 1 - i18n/ug.i18n.json | 1 - i18n/uk.i18n.json | 1 - i18n/zh.i18n.json | 1 - .../i18n/ar.i18n.json | 4 + .../i18n/cs.i18n.json | 3 + .../i18n/de.i18n.json | 4 + .../i18n/el.i18n.json | 4 + .../i18n/en.i18n.json | 43 ++-- .../i18n/es.i18n.json | 4 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 4 + .../i18n/fr.i18n.json | 4 + .../i18n/he.i18n.json | 4 + .../i18n/hr.i18n.json | 4 + .../i18n/hu.i18n.json | 4 + .../i18n/it.i18n.json | 4 + .../i18n/ja.i18n.json | 4 + .../i18n/km.i18n.json | 4 + .../i18n/ko.i18n.json | 4 + .../i18n/ms-MY.i18n.json | 4 + .../i18n/pl.i18n.json | 4 + .../i18n/pt.i18n.json | 43 ++-- .../i18n/ru.i18n.json | 4 + .../i18n/sq.i18n.json | 3 + .../i18n/sv.i18n.json | 3 + .../i18n/ta-IN.i18n.json | 4 + .../i18n/tr.i18n.json | 4 + .../i18n/ug.i18n.json | 4 + .../i18n/uk.i18n.json | 4 + .../i18n/zh.i18n.json | 4 + .../i18n/pl.i18n.json | 9 +- .../i18n/sq.i18n.json | 1 + packages/rocketchat-chatops/i18n/pl.i18n.json | 6 +- packages/rocketchat-chatops/i18n/sq.i18n.json | 1 + .../i18n/de.i18n.json | 3 +- .../i18n/pl.i18n.json | 8 +- .../i18n/sq.i18n.json | 1 + packages/rocketchat-gitlab/i18n/pl.i18n.json | 4 +- packages/rocketchat-gitlab/i18n/sq.i18n.json | 1 + packages/rocketchat-hubot/i18n/pl.i18n.json | 6 +- packages/rocketchat-hubot/i18n/sq.i18n.json | 1 + packages/rocketchat-ldap/i18n/sq.i18n.json | 1 + packages/rocketchat-lib/i18n/sq.i18n.json | 1 + .../rocketchat-livechat/i18n/en.i18n.json | 28 +-- .../rocketchat-livechat/i18n/pl.i18n.json | 5 +- .../rocketchat-livechat/i18n/pt.i18n.json | 28 +-- .../rocketchat-livechat/i18n/sq.i18n.json | 1 + packages/rocketchat-mailer/i18n/pl.i18n.json | 16 +- packages/rocketchat-mailer/i18n/sq.i18n.json | 1 + .../rocketchat-message-pin/i18n/ar.i18n.json | 5 +- .../rocketchat-message-pin/i18n/pl.i18n.json | 11 +- .../rocketchat-message-pin/i18n/sq.i18n.json | 1 + .../rocketchat-message-star/i18n/ar.i18n.json | 5 +- .../rocketchat-message-star/i18n/de.i18n.json | 5 +- .../rocketchat-message-star/i18n/pl.i18n.json | 8 +- .../rocketchat-message-star/i18n/sq.i18n.json | 1 + .../i18n/pl.i18n.json | 6 +- .../i18n/sq.i18n.json | 1 + .../i18n/de.i18n.json | 3 +- .../i18n/pl.i18n.json | 5 +- .../i18n/sq.i18n.json | 1 + packages/rocketchat-theme/i18n/pl.i18n.json | 24 +- packages/rocketchat-theme/i18n/sq.i18n.json | 1 + packages/rocketchat-webrtc/i18n/de.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/pl.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/sq.i18n.json | 1 + .../rocketchat-wordpress/i18n/pl.i18n.json | 7 +- .../rocketchat-wordpress/i18n/sq.i18n.json | 1 + 91 files changed, 703 insertions(+), 124 deletions(-) create mode 100644 i18n/sq.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ar.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/cs.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/de.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/el.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/es.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/fa.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/fi.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/fr.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/he.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/hr.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/hu.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/it.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ja.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/km.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ko.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/pl.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ru.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/sq.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/sv.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/tr.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ug.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/uk.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/zh.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/sq.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/sq.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/sq.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/sq.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/sq.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/sq.i18n.json create mode 100644 packages/rocketchat-lib/i18n/sq.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/sq.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/sq.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/sq.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/sq.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/sq.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/sq.i18n.json create mode 100644 packages/rocketchat-theme/i18n/sq.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/sq.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/sq.i18n.json diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index eca96366ccf..f12d75a47d0 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -1,14 +1,36 @@ { + "Access_online_demo" : "الدخول إلى العرض التجريبي", + "Access_Online_Demo" : "الدخول إلى العرض التجريبي", + "Add_Members" : "إضاÙØ© الأعضاء", "Add_users" : "إضاÙØ© مستخدمين", + "All_channels" : "جميع القنوات", "and" : "Ùˆ", + "are_also_typing" : "هم أيضا يكتبون", + "are_typing" : "يكتبون", + "Are_you_sure" : "هل أنت متأكد؟", + "away" : "بعيد", + "Away" : "بعيد", + "Back_to_login" : "العودة إلى تسجيل الدخول", + "bold" : "عريض", + "busy" : "مشغول", + "Busy" : "مشغول", + "busy_female" : "مشغولة", + "Busy_female" : "مشغولة", + "busy_male" : "مشغول", + "Busy_male" : "مشغول", "Cancel" : "إلغاء", + "Change_avatar" : "تغيير الصورة الرمزية", "Channels" : "القنوات", "Channels_list" : "قائمة القنوات العامة", "Chat_Rooms" : "غر٠المØادثة", "close" : "أغلق", + "coming_soon" : "قريبا", "Confirm_password" : "تأكيد كلمة السر", "Conversation" : "Ù…Øادثة", + "Create_new" : "إنشاء جديد", + "Create_new_private_group" : "إنشاء مجموعة خاصة جديدة", "Create_new_public_channel" : "إنشاء قناة عامة جديدة", + "Created_at" : "أنشئت ÙÙŠ", "Direct_Messages" : "الرسائل المباشرة", "edited" : "عدلت", "Email_or_username" : "البريد الإلكتروني أو اسم المستخدم", @@ -17,21 +39,43 @@ "Error_changing_password" : "خطأ ÙÙŠ تغيير كلمة السر", "Favorites" : "المÙضلة", "Forgot_password" : "نسيت كلمة السر", + "Get_to_know_the_team" : "تعر٠على Rocket.Team", + "github_no_public_email" : "ليس لديك أي بريد الإلكتروني عام ÙÙŠ Øسابك على Github", "Hide_room" : "إخÙاء الغرÙØ©", "History" : "تاريخ", + "inline_code" : "نص_برمجي", "Invalid_confirm_pass" : "تأكيد كلمة السر لا تطابق كلمة السر", "Invalid_email" : "البريد الإلكتروني المدخل غير صØÙŠØ", "Invalid_name" : "لا يجب أن يكون الاسم Ùارغ", "Invalid_pass" : "لا يجب أن تكون كلمة السر Ùارغة", + "invisible" : "Ø®ÙÙŠ", + "Invisible" : "Ø®ÙÙŠ", + "Invite_Users" : "دعوة المستخدمين", + "is_also_typing" : "هو أيضا يكتب", + "is_typing" : "يكتب", + "italics" : "مائل", + "join" : "انضم", + "Join_the_Community" : "إنظم للمجتمع", + "Language" : "لغة", "Language_Version" : "النسخة الإنجليزية", "Last_message" : "آخر رسالة", "Leave_room" : "مغادرة الغرÙØ©", + "line" : "خط", "Load_more" : "اعرض أكثر", + "Loading_suggestion" : "تØميل الاقتراØات ...", "Login" : "تسجيل الدخول", + "Login_with" : "تسجيل الدخول بـ %s", + "login_with" : "أو الدخول مباشرة مع", + "Logout" : "تسجيل خروج", "Members" : "الأعضاء", "Members_List" : "قائمة الأعضاء", "Members_placeholder" : "الأعضاء", + "Message_removed" : "مسØت الرسالة", + "Messages" : "رسائل", "More_channels" : "المزيد من القنوات", + "Msgs" : "رسائل", + "multi" : "متعدد", + "n_messages" : "%s رسائل", "Name" : "اسم", "New_messages" : "رسائل جديدة", "New_password" : "كلمة سر جديدة", @@ -39,10 +83,18 @@ "No_direct_messages_yet" : "لم تبدأ أي Ù…Øادثات Øتى الآن.", "No_favorites_yet" : "لم تقم بإضاÙØ© Ù…Ùضلات بعد.", "No_groups_yet" : "لا يوجد لديك مجموعات خاصة Øتى الآن.", + "No_permission_to_view_room" : "ليس لديك صلاØية لرؤية هذه الغرÙØ©", + "Not_allowed" : "غير مسموØ", + "Not_found_or_not_allowed" : "غير موجود أو غير مسموØ", + "Nothing_found" : "لا يوجد شيء", + "Online" : "متواجد", + "Oops!" : "عÙوا", "Password" : "كلمة السر", "Please_wait" : "يرجى الانتظار", + "Privacy" : "خصوصية", "Private_Groups" : "مجموعات خاصة", "Quick_Search" : "بØØ« سريع", + "quote" : "اقتباس", "Register" : "تسجيل Øساب جديد", "Remember_me" : "تذكرني", "Remove" : "إزالة", @@ -50,19 +102,42 @@ "Room" : "غرÙØ©", "Room_name_changed" : "تم تغيير اسم الغرÙØ© إلى: <em>__room_name__</em> بواسطة <em>__user_by__</em>", "Room_name_changed_successfully" : "تم تغيير اسم الغرÙØ© بنجاØ", - "Save" : "ØÙظ", "Search" : "بØØ«", + "Search_Messages" : "بØØ« الرسائل", + "Select_an_avatar" : "اختر صورة", + "Select_file" : "اختر ملÙا", + "Select_service_to_login" : "اختر خدمة للدخول إليها لتØميل صورتك أو قم بالتØميل مباشرة من جهازك", "Selected_users" : "أعضاء مختارين", "Send_confirmation_email" : "إرسال رسالة تأكيد", "Send_Message" : "أرسل رسالة", + "Settings" : "إعدادات", + "Showing_results" : "<p>يعرض <b>%s</b> نتائج</p>", + "Silence" : "الصمت", + "since_creation" : "منذ %s", "Start_of_conversation" : "بداية المØادثة", + "Stats_Total_Messages" : "مجموع الرسائل", + "strike" : "شطب", + "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_joined_channel" : "وقد انضمت قناة.", + "User_joined_channel" : "انضم للقناة.", "User_left" : "غادر القناة.", + "User_logged_out" : "المستخدم سجل الخروج", "User_removed_by" : "تم ØØ°Ù <em>__user_removed__</em> بواسطة <em>__user_by__</em>.", + "Username" : "اسم المستخدم", + "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_need_confirm_email" : "تØتاج إلى تأكيد بريدك الإلكتروني لتسجيل الدخول!" + "You_need_confirm_email" : "تØتاج إلى تأكيد بريدك الإلكتروني لتسجيل الدخول!", + "Your_Open_Source_solution" : "تطبيق المØادثة الخاص بك المÙØªÙˆØ Ø§Ù„Ù…ØµØ¯Ø±" } \ No newline at end of file diff --git a/i18n/cs.i18n.json b/i18n/cs.i18n.json index ea6cb524892..74ef43aab83 100644 --- a/i18n/cs.i18n.json +++ b/i18n/cs.i18n.json @@ -32,7 +32,6 @@ "Recents" : "Nedávné", "Room_name_changed" : "Jméno mÃstnosti zmÄ›nÄ›no na: <em>__room_name__</em> uživatelem <em>__user_by__</em>", "Room_name_changed_successfully" : "ZmÄ›na jména mÃstnosti probÄ›hla úspěšnÄ›", - "Save" : "Uložit", "See_all" : "Zobrazit vÅ¡echny", "See_only_online" : "Pouze online", "Selected_users" : "Vybranà Älenové", @@ -42,5 +41,6 @@ "User_added_by" : "<em>__user_by__</em> pÅ™idal uživatele <em>__user_added__</em>.", "User_left" : "Opustil(a) kanál.", "User_removed_by" : "<em>__user_by__</em> odstranil uživatele <em>__user_removed__</em>.", + "View_All" : "Zobrazit vÅ¡e", "Welcome" : "VÃtej <em>%s</em>." } \ No newline at end of file diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 0040d1a3823..22c80008b85 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -2,6 +2,13 @@ "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", "Accounts_EmailVerification" : "E-Mail-Verifizierung", "Accounts_ManuallyApproveNewUsers" : "Neue Benutzer manuell aktivieren", @@ -21,6 +28,9 @@ "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", @@ -45,6 +55,7 @@ "API" : "API", "API_Analytics" : "Analytics", "API_Embed" : "Einbetten", + "API_EmbedDisabledFor" : "Deaktiviere Embed für User", "API_EmbedDisabledFor_Description" : "Durch Kommata getrennte Liste von Benutzernamen", "are_also_typing" : "schreiben auch", "are_typing" : "schreiben", @@ -89,9 +100,11 @@ "Custom_oauth_unique_name" : "Eindeutigen Namen von benutzerdefinierte oauth", "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.", "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", "Direct_Messages" : "Private Nachrichten", "Disable_Favorite_Rooms" : "Favoriten deaktivieren", @@ -118,6 +131,7 @@ "FileUpload_Enabled" : "Datei-Upload aktivieren", "FileUpload_MaxFileSize" : "Max. Größe für hochgeladene Dateien (in Bytes)", "FileUpload_MediaTypeWhiteList" : "Durch Kommata getrennte Liste von 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.", "Forgot_password" : "Passwort vergessen?", "Fork_it_on_github" : "Fork es auf GitHub", @@ -170,7 +184,9 @@ "Layout_Sidenav_Footer_description" : "Die Footer Größe ist 260x70", "Layout_Terms_of_Service" : "Nutzungsbedingungen", "LDAP" : "LDAP", + "LDAP_Bind_Search" : "Bind Suche", "LDAP_DN" : "LDAP DN", + "LDAP_Enable" : "LDAP aktivieren", "LDAP_Port" : "LDAP Port", "LDAP_Url" : "LDAP URL", "Leave_room" : "Raum verlassen", @@ -185,6 +201,7 @@ "Logout" : "Abmelden", "Make_Admin" : "zum Admin machen", "Mark_as_read" : "Als gelesen markieren", + "Markdown_Headers" : "Markdown-Headers", "Members" : "Mitglieder", "Members_List" : "Mitgliederliste", "Members_placeholder" : "Mitglieder", @@ -192,6 +209,7 @@ "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", @@ -203,6 +221,7 @@ "Message_removed" : "Nachricht entfernt", "Message_ShowDeletedStatus" : "Zeige Löschstatus", "Message_ShowEditedStatus" : "Zeige Bearbeitungsstatus", + "Message_ShowFormattingTips" : "Formatierungs-Tipps anzeigen", "Messages" : "Nachrichten", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", @@ -244,6 +263,7 @@ "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.", "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", "Please_wait" : "Bitte warten", @@ -267,6 +287,8 @@ "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debuggen", "Push_enable" : "Aktivieren", + "Push_gcm_api_key" : "GCM API Key", + "Push_gcm_project_number" : "GCM Projektnummer", "Push_production" : "Produktion", "Quick_Search" : "Schnellsuche", "quote" : "Zitat", @@ -289,8 +311,10 @@ "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_Generate_Username" : "Benutzernamen generieren", - "Save" : "Speichern", + "SAML_Custom_Provider" : "Benutzerdefinierter Provider", "Save_changes" : "Änderungen speichern", "Save_Mobile_Bandwidth" : "Mobilfunkbandbreite verringern", "Search" : "Suche", @@ -386,6 +410,7 @@ "User_updated_successfully" : "Benutzer 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_title" : "Benutzernamen festlegen", diff --git a/i18n/el.i18n.json b/i18n/el.i18n.json index d9495ff5276..e10c119709d 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -195,7 +195,6 @@ "Room_name_changed" : "Το όνομα του δωματίου άλλαξε σε: <em>__room_name__</em> από τον χÏήστη <em>__user_by__</em>", "Room_name_changed_successfully" : "Το όνομα του δωματίου άλλαξε επιτυχώς", "room_user_count" : "%s χÏήστες", - "Save" : "Αποθήκευση", "Save_changes" : "Αποθήκευση αλλαγών", "Search" : "Αναζήτηση", "Search_settings" : "Ρυθμίσεις αναζήτησης", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 6285218a57f..f67fe7f4691 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -51,7 +51,7 @@ "Accounts_RegistrationForm" : "Registration Form", "Accounts_RegistrationForm_Public" : "Public", "Accounts_RegistrationForm_Disabled" : "Disabled", - "Accounts_RegistrationForm_LinkReplacementText": "Registration Form Link Replacement Text", + "Accounts_RegistrationForm_LinkReplacementText" : "Registration Form Link Replacement Text", "Accounts_RegistrationForm_Secret_URL" : "Secret URL", "Accounts_RegistrationForm_SecretURL" : "Registration Form Secret URL", "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]", @@ -357,7 +357,6 @@ "SAML_Custom_Generate_Username" : "Generate Username", "SAML_Custom_Issuer" : "Custom Issuer", "SAML_Custom_Provider" : "Custom Provider", - "Save" : "Save", "Save_changes" : "Save changes", "Save_Mobile_Bandwidth" : "Save Mobile Bandwidth", "Search" : "Search", @@ -479,4 +478,4 @@ "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_Open_Source_solution" : "Your own Open Source chat solution" -} +} \ No newline at end of file diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json index d9c22cd7cfb..2936c434ec1 100644 --- a/i18n/es.i18n.json +++ b/i18n/es.i18n.json @@ -103,7 +103,6 @@ "Room" : "Sala", "Room_name_changed" : "El nombre de la sala ha sido cambiado a: <em>__room_name__</em> por <em>__user_by__</em>", "Room_name_changed_successfully" : "El nombre de la sala fue cambiado con éxito", - "Save" : "Guardar", "Search" : "Buscar", "Search_settings" : "Configuración de búsqueda", "See_all" : "Ver todos", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 06ba09ac2fc..7b8e70f53a9 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -330,7 +330,6 @@ "SAML_Custom_Generate_Username" : "Generoi käyttäjätunnus", "SAML_Custom_Issuer" : "Custom Issuer", "SAML_Custom_Provider" : "Custom Provider", - "Save" : "Tallenna", "Save_changes" : "Tallenna muutokset", "Save_Mobile_Bandwidth" : "Säästä kaistaa mobiilissa", "Search" : "Etsi", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index bab470be4b3..31144e2a9c0 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -276,7 +276,6 @@ "Rooms" : "Salons", "S_new_messages_since_s" : "%s nouveaux messages depuis %s", "SAML" : "SAML", - "Save" : "Enregistrer", "Save_changes" : "Sauvegarder les modifications", "Save_Mobile_Bandwidth" : "Préserver la bande passante sur mobile", "Search" : "Recherche", diff --git a/i18n/he.i18n.json b/i18n/he.i18n.json index c6f3ffa45c4..0a641b93d4d 100644 --- a/i18n/he.i18n.json +++ b/i18n/he.i18n.json @@ -102,7 +102,6 @@ "Room" : "חדר", "Room_name_changed" : "×©× ×”×—×“×¨ ×©×•× ×” ל: <em>__room_name__</em> על ידי המשתמש <em>__user_by__</em>", "Room_name_changed_successfully" : "×©× ×”×—×“×¨ ×©×•× ×” בהצלחה", - "Save" : "שמור", "Search" : "חפש", "See_all" : "צפה בהכל", "See_only_online" : "רק מחובר", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 39dc2a776e5..1af3a9b6f94 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -224,7 +224,6 @@ "Rooms" : "Sobe", "S_new_messages_since_s" : "novih poruka od", "SAML_Custom_Generate_Username" : "Izradi korisniÄko ime", - "Save" : "SaÄuvaj", "Save_changes" : "Spremi promjene", "Search" : "Traži", "Search_Messages" : "Pretraži poruke", diff --git a/i18n/hu.i18n.json b/i18n/hu.i18n.json index fbc75e72ccf..abc710b4914 100644 --- a/i18n/hu.i18n.json +++ b/i18n/hu.i18n.json @@ -87,7 +87,6 @@ "Room" : "Szoba", "Room_name_changed" : "A szoba neve megváltozott: <em>__room_name__</em>, megváltoztatta <em>__user_by__</em>", "Room_name_changed_successfully" : "A szoba neve sikeresen megváltozott", - "Save" : "Mentés", "Search" : "Keresés", "See_all" : "Összes megtekintése", "See_only_online" : "Csak online", diff --git a/i18n/it.i18n.json b/i18n/it.i18n.json index 672374e1b9d..12d51aa52a2 100644 --- a/i18n/it.i18n.json +++ b/i18n/it.i18n.json @@ -88,7 +88,6 @@ "Room" : "Stanza", "Room_name_changed" : "Il nome della stanza è cambiato per: <em>__room_name__</em> da <em>__user_by__</em>", "Room_name_changed_successfully" : "Nome della stanza cambiato con successo", - "Save" : "Salva", "Search" : "Ricerca", "See_all" : "Guarda tuttto", "See_only_online" : "Solo online", diff --git a/i18n/ja.i18n.json b/i18n/ja.i18n.json index 318b963b6d9..d373313de64 100644 --- a/i18n/ja.i18n.json +++ b/i18n/ja.i18n.json @@ -109,7 +109,6 @@ "Room" : "ルーム", "Room_name_changed" : "ルームåを変更ã—ã¾ã—ãŸ: <em>__room_name__</em> by <em>__user_by__</em>", "Room_name_changed_successfully" : "ルームåã®å¤‰æ›´ãŒæˆåŠŸã—ã¾ã—ãŸ", - "Save" : "ä¿å˜", "Save_Mobile_Bandwidth" : "モãƒã‚¤ãƒ«ãƒ‡ãƒ¼ã‚¿é€šä¿¡é‡ã‚’節約ã™ã‚‹", "Search" : "検索", "See_all" : "ã™ã¹ã¦è¦‹ã‚‹", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 682995e7985..7eec24db6be 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -310,7 +310,6 @@ "SAML" : "ប្រើ SAML", "SAML_Custom_Cert" : "វិញ្ញាបនបážáŸ’រ​ផ្ទាល់ážáŸ’លួន", "SAML_Custom_Generate_Username" : "គណនាឈ្មោះអ្នកប្រើប្រាស់", - "Save" : "រក្សាទុក", "Save_changes" : "រក្សា​ទុក​ការ​ផ្លាស់​ប្ážáž¼â€‹ážš", "Save_Mobile_Bandwidth" : "រក្សាទុកកម្រិážáž”ញ្ជូនážáž¶áž˜áž‘ូរសáŸáž–្ទដៃ", "Search" : "ស្វែង​រក", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index ad3d826a915..b066ea7f2af 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -279,7 +279,6 @@ "room_user_count" : "%s 사용ìž", "Rooms" : "ë°©", "SAML" : "SAML", - "Save" : "ì €ìž¥", "Save_changes" : "ë³€ê²½ì‚¬í• ì €ìž¥", "Save_Mobile_Bandwidth" : "ëª¨ë°”ì¼ ëŒ€ì—í ì €ìž¥", "Search" : "검색", diff --git a/i18n/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 52e0cc33ed9..6af1ed50e0f 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -264,7 +264,6 @@ "Rooms" : "Bilik", "S_new_messages_since_s" : "%s mesej baru sejak %s", "SAML" : "SAML", - "Save" : "Simpan", "Save_changes" : "Simpan perubahan", "Save_Mobile_Bandwidth" : "Simpan Jalur lebar mudah alih", "Search" : "Cari", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 2e0271c4960..b7d0b3fa80f 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -1,33 +1,83 @@ { "Access_online_demo" : "Uzyskaj dostÄ™p do demo online", "Access_Online_Demo" : "Uzyskaj dostÄ™p do demo online", + "Access_not_authorized" : "DostÄ™p zabroniony", + "Accounts" : "Konta", + "Accounts_AllowedDomainsList" : "Lista dozwolonych domen", + "Accounts_AllowedDomainsList_Description" : "Lista dozwolonych domen oddzielona przecinkami", + "Accounts_AllowPasswordChange" : "Pozwól na zmianÄ™ hasÅ‚a", + "Accounts_AllowUserAvatarChange" : "Pozwól na zmienianie avatarów", + "Accounts_AllowUserProfileChange" : "Pozwól na zmienianie profilów użytkowników", + "Accounts_AllowUsernameChange" : "Pozwól na zmianÄ™ nazwy użytkownika", + "Accounts_AvatarResize" : "Zmiana rozmiaru avatarów", + "Accounts_AvatarSize" : "Rozmiar avataru", + "Accounts_AvatarStorePath" : "Åšcieżka przechowywania avatarów", + "Accounts_AvatarStoreType" : "Rodzaj magazynu avatarów", + "Accounts_denyUnverifiedEmail" : "Odrzucaj niezweryfikowane adresy email", "Accounts_EmailVerification" : "Weryfikacja adresu email", + "Accounts_ManuallyApproveNewUsers" : "RÄ™czne zatwierdzanie nowych użytkowników", + "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", + "Accounts_OAuth_Custom_Button_Color" : "Kolor przycisku", + "Accounts_OAuth_Custom_Button_Label_Color" : "Kolor etykiety przycisku", + "Accounts_OAuth_Custom_Button_Label_Text" : "Etykieta przycisku", + "Accounts_OAuth_Custom_Enable" : "WÅ‚Ä…cz", + "Accounts_OAuth_Custom_id" : "Id", + "Accounts_OAuth_Custom_Identity_Path" : "Identity Path", + "Accounts_OAuth_Custom_Secret" : "Secret", + "Accounts_OAuth_Custom_Token_Path" : "Token Path", + "Accounts_OAuth_Custom_URL" : "Adres URL", "Accounts_OAuth_Facebook" : "Facebook Login", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", "Accounts_OAuth_Github" : "GitHub Login", "Accounts_OAuth_Github_id" : "GitHub Id", "Accounts_OAuth_Github_secret" : "GitHub Secret", + "Accounts_OAuth_Gitlab" : "OAuth WÅ‚Ä…czone", + "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" : "LinkedIn 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_Registration_AuthenticationServices_Enabled" : "Rejestracja przy użyciu serwisów zewnÄ™trznych", + "Accounts_RegistrationForm" : "Formularz rejestracyjny", + "Accounts_RegistrationForm_Public" : "Publiczny", + "Accounts_RegistrationForm_Disabled" : "WyÅ‚Ä…czony", + "Accounts_RegistrationForm_LinkReplacementText" : "Treść tekstu zamiennego w formularzu rejestracyjnym", + "Accounts_RegistrationForm_Secret_URL" : "Sekretny adres URL", + "Accounts_RegistrationForm_SecretURL" : "Sekretny adres URL formularza rejestracyjnego", "Accounts_RegistrationRequired" : "Wymagana rejestracja", + "Accounts_RequireNameForSignUp" : "Wymagaj podana nazwy podczas rejestracji", + "Accounts_Enrollment_Email" : "Adres email do rekrutacji", + "Accounts_Enrollment_Email_Description" : "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.", "Activate" : "Aktywować", + "Add_custom_oauth" : "Dodaj wÅ‚asne OAuth", "Add_Members" : "Dodaj czÅ‚onków", "Add_users" : "Dodaj użytkowników", "Administration" : "Administracja", "All_channels" : "Wszystkie kanaÅ‚y", + "Allow_Invalid_SelfSigned_Certs" : "Pozwól na nieprawidÅ‚owe certyfikaty", + "Allow_Invalid_SelfSigned_Certs_Description" : "Pozwól na nieprawidÅ‚owe i samodzielnie podpisane certyfikaty SSL podczas walidacji linków i podglÄ…dów", "and" : "i", "API" : "API", "API_Analytics" : "Analityka", "API_Embed" : "Osadź", + "API_EmbedDisabledFor" : "WyÅ‚Ä…dz osadzanie dla użytkowników", + "API_EmbedDisabledFor_Description" : "Lista użytkowników oddzielonych przecinkami", "are_also_typing" : "również piszÄ…", "are_typing" : "piszÄ…", "Are_you_sure" : "Potwierdź, czy na pewno?", + "Auto_Load_Images" : "Automatycznie Å‚aduj zdjÄ™cia", "Avatar_changed_successfully" : "Avatar zmieniony z powodzeniem", + "Avatar_url_invalid_or_error" : "Podany adres URL jest nieprawidÅ‚owy. Popraw go i spróbuj ponownie.", "away" : "poza", "Away" : "Poza", "away_female" : "poza", @@ -43,43 +93,80 @@ "busy_male" : "zajÄ™ty", "Busy_male" : "ZajÄ™ty", "Cancel" : "Anuluj", + "CDN_PREFIX" : "Prefiks CDN", "Change_avatar" : "ZmieÅ„ avatar", "Channels" : "KanaÅ‚y", "Channels_list" : "Lista kanałów publicznych", "Chat_Rooms" : "Pokoje", + "Clear_all_unreads_question" : "WyczyÅ›cić wszystkie nieprzeczytane?", "close" : "zamknij", "coming_soon" : "wkrótce", + "Commands" : "Polecenia", + "Compact_View" : "Widok kompaktowy", "Confirm_password" : "Potwierdź hasÅ‚o", "Contact" : "Kontakt", "Conversation" : "Rozmowa", + "Convert_Ascii_Emojis" : "Konwertuj ASCII do Emoji", "Create_new" : "Utwórz nowe", "Create_new_direct_message_room" : "Utwórz nowy kanaÅ‚ prywatny", "Create_new_private_group" : "Utwórz prywatnÄ… grupÄ™", "Create_new_public_channel" : "Utwórz kanaÅ‚ publiczny", "Created_at" : "Utworzono", + "Custom_oauth_helper" : "Przy konfiguracji dostawcy OAuth bÄ™dziesz musiaÅ‚ podać zwrotny adres URL (Callback). Użyj adresu <pre>%s</pre>.", + "Custom_oauth_unique_name" : "Nazwa wÅ‚asnego serwisu OAuth", + "days" : "dni", "Deactivate" : "Dezaktywować", + "Delete_Room_Warning" : "UsuniÄ™cie pokoju wiąże siÄ™ z usuniÄ™ciem wszystkich wiadomoÅ›ci wysÅ‚anych do niego. Tej operacji nie można cofnąć.", + "Delete_User_Warning" : "UsuniÄ™cie użytkownika wiąże siÄ™ z usuniÄ™ciem wszystkich jego wiadomoÅ›ci. Tej czynnoÅ›ci nie można cofnąć.", "Deleted" : "UsuniÄ™te!", + "Desktop_Notifications" : "Powiadomienia na pulpicie", + "Desktop_Notifications_Disabled" : "Powiadomienia na pulpicie sÄ… wyÅ‚Ä…czone. ZmieÅ„ ustawienia swojej przeglÄ…darki jeżeli chcesz wÅ‚Ä…czyć powiadomienia.", + "Desktop_Notifications_Enabled" : "Powiadomienia na pulpicie sÄ… wÅ‚Ä…czone", "Direct_Messages" : "BezpoÅ›rednie wiadomoÅ›ci", + "Disable_Favorite_Rooms" : "WyÅ‚Ä…cz ulubione", + "Disable_New_Message_Notification" : "WyÅ‚Ä…cz powiadomienia dla nowych wiadomoÅ›ci", + "Disable_New_Room_Notification" : "WyÅ‚Ä…cz powiadomienia dla nowych kanałów", "Drop_to_upload_file" : "PrzeciÄ…gnij, aby przesÅ‚ać plik", "Duplicate_channel_name" : "KanaÅ‚ o nazwie \"% s\" istnieje", "Duplicate_private_group_name" : "Grupa Prywatna o nazwie '% s' istnieje", + "E-mail" : "Email", "edited" : "zmieniono", "Email_already_exists" : "Email już istnieje", "Email_or_username" : "Email lub nazwa użytkownika", "Email_verified" : "E-mail zweryfikowany", + "Emoji" : "Emoji", + "Enable_Desktop_Notifications" : "WÅ‚Ä…cz powiadomienia na pulpicie", "Enter_info" : "Podaj swoje dane", + "Enter_to" : "NaciÅ›nij Enter: ", "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: ", "False" : "FaÅ‚sz", "Favorites" : "Ulubione", + "FileUpload" : "PrzesyÅ‚anie plików", + "FileUpload_Enabled" : "PrzesyÅ‚anie plików wÅ‚Ä…czone", + "FileUpload_MaxFileSize" : "Maksymalny rozmiar przesÅ‚anego pliku (w bajtach)", + "FileUpload_MediaTypeWhiteList" : "Dozwolone typy plików", + "FileUpload_MediaTypeWhiteListDescription" : "Typy plików, oddzielone przecinkami", "Follow_social_profiles" : "Åšledź nasze profile spoÅ‚eczne, widelec do nas na github i podziel siÄ™ swoimi przemyÅ›leniami na temat rocket.chat aplikacji na naszej trello pokÅ‚adzie.", "Forgot_password" : "ZapomniaÅ‚eÅ› hasÅ‚a", "Fork_it_on_github" : "Fork it on GitHub", + "From_Email" : "Adres nadawcy", + "General" : "Ogólne", "Get_to_know_the_team" : "Poznaj Rocket.Team", "github_no_public_email" : "Nie posiadasz publicznego konta e-mail przypisanego do swojego profilu GitHub.", + "Give_a_unique_name_for_the_custom_oauth" : "Podaj unikalnÄ… nazwÄ™ dla wÅ‚asnego serwisu OAuth", + "Has_more" : "Jest wiÄ™cej", "Have_your_own_chat" : "Załóż swój wÅ‚asny czat. DziÄ™ki Meteor.com, Rocket.Chat jest idealnym rozwiÄ…zaniem dla wszystkich chcÄ…cych budować i rozwijać swojÄ… wÅ‚asnÄ… platformÄ™ do rozmów.", "Hide_room" : "Ukryj pokój", "History" : "Historia", + "hours" : "godzin", + "Incorrect_Password" : "HasÅ‚o jest nieprawidÅ‚owe", "inline_code" : "inline", + "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\").", "Invalid_confirm_pass" : "Podane hasÅ‚a nie sÄ… jednakowe", "Invalid_email" : "E-mail jest nieprawidÅ‚owy", "Invalid_name" : "Nazwa nie może być pusta", @@ -87,6 +174,7 @@ "Invalid_room_name" : "<strong>% s</strong>nie jest poprawnÄ… nazwÄ… pokoju, <br / >użyj tylko liter, cyfr i myÅ›lników", "invisible" : "niewidoczny", "Invisible" : "Niewidoczny", + "Invitation_HTML" : "Kod HTML zaproszenia", "Invitation_Subject" : "Temat zaproszenia", "Invite_Users" : "ZaproÅ› użytkowników", "is_also_typing" : "również pisze", @@ -102,65 +190,123 @@ "Language_Version" : "Wersja angielska", "Last_login" : "Ostatnie logowanie", "Last_message" : "Ostatnia wiadomość", + "Layout" : "WyglÄ…d i treść", "Layout_Home_Body" : "Treść strony głównej", "Layout_Home_Title" : "TytuÅ‚ strony głównej", + "Layout_Login_Header" : "Nagłówek formularza logowania", + "Layout_Login_Terms" : "Regulamin rejestacji", + "Layout_Privacy_Policy" : "Polityka PrywatnoÅ›ci", + "Layout_Sidenav_Footer" : "Stopka panelu nawigacyjnego", + "Layout_Sidenav_Footer_description" : "Stopka ma rozmiar 260 x 70 pikseli", + "Layout_Terms_of_Service" : "Regulamin", + "LDAP_Bind_Search" : "Zapytanie Bind", + "LDAP_Bind_Search_Description" : "KawaÅ‚ek kodu JSON który pozwala na powiÄ…zanie danych, w formie {\"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 to hierarchiczna baza danych wykorzystywana przez wiele firm w celu udostÄ™pniania pojedynczej usÅ‚ugi autoryzacji użytkowników pomiÄ™dzy wieloma serwisami. Aby uzyskać dodatkowe informacje i przykÅ‚ady konfiguracji, odwiedź nasze wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", "LDAP_DN" : "LDAP DN", + "LDAP_DN_Description" : "Search root; przykÅ‚ad: dc=domena,dc=com", + "LDAP_Enable" : "WÅ‚Ä…cz LDAP", + "LDAP_Enable_Description" : "WÅ‚Ä…cza LDAP podczas uwierzytelniania.", "LDAP_Port" : "Port LDAP", + "LDAP_Port_Description" : "Port dostÄ™powy dla LDAP; np: 389", + "LDAP_Sync_User_Data" : "Synchronizuj dane", + "LDAP_Sync_User_Data_Description" : "Utrzymuj dane (np: nazwa, email) w synchronizacji z serwerem podczas logowania", + "LDAP_Sync_User_Data_FieldMap" : "Mapa pól użytkownika", + "LDAP_Sync_User_Data_FieldMap_Description" : "Konfigurowanie sposobu w jaki pola kont (np. email) sÄ… uzupeÅ‚niane z rekordów LDAP (gdy takowe zostanÄ… znalezione). Na przykÅ‚ad podajÄ…c {\"cn\":\"name\", \"mail\":\"email\"} system wybierze wyÅ›wietlanÄ… nazwÄ™ użytkownika z pola cn i jego adres email z pola email. DostÄ™pne pola to: name, email.", "LDAP_Url" : "Adres URL LDAP", + "LDAP_Url_Description" : "Adres serwera LDAP; na przykÅ‚ad: ldap://mojafirma.dns.com", "Leave_room" : "Opuść pokój", "line" : "linia", "Load_more" : "WiÄ™cej", "Loading..." : "Åadowanie ...", + "Loading_more_from_history" : "Åadowanie wiÄ™cej z historii", "Loading_suggestion" : "Åadowanie sugestii...", "Login" : "Login", "Login_with" : "Zaloguj siÄ™ z %s", "login_with" : "lub zaloguj bezpoÅ›rednio z", "Logout" : "Wyloguj", + "Make_Admin" : "Przydziel Admina", + "Mark_as_read" : "Oznacz jako przeczytane", + "Markdown_Headers" : "Nagłówki Markdown", "Members" : "CzÅ‚onkowie", "Members_List" : "Lista użytkowników", "Members_placeholder" : "CzÅ‚onkowie", "Message" : "Wiadomość", "Message_AllowDeleting" : "Pozwól usunąć wiadomość", "Message_AllowEditing" : "Pozwól edytować wiadomość", + "Message_AllowEditing_BlockEditInMinutes" : "Blokuj edytowanie wiadomoÅ›ci po (n) minutach", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Wpisz 0, aby wyÅ‚Ä…czyć blokowanie.", + "Message_AudioRecorderEnabled" : "WysyÅ‚anie nagraÅ„ audio wÅ‚Ä…czone", + "Message_AudioRecorderEnabledDescription" : "Wymagane jest akceptowanie plików 'audio/wav' w panelu ustawieÅ„ 'PrzesyÅ‚anie plików'", + "Message_deleting_not_allowed" : "Usuwanie wiadomoÅ›ci jest niedozwolone", + "Message_editing_blocked" : "Nie można już edytować tej wiadomoÅ›ci", + "Message_editing_not_allowed" : "Edycja wiadomoÅ›ci jest niedozwolona", "Message_KeepHistory" : "Zachowaj historiÄ™ wiadomoÅ›ci", + "Message_MaxAllowedSize" : "Maksymalna dozwolona dÅ‚ugość wiadomoÅ›ci", + "Message_pinned" : "Wiadomość przypiÄ™ta", + "Message_pinning_not_allowed" : "Przypinanie wiadomoÅ›ci jest niedozwolone", "Message_removed" : "Wiadomość usuniÄ™ta", "Message_ShowDeletedStatus" : "Pokaż usuniÄ™ty status", "Message_ShowEditedStatus" : "Pokaż zmieniony status", + "Message_ShowFormattingTips" : "Pokaż porady formatowania wiadomoÅ›ci", + "Messages" : "WiadomoÅ›ci", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Weryfikacja Google", "Meta_language" : "JÄ™zyk", "Meta_msvalidate01" : "MSValidate.01", "Meta_robots" : "Robots", + "minutes" : "minut", "More_channels" : "WiÄ™cej kanałów", + "More_groups" : "WiÄ™cej grup prywatnych", + "More_unreads" : "WiÄ™cej nieprzeczytanych", "Msgs" : "WiadomoÅ›ci", "multi" : "multi", "My_Account" : "Moje konto", "n_messages" : "%s wiadomoÅ›ci", "Name" : "Nazwa", + "Name_cant_be_empty" : "Nazwa nie może być pusta", + "Name_optional" : "Nazwa (opcjonalnie)", "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>!", "No_channels_yet" : "Nie jesteÅ› czÅ‚onkiem żadnego kanaÅ‚u.", "No_direct_messages_yet" : "Nie rozpoczÄ…Å‚eÅ› jeszcze żadnej rozmowy.", "No_favorites_yet" : "Brak ulubionych.", + "No_group_with_name_%s_was_found" : "Nie odnaleziono grupy o nazwie <strong>\"%s\"</strong>!", "No_groups_yet" : "Nie masz prywatnych grup.", + "No_livechats" : "Nie masz żadnych livechatów.", "No_permission_to_view_room" : "Nie masz dostÄ™pu do tego pokoju", + "No_user_with_username_%s_was_found" : "Nie odnaleziono użytkownika o nazwie <strong>\"%s\"</strong>!", "Not_allowed" : "Niedozwolone", + "Not_authorized" : "Brak autoryzacji", "Not_found_or_not_allowed" : "Nie znaleziono lub nie dozwolone", "Nothing_found" : "Nic nie znaleziono", "Notify_all_in_this_room" : "Powiadom wszystkich w pokoju", + "Old_and_new_password_required" : "Aby zmienić hasÅ‚o musisz podać zarówno stare jak i nowe hasÅ‚o.", + "Old_Password" : "Stare hasÅ‚o", "Online" : "Online", "Only_you_can_see_this_message" : "Tylko Ty widzisz tÄ™ wiadomość", "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.", "others" : "inni", "Password" : "HasÅ‚o", + "Password_Change_Disabled" : "Administrator czatu wyÅ‚Ä…czyÅ‚ możliwość zmiany haseÅ‚", "Password_changed_successfully" : "HasÅ‚o zostaÅ‚o zmienione", + "People" : "Ludzie", + "Please_enter_value_for_url" : "Wprowadź poprawny adres URL dla swojego awatara.", "Please_wait" : "ProszÄ™ czekaj", + "Please_wait_activation" : "To może chwilÄ™ potrwać, proszÄ™ czekaj.", + "Please_wait_statistics" : "GenerujÄ™ statystyki, proszÄ™ czekaj.", "Powered_by" : "Wspierane przez", + "Preferences" : "Preferencje", + "Preferences_saved" : "Preferencje zapisane", "Privacy" : "Prywatność", "Private_Groups" : "Prywatne grupy", + "Private_Groups_list" : "Lista prywatnych grup", "Profile" : "Profil", "Profile_saved_successfully" : "Profil zostaÅ‚ zapisany", "Proudly_developed" : "Dumnie opracowane z Meteor", + "Push" : "Powiadomienia", "Push_apn_cert" : "Certyfikat APN", "Push_apn_dev_cert" : "Certyfikat Dev APN", "Push_apn_dev_key" : "Klucz Dev APN", @@ -169,25 +315,41 @@ "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", "Push_enable" : "WÅ‚Ä…cz", + "Push_gcm_api_key" : "Klucz API GCM", + "Push_gcm_project_number" : "Identyfikator projektu GCM", "Push_production" : "Serwer produkcyjny", "Quick_Search" : "Szybkie wyszukiwanie", "quote" : "cytat", "Recents" : "Najnowsze", + "Record" : "Nagrywaj", "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", "Reset_password" : "Zresetuj hasÅ‚o", "Room" : "Pokój", "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", + "Room_uploaded_file_list" : "Lista plików", + "Room_uploaded_file_list_empty" : "Brak dostÄ™pnych plików", "room_user_count" : "%s użytkowników", "Rooms" : "Pokoje", + "S_new_messages_since_s" : "%s nowych wiadomoÅ›ci od %s", "SAML" : "SAML", - "Save" : "Zapisz", + "SAML_Custom_Cert" : "WÅ‚asny certyfikat", + "SAML_Custom_Entry_point" : "Niestandardowy punkt wejÅ›cia", + "SAML_Custom_Generate_Username" : "Generowanie nazwy użytkownika", + "SAML_Custom_Issuer" : "WÅ‚asny wydawca (issuer)", + "SAML_Custom_Provider" : "WÅ‚asny dostawca (provider)", "Save_changes" : "Zapisz zmiany", + "Save_Mobile_Bandwidth" : "OszczÄ™dzaj przepustowość", "Search" : "Szukaj", "Search_Messages" : "Przeszukaj wiadomoÅ›ci", "Search_settings" : "Wyszukaj w ustawieniach", + "seconds" : "sekund", "See_all" : "Zobacz wszystko", "See_only_online" : "WyÅ‚Ä…cznie w trybie online", "Select_an_avatar" : "Wybierz awatar", @@ -196,6 +358,11 @@ "Selected_users" : "Wybrani czÅ‚onkowie", "Send" : "WyÅ›lij", "Send_confirmation_email" : "WyÅ›lij e-mail z potwierdzeniem", + "Send_invitation_email" : "WyÅ›lij email z zaproszeniem", + "Send_invitation_email_error" : "Nie wprowadziÅ‚eÅ› poprawnego adresu email.", + "Send_invitation_email_info" : "Możesz wysÅ‚ać kilka zaproszeÅ„ na raz.", + "Send_invitation_email_success" : "Zaproszenia zostaÅ‚y wysÅ‚ane na nastÄ™pujÄ…ce adresy email:", + "Send_invitation_email_warning" : "Aby wysÅ‚ać zaproszenie, skonfiguruj najpierw ustawienia serwera SMTP.", "Send_Message" : "WyÅ›lij wiadomość", "Settings" : "Ustawienia", "Settings_updated" : "Ustawienia zaktualizowane", @@ -203,27 +370,65 @@ "Showing_results" : "<p>WyÅ›wietlono <b>% s</b>wyników</p>", "Silence" : "Cisza", "since_creation" : "od %s", + "Site_Name" : "Nazwa strony", + "Site_Url" : "Adres strony", + "Site_Url_Description" : "PrzykÅ‚ad: https://chat.domain.com/", "SMTP" : "SMTP", "SMTP_Host" : "SMTP Host", "SMTP_Password" : "HasÅ‚o SMTP", "SMTP_Port" : "Port SMTP", "SMTP_Username" : "Nazwa użytkownika SMTP", + "Sound" : "DźwiÄ™k", "Start_of_conversation" : "Rozpocznij rozmowÄ™", "Statistics" : "Statystyka", + "Stats_Active_Users" : "Aktywni użytkownicy", + "Stats_Avg_Channel_Users" : "Åšrednio użytkowników w kanaÅ‚ach", + "Stats_Avg_Private_Group_Users" : "Åšrednio użytkowników w grupach", + "Stats_Away_Users" : "Nieobecni użytkownicy", + "Stats_Max_Room_Users" : "Maksymalnie użytkowników w kanaÅ‚ach", + "Stats_Non_Active_Users" : "Nieaktywni użytkownicy", + "Stats_Offline_Users" : "NiepodÅ‚Ä…czeni użytkownicy", + "Stats_Online_Users" : "PodÅ‚Ä…czeni użytkownicy", + "Stats_OS_Arch" : "Architektura systemu", + "Stats_OS_Cpus" : "Ilość procesorów", + "Stats_OS_Freemem" : "Ilość wolnej pamiÄ™ci", + "Stats_OS_Loadavg" : "Åšrednie obciążenie systemu", + "Stats_OS_Platform" : "Platforma systemu", + "Stats_OS_Release" : "Wydanie systemu", + "Stats_OS_Totalmem" : "CaÅ‚kowita ilość pamiÄ™ci systemu", + "Stats_OS_Type" : "Typ systemu ", + "Stats_OS_Uptime" : "Czas pracy systemu", + "Stats_Total_Channels" : "Liczba kanałów", + "Stats_Total_Direct_Messages" : "Liczba sesji prywatnych", + "Stats_Total_Messages" : "Liczba wiadomoÅ›ci", + "Stats_Total_Private_Groups" : "Liczba grup prywatnych", + "Stats_Total_Rooms" : "Liczba wszystkich pokoi", + "Stats_Total_Users" : "Liczba użytkowników", + "Stop_Recording" : "Zatrzymaj nagrywanie", "strike" : "przekreÅ›lenie", "Submit" : "PrzeÅ›lij", "The_field_is_required" : "Pole %s jest wymagane.", "True" : "Prawda", "Unnamed" : "Anonimowy", + "Unread_Rooms" : "Nieprzeczytane pokoje", + "Unread_Rooms_Mode" : "Tryb nieprzeczytanych pokoi", "Upload_file_question" : "PrzesÅ‚ać plik?", + "Use_Emojis" : "Użyj Emoji", "Use_initials_avatar" : "Użyj inicjałów", "use_menu" : "Skorzystaj z menu bocznego celem dostÄ™pu do pokoi i czatów", "Use_service_avatar" : "Użyj %s avatar", "Use_this_username" : "Użyj tej nazwy użytkownika", "Use_uploaded_avatar" : "Użyj dodany awatar", + "Use_url_for_avatar" : "Użyj adresu URL", "User_added_by" : "Użytkownik <em>__user_added__</em>dodany przez <em>__user_by__</em>.", + "User_Channels" : "KanaÅ‚y użytkowników", "User_has_been_activated" : "Użytkownik zostaÅ‚ aktywowany", "User_has_been_deactivated" : "Użytkownik zostaÅ‚ deaktywowany", + "User_has_been_deleted" : "Użytkownik zostaÅ‚ usuniÄ™ty", + "User_Info" : "Informacje o użytkowniku", + "User_is_no_longer_an_admin" : "Użytkownik nie jest już adminem", + "User_is_not_activated" : "Użytkownik nie jest aktywny", + "User_is_now_an_admin" : "Użytkownik jest teraz adminem", "User_joined_channel" : "DoÅ‚Ä…czyÅ‚ do kanaÅ‚u", "User_joined_channel_female" : "DoÅ‚Ä…czyÅ‚a do kanaÅ‚u", "User_joined_channel_male" : "DoÅ‚Ä…czyÅ‚ do kanaÅ‚u", @@ -231,21 +436,27 @@ "User_left_female" : "Użytkownik <em>__user_left__</em> wyszÅ‚a.", "User_left_male" : "Użytkownik <em>__user_left__</em> wyszedÅ‚.", "User_logged_out" : "Użytkownik jest wylogowany", + "User_not_found_or_incorrect_password" : "Nie znaleziono użytkownika lub nieprawidÅ‚owe hasÅ‚o", "User_removed_by" : "Użytkownik <em>__user_removed__</em>usuniÄ™ty przez <em>__user_by__</em>.", "User_Settings" : "Ustawienia użytkownika", + "User_updated_successfully" : "Zaktualizowano dane użytkownika", "Username" : "Nazwa użytkownika", "Username_cant_be_empty" : "Nazwa użytkownika nie może być pusta", + "Username_Change_Disabled" : "Administrator czatu nie zezwoliÅ‚ na zmianÄ™ nazw użytkownika", "Username_description" : "Nazwa użytkownika jest używana, by inni mogli CiÄ™ wspomnieć w wiadomoÅ›ci.", "Username_invalid" : "<strong>% s</strong>nie jest prawidÅ‚owÄ… nazwÄ… użytkownika, <br / >użyj jedynie liter, cyfr, kropek i kresek", "Username_title" : "Zarejestruj użytkownika", "Username_unavaliable" : "<strong>% s</strong> jest zajÄ™te :(", "Users" : "Użytkownicy", "View_All" : "Zobacz wszystkie", + "Wait_activation_warning" : "Zanim siÄ™ zalogujesz, twoje konto musi być aktywowane przez administratora.", "We_have_sent_password_email" : "WysÅ‚aliÅ›my Ci e-mail z instrukcjami resetowania hasÅ‚a. JeÅ›li nie dostaniesz wiadomoÅ›ci, spróbuj proszÄ™ ponownie.", "We_have_sent_registration_email" : "WysÅ‚aliÅ›my e-mail w celu potwierdzenie Twojej rejestracji. JeÅ›li nie dostaniesz wiadomoÅ›ci, spróbuj proszÄ™ ponownie.", "Welcome" : "Witamy <em>% s</em>.", "Welcome_to_the" : "Witaj w", "With_whom" : "Z kim", + "Yes" : "Tak", + "Yes_clear_all" : "Tak, wyczyść!", "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" : "Musisz potwierdzić swój adres e-mail, aby zalogować siÄ™!", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 5d4d9e939cc..1af6d7f2715 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -297,7 +297,6 @@ "Rooms" : "Salas", "S_new_messages_since_s" : "%s novas mensagens desde %s", "SAML" : "SAML", - "Save" : "Salvar", "Save_changes" : "Salvar alterações", "Save_Mobile_Bandwidth" : "Economizar Banda Móvel", "Search" : "Pesquisar", @@ -414,4 +413,4 @@ "You_will_not_be_able_to_recover" : "Você não será capaz de desfazer!", "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source" -} +} \ No newline at end of file diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index c069e2dc5e4..4295b405854 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -178,7 +178,6 @@ "Room_name_changed_successfully" : "Ðазвание чата уÑпешно изменено", "Room_not_found" : "Комната не найдена", "room_user_count" : "%s пользователей", - "Save" : "Сохранить", "Save_changes" : "Сохранить изменениÑ", "Search" : "ПоиÑк", "Search_Messages" : "ПоиÑк Ñообщений", diff --git a/i18n/sq.i18n.json b/i18n/sq.i18n.json new file mode 100644 index 00000000000..364aaf1e358 --- /dev/null +++ b/i18n/sq.i18n.json @@ -0,0 +1,77 @@ +{ + "Add_users" : "Shtoni përdoruesit", + "and" : "dhe", + "are_also_typing" : "janë gjithashtu shtypja", + "are_typing" : "janë shtypur", + "Cancel" : "Anuloj", + "Channels" : "Kanalet", + "Channels_list" : "Lista e kanaleve publike", + "Chat_Rooms" : "Chat dhoma", + "close" : "Mbyll", + "Confirm_password" : "Konfirmoni fjalëkalimin tuaj", + "Contact" : "Kontakt", + "Conversation" : "Bisedë", + "Create_new_public_channel" : "Krijo një kanal të ri publik", + "Direct_Messages" : "Mesazhe të drejtpërdrejta", + "edited" : "edited", + "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", + "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", + "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", + "is_also_typing" : "janë gjithashtu shtypja", + "is_typing" : "është shtypja", + "Join_the_Community" : "Join Komuniteti", + "Language_Version" : "Versioni anglisht", + "Leave_room" : "Dhomë Leave", + "Load_more" : "Lexo më shumë", + "Login" : "Hyrje", + "Members" : "Anëtarët", + "Members_List" : "Lista e Anëtarëve", + "Members_placeholder" : "Anëtarët", + "More_channels" : "Më shumë kanale", + "Name" : "Emër", + "New_messages" : "Mesazhe të reja", + "New_password" : "Fjalëkalimi i ri", + "No_channels_yet" : "Ju nuk jeni pjesë e ndonjë kanali ende.", + "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.", + "Password" : "Fjalëkalim", + "Please_wait" : "Te lutem prit", + "Powered_by" : "Mundësuar nga", + "Private_Groups" : "Grupet Private", + "Proudly_developed" : "Zhvilluar me krenari me Meteor", + "Quick_Search" : "Kërko Shpejt", + "Recents" : "Recents", + "Register" : "Regjistrohu një llogari të re", + "Remember_me" : "Mua më kujtoni", + "Remove" : "Hiq", + "Reset_password" : "Fjalëkalimi i ri", + "Room_name_changed" : "Emri dhomë ndryshuar për:", + "Room_name_changed_successfully" : "Emri dhomë ndryshuar me sukses", + "Search" : "Kërko", + "See_all" : "Shih të gjithë", + "See_only_online" : "Vetëm online", + "Selected_users" : "Anëtarë të zgjedhur", + "Send_confirmation_email" : "Dërgo email konfirmimi", + "Send_Message" : "Dërgoni mesazh", + "Showing_online_users" : "Duke treguar", + "Start_of_conversation" : "Fillimi i bisedës", + "Submit" : "Paraqes", + "use_menu" : "Përdorni menynë anësore për të hyrë në dhomat tuaja dhe biseda", + "User_added_by" : "Përdorues", + "User_left" : "Ka lënë kanal.", + "User_logged_out" : "Përdoruesi është regjistruar jashtë", + "User_removed_by" : "Përdorues", + "View_All" : "Shiko të gjitha", + "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!" +} \ No newline at end of file diff --git a/i18n/sv.i18n.json b/i18n/sv.i18n.json index 561a0a5f033..0d83eeed020 100644 --- a/i18n/sv.i18n.json +++ b/i18n/sv.i18n.json @@ -172,7 +172,6 @@ "Room_name_changed" : "Rummets namn ändrat till : <em>__room_name__</em> av <em>__user_by__</em>", "Room_name_changed_successfully" : "Rummets namn har ändrats ", "room_user_count" : "%s användare", - "Save" : "Spara", "Save_changes" : "Spara ändringar", "Search" : "Sök", "Search_settings" : "Sökinställningar", diff --git a/i18n/ta-IN.i18n.json b/i18n/ta-IN.i18n.json index 473329c3c2b..283e187244e 100644 --- a/i18n/ta-IN.i18n.json +++ b/i18n/ta-IN.i18n.json @@ -74,7 +74,6 @@ "Room" : "அறை", "Room_name_changed" : "அறை பெயர௠மாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯: <em>__room_name__</em>மறà¯à®±à®¿à®¯à®µà®°à¯ <em>__user_by__</em>", "Room_name_changed_successfully" : "அறை பெயர௠வெறà¯à®±à®¿à®•à®°à®®à®¾à®• மாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯", - "Save" : "சேமி", "Search" : "தேடà¯", "Search_settings" : "தேடல௠அமைபà¯à®ªà¯à®•à®³à¯", "See_all" : "அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ பாரà¯à®•à¯à®•", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 71b54e53e54..6e8f5807bbe 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -176,7 +176,6 @@ "Room_name_changed" : "Oda adı <em>__user_by__</em> tarafından <em>__room_name__</em> olarak deÄŸiÅŸtirildi", "Room_name_changed_successfully" : "Oda adı baÅŸarıyla deÄŸiÅŸtirildi", "room_user_count" : "%s kullanıcılar", - "Save" : "Kaydet", "Save_changes" : "DeÄŸiÅŸiklikleri kaydet", "Search" : "Ara", "Search_Messages" : "Mesajlarda ara", diff --git a/i18n/ug.i18n.json b/i18n/ug.i18n.json index 893c8ddb903..8ebd191b0b9 100644 --- a/i18n/ug.i18n.json +++ b/i18n/ug.i18n.json @@ -98,7 +98,6 @@ "Room" : "پاراÚخانا", "Room_name_changed" : "پاراÚخانا نامى <em>__user_by__</em> تەرىپىدىن <em>__room_name__</em> قىلىپ ئۆزگەرتىلدى ", "Room_name_changed_successfully" : "پاراÚخانا نامى مۇۋەپپەقىيەتلىك ئۆزگەرتىلدى", - "Save" : "ساقلاش", "Search" : "ئىزدەش", "See_all" : "ھەممىنى كۆرۈش", "See_only_online" : "توردىكىلەرنىلا كۆرۈش", diff --git a/i18n/uk.i18n.json b/i18n/uk.i18n.json index 47ccaa042ed..94ab0dc0867 100644 --- a/i18n/uk.i18n.json +++ b/i18n/uk.i18n.json @@ -88,7 +88,6 @@ "Room" : "Кімната", "Room_name_changed" : "Ðазва кімнати змінена: <em>__room_name__</em> кориÑтувачем <em>__user_by__</em>", "Room_name_changed_successfully" : "Ðазву кімнати змінено", - "Save" : "Зберегти", "Search" : "Пошук", "See_all" : "ПереглÑнути вÑе", "See_only_online" : "Тільки онлайн", diff --git a/i18n/zh.i18n.json b/i18n/zh.i18n.json index c80457321d4..6bc284a06ff 100644 --- a/i18n/zh.i18n.json +++ b/i18n/zh.i18n.json @@ -218,7 +218,6 @@ "Rooms" : "房间", "S_new_messages_since_s" : "%s 新消æ¯ï¼Œè‡ªä»Ž %s", "SAML" : "SAML", - "Save" : "ä¿å˜", "Save_changes" : "ä¿å˜ä¿®æ”¹", "Save_Mobile_Bandwidth" : "节约移动带宽", "Search" : "æœç´¢", diff --git a/packages/rocketchat-authorization/i18n/ar.i18n.json b/packages/rocketchat-authorization/i18n/ar.i18n.json new file mode 100644 index 00000000000..0a06728ddc3 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ar.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "ØÙظ", + "User_added" : "وأضا٠العضو <em>__user_added__</em>." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/cs.i18n.json b/packages/rocketchat-authorization/i18n/cs.i18n.json new file mode 100644 index 00000000000..84eb3ce32fd --- /dev/null +++ b/packages/rocketchat-authorization/i18n/cs.i18n.json @@ -0,0 +1,3 @@ +{ + "Save" : "Uložit" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/de.i18n.json b/packages/rocketchat-authorization/i18n/de.i18n.json new file mode 100644 index 00000000000..e13943efa3e --- /dev/null +++ b/packages/rocketchat-authorization/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Speichern", + "User_added" : "Benutzer <em>__user_added__</em> wurde hinzugefügt." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/el.i18n.json b/packages/rocketchat-authorization/i18n/el.i18n.json new file mode 100644 index 00000000000..c0b916f189e --- /dev/null +++ b/packages/rocketchat-authorization/i18n/el.i18n.json @@ -0,0 +1,4 @@ +{ + "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 e390524161a..de2989add91 100644 --- a/packages/rocketchat-authorization/i18n/en.i18n.json +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -1,24 +1,21 @@ { - "Add": "Add", - "Add_user": "Add user", - "Back_to_permissions": "Back to permissions", - "Cannot_delete_a_protected_role": "Cannot delete a protected role", - "Cannot_delete_role_because_its_in_use": "Cannot delete role because it's in use", - "Description": "Description", - "Enter_a_username": "Enter a username", - "New_role": "New role", - "Permissions": "Permissions", - "Please_fill_a_username": "Please fill a username", - "Removed": "Removed", - "Role": "Role", - "Role_Editing": "Role Editing", - "Role_removed": "Role removed", - "Save": "Save", - "Saved": "Saved", - "Saving": "Saving", - "There_are_no_users_in_this_role": "There are no users in this role.", - "User_added": "User added", - "User_not_found": "User not found", - "User_removed": "User removed", - "Users_in_role": "Users in role" -} + "Add_user" : "Add user", + "Back_to_permissions" : "Back to permissions", + "Cannot_delete_a_protected_role" : "Cannot delete a protected role", + "Cannot_delete_role_because_its_in_use" : "Cannot delete role because it's in use", + "Description" : "Description", + "New_role" : "New role", + "Permissions" : "Permissions", + "Removed" : "Removed", + "Role" : "Role", + "Role_Editing" : "Role Editing", + "Role_removed" : "Role removed", + "Save" : "Save", + "Saved" : "Saved", + "Saving" : "Saving", + "There_are_no_users_in_this_role" : "There are no users in this role.", + "User_added" : "User added", + "User_not_found" : "User not found", + "User_removed" : "User removed", + "Users_in_role" : "Users in role" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/es.i18n.json b/packages/rocketchat-authorization/i18n/es.i18n.json new file mode 100644 index 00000000000..9ace70c0a3c --- /dev/null +++ b/packages/rocketchat-authorization/i18n/es.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Guardar", + "User_added" : "Usuario <em>__user_added__</em> añadido." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/fa.i18n.json b/packages/rocketchat-authorization/i18n/fa.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/fi.i18n.json b/packages/rocketchat-authorization/i18n/fi.i18n.json new file mode 100644 index 00000000000..dbd25410a43 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/fi.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Tallenna", + "User_added" : "Käyttäjä <em>__user_added__</em> lisätty." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/fr.i18n.json b/packages/rocketchat-authorization/i18n/fr.i18n.json new file mode 100644 index 00000000000..ee7fabae8a3 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/fr.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..ed313b29364 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/he.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "שמור", + "User_added" : "המשתמש <em>__user_added__</em> × ×•×¡×£." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/hr.i18n.json b/packages/rocketchat-authorization/i18n/hr.i18n.json new file mode 100644 index 00000000000..6b72824ca23 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/hr.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "SaÄuvaj", + "User_added" : "Korisnik <em>__user_added__</em> je dodan." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/hu.i18n.json b/packages/rocketchat-authorization/i18n/hu.i18n.json new file mode 100644 index 00000000000..9f88a36530a --- /dev/null +++ b/packages/rocketchat-authorization/i18n/hu.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..73b11372f50 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/it.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..846240cce4b --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ja.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..d3ce4c6f879 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/km.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..a7ed67a8ddf --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ko.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "ì €ìž¥", + "User_added" : "ì‚¬ìš©ìž <em>__user_added__</em> 추가함." +} \ 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 new file mode 100644 index 00000000000..07811f70be0 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ms-MY.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Simpan", + "User_added" : "Pengguna <em>__user_added__</em> ditambah." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/pl.i18n.json b/packages/rocketchat-authorization/i18n/pl.i18n.json new file mode 100644 index 00000000000..14ea715b8ec --- /dev/null +++ b/packages/rocketchat-authorization/i18n/pl.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Zapisz", + "User_added" : "Użytkownik <em>__user_added__</em> dodany." +} \ 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 da82a048405..dca06e8c94c 100644 --- a/packages/rocketchat-authorization/i18n/pt.i18n.json +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -1,24 +1,21 @@ { - "Add": "Adicionar", - "Add_user": "Adicionar usuário", - "Back_to_permissions": "Voltar para permissões", - "Cannot_delete_a_protected_role": "Não é possÃvel remover um papel protegido", - "Cannot_delete_role_because_its_in_use": "Não é possÃvel remover o papel pois ele está em uso", - "Description": "Descrição", - "Enter_a_username": "Preencha um nome de usuário", - "New_role": "Novo papel", - "Permissions": "Permissões", - "Please_fill_a_username": "Por favor preencha um nome de usuário", - "Removed": "Removido", - "Role": "Papel", - "Role_Editing": "Edição de Papel", - "Role_removed": "Papel Removido", - "Save": "Salvar", - "Saved": "Salvo", - "Saving": "Salvando", - "There_are_no_users_in_this_role": "Não há usuários neste papel.", - "User_added": "Usuário adicionado", - "User_not_found": "Usuário não encontrado", - "User_removed": "Usuário removido", - "Users_in_role": "Usuários no papel" -} + "Add_user" : "Adicionar usuário", + "Back_to_permissions" : "Voltar para permissões", + "Cannot_delete_a_protected_role" : "Não é possÃvel remover um papel protegido", + "Cannot_delete_role_because_its_in_use" : "Não é possÃvel remover o papel pois ele está em uso", + "Description" : "Descrição", + "New_role" : "Novo papel", + "Permissions" : "Permissões", + "Removed" : "Removido", + "Role" : "Papel", + "Role_Editing" : "Edição de Papel", + "Role_removed" : "Papel Removido", + "Save" : "Salvar", + "Saved" : "Salvo", + "Saving" : "Salvando", + "There_are_no_users_in_this_role" : "Não há usuários neste papel.", + "User_added" : "Usuário adicionado", + "User_not_found" : "Usuário não encontrado", + "User_removed" : "Usuário removido", + "Users_in_role" : "Usuários no papel" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ru.i18n.json b/packages/rocketchat-authorization/i18n/ru.i18n.json new file mode 100644 index 00000000000..a1e844169a3 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ru.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Сохранить", + "User_added" : "Пользователь <em>__user_added__</em> добавлен." +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/sq.i18n.json b/packages/rocketchat-authorization/i18n/sq.i18n.json new file mode 100644 index 00000000000..b01a59cc8c1 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/sq.i18n.json @@ -0,0 +1,3 @@ +{ + "Save" : "Ruaj" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/sv.i18n.json b/packages/rocketchat-authorization/i18n/sv.i18n.json new file mode 100644 index 00000000000..7bc9d5f5301 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/sv.i18n.json @@ -0,0 +1,3 @@ +{ + "Save" : "Spara" +} \ 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 new file mode 100644 index 00000000000..24a652c5f05 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ta-IN.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..87c7ba45b61 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/tr.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..64384b7a94a --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ug.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..c1ac4e32dd6 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/uk.i18n.json @@ -0,0 +1,4 @@ +{ + "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 new file mode 100644 index 00000000000..5b7a5b62c1e --- /dev/null +++ b/packages/rocketchat-authorization/i18n/zh.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "ä¿å˜", + "User_added" : "å·²æ·»åŠ ç”¨æˆ· <em>__user_added__</em> 。" +} \ 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 6f31cf5a2e6..f93465d0f99 100644 --- a/packages/rocketchat-channel-settings/i18n/pl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/pl.i18n.json @@ -1 +1,8 @@ -{ } \ No newline at end of file +{ + "Channel" : "KanaÅ‚", + "Private_Group" : "Grupa Prywatna", + "Room_Type" : "Rodzaj pokoju", + "Room_Settings" : "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>" +} \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/pl.i18n.json b/packages/rocketchat-chatops/i18n/pl.i18n.json index 6f31cf5a2e6..ba524485ad4 100644 --- a/packages/rocketchat-chatops/i18n/pl.i18n.json +++ b/packages/rocketchat-chatops/i18n/pl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Chatops_Enabled" : "WÅ‚Ä…cz opów w pokojach", + "Chatops_Title" : "Panel operatora", + "Chatops_Username" : "Nazwa użytkownika operatora" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/sq.i18n.json b/packages/rocketchat-chatops/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ 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 77967ea7cdd..22bde54918d 100644 --- a/packages/rocketchat-github-enterprise/i18n/de.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/de.i18n.json @@ -2,5 +2,6 @@ "Accounts_OAuth_GitHub_Enterprise" : "OAuth aktiviert", "API_GitHub_Enterprise_URL" : "GitHub Enterprise", "Accounts_OAuth_GitHub_Enterprise_id" : "Client-ID", - "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret" + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", + "Github_Enterprise_Url_No_Trail" : "Beispiel: http://domain.com (ohne Schrägstrich)" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/pl.i18n.json b/packages/rocketchat-github-enterprise/i18n/pl.i18n.json index 6f31cf5a2e6..a3695be5a53 100644 --- a/packages/rocketchat-github-enterprise/i18n/pl.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/pl.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Accounts_OAuth_GitHub_Enterprise" : "OAuth WÅ‚Ä…czone", + "API_GitHub_Enterprise_URL" : "Adres serwera", + "Accounts_OAuth_GitHub_Enterprise_id" : "Client Id", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Client Secret", + "Github_Enterprise_Url_No_Trail" : "PrzykÅ‚ad: http://domain.com (bez koÅ„cowego ukoÅ›nika)" +} \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/sq.i18n.json b/packages/rocketchat-github-enterprise/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/pl.i18n.json b/packages/rocketchat-gitlab/i18n/pl.i18n.json index 6f31cf5a2e6..ae09fc6be87 100644 --- a/packages/rocketchat-gitlab/i18n/pl.i18n.json +++ b/packages/rocketchat-gitlab/i18n/pl.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "API_Gitlab_URL" : "Adres GitLab" +} \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/sq.i18n.json b/packages/rocketchat-gitlab/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/pl.i18n.json b/packages/rocketchat-hubot/i18n/pl.i18n.json index 6f31cf5a2e6..7948ad6b145 100644 --- a/packages/rocketchat-hubot/i18n/pl.i18n.json +++ b/packages/rocketchat-hubot/i18n/pl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "RocketBot_Enabled" : "WÅ‚Ä…cz RocketBot", + "RocketBot_Name" : "Nazwa RocketBota", + "RocketBot_Name_Description" : "Nazwa RocketBota musi być poprawnÄ… nazwÄ… zarejestrowanego użytkownika." +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/sq.i18n.json b/packages/rocketchat-hubot/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/sq.i18n.json b/packages/rocketchat-ldap/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/sq.i18n.json b/packages/rocketchat-lib/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6de6b790589..c03fbe02fa0 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -1,17 +1,17 @@ { - "Add": "Add", - "Add_agent": "Add agent", - "Add_manager": "Add manager", - "Agent_added": "Agent added", - "Agent_removed": "Agent removed", - "Enter_a_username": "Enter a username", - "Livechat_agents": "Livechat agents", - "Livechat_Manager": "Livechat Manager", - "Livechat_managers": "Livechat managers", + "Add" : "Add", + "Add_agent" : "Add agent", + "Add_manager" : "Add manager", + "Agent_added" : "Agent added", + "Agent_removed" : "Agent removed", + "Enter_a_username" : "Enter a username", + "Livechat_agents" : "Livechat agents", + "Livechat_Manager" : "Livechat Manager", + "Livechat_managers" : "Livechat managers", "Livechat_title" : "Livechat Title", "Livechat_title_color" : "Livechat Title Background Color", - "Manager_added": "Manager added", - "Manager_removed": "Manager removed", - "Please_fill_a_username": "Please fill a username", - "Username_not_found": "Username not found" -} + "Manager_added" : "Manager added", + "Manager_removed" : "Manager removed", + "Please_fill_a_username" : "Please fill a username", + "Username_not_found" : "Username not found" +} \ 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 6f31cf5a2e6..743f3732748 100644 --- a/packages/rocketchat-livechat/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/i18n/pl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Livechat_title" : "TytuÅ‚ Livechatu", + "Livechat_title_color" : "Kolor tÅ‚a nagłówka Livechat" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/pt.i18n.json b/packages/rocketchat-livechat/i18n/pt.i18n.json index 1782d554f8c..18ea87b4f36 100644 --- a/packages/rocketchat-livechat/i18n/pt.i18n.json +++ b/packages/rocketchat-livechat/i18n/pt.i18n.json @@ -1,17 +1,17 @@ { - "Add": "Adicionar", - "Add_agent": "Adicionar agente", - "Add_manager": "Adicionar gerente", - "Agent_added": "Agente adicionado", - "Agent_removed": "Agente removido", - "Enter_a_username": "Nome de usuário", - "Livechat_agents": "Agentes do Livechat", - "Livechat_Manager": "Administração Livechat", - "Livechat_managers": "Gerentes do Livechat", + "Add" : "Adicionar", + "Add_agent" : "Adicionar agente", + "Add_manager" : "Adicionar gerente", + "Agent_added" : "Agente adicionado", + "Agent_removed" : "Agente removido", + "Enter_a_username" : "Nome de usuário", + "Livechat_agents" : "Agentes do Livechat", + "Livechat_Manager" : "Administração Livechat", + "Livechat_managers" : "Gerentes do Livechat", "Livechat_title" : "TÃtulo Livechat", "Livechat_title_color" : "Cor de fundo do tÃtulo do Livechat", - "Manager_added": "Gerente adicionado", - "Manager_removed": "Gerente removido", - "Please_fill_a_username": "Por favor preencha um nome de usuário", - "Username_not_found": "Nome de usuário não encontrado" -} + "Manager_added" : "Gerente adicionado", + "Manager_removed" : "Gerente removido", + "Please_fill_a_username" : "Por favor preencha um nome de usuário", + "Username_not_found" : "Nome de usuário não encontrado" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/sq.i18n.json b/packages/rocketchat-livechat/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..bb5615f66bb 100644 --- a/packages/rocketchat-mailer/i18n/pl.i18n.json +++ b/packages/rocketchat-mailer/i18n/pl.i18n.json @@ -1 +1,15 @@ -{ } \ No newline at end of file +{ + "From_email_warning" : "<b>Uwaga</b>: Pole <b>Od</b> może być uzależnione od ustawieÅ„ serwera.", + "From_email_is_required" : "Adres nadawcy jest wymagany", + "Email_from" : "Od", + "Email_subject" : "Temat", + "Email_body" : "Treść wiadomoÅ›ci", + "Rocket_Mailer" : "WyÅ›lij email użytkownikom", + "RocketMailer_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.", + "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Ä™.", + "You_have_successfully_unsubscribed" : "Twój email zostaÅ‚ usuniÄ™ty z naszej listy powiadomieÅ„.", + "You_informed_an_invalid_FROM_address" : "Adres nadawcy jest nieprawidÅ‚owy", + "You_must_provide_the_unsubscribe_link" : "Musisz wstawić w treÅ›ci znacznik [unsubscribe]." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/sq.i18n.json b/packages/rocketchat-mailer/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ar.i18n.json b/packages/rocketchat-message-pin/i18n/ar.i18n.json index 6f31cf5a2e6..ab3b6e37c08 100644 --- a/packages/rocketchat-message-pin/i18n/ar.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ar.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Pinned_Messages" : "رسائل مثبتة", + "No_pinned_messages" : "لا توجد رسائل مثبتة" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/pl.i18n.json b/packages/rocketchat-message-pin/i18n/pl.i18n.json index 6f31cf5a2e6..d5d4d7158da 100644 --- a/packages/rocketchat-message-pin/i18n/pl.i18n.json +++ b/packages/rocketchat-message-pin/i18n/pl.i18n.json @@ -1 +1,10 @@ -{ } \ No newline at end of file +{ + "Message_AllowPinning" : "Pozwól na przypinanie wiadomoÅ›ci", + "Message_AllowPinning_Description" : "Pozwól na przypinanie wiadomoÅ›ci we wszystkich kanaÅ‚ach.", + "Message_AllowPinningByAnyone" : "Pozwól każdemu na przypinanie wiadomoÅ›ci", + "Message_AllowPinningByAnyone_Description" : "Pozwól wszystkim na przypinanie wiadomoÅ›ci, nie tylko administratorom.", + "Pin_Message" : "Przypnij wiadomość", + "Unpin_Message" : "Odepnij wiadomość", + "Pinned_Messages" : "PrzypiÄ™te wiadomoÅ›ci", + "No_pinned_messages" : "Brak przypiÄ™tych wiadomoÅ›ci" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/sq.i18n.json b/packages/rocketchat-message-pin/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ar.i18n.json b/packages/rocketchat-message-star/i18n/ar.i18n.json index 6f31cf5a2e6..c31ffef0487 100644 --- a/packages/rocketchat-message-star/i18n/ar.i18n.json +++ b/packages/rocketchat-message-star/i18n/ar.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Starred_Messages" : "رسائل مميزة", + "No_starred_messages" : "لا توجد رسائل مميزة" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/de.i18n.json b/packages/rocketchat-message-star/i18n/de.i18n.json index ceffff43684..bb056d4d81b 100644 --- a/packages/rocketchat-message-star/i18n/de.i18n.json +++ b/packages/rocketchat-message-star/i18n/de.i18n.json @@ -1,4 +1,7 @@ { + "Message_AllowStarring" : "Erlaube Nachricht mit einem Stern zu makieren", "Star_Message" : "Stern-Nachrichten", - "Unstar_Message" : "Stern entfernen" + "Unstar_Message" : "Stern entfernen", + "Starred_Messages" : "Nachrichten mit Stern", + "No_starred_messages" : "Keine Nachrichten mit einem Stern" } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/pl.i18n.json b/packages/rocketchat-message-star/i18n/pl.i18n.json index 6f31cf5a2e6..2d74e595816 100644 --- a/packages/rocketchat-message-star/i18n/pl.i18n.json +++ b/packages/rocketchat-message-star/i18n/pl.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Message_AllowStarring" : "Pozwól oznaczać wiadomoÅ›ci gwiazdkÄ…", + "Star_Message" : "Oznacz wiadomość", + "Unstar_Message" : "UsuÅ„ oznaczenie", + "Starred_Messages" : "Ulubione wiadomoÅ›ci", + "No_starred_messages" : "Brak ulubionych wiadomoÅ›ci" +} \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/sq.i18n.json b/packages/rocketchat-message-star/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json index 6f31cf5a2e6..ec0221de36a 100644 --- a/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json +++ b/packages/rocketchat-slashcommands-invite/i18n/pl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "Invite_user_to_join_channel" : "ZaproÅ› użytkownika by doÅ‚Ä…czyÅ‚ do kanaÅ‚u", + "User_doesnt_exist" : "Nie istnieje użytkownik o nazwie `@%s`.", + "Username_is_already_in_here" : "`@%s` już tutaj jest." +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/sq.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ 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 78da1cc9d2c..ad6c15152fa 100644 --- a/packages/rocketchat-slashcommands-join/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/de.i18n.json @@ -1,3 +1,4 @@ { - "Channel_doesnt_exist" : "Der Kanal `#% s` existiert nicht." + "Channel_doesnt_exist" : "Der Kanal `#% s` existiert nicht.", + "Join_the_given_channel" : "Trete dem vorgeschlagenen Kanal bei" } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json index 6f31cf5a2e6..4f8e5bf4147 100644 --- a/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json +++ b/packages/rocketchat-slashcommands-join/i18n/pl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Channel_doesnt_exist" : "KanaÅ‚ `#%s` nie istnieje.", + "Join_the_given_channel" : "DoÅ‚Ä…cz do tego kanaÅ‚u" +} \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/sq.i18n.json b/packages/rocketchat-slashcommands-join/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/pl.i18n.json b/packages/rocketchat-theme/i18n/pl.i18n.json index 6f31cf5a2e6..f811cf22280 100644 --- a/packages/rocketchat-theme/i18n/pl.i18n.json +++ b/packages/rocketchat-theme/i18n/pl.i18n.json @@ -1 +1,23 @@ -{ } \ No newline at end of file +{ + "theme-color-blockquote-background" : "Kolor tÅ‚a bloku cytatu", + "theme-color-code-background" : "Kolor tÅ‚a bloku kodu", + "theme-color-code-border" : "Kolor ramki bloku kodu", + "theme-color-code-color" : "Kolor czcionki bloku kodu", + "theme-color-content-background-color" : "Kolor tÅ‚a zawartoÅ›ci", + "theme-color-info-active-font-color" : "Kolor czcionki aktywnej informacji", + "theme-color-info-font-color" : "Kolor czcionki informacji", + "theme-color-input-font-color" : "Kolor czcionki w polach tekstowych", + "theme-color-link-font-color" : "Kolor czcionki odnoÅ›ników", + "theme-color-primary-background-color" : "Podstawowy kolor tÅ‚a", + "theme-color-primary-font-color" : "Podstawowy kolor czcionki", + "theme-color-secondary-background-color" : "Dodatkowy kolor tÅ‚a", + "theme-color-secondary-font-color" : "Dodatkowy kolor czcionki", + "theme-color-smallprint-font-color" : "Kolor czcionki drobnego druku", + "theme-color-smallprint-hover-color" : "Kolor aktywny drobnego druku", + "theme-color-status-away" : "Kolor statusu Zaraz wracam", + "theme-color-status-busy" : "Kolor statusu ZajÄ™ty", + "theme-color-status-offline" : "Kolor statusu NiedostÄ™pny", + "theme-color-status-online" : "Kolor statusu Online", + "theme-color-tertiary-background-color" : "TrzeciorzÄ™dny kolor tÅ‚a", + "theme-color-tertiary-font-color" : "TrzeciorzÄ™dny kolor czcionki" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/sq.i18n.json b/packages/rocketchat-theme/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..4f6f648650c 100644 --- a/packages/rocketchat-webrtc/i18n/de.i18n.json +++ b/packages/rocketchat-webrtc/i18n/de.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "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" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/pl.i18n.json b/packages/rocketchat-webrtc/i18n/pl.i18n.json index 6f31cf5a2e6..e4a29fbf820 100644 --- a/packages/rocketchat-webrtc/i18n/pl.i18n.json +++ b/packages/rocketchat-webrtc/i18n/pl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "WebRTC_Enable_Channel" : "WÅ‚Ä…cz dla kanałów publicznych", + "WebRTC_Enable_Direct" : "WÅ‚Ä…cz dla prywatnych wiadomoÅ›ci", + "WebRTC_Enable_Private" : "WÅ‚Ä…cz dla grup prywatnych" +} \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/sq.i18n.json b/packages/rocketchat-webrtc/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/pl.i18n.json b/packages/rocketchat-wordpress/i18n/pl.i18n.json index 6f31cf5a2e6..06727b945fe 100644 --- a/packages/rocketchat-wordpress/i18n/pl.i18n.json +++ b/packages/rocketchat-wordpress/i18n/pl.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "API_Wordpress_URL" : "WordPress URL", + "Accounts_OAuth_Wordpress" : "WordPress Login", + "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/sq.i18n.json b/packages/rocketchat-wordpress/i18n/sq.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file -- GitLab From 8f364c7925b8b4fcd33a588a62bc4a3134f5e184 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 7 Dec 2015 14:55:15 -0200 Subject: [PATCH 0719/1338] Clear iOS app badge on app startup --- packages/rocketchat-ui/lib/cordova/push.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-ui/lib/cordova/push.coffee b/packages/rocketchat-ui/lib/cordova/push.coffee index 659305fcf1d..edb317df4d2 100644 --- a/packages/rocketchat-ui/lib/cordova/push.coffee +++ b/packages/rocketchat-ui/lib/cordova/push.coffee @@ -65,5 +65,6 @@ if Meteor.isCordova vibrate: true ios: badge: true + clearBadge: true sound: true alert: true -- GitLab From 6b56d5ed923414ae8392374e25b57b7e7edd5bf3 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 7 Dec 2015 15:19:54 -0200 Subject: [PATCH 0720/1338] Add agents to departments --- .../views/app/livechatDepartmentForm.html | 32 +++++++- .../views/app/livechatDepartmentForm.js | 77 ++++++++++++++++--- .../rocketchat-livechat/i18n/en.i18n.json | 1 + packages/rocketchat-livechat/package.js | 1 + .../server/methods/saveDepartment.js | 5 +- .../server/methods/searchAgent.js | 21 +++++ .../server/models/LivechatDepartment.js | 12 ++- 7 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 packages/rocketchat-livechat/server/methods/searchAgent.js diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html index 5db5126701f..5a82ac77c71 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -22,9 +22,39 @@ <textarea name="description" rows="6">{{department.description}}</textarea> </div> </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}} + <tr> + <td colspan="2">{{_ "There_are_no_agents_added_to_this_department_yet"}}</td> + </tr> + {{/if}} + </tbody> + </table> + </div> </fieldset> <div class="submit"> - <button class="button secondary back"><i class="icon-left-big"></i><span>{{_ "Back"}}</span></button> + <button type="button" class="button secondary back"><i class="icon-left-big"></i><span>{{_ "Back"}}</span></button> <button class="button save"><i class="icon-floppy"></i><span>{{_ "Save"}}</span></button> </div> {{else}} diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js index eff4f358d9c..d4ff6d0fcac 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js @@ -1,6 +1,10 @@ Template.livechatDepartmentForm.helpers({ department() { - return Template.instance().department || { enabled: true }; + // 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 : [] } }); @@ -22,17 +26,20 @@ Template.livechatDepartmentForm.events({ return toastr.error(t('Please_fill_a_name')); } - var oldBtnValue = $btn.val(); - $btn.val(t('Saving')); + var oldBtnValue = $btn.html(); + $btn.html(t('Saving')); + + agents = instance.department && !_.isEmpty(instance.department.get()) ? instance.department.get().agents : []; departmentData = { enabled: enabled === "1" ? true : false, name: name.trim(), - description: description.trim() + description: description.trim(), + agents: agents } Meteor.call('livechat:saveDepartment', _id, departmentData, function(error, result) { - $btn.val(oldBtnValue); + $btn.html(oldBtnValue); if (error) { return toastr.error(t(error.reason || error.error)); } @@ -42,13 +49,65 @@ Template.livechatDepartmentForm.events({ }); }, - 'click button.back' () { - event.preventDefault(); + 'click button.back' (e, instance) { + e.preventDefault(); FlowRouter.go('livechat-departments'); + }, + + 'click button.add-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(''); + }); + }, + + '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(); + } } }); Template.livechatDepartmentForm.onCreated(function() { - this.department = LivechatDepartment.findOne({ _id: FlowRouter.getParam('_id') }); - this.subscribe('livechat:departments', FlowRouter.getParam('_id')); + this.department = new ReactiveVar({ enabled: true }); + 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); + } + } + }); }); diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 374873a7ed2..838fe206c37 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -30,6 +30,7 @@ "Please_select_enabled_yes_or_no": "Please select an option for Enabled", "Please_fill_a_name": "Please fill a name", "Saved": "Saved", + "There_are_no_agents_added_to_this_department_yet": "There are no agents added to this department yet.", "Theme": "Theme", "User_management": "User Management", "Username_not_found": "Username not found" diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 4617b065094..a10af188c13 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -51,6 +51,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); api.addFiles('server/methods/saveDepartment.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'); diff --git a/packages/rocketchat-livechat/server/methods/saveDepartment.js b/packages/rocketchat-livechat/server/methods/saveDepartment.js index 88c60936332..526b32134f2 100644 --- a/packages/rocketchat-livechat/server/methods/saveDepartment.js +++ b/packages/rocketchat-livechat/server/methods/saveDepartment.js @@ -9,7 +9,8 @@ Meteor.methods({ if (_id) { check(_id, String); } - check(departmentData, Match.ObjectIncluding({ enabled: Boolean, name: String, description: Match.Optional(String) })); + + check(departmentData, Match.ObjectIncluding({ enabled: Boolean, name: String, description: Match.Optional(String), agents: Match.Optional([Match.ObjectIncluding({ _id: String, username: String })]) })); if (_id) { department = RocketChat.models.LivechatDepartment.findOneById(_id); @@ -18,6 +19,6 @@ Meteor.methods({ } } - return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description); + return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description, departmentData.agents); } }); diff --git a/packages/rocketchat-livechat/server/methods/searchAgent.js b/packages/rocketchat-livechat/server/methods/searchAgent.js new file mode 100644 index 00000000000..72b9d3d9bb0 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/searchAgent.js @@ -0,0 +1,21 @@ +Meteor.methods({ + 'livechat:searchAgent' (username) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { + throw new Meteor.Error("not-authorized"); + } + + if (!username || !_.isString(username)) { + 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) { + throw new Meteor.Error('user-not-found', 'Username_not_found'); + } + + return user; + } +}); diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index e6ae538b945..41141b8d68e 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -20,12 +20,20 @@ class LivechatDepartment extends RocketChat.models._Base { } // UPSERT - createOrUpdateDepartment(_id, enabled, name, description, extraData) { + createOrUpdateDepartment(_id, enabled, name, description, agents, extraData) { record = { enabled: enabled, name: name, - description: description + description: description, + agents: [] } + + if (!_.isEmpty(agents)) { + for (agent of agents) { + record.agents.push({ _id: agent._id, username: agent.username }); + } + } + _.extend(record, extraData); this.upsert({ _id: _id }, { $set: record }); return _.extend(record, { _id: _id }); -- GitLab From 6fdc692216c0868156d8fe12ab2cf69c4d977589 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Mon, 7 Dec 2015 13:25:37 -0500 Subject: [PATCH 0721/1338] Fix for image swipebox to show in RTL interface swipebox has not built in support for RTL, and without this fix the images will display outside of the window range since it does the calculation for the window location assuming every thing is aligned left, and that is hard-coded in its javascript and cannot be overridden with css. The easiest fix which is proposed here is to override the global RTL just for swipebox, and make it display in LTR to match its calculations. The problem however, is that the Next and Prev buttons are still in LTR direction which is the opposite of what users of RTL expect. The other solution is to either replace swipebox with something that is RTL aware, or modify swipebox code to add RTL support. --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 0c8af2e4567..7a7d549c193 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -620,6 +620,9 @@ .left(10px); } } + #swipebox-overlay{ + direction: ltr; + } /* Overridding the icons Unicode to suit RTL languages * from _octicons.less */ -- GitLab From 349d5f70bc9343e30c2f7d3381e271bffa3f3e9c Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Mon, 7 Dec 2015 15:51:23 -0500 Subject: [PATCH 0722/1338] Updating the font file to move "spin4" and "sliders" icons to locations with no mirror property --- .../assets/stylesheets/fontello.css | 4 +- private/fontello.json | 4 +- public/fonts/fontello.eot | Bin 121588 -> 119036 bytes public/fonts/fontello.html | 88 +++++++++--------- public/fonts/fontello.ttf | Bin 121420 -> 118868 bytes public/fonts/fontello.woff | Bin 70044 -> 69372 bytes 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/fontello.css b/packages/rocketchat-theme/assets/stylesheets/fontello.css index 97693d464e3..30f207ccd4d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/fontello.css +++ b/packages/rocketchat-theme/assets/stylesheets/fontello.css @@ -81,9 +81,7 @@ .icon-spin1:before { content: '\39'; } /* '9' */ .icon-spin2:before { content: '\3a'; } /* ':' */ .icon-spin3:before { content: '\3b'; } /* ';' */ -.icon-spin4:before { content: '\3c'; } /* '<' */ .icon-spin5:before { content: '\3d'; } /* '=' */ -.icon-sliders:before { content: '\3e'; } /* '>' */ .icon-history:before { content: '\3f'; } /* '?' */ .icon-circle-notch:before { content: '\40'; } /* '@' */ .icon-marquee:before { content: '\41'; } /* 'A' */ @@ -132,6 +130,8 @@ .icon-behance:before { content: '\6c'; } /* 'l' */ .icon-gitlab:before { content: '\6d'; } /* 'm' */ .icon-rocketchat:before { content: '\6e'; } /* 'n' */ +.icon-spin4:before { content: '\6f'; } /* 'o' */ +.icon-sliders:before { content: '\70'; } /* 'p' */ .icon-camera:before { content: '\e800'; } /* 'î €' */ .icon-videocam:before { content: '\e801'; } /* 'î ' */ .icon-heart:before { content: '\e802'; } /* 'î ‚' */ diff --git a/private/fontello.json b/private/fontello.json index 45668495da2..9b4d945f8b6 100644 --- a/private/fontello.json +++ b/private/fontello.json @@ -293,7 +293,7 @@ { "uid": "9bd60140934a1eb9236fd7a8ab1ff6ba", "css": "spin4", - "code": 60, + "code": 111, "src": "fontelico" }, { @@ -1061,7 +1061,7 @@ { "uid": "21b42d3c3e6be44c3cc3d73042faa216", "css": "sliders", - "code": 62, + "code": 112, "src": "fontawesome" }, { diff --git a/public/fonts/fontello.eot b/public/fonts/fontello.eot index 3f0394a39f228c7a9c1a7997a09e4e2f8c83bf21..48cac3bf6a9be4a4fad5431a2cbf2d14e2c24b15 100644 GIT binary patch delta 12938 zcmb_j3v^V~x!(Ki^PKlgCKK`wAq0pa@(2&*b%=okh!8>y6AWR1Bp_i(2q+JMsfvh* z2plTbiwJ^<sECe&wMqr4QbknivU=CG*ScK2k=oXJEv1xe?zhim!Xyw9XtN@j$NnGt z-~Z$L|9$-7RpsJtMZWkECFLJ&k%x-aald_Vi@rW&%>Bh!LTDlWdwlL)OEcnji|K@( z$RdOcuWOta+^}VHCEiyNVr`r^dr2cccj0{s{;Km9uBdzE+2>~vB78~clgH=R&aSac zo&GhUPwmC`L+9fIi$@ub_y2|WS@VNSmwR{M72Sh>6xYIrxf5o8aBl8WLJznIVH<+8 zmp8Hl_EUtuz?Wq#njNe?^+a+i-oF7MA2c>BS^B|mUTh@v&_+Vy9%*c<ZTw?V@o_>w zJY{UA4YzG0j8IUf5Roj$-y|r@hy|}kkWr+u+1H%e+^0FGc|>#ZHx1vcYH7hYg!IIB zW12~GkLE0Vm)kt5dEz&V`FAZ}w)}U??~Gz0$Ji{0Mw6g3ur|WN31bDj$!aSmf<XO* zQn&FYOO_(9zF->@GxSuA36#(xnbJar7o<U;l-3y=#1Sc(disDHGvWm*6M+^HD$oWZ z5TOC8)EUj<p^ymCcd)Z;8c~UxOd)=9^6=0+L6T|Fq(jzHzdo3Vs;r7~kjRoMOZ7w& zR7t2O3Q<Kx4G_jaLx{IcK^L8nJn4|5d!$92*4K`<yAqwTRN=qMDKvoNZfR**!2Za} zV7%LPd%QQ!A`-zvDG^%t<ANcfEFtb<So4yy{BtN0^SRDHf|N@i8Ee(r5RqWALu@y* z5+_L}1Ibu2nf8bnYna0#@FQR(XjcUyQX<yds3_pK-bw`-zxA*qg&j4Vk*!#vlH``S z!E7*CcgRCA^o|&MZtxM^60cBMF~vKIiK4&^5f$`YsKjUk=RsJ5sXuAp+KUZbcQ}nK z$qj0&%9Y`Dnw5?kcf@9e3(%;$Sn<*{uZu+8fPZ9KmVc!4ccxMC&iKmmm(bgK50^z@ zj1C@<oFs}Y2S#H>LuEl27cpuk+!h|rf`o|z6YCLhf=KFdIJRO5A$Unr=PMmCD^p;p zWP}4Yg#F&w0Jf|FOvQ#MH$AcK>ki-6RT_TV2UD<`wA6_T!p2T|kY40QGEFaKa5Irg zV!T&i5<|2h)Tj{T+6rR5LPd#)Jb)N}>t$#TJ22*A6O66)ut11W==hjA!aipfRcMvz z62?eZTJP3yN-3K%h>23kfSi7*E~i3;zCH@Gv7$bd6ejbPp~}ihhcs-j7X%5CC<L*J zN&<y6O0c_nI44<z19zG}XX(yTZ<~8|$+arNmb+rVD`>zZ%Ic9MVSsu>RaB2|X<Jzt ze%mz^yD-kXAEF7yT2H<V^YMIm)N>Pc8s|MfP>1oSxMd-#>DC*mNL583jE6n9NN;{J zIDw!{84@4@6n>1ql29Gvkgznj$<-IfxVP^Li$k5V=8l(jnI7B{?Q}u@g!!-mIHe>u zv?<)WP!Oat9)m&!5hP(^C4TgTY15`mnN~5a;<oZBVQ;*XR>GZHcCcoaLA)f3H0loI zA}P(xgBH|@NP<p>>q{czM&Yi>PX(oe&?@+<=n$btCSEZSK_D?GA`z*<SmC?R_&;BQ zLeE7!balc&IpU$l>V%{?%kn0LImt3rfR7>uG&<f`o^W%B*OD=WX$aw3D^;nWmJ@1M z1fCQFM2@2xleK`u;%1`F0}pYEBtV=lm$RHWoi0CdIb9{KX;SBGG$sbGflsI-BkrW* zx@P32qJ@a%4r+;LWx0Y@dN&kGyZX+;cPDP3A!6p0P2w`t7L|BVUB;0!uclH&Z?qcQ ztpZQa0tw<kQD<nqM5)ZETyIeYSz%^sSCmCaEH*!}*=#JDh6i^^dMhsrF|-cQ>chJv zi&EJjvK%6rpD-IMF~Z4Tg%0Yj^f*CcSr$Pcs4oI*-AKQv>!F--&qF%oX%bnTmrLY$ z5s(Mb-3BJQCO|oh5a=1GAg0s$kl4A?a_$7k$ISUi8Lrg(wo@z3lWwGAgj(Zd>Uz^Z ztJA5~8}GHo2m7SPF(E6-#gIg$K<{LDWo8ctQ)E#I^h$IxIm2gTnhK9iqZY4fDeswJ zXDabpRc|0W#ltu%>Wf^9ToE5{;<igj<BC#3|B@J#*BCMS6(w9<KyDWsL9V?dA$%fZ zJ2PfxrO+B9l+}~U#_p^>#tpp_Ly=@#OEf2SY7`Y4zRNgv6sgQBH&4N+fCQ-o$ws9_ zttYCBs;+wCa!{9}o;VchPyjEjRI%1`AnWua0eFjT)M^D*al0*kJGEF`7Vg(PsnoX# z6KIIR!yuIl1<<-ap}ZbkMJ5Mou`**t0-XJ8GJRLxCr?%lG5d^_87ne$Eyj)RvrVSm z?ur<gMD5$-DtnEU8x<Ss&Y?!-I<K@>J=l$HM#WtwZO|2b2#({%Z~Y~)u})MO&h4{J zGLGeX*<^i^@mX$KlAs8UL<V}3X#l;WLdsEj6+b$ja6<p7bPO|ljAmfJ98yW{CFAv5 zZlgeYyuAX}k~p$J)_}Vs=lNT49)K;<A_sfn-{vi*L!_1qX5Zx}sc0CdlO^O4lBeI$ zk0Rys7Ou5b69H0VNS__>B)vswxriR;Tl6^TWDF_MC#1TN*oO8KM4+80R#s>$SZ=2S z`bJ4|NfV6bL0=eShh);bjXQ=Uhva*yBK`U;LA9JbCTObCikS)k2Sju+K?lCJNQxy$ zEUIMTA*)HM#ycAT1CdqR(Oyc5EJdIcngs#5SkqiuwD#zoaWYwiI_06N2>B?ZcsOGL zn4|8Y{GnFz?y93|o#;ejIO&BQm<+j$%hfj+(J0(!*kl1MB7oLQtP&M_AQ?}7vvovD zD4(ckDO52?&>@IOW>n@VCkPLcsUq{9**pldsW-c4cU!a6U0N8JpDa9+)9Qm_MD}hc zQzA^2SfEXIl*%|W;{9IS)kw>H_6@t0^d!l8kF->WU8Lg>D<*H=qkTSdt}$v<&v9g* zz9-e1!ZZt2?V4Jh?o4BL2erBFwrUxu4!kOol_V*V^-z#Oi+d$x#`lcNP~2`;h0p6@ zF8oX|<k4rwVQI@hShKJix@VHXWVAklqZ+|ZIbP@BhU0VaLs0Qz!BKhufLNq}j8ydF z<i!$W>X<ztnTMiyBSOJV1|g0LNd=ijJ%^__c*ocZHHwH;Q#Gp^M4f?m3-wME2~A+= z$WVyT76ok<J|F>xLQcak+<`$CfY5-OY8q;|D7t`#BcM5kUFf>_p;$-w=`pOXi<63~ zY_bZk8rz#1y9)9{^sQIFpmuY5lYn@+!^AwiF-13lwPdc3I#iG9@C1{nM^imoeLR-C zWxG3=NZpF;R_eXfhVp82!F`hx;+&$SiqdT0QB77gAa$ZxWF^pp;y8;@D6D>BwYsd_ zI!UGe5K1FQS=T8MT&)(D6+oeL$+0r^1?{Dg+Z(Q7f7d82TrhqBi-YqL!pej_#E1Ml zip<pm#`+1pQZ0N)fkp|V6At4sC$aM8ig!&?UHFp;jE=Vzi%5-d(MZrn+$j+l3BwI! z2TC377wA4dpa4&SHC&=JQYV#$Ht;!$z+4CsAv)PYH`mIEj~xid&~RNoWojqz3d`V; zTzKm;y(eOgiRQqC*A$#6K^fru;BThx#@Ca!du+u>YVEdTRF`B)=Jt%kC26g%J}=pP z+iHDfW#P~vBDM8N^LZo*iWVVcT@JS^Kpe#GblB1C5z*!pt3A|)euvp;AWjmP1x-A% zK>!V-rU~WvBWQjr)da01oH=<kdZv#LYj6UT-v}Jc=dPy`s`98-HDq!=s}v<g3}AGL zbrOLS%XUAp+r7o$6jP?Ih1M6Ly$Ll=zZN=YRHk8+{x!s_$5B=Qry4{?lDBn>hgul= zBq@5RIXDMmk(ec5(>S_7B?c;yWdb7*f}>Rw)z7P&$|JB3LcTBmLS{q`T#+<pz1}~s zi?yn%l($My)RIa=Eqi}>Bmg!GW6+?ckZdwazqwbELxQi<BA8xQ1wQ8rAh}{vQEpBu z{5WsP@J?H6?)P1mESw{yWH#Lr8GHJYvFTY<vp^eh1TyhRR7t6*HQ&a3OJl#)W4?$b z<1;Yc7vv*uFv<jI5r{<-ECHg4A)=L|dO%A)U63TxbTFbUb9|?`6>dZh@CUUKtLDHv z5W}P$k9L$CrVs9%lE7OvoF0aUru=rae3W!OQuSe-3l!U{swj53ymha#Qc@W{UY<?O zBWV(z5iSCWW|PNt8<Gl!Pep0SJ>w&$%)#JJ;ll;q$e{;DDxivp+DwUpp&~42D@JIw zPGSdQCq0S66wFhZjC3fAGEgi<N6yPobfKPZu1W565oWEG6{|25fyV(a#4#%-S^22( zZ|Tk+fVXi-a_IB`8d^g?mxwZxMKplWi%=y9);!{oKJZ>u)GBOV^8>!w<Y+bTk|w>4 z$N?f8Q3n~u)ah}?!s&mceT>!q^wtJ=2C=CQ)#eBihgEf;p0y=ZMPvYk1lA<5rWK)W zg=ZpQ&@%+gl!R^<9;vFPqDZ)kBKx5?fUqFA1+F(AQFbCBgy#1eMW9ApE`kS8CnByY z0Z_iXyWqicJt86!P_mp(l&lVR3dI;opGlkmeoi%b-KPQbcMx!izd3kKTE47lad6?h zy1=X%{<5j*;eXDUPeX6&-Z;3P53mx+oX~U$vn{dJOZy{UQMxf45&5}G+*@({@KHf9 zvk*>Sk|Jl`=B8Z|!4z#o{o$uKTqZ?99aRM2=vHab<%VbGGjS;E_#ACz5i3KCZ9?1| zJ*zWh6F|6(zs$_mOpw5*SjPJ^(>U@pZ_kXy)lbCn+mHq9c91%dL~?<OzA&<8^$z92 z&j~y|h(QlRfY5*i|H2qjz)EE>*HF%*eQ|5L?}EnHo<_ggayMi++pRZ}17{MEeOrEn zzGtDYizJes=;H^YdHB>2XZHzV&IqlU!Zjq4C`$pZB=Petc#EOG*kPP^H3DCI0*v)L zXYMrDs!{Gn{G8t;D%`N*FQF*tkS&}fjwFx*GS?91_RIAaBl*Q#f7#$czP8VF{?-|N zYb>05+RYQ`0>*DHIlFW+(U@G*qaXY&mJ5Jo1Pey5>&(`Hi!t`sEDnK`>(qephZVYv zL0f1ak)0)oqGUy;jpCNxe5xynyp3aMLD9xZ@Fm9FCTNUqvh~cbuo&KU*<u~*dUfOq zN9?#T?5J~5J1z$iXw*!jZsUe|y^XYaHq3r!&dZ_h@cMc83(12c<*g*Chu}+aCHP!H zuLsu_2`*>7@qY`_hs4LZnG^GGO?7I4<U}DM0egtGRcDj~E~mtXB9wY(L`jzuVRI%? zxS;-Bem%fr^aQKI0hW=yx;rB&!7Vai3W45&v3ax(_95t9VRU3_3aE|hBS@6Pcw7qd z+AZ>%H=B8_$CGfkmOG>g8OeGoGM0q?hG9U3o5%K3sygGv;Dv~P91=FdXOnO(T1_sz zT256Kh39$5ORB(-lW{$#@<A_lrH}v=6hyy<@G?_QO#0(+tZOPWJAsN9fVQle&$lcI zwQxbqKunoZj7(TTtmGo2#1YzVNHeovR7ZXR7e8>o^xI0O6pah7X-ESu`KPh7F}r3Y zHpvvV7S|EDxJHYI_&{9%5``T#DZtMY^Fg2!#cZQZBx>=a!*!eEZGJjk@i4w?^c6%& z^qV_Mv=T+NDuGTV%W_1Xv3K$R(9eyHO^Kl_bWkW)lmr2u5W;v?K?UfOq(yKYbG6qT zhVX;wdabW*aFP?tmk(MnfRTBI1%KfZ_go7n=>}(~IH59ZUDBT>T*~JX8I36%dJED- z&Kspm(?Y{xeB3pen?Zi!(SVr11X<H$zs0OVNFZj-b)z*y$HO}Tm)Qw$`*%riW-7D% zcA&>$Fm0H5QHfHo;gJOnMzx3vTC56iCp?4EPI~x-J8P)nT9$n42K|8qsuC4pry%Sk z+*?Uj%o2T=Dk^fdQxk+ZJ9jTuo#^f1h?hi<4O3{5R%7gq`Aix9SS=MUYOz`-8uu)F z)<pb~k)<8wdP5`$W+4utADk4}1j8{@f#{HuF+Ot>-EAk?*;-g3X04vtk!57u2D}?x zW&C{kJfr7|{x-xvKLi_YcHG8{6+I&#I9fk=U`3`JFux1GxWY+8)wo*5&5{W4K!s}l z1%JK+Wx%}b<k#%k_)xPn@Z9adgE+8ydz$EKeL!R(?-W?$Wy|r*RhcP^3Kd)&<@fEn zG3xHMmSKASzyU}vw8;4Q?gYD8hT3MPDXVrHZ>$=O#}d9<HI1$`3Rh>#a531>Xk49^ z0Xs#^sVA5T6=fXPlh{jS-0wERt9N>No7h@tZ78&T@Nm{q<AF7)XfZfC&%wM>lqrVH zGFHkWH>&BnW{EPph3K@uwaRu%VV0)$6rHnoVxjp&6uSH9ZNkRTcgE_U{5?b)^yKO2 z<tv5=f~7D~(1cs^(wL%&MNT|?(b`N_6PwfJ<l{xjrMe_!Wl_bj9MwwE9Gb#=CaO6Q zr!E|aD!SBap1kmkTL4ejX^I6i$Y|PhIz4{k!61tFN67td{6rhOf4>-<nkgnCMX$PS zACo%Sh=(|B9%rB%8@j|lylm}!YW)6wpS&XSn8o?~`{YI8(mf7Dsu!iiK{u`tWJgo6 zmD$y~m}%Q@$MCj{YF4Ev*#Jq~6G5|JGzX!uuIvyUvIt17h;~u22Z^1DcEr18m8=@N z5eIH99Ne9V#l|c!BgW@8EALKPZ$&vI!Sfg{I2y8+AGc{P)9Sn}?I<SnZ;%toj+f+c z@9!w5Gco9guX{hdzI9hlXJSHab~A&_v|Gph@G4W=@py<L^5-i7lkB2uufN7aY7>UX zUOJpo>c3%EZJPq~R%d802Ca9*-EQmJ-|#ptbpZo)aZa%U!hIe*K|?a~<9Ttpa00HX zp_|Djd1Ndd{^~G_z8lSU9Clhth@ILAnr&)R=v;zpOHryNc4AZPHsCH?1!2NG8?B6m z@j(nD94J=1D36hHuyx3qBY?M}T*>EHw;}|+;5(I&P)Ek9q#>BDpR-;TqpY3U&@-u8 z=S;J^rEjJ2@k2j&ZEg39=<W#Rk5)U3&o_P#2#ca$68`w%zSJqS{HbLQy9nT(082h^ zd@?xKYR0%({auDNzt`4$i+K}fjLlExB@Y0aBLiHH8JqK8GVZ)-j=S2Yc^IDWLVp18 zkD45AzDc9^{bSRSe{7;t(o!D$ZCv#%=g7YiD{F=t<jg}m|2Oh?>D$|DUZBs?=Iy?N z^tjBvA%s;P`Sc+DLJB<&ju(U~R?YUaAH>(Bo24o_M`=>_s#WSP?Vu&adfK+rKEU~B z@8tNj_;bE56B-jslhTp`Nf(nFQ`V(@oxU>tOh#eGnVvf`SN0m(Yg^X0y_aVX?@Ri= z+;4o2H|NV6*4*%A?za9-{XfggzH#$_s)2z);|CY#H|C!o(l|6PH1xG$eTUTy`)>Hj zn}*-KW7MG014chO#;+6o=vd3x(PNv&K0o$+L0Umw!P#3D-g3IoQ8==2W8rt>(#9<v z?;0N%|9VkLaa!@c#cvh=IH7#Pt_dGa^i3?8xOL*`Nuwt{HtAeRLCKC=cij5@<owAC zCm)_7PZ>UCT`4IYSz1-Px%6b|g{h(Psc)2d%c{!GPMbXK(emNtpWU{$LawN;*je$> z^t|cwr=Rl|`ZxREt5hrX%KbAOGpc7Cobki$i*7$y<(nzaTr~4gb$0cJSsAl_GV5fZ zZ(u{<``L}NPs~Y~Q$FX>ITz=ynR}=vvu1wH!J1EMN7t^e{i?3C?$o@=^BU*9GylvT zCl>fZ3%;s%)tA>FT$r`6ap9R@O0YcmRPcvIYZrankkjx^!@0&s8!s#_UA%Acw@qu8 zWG>mdlq_Ah^sS{A?kv8u`L2q)w%v95uJ4x(U-sFui^~tJs93RgW&X;#l}GPRyZgYZ zj8!kM&REm5=J-!G-9zqay63Zd%kO>k-jny0-?wQkS(~?Z>)JE-hsy7NXI<&K?;dD; z;OzSO>%V$%&VyfV5H@6P@NYQzP~JoShc-WSeq-atPadv*_?1oirh}U<KC<$WuQ!)( zKCs2NrDn?;TfW~qW9tFKXDl)f8eeW3y=~LBGe1rH>HMD_eKhOQjoWS8-+651V|yPv z_p`vy9{bth$1DEh@D6pyf*og`Sog%YJ4<&y6?(GAlcS&9xGR6xu3cw$TXyH{UbXww zQ)y2%K6QLg?w(D1PVBk3w`A|3r-i2rpFZ{U*?pFML-)<uw`t$&`~L8Z=b6#ZEO=)B zGk@5hxxaD$(ft>m{q(@i2R0t~<hiux>YjW2xv!po`33cbf*1aLu;5_eMft^DFMfYW zKeX$mH7|Yr^1_!t4QGZ=yb|)ia_ZHjS06tt9IiY3-jTc`2VTp5?dzXcz3zE^$1g_z z;^jBU8>Mf2_GaHV=e)V~%^%-7bIf}z|JcG~yN;bbo_4(S_>SWry)D1J`R(7G$USlT z#E-vP@T<pv)%;HWJ8RxK`L6HXns+z8d-&boom5ZiC+|9W@Z=wUJ^I&2-y`qUykGtP z!BdV?>rQ=}{lV$eDIaEixbwr`BUS;w=m~nB#PhfXaxEis@cas))+1%F(FF<}a^(GA z(wC`2TGDvOqI_k^!aHheo0c3|eT<gd`TyOJ>LDIxZTUM(Wm8-3z|#|dYbj@Cm`qLM z?~j~2O*dO_NT4L=B_b7sEh<$bue`GPN-lU^cneBs_*5x)o#@+N`cFF0V^gUu=QY}L O{~__=mjqlBkpBlZXvA&+ delta 15514 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 B*V_O9 diff --git a/public/fonts/fontello.html b/public/fonts/fontello.html index 201613af7eb..89f21ec99cc 100644 --- a/public/fonts/fontello.html +++ b/public/fonts/fontello.html @@ -229,48 +229,48 @@ body { } @font-face { font-family: 'fontello'; - src: url('./fontello.eot?81635713'); - src: url('./fontello.eot?81635713#iefix') format('embedded-opentype'), - url('./fontello.woff?81635713') format('woff'), - url('./fontello.ttf?81635713') format('truetype'), - url('./fontello.svg?81635713#fontello') format('svg'); + src: url('./font/fontello.eot?45674533'); + src: url('./font/fontello.eot?45674533#iefix') format('embedded-opentype'), + url('./font/fontello.woff?45674533') format('woff'), + url('./font/fontello.ttf?45674533') format('truetype'), + url('./font/fontello.svg?45674533#fontello') format('svg'); font-weight: normal; font-style: normal; } - - + + .demo-icon { font-family: "fontello"; font-style: normal; font-weight: normal; speak: none; - + display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ - + /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; - + /* fix buttons height, for twitter bootstrap */ line-height: 1em; - + /* Animation center compensation - margins should be symmetric */ /* remove if not needed */ margin-left: .2em; - + /* You can be more comfortable with increased icons size */ /* font-size: 120%; */ - + /* Font smoothing. That was taken from TWBS */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - + /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } @@ -279,14 +279,14 @@ body { <script> function toggleCodes(on) { var obj = document.getElementById('icons'); - + if (on) { obj.className += ' codesOn'; } else { obj.className = obj.className.replace(' codesOn', ''); } } - + </script> </head> <body> @@ -340,83 +340,83 @@ body { <div title="Code: 0x39" class="the-icons span3"><i class="demo-icon icon-spin1 animate-spin">9</i> <span class="i-name">icon-spin1</span><span class="i-code">0x39</span></div> <div title="Code: 0x3a" class="the-icons span3"><i class="demo-icon icon-spin2 animate-spin">:</i> <span class="i-name">icon-spin2</span><span class="i-code">0x3a</span></div> <div title="Code: 0x3b" class="the-icons span3"><i class="demo-icon icon-spin3 animate-spin">;</i> <span class="i-name">icon-spin3</span><span class="i-code">0x3b</span></div> - <div title="Code: 0x3c" class="the-icons span3"><i class="demo-icon icon-spin4 animate-spin"><</i> <span class="i-name">icon-spin4</span><span class="i-code">0x3c</span></div> + <div title="Code: 0x3d" class="the-icons span3"><i class="demo-icon icon-spin5 animate-spin">=</i> <span class="i-name">icon-spin5</span><span class="i-code">0x3d</span></div> </div> <div class="row"> - <div title="Code: 0x3d" class="the-icons span3"><i class="demo-icon icon-spin5 animate-spin">=</i> <span class="i-name">icon-spin5</span><span class="i-code">0x3d</span></div> - <div title="Code: 0x3e" class="the-icons span3"><i class="demo-icon icon-sliders">></i> <span class="i-name">icon-sliders</span><span class="i-code">0x3e</span></div> <div title="Code: 0x3f" class="the-icons span3"><i class="demo-icon icon-history">?</i> <span class="i-name">icon-history</span><span class="i-code">0x3f</span></div> <div title="Code: 0x40" class="the-icons span3"><i class="demo-icon icon-circle-notch">@</i> <span class="i-name">icon-circle-notch</span><span class="i-code">0x40</span></div> - </div> - <div class="row"> <div title="Code: 0x41" class="the-icons span3"><i class="demo-icon icon-marquee">A</i> <span class="i-name">icon-marquee</span><span class="i-code">0x41</span></div> <div title="Code: 0x42" class="the-icons span3"><i class="demo-icon icon-eye">B</i> <span class="i-name">icon-eye</span><span class="i-code">0x42</span></div> - <div title="Code: 0x43" class="the-icons span3"><i class="demo-icon icon-users">C</i> <span class="i-name">icon-users</span><span class="i-code">0x43</span></div> - <div title="Code: 0x44" class="the-icons span3"><i class="demo-icon icon-shower">D</i> <span class="i-name">icon-shower</span><span class="i-code">0x44</span></div> </div> <div class="row"> + <div title="Code: 0x43" class="the-icons span3"><i class="demo-icon icon-users">C</i> <span class="i-name">icon-users</span><span class="i-code">0x43</span></div> + <div title="Code: 0x44" class="the-icons span3"><i class="demo-icon icon-shower">D</i> <span class="i-name">icon-shower</span><span class="i-code">0x44</span></div> <div title="Code: 0x45" class="the-icons span3"><i class="demo-icon icon-swimming">E</i> <span class="i-name">icon-swimming</span><span class="i-code">0x45</span></div> <div title="Code: 0x46" class="the-icons span3"><i class="demo-icon icon-chart-area">F</i> <span class="i-name">icon-chart-area</span><span class="i-code">0x46</span></div> - <div title="Code: 0x47" class="the-icons span3"><i class="demo-icon icon-chart-pie">G</i> <span class="i-name">icon-chart-pie</span><span class="i-code">0x47</span></div> - <div title="Code: 0x48" class="the-icons span3"><i class="demo-icon icon-chart-line">H</i> <span class="i-name">icon-chart-line</span><span class="i-code">0x48</span></div> </div> <div class="row"> + <div title="Code: 0x47" class="the-icons span3"><i class="demo-icon icon-chart-pie">G</i> <span class="i-name">icon-chart-pie</span><span class="i-code">0x47</span></div> + <div title="Code: 0x48" class="the-icons span3"><i class="demo-icon icon-chart-line">H</i> <span class="i-name">icon-chart-line</span><span class="i-code">0x48</span></div> <div title="Code: 0x49" class="the-icons span3"><i class="demo-icon icon-bicycle">I</i> <span class="i-name">icon-bicycle</span><span class="i-code">0x49</span></div> <div title="Code: 0x4a" class="the-icons span3"><i class="demo-icon icon-bus">J</i> <span class="i-name">icon-bus</span><span class="i-code">0x4a</span></div> - <div title="Code: 0x4b" class="the-icons span3"><i class="demo-icon icon-at">K</i> <span class="i-name">icon-at</span><span class="i-code">0x4b</span></div> - <div title="Code: 0x4c" class="the-icons span3"><i class="demo-icon icon-infinity">L</i> <span class="i-name">icon-infinity</span><span class="i-code">0x4c</span></div> </div> <div class="row"> + <div title="Code: 0x4b" class="the-icons span3"><i class="demo-icon icon-at">K</i> <span class="i-name">icon-at</span><span class="i-code">0x4b</span></div> + <div title="Code: 0x4c" class="the-icons span3"><i class="demo-icon icon-infinity">L</i> <span class="i-name">icon-infinity</span><span class="i-code">0x4c</span></div> <div title="Code: 0x4d" class="the-icons span3"><i class="demo-icon icon-at-1">M</i> <span class="i-name">icon-at-1</span><span class="i-code">0x4d</span></div> <div title="Code: 0x4e" class="the-icons span3"><i class="demo-icon icon-child">N</i> <span class="i-name">icon-child</span><span class="i-code">0x4e</span></div> - <div title="Code: 0x4f" class="the-icons span3"><i class="demo-icon icon-plus-squared-alt">O</i> <span class="i-name">icon-plus-squared-alt</span><span class="i-code">0x4f</span></div> - <div title="Code: 0x50" class="the-icons span3"><i class="demo-icon icon-unlink">P</i> <span class="i-name">icon-unlink</span><span class="i-code">0x50</span></div> </div> <div class="row"> + <div title="Code: 0x4f" class="the-icons span3"><i class="demo-icon icon-plus-squared-alt">O</i> <span class="i-name">icon-plus-squared-alt</span><span class="i-code">0x4f</span></div> + <div title="Code: 0x50" class="the-icons span3"><i class="demo-icon icon-unlink">P</i> <span class="i-name">icon-unlink</span><span class="i-code">0x50</span></div> <div title="Code: 0x51" class="the-icons span3"><i class="demo-icon icon-share-squared">Q</i> <span class="i-name">icon-share-squared</span><span class="i-code">0x51</span></div> <div title="Code: 0x52" class="the-icons span3"><i class="demo-icon icon-tree">R</i> <span class="i-name">icon-tree</span><span class="i-code">0x52</span></div> - <div title="Code: 0x53" class="the-icons span3"><i class="demo-icon icon-database">S</i> <span class="i-name">icon-database</span><span class="i-code">0x53</span></div> - <div title="Code: 0x54" class="the-icons span3"><i class="demo-icon icon-lifebuoy">T</i> <span class="i-name">icon-lifebuoy</span><span class="i-code">0x54</span></div> </div> <div class="row"> + <div title="Code: 0x53" class="the-icons span3"><i class="demo-icon icon-database">S</i> <span class="i-name">icon-database</span><span class="i-code">0x53</span></div> + <div title="Code: 0x54" class="the-icons span3"><i class="demo-icon icon-lifebuoy">T</i> <span class="i-name">icon-lifebuoy</span><span class="i-code">0x54</span></div> <div title="Code: 0x55" class="the-icons span3"><i class="demo-icon icon-cubes">U</i> <span class="i-name">icon-cubes</span><span class="i-code">0x55</span></div> <div title="Code: 0x56" class="the-icons span3"><i class="demo-icon icon-cube">V</i> <span class="i-name">icon-cube</span><span class="i-code">0x56</span></div> - <div title="Code: 0x57" class="the-icons span3"><i class="demo-icon icon-bell-off">W</i> <span class="i-name">icon-bell-off</span><span class="i-code">0x57</span></div> - <div title="Code: 0x58" class="the-icons span3"><i class="demo-icon icon-trash-1">X</i> <span class="i-name">icon-trash-1</span><span class="i-code">0x58</span></div> </div> <div class="row"> + <div title="Code: 0x57" class="the-icons span3"><i class="demo-icon icon-bell-off">W</i> <span class="i-name">icon-bell-off</span><span class="i-code">0x57</span></div> + <div title="Code: 0x58" class="the-icons span3"><i class="demo-icon icon-trash-1">X</i> <span class="i-name">icon-trash-1</span><span class="i-code">0x58</span></div> <div title="Code: 0x59" class="the-icons span3"><i class="demo-icon icon-toggle-off">Y</i> <span class="i-name">icon-toggle-off</span><span class="i-code">0x59</span></div> <div title="Code: 0x5a" class="the-icons span3"><i class="demo-icon icon-toggle-on">Z</i> <span class="i-name">icon-toggle-on</span><span class="i-code">0x5a</span></div> - <div title="Code: 0x5b" class="the-icons span3"><i class="demo-icon icon-birthday">[</i> <span class="i-name">icon-birthday</span><span class="i-code">0x5b</span></div> - <div title="Code: 0x5c" class="the-icons span3"><i class="demo-icon icon-github-circled">\</i> <span class="i-name">icon-github-circled</span><span class="i-code">0x5c</span></div> </div> <div class="row"> + <div title="Code: 0x5b" class="the-icons span3"><i class="demo-icon icon-birthday">[</i> <span class="i-name">icon-birthday</span><span class="i-code">0x5b</span></div> + <div title="Code: 0x5c" class="the-icons span3"><i class="demo-icon icon-github-circled">\</i> <span class="i-name">icon-github-circled</span><span class="i-code">0x5c</span></div> <div title="Code: 0x5d" class="the-icons span3"><i class="demo-icon icon-google">]</i> <span class="i-name">icon-google</span><span class="i-code">0x5d</span></div> <div title="Code: 0x5e" class="the-icons span3"><i class="demo-icon icon-pied-piper-squared">^</i> <span class="i-name">icon-pied-piper-squared</span><span class="i-code">0x5e</span></div> - <div title="Code: 0x5f" class="the-icons span3"><i class="demo-icon icon-slideshare">_</i> <span class="i-name">icon-slideshare</span><span class="i-code">0x5f</span></div> - <div title="Code: 0x60" class="the-icons span3"><i class="demo-icon icon-wordpress">`</i> <span class="i-name">icon-wordpress</span><span class="i-code">0x60</span></div> </div> <div class="row"> + <div title="Code: 0x5f" class="the-icons span3"><i class="demo-icon icon-slideshare">_</i> <span class="i-name">icon-slideshare</span><span class="i-code">0x5f</span></div> + <div title="Code: 0x60" class="the-icons span3"><i class="demo-icon icon-wordpress">`</i> <span class="i-name">icon-wordpress</span><span class="i-code">0x60</span></div> <div title="Code: 0x61" class="the-icons span3"><i class="demo-icon icon-digg">a</i> <span class="i-name">icon-digg</span><span class="i-code">0x61</span></div> <div title="Code: 0x62" class="the-icons span3"><i class="demo-icon icon-delicious">b</i> <span class="i-name">icon-delicious</span><span class="i-code">0x62</span></div> - <div title="Code: 0x63" class="the-icons span3"><i class="demo-icon icon-hash">c</i> <span class="i-name">icon-hash</span><span class="i-code">0x63</span></div> - <div title="Code: 0x64" class="the-icons span3"><i class="demo-icon icon-hash-1">d</i> <span class="i-name">icon-hash-1</span><span class="i-code">0x64</span></div> </div> <div class="row"> + <div title="Code: 0x63" class="the-icons span3"><i class="demo-icon icon-hash">c</i> <span class="i-name">icon-hash</span><span class="i-code">0x63</span></div> + <div title="Code: 0x64" class="the-icons span3"><i class="demo-icon icon-hash-1">d</i> <span class="i-name">icon-hash-1</span><span class="i-code">0x64</span></div> <div title="Code: 0x65" class="the-icons span3"><i class="demo-icon icon-clock-1">e</i> <span class="i-name">icon-clock-1</span><span class="i-code">0x65</span></div> <div title="Code: 0x66" class="the-icons span3"><i class="demo-icon icon-asterisk-1">f</i> <span class="i-name">icon-asterisk-1</span><span class="i-code">0x66</span></div> - <div title="Code: 0x67" class="the-icons span3"><i class="demo-icon icon-cancel-circled">g</i> <span class="i-name">icon-cancel-circled</span><span class="i-code">0x67</span></div> - <div title="Code: 0x68" class="the-icons span3"><i class="demo-icon icon-bell-off-empty">h</i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0x68</span></div> </div> <div class="row"> + <div title="Code: 0x67" class="the-icons span3"><i class="demo-icon icon-cancel-circled">g</i> <span class="i-name">icon-cancel-circled</span><span class="i-code">0x67</span></div> + <div title="Code: 0x68" class="the-icons span3"><i class="demo-icon icon-bell-off-empty">h</i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0x68</span></div> <div title="Code: 0x69" class="the-icons span3"><i class="demo-icon icon-meteor">i</i> <span class="i-name">icon-meteor</span><span class="i-code">0x69</span></div> <div title="Code: 0x6a" class="the-icons span3"><i class="demo-icon icon-git-squared">j</i> <span class="i-name">icon-git-squared</span><span class="i-code">0x6a</span></div> - <div title="Code: 0x6b" class="the-icons span3"><i class="demo-icon icon-angellist">k</i> <span class="i-name">icon-angellist</span><span class="i-code">0x6b</span></div> - <div title="Code: 0x6c" class="the-icons span3"><i class="demo-icon icon-behance">l</i> <span class="i-name">icon-behance</span><span class="i-code">0x6c</span></div> </div> <div class="row"> + <div title="Code: 0x6b" class="the-icons span3"><i class="demo-icon icon-angellist">k</i> <span class="i-name">icon-angellist</span><span class="i-code">0x6b</span></div> + <div title="Code: 0x6c" class="the-icons span3"><i class="demo-icon icon-behance">l</i> <span class="i-name">icon-behance</span><span class="i-code">0x6c</span></div> <div title="Code: 0x6d" class="the-icons span3"><i class="demo-icon icon-gitlab">m</i> <span class="i-name">icon-gitlab</span><span class="i-code">0x6d</span></div> <div title="Code: 0x6e" class="the-icons span3"><i class="demo-icon icon-rocketchat">n</i> <span class="i-name">icon-rocketchat</span><span class="i-code">0x6e</span></div> + </div> + <div class="row"> + <div title="Code: 0x6f" class="the-icons span3"><i class="demo-icon icon-spin4 animate-spin">o</i> <span class="i-name">icon-spin4</span><span class="i-code">0x6f</span></div> + <div title="Code: 0x70" class="the-icons span3"><i class="demo-icon icon-sliders">p</i> <span class="i-name">icon-sliders</span><span class="i-code">0x70</span></div> <div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon icon-camera"></i> <span class="i-name">icon-camera</span><span class="i-code">0xe800</span></div> <div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon icon-videocam"></i> <span class="i-name">icon-videocam</span><span class="i-code">0xe801</span></div> </div> @@ -980,4 +980,4 @@ body { </div> <div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div> </body> -</html> +</html> \ No newline at end of file diff --git a/public/fonts/fontello.ttf b/public/fonts/fontello.ttf index 7a3e33ddae8da50d363e63183182db115e9d1476..43fc3e31441bec33e9acf7d586154839cb06c5e3 100644 GIT binary patch delta 12791 zcmb_j3wTsTmae*WpZ)Gmr$e5EBm{_&X9VOCF9;++Bq4;@!O%311WeOOc&LbI`#{G5 zWPppJEb<UVL`Ad(90y%RM$thW(Q)1VMrHl{W+US`uIn(a%V+kl+v(5=2?S>RqTPLO z)j6k5o%5eZl_y?SKHjNp$c`BEe>08{IsyM~oqy}{?4(^{Z$gjd5kf}RH!lpY*|?zw zziSDxHZPpJtQpT;_?>}Ib>ZUM>tBB6xmkn=rwQG0bWz>h1(xYIensdLPvZUXMR;KG zC?oOvkNBOpD7<`ycN@OZ-T05<THG{$^4#~&&R<UGJ{KWuO?d8#X133Mg3#yru<XXU z;kpx#r)T2#5iohbxoO$*_dj}}na~642ub=?^U}KJKbMpqCG>+68(W%YZYGRSOw1r6 zS%J?q$jXQX-$s+Mq`Ae{lGD<!rJ!YWOX=55U$1Iy#T!EU;N5jCq@`C&9^MtUjBT0n z^%DNB^>phOt)Ck^X@QYVMdLlHGmti{!ZG7R;o7Tgr9=>@pHS+ilhgG~iHb~Mq7arL z0}}}gw!b&7Ve3+}^-PTkl+Y5H(g_S-NRvP*tv9}8qcd{!-h&5aCks?20xcm_piM*| zLK6h6H+1npM1(*$vomZ4QHh(B6F)hAX!t-ul4;4*1J(+^K8%Q}tcr4&$dW2cAtDK? zB!q}UR8dibgfYw^#M>^m3t~?_;ON=Z5<b`0VQx=3IumC_C(9W$2pec^ZEawGW|dIs zO}ahVn`9A*;GvWVZR>GCeGrxqcPVsyUReGdf+RfG`6F;S|H$~GQfKI@H$r>GlrzF% z5xB}33ENeHh?IyS8x;log{)MN@fU*LDD<XbPi&<Ml_a;s6=Z{gE_1pgK0VT=;L$x| zuTWVr**i*!qF~uE5%fZc#Ap+zL0FS1KWXC9i%nd17>O*&O>Gj_)YRy?*N-1IG&5sz zsc}Ya9Xs)`&5F&ZaYM1<tEpHQi5mcaWa^YZ()lk_o%m&pviz04WfWMmBRQ~27%&UN zx?$)cc$pxQ5Oi-Vm0<Jd$#p-{kuWj?icN>LLw>$IP-RV^DK^E4>8Xit9f_~&Ym5Wd z_scPywAPCXyuwa;kz6u}%+M<stVpDinCump#NbTuBr1ftw1OB?s3;MU`v=2ch<hs* z%b1HzHqO|h0wKmW`-jvKZFJ<(2(67-Kt^TxP$o)cg9`>^x||9X`uku^l$G?OWJ236 zcR7Z|$LL+Yj+3aVnR-BjLUJLRAOS_df=WV!LO@EOkr2$6G{PjDrd3)l9DCtVZ@U3^ zB75P`7*!4i0}>^eC<*3RCQ%jwm_lbE_*q<z&f<1Sx27hV?i!9&7!~fdG{yL%yT}TS zx8ddp<Fq^5813;=r%~bgfjW$dNw-C)rdtP5k*bP77)J!Io4$Nkv3o#R25f{c!{+fR z34sKQ#b$8jTzqhX{rkEY9O;%cH`=@l<lrjlAPbKO0|*uXi<ZQuc7fXl3W8M0{Z*(Y zf+S3V&(`QEGiH>R�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 J3h3yQ{|A#vrjP&t delta 15535 zcmcgz3wV@OdOnx`I`^4mCV^ZDAzVZV0s#T>2a$w3h7e{#5)#6F2nhjQtgb(x>mpT* z{8U*)ig;JlXt=Ffi<TmbNLiQq?Aph6cS~)w*6#YSTkAtf-}BE*n1m#R-R?fm!2EOm zbH498-}&y}$@%^2nL}!Gu6gS0{(mNfPQ$<Lb$4yd4ZW!BAoOfHA!O2u#+CKkA8U@_ zcNrnh#+9`j8Zqv}Zy&z3m22-_@o;Jx-m!CpzI1Zc^4ewk<lX6n9^8%hMXNC22&m)n z`y77fud3g;DRnQN=)sGGsJ^ugbu(&D><ecSdPpLKZ?CW2)W}b`&k%aF8Pjst)z&XR z^HfF_ezyS0M~w{|HZJ=neIB82Z6+k;(Z;6bjcaGjK0)X&PCVAuFyjHj3B|%pB9T@2 z4uMuq6g;hK3$^974Q?COHnFYbi-s@mZEwdYAp_b-TY6hQ#)r4v(l+yp^<upJm)1c# z%=(lXG}FprC#-*A6L0X85XLBYK?8I~hLI&xi8C&-dIcD{M0icdd+T=o@PHx4Ae}Qx zXt6@+G>!*KO7TT#Im08JX?@8j4jgI}6pqXdGO7?piwR}4fiP^f48TYj4`jAAMQSmz zA=18@f5{gRjrhqt5~dYLibgP5p~bUW9P`7*c%pKRsLP2aaZQR6N#T+bC5p@yIZ9;4 zWfmoz3!o&_v6mqBGONXj^*4+4T-EBk17KbYg6CQgx&lb=LPDrl0E@fXgufF6qo_Cf zJFqjs;;IB6{Cq|v(t1?Rq$X`|Z(qazgO@^hHX80=YKlW5EP#_@V6b424@UyVLGDU$ zmNCYOZHsa2rqj6CjTi@wN#hv8!8dk{6JU=V&JKpSY)w?FOc`g~!k^|&;w2em6q!Qi zl9m|qAsz?gPRbO{YFt#pu}VsfTZ5?3uuduUl&DmeQ)F?Pf~afF_jSxS3b0;4lCmkO z=?+aCa_c_LN$-dpbvYqLREVA6iW84ESArygTMXF@i46%}h#{L7VhFzk*<uJBus+xS zi|(~PapaoNa|V^+_0T7%7Gzka5d11I%)=7Udzs|JBqJA!#2N_Y&?GML2BA4p8IdFs zv7yb0L<~PAdATWmw@cT^L^@HCQ*V$*P;0OAP`%Kz6_N@)bCYy3kc=cvhL=MOBr3CD zD%6N$=jqr}HV#vWQ@tudS7pxRT44&XP0oWHlypoWSk%~M7Ito=S%2+nwHCV1QD19; zC!aEMz`Dbmy?R!Q4)|FrWfGMbg@wUxfUOF<ki$fl{gU8@(E45`g)phN_W;uRh_8rR zfA8N;v#j}nF$!phd9$_$Zl-?gMBpOzSwBwso=M&|oFl13HI)%A)IpG!39%r;s#GhK z!vc~@P!~JZ4(fWIBZ!;Tl6g%y#y~;`2sx0dyWlGYTHBg&GP^Z9m_y5jwIuC(c^l6q zsU)974Ua^LoNeo{14cNe8W}ha%7xPsX1G#;-bi7UN|F!SV+@GB#c#X-;u`Dm(ET|? z6@EbuvL=Yd2vSTIkZQ7$Y+`%uW3cw8jT(;qq+mZoZq0<BXjnIHa0XF0j!xpy0JLjU zlghp1dm8h3m1673v<ar*;_Yq~vlS?IJyCS3)TL0J6TJ?iOQ8WChaav5`W|&^jJg6c zCtgZwh}Y-yE+k&BFG74?-<-HGOz#dD;KA;91I_FWoC~xW$>6x4O@~%qA6bGUQ@X(6 zQ5%qXeUL@~QgJdQa7&L0cJ;W!o;PUBcB`{HF}@d2#7T*Bp+<Y=Kb**K)3;Mo7>^y& z_h7&^5`YQ6og6uwh0{$K%b}1*SSLd3-A=|F8dFrJRLhj=RHdqLORg|+xje8QF<I^7 z0-rE9h0@3bbmD@Zx_AvBD=IDPf{dyW8{ZtOIOEsmF2k3T!epNBfE9x)V8Xr$%bpFL zhB0O}FgQ{e%Izr;_RUuD6gzAXj^?UazRt4@5sTT1lmM3uBoeXS&or%Dvqm%iy0tND zo2?Xg7GwsX+rrq?56((~WhG3G=J)q;SyJV?K^agAl}KuIU_UQcR9#i{`rMF<>zb<9 z4M=ly&7o?JXf}1Es*cnsNp-5J&S(yG27}JJymSv&RT3G3y})q=gLX`ph=a_qv8fmA zM3$nxqSvCm;#Zx)Xm12~OtAFNNdWwGCk~jxTmLx;fXhiDz%Y9|`~MH_lORFtR+W4R zepSR_ktvJdVq0&_Y3A13dD)6;dwJ{Aya80QF69mG?}1YPj{E{*sS*$Q43nLB(nxVe z$0Wmy#B`^U=w9m8DIyv8O)k~Ld1x{b!L>)$JW(I@sIo_m64fcI&L}()^@d^3Lr@+` za)w>h=|q?*%g#vr(eHPJ-PGX-Iuf>_I~-<Tkfiq!i4cYEko1DX?AVFFk4Qu$6}dic z5kDB=cT{$R%k0cHC(L5FXW%|r^F@izBl|p2(&<2O3bGSXqYUo*WoPZxC}~V)2GgI= zQ}oC57=4aDL)W+d@1V`{BG^09UdR6nL54;Kk(ney>d8W*G=zAgx+=(3<P-xleVk1r z5|<hfjVOpykpjXrLQ+(PKr)!h8Zn?M3yGqrVT`t(x#13K5^iTIZHQ2Z0q|CG=i!CI zrNC;711ms8Dl;nABV3Xg%oT!X5{?I^lElM_=oEofmx;(>C0==DJ`*8oMFk}lTPwEQ zednrWX#t1cy7tCe5FxjJXQ!iKl0_zxMPvhcltfyGQgVBYjQ(&G1bedcSqbrYGU}YG zUUF`S=z=<l&yE=GhkkhXru7ZQ(?{MYBRC&7YTyVuxS(j<WSVwUFfG)YJ8}!1PgwgU z<ZNFdXUieCk{1nEmJi;wXedKw9*<JRF71>;g%-wg3Rn@j(=Op_gMxF`yM_J6!5+nf z?4Sq-`?4MhMVfV?@G~!K|IhZN{1WI%Ly-7$YyXzv)^}SRYS0dLJ=W`6vivZ(ad#RU z4T;e)z?w8_3<R}c9o!!rAC3v>D?(AJ64815EFpeY;np{-_eSN7{>`iw5gZLeNWrLs zGf3A|CXuG~YgX6RM8X=Ewo;Y<<T%qDr`}_5lCW48MhzFXN`#<eJ$UQjs-xbmxHv*> zu1dUGq-f=_tWDEc7^x@ol@NzRFDJSl)DuRi`^E9u$sl0OIxP;)hpX*=^%c|tjus}G z)^)Xz^wHhYjU`0WnO1WJN@v7^RfS@ydDWh;taT9Gp;vT(5J_th*2oSSY!dl5A`xEg zhRVvSB3JjaP<WPzG5E<nD^@IAI3V}ThbR8-aO<9fPaa&+I&*XpvwpR8seegG4{)kc zI191_`kB&NcE3)&BAa=GM-WYpBGbvgS<PcJ%?ZG)$=t5e$aa}WMN9-gqJWSnYzRXx zfmA|~BakS&W@T4=QaZBp>w|zZj}@YbfMARp-#7d+ESId*bgZ@J7kxMh0ayDf{so^y z29Tm7*;yX9MC0Z{)CX)j?fQTylMq@KAERV;<ghh)T%EOlT;3F_#|+HeEN3RyVPAEv z-a$1t(cIA-Z#H+kh}#wQP?w*${80ruFQhO-?JxJ^=_*PN)^Eq9lm&g*%&b0v7?_q9 z9FUT$`a`J!?(_R9x`8Q@`K6XR{$p5YZ1R728~Z-0ba`YnS#LO@mz=qAx(TCH0If#i zEb1Jn8`KGRfn2i&d7fnNT14Aanw?<`?lh4IGtlkKh@q#2h6d9^R{qUTS;ucqGp!@@ zJi_qBWBDmw$~3M4r3cBn#z_?P$QqHOa1&IK>xk3kKpyI(H9o3ode~2O9nrC(ND<h> zxB-La^bwHR84`?MCrG}&L+T6&cCr&7VF#vmvo|=X#O5@aM!VZxXHdqi-9YIH2r9~w zB2``ClwY%>0VBJ*sv=TeRyx1+XA}BS>pv%sHu*mu{*1cqDy=ZKcZvM3LDZ8_p0X1o z6l`S?6V`{QN0&Wy{R2!_WK;kYx2(9MLF)F)Zhy2N^{cX9Xu7aLQQ~mP4p%glx_q+B z7fq)=r|ffLqt10Gcgds_wo49Yq?svR{E}zKD+KHNie6NX{}B8nBTZlg^J_p$&}j-s zA&LMiy2Y%^nqJ>O6!1u5&&fzt*{w$V`C0GV?TSud6TZADfz9lR&w4b@=wzhV!|Co& z_Xp}t3Dh=b2qKZX9PuBGy6YidIpe_~;O=AsP?8X#1M-e!A^Ve2V3^6sfg6pBPRIkY zClKvV1G*g0qonJhUl0F#V1n&$BU5gI2f0ixlGX=q8N@?S2H0i%SIVA2Qz(brLK=*< z);q?)p`v%giBzwtPQ*U=L`6YxodaPbXJz<eA}D2icIzdBQ!96>dg~%Uy5dj!!E47t zHA;OY5*8pFj!iH^@iH{y4Od=Rw@;mKZWSeQ#(juZSfas@g>ouTAq5cie8d5E)g{() z=y2c3li-}=lk9T4?V+!{kH3PQi~Cl*k3^38Q~kk#R_1Mw21Gq4iCR>gtR1&yxkLdc zF>HN)TQ>3;Y{$~4HJiUO{E=xzV<qYuoE-|tGIk!1v*!@M&+D&4G9~%yQ1Ehb7wY&L zwx<)O*CSzedp&LxE{WvwN=pLNMRnK06gWW#iptn`4TfAg;!NG8!}HAoJbweg`5LZ3 zoA3vMix@*%zn(T3O`h3DKn`p#s20`pF)(tfq%6mf3=fQS9c3k1m1>drIhY3PR88FO zPzmfcwP}k-zM?!fR;+a^YJJ}qn@MqV-&Utzg<5#LKBD$_S!|5GsSjAOR~!P>E3tFG z8xmt(nEu<F?9%$Xd@9uFCNhcq$Z!OZYM@*wC#1KKIMC*B$n~gqI8a~TS&}*#Qmm?4 z1Oa?NL%=m6F$D!x)W(TY6QAqSMJkH;n${#Ou(p<bI3=OE&Fof`R5M8dnPyBG*x!RB zPC{!{L!x6FIK(k%!muc0U1DS*z6c9LK8f{%84tiJAuRiVXRzOs`J|Q>#$w1&26eC{ zRC0hGX(EF8Nl3Tl;tWH);8(wh7k5Sy2a}jXs@IVS0Dn{%07?{w5Kflud<7dv(jLKP z0xEoxX{Y8lc3p?)Rc4x8le9j0mE9g0(-8tXV5s6q(G!R!7Q_4iHxwutBf7bX5K}B0 z-upULRm$S46?IOlHLCy_zTj9Bdx2d-hF?G$4Hs+`YFWkENKL25s$6*@S5#E42pyoL z5dn?plT`~?C|IZ-1&2Pk>m-#Zl8W3wLTjWH!KFwuB|0-=I8%awKw3&lswQVzwR6^) z5H`fpDM*0w$rv&X8NN3iX?zM!RWw#eqEej?6oLZ51dyOgLX3!}YL%cwM*&C|l*B6P z*PiPWR1bsQ3Mz<7P($ww+iEBYT07_dLV0~wOUC@LwRT<xBu_z3y>?zsBB!n(9+%VQ zal(|N!XrAGL}e)Z)T3tTkev<~80=q`U=Y2K6%lc}5ply-3nLhRgabn1hA||+sv3W^ z+n~a9b&mnZb`2D8CkYgI>=A{qaNVQm6@z&lyAa)j>p=l;cTGN-of(DmF{+4H*K{v3 z=Dr@uHL)ZkLGdyP{@gBSu0YtYJ`jNbLTR72J1p$1IAJ9WX${2A1VKRx%5SYrcYL4H z<JNCVGtH5x2y)d<8d1DJPLqi2VCm3SsulWH0{f#x04AkF-uti&j7?ew(TAww779nz zj#ImV4q;6}7?;45m~B0|-~}HBQG_c-(Q6EO8+O6kQZ|SNt$WG}T!=~%7bQX%&W-h# zgVqaWIZk*EyOS*nS?9{05+R!Co~_}F0m%cKGo0K)bF9q^2bqNq*avigL4l}jvM4Gg zq9<xQ3k4yAqJ&CxC<>22phfFFrs{oIm)>=qaIam~E$9xRzw<)l#vW+|VIqF4vQJph zD%uU!*z%9ll=jQm@0ZxGkMtu0P|h8V+Xy#Xxr+vyMOcHwRuPdX43!-$l$m{z$1duM z-IB22L#PCprKBE~P^&(#PVc%}>>sP6eM9c=yxbVwJJq06nEI+K)cYai*4afrv-XGk z(M{G{;h|GPC9v%1(j-pN1zku_8WR+XF@MLH;lc_A_k%$J&l@?L3ULzNV~u^AhQk}= zkUHz@NcvRhNHTO$c!K;Vh6M0y)uODC73*!+v_@(`5#EVn@2%uJ+Zh<{i3Ry0B5}eO zF$5B^-{>XSzvJ;kj<}V;Wdg4t%eE0tu|saVvwG!TQKxB8CDa8wrkU~kM}po?^I%Dm z=f$T9JDAyl6+T52<|~0cHeGa&^F-A^mPG$SkcKSis!4Vw6PISjj81KxwOFNYPYG_l zh{zbmEX7(<ImqqnH1b&GFq+c(PUR1nwmudy6k9Dzatc!e%!i(|uKDzu{^=|fN(*Q7 zV`*ujl3<FTd%Xl#Ig%ux_eJSfFA`j_7v0bkCV$sO#xy}$LGpZ?7J`hWBAG^i2xfVF z%?A_(G}3;8S0XwoC9hhZrTxr7kU3Grg{2hCL+eGvhp^NViZUq2fZ?7Fx$eVcpD4Kw z>jfyvfijv@vM8M*eVJ|TTl$?Xnl0>Mn3evxy;My;K3qmMo~Q(lg^HpMC<@3b(@;+$ zxOpHlA8}JaiK5%UB-|*IBnT#aQfFt<m&G&f)sWYu)yP=-h&AR3<5*j_FB=9y&9ROw zFBlH*5C5kvN4~Dwcf%NNRDs1*WpIW%9E2_$gs6{3En`K<jG*qH($Ouwp5?;Pp<{+1 zQgwz=#)5%R6h{J{F}+We<itpUeNZ*0isEh@W&)D6d&R%gUDoE6{mg9iWE7!(jfmy# zbW#Mek|T^A#4bt+qu$%BbaB_Kw+XoHg*Jq5ad_-#|Jb~KV^dR815P>X2Ab-jtyQa1 zsnxhT#OM}l+v;pI8FbuS(qW%a8bPihJipit>ebv+0s@H=aoAoLvX@fgM8(*S_k$wW zv9BNY2EmsE0b+7B1hd7D?Op+ad#t<;(Saheo;W2}h=9ag4Z_a1CU$H?KoEM^HxN@) zu@PLTO>m*x<=8b&Rz(*&!HyUuG8o-jxn>!)-i!7xw~XdAOw<~nXQUy;ji^erA?y34 zrh9_OU~$6_RefaKva{Y#oeq3Z;tipXqbk*2ow0yRggkVKcxH}8K4h$pS=NxXFPShY zB1emLh}?*n9*No5K|%#^)e)x^!zFA_M>oi>DW$|3lHhWWlOglM5<m>aWCMNBE<k-S zKDd}u-7(Fos9$LvuOH#6Mal#@apAT?!1}I!Ky1Jl9~itYPpP%vwa#1TrREZ!7vU_L zDhz3GwRiz10stv?94BrF7GO|!GzgF3!97)~lg?`rvyH;oM3J%a#;c~IIa+GtqO4q? zqiiNr!uqV?fyK*?j4EX4e4;Fr288*DGewvs<R86c(L#@1Y!uEFJ@=S%G6r;=hKPgP zw^d`aMgLs49&LQu8nyl=G@h2NUqDUk*!qGQ2ts0fjcH3J;ul$5a;gUlB;bZf$T)yF z@4I~+I~psmX`g-TEEbEn5Q_{Z^XSd7Xe48H!5|Mre=M$n4G<YR+>%s0E*(9>=@~|s zw+PLyyp2aHXjDP*85CbZwho(E0|wZt4)0)JY?kGq*>UN(=jqV%#B_VM@X$Tah9Y&E zEy9;U9i*T-+lic8M5!URMEJ|$@MO5ViNj0KZZEKvzk~e5bX2#tZ1|1UxbfROK6F-# zD4(Y<Djy5^nbwc#?6wivT-AB87v5!hhPCF-tVDvpn0N!OfY((|T)qGrFvKSZe4<Y; z1#suW?L^ZZqEm-L7z=Q?DIEc|uA=*fOT8*oKIRQ-Az6V437`}U595yzzdyw<Y^X@T zE4xEscEJ&Vc>bYCgj4AjNiR6eYwg7Ll}S5E1(J&HcG3%yt8fHRLk=+ELrvkBYdbSb zoLUbk#6iT41ghLCudblz2EzzoK&b{NZeDfdSD_%>5#XXj#{!OSPQDjJXp(g+RY@pj z#J15r4x)OPDy}k7=7Eg$j7dcDt#915iuQx=5@`}UfpAeJZseiE$U3rzFS5388f?Zc zh^z+RJ%oBtK~eBQXHYm&xKsNMrbbmaQQcAE=J?>Mu>&8`pTq}p@06V)E^`s5?!rAP z#^U$fpy9qS@%dm#kcJ4!589G1YFi0}=AQ(k?WU733SCQJ?2Hh9_3|g#qfor=F?L31 zUME*=D{FJL>mG%@?F+`v2+eDrqisjK#h3+*EB;8qF_R@nCVts3{uIO(pd`e?=r8*t zF$qNYlQ!x@;GGavnRq&3WUX87If25stufz9o7f3>dmV*^0$lc*LcTpb4zZaCA%w}R zBE(JIBCm46<hw*2$4OOOvtZQ8qPS~-&LX&r_O~YM^*)M9vo4`j=thgg?SP-s6lf$x z+m@mSg;#nRl58dHS&3Wk3L0cfx<w#v0Q88#qf5}?9xy<$b&v3mq72EE+1Bd&E~Z|| zR#6lYf4Kyuwbq;8AT30mGN*O*<{|X{st1l%JwWGWXU@HE{MsenNxvgb-iDdvV|J@M z_MQ6K6Q>T)m*g)9;cZW3KSx7PJn#%{IXdZC`cJaCkNVh5c8ovBKa~okPvjNyHl<uO z)Fy41woWhC-*=vLZF75kO{vcYH-%QEtx7LQztI13#ygoiGk=}cl07+RSKj4;dj@`! zUz7j!pf3k2gI^os8#;dIYr~cfUw32fjb}!@HS$>D(!z72Uc2exo4y%sj5#%SchR<S zo5$DOd}cz0IpO@oos%*r9hmgbx2&DKb@De;#@zPSwB6G#-+p|$Yq~Lg<Mh|2e^;Da zysG%Cl658LX82}Ip0Q)bH#2i*-Zd*QYw4_aX3w3IJLiEp@6RQ3%jX`L`|-T=d2{FO zns;u#F@MkeZ||6P$G*~ir56_zEm*hUSeaHfp={eiws7*o>V-QOo?dvV+$=ADcTs3j z^`fuB^TWF%6C$5hJh)g}T(fxp;*To}E7w$hTQ$9EXVsZ%NA=X|mzVgK)GTRP^81>` znwHx1rOMLArEk^^se5=?-m<OBPA?y}{Nd#nS2V3SxiWiY`O4iZFR$9X>dn>ptJkb< zS^dcxW6kz87ow%nvuo$CZCZP({`|U=4e4gXg~mW*d1K4^g7r=7&o^Z^l{Y=x^!p7D zZuolR@QtT7etYNcJ1^Z;de@70ef_-$H|1~IbvL_v+uiTqed#Y|{>7K~gztI$o^$tH zym!LApWb`<`v>m}-}k&(WUexgZ_eF(a7*5nLtFFi-+2FtA2dJ69^Clgr#~$J;qD)v z-d4V?`62dD;X}I~I=|g4-+t;ZOaJnlhnpV$>X9{%T-dQ}$Aw3wNAn-8c=U90VRJ?E z&gSnPYkKUHoi#g;SW~SQ>+-I9cYXd><$rbX@$|=6JpS(E7oVtn;^6M|-Hp3jcK`ZE z#*dnRbbe3no;7=pKUwhPj=i3}r=Gg^spp^icHh!{d-fgs>+t?#PdlDo`}Fw(+YWsF zOzAVvn$Pxs)_8Wub4AY`c<!s`UC$4H{=VnWzL5Ju(+ekF9PwiFizi>a{L<W)-h5el zdHTy|U;gS9*DK>+S@ufvEAPD0b};pzad7Rymk+kRn*VCktH)ox^xDr~pY-~U*FR~= zZCTZ_x8=echu(C&Iql8gv`%YXdPqBT;LydxQx6|FviZp8N7o(w`LX<CCx2{K{P^r! znQ!fVTY7ud+h^V>eCOcb4EdYS->v@J)W6+#+&F&dJ@#Jdd!N2P?EPi$@A^CP_vcTB zP8OY9ck;l=uRh5Ap!9=%AAEdDJGJxFFMl%PC+AL+(`!%fJ^kf}MIUbd@bsDVGb_&Q zICJdGFF$g8H1(rRAGLhccGft1{2$mqtT<P5uH~n`pKkl<*N%_R{Ve-@!TJ5?|MiJI zuhI-U=;)DG=^E8LM&8i4dfixc!`ju$mN#uUI^ZyUlOFxm5&S{Ppkh)?FXC3>bb66H z+y9$q@jKcNBNzQ$dl@f9*>!>VeYE@pZFb(!kCI_;5P52=Q>R+&DWup>%G9@zGf|>r gRGs=3+5Ck6932(#Xw)_A7;XPSi}c7F42?hXe-n=OQUCw| diff --git a/public/fonts/fontello.woff b/public/fonts/fontello.woff index adb43f608b35cf1633c78c9d038cb14ee2d8c579..cd8bd2afde3fcb8dac46e1f8416c9692dcff41da 100644 GIT binary patch delta 66820 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 delta 67465 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 -- GitLab From 3f1d958c4adc3bdcb47e9597264fd2cd2e6d6183 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 21:41:38 -0200 Subject: [PATCH 0723/1338] simplifying deploy scripts --- .sandstorm/buildrc.sh | 19 ---------- .sandstorm/preprcbuild.sh | 18 --------- .sandstorm/sandstorm-pkgdef.capnp | 4 +- .travis.yml | 54 +++++++++++++-------------- .travis/{builddocker.sh => docker.sh} | 0 .travis/namefiles.sh | 8 ++-- .travis/sandstorm.sh | 38 +++++++++++++++++++ rocketchat.info | 2 +- 8 files changed, 71 insertions(+), 72 deletions(-) delete mode 100755 .sandstorm/buildrc.sh delete mode 100755 .sandstorm/preprcbuild.sh rename .travis/{builddocker.sh => docker.sh} (100%) create mode 100755 .travis/sandstorm.sh diff --git a/.sandstorm/buildrc.sh b/.sandstorm/buildrc.sh deleted file mode 100755 index 159c8a83b02..00000000000 --- a/.sandstorm/buildrc.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -cd /tmp -spk init -p3000 -- nothing -export SANDSTORM_ID="$(grep '\sid =' sandstorm-pkgdef.capnp)" -cd $TRAVIS_BUILD_DIR -export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" -export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle -cd /home/vagrant && tar zxf ./Rocket.Chat.tar.gz -rm ./Rocket.Chat.tar.gz -cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install -cd $TRAVIS_BUILD_DIR/.sandstorm -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 $TRAVIS_BUILD_DIR/rocket.chat.latest.spk diff --git a/.sandstorm/preprcbuild.sh b/.sandstorm/preprcbuild.sh deleted file mode 100755 index e7ea8528c10..00000000000 --- a/.sandstorm/preprcbuild.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -cd /tmp -curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - -sudo mkdir -p /home/vagrant -sudo chown -R travis /home/vagrant -sudo mkdir -p /opt -sudo chown -R travis /opt -cd /opt -curl curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - -ln -s meteor-spk-0.1.8 meteor-spk -cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ -cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ -cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ -cd $TRAVIS_BUILD_DIR -cp -r . /opt/app diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 685352e67ad..3451445dd38 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 2, # Increment this for every release. + appVersion = 3, # Increment this for every release. - appMarketingVersion = (defaultText = "0.7.2445"), + appMarketingVersion = (defaultText = "0.8.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 df91835e5a9..0cdd81e7a51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,41 +4,39 @@ branches: only: - develop - master + - even-faster-deploy node_js: - '0.12' before_install: - curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' - mkdir -p node_modules -- cd $TRAVIS_BUILD_DIR -- mkdir ../build -- export TAG=$(git describe --abbrev=0 --tags) -- export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") -- export PATH=$PATH:/tmp/sandstorm-$SANDSTORM_VERSION/bin -- cd .sandstorm -- ./preprcbuild.sh script: - cd $TRAVIS_BUILD_DIR -- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then echo "Building PR $TRAVIS_PULL_REQUEST"; meteor build ../build; exit $?; fi -- meteor build ../build -- cp ../build/Rocket.Chat.tar.gz /home/vagrant -- cd .travis -- sh ./namefiles.sh -- cd $TRAVIS_BUILD_DIR/.sandstorm -- ./buildrc.sh -- cd $TRAVIS_BUILD_DIR -- mv rocket.chat.latest.spk ../build +- mkdir /tmp/build +- meteor build /tmp/build +before_deploy: +- mkdir /tmp/deploy +- sh $TRAVIS_BUILD_DIR/.travis/namefiles.sh +- sh $TRAVIS_BUILD_DIR/.travis/sandstorm.sh deploy: - provider: s3 - access_key_id: "AKIAIKIA7H7D47KUHYCA" - secret_access_key: $ACCESSKEY - bucket: "rocketchatbuild" - skip_cleanup: true - local_dir: ../build - on: - branch: - - develop - - master + - provider: s3 + access_key_id: "AKIAIKIA7H7D47KUHYCA" + secret_access_key: $ACCESSKEY + bucket: "rocketchatbuild" + skip_cleanup: true + local_dir: /tmp/deploy + on: + branch: + - develop + - master + - even-faster-deploy + - provider: releases + api_key: "GITHUB OAUTH TOKEN" + file: "FILE TO UPLOAD" + skip_cleanup: true + on: + branch: master + tags: true after_deploy: -- cd .travis -- ./builddocker.sh +- sh $TRAVIS_BUILD_DIR/.travis/docker.sh diff --git a/.travis/builddocker.sh b/.travis/docker.sh similarity index 100% rename from .travis/builddocker.sh rename to .travis/docker.sh diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 4b0f3b12ee0..dbffdd22eac 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,4 +1,4 @@ -cd ../../build -FILENAME=rocket.chat-"$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH".tgz -mv Rocket.Chat.tar.gz "$FILENAME" -ln -s "$FILENAME" "$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" +cd $TRAVIS_BUILD_DIR +export TAG=$(git describe --abbrev=0 --tags) +ln -s /tmp/build/Rocket.Chat.tar.gz "/tmp/deploy/$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH.tgz" +ln -s /tmp/build/Rocket.Chat.tar.gz "/tmp/deploy/$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh new file mode 100755 index 00000000000..98bd111e3a2 --- /dev/null +++ b/.travis/sandstorm.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +set -euo pipefail + +export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") +export PATH=$PATH:/tmp/sandstorm-$SANDSTORM_VERSION/bin + +cd /tmp +curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - + +sudo mkdir -p /opt +sudo chown -R travis /opt +cd /opt +curl curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - +ln -s meteor-spk-0.1.8 meteor-spk +cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ +cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +cp -a /lib/x86_64-linux-gnu/libtinfo.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ +ln -s $TRAVIS_BUILD_DIR /opt/app + +cd /tmp +spk init -p3000 -- nothing +export SANDSTORM_ID="$(grep '\sid =' sandstorm-pkgdef.capnp)" + +cd $TRAVIS_BUILD_DIR +export METEOR_WAREHOUSE_DIR="${METEOR_WAREHOUSE_DIR:-$HOME/.meteor}" +export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor"))/dev_bundle + +sudo mkdir -p /home/vagrant +sudo chown -R travis /home/vagrant +tar -zxf /tmp/build/Rocket.Chat.tar.gz /home/vagrant +cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install +cd $TRAVIS_BUILD_DIR/.sandstorm +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.latest.spk diff --git a/rocketchat.info b/rocketchat.info index f9a62bc59fe..12759ff2748 100644 --- a/rocketchat.info +++ b/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.7.0" + "version": "0.8.0" } -- GitLab From 53b88e368010e598259973d3cf7a8b93df50fb02 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 21:51:19 -0200 Subject: [PATCH 0724/1338] fix indentation of .travis.yml --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0cdd81e7a51..96a6a2e60d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,11 +32,11 @@ deploy: - master - even-faster-deploy - provider: releases - api_key: "GITHUB OAUTH TOKEN" - file: "FILE TO UPLOAD" - skip_cleanup: true - on: - branch: master - tags: true + api_key: "GITHUB OAUTH TOKEN" + file: "FILE TO UPLOAD" + skip_cleanup: true + on: + branch: master + tags: true after_deploy: - sh $TRAVIS_BUILD_DIR/.travis/docker.sh -- GitLab From 399a11f4622f98faffd4d7ae50ede98948e9a48e Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 22:11:45 -0200 Subject: [PATCH 0725/1338] removing sh --- .travis.yml | 6 +++--- .travis/docker.sh | 2 +- .travis/namefiles.sh | 4 ++++ .travis/sandstorm.sh | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 96a6a2e60d7..82efab68353 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ script: - meteor build /tmp/build before_deploy: - mkdir /tmp/deploy -- sh $TRAVIS_BUILD_DIR/.travis/namefiles.sh -- sh $TRAVIS_BUILD_DIR/.travis/sandstorm.sh +- .travis/namefiles.sh +- .travis/sandstorm.sh deploy: - provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" @@ -39,4 +39,4 @@ deploy: branch: master tags: true after_deploy: -- sh $TRAVIS_BUILD_DIR/.travis/docker.sh +- .travis/docker.sh diff --git a/.travis/docker.sh b/.travis/docker.sh index 14d59768cc5..a6afcceb1c8 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -1,6 +1,6 @@ #!/bin/bash - set -euo pipefail +IFS=$'\n\t' # TRAVIS_TAG='v0.7' # TAG="v0.7" diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index dbffdd22eac..7e674613fe4 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,3 +1,7 @@ +#!/bin/bash +set -euo 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/$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH.tgz" diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 98bd111e3a2..22867a7f395 100755 --- a/.travis/sandstorm.sh +++ b/.travis/sandstorm.sh @@ -1,6 +1,6 @@ #!/bin/bash - set -euo pipefail +IFS=$'\n\t' export SANDSTORM_VERSION=$(curl -f "https://install.sandstorm.io/dev?from=0&type=install") export PATH=$PATH:/tmp/sandstorm-$SANDSTORM_VERSION/bin -- GitLab From 1656ed2c7fd01baf499aacef70f4482a155813d6 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 22:23:27 -0200 Subject: [PATCH 0726/1338] fixed typos --- .travis/sandstorm.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 22867a7f395..3dd4c40c6d3 100755 --- a/.travis/sandstorm.sh +++ b/.travis/sandstorm.sh @@ -11,7 +11,7 @@ curl https://dl.sandstorm.io/sandstorm-$SANDSTORM_VERSION.tar.xz | tar -xJf - sudo mkdir -p /opt sudo chown -R travis /opt cd /opt -curl curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - +curl https://dl.sandstorm.io/meteor-spk-0.1.8.tar.xz | tar -xJf - ln -s meteor-spk-0.1.8 meteor-spk cp -a /bin/bash /opt/meteor-spk/meteor-spk.deps/bin/ cp -a /lib/x86_64-linux-gnu/libncurses.so.* /opt/meteor-spk/meteor-spk.deps/lib/x86_64-linux-gnu/ @@ -28,7 +28,7 @@ export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor") sudo mkdir -p /home/vagrant sudo chown -R travis /home/vagrant -tar -zxf /tmp/build/Rocket.Chat.tar.gz /home/vagrant +tar -zxf /tmp/build/Rocket.Chat.tar.gz /home/vagrant/ cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install cd $TRAVIS_BUILD_DIR/.sandstorm sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp -- GitLab From 293b2c97b0c07b1b451afc178881fb6ad5a3efe5 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 22:37:07 -0200 Subject: [PATCH 0727/1338] fixing tar command --- .travis.yml | 9 +++++++-- .travis/sandstorm.sh | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82efab68353..2819639690a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,13 +7,18 @@ branches: - even-faster-deploy node_js: - '0.12' +cache: + directories: + - ~/.meteor before_install: -- curl https://install.meteor.com | /bin/sh - npm install -g npm@'>=2.13.5' - mkdir -p node_modules +install: +- curl https://install.meteor.com | /bin/sh +before_script: +- mkdir /tmp/build script: - cd $TRAVIS_BUILD_DIR -- mkdir /tmp/build - meteor build /tmp/build before_deploy: - mkdir /tmp/deploy diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 3dd4c40c6d3..8ecc5c47ed1 100755 --- a/.travis/sandstorm.sh +++ b/.travis/sandstorm.sh @@ -28,7 +28,7 @@ export METEOR_DEV_BUNDLE=$(dirname $(readlink -f "$METEOR_WAREHOUSE_DIR/meteor") sudo mkdir -p /home/vagrant sudo chown -R travis /home/vagrant -tar -zxf /tmp/build/Rocket.Chat.tar.gz /home/vagrant/ +tar -zxf /tmp/build/Rocket.Chat.tar.gz --directory /home/vagrant/ cd /home/vagrant/bundle/programs/server && "$METEOR_DEV_BUNDLE/bin/npm" install cd $TRAVIS_BUILD_DIR/.sandstorm sed -i "s/\sid = .*/$SANDSTORM_ID/" sandstorm-pkgdef.capnp -- GitLab From 82db55f153ead30fd165bba54c3416b97dfba3f7 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Mon, 7 Dec 2015 19:59:52 -0500 Subject: [PATCH 0728/1338] A better fix for the font, Remove the icons that are not mirrored to regular locations. And moved the icons that need mirroring to mirrored locations. Replaced "octicon-chevron-right" with new set of mirrored icons from fontello --- .../assets/stylesheets/base.less | 3 +- .../assets/stylesheets/fontello.css | 36 +++-- .../assets/stylesheets/rtl.less | 11 +- .../flex-tab/tabs/messageSearch.html | 2 +- private/fontello.json | 30 ++-- private/images/fontello.svg | 22 +-- public/fonts/fontello.eot | Bin 119036 -> 122148 bytes public/fonts/fontello.html | 148 +++++++++--------- public/fonts/fontello.ttf | Bin 118868 -> 121980 bytes public/fonts/fontello.woff | Bin 69372 -> 70580 bytes 10 files changed, 135 insertions(+), 117 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index fcf06ddf5a9..b2504d9a68b 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -297,7 +297,8 @@ blockquote { animation-iteration-count: infinite; animation-timing-function: linear; } - .icon-search { + .icon-search, + .icon-right-open-small { position: absolute; left: 2px; top: 10px; diff --git a/packages/rocketchat-theme/assets/stylesheets/fontello.css b/packages/rocketchat-theme/assets/stylesheets/fontello.css index 30f207ccd4d..1d3bca10400 100644 --- a/packages/rocketchat-theme/assets/stylesheets/fontello.css +++ b/packages/rocketchat-theme/assets/stylesheets/fontello.css @@ -18,42 +18,42 @@ } } */ - + [class^="icon-"]:before, [class*=" icon-"]:before { font-family: "fontello"; font-style: normal; font-weight: normal; speak: none; - + display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ - + /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; - + /* fix buttons height, for twitter bootstrap */ line-height: 1em; - + /* Animation center compensation - margins should be symmetric */ /* remove if not needed */ margin-left: .2em; - + /* you can be more comfortable with increased icons size */ /* font-size: 120%; */ - + /* Font smoothing. That was taken from TWBS */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - + /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } - + .icon-religious-islam:before { content: '\21'; } /* '!' */ .icon-religious-jewish:before { content: '\22'; } /* '"' */ .icon-graduation-cap-1:before { content: '\23'; } /* '#' */ @@ -61,8 +61,6 @@ .icon-paper-plane:before { content: '\25'; } /* '%' */ .icon-paw:before { content: '\26'; } /* '&' */ .icon-spoon:before { content: '\27'; } /* ''' */ -.icon-spin6:before { content: '\28'; } /* '(' */ -.icon-firefox:before { content: '\29'; } /* ')' */ .icon-chrome:before { content: '\2a'; } /* '*' */ .icon-opera:before { content: '\2b'; } /* '+' */ .icon-crown:before { content: '\2c'; } /* ',' */ @@ -81,7 +79,9 @@ .icon-spin1:before { content: '\39'; } /* '9' */ .icon-spin2:before { content: '\3a'; } /* ':' */ .icon-spin3:before { content: '\3b'; } /* ';' */ +.icon-left-open:before { content: '\3c'; } /* '<' */ .icon-spin5:before { content: '\3d'; } /* '=' */ +.icon-right-open:before { content: '\3e'; } /* '>' */ .icon-history:before { content: '\3f'; } /* '?' */ .icon-circle-notch:before { content: '\40'; } /* '@' */ .icon-marquee:before { content: '\41'; } /* 'A' */ @@ -132,6 +132,14 @@ .icon-rocketchat:before { content: '\6e'; } /* 'n' */ .icon-spin4:before { content: '\6f'; } /* 'o' */ .icon-sliders:before { content: '\70'; } /* 'p' */ +.icon-spin6:before { content: '\71'; } /* 'q' */ +.icon-firefox:before { content: '\72'; } /* 'r' */ +.icon-angle-double-left:before { content: '\ab'; } /* '«' */ +.icon-angle-double-right:before { content: '\bb'; } /* '»' */ +.icon-angle-left:before { content: '\2039'; } /* '‹' */ +.icon-angle-right:before { content: '\203a'; } /* '›' */ +.icon-left-open-small:before { content: '\276e'; } /* 'â®' */ +.icon-right-open-small:before { content: '\276f'; } /* 'â¯' */ .icon-camera:before { content: '\e800'; } /* 'î €' */ .icon-videocam:before { content: '\e801'; } /* 'î ' */ .icon-heart:before { content: '\e802'; } /* 'î ‚' */ @@ -398,18 +406,12 @@ .icon-left-dir:before { content: '\e90e'; } /* '' */ .icon-right-dir:before { content: '\e90f'; } /* 'î¤' */ .icon-down-open:before { content: '\e910'; } /* 'î¤' */ -.icon-left-open:before { content: '\e911'; } /* '' */ -.icon-right-open:before { content: '\e912'; } /* '' */ .icon-up-open:before { content: '\e913'; } /* '' */ -.icon-angle-left:before { content: '\e914'; } /* '' */ -.icon-angle-right:before { content: '\e915'; } /* '' */ .icon-angle-up:before { content: '\e916'; } /* '' */ .icon-angle-down:before { content: '\e917'; } /* '' */ .icon-angle-circled-left:before { content: '\e918'; } /* '' */ .icon-angle-circled-right:before { content: '\e919'; } /* '' */ .icon-angle-circled-down:before { content: '\e91a'; } /* '' */ -.icon-angle-double-left:before { content: '\e91b'; } /* '' */ -.icon-angle-double-right:before { content: '\e91c'; } /* '' */ .icon-angle-circled-up:before { content: '\e91d'; } /* 'î¤' */ .icon-scissors:before { content: '\e91e'; } /* '' */ .icon-align-left:before { content: '\e91f'; } /* '' */ diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 0c8af2e4567..39609cabef1 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -315,7 +315,8 @@ .icon-spin4 { .left(5px); } - .icon-search { + .icon-search, + .icon-right-open-small { .right(2px); } input { @@ -606,7 +607,8 @@ } .statistics-table { - th, td { + th, + td { text-align: right; } } @@ -620,9 +622,4 @@ .left(10px); } } - - /* Overridding the icons Unicode to suit RTL languages - * from _octicons.less */ - .octicon-chevron-right:before { content: '\f0a4'} - .icon-angle-right:before { content: '\e914'; } } diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html index 6a56385a986..25931d64987 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.html @@ -4,7 +4,7 @@ <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="octicon octicon-chevron-right"></i> + <i class="icon-right-open-small"></i> </div> </form> </div> diff --git a/private/fontello.json b/private/fontello.json index 9b4d945f8b6..d615fff1908 100644 --- a/private/fontello.json +++ b/private/fontello.json @@ -305,13 +305,13 @@ { "uid": "9bc2902722abb366a213a052ade360bc", "css": "spin6", - "code": 40, + "code": 113, "src": "fontelico" }, { "uid": "62c089cb34e74b3a1200bc7f5314eb4e", "css": "firefox", - "code": 41, + "code": 114, "src": "fontelico" }, { @@ -1253,13 +1253,13 @@ { "uid": "d870630ff8f81e6de3958ecaeac532f2", "css": "left-open", - "code": 59665, + "code": 60, "src": "fontawesome" }, { "uid": "399ef63b1e23ab1b761dfbb5591fa4da", "css": "right-open", - "code": 59666, + "code": 62, "src": "fontawesome" }, { @@ -1271,13 +1271,13 @@ { "uid": "f3f90c8c89795da30f7444634476ea4f", "css": "angle-left", - "code": 59668, + "code": 8249, "src": "fontawesome" }, { "uid": "7bf14281af5633a597f85b061ef1cfb9", "css": "angle-right", - "code": 59669, + "code": 8250, "src": "fontawesome" }, { @@ -1319,13 +1319,13 @@ { "uid": "745f12abe1472d14f8f658de7e5aba66", "css": "angle-double-left", - "code": 59675, + "code": 171, "src": "fontawesome" }, { "uid": "fdfbd1fcbd4cb229716a810801a5f207", "css": "angle-double-right", - "code": 59676, + "code": 187, "src": "fontawesome" }, { @@ -2732,6 +2732,18 @@ "code": 49, "src": "entypo" }, + { + "uid": "c311c48d79488965b0fab7f9cd12b6b5", + "css": "left-open-small", + "code": 10094, + "src": "entypo" + }, + { + "uid": "749e7d90a9182938180f1d2d8c33584e", + "css": "right-open-small", + "code": 10095, + "src": "entypo" + }, { "uid": "ef74ff62feda486fd414410e782b598a", "css": "graduation-cap-1", @@ -2877,4 +2889,4 @@ "src": "websymbols" } ] -} \ No newline at end of file +} diff --git a/private/images/fontello.svg b/private/images/fontello.svg index 4b0b2269169..cabf3bec776 100644 --- a/private/images/fontello.svg +++ b/private/images/fontello.svg @@ -13,8 +13,6 @@ <glyph glyph-name="paper-plane" unicode="%" d="m984 844q19-14 15-36l-142-857q-3-16-18-25-8-5-18-5-6 0-13 3l-253 103-135-164q-10-13-27-13-7 0-12 2-11 4-17 13t-7 21v194l482 591-596-516-221 91q-20 7-22 30-1 23 18 33l928 536q9 5 18 5 11 0 20-6z" horiz-adv-x="1000" /> <glyph glyph-name="paw" unicode="&" d="m435 587q0-34-10-64t-35-51-59-22q-42 0-77 32t-51 76-17 84q0 33 10 63t36 52 58 21q43 0 77-32t52-75 16-84z m-191-270q0-45-23-77t-66-33q-43 0-79 31t-56 74-20 85q0 45 23 78t67 33q42 0 79-31t56-75 19-85z m220 15q66 0 143-54t127-132 52-142q0-26-10-43t-27-25-36-12-42-3q-38 0-105 25t-102 26q-37 0-107-25t-112-25q-102 0-102 82 0 47 31 106t78 108 105 81 107 33z m134 118q-34 0-59 22t-35 51-11 64q0 41 17 84t51 75 77 33q34 0 59-22t35-52 11-63q0-41-17-84t-51-76-77-32z m241 58q43 0 66-33t24-78q0-41-20-85t-56-74-79-31q-43 0-66 33t-24 77q0 41 20 85t56 75 79 31z" horiz-adv-x="928.6" /> <glyph glyph-name="spoon" unicode="'" d="m393 555q0-81-32-136t-85-75l25-458q1-15-9-25t-24-11h-107q-15 0-25 11t-9 25l25 458q-53 20-84 75t-32 136q0 72 23 140t66 111 89 44 90-44 65-111 24-140z" horiz-adv-x="428.6" /> -<glyph glyph-name="spin6" unicode="(" d="m855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" /> -<glyph glyph-name="firefox" unicode=")" d="m504-137c-216 0-387 126-466 306-87 200-17 521 139 663l-6-156c8 9 68 12 78-1 32 62 136 109 220 110-32-26-106-124-99-174 40-13 103-13 136-15 10-6 8-40-12-68-27-37-97-49-97-49l8-106-77 38c-26-64 35-120 97-110 69 12 94 57 142 54 49-2 68-29 61-54-7-30-59-25-59-25-44-70-103-101-198-93 144-119 338-10 387 87 50 97 7 241-43 283 59-25 99-51 120-108 11 125-46 267-149 350 193-56 311-206 314-445 3-239-211-487-496-487z" horiz-adv-x="1000" /> <glyph glyph-name="chrome" unicode="*" d="m498 850c-147-1-291-67-387-186l154-237c39 111 150 182 267 170l414-22c-42 84-108 157-196 208-79 46-166 67-252 67z m-416-226c-52-79-82-173-82-274 0-250 183-457 423-494l128 252c-116-22-233 39-281 146l-188 370z m885-94l-282-15c76-89 82-221 13-317l-226-347c94-6 190 15 278 66 216 125 304 387 217 613z m-467-11c-93 0-169-76-169-169s76-169 169-169 169 76 169 169-76 169-169 169z" horiz-adv-x="1000" /> <glyph glyph-name="opera" unicode="+" d="m426-150c-568 0-568 1000 0 1000s567-1000 0-1000z m0 92c237 0 237 816 0 816s-238-816 0-816z" horiz-adv-x="851" /> <glyph glyph-name="crown" unicode="," d="m419 822c-39 0-71-32-71-72 0-40 32-72 71-72 39 0 74 32 74 72 0 40-35 72-74 72z m-48-222c-40-119-101-152-101-152s-52 146-109 232c-23-52-47-86-96-100-1-44 51-208 55-290l601 0c2 79 55 256 55 288-38 16-85 51-96 102-63-86-109-232-109-232s-61 33-101 152c-27-13-77-13-99 0z m-297 222c-40 0-74-32-74-72 0-40 34-72 74-72 39 0 70 32 70 72 0 40-31 72-70 72z m47-603l0-119 600 0c0 43 0 81 0 119z m644 603c-40 0-72-32-72-72 0-40 32-72 72-72 40 0 72 32 72 72 0 40-32 72-72 72z" horiz-adv-x="837" /> @@ -33,9 +31,9 @@ <glyph glyph-name="spin1" unicode="9" d="m496 850c-176 0-331-90-421-226-18-27-33-55-46-85-12-29-21-60-28-92 0 0 0-1 0-1l0 0 0 0c0-1 0-2 0-2 0-7 5-12 11-12l101 0c5 0 10 4 11 9 29 113 109 206 214 253 20 10 41 17 63 23 31 7 62 11 95 11l0 0 0 0 0 0c25 0 50-2 74-7 5-1 10-2 14-3 6-1 10-3 14-4l0 0c5-1 11 1 13 6l51 87c0 0 1 1 1 2 2 6-1 13-7 15-22 7-43 13-65 17-5 1-9 1-13 2-27 5-54 7-82 7l0 0 0 0z m327-114c-5 0-9-2-11-6l-50-87c-3-4-2-10 2-14 29-29 54-63 73-101 4-7 7-14 11-22 19-46 30-97 30-151l0 0 0 0c0-77-22-149-62-209-7-11-15-23-24-34-9-10-18-20-28-30l0 0 0 0 0 0c-4-4-5-10-2-14l50-87c0-1 1-2 2-3 4-5 11-5 16-1 58 52 104 117 134 190 6 14 11 29 15 44 14 46 21 94 21 144 0 108-34 209-92 291-11 16-23 31-37 46-13 14-26 28-41 41l0 0c-1 1-1 1-2 1-2 1-4 2-5 2z m-811-468l0 0c-1 0-2 0-3 0-6-1-10-8-9-14 34-166 149-302 302-366 30-12 61-21 93-28 32-6 66-10 100-10l0 0 0 0c40 0 79 5 117 14 7 1 14 3 22 5 6 2 13 5 20 7 1 0 2 1 3 1 6 3 8 10 4 16l-50 87c-3 5-8 7-13 6-14-4-28-7-42-9-3-1-6-1-8-2-18-2-35-3-53-3l0 0 0 0c-128 0-242 63-311 160-1 0-1 0-1 0-13 19-25 40-35 61-10 21-18 43-24 65-1 6-6 10-11 10l-101 0z" horiz-adv-x="1000" /> <glyph glyph-name="spin2" unicode=":" d="m46 144l0 0c0 0-1 0-1 0-8 18-15 37-21 55-6 19-11 38-15 58-19 99-8 203 35 298 3 6 10 8 15 5 1 0 2 0 2-1l0 0 80-59c5-3 6-9 4-14-5-12-9-25-12-38-4-12-7-26-9-39-11-67-3-137 23-201 2-5 0-10-4-13l0 0-80-56c-5-4-12-3-16 3-1 0-1 1-1 2l0 0z m120 574l0 0c0 1 0 1 0 1 15 13 30 25 46 37 16 11 33 22 51 31 89 50 192 72 297 60 6-1 10-6 10-13 0-1-1-1-1-2l0 0-31-94c-2-5-8-8-13-7-13 0-27 0-40 0-14-1-27-2-40-4-68-11-133-40-186-84-4-3-10-3-14 0l0 0-79 58c-5 3-6 11-2 16 0 0 1 1 2 1l0 0z m588 65l0 0c0 0 1 0 1 0 17-10 34-21 50-32 16-12 31-25 46-38 74-69 127-160 148-262 2-6-2-12-9-13-1 0-1 0-2 0l0 0-100 1c-5 0-10 4-11 9-3 13-8 26-12 38-5 12-10 25-17 36-31 61-78 113-137 150-5 3-6 8-5 13l0 0 31 92c2 6 9 9 15 7 1 0 2-1 2-1l0 0z m244-535l0 0c0 0 0 0 0 0-4-20-9-39-15-57-7-19-14-37-22-55-44-92-114-170-205-221-6-3-13-1-16 4 0 1-1 2-1 2l0 0-30 94c-2 6 1 12 6 14 11 7 22 15 32 23 11 9 21 18 30 27 49 48 84 109 101 176 2 5 6 8 11 8l0 0 98-1c6 0 11-5 11-11 0-1 0-2 0-3l0 0z m-438-395l0 0c0 0 0 0 0 0-20-2-40-3-60-3-20 0-40 1-59 4-102 12-198 54-276 125-5 4-5 11 0 16 0 0 1 1 1 1l0 0 81 58c5 3 12 2 16-2 10-8 20-16 32-23 11-7 22-14 34-20 62-31 131-45 200-41 6 0 10-3 12-8l0 0 29-92c2-6-1-12-7-14-1-1-2-1-3-1l0 0z" horiz-adv-x="1000" /> <glyph glyph-name="spin3" unicode=";" d="m494 850c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" /> -<glyph glyph-name="spin4" unicode="<" d="m498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" /> +<glyph glyph-name="left-open" unicode="<" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" /> <glyph glyph-name="spin5" unicode="=" d="m462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-35c0 0 0 0 0 0 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 10 4 16l-35 61c-2 3-6 5-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-92 0 0c6-3 13-1 16 5l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-2 16 4l35 61c3 5 1 12-4 15l-158 91 0 0c-2 1-4 2-6 2z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-11-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 5-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-3c-4 1-8-2-10-5l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 34c0 1 0 1 0 1-2 1-4 1-6 1z m149-57c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" /> -<glyph glyph-name="sliders" unicode=">" d="m196 64v-71h-196v71h196z m197 72q14 0 25-11t11-25v-143q0-14-11-25t-25-11h-143q-14 0-25 11t-11 25v143q0 15 11 25t25 11h143z m89 214v-71h-482v71h482z m-357 286v-72h-125v72h125z m732-572v-71h-411v71h411z m-536 643q15 0 26-10t10-26v-142q0-15-10-26t-26-10h-142q-15 0-26 10t-10 26v142q0 15 10 26t26 10h142z m358-286q14 0 25-10t10-25v-143q0-15-10-25t-25-11h-143q-15 0-25 11t-11 25v143q0 14 11 25t25 10h143z m178-71v-71h-125v71h125z m0 286v-72h-482v72h482z" horiz-adv-x="857.1" /> +<glyph glyph-name="right-open" unicode=">" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" /> <glyph glyph-name="history" unicode="?" d="m857 350q0-87-34-166t-91-137-137-92-166-34q-96 0-183 41t-147 114q-4 6-4 13t5 11l76 77q6 5 14 5 9-1 13-7 41-53 100-82t126-29q58 0 110 23t92 61 61 91 22 111-22 111-61 91-92 61-110 23q-55 0-105-20t-90-57l77-77q17-16 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l72-72q60 57 137 88t159 31q87 0 166-34t137-92 91-137 34-166z m-357 161v-250q0-8-5-13t-13-5h-178q-8 0-13 5t-5 13v35q0 8 5 13t13 5h125v197q0 8 5 13t12 5h36q8 0 13-5t5-13z" horiz-adv-x="857.1" /> <glyph glyph-name="circle-notch" unicode="@" d="m1000 350q0-102-40-194t-106-160-160-106-194-40-194 40-160 106-106 160-40 194q0 124 56 231t155 177 218 87v-145q-124-25-205-124t-81-226q0-73 28-139t77-114 113-76 139-28 139 28 114 76 76 114 28 139q0 128-81 226t-205 124v145q120-17 218-87t155-177 56-231z" horiz-adv-x="1000" /> <glyph glyph-name="marquee" unicode="A" d="m0 850l0-143 143 0 0 143-143 0z m286 0l0-143 143 0 0 143-143 0z m285 0l0-143 143 0 0 143-143 0z m286 0l0-143 143 0 0 143-143 0z m-857-286l0-143 143 0 0 143-143 0z m857 0l0-143 143 0 0 143-143 0z m-857-285l0-143 143 0 0 143-143 0z m857 0l0-143 143 0 0 143-143 0z m-857-286l0-143 143 0 0 143-143 0z m286 0l0-143 143 0 0 143-143 0z m285 0l0-143 143 0 0 143-143 0z m286 0l0-143 143 0 0 143-143 0z" horiz-adv-x="1000" /> @@ -84,6 +82,16 @@ <glyph glyph-name="behance" unicode="l" d="m1031 661h-285v-69h285v69z m-140-238q-51 0-82-29t-34-80h227q-10 109-111 109z m9-326q35 0 68 17t42 49h123q-55-171-238-171-119 0-190 73t-71 194q0 116 73 193t188 77q77 0 134-38t86-100 28-139q0-9-1-26h-367q0-62 32-96t93-33z m-745 27h165q114 0 114 94 0 100-111 100h-168v-194z m0 300h156q44 0 69 20t26 64q0 80-106 80h-145v-164z m-155 284h332q48 0 86-8t71-26 50-54 17-86q0-101-96-147 64-17 96-64t33-114q0-41-14-76t-37-58-55-39-67-24-75-7h-341v703z" horiz-adv-x="1142.9" /> <glyph glyph-name="gitlab" unicode="m" d="m962 288c-42 131-85 262-127 393-9 28-18 55-27 83-6 16-29 18-34 0-3-9-6-18-9-26-27-84-55-168-82-252-4-11-5-38-19-38-34 0-68 0-102 0-78 0-155 0-232 0-6 0-21 59-23 65-14 45-29 90-43 134-8 23-15 46-22 68-5 15-8 37-17 50-6 21-30 11-35-5-44-137-89-274-133-411-10-28-38-79-7-101 11-11 26-19 39-28 71-52 143-104 215-157 61-44 123-89 184-134 16-11 15-6 31 7 36 25 71 51 106 76 108 79 216 157 324 236 12 9 18 24 13 40z" horiz-adv-x="1000" /> <glyph glyph-name="rocketchat" unicode="n" d="m969 351c0 47-14 93-41 135-25 37-60 71-104 99-85 54-197 84-315 84-39 0-78-4-115-10-24 22-51 41-80 57-154 75-282 2-282 2s119-98 100-184c-54-53-83-116-83-183 0 0 0 0 0 0 0-1 0-1 0-1 0-66 29-130 83-183 19-85-100-183-100-183s128-73 282 1c29 16 56 36 80 58 37-7 76-10 115-10 118 0 230 30 315 84 44 28 79 61 104 99 27 42 41 87 41 134 0 0 0 0 0 1 0 0 0 0 0 0z m-459-258c-50 0-97 5-141 16-45-54-143-128-238-104 31 33 77 89 67 182-57 44-91 101-91 163 0 142 180 257 403 257 222 0 402-115 402-257 0-142-180-257-402-257z m53 257c0-29-24-53-53-53-30 0-54 24-54 53s24 54 54 54c29 0 53-24 53-54z m133 54c-30 0-54-24-54-54s24-53 54-53c29 0 53 24 53 53s-24 54-53 54z m-373 0c-29 0-53-24-53-54s24-53 53-53c30 0 54 24 54 53s-24 54-54 54z" horiz-adv-x="1000" /> +<glyph glyph-name="spin4" unicode="o" d="m498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" /> +<glyph glyph-name="sliders" unicode="p" d="m196 64v-71h-196v71h196z m197 72q14 0 25-11t11-25v-143q0-14-11-25t-25-11h-143q-14 0-25 11t-11 25v143q0 15 11 25t25 11h143z m89 214v-71h-482v71h482z m-357 286v-72h-125v72h125z m732-572v-71h-411v71h411z m-536 643q15 0 26-10t10-26v-142q0-15-10-26t-26-10h-142q-15 0-26 10t-10 26v142q0 15 10 26t26 10h142z m358-286q14 0 25-10t10-25v-143q0-15-10-25t-25-11h-143q-15 0-25 11t-11 25v143q0 14 11 25t25 10h143z m178-71v-71h-125v71h125z m0 286v-72h-482v72h482z" horiz-adv-x="857.1" /> +<glyph glyph-name="spin6" unicode="q" d="m855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" /> +<glyph glyph-name="firefox" unicode="r" d="m504-137c-216 0-387 126-466 306-87 200-17 521 139 663l-6-156c8 9 68 12 78-1 32 62 136 109 220 110-32-26-106-124-99-174 40-13 103-13 136-15 10-6 8-40-12-68-27-37-97-49-97-49l8-106-77 38c-26-64 35-120 97-110 69 12 94 57 142 54 49-2 68-29 61-54-7-30-59-25-59-25-44-70-103-101-198-93 144-119 338-10 387 87 50 97 7 241-43 283 59-25 99-51 120-108 11 125-46 267-149 350 193-56 311-206 314-445 3-239-211-487-496-487z" horiz-adv-x="1000" /> +<glyph glyph-name="angle-double-left" unicode="«" d="m350 82q0-7-6-13l-28-28q-5-5-12-5t-13 5l-260 260q-6 6-6 13t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13t-6-12l-219-220 219-219q6-6 6-13z m214 0q0-7-5-13l-28-28q-6-5-13-5t-13 5l-260 260q-6 6-6 13t6 13l260 260q6 6 13 6t13-6l28-28q5-5 5-13t-5-12l-220-220 220-219q5-6 5-13z" horiz-adv-x="571.4" /> +<glyph glyph-name="angle-double-right" unicode="»" d="m332 314q0-7-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13z m214 0q0-7-5-13l-260-260q-6-5-13-5t-13 5l-28 28q-5 6-5 13t5 13l219 219-219 220q-5 5-5 12t5 13l28 28q6 6 13 6t13-6l260-260q5-5 5-13z" horiz-adv-x="571.4" /> +<glyph glyph-name="angle-left" unicode="‹" d="m350 546q0-7-6-12l-219-220 219-219q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-260 260q-6 6-6 13t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="357.1" /> +<glyph glyph-name="angle-right" unicode="›" d="m332 314q0-7-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13z" horiz-adv-x="357.1" /> +<glyph glyph-name="left-open-small" unicode="❮" d="m242 626q14 16 39 16t41-16q38-36 0-80l-186-196 186-194q38-44 0-80-16-16-40-16t-40 16l-226 236q-16 16-16 38 0 24 16 40 206 214 226 236z" horiz-adv-x="341" /> +<glyph glyph-name="right-open-small" unicode="❯" d="m98 626l226-236q16-16 16-40 0-22-16-38l-226-236q-16-16-40-16t-40 16q-36 36 0 80l186 194-186 196q-36 44 0 80 16 16 41 16t39-16z" horiz-adv-x="340" /> <glyph glyph-name="camera" unicode="" d="m536 475q66 0 113-47t47-114-47-113-113-47-114 47-47 113 47 114 114 47z m393 232q59 0 101-42t41-101v-500q0-59-41-101t-101-42h-786q-59 0-101 42t-42 101v500q0 59 42 101t101 42h125l28 76q11 27 39 47t58 20h286q29 0 57-20t39-47l29-76h125z m-393-643q103 0 176 74t74 176-74 177-176 73-177-73-73-177 73-176 177-74z" horiz-adv-x="1071.4" /> <glyph glyph-name="videocam" unicode="" d="m1000 654v-608q0-23-22-32-7-3-14-3-15 0-25 10l-225 225v-92q0-67-47-114t-113-47h-393q-67 0-114 47t-47 114v392q0 67 47 114t114 47h393q66 0 113-47t47-114v-92l225 225q10 10 25 10 7 0 14-3 22-9 22-32z" horiz-adv-x="1000" /> <glyph glyph-name="heart" unicode="" d="m500-79q-14 0-25 10l-348 336q-5 5-15 15t-31 36-38 55-30 67-13 77q0 123 71 192t196 70q34 0 70-12t67-33 54-38 42-38q20 20 42 38t54 38 67 33 70 12q125 0 196-70t71-192q0-123-128-251l-347-335q-10-10-25-10z" horiz-adv-x="1000" /> @@ -350,18 +358,12 @@ <glyph glyph-name="left-dir" unicode="" d="m357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" /> <glyph glyph-name="right-dir" unicode="" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11-11 25v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" /> <glyph glyph-name="down-open" unicode="" d="m939 399l-414-413q-10-11-25-11t-25 11l-414 413q-11 11-11 26t11 25l92 92q11 11 26 11t25-11l296-296 296 296q11 11 25 11t26-11l92-92q11-11 11-25t-11-26z" horiz-adv-x="1000" /> -<glyph glyph-name="left-open" unicode="" d="m653 682l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25z" horiz-adv-x="714.3" /> -<glyph glyph-name="right-open" unicode="" d="m618 361l-414-415q-11-10-25-10t-26 10l-92 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" /> <glyph glyph-name="up-open" unicode="" d="m939 107l-92-92q-11-10-26-10t-25 10l-296 297-296-297q-11-10-25-10t-26 10l-92 92q-11 11-11 26t11 25l414 414q11 10 25 10t25-10l414-414q11-11 11-25t-11-26z" horiz-adv-x="1000" /> -<glyph glyph-name="angle-left" unicode="" d="m350 546q0-7-6-12l-219-220 219-219q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-260 260q-6 6-6 13t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="357.1" /> -<glyph glyph-name="angle-right" unicode="" d="m332 314q0-7-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13z" horiz-adv-x="357.1" /> <glyph glyph-name="angle-up" unicode="" d="m600 189q0-7-6-13l-28-27q-5-6-12-6t-13 6l-220 219-219-219q-5-6-13-6t-13 6l-27 27q-6 6-6 13t6 13l260 260q5 6 12 6t13-6l260-260q6-5 6-13z" horiz-adv-x="642.9" /> <glyph glyph-name="angle-down" unicode="" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" /> <glyph glyph-name="angle-circled-left" unicode="" d="m507 72l57 56q11 11 11 26t-11 25l-171 171 171 171q11 11 11 25t-11 25l-57 57q-10 11-25 11t-25-11l-253-253q-11-11-11-25t11-25l253-254q11-10 25-10t25 10z m350 278q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" /> <glyph glyph-name="angle-circled-right" unicode="" d="m400 72l253 253q11 11 11 25t-11 25l-253 253q-10 11-25 11t-25-11l-57-56q-11-11-11-26t11-25l171-171-171-171q-11-11-11-25t11-26l57-57q11-10 25-10t25 10z m457 278q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" /> <glyph glyph-name="angle-circled-down" unicode="" d="m454 125l253 253q11 11 11 26t-11 25l-57 57q-10 10-25 10t-25-10l-171-172-172 172q-10 10-25 10t-25-10l-57-57q-10-11-10-25t10-26l253-253q11-10 26-10t25 10z m403 225q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" /> -<glyph glyph-name="angle-double-left" unicode="" d="m350 82q0-7-6-13l-28-28q-5-5-12-5t-13 5l-260 260q-6 6-6 13t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13t-6-12l-219-220 219-219q6-6 6-13z m214 0q0-7-5-13l-28-28q-6-5-13-5t-13 5l-260 260q-6 6-6 13t6 13l260 260q6 6 13 6t13-6l28-28q5-5 5-13t-5-12l-220-220 220-219q5-6 5-13z" horiz-adv-x="571.4" /> -<glyph glyph-name="angle-double-right" unicode="" d="m332 314q0-7-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13z m214 0q0-7-5-13l-260-260q-6-5-13-5t-13 5l-28 28q-5 6-5 13t5 13l219 219-219 220q-5 5-5 12t5 13l28 28q6 6 13 6t13-6l260-260q5-5 5-13z" horiz-adv-x="571.4" /> <glyph glyph-name="angle-circled-up" unicode="" d="m650 214l57 57q11 11 11 25t-11 26l-253 253q-11 10-25 10t-26-10l-253-254q-10-10-10-25t10-25l57-57q11-10 25-10t25 10l172 172 171-172q11-10 25-10t25 10z m207 136q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" /> <glyph glyph-name="scissors" unicode="" d="m536 350q14 0 25-11t10-25-10-25-25-10-25 10-11 25 11 25 25 11z m167-36l283-222q16-11 14-31-3-20-20-28l-71-36q-7-4-16-4-10 0-17 4l-385 216-62-37q-4-2-7-2 8-28 6-54-4-43-31-83t-74-69q-74-47-154-47-76 0-124 44-51 47-44 116 4 42 31 82t73 69q74 47 155 47 46 0 84-18 5 8 13 13l68 40-68 41q-8 5-13 12-38-17-84-17-81 0-155 47-46 29-73 69t-31 82q-3 33 8 63t36 52q47 44 124 44 80 0 154-47 46-29 74-68t31-83q2-27-6-54 3-1 7-3l62-37 385 216q7 5 17 5 9 0 16-4l71-36q17-9 20-28 2-20-14-32z m-380 145q26 24 12 61t-59 65q-52 33-107 33-42 0-63-20-26-24-12-60t59-66q51-33 107-33 41 0 63 20z m-47-415q45 28 59 65t-12 60q-22 20-63 20-56 0-107-33-45-28-59-65t12-60q21-20 63-20 55 0 107 33z m99 342l54-33v7q0 20 18 31l8 4-44 26-15-14q-1-2-5-6t-7-7q-1-1-2-2t-2-1z m125-125l54-18 410 321-71 36-429-240v-64l-89-53 5-5q1-1 4-3 2-2 6-7t6-6l15-15z m393-232l71 35-290 228-99-77q-1-2-7-4z" horiz-adv-x="1000" /> <glyph glyph-name="align-left" unicode="" d="m1000 100v-71q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25v71q0 15 11 25t25 11h928q15 0 25-11t11-25z m-214 214v-71q0-15-11-25t-25-11h-714q-15 0-25 11t-11 25v71q0 15 11 25t25 11h714q15 0 25-11t11-25z m143 215v-72q0-14-11-25t-25-11h-857q-15 0-25 11t-11 25v72q0 14 11 25t25 10h857q14 0 25-10t11-25z m-215 214v-72q0-14-10-25t-25-10h-643q-15 0-25 10t-11 25v72q0 14 11 25t25 11h643q14 0 25-11t10-25z" horiz-adv-x="1000" /> diff --git a/public/fonts/fontello.eot b/public/fonts/fontello.eot index 48cac3bf6a9be4a4fad5431a2cbf2d14e2c24b15..bec3e9412a0c4b5125d002994d915901681a2b14 100644 GIT binary patch delta 6365 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 WH+L?Z1K4UBo9$lQ`rtHvp#DFY=<Nsq delta 3651 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 diff --git a/public/fonts/fontello.html b/public/fonts/fontello.html index 89f21ec99cc..4524e875949 100644 --- a/public/fonts/fontello.html +++ b/public/fonts/fontello.html @@ -229,11 +229,11 @@ body { } @font-face { font-family: 'fontello'; - src: url('./font/fontello.eot?45674533'); - src: url('./font/fontello.eot?45674533#iefix') format('embedded-opentype'), - url('./font/fontello.woff?45674533') format('woff'), - url('./font/fontello.ttf?45674533') format('truetype'), - url('./font/fontello.svg?45674533#fontello') format('svg'); + src: url('./fontello.eot?51223153'); + src: url('./fontello.eot?51223153#iefix') format('embedded-opentype'), + url('./fontello.woff?51223153') format('woff'), + url('./fontello.ttf?51223153') format('truetype'), + url('./fontello.svg?51223153#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -310,37 +310,37 @@ body { <div title="Code: 0x25" class="the-icons span3"><i class="demo-icon icon-paper-plane">%</i> <span class="i-name">icon-paper-plane</span><span class="i-code">0x25</span></div> <div title="Code: 0x26" class="the-icons span3"><i class="demo-icon icon-paw">&</i> <span class="i-name">icon-paw</span><span class="i-code">0x26</span></div> <div title="Code: 0x27" class="the-icons span3"><i class="demo-icon icon-spoon">'</i> <span class="i-name">icon-spoon</span><span class="i-code">0x27</span></div> - <div title="Code: 0x28" class="the-icons span3"><i class="demo-icon icon-spin6 animate-spin">(</i> <span class="i-name">icon-spin6</span><span class="i-code">0x28</span></div> + <div title="Code: 0x2a" class="the-icons span3"><i class="demo-icon icon-chrome">*</i> <span class="i-name">icon-chrome</span><span class="i-code">0x2a</span></div> </div> <div class="row"> - <div title="Code: 0x29" class="the-icons span3"><i class="demo-icon icon-firefox">)</i> <span class="i-name">icon-firefox</span><span class="i-code">0x29</span></div> - <div title="Code: 0x2a" class="the-icons span3"><i class="demo-icon icon-chrome">*</i> <span class="i-name">icon-chrome</span><span class="i-code">0x2a</span></div> <div title="Code: 0x2b" class="the-icons span3"><i class="demo-icon icon-opera">+</i> <span class="i-name">icon-opera</span><span class="i-code">0x2b</span></div> <div title="Code: 0x2c" class="the-icons span3"><i class="demo-icon icon-crown">,</i> <span class="i-name">icon-crown</span><span class="i-code">0x2c</span></div> - </div> - <div class="row"> <div title="Code: 0x2d" class="the-icons span3"><i class="demo-icon icon-recycle">-</i> <span class="i-name">icon-recycle</span><span class="i-code">0x2d</span></div> <div title="Code: 0x2e" class="the-icons span3"><i class="demo-icon icon-note-beamed">.</i> <span class="i-name">icon-note-beamed</span><span class="i-code">0x2e</span></div> - <div title="Code: 0x2f" class="the-icons span3"><i class="demo-icon icon-ie">/</i> <span class="i-name">icon-ie</span><span class="i-code">0x2f</span></div> - <div title="Code: 0x30" class="the-icons span3"><i class="demo-icon icon-note">0</i> <span class="i-name">icon-note</span><span class="i-code">0x30</span></div> </div> <div class="row"> + <div title="Code: 0x2f" class="the-icons span3"><i class="demo-icon icon-ie">/</i> <span class="i-name">icon-ie</span><span class="i-code">0x2f</span></div> + <div title="Code: 0x30" class="the-icons span3"><i class="demo-icon icon-note">0</i> <span class="i-name">icon-note</span><span class="i-code">0x30</span></div> <div title="Code: 0x31" class="the-icons span3"><i class="demo-icon icon-alert">1</i> <span class="i-name">icon-alert</span><span class="i-code">0x31</span></div> <div title="Code: 0x32" class="the-icons span3"><i class="demo-icon icon-chat-1">2</i> <span class="i-name">icon-chat-1</span><span class="i-code">0x32</span></div> - <div title="Code: 0x33" class="the-icons span3"><i class="demo-icon icon-360">3</i> <span class="i-name">icon-360</span><span class="i-code">0x33</span></div> - <div title="Code: 0x34" class="the-icons span3"><i class="demo-icon icon-cab">4</i> <span class="i-name">icon-cab</span><span class="i-code">0x34</span></div> </div> <div class="row"> + <div title="Code: 0x33" class="the-icons span3"><i class="demo-icon icon-360">3</i> <span class="i-name">icon-360</span><span class="i-code">0x33</span></div> + <div title="Code: 0x34" class="the-icons span3"><i class="demo-icon icon-cab">4</i> <span class="i-name">icon-cab</span><span class="i-code">0x34</span></div> <div title="Code: 0x35" class="the-icons span3"><i class="demo-icon icon-share">5</i> <span class="i-name">icon-share</span><span class="i-code">0x35</span></div> <div title="Code: 0x36" class="the-icons span3"><i class="demo-icon icon-building-filled">6</i> <span class="i-name">icon-building-filled</span><span class="i-code">0x36</span></div> - <div title="Code: 0x37" class="the-icons span3"><i class="demo-icon icon-linux">7</i> <span class="i-name">icon-linux</span><span class="i-code">0x37</span></div> - <div title="Code: 0x38" class="the-icons span3"><i class="demo-icon icon-camera-tour">8</i> <span class="i-name">icon-camera-tour</span><span class="i-code">0x38</span></div> </div> <div class="row"> + <div title="Code: 0x37" class="the-icons span3"><i class="demo-icon icon-linux">7</i> <span class="i-name">icon-linux</span><span class="i-code">0x37</span></div> + <div title="Code: 0x38" class="the-icons span3"><i class="demo-icon icon-camera-tour">8</i> <span class="i-name">icon-camera-tour</span><span class="i-code">0x38</span></div> <div title="Code: 0x39" class="the-icons span3"><i class="demo-icon icon-spin1 animate-spin">9</i> <span class="i-name">icon-spin1</span><span class="i-code">0x39</span></div> <div title="Code: 0x3a" class="the-icons span3"><i class="demo-icon icon-spin2 animate-spin">:</i> <span class="i-name">icon-spin2</span><span class="i-code">0x3a</span></div> + </div> + <div class="row"> <div title="Code: 0x3b" class="the-icons span3"><i class="demo-icon icon-spin3 animate-spin">;</i> <span class="i-name">icon-spin3</span><span class="i-code">0x3b</span></div> + <div title="Code: 0x3c" class="the-icons span3"><i class="demo-icon icon-left-open"><</i> <span class="i-name">icon-left-open</span><span class="i-code">0x3c</span></div> <div title="Code: 0x3d" class="the-icons span3"><i class="demo-icon icon-spin5 animate-spin">=</i> <span class="i-name">icon-spin5</span><span class="i-code">0x3d</span></div> + <div title="Code: 0x3e" class="the-icons span3"><i class="demo-icon icon-right-open">></i> <span class="i-name">icon-right-open</span><span class="i-code">0x3e</span></div> </div> <div class="row"> <div title="Code: 0x3f" class="the-icons span3"><i class="demo-icon icon-history">?</i> <span class="i-name">icon-history</span><span class="i-code">0x3f</span></div> @@ -417,6 +417,18 @@ body { <div class="row"> <div title="Code: 0x6f" class="the-icons span3"><i class="demo-icon icon-spin4 animate-spin">o</i> <span class="i-name">icon-spin4</span><span class="i-code">0x6f</span></div> <div title="Code: 0x70" class="the-icons span3"><i class="demo-icon icon-sliders">p</i> <span class="i-name">icon-sliders</span><span class="i-code">0x70</span></div> + <div title="Code: 0x71" class="the-icons span3"><i class="demo-icon icon-spin6 animate-spin">q</i> <span class="i-name">icon-spin6</span><span class="i-code">0x71</span></div> + <div title="Code: 0x72" class="the-icons span3"><i class="demo-icon icon-firefox">r</i> <span class="i-name">icon-firefox</span><span class="i-code">0x72</span></div> + </div> + <div class="row"> + <div title="Code: 0xab" class="the-icons span3"><i class="demo-icon icon-angle-double-left">«</i> <span class="i-name">icon-angle-double-left</span><span class="i-code">0xab</span></div> + <div title="Code: 0xbb" class="the-icons span3"><i class="demo-icon icon-angle-double-right">»</i> <span class="i-name">icon-angle-double-right</span><span class="i-code">0xbb</span></div> + <div title="Code: 0x2039" class="the-icons span3"><i class="demo-icon icon-angle-left">‹</i> <span class="i-name">icon-angle-left</span><span class="i-code">0x2039</span></div> + <div title="Code: 0x203a" class="the-icons span3"><i class="demo-icon icon-angle-right">›</i> <span class="i-name">icon-angle-right</span><span class="i-code">0x203a</span></div> + </div> + <div class="row"> + <div title="Code: 0x276e" class="the-icons span3"><i class="demo-icon icon-left-open-small">❮</i> <span class="i-name">icon-left-open-small</span><span class="i-code">0x276e</span></div> + <div title="Code: 0x276f" class="the-icons span3"><i class="demo-icon icon-right-open-small">❯</i> <span class="i-name">icon-right-open-small</span><span class="i-code">0x276f</span></div> <div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon icon-camera"></i> <span class="i-name">icon-camera</span><span class="i-code">0xe800</span></div> <div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon icon-videocam"></i> <span class="i-name">icon-videocam</span><span class="i-code">0xe801</span></div> </div> @@ -817,13 +829,7 @@ body { <div title="Code: 0xe910" class="the-icons span3"><i class="demo-icon icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe910</span></div> </div> <div class="row"> - <div title="Code: 0xe911" class="the-icons span3"><i class="demo-icon icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe911</span></div> - <div title="Code: 0xe912" class="the-icons span3"><i class="demo-icon icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe912</span></div> <div title="Code: 0xe913" class="the-icons span3"><i class="demo-icon icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe913</span></div> - <div title="Code: 0xe914" class="the-icons span3"><i class="demo-icon icon-angle-left"></i> <span class="i-name">icon-angle-left</span><span class="i-code">0xe914</span></div> - </div> - <div class="row"> - <div title="Code: 0xe915" class="the-icons span3"><i class="demo-icon icon-angle-right"></i> <span class="i-name">icon-angle-right</span><span class="i-code">0xe915</span></div> <div title="Code: 0xe916" class="the-icons span3"><i class="demo-icon icon-angle-up"></i> <span class="i-name">icon-angle-up</span><span class="i-code">0xe916</span></div> <div title="Code: 0xe917" class="the-icons span3"><i class="demo-icon icon-angle-down"></i> <span class="i-name">icon-angle-down</span><span class="i-code">0xe917</span></div> <div title="Code: 0xe918" class="the-icons span3"><i class="demo-icon icon-angle-circled-left"></i> <span class="i-name">icon-angle-circled-left</span><span class="i-code">0xe918</span></div> @@ -831,150 +837,148 @@ body { <div class="row"> <div title="Code: 0xe919" class="the-icons span3"><i class="demo-icon icon-angle-circled-right"></i> <span class="i-name">icon-angle-circled-right</span><span class="i-code">0xe919</span></div> <div title="Code: 0xe91a" class="the-icons span3"><i class="demo-icon icon-angle-circled-down"></i> <span class="i-name">icon-angle-circled-down</span><span class="i-code">0xe91a</span></div> - <div title="Code: 0xe91b" class="the-icons span3"><i class="demo-icon icon-angle-double-left"></i> <span class="i-name">icon-angle-double-left</span><span class="i-code">0xe91b</span></div> - <div title="Code: 0xe91c" class="the-icons span3"><i class="demo-icon icon-angle-double-right"></i> <span class="i-name">icon-angle-double-right</span><span class="i-code">0xe91c</span></div> - </div> - <div class="row"> <div title="Code: 0xe91d" class="the-icons span3"><i class="demo-icon icon-angle-circled-up"></i> <span class="i-name">icon-angle-circled-up</span><span class="i-code">0xe91d</span></div> <div title="Code: 0xe91e" class="the-icons span3"><i class="demo-icon icon-scissors"></i> <span class="i-name">icon-scissors</span><span class="i-code">0xe91e</span></div> - <div title="Code: 0xe91f" class="the-icons span3"><i class="demo-icon icon-align-left"></i> <span class="i-name">icon-align-left</span><span class="i-code">0xe91f</span></div> - <div title="Code: 0xe920" class="the-icons span3"><i class="demo-icon icon-mobile"></i> <span class="i-name">icon-mobile</span><span class="i-code">0xe920</span></div> </div> <div class="row"> + <div title="Code: 0xe91f" class="the-icons span3"><i class="demo-icon icon-align-left"></i> <span class="i-name">icon-align-left</span><span class="i-code">0xe91f</span></div> + <div title="Code: 0xe920" class="the-icons span3"><i class="demo-icon icon-mobile"></i> <span class="i-name">icon-mobile</span><span class="i-code">0xe920</span></div> <div title="Code: 0xe921" class="the-icons span3"><i class="demo-icon icon-play-circled2"></i> <span class="i-name">icon-play-circled2</span><span class="i-code">0xe921</span></div> <div title="Code: 0xe922" class="the-icons span3"><i class="demo-icon icon-right-circled"></i> <span class="i-name">icon-right-circled</span><span class="i-code">0xe922</span></div> - <div title="Code: 0xe923" class="the-icons span3"><i class="demo-icon icon-left-circled"></i> <span class="i-name">icon-left-circled</span><span class="i-code">0xe923</span></div> - <div title="Code: 0xe924" class="the-icons span3"><i class="demo-icon icon-play-circled"></i> <span class="i-name">icon-play-circled</span><span class="i-code">0xe924</span></div> </div> <div class="row"> + <div title="Code: 0xe923" class="the-icons span3"><i class="demo-icon icon-left-circled"></i> <span class="i-name">icon-left-circled</span><span class="i-code">0xe923</span></div> + <div title="Code: 0xe924" class="the-icons span3"><i class="demo-icon icon-play-circled"></i> <span class="i-name">icon-play-circled</span><span class="i-code">0xe924</span></div> <div title="Code: 0xe925" class="the-icons span3"><i class="demo-icon icon-tablet"></i> <span class="i-name">icon-tablet</span><span class="i-code">0xe925</span></div> <div title="Code: 0xe926" class="the-icons span3"><i class="demo-icon icon-text-width"></i> <span class="i-name">icon-text-width</span><span class="i-code">0xe926</span></div> - <div title="Code: 0xe927" class="the-icons span3"><i class="demo-icon icon-crop"></i> <span class="i-name">icon-crop</span><span class="i-code">0xe927</span></div> - <div title="Code: 0xe928" class="the-icons span3"><i class="demo-icon icon-columns"></i> <span class="i-name">icon-columns</span><span class="i-code">0xe928</span></div> </div> <div class="row"> + <div title="Code: 0xe927" class="the-icons span3"><i class="demo-icon icon-crop"></i> <span class="i-name">icon-crop</span><span class="i-code">0xe927</span></div> + <div title="Code: 0xe928" class="the-icons span3"><i class="demo-icon icon-columns"></i> <span class="i-name">icon-columns</span><span class="i-code">0xe928</span></div> <div title="Code: 0xe929" class="the-icons span3"><i class="demo-icon icon-text-height"></i> <span class="i-name">icon-text-height</span><span class="i-code">0xe929</span></div> <div title="Code: 0xe92a" class="the-icons span3"><i class="demo-icon icon-laptop"></i> <span class="i-name">icon-laptop</span><span class="i-code">0xe92a</span></div> - <div title="Code: 0xe92b" class="the-icons span3"><i class="demo-icon icon-play"></i> <span class="i-name">icon-play</span><span class="i-code">0xe92b</span></div> - <div title="Code: 0xe92c" class="the-icons span3"><i class="demo-icon icon-down-hand"></i> <span class="i-name">icon-down-hand</span><span class="i-code">0xe92c</span></div> </div> <div class="row"> + <div title="Code: 0xe92b" class="the-icons span3"><i class="demo-icon icon-play"></i> <span class="i-name">icon-play</span><span class="i-code">0xe92b</span></div> + <div title="Code: 0xe92c" class="the-icons span3"><i class="demo-icon icon-down-hand"></i> <span class="i-name">icon-down-hand</span><span class="i-code">0xe92c</span></div> <div title="Code: 0xe92d" class="the-icons span3"><i class="demo-icon icon-up-hand"></i> <span class="i-name">icon-up-hand</span><span class="i-code">0xe92d</span></div> <div title="Code: 0xe92e" class="the-icons span3"><i class="demo-icon icon-collapse-left"></i> <span class="i-name">icon-collapse-left</span><span class="i-code">0xe92e</span></div> - <div title="Code: 0xe92f" class="the-icons span3"><i class="demo-icon icon-desktop"></i> <span class="i-name">icon-desktop</span><span class="i-code">0xe92f</span></div> - <div title="Code: 0xe930" class="the-icons span3"><i class="demo-icon icon-italic"></i> <span class="i-name">icon-italic</span><span class="i-code">0xe930</span></div> </div> <div class="row"> + <div title="Code: 0xe92f" class="the-icons span3"><i class="demo-icon icon-desktop"></i> <span class="i-name">icon-desktop</span><span class="i-code">0xe92f</span></div> + <div title="Code: 0xe930" class="the-icons span3"><i class="demo-icon icon-italic"></i> <span class="i-name">icon-italic</span><span class="i-code">0xe930</span></div> <div title="Code: 0xe931" class="the-icons span3"><i class="demo-icon icon-table"></i> <span class="i-name">icon-table</span><span class="i-code">0xe931</span></div> <div title="Code: 0xe932" class="the-icons span3"><i class="demo-icon icon-subscript"></i> <span class="i-name">icon-subscript</span><span class="i-code">0xe932</span></div> - <div title="Code: 0xe933" class="the-icons span3"><i class="demo-icon icon-bold"></i> <span class="i-name">icon-bold</span><span class="i-code">0xe933</span></div> - <div title="Code: 0xe934" class="the-icons span3"><i class="demo-icon icon-award"></i> <span class="i-name">icon-award</span><span class="i-code">0xe934</span></div> </div> <div class="row"> + <div title="Code: 0xe933" class="the-icons span3"><i class="demo-icon icon-bold"></i> <span class="i-name">icon-bold</span><span class="i-code">0xe933</span></div> + <div title="Code: 0xe934" class="the-icons span3"><i class="demo-icon icon-award"></i> <span class="i-name">icon-award</span><span class="i-code">0xe934</span></div> <div title="Code: 0xe935" class="the-icons span3"><i class="demo-icon icon-expand-right"></i> <span class="i-name">icon-expand-right</span><span class="i-code">0xe935</span></div> <div title="Code: 0xe936" class="the-icons span3"><i class="demo-icon icon-left-hand"></i> <span class="i-name">icon-left-hand</span><span class="i-code">0xe936</span></div> - <div title="Code: 0xe937" class="the-icons span3"><i class="demo-icon icon-right-hand"></i> <span class="i-name">icon-right-hand</span><span class="i-code">0xe937</span></div> - <div title="Code: 0xe938" class="the-icons span3"><i class="demo-icon icon-signal"></i> <span class="i-name">icon-signal</span><span class="i-code">0xe938</span></div> </div> <div class="row"> + <div title="Code: 0xe937" class="the-icons span3"><i class="demo-icon icon-right-hand"></i> <span class="i-name">icon-right-hand</span><span class="i-code">0xe937</span></div> + <div title="Code: 0xe938" class="the-icons span3"><i class="demo-icon icon-signal"></i> <span class="i-name">icon-signal</span><span class="i-code">0xe938</span></div> <div title="Code: 0xe939" class="the-icons span3"><i class="demo-icon icon-collapse"></i> <span class="i-name">icon-collapse</span><span class="i-code">0xe939</span></div> <div title="Code: 0xe93a" class="the-icons span3"><i class="demo-icon icon-font"></i> <span class="i-name">icon-font</span><span class="i-code">0xe93a</span></div> - <div title="Code: 0xe93b" class="the-icons span3"><i class="demo-icon icon-superscript"></i> <span class="i-name">icon-superscript</span><span class="i-code">0xe93b</span></div> - <div title="Code: 0xe93c" class="the-icons span3"><i class="demo-icon icon-align-center"></i> <span class="i-name">icon-align-center</span><span class="i-code">0xe93c</span></div> </div> <div class="row"> + <div title="Code: 0xe93b" class="the-icons span3"><i class="demo-icon icon-superscript"></i> <span class="i-name">icon-superscript</span><span class="i-code">0xe93b</span></div> + <div title="Code: 0xe93c" class="the-icons span3"><i class="demo-icon icon-align-center"></i> <span class="i-name">icon-align-center</span><span class="i-code">0xe93c</span></div> <div title="Code: 0xe93d" class="the-icons span3"><i class="demo-icon icon-align-right"></i> <span class="i-name">icon-align-right</span><span class="i-code">0xe93d</span></div> <div title="Code: 0xe93e" class="the-icons span3"><i class="demo-icon icon-align-justify"></i> <span class="i-name">icon-align-justify</span><span class="i-code">0xe93e</span></div> - <div title="Code: 0xe93f" class="the-icons span3"><i class="demo-icon icon-indent-left"></i> <span class="i-name">icon-indent-left</span><span class="i-code">0xe93f</span></div> - <div title="Code: 0xe940" class="the-icons span3"><i class="demo-icon icon-indent-right"></i> <span class="i-name">icon-indent-right</span><span class="i-code">0xe940</span></div> </div> <div class="row"> + <div title="Code: 0xe93f" class="the-icons span3"><i class="demo-icon icon-indent-left"></i> <span class="i-name">icon-indent-left</span><span class="i-code">0xe93f</span></div> + <div title="Code: 0xe940" class="the-icons span3"><i class="demo-icon icon-indent-right"></i> <span class="i-name">icon-indent-right</span><span class="i-code">0xe940</span></div> <div title="Code: 0xe941" class="the-icons span3"><i class="demo-icon icon-list"></i> <span class="i-name">icon-list</span><span class="i-code">0xe941</span></div> <div title="Code: 0xe942" class="the-icons span3"><i class="demo-icon icon-list-bullet"></i> <span class="i-name">icon-list-bullet</span><span class="i-code">0xe942</span></div> - <div title="Code: 0xe943" class="the-icons span3"><i class="demo-icon icon-list-numbered"></i> <span class="i-name">icon-list-numbered</span><span class="i-code">0xe943</span></div> - <div title="Code: 0xe944" class="the-icons span3"><i class="demo-icon icon-strike"></i> <span class="i-name">icon-strike</span><span class="i-code">0xe944</span></div> </div> <div class="row"> + <div title="Code: 0xe943" class="the-icons span3"><i class="demo-icon icon-list-numbered"></i> <span class="i-name">icon-list-numbered</span><span class="i-code">0xe943</span></div> + <div title="Code: 0xe944" class="the-icons span3"><i class="demo-icon icon-strike"></i> <span class="i-name">icon-strike</span><span class="i-code">0xe944</span></div> <div title="Code: 0xe945" class="the-icons span3"><i class="demo-icon icon-underline"></i> <span class="i-name">icon-underline</span><span class="i-code">0xe945</span></div> <div title="Code: 0xe946" class="the-icons span3"><i class="demo-icon icon-leaf"></i> <span class="i-name">icon-leaf</span><span class="i-code">0xe946</span></div> - <div title="Code: 0xe947" class="the-icons span3"><i class="demo-icon icon-fighter-jet"></i> <span class="i-name">icon-fighter-jet</span><span class="i-code">0xe947</span></div> - <div title="Code: 0xe948" class="the-icons span3"><i class="demo-icon icon-flight"></i> <span class="i-name">icon-flight</span><span class="i-code">0xe948</span></div> </div> <div class="row"> + <div title="Code: 0xe947" class="the-icons span3"><i class="demo-icon icon-fighter-jet"></i> <span class="i-name">icon-fighter-jet</span><span class="i-code">0xe947</span></div> + <div title="Code: 0xe948" class="the-icons span3"><i class="demo-icon icon-flight"></i> <span class="i-name">icon-flight</span><span class="i-code">0xe948</span></div> <div title="Code: 0xe949" class="the-icons span3"><i class="demo-icon icon-umbrella"></i> <span class="i-name">icon-umbrella</span><span class="i-code">0xe949</span></div> <div title="Code: 0xe94a" class="the-icons span3"><i class="demo-icon icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe94a</span></div> - <div title="Code: 0xe94b" class="the-icons span3"><i class="demo-icon icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe94b</span></div> - <div title="Code: 0xe94c" class="the-icons span3"><i class="demo-icon icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe94c</span></div> </div> <div class="row"> + <div title="Code: 0xe94b" class="the-icons span3"><i class="demo-icon icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe94b</span></div> + <div title="Code: 0xe94c" class="the-icons span3"><i class="demo-icon icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe94c</span></div> <div title="Code: 0xe94d" class="the-icons span3"><i class="demo-icon icon-sun"></i> <span class="i-name">icon-sun</span><span class="i-code">0xe94d</span></div> <div title="Code: 0xe94e" class="the-icons span3"><i class="demo-icon icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe94e</span></div> - <div title="Code: 0xe94f" class="the-icons span3"><i class="demo-icon icon-inbox"></i> <span class="i-name">icon-inbox</span><span class="i-code">0xe94f</span></div> - <div title="Code: 0xe950" class="the-icons span3"><i class="demo-icon icon-stop"></i> <span class="i-name">icon-stop</span><span class="i-code">0xe950</span></div> </div> <div class="row"> + <div title="Code: 0xe94f" class="the-icons span3"><i class="demo-icon icon-inbox"></i> <span class="i-name">icon-inbox</span><span class="i-code">0xe94f</span></div> + <div title="Code: 0xe950" class="the-icons span3"><i class="demo-icon icon-stop"></i> <span class="i-name">icon-stop</span><span class="i-code">0xe950</span></div> <div title="Code: 0xe951" class="the-icons span3"><i class="demo-icon icon-pause"></i> <span class="i-name">icon-pause</span><span class="i-code">0xe951</span></div> <div title="Code: 0xe952" class="the-icons span3"><i class="demo-icon icon-to-end"></i> <span class="i-name">icon-to-end</span><span class="i-code">0xe952</span></div> - <div title="Code: 0xe953" class="the-icons span3"><i class="demo-icon icon-to-end-alt"></i> <span class="i-name">icon-to-end-alt</span><span class="i-code">0xe953</span></div> - <div title="Code: 0xe954" class="the-icons span3"><i class="demo-icon icon-to-start"></i> <span class="i-name">icon-to-start</span><span class="i-code">0xe954</span></div> </div> <div class="row"> + <div title="Code: 0xe953" class="the-icons span3"><i class="demo-icon icon-to-end-alt"></i> <span class="i-name">icon-to-end-alt</span><span class="i-code">0xe953</span></div> + <div title="Code: 0xe954" class="the-icons span3"><i class="demo-icon icon-to-start"></i> <span class="i-name">icon-to-start</span><span class="i-code">0xe954</span></div> <div title="Code: 0xe955" class="the-icons span3"><i class="demo-icon icon-fast-fw"></i> <span class="i-name">icon-fast-fw</span><span class="i-code">0xe955</span></div> <div title="Code: 0xe956" class="the-icons span3"><i class="demo-icon icon-to-start-alt"></i> <span class="i-name">icon-to-start-alt</span><span class="i-code">0xe956</span></div> - <div title="Code: 0xe957" class="the-icons span3"><i class="demo-icon icon-fast-bw"></i> <span class="i-name">icon-fast-bw</span><span class="i-code">0xe957</span></div> - <div title="Code: 0xe958" class="the-icons span3"><i class="demo-icon icon-eject"></i> <span class="i-name">icon-eject</span><span class="i-code">0xe958</span></div> </div> <div class="row"> + <div title="Code: 0xe957" class="the-icons span3"><i class="demo-icon icon-fast-bw"></i> <span class="i-name">icon-fast-bw</span><span class="i-code">0xe957</span></div> + <div title="Code: 0xe958" class="the-icons span3"><i class="demo-icon icon-eject"></i> <span class="i-name">icon-eject</span><span class="i-code">0xe958</span></div> <div title="Code: 0xe959" class="the-icons span3"><i class="demo-icon icon-target"></i> <span class="i-name">icon-target</span><span class="i-code">0xe959</span></div> <div title="Code: 0xe95a" class="the-icons span3"><i class="demo-icon icon-expand"></i> <span class="i-name">icon-expand</span><span class="i-code">0xe95a</span></div> - <div title="Code: 0xe95b" class="the-icons span3"><i class="demo-icon icon-exchange"></i> <span class="i-name">icon-exchange</span><span class="i-code">0xe95b</span></div> - <div title="Code: 0xe95c" class="the-icons span3"><i class="demo-icon icon-shuffle"></i> <span class="i-name">icon-shuffle</span><span class="i-code">0xe95c</span></div> </div> <div class="row"> + <div title="Code: 0xe95b" class="the-icons span3"><i class="demo-icon icon-exchange"></i> <span class="i-name">icon-exchange</span><span class="i-code">0xe95b</span></div> + <div title="Code: 0xe95c" class="the-icons span3"><i class="demo-icon icon-shuffle"></i> <span class="i-name">icon-shuffle</span><span class="i-code">0xe95c</span></div> <div title="Code: 0xe95d" class="the-icons span3"><i class="demo-icon icon-level-down"></i> <span class="i-name">icon-level-down</span><span class="i-code">0xe95d</span></div> <div title="Code: 0xe95e" class="the-icons span3"><i class="demo-icon icon-arrows-cw"></i> <span class="i-name">icon-arrows-cw</span><span class="i-code">0xe95e</span></div> - <div title="Code: 0xe95f" class="the-icons span3"><i class="demo-icon icon-level-up"></i> <span class="i-name">icon-level-up</span><span class="i-code">0xe95f</span></div> - <div title="Code: 0xe960" class="the-icons span3"><i class="demo-icon icon-ccw"></i> <span class="i-name">icon-ccw</span><span class="i-code">0xe960</span></div> </div> <div class="row"> + <div title="Code: 0xe95f" class="the-icons span3"><i class="demo-icon icon-level-up"></i> <span class="i-name">icon-level-up</span><span class="i-code">0xe95f</span></div> + <div title="Code: 0xe960" class="the-icons span3"><i class="demo-icon icon-ccw"></i> <span class="i-name">icon-ccw</span><span class="i-code">0xe960</span></div> <div title="Code: 0xe961" class="the-icons span3"><i class="demo-icon icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe961</span></div> <div title="Code: 0xe962" class="the-icons span3"><i class="demo-icon icon-down-circled"></i> <span class="i-name">icon-down-circled</span><span class="i-code">0xe962</span></div> - <div title="Code: 0xe963" class="the-icons span3"><i class="demo-icon icon-up-circled"></i> <span class="i-name">icon-up-circled</span><span class="i-code">0xe963</span></div> - <div title="Code: 0xe964" class="the-icons span3"><i class="demo-icon icon-angle-double-up"></i> <span class="i-name">icon-angle-double-up</span><span class="i-code">0xe964</span></div> </div> <div class="row"> + <div title="Code: 0xe963" class="the-icons span3"><i class="demo-icon icon-up-circled"></i> <span class="i-name">icon-up-circled</span><span class="i-code">0xe963</span></div> + <div title="Code: 0xe964" class="the-icons span3"><i class="demo-icon icon-angle-double-up"></i> <span class="i-name">icon-angle-double-up</span><span class="i-code">0xe964</span></div> <div title="Code: 0xe965" class="the-icons span3"><i class="demo-icon icon-angle-double-down"></i> <span class="i-name">icon-angle-double-down</span><span class="i-code">0xe965</span></div> <div title="Code: 0xe966" class="the-icons span3"><i class="demo-icon icon-down"></i> <span class="i-name">icon-down</span><span class="i-code">0xe966</span></div> - <div title="Code: 0xe967" class="the-icons span3"><i class="demo-icon icon-left"></i> <span class="i-name">icon-left</span><span class="i-code">0xe967</span></div> - <div title="Code: 0xe968" class="the-icons span3"><i class="demo-icon icon-right"></i> <span class="i-name">icon-right</span><span class="i-code">0xe968</span></div> </div> <div class="row"> + <div title="Code: 0xe967" class="the-icons span3"><i class="demo-icon icon-left"></i> <span class="i-name">icon-left</span><span class="i-code">0xe967</span></div> + <div title="Code: 0xe968" class="the-icons span3"><i class="demo-icon icon-right"></i> <span class="i-name">icon-right</span><span class="i-code">0xe968</span></div> <div title="Code: 0xe969" class="the-icons span3"><i class="demo-icon icon-up"></i> <span class="i-name">icon-up</span><span class="i-code">0xe969</span></div> <div title="Code: 0xe96a" class="the-icons span3"><i class="demo-icon icon-down-big"></i> <span class="i-name">icon-down-big</span><span class="i-code">0xe96a</span></div> - <div title="Code: 0xe96b" class="the-icons span3"><i class="demo-icon icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe96b</span></div> - <div title="Code: 0xe96c" class="the-icons span3"><i class="demo-icon icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe96c</span></div> </div> <div class="row"> + <div title="Code: 0xe96b" class="the-icons span3"><i class="demo-icon icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe96b</span></div> + <div title="Code: 0xe96c" class="the-icons span3"><i class="demo-icon icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe96c</span></div> <div title="Code: 0xe96d" class="the-icons span3"><i class="demo-icon icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe96d</span></div> <div title="Code: 0xe96e" class="the-icons span3"><i class="demo-icon icon-bedroom"></i> <span class="i-name">icon-bedroom</span><span class="i-code">0xe96e</span></div> - <div title="Code: 0xe96f" class="the-icons span3"><i class="demo-icon icon-fast-food"></i> <span class="i-name">icon-fast-food</span><span class="i-code">0xe96f</span></div> - <div title="Code: 0xe971" class="the-icons span3"><i class="demo-icon icon-police"></i> <span class="i-name">icon-police</span><span class="i-code">0xe971</span></div> </div> <div class="row"> + <div title="Code: 0xe96f" class="the-icons span3"><i class="demo-icon icon-fast-food"></i> <span class="i-name">icon-fast-food</span><span class="i-code">0xe96f</span></div> + <div title="Code: 0xe971" class="the-icons span3"><i class="demo-icon icon-police"></i> <span class="i-name">icon-police</span><span class="i-code">0xe971</span></div> <div title="Code: 0xe972" class="the-icons span3"><i class="demo-icon icon-elevator"></i> <span class="i-name">icon-elevator</span><span class="i-code">0xe972</span></div> <div title="Code: 0xe973" class="the-icons span3"><i class="demo-icon icon-food-1"></i> <span class="i-name">icon-food-1</span><span class="i-code">0xe973</span></div> - <div title="Code: 0xe974" class="the-icons span3"><i class="demo-icon icon-pan"></i> <span class="i-name">icon-pan</span><span class="i-code">0xe974</span></div> - <div title="Code: 0xe975" class="the-icons span3"><i class="demo-icon icon-tap"></i> <span class="i-name">icon-tap</span><span class="i-code">0xe975</span></div> </div> <div class="row"> + <div title="Code: 0xe974" class="the-icons span3"><i class="demo-icon icon-pan"></i> <span class="i-name">icon-pan</span><span class="i-code">0xe974</span></div> + <div title="Code: 0xe975" class="the-icons span3"><i class="demo-icon icon-tap"></i> <span class="i-name">icon-tap</span><span class="i-code">0xe975</span></div> <div title="Code: 0xe976" class="the-icons span3"><i class="demo-icon icon-gym"></i> <span class="i-name">icon-gym</span><span class="i-code">0xe976</span></div> <div title="Code: 0xe977" class="the-icons span3"><i class="demo-icon icon-sports"></i> <span class="i-name">icon-sports</span><span class="i-code">0xe977</span></div> - <div title="Code: 0xe978" class="the-icons span3"><i class="demo-icon icon-football"></i> <span class="i-name">icon-football</span><span class="i-code">0xe978</span></div> - <div title="Code: 0xe979" class="the-icons span3"><i class="demo-icon icon-tennis"></i> <span class="i-name">icon-tennis</span><span class="i-code">0xe979</span></div> </div> <div class="row"> + <div title="Code: 0xe978" class="the-icons span3"><i class="demo-icon icon-football"></i> <span class="i-name">icon-football</span><span class="i-code">0xe978</span></div> + <div title="Code: 0xe979" class="the-icons span3"><i class="demo-icon icon-tennis"></i> <span class="i-name">icon-tennis</span><span class="i-code">0xe979</span></div> <div title="Code: 0xe97a" class="the-icons span3"><i class="demo-icon icon-fax"></i> <span class="i-name">icon-fax</span><span class="i-code">0xe97a</span></div> <div title="Code: 0xe97b" class="the-icons span3"><i class="demo-icon icon-taxi"></i> <span class="i-name">icon-taxi</span><span class="i-code">0xe97b</span></div> + </div> + <div class="row"> <div title="Code: 0xe97c" class="the-icons span3"><i class="demo-icon icon-paragraph"></i> <span class="i-name">icon-paragraph</span><span class="i-code">0xe97c</span></div> </div> </div> diff --git a/public/fonts/fontello.ttf b/public/fonts/fontello.ttf index 43fc3e31441bec33e9acf7d586154839cb06c5e3..275bf21f0b4b385e23cd95bc4fe5324a1dfde8bb 100644 GIT binary patch delta 6377 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 delta 3786 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 diff --git a/public/fonts/fontello.woff b/public/fonts/fontello.woff index cd8bd2afde3fcb8dac46e1f8416c9692dcff41da..038b7413a5bec28ce923f1d35c069d7a459f4dc2 100644 GIT binary patch delta 69096 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	)(lM$ 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 Sc${PK-obDpC}Nk24gqqQE!{}~ delta 67871 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 -- GitLab From 9c31987d7f177a102d19838fd802be7a3e34ab32 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 23:09:06 -0200 Subject: [PATCH 0729/1338] simplifying file names --- .docker/dockerfiles/develop/Dockerfile | 2 +- .docker/dockerfiles/master/Dockerfile | 2 +- .travis.yml | 1 - .travis/namefiles.sh | 7 +++---- .travis/sandstorm.sh | 2 +- README.md | 3 ++- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index d43c1d2cd2c..cbb9a7bfe12 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -16,7 +16,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/develop.rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ +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 \ diff --git a/.docker/dockerfiles/master/Dockerfile b/.docker/dockerfiles/master/Dockerfile index 32770f2b470..dd62d8cc71e 100644 --- a/.docker/dockerfiles/master/Dockerfile +++ b/.docker/dockerfiles/master/Dockerfile @@ -16,7 +16,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/master.rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ +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 \ diff --git a/.travis.yml b/.travis.yml index 2819639690a..b88a50ff57b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,6 @@ install: before_script: - mkdir /tmp/build script: -- cd $TRAVIS_BUILD_DIR - meteor build /tmp/build before_deploy: - mkdir /tmp/deploy diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 7e674613fe4..4848dea2b11 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -2,7 +2,6 @@ set -euo 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/$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH.tgz" -ln -s /tmp/build/Rocket.Chat.tar.gz "/tmp/deploy/$TRAVIS_BRANCH.rocket.chat-v.latest.tgz" +#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" diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 8ecc5c47ed1..43250534b7e 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.latest.spk +spk pack /tmp/deploy/rocket.chat-$TRAVIS_BRANCH.spk diff --git a/README.md b/README.md index 677f275c0c4..d98545756aa 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,8 @@ Branch **develop** (Newer but unstable): ## Sandstorm.io [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) -_*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat.latest.spk) for testing on your own server. +_*Grab*_ the latest [Sandstorm SPK](https://s3.amazonaws.com/rocketchatbuild/rocket.chat-develop.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) -- GitLab From 85530f4909867d2e945dd55c5e1a8eeaf974b284 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 7 Dec 2015 23:41:34 -0200 Subject: [PATCH 0730/1338] only deploy from master on tags --- .travis.yml | 14 +++++++------- .travis/docker.sh | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index b88a50ff57b..c494279d497 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ branches: only: - develop - master - - even-faster-deploy node_js: - '0.12' cache: @@ -33,14 +32,15 @@ deploy: on: branch: - develop - - master - - even-faster-deploy - - provider: releases - api_key: "GITHUB OAUTH TOKEN" - file: "FILE TO UPLOAD" + - provider: s3 + access_key_id: "AKIAIKIA7H7D47KUHYCA" + secret_access_key: $ACCESSKEY + bucket: "rocketchatbuild" skip_cleanup: true + local_dir: /tmp/deploy on: - branch: master tags: true + branch: + - master after_deploy: - .travis/docker.sh diff --git a/.travis/docker.sh b/.travis/docker.sh index a6afcceb1c8..d2c479d5cf5 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -13,9 +13,9 @@ CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSH if [ -z ${TRAVIS_TAG+x} ]; then -CURL_DATA='{"source_type": "Branch", "source_name": "'$TRAVIS_BRANCH'", "docker_tag": "'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'"}'; +CURL_DATA='{"source_type": "Branch", "source_name": "'$TRAVIS_BRANCH'", "docker_tag": "'$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'"}'; else -CURL_DATA='{"source_type": "Tag", "source_name": "'$TAG'", "docker_tag": "'$TAG.$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'"}'; +CURL_DATA='{"source_type": "Tag", "source_name": "'$TRAVIS_TAG'", "docker_tag": "'$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH.$TRAVIS_TAG'"}'; fi curl -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST "${CURL_URL}" -- GitLab From 820ed44aca3b329aa4a2975ad45ae60d5d79bb19 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 00:06:46 -0200 Subject: [PATCH 0731/1338] fixing docker hub build --- .travis.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index c494279d497..6d5742f1429 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,17 +30,8 @@ deploy: skip_cleanup: true local_dir: /tmp/deploy on: - branch: - - develop - - provider: s3 - access_key_id: "AKIAIKIA7H7D47KUHYCA" - secret_access_key: $ACCESSKEY - bucket: "rocketchatbuild" - skip_cleanup: true - local_dir: /tmp/deploy - on: - tags: true branch: - master + - develop after_deploy: - .travis/docker.sh -- GitLab From c18ffd5680058e3c8477f0cac83db7aba3f86234 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 00:45:03 -0200 Subject: [PATCH 0732/1338] trying to fix docker hub triggers --- .travis/docker.sh | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index d2c479d5cf5..a270f1dfafd 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -2,22 +2,18 @@ set -euo pipefail IFS=$'\n\t' -# TRAVIS_TAG='v0.7' -# TAG="v0.7" -# TRAVIS_BUILD_NUMBER="1234" -# TRAVIS_BRANCH="develop" -# PUSHTOKEN="secret" - CURL_HEADER="Content-Type: application/json" CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" -if [ -z ${TRAVIS_TAG+x} ]; -then -CURL_DATA='{"source_type": "Branch", "source_name": "'$TRAVIS_BRANCH'", "docker_tag": "'$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH'"}'; +if [ "$TRAVIS_TAG" ]; then + CURL_DATA='{"source_type": "Tag", "source_name": "'$TRAVIS_TAG'", "docker_tag": "'$TRAVIS_TAG'"}'; else -CURL_DATA='{"source_type": "Tag", "source_name": "'$TRAVIS_TAG'", "docker_tag": "'$TRAVIS_BUILD_NUMBER.$TRAVIS_BRANCH.$TRAVIS_TAG'"}'; + 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 fi -curl -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST "${CURL_URL}" - - +echo -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST $CURL_URL +curl -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST $CURL_URL -- GitLab From 45982dd6bcb454c2c369a5cf8e68ca2284d4695f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 00:58:59 -0200 Subject: [PATCH 0733/1338] fixing scape for t he curl command --- .travis/docker.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index a270f1dfafd..f66c5e39003 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -15,5 +15,4 @@ else fi fi -echo -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST $CURL_URL -curl -H "${CURL_HEADER}" --data "${CURL_DATA}" -X POST $CURL_URL +curl -H '"'$CURL_HEADER'"' --data "'"$CURL_DATA"'" -X POST $CURL_URL -- GitLab From ef852a9b39d6f7ed1ed81e9d09ef059f0613fedd Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 01:05:02 -0200 Subject: [PATCH 0734/1338] remove spaces --- .travis/docker.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index f66c5e39003..6bdb021fe19 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -5,13 +5,13 @@ IFS=$'\n\t' CURL_HEADER="Content-Type: application/json" 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'","docker_tag":"'$TRAVIS_TAG'"}'; else - if [ "$TRAVIS_BRANCH" = "master" ]; then - CURL_DATA='{"source_type": "Branch", "source_name": "master", "docker_tag": "latest"}'; + 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'"}'; + CURL_DATA='{"source_type":"Branch","source_name":"'$TRAVIS_BRANCH'","docker_tag":"'$TRAVIS_BRANCH'"}'; fi fi -- GitLab From 316f0e4dc70e145cbe41cac83bd32e48c96e1c4f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 01:16:16 -0200 Subject: [PATCH 0735/1338] trying to fix curl --- .travis/docker.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index 6bdb021fe19..2590733df8b 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -6,13 +6,14 @@ CURL_HEADER="Content-Type: application/json" 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'"}'; + CURL_DATA='{"source_type":"Tag","source_name":"$TRAVIS_TAG","docker_tag":"$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'"}'; + CURL_DATA='{"source_type":"Branch","source_name":"$TRAVIS_BRANCH","docker_tag":"$TRAVIS_BRANCH"}'; fi fi +echo -H '"'$CURL_HEADER'"' --data "'"$CURL_DATA"'" -X POST CURL_URL curl -H '"'$CURL_HEADER'"' --data "'"$CURL_DATA"'" -X POST $CURL_URL -- GitLab From 912434e829782bdd34eaa9a0c467ba1a422df4e4 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 01:32:56 -0200 Subject: [PATCH 0736/1338] curl.... --- .travis/docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index 2590733df8b..8205138a8a0 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -11,7 +11,7 @@ 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"}'; + CURL_DATA='{"source_type":"Branch","source_name":"'$TRAVIS_BRANCH'","docker_tag":"'$TRAVIS_BRANCH'"}'; fi fi -- GitLab From f4c58e17373d6ee978bf9a67ea3862e8962644ec Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 02:12:48 -0200 Subject: [PATCH 0737/1338] curl.... --- .travis/docker.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index 8205138a8a0..76f307a3de2 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -2,18 +2,17 @@ set -euo pipefail IFS=$'\n\t' -CURL_HEADER="Content-Type: application/json" 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"}'; + CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'","docker_tag":"'"$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'"}'; + CURL_DATA='{"source_type":"Branch","source_name":"'"$TRAVIS_BRANCH"'","docker_tag":"'"$TRAVIS_BRANCH"'"}'; fi fi -echo -H '"'$CURL_HEADER'"' --data "'"$CURL_DATA"'" -X POST CURL_URL -curl -H '"'$CURL_HEADER'"' --data "'"$CURL_DATA"'" -X POST $CURL_URL +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" -- GitLab From 827032390689f01895ed402e1a359b0e81c19feb Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 02:28:16 -0200 Subject: [PATCH 0738/1338] fix typo --- .travis/docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/docker.sh b/.travis/docker.sh index 76f307a3de2..255601ef0f5 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -7,7 +7,7 @@ CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSH if ["$TRAVIS_TAG" ]; then CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'","docker_tag":"'"$TRAVIS_TAG"'"}'; else - if ["$TRAVIS_BRANCH" ="master" ]; then + 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"'"}'; -- GitLab From 15ec77bbda951b618914302c06acca1c751ba240 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 11:58:30 -0200 Subject: [PATCH 0739/1338] Add a new setting type "action" to call server methods --- packages/rocketchat-ui-admin/admin/admin.coffee | 11 +++++++++++ packages/rocketchat-ui-admin/admin/admin.html | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 1f8c90a7dd4..4284b5ab0ff 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -138,6 +138,17 @@ Template.admin.events $(e.currentTarget).closest('.section').addClass('section-collapsed') $(e.currentTarget).closest('button').addClass('expand').removeClass('collapse').find('span').text(TAPi18n.__ "Expand") + "click button.action": (e) -> + if @type isnt 'action' + return + + Meteor.call @value, (err, data) -> + if err? + toastr.error TAPi18n.__(err.error), TAPi18n.__('Error') + return + + toastr.success TAPi18n.__("Your_push_was_sent_to_s_devices", data), TAPi18n.__('Success') + Template.admin.onRendered -> Tracker.afterFlush -> diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 3375b44f776..a8f22e68d0f 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -74,6 +74,10 @@ <input type="text" class="minicolors" name="{{_id}}" value="{{value}}" /> {{/if}} + {{#if $eq type 'action'}} + <button type="button" class="button primary action" data-setting="{{_id}}" data-action="{{value}}">{{_ actionText}}</button> + {{/if}} + {{#if $eq type 'asset'}} {{#if value}} <div class="settings-file-preview"> -- GitLab From 5045fe9e909a3a0ad2d417237e2cfc160f09819c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 11:58:44 -0200 Subject: [PATCH 0740/1338] Create a setting/action to test push notifications --- i18n/en.i18n.json | 28 ++++++++----- .../server/startup/settings.coffee | 1 + server/lib/cordova.coffee | 39 +++++++++++++++++++ 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index f67fe7f4691..d8a73b7c3e2 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1,20 +1,22 @@ { + "Access_not_authorized" : "Access not authorized", "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", - "Access_not_authorized" : "Access not authorized", "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Allowed Domains List", "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains", "Accounts_AllowPasswordChange" : "Allow Password Change", "Accounts_AllowUserAvatarChange" : "Allow User Avatar Change", - "Accounts_AllowUserProfileChange" : "Allow User Profile Change", "Accounts_AllowUsernameChange" : "Allow Username Change", + "Accounts_AllowUserProfileChange" : "Allow User Profile Change", "Accounts_AvatarResize" : "Resize Avatars", "Accounts_AvatarSize" : "Avatar Size", "Accounts_AvatarStorePath" : "Avatar Storage Path", "Accounts_AvatarStoreType" : "Avatar Storage Type", "Accounts_denyUnverifiedEmail" : "Deny unverified e-mail", "Accounts_EmailVerification" : "E-mail Verification", + "Accounts_Enrollment_Email" : "Enrollment E-mail", + "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", "Accounts_OAuth_Custom_Button_Color" : "Button Color", @@ -47,19 +49,17 @@ "Accounts_OAuth_Twitter" : "Twitter Login", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Password Reset", "Accounts_Registration_AuthenticationServices_Enabled" : "Registration with Authentication Services", "Accounts_RegistrationForm" : "Registration Form", - "Accounts_RegistrationForm_Public" : "Public", "Accounts_RegistrationForm_Disabled" : "Disabled", "Accounts_RegistrationForm_LinkReplacementText" : "Registration Form Link Replacement Text", + "Accounts_RegistrationForm_Public" : "Public", "Accounts_RegistrationForm_Secret_URL" : "Secret URL", "Accounts_RegistrationForm_SecretURL" : "Registration Form Secret URL", "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_PasswordReset" : "Password Reset", - "Accounts_Enrollment_Email" : "Enrollment E-mail", - "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", @@ -141,6 +141,7 @@ "Enable_Desktop_Notifications" : "Enable Desktop Notifications", "Enter_info" : "Enter your information", "Enter_to" : "Enter to", + "Error" : "Error", "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", @@ -172,8 +173,6 @@ "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", "Invalid_asset" : "Invalid asset", "Invalid_confirm_pass" : "The password confirmation does not match password", - "Invalid_Secret_URL" : "Invalid Secret URL", - "Invalid_secret_URL_message" : "The URL provided is invalid.", "Invalid_email" : "The e-mail entered is invalid", "Invalid_file_height" : "Invalid file height", "Invalid_file_type" : "Invalid file type", @@ -181,6 +180,8 @@ "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_Secret_URL" : "Invalid Secret URL", + "Invalid_secret_URL_message" : "The URL provided is invalid.", "invisible" : "invisible", "Invisible" : "Invisible", "Invitation_HTML" : "Invitation HTML", @@ -286,6 +287,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_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", "Not_authorized" : "Not authorized", @@ -325,12 +327,14 @@ "Push_apn_key" : "APN Key", "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", + "push_disabled" : "Push disabled", "Push_enable" : "Enable", "Push_enable_gateway" : "Enable Gateway", "Push_gateway" : "Gateway", "Push_gcm_api_key" : "GCM API Key", "Push_gcm_project_number" : "GCM Project Number", "Push_production" : "Production", + "Push_test_push" : "Test", "Quick_Search" : "Quick Search", "quote" : "quote", "Recents" : "Recents", @@ -370,6 +374,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_push_to_my_user" : "Send a test push to my user", "Send_confirmation_email" : "Send confirmation email", "Send_invitation_email" : "Send invitation e-mail", "Send_invitation_email_error" : "You haven't provided any valid e-mail address.", @@ -420,8 +425,10 @@ "Stop_Recording" : "Stop Recording", "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_field_is_required" : "The field %s is required.", + "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", "Unnamed" : "Unnamed", "Unread_Rooms" : "Unread Rooms", @@ -477,5 +484,6 @@ "You_need_confirm_email" : "You need to confirm your email to login!", "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_Open_Source_solution" : "Your own Open Source chat solution" -} \ No newline at end of file + "Your_Open_Source_solution" : "Your own Open Source chat solution", + "Your_push_was_sent_to_s_devices" : "Your push was sent to %s devices" +} diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 2421e30a7ec..144f3242328 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -104,6 +104,7 @@ RocketChat.settings.add 'Push_enable', true, { type: 'boolean', group: 'Push', p 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' } diff --git a/server/lib/cordova.coffee b/server/lib/cordova.coffee index ccd906e83ac..ce7f4ff2634 100644 --- a/server/lib/cordova.coffee +++ b/server/lib/cordova.coffee @@ -2,6 +2,45 @@ Meteor.methods log: -> console.log.apply console, arguments + push_test: -> + user = Meteor.user() + if not user? + throw new Meteor.Error 'unauthorized', '[methods] push_test -> Unauthorized' + + if not RocketChat.authz.hasRole(user._id, 'admin') + throw new Meteor.Error 'unauthorized', '[methods] push_test -> Unauthorized' + + if Push.enabled isnt true + throw new Meteor.Error 'push_disabled' + + query = + $and: [ + userId: user._id + { + $or: [ + { 'token.apn': { $exists: true } } + { 'token.gcm': { $exists: true } } + ] + } + ] + + tokens = Push.appCollection.find(query).count() + + if tokens is 0 + throw new Meteor.Error 'no_tokens_for_this_user' + + Push.send + from: 'push' + title: "@#{user.username}" + text: TAPi18n.__ "This_is_a_push_test_messsage" + apn: + text: "@#{user.username} :\n" + TAPi18n.__ "This_is_a_push_test_messsage" + sound: 'chime' + query: + userId: user._id + + return tokens + Meteor.startup -> Push.debug = RocketChat.settings.get 'Push_debug' -- GitLab From 4d0a2ee427c61f741d510215b26a8bb378e3352d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 12:13:38 -0200 Subject: [PATCH 0741/1338] Pass success message to settings/actions --- packages/rocketchat-ui-admin/admin/admin.coffee | 4 +++- server/lib/cordova.coffee | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 4284b5ab0ff..4e215e45f5e 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -147,7 +147,9 @@ Template.admin.events toastr.error TAPi18n.__(err.error), TAPi18n.__('Error') return - toastr.success TAPi18n.__("Your_push_was_sent_to_s_devices", data), TAPi18n.__('Success') + args = [data.message].concat data.params + + toastr.success TAPi18n.__.apply(TAPi18n, args), TAPi18n.__('Success') Template.admin.onRendered -> diff --git a/server/lib/cordova.coffee b/server/lib/cordova.coffee index ce7f4ff2634..0f12e57b352 100644 --- a/server/lib/cordova.coffee +++ b/server/lib/cordova.coffee @@ -34,12 +34,15 @@ Meteor.methods title: "@#{user.username}" text: TAPi18n.__ "This_is_a_push_test_messsage" apn: - text: "@#{user.username} :\n" + TAPi18n.__ "This_is_a_push_test_messsage" + text: "@#{user.username}:\n" + TAPi18n.__ "This_is_a_push_test_messsage" sound: 'chime' query: userId: user._id - return tokens + return {} = + message: "Your_push_was_sent_to_s_devices" + params: [tokens] + Meteor.startup -> -- GitLab From b63b28f23b86c3106adc87bd7a2c726c7770735e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 12:13:57 -0200 Subject: [PATCH 0742/1338] Add settings/action to allow admins restart the server --- i18n/en.i18n.json | 3 +++ packages/rocketchat-lib/package.js | 1 + .../server/methods/restartServer.coffee | 15 +++++++++++++++ .../rocketchat-lib/server/startup/settings.coffee | 1 + 4 files changed, 20 insertions(+) create mode 100644 packages/rocketchat-lib/server/methods/restartServer.coffee diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index d8a73b7c3e2..c4407e54e52 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -346,6 +346,8 @@ "Remove_Admin" : "Remove Admin", "Remove_custom_oauth" : "Remove custom oauth", "Reset_password" : "Reset password", + "Restart" : "Restart", + "Restart_the_server" : "Restart the server", "Room" : "Room", "Room_name_changed" : "Room name changed to: <em>__room_name__</em> by <em>__user_by__</em>", "Room_name_changed_successfully" : "Room name changed successfully", @@ -428,6 +430,7 @@ "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_field_is_required" : "The field %s is required.", + "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", "Unnamed" : "Unnamed", diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 3d150e39dd3..897bd0bab52 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -66,6 +66,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/setRealName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); + api.addFiles('server/methods/restartServer.coffee', 'server'); // SERVER STARTUP api.addFiles('server/startup/settingsOnLoadCdnPrefix.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/restartServer.coffee b/packages/rocketchat-lib/server/methods/restartServer.coffee new file mode 100644 index 00000000000..4b15cf58488 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/restartServer.coffee @@ -0,0 +1,15 @@ +Meteor.methods + restart_server: -> + if not Meteor.userId() + throw new Meteor.Error 'invalid-user', "[methods] restart_server -> Invalid user" + + unless RocketChat.authz.hasRole( Meteor.userId(), 'admin') is true + throw new Meteor.Error 'not-authorized', '[methods] restart_server -> Not authorized' + + Meteor.setTimeout -> + process.exit(0) + , 2000 + + return {} = + message: "The_server_will_restart_in_s_seconds" + params: [2] diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 144f3242328..5597f56d1b3 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -59,6 +59,7 @@ RocketChat.settings.add 'Site_Name', 'Rocket.Chat', { type: 'string', group: 'Ge 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 } RocketChat.settings.add 'UTF8_Names_Slugify', true, { type: 'boolean', group: 'General', section: 'UTF8', public: true } -- GitLab From 6798c08970da1be29ea46b8dc0c6ab6370d3cd2e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 12:32:58 -0200 Subject: [PATCH 0743/1338] Allow arrays of keys in RocketChat.settings.onload --- packages/rocketchat-lib/lib/settings.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/lib/settings.coffee b/packages/rocketchat-lib/lib/settings.coffee index 7f3694134de..91d58ae475e 100644 --- a/packages/rocketchat-lib/lib/settings.coffee +++ b/packages/rocketchat-lib/lib/settings.coffee @@ -41,5 +41,8 @@ RocketChat.settings = # else if Meteor.settings?[_id]? # callback key, Meteor.settings[_id], false - RocketChat.settings.callbacks[key] ?= [] - RocketChat.settings.callbacks[key].push callback + keys = [].concat key + + for k in keys + RocketChat.settings.callbacks[k] ?= [] + RocketChat.settings.callbacks[k].push callback -- GitLab From 8f275d7edf5fa93f634cdb504059bc8e109bf94f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 12:33:13 -0200 Subject: [PATCH 0744/1338] Prepare code to reconfigure push plugin in runtime --- server/lib/cordova.coffee | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/server/lib/cordova.coffee b/server/lib/cordova.coffee index 0f12e57b352..2815176799f 100644 --- a/server/lib/cordova.coffee +++ b/server/lib/cordova.coffee @@ -44,7 +44,8 @@ Meteor.methods params: [tokens] -Meteor.startup -> +configurePush = -> + console.log 'configuring push' Push.debug = RocketChat.settings.get 'Push_debug' @@ -123,3 +124,30 @@ Meteor.startup -> pushGetway = DDP.connect(RocketChat.settings.get('Push_gateway'), {_dontPrintErrors: false}) Push.enabled = true + + +Meteor.startup -> + configurePush() + + ## Prepared to reconfigure the push plugin + # + # keys = [ + # 'Push_enable' + # 'Push_enable_gateway' + # 'Push_gcm_api_key' + # 'Push_gcm_project_number' + # 'Push_apn_passphrase' + # 'Push_apn_key' + # 'Push_apn_cert' + # 'Push_production' + # 'Push_apn_dev_passphrase' + # 'Push_apn_dev_key' + # 'Push_apn_dev_cert' + # 'Push_gateway' + # ] + + # configurePushDebounce = _.debounce Meteor.bindEnvironment(configurePush), 1000 + + # RocketChat.settings.onload keys, -> + # configurePushDebounce() + -- GitLab From 5d1396cae12a8a5ba73707e8671f441520a8b6e9 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Tue, 8 Dec 2015 09:54:38 -0500 Subject: [PATCH 0745/1338] Adding the new changes to the rtl.less from the previous patch --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 39609cabef1..0380d0d2775 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -622,4 +622,7 @@ .left(10px); } } + #swipebox-overlay{ + direction: ltr; + } } -- GitLab From c7ce2eae130b5e1075144e790bd1ec6a0673cdf2 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 8 Dec 2015 13:17:28 -0200 Subject: [PATCH 0746/1338] Register before joining live chat --- .../rocketchat-livechat/app/.meteor/packages | 1 + .../rocketchat-livechat/app/.meteor/versions | 5 ++ .../app/client/routes/router.coffee | 5 +- .../app/client/stylesheets/main.less | 60 +++++++++++++++++++ .../app/client/views/register.coffee | 41 +++++++++++++ .../app/client/views/register.html | 22 +++++++ .../app/client/views/room.coffee | 3 + .../rocketchat-livechat/app/i18n/en.i18n.json | 7 +++ .../rocketchat-livechat/server/methods.js | 19 ++++-- 9 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 packages/rocketchat-livechat/app/client/views/register.coffee create mode 100644 packages/rocketchat-livechat/app/client/views/register.html create mode 100644 packages/rocketchat-livechat/app/i18n/en.i18n.json diff --git a/packages/rocketchat-livechat/app/.meteor/packages b/packages/rocketchat-livechat/app/.meteor/packages index b5196ffad92..b1a1bda47a6 100644 --- a/packages/rocketchat-livechat/app/.meteor/packages +++ b/packages/rocketchat-livechat/app/.meteor/packages @@ -34,3 +34,4 @@ mizzao:timesync reactive-var accounts-password standard-minifiers +tap:i18n diff --git a/packages/rocketchat-livechat/app/.meteor/versions b/packages/rocketchat-livechat/app/.meteor/versions index 2ca4cd982ac..fe32472575e 100644 --- a/packages/rocketchat-livechat/app/.meteor/versions +++ b/packages/rocketchat-livechat/app/.meteor/versions @@ -1,5 +1,6 @@ accounts-base@1.2.2 accounts-password@1.1.4 +aldeed:simple-schema@1.3.3 arunoda:streams@0.1.17 babel-compiler@5.8.24_1 babel-runtime@0.1.4 @@ -11,6 +12,7 @@ boilerplate-generator@1.0.4 caching-compiler@1.0.0 caching-html-compiler@1.0.2 callback-hook@1.0.4 +cfs:http-methods@0.0.30 check@1.1.0 coffeescript@1.0.11 cosmos:browserify@0.9.2 @@ -39,6 +41,7 @@ livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 meteor@1.1.10 +meteorspark:util@0.2.0 minifiers@1.1.7 minimongo@1.0.10 mizzao:timesync@0.3.4 @@ -50,6 +53,7 @@ npm-mongo@1.4.39_1 observe-sequence@1.0.7 ordered-dict@1.0.4 promise@0.5.1 +raix:eventemitter@0.1.3 random@1.0.5 rate-limit@1.0.0 reactive-dict@1.1.3 @@ -63,6 +67,7 @@ spacebars@1.0.7 spacebars-compiler@1.0.7 srp@1.0.4 standard-minifiers@1.0.2 +tap:i18n@1.7.0 templating@1.1.5 templating-tools@1.0.0 tracker@1.0.9 diff --git a/packages/rocketchat-livechat/app/client/routes/router.coffee b/packages/rocketchat-livechat/app/client/routes/router.coffee index 976443f1c31..b84f7874eb2 100644 --- a/packages/rocketchat-livechat/app/client/routes/router.coffee +++ b/packages/rocketchat-livechat/app/client/routes/router.coffee @@ -7,4 +7,7 @@ FlowRouter.route '/livechat', ] action: -> - BlazeLayout.render 'main', {center: 'room'} + if Meteor.userId() + BlazeLayout.render 'main', {center: 'room'} + else + BlazeLayout.render 'main', {center: 'register'} diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index de53ed4ab8f..dd550d2ca65 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -320,6 +320,66 @@ input:focus { } } +.livechat-registration { + position: fixed; + top: 0; + bottom: 0; + .title { + border-top-right-radius: 5px; + border-top-left-radius: 5px; + color: #FFF; + position: fixed; + top: 0; + width: 100%; + height: @header-min-height; + display: table; + z-index: 10; + cursor: pointer; + h1 { + margin: 0; + padding: 0 5px; + font-size: 9pt; + display: table-cell; + vertical-align: middle; + } + } + .livechat-form { + display: block; + background-color: #FFF; + top: @header-min-height; + bottom: @footer-min-height; + border-left: 1px solid #E7E7E7; + border-right: 1px solid #E7E7E7; + position: fixed; + width: 100%; + .wrapper { + height: 100%; + overflow-y: auto; + padding-bottom: 6px; + + input, button { + display: block; + padding: 5px; + margin: 5px; + } + } + .error { + bottom: 50px; + position: fixed; + width: 100%; + background-color: #F7D799; + padding: 5px; + + .transition(transform 0.3s ease-out); + .transform(translateY(200%)); + + &.show { + .transform(translateY(8px)); + } + } + } +} + @media all and(max-height: 200px) { .livechat-room { .title { diff --git a/packages/rocketchat-livechat/app/client/views/register.coffee b/packages/rocketchat-livechat/app/client/views/register.coffee new file mode 100644 index 00000000000..c1c1af961e7 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/register.coffee @@ -0,0 +1,41 @@ +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() + instance.error.set(TAPi18n.__('Please_fill_name_and_email')) + else + Meteor.call 'registerGuest', visitor.getToken(), $name.val(), $email.val(), (err, result) -> + if error? + return instance.error.set error.reason + + Meteor.loginWithPassword result.user, result.pass, (error) -> + if error + return instance.error.set error.reason + + BlazeLayout.render 'main', {center: 'room'} + + 'click .error': (e, instance) -> + instance.error.set() + +Template.register.onCreated -> + @subscribe 'settings', ['Livechat_title', 'Livechat_title_color'] + @error = new ReactiveVar diff --git a/packages/rocketchat-livechat/app/client/views/register.html b/packages/rocketchat-livechat/app/client/views/register.html new file mode 100644 index 00000000000..8a8249834e9 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/register.html @@ -0,0 +1,22 @@ +<template name="register"> + <div class="livechat-registration"> + <div class="title" style="background-color:{{color}}"> + <h1>{{title}}</h1> + </div> + <form id="livechat-registration" class="livechat-form"> + <div class="wrapper"> + <label> + {{{welcomeMessage}}} + </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> + </div> + {{#if error}} + <div class="error show"> + <span>{{error}}</span> + </div> + {{/if}} + </form> + </div> +</template> diff --git a/packages/rocketchat-livechat/app/client/views/room.coffee b/packages/rocketchat-livechat/app/client/views/room.coffee index f29371d9d73..6baa970bafa 100644 --- a/packages/rocketchat-livechat/app/client/views/room.coffee +++ b/packages/rocketchat-livechat/app/client/views/room.coffee @@ -49,6 +49,9 @@ Template.room.onCreated -> self.atBottom = true Template.room.onRendered -> + unless Meteor.userId() + return BlazeLayout.render 'main', {center: 'register'} + this.chatMessages = new ChatMessages this.chatMessages.init(this.firstNode) diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json new file mode 100644 index 00000000000..03baaa5f9fb --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -0,0 +1,7 @@ +{ + "E-mail": "E-mail", + "Name": "Name", + "Message": "Message", + "Please_fill_name_and_email": "Please fill name and e-mail", + "Start_Chat": "Start Chat" +} diff --git a/packages/rocketchat-livechat/server/methods.js b/packages/rocketchat-livechat/server/methods.js index f97d83ecce6..8b7b0dd70e7 100644 --- a/packages/rocketchat-livechat/server/methods.js +++ b/packages/rocketchat-livechat/server/methods.js @@ -1,5 +1,5 @@ Meteor.methods({ - registerGuest: function(token) { + registerGuest: function(token, name, email) { console.log('registerGuest ->'.green, token); var pass, qt, user, userData, userExists, userId, inc = 0; check(token, String); @@ -36,12 +36,19 @@ Meteor.methods({ 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: { - name: user, - "profile.guest": true, - "profile.token": token - } + $set: updateUser }); return { user: user, -- GitLab From 3386bcc031a261f7a1ac299f92142b573fa478d8 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 8 Dec 2015 13:44:00 -0200 Subject: [PATCH 0747/1338] Display error correctly --- packages/rocketchat-livechat/app/client/views/register.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/app/client/views/register.coffee b/packages/rocketchat-livechat/app/client/views/register.coffee index c1c1af961e7..d40e057b3b9 100644 --- a/packages/rocketchat-livechat/app/client/views/register.coffee +++ b/packages/rocketchat-livechat/app/client/views/register.coffee @@ -23,7 +23,7 @@ Template.register.events unless $name.val().trim() and $email.val().trim() instance.error.set(TAPi18n.__('Please_fill_name_and_email')) else - Meteor.call 'registerGuest', visitor.getToken(), $name.val(), $email.val(), (err, result) -> + Meteor.call 'registerGuest', visitor.getToken(), $name.val(), $email.val(), (error, result) -> if error? return instance.error.set error.reason -- GitLab From 0904e08cb64d7de940b5a694b026396b29492292 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 14:21:46 -0200 Subject: [PATCH 0748/1338] Do not alert admins about wrong url if accessing from cordova --- .../rocketchat-lib/client/lib/settings.coffee | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee index 579f7234991..16ce89cf20f 100644 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ b/packages/rocketchat-lib/client/lib/settings.coffee @@ -32,16 +32,17 @@ RocketChat.settings.init = -> RocketChat.settings.init() Meteor.startup -> - Tracker.autorun (c) -> - siteUrl = RocketChat.settings.get('Site_Url') - if not siteUrl or not Meteor.userId()? - return + if Meteor.isCordova is false + Tracker.autorun (c) -> + siteUrl = RocketChat.settings.get('Site_Url') + if not siteUrl or not Meteor.userId()? + return - if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false - return c.stop() + if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false + 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') + siteUrl = siteUrl.replace /\/$/, '' + if siteUrl isnt location.origin + toastr.warning TAPi18n.__('The_configured_URL_is_different_from_the_URL_you_are_accessing'), TAPi18n.__('Warning') - return c.stop() + return c.stop() -- GitLab From 79873f8fdf12570c4bd8320360914477234a2103 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 8 Dec 2015 15:08:04 -0200 Subject: [PATCH 0749/1338] Move RocketMailer to Mailer. --- .../rocketchat-mailer/client/router.coffee | 14 ++-- .../rocketchat-mailer/client/startup.coffee | 6 +- .../{rocketMailer.coffee => mailer.coffee} | 7 +- .../views/{rocketMailer.html => mailer.html} | 17 +++- ...nsubscribe.html => mailerUnsubscribe.html} | 2 +- packages/rocketchat-mailer/i18n/en.i18n.json | 8 +- packages/rocketchat-mailer/i18n/pl.i18n.json | 6 +- packages/rocketchat-mailer/i18n/pt.i18n.json | 4 +- packages/rocketchat-mailer/lib/Mailer.coffee | 1 + .../rocketchat-mailer/lib/RocketMailer.coffee | 1 - packages/rocketchat-mailer/package.js | 10 +-- .../server/functions/sendMail.coffee | 77 +++++++++++++------ .../server/functions/unsubscribe.coffee | 2 +- .../server/methods/sendMail.coffee | 8 +- .../server/methods/unsubscribe.coffee | 6 +- .../server/models/Users.coffee | 4 +- .../rocketchat-mailer/server/startup.coffee | 2 +- 17 files changed, 107 insertions(+), 68 deletions(-) rename packages/rocketchat-mailer/client/views/{rocketMailer.coffee => mailer.coffee} (75%) rename packages/rocketchat-mailer/client/views/{rocketMailer.html => mailer.html} (71%) rename packages/rocketchat-mailer/client/views/{rocketMailerUnsubscribe.html => mailerUnsubscribe.html} (86%) create mode 100644 packages/rocketchat-mailer/lib/Mailer.coffee delete mode 100644 packages/rocketchat-mailer/lib/RocketMailer.coffee diff --git a/packages/rocketchat-mailer/client/router.coffee b/packages/rocketchat-mailer/client/router.coffee index 361cd663ae9..3bbadf4e5f0 100644 --- a/packages/rocketchat-mailer/client/router.coffee +++ b/packages/rocketchat-mailer/client/router.coffee @@ -1,15 +1,15 @@ tabReset = -> RocketChat.TabBar.reset() -FlowRouter.route '/rocket-mailer', - name: 'rocket-mailer' +FlowRouter.route '/mailer', + name: 'mailer' triggersEnter: [tabReset] triggersExit: [tabReset] action: -> - BlazeLayout.render 'main', {center: 'rocketMailer'} + BlazeLayout.render 'main', {center: 'mailer'} -FlowRouter.route '/rocket-mailer/unsubscribe/:_id/:createdAt', - name: 'rocket-mailer-unsubscribe' +FlowRouter.route '/mailer/unsubscribe/:_id/:createdAt', + name: 'mailer-unsubscribe' action: (params) -> - Meteor.call 'RocketMailer.unsubscribe', params._id, params.createdAt - BlazeLayout.render 'rocketMailerUnsubscribe' + Meteor.call 'Mailer.unsubscribe', params._id, params.createdAt + BlazeLayout.render 'mailerUnsubscribe' diff --git a/packages/rocketchat-mailer/client/startup.coffee b/packages/rocketchat-mailer/client/startup.coffee index c7abd7b5de9..9b4dd084726 100644 --- a/packages/rocketchat-mailer/client/startup.coffee +++ b/packages/rocketchat-mailer/client/startup.coffee @@ -1,5 +1,5 @@ RocketChat.AdminBox.addOption - href: 'rocket-mailer' - i18nLabel: 'Rocket_Mailer' + href: 'mailer' + i18nLabel: 'Mailer' permissionGranted: -> - return RocketChat.authz.hasAllPermission('access-rocket-mailer') + return RocketChat.authz.hasAllPermission('access-mailer') diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.coffee b/packages/rocketchat-mailer/client/views/mailer.coffee similarity index 75% rename from packages/rocketchat-mailer/client/views/rocketMailer.coffee rename to packages/rocketchat-mailer/client/views/mailer.coffee index d615dad8f39..c8000bb5d15 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailer.coffee +++ b/packages/rocketchat-mailer/client/views/mailer.coffee @@ -1,13 +1,14 @@ -Template.rocketMailer.helpers +Template.mailer.helpers fromEmail: -> return RocketChat.settings.get 'From_Email' -Template.rocketMailer.events +Template.mailer.events 'click .send': (e, t) -> e.preventDefault() from = $(t.find('[name=from]')).val() subject = $(t.find('[name=subject]')).val() body = $(t.find('[name=body]')).val() + dryrun = $(t.find('[name=dryrun]:checked')).val() unless from toastr.error TAPi18n.__('From_email_is_required') @@ -17,6 +18,6 @@ Template.rocketMailer.events toastr.error TAPi18n.__('You_must_provide_the_unsubscribe_link') return - Meteor.call 'RocketMailer.sendMail', from, subject, body, (err) -> + Meteor.call 'Mailer.sendMail', from, subject, body, dryrun, (err) -> return toastr.error err.reason if err toastr.success TAPi18n.__('The_emails_are_being_sent') diff --git a/packages/rocketchat-mailer/client/views/rocketMailer.html b/packages/rocketchat-mailer/client/views/mailer.html similarity index 71% rename from packages/rocketchat-mailer/client/views/rocketMailer.html rename to packages/rocketchat-mailer/client/views/mailer.html index 309b0d66122..ea0f0c454c4 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailer.html +++ b/packages/rocketchat-mailer/client/views/mailer.html @@ -1,13 +1,13 @@ -<template name="rocketMailer"> +<template name="mailer"> <section class="page-container page-list"> <head class="fixed-title"> {{> burger}} <h2> - <span class="room-title">{{_ "Rocket_Mailer"}}</span> + <span class="room-title">{{_ "Mailer"}}</span> </h2> </head> <div class="content"> - {{#unless hasPermission 'access-rocket-mailer'}} + {{#unless hasPermission 'access-mailer'}} <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} <form> @@ -34,7 +34,16 @@ <textarea name="body" rows="10" style="height: auto"></textarea> </div> <div> - <small class="settings-description">{{{_ "RocketMailer_body_tags"}}}</small> + <small class="settings-description">{{{_ "Mailer_body_tags"}}}</small> + </div> + </div> + <div class="input-line"> + <label>{{_ "Dry_run"}}</label> + <div> + <input type="checkbox" name="dryrun" value="1" /> + </div> + <div> + <small class="settings-description">{{{_ "Dry_run_description"}}}</small> </div> </div> </fieldset> diff --git a/packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html b/packages/rocketchat-mailer/client/views/mailerUnsubscribe.html similarity index 86% rename from packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html rename to packages/rocketchat-mailer/client/views/mailerUnsubscribe.html index 0460087f1a3..c308fb973f9 100644 --- a/packages/rocketchat-mailer/client/views/rocketMailerUnsubscribe.html +++ b/packages/rocketchat-mailer/client/views/mailerUnsubscribe.html @@ -1,4 +1,4 @@ -<template name="rocketMailerUnsubscribe"> +<template name="mailerUnsubscribe"> <section class="full-page"> <div class="wrapper"> <header> diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index bbde6b8b807..e2a997a0964 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -1,15 +1,17 @@ { "From_email_warning" : "<b>Warning</b>: The field <b>From</b> is subject to your mail server settings.", "From_email_is_required" : "From e-mail is required", + "Dry_run" : "Dry run", + "Dry_run_description" : "Will only send one e-mail, to the same address as in From. The e-mail must belong to a valid user.", "Email_from" : "From", "Email_subject" : "Subject", "Email_body" : "E-mail body", - "Rocket_Mailer" : "Rocket Mailer", - "RocketMailer_body_tags" : "You <b>must</b> use [unsubscribe] for the unsubscription link.<br />You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Mailer" : "Mailer", + "Mailer_body_tags" : "You <b>must</b> use [unsubscribe] for the unsubscription link.<br />You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Send_email" : "Send E-mail", "The_emails_are_being_sent" : "The e-mails are being sent.", "You_are_not_authorized_to_view_this_page" : "You are not authorized to view this page.", "You_have_successfully_unsubscribed" : "You have successfully unsubscribed from our Mailling List.", "You_informed_an_invalid_FROM_address" : "You informed an invalid FROM address.", "You_must_provide_the_unsubscribe_link" : "You must provide the [unsubscribe] link." -} \ 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 bb5615f66bb..15ded0753a1 100644 --- a/packages/rocketchat-mailer/i18n/pl.i18n.json +++ b/packages/rocketchat-mailer/i18n/pl.i18n.json @@ -4,12 +4,12 @@ "Email_from" : "Od", "Email_subject" : "Temat", "Email_body" : "Treść wiadomoÅ›ci", - "Rocket_Mailer" : "WyÅ›lij email użytkownikom", - "RocketMailer_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.", + "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.", "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Ä™.", "You_have_successfully_unsubscribed" : "Twój email zostaÅ‚ usuniÄ™ty z naszej listy powiadomieÅ„.", "You_informed_an_invalid_FROM_address" : "Adres nadawcy jest nieprawidÅ‚owy", "You_must_provide_the_unsubscribe_link" : "Musisz wstawić w treÅ›ci znacznik [unsubscribe]." -} \ No newline at end of file +} diff --git a/packages/rocketchat-mailer/i18n/pt.i18n.json b/packages/rocketchat-mailer/i18n/pt.i18n.json index cff0ad90bed..3e24aeb3497 100644 --- a/packages/rocketchat-mailer/i18n/pt.i18n.json +++ b/packages/rocketchat-mailer/i18n/pt.i18n.json @@ -2,8 +2,8 @@ "Email_from" : "De", "Email_subject" : "Assunto", "Email_body" : "Corpo do E-mail", - "Rocket_Mailer" : "Rocket Mailer", + "Mailer" : "Mailer", "Send_email" : "Enviar E-mail", "You_are_not_authorized_to_view_this_page" : "Você não possui permissão para visualizar esta página.", "You_have_successfully_unsubscribed" : "A partir de agora você não está mais cadastrado em nossa lista de e-mails." -} \ No newline at end of file +} diff --git a/packages/rocketchat-mailer/lib/Mailer.coffee b/packages/rocketchat-mailer/lib/Mailer.coffee new file mode 100644 index 00000000000..8158d6d741d --- /dev/null +++ b/packages/rocketchat-mailer/lib/Mailer.coffee @@ -0,0 +1 @@ +Mailer = {} diff --git a/packages/rocketchat-mailer/lib/RocketMailer.coffee b/packages/rocketchat-mailer/lib/RocketMailer.coffee deleted file mode 100644 index 90d0dee81ab..00000000000 --- a/packages/rocketchat-mailer/lib/RocketMailer.coffee +++ /dev/null @@ -1 +0,0 @@ -RocketMailer = {} diff --git a/packages/rocketchat-mailer/package.js b/packages/rocketchat-mailer/package.js index db49ba91bc2..7dd1c4cd5a8 100644 --- a/packages/rocketchat-mailer/package.js +++ b/packages/rocketchat-mailer/package.js @@ -15,14 +15,14 @@ Package.onUse(function(api) { 'rocketchat:authorization@0.0.1' ]); - api.addFiles('lib/RocketMailer.coffee'); + api.addFiles('lib/Mailer.coffee'); api.addFiles([ 'client/startup.coffee', 'client/router.coffee', - 'client/views/rocketMailer.html', - 'client/views/rocketMailer.coffee', - 'client/views/rocketMailerUnsubscribe.html' + 'client/views/mailer.html', + 'client/views/mailer.coffee', + 'client/views/mailerUnsubscribe.html' ], 'client'); api.addFiles([ @@ -47,5 +47,5 @@ Package.onUse(function(api) { api.imply('tap:i18n'); api.addFiles(tapi18nFiles, ['client', 'server']); - api.export('RocketMailer'); + api.export('Mailer'); }); diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee index ed46eafdf7c..b56cfb0f528 100644 --- a/packages/rocketchat-mailer/server/functions/sendMail.coffee +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -1,4 +1,4 @@ -RocketMailer.sendMail = (from, subject, body) -> +Mailer.sendMail = (from, subject, body, dryrun) -> 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])?)*)(?:>?)$/ # rfcMailPattern = /^[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])?)*$/ @@ -9,27 +9,54 @@ RocketMailer.sendMail = (from, subject, body) -> if body.indexOf('[unsubscribe]') is -1 throw new Meteor.Error 'missing-unsubscribe-link', TAPi18n.__('You_must_provide_the_unsubscribe_link') - Meteor.users.find({ "rocketMailer.unsubscribed": { $exists: 0 } }).forEach (user) -> - # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> - email = user.emails?[0]?.address - - html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('rocket-mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) - html = html.replace /\[name\]/g, user.name - fname = _.strLeft user.name, ' ' - lname = _.strRightBack user.name, ' ' - html = html.replace /\[fname\]/g, fname - html = html.replace /\[lname\]/g, lname - html = html.replace /\[email\]/g, email - html = html.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2') - - email = "#{user.name} <#{email}>" - - if rfcMailPatternWithName.test email - Meteor.defer -> - Email.send - to: email - from: from - subject: subject - html: html - - console.log 'Sending email to ' + email + if dryrun + Meteor.users.find({ "emails.address": from }).forEach (user) -> + # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> + email = user.emails?[0]?.address + + html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('rocket-mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) + html = html.replace /\[name\]/g, user.name + fname = _.strLeft user.name, ' ' + lname = _.strRightBack user.name, ' ' + html = html.replace /\[fname\]/g, fname + html = html.replace /\[lname\]/g, lname + html = html.replace /\[email\]/g, email + html = html.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2') + + email = "#{user.name} <#{email}>" + + if rfcMailPatternWithName.test email + Meteor.defer -> + Email.send + to: email + from: from + subject: subject + html: html + + console.log 'Sending email to ' + email + + else + Meteor.users.find({ "mailer.unsubscribed": { $exists: 0 } }).forEach (user) -> + # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> + email = user.emails?[0]?.address + + html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('rocket-mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) + html = html.replace /\[name\]/g, user.name + fname = _.strLeft user.name, ' ' + lname = _.strRightBack user.name, ' ' + html = html.replace /\[fname\]/g, fname + html = html.replace /\[lname\]/g, lname + html = html.replace /\[email\]/g, email + html = html.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2') + + email = "#{user.name} <#{email}>" + + if rfcMailPatternWithName.test email + Meteor.defer -> + Email.send + to: email + from: from + subject: subject + html: html + + console.log 'Sending email to ' + email diff --git a/packages/rocketchat-mailer/server/functions/unsubscribe.coffee b/packages/rocketchat-mailer/server/functions/unsubscribe.coffee index 9b559f1d38a..955a0ec95fb 100644 --- a/packages/rocketchat-mailer/server/functions/unsubscribe.coffee +++ b/packages/rocketchat-mailer/server/functions/unsubscribe.coffee @@ -1,4 +1,4 @@ -RocketMailer.unsubscribe = (_id, createdAt) -> +Mailer.unsubscribe = (_id, createdAt) -> if _id and createdAt return RocketChat.models.Users.RocketMailUnsubscribe(_id, createdAt) == 1 return false diff --git a/packages/rocketchat-mailer/server/methods/sendMail.coffee b/packages/rocketchat-mailer/server/methods/sendMail.coffee index 7c693bd6b57..f71b8eb299d 100644 --- a/packages/rocketchat-mailer/server/methods/sendMail.coffee +++ b/packages/rocketchat-mailer/server/methods/sendMail.coffee @@ -1,13 +1,13 @@ Meteor.methods - 'RocketMailer.sendMail': (from, subject, body) -> + 'Mailer.sendMail': (from, subject, body, dryrun) -> - console.log '[method] RocketMailer.sendMail', from, subject, body + console.log '[method] Mailer.sendMail', from, subject, body, dryrun - return RocketMailer.sendMail from, subject, body + return Mailer.sendMail from, subject, body, dryrun # Limit setting username once per minute # DDPRateLimiter.addRule # type: 'method' -# name: 'RocketMailer.sendMail' +# name: 'Mailer.sendMail' # connectionId: -> return true # , 1, 60000 diff --git a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee index 5d0a1e6a448..8df56684548 100644 --- a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee +++ b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee @@ -1,10 +1,10 @@ Meteor.methods - 'RocketMailer.unsubscribe': (_id, createdAt) -> - return RocketMailer.unsubscribe _id, createdAt + 'Mailer.unsubscribe': (_id, createdAt) -> + return Mailer.unsubscribe _id, createdAt # Limit setting username once per minute DDPRateLimiter.addRule type: 'method' - name: 'RocketMailer.unsubscribe' + name: 'Mailer.unsubscribe' connectionId: -> return true , 1, 60000 diff --git a/packages/rocketchat-mailer/server/models/Users.coffee b/packages/rocketchat-mailer/server/models/Users.coffee index 1125205ccc0..0ef727a8a74 100644 --- a/packages/rocketchat-mailer/server/models/Users.coffee +++ b/packages/rocketchat-mailer/server/models/Users.coffee @@ -8,10 +8,10 @@ RocketChat.models.Users.RocketMailUnsubscribe = (_id, createdAt) -> update = $set: - "rocketMailer.unsubscribed": true + "mailer.unsubscribed": true affectedRows = @update query, update - console.log '[RocketMailer.Unsubscribe]', _id, createdAt, new Date(parseInt createdAt), affectedRows + console.log '[Mailer.Unsubscribe]', _id, createdAt, new Date(parseInt createdAt), affectedRows return affectedRows diff --git a/packages/rocketchat-mailer/server/startup.coffee b/packages/rocketchat-mailer/server/startup.coffee index 24ee1c22c77..acf55f73c49 100644 --- a/packages/rocketchat-mailer/server/startup.coffee +++ b/packages/rocketchat-mailer/server/startup.coffee @@ -1,2 +1,2 @@ Meteor.startup -> - RocketChat.models.Permissions.upsert( 'access-rocket-mailer', { $setOnInsert : { _id: 'access-rocket-mailer', roles : ['admin'] } }) + RocketChat.models.Permissions.upsert( 'access-mailer', { $setOnInsert : { _id: 'access-mailer', roles : ['admin'] } }) -- GitLab From fec1d040d4789c534c1324df9aa51e6612fcfac4 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 8 Dec 2015 15:11:52 -0200 Subject: [PATCH 0750/1338] Fix unsubscription link --- packages/rocketchat-mailer/server/functions/sendMail.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee index b56cfb0f528..6099f264f43 100644 --- a/packages/rocketchat-mailer/server/functions/sendMail.coffee +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -40,7 +40,7 @@ Mailer.sendMail = (from, subject, body, dryrun) -> # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> email = user.emails?[0]?.address - html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('rocket-mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) + html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) html = html.replace /\[name\]/g, user.name fname = _.strLeft user.name, ' ' lname = _.strRightBack user.name, ' ' -- GitLab From 10212332c284980ddbfc3127101d72372554b6e9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 8 Dec 2015 15:17:24 -0200 Subject: [PATCH 0751/1338] Fix unsubscriptions --- packages/rocketchat-mailer/server/functions/sendMail.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee index 6099f264f43..2e1292112da 100644 --- a/packages/rocketchat-mailer/server/functions/sendMail.coffee +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -14,7 +14,7 @@ Mailer.sendMail = (from, subject, body, dryrun) -> # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> email = user.emails?[0]?.address - html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('rocket-mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) + html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('mailer/unsubscribe/:_id/:createdAt', { _id: user._id, createdAt: user.createdAt.getTime() })) html = html.replace /\[name\]/g, user.name fname = _.strLeft user.name, ' ' lname = _.strRightBack user.name, ' ' @@ -40,7 +40,7 @@ Mailer.sendMail = (from, subject, body, dryrun) -> # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> email = user.emails?[0]?.address - html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('mailer/unsubscribe/:hash', { hash: "#{user._id}:#{user.createdAt.getTime()}" })) + html = body.replace /\[unsubscribe\]/g, Meteor.absoluteUrl(FlowRouter.path('mailer/unsubscribe/:_id/:createdAt', { _id: user._id, createdAt: user.createdAt.getTime() })) html = html.replace /\[name\]/g, user.name fname = _.strLeft user.name, ' ' lname = _.strRightBack user.name, ' ' -- GitLab From 3825cd4a67e630bacace60f0081a929d377f3a43 Mon Sep 17 00:00:00 2001 From: Nberton <eternal.pretzel@gmail.com> Date: Tue, 8 Dec 2015 12:30:23 -0500 Subject: [PATCH 0752/1338] Added in functionality recommended in issue #1412 --- packages/rocketchat-oembed/server/server.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 4a59fda45e2..7696e42b770 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -31,7 +31,7 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> parsedUrl: parsedUrl request = httpOrHttps.request opts, Meteor.bindEnvironment (response) -> - if response.statusCode is 301 and response.headers.location? + if response.statusCode in [301,302,307] and response.headers.location? request.abort() console.log response.headers.location -- GitLab From 74284cb9cb80b0b6049b44704bf2faa5cca33e2d Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 16:02:45 -0200 Subject: [PATCH 0753/1338] update sandstorm tags --- .sandstorm/sandstorm-pkgdef.capnp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 3451445dd38..eb056c7685a 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 3, # Increment this for every release. + appVersion = 4, # Increment this for every release. - appMarketingVersion = (defaultText = "0.8.0"), + appMarketingVersion = (defaultText = "0.8.1"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. @@ -50,7 +50,7 @@ const pkgdef :Spk.PackageDefinition = ( website = "https://rocket.chat", codeUrl = "https://github.com/RocketChat/Rocket.Chat", license = (openSource = mit), - categories = [communications, productivity], + categories = [communications, productivity, office, devtools, social], author = ( contactEmail = "team@rocket.chat", -- GitLab From 141380b1303741dd03845977a6e2c03ee603f521 Mon Sep 17 00:00:00 2001 From: matthewmawby <themesta@gmail.com> Date: Tue, 8 Dec 2015 13:08:34 -0500 Subject: [PATCH 0754/1338] Added the code to fix issue #1579 --- packages/rocketchat-ui/views/app/room.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index e1fe97dec71..bd43deec8d9 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -386,6 +386,13 @@ Template.room.events 'dragleave .dropzone-overlay': (e) -> e.currentTarget.parentNode.classList.remove 'over' +'dragover .dropzone-overlay': (e) -> + e = e.originalEvent or e + if e.dataTransfer.effectAllowed in ['move', 'linkMove'] + e.dataTransfer.dropEffect = 'move' + else + e.dataTransfer.dropEffect = 'copy' + 'dropped .dropzone-overlay': (event) -> event.currentTarget.parentNode.classList.remove 'over' -- GitLab From 81d46cfb11be08afb17ee325c41b54aec24030a0 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 16:26:46 -0200 Subject: [PATCH 0755/1338] future Dokerfile for Github assets --- .docker/dockerfiles/latest/Dockerfile | 40 +++++++++++++++++++++++++++ .sandstorm/README.md | 8 ++++++ 2 files changed, 48 insertions(+) create mode 100644 .docker/dockerfiles/latest/Dockerfile create mode 100644 .sandstorm/README.md diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile new file mode 100644 index 00000000000..6e52e7fdf7f --- /dev/null +++ b/.docker/dockerfiles/latest/Dockerfile @@ -0,0 +1,40 @@ +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 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 \ +&& 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/.sandstorm/README.md b/.sandstorm/README.md new file mode 100644 index 00000000000..c75365019e5 --- /dev/null +++ b/.sandstorm/README.md @@ -0,0 +1,8 @@ +# Publish commands + +``` +cd Rocket.Chat +vagrant-spk up && vagrant-spk dev +^C +vagrant-spk pack ../rocketchat.spk && vagrant-spk publish ../rocketchat.spk +``` -- GitLab From ed56869f087391c3ad598260bbf59285a576bc4c Mon Sep 17 00:00:00 2001 From: matthewmawby <themesta@gmail.com> Date: Tue, 8 Dec 2015 13:34:06 -0500 Subject: [PATCH 0756/1338] tabbed added code --- packages/rocketchat-ui/views/app/room.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index bd43deec8d9..729cb22d93d 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -386,12 +386,12 @@ Template.room.events 'dragleave .dropzone-overlay': (e) -> e.currentTarget.parentNode.classList.remove 'over' -'dragover .dropzone-overlay': (e) -> - e = e.originalEvent or e - if e.dataTransfer.effectAllowed in ['move', 'linkMove'] - e.dataTransfer.dropEffect = 'move' - else - e.dataTransfer.dropEffect = 'copy' + 'dragover .dropzone-overlay': (e) -> + e = e.originalEvent or e + if e.dataTransfer.effectAllowed in ['move', 'linkMove'] + e.dataTransfer.dropEffect = 'move' + else + e.dataTransfer.dropEffect = 'copy' 'dropped .dropzone-overlay': (event) -> event.currentTarget.parentNode.classList.remove 'over' -- GitLab From 4ca159823a46c8a5850fbc007d816de53cded151 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 16:36:50 -0200 Subject: [PATCH 0757/1338] fixed categories keywords --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index eb056c7685a..3e50eea4c3b 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -50,7 +50,7 @@ const pkgdef :Spk.PackageDefinition = ( website = "https://rocket.chat", codeUrl = "https://github.com/RocketChat/Rocket.Chat", license = (openSource = mit), - categories = [communications, productivity, office, devtools, social], + categories = [communications, productivity, office, social, devTools], author = ( contactEmail = "team@rocket.chat", -- GitLab From c3ce99d41cb00f8d779f0a7577fbf95117fe22ff Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 8 Dec 2015 16:53:13 -0200 Subject: [PATCH 0758/1338] fix developerTools --- .meteor/versions | 2 +- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 8c88fab5cc1..4dfa6517c34 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -107,7 +107,7 @@ ordered-dict@1.0.4 pauli:accounts-linkedin@1.2.0 pauli:linkedin@1.2.0 perak:codemirror@1.2.8 -percolate:migrations@0.9.6 +percolate:migrations@0.9.7 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 3e50eea4c3b..b87c8cdd6ca 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -50,7 +50,7 @@ const pkgdef :Spk.PackageDefinition = ( website = "https://rocket.chat", codeUrl = "https://github.com/RocketChat/Rocket.Chat", license = (openSource = mit), - categories = [communications, productivity, office, social, devTools], + categories = [communications, productivity, office, social, developerTools], author = ( contactEmail = "team@rocket.chat", -- GitLab From 0b9bfa6e9b20e15f2f8905016b540b5d6b06131d Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Tue, 8 Dec 2015 14:06:37 -0500 Subject: [PATCH 0759/1338] Removed trash can icon Removed the trash icon since the buttons are used to upload files and not delete them --- packages/rocketchat-ui-admin/admin/admin.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index a8f22e68d0f..492d539321b 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -90,7 +90,7 @@ <div class="settings-file-preview"> <div class="preview no-file"><i class="icon-upload"></i></div> <div class="action"> - <div class="button primary"><i class="icon-trash"></i>{{_ 'Select_file'}} + <div class="button primary">{{_ 'Select_file'}} <input type="file" accept="{{fileConstraints.contentType}}" /> </div> </div> -- GitLab From 7a2bb2c62870d942414a82c5ba426461f3e2b022 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 21:24:39 -0200 Subject: [PATCH 0760/1338] Add lib clipboard.js --- packages/rocketchat-ui-master/master/main.coffee | 2 ++ packages/rocketchat-ui/lib/clipboardjs/clipboard.js | 7 +++++++ packages/rocketchat-ui/package.js | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 packages/rocketchat-ui/lib/clipboardjs/clipboard.js diff --git a/packages/rocketchat-ui-master/master/main.coffee b/packages/rocketchat-ui-master/master/main.coffee index e43df650fbd..14ec9d986b2 100644 --- a/packages/rocketchat-ui-master/master/main.coffee +++ b/packages/rocketchat-ui-master/master/main.coffee @@ -1,4 +1,6 @@ Template.body.onRendered -> + new Clipboard('.clipboard') + $(document.body).on 'keydown', (e) -> if e.keyCode is 80 and (e.ctrlKey is true or e.metaKey is true) e.preventDefault() diff --git a/packages/rocketchat-ui/lib/clipboardjs/clipboard.js b/packages/rocketchat-ui/lib/clipboardjs/clipboard.js new file mode 100644 index 00000000000..000e4b48ed9 --- /dev/null +++ b/packages/rocketchat-ui/lib/clipboardjs/clipboard.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v1.5.5 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(t,e,n){var r=t("matches-selector");e.exports=function(t,e,n){for(var o=n?t:t.parentNode;o&&o!==document;){if(r(o,e))return o;o=o.parentNode}}},{"matches-selector":2}],2:[function(t,e,n){function r(t,e){if(i)return i.call(t,e);for(var n=t.parentNode.querySelectorAll(e),r=0;r<n.length;++r)if(n[r]==t)return!0;return!1}var o=Element.prototype,i=o.matchesSelector||o.webkitMatchesSelector||o.mozMatchesSelector||o.msMatchesSelector||o.oMatchesSelector;e.exports=r},{}],3:[function(t,e,n){function r(t,e,n,r){var i=o.apply(this,arguments);return t.addEventListener(n,i),{destroy:function(){t.removeEventListener(n,i)}}}function o(t,e,n,r){return function(n){n.delegateTarget=i(n.target,e,!0),n.delegateTarget&&r.call(t,n)}}var i=t("closest");e.exports=r},{closest:1}],4:[function(t,e,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.function=function(t){var e=Object.prototype.toString.call(t);return"[object Function]"===e}},{}],5:[function(t,e,n){function r(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!c.string(e))throw new TypeError("Second argument must be a String");if(!c.function(n))throw new TypeError("Third argument must be a Function");if(c.node(t))return o(t,e,n);if(c.nodeList(t))return i(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function o(t,e,n){return t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function i(t,e,n){return Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function a(t,e,n){return s(document.body,t,e,n)}var c=t("./is"),s=t("delegate");e.exports=r},{"./is":4,delegate:3}],6:[function(t,e,n){function r(t){var e;if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName)t.focus(),t.setSelectionRange(0,t.value.length),e=t.value;else{t.hasAttribute("contenteditable")&&t.focus();var n=window.getSelection(),r=document.createRange();r.selectNodeContents(t),n.removeAllRanges(),n.addRange(r),e=n.toString()}return e}e.exports=r},{}],7:[function(t,e,n){function r(){}r.prototype={on:function(t,e,n){var r=this.e||(this.e={});return(r[t]||(r[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function r(){o.off(t,r),e.apply(n,arguments)}var o=this;return r._=e,this.on(t,r,n)},emit:function(t){var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),r=0,o=n.length;for(r;o>r;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(e,n,r){return n&&t(e.prototype,n),r&&t(e,r),e}}(),a=t("select"),c=r(a),s=function(){function t(e){o(this,t),this.resolveOptions(e),this.initSelection()}return t.prototype.resolveOptions=function t(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.action=e.action,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""},t.prototype.initSelection=function t(){if(this.text&&this.target)throw new Error('Multiple attributes declared, use either "target" or "text"');if(this.text)this.selectFake();else{if(!this.target)throw new Error('Missing required attributes, use either "target" or "text"');this.selectTarget()}},t.prototype.selectFake=function t(){var e=this;this.removeFake(),this.fakeHandler=document.body.addEventListener("click",function(){return e.removeFake()}),this.fakeElem=document.createElement("textarea"),this.fakeElem.style.position="absolute",this.fakeElem.style.left="-9999px",this.fakeElem.style.top=(window.pageYOffset||document.documentElement.scrollTop)+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=c.default(this.fakeElem),this.copyText()},t.prototype.removeFake=function t(){this.fakeHandler&&(document.body.removeEventListener("click"),this.fakeHandler=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)},t.prototype.selectTarget=function t(){this.selectedText=c.default(this.target),this.copyText()},t.prototype.copyText=function t(){var e=void 0;try{e=document.execCommand(this.action)}catch(n){e=!1}this.handleResult(e)},t.prototype.handleResult=function t(e){e?this.emitter.emit("success",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)}):this.emitter.emit("error",{action:this.action,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})},t.prototype.clearSelection=function t(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()},t.prototype.destroy=function t(){this.removeFake()},i(t,[{key:"action",set:function t(){var e=arguments.length<=0||void 0===arguments[0]?"copy":arguments[0];if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function t(){return this._action}},{key:"target",set:function t(e){if(void 0!==e){if(!e||"object"!=typeof e||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');this._target=e}},get:function t(){return this._target}}]),t}();n.default=s,e.exports=n.default},{select:6}],9:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t,e){var n="data-clipboard-"+t;if(e.hasAttribute(n))return e.getAttribute(n)}n.__esModule=!0;var c=t("./clipboard-action"),s=r(c),u=t("tiny-emitter"),l=r(u),f=t("good-listener"),d=r(f),h=function(t){function e(n,r){o(this,e),t.call(this),this.resolveOptions(r),this.listenClick(n)}return i(e,t),e.prototype.resolveOptions=function t(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText},e.prototype.listenClick=function t(e){var n=this;this.listener=d.default(e,"click",function(t){return n.onClick(t)})},e.prototype.onClick=function t(e){var n=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new s.default({action:this.action(n),target:this.target(n),text:this.text(n),trigger:n,emitter:this})},e.prototype.defaultAction=function t(e){return a("action",e)},e.prototype.defaultTarget=function t(e){var n=a("target",e);return n?document.querySelector(n):void 0},e.prototype.defaultText=function t(e){return a("text",e)},e.prototype.destroy=function t(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)},e}(l.default);n.default=h,e.exports=n.default},{"./clipboard-action":8,"good-listener":5,"tiny-emitter":7}]},{},[9])(9)}); diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index aa26d00f396..e7822568ede 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -68,6 +68,9 @@ Package.onUse(function(api) { api.addFiles('lib/recorderjs/audioRecorder.coffee', 'client'); api.addFiles('lib/recorderjs/recorder.js', 'client'); + // LIB CLIPBOARDJS + api.addFiles('lib/clipboardjs/clipboard.js', 'client'); + // TEMPLATE FILES api.addFiles('views/cmsPage.html', 'client'); api.addFiles('views/fxos.html', 'client'); -- GitLab From 1f74b78351dbfb355bd0ecf7216f51d2a342c850 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 21:25:03 -0200 Subject: [PATCH 0761/1338] Style disabled fields correctly --- packages/rocketchat-theme/assets/stylesheets/base.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index eaea1acb776..0a2c3b9a06c 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -470,6 +470,10 @@ form.inline { } } +input[disabled] { + background-color: #f4f4f4 !important; +} + .search-form { position: relative; } -- GitLab From e3dd15a769dc7c1d4fea5bc8305bdf7eace4e772 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 21:25:30 -0200 Subject: [PATCH 0762/1338] First version of integrations working --- .../server/publications/integrations.coffee | 0 .../client/route.coffee | 3 +- .../client/startup.coffee | 2 + .../client/views/integrations.coffee | 3 + .../client/views/integrations.html | 25 +++++- .../client/views/integrationsIncoming.coffee | 62 +++++++++++++++ .../client/views/integrationsIncoming.html | 56 +++++++------ packages/rocketchat-integrations/package.js | 35 +++------ .../server/api/api.coffee | 78 +++++++++++++++++++ .../server/methods/addIntegration.coffee | 57 ++++++++++++++ .../server/methods/deleteIntegration.coffee | 8 ++ .../server/methods/updateIntegration.coffee | 38 +++++++++ .../server/models/Integrations.coffee | 13 ++++ .../server/publications/integrations.coffee | 8 ++ 14 files changed, 330 insertions(+), 58 deletions(-) create mode 100644 packages/rocketchat-authorization/server/publications/integrations.coffee create mode 100644 packages/rocketchat-integrations/server/api/api.coffee create mode 100644 packages/rocketchat-integrations/server/methods/addIntegration.coffee create mode 100644 packages/rocketchat-integrations/server/methods/deleteIntegration.coffee create mode 100644 packages/rocketchat-integrations/server/methods/updateIntegration.coffee create mode 100644 packages/rocketchat-integrations/server/models/Integrations.coffee create mode 100644 packages/rocketchat-integrations/server/publications/integrations.coffee diff --git a/packages/rocketchat-authorization/server/publications/integrations.coffee b/packages/rocketchat-authorization/server/publications/integrations.coffee new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-integrations/client/route.coffee b/packages/rocketchat-integrations/client/route.coffee index e32f6d73e8c..62d2b85b1d1 100644 --- a/packages/rocketchat-integrations/client/route.coffee +++ b/packages/rocketchat-integrations/client/route.coffee @@ -16,10 +16,11 @@ FlowRouter.route '/admin/integrations/new', pageTemplate: 'integrationsNew' -FlowRouter.route '/admin/integrations/incoming', +FlowRouter.route '/admin/integrations/incoming/:token?', name: 'admin-integrations-incoming' action: (params) -> BlazeLayout.render 'main', center: 'pageSettingsContainer' pageTitle: t('Integration_Incoming_WebHook') pageTemplate: 'integrationsIncoming' + params: params diff --git a/packages/rocketchat-integrations/client/startup.coffee b/packages/rocketchat-integrations/client/startup.coffee index b1279bb0dfe..64191b37e73 100644 --- a/packages/rocketchat-integrations/client/startup.coffee +++ b/packages/rocketchat-integrations/client/startup.coffee @@ -1,3 +1,5 @@ +Meteor.subscribe 'integrations' + RocketChat.AdminBox.addOption href: 'admin-integrations' i18nLabel: 'Integrations' diff --git a/packages/rocketchat-integrations/client/views/integrations.coffee b/packages/rocketchat-integrations/client/views/integrations.coffee index be6f7ccdc46..1bab31e4dfa 100644 --- a/packages/rocketchat-integrations/client/views/integrations.coffee +++ b/packages/rocketchat-integrations/client/views/integrations.coffee @@ -1,3 +1,6 @@ Template.integrations.helpers hasPermission: -> return RocketChat.authz.hasAllPermission 'manage-integrations' + + integrations: -> + return ChatIntegrations.find() diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index 94402e8603d..88470f77269 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -3,11 +3,28 @@ {{#if hasPermission}} <a href="{{pathFor "admin-integrations-new"}}" class="button primary new-role">{{_ "New_integration"}}</a> - {{#each integration}} - <div> - + <div class="rocket-form"> + <div class="section"> + <div class="admin-integrations-new-panel"> + {{#each integrations}} + <a href="{{pathFor "admin-integrations-incoming" token=token}}"> + <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 <strong>{{channel}}</strong> as <strong>{{username}}</strong> + </div> + </div> + <i class="icon-angle-right"></i> + </div> + </a> + {{/each}} + </div> </div> - {{/each}} + </div> {{else}} {{_ "Not_authorized"}} {{/if}} diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index 2ce5018f126..ef008cc8725 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -4,5 +4,67 @@ Template.integrationsIncoming.helpers return RocketChat.authz.hasAllPermission 'manage-integrations' data: -> + params = Template.instance().data.params() + + if params.token? + data = ChatIntegrations.findOne({token: params.token}) + data.url = Meteor.absoluteUrl("hooks/#{data._id}/#{data.userId}/#{data.token}") + return data + return {} = channelType: 'c' + + +Template.integrationsIncoming.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 "deleteIntegration", params._id, (err, data) -> + swal + title: t('Deleted') + text: t('Your_entry_has_been_deleted') + type: 'success' + timer: 1000 + showConfirmButton: false + + "click .submit > .save": -> + name = $('[name=name]').val().trim() + channel = $('[name=channel]').val().trim() + username = $('[name=username]').val().trim() + + if channel is '' + return toastr.error TAPi18n.__("The_channel_name_is_required") + + if username is '' + return toastr.error TAPi18n.__("The_username_is_required") + + integration = + channel: channel + name: name if name isnt '' + + params = Template.instance().data.params() + if params._id? + Meteor.call "updateIntegration", params._id, integration, (err, data) -> + if err? + toastr.error TAPi18n.__(err.error) + toastr.success TAPi18n.__("Integration_updated") + else + integration.type = 'webhook-incoming' + integration.username = username + + Meteor.call "addIntegration", integration, (err, data) -> + if err? + toastr.error TAPi18n.__(err.error) + toastr.success TAPi18n.__("Integration_added") + FlowRouter.go "admin-integrations-incoming", {token: data.token} diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index 4b723e36d2e..e8a650585e2 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -6,49 +6,47 @@ <div class="section"> <div class="section-content"> <div class="input-line double-col"> - <label>Post to Channel</label> + <label>Name (optional)</label> <div> - <div> - <label><input type="radio" name="channelType" value="c" checked="{{$eq data.channelType 'c'}}" /> {{_ "Channel"}}</label> - <label><input type="radio" name="channelType" value="d" checked="{{$eq data.channelType 'd'}}" /> {{_ "User"}}</label> - </div> - <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{_ 'User_or_channel_name'}}" /> - <div class="settings-description">Messages that are sent to the incoming webhook will be posted here.</div> + <input type="text" name="name" value="{{data.name}}" placeholder="{{_ 'Optional'}}" /> + <div class="settings-description">You can give a name just to manage your integrations.</div> </div> </div> <div class="input-line double-col"> - <label>Customize Name</label> + <label>Post to Channel</label> <div> - <input type="text" name="{{_id}}" value="{{value}}" placeholder="{{placeholder}}" /> - <div class="settings-description">Choose the username that this integration will post as.</div> + <input type="text" name="channel" value="{{data.channel}}" placeholder="{{_ 'User_or_channel_name'}}" /> + <div class="settings-description">Messages that are sent to the incoming webhook will be posted here.</div> + <div class="settings-description">Start with <code class="inline">@</code> for user or <code class="inline">#</code> for channel. Eg: <code class="inline">@john</code> or <code class="inline">#general</code>.</div> </div> </div> - <!-- <div class="input-line double-col"> - <label>Customize Icon</label> + <div class="input-line double-col"> + <label>Post as:</label> <div> - {{#if value}} - <div class="settings-file-preview"> - <div class="preview" style="background-image:url({{value}}?_dc={{random}});"></div> - <div class="action"> - <button type="button" class="button red delete-asset"><i class="icon-trash"></i>{{_ 'Delete'}}</button> - </div> - </div> + {{#if data.username}} + <input type="text" name="username" value="{{data.username}}" disabled="disabled" /> {{else}} - <div class="settings-file-preview"> - <div class="preview no-file"><i class="icon-upload"></i></div> - <div class="action"> - <div class="button primary">{{_ 'Select_file'}} - <input type="file" accept="{{fileConstraints.contentType}}" /> - </div> - </div> - </div> + <input type="text" name="username" value="{{data.username}}" /> {{/if}} - <div class="settings-description">Change the icon that is used for messages from this integration.</div> + <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> + {{#if data.token}} + <div class="input-line double-col"> + <label>Webhook URL</label> + <div> + <input type="text" name="token" value="{{data.url}}" disabled="disabled" /> + <div class="settings-description">Send your JSON payloads to this URL. <a href="#" class="clipboard" data-clipboard-target="[name=token]">COPY TO CLIPBOARD</a></div> + </div> </div> - </div> --> + {{/if}} </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> diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index 588673a00a6..ae298211d72 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -33,36 +33,23 @@ Package.onUse(function(api) { api.addAssets('client/stylesheets/integrations.less', 'server'); api.addFiles('client/stylesheets/load.coffee', 'server'); - // api.addFiles('server/models/Permissions.coffee', ['server']); + api.addFiles('server/models/Integrations.coffee', 'server'); - // api.addFiles('server/functions/addUsersToRoles.coffee', ['server']); - // api.addFiles('server/functions/getPermissionsForRole.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']); + // publications + api.addFiles('server/publications/integrations.coffee', 'server'); - // // publications - // api.addFiles('server/publication.coffee', ['server']); - // api.addFiles('server/publications/roles.coffee', 'server'); - // api.addFiles('server/publications/usersInRole.coffee', 'server'); + // methods + api.addFiles('server/methods/addIntegration.coffee', 'server'); + api.addFiles('server/methods/updateIntegration.coffee', 'server'); + api.addFiles('server/methods/deleteIntegration.coffee', 'server'); - // // methods - // api.addFiles('server/methods/addUserToRole.coffee', 'server'); - // api.addFiles('server/methods/deleteRole.coffee', 'server'); - // api.addFiles('server/methods/removeUserFromRole.coffee', 'server'); - // api.addFiles('server/methods/saveRole.coffee', 'server'); - // api.addFiles('server/methods/addPermissionToRole.coffee', 'server'); - // api.addFiles('server/methods/removeRoleFromPermission.coffee', 'server'); - - // api.addFiles('server/startup.coffee', ['server']); + // api + api.addFiles('server/api/api.coffee', 'server'); var _ = Npm.require('underscore'); var fs = Npm.require('fs'); - tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-authorization/i18n'), function(filename) { - if (fs.statSync('packages/rocketchat-authorization/i18n/' + filename).size > 16) { + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-integrations/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-integrations/i18n/' + filename).size > 16) { return 'i18n/' + filename; } })); diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee new file mode 100644 index 00000000000..ae296cdb2e9 --- /dev/null +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -0,0 +1,78 @@ +Api = new Restivus + enableCors: false + apiPath: 'hooks/' + auth: + user: -> + user = RocketChat.models.Users.findOne + _id: @request.params.userId + 'services.resume.loginTokens.hashedToken': @request.params.token + + return user: user + + +Api.addRoute ':integrationId/:userId/:token', authRequired: true, + post: -> + 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 = + msg: @bodyParams.text + + RocketChat.sendMessage user, message, room, {} + + return {} = + statusCode: 200 + body: + success: true diff --git a/packages/rocketchat-integrations/server/methods/addIntegration.coffee b/packages/rocketchat-integrations/server/methods/addIntegration.coffee new file mode 100644 index 00000000000..8be0557dd5e --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/addIntegration.coffee @@ -0,0 +1,57 @@ +Meteor.methods + addIntegration: (integration) -> + if not _.isString(integration.channel) + throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel must be string' + + if integration.channel.trim() is '' + throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel can\'t be empty' + + if integration.channel[0] not in ['@', '#'] + throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel should start with # or @' + + if not _.isString(integration.username) + throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username must be string' + + if integration.username.trim() is '' + throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username can\'t be empty' + + record = undefined + switch integration.channel[0] + when '#' + record = RocketChat.models.Rooms.findOne + $or: [ + {_id: integration.channel} + {name: integration.channel} + ] + when '@' + record = RocketChat.models.Users.findOne + $or: [ + {_id: integration.channel} + {username: integration.channel} + ] + + if record is undefined + throw new Meteor.Error 'channel_does_not_exists', "[methods] addIntegration -> 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" + + stampedToken = Accounts._generateStampedLoginToken() + hashStampedToken = Accounts._hashStampedToken(stampedToken) + + updateObj = + $push: + 'services.resume.loginTokens': + hashedToken: hashStampedToken.hashedToken + integration: true + + integration.token = hashStampedToken.hashedToken + integration.userId = user._id + + RocketChat.models.Users.update {_id: user._id}, updateObj + + RocketChat.models.Integrations.insert integration + + return integration diff --git a/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee b/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee new file mode 100644 index 00000000000..e257b8e903c --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee @@ -0,0 +1,8 @@ +Meteor.methods + deleteIntegration: (integrationId) -> + if not RocketChat.models.Integrations.findOne(integrationId)? + throw new Meteor.Error 'invalid_integration', '[methods] addIntegration -> integration not found' + + RocketChat.models.Integrations.remove _id: integrationId + + return true diff --git a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee new file mode 100644 index 00000000000..5bfa786dd04 --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee @@ -0,0 +1,38 @@ +Meteor.methods + updateIntegration: (integrationId, integration) -> + if not _.isString(integration.channel) + throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel must be string' + + if integration.channel.trim() is '' + throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel can\'t be empty' + + if integration.channel[0] not in ['@', '#'] + throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel should start with # or @' + + if not RocketChat.models.Integrations.findOne(integrationId)? + throw new Meteor.Error 'invalid_integration', '[methods] addIntegration -> integration not found' + + record = undefined + switch integration.channel[0] + when '#' + record = RocketChat.models.Rooms.findOne + $or: [ + {_id: integration.channel} + {name: integration.channel} + ] + when '@' + record = RocketChat.models.Users.findOne + $or: [ + {_id: integration.channel} + {username: integration.channel} + ] + + if record is undefined + throw new Meteor.Error 'channel_does_not_exists', "[methods] addIntegration -> The channel does not exists" + + RocketChat.models.Integrations.update integrationId, + $set: + name: integration.name + channel: integration.channel + + return RocketChat.models.Integrations.findOne(integrationId) diff --git a/packages/rocketchat-integrations/server/models/Integrations.coffee b/packages/rocketchat-integrations/server/models/Integrations.coffee new file mode 100644 index 00000000000..8ca464e07ce --- /dev/null +++ b/packages/rocketchat-integrations/server/models/Integrations.coffee @@ -0,0 +1,13 @@ +RocketChat.models.Integrations = new class extends RocketChat.models._Base + constructor: -> + @_initModel 'integrations' + + + # FIND + # findByRole: (role, options) -> + # query = + # roles: role + + # return @find query, options + + # CREATE diff --git a/packages/rocketchat-integrations/server/publications/integrations.coffee b/packages/rocketchat-integrations/server/publications/integrations.coffee new file mode 100644 index 00000000000..1d958bd2922 --- /dev/null +++ b/packages/rocketchat-integrations/server/publications/integrations.coffee @@ -0,0 +1,8 @@ +Meteor.publish 'integrations', -> + unless @userId + return @ready() + + if not RocketChat.authz.hasPermission @userId, 'manage-integrations' + throw new Meteor.Error "not-authorized" + + return RocketChat.models.Integrations.find() -- GitLab From 63d939f3106ddf2664909192a046902666c658f6 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 22:04:04 -0200 Subject: [PATCH 0763/1338] Fix some errors and add permissions --- .../client/route.coffee | 2 +- .../client/views/integrations.html | 4 ++- .../client/views/integrationsIncoming.coffee | 32 +++++++++++-------- .../client/views/integrationsIncoming.html | 4 +-- .../server/methods/addIntegration.coffee | 18 +++++++---- .../server/methods/deleteIntegration.coffee | 15 ++++++++- .../server/methods/updateIntegration.coffee | 16 +++++++--- 7 files changed, 61 insertions(+), 30 deletions(-) diff --git a/packages/rocketchat-integrations/client/route.coffee b/packages/rocketchat-integrations/client/route.coffee index 62d2b85b1d1..4a87624ca34 100644 --- a/packages/rocketchat-integrations/client/route.coffee +++ b/packages/rocketchat-integrations/client/route.coffee @@ -16,7 +16,7 @@ FlowRouter.route '/admin/integrations/new', pageTemplate: 'integrationsNew' -FlowRouter.route '/admin/integrations/incoming/:token?', +FlowRouter.route '/admin/integrations/incoming/:id?', name: 'admin-integrations-incoming' action: (params) -> BlazeLayout.render 'main', diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index 88470f77269..8080aa6c9ab 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -7,7 +7,7 @@ <div class="section"> <div class="admin-integrations-new-panel"> {{#each integrations}} - <a href="{{pathFor "admin-integrations-incoming" token=token}}"> + <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"> @@ -21,6 +21,8 @@ <i class="icon-angle-right"></i> </div> </a> + {{else}} + <h1>There is no integrations</h1> {{/each}} </div> </div> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index ef008cc8725..cd2560926b6 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -4,15 +4,15 @@ Template.integrationsIncoming.helpers return RocketChat.authz.hasAllPermission 'manage-integrations' data: -> - params = Template.instance().data.params() + params = Template.instance().data.params?() - if params.token? - data = ChatIntegrations.findOne({token: params.token}) - data.url = Meteor.absoluteUrl("hooks/#{data._id}/#{data.userId}/#{data.token}") - return data + if params?.id? + data = ChatIntegrations.findOne({_id: params.id}) + if data? + data.url = Meteor.absoluteUrl("hooks/#{data._id}/#{data.userId}/#{data.token}") + return data - return {} = - channelType: 'c' + return {} Template.integrationsIncoming.events @@ -30,7 +30,7 @@ Template.integrationsIncoming.events closeOnConfirm: false html: false , -> - Meteor.call "deleteIntegration", params._id, (err, data) -> + Meteor.call "deleteIntegration", params.id, (err, data) -> swal title: t('Deleted') text: t('Your_entry_has_been_deleted') @@ -38,6 +38,8 @@ Template.integrationsIncoming.events timer: 1000 showConfirmButton: false + FlowRouter.go "admin-integrations" + "click .submit > .save": -> name = $('[name=name]').val().trim() channel = $('[name=channel]').val().trim() @@ -53,11 +55,12 @@ Template.integrationsIncoming.events channel: channel name: name if name isnt '' - params = Template.instance().data.params() - if params._id? - Meteor.call "updateIntegration", params._id, integration, (err, data) -> + params = Template.instance().data.params?() + if params?.id? + Meteor.call "updateIntegration", params.id, integration, (err, data) -> if err? - toastr.error TAPi18n.__(err.error) + return toastr.error TAPi18n.__(err.error) + toastr.success TAPi18n.__("Integration_updated") else integration.type = 'webhook-incoming' @@ -65,6 +68,7 @@ Template.integrationsIncoming.events Meteor.call "addIntegration", integration, (err, data) -> if err? - toastr.error TAPi18n.__(err.error) + return toastr.error TAPi18n.__(err.error) + toastr.success TAPi18n.__("Integration_added") - FlowRouter.go "admin-integrations-incoming", {token: data.token} + FlowRouter.go "admin-integrations-incoming", {id: data._id} diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index e8a650585e2..5de35210960 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -1,7 +1,7 @@ <template name="integrationsIncoming"> <div class="permissions-manager"> {{#if hasPermission}} - <a href="{{pathFor "admin-integrations-new"}}"><i class="icon-angle-left"></i> {{_ "Back_to_integrations"}}</a><br><br> + <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"> @@ -21,7 +21,7 @@ </div> </div> <div class="input-line double-col"> - <label>Post as:</label> + <label>Post as</label> <div> {{#if data.username}} <input type="text" name="username" value="{{data.username}}" disabled="disabled" /> diff --git a/packages/rocketchat-integrations/server/methods/addIntegration.coffee b/packages/rocketchat-integrations/server/methods/addIntegration.coffee index 8be0557dd5e..524e7403ba5 100644 --- a/packages/rocketchat-integrations/server/methods/addIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/addIntegration.coffee @@ -1,5 +1,8 @@ Meteor.methods addIntegration: (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' @@ -16,18 +19,21 @@ Meteor.methods throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username can\'t be empty' record = undefined - switch integration.channel[0] + channelType = integration.channel[0] + channel = integration.channel.substr(1) + + switch channelType when '#' record = RocketChat.models.Rooms.findOne $or: [ - {_id: integration.channel} - {name: integration.channel} + {_id: channel} + {name: channel} ] when '@' record = RocketChat.models.Users.findOne $or: [ - {_id: integration.channel} - {username: integration.channel} + {_id: channel} + {username: channel} ] if record is undefined @@ -52,6 +58,6 @@ Meteor.methods RocketChat.models.Users.update {_id: user._id}, updateObj - RocketChat.models.Integrations.insert integration + 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/deleteIntegration.coffee index e257b8e903c..d6f22c27701 100644 --- a/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/deleteIntegration.coffee @@ -1,8 +1,21 @@ Meteor.methods deleteIntegration: (integrationId) -> - if not RocketChat.models.Integrations.findOne(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' + updateObj = + $pull: + 'services.resume.loginTokens': + hashedToken: integration.token + integration: true + + RocketChat.models.Users.update {_id: integration.userId}, updateObj + RocketChat.models.Integrations.remove _id: integrationId return true diff --git a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee index 5bfa786dd04..84c7131a463 100644 --- a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee @@ -1,5 +1,8 @@ Meteor.methods updateIntegration: (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' @@ -13,18 +16,21 @@ Meteor.methods throw new Meteor.Error 'invalid_integration', '[methods] addIntegration -> integration not found' record = undefined - switch integration.channel[0] + channelType = integration.channel[0] + channel = integration.channel.substr(1) + + switch channelType when '#' record = RocketChat.models.Rooms.findOne $or: [ - {_id: integration.channel} - {name: integration.channel} + {_id: channel} + {name: channel} ] when '@' record = RocketChat.models.Users.findOne $or: [ - {_id: integration.channel} - {username: integration.channel} + {_id: channel} + {username: channel} ] if record is undefined -- GitLab From 0656ee7225cffbcebdad49839e449e0fd466c691 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 8 Dec 2015 22:20:45 -0200 Subject: [PATCH 0764/1338] Encode url and token --- .../client/views/integrationsIncoming.coffee | 2 +- packages/rocketchat-integrations/server/api/api.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index cd2560926b6..715ffb0ffbb 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -9,7 +9,7 @@ Template.integrationsIncoming.helpers if params?.id? data = ChatIntegrations.findOne({_id: params.id}) if data? - data.url = Meteor.absoluteUrl("hooks/#{data._id}/#{data.userId}/#{data.token}") + data.url = Meteor.absoluteUrl("hooks/#{encodeURIComponent(data._id)}/#{encodeURIComponent(data.userId)}/#{encodeURIComponent(data.token)}") return data return {} diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index ae296cdb2e9..5c058f4b9a2 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -5,7 +5,7 @@ Api = new Restivus user: -> user = RocketChat.models.Users.findOne _id: @request.params.userId - 'services.resume.loginTokens.hashedToken': @request.params.token + 'services.resume.loginTokens.hashedToken': decodeURIComponent @request.params.token return user: user -- GitLab From 743e4826b6a1b74148235ca57e5740d731eba147 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 9 Dec 2015 09:37:33 -0200 Subject: [PATCH 0765/1338] fixes blockquote non-continous border - closes #1605 --- packages/rocketchat-theme/assets/stylesheets/base.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index eaea1acb776..b20cb3b9822 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -76,11 +76,12 @@ blockquote { position: relative; &:before { content: ' '; - height: 100%; width: 4px; position: absolute; + border-radius: 2px; left: 0px; - border-radius: 10px; + top: -1px; + bottom: -1px; } } -- GitLab From 662d63e849defa5324fd618324863a4db006ef1e Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 9 Dec 2015 09:47:07 -0200 Subject: [PATCH 0766/1338] Flex settings --- .../client/views/sideNav/livechatFlex.js | 13 +++++++++++++ packages/rocketchat-livechat/package.js | 1 + 2 files changed, 14 insertions(+) create mode 100644 packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js new file mode 100644 index 00000000000..2fa2ed15adf --- /dev/null +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js @@ -0,0 +1,13 @@ +Template.livechatFlex.events({ + 'mouseenter header' () { + SideNav.overArrow() + }, + + 'mouseleave header' () { + SideNav.leaveArrow() + }, + + 'click header' () { + SideNav.closeFlex() + } +}) diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index c20e87ff79f..882c160f666 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -46,6 +46,7 @@ Package.onUse(function(api) { 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'); // methods api.addFiles('server/methods/addAgent.js', 'server'); -- GitLab From d6299ff184579dc7397a71f154c274289c6caa5c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 10:13:14 -0200 Subject: [PATCH 0767/1338] Move all texts to i18n --- i18n/en.i18n.json | 18 +++++++ .../client/views/integrations.html | 4 +- .../client/views/integrationsIncoming.html | 19 +++---- .../client/views/integrationsNew.html | 54 +++++++++---------- 4 files changed, 57 insertions(+), 38 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index c4407e54e52..0002a15b1c7 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -86,6 +86,7 @@ "Away_female" : "Away", "away_male" : "away", "Away_male" : "Away", + "Back_to_integrations" : "Back to integrations", "Back_to_login" : "Back to login", "bold" : "bold", "busy" : "busy", @@ -101,6 +102,7 @@ "Channels" : "Channels", "Channels_list" : "List of public channels", "Chat_Rooms" : "Chat Rooms", + "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?", "close" : "close", "coming_soon" : "coming soon", @@ -110,6 +112,7 @@ "Contact" : "Contact", "Conversation" : "Conversation", "Convert_Ascii_Emojis" : "Convert ASCII to Emoji", + "COPY_TO_CLIPBOARD" : "COPY TO CLIPBOARD", "Create_new" : "Create new", "Create_new_direct_message_room" : "Create a new direct message room", "Create_new_private_group" : "Create a new private group", @@ -171,6 +174,9 @@ "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_Incoming_WebHook" : "Incoming WebHook Integration", + "Integration_New" : "New Integration", + "Integrations" : "Integrations", "Invalid_asset" : "Invalid asset", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_email" : "The e-mail entered is invalid", @@ -260,6 +266,7 @@ "Message_ShowEditedStatus" : "Show Edited Status", "Message_ShowFormattingTips" : "Show Formatting Tips", "Messages" : "Messages", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here" : "Messages that are sent to the Incoming WebHook will be posted here.", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook App Id", "Meta_google-site-verification" : "Google Site Verification", @@ -301,6 +308,7 @@ "Oops!" : "Oops", "Opt_out_statistics" : "Don't send my statistics to Rocket.Chat", "Opt_out_statistics_warning" : "By sending your statistics, you'll help us identify how many instances of Rocket.Chat are deployed, as well as how good the system is behaving, so we can further improve it. Don't worry, as no user information is sent and all the information we receive is kept confidential. If you want to continue sending us your statistics, uncheck the above checkbox. Thank you.", + "optional" : "optional", "others" : "others", "Password" : "Password", "Password_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of passwords", @@ -310,6 +318,10 @@ "Please_wait" : "Please wait", "Please_wait_activation" : "Please wait, this can take some time.", "Please_wait_statistics" : "Please wait, statistics are being generated.", + "Post_as" : "Post as", + "New_integration" : "New integration", + "Post_to_s_as_s" : "Post to <strong>%s</strong> as <strong>%s</strong>", + "Post_to_Channel" : "Post to Channel", "Powered_by" : "Powered by", "Preferences" : "Preferences", "Preferences_saved" : "Preferences saved", @@ -378,14 +390,17 @@ "Send" : "Send", "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.", "Send_invitation_email" : "Send invitation e-mail", "Send_invitation_email_error" : "You haven't provided any valid e-mail address.", "Send_invitation_email_info" : "You can send multiple e-mail invitations at once.", "Send_invitation_email_success" : "You have successfully sent an invitation e-mail to the following addresses:", "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.", "Settings" : "Settings", "Settings_updated" : "Settings updated", + "Should_exists_a_user_with_this_username" : "Should exists a user with this username.", "Showing_online_users" : "Showing <b>__total_online__</b> of __total__ users", "Showing_results" : "<p>Showing <b>%s</b> results</p>", "Silence" : "Silence", @@ -400,6 +415,7 @@ "SMTP_Username" : "SMTP Username", "Sound" : "Sound", "Start_of_conversation" : "Start of conversation", + "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", "Stats_Avg_Channel_Users" : "Average Channel Users", @@ -431,6 +447,7 @@ "The_configured_URL_is_different_from_the_URL_you_are_accessing" : "The configured URL is different from the URL you are accessing!", "The_field_is_required" : "The field %s is required.", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", + "There_is_no_integrations" : "There is no integrations", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", "Unnamed" : "Unnamed", @@ -485,6 +502,7 @@ "Yes_delete_it" : "Yes, delete it!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", "You_need_confirm_email" : "You need to confirm your email to login!", + "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_Open_Source_solution" : "Your own Open Source chat solution", diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index 8080aa6c9ab..eacfc0c3e85 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -15,14 +15,14 @@ Incoming WebHook {{#if name}}- {{name}}{{/if}} </div> <div class="admin-integrations-new-item-description"> - Post to <strong>{{channel}}</strong> as <strong>{{username}}</strong> + {{{_ "Post_to_s_as_s" channel username}}} </div> </div> <i class="icon-angle-right"></i> </div> </a> {{else}} - <h1>There is no integrations</h1> + <h1>{{_ "There_is_no_integrations"}}</h1> {{/each}} </div> </div> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index 5de35210960..976ad0c97e0 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -6,30 +6,30 @@ <div class="section"> <div class="section-content"> <div class="input-line double-col"> - <label>Name (optional)</label> + <label>{{_ "Name"}} ({{_ "optional"}})</label> <div> <input type="text" name="name" value="{{data.name}}" placeholder="{{_ 'Optional'}}" /> - <div class="settings-description">You can give a name just to manage your integrations.</div> + <div class="settings-description">{{_ "You_should_name_it_to_easily_manage_your_integrations"}}</div> </div> </div> <div class="input-line double-col"> - <label>Post to Channel</label> + <label>{{_ "Post_to_Channel"}}</label> <div> <input type="text" name="channel" value="{{data.channel}}" placeholder="{{_ 'User_or_channel_name'}}" /> - <div class="settings-description">Messages that are sent to the incoming webhook will be posted here.</div> - <div class="settings-description">Start with <code class="inline">@</code> for user or <code class="inline">#</code> for channel. Eg: <code class="inline">@john</code> or <code class="inline">#general</code>.</div> + <div class="settings-description">{{_ "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here"}}</div> + <div class="settings-description">{{{_ "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" "@" "#" "@john" "#general"}}}</div> </div> </div> <div class="input-line double-col"> - <label>Post as</label> + <label>{{_ "Post_as"}}</label> <div> {{#if data.username}} <input type="text" name="username" value="{{data.username}}" disabled="disabled" /> {{else}} <input type="text" name="username" value="{{data.username}}" /> {{/if}} - <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 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> {{#if data.token}} @@ -37,7 +37,8 @@ <label>Webhook URL</label> <div> <input type="text" name="token" value="{{data.url}}" disabled="disabled" /> - <div class="settings-description">Send your JSON payloads to this URL. <a href="#" class="clipboard" data-clipboard-target="[name=token]">COPY TO CLIPBOARD</a></div> + <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> </div> {{/if}} diff --git a/packages/rocketchat-integrations/client/views/integrationsNew.html b/packages/rocketchat-integrations/client/views/integrationsNew.html index 5f256aa12f0..496cf5112bb 100644 --- a/packages/rocketchat-integrations/client/views/integrationsNew.html +++ b/packages/rocketchat-integrations/client/views/integrationsNew.html @@ -5,36 +5,36 @@ <div class="rocket-form"> <div class="section"> - <div class="admin-integrations-new-panel"> - <a href="{{pathFor "admin-integrations-incoming"}}"> - <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 + <div class="admin-integrations-new-panel"> + <a href="{{pathFor "admin-integrations-incoming"}}"> + <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 + </div> + <div class="admin-integrations-new-item-description"> + {{_ "Send_data_into_RocketChat_in_realtime"}} + </div> + </div> + <i class="icon-angle-right"></i> </div> - <div class="admin-integrations-new-item-description"> - Send data into Rocket.Chat in real-time. + </a> + <!-- <a href="{{pathFor "admin-integrations-incoming"}}"> + <div class="admin-integrations-new-item"> + <i class="icon-logout"></i> + <div class="admin-integrations-new-item-body"> + <div class="admin-integrations-new-item-title"> + Outgoing WebHook + </div> + <div class="admin-integrations-new-item-description"> + Get data out of Rocket.Chat in real-time. + </div> + </div> + <i class="icon-angle-right"></i> </div> - </div> - <i class="icon-angle-right"></i> + </a> --> </div> - </a> - <a href="{{pathFor "admin-integrations-incoming"}}"> - <div class="admin-integrations-new-item"> - <i class="icon-logout"></i> - <div class="admin-integrations-new-item-body"> - <div class="admin-integrations-new-item-title"> - Outgoing WebHook - </div> - <div class="admin-integrations-new-item-description"> - Get data out of Rocket.Chat in real-time. - </div> - </div> - <i class="icon-angle-right"></i> - </div> - </a> - </div> </div> </div> {{else}} -- GitLab From b64ed385b1967c021570f751a9c1c520519464a1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 10:47:56 -0200 Subject: [PATCH 0768/1338] Integrations: Add information about created and updated --- i18n/en.i18n.json | 1 + .../rocketchat-integrations/client/views/integrations.coffee | 3 +++ .../rocketchat-integrations/client/views/integrations.html | 3 +++ .../server/methods/addIntegration.coffee | 2 ++ .../server/methods/updateIntegration.coffee | 2 ++ 5 files changed, 11 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 0002a15b1c7..cce5862b7ef 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -321,6 +321,7 @@ "Post_as" : "Post as", "New_integration" : "New integration", "Post_to_s_as_s" : "Post to <strong>%s</strong> as <strong>%s</strong>", + "Created_at_s_by_s" : "Created at <strong>%s</strong> by <strong>%s</strong>", "Post_to_Channel" : "Post to Channel", "Powered_by" : "Powered by", "Preferences" : "Preferences", diff --git a/packages/rocketchat-integrations/client/views/integrations.coffee b/packages/rocketchat-integrations/client/views/integrations.coffee index 1bab31e4dfa..bd869cc421c 100644 --- a/packages/rocketchat-integrations/client/views/integrations.coffee +++ b/packages/rocketchat-integrations/client/views/integrations.coffee @@ -4,3 +4,6 @@ Template.integrations.helpers integrations: -> return ChatIntegrations.find() + + dateFormated: (date) -> + return moment(date).format('L LT') diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index eacfc0c3e85..d1075af7756 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -17,6 +17,9 @@ <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> diff --git a/packages/rocketchat-integrations/server/methods/addIntegration.coffee b/packages/rocketchat-integrations/server/methods/addIntegration.coffee index 524e7403ba5..454b87d6bd2 100644 --- a/packages/rocketchat-integrations/server/methods/addIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/addIntegration.coffee @@ -55,6 +55,8 @@ Meteor.methods integration.token = hashStampedToken.hashedToken integration.userId = user._id + integration._createdAt = new Date + integration._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}} RocketChat.models.Users.update {_id: user._id}, updateObj diff --git a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee index 84c7131a463..272348dcbe0 100644 --- a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee @@ -40,5 +40,7 @@ Meteor.methods $set: name: integration.name channel: integration.channel + _updatedAt: new Date + _updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}} return RocketChat.models.Integrations.findOne(integrationId) -- GitLab From 04ef6f825123ead5e387e03c26ed01200f73f7c0 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 9 Dec 2015 11:20:45 -0200 Subject: [PATCH 0769/1338] Error message when file upload media type it not accepted --- i18n/en.i18n.json | 1 + packages/rocketchat-ui-message/message/messageBox.coffee | 5 ++++- packages/rocketchat-ui/lib/fileUpload.coffee | 7 ++++++- packages/rocketchat-ui/views/app/room.coffee | 3 --- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index c4407e54e52..1014267948e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -151,6 +151,7 @@ "FileUpload_Enabled" : "File Uploads Enabled", "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", + "FileUpload_MediaType_NotAccepted" : "Media Types Not Accepted", "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", diff --git a/packages/rocketchat-ui-message/message/messageBox.coffee b/packages/rocketchat-ui-message/message/messageBox.coffee index 815aca534b8..dd9ae3c8d74 100644 --- a/packages/rocketchat-ui-message/message/messageBox.coffee +++ b/packages/rocketchat-ui-message/message/messageBox.coffee @@ -50,6 +50,9 @@ Template.messageBox.helpers selfTyping: MsgTyping.selfTyping.get() users: usernames.join " #{t 'and'} " } + fileUploadAllowedMediaTypes: -> + return RocketChat.settings.get('FileUpload_MediaTypeWhiteList') + Template.messageBox.events 'click .join': (event) -> @@ -132,4 +135,4 @@ Template.messageBox.events Template.messageBox.onRendered -> # unless window.chatMessages[Session.get('openedRoom')] # window.chatMessages[Session.get('openedRoom')] = new ChatMessages - # this.chatMessages.init(this.firstNode) \ No newline at end of file + # this.chatMessages.init(this.firstNode) diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index 1cfba202797..48db0ca7dbe 100644 --- a/packages/rocketchat-ui/lib/fileUpload.coffee +++ b/packages/rocketchat-ui/lib/fileUpload.coffee @@ -24,7 +24,12 @@ readAsArrayBuffer = (file, callback) -> return readAsDataURL file.file, (fileContent) -> - return unless fileUploadIsValidContentType file.file.type + if not fileUploadIsValidContentType file.file.type + swal + title: t('FileUpload_MediaType_NotAccepted') + type: 'error' + timer: 1000 + return text = '' diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index e1fe97dec71..4feda75c807 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -210,9 +210,6 @@ Template.room.helpers compactView: -> return 'compact' if Meteor.user()?.settings?.preferences?.compactView - fileUploadAllowedMediaTypes: -> - return RocketChat.settings.get('FileUpload_MediaTypeWhiteList') - Template.room.events "click, touchend": (e, t) -> -- GitLab From 2be525bb91d5c0e7c5b166e6fc502a8201da9e02 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 9 Dec 2015 11:21:40 -0200 Subject: [PATCH 0770/1338] Add query operator for mailer --- .../rocketchat-mailer/client/router.coffee | 2 +- .../client/views/mailer.coffee | 3 ++- .../client/views/mailer.html | 25 +++++++++++++------ packages/rocketchat-mailer/i18n/en.i18n.json | 2 ++ .../server/functions/sendMail.coffee | 6 ++++- .../server/methods/sendMail.coffee | 6 ++--- .../server/methods/unsubscribe.coffee | 4 +-- .../server/models/Users.coffee | 2 +- 8 files changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/rocketchat-mailer/client/router.coffee b/packages/rocketchat-mailer/client/router.coffee index 3bbadf4e5f0..5205c1f2a69 100644 --- a/packages/rocketchat-mailer/client/router.coffee +++ b/packages/rocketchat-mailer/client/router.coffee @@ -11,5 +11,5 @@ FlowRouter.route '/mailer', FlowRouter.route '/mailer/unsubscribe/:_id/:createdAt', name: 'mailer-unsubscribe' action: (params) -> - Meteor.call 'Mailer.unsubscribe', params._id, params.createdAt + Meteor.call 'Mailer:unsubscribe', params._id, params.createdAt BlazeLayout.render 'mailerUnsubscribe' diff --git a/packages/rocketchat-mailer/client/views/mailer.coffee b/packages/rocketchat-mailer/client/views/mailer.coffee index c8000bb5d15..e4240317620 100644 --- a/packages/rocketchat-mailer/client/views/mailer.coffee +++ b/packages/rocketchat-mailer/client/views/mailer.coffee @@ -9,6 +9,7 @@ Template.mailer.events subject = $(t.find('[name=subject]')).val() body = $(t.find('[name=body]')).val() dryrun = $(t.find('[name=dryrun]:checked')).val() + query = $(t.find('[name=query]')).val() unless from toastr.error TAPi18n.__('From_email_is_required') @@ -18,6 +19,6 @@ Template.mailer.events toastr.error TAPi18n.__('You_must_provide_the_unsubscribe_link') return - Meteor.call 'Mailer.sendMail', from, subject, body, dryrun, (err) -> + Meteor.call 'Mailer.sendMail', from, subject, body, dryrun, query, (err) -> return toastr.error err.reason if err toastr.success TAPi18n.__('The_emails_are_being_sent') diff --git a/packages/rocketchat-mailer/client/views/mailer.html b/packages/rocketchat-mailer/client/views/mailer.html index ea0f0c454c4..43f609e117c 100644 --- a/packages/rocketchat-mailer/client/views/mailer.html +++ b/packages/rocketchat-mailer/client/views/mailer.html @@ -23,27 +23,36 @@ </div> </div> <div class="input-line"> - <label>{{_ "Email_subject"}}</label> + <label>{{_ "Dry_run"}}</label> <div> - <input type="text" name="subject" value="" /> + <input type="checkbox" name="dryrun" value="1" /> + </div> + <div> + <small class="settings-description">{{{_ "Dry_run_description"}}}</small> </div> </div> <div class="input-line"> - <label>{{_ "Email_body"}}</label> + <label>{{_ "Query"}}</label> <div> - <textarea name="body" rows="10" style="height: auto"></textarea> + <input type="text" name="query" value="" /> </div> <div> - <small class="settings-description">{{{_ "Mailer_body_tags"}}}</small> + <small class="settings-description">{{{_ "Query_description"}}}</small> </div> </div> <div class="input-line"> - <label>{{_ "Dry_run"}}</label> + <label>{{_ "Email_subject"}}</label> <div> - <input type="checkbox" name="dryrun" value="1" /> + <input type="text" name="subject" value="" /> </div> + </div> + <div class="input-line"> + <label>{{_ "Email_body"}}</label> <div> - <small class="settings-description">{{{_ "Dry_run_description"}}}</small> + <textarea name="body" rows="10" style="height: auto"></textarea> + </div> + <div> + <small class="settings-description">{{{_ "Mailer_body_tags"}}}</small> </div> </div> </fieldset> diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index e2a997a0964..30fccf32896 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -8,6 +8,8 @@ "Email_body" : "E-mail body", "Mailer" : "Mailer", "Mailer_body_tags" : "You <b>must</b> use [unsubscribe] for the unsubscription link.<br />You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Query" : "Query", + "Query_description" : "Additional conditions for determining which users to send the e-mail to. Unsubscribed users are automatically removed from the query. It must be a valid JSON. Example: \"{\"createdAt\":{\"$gt\":{\"$date\": \"2015-01-01T00:00:00.000Z\"}}}\"", "Send_email" : "Send E-mail", "The_emails_are_being_sent" : "The e-mails are being sent.", "You_are_not_authorized_to_view_this_page" : "You are not authorized to view this page.", diff --git a/packages/rocketchat-mailer/server/functions/sendMail.coffee b/packages/rocketchat-mailer/server/functions/sendMail.coffee index 2e1292112da..123562b0dbb 100644 --- a/packages/rocketchat-mailer/server/functions/sendMail.coffee +++ b/packages/rocketchat-mailer/server/functions/sendMail.coffee @@ -1,4 +1,4 @@ -Mailer.sendMail = (from, subject, body, dryrun) -> +Mailer.sendMail = (from, subject, body, dryrun, query) -> 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])?)*)(?:>?)$/ # rfcMailPattern = /^[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])?)*$/ @@ -9,6 +9,10 @@ Mailer.sendMail = (from, subject, body, dryrun) -> if body.indexOf('[unsubscribe]') is -1 throw new Meteor.Error 'missing-unsubscribe-link', TAPi18n.__('You_must_provide_the_unsubscribe_link') + userQuery = { "mailer.unsubscribed": { $exists: 0 } } + if query + userQuery = { $and: [ userQuery, EJSON.parse(query) ] } + if dryrun Meteor.users.find({ "emails.address": from }).forEach (user) -> # Meteor.users.find({ "username": /\.rocket\.team/ }).forEach (user) -> diff --git a/packages/rocketchat-mailer/server/methods/sendMail.coffee b/packages/rocketchat-mailer/server/methods/sendMail.coffee index f71b8eb299d..a4b7fd4194b 100644 --- a/packages/rocketchat-mailer/server/methods/sendMail.coffee +++ b/packages/rocketchat-mailer/server/methods/sendMail.coffee @@ -1,9 +1,9 @@ Meteor.methods - 'Mailer.sendMail': (from, subject, body, dryrun) -> + 'Mailer.sendMail': (from, subject, body, dryrun, query) -> - console.log '[method] Mailer.sendMail', from, subject, body, dryrun + console.log '[method] Mailer.sendMail', from, subject, body, dryrun, query - return Mailer.sendMail from, subject, body, dryrun + return Mailer.sendMail from, subject, body, dryrun, query # Limit setting username once per minute # DDPRateLimiter.addRule diff --git a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee index 8df56684548..88e5d7a1494 100644 --- a/packages/rocketchat-mailer/server/methods/unsubscribe.coffee +++ b/packages/rocketchat-mailer/server/methods/unsubscribe.coffee @@ -1,10 +1,10 @@ Meteor.methods - 'Mailer.unsubscribe': (_id, createdAt) -> + 'Mailer:unsubscribe': (_id, createdAt) -> return Mailer.unsubscribe _id, createdAt # Limit setting username once per minute DDPRateLimiter.addRule type: 'method' - name: 'Mailer.unsubscribe' + name: 'Mailer:unsubscribe' connectionId: -> return true , 1, 60000 diff --git a/packages/rocketchat-mailer/server/models/Users.coffee b/packages/rocketchat-mailer/server/models/Users.coffee index 0ef727a8a74..7622b890d48 100644 --- a/packages/rocketchat-mailer/server/models/Users.coffee +++ b/packages/rocketchat-mailer/server/models/Users.coffee @@ -12,6 +12,6 @@ RocketChat.models.Users.RocketMailUnsubscribe = (_id, createdAt) -> affectedRows = @update query, update - console.log '[Mailer.Unsubscribe]', _id, createdAt, new Date(parseInt createdAt), affectedRows + console.log '[Mailer:Unsubscribe]', _id, createdAt, new Date(parseInt createdAt), affectedRows return affectedRows -- GitLab From 5d5beb6da06d3470c124a6f797ff0208de494bdc Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 9 Dec 2015 12:59:23 -0200 Subject: [PATCH 0771/1338] Merge --- packages/rocketchat-ui/package.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index af4028150c0..b5b3a7e0853 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -55,7 +55,6 @@ 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'); // LIB CORDOVA api.addFiles('lib/cordova/facebook-login.coffee', 'client'); -- GitLab From 2797c333e62601308232a923351d300b72fe2bcd Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Wed, 9 Dec 2015 11:22:23 -0500 Subject: [PATCH 0772/1338] Add some missing vlaues Added UTF8_Names_Validation and UTF8_Names_Slugify --- i18n/en.i18n.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1014267948e..bd506ef799f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -474,6 +474,8 @@ "Username_title" : "Register username", "Username_unavaliable" : "<strong>%s</strong> is already in use :(", "Users" : "Users", + "UTF8_Names_Slugify" : "UTF8 Names Slugify", + "UTF8_Names_Validation" : "UTF8 Names Validation", "View_All" : "View All", "Wait_activation_warning" : "Before you can login, your account must be manually activated by an administrator.", "We_have_sent_password_email" : "We have sent you an e-mail with password reset instructions. If you do not receive an e-mail shortly, please come back and try again.", -- GitLab From ce4219ebb5bc26837cdf9ee099a8b452658d2f97 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Wed, 9 Dec 2015 11:43:15 -0500 Subject: [PATCH 0773/1338] Force file names to always be in LTR In RTL interface if the file name has only number, or included RTL characters the file extension will be shown in the wrong side. This fix makes file extensions show correctly for all files --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 0380d0d2775..f81703f69b1 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -576,6 +576,9 @@ } } &.uploaded-files-list { + a { + direction: ltr; + } i { float: right; .margin-left(10px); -- GitLab From 506bdeacf912749bf433fbf3eb015641cbba7826 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Wed, 9 Dec 2015 13:20:37 -0500 Subject: [PATCH 0774/1338] When uploading an avatar keep "Select file" button Currently when you upload an image as an avatar, the "SELECT FILE" button disappears and you get another button to use the uploaded file. However, if you didn't like how the uploaded image looks you cannot upload another one. The work around is to reopen the avatar settings page, instead the upload button should stay there to allow the user to upload a different image. --- packages/rocketchat-ui-account/account/avatar/prompt.html | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-ui-account/account/avatar/prompt.html b/packages/rocketchat-ui-account/account/avatar/prompt.html index 86ccb8b6d8c..a3291b8c72d 100644 --- a/packages/rocketchat-ui-account/account/avatar/prompt.html +++ b/packages/rocketchat-ui-account/account/avatar/prompt.html @@ -48,14 +48,12 @@ <div style="background-image: url({{upload.blob}});" class="avatar {{#unless upload}}question-mark icon-upload{{/unless}}"> </div> <div class="action"> + <div class="button primary">{{_ "Select_file"}} + <input type="file" class="avatar-file-input" accept="image/*"> + </div> {{#with upload}} <button type="button" class="button primary select-service">{{_ "Use_uploaded_avatar"}}</button> {{/with}} - {{#unless upload}} - <div class="button primary">{{_ "Select_file"}} - <input type="file" class="avatar-file-input" accept="image/*"> - </div> - {{/unless}} </div> </div> <div class="avatar-suggestion-item"> -- GitLab From c57f16bf403df457e4d0f393fc628d834e1db207 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 16:38:50 -0200 Subject: [PATCH 0775/1338] Integrations: allow execute hooks with payload format --- packages/rocketchat-integrations/server/api/api.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 5c058f4b9a2..eb688423213 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -12,6 +12,9 @@ Api = new Restivus Api.addRoute ':integrationId/:userId/:token', authRequired: true, post: -> + if @bodyParams?.payload? + @bodyParams = JSON.parse @bodyParams.payload + integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) user = RocketChat.models.Users.findOne(@userId) -- GitLab From 08277259cd50ef46267ba313f680fef423d6f312 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 16:39:08 -0200 Subject: [PATCH 0776/1338] Integrations: Allow pass attachments --- packages/rocketchat-integrations/server/api/api.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index eb688423213..e0c7e944d01 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -71,7 +71,9 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, error: 'invalid-channel-type' message = - msg: @bodyParams.text + msg: @bodyParams.text or '' + attachments: @bodyParams.attachments + parseUrls: false RocketChat.sendMessage user, message, room, {} -- GitLab From b68a8f62658cb7f3dba2b1b6e8f929ee2ac49ef3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 16:39:33 -0200 Subject: [PATCH 0777/1338] Prevent parse message urls if option parseUrls is false in message --- packages/rocketchat-lib/server/functions/sendMessage.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index ed0159147b0..4113c918d02 100644 --- a/packages/rocketchat-lib/server/functions/sendMessage.coffee +++ b/packages/rocketchat-lib/server/functions/sendMessage.coffee @@ -10,8 +10,9 @@ RocketChat.sendMessage = (user, message, room, options) -> message.rid = room._id - if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g - message.urls = urls.map (url) -> url: url + if not message.parseUrls is false + if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g + message.urls = urls.map (url) -> url: url message = RocketChat.callbacks.run 'beforeSaveMessage', message -- GitLab From 5a6f99abd573b4cc01d47c0071b26e562fbf1b3c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 16:40:01 -0200 Subject: [PATCH 0778/1338] Allow use Markdown to render a single stringn and register a helper RocketChatMarkdown --- packages/rocketchat-markdown/markdown.coffee | 67 ++++++++++++-------- packages/rocketchat-markdown/package.js | 1 + 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index 78c06832cfb..c578fec7160 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -5,51 +5,64 @@ class Markdown constructor: (message) -> + msg = message - if _.trim message.html + if not _.isString message + if _.trim message.html + msg = message.html + else + return message - msg = message.html + # 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>') - # 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>') + # Support [Text](http://link) + msg = msg.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/gm, '<a href="$2" target="_blank">$1</a>') - # Support [Text](http://link) - msg = msg.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/gm, '<a href="$2" target="_blank">$1</a>') + # Support <http://link|Text> + msg = msg.replace(/(?:<|<)(https?:\/\/[^\|]+)\|(.+?)(?=>|>)(?:>|>)/gm, '<a href="$1" target="_blank">$2</a>') - if RocketChat.settings.get('Markdown_Headers') - # Support # Text for h1 - msg = msg.replace(/^# (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h1>$1</h1>') + if RocketChat.settings.get('Markdown_Headers') + # Support # Text for h1 + msg = msg.replace(/^# (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h1>$1</h1>') - # Support # Text for h2 - msg = msg.replace(/^## (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h2>$1</h2>') + # Support # Text for h2 + msg = msg.replace(/^## (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h2>$1</h2>') - # Support # Text for h3 - msg = msg.replace(/^### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h3>$1</h4>') + # Support # Text for h3 + msg = msg.replace(/^### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h3>$1</h4>') - # Support # Text for h4 - msg = msg.replace(/^#### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h4>$1</h4>') + # 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` + 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') + # 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') - # Support _text_ to make italics - msg = msg.replace(/(^|>|[ >*~`])\_([^\_\r\n]+)\_([<*~`]|\B|\b|$)/gm, '$1<span class="copyonly">_</span><em>$2</em><span class="copyonly">_</span>$3') + # Support _text_ to make italics + msg = msg.replace(/(^|>|[ >*~`])\_([^\_\r\n]+)\_([<*~`]|\B|\b|$)/gm, '$1<span class="copyonly">_</span><em>$2</em><span class="copyonly">_</span>$3') - # Support ~text~ to strike through text - msg = msg.replace(/(^|>|[ >_*`])\~{1,2}([^~\r\n]+)\~{1,2}([<_*`]|\B|\b|$)/gm, '$1<span class="copyonly">~</span><strike>$2</strike><span class="copyonly">~</span>$3') + # Support ~text~ to strike through text + msg = msg.replace(/(^|>|[ >_*`])\~{1,2}([^~\r\n]+)\~{1,2}([<_*`]|\B|\b|$)/gm, '$1<span class="copyonly">~</span><strike>$2</strike><span class="copyonly">~</span>$3') - # Support >Text for quote - msg = msg.replace(/^>(.*)$/gm, '<blockquote><span class="copyonly">></span>$1</blockquote>') - msg = msg.replace(/<\/blockquote>\n<blockquote>/gm, '</blockquote><blockquote>') + # Support >Text for quote + msg = msg.replace(/^>(.*)$/gm, '<blockquote><span class="copyonly">></span>$1</blockquote>') + msg = msg.replace(/<\/blockquote>\n<blockquote>/gm, '</blockquote><blockquote>') + if not _.isString message message.html = msg + else + message = msg - console.log 'Markdown', message if window?.rocketDebug + console.log 'Markdown', message if window?.rocketDebug return message RocketChat.callbacks.add 'renderMessage', Markdown, RocketChat.callbacks.priority.HIGH RocketChat.Markdown = Markdown + +if Meteor.isClient + Blaze.registerHelper 'RocketChatMarkdown', (text) -> + return RocketChat.Markdown text diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index 69740c6cd82..aca6f0d8415 100644 --- a/packages/rocketchat-markdown/package.js +++ b/packages/rocketchat-markdown/package.js @@ -10,6 +10,7 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); + api.use('templating'); api.use('underscorestring:underscore.string'); api.use('rocketchat:lib@0.0.1'); -- GitLab From 441ae0b552340b45548b416dcbf29536ac925749 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 16:43:45 -0200 Subject: [PATCH 0779/1338] Implement package for message attachments --- .meteor/packages | 1 + .meteor/versions | 1 + .../client/messageAttachment.html | 82 ++++++++++++++++ .../client/stylesheets/loader.coffee | 2 + .../stylesheets/messageAttachments.less | 94 +++++++++++++++++++ .../rocketchat-message-attachments/package.js | 27 ++++++ .../message/message.html | 3 + 7 files changed, 210 insertions(+) create mode 100644 packages/rocketchat-message-attachments/client/messageAttachment.html create mode 100644 packages/rocketchat-message-attachments/client/stylesheets/loader.coffee create mode 100644 packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less create mode 100644 packages/rocketchat-message-attachments/package.js diff --git a/.meteor/packages b/.meteor/packages index 551eb7d6b64..b48661e4c0d 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -126,3 +126,4 @@ yasinuslu:blaze-meta # velocity:html-reporter rocketchat:assets rocketchat:integrations +rocketchat:message-attachments diff --git a/.meteor/versions b/.meteor/versions index 5f1ffd866a4..a27fecd55b0 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -143,6 +143,7 @@ rocketchat:mailer@0.0.1 rocketchat:markdown@0.0.1 rocketchat:me@0.0.1 rocketchat:mentions@0.0.1 +rocketchat:message-attachments@0.0.1 rocketchat:message-pin@0.0.1 rocketchat:message-star@0.0.1 rocketchat:oembed@0.0.1 diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html new file mode 100644 index 00000000000..b1d35b412dc --- /dev/null +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -0,0 +1,82 @@ +<template name="messageAttachment"> + <div class="attachment"> + <!-- <div>fallback: {{fallback}}</div> --> + {{pretext}} + <div class="attachment-block"> + <div class="attachment-block-border" style="background-color: {{color}}"></div> + + <div class="attachment-flex {{#if thumb_url}}attachment-small-content{{/if}}"> + <div class="attachment-flex-column-grow"> + {{#if author_name}} + {{#if author_link}} + <div class="attachment-author"> + {{#if author_icon}} + <img src="{{author_icon}}"> + {{/if}} + <a href="{{author_link}}" target="_blank">{{author_name}}</a> + </div> + {{else}} + <div class="attachment-author"> + {{#if author_icon}} + <img src="{{author_icon}}"> + {{/if}} + {{author_name}} + </div> + {{/if}} + {{/if}} + + {{#if title}} + {{#if title_link}} + <div class="attachment-title"><a href="{{title_link}}" target="_blank">{{title}}</a></div> + {{else}} + <div class="attachment-title">{{title}}</div> + {{/if}} + {{/if}} + + {{#if text}} + <div class="attachment-text"> + {{{RocketChatMarkdown text}}} + </div> + {{/if}} + </div> + + {{#if thumb_url}} + <div class="attachment-thumb"> + <img src="{{thumb_url}}"> + </div> + {{/if}} + </div> + + {{#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}}"> + </div> + </a> + </div> + {{/if}} + + {{#if fields}} + <div class="attachment-fields"> + {{#each fields}} + {{#unless short}} + <div class="attachment-field"> + <div class="attachment-field-title">{{title}}</div> + {{value}} + </div> + {{/unless}} + {{/each}} + {{#each fields}} + {{#if short}} + <div class="attachment-field attachment-field-short"> + <div class="attachment-field-title">{{title}}</div> + {{value}} + </div> + {{/if}} + {{/each}} + </div> + {{/if}} + </div> + </div> +</template> diff --git a/packages/rocketchat-message-attachments/client/stylesheets/loader.coffee b/packages/rocketchat-message-attachments/client/stylesheets/loader.coffee new file mode 100644 index 00000000000..767a5689253 --- /dev/null +++ b/packages/rocketchat-message-attachments/client/stylesheets/loader.coffee @@ -0,0 +1,2 @@ +RocketChat.theme.addPackageAsset -> + return Assets.getText 'client/stylesheets/messageAttachments.less' diff --git a/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less b/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less new file mode 100644 index 00000000000..848a927ce1d --- /dev/null +++ b/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less @@ -0,0 +1,94 @@ +.attachment { + .attachment-block { + padding-left: 15px; + margin: 5px 0; + position: relative; + + .attachment-block-border { + width: 4px; + position: absolute; + border-radius: 8px; + left: 0; + top: 0; + bottom: 0; + background-color: #ccc; + } + } + + .attachment-author { + font-size: 0.95rem; + font-weight: 600; + line-height: 1.2rem; + + > a { + font-weight: 600; + color: #444; + } + + img { + max-height: 16px; + margin-right: 2px; + margin-bottom: -2px; + } + } + + .attachment-title { + font-size: 1.02rem; + font-weight: 500; + line-height: 1.5rem; + + > a { + font-weight: 500; + } + } + + .attachment-text { + line-height: 1rem; + padding: 3px 0; + } + + .attachment-image { + margin-top: 4px; + } + + .attachment-fields { + margin-top: 4px; + + .attachment-field { + &.attachment-field-short { + width: 48%; + display: inline-block; + } + + .attachment-field-title { + font-weight: 600; + line-height: 1rem; + } + } + } + + .attachment-field ~ .attachment-field { + margin-top: 8px; + } + + .attachment-thumb { + padding-left: 5px; + + img { + max-width: 100px; + } + } + + .attachment-flex { + display: flex; + align-items: center; + + .attachment-flex-column-grow { + flex-grow: 1; + } + } + + .attachment-small-content { + max-width: 700px; + } +} diff --git a/packages/rocketchat-message-attachments/package.js b/packages/rocketchat-message-attachments/package.js new file mode 100644 index 00000000000..928f83ea8dc --- /dev/null +++ b/packages/rocketchat-message-attachments/package.js @@ -0,0 +1,27 @@ +Package.describe({ + name: 'rocketchat:message-attachments', + version: '0.0.1', + summary: 'Widget for message attachments', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'templating', + 'coffeescript', + 'underscore', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('client/messageAttachment.html', 'client'); + + // stylesheets + api.addAssets('client/stylesheets/messageAttachments.less', 'server'); + api.addFiles('client/stylesheets/loader.coffee', 'server'); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 5768abe8696..8b82be03ee7 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -34,6 +34,9 @@ {{> oembedBaseWidget}} {{/each}} {{/if}} + {{#each attachments}} + {{> messageAttachment}} + {{/each}} </div> </li> </template> -- GitLab From 6617a03b71a7b1cf7f25f8e93de3916ce4c0e93a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 17:31:40 -0200 Subject: [PATCH 0780/1338] Sho if message is from bot and never render compact message version for bots --- .../assets/stylesheets/base.less | 6 +++ .../message/message.coffee | 6 ++- .../message/message.html | 49 ++++++++++--------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index b087c00b47e..2208b33a840 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2601,6 +2601,12 @@ a.github-fork { padding-left: 3px; margin-left: 3px; } + .is-bot { + background-color: #ccc; + padding: 1px 4px; + border-radius: 2px; + color: white; + } } .private { margin-left: 10px; diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index b934b460ecd..c596d6e36af 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -1,4 +1,6 @@ Template.message.helpers + isBot: -> + return 'bot' if this.bot? own: -> return 'own' if this.u?._id is Meteor.userId() chatops: -> @@ -109,7 +111,7 @@ Template.message.onViewRendered = (context) -> if lastNode.previousElementSibling?.dataset?.date isnt lastNode.dataset.date $(lastNode).addClass('new-day') $(lastNode).removeClass('sequential') - else if lastNode.previousElementSibling?.dataset?.username isnt lastNode.dataset.username + 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 @@ -119,7 +121,7 @@ Template.message.onViewRendered = (context) -> $(lastNode.nextElementSibling).addClass('new-day') $(lastNode.nextElementSibling).removeClass('sequential') - if lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username + if lastNode.nextElementSibling?.dataset?.bot is 'bot' or lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username $(lastNode.nextElementSibling).removeClass('sequential') if not lastNode.nextElementSibling? diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 8b82be03ee7..5a3ced89fa2 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -1,31 +1,34 @@ <template name="message"> - <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-date="{{date}}"> + <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-bot="{{isBot}}" data-date="{{date}}"> <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> <a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</a> <span class="info"> - {{#if edited}} - <span - title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' - class="time"> - {{time}} - </span> - <span class="edited" title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' > - <i class="icon-edit" aria-label="{{_ "Edited"}}"></i> - {{_ "by"}} - <a class="thumb thumb-small user-card-message" href="#" data-username="{{editedBy}}" tabindex="1"> - {{> avatar username=editedBy}} - </a> - </span> - {{else}} - <span class="time">{{time}}</span> - {{/if}} - {{#if private}} - <span class="private">{{_ "Only_you_can_see_this_message"}}</span> - {{/if}} + {{#if isBot}} + <span class="is-bot">BOT</span> + {{/if}} + {{#if edited}} + <span + title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' + class="time"> + {{time}} + </span> + <span class="edited" title='{{_ "edited"}} at {{editTime}} {{_ "by"}} {{editedBy}}' > + <i class="icon-edit" aria-label="{{_ "Edited"}}"></i> + {{_ "by"}} + <a class="thumb thumb-small user-card-message" href="#" data-username="{{editedBy}}" tabindex="1"> + {{> avatar username=editedBy}} + </a> + </span> + {{else}} + <span class="time">{{time}}</span> + {{/if}} + {{#if private}} + <span class="private">{{_ "Only_you_can_see_this_message"}}</span> + {{/if}} - <div class="message-cog-container"> - <i class="icon-cog message-cog" aria-label="{{_ "Actions"}}"></i> - </div> + <div class="message-cog-container"> + <i class="icon-cog message-cog" aria-label="{{_ "Actions"}}"></i> + </div> </span> <div class="body" dir="auto"> {{{body}}} -- GitLab From dc9665e6054d1f5e3c3c1548512eb74696a4a242 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 17:31:55 -0200 Subject: [PATCH 0781/1338] Integrations: Add bot info in message --- packages/rocketchat-integrations/server/api/api.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index e0c7e944d01..e9aed714393 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -74,6 +74,8 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, msg: @bodyParams.text or '' attachments: @bodyParams.attachments parseUrls: false + bot: + i: integration._id RocketChat.sendMessage user, message, room, {} -- GitLab From 04573f8a015db65f596f34912d4f30cd4d80c371 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 9 Dec 2015 17:32:08 -0200 Subject: [PATCH 0782/1338] Change layout of attachments --- .../client/messageAttachment.html | 60 +++++++++---------- .../stylesheets/messageAttachments.less | 6 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index b1d35b412dc..7429edaedb1 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -5,46 +5,44 @@ <div class="attachment-block"> <div class="attachment-block-border" style="background-color: {{color}}"></div> - <div class="attachment-flex {{#if thumb_url}}attachment-small-content{{/if}}"> - <div class="attachment-flex-column-grow"> - {{#if author_name}} - {{#if author_link}} - <div class="attachment-author"> - {{#if author_icon}} - <img src="{{author_icon}}"> - {{/if}} - <a href="{{author_link}}" target="_blank">{{author_name}}</a> - </div> - {{else}} - <div class="attachment-author"> - {{#if author_icon}} - <img src="{{author_icon}}"> - {{/if}} - {{author_name}} - </div> + {{#if author_name}} + {{#if author_link}} + <div class="attachment-author"> + {{#if author_icon}} + <img src="{{author_icon}}"> {{/if}} - {{/if}} - - {{#if title}} - {{#if title_link}} - <div class="attachment-title"><a href="{{title_link}}" target="_blank">{{title}}</a></div> - {{else}} - <div class="attachment-title">{{title}}</div> + <a href="{{author_link}}" target="_blank">{{author_name}}</a> + </div> + {{else}} + <div class="attachment-author"> + {{#if author_icon}} + <img src="{{author_icon}}"> {{/if}} - {{/if}} + {{author_name}} + </div> + {{/if}} + {{/if}} - {{#if text}} - <div class="attachment-text"> - {{{RocketChatMarkdown text}}} - </div> - {{/if}} - </div> + {{#if title}} + {{#if title_link}} + <div class="attachment-title"><a href="{{title_link}}" target="_blank">{{title}}</a></div> + {{else}} + <div class="attachment-title">{{title}}</div> + {{/if}} + {{/if}} + <div class="attachment-flex"> {{#if thumb_url}} <div class="attachment-thumb"> <img src="{{thumb_url}}"> </div> {{/if}} + + {{#if text}} + <div class="attachment-flex-column-grow attachment-text"> + {{{RocketChatMarkdown text}}} + </div> + {{/if}} </div> {{#if image_url}} diff --git a/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less b/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less index 848a927ce1d..b58eb81cc58 100644 --- a/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less +++ b/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.less @@ -72,7 +72,9 @@ } .attachment-thumb { - padding-left: 5px; + padding-right: 10px; + padding-top: 5px; + line-height: 0px; img { max-width: 100px; @@ -81,7 +83,7 @@ .attachment-flex { display: flex; - align-items: center; + align-items: flex-start; .attachment-flex-column-grow { flex-grow: 1; -- GitLab From 3c631eb20d1716ae11dfeaf703bdfd8e16d30526 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 9 Dec 2015 20:57:27 -0500 Subject: [PATCH 0783/1338] Announce support for Cent OS 7 Ansible deployment --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d98545756aa..f1ca0ea535f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ The Ultimate Open Source WebChat Platform * [Sloppy.io](#sloppyio) * [Docker](#docker) * [FreeBSD](#freebsd) + * [CentOS 7 Ansible](#ansible) * [Ubuntu VPS](#ubuntu-vps) * [Ubuntu Software Center](#ubuntu-software-center) * [About Rocket.Chat](#about-rocketchat) @@ -93,6 +94,11 @@ Run solid five-nines deployment on industry workhorse FreeBSD server: [](https://github.com/RocketChat/Rocket.Chat/wiki/FreeBSD) +## Ansible +Automated production grade deployment in minutes, for CentOS 7: + +[](https://galaxy.ansible.com/detail#/role/6458) + ## Ubuntu VPS Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) -- GitLab From fd81049609d776fac1a0fb85ed30569baf3e2738 Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Thu, 10 Dec 2015 10:50:54 +0100 Subject: [PATCH 0784/1338] Add archive/unarchive button in the channel settings --- i18n/en.i18n.json | 2 ++ .../client/views/channelSettings.coffee | 15 +++++++++++++++ .../client/views/channelSettings.html | 11 +++++++++++ .../server/models/Subscriptions.coffee | 2 +- server/methods/unarchiveRoom.coffee | 6 +++--- server/startup/roomPublishes.coffee | 2 ++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1b4ee275396..d74bd48653c 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -74,6 +74,7 @@ "API_Embed" : "Embed", "API_EmbedDisabledFor" : "Disable Embed for Users", "API_EmbedDisabledFor_Description" : "Comma-separated list of usernames", + "Archive" : "Archive", "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", @@ -452,6 +453,7 @@ "There_is_no_integrations" : "There is no integrations", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", + "Unarchive" : "Unarchive", "Unnamed" : "Unnamed", "Unread_Rooms" : "Unread Rooms", "Unread_Rooms_Mode" : "Unread Rooms Mode", diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 4f9f5d344c5..18a254406ca 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -3,6 +3,8 @@ Template.channelSettings.helpers return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> return ChatRoom.findOne(@rid)?.t + archived: -> + return ChatRoom.findOne(@rid)?.archived Template.channelSettings.events 'click .save': (e, t) -> @@ -15,6 +17,19 @@ Template.channelSettings.events return toastr.error err.reason if err toastr.success TAPi18n.__ 'Settings_updated' + 'click .archive': (e, t) -> + e.preventDefault() + + Meteor.call 'archiveRoom', t.data.rid, true, (err, results) -> + return toastr.error err.reason if err + toastr.success 'Channel archived' + + 'click .unarchive': (e, t) -> + e.preventDefault() + + Meteor.call 'unarchiveRoom', t.data.rid, true, (err, results) -> + return toastr.error err.reason if err + toastr.success 'Channel unarchived' # switch room.t # when 'c' diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index c72ecae4ad6..a14bf375e92 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -21,5 +21,16 @@ <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> </div> </form> + <form> + {{#if notDirect}} + <div class="submit"> + {{#if archived}} + <button class="button unarchive"><span>{{_ "Unarchive"}}</span></button> + {{else}} + <button class="button archive"><span>{{_ "Archive"}}</span></button> + {{/if}} + </div> + {{/if}} + </form> </div> </template> diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 20910f4e03d..245f8b987a0 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -54,7 +54,7 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base update = $set: alert: false - open: false + open: true archived: false return @update query, update diff --git a/server/methods/unarchiveRoom.coffee b/server/methods/unarchiveRoom.coffee index eed9cbfdc2d..b599865f084 100644 --- a/server/methods/unarchiveRoom.coffee +++ b/server/methods/unarchiveRoom.coffee @@ -1,9 +1,9 @@ Meteor.methods - unArchiveRoom: (rid) -> + unarchiveRoom: (rid) -> if not Meteor.userId() - throw new Meteor.Error 'invalid-user', '[methods] unArchiveRoom -> Invalid user' + throw new Meteor.Error 'invalid-user', '[methods] unarchiveRoom -> Invalid user' - console.log '[methods] unArchiveRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments + console.log '[methods] unarchiveRoom -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments room = RocketChat.models.Rooms.findOneById rid diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index 409131cc9b4..182c96d609a 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -7,6 +7,7 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + archived: 1 return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options RocketChat.roomTypes.setPublish 'p', (identifier) -> @@ -17,6 +18,7 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + archived: 1 user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options -- GitLab From bd2c75f17cfa3dbaa7177c7b14b0def74bf9fe94 Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Thu, 10 Dec 2015 11:05:26 +0100 Subject: [PATCH 0785/1338] Prevent archived rooms from showing up in the list of all channels --- packages/rocketchat-lib/server/models/Rooms.coffee | 11 +++++++++++ server/methods/channelsList.coffee | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index e1588bc5484..6db1614eb46 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 diff --git a/server/methods/channelsList.coffee b/server/methods/channelsList.coffee index 7aa42ff6351..c57d66e3a54 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() } -- GitLab From bb0590eb0c2a314fafb8709014dcd8719489cfbe Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Thu, 10 Dec 2015 11:13:35 +0100 Subject: [PATCH 0786/1338] Prevent archived private groups from showing up in the list of all private groups --- .../rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee | 2 +- server/publications/subscription.coffee | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee index 08ea0d9eb0c..1c4e3d423b6 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/server/publications/subscription.coffee b/server/publications/subscription.coffee index f188e99522e..3fe0f7d627d 100644 --- a/server/publications/subscription.coffee +++ b/server/publications/subscription.coffee @@ -15,3 +15,4 @@ Meteor.publish 'subscription', -> open: 1 alert: 1 unread: 1 + archived: 1 -- GitLab From 9635fa5d024a74f93c1d141664d1d06f78456fb9 Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Thu, 10 Dec 2015 11:33:08 +0100 Subject: [PATCH 0787/1338] Change the way archived rooms are displayed in the history --- i18n/en.i18n.json | 1 + .../views/app/privateHistory.coffee | 9 +++++++- .../views/app/privateHistory.html | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index d74bd48653c..1f024523cf4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -405,6 +405,7 @@ "Settings_updated" : "Settings updated", "Should_exists_a_user_with_this_username" : "Should exists a user with this username.", "Showing_online_users" : "Showing <b>__total_online__</b> of __total__ users", + "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", "Showing_results" : "<p>Showing <b>%s</b> results</p>", "Silence" : "Silence", "since_creation" : "since %s", diff --git a/packages/rocketchat-ui/views/app/privateHistory.coffee b/packages/rocketchat-ui/views/app/privateHistory.coffee index b04ecd4f803..97a45d9aca7 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() diff --git a/packages/rocketchat-ui/views/app/privateHistory.html b/packages/rocketchat-ui/views/app/privateHistory.html index 7b51de5161c..fd8d6caa3a4 100644 --- a/packages/rocketchat-ui/views/app/privateHistory.html +++ b/packages/rocketchat-ui/views/app/privateHistory.html @@ -35,6 +35,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> -- GitLab From c33d75a7e35bf59ed1dd1436c51184d485aae87e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 10:22:39 -0200 Subject: [PATCH 0788/1338] Fix oembed --- packages/rocketchat-lib/server/functions/sendMessage.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index 4113c918d02..20620d1c9dc 100644 --- a/packages/rocketchat-lib/server/functions/sendMessage.coffee +++ b/packages/rocketchat-lib/server/functions/sendMessage.coffee @@ -10,7 +10,7 @@ RocketChat.sendMessage = (user, message, room, options) -> message.rid = room._id - if not message.parseUrls is false + 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 message.urls = urls.map (url) -> url: url -- GitLab From c3cfb051e8e8fabe4449ed4505dfc8f169813159 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 10 Dec 2015 11:42:51 -0200 Subject: [PATCH 0789/1338] Fixes issue #1619 persistent custom oauth. --- .../server/methods/addOAuthService.coffee | 20 +++++++++---------- server/startup/migrations/v25.coffee | 5 +++++ 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 server/startup/migrations/v25.coffee diff --git a/packages/rocketchat-lib/server/methods/addOAuthService.coffee b/packages/rocketchat-lib/server/methods/addOAuthService.coffee index bf10e8f8907..4545add5841 100644 --- a/packages/rocketchat-lib/server/methods/addOAuthService.coffee +++ b/packages/rocketchat-lib/server/methods/addOAuthService.coffee @@ -10,13 +10,13 @@ Meteor.methods name = name.toLowerCase().replace(/[^a-z0-9]/g, '') name = s.capitalize(name) - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}" , false , { type: 'boolean', group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Enable'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_url" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_URL'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_token_path" , '/oauth/token' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Token_Path'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_identity_path" , '/me' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Identity_Path'} - 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'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_id" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_id'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_secret" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Secret'} - 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'} - 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'} - RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_button_color" , '#13679A' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Button_Color'} + RocketChat.settings.add "Accounts_OAuth_Custom_#{name}" , false , { type: 'boolean', group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Enable', persistent: true } + RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_url" , '' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_URL', persistent: true } + RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_token_path" , '/oauth/token' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Token_Path', persistent: true } + RocketChat.settings.add "Accounts_OAuth_Custom_#{name}_identity_path" , '/me' , { type: 'string' , group: 'Accounts', section: "Custom OAuth: #{name}", i18nLabel: 'Accounts_OAuth_Custom_Identity_Path', persistent: true } + 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}_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/server/startup/migrations/v25.coffee b/server/startup/migrations/v25.coffee new file mode 100644 index 00000000000..cb4301fcec6 --- /dev/null +++ b/server/startup/migrations/v25.coffee @@ -0,0 +1,5 @@ +Meteor.startup -> + Migrations.add + version: 25 + up: -> + RocketChat.models.Settings.update({ _id: /Accounts_OAuth_Custom/ }, { $set: { persistent: true }, $unset: {hidden: true} }, { multi: true }) -- GitLab From e9aa6650b633c670bb46bb85ac55c3a89ea38e6c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 14:49:15 -0200 Subject: [PATCH 0790/1338] Create a user rocket.cat and set avatar on system initialization --- private/avatars/rocketcat.png | Bin 0 -> 6767 bytes server/startup/initialData.coffee | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 private/avatars/rocketcat.png diff --git a/private/avatars/rocketcat.png b/private/avatars/rocketcat.png new file mode 100644 index 0000000000000000000000000000000000000000..caf940d6b044049ce3760d53bfee6edab62264e1 GIT binary patch literal 6767 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 V-4dhkas7{b!Q`@WouPZ;{{j9olaT-b literal 0 HcmV?d00001 diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index 7840064f439..fa806674792 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -5,6 +5,25 @@ Meteor.startup -> RocketChat.models.Rooms.createWithIdTypeAndName 'GENERAL', 'c', 'general', default: true + if not RocketChat.models.Users.findOneByUsername('rocket.cat')? + userId = RocketChat.models.Users.create + name: "Rocket.Cat" + username: 'rocket.cat' + status: "offline" + statusDefault: "offline" + utcOffset: 0 + active: true + bot: true + + rs = RocketChatFile.bufferToStream new Buffer(Assets.getBinary('avatars/rocketcat.png'), 'utf8') + RocketChatFileAvatarInstance.deleteFile "rocket.cat.jpg" + ws = RocketChatFileAvatarInstance.createWriteStream "rocket.cat.jpg", 'image/png' + ws.on 'end', Meteor.bindEnvironment -> + RocketChat.models.Users.setAvatarOrigin userId, 'local' + + rs.pipe(ws) + + if process.env.ADMIN_EMAIL? and process.env.ADMIN_PASS? re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i if re.test process.env.ADMIN_EMAIL -- GitLab From 70b50c4d6899dd132b5101ecbf5005be7d148c0e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 14:49:51 -0200 Subject: [PATCH 0791/1338] Add new i18n string User_or_channel_name --- i18n/en.i18n.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1b4ee275396..17e84777e6f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -118,6 +118,7 @@ "Create_new_private_group" : "Create a new private group", "Create_new_public_channel" : "Create a new public channel", "Created_at" : "Created at", + "Created_at_s_by_s" : "Created at <strong>%s</strong> by <strong>%s</strong>", "Custom_oauth_helper" : "When setting up your OAuth Provider, you'll have to inform a Callback URL. Use <pre>%s</pre> .", "Custom_oauth_unique_name" : "Custom oauth unique name", "days" : "days", @@ -153,8 +154,8 @@ "FileUpload" : "File Upload", "FileUpload_Enabled" : "File Uploads Enabled", "FileUpload_MaxFileSize" : "Maximum File Upload Size (in bytes)", - "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", "FileUpload_MediaType_NotAccepted" : "Media Types Not Accepted", + "FileUpload_MediaTypeWhiteList" : "Accepted Media Types", "FileUpload_MediaTypeWhiteListDescription" : "Comma-separated list of media types", "Follow_social_profiles" : "Follow our social profiles, fork us on github and share your thoughts about the rocket.chat app on our trello board.", "Forgot_password" : "Forgot your password", @@ -285,6 +286,7 @@ "Name" : "Name", "Name_cant_be_empty" : "Name can't be empty", "Name_optional" : "Name (optional)", + "New_integration" : "New integration", "New_messages" : "New messages", "New_password" : "New password", "No_channel_with_name_%s_was_found" : "No channel with name <strong>\"%s\"</strong> was found!", @@ -320,10 +322,8 @@ "Please_wait_activation" : "Please wait, this can take some time.", "Please_wait_statistics" : "Please wait, statistics are being generated.", "Post_as" : "Post as", - "New_integration" : "New integration", - "Post_to_s_as_s" : "Post to <strong>%s</strong> as <strong>%s</strong>", - "Created_at_s_by_s" : "Created at <strong>%s</strong> by <strong>%s</strong>", "Post_to_Channel" : "Post to Channel", + "Post_to_s_as_s" : "Post to <strong>%s</strong> as <strong>%s</strong>", "Powered_by" : "Powered by", "Preferences" : "Preferences", "Preferences_saved" : "Preferences saved", @@ -481,6 +481,7 @@ "User_left_male" : "Has left the channel.", "User_logged_out" : "User is logged out", "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_Settings" : "User Settings", "User_updated_successfully" : "User updated successfully", -- GitLab From 14c1a5e57ca2b620638aca61a945934544796466 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 14:50:20 -0200 Subject: [PATCH 0792/1338] Set rocket.cat as the default user for integrations --- .../client/views/integrationsIncoming.coffee | 3 ++- .../client/views/integrationsIncoming.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index 715ffb0ffbb..dd8c371ece5 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -12,7 +12,8 @@ Template.integrationsIncoming.helpers data.url = Meteor.absoluteUrl("hooks/#{encodeURIComponent(data._id)}/#{encodeURIComponent(data.userId)}/#{encodeURIComponent(data.token)}") return data - return {} + return {} = + username: 'rocket.cat' Template.integrationsIncoming.events diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index 976ad0c97e0..b33a335af1e 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -23,7 +23,7 @@ <div class="input-line double-col"> <label>{{_ "Post_as"}}</label> <div> - {{#if data.username}} + {{#if data.token}} <input type="text" name="username" value="{{data.username}}" disabled="disabled" /> {{else}} <input type="text" name="username" value="{{data.username}}" /> -- GitLab From 431d22536f9a3628e4f22e48df6b2d30242a50e9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 14:50:37 -0200 Subject: [PATCH 0793/1338] Add a example of message in integration page --- .../client/stylesheets/integrations.less | 6 ++++++ .../client/views/integrationsIncoming.coffee | 18 ++++++++++++++++++ .../client/views/integrationsIncoming.html | 3 +++ 3 files changed, 27 insertions(+) diff --git a/packages/rocketchat-integrations/client/stylesheets/integrations.less b/packages/rocketchat-integrations/client/stylesheets/integrations.less index 129cf9e9e31..04e51fba414 100644 --- a/packages/rocketchat-integrations/client/stylesheets/integrations.less +++ b/packages/rocketchat-integrations/client/stylesheets/integrations.less @@ -40,3 +40,9 @@ border-bottom: none; } } + +.message-example { + li { + list-style: none; + } +} diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index dd8c371ece5..51be06db248 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -15,6 +15,24 @@ Template.integrationsIncoming.helpers return {} = username: 'rocket.cat' + example: -> + return {} = + _id: Random.id() + msg: 'Example message' + bot: + i: Random.id() + 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: "rocket.cat" + Template.integrationsIncoming.events "click .submit > .delete": -> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index b33a335af1e..c210dcf32b9 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -42,6 +42,9 @@ </div> </div> {{/if}} + <div class="input-line double-col message-example"> + {{#nrr nrrargs 'message' example}}{{/nrr}} + </div> </div> </div> <div class="submit"> -- GitLab From 75afe115c6d08ce49102da3085c463669a8a5857 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 10 Dec 2015 15:55:58 -0200 Subject: [PATCH 0794/1338] fixed layout issues using flex --- .../app/client/routes/router.coffee | 2 + .../app/client/stylesheets/main.less | 46 +++++++++---------- .../app/client/views/room.coffee | 16 +++---- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/routes/router.coffee b/packages/rocketchat-livechat/app/client/routes/router.coffee index 976443f1c31..1105938efd9 100644 --- a/packages/rocketchat-livechat/app/client/routes/router.coffee +++ b/packages/rocketchat-livechat/app/client/routes/router.coffee @@ -1,3 +1,5 @@ +BlazeLayout.setRoot('body'); + FlowRouter.route '/livechat', name: 'index' diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index de53ed4ab8f..1b68c752383 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -9,6 +9,9 @@ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } +html, body { + height: 100%; +} body { padding: 0; margin: 0; @@ -21,7 +24,7 @@ body { -webkit-font-smoothing: antialiased; line-height: 1rem; padding: 0; - overflow: visible; + overflow: hidden; position: relative; // background-color: @primary-background-color; } @@ -41,18 +44,18 @@ input:focus { } .livechat-room { - position: fixed; - top: 0; - bottom: 0; + display: flex; + flex-direction: column; + height: 100%; + .title { + flex: 1 1 @header-min-height; + + line-height: @header-min-height; + border-top-right-radius: 5px; border-top-left-radius: 5px; color: #FFF; - position: fixed; - top: 0; - width: 100%; - height: @header-min-height; - display: table; z-index: 10; cursor: pointer; h1 { @@ -64,17 +67,13 @@ input:focus { } } .messages { - display: block; + flex: 1 1 100%; + background-color: #FFF; - top: @header-min-height; - bottom: @footer-min-height; border-left: 1px solid #E7E7E7; border-right: 1px solid #E7E7E7; - position: fixed; - width: 100%; + overflow-y: auto; .wrapper { - height: 100%; - overflow-y: auto; padding-bottom: 6px; ul { @@ -262,10 +261,11 @@ input:focus { cursor: pointer; bottom: 8px; left: 50%; + z-index: 5; .transition(transform 0.3s ease-out); - .transform(translateY(0)); + .transform(translateY(-40px)); &.not { - .transform(translateY(150%)); + .transform(translateY(100%)); } } @@ -275,6 +275,7 @@ input:focus { width: 100%; background-color: #F7D799; padding: 5px; + z-index: 5; .transition(transform 0.3s ease-out); .transform(translateY(200%)); @@ -285,12 +286,11 @@ input:focus { } } .footer { - display: block; + flex: 1 1 @footer-min-height; + + z-index: 10; + background-color: #FCFCFC; - position: fixed; - bottom: 0; - width: 100%; - height: auto; border-top: 1px solid #E7E7E7; border-left: 1px solid #E7E7E7; border-right: 1px solid #E7E7E7; diff --git a/packages/rocketchat-livechat/app/client/views/room.coffee b/packages/rocketchat-livechat/app/client/views/room.coffee index f29371d9d73..351315925dc 100644 --- a/packages/rocketchat-livechat/app/client/views/room.coffee +++ b/packages/rocketchat-livechat/app/client/views/room.coffee @@ -53,40 +53,40 @@ Template.room.onRendered -> this.chatMessages.init(this.firstNode) Template.room.onRendered -> - wrapper = this.find('.wrapper') + messages = this.find('.messages') newMessage = this.find(".new-message") template = this onscroll = _.throttle -> - template.atBottom = wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight + template.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight , 200 Meteor.setInterval -> if template.atBottom - wrapper.scrollTop = wrapper.scrollHeight - wrapper.clientHeight + messages.scrollTop = messages.scrollHeight - messages.clientHeight newMessage.className = "new-message not" , 100 - wrapper.addEventListener 'touchstart', -> + messages.addEventListener 'touchstart', -> template.atBottom = false - wrapper.addEventListener 'touchend', -> + messages.addEventListener 'touchend', -> onscroll() # readMessage.enable() # readMessage.read() - wrapper.addEventListener 'scroll', -> + messages.addEventListener 'scroll', -> template.atBottom = false onscroll() - wrapper.addEventListener 'mousewheel', -> + messages.addEventListener 'mousewheel', -> template.atBottom = false onscroll() # readMessage.enable() # readMessage.read() - wrapper.addEventListener 'wheel', -> + messages.addEventListener 'wheel', -> template.atBottom = false onscroll() # readMessage.enable() -- GitLab From 862deed7503ff7b1a717bad5e3fa070789d6ce59 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 10 Dec 2015 15:56:10 -0200 Subject: [PATCH 0795/1338] added a dafault test page --- public/livechat-demo.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 public/livechat-demo.html diff --git a/public/livechat-demo.html b/public/livechat-demo.html new file mode 100644 index 00000000000..512a7f8d0c6 --- /dev/null +++ b/public/livechat-demo.html @@ -0,0 +1,22 @@ +<html> + +<head> + <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 = '/packages/rocketchat_livechat/rocket-livechat.js'; + h.parentNode.insertBefore(j, h); + })(window, document, 'script', 'initRocket', '/livechat'); + </script> +</head> + +<body style="background-color: #EFEFEF"> + <h1 style="color:#000">test</h1> + <p style="color:#000">Talk to us.</p> +</body> + +</html> -- GitLab From a144ffe59c11ffaab930d6be8d1361028c66d78d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 16:04:25 -0200 Subject: [PATCH 0796/1338] Allow avatar and alias customization --- i18n/en.i18n.json | 5 ++++ .../client/views/integrationsIncoming.coffee | 26 ++++++++++++++++--- .../client/views/integrationsIncoming.html | 17 +++++++++++- .../server/api/api.coffee | 2 ++ .../server/methods/updateIntegration.coffee | 2 ++ .../assets/stylesheets/base.less | 7 +++++ .../stylesheets/utils/_colors.import.less | 1 + .../message/message.html | 16 ++++++++++-- 8 files changed, 70 insertions(+), 6 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 17e84777e6f..dff853cce2e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -65,6 +65,7 @@ "Add_Members" : "Add Members", "Add_users" : "Add users", "Administration" : "Administration", + "Alias" : "Alias", "All_channels" : "All channels", "Allow_Invalid_SelfSigned_Certs" : "Allow Invalid Self-Signed Certs", "Allow_Invalid_SelfSigned_Certs_Description" : "Allow invalid and self-signed SSL certificate's for link validation and previews.", @@ -79,6 +80,7 @@ "Are_you_sure" : "Are you sure?", "Auto_Load_Images" : "Auto Load Images", "Avatar_changed_successfully" : "Avatar changed successfully", + "Avatar_URL" : "Avatar URL", "Avatar_url_invalid_or_error" : "The url provided is invalid or not accessible. Please try again, but with a different url.", "away" : "away", "Away" : "Away", @@ -102,6 +104,7 @@ "Channels" : "Channels", "Channels_list" : "List of public channels", "Chat_Rooms" : "Chat Rooms", + "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?", "close" : "close", @@ -402,6 +405,7 @@ "Send_your_JSON_payloads_to_this_URL" : "Send your JSON payloads to this URL.", "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.", "Showing_online_users" : "Showing <b>__total_online__</b> of __total__ users", "Showing_results" : "<p>Showing <b>%s</b> results</p>", @@ -506,6 +510,7 @@ "Yes_clear_all" : "Yes, clear all!", "Yes_delete_it" : "Yes, delete it!", "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_need_confirm_email" : "You need to confirm your email to login!", "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!", diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index 51be06db248..28f19b530c6 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -1,3 +1,8 @@ +Template.integrationsIncoming.onCreated -> + @record = new ReactiveVar + username: 'rocket.cat' + + Template.integrationsIncoming.helpers hasPermission: -> @@ -10,14 +15,17 @@ 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)}") + Template.instance().record.set data return data - return {} = - username: 'rocket.cat' + return Template.instance().record.curValue example: -> + record = Template.instance().record.get() return {} = _id: Random.id() + alias: record.alias + avatar: record.avatar msg: 'Example message' bot: i: Random.id() @@ -31,10 +39,18 @@ Template.integrationsIncoming.helpers ts: new Date u: _id: Random.id() - username: "rocket.cat" + username: record.username Template.integrationsIncoming.events + "blur input": (e, t) -> + t.record.set + name: $('[name=name]').val().trim() + alias: $('[name=alias]').val().trim() + avatar: $('[name=avatar]').val().trim() + channel: $('[name=channel]').val().trim() + username: $('[name=username]').val().trim() + "click .submit > .delete": -> params = Template.instance().data.params() @@ -61,6 +77,8 @@ Template.integrationsIncoming.events "click .submit > .save": -> name = $('[name=name]').val().trim() + alias = $('[name=alias]').val().trim() + avatar = $('[name=avatar]').val().trim() channel = $('[name=channel]').val().trim() username = $('[name=username]').val().trim() @@ -72,6 +90,8 @@ Template.integrationsIncoming.events integration = channel: channel + alias: alias if alias isnt '' + avatar: avatar if avatar isnt '' name: name if name isnt '' params = Template.instance().data.params?() diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index c210dcf32b9..d17db30e5c5 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -32,6 +32,21 @@ <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> {{#if data.token}} <div class="input-line double-col"> <label>Webhook URL</label> @@ -42,7 +57,7 @@ </div> </div> {{/if}} - <div class="input-line double-col message-example"> + <div class="input-line message-example"> {{#nrr nrrargs 'message' example}}{{/nrr}} </div> </div> diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index e9aed714393..4001e3c09a7 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -71,6 +71,8 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, error: 'invalid-channel-type' message = + avatar: integration.avatar + alias: integration.alias msg: @bodyParams.text or '' attachments: @bodyParams.attachments parseUrls: false diff --git a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee index 272348dcbe0..d41d0e3d145 100644 --- a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee @@ -39,6 +39,8 @@ Meteor.methods RocketChat.models.Integrations.update integrationId, $set: name: integration.name + avatar: integration.avatar + alias: integration.alias channel: integration.channel _updatedAt: new Date _updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}} diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 2208b33a840..2ba3fe0465b 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -427,6 +427,7 @@ select, input[type='text'], input[type='number'], input[type='email'], +input[type='url'], input[type='password'] { -webkit-appearance: none; height: 35px; @@ -466,6 +467,7 @@ form.inline { input[type='text'], input[type='number'], input[type='email'], + input[type='url'], input[type='password'] { width: auto; } @@ -2700,6 +2702,11 @@ a.github-fork { &.temp .body { opacity: .5; } + .message-alias { + color: #aaa; + font-weight: 400; + padding-left: 2px; + } } .compact { diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index e0cb54f452a..7bdb7b45f75 100644 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -136,6 +136,7 @@ select, input[type='text'], input[type='number'], input[type='email'], +input[type='url'], input[type='password'] { border-color: #E7E7E7; background-color: #fff; diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 5a3ced89fa2..0ae084bfc99 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -1,7 +1,19 @@ <template name="message"> <li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-bot="{{isBot}}" data-date="{{date}}"> - <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> - <a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</a> + {{#if avatar}} + <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1"> + <div class="avatar"> + <div class="avatar-image" style="background-image:url({{avatar}});"></div> + </div> + </a> + {{else}} + <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a> + {{/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> + {{else}} + <a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</a> + {{/if}} <span class="info"> {{#if isBot}} <span class="is-bot">BOT</span> -- GitLab From 7dee035bb822a71504050796c7e0fa179ad2e990 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 10 Dec 2015 17:23:39 -0200 Subject: [PATCH 0797/1338] improved error UI --- .../app/client/stylesheets/_variables.less | 2 +- .../app/client/stylesheets/main.less | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/_variables.less b/packages/rocketchat-livechat/app/client/stylesheets/_variables.less index e746bcf8cad..516e8695e10 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: 52px; @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 1b68c752383..ae8e8f8c191 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -270,18 +270,18 @@ input:focus { } .error { - bottom: 50px; + bottom: 40px; position: fixed; width: 100%; background-color: #F7D799; padding: 5px; - z-index: 5; + z-index: 8; - .transition(transform 0.3s ease-out); - .transform(translateY(200%)); + .transition(transform 0.2s ease-out); + .transform(translateY(100%)); &.show { - .transform(translateY(8px)); + .transform(translateY(0)); } } } -- GitLab From f8c356d35fd4f091a954f26c25be669eff99924f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 10 Dec 2015 17:54:34 -0200 Subject: [PATCH 0798/1338] Set 'rockat.cat' as the _id of user rocket.cat --- server/startup/initialData.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index fa806674792..dbfafd86f22 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -5,8 +5,9 @@ Meteor.startup -> RocketChat.models.Rooms.createWithIdTypeAndName 'GENERAL', 'c', 'general', default: true - if not RocketChat.models.Users.findOneByUsername('rocket.cat')? - userId = RocketChat.models.Users.create + if not RocketChat.models.Users.findOneById('rocket.cat')? + RocketChat.models.Users.create + _id: 'rocket.cat' name: "Rocket.Cat" username: 'rocket.cat' status: "offline" @@ -19,7 +20,7 @@ Meteor.startup -> RocketChatFileAvatarInstance.deleteFile "rocket.cat.jpg" ws = RocketChatFileAvatarInstance.createWriteStream "rocket.cat.jpg", 'image/png' ws.on 'end', Meteor.bindEnvironment -> - RocketChat.models.Users.setAvatarOrigin userId, 'local' + RocketChat.models.Users.setAvatarOrigin 'rocket.cat', 'local' rs.pipe(ws) -- GitLab From 819783b14c4f2625363f2bc405853c07fb2e42f6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 10 Dec 2015 18:00:00 -0200 Subject: [PATCH 0799/1338] livechat popout support --- .../app/client/stylesheets/_variables.less | 2 +- .../app/client/stylesheets/fontello.css | 509 ++++++++++++++++++ .../app/client/stylesheets/main.less | 13 +- .../app/client/views/room.coffee | 96 ---- .../app/client/views/room.html | 5 + .../app/client/views/room.js | 120 +++++ .../rocketchat-livechat/rocket-livechat.js | 30 +- 7 files changed, 668 insertions(+), 107 deletions(-) create mode 100644 packages/rocketchat-livechat/app/client/stylesheets/fontello.css delete mode 100644 packages/rocketchat-livechat/app/client/views/room.coffee create mode 100644 packages/rocketchat-livechat/app/client/views/room.js diff --git a/packages/rocketchat-livechat/app/client/stylesheets/_variables.less b/packages/rocketchat-livechat/app/client/stylesheets/_variables.less index 516e8695e10..e746bcf8cad 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: 52px; +@footer-min-height: 42px; @rooms-box-width: 260px; @flex-tab-width: 400px; diff --git a/packages/rocketchat-livechat/app/client/stylesheets/fontello.css b/packages/rocketchat-livechat/app/client/stylesheets/fontello.css new file mode 100644 index 00000000000..fc28243c86e --- /dev/null +++ b/packages/rocketchat-livechat/app/client/stylesheets/fontello.css @@ -0,0 +1,509 @@ +@font-face { + font-family: 'fontello'; + src: url('/fonts/fontello.eot?52343198'); + src: url('/fonts/fontello.eot?52343198#iefix') format('embedded-opentype'), + url('/fonts/fontello.woff?52343198') format('woff'), + url('/fonts/fontello.ttf?52343198') format('truetype'), + url('/fonts/fontello.svg?52343198#fontello') format('svg'); + font-weight: normal; + font-style: normal; +} +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ +/* +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: 'fontello'; + src: url('/fonts/fontello.svg?52343198#fontello') format('svg'); + } +} +*/ + + [class^="icon-"]:before, [class*=" icon-"]:before { + font-family: "fontello"; + font-style: normal; + font-weight: normal; + speak: none; + + display: inline-block; + text-decoration: inherit; + width: 1em; + margin-right: .2em; + text-align: center; + /* opacity: .8; */ + + /* For safety - reset parent styles, that can break glyph codes*/ + font-variant: normal; + text-transform: none; + + /* fix buttons height, for twitter bootstrap */ + line-height: 1em; + + /* Animation center compensation - margins should be symmetric */ + /* remove if not needed */ + margin-left: .2em; + + /* you can be more comfortable with increased icons size */ + /* font-size: 120%; */ + + /* Font smoothing. That was taken from TWBS */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + /* Uncomment for 3D effect */ + /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ +} + +.icon-religious-islam:before { content: '\21'; } /* '!' */ +.icon-religious-jewish:before { content: '\22'; } /* '"' */ +.icon-graduation-cap-1:before { content: '\23'; } /* '#' */ +.icon-universal-access:before { content: '\24'; } /* '$' */ +.icon-paper-plane:before { content: '\25'; } /* '%' */ +.icon-paw:before { content: '\26'; } /* '&' */ +.icon-spoon:before { content: '\27'; } /* ''' */ +.icon-chrome:before { content: '\2a'; } /* '*' */ +.icon-opera:before { content: '\2b'; } /* '+' */ +.icon-crown:before { content: '\2c'; } /* ',' */ +.icon-recycle:before { content: '\2d'; } /* '-' */ +.icon-note-beamed:before { content: '\2e'; } /* '.' */ +.icon-ie:before { content: '\2f'; } /* '/' */ +.icon-note:before { content: '\30'; } /* '0' */ +.icon-alert:before { content: '\31'; } /* '1' */ +.icon-chat-1:before { content: '\32'; } /* '2' */ +.icon-360:before { content: '\33'; } /* '3' */ +.icon-cab:before { content: '\34'; } /* '4' */ +.icon-share:before { content: '\35'; } /* '5' */ +.icon-building-filled:before { content: '\36'; } /* '6' */ +.icon-linux:before { content: '\37'; } /* '7' */ +.icon-camera-tour:before { content: '\38'; } /* '8' */ +.icon-spin1:before { content: '\39'; } /* '9' */ +.icon-spin2:before { content: '\3a'; } /* ':' */ +.icon-spin3:before { content: '\3b'; } /* ';' */ +.icon-left-open:before { content: '\3c'; } /* '<' */ +.icon-spin5:before { content: '\3d'; } /* '=' */ +.icon-right-open:before { content: '\3e'; } /* '>' */ +.icon-history:before { content: '\3f'; } /* '?' */ +.icon-circle-notch:before { content: '\40'; } /* '@' */ +.icon-marquee:before { content: '\41'; } /* 'A' */ +.icon-eye:before { content: '\42'; } /* 'B' */ +.icon-users:before { content: '\43'; } /* 'C' */ +.icon-shower:before { content: '\44'; } /* 'D' */ +.icon-swimming:before { content: '\45'; } /* 'E' */ +.icon-chart-area:before { content: '\46'; } /* 'F' */ +.icon-chart-pie:before { content: '\47'; } /* 'G' */ +.icon-chart-line:before { content: '\48'; } /* 'H' */ +.icon-bicycle:before { content: '\49'; } /* 'I' */ +.icon-bus:before { content: '\4a'; } /* 'J' */ +.icon-at:before { content: '\4b'; } /* 'K' */ +.icon-infinity:before { content: '\4c'; } /* 'L' */ +.icon-at-1:before { content: '\4d'; } /* 'M' */ +.icon-child:before { content: '\4e'; } /* 'N' */ +.icon-plus-squared-alt:before { content: '\4f'; } /* 'O' */ +.icon-unlink:before { content: '\50'; } /* 'P' */ +.icon-share-squared:before { content: '\51'; } /* 'Q' */ +.icon-tree:before { content: '\52'; } /* 'R' */ +.icon-database:before { content: '\53'; } /* 'S' */ +.icon-lifebuoy:before { content: '\54'; } /* 'T' */ +.icon-cubes:before { content: '\55'; } /* 'U' */ +.icon-cube:before { content: '\56'; } /* 'V' */ +.icon-bell-off:before { content: '\57'; } /* 'W' */ +.icon-trash-1:before { content: '\58'; } /* 'X' */ +.icon-toggle-off:before { content: '\59'; } /* 'Y' */ +.icon-toggle-on:before { content: '\5a'; } /* 'Z' */ +.icon-birthday:before { content: '\5b'; } /* '[' */ +.icon-github-circled:before { content: '\5c'; } /* '\' */ +.icon-google:before { content: '\5d'; } /* ']' */ +.icon-pied-piper-squared:before { content: '\5e'; } /* '^' */ +.icon-slideshare:before { content: '\5f'; } /* '_' */ +.icon-wordpress:before { content: '\60'; } /* '`' */ +.icon-digg:before { content: '\61'; } /* 'a' */ +.icon-delicious:before { content: '\62'; } /* 'b' */ +.icon-hash:before { content: '\63'; } /* 'c' */ +.icon-hash-1:before { content: '\64'; } /* 'd' */ +.icon-clock-1:before { content: '\65'; } /* 'e' */ +.icon-asterisk-1:before { content: '\66'; } /* 'f' */ +.icon-cancel-circled:before { content: '\67'; } /* 'g' */ +.icon-bell-off-empty:before { content: '\68'; } /* 'h' */ +.icon-meteor:before { content: '\69'; } /* 'i' */ +.icon-git-squared:before { content: '\6a'; } /* 'j' */ +.icon-angellist:before { content: '\6b'; } /* 'k' */ +.icon-behance:before { content: '\6c'; } /* 'l' */ +.icon-gitlab:before { content: '\6d'; } /* 'm' */ +.icon-rocketchat:before { content: '\6e'; } /* 'n' */ +.icon-spin4:before { content: '\6f'; } /* 'o' */ +.icon-sliders:before { content: '\70'; } /* 'p' */ +.icon-spin6:before { content: '\71'; } /* 'q' */ +.icon-firefox:before { content: '\72'; } /* 'r' */ +.icon-angle-double-left:before { content: '\ab'; } /* '«' */ +.icon-angle-double-right:before { content: '\bb'; } /* '»' */ +.icon-angle-left:before { content: '\2039'; } /* '‹' */ +.icon-angle-right:before { content: '\203a'; } /* '›' */ +.icon-left-open-small:before { content: '\276e'; } /* 'â®' */ +.icon-right-open-small:before { content: '\276f'; } /* 'â¯' */ +.icon-camera:before { content: '\e800'; } /* 'î €' */ +.icon-videocam:before { content: '\e801'; } /* 'î ' */ +.icon-heart:before { content: '\e802'; } /* 'î ‚' */ +.icon-star:before { content: '\e803'; } /* 'î ƒ' */ +.icon-star-empty:before { content: '\e804'; } /* 'î „' */ +.icon-star-half:before { content: '\e805'; } /* 'î …' */ +.icon-star-half-alt:before { content: '\e806'; } /* 'î †' */ +.icon-thumbs-up-alt:before { content: '\e807'; } /* 'î ‡' */ +.icon-thumbs-down-alt:before { content: '\e808'; } /* 'î ˆ' */ +.icon-print:before { content: '\e809'; } /* 'î ‰' */ +.icon-user:before { content: '\e80a'; } /* 'î Š' */ +.icon-ok:before { content: '\e80b'; } /* 'î ‹' */ +.icon-bell-alt:before { content: '\e80c'; } /* 'î Œ' */ +.icon-bell:before { content: '\e80d'; } /* 'î ' */ +.icon-direction:before { content: '\e80e'; } /* 'î Ž' */ +.icon-home:before { content: '\e80f'; } /* 'î ' */ +.icon-trash:before { content: '\e810'; } /* 'î ' */ +.icon-menu:before { content: '\e811'; } /* 'î ‘' */ +.icon-attach:before { content: '\e812'; } /* 'î ’' */ +.icon-th-list:before { content: '\e813'; } /* 'î “' */ +.icon-th:before { content: '\e814'; } /* 'î ”' */ +.icon-th-large:before { content: '\e815'; } /* 'î •' */ +.icon-ok-circled:before { content: '\e816'; } /* 'î –' */ +.icon-cancel:before { content: '\e818'; } /* 'î ˜' */ +.icon-attention:before { content: '\e819'; } /* 'î ™' */ +.icon-attention-circled:before { content: '\e81a'; } /* 'î š' */ +.icon-location:before { content: '\e81b'; } /* 'î ›' */ +.icon-pencil:before { content: '\e81c'; } /* 'î œ' */ +.icon-glass:before { content: '\e81d'; } /* 'î ' */ +.icon-music:before { content: '\e81e'; } /* 'î ž' */ +.icon-search:before { content: '\e81f'; } /* 'î Ÿ' */ +.icon-mail:before { content: '\e820'; } /* 'î ' */ +.icon-mail-alt:before { content: '\e821'; } /* 'î ¡' */ +.icon-heart-empty:before { content: '\e822'; } /* 'î ¢' */ +.icon-male:before { content: '\e824'; } /* 'î ¤' */ +.icon-female:before { content: '\e825'; } /* 'î ¥' */ +.icon-video:before { content: '\e826'; } /* 'î ¦' */ +.icon-picture:before { content: '\e827'; } /* 'î §' */ +.icon-ok-squared:before { content: '\e82a'; } /* 'î ª' */ +.icon-plus:before { content: '\e82c'; } /* 'î ¬' */ +.icon-plus-circled:before { content: '\e82d'; } /* 'î ' */ +.icon-plus-squared:before { content: '\e82e'; } /* 'î ®' */ +.icon-religious-christian:before { content: '\e82f'; } /* 'î ¯' */ +.icon-water:before { content: '\e830'; } /* 'î °' */ +.icon-toilet:before { content: '\e831'; } /* 'î ±' */ +.icon-droplet:before { content: '\e832'; } /* 'î ²' */ +.icon-minus:before { content: '\e833'; } /* 'î ³' */ +.icon-minus-circled:before { content: '\e834'; } /* 'î ´' */ +.icon-minus-squared:before { content: '\e835'; } /* 'î µ' */ +.icon-airport:before { content: '\e836'; } /* 'î ¶' */ +.icon-help:before { content: '\e837'; } /* 'î ·' */ +.icon-help-circled:before { content: '\e838'; } /* 'î ¸' */ +.icon-info-circled:before { content: '\e839'; } /* 'î ¹' */ +.icon-info:before { content: '\e83a'; } /* 'î º' */ +.icon-link:before { content: '\e83b'; } /* 'î »' */ +.icon-link-ext:before { content: '\e83d'; } /* 'î ½' */ +.icon-link-ext-alt:before { content: '\e83e'; } /* 'î ¾' */ +.icon-thumbs-down:before { content: '\e83f'; } /* 'î ¿' */ +.icon-thumbs-up:before { content: '\e840'; } /* 'î¡€' */ +.icon-flag-checkered:before { content: '\e841'; } /* 'î¡' */ +.icon-flag-empty:before { content: '\e842'; } /* 'î¡‚' */ +.icon-flag:before { content: '\e843'; } /* '' */ +.icon-bookmark-empty:before { content: '\e844'; } /* 'î¡„' */ +.icon-bookmark:before { content: '\e845'; } /* 'î¡…' */ +.icon-tags:before { content: '\e846'; } /* '' */ +.icon-tag:before { content: '\e847'; } /* '' */ +.icon-eye-off:before { content: '\e848'; } /* '' */ +.icon-minus-squared-alt:before { content: '\e84a'; } /* 'î¡Š' */ +.icon-pin:before { content: '\e84b'; } /* 'î¡‹' */ +.icon-lock-open-alt:before { content: '\e84c'; } /* 'î¡Œ' */ +.icon-lock-open:before { content: '\e84d'; } /* 'î¡' */ +.icon-lock:before { content: '\e84e'; } /* 'î¡Ž' */ +.icon-download:before { content: '\e84f'; } /* 'î¡' */ +.icon-upload:before { content: '\e850'; } /* 'î¡' */ +.icon-download-cloud:before { content: '\e851'; } /* 'î¡‘' */ +.icon-upload-cloud:before { content: '\e852'; } /* 'î¡’' */ +.icon-reply:before { content: '\e853'; } /* 'î¡“' */ +.icon-edit:before { content: '\e854'; } /* 'î¡”' */ +.icon-compass:before { content: '\e855'; } /* 'î¡•' */ +.icon-retweet:before { content: '\e856'; } /* 'î¡–' */ +.icon-keyboard:before { content: '\e857'; } /* 'î¡—' */ +.icon-gamepad:before { content: '\e858'; } /* '' */ +.icon-comment:before { content: '\e859'; } /* 'î¡™' */ +.icon-chat:before { content: '\e85a'; } /* 'î¡š' */ +.icon-comment-empty:before { content: '\e85b'; } /* 'î¡›' */ +.icon-chat-empty:before { content: '\e85c'; } /* 'î¡œ' */ +.icon-reply-all:before { content: '\e85d'; } /* 'î¡' */ +.icon-forward:before { content: '\e85e'; } /* 'î¡ž' */ +.icon-quote-left:before { content: '\e85f'; } /* 'î¡Ÿ' */ +.icon-quote-right:before { content: '\e860'; } /* 'î¡ ' */ +.icon-code:before { content: '\e861'; } /* 'î¡¡' */ +.icon-export:before { content: '\e862'; } /* 'î¡¢' */ +.icon-export-alt:before { content: '\e863'; } /* 'î¡£' */ +.icon-pencil-squared:before { content: '\e864'; } /* '' */ +.icon-attention-alt:before { content: '\e865'; } /* 'î¡¥' */ +.icon-doc:before { content: '\e866'; } /* '' */ +.icon-docs:before { content: '\e867'; } /* '' */ +.icon-doc-text:before { content: '\e868'; } /* '' */ +.icon-doc-inv:before { content: '\e869'; } /* 'î¡©' */ +.icon-doc-text-inv:before { content: '\e86a'; } /* '' */ +.icon-folder-open:before { content: '\e86b'; } /* 'î¡«' */ +.icon-folder-empty:before { content: '\e86c'; } /* '' */ +.icon-folder:before { content: '\e86d'; } /* 'î¡' */ +.icon-folder-open-empty:before { content: '\e86e'; } /* 'î¡®' */ +.icon-box:before { content: '\e86f'; } /* '' */ +.icon-rss:before { content: '\e870'; } /* 'î¡°' */ +.icon-rss-squared:before { content: '\e871'; } /* '' */ +.icon-phone:before { content: '\e872'; } /* '' */ +.icon-phone-squared:before { content: '\e873'; } /* '' */ +.icon-blank:before { content: '\e874'; } /* 'î¡´' */ +.icon-youtube-play:before { content: '\e875'; } /* '' */ +.icon-youtube-squared:before { content: '\e876'; } /* '' */ +.icon-youtube:before { content: '\e877'; } /* 'î¡·' */ +.icon-key-1:before { content: '\e878'; } /* '' */ +.icon-foxter:before { content: '\e879'; } /* '' */ +.icon-windows:before { content: '\e87a'; } /* '' */ +.icon-kettle:before { content: '\e87b'; } /* 'î¡»' */ +.icon-graduation-cap:before { content: '\e87c'; } /* '' */ +.icon-vimeo-squared:before { content: '\e87d'; } /* '' */ +.icon-twitter:before { content: '\e87e'; } /* '' */ +.icon-twitter-squared:before { content: '\e87f'; } /* 'î¡¿' */ +.icon-tumblr-squared:before { content: '\e880'; } /* '' */ +.icon-tumblr:before { content: '\e881'; } /* 'î¢' */ +.icon-trello:before { content: '\e882'; } /* '' */ +.icon-stackoverflow:before { content: '\e883'; } /* '' */ +.icon-lemon:before { content: '\e884'; } /* '' */ +.icon-parking:before { content: '\e885'; } /* '' */ +.icon-gittip:before { content: '\e886'; } /* '' */ +.icon-gplus:before { content: '\e887'; } /* '' */ +.icon-html5:before { content: '\e888'; } /* '' */ +.icon-gplus-squared:before { content: '\e889'; } /* '' */ +.icon-instagramm:before { content: '\e88a'; } /* '' */ +.icon-linkedin-squared:before { content: '\e88b'; } /* '' */ +.icon-fuel:before { content: '\e88c'; } /* '' */ +.icon-linkedin:before { content: '\e88d'; } /* 'î¢' */ +.icon-money-1:before { content: '\e88e'; } /* '' */ +.icon-pagelines:before { content: '\e88f'; } /* 'î¢' */ +.icon-pinterest-circled:before { content: '\e890'; } /* 'î¢' */ +.icon-pinterest-squared:before { content: '\e891'; } /* '' */ +.icon-skype:before { content: '\e892'; } /* '' */ +.icon-stackexchange:before { content: '\e893'; } /* '' */ +.icon-renren:before { content: '\e894'; } /* '' */ +.icon-bank:before { content: '\e895'; } /* '' */ +.icon-school:before { content: '\e896'; } /* '' */ +.icon-foursquare:before { content: '\e897'; } /* '' */ +.icon-flickr:before { content: '\e898'; } /* '' */ +.icon-facebook-squared:before { content: '\e899'; } /* '' */ +.icon-facebook:before { content: '\e89a'; } /* '' */ +.icon-dropbox:before { content: '\e89b'; } /* '' */ +.icon-dribbble:before { content: '\e89c'; } /* '' */ +.icon-css3:before { content: '\e89d'; } /* 'î¢' */ +.icon-bitbucket-squared:before { content: '\e89e'; } /* '' */ +.icon-bitbucket:before { content: '\e89f'; } /* '' */ +.icon-apple:before { content: '\e8a0'; } /* 'î¢ ' */ +.icon-android:before { content: '\e8a1'; } /* '' */ +.icon-adn:before { content: '\e8a2'; } /* '' */ +.icon-wheelchair:before { content: '\e8a3'; } /* '' */ +.icon-bullseye:before { content: '\e8a4'; } /* '' */ +.icon-user-md:before { content: '\e8a5'; } /* '' */ +.icon-stethoscope:before { content: '\e8a6'; } /* '' */ +.icon-ambulance:before { content: '\e8a7'; } /* '' */ +.icon-medkit:before { content: '\e8a8'; } /* '' */ +.icon-hospital:before { content: '\e8a9'; } /* '' */ +.icon-h-sigh:before { content: '\e8aa'; } /* '' */ +.icon-building:before { content: '\e8ab'; } /* '' */ +.icon-smile:before { content: '\e8ac'; } /* '' */ +.icon-frown:before { content: '\e8ad'; } /* 'î¢' */ +.icon-meh:before { content: '\e8ae'; } /* '' */ +.icon-anchor:before { content: '\e8af'; } /* '' */ +.icon-terminal:before { content: '\e8b0'; } /* '' */ +.icon-eraser:before { content: '\e8b1'; } /* '' */ +.icon-puzzle:before { content: '\e8b2'; } /* '' */ +.icon-shield:before { content: '\e8b3'; } /* '' */ +.icon-extinguisher:before { content: '\e8b4'; } /* '' */ +.icon-beer:before { content: '\e8b5'; } /* '' */ +.icon-food:before { content: '\e8b6'; } /* '' */ +.icon-coffee:before { content: '\e8b7'; } /* '' */ +.icon-spinner:before { content: '\e8b8'; } /* '' */ +.icon-sitemap:before { content: '\e8b9'; } /* '' */ +.icon-gauge:before { content: '\e8ba'; } /* '' */ +.icon-hammer:before { content: '\e8bb'; } /* '' */ +.icon-sort-number-down:before { content: '\e8bc'; } /* '' */ +.icon-sort-name-down:before { content: '\e8bd'; } /* '' */ +.icon-sort-number-up:before { content: '\e8be'; } /* '' */ +.icon-sort-name-up:before { content: '\e8bf'; } /* '' */ +.icon-sort-alt-down:before { content: '\e8c0'; } /* '' */ +.icon-sort-alt-up:before { content: '\e8c1'; } /* 'î£' */ +.icon-sort-up:before { content: '\e8c2'; } /* '' */ +.icon-sort-down:before { content: '\e8c3'; } /* '' */ +.icon-sort:before { content: '\e8c4'; } /* '' */ +.icon-certificate:before { content: '\e8c5'; } /* '' */ +.icon-tasks:before { content: '\e8c6'; } /* '' */ +.icon-filter:before { content: '\e8c7'; } /* '' */ +.icon-beaker:before { content: '\e8c8'; } /* '' */ +.icon-magic:before { content: '\e8c9'; } /* '' */ +.icon-truck:before { content: '\e8ca'; } /* '' */ +.icon-money:before { content: '\e8cb'; } /* '' */ +.icon-euro:before { content: '\e8cc'; } /* '' */ +.icon-pound:before { content: '\e8cd'; } /* 'î£' */ +.icon-dollar:before { content: '\e8ce'; } /* '' */ +.icon-bug:before { content: '\e8cf'; } /* 'î£' */ +.icon-rocket:before { content: '\e8d0'; } /* 'î£' */ +.icon-fork:before { content: '\e8d1'; } /* '' */ +.icon-key:before { content: '\e8d2'; } /* '' */ +.icon-hdd:before { content: '\e8d3'; } /* '' */ +.icon-megaphone:before { content: '\e8d4'; } /* '' */ +.icon-floppy:before { content: '\e8d5'; } /* '' */ +.icon-credit-card:before { content: '\e8d6'; } /* '' */ +.icon-ticket:before { content: '\e8d7'; } /* '' */ +.icon-chart-bar:before { content: '\e8d8'; } /* '' */ +.icon-magnet:before { content: '\e8d9'; } /* '' */ +.icon-fire:before { content: '\e8da'; } /* '' */ +.icon-gift:before { content: '\e8db'; } /* '' */ +.icon-asterisk:before { content: '\e8dc'; } /* '' */ +.icon-dot-circled:before { content: '\e8dd'; } /* 'î£' */ +.icon-circle-empty:before { content: '\e8de'; } /* '' */ +.icon-paste:before { content: '\e8df'; } /* '' */ +.icon-briefcase:before { content: '\e8e0'; } /* 'î£ ' */ +.icon-suitcase:before { content: '\e8e1'; } /* '' */ +.icon-ellipsis:before { content: '\e8e2'; } /* '' */ +.icon-ellipsis-vert:before { content: '\e8e3'; } /* '' */ +.icon-off:before { content: '\e8e4'; } /* '' */ +.icon-road:before { content: '\e8e5'; } /* '' */ +.icon-qrcode:before { content: '\e8e6'; } /* '' */ +.icon-barcode:before { content: '\e8e7'; } /* '' */ +.icon-list-alt:before { content: '\e8e8'; } /* '' */ +.icon-book:before { content: '\e8e9'; } /* '' */ +.icon-ajust:before { content: '\e8ea'; } /* '' */ +.icon-tint:before { content: '\e8eb'; } /* '' */ +.icon-check:before { content: '\e8ec'; } /* '' */ +.icon-check-empty:before { content: '\e8ed'; } /* 'î£' */ +.icon-circle:before { content: '\e8ee'; } /* '' */ +.icon-cog:before { content: '\e8ef'; } /* '' */ +.icon-cog-alt:before { content: '\e8f0'; } /* '' */ +.icon-wrench:before { content: '\e8f1'; } /* '' */ +.icon-basket:before { content: '\e8f2'; } /* '' */ +.icon-calendar-empty:before { content: '\e8f3'; } /* '' */ +.icon-calendar:before { content: '\e8f4'; } /* '' */ +.icon-login:before { content: '\e8f5'; } /* '' */ +.icon-logout:before { content: '\e8f6'; } /* '' */ +.icon-mic:before { content: '\e8f7'; } /* '' */ +.icon-mute:before { content: '\e8f8'; } /* '' */ +.icon-volume-off:before { content: '\e8f9'; } /* '' */ +.icon-volume-down:before { content: '\e8fa'; } /* '' */ +.icon-volume-up:before { content: '\e8fb'; } /* '' */ +.icon-headphones:before { content: '\e8fc'; } /* '' */ +.icon-clock:before { content: '\e8fd'; } /* '' */ +.icon-up-dir:before { content: '\e8fe'; } /* '' */ +.icon-down-dir:before { content: '\e8ff'; } /* '' */ +.icon-right-circled2:before { content: '\e900'; } /* '' */ +.icon-left-circled2:before { content: '\e901'; } /* 'î¤' */ +.icon-up-circled2:before { content: '\e902'; } /* '' */ +.icon-down-circled2:before { content: '\e903'; } /* '' */ +.icon-zoom-out:before { content: '\e904'; } /* '' */ +.icon-zoom-in:before { content: '\e905'; } /* '' */ +.icon-move:before { content: '\e906'; } /* '' */ +.icon-resize-horizontal:before { content: '\e907'; } /* '' */ +.icon-resize-vertical:before { content: '\e908'; } /* '' */ +.icon-resize-small:before { content: '\e909'; } /* '' */ +.icon-resize-full-alt:before { content: '\e90a'; } /* '' */ +.icon-resize-full:before { content: '\e90b'; } /* '' */ +.icon-block:before { content: '\e90c'; } /* '' */ +.icon-lightbulb:before { content: '\e90d'; } /* 'î¤' */ +.icon-left-dir:before { content: '\e90e'; } /* '' */ +.icon-right-dir:before { content: '\e90f'; } /* 'î¤' */ +.icon-down-open:before { content: '\e910'; } /* 'î¤' */ +.icon-up-open:before { content: '\e913'; } /* '' */ +.icon-angle-up:before { content: '\e916'; } /* '' */ +.icon-angle-down:before { content: '\e917'; } /* '' */ +.icon-angle-circled-left:before { content: '\e918'; } /* '' */ +.icon-angle-circled-right:before { content: '\e919'; } /* '' */ +.icon-angle-circled-down:before { content: '\e91a'; } /* '' */ +.icon-angle-circled-up:before { content: '\e91d'; } /* 'î¤' */ +.icon-scissors:before { content: '\e91e'; } /* '' */ +.icon-align-left:before { content: '\e91f'; } /* '' */ +.icon-mobile:before { content: '\e920'; } /* 'î¤ ' */ +.icon-play-circled2:before { content: '\e921'; } /* '' */ +.icon-right-circled:before { content: '\e922'; } /* '' */ +.icon-left-circled:before { content: '\e923'; } /* '' */ +.icon-play-circled:before { content: '\e924'; } /* '' */ +.icon-tablet:before { content: '\e925'; } /* '' */ +.icon-text-width:before { content: '\e926'; } /* '' */ +.icon-crop:before { content: '\e927'; } /* '' */ +.icon-columns:before { content: '\e928'; } /* '' */ +.icon-text-height:before { content: '\e929'; } /* '' */ +.icon-laptop:before { content: '\e92a'; } /* '' */ +.icon-play:before { content: '\e92b'; } /* '' */ +.icon-down-hand:before { content: '\e92c'; } /* '' */ +.icon-up-hand:before { content: '\e92d'; } /* 'î¤' */ +.icon-collapse-left:before { content: '\e92e'; } /* '' */ +.icon-desktop:before { content: '\e92f'; } /* '' */ +.icon-italic:before { content: '\e930'; } /* '' */ +.icon-table:before { content: '\e931'; } /* '' */ +.icon-subscript:before { content: '\e932'; } /* '' */ +.icon-bold:before { content: '\e933'; } /* '' */ +.icon-award:before { content: '\e934'; } /* '' */ +.icon-expand-right:before { content: '\e935'; } /* '' */ +.icon-left-hand:before { content: '\e936'; } /* '' */ +.icon-right-hand:before { content: '\e937'; } /* '' */ +.icon-signal:before { content: '\e938'; } /* '' */ +.icon-collapse:before { content: '\e939'; } /* '' */ +.icon-font:before { content: '\e93a'; } /* '' */ +.icon-superscript:before { content: '\e93b'; } /* '' */ +.icon-align-center:before { content: '\e93c'; } /* '' */ +.icon-align-right:before { content: '\e93d'; } /* '' */ +.icon-align-justify:before { content: '\e93e'; } /* '' */ +.icon-indent-left:before { content: '\e93f'; } /* '' */ +.icon-indent-right:before { content: '\e940'; } /* '' */ +.icon-list:before { content: '\e941'; } /* 'î¥' */ +.icon-list-bullet:before { content: '\e942'; } /* '' */ +.icon-list-numbered:before { content: '\e943'; } /* '' */ +.icon-strike:before { content: '\e944'; } /* '' */ +.icon-underline:before { content: '\e945'; } /* '' */ +.icon-leaf:before { content: '\e946'; } /* '' */ +.icon-fighter-jet:before { content: '\e947'; } /* '' */ +.icon-flight:before { content: '\e948'; } /* '' */ +.icon-umbrella:before { content: '\e949'; } /* '' */ +.icon-moon:before { content: '\e94a'; } /* '' */ +.icon-flash:before { content: '\e94b'; } /* '' */ +.icon-cloud:before { content: '\e94c'; } /* '' */ +.icon-sun:before { content: '\e94d'; } /* 'î¥' */ +.icon-globe:before { content: '\e94e'; } /* '' */ +.icon-inbox:before { content: '\e94f'; } /* 'î¥' */ +.icon-stop:before { content: '\e950'; } /* 'î¥' */ +.icon-pause:before { content: '\e951'; } /* '' */ +.icon-to-end:before { content: '\e952'; } /* '' */ +.icon-to-end-alt:before { content: '\e953'; } /* '' */ +.icon-to-start:before { content: '\e954'; } /* '' */ +.icon-fast-fw:before { content: '\e955'; } /* '' */ +.icon-to-start-alt:before { content: '\e956'; } /* '' */ +.icon-fast-bw:before { content: '\e957'; } /* '' */ +.icon-eject:before { content: '\e958'; } /* '' */ +.icon-target:before { content: '\e959'; } /* '' */ +.icon-expand:before { content: '\e95a'; } /* '' */ +.icon-exchange:before { content: '\e95b'; } /* '' */ +.icon-shuffle:before { content: '\e95c'; } /* '' */ +.icon-level-down:before { content: '\e95d'; } /* 'î¥' */ +.icon-arrows-cw:before { content: '\e95e'; } /* '' */ +.icon-level-up:before { content: '\e95f'; } /* '' */ +.icon-ccw:before { content: '\e960'; } /* 'î¥ ' */ +.icon-cw:before { content: '\e961'; } /* '' */ +.icon-down-circled:before { content: '\e962'; } /* '' */ +.icon-up-circled:before { content: '\e963'; } /* '' */ +.icon-angle-double-up:before { content: '\e964'; } /* '' */ +.icon-angle-double-down:before { content: '\e965'; } /* '' */ +.icon-down:before { content: '\e966'; } /* '' */ +.icon-left:before { content: '\e967'; } /* '' */ +.icon-right:before { content: '\e968'; } /* '' */ +.icon-up:before { content: '\e969'; } /* '' */ +.icon-down-big:before { content: '\e96a'; } /* '' */ +.icon-left-big:before { content: '\e96b'; } /* '' */ +.icon-right-big:before { content: '\e96c'; } /* '' */ +.icon-up-big:before { content: '\e96d'; } /* 'î¥' */ +.icon-bedroom:before { content: '\e96e'; } /* '' */ +.icon-fast-food:before { content: '\e96f'; } /* '' */ +.icon-police:before { content: '\e971'; } /* '' */ +.icon-elevator:before { content: '\e972'; } /* '' */ +.icon-food-1:before { content: '\e973'; } /* '' */ +.icon-pan:before { content: '\e974'; } /* '' */ +.icon-tap:before { content: '\e975'; } /* '' */ +.icon-gym:before { content: '\e976'; } /* '' */ +.icon-sports:before { content: '\e977'; } /* '' */ +.icon-football:before { content: '\e978'; } /* '' */ +.icon-tennis:before { content: '\e979'; } /* '' */ +.icon-fax:before { content: '\e97a'; } /* '' */ +.icon-taxi:before { content: '\e97b'; } /* '' */ +.icon-paragraph:before { content: '\e97c'; } /* '' */ diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index ae8e8f8c191..e2c30ccf16c 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -49,7 +49,7 @@ input:focus { height: 100%; .title { - flex: 1 1 @header-min-height; + flex: 1 0 @header-min-height; line-height: @header-min-height; @@ -62,8 +62,13 @@ input:focus { margin: 0; padding: 0 5px; font-size: 9pt; - display: table-cell; - vertical-align: middle; + display: inline-block; + } + + .toolbar { + display: inline-block; + float: right; + padding-right: 5px; } } .messages { @@ -286,7 +291,7 @@ input:focus { } } .footer { - flex: 1 1 @footer-min-height; + flex: 1 0 @footer-min-height; z-index: 10; diff --git a/packages/rocketchat-livechat/app/client/views/room.coffee b/packages/rocketchat-livechat/app/client/views/room.coffee deleted file mode 100644 index 351315925dc..00000000000 --- a/packages/rocketchat-livechat/app/client/views/room.coffee +++ /dev/null @@ -1,96 +0,0 @@ -Template.room.helpers - messages: -> - return ChatMessage.find { rid: visitor.getRoom(), t: { '$ne': 't' } }, { sort: { ts: 1 } } - - 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' - -Template.room.events - 'keyup .input-message': (event) -> - Template.instance().chatMessages.keyup(visitor.getRoom(), event, Template.instance()) - # Inital height is 28. If the scrollHeight is greater than that( we have more text than area ), - # increase the size of the textarea. The max-height is set at 200 - # even if the scrollHeight become bigger than that it should never exceed that. - # Account for no text in the textarea when increasing the height. - # If there is no text, reset the height. - inputScrollHeight = $(event.currentTarget).prop('scrollHeight') - if inputScrollHeight > 28 - $(event.currentTarget).height( if $(event.currentTarget).val() == '' then '15px' else (if inputScrollHeight >= 200 then inputScrollHeight-50 else inputScrollHeight-20)) - - 'keydown .input-message': (event) -> - Template.instance().chatMessages.keydown(visitor.getRoom(), event, Template.instance()) - - 'click .new-message': (e) -> - Template.instance().atBottom = true - Template.instance().find('.input-message').focus() - - 'click .title': -> - parentCall 'toggleWindow' - - 'click .error': (e) -> - $(e.currentTarget).removeClass('show') - -Template.room.onCreated -> - self = @ - self.autorun -> - self.subscribe 'livechat:visitorRoom', visitor.getToken(), -> - room = ChatRoom.findOne() - if room? - visitor.setRoom room._id - RoomHistoryManager.getMoreIfIsEmpty room._id - - self.subscribe 'settings', ['Livechat_title', 'Livechat_title_color'] - - self.atBottom = true - -Template.room.onRendered -> - this.chatMessages = new ChatMessages - this.chatMessages.init(this.firstNode) - -Template.room.onRendered -> - messages = this.find('.messages') - newMessage = this.find(".new-message") - - template = this - - onscroll = _.throttle -> - template.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight - , 200 - - Meteor.setInterval -> - if template.atBottom - messages.scrollTop = messages.scrollHeight - messages.clientHeight - newMessage.className = "new-message not" - , 100 - - messages.addEventListener 'touchstart', -> - template.atBottom = false - - messages.addEventListener 'touchend', -> - onscroll() - # readMessage.enable() - # readMessage.read() - - messages.addEventListener 'scroll', -> - template.atBottom = false - onscroll() - - messages.addEventListener 'mousewheel', -> - template.atBottom = false - onscroll() - # readMessage.enable() - # readMessage.read() - - messages.addEventListener 'wheel', -> - template.atBottom = false - onscroll() - # readMessage.enable() - # readMessage.read() - - # salva a data da renderização para exibir alertas de novas mensagens - # $.data(this.firstNode, 'renderedAt', new Date) diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/room.html index 4edc9dce073..18c40b4e09a 100644 --- a/packages/rocketchat-livechat/app/client/views/room.html +++ b/packages/rocketchat-livechat/app/client/views/room.html @@ -1,6 +1,11 @@ <template name="room"> <div class="livechat-room"> <div class="title" style="background-color:{{color}}"> + <div class="toolbar"> + {{#unless popoutActive}} + <i class="popout icon-link-ext" title="Open in a new window"></i> + {{/unless}} + </div> <h1>{{title}}</h1> </div> <div class="messages"> diff --git a/packages/rocketchat-livechat/app/client/views/room.js b/packages/rocketchat-livechat/app/client/views/room.js new file mode 100644 index 00000000000..7885a13f949 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/room.js @@ -0,0 +1,120 @@ +Template.room.helpers({ + messages: function() { + return ChatMessage.find({ + rid: visitor.getRoom(), + t: { + '$ne': 't' + } + }, { + sort: { + ts: 1 + } + }); + }, + title: function() { + var ref; + if (!Template.instance().subscriptionsReady()) { + return ''; + } + return ((ref = Settings.findOne('Livechat_title')) != null ? ref.value : void 0) || 'Rocket.Chat'; + }, + color: function() { + var ref; + if (!Template.instance().subscriptionsReady()) { + return 'transparent'; + } + return ((ref = Settings.findOne('Livechat_title_color')) != null ? ref.value : void 0) || '#C1272D'; + }, + popoutActive: function() { + return FlowRouter.getQueryParam('mode') === 'popout'; + } +}); + +Template.room.events({ + 'keyup .input-message': function(event) { + // Inital height is 28. If the scrollHeight is greater than that( we have more text than area ), + // increase the size of the textarea. The max-height is set at 200 + // even if the scrollHeight become bigger than that it should never exceed that. + // Account for no text in the textarea when increasing the height. + // If there is no text, reset the height. + var inputScrollHeight; + Template.instance().chatMessages.keyup(visitor.getRoom(), event, Template.instance()); + inputScrollHeight = $(event.currentTarget).prop('scrollHeight'); + if (inputScrollHeight > 28) { + return $(event.currentTarget).height($(event.currentTarget).val() === '' ? '15px' : (inputScrollHeight >= 200 ? inputScrollHeight - 50 : inputScrollHeight - 20)); + } + }, + 'keydown .input-message': function(event) { + return Template.instance().chatMessages.keydown(visitor.getRoom(), event, Template.instance()); + }, + 'click .new-message': function() { + Template.instance().atBottom = true; + return Template.instance().find('.input-message').focus(); + }, + 'click .title': function() { + return parentCall('toggleWindow'); + }, + 'click .error': function(event) { + return $(event.currentTarget).removeClass('show'); + }, + 'click .popout': function(event) { + event.stopPropagation(); + parentCall('openPopout'); + } +}); + +Template.room.onCreated(function() { + var self; + self = this; + self.autorun(function() { + self.subscribe('livechat:visitorRoom', visitor.getToken(), function() { + var room; + room = ChatRoom.findOne(); + if (room != null) { + visitor.setRoom(room._id); + RoomHistoryManager.getMoreIfIsEmpty(room._id); + } + }); + }); + self.subscribe('settings', ['Livechat_title', 'Livechat_title_color']); + self.atBottom = true; +}); + +Template.room.onRendered(function() { + this.chatMessages = new ChatMessages; + this.chatMessages.init(this.firstNode); +}); + +Template.room.onRendered(function() { + var messages, newMessage, onscroll, template; + messages = this.find('.messages'); + newMessage = this.find(".new-message"); + template = this; + onscroll = _.throttle(function() { + template.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight; + }, 200); + Meteor.setInterval(function() { + if (template.atBottom) { + messages.scrollTop = messages.scrollHeight - messages.clientHeight; + newMessage.className = "new-message not"; + } + }, 100); + messages.addEventListener('touchstart', function() { + template.atBottom = false; + }); + messages.addEventListener('touchend', function() { + onscroll(); + }); + messages.addEventListener('scroll', function() { + template.atBottom = false; + onscroll(); + }); + messages.addEventListener('mousewheel', function() { + template.atBottom = false; + onscroll(); + }); + messages.addEventListener('wheel', function() { + template.atBottom = false; + onscroll(); + }); +}); diff --git a/packages/rocketchat-livechat/rocket-livechat.js b/packages/rocketchat-livechat/rocket-livechat.js index 363881f57b9..1ad78293092 100644 --- a/packages/rocketchat-livechat/rocket-livechat.js +++ b/packages/rocketchat-livechat/rocket-livechat.js @@ -11,17 +11,31 @@ ;(function(w) { var exports = {}; + var config = {}; + var widget; + + var closeWidget = () => { + widget.dataset.state = 'closed'; + widget.style.height = '30px'; + }; + + var openWidget = () => { + widget.dataset.state = 'opened'; + widget.style.height = '300px'; + }; var api = { - toggleWindow: function() { - var widget = document.querySelector('.rocketchat-widget'); + toggleWindow: function(forceClose) { if (widget.dataset.state === 'closed') { - widget.dataset.state = 'opened'; - widget.style.height = '300px'; + openWidget(); } else { - widget.dataset.state = 'closed'; - widget.style.height = '30px'; + closeWidget(); } + }, + openPopout: function() { + closeWidget(); + var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no'); + popup.focus(); } }; @@ -30,6 +44,8 @@ return; } + config.url = url; + var chatWidget = document.createElement('div'); chatWidget.dataset.state = 'closed'; chatWidget.className = 'rocketchat-widget'; @@ -48,6 +64,8 @@ document.getElementsByTagName('body')[0].appendChild(chatWidget); + widget = document.querySelector('.rocketchat-widget'); + 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') { -- GitLab From 7730a0e6d62d86f9fb5a361a1cf4063541835371 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 10 Dec 2015 18:01:57 -0200 Subject: [PATCH 0800/1338] Livechat survey --- .../rocketchat-lib/client/MessageTypes.coffee | 5 +++++ .../rocketchat-lib/server/models/Messages.coffee | 3 +++ .../app/client/lib/tapi18n.coffee | 15 +++++++++++++++ .../app/client/views/message.coffee | 4 +++- .../rocketchat-livechat/app/i18n/en.i18n.json | 4 +++- server/methods/leaveRoom.coffee | 4 ++++ 6 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-livechat/app/client/lib/tapi18n.coffee diff --git a/packages/rocketchat-lib/client/MessageTypes.coffee b/packages/rocketchat-lib/client/MessageTypes.coffee index 3e374f4d7ca..d689491193b 100644 --- a/packages/rocketchat-lib/client/MessageTypes.coffee +++ b/packages/rocketchat-lib/client/MessageTypes.coffee @@ -68,3 +68,8 @@ Meteor.startup -> id: 'rtc' render: (message) -> RocketChat.callbacks.run 'renderRtcMessage', message + + RocketChat.MessageTypes.registerType + id: 'command' + system: true + render: -> diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 3d05788863c..107a0fe4108 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -269,6 +269,9 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base createRoomRenamedWithRoomIdRoomNameAndUser: (roomId, roomName, user, extraData) -> return @createWithTypeRoomIdMessageAndUser 'r', roomId, roomName, user, extraData + createCommandWithRoomIdAndUser: (command, roomId, user, extraData) -> + return @createWithTypeRoomIdMessageAndUser 'command', roomId, command, user, extraData + # REMOVE removeById: (_id) -> diff --git a/packages/rocketchat-livechat/app/client/lib/tapi18n.coffee b/packages/rocketchat-livechat/app/client/lib/tapi18n.coffee new file mode 100644 index 00000000000..1cf705e3952 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/lib/tapi18n.coffee @@ -0,0 +1,15 @@ +@t = (key, replaces...) -> + if _.isObject replaces[0] + return TAPi18n.__ key, replaces + else + return TAPi18n.__ key, { postProcess: 'sprintf', sprintf: replaces } + +@tr = (key, options, replaces...) -> + if _.isObject replaces[0] + return TAPi18n.__ key, options, replaces + else + return TAPi18n.__ key, options, { postProcess: 'sprintf', sprintf: replaces } + +@isRtl = (language) -> + # https://en.wikipedia.org/wiki/Right-to-left#cite_note-2 + return language?.split('-').shift().toLowerCase() in ['ar', 'dv', 'fa', 'he', 'ku', 'ps', 'sd', 'ug', 'ur', 'yi'] diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index 1b49884bd82..9bf0bc5d58e 100644 --- a/packages/rocketchat-livechat/app/client/views/message.coffee +++ b/packages/rocketchat-livechat/app/client/views/message.coffee @@ -26,6 +26,8 @@ Template.message.helpers when 'uj' then tr('User_joined_channel', { context: this.u.gender }, { user: this.u.username }) when 'wm' then t('Welcome', { user: this.u.username }) # when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this + when 'command' + if this.msg is 'survey' then t('Please_answer_survey') else this.html = this.msg if s.trim(this.html) isnt '' @@ -36,7 +38,7 @@ Template.message.helpers return this.html system: -> - return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj'] + return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj', 'command'] Template.message.onViewRendered = (context) -> diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index 03baaa5f9fb..137fe39c88e 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -3,5 +3,7 @@ "Name": "Name", "Message": "Message", "Please_fill_name_and_email": "Please fill name and e-mail", - "Start_Chat": "Start Chat" + "Start_Chat": "Start Chat", + "Please_answer_survey": "Please take a moment to answer a quick survey about this chat:", + "User_left" : "Has left the channel." } diff --git a/server/methods/leaveRoom.coffee b/server/methods/leaveRoom.coffee index e3f103ba6b6..4ff40c087fb 100644 --- a/server/methods/leaveRoom.coffee +++ b/server/methods/leaveRoom.coffee @@ -18,6 +18,10 @@ Meteor.methods RocketChat.models.Messages.createUserLeaveWithRoomIdAndUser rid, removedUser + if room.t is 'l' + RocketChat.models.Messages.createCommandWithRoomIdAndUser 'survey', rid, user + + if room.u?._id is Meteor.userId() newOwner = _.without(room.usernames, user.username)[0] if newOwner? -- GitLab From d92c55577549329b9d244ca47be974aac6c74c2e Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Thu, 10 Dec 2015 15:23:22 -0500 Subject: [PATCH 0801/1338] Set code blocks to always be LTR Code blocks and inline code that are preceded by RTL text will get displayed in RTL, and that breaks the formatting. This fix forces it to always display in LTR --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index f81703f69b1..f1671e6aad3 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -32,6 +32,11 @@ padding-right: 0px; } + code { + unicode-bidi: embed; + direction: ltr; + } + .side-nav { .right(0px); .header { -- GitLab From 17ff96d117e05bfe88a67c062e732c7bee106363 Mon Sep 17 00:00:00 2001 From: Jan Gerle <gerle@c2is.de> Date: Thu, 10 Dec 2015 22:31:54 +0100 Subject: [PATCH 0802/1338] fix broken image-link when og:image contains "&" (e.g. Google Maps) --- packages/rocketchat-oembed/client/oembedUrlWidget.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee index 95dd16ab012..3193a2df5a9 100644 --- a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee +++ b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee @@ -26,7 +26,9 @@ Template.oembedUrlWidget.helpers if not this.meta? return - return this.meta.ogImage or this.meta.twitterImage + decodedOgImage = @meta.ogImage.replace(/&/g, '&') + + return decodedOgImage or this.meta.twitterImage show: -> return getDescription(this)? or getTitle(this)? -- GitLab From 7ea024707df729e323df5448002723539c2f29ad Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Thu, 10 Dec 2015 18:54:47 -0500 Subject: [PATCH 0803/1338] Update to the previous pull https://github.com/RocketChat/Rocket.Chat/pull/1626 >Code blocks and inline code that are preceded by RTL text will get displayed in RTL, and that breaks the formatting. This fix forces it to always display in LTR Moved the changes to the `base.less` since it is not specific to RTL interface it also applies even if the user interface is LTR. --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 ++ packages/rocketchat-theme/assets/stylesheets/rtl.less | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 2ba3fe0465b..55ecffa41af 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -53,6 +53,8 @@ code { word-wrap: break-word; text-align: left; white-space: pre-wrap; + unicode-bidi: embed; + direction: ltr; &.inline { display: inline; padding: 0 0.5em; diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index f1671e6aad3..f81703f69b1 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -32,11 +32,6 @@ padding-right: 0px; } - code { - unicode-bidi: embed; - direction: ltr; - } - .side-nav { .right(0px); .header { -- GitLab From 60cea700879165a06a74f5c411515d08798be9b1 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 11:16:20 -0200 Subject: [PATCH 0804/1338] moved files to assets folder --- .../rocketchat-livechat/assets}/livechat-demo.html | 0 packages/rocketchat-livechat/{ => assets}/rocket-livechat.js | 0 packages/rocketchat-livechat/package.js | 3 ++- 3 files changed, 2 insertions(+), 1 deletion(-) rename {public => packages/rocketchat-livechat/assets}/livechat-demo.html (100%) rename packages/rocketchat-livechat/{ => assets}/rocket-livechat.js (100%) diff --git a/public/livechat-demo.html b/packages/rocketchat-livechat/assets/livechat-demo.html similarity index 100% rename from public/livechat-demo.html rename to packages/rocketchat-livechat/assets/livechat-demo.html diff --git a/packages/rocketchat-livechat/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js similarity index 100% rename from packages/rocketchat-livechat/rocket-livechat.js rename to packages/rocketchat-livechat/assets/rocket-livechat.js diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 0cc296524de..58c3d7f84e1 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -56,7 +56,8 @@ Package.onUse(function(api) { api.addFiles('server/publications/visitorRoom.js', 'server'); // livechat app - api.addAssets('rocket-livechat.js', 'client'); + api.addAssets('assets/demo.html', 'client'); + api.addAssets('assets/rocket-livechat.js', 'client'); api.addAssets('public/livechat.css', 'client'); api.addAssets('public/livechat.js', 'client'); api.addAssets('public/head.html', 'server'); -- GitLab From 4e5c84138abba65f369d275fae7cf98160e613e8 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 11:21:20 -0200 Subject: [PATCH 0805/1338] moved files to assets folder --- .../assets/{livechat-demo.html => demo.html} | 4 +++- packages/rocketchat-livechat/assets/rocket-livechat.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) rename packages/rocketchat-livechat/assets/{livechat-demo.html => demo.html} (74%) diff --git a/packages/rocketchat-livechat/assets/livechat-demo.html b/packages/rocketchat-livechat/assets/demo.html similarity index 74% rename from packages/rocketchat-livechat/assets/livechat-demo.html rename to packages/rocketchat-livechat/assets/demo.html index 512a7f8d0c6..8b3929901c4 100644 --- a/packages/rocketchat-livechat/assets/livechat-demo.html +++ b/packages/rocketchat-livechat/assets/demo.html @@ -8,12 +8,14 @@ var h = d.getElementsByTagName(s)[0], j = d.createElement(s); j.async = true; - j.src = '/packages/rocketchat_livechat/rocket-livechat.js'; + j.src = '/packages/rocketchat_livechat/assets/rocket-livechat.js'; h.parentNode.insertBefore(j, h); })(window, document, 'script', 'initRocket', '/livechat'); </script> </head> +<!-- Access: http://localhost:3000/packages/rocketchat_livechat/assets/demo.html --> + <body style="background-color: #EFEFEF"> <h1 style="color:#000">test</h1> <p style="color:#000">Talk to us.</p> diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index 1ad78293092..b7633e3073c 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -4,7 +4,7 @@ // var h = d.getElementsByTagName(s)[0], // j = d.createElement(s); // j.async = true; -// j.src = 'rocket-livechat.js'; +// j.src = '/packages/rocketchat_livechat/assets/rocket-livechat.js'; // h.parentNode.insertBefore(j, h); // })(window, document, 'script', 'initRocket', 'http://localhost:5000/livechat'); // </script> -- GitLab From e44c17fef153209882f693b3041e352252903253 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Fri, 11 Dec 2015 10:23:14 -0500 Subject: [PATCH 0806/1338] Fix for mentioning RTL names The current @mention (for user names and channel names) uses the regex `\b` to detect the name boundaries, however that token doesn't support unicode characters. This solution replaces the word boundary with regex that match end of the word with any of the following white space, colon, comma and dot. However, ending a name with a dot still has a problem as it doesn't get a mention link and this fix does not fix it. Part of the problem is that dots are allowed in the name validation regex. So this problem need to be solved later. Another thing that this fix adds is a description to the UTF8 Name Validation settings, to inform chat admins about the characters that they need to avoid using in their regexes to not break other chat functionalities that depends on special characters to denote special meanings. --- i18n/en.i18n.json | 1 + packages/rocketchat-lib/server/startup/settings.coffee | 2 +- packages/rocketchat-mentions/client.coffee | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index dff853cce2e..426e1ae7cb0 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -499,6 +499,7 @@ "Users" : "Users", "UTF8_Names_Slugify" : "UTF8 Names Slugify", "UTF8_Names_Validation" : "UTF8 Names Validation", + "UTF8_Names_Validation_Description" : "Do not allow special characters and spaces. You can use - _ and . but not at the end of the name", "View_All" : "View All", "Wait_activation_warning" : "Before you can login, your account must be manually activated by an administrator.", "We_have_sent_password_email" : "We have sent you an e-mail with password reset instructions. If you do not receive an e-mail shortly, please come back and try again.", diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 5597f56d1b3..e47f2b7dee7 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -61,7 +61,7 @@ RocketChat.settings.add 'Disable_Favorite_Rooms', false, { type: 'boolean', grou 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 } +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' diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index b61ca51c479..d83708e2bd6 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -19,7 +19,7 @@ class MentionsClient if mentions.length isnt 0 mentions = _.unique mentions mentions = mentions.join('|') - msg = msg.replace new RegExp("(?:^|\\s|\\n)(@(#{mentions}):?)\\b", 'g'), (match, mention, username) -> + msg = msg.replace new RegExp("(?:^|\\s|\\n)(@(#{mentions}):?)[:.,\s]?", 'g'), (match, mention, username) -> if username is 'all' return match.replace mention, "<a href=\"\" class=\"mention-link mention-link-me\">#{mention}</a>" @@ -41,7 +41,7 @@ class MentionsClient if channels.length isnt 0 channels = _.unique channels channels = channels.join('|') - msg = msg.replace new RegExp("(?:^|\\s|\\n)(#(#{channels}))\\b", 'g'), (match, mention, channel) -> + msg = msg.replace new RegExp("(?:^|\\s|\\n)(#(#{channels}))[:.,\s]?", 'g'), (match, mention, channel) -> if not message.temp? if not _.findWhere(message.channels, {name: channel})? return match -- GitLab From 9f50459ed833b24678c572c142472f21eb8e8b72 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 14:06:52 -0200 Subject: [PATCH 0807/1338] hack to centralize livechat toolbar --- packages/rocketchat-livechat/app/client/views/room.html | 1 + packages/rocketchat-livechat/app/client/views/room.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/room.html index 399bd055b7e..90c31283b2b 100644 --- a/packages/rocketchat-livechat/app/client/views/room.html +++ b/packages/rocketchat-livechat/app/client/views/room.html @@ -2,6 +2,7 @@ <div class="livechat-room"> <div class="title" style="background-color:{{color}}"> <div class="toolbar"> + {{#unless popoutActive}} <i class="popout icon-link-ext" title="Open in a new window"></i> {{/unless}} diff --git a/packages/rocketchat-livechat/app/client/views/room.js b/packages/rocketchat-livechat/app/client/views/room.js index 9e175b84ea9..530adb4d01f 100644 --- a/packages/rocketchat-livechat/app/client/views/room.js +++ b/packages/rocketchat-livechat/app/client/views/room.js @@ -20,8 +20,7 @@ Template.room.helpers({ Template.room.events({ 'click .title': function() { - console.log('toggleWindow'); - return parentCall('toggleWindow'); + parentCall('toggleWindow'); }, 'click .popout': function(event) { event.stopPropagation(); -- GitLab From 982569dc2bf2fbfa3aeb8cedad3bfef29d016a97 Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Fri, 11 Dec 2015 17:27:27 +0100 Subject: [PATCH 0808/1338] Show specific error message when trying to create a channel named like an archived one --- i18n/en.i18n.json | 1 + .../rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee | 3 +++ .../rocketchat-ui-sidenav/side-nav/createChannelFlex.html | 6 ++++++ server/methods/createChannel.coffee | 5 ++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1f024523cf4..a1c92e56044 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -134,6 +134,7 @@ "Disable_New_Message_Notification" : "Disable New Message Notification", "Disable_New_Room_Notification" : "Disable New Room Notification", "Drop_to_upload_file" : "Drop to upload file", + "Duplicate_archived_channel_name" : "An archived Channel 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", diff --git a/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/createChannelFlex.coffee index 7d5448acdb9..a6abfa19958 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 2f5e3043126..32f223608d2 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/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index 3c8319079d3..0fd82cb0c03 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -23,7 +23,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 -- GitLab From 801864c20335d45943f6d0c3dcc319fc3de99c12 Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Fri, 11 Dec 2015 17:39:10 +0100 Subject: [PATCH 0809/1338] Show specific error message when trying to create a private group named like an archived one --- i18n/en.i18n.json | 1 + .../rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee | 3 +++ .../rocketchat-ui-sidenav/side-nav/privateGroupsFlex.html | 6 ++++++ server/methods/createPrivateGroup.coffee | 5 ++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index a1c92e56044..aa8f22f21ab 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -136,6 +136,7 @@ "Drop_to_upload_file" : "Drop to upload file", "Duplicate_archived_channel_name" : "An archived Channel with name '%s' exists", "Duplicate_channel_name" : "A Channel with name '%s' exists", + "Duplicate_archived_private_group_name" : "An archived Private Group with name '%s' exists", "Duplicate_private_group_name" : "A Private Group with name '%s' exists", "E-mail" : "E-mail", "edited" : "edited", diff --git a/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/privateGroupsFlex.coffee index 2b8db2c1bd6..260dec67a5c 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 24e9050283e..821a4361efa 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/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 22080081372..11f068c08bd 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -26,7 +26,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' # create new room room = RocketChat.models.Rooms.createWithTypeNameUserAndUsernames 'p', name, me, members, -- GitLab From f838e9efb88902148d9cf0400d18802de24abc4c Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Fri, 11 Dec 2015 17:58:50 +0100 Subject: [PATCH 0810/1338] Add localization for archived/unarchived messages --- i18n/en.i18n.json | 2 ++ .../client/views/channelSettings.coffee | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index aa8f22f21ab..d194a0784fc 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -366,6 +366,8 @@ "Restart" : "Restart", "Restart_the_server" : "Restart the server", "Room" : "Room", + "Room_archived" : "Room archived", + "Room_unarchived" : "Room unarchived", "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", diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 18a254406ca..a325ef9f55e 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -22,14 +22,14 @@ Template.channelSettings.events Meteor.call 'archiveRoom', t.data.rid, true, (err, results) -> return toastr.error err.reason if err - toastr.success 'Channel archived' + toastr.success TAPi18n.__ 'Room_archived' 'click .unarchive': (e, t) -> e.preventDefault() Meteor.call 'unarchiveRoom', t.data.rid, true, (err, results) -> return toastr.error err.reason if err - toastr.success 'Channel unarchived' + toastr.success TAPi18n.__ 'Room_unarchived' # switch room.t # when 'c' -- GitLab From 741469bdc2e42aea988c29fa13d4ef253d1e48df Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 11 Dec 2015 15:15:03 -0200 Subject: [PATCH 0811/1338] Livechat Survey support --- .../server/models/Messages.coffee | 1 - .../rocketchat-livechat/app/.meteor/packages | 1 + .../rocketchat-livechat/app/.meteor/versions | 1 + .../lib/fromApp/RoomHistoryManager.coffee | 4 +- .../app/client/startup/room.coffee | 7 +- .../app/client/stylesheets/main.less | 116 +++++++++ .../client/stylesheets/utils/_octicons.less | 220 ++++++++++++++++++ .../app/client/views/message.coffee | 2 - .../app/client/views/survey.html | 66 ++++++ .../app/client/views/survey.js | 17 ++ .../rocketchat-livechat/app/i18n/en.i18n.json | 14 +- packages/rocketchat-livechat/package.js | 2 + .../server/methods/saveSurveyFeedback.js | 26 +++ .../server/models/Rooms.js | 17 ++ .../server/models/Users.js | 13 ++ 15 files changed, 500 insertions(+), 7 deletions(-) create mode 100644 packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less create mode 100644 packages/rocketchat-livechat/app/client/views/survey.html create mode 100644 packages/rocketchat-livechat/app/client/views/survey.js create mode 100644 packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js create mode 100644 packages/rocketchat-livechat/server/models/Rooms.js diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 107a0fe4108..b7449cddf47 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -272,7 +272,6 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base createCommandWithRoomIdAndUser: (command, roomId, user, extraData) -> return @createWithTypeRoomIdMessageAndUser 'command', roomId, command, user, extraData - # REMOVE removeById: (_id) -> query = diff --git a/packages/rocketchat-livechat/app/.meteor/packages b/packages/rocketchat-livechat/app/.meteor/packages index b1a1bda47a6..2f093f91006 100644 --- a/packages/rocketchat-livechat/app/.meteor/packages +++ b/packages/rocketchat-livechat/app/.meteor/packages @@ -35,3 +35,4 @@ reactive-var accounts-password standard-minifiers tap:i18n +kevohagan:sweetalert diff --git a/packages/rocketchat-livechat/app/.meteor/versions b/packages/rocketchat-livechat/app/.meteor/versions index fe32472575e..34a2055ee61 100644 --- a/packages/rocketchat-livechat/app/.meteor/versions +++ b/packages/rocketchat-livechat/app/.meteor/versions @@ -35,6 +35,7 @@ id-map@1.0.4 jquery@1.11.4 kadira:blaze-layout@2.3.0 kadira:flow-router@2.10.0 +kevohagan:sweetalert@1.0.0 konecty:nrr@2.0.2 less@2.5.1 livedata@1.0.15 diff --git a/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee b/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee index 08cec76ff0f..c12bd00df8d 100644 --- a/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee +++ b/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee @@ -30,7 +30,9 @@ ts = new Date Meteor.call 'loadHistory', rid, ts, limit, undefined, (err, result) -> - ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] + for item in result?.messages or [] + if item.t isnt 'command' + ChatMessage.upsert {_id: item._id}, item room.isLoading.set false room.loaded += result.messages.length if result.messages.length < limit diff --git a/packages/rocketchat-livechat/app/client/startup/room.coffee b/packages/rocketchat-livechat/app/client/startup/room.coffee index 81c83bb3e4b..cbed0d65ef5 100644 --- a/packages/rocketchat-livechat/app/client/startup/room.coffee +++ b/packages/rocketchat-livechat/app/client/startup/room.coffee @@ -2,4 +2,9 @@ msgStream = new Meteor.Stream 'messages' Tracker.autorun -> if visitor.getRoom()? msgStream.on visitor.getRoom(), (msg) -> - ChatMessage.upsert { _id: msg._id }, msg + if msg.t is 'command' + if msg.msg is 'survey' + unless $('body #survey').length + Blaze.render(Template.survey, $('body').get(0)) + else + ChatMessage.upsert { _id: msg._id }, msg diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index dd550d2ca65..625f0ecd8aa 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -40,6 +40,65 @@ input:focus { box-shadow: 0 0 0; } +.button { + &:extend(.unselectable); + display: inline-block; + padding: 9px 12px; + font-weight: 500; + font-size: 13px; + margin: 4px; + text-transform: uppercase; + word-spacing: 0; + box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.125); + border: none; + line-height: 16px; + position: relative; + cursor: pointer;background-color: #FFF; + color: rgba(255, 255, 255, 0.85); + background-color: lighten(desaturate(@primary-background-color, 15%), 12.5%); + span { + position: relative; + z-index: 2; + } + &:before { + background-color: rgba(0, 0, 0, 0.1); + content: " "; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; + z-index: 1; + .transition(opacity .1s ease-out); + } + &:hover { + text-decoration: none; + color: #FFF; + &:before { + opacity: 1; + } + } + &.secondary { + background-color: @tertiary-background-color; + color: @primary-font-color; + &:before { + background-color: rgba(0, 0, 0, 0.045); + } + } + &.clean { + font-size: 14px; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.08); + &.primary { + font-weight: 600; + } + } + &.button-block { + display: block; + width: 100%; + } +} + .livechat-room { position: fixed; top: 0; @@ -380,6 +439,63 @@ input:focus { } } +#survey { + .overlay { + background-color: rgba(0,0,0,0.5); + position: fixed; + height: 100%; + width: 100%; + + .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; + } + + .content { + overflow-y: scroll; + padding: 10px; + + .instructions { + margin-top: 5px; + } + + .survey-item { + margin-top: 20px; + + .question { + display: block; + } + + .answer { + margin-right: 5px; + } + } + } + + footer { + flex: 1 0 60px; + border-top: 1px solid rgba(0, 0, 0, 0.1); + line-height: 60px; + text-align: right; + padding-right: 20px; + } + } + } +} + @media all and(max-height: 200px) { .livechat-room { .title { diff --git a/packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less b/packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less new file mode 100644 index 00000000000..f7b02c4ed54 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less @@ -0,0 +1,220 @@ +@octicons-font-path: "/fonts/github"; +@octicons-version: "396334ee3da78f4302d25c758ae3e3ce5dc3c97d"; + +@font-face { + font-family: 'octicons'; + src: ~"url('@{octicons-font-path}/octicons.eot?#iefix&v=@{octicons-version}') format('embedded-opentype')", + ~"url('@{octicons-font-path}/octicons.woff?v=@{octicons-version}') format('woff')", + ~"url('@{octicons-font-path}/octicons.ttf?v=@{octicons-version}') format('truetype')", + ~"url('@{octicons-font-path}/octicons.svg?v=@{octicons-version}#octicons') format('svg')"; + font-weight: normal; + font-style: normal; +} + +// .octicon is optimized for 16px. +// .mega-octicon is optimized for 32px but can be used larger. +.octicon, .mega-octicon { + font: normal normal normal 16px/1 octicons; + display: inline-block; + text-decoration: none; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.mega-octicon { font-size: 32px; } + +.octicon-alert:before { content: '\f02d'} /* ï€ */ +.octicon-arrow-down:before { content: '\f03f'} /*  */ +.octicon-arrow-left:before { content: '\f040'} /* ï€ */ +.octicon-arrow-right:before { content: '\f03e'} /*  */ +.octicon-arrow-small-down:before { content: '\f0a0'} /* ï‚ */ +.octicon-arrow-small-left:before { content: '\f0a1'} /* ï‚¡ */ +.octicon-arrow-small-right:before { content: '\f071'} /* ï± */ +.octicon-arrow-small-up:before { content: '\f09f'} /* ï‚Ÿ */ +.octicon-arrow-up:before { content: '\f03d'} /*  */ +.octicon-microscope:before, +.octicon-beaker:before { content: '\f0dd'} /* ïƒ */ +.octicon-bell:before { content: '\f0de'} /*  */ +.octicon-book:before { content: '\f007'} /*  */ +.octicon-bookmark:before { content: '\f07b'} /* ï» */ +.octicon-briefcase:before { content: '\f0d3'} /*  */ +.octicon-broadcast:before { content: '\f048'} /* ïˆ */ +.octicon-browser:before { content: '\f0c5'} /*  */ +.octicon-bug:before { content: '\f091'} /* ï‚‘ */ +.octicon-calendar:before { content: '\f068'} /* ï¨ */ +.octicon-check:before { content: '\f03a'} /*  */ +.octicon-checklist:before { content: '\f076'} /* ï¶ */ +.octicon-chevron-down:before { content: '\f0a3'} /* ï‚£ */ +.octicon-chevron-left:before { content: '\f0a4'} /*  */ +.octicon-chevron-right:before { content: '\f078'} /* ï¸ */ +.octicon-chevron-up:before { content: '\f0a2'} /* ï‚¢ */ +.octicon-circle-slash:before { content: '\f084'} /* ï‚„ */ +.octicon-circuit-board:before { content: '\f0d6'} /*  */ +.octicon-clippy:before { content: '\f035'} /*  */ +.octicon-clock:before { content: '\f046'} /* ï† */ +.octicon-cloud-download:before { content: '\f00b'} /*  */ +.octicon-cloud-upload:before { content: '\f00c'} /*  */ +.octicon-code:before { content: '\f05f'} /* ïŸ */ +.octicon-color-mode:before { content: '\f065'} /* ï¥ */ +.octicon-comment-add:before, +.octicon-comment:before { content: '\f02b'} /*  */ +.octicon-comment-discussion:before { content: '\f04f'} /* ï */ +.octicon-credit-card:before { content: '\f045'} /* ï… */ +.octicon-dash:before { content: '\f0ca'} /*  */ +.octicon-dashboard:before { content: '\f07d'} /* ï½ */ +.octicon-database:before { content: '\f096'} /* ï‚– */ +.octicon-clone:before, +.octicon-desktop-download:before { content: '\f0dc'} /*  */ +.octicon-device-camera:before { content: '\f056'} /* ï– */ +.octicon-device-camera-video:before { content: '\f057'} /* ï— */ +.octicon-device-desktop:before { content: '\f27c'} /*  */ +.octicon-device-mobile:before { content: '\f038'} /*  */ +.octicon-diff:before { content: '\f04d'} /* ï */ +.octicon-diff-added:before { content: '\f06b'} /* ï« */ +.octicon-diff-ignored:before { content: '\f099'} /* ï‚™ */ +.octicon-diff-modified:before { content: '\f06d'} /* ï */ +.octicon-diff-removed:before { content: '\f06c'} /* ï¬ */ +.octicon-diff-renamed:before { content: '\f06e'} /* ï® */ +.octicon-ellipsis:before { content: '\f09a'} /* ï‚š */ +.octicon-eye-unwatch:before, +.octicon-eye-watch:before, +.octicon-eye:before { content: '\f04e'} /* ïŽ */ +.octicon-file-binary:before { content: '\f094'} /* ï‚” */ +.octicon-file-code:before { content: '\f010'} /* ï€ */ +.octicon-file-directory:before { content: '\f016'} /*  */ +.octicon-file-media:before { content: '\f012'} /*  */ +.octicon-file-pdf:before { content: '\f014'} /*  */ +.octicon-file-submodule:before { content: '\f017'} /*  */ +.octicon-file-symlink-directory:before { content: '\f0b1'} /*  */ +.octicon-file-symlink-file:before { content: '\f0b0'} /* ï‚° */ +.octicon-file-text:before { content: '\f011'} /*  */ +.octicon-file-zip:before { content: '\f013'} /*  */ +.octicon-flame:before { content: '\f0d2'} /*  */ +.octicon-fold:before { content: '\f0cc'} /*  */ +.octicon-gear:before { content: '\f02f'} /*  */ +.octicon-gift:before { content: '\f042'} /* ï‚ */ +.octicon-gist:before { content: '\f00e'} /*  */ +.octicon-gist-secret:before { content: '\f08c'} /* ï‚Œ */ +.octicon-git-branch-create:before, +.octicon-git-branch-delete:before, +.octicon-git-branch:before { content: '\f020'} /* ï€ */ +.octicon-git-commit:before { content: '\f01f'} /*  */ +.octicon-git-compare:before { content: '\f0ac'} /*  */ +.octicon-git-merge:before { content: '\f023'} /*  */ +.octicon-git-pull-request-abandoned:before, +.octicon-git-pull-request:before { content: '\f009'} /*  */ +.octicon-globe:before { content: '\f0b6'} /*  */ +.octicon-graph:before { content: '\f043'} /* ïƒ */ +.octicon-heart:before { content: '\2665'} /* ♥ */ +.octicon-history:before { content: '\f07e'} /* ï¾ */ +.octicon-home:before { content: '\f08d'} /* ï‚ */ +.octicon-horizontal-rule:before { content: '\f070'} /* ï° */ +.octicon-hubot:before { content: '\f09d'} /* ï‚ */ +.octicon-inbox:before { content: '\f0cf'} /* ïƒ */ +.octicon-info:before { content: '\f059'} /* ï™ */ +.octicon-issue-closed:before { content: '\f028'} /*  */ +.octicon-issue-opened:before { content: '\f026'} /*  */ +.octicon-issue-reopened:before { content: '\f027'} /*  */ +.octicon-jersey:before { content: '\f019'} /*  */ +.octicon-key:before { content: '\f049'} /* ï‰ */ +.octicon-keyboard:before { content: '\f00d'} /* ï€ */ +.octicon-law:before { content: '\f0d8'} /*  */ +.octicon-light-bulb:before { content: '\f000'} /*  */ +.octicon-link:before { content: '\f05c'} /* ïœ */ +.octicon-link-external:before { content: '\f07f'} /* ï¿ */ +.octicon-list-ordered:before { content: '\f062'} /* ï¢ */ +.octicon-list-unordered:before { content: '\f061'} /* ï¡ */ +.octicon-location:before { content: '\f060'} /* ï */ +.octicon-gist-private:before, +.octicon-mirror-private:before, +.octicon-git-fork-private:before, +.octicon-lock:before { content: '\f06a'} /* ïª */ +.octicon-logo-github:before { content: '\f092'} /* ï‚’ */ +.octicon-mail:before { content: '\f03b'} /*  */ +.octicon-mail-read:before { content: '\f03c'} /*  */ +.octicon-mail-reply:before { content: '\f051'} /* ï‘ */ +.octicon-mark-github:before { content: '\f00a'} /*  */ +.octicon-markdown:before { content: '\f0c9'} /*  */ +.octicon-megaphone:before { content: '\f077'} /* ï· */ +.octicon-mention:before { content: '\f0be'} /*  */ +.octicon-milestone:before { content: '\f075'} /* ïµ */ +.octicon-mirror-public:before, +.octicon-mirror:before { content: '\f024'} /*  */ +.octicon-mortar-board:before { content: '\f0d7'} /*  */ +.octicon-mute:before { content: '\f080'} /* ï‚€ */ +.octicon-no-newline:before { content: '\f09c'} /* ï‚œ */ +.octicon-octoface:before { content: '\f008'} /*  */ +.octicon-organization:before { content: '\f037'} /*  */ +.octicon-package:before { content: '\f0c4'} /*  */ +.octicon-paintcan:before { content: '\f0d1'} /*  */ +.octicon-pencil:before { content: '\f058'} /* ï˜ */ +.octicon-person-add:before, +.octicon-person-follow:before, +.octicon-person:before { content: '\f018'} /*  */ +.octicon-pin:before { content: '\f041'} /* ï */ +.octicon-plug:before { content: '\f0d4'} /*  */ +.octicon-repo-create:before, +.octicon-gist-new:before, +.octicon-file-directory-create:before, +.octicon-file-add:before, +.octicon-plus:before { content: '\f05d'} /* ï */ +.octicon-primitive-dot:before { content: '\f052'} /* ï’ */ +.octicon-primitive-square:before { content: '\f053'} /* ï“ */ +.octicon-pulse:before { content: '\f085'} /* ï‚… */ +.octicon-question:before { content: '\f02c'} /*  */ +.octicon-quote:before { content: '\f063'} /* ï£ */ +.octicon-radio-tower:before { content: '\f030'} /*  */ +.octicon-repo-delete:before, +.octicon-repo:before { content: '\f001'} /* ï€ */ +.octicon-repo-clone:before { content: '\f04c'} /* ïŒ */ +.octicon-repo-force-push:before { content: '\f04a'} /* ïŠ */ +.octicon-gist-fork:before, +.octicon-repo-forked:before { content: '\f002'} /*  */ +.octicon-repo-pull:before { content: '\f006'} /*  */ +.octicon-repo-push:before { content: '\f005'} /*  */ +.octicon-rocket:before { content: '\f033'} /*  */ +.octicon-rss:before { content: '\f034'} /*  */ +.octicon-ruby:before { content: '\f047'} /* ï‡ */ +.octicon-screen-full:before { content: '\f066'} /* ï¦ */ +.octicon-screen-normal:before { content: '\f067'} /* ï§ */ +.octicon-search-save:before, +.octicon-search:before { content: '\f02e'} /*  */ +.octicon-server:before { content: '\f097'} /* ï‚— */ +.octicon-settings:before { content: '\f07c'} /* ï¼ */ +.octicon-shield:before { content: '\f0e1'} /*  */ +.octicon-log-in:before, +.octicon-sign-in:before { content: '\f036'} /*  */ +.octicon-log-out:before, +.octicon-sign-out:before { content: '\f032'} /*  */ +.octicon-squirrel:before { content: '\f0b2'} /*  */ +.octicon-star-add:before, +.octicon-star-delete:before, +.octicon-star:before { content: '\f02a'} /*  */ +.octicon-stop:before { content: '\f08f'} /* ï‚ */ +.octicon-repo-sync:before, +.octicon-sync:before { content: '\f087'} /*  */ +.octicon-tag-remove:before, +.octicon-tag-add:before, +.octicon-tag:before { content: '\f015'} /*  */ +.octicon-telescope:before { content: '\f088'} /*  */ +.octicon-terminal:before { content: '\f0c8'} /*  */ +.octicon-three-bars:before { content: '\f05e'} /* ïž */ +.octicon-thumbsdown:before { content: '\f0db'} /*  */ +.octicon-thumbsup:before { content: '\f0da'} /*  */ +.octicon-tools:before { content: '\f031'} /*  */ +.octicon-trashcan:before { content: '\f0d0'} /* ïƒ */ +.octicon-triangle-down:before { content: '\f05b'} /* ï› */ +.octicon-triangle-left:before { content: '\f044'} /* ï„ */ +.octicon-triangle-right:before { content: '\f05a'} /* ïš */ +.octicon-triangle-up:before { content: '\f0aa'} /*  */ +.octicon-unfold:before { content: '\f039'} /*  */ +.octicon-unmute:before { content: '\f0ba'} /*  */ +.octicon-versions:before { content: '\f064'} /* ï¤ */ +.octicon-watch:before { content: '\f0e0'} /* ïƒ */ +.octicon-remove-close:before, +.octicon-x:before { content: '\f081'} /* ï‚ */ +.octicon-zap:before { content: '\26A1'} /* âš¡ */ diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index 9bf0bc5d58e..ddb72c419b6 100644 --- a/packages/rocketchat-livechat/app/client/views/message.coffee +++ b/packages/rocketchat-livechat/app/client/views/message.coffee @@ -26,8 +26,6 @@ Template.message.helpers when 'uj' then tr('User_joined_channel', { context: this.u.gender }, { user: this.u.username }) when 'wm' then t('Welcome', { user: this.u.username }) # when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this - when 'command' - if this.msg is 'survey' then t('Please_answer_survey') else this.html = this.msg if s.trim(this.html) isnt '' diff --git a/packages/rocketchat-livechat/app/client/views/survey.html b/packages/rocketchat-livechat/app/client/views/survey.html new file mode 100644 index 00000000000..07babef73d2 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/survey.html @@ -0,0 +1,66 @@ +<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> + </div> + </div> +</template> diff --git a/packages/rocketchat-livechat/app/client/views/survey.js b/packages/rocketchat-livechat/app/client/views/survey.js new file mode 100644 index 00000000000..95b4919a887 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/survey.js @@ -0,0 +1,17 @@ +Template.survey.events({ + 'click button.skip': function(e, instance) { + instance.$('#survey').remove(); + }, + + 'click button.send': function(e, instance) { + formData = instance.$('form').serializeArray(); + Meteor.call('livechat:saveSurveyFeedback', visitor.getToken(), visitor.getRoom(), formData, function(err, results) { + instance.$('#survey').remove(); + swal({ + title: t('Thank_you_for_your_feedback'), + type: 'success', + timer: 2000 + }); + }); + } +}) diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index 137fe39c88e..8d6e2fe32e6 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -1,9 +1,19 @@ { + "Additional_Feedback": "Additional Feedback", + "Skip": "Skip", "E-mail": "E-mail", - "Name": "Name", + "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", + "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", "Start_Chat": "Start Chat", - "Please_answer_survey": "Please take a moment to answer a quick survey about this 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." } diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 882c160f666..1afe1e02269 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -52,12 +52,14 @@ Package.onUse(function(api) { api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); api.addFiles('server/methods/saveDepartment.js', 'server'); + api.addFiles('server/methods/saveSurveyFeedback.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'); // models api.addFiles('server/models/Users.js', 'server'); + api.addFiles('server/models/Rooms.js', 'server'); api.addFiles('server/models/LivechatDepartment.js', 'server'); // collections diff --git a/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js b/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js new file mode 100644 index 00000000000..44d8fd05767 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js @@ -0,0 +1,26 @@ +Meteor.methods({ + 'livechat:saveSurveyFeedback' (visitorToken, visitorRoom, formData) { + check(visitorToken, String); + 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); + + if (visitor !== undefined && room !== undefined && room.v !== undefined && visitor.profile !== undefined && room.v.token === visitor.profile.token) { + updateData = {}; + for (var item of formData) { + if (_.contains(['satisfaction', 'agentKnowledge', 'agentResposiveness', 'agentFriendliness'], item.name) && _.contains(["1","2","3","4","5"], item.value)) { + updateData[item.name] = item.value; + } else if (item.name === 'additionalFeedback') { + updateData[item.name] = item.value; + } + } + if (!_.isEmpty(updateData)) { + return RocketChat.models.Rooms.updateSurveyFeedbackById(room._id, updateData); + } + } + } +}); diff --git a/packages/rocketchat-livechat/server/models/Rooms.js b/packages/rocketchat-livechat/server/models/Rooms.js new file mode 100644 index 00000000000..d1a654f2493 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/Rooms.js @@ -0,0 +1,17 @@ +/** + * Gets visitor by token + * @param {string} token - Visitor token + */ +RocketChat.models.Rooms.updateSurveyFeedbackById = function(_id, surveyFeedback) { + query = { + _id: _id + }; + + update = { + $set: { + surveyFeedback: surveyFeedback + } + }; + + return this.update(query, update); +}; diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index adc6863d011..1481564cf1d 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -12,3 +12,16 @@ RocketChat.models.Users.setOperator = function(_id, operator) { return this.update(_id, update); }; + +/** + * Gets visitor by token + * @param {string} token - Visitor token + */ +RocketChat.models.Users.getVisitorByToken = function(token, options) { + var query = { + "profile.guest": true, + "profile.token": token + }; + + return this.findOne(query, options); +}; -- GitLab From 8fa87c280732d78b2e100962e022107a5bd18ee0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 11 Dec 2015 15:20:15 -0200 Subject: [PATCH 0812/1338] Prompt users to install extentions to enable screen sharing --- i18n/en.i18n.json | 3 ++ .../rocketchat-ui-master/master/main.html | 1 + .../views/app/videoCall/videoCall.coffee | 4 +-- .../views/app/videoCall/videoCall.html | 2 +- packages/rocketchat-webrtc/WebRTCClass.coffee | 32 +++++++++++++++++-- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 426e1ae7cb0..defdb3b3930 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -494,6 +494,9 @@ "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "Username_description" : "The username is used to allow others to mention you in messages.", "Username_invalid" : "<strong>%s</strong> is not a valid username,<br/> use only letters, numbers, dots and dashes", + "Screen_Share" : "Screen Share", + "You_need_install_an_extension_to_allow_screen_sharing" : "You need install an extension to allow screen sharing", + "Install_Extension" : "Install Extension", "Username_title" : "Register username", "Username_unavaliable" : "<strong>%s</strong> is already in use :(", "Users" : "Users", diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index 4219a22d722..abf74f660a8 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -13,6 +13,7 @@ <meta name="msapplication-config" content="/images/logo/browserconfig.xml?v=3"> <meta name="theme-color" content="#04436a"> <link rel="manifest" href="/images/logo/manifest.json?v=3"> + <link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/nocfbnnmjnndkbipkabodnheejiegccf"> <link rel="icon" sizes="any" type="image/svg+xml" href="/assets/favicon.svg?v=3"> <link rel="icon" sizes="256x256" type="image/png" href="/assets/favicon_256.png?v=3"> <link rel="icon" sizes="192x192" type="image/png" href="/assets/favicon_192.png?v=3"> diff --git a/packages/rocketchat-ui/views/app/videoCall/videoCall.coffee b/packages/rocketchat-ui/views/app/videoCall/videoCall.coffee index a3431aa73a0..d0ac0bab637 100644 --- a/packages/rocketchat-ui/views/app/videoCall/videoCall.coffee +++ b/packages/rocketchat-ui/views/app/videoCall/videoCall.coffee @@ -29,8 +29,8 @@ Template.videoCall.helpers audioAndVideoEnabled: -> return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).audioEnabled.get() and WebRTC.getInstanceByRoomId(Session.get('openedRoom')).videoEnabled.get() - screenShareAvaliable: -> - return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareAvaliable + screenShareAvailable: -> + return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareAvailable screenShareEnabled: -> return WebRTC.getInstanceByRoomId(Session.get('openedRoom')).screenShareEnabled.get() diff --git a/packages/rocketchat-ui/views/app/videoCall/videoCall.html b/packages/rocketchat-ui/views/app/videoCall/videoCall.html index bf473be61e6..38ed5e6d774 100644 --- a/packages/rocketchat-ui/views/app/videoCall/videoCall.html +++ b/packages/rocketchat-ui/views/app/videoCall/videoCall.html @@ -43,7 +43,7 @@ {{else}} <button class="enable-video button"><i class="icon-eye"></i></button> {{/if}} - {{#if screenShareAvaliable}} + {{#if screenShareAvailable}} {{#if screenShareEnabled}} <button class="disable-screen-share button red"><i class="icon-desktop"></i></button> {{else}} diff --git a/packages/rocketchat-webrtc/WebRTCClass.coffee b/packages/rocketchat-webrtc/WebRTCClass.coffee index ffa9785b84b..eee787913b4 100644 --- a/packages/rocketchat-webrtc/WebRTCClass.coffee +++ b/packages/rocketchat-webrtc/WebRTCClass.coffee @@ -135,8 +135,15 @@ class WebRTCClass @monitor = false @autoAccept = false - @navigator = if navigator.mozGetUserMedia? then 'firefox' else 'chrome' - @screenShareAvaliable = document.cookie.includes('rocketchatscreenshare=chrome') is true or window.rocketchatscreenshare is 'firefox' + @navigator = undefined + if navigator.userAgent.toLocaleLowerCase().indexOf('chrome') > -1 + @navigator = 'chrome' + else if navigator.userAgent.toLocaleLowerCase().indexOf('firefox') > -1 + @navigator = 'firefox' + else if navigator.userAgent.toLocaleLowerCase().indexOf('safari') > -1 + @navigator = 'safari' + + @screenShareAvailable = @navigator in ['chrome', 'firefox'] @media = video: true @@ -308,11 +315,30 @@ class WebRTCClass navigator.getUserMedia media, onSuccess, onError return - if @screenShareAvaliable isnt true + if @screenShareAvailable isnt true console.log 'Screen share is not avaliable' return getScreen = (audioStream) => + if document.cookie.indexOf("rocketchatscreenshare=chrome") is -1 and not window.rocketchatscreenshare? + swal + type: "warning" + title: TAPi18n.__ "Screen_Share" + text: TAPi18n.__ "You_need_install_an_extension_to_allow_screen_sharing" + html: true + showCancelButton: true + confirmButtonText: TAPi18n.__ "Install_Extension" + cancelButtonText: TAPi18n.__ "Cancel" + , (isConfirm) => + if isConfirm + if @navigator is 'chrome' + chrome.webstore.install undefined, undefined, -> + window.open('https://chrome.google.com/webstore/detail/rocketchat-screen-share/nocfbnnmjnndkbipkabodnheejiegccf') + else if @navigator is 'firefox' + window.open('https://addons.mozilla.org/en-GB/firefox/addon/rocketchat-screen-share/') + + return + getScreenSuccess = (stream) => if audioStream? stream.addTrack(audioStream.getAudioTracks()[0]) -- GitLab From b42cec3e939f4b565347bc7122ebb2e1416d6fd6 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 11 Dec 2015 15:23:21 -0200 Subject: [PATCH 0813/1338] no message --- packages/rocketchat-livechat/app/client/stylesheets/main.less | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 625f0ecd8aa..ed49071d21a 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -467,6 +467,7 @@ input:focus { .content { overflow-y: scroll; padding: 10px; + flex: 1 1 100%; .instructions { margin-top: 5px; -- GitLab From 1d2b1587f90abd8f4e6e57bdc3c6e4b8463812fe Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 11 Dec 2015 15:36:22 -0200 Subject: [PATCH 0814/1338] Inform user to refresh page after extension install --- i18n/en.i18n.json | 7 +++--- packages/rocketchat-webrtc/WebRTCClass.coffee | 22 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index defdb3b3930..fd9d852178e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -175,6 +175,7 @@ "hours" : "hours", "Incorrect_Password" : "Incorrect Password", "inline_code" : "inline_code", + "Install_Extension" : "Install Extension", "Install_FxOs" : "Install Rocket.Chat on your Firefox", "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:", @@ -356,6 +357,7 @@ "quote" : "quote", "Recents" : "Recents", "Record" : "Record", + "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", @@ -382,6 +384,7 @@ "SAML_Custom_Provider" : "Custom Provider", "Save_changes" : "Save changes", "Save_Mobile_Bandwidth" : "Save Mobile Bandwidth", + "Screen_Share" : "Screen Share", "Search" : "Search", "Search_Messages" : "Search Messages", "Search_settings" : "Search settings", @@ -494,9 +497,6 @@ "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "Username_description" : "The username is used to allow others to mention you in messages.", "Username_invalid" : "<strong>%s</strong> is not a valid username,<br/> use only letters, numbers, dots and dashes", - "Screen_Share" : "Screen Share", - "You_need_install_an_extension_to_allow_screen_sharing" : "You need install an extension to allow screen sharing", - "Install_Extension" : "Install Extension", "Username_title" : "Register username", "Username_unavaliable" : "<strong>%s</strong> is already in use :(", "Users" : "Users", @@ -516,6 +516,7 @@ "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_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.", diff --git a/packages/rocketchat-webrtc/WebRTCClass.coffee b/packages/rocketchat-webrtc/WebRTCClass.coffee index eee787913b4..b57170eb620 100644 --- a/packages/rocketchat-webrtc/WebRTCClass.coffee +++ b/packages/rocketchat-webrtc/WebRTCClass.coffee @@ -321,6 +321,11 @@ class WebRTCClass getScreen = (audioStream) => if document.cookie.indexOf("rocketchatscreenshare=chrome") is -1 and not window.rocketchatscreenshare? + refresh = -> + swal + type: "warning" + title: TAPi18n.__ "Refresh_your_page_after_install_to_enable_screen_sharing" + swal type: "warning" title: TAPi18n.__ "Screen_Share" @@ -332,12 +337,14 @@ class WebRTCClass , (isConfirm) => if isConfirm if @navigator is 'chrome' - chrome.webstore.install undefined, undefined, -> + chrome.webstore.install undefined, refresh, -> window.open('https://chrome.google.com/webstore/detail/rocketchat-screen-share/nocfbnnmjnndkbipkabodnheejiegccf') + refresh() else if @navigator is 'firefox' window.open('https://addons.mozilla.org/en-GB/firefox/addon/rocketchat-screen-share/') + refresh() - return + return onError(false) getScreenSuccess = (stream) => if audioStream? @@ -350,7 +357,6 @@ class WebRTCClass video: mozMediaSource: 'window' mediaSource: 'window' - navigator.getUserMedia media, getScreenSuccess, onError else ChromeScreenShare.getSourceId (id) => @@ -399,7 +405,11 @@ class WebRTCClass callback null, @localStream - @getUserMedia @media, onSuccess, @onError + onError = (error) => + callback false + @onError error + + @getUserMedia @media, onSuccess, onError ### @@ -458,7 +468,9 @@ class WebRTCClass if @localStream? @media.desktop = enabled delete @localStream - @getLocalUserMedia => + @getLocalUserMedia (err) => + if err? + return @screenShareEnabled.set enabled @stopAllPeerConnections() @joinCall() -- GitLab From e93493b99ee84400ef9b65e223d43719af926bf8 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 11 Dec 2015 15:38:39 -0200 Subject: [PATCH 0815/1338] Livechat Survey --- .../rocketchat-lib/client/MessageTypes.coffee | 5 - .../client/stylesheets/utils/_octicons.less | 220 ------------------ .../app/client/views/message.coffee | 2 +- .../lib/RoomHistoryManager.coffee | 2 +- packages/rocketchat-ui/lib/RoomManager.coffee | 11 +- 5 files changed, 8 insertions(+), 232 deletions(-) delete mode 100644 packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less diff --git a/packages/rocketchat-lib/client/MessageTypes.coffee b/packages/rocketchat-lib/client/MessageTypes.coffee index d689491193b..3e374f4d7ca 100644 --- a/packages/rocketchat-lib/client/MessageTypes.coffee +++ b/packages/rocketchat-lib/client/MessageTypes.coffee @@ -68,8 +68,3 @@ Meteor.startup -> id: 'rtc' render: (message) -> RocketChat.callbacks.run 'renderRtcMessage', message - - RocketChat.MessageTypes.registerType - id: 'command' - system: true - render: -> diff --git a/packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less b/packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less deleted file mode 100644 index f7b02c4ed54..00000000000 --- a/packages/rocketchat-livechat/app/client/stylesheets/utils/_octicons.less +++ /dev/null @@ -1,220 +0,0 @@ -@octicons-font-path: "/fonts/github"; -@octicons-version: "396334ee3da78f4302d25c758ae3e3ce5dc3c97d"; - -@font-face { - font-family: 'octicons'; - src: ~"url('@{octicons-font-path}/octicons.eot?#iefix&v=@{octicons-version}') format('embedded-opentype')", - ~"url('@{octicons-font-path}/octicons.woff?v=@{octicons-version}') format('woff')", - ~"url('@{octicons-font-path}/octicons.ttf?v=@{octicons-version}') format('truetype')", - ~"url('@{octicons-font-path}/octicons.svg?v=@{octicons-version}#octicons') format('svg')"; - font-weight: normal; - font-style: normal; -} - -// .octicon is optimized for 16px. -// .mega-octicon is optimized for 32px but can be used larger. -.octicon, .mega-octicon { - font: normal normal normal 16px/1 octicons; - display: inline-block; - text-decoration: none; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.mega-octicon { font-size: 32px; } - -.octicon-alert:before { content: '\f02d'} /* ï€ */ -.octicon-arrow-down:before { content: '\f03f'} /*  */ -.octicon-arrow-left:before { content: '\f040'} /* ï€ */ -.octicon-arrow-right:before { content: '\f03e'} /*  */ -.octicon-arrow-small-down:before { content: '\f0a0'} /* ï‚ */ -.octicon-arrow-small-left:before { content: '\f0a1'} /* ï‚¡ */ -.octicon-arrow-small-right:before { content: '\f071'} /* ï± */ -.octicon-arrow-small-up:before { content: '\f09f'} /* ï‚Ÿ */ -.octicon-arrow-up:before { content: '\f03d'} /*  */ -.octicon-microscope:before, -.octicon-beaker:before { content: '\f0dd'} /* ïƒ */ -.octicon-bell:before { content: '\f0de'} /*  */ -.octicon-book:before { content: '\f007'} /*  */ -.octicon-bookmark:before { content: '\f07b'} /* ï» */ -.octicon-briefcase:before { content: '\f0d3'} /*  */ -.octicon-broadcast:before { content: '\f048'} /* ïˆ */ -.octicon-browser:before { content: '\f0c5'} /*  */ -.octicon-bug:before { content: '\f091'} /* ï‚‘ */ -.octicon-calendar:before { content: '\f068'} /* ï¨ */ -.octicon-check:before { content: '\f03a'} /*  */ -.octicon-checklist:before { content: '\f076'} /* ï¶ */ -.octicon-chevron-down:before { content: '\f0a3'} /* ï‚£ */ -.octicon-chevron-left:before { content: '\f0a4'} /*  */ -.octicon-chevron-right:before { content: '\f078'} /* ï¸ */ -.octicon-chevron-up:before { content: '\f0a2'} /* ï‚¢ */ -.octicon-circle-slash:before { content: '\f084'} /* ï‚„ */ -.octicon-circuit-board:before { content: '\f0d6'} /*  */ -.octicon-clippy:before { content: '\f035'} /*  */ -.octicon-clock:before { content: '\f046'} /* ï† */ -.octicon-cloud-download:before { content: '\f00b'} /*  */ -.octicon-cloud-upload:before { content: '\f00c'} /*  */ -.octicon-code:before { content: '\f05f'} /* ïŸ */ -.octicon-color-mode:before { content: '\f065'} /* ï¥ */ -.octicon-comment-add:before, -.octicon-comment:before { content: '\f02b'} /*  */ -.octicon-comment-discussion:before { content: '\f04f'} /* ï */ -.octicon-credit-card:before { content: '\f045'} /* ï… */ -.octicon-dash:before { content: '\f0ca'} /*  */ -.octicon-dashboard:before { content: '\f07d'} /* ï½ */ -.octicon-database:before { content: '\f096'} /* ï‚– */ -.octicon-clone:before, -.octicon-desktop-download:before { content: '\f0dc'} /*  */ -.octicon-device-camera:before { content: '\f056'} /* ï– */ -.octicon-device-camera-video:before { content: '\f057'} /* ï— */ -.octicon-device-desktop:before { content: '\f27c'} /*  */ -.octicon-device-mobile:before { content: '\f038'} /*  */ -.octicon-diff:before { content: '\f04d'} /* ï */ -.octicon-diff-added:before { content: '\f06b'} /* ï« */ -.octicon-diff-ignored:before { content: '\f099'} /* ï‚™ */ -.octicon-diff-modified:before { content: '\f06d'} /* ï */ -.octicon-diff-removed:before { content: '\f06c'} /* ï¬ */ -.octicon-diff-renamed:before { content: '\f06e'} /* ï® */ -.octicon-ellipsis:before { content: '\f09a'} /* ï‚š */ -.octicon-eye-unwatch:before, -.octicon-eye-watch:before, -.octicon-eye:before { content: '\f04e'} /* ïŽ */ -.octicon-file-binary:before { content: '\f094'} /* ï‚” */ -.octicon-file-code:before { content: '\f010'} /* ï€ */ -.octicon-file-directory:before { content: '\f016'} /*  */ -.octicon-file-media:before { content: '\f012'} /*  */ -.octicon-file-pdf:before { content: '\f014'} /*  */ -.octicon-file-submodule:before { content: '\f017'} /*  */ -.octicon-file-symlink-directory:before { content: '\f0b1'} /*  */ -.octicon-file-symlink-file:before { content: '\f0b0'} /* ï‚° */ -.octicon-file-text:before { content: '\f011'} /*  */ -.octicon-file-zip:before { content: '\f013'} /*  */ -.octicon-flame:before { content: '\f0d2'} /*  */ -.octicon-fold:before { content: '\f0cc'} /*  */ -.octicon-gear:before { content: '\f02f'} /*  */ -.octicon-gift:before { content: '\f042'} /* ï‚ */ -.octicon-gist:before { content: '\f00e'} /*  */ -.octicon-gist-secret:before { content: '\f08c'} /* ï‚Œ */ -.octicon-git-branch-create:before, -.octicon-git-branch-delete:before, -.octicon-git-branch:before { content: '\f020'} /* ï€ */ -.octicon-git-commit:before { content: '\f01f'} /*  */ -.octicon-git-compare:before { content: '\f0ac'} /*  */ -.octicon-git-merge:before { content: '\f023'} /*  */ -.octicon-git-pull-request-abandoned:before, -.octicon-git-pull-request:before { content: '\f009'} /*  */ -.octicon-globe:before { content: '\f0b6'} /*  */ -.octicon-graph:before { content: '\f043'} /* ïƒ */ -.octicon-heart:before { content: '\2665'} /* ♥ */ -.octicon-history:before { content: '\f07e'} /* ï¾ */ -.octicon-home:before { content: '\f08d'} /* ï‚ */ -.octicon-horizontal-rule:before { content: '\f070'} /* ï° */ -.octicon-hubot:before { content: '\f09d'} /* ï‚ */ -.octicon-inbox:before { content: '\f0cf'} /* ïƒ */ -.octicon-info:before { content: '\f059'} /* ï™ */ -.octicon-issue-closed:before { content: '\f028'} /*  */ -.octicon-issue-opened:before { content: '\f026'} /*  */ -.octicon-issue-reopened:before { content: '\f027'} /*  */ -.octicon-jersey:before { content: '\f019'} /*  */ -.octicon-key:before { content: '\f049'} /* ï‰ */ -.octicon-keyboard:before { content: '\f00d'} /* ï€ */ -.octicon-law:before { content: '\f0d8'} /*  */ -.octicon-light-bulb:before { content: '\f000'} /*  */ -.octicon-link:before { content: '\f05c'} /* ïœ */ -.octicon-link-external:before { content: '\f07f'} /* ï¿ */ -.octicon-list-ordered:before { content: '\f062'} /* ï¢ */ -.octicon-list-unordered:before { content: '\f061'} /* ï¡ */ -.octicon-location:before { content: '\f060'} /* ï */ -.octicon-gist-private:before, -.octicon-mirror-private:before, -.octicon-git-fork-private:before, -.octicon-lock:before { content: '\f06a'} /* ïª */ -.octicon-logo-github:before { content: '\f092'} /* ï‚’ */ -.octicon-mail:before { content: '\f03b'} /*  */ -.octicon-mail-read:before { content: '\f03c'} /*  */ -.octicon-mail-reply:before { content: '\f051'} /* ï‘ */ -.octicon-mark-github:before { content: '\f00a'} /*  */ -.octicon-markdown:before { content: '\f0c9'} /*  */ -.octicon-megaphone:before { content: '\f077'} /* ï· */ -.octicon-mention:before { content: '\f0be'} /*  */ -.octicon-milestone:before { content: '\f075'} /* ïµ */ -.octicon-mirror-public:before, -.octicon-mirror:before { content: '\f024'} /*  */ -.octicon-mortar-board:before { content: '\f0d7'} /*  */ -.octicon-mute:before { content: '\f080'} /* ï‚€ */ -.octicon-no-newline:before { content: '\f09c'} /* ï‚œ */ -.octicon-octoface:before { content: '\f008'} /*  */ -.octicon-organization:before { content: '\f037'} /*  */ -.octicon-package:before { content: '\f0c4'} /*  */ -.octicon-paintcan:before { content: '\f0d1'} /*  */ -.octicon-pencil:before { content: '\f058'} /* ï˜ */ -.octicon-person-add:before, -.octicon-person-follow:before, -.octicon-person:before { content: '\f018'} /*  */ -.octicon-pin:before { content: '\f041'} /* ï */ -.octicon-plug:before { content: '\f0d4'} /*  */ -.octicon-repo-create:before, -.octicon-gist-new:before, -.octicon-file-directory-create:before, -.octicon-file-add:before, -.octicon-plus:before { content: '\f05d'} /* ï */ -.octicon-primitive-dot:before { content: '\f052'} /* ï’ */ -.octicon-primitive-square:before { content: '\f053'} /* ï“ */ -.octicon-pulse:before { content: '\f085'} /* ï‚… */ -.octicon-question:before { content: '\f02c'} /*  */ -.octicon-quote:before { content: '\f063'} /* ï£ */ -.octicon-radio-tower:before { content: '\f030'} /*  */ -.octicon-repo-delete:before, -.octicon-repo:before { content: '\f001'} /* ï€ */ -.octicon-repo-clone:before { content: '\f04c'} /* ïŒ */ -.octicon-repo-force-push:before { content: '\f04a'} /* ïŠ */ -.octicon-gist-fork:before, -.octicon-repo-forked:before { content: '\f002'} /*  */ -.octicon-repo-pull:before { content: '\f006'} /*  */ -.octicon-repo-push:before { content: '\f005'} /*  */ -.octicon-rocket:before { content: '\f033'} /*  */ -.octicon-rss:before { content: '\f034'} /*  */ -.octicon-ruby:before { content: '\f047'} /* ï‡ */ -.octicon-screen-full:before { content: '\f066'} /* ï¦ */ -.octicon-screen-normal:before { content: '\f067'} /* ï§ */ -.octicon-search-save:before, -.octicon-search:before { content: '\f02e'} /*  */ -.octicon-server:before { content: '\f097'} /* ï‚— */ -.octicon-settings:before { content: '\f07c'} /* ï¼ */ -.octicon-shield:before { content: '\f0e1'} /*  */ -.octicon-log-in:before, -.octicon-sign-in:before { content: '\f036'} /*  */ -.octicon-log-out:before, -.octicon-sign-out:before { content: '\f032'} /*  */ -.octicon-squirrel:before { content: '\f0b2'} /*  */ -.octicon-star-add:before, -.octicon-star-delete:before, -.octicon-star:before { content: '\f02a'} /*  */ -.octicon-stop:before { content: '\f08f'} /* ï‚ */ -.octicon-repo-sync:before, -.octicon-sync:before { content: '\f087'} /*  */ -.octicon-tag-remove:before, -.octicon-tag-add:before, -.octicon-tag:before { content: '\f015'} /*  */ -.octicon-telescope:before { content: '\f088'} /*  */ -.octicon-terminal:before { content: '\f0c8'} /*  */ -.octicon-three-bars:before { content: '\f05e'} /* ïž */ -.octicon-thumbsdown:before { content: '\f0db'} /*  */ -.octicon-thumbsup:before { content: '\f0da'} /*  */ -.octicon-tools:before { content: '\f031'} /*  */ -.octicon-trashcan:before { content: '\f0d0'} /* ïƒ */ -.octicon-triangle-down:before { content: '\f05b'} /* ï› */ -.octicon-triangle-left:before { content: '\f044'} /* ï„ */ -.octicon-triangle-right:before { content: '\f05a'} /* ïš */ -.octicon-triangle-up:before { content: '\f0aa'} /*  */ -.octicon-unfold:before { content: '\f039'} /*  */ -.octicon-unmute:before { content: '\f0ba'} /*  */ -.octicon-versions:before { content: '\f064'} /* ï¤ */ -.octicon-watch:before { content: '\f0e0'} /* ïƒ */ -.octicon-remove-close:before, -.octicon-x:before { content: '\f081'} /* ï‚ */ -.octicon-zap:before { content: '\26A1'} /* âš¡ */ diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index ddb72c419b6..1b49884bd82 100644 --- a/packages/rocketchat-livechat/app/client/views/message.coffee +++ b/packages/rocketchat-livechat/app/client/views/message.coffee @@ -36,7 +36,7 @@ Template.message.helpers return this.html system: -> - return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj', 'command'] + return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'wm', 'uj'] Template.message.onViewRendered = (context) -> diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index 44807d2d76c..aac7ca39f1f 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -47,7 +47,7 @@ if wrapper? previousHeight = wrapper.scrollHeight - ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] + ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] when item.t isnt 'command' if wrapper? heightDiff = wrapper.scrollHeight - previousHeight diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index a0c0a3c1c87..0a70060a78e 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -109,12 +109,13 @@ RocketChat.Notifications.onUser 'message', (msg) -> Dep.changed() msgStream.on openedRooms[typeName].rid, (msg) -> - ChatMessage.upsert { _id: msg._id }, msg + if msg.t isnt 'command' + ChatMessage.upsert { _id: msg._id }, msg + else + Meteor.defer -> + RoomManager.updateMentionsMarksOfRoom typeName - Meteor.defer -> - RoomManager.updateMentionsMarksOfRoom typeName - - RocketChat.callbacks.run 'streamMessage', msg + RocketChat.callbacks.run 'streamMessage', msg RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream -- GitLab From 9f78357183edd4dd6976e770f43026975e0b42df Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 16:01:37 -0200 Subject: [PATCH 0816/1338] livechat hooks --- .../app/client/lib/hooks.js | 19 ++++++ .../assets/rocket-livechat.js | 62 +++++++++++++++++-- 2 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 packages/rocketchat-livechat/app/client/lib/hooks.js 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 00000000000..8ef6fc58fa7 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/lib/hooks.js @@ -0,0 +1,19 @@ +var api = { + pageVisited: function(info) { + console.log('pageVisited ->',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/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index b7633e3073c..dc6d9ffbb00 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -9,10 +9,12 @@ // })(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 = () => { widget.dataset.state = 'closed'; @@ -25,6 +27,16 @@ }; var api = { + ready: function() { + console.log('ready!!!'); + ready = true; + if (hookQueue.length > 0) { + hookQueue.forEach(function(hookParams) { + callHook.apply(this, hookParams); + }); + hookQueue = []; + } + }, toggleWindow: function(forceClose) { if (widget.dataset.state === 'closed') { openWidget(); @@ -39,6 +51,41 @@ } }; + // hooks + var callHook = function(action, params) { + if (!ready) { + console.log('queueing hook ->',action); + return hookQueue.push(arguments); + } + console.log('calling hook ->',action); + var data = { + src: 'rocketchat', + fn: action, + args: params + }; + iframe.contentWindow.postMessage(data, '*'); + }; + + var pageVisited = function() { + console.log('calling pageVisited'); + callHook('pageVisited', JSON.parse(JSON.stringify(document.location))); + }; + + var currentPage = { + href: null, + title: null + }; + var trackNavigation = function() { + setInterval(function() { + if (document.title !== currentPage.title) { + pageVisited(); + + currentPage.href = document.location.href; + currentPage.title = document.title; + } + }, 500); + }; + var initRocket = function(url) { if (!url) { return; @@ -50,7 +97,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'; @@ -65,6 +112,7 @@ 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') { @@ -90,6 +138,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') { @@ -104,5 +155,8 @@ initRocket.apply(null, [url]); }; - return exports; + // exports + return { + pageVisited: pageVisited + }; })(window); -- GitLab From ea7d386626975cb218188e399e72da021757c072 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 16:15:27 -0200 Subject: [PATCH 0817/1338] using flow-router group routes --- packages/rocketchat-livechat/client/route.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/client/route.js b/packages/rocketchat-livechat/client/route.js index a2029900297..4f28867b5a4 100644 --- a/packages/rocketchat-livechat/client/route.js +++ b/packages/rocketchat-livechat/client/route.js @@ -10,7 +10,12 @@ FlowRouter.route('/live/:name', { triggersExit: [roomExit] }); -FlowRouter.route('/livechat-manager/departments', { +livechatManagerRoutes = FlowRouter.group({ + prefix: '/livechat-manager', + name: 'livechat-manager' +}); + +livechatManagerRoutes.route('/departments', { name: 'livechat-departments', action: function(params, queryParams) { @@ -18,7 +23,7 @@ FlowRouter.route('/livechat-manager/departments', { } }); -FlowRouter.route('/livechat-manager/department/:_id?', { +livechatManagerRoutes.route('/department/:_id?', { name: 'livechat-department', action: function(params, queryParams) { -- GitLab From 9c3870a84c13169a7d304427d574038db412b74b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 11 Dec 2015 17:31:41 -0200 Subject: [PATCH 0818/1338] Removed debugging info on statistics. Closes issue #1552 --- packages/rocketchat-statistics/server/functions/get.coffee | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/rocketchat-statistics/server/functions/get.coffee b/packages/rocketchat-statistics/server/functions/get.coffee index d321b5fd48e..4343f6d25c0 100644 --- a/packages/rocketchat-statistics/server/functions/get.coffee +++ b/packages/rocketchat-statistics/server/functions/get.coffee @@ -58,18 +58,12 @@ RocketChat.statistics.get = -> if RocketChat.models.MRStatistics.findOneById(1) statistics.maxRoomUsers = RocketChat.models.MRStatistics.findOneById(1).value.max - else - console.log 'max room user statistic not found'.red if RocketChat.models.MRStatistics.findOneById('c') statistics.avgChannelUsers = RocketChat.models.MRStatistics.findOneById('c').value.avg - else - console.log 'channel user statistic not found'.red if RocketChat.models.MRStatistics.findOneById('p') statistics.avgPrivateGroupUsers = RocketChat.models.MRStatistics.findOneById('p').value.avg - else - console.log 'private group user statistic not found'.red statistics.lastLogin = RocketChat.models.Users.getLastLogin() statistics.lastMessageSentAt = RocketChat.models.Messages.getLastTimestamp() -- GitLab From 19a44c7d276a2f27409f449a42824cffdc20617e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 18:03:56 -0200 Subject: [PATCH 0819/1338] saving livechat trigger config --- .../client/lib/LivechatTrigger.js | 1 + packages/rocketchat-livechat/client/route.js | 8 +++ .../client/views/app/livechatTriggers.html | 24 +++++++++ .../client/views/app/livechatTriggers.js | 51 +++++++++++++++++++ .../client/views/sideNav/livechatFlex.html | 1 + .../rocketchat-livechat/i18n/en.i18n.json | 1 + packages/rocketchat-livechat/package.js | 7 +++ .../server/methods/saveTrigger.js | 11 ++++ .../server/models/LivechatTrigger.js | 22 ++++++++ .../server/publications/trigger.js | 13 +++++ 10 files changed, 139 insertions(+) create mode 100644 packages/rocketchat-livechat/client/lib/LivechatTrigger.js create mode 100644 packages/rocketchat-livechat/client/views/app/livechatTriggers.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatTriggers.js create mode 100644 packages/rocketchat-livechat/server/methods/saveTrigger.js create mode 100644 packages/rocketchat-livechat/server/models/LivechatTrigger.js create mode 100644 packages/rocketchat-livechat/server/publications/trigger.js diff --git a/packages/rocketchat-livechat/client/lib/LivechatTrigger.js b/packages/rocketchat-livechat/client/lib/LivechatTrigger.js new file mode 100644 index 00000000000..8cca1caa586 --- /dev/null +++ b/packages/rocketchat-livechat/client/lib/LivechatTrigger.js @@ -0,0 +1 @@ +this.LivechatTrigger = new Mongo.Collection('rocketchat_livechat_trigger'); diff --git a/packages/rocketchat-livechat/client/route.js b/packages/rocketchat-livechat/client/route.js index 4f28867b5a4..885ffecfd57 100644 --- a/packages/rocketchat-livechat/client/route.js +++ b/packages/rocketchat-livechat/client/route.js @@ -35,3 +35,11 @@ livechatManagerRoutes.route('/department/:_id?', { BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatDepartmentForm', pageTitle: pageTitle}); } }); + +livechatManagerRoutes.route('/triggers', { + name: 'livechat-triggers', + + action: function(params, queryParams) { + BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatTriggers', pageTitle: t('Triggers') }); + } +}); 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 00000000000..17657bc2d45 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatTriggers.html @@ -0,0 +1,24 @@ +<template name="livechatTriggers"> + <form id="trigger-form"> + <div class="rocket-form"> + <fieldset> + <div class="input-line"> + <label>{{_ "Trigger_by_URL"}}</label> + <input type="text" name="url-regex" placeholder="{{_ "Enter_a_regex"}}" value="{{urlRegex}}"> + </div> + <div class="input-line"> + <label>{{_ "Trigger_by_time"}}</label> + <input type="number" name="trigger-time" placeholder="{{_ "Time_in_seconds_at_the_same_page"}}" value="{{time}}"> + </div> + <div class="input-line"> + <label>{{_ "Trigger_message"}}</label> + <input type="text" name="trigger-message" placeholder="{{_ "Enter_a_message_to_your_customer"}}" value="{{message}}"> + </div> + </fieldset> + <div class="submit"> + <button type="reset" class="button secondary reset"><i class="icon-ccw"></i><span>{{_ "Reset"}}</span></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 00000000000..628a3c4a78f --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatTriggers.js @@ -0,0 +1,51 @@ +Template.livechatTriggers.helpers({ + urlRegex() { + return Template.instance().trigger.get().urlRegex; + }, + time() { + return Template.instance().trigger.get().time; + }, + message() { + return Template.instance().trigger.get().message; + }, +}); + +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 = { + urlRegex: instance.$('input[name=url-regex]').val(), + time: instance.$('input[name=trigger-time]').val(), + message: instance.$('input[name=trigger-message]').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')); + }); + }, +}); + +Template.livechatTriggers.onCreated(function() { + this.subscribe('livechat:trigger'); + this.trigger = new ReactiveVar({ + urlRegex: '', + time: '', + message: '', + }); + this.autorun(() => { + trigger = LivechatTrigger.findOne(); + if (trigger) { + this.trigger.set(trigger); + } + }); +}); diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index ae76e6746d9..b8c16f4b6e7 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -11,6 +11,7 @@ <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="{{pathFor 'livechat-triggers'}}" class="admin-link">{{_ "Triggers"}}</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> diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 2d6abc513b7..12ac327cf30 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -32,6 +32,7 @@ "Saved" : "Saved", "Theme" : "Theme", "There_are_no_agents_added_to_this_department_yet" : "There are no agents added to this department yet.", + "Triggers": "Triggers", "User_management" : "User Management", "Username_not_found" : "Username not found" } diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index c44b7834d23..ed592f9251f 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -43,6 +43,8 @@ Package.onUse(function(api) { api.addFiles('client/views/app/livechatDepartments.js', 'client'); api.addFiles('client/views/app/livechatDepartmentForm.html', 'client'); api.addFiles('client/views/app/livechatDepartmentForm.js', 'client'); + api.addFiles('client/views/app/livechatTriggers.html', 'client'); + api.addFiles('client/views/app/livechatTriggers.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'); @@ -56,17 +58,22 @@ Package.onUse(function(api) { 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/saveTrigger.js', 'server'); + // models api.addFiles('server/models/Users.js', 'server'); api.addFiles('server/models/LivechatDepartment.js', 'server'); + api.addFiles('server/models/LivechatTrigger.js', 'server'); // collections api.addFiles('client/lib/LivechatDepartment.js', 'client'); + api.addFiles('client/lib/LivechatTrigger.js', 'client'); // publications 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/trigger.js', 'server'); api.addFiles('server/publications/visitorRoom.js', 'server'); // livechat app diff --git a/packages/rocketchat-livechat/server/methods/saveTrigger.js b/packages/rocketchat-livechat/server/methods/saveTrigger.js new file mode 100644 index 00000000000..fa721480016 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/saveTrigger.js @@ -0,0 +1,11 @@ +Meteor.methods({ + 'livechat:saveTrigger' (trigger) { + console.log('[methods] livechat:saveTrigger -> '.green, 'arguments:', arguments); + + 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/models/LivechatTrigger.js b/packages/rocketchat-livechat/server/models/LivechatTrigger.js new file mode 100644 index 00000000000..4b5ddfd5b35 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/LivechatTrigger.js @@ -0,0 +1,22 @@ +/** + * 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); + } + } +} + +RocketChat.models.LivechatTrigger = new LivechatTrigger(); diff --git a/packages/rocketchat-livechat/server/publications/trigger.js b/packages/rocketchat-livechat/server/publications/trigger.js new file mode 100644 index 00000000000..dad9c34bc2e --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/trigger.js @@ -0,0 +1,13 @@ +Meteor.publish('livechat:trigger', function() { + if (!this.userId) { + throw new Meteor.Error('not-authorized'); + } + + if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { + throw new Meteor.Error('not-authorized'); + } + + console.log('[publish] livechat:trigger -> '.green, 'arguments:', arguments); + + return RocketChat.models.LivechatTrigger.find(); +}); -- GitLab From 0c0cbc0cb3959ad4fb026afd3ecda376cd109eb5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 11 Dec 2015 18:46:08 -0200 Subject: [PATCH 0820/1338] initial trigger support --- .../app/client/lib/collections.coffee | 1 + .../app/client/lib/hooks.js | 1 + .../app/client/lib/triggers.js | 61 +++++++++++++++++++ .../app/client/startup/triggers.js | 8 +++ .../app/client/views/room.html | 2 +- .../app/client/views/room.js | 3 + .../assets/rocket-livechat.js | 11 +++- .../server/publications/trigger.js | 14 ++--- 8 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 packages/rocketchat-livechat/app/client/lib/triggers.js create mode 100644 packages/rocketchat-livechat/app/client/startup/triggers.js diff --git a/packages/rocketchat-livechat/app/client/lib/collections.coffee b/packages/rocketchat-livechat/app/client/lib/collections.coffee index 48b9e6fcd37..788b96e4440 100644 --- a/packages/rocketchat-livechat/app/client/lib/collections.coffee +++ b/packages/rocketchat-livechat/app/client/lib/collections.coffee @@ -1,3 +1,4 @@ @ChatMessage = new Meteor.Collection null @ChatRoom = new Meteor.Collection 'rocketchat_room' @Settings = new Meteor.Collection 'rocketchat_settings' +@Trigger = new Meteor.Collection 'rocketchat_livechat_trigger' diff --git a/packages/rocketchat-livechat/app/client/lib/hooks.js b/packages/rocketchat-livechat/app/client/lib/hooks.js index 8ef6fc58fa7..9d4dada5d80 100644 --- a/packages/rocketchat-livechat/app/client/lib/hooks.js +++ b/packages/rocketchat-livechat/app/client/lib/hooks.js @@ -1,6 +1,7 @@ var api = { pageVisited: function(info) { console.log('pageVisited ->',info); + Triggers.processRequest(info); } }; 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 00000000000..e30e95f77a9 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/lib/triggers.js @@ -0,0 +1,61 @@ +this.Triggers = (function() { + var urlRegex = null; + var time = null; + var message = 'Default trigger message'; + + var timeout = null; + + var init = function() { + console.log('init!!'); + Tracker.autorun(function() { + var trigger = Trigger.findOne(); + console.log('trigger found ->',trigger); + if (trigger) { + urlRegex = trigger.urlRegex; + time = trigger.time; + message = trigger.message; + } + }); + }; + + var fire = function() { + if (Meteor.userId()) { + console.log('already logged user - does nothing'); + return; + } + parentCall('triggerMessage', message); + + var room = Random.id(); + visitor.setRoom(room); + + Session.set('triggered', true); + ChatMessage.insert({ + msg: message, + rid: room, + u: { + username: 'random-agent' + } + }); + }; + + var processRequest = function(request) { + if (urlRegex && urlRegex !== '') { + if (request.href.match(urlRegex)) { + fire(); + } + } + + if (time) { + console.log('registerTimeout ->',time); + clearTimeout(timeout); + timeout = setTimeout(function() { + fire(); + }, time * 1000); + } + }; + + return { + init: init, + processRequest: processRequest + }; +})(); 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 00000000000..46b0e51ac6e --- /dev/null +++ b/packages/rocketchat-livechat/app/client/startup/triggers.js @@ -0,0 +1,8 @@ +console.log('startup trigger'); +Meteor.startup(function() { + console.log('go'); + Meteor.subscribe('livechat:trigger', function() { + console.log('ready'); + Triggers.init() + }) +}); diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/room.html index 90c31283b2b..de0292052e2 100644 --- a/packages/rocketchat-livechat/app/client/views/room.html +++ b/packages/rocketchat-livechat/app/client/views/room.html @@ -9,7 +9,7 @@ </div> <h1>{{title}}</h1> </div> - {{#if currentUser}} + {{#if showMessages}} {{> messages}} {{else}} {{> register}} diff --git a/packages/rocketchat-livechat/app/client/views/room.js b/packages/rocketchat-livechat/app/client/views/room.js index 530adb4d01f..9aa6e2e9181 100644 --- a/packages/rocketchat-livechat/app/client/views/room.js +++ b/packages/rocketchat-livechat/app/client/views/room.js @@ -15,6 +15,9 @@ Template.room.helpers({ }, popoutActive: function() { return FlowRouter.getQueryParam('mode') === 'popout'; + }, + showMessages: function() { + return Session.get('triggered') || Meteor.userId(); } }); diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index dc6d9ffbb00..69aca27475c 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -28,7 +28,7 @@ var api = { ready: function() { - console.log('ready!!!'); + // console.log('ready!!!'); ready = true; if (hookQueue.length > 0) { hookQueue.forEach(function(hookParams) { @@ -48,6 +48,11 @@ closeWidget(); var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no'); popup.focus(); + }, + triggerMessage: function(msg) { + console.log('trigger fired!!!! ->',msg); + + openWidget(); } }; @@ -57,7 +62,7 @@ console.log('queueing hook ->',action); return hookQueue.push(arguments); } - console.log('calling hook ->',action); + // console.log('calling hook ->',action); var data = { src: 'rocketchat', fn: action, @@ -67,7 +72,7 @@ }; var pageVisited = function() { - console.log('calling pageVisited'); + // console.log('calling pageVisited'); callHook('pageVisited', JSON.parse(JSON.stringify(document.location))); }; diff --git a/packages/rocketchat-livechat/server/publications/trigger.js b/packages/rocketchat-livechat/server/publications/trigger.js index dad9c34bc2e..981e16da6d5 100644 --- a/packages/rocketchat-livechat/server/publications/trigger.js +++ b/packages/rocketchat-livechat/server/publications/trigger.js @@ -1,13 +1,13 @@ Meteor.publish('livechat:trigger', function() { - if (!this.userId) { - throw new Meteor.Error('not-authorized'); - } + // if (!this.userId) { + // throw new Meteor.Error('not-authorized'); + // } - if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { - throw new Meteor.Error('not-authorized'); - } + // if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { + // throw new Meteor.Error('not-authorized'); + // } - console.log('[publish] livechat:trigger -> '.green, 'arguments:', arguments); + // console.log('[publish] livechat:trigger -> '.green, 'arguments:', arguments); return RocketChat.models.LivechatTrigger.find(); }); -- GitLab From 16a0ddd99b972ed317e8d97cf02740408e2b12da Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Fri, 11 Dec 2015 16:01:13 -0500 Subject: [PATCH 0821/1338] Avatars for Unicode usernames When a new avatar is saved the user name gets encoded using `encodeURIComponent`, this does not affect names in latin characters, however it does change non-latin/unicode names to an encoded string. However, when reading the avatar image file, the function uses the username directly without enocinding it, so latin names work since the encoding doesn't change anything, however, Unicode names don't since the usernames don't match the encoded names. This fix adds the encoding function when reading the avatars. Also adds the encoding to the function that writes avatars from URL. --- server/methods/setAvatarFromService.coffee | 4 ++-- server/startup/avatar.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index 4a13971591b..0df26725a6b 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -32,8 +32,8 @@ Meteor.methods throw new Meteor.Error('invalid-avatar-url', '[methods] setAvatarFromService -> url service -> invalid content-type') ars = RocketChatFile.bufferToStream new Buffer(result.content, 'binary') - RocketChatFileAvatarInstance.deleteFile "#{user.username}.jpg" - aws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", result.headers['content-type'] + RocketChatFileAvatarInstance.deleteFile encodeURIComponent("#{user.username}.jpg") + aws = RocketChatFileAvatarInstance.createWriteStream encodeURIComponent("#{user.username}.jpg"), result.headers['content-type'] aws.on 'end', Meteor.bindEnvironment -> Meteor.setTimeout -> console.log "Set #{user.username}'s avatar from the url: #{dataURI}" diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index b97040ef457..45e9f590c99 100644 --- a/server/startup/avatar.coffee +++ b/server/startup/avatar.coffee @@ -33,7 +33,7 @@ Meteor.startup -> username: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) if params.username[0] isnt '@' - file = RocketChatFileAvatarInstance.getFileWithReadStream params.username + file = RocketChatFileAvatarInstance.getFileWithReadStream encodeURIComponent(params.username) else params.username = params.username.replace '@', '' -- GitLab From fab937fe2acb8082b38849f89032f78c56161790 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 11 Dec 2015 21:30:50 -0200 Subject: [PATCH 0822/1338] Move avatars on username change --- .../rocketchat-lib/server/functions/setUsername.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index 95ae56aad69..f05ea65d085 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -45,6 +45,14 @@ RocketChat._setUsername = (userId, username) -> RocketChat.models.Subscriptions.setUserUsernameByUserId user._id, username RocketChat.models.Subscriptions.setNameForDirectRoomsWithOldName previousUsername, username + rs = RocketChatFileAvatarInstance.getFileWithReadStream("#{previousUsername}.jpg") + if rs? + RocketChatFileAvatarInstance.deleteFile "#{username}.jpg" + ws = RocketChatFileAvatarInstance.createWriteStream "#{username}.jpg", rs.contentType + ws.on 'end', Meteor.bindEnvironment -> + RocketChatFileAvatarInstance.deleteFile "#{previousUsername}.jpg" + rs.readStream.pipe(ws) + # Set new username RocketChat.models.Users.setUsername user._id, username user.username = username -- GitLab From d4d3f16427c461ea5d4cbb04124399a35ede5d97 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Fri, 11 Dec 2015 18:59:48 -0500 Subject: [PATCH 0823/1338] Fixed indentation and added unicode support The avatar image move need to only be done if a previous username exists. Also we need `encodeURIComponent` to support names in unicode. --- .../server/functions/setUsername.coffee | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index f05ea65d085..da23f4970b5 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -45,13 +45,13 @@ RocketChat._setUsername = (userId, username) -> RocketChat.models.Subscriptions.setUserUsernameByUserId user._id, username RocketChat.models.Subscriptions.setNameForDirectRoomsWithOldName previousUsername, username - rs = RocketChatFileAvatarInstance.getFileWithReadStream("#{previousUsername}.jpg") - if rs? - RocketChatFileAvatarInstance.deleteFile "#{username}.jpg" - ws = RocketChatFileAvatarInstance.createWriteStream "#{username}.jpg", rs.contentType - ws.on 'end', Meteor.bindEnvironment -> - RocketChatFileAvatarInstance.deleteFile "#{previousUsername}.jpg" - rs.readStream.pipe(ws) + rs = RocketChatFileAvatarInstance.getFileWithReadStream(encodeURIComponent("#{previousUsername}.jpg")) + if rs? + RocketChatFileAvatarInstance.deleteFile encodeURIComponent("#{username}.jpg") + ws = RocketChatFileAvatarInstance.createWriteStream encodeURIComponent("#{username}.jpg"), rs.contentType + ws.on 'end', Meteor.bindEnvironment -> + RocketChatFileAvatarInstance.deleteFile encodeURIComponent("#{previousUsername}.jpg") + rs.readStream.pipe(ws) # Set new username RocketChat.models.Users.setUsername user._id, username -- GitLab From 8ded0150ae1458b5d5ff07bd9a6116c6435e266e Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Fri, 11 Dec 2015 20:00:42 -0500 Subject: [PATCH 0824/1338] Show toastr messages on the left side --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index f81703f69b1..9f4d66fcd29 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -628,4 +628,9 @@ #swipebox-overlay{ direction: ltr; } + + /* Override toastr messages to show on hte left side */ + .toast-top-right { + .left(12px); + } } -- GitLab From b20e8aa04502cda71b8e9ef4edf7aac3b48e058b Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Sat, 12 Dec 2015 11:06:17 -0600 Subject: [PATCH 0825/1338] Fix rocket.cat user messing up the first real user being made admin. --- server/lib/accounts.coffee | 3 ++- server/startup/initialData.coffee | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index a6d678fcb4a..ae3f72ac3df 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -75,8 +75,9 @@ Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc) -> _id = insertUserDoc.call(Accounts, options, user) # when inserting first user give them admin privileges otherwise make a regular user - firstUser = RocketChat.models.Users.findOne({},{sort:{createdAt:1}}) + firstUser = RocketChat.models.Users.findOne({ _id: { $ne: 'rocket.cat' }}, { sort: { createdAt: 1 }}) roleName = if firstUser?._id is _id then 'admin' else 'user' + console.log "The role for #{_id} is #{roleName}." RocketChat.authz.addUsersToRoles(_id, roleName) RocketChat.callbacks.run 'afterCreateUser', options, user diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index dbfafd86f22..47ba296a93f 100644 --- a/server/startup/initialData.coffee +++ b/server/startup/initialData.coffee @@ -53,7 +53,7 @@ Meteor.startup -> # Set oldest user as admin, if none exists yet if _.isEmpty( RocketChat.authz.getUsersInRole( 'admin' ).fetch()) # get oldest user - oldestUser = RocketChat.models.Users.findOne({}, { fields: { username: 1 }, sort: {createdAt: 1}}) + oldestUser = RocketChat.models.Users.findOne({ _id: { $ne: 'rocket.cat' }}, { fields: { username: 1 }, sort: {createdAt: 1}}) if oldestUser RocketChat.authz.addUsersToRoles( oldestUser._id, 'admin') console.log "No admins are found. Set #{oldestUser.username} as admin for being the oldest user" -- GitLab From cebb602af652b3667b5d5de0dc17a28494ce35ab Mon Sep 17 00:00:00 2001 From: graywolf336 <graywolf336@craftyn.com> Date: Sat, 12 Dec 2015 11:07:03 -0600 Subject: [PATCH 0826/1338] Remove the debugging message on account creation. --- server/lib/accounts.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index ae3f72ac3df..81f619cfeb1 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -77,7 +77,6 @@ Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc) -> # 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' - console.log "The role for #{_id} is #{roleName}." RocketChat.authz.addUsersToRoles(_id, roleName) RocketChat.callbacks.run 'afterCreateUser', options, user -- GitLab From a4212558a2413cfac83988159a6beff22d4f96f8 Mon Sep 17 00:00:00 2001 From: Matthias Brun <matthias-brun@users.noreply.github.com> Date: Sat, 12 Dec 2015 22:20:57 +0100 Subject: [PATCH 0827/1338] Fix 'create new' in private group list opening 'create channel' flex --- .../rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee index 08ea0d9eb0c..6b15e850542 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/listPrivateGroupsFlex.coffee @@ -10,7 +10,7 @@ Template.listPrivateGroupsFlex.events SideNav.closeFlex() 'click footer .create': -> - SideNav.setFlex "createChannelFlex" + SideNav.setFlex "privateGroupsFlex" 'mouseenter header': -> SideNav.overArrow() -- GitLab From c99716216cc1e8b97930e0f87a56c2999a8a264a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Sun, 13 Dec 2015 16:47:47 -0200 Subject: [PATCH 0828/1338] livechat enabled parameter --- .../app/client/stylesheets/main.less | 7 ++++ .../app/client/views/messages.js | 1 - .../app/client/views/room.html | 34 +++++++++++-------- .../app/client/views/room.js | 29 ++++++++++++++++ .../rocketchat-livechat/app/i18n/en.i18n.json | 3 +- .../assets/rocket-livechat.js | 3 ++ packages/rocketchat-livechat/config.js | 1 + .../rocketchat-livechat/i18n/en.i18n.json | 1 + 8 files changed, 63 insertions(+), 16 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 9407a2dc5df..1335a011451 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -382,6 +382,13 @@ input:focus { } } } + .offline { + flex: 1 1 100%; + font-weight: bold; + background-color: white; + padding: 2em 0; + text-align: center; + } } .livechat-form { diff --git a/packages/rocketchat-livechat/app/client/views/messages.js b/packages/rocketchat-livechat/app/client/views/messages.js index e6391df2303..d2f45ce48d0 100644 --- a/packages/rocketchat-livechat/app/client/views/messages.js +++ b/packages/rocketchat-livechat/app/client/views/messages.js @@ -52,7 +52,6 @@ Template.messages.onCreated(function() { } }); }); - self.subscribe('settings', ['Livechat_title', 'Livechat_title_color']); self.atBottom = true; }); diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/room.html index 90c31283b2b..0220ed9abfa 100644 --- a/packages/rocketchat-livechat/app/client/views/room.html +++ b/packages/rocketchat-livechat/app/client/views/room.html @@ -1,18 +1,24 @@ <template name="room"> - <div class="livechat-room"> - <div class="title" style="background-color:{{color}}"> - <div class="toolbar"> - - {{#unless popoutActive}} - <i class="popout icon-link-ext" title="Open in a new window"></i> - {{/unless}} + {{#if livechatStartedEnabled}} + <div class="livechat-room"> + <div class="title" style="background-color:{{color}}"> + <div class="toolbar"> + + {{#unless popoutActive}} + <i class="popout icon-link-ext" title="Open in a new window"></i> + {{/unless}} + </div> + <h1>{{title}}</h1> </div> - <h1>{{title}}</h1> + {{#if currentUser}} + {{> messages}} + {{else}} + {{#if livechatEnabled}} + {{> register}} + {{else}} + <div class="offline">{{_ "We_are_offline_Sorry_for_the_inconvenience"}}</div> + {{/if}} + {{/if}} </div> - {{#if currentUser}} - {{> messages}} - {{else}} - {{> register}} - {{/if}} - </div> + {{/if}} </template> diff --git a/packages/rocketchat-livechat/app/client/views/room.js b/packages/rocketchat-livechat/app/client/views/room.js index 530adb4d01f..a844293decb 100644 --- a/packages/rocketchat-livechat/app/client/views/room.js +++ b/packages/rocketchat-livechat/app/client/views/room.js @@ -15,6 +15,12 @@ Template.room.helpers({ }, popoutActive: function() { return FlowRouter.getQueryParam('mode') === 'popout'; + }, + livechatStartedEnabled: function() { + return Template.instance().startedEnabled.get() !== null; + }, + livechatEnabled: function() { + return Template.instance().startedEnabled.get(); } }); @@ -27,3 +33,26 @@ Template.room.events({ parentCall('openPopout'); } }); + +Template.room.onCreated(function() { + self = this; + + self.startedEnabled = new ReactiveVar(null); + + self.subscribe('settings', ['Livechat_title', 'Livechat_title_color', 'Livechat_enabled']); + + var initialCheck = true; + + self.autorun(function() { + if (self.subscriptionsReady()) { + var enabled = Settings.findOne('Livechat_enabled'); + if (enabled !== undefined) { + if (!enabled.value && initialCheck) { + parentCall('removeWidget'); + } + initialCheck = false; + self.startedEnabled.set(enabled.value); + } + } + }); +}); diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index 8d6e2fe32e6..a14d83d215e 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -15,5 +15,6 @@ "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." + "User_left" : "Has left the channel.", + "We_are_offline_Sorry_for_the_inconvenience": "We are offline. Sorry for the inconvenience." } diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index b7633e3073c..c16c5a7bd92 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -36,6 +36,9 @@ closeWidget(); var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no'); popup.focus(); + }, + removeWidget: function() { + document.getElementsByTagName('body')[0].removeChild(widget); } }; diff --git a/packages/rocketchat-livechat/config.js b/packages/rocketchat-livechat/config.js index 1295c45ed9c..9ae62a8ecb1 100644 --- a/packages/rocketchat-livechat/config.js +++ b/packages/rocketchat-livechat/config.js @@ -2,4 +2,5 @@ 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 }); }); diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 2d6abc513b7..fe6208b2989 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -17,6 +17,7 @@ "Integrations" : "Integrations", "Live_sessions" : "Live sessions", "Livechat_agents" : "Livechat agents", + "Livechat_enabled" : "Livechat enabled", "Livechat_Manager" : "Livechat Manager", "Livechat_managers" : "Livechat managers", "Livechat_title" : "Livechat Title", -- GitLab From 4380757729a465446268c43aa180e3ac2ba00324 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sun, 13 Dec 2015 19:39:34 -0500 Subject: [PATCH 0829/1338] Update Ansible for Ubuntu LTS support --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f1ca0ea535f..c2401659a1c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Ultimate Open Source WebChat Platform * [Sloppy.io](#sloppyio) * [Docker](#docker) * [FreeBSD](#freebsd) - * [CentOS 7 Ansible](#ansible) + * [Ansible](#ansible) * [Ubuntu VPS](#ubuntu-vps) * [Ubuntu Software Center](#ubuntu-software-center) * [About Rocket.Chat](#about-rocketchat) @@ -95,9 +95,9 @@ Run solid five-nines deployment on industry workhorse FreeBSD server: [](https://github.com/RocketChat/Rocket.Chat/wiki/FreeBSD) ## Ansible -Automated production grade deployment in minutes, for CentOS 7: +Automated production-grade deployment in minutes, for RHEL/CentOS 7 or Ubuntu 14.04LTS/15.04: -[](https://galaxy.ansible.com/detail#/role/6458) +[ ## Ubuntu VPS Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) -- GitLab From 70c54e02b65149fd931446b44e191d82dc34099a Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Sun, 13 Dec 2015 19:47:01 -0500 Subject: [PATCH 0830/1338] Fix broken link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c2401659a1c..6f5ff72f957 100644 --- a/README.md +++ b/README.md @@ -95,9 +95,9 @@ Run solid five-nines deployment on industry workhorse FreeBSD server: [](https://github.com/RocketChat/Rocket.Chat/wiki/FreeBSD) ## Ansible -Automated production-grade deployment in minutes, for RHEL/CentOS 7 or Ubuntu 14.04LTS/15.04: +Automated production-grade deployment in minutes, for RHEL / CentOS 7 or Ubuntu 14.04 LTS / 15.04: -[ +[](https://galaxy.ansible.com/detail#/role/6478) ## Ubuntu VPS Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) -- GitLab From 9b75b82d5177d956142bcbfbb0159026cd231932 Mon Sep 17 00:00:00 2001 From: Kristjan Kullerkann <litewhatever@gmail.com> Date: Wed, 9 Dec 2015 16:21:32 +0200 Subject: [PATCH 0831/1338] Added setting Accounts_LoginExpiration Setting allows admin to modify Meteor.loginTokenExpires from default 90 days to something else. Server restart is required for this setting to take effect. Default value is still 90 days if not modified by admin. --- i18n/en.i18n.json | 1 + packages/rocketchat-lib/server/startup/settings.coffee | 2 ++ server/lib/accounts.coffee | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1014267948e..88806019925 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -17,6 +17,7 @@ "Accounts_EmailVerification" : "E-mail Verification", "Accounts_Enrollment_Email" : "Enrollment E-mail", "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", + "Accounts_LoginExpiration" : "Login Expiration in Days", "Accounts_ManuallyApproveNewUsers" : "Manually Approve New Users", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", "Accounts_OAuth_Custom_Button_Color" : "Button Color", diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 5597f56d1b3..190f9f8b258 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -47,6 +47,8 @@ RocketChat.settings.add 'Accounts_AllowUsernameChange', true, { type: 'boolean', 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 } diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index a6d678fcb4a..c735ef73635 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -1,5 +1,5 @@ -# Deny Account.createUser in client -accountsConfig = { forbidClientAccountCreation: true } +# 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() -- GitLab From f197c1a96e560e3ad05c3860d78c0d307ab5bdc1 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 14 Dec 2015 11:42:56 +0000 Subject: [PATCH 0832/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 42 +++ i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 78 ++++- i18n/km.i18n.json | 5 + i18n/ku.i18n.json | 120 +++++++ i18n/lo.i18n.json | 1 + i18n/nl.i18n.json | 294 ++++++++++++++++++ i18n/pl.i18n.json | 122 ++++---- i18n/pt.i18n.json | 53 +++- .../i18n/ar.i18n.json | 4 +- .../i18n/en.i18n.json | 2 - .../i18n/fi.i18n.json | 17 +- .../i18n/ku.i18n.json | 4 + .../i18n/lo.i18n.json | 1 + .../i18n/nl.i18n.json | 4 + .../i18n/pt.i18n.json | 2 - .../i18n/fi.i18n.json | 9 +- .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/pt.i18n.json | 7 +- packages/rocketchat-chatops/i18n/ku.i18n.json | 1 + packages/rocketchat-chatops/i18n/lo.i18n.json | 1 + packages/rocketchat-chatops/i18n/nl.i18n.json | 1 + .../i18n/fi.i18n.json | 2 +- .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + packages/rocketchat-gitlab/i18n/ku.i18n.json | 1 + packages/rocketchat-gitlab/i18n/lo.i18n.json | 1 + packages/rocketchat-gitlab/i18n/nl.i18n.json | 3 + packages/rocketchat-hubot/i18n/ku.i18n.json | 1 + packages/rocketchat-hubot/i18n/lo.i18n.json | 1 + packages/rocketchat-hubot/i18n/nl.i18n.json | 1 + packages/rocketchat-ldap/i18n/ku.i18n.json | 1 + packages/rocketchat-ldap/i18n/lo.i18n.json | 1 + packages/rocketchat-ldap/i18n/nl.i18n.json | 1 + packages/rocketchat-lib/i18n/ku.i18n.json | 1 + packages/rocketchat-lib/i18n/lo.i18n.json | 1 + packages/rocketchat-lib/i18n/nl.i18n.json | 1 + .../rocketchat-livechat/app/i18n/ar.i18n.json | 1 + .../rocketchat-livechat/app/i18n/cs.i18n.json | 1 + .../rocketchat-livechat/app/i18n/de.i18n.json | 1 + .../rocketchat-livechat/app/i18n/el.i18n.json | 1 + .../rocketchat-livechat/app/i18n/en.i18n.json | 33 +- .../rocketchat-livechat/app/i18n/es.i18n.json | 1 + .../rocketchat-livechat/app/i18n/fa.i18n.json | 1 + .../rocketchat-livechat/app/i18n/fi.i18n.json | 14 + .../rocketchat-livechat/app/i18n/fr.i18n.json | 1 + .../rocketchat-livechat/app/i18n/he.i18n.json | 1 + .../rocketchat-livechat/app/i18n/hr.i18n.json | 1 + .../rocketchat-livechat/app/i18n/hu.i18n.json | 1 + .../rocketchat-livechat/app/i18n/it.i18n.json | 1 + .../rocketchat-livechat/app/i18n/ja.i18n.json | 1 + .../rocketchat-livechat/app/i18n/km.i18n.json | 1 + .../rocketchat-livechat/app/i18n/ko.i18n.json | 1 + .../rocketchat-livechat/app/i18n/ku.i18n.json | 1 + .../rocketchat-livechat/app/i18n/lo.i18n.json | 1 + .../app/i18n/ms-MY.i18n.json | 1 + .../rocketchat-livechat/app/i18n/nl.i18n.json | 1 + .../rocketchat-livechat/app/i18n/pl.i18n.json | 1 + .../rocketchat-livechat/app/i18n/pt.i18n.json | 1 + .../rocketchat-livechat/app/i18n/ru.i18n.json | 1 + .../rocketchat-livechat/app/i18n/sq.i18n.json | 1 + .../rocketchat-livechat/app/i18n/sv.i18n.json | 1 + .../app/i18n/ta-IN.i18n.json | 1 + .../rocketchat-livechat/app/i18n/tr.i18n.json | 1 + .../rocketchat-livechat/app/i18n/ug.i18n.json | 1 + .../rocketchat-livechat/app/i18n/uk.i18n.json | 1 + .../rocketchat-livechat/app/i18n/zh.i18n.json | 1 + .../rocketchat-livechat/i18n/en.i18n.json | 4 +- .../rocketchat-livechat/i18n/fi.i18n.json | 33 +- .../rocketchat-livechat/i18n/ku.i18n.json | 1 + .../rocketchat-livechat/i18n/lo.i18n.json | 1 + .../rocketchat-livechat/i18n/nl.i18n.json | 1 + .../rocketchat-livechat/i18n/pt.i18n.json | 2 + packages/rocketchat-mailer/i18n/en.i18n.json | 2 +- packages/rocketchat-mailer/i18n/fi.i18n.json | 20 +- packages/rocketchat-mailer/i18n/ku.i18n.json | 6 + packages/rocketchat-mailer/i18n/lo.i18n.json | 1 + packages/rocketchat-mailer/i18n/nl.i18n.json | 1 + packages/rocketchat-mailer/i18n/pl.i18n.json | 2 +- packages/rocketchat-mailer/i18n/pt.i18n.json | 2 +- .../rocketchat-message-pin/i18n/fi.i18n.json | 9 +- .../rocketchat-message-pin/i18n/ku.i18n.json | 1 + .../rocketchat-message-pin/i18n/lo.i18n.json | 1 + .../rocketchat-message-pin/i18n/nl.i18n.json | 1 + .../rocketchat-message-star/i18n/ku.i18n.json | 1 + .../rocketchat-message-star/i18n/lo.i18n.json | 1 + .../rocketchat-message-star/i18n/nl.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + packages/rocketchat-theme/i18n/ar.i18n.json | 4 +- packages/rocketchat-theme/i18n/fi.i18n.json | 24 +- packages/rocketchat-theme/i18n/ku.i18n.json | 1 + packages/rocketchat-theme/i18n/lo.i18n.json | 1 + packages/rocketchat-theme/i18n/nl.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ku.i18n.json | 1 + packages/rocketchat-webrtc/i18n/lo.i18n.json | 1 + packages/rocketchat-webrtc/i18n/nl.i18n.json | 1 + packages/rocketchat-webrtc/i18n/pt.i18n.json | 4 +- .../rocketchat-wordpress/i18n/ku.i18n.json | 1 + .../rocketchat-wordpress/i18n/lo.i18n.json | 1 + .../rocketchat-wordpress/i18n/nl.i18n.json | 1 + 108 files changed, 896 insertions(+), 109 deletions(-) create mode 100644 i18n/ku.i18n.json create mode 100644 i18n/lo.i18n.json create mode 100644 i18n/nl.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ku.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/lo.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/nl.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ku.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/lo.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/nl.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ku.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/lo.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/nl.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/ku.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/lo.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/nl.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/ku.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/lo.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/nl.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ku.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/lo.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/nl.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/ku.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/lo.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/nl.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ku.i18n.json create mode 100644 packages/rocketchat-lib/i18n/lo.i18n.json create mode 100644 packages/rocketchat-lib/i18n/nl.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ar.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/cs.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/de.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/el.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/es.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/fa.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/fi.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/fr.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/he.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/hr.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/hu.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/it.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ja.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/km.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ko.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ku.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/lo.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/nl.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/pl.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/pt.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ru.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/sq.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/sv.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/tr.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ug.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/uk.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/zh.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/ku.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/lo.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/nl.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ku.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/lo.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/nl.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ku.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/lo.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/nl.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ku.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/lo.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/nl.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ku.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/lo.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ku.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/lo.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/nl.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ku.i18n.json create mode 100644 packages/rocketchat-theme/i18n/lo.i18n.json create mode 100644 packages/rocketchat-theme/i18n/nl.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ku.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/lo.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/nl.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/ku.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/lo.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/nl.i18n.json diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index f12d75a47d0..d2e04cbfc21 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -1,8 +1,13 @@ { "Access_online_demo" : "الدخول إلى العرض التجريبي", "Access_Online_Demo" : "الدخول إلى العرض التجريبي", + "Accounts" : "الØسابات", + "Accounts_AllowPasswordChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± كلمة السر", + "Accounts_AllowUserProfileChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ¹Ø¯ÙŠÙ„ المل٠الشخصي للعضو", + "Accounts_PasswordReset" : "إعادة تعيين كلمة السر", "Add_Members" : "إضاÙØ© الأعضاء", "Add_users" : "إضاÙØ© مستخدمين", + "Administration" : "الإدارة", "All_channels" : "جميع القنوات", "and" : "Ùˆ", "are_also_typing" : "هم أيضا يكتبون", @@ -10,6 +15,10 @@ "Are_you_sure" : "هل أنت متأكد؟", "away" : "بعيد", "Away" : "بعيد", + "away_female" : "بعيدة", + "Away_female" : "بعيدة", + "away_male" : "بعيد", + "Away_male" : "بعيد", "Back_to_login" : "العودة إلى تسجيل الدخول", "bold" : "عريض", "busy" : "مشغول", @@ -31,18 +40,27 @@ "Create_new_private_group" : "إنشاء مجموعة خاصة جديدة", "Create_new_public_channel" : "إنشاء قناة عامة جديدة", "Created_at" : "أنشئت ÙÙŠ", + "Desktop_Notifications" : "تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨", + "Desktop_Notifications_Disabled" : "تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ معطلة. قم بتغيير إعدادات المتصÙØ Ø¥Ø°Ø§ أردت تÙعيلها.", + "Desktop_Notifications_Enabled" : "تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ Ù…Ùعلة", "Direct_Messages" : "الرسائل المباشرة", + "Disable_Favorite_Rooms" : "تعطيل المÙضلة", + "Disable_New_Message_Notification" : "تعطيل التنبيه عن رسالة جديدة", + "Disable_New_Room_Notification" : "تعطيل التنبيه عن غرÙØ© جديدة", "edited" : "عدلت", "Email_or_username" : "البريد الإلكتروني أو اسم المستخدم", "Email_verified" : "تم التØقق من البريد الإلكتروني", + "Enable_Desktop_Notifications" : "تÙعيل تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨", "Enter_info" : "ادخل المعلومات الخاصة بك", "Error_changing_password" : "خطأ ÙÙŠ تغيير كلمة السر", + "False" : "لا", "Favorites" : "المÙضلة", "Forgot_password" : "نسيت كلمة السر", "Get_to_know_the_team" : "تعر٠على Rocket.Team", "github_no_public_email" : "ليس لديك أي بريد الإلكتروني عام ÙÙŠ Øسابك على Github", "Hide_room" : "إخÙاء الغرÙØ©", "History" : "تاريخ", + "Incorrect_Password" : "كلمة السر غير صØÙŠØØ©", "inline_code" : "نص_برمجي", "Invalid_confirm_pass" : "تأكيد كلمة السر لا تطابق كلمة السر", "Invalid_email" : "البريد الإلكتروني المدخل غير صØÙŠØ", @@ -75,6 +93,7 @@ "More_channels" : "المزيد من القنوات", "Msgs" : "رسائل", "multi" : "متعدد", + "My_Account" : "Øسابي", "n_messages" : "%s رسائل", "Name" : "اسم", "New_messages" : "رسائل جديدة", @@ -87,21 +106,31 @@ "Not_allowed" : "غير مسموØ", "Not_found_or_not_allowed" : "غير موجود أو غير مسموØ", "Nothing_found" : "لا يوجد شيء", + "Old_and_new_password_required" : "تØتاج إلى كتابة كلمة السر القديمة والجديدة لتغيير كلمة السر الخاصة بك.", + "Old_Password" : "كلمة السر القديمة", "Online" : "متواجد", "Oops!" : "عÙوا", "Password" : "كلمة السر", + "Password_changed_successfully" : "تم تغيير كلمة السر بنجاØ", "Please_wait" : "يرجى الانتظار", + "Please_wait_statistics" : "يرجى الانتظار إلى أن يتم Øساب الإØصائيات", + "Preferences" : "الإعدادات", + "Preferences_saved" : "تم ØÙظ الإعدادات", "Privacy" : "خصوصية", "Private_Groups" : "مجموعات خاصة", + "Profile" : "المل٠الشخصي", + "Profile_saved_successfully" : "تم ØÙظ المل٠الشخصي بنجاØ", "Quick_Search" : "بØØ« سريع", "quote" : "اقتباس", "Register" : "تسجيل Øساب جديد", "Remember_me" : "تذكرني", "Remove" : "إزالة", + "Remove_Admin" : "إزالة مدير", "Reset_password" : "إعادة تعيين كلمة السر", "Room" : "غرÙØ©", "Room_name_changed" : "تم تغيير اسم الغرÙØ© إلى: <em>__room_name__</em> بواسطة <em>__user_by__</em>", "Room_name_changed_successfully" : "تم تغيير اسم الغرÙØ© بنجاØ", + "Rooms" : "الغرÙ", "Search" : "بØØ«", "Search_Messages" : "بØØ« الرسائل", "Select_an_avatar" : "اختر صورة", @@ -114,18 +143,31 @@ "Showing_results" : "<p>يعرض <b>%s</b> نتائج</p>", "Silence" : "الصمت", "since_creation" : "منذ %s", + "Sound" : "صوت", "Start_of_conversation" : "بداية المØادثة", + "Statistics" : "Ø¥Øصائيات", + "Stats_Away_Users" : "المستخدمين البعيدين", + "Stats_Max_Room_Users" : "أقصى عدد للمستخدمين ÙÙŠ الغرÙ", + "Stats_Total_Direct_Messages" : "إجمالي عدد غر٠الرسالة المباشرة", "Stats_Total_Messages" : "مجموع الرسائل", + "Stats_Total_Rooms" : "إجمالي عدد الغرÙ", "strike" : "شطب", + "True" : "نعم", + "Unread_Rooms" : "غر٠غير مقروءة", + "Unread_Rooms_Mode" : "وضع الغر٠الغير مقروءة", "Use_initials_avatar" : "استخدم الأØر٠الأولى من اسم المستخدم", "use_menu" : "استخدم القائمة الجانبية للوصول إلى الغر٠الخاصة بك والمØادثات", "Use_service_avatar" : "استخدام %s الرمزية", "Use_this_username" : "استخدم هذا الاسم", "Use_uploaded_avatar" : "استخدم الصورة المØملة", + "Use_url_for_avatar" : "استخدم رابط للصورة الرمزية", "User_added_by" : "تم إضاÙØ© <em>__user_added__</em> بواسطة <em>__user_by__</em>.", + "User_is_no_longer_an_admin" : "المستخدم لم يعد مديرا", + "User_is_now_an_admin" : "المستخدم الآن مدير", "User_joined_channel" : "انضم للقناة.", "User_left" : "غادر القناة.", "User_logged_out" : "المستخدم سجل الخروج", + "User_not_found_or_incorrect_password" : "اسم المستخدم غير موجود أو كلمة السر غير صØÙŠØØ©", "User_removed_by" : "تم ØØ°Ù <em>__user_removed__</em> بواسطة <em>__user_by__</em>.", "Username" : "اسم المستخدم", "Username_cant_be_empty" : "اسم المستخدم لا يمكن أن يكون Ùارغا", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index fb21a34ff28..56d73d095a8 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -523,4 +523,4 @@ "Your_entry_has_been_deleted" : "Your entry has been deleted.", "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 7b8e70f53a9..01f48d5c754 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -1,16 +1,22 @@ { + "Access_not_authorized" : "Pääsy estetty.", "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", "Accounts" : "Käyttäjätilit", "Accounts_AllowedDomainsList" : "Pilkkueroteltu lista sallituista domaineista", + "Accounts_AllowedDomainsList_Description" : "Pilkuilla eroteltu luettelo sallituista verkkotunnuksia", "Accounts_AllowPasswordChange" : "Salli salasanan vaihto", + "Accounts_AllowUserAvatarChange" : "Salli käyttäjän avatarin muutos", "Accounts_AllowUsernameChange" : "Salli käyttäjätunnuksen muuttaminen", + "Accounts_AllowUserProfileChange" : "Salli käyttäjän profiilin muutos", "Accounts_AvatarResize" : "Muuta avatarien kokoa", "Accounts_AvatarSize" : "Avatarin koko", "Accounts_AvatarStorePath" : "Avatarin tallennuspolku", "Accounts_AvatarStoreType" : "Avatarien tallennusmuoto", "Accounts_denyUnverifiedEmail" : "Estä vahvistamaton sähköpostiosoite", "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_ManuallyApproveNewUsers" : "Hyväksy uudet käyttäjät manuaalisesti", "Accounts_OAuth_Custom_Authorize_Path" : "Auktorisointipolku", "Accounts_OAuth_Custom_Button_Color" : "Painikkeen väri", @@ -43,6 +49,15 @@ "Accounts_OAuth_Twitter" : "Twitter-tunnus", "Accounts_OAuth_Twitter_id" : "Twitter ID", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Salasanan nollaus", + "Accounts_Registration_AuthenticationServices_Enabled" : "Rekisteröinti autentikointipalveluiden kautta", + "Accounts_RegistrationForm" : "Rekisteröintilomake", + "Accounts_RegistrationForm_Disabled" : "Pois päältä", + "Accounts_RegistrationForm_LinkReplacementText" : "Ilmoittautumislomakkeen linkin korvaava teksti", + "Accounts_RegistrationForm_Public" : "Julkinen", + "Accounts_RegistrationForm_Secret_URL" : "Salainen URL", + "Accounts_RegistrationForm_SecretURL" : "Ilmoittautumislomakkeen salainen URL", + "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ä", "Activate" : "Aktivoi", @@ -50,8 +65,10 @@ "Add_Members" : "Lisää osallistujia", "Add_users" : "Lisää käyttäjiä", "Administration" : "Ylläpito", + "Alias" : "Alias", "All_channels" : "Kaikki kanavat", "Allow_Invalid_SelfSigned_Certs" : "Salli virheelliset ja itse allekirjoitetut SSL varmenteet linkin validointiin ja esikatseluihin", + "Allow_Invalid_SelfSigned_Certs_Description" : "Hyväksy virheelliset ja itse allekirjoitetut SSL-varmenteet linkkien validoinnissa ja esikatselussa.", "and" : "ja", "API" : "API", "API_Analytics" : "Analytics", @@ -63,6 +80,7 @@ "Are_you_sure" : "Oletko varma?", "Auto_Load_Images" : "Lataa kuvat automaattisesti\n", "Avatar_changed_successfully" : "Avatar vaihdettu onnistuneesti", + "Avatar_URL" : "Avatarin URL", "Avatar_url_invalid_or_error" : "URL on virheellinen tai ei ole käytettävissä. Yritä uudestaan.", "away" : "poissa", "Away" : "Poissa", @@ -70,6 +88,7 @@ "Away_female" : "Poissa", "away_male" : "poissa", "Away_male" : "Poissa", + "Back_to_integrations" : "Takaisin integraatioihin", "Back_to_login" : "Takaisin kirjautumiseen", "bold" : "lihavoitu", "busy" : "varattu", @@ -80,10 +99,13 @@ "Busy_male" : "Varattu", "Cancel" : "Peruuta", "CDN_PREFIX" : "CDN etuliite", + "Certificates_and_Keys" : "Sertifikaatit ja avaimet", "Change_avatar" : "Vaihda avatar", "Channels" : "Kanavat", "Channels_list" : "Julkiset kanavat", "Chat_Rooms" : "Chathuoneet", + "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?", "close" : "sulje", "coming_soon" : "tulossa", @@ -93,11 +115,13 @@ "Contact" : "Yhteys", "Conversation" : "Keskustelu", "Convert_Ascii_Emojis" : "Muunna ASCII-merkit Emojiksi", + "COPY_TO_CLIPBOARD" : "KOPIOI LEIKEPÖYDÄLLE", "Create_new" : "Luo uusi", "Create_new_direct_message_room" : "Luo uusi yksityisviestikeskustelu", "Create_new_private_group" : "Luo uusi privaattiryhmä", "Create_new_public_channel" : "Luo uusi julkinen kanava", "Created_at" : "Luotu", + "Created_at_s_by_s" : "Luotu <strong>%s</strong> käyttäjän <strong>%s</strong> toimesta", "Custom_oauth_helper" : "Kun perustat OAuth Providerin, sinun täytyy ilmoittaa Callback URL. Käytä <pre>%s</pre>.", "Custom_oauth_unique_name" : "Mukautettu oauth yksilöllinen nimi", "days" : "päivää", @@ -124,6 +148,7 @@ "Enable_Desktop_Notifications" : "Ota työpöytäilmoitukset käyttöön", "Enter_info" : "Syötä kirjautumistietosi", "Enter_to" : "Astu sisään", + "Error" : "Virhe", "Error_changing_password" : "Virhe vaihtaessa salasanaa", "Error_too_many_requests" : "Virhe, liikaa pyyntöjä. Rauhoitu hieman.\nOdota %s sekuntia ennen uudelleenyritystä.", "Esc_to" : "Poistu", @@ -132,6 +157,7 @@ "FileUpload" : "Lähetä tiedosto", "FileUpload_Enabled" : "Tiedostojen lähetykset käytössä", "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ä", "Follow_social_profiles" : "Seuraa someamme, forkkaa Githubissa ja jaa ajatuksiasi rocket.chatista trellossa.", @@ -149,15 +175,25 @@ "hours" : "tuntia", "Incorrect_Password" : "Väärä salasana", "inline_code" : "koodi", + "Install_Extension" : "Asenna laajennus", "Install_FxOs" : "Asenna Rocket.Chat Firefoxiisi", "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_Incoming_WebHook" : "Sisääntuleva WebHook-integraatio", + "Integration_New" : "Uusi integraatio", + "Integrations" : "Integraatiot", + "Invalid_asset" : "Virheellinen resurssi", "Invalid_confirm_pass" : "Salasanat eivät täsmää", "Invalid_email" : "Annettu sähköpostiosoite ei ole oikea", + "Invalid_file_height" : "Virheellinen tiedoston korkeus", + "Invalid_file_type" : "Virheellinen tiedostotyyppi", + "Invalid_file_width" : "Virheellinen tiedoston leveys", "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_Secret_URL" : "Virheellinen salainen URL", + "Invalid_secret_URL_message" : "URL on virheellinen.", "invisible" : "näkymätön", "Invisible" : "Näkymätön", "Invitation_HTML" : "Kutsu HTML", @@ -223,7 +259,7 @@ "Message_AllowEditing_BlockEditInMinutes" : "Estä viestin muokkaus (x) minuutin jälkeen", "Message_AllowEditing_BlockEditInMinutesDescription" : "Syötä 0 poistaaksesi muutoseston", "Message_AudioRecorderEnabled" : "Äänentallennin käytössä", - "Message_AudioRecorderEnabledDescription" : "Jotta tämä toimisi, WAV-tiedostojen lähetys tulee olla sallittu", + "Message_AudioRecorderEnabledDescription" : "Jotta tämä toimisi, WAV-tiedostojen (mediatyyppi 'audio/wav') lähetys tulee olla sallittu", "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", @@ -236,6 +272,7 @@ "Message_ShowEditedStatus" : "Näytä muokkaustila", "Message_ShowFormattingTips" : "Näytä muotoiluvihjeet", "Messages" : "Viestit", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here" : "Viestit, jotka lähetetään sisääntulevaan WebHookiin, postataan tänne", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Google Site Verification", @@ -253,6 +290,7 @@ "Name" : "Nimi", "Name_cant_be_empty" : "Nimi ei voi olla tyhjä", "Name_optional" : "Nimi (valinnainen)", + "New_integration" : "Uusi integraatio", "New_messages" : "Uusia viestejä", "New_password" : "Uusi salasana", "No_channel_with_name_%s_was_found" : "Kanavaa nimeltä '%s' ei löytynyt!", @@ -261,9 +299,12 @@ "No_favorites_yet" : "Et ole vielä lisännyt suosikkeja.", "No_group_with_name_%s_was_found" : "Privaattiryhmää '%s' ei löytynyt!", "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_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", + "Not_authorized" : "Ei sallittu", "Not_found_or_not_allowed" : "Ei löydy tai ei sallittu", "Nothing_found" : "Ei löytynyt", "Notify_all_in_this_room" : "Ilmoita kaikille kanavallaolijoille", @@ -274,6 +315,7 @@ "Oops!" : "Oho", "Opt_out_statistics" : "Älä lähetä anonyymejä tilastoja Rocket.Chatille", "Opt_out_statistics_warning" : "Lähettämällä anonyymit tilastot, autat meitä selvittämään, kuinka monta Rocket.Chat -ympäristöä on käynnistetty, kuten myös sen, miten hyvin järjestelmä toimii. Tätä tietoa käytetään Rocket.Chatin parantamiseen.\nJos haluat jatkaa anonyymien tilastojen lähettämistä, poista ylläoleva ruksi. Kiitos.", + "optional" : "valinnainen", "others" : "muut", "Password" : "Salasana", "Password_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut salasanan vaihtamismahdollisuuden", @@ -283,6 +325,9 @@ "Please_wait" : "Odota hetki", "Please_wait_activation" : "Odota, tämä voi kestää jonkin aikaa.", "Please_wait_statistics" : "Odota, tilastoja generoidaan.", + "Post_as" : "Postaa käyttäjänä", + "Post_to_Channel" : "Postaa kanavalle", + "Post_to_s_as_s" : "Postaa paikkaan <strong>%s</strong> käyttäjänä <strong>%s</strong>", "Powered_by" : "Powered by", "Preferences" : "Asetukset", "Preferences_saved" : "Asetukset tallennettu", @@ -300,14 +345,19 @@ "Push_apn_key" : "APN Key", "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", + "push_disabled" : "Push pois päältä", "Push_enable" : "Kytke päälle", + "Push_enable_gateway" : "Ota yhdyskäytävä käyttöön", + "Push_gateway" : "Yhdyskäytävä", "Push_gcm_api_key" : "GCM API Key", "Push_gcm_project_number" : "GCM Project Number", "Push_production" : "Tuotanto", + "Push_test_push" : "Testaa", "Quick_Search" : "Pikaetsintä", "quote" : "lainaus", "Recents" : "Viimeisimmät", "Record" : "Nauhoita", + "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", @@ -315,6 +365,8 @@ "Remove_Admin" : "Poista ylläpitäjyys", "Remove_custom_oauth" : "Poista mukautettu oauth", "Reset_password" : "Nollaa salasana", + "Restart" : "Käynnistä uudelleen", + "Restart_the_server" : "Käynnistä palvelin uudelleen", "Room" : "Huone", "Room_name_changed" : "Huoneen nimi vaihdettu <em>__room_name__</em> <em>__user_by__</em> toimesta", "Room_name_changed_successfully" : "Huoneen nimi vaihdettu", @@ -332,6 +384,7 @@ "SAML_Custom_Provider" : "Custom Provider", "Save_changes" : "Tallenna muutokset", "Save_Mobile_Bandwidth" : "Säästä kaistaa mobiilissa", + "Screen_Share" : "Näytön jakaminen", "Search" : "Etsi", "Search_Messages" : "Etsi viestejä", "Search_settings" : "Etsi asetuksista", @@ -343,15 +396,20 @@ "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_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", "Send_invitation_email" : "Lähetä kutsusähköposti", "Send_invitation_email_error" : "Et ole antanyt yhtään validia sähköpostiosoitetta.", "Send_invitation_email_info" : "Voit lähettää useita sähköpostikutsuja kerralla.", "Send_invitation_email_success" : "Olet onnistuneesti lähettänyt sähköpostikutsun seuraaviin osoitteisiin:", "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", "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_online_users" : "Näytetään <b>__total_online__</b>/__total__ users", "Showing_results" : "<p>Näytetään <b>%s</b> tulosta</p>", "Silence" : "Hiljaisuus", @@ -366,6 +424,7 @@ "SMTP_Username" : "SMTP Käyttäjätunnus", "Sound" : "Ääni", "Start_of_conversation" : "Keskustelun alku", + "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ä", "Stats_Avg_Channel_Users" : "Keskimääräinen kanavan käyttäjämäärä", @@ -393,12 +452,18 @@ "Stop_Recording" : "Lopeta nauhoittaminen", "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_field_is_required" : "Kenttä %s vaaditaan.", + "The_server_will_restart_in_s_seconds" : "Palvelin käynnistyy %s sekunnin kuluttua", + "There_is_no_integrations" : "Integraatioita ei ole", + "This_is_a_push_test_messsage" : "Tämä on testi-pushviesti", "True" : "Kyllä", "Unnamed" : "Nimetön", "Unread_Rooms" : "Lukemattomia", "Unread_Rooms_Mode" : "Lukemattomien tila", "Upload_file_question" : "Lähetä tiedosto?", + "Uploading_file" : "Ladataan tiedostoa...", "Use_Emojis" : "Käytä Emojia", "Use_initials_avatar" : "Käytä käyttäjätunnuksen nimikirjaimia", "use_menu" : "Käytä sivuvalikkoa käyttääksesi huoneitasi ja chattejasi", @@ -423,6 +488,7 @@ "User_left_male" : "Käyttäjä poistui kanavalta.", "User_logged_out" : "Käyttäjä on kirjautunut ulos", "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_Settings" : "Käyttäjän asetukset", "User_updated_successfully" : "Käyttäjän tiedot päivitetty", @@ -434,6 +500,9 @@ "Username_title" : "Rekisteröi käyttäjänimi", "Username_unavaliable" : "<strong>%s</strong> on jo käytössä :(", "Users" : "Käyttäjät", + "UTF8_Names_Slugify" : "Siisti UTF8-nimet", + "UTF8_Names_Validation" : "UTF-nimien validointi", + "UTF8_Names_Validation_Description" : "Älä anna erikoismerkkejä ja välilyöntejä. Voit käyttää - _ ja . mutta ei nimen lopussa", "View_All" : "Katso kaikki", "Wait_activation_warning" : "Ennen kuin voit kirjautua, tunnuksesi pitää aktivoida ylläpitäjän toimesta.", "We_have_sent_password_email" : "Lähetimme salasanan nollausohjeet sähköpostiisi. Mikäli et saanut sähköpostia, yritä uudelleen.", @@ -441,11 +510,16 @@ "Welcome" : "Tervetuloa <em>%s</em>.", "Welcome_to_the" : "Tervetuloa", "With_whom" : "kanssa", + "Yes" : "Kyllä", "Yes_clear_all" : "Jep, tyhjennä kaikki!", "Yes_delete_it" : "Kyllä, poista!", "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_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_Open_Source_solution" : "Your own Open Source chat solution" + "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/km.i18n.json b/i18n/km.i18n.json index 7eec24db6be..696cdec725e 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -77,6 +77,7 @@ "busy_male" : "រវល់", "Busy_male" : "រវល់", "Cancel" : "បញ្ឈប់", + "CDN_PREFIX" : "CDN បុព្វបទ", "Change_avatar" : "ប្ážáž¼ážšâ€‹ážšáž¼áž”", "Channels" : "ប៉ុស្ážáž·áŸ", "Channels_list" : "បណ្ážáž¶áž”៉ុស្ážáž·áŸâ€‹ážŸáž¶áž’ារណៈ", @@ -185,8 +186,10 @@ "LDAP" : "ប្រើ LDAP", "LDAP_Bind_Search" : "ចំណងស្វែងរក", "LDAP_DN" : " LDAP DN", + "LDAP_DN_Description" : "ការស្វែង root; ឧទាហរណ០dc=domain, dc=com", "LDAP_Enable" : "អនុញ្ញាážáž· LDAP", "LDAP_Port" : "ច្រក LDAP", + "LDAP_Port_Description" : "ផែដើម្បីចូលទៅកាន់ LDAP ážáŸ’រង់លáŸáž; ឧទាហរណáŸáŸ– 389 ", "LDAP_Sync_User_Data" : "រក្សាទិន្ននáŸáž™ User ដោយ Sync ជាមួយ Server", "LDAP_Url" : "URL របស់ LDAP", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", @@ -374,6 +377,8 @@ "The_field_is_required" : "ចន្លោះ %s ážáŸ’រូវ​បំពáŸáž‰", "True" : "áž–áž·áž", "Unnamed" : "គ្មាន​ឈ្មោះ", + "Unread_Rooms" : "បន្ទប់​ដែល​មិនទាន់​អាន", + "Unread_Rooms_Mode" : "របៀប​បន្ទប់​ដែល​មិនទាន់​អាន", "Upload_file_question" : "ផ្ទុក​ឯកសារ​ឡើង​ឬ?", "Use_Emojis" : "ប្រើ Emoji", "Use_initials_avatar" : "ប្រើឈ្មោះ​អ្នក​ជា​ពិសáŸážŸ", diff --git a/i18n/ku.i18n.json b/i18n/ku.i18n.json new file mode 100644 index 00000000000..6a7fb207c0d --- /dev/null +++ b/i18n/ku.i18n.json @@ -0,0 +1,120 @@ +{ + "Access_online_demo" : "سەیری دێمۆی سەرهێڵ بکە", + "Access_Online_Demo" : "سەیری دێمۆی سەرهێڵ بکە", + "Add_users" : "بەکارهێنەر زیادبکە", + "and" : "Ùˆ", + "are_also_typing" : "ئەوانیش ئەنوسن", + "are_typing" : "ئەنوسن", + "Back_to_integrations" : "گەڕانەوە بۆ تێهەڵکێشان", + "Cancel" : "پوچکردنەوە", + "Channels" : "کەناڵەکان", + "Channels_list" : "لیستی کەناڵه گشتیەکان", + "Chat_Rooms" : "ژوورەکانی چات", + "Choose_the_username_that_this_integration_will_post_as" : "ناوی بەکارهێنەرێ هەڵبژێرە Ú©Û• ئەم تێهەڵکێشانە بڵاوکرێتەوە بە ناویەوە.", + "close" : "داخستن", + "Confirm_password" : "تێپەڕەوشەکەت پشتڕاستکەوە", + "Contact" : "پەیوەندیەکان", + "Conversation" : "Ú¯Ùتوگۆ", + "COPY_TO_CLIPBOARD" : "Ú©Û†Ù¾ÛŒ بکە", + "Create_new_public_channel" : "کەناڵێکی گشتی دروست بکە", + "Created_at" : "دروستکرا Ù„Û•", + "Direct_Messages" : "نامەی ڕاستەوخۆ", + "edited" : "دەستکاریکرا", + "Email_or_username" : "ئیمەیڵ یان ناوی بەکارهێنەر", + "Email_verified" : "ئیمەیڵ پشتڕاستکرایەوە", + "Enter_info" : "زانیاریەکانت تێ بکە", + "Error_changing_password" : "Ù‡Û•ÚµÛ• ڕوویدا Ù„Û• گۆڕینی تێپەڕەوشە", + "Favorites" : "دڵخوازەکان", + "FileUpload_MediaType_NotAccepted" : "جۆری میدیا Ú•ÛŽ پێدراو نیە", + "Follow_social_profiles" : "Ù„Û• پرۆÙایلە کۆمەڵایەتیەکانمان شوێنمان Ú©Û•ÙˆÛ•ØŒ Ùۆرکمان بکە Ù„Û• گیتهەب Ùˆ بۆچوونەکانت بەش بکە دەربارەی ڕۆکێت.چات لەسەر بۆردی ترێلۆ'کەمان", + "Forgot_password" : "تێپەڕەوشەت بیرچوە", + "Fork_it_on_github" : "Ùۆرکی بکە Ù„Û• گیتهەب", + "github_no_public_email" : "Ù„Û• هەژماری گیتهەبەکەت هیچ ئیمەیڵێکی کراوەی گشتیت نیە", + "Have_your_own_chat" : "تۆڕی چاتکردنی خۆتت هەبێت. پەرەپێدراو بە Meteor.comØŒ ڕۆکێت چات بژاردەیەکی زۆر چاکە بۆ پەرەپێدەرانێک بەدوای دروستکردن Ùˆ گەشەپێدانی پلاتÙۆرمی چاتی خۆیاندا بگەڕێن.", + "Hide_room" : "شاردنەوەی ژوور", + "History" : "مێژوو", + "Integration_Incoming_WebHook" : "تێهەڵکێشانی هاتوو Ù„Û• WebHook", + "Integration_New" : "تێهەڵکێشانی تازە", + "Integrations" : "تێهەڵکێشان", + "Invalid_confirm_pass" : "دووبارەکراوەی تێپەڕەوشە یەکناگرێتەوە Ù„Û•Ú¯Û•Úµ تێپەڕەوشە", + "Invalid_email" : "ئیمەیڵی نوسراو هەڵەیە.", + "Invalid_name" : "ناو نابێ بەتاڵ بێت", + "Invalid_pass" : "تێپەڕەوشە نابێ بەتاڵ بێت", + "Invalid_room_name" : "<strong>%s</strong> ناوێکی دروست نیە بۆ ژوور، <br/> تەنها پیت، ژمارە Ùˆ داش بەکاربهێنە", + "is_also_typing" : "یش ئەنوسێ", + "is_typing" : "ئەنوسێ", + "Join_the_Community" : "پەیوەندی بکە بە کۆمەڵگاکەوە", + "Language_Version" : "وەشانی ئینگلیزی", + "Last_message" : "دوا نامە", + "Leave_room" : "جێهێشتنی ژوور", + "Load_more" : "زیاتر بارکە", + "Loading_suggestion" : "بژاردەکان بارئەکرێن...", + "Login" : "چوونەژوور", + "login_with" : "یان بچۆ ژوورەوە بە", + "Members" : "ئەندامان", + "Members_List" : "لیستی ئەندامان", + "Members_placeholder" : "ئەندامان", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here" : "ئەو نامانەی ئەنێردرێن بۆ WebHookÛ• هاتوەکان لێرە دا ئەنرێت", + "More_channels" : "کەناڵی تر", + "Msgs" : "نامەکان", + "n_messages" : "%s نامە", + "Name" : "ناو", + "New_integration" : "تێهەڵکێشانی تازە", + "New_messages" : "نامە تازەکان", + "New_password" : "تێپەڕەوشەی نوێ", + "No_channels_yet" : "تۆ هێشتا Ù„Û• هیچ کەناڵێک نیت.", + "No_direct_messages_yet" : "تۆ هێشتا هیچ Ú¯Ùتوگۆیەکت دەست پێنەکردوە.", + "No_favorites_yet" : "هێشتا هیچ شتێکت دڵخواز نەکردوە.", + "No_groups_yet" : "هێشتا گروپی تایبەتت نیە.", + "No_permission_to_view_room" : "مۆڵەتت پێنەدراوە ئەم ژوورە ببینیت", + "Nothing_found" : "هیچ نەدۆزرایەوە", + "optional" : "بژاردەییە", + "Password" : "تێپەڕەوشە", + "Please_wait" : "تکایە چاوەڕێ بە", + "Post_as" : "بڵاویکەوە بەناوی", + "Post_to_Channel" : "بینێر بۆ کەناڵ", + "Powered_by" : "پشتبەستوو بە", + "Private_Groups" : "گروپی تایبەت", + "Proudly_developed" : "بە شانازیەوە Ú¯Û•Ø´Û•ÛŒ پێدراوە بە میتیۆ", + "Quick_Search" : "گەڕانی خێرا", + "Recents" : "تازەکان", + "Register" : "بۆ هەژماری نوێ خۆت تۆمارکە", + "Remember_me" : "منت بیر بێ", + "Remove" : "لایبە", + "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" : "تەنها سەرهێڵ", + "Selected_users" : "ئەندامانی هەڵبژێردراو", + "Send_confirmation_email" : "ئیمەیڵی پشتڕاستکردنەوە بنێرە", + "Send_data_into_RocketChat_in_realtime" : "داتا بنێر بۆ ڕۆکێت.چات بە لەهەمان کاتدا", + "Send_Message" : "نامەی نوێ", + "Send_your_JSON_payloads_to_this_URL" : "پەیلۆدە جەیسنەکانت بنێرە بۆ ئەم URL", + "Should_exists_a_user_with_this_username" : "ئەبێ بەکارهێنەرێ بەم ناوە هەبێت", + "Showing_online_users" : "<b>__total_online__</b> Ù„Û• __total__ users نیشاندراوە", + "Showing_results" : "<p>نیشاندانی <b>%s</b> ئەنجام</p>", + "since_creation" : "Ù„Û• %s Ù€Û•ÙˆÛ•", + "Start_of_conversation" : "سەرەتای Ú¯Ùتوگۆ", + "Submit" : "ناردن", + "The_server_will_restart_in_s_seconds" : "ڕاژەکارەکە Ù‡Û•Úµ ئەبێتەوە Ù„Û• %s چرکەدا", + "use_menu" : "مێنوی لاتەنیشت بەکاربهێنە بۆ چوونە ناو ژوور Ùˆ چاتەکانت", + "User_added_by" : "بەکارهێنەر <em>__user_added__</em> زیادکرا لەلایەن <em>__user_by__</em>.\n", + "User_left" : "کەناڵی جێهێشت.", + "User_logged_out" : "بەکارهێنەر Ú†ÙˆÛ• دەرەوە", + "User_removed_by" : "بەکارهێنەر <em>__user_removed__</em> لابرا لەلایەن <em>__user_by__</em>.", + "Username" : "ناوی بەکارهێنەر", + "UTF8_Names_Slugify" : "نازناو بۆ ناوی UTF8", + "UTF8_Names_Validation" : "پشتڕاستکردنەوەی ناوی UTF8", + "View_All" : "هەموو ببینە", + "We_have_sent_password_email" : "ئێمە ئیمەیڵێکمان بۆ ناردی بۆ ئەوەی تێپەڕەوشەکەت دانێیتەوە. ەگەر ئیمەیڵەکە بەم زوانە نەهات، تکایە وەرەوە Ùˆ دووبارە Ù‡Û•ÙˆÚµ بدەرەوە.", + "We_have_sent_registration_email" : "ئێمە ئیمەیڵێکمان بۆ ناردی بۆ دڵنیاکردنەوە Ù„Û• تۆمارکردنەکەت. ئەگەر ئیمەیڵەکە بەم زوانە نەهات، تکایە وەرەوە Ùˆ دووبارە Ù‡Û•ÙˆÚµ بدەرەوە.", + "Welcome" : "خێرهاتی <em>%s</em>.", + "Welcome_to_the" : "خێرهاتی بۆ", + "You_need_confirm_email" : "ئەبێ ئیمەیڵەکەت پشتڕاستکەیتەوە تا بچیتە ژوور.", + "Your_Open_Source_solution" : "چاتی سەرچاوە کراوەی خۆت" +} \ No newline at end of file diff --git a/i18n/lo.i18n.json b/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/i18n/nl.i18n.json b/i18n/nl.i18n.json new file mode 100644 index 00000000000..0e333939023 --- /dev/null +++ b/i18n/nl.i18n.json @@ -0,0 +1,294 @@ +{ + "Access_online_demo" : "Toegang tot de online demo", + "Access_Online_Demo" : "Toegang tot de online demo", + "Accounts_denyUnverifiedEmail" : "Weiger ongeverifieerde e-mail", + "Accounts_EmailVerification" : "Email verificatie", + "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_Google" : "Google Inloggen", + "Accounts_OAuth_Google_id" : "Google Id", + "Accounts_OAuth_Google_secret" : "Google Secret", + "Accounts_OAuth_Linkedin" : "LinkedIn Inloggen", + "Accounts_OAuth_Linkedin_id" : "LinkedIn Id", + "Accounts_OAuth_Linkedin_secret" : "LinkedIn Secret", + "Accounts_OAuth_Meteor" : "Meteor Inloggen", + "Accounts_OAuth_Meteor_id" : "Meteor Id", + "Accounts_OAuth_Meteor_secret" : "Meteor Secret", + "Accounts_OAuth_Twitter" : "Twitter Inloggen", + "Accounts_OAuth_Twitter_id" : "Twitter Id", + "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_RegistrationRequired" : "Registratie vereist", + "Add_Members" : "Voeg leden toe", + "Add_users" : "Gebruikers toevoegen", + "Administration" : "Administratie", + "All_channels" : "Alle kanalen", + "and" : "en", + "API_Analytics" : "Analytics", + "API_Embed" : "Embed", + "are_also_typing" : "zijn ook aan het typen", + "are_typing" : "zijn aan het typen", + "Are_you_sure" : "Weet u het zeker?", + "Avatar_changed_successfully" : "Afbeelding is gewijzigd", + "away" : "Afwezig", + "Away" : "Afwezig", + "away_female" : "afwezig", + "Away_female" : "Afwezig", + "away_male" : "afwezig", + "Away_male" : "Afwezig", + "Back_to_login" : "Terug naar Inloggen", + "bold" : "vetgedrukt", + "busy" : "Bezet", + "Busy" : "Bezet", + "busy_female" : "bezet", + "Busy_female" : "Bezet", + "busy_male" : "bezet", + "Busy_male" : "Bezet", + "Cancel" : "Annuleren", + "Change_avatar" : "Verander uw foto", + "Channels" : "Kanalen", + "Channels_list" : "Lijst van de openbare kanalen", + "Chat_Rooms" : "Kanalen", + "close" : "Sluiten", + "coming_soon" : "binnekort beschikbaar", + "Confirm_password" : "Bevestig uw wachtwoord", + "Contact" : "Contact", + "Conversation" : "Gesprek", + "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", + "days" : "dagen", + "Delete_User_Warning" : "Een gebruiker verwijderen betekent dat alle berichten van die gebruiker ook verwijderd worden. Dit kan niet ongedaan gemaakt worden.", + "Deleted" : "Verwijderd!", + "Direct_Messages" : "Directe berichten", + "Drop_to_upload_file" : "Sleep hierheen om een bestand te uploaden", + "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", + "edited" : "bewerkt", + "Email_already_exists" : "Emailadres bestaat al", + "Email_or_username" : "E-mail of gebruikersnaam", + "Email_verified" : "E-mail geverifiëerd", + "Enter_info" : "Voer uw gegevens in", + "Error_changing_password" : "Fout bij het veranderen van het wachtwoord", + "False" : "False", + "Favorites" : "Favorieten", + "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", + "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.", + "Hide_room" : "Kamer verbergen", + "History" : "Geschiedenis", + "hours" : "uur", + "inline_code" : "inline_code", + "Invalid_confirm_pass" : "De wachtwoorden zijn niet gelijk", + "Invalid_email" : "Ongeldig e-mail adres", + "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", + "invisible" : "onzichtbaar", + "Invisible" : "Onzichtbaar", + "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", + "is_typing" : "is aan het typen", + "is_typing_female" : "is aan het typen", + "is_typing_male" : "is aan het typen", + "italics" : "cursief", + "join" : "Toetreden", + "Join_the_Community" : "Word lid", + "Language" : "Taal", + "Language_Version" : "Nederlndse versie", + "Last_login" : "Laatste aanmelding", + "Last_message" : "Laatste bericht", + "Layout_Home_Body" : "Home Body", + "Layout_Home_Title" : "Home Titel", + "Layout_Sidenav_Footer" : "Side Navigation Footer", + "Layout_Sidenav_Footer_description" : "Footer afmetingen is 260 x 70px", + "LDAP_DN" : "Distinguished Name (DN)", + "LDAP_Port" : "LDAP Port", + "LDAP_Url" : "LDAP URL", + "Leave_room" : "Kamer verlaten", + "line" : "lijn", + "Load_more" : "Meer laden", + "Loading..." : "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", + "Members" : "Leden", + "Members_List" : "Ledenlijst", + "Members_placeholder" : "Leden", + "Message" : "Bericht", + "Message_AllowDeleting" : "Bericht verwijderen toestaan", + "Message_AllowEditing" : "Bericht bewerken toestaan", + "Message_deleting_not_allowed" : "Bericht verwijderen niet toegestaan", + "Message_editing_not_allowed" : "Bericht bewerken niet toegestaan", + "Message_KeepHistory" : "Bewaar berichten geschiedenis", + "Message_removed" : "Bericht verwijderd", + "Message_ShowDeletedStatus" : "Toon Verwijderde Status", + "Message_ShowEditedStatus" : "Toon Gewijzigde Status", + "Meta_fb_app_id" : "Facebook App Id", + "Meta_google-site-verification" : "Google Site Verification", + "Meta_language" : "Taal", + "Meta_msvalidate01" : "MSValidate.01", + "Meta_robots" : "Robots", + "minutes" : "minuten", + "More_channels" : "Meer kanalen", + "Msgs" : "Berichten", + "multi" : "multi", + "My_Account" : "Mijn account", + "n_messages" : "%s berichten", + "Name" : "Naam", + "New_messages" : "Nieuwe berichten", + "New_password" : "Nieuw Wachtwoord", + "No_channel_with_name_%s_was_found" : "Geen kanaal met de naam <strong>\"%s\"</strong> gevonden", + "No_channels_yet" : "U maakt nog geen deel uit van een kanaal.", + "No_direct_messages_yet" : "U bent nog geen gesprekken begonnen.", + "No_favorites_yet" : "U heeft nog geen favorieten toegevoegd.", + "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_user_with_username_%s_was_found" : "Geen gebruiker met de naam <strong>\"%s\"</strong> gevonden", + "Not_allowed" : "Niet toegestaan", + "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", + "Online" : "Online", + "Oops!" : "Oeps", + "others" : "anderen", + "Password" : "Wachtwoord", + "Password_changed_successfully" : "Wachtwoord succesvol gewijzigd", + "Please_wait" : "Wacht alstublieft", + "Please_wait_activation" : "Even geduld, dit kan enige tijd duren.", + "Please_wait_statistics" : "Even geduld, er worden statistieken gegenereerd.", + "Powered_by" : "Mede mogelijk gemaakt door", + "Privacy" : "Privacy", + "Private_Groups" : "Privé groepen", + "Profile" : "Profiel", + "Profile_saved_successfully" : "Profiel succesvol opgeslagen", + "Proudly_developed" : "Ontwikkeld met Meteor", + "Push_apn_cert" : "APN Certificaat", + "Push_apn_dev_cert" : "APN Ontwikkelaars Certificaat", + "Push_apn_dev_key" : "APN Ontwikkelaars Sleutel", + "Push_apn_dev_passphrase" : "APN Ontwikkelaars Wachtwoord", + "Push_apn_key" : "APN Key", + "Push_apn_passphrase" : "APN Wachtwoord", + "Push_debug" : "Debug", + "Push_enable" : "Enable", + "Push_production" : "Productie", + "Quick_Search" : "Snelzoeken", + "quote" : "citaat", + "Recents" : "Recente", + "Register" : "Registreer een nieuwe gebruiker", + "Registration_Succeeded" : "Registratie Geslaagd", + "Remember_me" : "Onthou me", + "Remove" : "Verwijderen", + "Remove_Admin" : "Verwijder Admin", + "Reset_password" : "Nieuw Wachtwoord", + "Room" : "Kamer", + "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_user_count" : "%s gebruikers", + "Save_changes" : "Wijzigingen opslaan", + "Search" : "Zoeken", + "Search_settings" : "Zoekinstellingen", + "seconds" : "secondes", + "See_all" : "Alles zien", + "See_only_online" : "Alleen online", + "Select_an_avatar" : "Selecteer een afbeelding", + "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_Message" : "Bericht verzenden", + "Settings" : "Instellingen", + "Settings_updated" : "Instellingen bijgewerkt", + "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", + "SMTP_Host" : "SMTP Host", + "SMTP_Password" : "SMTP-wachtwoord", + "SMTP_Port" : "SMTP Poort", + "SMTP_Username" : "SMTP Gebruikersnaam", + "Start_of_conversation" : "Begin van het gesprek", + "Stats_Active_Users" : "Actieve gebruikers", + "Stats_Avg_Channel_Users" : "Gemiddeld aantal Kanaal Gebruikers", + "Stats_Avg_Private_Group_Users" : "Gemiddeld aantal Privé Groep Gebruikers", + "Stats_Max_Room_Users" : "Maximaal aantal Kamer Gebruikers", + "Stats_Non_Active_Users" : "Inactieve Gebruikers", + "Stats_Offline_Users" : "Offline Gebruikers", + "Stats_Online_Users" : "Online Gebruikers", + "Stats_OS_Arch" : "OS Arch", + "Stats_OS_Cpus" : "OS CPU Count", + "Stats_OS_Freemem" : "OS Free Memory", + "Stats_OS_Loadavg" : "OS Load Gemiddeld", + "Stats_OS_Platform" : "OS Platform", + "Stats_OS_Release" : "OS Versie", + "Stats_OS_Totalmem" : "OS Totaal geheugen", + "Stats_OS_Type" : "OS Type", + "Stats_OS_Uptime" : "OS Uptime", + "Stats_Total_Channels" : "Totaal Kanalen", + "Stats_Total_Direct_Messages" : "Totaal Directe Berichten Kamers", + "Stats_Total_Private_Groups" : "Totaal Privé Groepen", + "Stats_Total_Rooms" : "Totaal aantal Kamers", + "Stats_Total_Users" : "Totaal aantal leden", + "strike" : "doorhalen", + "Submit" : "Verzenden", + "The_field_is_required" : "Het veld %s is vereist.", + "True" : "True", + "Unnamed" : "Naamloos", + "Upload_file_question" : "Bestand uploaden?", + "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", + "User_added_by" : "Gebruiker <em>__user_added__</em> toegevoegd door <em>__user_by__</em>", + "User_has_been_activated" : "Gebruiker is geactiveerd", + "User_has_been_deactivated" : "Gebruiker is gedeactiveerd", + "User_has_been_deleted" : "Gebruiker is verwijderd", + "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", + "User_joined_channel" : "Heeft zich aangesloten bij het kanaal.", + "User_joined_channel_female" : "Heeft zich aangesloten bij het kanaal.", + "User_joined_channel_male" : "Heeft zich aangesloten bij het kanaal.", + "User_left" : "Heeft het kanaal verlaten.", + "User_left_female" : "Heeft het kanaal verlaten.", + "User_left_male" : "Heeft het kanaal verlaten.", + "User_logged_out" : "Gebruiker is uitgelogd", + "User_removed_by" : "Gebruiker <em>__user_removed__</em> verwijderd door <em>__user_by__</em>.", + "User_Settings" : "Gebruikersinstellingen", + "User_updated_successfully" : "Gebruiker succesvol bijgewerkt", + "Username" : "Gebruikersnaam", + "Username_cant_be_empty" : "De gebruikersnaam mag niet leeg zijn", + "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 :(", + "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.", + "We_have_sent_registration_email" : "Wij hebben een e-mail gestuurd om uw registratie te bevestigen. Als u deze e-mail niet snel ontvangt, ook niet in uw spam-folder, kom dan terug en probeer het opnieuw.", + "Welcome" : "Welkom <em>%s</em>.", + "Welcome_to_the" : "Welkom bij de", + "With_whom" : "Met wie", + "Yes_delete_it" : "Ja, verwijder het!", + "you_are_in_preview_mode_of" : "U kijkt naar de voorbeschouwing van kanaal #<strong>__room_name__</strong>", + "You_need_confirm_email" : "U dient uw e-mail te bevestigen on in te kunnen loggen!", + "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" +} \ No newline at end of file diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index b7d0b3fa80f..040ad0cf694 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -1,20 +1,22 @@ { + "Access_not_authorized" : "DostÄ™p zabroniony", "Access_online_demo" : "Uzyskaj dostÄ™p do demo online", "Access_Online_Demo" : "Uzyskaj dostÄ™p do demo online", - "Access_not_authorized" : "DostÄ™p zabroniony", "Accounts" : "Konta", "Accounts_AllowedDomainsList" : "Lista dozwolonych domen", "Accounts_AllowedDomainsList_Description" : "Lista dozwolonych domen oddzielona przecinkami", "Accounts_AllowPasswordChange" : "Pozwól na zmianÄ™ hasÅ‚a", "Accounts_AllowUserAvatarChange" : "Pozwól na zmienianie avatarów", - "Accounts_AllowUserProfileChange" : "Pozwól na zmienianie profilów użytkowników", "Accounts_AllowUsernameChange" : "Pozwól na zmianÄ™ nazwy użytkownika", + "Accounts_AllowUserProfileChange" : "Pozwól na zmienianie profilów użytkowników", "Accounts_AvatarResize" : "Zmiana rozmiaru avatarów", "Accounts_AvatarSize" : "Rozmiar avataru", "Accounts_AvatarStorePath" : "Åšcieżka przechowywania avatarów", "Accounts_AvatarStoreType" : "Rodzaj magazynu avatarów", "Accounts_denyUnverifiedEmail" : "Odrzucaj niezweryfikowane adresy email", "Accounts_EmailVerification" : "Weryfikacja adresu email", + "Accounts_Enrollment_Email" : "Adres email do rekrutacji", + "Accounts_Enrollment_Email_Description" : "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.", "Accounts_ManuallyApproveNewUsers" : "RÄ™czne zatwierdzanie nowych użytkowników", "Accounts_OAuth_Custom_Authorize_Path" : "Authorize Path", "Accounts_OAuth_Custom_Button_Color" : "Kolor przycisku", @@ -49,16 +51,14 @@ "Accounts_OAuth_Twitter_secret" : "Twitter Secret", "Accounts_Registration_AuthenticationServices_Enabled" : "Rejestracja przy użyciu serwisów zewnÄ™trznych", "Accounts_RegistrationForm" : "Formularz rejestracyjny", - "Accounts_RegistrationForm_Public" : "Publiczny", "Accounts_RegistrationForm_Disabled" : "WyÅ‚Ä…czony", "Accounts_RegistrationForm_LinkReplacementText" : "Treść tekstu zamiennego w formularzu rejestracyjnym", + "Accounts_RegistrationForm_Public" : "Publiczny", "Accounts_RegistrationForm_Secret_URL" : "Sekretny adres URL", "Accounts_RegistrationForm_SecretURL" : "Sekretny adres URL formularza rejestracyjnego", - "Accounts_RegistrationRequired" : "Wymagana rejestracja", + "Accounts_RegistrationRequired" : "Musisz siÄ™ zarejestrować", "Accounts_RequireNameForSignUp" : "Wymagaj podana nazwy podczas rejestracji", - "Accounts_Enrollment_Email" : "Adres email do rekrutacji", - "Accounts_Enrollment_Email_Description" : "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.", - "Activate" : "Aktywować", + "Activate" : "Aktywuj", "Add_custom_oauth" : "Dodaj wÅ‚asne OAuth", "Add_Members" : "Dodaj czÅ‚onków", "Add_users" : "Dodaj użytkowników", @@ -68,22 +68,22 @@ "Allow_Invalid_SelfSigned_Certs_Description" : "Pozwól na nieprawidÅ‚owe i samodzielnie podpisane certyfikaty SSL podczas walidacji linków i podglÄ…dów", "and" : "i", "API" : "API", - "API_Analytics" : "Analityka", + "API_Analytics" : "Analytics", "API_Embed" : "Osadź", "API_EmbedDisabledFor" : "WyÅ‚Ä…dz osadzanie dla użytkowników", "API_EmbedDisabledFor_Description" : "Lista użytkowników oddzielonych przecinkami", "are_also_typing" : "również piszÄ…", "are_typing" : "piszÄ…", - "Are_you_sure" : "Potwierdź, czy na pewno?", + "Are_you_sure" : "JesteÅ› pewny?", "Auto_Load_Images" : "Automatycznie Å‚aduj zdjÄ™cia", - "Avatar_changed_successfully" : "Avatar zmieniony z powodzeniem", + "Avatar_changed_successfully" : "Twój avatar zostaÅ‚ zapisany", "Avatar_url_invalid_or_error" : "Podany adres URL jest nieprawidÅ‚owy. Popraw go i spróbuj ponownie.", - "away" : "poza", - "Away" : "Poza", - "away_female" : "poza", - "Away_female" : "Poza", - "away_male" : "poza", - "Away_male" : "Poza", + "away" : "zaraz wracam", + "Away" : "Zaraz wracam", + "away_female" : "zaraz wracam", + "Away_female" : "Zaraz wracam", + "away_male" : "zaraz wracam", + "Away_male" : "Zaraz wracam", "Back_to_login" : "Wróć do strony logowania", "bold" : "pogrubienie", "busy" : "zajÄ™ty", @@ -107,31 +107,31 @@ "Contact" : "Kontakt", "Conversation" : "Rozmowa", "Convert_Ascii_Emojis" : "Konwertuj ASCII do Emoji", - "Create_new" : "Utwórz nowe", - "Create_new_direct_message_room" : "Utwórz nowy kanaÅ‚ prywatny", + "Create_new" : "Utwórz", + "Create_new_direct_message_room" : "Nowa prywatna rozmowa", "Create_new_private_group" : "Utwórz prywatnÄ… grupÄ™", "Create_new_public_channel" : "Utwórz kanaÅ‚ publiczny", "Created_at" : "Utworzono", "Custom_oauth_helper" : "Przy konfiguracji dostawcy OAuth bÄ™dziesz musiaÅ‚ podać zwrotny adres URL (Callback). Użyj adresu <pre>%s</pre>.", "Custom_oauth_unique_name" : "Nazwa wÅ‚asnego serwisu OAuth", "days" : "dni", - "Deactivate" : "Dezaktywować", + "Deactivate" : "Deaktywuj", "Delete_Room_Warning" : "UsuniÄ™cie pokoju wiąże siÄ™ z usuniÄ™ciem wszystkich wiadomoÅ›ci wysÅ‚anych do niego. Tej operacji nie można cofnąć.", "Delete_User_Warning" : "UsuniÄ™cie użytkownika wiąże siÄ™ z usuniÄ™ciem wszystkich jego wiadomoÅ›ci. Tej czynnoÅ›ci nie można cofnąć.", "Deleted" : "UsuniÄ™te!", "Desktop_Notifications" : "Powiadomienia na pulpicie", "Desktop_Notifications_Disabled" : "Powiadomienia na pulpicie sÄ… wyÅ‚Ä…czone. ZmieÅ„ ustawienia swojej przeglÄ…darki jeżeli chcesz wÅ‚Ä…czyć powiadomienia.", "Desktop_Notifications_Enabled" : "Powiadomienia na pulpicie sÄ… wÅ‚Ä…czone", - "Direct_Messages" : "BezpoÅ›rednie wiadomoÅ›ci", + "Direct_Messages" : "Prywatne wiadomoÅ›ci", "Disable_Favorite_Rooms" : "WyÅ‚Ä…cz ulubione", "Disable_New_Message_Notification" : "WyÅ‚Ä…cz powiadomienia dla nowych wiadomoÅ›ci", "Disable_New_Room_Notification" : "WyÅ‚Ä…cz powiadomienia dla nowych kanałów", "Drop_to_upload_file" : "PrzeciÄ…gnij, aby przesÅ‚ać plik", - "Duplicate_channel_name" : "KanaÅ‚ o nazwie \"% s\" istnieje", - "Duplicate_private_group_name" : "Grupa Prywatna o nazwie '% s' istnieje", + "Duplicate_channel_name" : "KanaÅ‚ o nazwie \"%s\" już istnieje", + "Duplicate_private_group_name" : "Grupa Prywatna o nazwie '%s' istnieje", "E-mail" : "Email", "edited" : "zmieniono", - "Email_already_exists" : "Email już istnieje", + "Email_already_exists" : "Ten email jest zajÄ™ty", "Email_or_username" : "Email lub nazwa użytkownika", "Email_verified" : "E-mail zweryfikowany", "Emoji" : "Emoji", @@ -141,16 +141,16 @@ "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: ", - "False" : "FaÅ‚sz", + "False" : "Nie", "Favorites" : "Ulubione", "FileUpload" : "PrzesyÅ‚anie plików", "FileUpload_Enabled" : "PrzesyÅ‚anie plików wÅ‚Ä…czone", "FileUpload_MaxFileSize" : "Maksymalny rozmiar przesÅ‚anego pliku (w bajtach)", "FileUpload_MediaTypeWhiteList" : "Dozwolone typy plików", "FileUpload_MediaTypeWhiteListDescription" : "Typy plików, oddzielone przecinkami", - "Follow_social_profiles" : "Åšledź nasze profile spoÅ‚eczne, widelec do nas na github i podziel siÄ™ swoimi przemyÅ›leniami na temat rocket.chat aplikacji na naszej trello pokÅ‚adzie.", + "Follow_social_profiles" : "Åšledź nas w portalach spoÅ‚ecznoÅ›ciowych, forkuj projekt na githubie lub powiedz nam co myÅ›lisz o rocket.chat na naszym trello.", "Forgot_password" : "ZapomniaÅ‚eÅ› hasÅ‚a", - "Fork_it_on_github" : "Fork it on GitHub", + "Fork_it_on_github" : "Forkuj projekt na GitHubie", "From_Email" : "Adres nadawcy", "General" : "Ogólne", "Get_to_know_the_team" : "Poznaj Rocket.Team", @@ -162,7 +162,7 @@ "History" : "Historia", "hours" : "godzin", "Incorrect_Password" : "HasÅ‚o jest nieprawidÅ‚owe", - "inline_code" : "inline", + "inline_code" : "kod", "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:", @@ -171,7 +171,7 @@ "Invalid_email" : "E-mail jest nieprawidÅ‚owy", "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_room_name" : "<strong>%s</strong> nie jest poprawnÄ… nazwÄ… pokoju, <br / >użyj tylko liter, cyfr i myÅ›lników", "invisible" : "niewidoczny", "Invisible" : "Niewidoczny", "Invitation_HTML" : "Kod HTML zaproszenia", @@ -202,7 +202,7 @@ "LDAP_Bind_Search" : "Zapytanie Bind", "LDAP_Bind_Search_Description" : "KawaÅ‚ek kodu JSON który pozwala na powiÄ…zanie danych, w formie {\"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 to hierarchiczna baza danych wykorzystywana przez wiele firm w celu udostÄ™pniania pojedynczej usÅ‚ugi autoryzacji użytkowników pomiÄ™dzy wieloma serwisami. Aby uzyskać dodatkowe informacje i przykÅ‚ady konfiguracji, odwiedź nasze wiki: https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication.", - "LDAP_DN" : "LDAP DN", + "LDAP_DN" : "Nazwa wyróżniajÄ…ca (DN)", "LDAP_DN_Description" : "Search root; przykÅ‚ad: dc=domena,dc=com", "LDAP_Enable" : "WÅ‚Ä…cz LDAP", "LDAP_Enable_Description" : "WÅ‚Ä…cza LDAP podczas uwierzytelniania.", @@ -216,7 +216,7 @@ "LDAP_Url_Description" : "Adres serwera LDAP; na przykÅ‚ad: ldap://mojafirma.dns.com", "Leave_room" : "Opuść pokój", "line" : "linia", - "Load_more" : "WiÄ™cej", + "Load_more" : "ZaÅ‚aduj wiÄ™cej", "Loading..." : "Åadowanie ...", "Loading_more_from_history" : "Åadowanie wiÄ™cej z historii", "Loading_suggestion" : "Åadowanie sugestii...", @@ -231,8 +231,8 @@ "Members_List" : "Lista użytkowników", "Members_placeholder" : "CzÅ‚onkowie", "Message" : "Wiadomość", - "Message_AllowDeleting" : "Pozwól usunąć wiadomość", - "Message_AllowEditing" : "Pozwól edytować wiadomość", + "Message_AllowDeleting" : "Pozwól usuwać wiadomoÅ›ci", + "Message_AllowEditing" : "Pozwól edytować wiadomoÅ›ci", "Message_AllowEditing_BlockEditInMinutes" : "Blokuj edytowanie wiadomoÅ›ci po (n) minutach", "Message_AllowEditing_BlockEditInMinutesDescription" : "Wpisz 0, aby wyÅ‚Ä…czyć blokowanie.", "Message_AudioRecorderEnabled" : "WysyÅ‚anie nagraÅ„ audio wÅ‚Ä…czone", @@ -245,15 +245,15 @@ "Message_pinned" : "Wiadomość przypiÄ™ta", "Message_pinning_not_allowed" : "Przypinanie wiadomoÅ›ci jest niedozwolone", "Message_removed" : "Wiadomość usuniÄ™ta", - "Message_ShowDeletedStatus" : "Pokaż usuniÄ™ty status", - "Message_ShowEditedStatus" : "Pokaż zmieniony status", + "Message_ShowDeletedStatus" : "Pokaż informacjÄ™ o usuniÄ™ciu", + "Message_ShowEditedStatus" : "Pokaż informacjÄ™ o edycji", "Message_ShowFormattingTips" : "Pokaż porady formatowania wiadomoÅ›ci", "Messages" : "WiadomoÅ›ci", "Meta_fb_app_id" : "Facebook APP ID", "Meta_google-site-verification" : "Weryfikacja Google", "Meta_language" : "JÄ™zyk", "Meta_msvalidate01" : "MSValidate.01", - "Meta_robots" : "Robots", + "Meta_robots" : "Roboty", "minutes" : "minut", "More_channels" : "WiÄ™cej kanałów", "More_groups" : "WiÄ™cej grup prywatnych", @@ -270,7 +270,7 @@ "No_channel_with_name_%s_was_found" : "Nie odnaleziono kanaÅ‚u o nazwie <strong>\"%s\"</strong>!", "No_channels_yet" : "Nie jesteÅ› czÅ‚onkiem żadnego kanaÅ‚u.", "No_direct_messages_yet" : "Nie rozpoczÄ…Å‚eÅ› jeszcze żadnej rozmowy.", - "No_favorites_yet" : "Brak ulubionych.", + "No_favorites_yet" : "Nie masz żadnych ulubionych.", "No_group_with_name_%s_was_found" : "Nie odnaleziono grupy o nazwie <strong>\"%s\"</strong>!", "No_groups_yet" : "Nie masz prywatnych grup.", "No_livechats" : "Nie masz żadnych livechatów.", @@ -278,7 +278,7 @@ "No_user_with_username_%s_was_found" : "Nie odnaleziono użytkownika o nazwie <strong>\"%s\"</strong>!", "Not_allowed" : "Niedozwolone", "Not_authorized" : "Brak autoryzacji", - "Not_found_or_not_allowed" : "Nie znaleziono lub nie dozwolone", + "Not_found_or_not_allowed" : "Nie znaleziono lub niedozwolone", "Nothing_found" : "Nic nie znaleziono", "Notify_all_in_this_room" : "Powiadom wszystkich w pokoju", "Old_and_new_password_required" : "Aby zmienić hasÅ‚o musisz podać zarówno stare jak i nowe hasÅ‚o.", @@ -297,15 +297,15 @@ "Please_wait" : "ProszÄ™ czekaj", "Please_wait_activation" : "To może chwilÄ™ potrwać, proszÄ™ czekaj.", "Please_wait_statistics" : "GenerujÄ™ statystyki, proszÄ™ czekaj.", - "Powered_by" : "Wspierane przez", + "Powered_by" : "TechnologiÄ™ dostarcza ", "Preferences" : "Preferencje", "Preferences_saved" : "Preferencje zapisane", "Privacy" : "Prywatność", "Private_Groups" : "Prywatne grupy", "Private_Groups_list" : "Lista prywatnych grup", "Profile" : "Profil", - "Profile_saved_successfully" : "Profil zostaÅ‚ zapisany", - "Proudly_developed" : "Dumnie opracowane z Meteor", + "Profile_saved_successfully" : "Dane zostaÅ‚y zapisane", + "Proudly_developed" : "Stworzone na platformie Meteor", "Push" : "Powiadomienia", "Push_apn_cert" : "Certyfikat APN", "Push_apn_dev_cert" : "Certyfikat Dev APN", @@ -313,7 +313,7 @@ "Push_apn_dev_passphrase" : "APN Dev Passphrase", "Push_apn_key" : "Klucz APN", "Push_apn_passphrase" : "APN Passphrase", - "Push_debug" : "Debug", + "Push_debug" : "Debugowanie", "Push_enable" : "WÅ‚Ä…cz", "Push_gcm_api_key" : "Klucz API GCM", "Push_gcm_project_number" : "Identyfikator projektu GCM", @@ -348,7 +348,7 @@ "Save_Mobile_Bandwidth" : "OszczÄ™dzaj przepustowość", "Search" : "Szukaj", "Search_Messages" : "Przeszukaj wiadomoÅ›ci", - "Search_settings" : "Wyszukaj w ustawieniach", + "Search_settings" : "Przeszukaj ustawienia", "seconds" : "sekund", "See_all" : "Zobacz wszystko", "See_only_online" : "WyÅ‚Ä…cznie w trybie online", @@ -365,22 +365,22 @@ "Send_invitation_email_warning" : "Aby wysÅ‚ać zaproszenie, skonfiguruj najpierw ustawienia serwera SMTP.", "Send_Message" : "WyÅ›lij wiadomość", "Settings" : "Ustawienia", - "Settings_updated" : "Ustawienia zaktualizowane", + "Settings_updated" : "Ustawienia zapisane", "Showing_online_users" : "Widocznych <b>__total_online__</b> z __total__users", - "Showing_results" : "<p>WyÅ›wietlono <b>% s</b>wyników</p>", + "Showing_results" : "<p>WyÅ›wietlono <b>%s</b> wyników</p>", "Silence" : "Cisza", "since_creation" : "od %s", "Site_Name" : "Nazwa strony", "Site_Url" : "Adres strony", "Site_Url_Description" : "PrzykÅ‚ad: https://chat.domain.com/", "SMTP" : "SMTP", - "SMTP_Host" : "SMTP Host", + "SMTP_Host" : "Nazwa hosta SMTP", "SMTP_Password" : "HasÅ‚o SMTP", "SMTP_Port" : "Port SMTP", "SMTP_Username" : "Nazwa użytkownika SMTP", "Sound" : "DźwiÄ™k", "Start_of_conversation" : "Rozpocznij rozmowÄ™", - "Statistics" : "Statystyka", + "Statistics" : "Statystyki", "Stats_Active_Users" : "Aktywni użytkownicy", "Stats_Avg_Channel_Users" : "Åšrednio użytkowników w kanaÅ‚ach", "Stats_Avg_Private_Group_Users" : "Åšrednio użytkowników w grupach", @@ -408,15 +408,15 @@ "strike" : "przekreÅ›lenie", "Submit" : "PrzeÅ›lij", "The_field_is_required" : "Pole %s jest wymagane.", - "True" : "Prawda", + "True" : "Tak", "Unnamed" : "Anonimowy", "Unread_Rooms" : "Nieprzeczytane pokoje", "Unread_Rooms_Mode" : "Tryb nieprzeczytanych pokoi", "Upload_file_question" : "PrzesÅ‚ać plik?", "Use_Emojis" : "Użyj Emoji", "Use_initials_avatar" : "Użyj inicjałów", - "use_menu" : "Skorzystaj z menu bocznego celem dostÄ™pu do pokoi i czatów", - "Use_service_avatar" : "Użyj %s avatar", + "use_menu" : "Otwórz menu boczne by uzyskać dostÄ™p do twoich pokoi i rozmów", + "Use_service_avatar" : "Użyj avatar z %s", "Use_this_username" : "Użyj tej nazwy użytkownika", "Use_uploaded_avatar" : "Użyj dodany awatar", "Use_url_for_avatar" : "Użyj adresu URL", @@ -433,34 +433,34 @@ "User_joined_channel_female" : "DoÅ‚Ä…czyÅ‚a do kanaÅ‚u", "User_joined_channel_male" : "DoÅ‚Ä…czyÅ‚ do kanaÅ‚u", "User_left" : "Użytkownik <em>__user_left__</em> wyszedÅ‚.", - "User_left_female" : "Użytkownik <em>__user_left__</em> wyszÅ‚a.", + "User_left_female" : "Użytkowniczka <em>__user_left__</em> wyszÅ‚a.", "User_left_male" : "Użytkownik <em>__user_left__</em> wyszedÅ‚.", "User_logged_out" : "Użytkownik jest wylogowany", "User_not_found_or_incorrect_password" : "Nie znaleziono użytkownika lub nieprawidÅ‚owe hasÅ‚o", - "User_removed_by" : "Użytkownik <em>__user_removed__</em>usuniÄ™ty przez <em>__user_by__</em>.", + "User_removed_by" : "Użytkownik <em>__user_removed__</em> zostaÅ‚ usuniÄ™ty przez <em>__user_by__</em>.", "User_Settings" : "Ustawienia użytkownika", "User_updated_successfully" : "Zaktualizowano dane użytkownika", "Username" : "Nazwa użytkownika", "Username_cant_be_empty" : "Nazwa użytkownika nie może być pusta", "Username_Change_Disabled" : "Administrator czatu nie zezwoliÅ‚ na zmianÄ™ nazw użytkownika", - "Username_description" : "Nazwa użytkownika jest używana, by inni mogli CiÄ™ wspomnieć w wiadomoÅ›ci.", - "Username_invalid" : "<strong>% s</strong>nie jest prawidÅ‚owÄ… nazwÄ… użytkownika, <br / >użyj jedynie liter, cyfr, kropek i kresek", - "Username_title" : "Zarejestruj użytkownika", - "Username_unavaliable" : "<strong>% s</strong> jest zajÄ™te :(", + "Username_description" : "Nazwa użytkownika jest używana, by inni mogli CiÄ™ wspomnieć w swoich wiadomoÅ›ciach.", + "Username_invalid" : "<strong>%s</strong> nie jest prawidÅ‚owÄ… nazwÄ… użytkownika, <br / >użyj jedynie liter, cyfr, kropek i kresek", + "Username_title" : "Utwórz nazwÄ™ użytkownika", + "Username_unavaliable" : "Nazwa <strong>%s</strong> jest zajÄ™ta :(", "Users" : "Użytkownicy", - "View_All" : "Zobacz wszystkie", + "View_All" : "Pokaż wszystko", "Wait_activation_warning" : "Zanim siÄ™ zalogujesz, twoje konto musi być aktywowane przez administratora.", - "We_have_sent_password_email" : "WysÅ‚aliÅ›my Ci e-mail z instrukcjami resetowania hasÅ‚a. JeÅ›li nie dostaniesz wiadomoÅ›ci, spróbuj proszÄ™ ponownie.", - "We_have_sent_registration_email" : "WysÅ‚aliÅ›my e-mail w celu potwierdzenie Twojej rejestracji. JeÅ›li nie dostaniesz wiadomoÅ›ci, spróbuj proszÄ™ ponownie.", - "Welcome" : "Witamy <em>% s</em>.", + "We_have_sent_password_email" : "WysÅ‚aliÅ›my Ci e-mail z instrukcjami resetowania hasÅ‚a. JeÅ›li nie dostaniesz wiadomoÅ›ci, prosimy spróbować ponownie.", + "We_have_sent_registration_email" : "WysÅ‚aliÅ›my e-mail w celu potwierdzenie Twojej rejestracji. JeÅ›li nie dostaniesz wiadomoÅ›ci, prosimy spróbować ponownie.", + "Welcome" : "Witamy <em>%s</em>.", "Welcome_to_the" : "Witaj w", "With_whom" : "Z kim", "Yes" : "Tak", "Yes_clear_all" : "Tak, wyczyść!", "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" : "Musisz potwierdzić swój adres e-mail, aby zalogować siÄ™!", - "You_will_not_be_able_to_recover" : "Nie bÄ™dziesz w stanie odzyskać!", + "You_need_confirm_email" : "Aby siÄ™ zalogować musisz potwierdzić swój adres e-mail!", + "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" } \ No newline at end of file diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 1af6d7f2715..eedf1d79fa6 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -1,12 +1,15 @@ { + "Access_not_authorized" : "Acesso não autorizado", "Access_online_demo" : "Acesse o demo online", "Access_Online_Demo" : "Acesse o Demo Online", - "Access_not_authorized" : "Acesso não autorizado", "Accounts" : "Contas", - "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos (separados por vÃrgula)", - "Accounts_AllowUsernameChange" : "Permitir alterar usuário", + "Accounts_AllowedDomainsList" : "Lista de domÃnios permitidos", + "Accounts_AllowPasswordChange" : "Permitir Alteração de Senha", + "Accounts_AllowUsernameChange" : "Permitir alterar nome de usuário", "Accounts_AvatarResize" : "Redimensionar Avatares", "Accounts_AvatarSize" : "Tamanho do Avatar", + "Accounts_AvatarStorePath" : "Caminho para armazenar Avatares", + "Accounts_AvatarStoreType" : "Tipo de armazenamento de Avatares", "Accounts_denyUnverifiedEmail" : "Proibir e-mail não verificado", "Accounts_EmailVerification" : "Verificação de E-mail", "Accounts_ManuallyApproveNewUsers" : "Aprovar manualmente novos usuários", @@ -26,6 +29,7 @@ "Accounts_OAuth_Github" : "Login do GitHub", "Accounts_OAuth_Github_id" : "GitHub Id", "Accounts_OAuth_Github_secret" : "GitHub Secret", + "Accounts_OAuth_Gitlab" : "OAuth Ativado", "Accounts_OAuth_Gitlab_id" : "Gitlab Id", "Accounts_OAuth_Google" : "Login do Google", "Accounts_OAuth_Google_id" : "Google Id", @@ -39,6 +43,10 @@ "Accounts_OAuth_Twitter" : "Login do Twitter", "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", + "Accounts_PasswordReset" : "Resetar senha", + "Accounts_RegistrationForm_Disabled" : "Desativado", + "Accounts_RegistrationForm_Public" : "Público", + "Accounts_RegistrationForm_Secret_URL" : "URL Secreta", "Accounts_RegistrationRequired" : "Registro Obrigatório", "Accounts_RequireNameForSignUp" : "Nome é obrigatório para cadastro", "Activate" : "Ativar", @@ -59,6 +67,7 @@ "Are_you_sure" : "Você tem certeza?", "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.", "away" : "ausente", "Away" : "Ausente", "away_female" : "ausente", @@ -74,10 +83,12 @@ "busy_male" : "ocupado", "Busy_male" : "Ocupado", "Cancel" : "Cancelar", + "Certificates_and_Keys" : "Certificados e Chaves", "Change_avatar" : "Alterar avatar", "Channels" : "Canais", "Channels_list" : "Lista de canais públicos", "Chat_Rooms" : "Salas de Chat", + "Clear_all_unreads_question" : "Limpar todas não lidas?", "close" : "fechar", "coming_soon" : "em breve", "Commands" : "Comandos", @@ -95,6 +106,7 @@ "Custom_oauth_unique_name" : "Nome exclusivo para oauth customizado", "days" : "dias", "Deactivate" : "Desativar", + "Delete_Room_Warning" : "A exclusão de uma sala irá apagar todas as mensagens postadas na sala. Isso não pode ser desfeito.", "Delete_User_Warning" : "Excluir um usuário irá apagar todas as mensagens desse usuário também. Isso não poderá ser desfeito.", "Deleted" : "Deletado!", "Desktop_Notifications" : "Notificações Desktop", @@ -116,6 +128,7 @@ "Enable_Desktop_Notifications" : "Habilitar Notificações Desktop", "Enter_info" : "Entre com seus dados de login", "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", "Esc_to" : "Esc para", @@ -124,7 +137,8 @@ "FileUpload" : "Upload de Arquivos", "FileUpload_Enabled" : "Habilitar upload de arquivos", "FileUpload_MaxFileSize" : "Tamanho máximo dos arquivos (em bytes)", - "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia (separados por vÃrgula)", + "FileUpload_MediaTypeWhiteList" : "Lista de tipos de mÃdia", + "FileUpload_MediaTypeWhiteListDescription" : "Lista de tipos de mÃdia separada por vÃrgula", "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", @@ -140,11 +154,17 @@ "hours" : "horas", "Incorrect_Password" : "Senha incorreta", "inline_code" : "código", + "Install_FxOs" : "Instale o Rocket.Chat em seu Firefox", "Invalid_confirm_pass" : "A confirmação de senha não é igual à senha", "Invalid_email" : "O e-mail informado é inválido", + "Invalid_file_height" : "Altura de arquivo inválida", + "Invalid_file_type" : "Tipo de arquivo inválido", + "Invalid_file_width" : "Altura de arquivo inválida", "Invalid_name" : "O nome não pode ser vazio", "Invalid_pass" : "A senha não pode ser vazia", "Invalid_room_name" : "<strong>%s</strong> não é um nome válido,<br/> utilizar apenas letras, números e hÃfens", + "Invalid_Secret_URL" : "URL Secreta inválida", + "Invalid_secret_URL_message" : "A URL fornecida é inválida.", "invisible" : "invisÃvel", "Invisible" : "InvisÃvel", "Invitation_HTML" : "HTML do Convite", @@ -174,6 +194,7 @@ "Layout_Terms_of_Service" : "Termos de Serviço", "LDAP" : "LDAP", "LDAP_DN" : "DN LDAP", + "LDAP_Enable" : "Ativar LDAP", "LDAP_Port" : "Porta LDAP", "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", "LDAP_Sync_User_Data_FieldMap" : "Mapeamento de campos do usuário", @@ -237,6 +258,7 @@ "No_groups_yet" : "Nenhum grupo privado ainda.", "No_livechats" : "Nenhum atendimento.", "No_permission_to_view_room" : "Sem permissões para ver a sala", + "no_tokens_for_this_user" : "Não existem tokens para este usuário", "No_user_with_username_%s_was_found" : "Nenhum usuário com nome de usuário <strong>\"%s\"</strong> foi encontrado!", "Not_allowed" : "Não permitido", "Not_authorized" : "Não autorizado", @@ -252,8 +274,10 @@ "Opt_out_statistics_warning" : "Enviando suas estatÃsticas anonimamente você nos ajudará a identificar quantas instâncias do Rocket.Chat são implantadas, bem como o quão bom o sistema está se comportando, para que nós possamos melhorar ainda mais. Se você quiser continuar nos enviando suas estatÃsticas anonimamente, desmarque a caixa de seleção acima. Obrigado", "others" : "outros", "Password" : "Senha", + "Password_Change_Disabled" : "O administrador do Rocket.Chat desativou a mudança de senhas", "Password_changed_successfully" : "Senha alterada com sucesso", "People" : "Pessoas", + "Please_enter_value_for_url" : "Por favor insira um valor para a URL do seu avatar.", "Please_wait" : "Aguarde", "Please_wait_activation" : "Por favor aguarde, isso pode levar algum tempo.", "Please_wait_statistics" : "Por favor aguarde, as estatÃsticas estão sendo geradas.", @@ -274,8 +298,12 @@ "Push_apn_key" : "APN Key", "Push_apn_passphrase" : "APN Passphrase", "Push_debug" : "Debug", + "push_disabled" : "Push desativado", "Push_enable" : "Habilitar", + "Push_enable_gateway" : "Ativar Gateway", + "Push_gateway" : "Gateway", "Push_production" : "Produção", + "Push_test_push" : "Teste", "Quick_Search" : "Pesquisa Rápida", "quote" : "citação", "Recents" : "Recentes", @@ -287,6 +315,8 @@ "Remove_Admin" : "Remover Administrador", "Remove_custom_oauth" : "Remover oauth customizado", "Reset_password" : "Resetar senha", + "Restart" : "Reiniciar", + "Restart_the_server" : "Reiniciar o servidor", "Room" : "Sala", "Room_name_changed" : "Nome da sala alterado para: <em>__room_name__</em> por <em>__user_by__</em>", "Room_name_changed_successfully" : "Nome da sala alterado com sucesso", @@ -297,6 +327,9 @@ "Rooms" : "Salas", "S_new_messages_since_s" : "%s novas mensagens desde %s", "SAML" : "SAML", + "SAML_Custom_Cert" : "Certificado personalizado", + "SAML_Custom_Entry_point" : "Entry Point personalizado", + "SAML_Custom_Generate_Username" : "Gerar nome de usuário", "Save_changes" : "Salvar alterações", "Save_Mobile_Bandwidth" : "Economizar Banda Móvel", "Search" : "Pesquisar", @@ -310,6 +343,7 @@ "Select_service_to_login" : "Selecione um serviço para iniciar sessão e carregar sua imagem ou faça upload de um arquivo de seu computador", "Selected_users" : "Membros selecionados", "Send" : "Enviar", + "Send_a_test_push_to_my_user" : "Enviar um Push de teste para o meu usuário", "Send_confirmation_email" : "Enviar email de confirmação", "Send_invitation_email" : "Enviar convite por e-mail", "Send_invitation_email_error" : "Você não forneceu qualquer e-mail válido.", @@ -360,18 +394,24 @@ "Stop_Recording" : "Parar Gravação", "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", "True" : "Sim", "Unnamed" : "Sem nome", "Unread_Rooms" : "Não Lidas", "Unread_Rooms_Mode" : "Agrupar Salas Não Lidas", "Upload_file_question" : "Enviar arquivo?", + "Uploading_file" : "Subindo arquivo...", "Use_Emojis" : "Usar Emojis", "Use_initials_avatar" : "Usar as iniciais do seu nome de usuário", "use_menu" : "Utilize o menu à esquerda para acessar suas salas", "Use_service_avatar" : "Use o avatar de %s", "Use_this_username" : "Usar este nome de usuário", "Use_uploaded_avatar" : "Use o avatar de upload", + "Use_url_for_avatar" : "Use url para o avatar", "User_added_by" : "Usuário <em>__user_added__</em> adicionado à conversa por <em>__user_by__</em>.", "User_Channels" : "Canais do Usuário", "User_has_been_activated" : "Usuário foi ativado", @@ -394,6 +434,7 @@ "User_updated_successfully" : "Usuário atualizado com sucesso", "Username" : "Nome de usuário", "Username_cant_be_empty" : "O nome de usuário não pode ser vazio", + "Username_Change_Disabled" : "O administrador do Rocket.Chat desabilitou a mudança de nome de usuário", "Username_description" : "O nome de usuário serve para que outras pessoas possam mencionar você em mensagens", "Username_invalid" : "<strong>%s</strong> não é um nome de usuário válido, <br/> usar somente letras, números, pontos e traços", "Username_title" : "Cadastre um nome de usuário", @@ -407,10 +448,12 @@ "Welcome_to_the" : "Bem-vindo ao", "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_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.", - "Your_Open_Source_solution" : "Sua própria solução Open Source" + "Your_Open_Source_solution" : "Sua própria solução Open Source", + "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ar.i18n.json b/packages/rocketchat-authorization/i18n/ar.i18n.json index 0a06728ddc3..6983bb7d0fe 100644 --- a/packages/rocketchat-authorization/i18n/ar.i18n.json +++ b/packages/rocketchat-authorization/i18n/ar.i18n.json @@ -1,4 +1,6 @@ { + "Add_user" : "إضاÙØ© مستخدم", "Save" : "ØÙظ", - "User_added" : "وأضا٠العضو <em>__user_added__</em>." + "User_added" : "وأضا٠العضو <em>__user_added__</em>.", + "User_removed" : "ازيل المستخدم" } \ 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 de2989add91..46367ea0176 100644 --- a/packages/rocketchat-authorization/i18n/en.i18n.json +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -3,7 +3,6 @@ "Back_to_permissions" : "Back to permissions", "Cannot_delete_a_protected_role" : "Cannot delete a protected role", "Cannot_delete_role_because_its_in_use" : "Cannot delete role because it's in use", - "Description" : "Description", "New_role" : "New role", "Permissions" : "Permissions", "Removed" : "Removed", @@ -11,7 +10,6 @@ "Role_Editing" : "Role Editing", "Role_removed" : "Role removed", "Save" : "Save", - "Saved" : "Saved", "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/fi.i18n.json b/packages/rocketchat-authorization/i18n/fi.i18n.json index dbd25410a43..041ed788cf1 100644 --- a/packages/rocketchat-authorization/i18n/fi.i18n.json +++ b/packages/rocketchat-authorization/i18n/fi.i18n.json @@ -1,4 +1,19 @@ { + "Add_user" : "Lisää käyttäjä", + "Back_to_permissions" : "Takaisin käyttöoikeuksiin", + "Cannot_delete_a_protected_role" : "Et voi poistaa suojattua roolia", + "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", - "User_added" : "Käyttäjä <em>__user_added__</em> lisätty." + "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.", + "User_not_found" : "Käyttäjää ei löydy", + "User_removed" : "Käyttäjä on poistettu", + "Users_in_role" : "Roolin käyttäjiä" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ku.i18n.json b/packages/rocketchat-authorization/i18n/ku.i18n.json new file mode 100644 index 00000000000..1e7dd6a0876 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ku.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "پاشەکەوت", + "User_added" : "بەکارهێنەر زیادکرا" +} \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/lo.i18n.json b/packages/rocketchat-authorization/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/nl.i18n.json b/packages/rocketchat-authorization/i18n/nl.i18n.json new file mode 100644 index 00000000000..039425c06c5 --- /dev/null +++ b/packages/rocketchat-authorization/i18n/nl.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Bewaren", + "User_added" : "Gebruiker toegevoegd" +} \ 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 dca06e8c94c..8664e27746f 100644 --- a/packages/rocketchat-authorization/i18n/pt.i18n.json +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -3,7 +3,6 @@ "Back_to_permissions" : "Voltar para permissões", "Cannot_delete_a_protected_role" : "Não é possÃvel remover um papel protegido", "Cannot_delete_role_because_its_in_use" : "Não é possÃvel remover o papel pois ele está em uso", - "Description" : "Descrição", "New_role" : "Novo papel", "Permissions" : "Permissões", "Removed" : "Removido", @@ -11,7 +10,6 @@ "Role_Editing" : "Edição de Papel", "Role_removed" : "Papel Removido", "Save" : "Salvar", - "Saved" : "Salvo", "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-channel-settings/i18n/fi.i18n.json b/packages/rocketchat-channel-settings/i18n/fi.i18n.json index 6f31cf5a2e6..ba9ae6c0008 100644 --- a/packages/rocketchat-channel-settings/i18n/fi.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/fi.i18n.json @@ -1 +1,8 @@ -{ } \ No newline at end of file +{ + "Channel" : "Kanava", + "Private_Group" : "Privaattiryhmä", + "Room_Type" : "Huoneen tyyppi", + "Room_Settings" : "Huoneen asetukset", + "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" +} \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings/i18n/lo.i18n.json b/packages/rocketchat-channel-settings/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..f9d1b2c38cc 100644 --- a/packages/rocketchat-channel-settings/i18n/pt.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/pt.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Channel" : "Canal", + "Private_Group" : "Grupo Privado", + "Room_Type" : "Tipo de sala", + "Room_Settings" : "Configurações da Sala" +} \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/ku.i18n.json b/packages/rocketchat-chatops/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/lo.i18n.json b/packages/rocketchat-chatops/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-chatops/i18n/nl.i18n.json b/packages/rocketchat-chatops/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/fi.i18n.json b/packages/rocketchat-github-enterprise/i18n/fi.i18n.json index 107ca5894b8..dd02132add1 100644 --- a/packages/rocketchat-github-enterprise/i18n/fi.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/fi.i18n.json @@ -3,5 +3,5 @@ "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" : "Huom: Älä syötä viimeistä kenoviivaa" + "Github_Enterprise_Url_No_Trail" : "Esim: http://example.com (ei kauttaviivaa loppuun)" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ku.i18n.json b/packages/rocketchat-github-enterprise/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/lo.i18n.json b/packages/rocketchat-github-enterprise/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-github-enterprise/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/ku.i18n.json b/packages/rocketchat-gitlab/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/lo.i18n.json b/packages/rocketchat-gitlab/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-gitlab/i18n/nl.i18n.json b/packages/rocketchat-gitlab/i18n/nl.i18n.json new file mode 100644 index 00000000000..aa29615cd10 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/nl.i18n.json @@ -0,0 +1,3 @@ +{ + "API_Gitlab_URL" : "GitLab URL" +} \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/ku.i18n.json b/packages/rocketchat-hubot/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/lo.i18n.json b/packages/rocketchat-hubot/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-hubot/i18n/nl.i18n.json b/packages/rocketchat-hubot/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/ku.i18n.json b/packages/rocketchat-ldap/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/lo.i18n.json b/packages/rocketchat-ldap/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/nl.i18n.json b/packages/rocketchat-ldap/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/ku.i18n.json b/packages/rocketchat-lib/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/lo.i18n.json b/packages/rocketchat-lib/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/nl.i18n.json b/packages/rocketchat-lib/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-lib/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ar.i18n.json b/packages/rocketchat-livechat/app/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } \ 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 a14d83d215e..437cfd80f94 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -1,20 +1,15 @@ { - "Additional_Feedback": "Additional Feedback", - "Skip": "Skip", - "E-mail": "E-mail", - "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", - "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", - "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." -} + "Additional_Feedback" : "Additional Feedback", + "Skip" : "Skip", + "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?", + "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", + "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", + "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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..f279ec41b30 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/fi.i18n.json @@ -0,0 +1,14 @@ +{ + "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?", + "Please_answer_survey" : "Käytä hetki vastataksesi pikakyselyyn tästä chatista", + "Please_fill_name_and_email" : "Täytä nimi ja sähköpostiosoite", + "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" +} \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } \ 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 fe6208b2989..a6db675dc4f 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -14,7 +14,6 @@ "Enable" : "Enable", "Enabled" : "Enabled", "Enter_a_username" : "Enter a username", - "Integrations" : "Integrations", "Live_sessions" : "Live sessions", "Livechat_agents" : "Livechat agents", "Livechat_enabled" : "Livechat enabled", @@ -24,7 +23,6 @@ "Livechat_title_color" : "Livechat Title Background Color", "Manager_added" : "Manager added", "Manager_removed" : "Manager removed", - "Name" : "Name", "New_Department" : "New Department", "Num_Agents" : "# Agents", "Please_fill_a_name" : "Please fill a name", @@ -35,4 +33,4 @@ "There_are_no_agents_added_to_this_department_yet" : "There are no agents added to this department yet.", "User_management" : "User Management", "Username_not_found" : "Username not found" -} +} \ 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 7a2d15b05eb..c3913e2b43c 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -1,4 +1,35 @@ { + "Add" : "Lisää", + "Add_agent" : "Lisää agentti", + "Add_manager" : "Lisää manageri", + "Agent_added" : "Agentti lisätty", + "Agent_removed" : "Agentti poistettu", + "Back" : "Takaisin", + "Dashboard" : "Kojelauta", + "Department_not_found" : "Osasto ei löytynyt", + "Department_removed" : "Osasto poistettu", + "Departments" : "Osastot", + "Description" : "Kuvaus", + "Edit_Department" : "Muokkaa osastoa", + "Enable" : "Ota käyttöön", + "Enabled" : "Käytössä", + "Enter_a_username" : "Syötä käyttäjätunnus", + "Live_sessions" : "Live-istunnot", + "Livechat_agents" : "Livechat agentit", + "Livechat_Manager" : "Livechat manageri", + "Livechat_managers" : "Livechat managerit", "Livechat_title" : "Livechat otsikko", - "Livechat_title_color" : "Livechat otsikon taustaväri" + "Livechat_title_color" : "Livechat otsikon taustaväri", + "Manager_added" : "Manageri lisätty", + "Manager_removed" : "Manageri poistettu", + "New_Department" : "Uusi osasto", + "Num_Agents" : "# Agenttia", + "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", + "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" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ku.i18n.json b/packages/rocketchat-livechat/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/lo.i18n.json b/packages/rocketchat-livechat/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/nl.i18n.json b/packages/rocketchat-livechat/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/pt.i18n.json b/packages/rocketchat-livechat/i18n/pt.i18n.json index 18ea87b4f36..629deb060be 100644 --- a/packages/rocketchat-livechat/i18n/pt.i18n.json +++ b/packages/rocketchat-livechat/i18n/pt.i18n.json @@ -4,6 +4,7 @@ "Add_manager" : "Adicionar gerente", "Agent_added" : "Agente adicionado", "Agent_removed" : "Agente removido", + "Description" : "Descrição", "Enter_a_username" : "Nome de usuário", "Livechat_agents" : "Agentes do Livechat", "Livechat_Manager" : "Administração Livechat", @@ -13,5 +14,6 @@ "Manager_added" : "Gerente adicionado", "Manager_removed" : "Gerente removido", "Please_fill_a_username" : "Por favor preencha um nome de usuário", + "Saved" : "Salvo", "Username_not_found" : "Nome de usuário não encontrado" } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index 30fccf32896..dd87fef341f 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -16,4 +16,4 @@ "You_have_successfully_unsubscribed" : "You have successfully unsubscribed from our Mailling List.", "You_informed_an_invalid_FROM_address" : "You informed an invalid FROM address.", "You_must_provide_the_unsubscribe_link" : "You must provide the [unsubscribe] link." -} +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/fi.i18n.json b/packages/rocketchat-mailer/i18n/fi.i18n.json index 6f31cf5a2e6..e3764478166 100644 --- a/packages/rocketchat-mailer/i18n/fi.i18n.json +++ b/packages/rocketchat-mailer/i18n/fi.i18n.json @@ -1 +1,19 @@ -{ } \ No newline at end of file +{ + "From_email_warning" : "<b>Varoitus</b>: Kenttä <b>Lähettäjä</b> tulee olla sähköpostipalvelimesi hyväksymä.", + "From_email_is_required" : "Lähettäjän sähköposti vaaditaan", + "Dry_run" : "Kuivaharjoitus", + "Dry_run_description" : "Lähettää vain yhden sähköpostin, lähettäjän osoitteeseen. Osoite tulee kuulua olemassaolevalle käyttäjälle.", + "Email_from" : "Lähettäjä", + "Email_subject" : "Aihe", + "Email_body" : "Viestin runko", + "Mailer" : "Postittaja", + "Mailer_body_tags" : "Sinun <b>tulee</b> käyttää [unsubscribe] postituslistalta poistumislinkkinä.<br />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.", + "Query" : "Kysely", + "Query_description" : "Lisämäärittelyt, joiden perusteella määritellään kenelle lähetetään sähköposteja. Postituslistalta poistuneita ei koskaan sisällytetä vastaanottajiin. Kyselymäärityksen tulee olla validia JSONia. Esimerkiksi: \"{\"createdAt\":{\"$gt\":{\"$date\": \"2015-01-01T00:00:00.000Z\"}}}\"", + "Send_email" : "Lähetä sähköposti", + "The_emails_are_being_sent" : "Sähköposteja lähetetään.", + "You_are_not_authorized_to_view_this_page" : "Sinulla ei ole oikeuksia tarkastella tätä sivua.", + "You_have_successfully_unsubscribed" : "Sinut on poistettu onnistuneesti postituslistaltamme.", + "You_informed_an_invalid_FROM_address" : "Virheellinen lähettäjän osoite.", + "You_must_provide_the_unsubscribe_link" : "Sinun on annettava [unsubscribe] -linkki." +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ku.i18n.json b/packages/rocketchat-mailer/i18n/ku.i18n.json new file mode 100644 index 00000000000..81d30755e75 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/ku.i18n.json @@ -0,0 +1,6 @@ +{ + "Dry_run" : "بۆ خۆشی", + "Dry_run_description" : "تەنها یەک ئیمەیڵ ئەنێرم، بۆ هەمان ئیمەیڵی ناو Ùۆرمەکە. ئیمەیڵەکە ئەبێ دروست بێت.", + "Mailer" : "نامەبەر", + "Query" : "داواکاری" +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/lo.i18n.json b/packages/rocketchat-mailer/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/nl.i18n.json b/packages/rocketchat-mailer/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 15ded0753a1..292bea7592f 100644 --- a/packages/rocketchat-mailer/i18n/pl.i18n.json +++ b/packages/rocketchat-mailer/i18n/pl.i18n.json @@ -12,4 +12,4 @@ "You_have_successfully_unsubscribed" : "Twój email zostaÅ‚ usuniÄ™ty z naszej listy powiadomieÅ„.", "You_informed_an_invalid_FROM_address" : "Adres nadawcy jest nieprawidÅ‚owy", "You_must_provide_the_unsubscribe_link" : "Musisz wstawić w treÅ›ci znacznik [unsubscribe]." -} +} \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/pt.i18n.json b/packages/rocketchat-mailer/i18n/pt.i18n.json index 3e24aeb3497..dcfa0ecd133 100644 --- a/packages/rocketchat-mailer/i18n/pt.i18n.json +++ b/packages/rocketchat-mailer/i18n/pt.i18n.json @@ -6,4 +6,4 @@ "Send_email" : "Enviar E-mail", "You_are_not_authorized_to_view_this_page" : "Você não possui permissão para visualizar esta página.", "You_have_successfully_unsubscribed" : "A partir de agora você não está mais cadastrado em nossa lista de e-mails." -} +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/fi.i18n.json b/packages/rocketchat-message-pin/i18n/fi.i18n.json index 80cefc15549..8d87c6d9e40 100644 --- a/packages/rocketchat-message-pin/i18n/fi.i18n.json +++ b/packages/rocketchat-message-pin/i18n/fi.i18n.json @@ -1,3 +1,10 @@ { - "Message_AllowPinning" : "Salli viestien kiinnittäminen" + "Message_AllowPinning" : "Salli viestien kiinnittäminen", + "Message_AllowPinning_Description" : "Salli viestien kiinnitys kaikilla kanavilla.", + "Message_AllowPinningByAnyone" : "Salli kaikkien kiinnittää viestejä.", + "Message_AllowPinningByAnyone_Description" : "Salli kaikkien - myös normaalien käyttäjien - kiinnittää viestejä.", + "Pin_Message" : "Kiinnitä viesti", + "Unpin_Message" : "Poista kiinnitys", + "Pinned_Messages" : "Kiinnitetyt viestit", + "No_pinned_messages" : "Ei kiinnitettyjä viestejä" } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ku.i18n.json b/packages/rocketchat-message-pin/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/lo.i18n.json b/packages/rocketchat-message-pin/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/nl.i18n.json b/packages/rocketchat-message-pin/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-pin/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/ku.i18n.json b/packages/rocketchat-message-star/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/lo.i18n.json b/packages/rocketchat-message-star/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/nl.i18n.json b/packages/rocketchat-message-star/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-message-star/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/ku.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-invite/i18n/lo.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/ku.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-slashcommands-join/i18n/lo.i18n.json b/packages/rocketchat-slashcommands-join/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ 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 new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-join/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ar.i18n.json b/packages/rocketchat-theme/i18n/ar.i18n.json index 6f31cf5a2e6..7275473661d 100644 --- a/packages/rocketchat-theme/i18n/ar.i18n.json +++ b/packages/rocketchat-theme/i18n/ar.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "theme-color-status-away" : "لون Øالة بعيد" +} \ 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 6f31cf5a2e6..83ead2db3d3 100644 --- a/packages/rocketchat-theme/i18n/fi.i18n.json +++ b/packages/rocketchat-theme/i18n/fi.i18n.json @@ -1 +1,23 @@ -{ } \ No newline at end of file +{ + "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-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-primary-background-color" : "Ensisijainen taustaväri", + "theme-color-primary-font-color" : "Ensisijainen fontin 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", + "theme-color-smallprint-hover-color" : "Pienen tekstin korostusväri", + "theme-color-status-away" : "Poissa-tilan väri", + "theme-color-status-busy" : "Varattu-tilan väri", + "theme-color-status-offline" : "Offline-tilan väri", + "theme-color-status-online" : "Online-tilan väri", + "theme-color-tertiary-background-color" : "Tertiäärinen (se kolmas) taustaväri", + "theme-color-tertiary-font-color" : "Tertiäärinen (se kolmas) fontin väri" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ku.i18n.json b/packages/rocketchat-theme/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/lo.i18n.json b/packages/rocketchat-theme/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/nl.i18n.json b/packages/rocketchat-theme/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/ku.i18n.json b/packages/rocketchat-webrtc/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/lo.i18n.json b/packages/rocketchat-webrtc/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/nl.i18n.json b/packages/rocketchat-webrtc/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-webrtc/i18n/pt.i18n.json b/packages/rocketchat-webrtc/i18n/pt.i18n.json index a0c6d126b99..bcbe2850b9e 100644 --- a/packages/rocketchat-webrtc/i18n/pt.i18n.json +++ b/packages/rocketchat-webrtc/i18n/pt.i18n.json @@ -1,3 +1,5 @@ { - "WebRTC_Enable_Direct" : "Ativar Mensagens Diretas" + "WebRTC_Enable_Channel" : "Habilitar para canais públicos", + "WebRTC_Enable_Direct" : "Ativar Mensagens Diretas", + "WebRTC_Enable_Private" : "Habilitar para canais privados" } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/ku.i18n.json b/packages/rocketchat-wordpress/i18n/ku.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/lo.i18n.json b/packages/rocketchat-wordpress/i18n/lo.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file diff --git a/packages/rocketchat-wordpress/i18n/nl.i18n.json b/packages/rocketchat-wordpress/i18n/nl.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file -- GitLab From d60b6ffdbf67200af35bc4e01ebd7869b0a5327f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 14 Dec 2015 09:53:05 -0200 Subject: [PATCH 0833/1338] fix formatting of /en.i18n.json --- .../rocketchat-livechat/app/i18n/en.i18n.json | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index a14d83d215e..b8a9e1d8a1b 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -1,20 +1,20 @@ { - "Additional_Feedback": "Additional Feedback", - "Skip": "Skip", - "E-mail": "E-mail", - "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", - "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", - "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." + "Additional_Feedback" : "Additional Feedback", + "Skip" : "Skip", + "E-mail" : "E-mail", + "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", + "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", + "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." } -- GitLab From 21844322849647bc6fbb6e364e97f4d79094a2d4 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 14 Dec 2015 10:25:55 -0200 Subject: [PATCH 0834/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. -- GitLab From 778f00816678087d9ad38991b25e71fe8014e0e6 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 14 Dec 2015 10:27:26 -0200 Subject: [PATCH 0835/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/lo.i18n.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/i18n/lo.i18n.json b/i18n/lo.i18n.json index 6f31cf5a2e6..11c7f733bb6 100644 --- a/i18n/lo.i18n.json +++ b/i18n/lo.i18n.json @@ -1 +1,6 @@ -{ } \ No newline at end of file +{ + "Channels" : "ຊ່àºàº‡â€‹àº—າງ​àºàº²àº™", + "edited" : "à»àºà»‰â€‹à»„ຂ", + "User_left" : "ໄດ້​ປະ​ໄວ້​ຊ່àºàº‡â€‹àº—າງ​àºàº²àº™â€‹.", + "New_password" : "ລະ​ຫັດ​ຜ່ານ​ໃຫມ່" +} \ No newline at end of file -- GitLab From 57a10be2d717d4cf3cab00284d1d0c494fa596d4 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 14 Dec 2015 10:41:59 -0200 Subject: [PATCH 0836/1338] bump version to 0.9.0 --- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- rocketchat.info | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index b87c8cdd6ca..908e6daf7f9 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 4, # Increment this for every release. + appVersion = 5, # Increment this for every release. - appMarketingVersion = (defaultText = "0.8.1"), + appMarketingVersion = (defaultText = "0.9.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/rocketchat.info b/rocketchat.info index 12759ff2748..49886ade63f 100644 --- a/rocketchat.info +++ b/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.8.0" + "version": "0.9.0" } -- GitLab From bf45996eef9b83de63169347f5b38ece23acff6a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 14 Dec 2015 11:22:58 -0200 Subject: [PATCH 0837/1338] updated aldeed:simple-schema to 1.5.0 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index a27fecd55b0..8aed6ee4dd1 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -7,7 +7,7 @@ accounts-oauth@1.1.8 accounts-password@1.1.4 accounts-twitter@1.0.6 alanning:roles@1.2.14 -aldeed:simple-schema@1.4.0 +aldeed:simple-schema@1.5.0 arunoda:streams@0.1.17 autoupdate@1.2.4 babel-compiler@5.8.24_1 -- GitLab From b079e1d605df491c54a23b8473c9ad6689888917 Mon Sep 17 00:00:00 2001 From: Omar Qunsul <omar.qunsul@expertiger.de> Date: Mon, 14 Dec 2015 15:36:06 +0100 Subject: [PATCH 0838/1338] Custom oAuth fix --- packages/rocketchat-custom-oauth/custom_oauth_server.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-custom-oauth/custom_oauth_server.coffee b/packages/rocketchat-custom-oauth/custom_oauth_server.coffee index 587157e6f00..039d41eb04f 100644 --- a/packages/rocketchat-custom-oauth/custom_oauth_server.coffee +++ b/packages/rocketchat-custom-oauth/custom_oauth_server.coffee @@ -82,7 +82,7 @@ class CustomOAuth params: access_token: accessToken - return response.data + return response.content catch err error = new Error("Failed to fetch identity from #{@name} at #{@identityPath}. " + err.message) @@ -94,7 +94,7 @@ class CustomOAuth accessToken = self.getAccessToken query console.log 'at:', accessToken - identity = self.getIdentity accessToken + identity = JSON.parse(self.getIdentity(accessToken)) # Fix WordPress-like identities having 'ID' instead of 'id' if identity?.ID and not identity.id -- GitLab From 4c5669a9a3e5470c15eefc27f6e1cab6357abcb5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 14 Dec 2015 14:51:36 -0200 Subject: [PATCH 0839/1338] Unsubscribe e-mails from CSV --- .../node_scripts/unsubscribe_csv/package.json | 20 +++++++++++ .../unsubscribe_csv/unsubscribe.coffee | 33 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 private/node_scripts/unsubscribe_csv/package.json create mode 100644 private/node_scripts/unsubscribe_csv/unsubscribe.coffee diff --git a/private/node_scripts/unsubscribe_csv/package.json b/private/node_scripts/unsubscribe_csv/package.json new file mode 100644 index 00000000000..1efe93181ce --- /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 00000000000..450d03329f8 --- /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() -- GitLab From 9c181604db936b28c62bc1598b2efff2d5631181 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 14 Dec 2015 16:44:57 -0200 Subject: [PATCH 0840/1338] Allow OEmbed to bypass file protection --- lib/fileUpload.coffee | 9 ++++++++- packages/rocketchat-oembed/package.js | 1 + packages/rocketchat-oembed/server/server.coffee | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index e927cc82cb2..83b6accfbd7 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -52,7 +52,14 @@ if UploadFS? uid = cookie.get('rc_uid', rawCookies) if rawCookies? token = cookie.get('rc_token', rawCookies) if rawCookies? - unless uid and token and RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) + if not uid or not token + throw new Meteor.Error 403, 'Not Allowed' + + if uid is OEmbed.rc_uid + if token isnt OEmbed.rc_token + throw new Meteor.Error 403, 'Not Allowed' + + else if not RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) throw new Meteor.Error 403, 'Not Allowed' res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index ace7d0496be..7112f25ee92 100644 --- a/packages/rocketchat-oembed/package.js +++ b/packages/rocketchat-oembed/package.js @@ -12,6 +12,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', + 'random', 'konecty:change-case', 'rocketchat:lib@0.0.1' ]); diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 7696e42b770..c98669c2c73 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -7,7 +7,10 @@ querystring = Npm.require('querystring') gunzipSync = Meteor.wrapAsync zlib.gunzip.bind(zlib) inflateSync = Meteor.wrapAsync zlib.inflate.bind(zlib) -OEmbed = {} +OEmbed = { + rc_uid: 'OEmbed' + rc_token: Random.id() +} getUrlContent = (urlObj, redirectCount = 5, callback) -> if _.isString(urlObj) @@ -21,6 +24,7 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> rejectUnauthorized: !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' + 'Cookie': "rc_uid=#{OEmbed.rc_uid}; rc_token=#{OEmbed.rc_token}" httpOrHttps = if urlObj.protocol is 'https:' then https else http -- GitLab From f7ed5d80c568133e74a11c9d33fcc9fd33481e7a Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 14 Dec 2015 17:12:20 -0200 Subject: [PATCH 0841/1338] Revert "Allow OEmbed to bypass file protection" This reverts commit 9c181604db936b28c62bc1598b2efff2d5631181. --- lib/fileUpload.coffee | 9 +-------- packages/rocketchat-oembed/package.js | 1 - packages/rocketchat-oembed/server/server.coffee | 6 +----- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 83b6accfbd7..e927cc82cb2 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -52,14 +52,7 @@ if UploadFS? uid = cookie.get('rc_uid', rawCookies) if rawCookies? token = cookie.get('rc_token', rawCookies) if rawCookies? - if not uid or not token - throw new Meteor.Error 403, 'Not Allowed' - - if uid is OEmbed.rc_uid - if token isnt OEmbed.rc_token - throw new Meteor.Error 403, 'Not Allowed' - - else if not RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) + unless uid and token and RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) throw new Meteor.Error 403, 'Not Allowed' res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index 7112f25ee92..ace7d0496be 100644 --- a/packages/rocketchat-oembed/package.js +++ b/packages/rocketchat-oembed/package.js @@ -12,7 +12,6 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'random', 'konecty:change-case', 'rocketchat:lib@0.0.1' ]); diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index c98669c2c73..7696e42b770 100644 --- a/packages/rocketchat-oembed/server/server.coffee +++ b/packages/rocketchat-oembed/server/server.coffee @@ -7,10 +7,7 @@ querystring = Npm.require('querystring') gunzipSync = Meteor.wrapAsync zlib.gunzip.bind(zlib) inflateSync = Meteor.wrapAsync zlib.inflate.bind(zlib) -OEmbed = { - rc_uid: 'OEmbed' - rc_token: Random.id() -} +OEmbed = {} getUrlContent = (urlObj, redirectCount = 5, callback) -> if _.isString(urlObj) @@ -24,7 +21,6 @@ getUrlContent = (urlObj, redirectCount = 5, callback) -> rejectUnauthorized: !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' - 'Cookie': "rc_uid=#{OEmbed.rc_uid}; rc_token=#{OEmbed.rc_token}" httpOrHttps = if urlObj.protocol is 'https:' then https else http -- GitLab From b2f18455cc6d761da4f088853ab793bddea3c508 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 14 Dec 2015 17:41:39 -0200 Subject: [PATCH 0842/1338] Fix language loading from cordova --- packages/rocketchat-cors/cors.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index f360cd65014..ea47d21760e 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -4,6 +4,14 @@ 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 -- GitLab From dfed59ad25a6ffb562ea4aa481f42392b56e2357 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 14 Dec 2015 18:04:46 -0200 Subject: [PATCH 0843/1338] improved triggers settings --- .../app/client/lib/triggers.js | 76 ++++++++-------- .../assets/rocket-livechat.js | 4 +- .../client/stylesheets/livechat.less | 19 ++++ .../client/views/app/livechatTriggers.html | 30 ++++--- .../client/views/app/livechatTriggers.js | 87 ++++++++++++++----- .../app/triggers/livechatTriggerAction.html | 15 ++++ .../app/triggers/livechatTriggerAction.js | 23 +++++ .../triggers/livechatTriggerCondition.html | 18 ++++ .../app/triggers/livechatTriggerCondition.js | 33 +++++++ .../rocketchat-livechat/i18n/en.i18n.json | 10 ++- packages/rocketchat-livechat/package.js | 9 ++ .../server/methods/removeTrigger.js | 11 +++ .../server/models/LivechatTrigger.js | 4 + 13 files changed, 266 insertions(+), 73 deletions(-) create mode 100644 packages/rocketchat-livechat/client/stylesheets/livechat.less create mode 100644 packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.html create mode 100644 packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerAction.js create mode 100644 packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.html create mode 100644 packages/rocketchat-livechat/client/views/app/triggers/livechatTriggerCondition.js create mode 100644 packages/rocketchat-livechat/server/methods/removeTrigger.js diff --git a/packages/rocketchat-livechat/app/client/lib/triggers.js b/packages/rocketchat-livechat/app/client/lib/triggers.js index e30e95f77a9..9d05e1845c0 100644 --- a/packages/rocketchat-livechat/app/client/lib/triggers.js +++ b/packages/rocketchat-livechat/app/client/lib/triggers.js @@ -1,57 +1,57 @@ this.Triggers = (function() { - var urlRegex = null; - var time = null; - var message = 'Default trigger message'; - - var timeout = null; + var triggers = []; var init = function() { - console.log('init!!'); Tracker.autorun(function() { - var trigger = Trigger.findOne(); - console.log('trigger found ->',trigger); - if (trigger) { - urlRegex = trigger.urlRegex; - time = trigger.time; - message = trigger.message; - } + triggers = Trigger.find().fetch(); }); }; - var fire = function() { + var fire = function(actions) { if (Meteor.userId()) { console.log('already logged user - does nothing'); return; } - parentCall('triggerMessage', message); - - var room = Random.id(); - visitor.setRoom(room); - - Session.set('triggered', true); - ChatMessage.insert({ - msg: message, - rid: room, - u: { - username: 'random-agent' + actions.forEach(function(action) { + if (action.name === 'send-message') { + var room = Random.id(); + visitor.setRoom(room); + + Session.set('triggered', true); + ChatMessage.insert({ + msg: action.params.msg, + rid: room, + u: { + username: action.params.name + } + }); + + parentCall('openWidget'); } }); }; var processRequest = function(request) { - if (urlRegex && urlRegex !== '') { - if (request.href.match(urlRegex)) { - fire(); - } - } - - if (time) { - console.log('registerTimeout ->',time); - clearTimeout(timeout); - timeout = setTimeout(function() { - fire(); - }, time * 1000); - } + triggers.forEach(function(trigger) { + trigger.conditions.forEach(function(condition) { + switch (condition.name) { + case 'page-url': + if (request.href.match(new RegExp(urlRegex))) { + 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 { diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index 69aca27475c..bc9c1c0c2e9 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -49,9 +49,7 @@ var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no'); popup.focus(); }, - triggerMessage: function(msg) { - console.log('trigger fired!!!! ->',msg); - + openWidget: function() { openWidget(); } }; diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less new file mode 100644 index 00000000000..d2cddae6c45 --- /dev/null +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -0,0 +1,19 @@ +.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; + } +} diff --git a/packages/rocketchat-livechat/client/views/app/livechatTriggers.html b/packages/rocketchat-livechat/client/views/app/livechatTriggers.html index 17657bc2d45..98e5bd9b9e5 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatTriggers.html +++ b/packages/rocketchat-livechat/client/views/app/livechatTriggers.html @@ -2,21 +2,29 @@ <form id="trigger-form"> <div class="rocket-form"> <fieldset> - <div class="input-line"> - <label>{{_ "Trigger_by_URL"}}</label> - <input type="text" name="url-regex" placeholder="{{_ "Enter_a_regex"}}" value="{{urlRegex}}"> + <legend>{{_ "Condition"}}</legend> + <div class="conditions"> + {{#each conditions}} + {{> livechatTriggerCondition}} + {{/each}} + {{#unless conditions}} + {{> livechatTriggerCondition}} + {{/unless}} </div> - <div class="input-line"> - <label>{{_ "Trigger_by_time"}}</label> - <input type="number" name="trigger-time" placeholder="{{_ "Time_in_seconds_at_the_same_page"}}" value="{{time}}"> - </div> - <div class="input-line"> - <label>{{_ "Trigger_message"}}</label> - <input type="text" name="trigger-message" placeholder="{{_ "Enter_a_message_to_your_customer"}}" value="{{message}}"> + </fieldset> + <fieldset> + <legend>{{_ "Action"}}</legend> + <div class="actions"> + {{#each actions}} + {{> livechatTriggerAction}} + {{/each}} + {{#unless actions}} + {{> livechatTriggerAction}} + {{/unless}} </div> </fieldset> <div class="submit"> - <button type="reset" class="button secondary reset"><i class="icon-ccw"></i><span>{{_ "Reset"}}</span></button> + <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> diff --git a/packages/rocketchat-livechat/client/views/app/livechatTriggers.js b/packages/rocketchat-livechat/client/views/app/livechatTriggers.js index 628a3c4a78f..d36632f0f7f 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatTriggers.js +++ b/packages/rocketchat-livechat/client/views/app/livechatTriggers.js @@ -1,13 +1,16 @@ Template.livechatTriggers.helpers({ - urlRegex() { - return Template.instance().trigger.get().urlRegex; - }, - time() { - return Template.instance().trigger.get().time; - }, - message() { - return Template.instance().trigger.get().message; + 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({ @@ -19,11 +22,34 @@ Template.livechatTriggers.events({ $btn.html(t('Saving')); var data = { - urlRegex: instance.$('input[name=url-regex]').val(), - time: instance.$('input[name=trigger-time]').val(), - message: instance.$('input[name=trigger-message]').val() + 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) { @@ -33,19 +59,40 @@ Template.livechatTriggers.events({ 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({ - urlRegex: '', - time: '', - message: '', - }); + this.trigger = new ReactiveVar(null); this.autorun(() => { - trigger = LivechatTrigger.findOne(); - if (trigger) { - this.trigger.set(trigger); - } + this.trigger.set(LivechatTrigger.findOne()); }); }); 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 00000000000..4a4328b7ae8 --- /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 00000000000..7ef854e593f --- /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 00000000000..3e61db95a66 --- /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 00000000000..a99fa0213e1 --- /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/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 12ac327cf30..c8da9eb6de1 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -13,6 +13,7 @@ "Edit_Department" : "Edit Department", "Enable" : "Enable", "Enabled" : "Enabled", + "Enter_a_regex": "Enter a regex", "Enter_a_username" : "Enter a username", "Integrations" : "Integrations", "Live_sessions" : "Live sessions", @@ -23,16 +24,23 @@ "Livechat_title_color" : "Livechat Title Background Color", "Manager_added" : "Manager added", "Manager_removed" : "Manager removed", + "Message": "Message", "Name" : "Name", + "Name_of_agent": "Name of agent", "New_Department" : "New Department", "Num_Agents" : "# Agents", "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", + "Send_a_message": "Send a message", "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", "Triggers": "Triggers", + "Trigger_removed": "Trigger removed", "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" } diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index ed592f9251f..e7d127ac7ff 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -25,6 +25,7 @@ Package.onUse(function(api) { 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'); @@ -36,6 +37,8 @@ Package.onUse(function(api) { api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); + api.addFiles('client/stylesheets/livechat.less', 'client'); + // client views api.addFiles('client/views/app/livechatManager.html', 'client'); api.addFiles('client/views/app/livechatManager.js', 'client'); @@ -50,6 +53,11 @@ Package.onUse(function(api) { 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'); @@ -59,6 +67,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/removeManager.js', 'server'); api.addFiles('server/methods/removeDepartment.js', 'server'); api.addFiles('server/methods/saveTrigger.js', 'server'); + api.addFiles('server/methods/removeTrigger.js', 'server'); // models api.addFiles('server/models/Users.js', 'server'); diff --git a/packages/rocketchat-livechat/server/methods/removeTrigger.js b/packages/rocketchat-livechat/server/methods/removeTrigger.js new file mode 100644 index 00000000000..bf09510d45d --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/removeTrigger.js @@ -0,0 +1,11 @@ +Meteor.methods({ + 'livechat:removeTrigger' (trigger) { + console.log('[methods] livechat:removeTrigger -> '.green, 'arguments:', arguments); + + 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/models/LivechatTrigger.js b/packages/rocketchat-livechat/server/models/LivechatTrigger.js index 4b5ddfd5b35..4873a44f1c2 100644 --- a/packages/rocketchat-livechat/server/models/LivechatTrigger.js +++ b/packages/rocketchat-livechat/server/models/LivechatTrigger.js @@ -17,6 +17,10 @@ class LivechatTrigger extends RocketChat.models._Base { return this.insert(data); } } + + removeAll() { + this.remove({}); + } } RocketChat.models.LivechatTrigger = new LivechatTrigger(); -- GitLab From b64a720d9940d14f0720f1a6fa1402c18d4f762d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 14 Dec 2015 19:52:19 -0200 Subject: [PATCH 0844/1338] Allow to set messages as ungroupable --- .../rocketchat-integrations/server/api/api.coffee | 1 + .../rocketchat-ui-message/message/message.coffee | 12 +++++++++--- packages/rocketchat-ui-message/message/message.html | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 4001e3c09a7..33e991a1418 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -78,6 +78,7 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, parseUrls: false bot: i: integration._id + groupable: false RocketChat.sendMessage user, message, room, {} diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index c596d6e36af..444636664f4 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -1,6 +1,10 @@ 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 own: -> return 'own' if this.u?._id is Meteor.userId() chatops: -> @@ -111,17 +115,19 @@ Template.message.onViewRendered = (context) -> 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 + else if lastNode.previousElementSibling?.dataset?.username isnt lastNode.dataset.username + $(lastNode).removeClass('sequential') + + if lastNode.previousElementSibling?.dataset?.groupable is 'false' $(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') - if lastNode.nextElementSibling?.dataset?.bot is 'bot' or lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username + if lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username $(lastNode.nextElementSibling).removeClass('sequential') if not lastNode.nextElementSibling? diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 0ae084bfc99..890ebd4e5a9 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}}"> {{#if avatar}} <a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1"> <div class="avatar"> -- GitLab From 2c588131fc112ac36f393e6d4831199a49c188e2 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 14 Dec 2015 19:54:30 -0200 Subject: [PATCH 0845/1338] Attachments: Concerning the mobile settings to save badwidth and fix relative urls in cordova --- .../client/messageAttachment.coffee | 14 +++++++++++ .../client/messageAttachment.html | 23 ++++++++++++------- .../rocketchat-message-attachments/package.js | 1 + packages/rocketchat-ui/views/app/room.coffee | 1 + 4 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 packages/rocketchat-message-attachments/client/messageAttachment.coffee diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee new file mode 100644 index 00000000000..b0b01c8a6c5 --- /dev/null +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -0,0 +1,14 @@ +Template.messageAttachment.helpers + fixCordova: (url) -> + if Meteor.isCordova and url?[0] is '/' + return Meteor.absoluteUrl().replace(/\/$/, '') + url + 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 diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 7429edaedb1..7b1c470fd5b 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -11,12 +11,12 @@ {{#if author_icon}} <img src="{{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,18 @@ {{#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}}"> + </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}} diff --git a/packages/rocketchat-message-attachments/package.js b/packages/rocketchat-message-attachments/package.js index 928f83ea8dc..a5b5873903d 100644 --- a/packages/rocketchat-message-attachments/package.js +++ b/packages/rocketchat-message-attachments/package.js @@ -16,6 +16,7 @@ Package.onUse(function(api) { ]); 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-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index d77154139d6..b7c9ede601c 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -368,6 +368,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}} + ChatMessage.update {_id: this._arguments[1]._id, 'attachments.image_url': $(event.currentTarget).data('url')}, {$set: {'attachments.$.downloadImages': true}} 'click .pin-message': (event) -> message = @_arguments[1] -- GitLab From 450fd3f2926aad2778f548f63ea5a744f3ff1fe8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 14 Dec 2015 19:55:08 -0200 Subject: [PATCH 0846/1338] Use attachments to render preview of uploads and use relative paths --- packages/rocketchat-ui/lib/fileUpload.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index 48db0ca7dbe..693ad45b6a3 100644 --- a/packages/rocketchat-ui/lib/fileUpload.coffee +++ b/packages/rocketchat-ui/lib/fileUpload.coffee @@ -86,15 +86,19 @@ readAsArrayBuffer = (file, callback) -> onComplete: (file) -> self = this + url = file.url.replace(Meteor.absoluteUrl(), '/') Meteor.call 'sendMessage', { _id: Random.id() rid: roomId - msg: """ - File Uploaded: *#{file.name}* - #{file.url} - """ + msg: "" file: _id: file._id + groupable: false + attachments: [{ + image_url: url + title: "File Uploaded: #{file.name}" + title_link: url + }] }, -> Meteor.setTimeout -> uploading = Session.get 'uploading' -- GitLab From 211c01ff27c0804412e5d45ce7eb6e7c389e17ca Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 14 Dec 2015 20:10:54 -0200 Subject: [PATCH 0847/1338] Render a player for audio files --- .../client/messageAttachment.html | 9 +++++++ packages/rocketchat-ui/lib/fileUpload.coffee | 26 ++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 7b1c470fd5b..6f43d940509 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -62,6 +62,15 @@ </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 fields}} <div class="attachment-fields"> {{#each fields}} diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index 693ad45b6a3..98d77ad8bf4 100644 --- a/packages/rocketchat-ui/lib/fileUpload.coffee +++ b/packages/rocketchat-ui/lib/fileUpload.coffee @@ -87,19 +87,31 @@ readAsArrayBuffer = (file, callback) -> onComplete: (file) -> self = this url = file.url.replace(Meteor.absoluteUrl(), '/') - Meteor.call 'sendMessage', { + + 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 + + if /^audio\/.+/.test file.type + attachment.audio_url = url + attachment.audio_type = file.type + attachment.audio_size = file.size + + msg = _id: Random.id() rid: roomId msg: "" file: _id: file._id groupable: false - attachments: [{ - image_url: url - title: "File Uploaded: #{file.name}" - title_link: url - }] - }, -> + attachments: [attachment] + + Meteor.call 'sendMessage', msg, -> Meteor.setTimeout -> uploading = Session.get 'uploading' if uploading? -- GitLab From 7f759f020abd7cc8bab952e17ced24536f5f9477 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 14 Dec 2015 20:19:13 -0200 Subject: [PATCH 0848/1338] Render a player for video files --- .../client/messageAttachment.html | 9 +++++++++ packages/rocketchat-ui/lib/fileUpload.coffee | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 6f43d940509..433029711e3 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -71,6 +71,15 @@ </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}} + {{#if fields}} <div class="attachment-fields"> {{#each fields}} diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index 98d77ad8bf4..b60a417f77f 100644 --- a/packages/rocketchat-ui/lib/fileUpload.coffee +++ b/packages/rocketchat-ui/lib/fileUpload.coffee @@ -102,6 +102,11 @@ readAsArrayBuffer = (file, callback) -> 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 -- GitLab From 26c15cd97d53c9fb4c7a6e64c8ed4d1b0273ab8c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 14 Dec 2015 23:10:28 +0000 Subject: [PATCH 0849/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/fi.i18n.json | 1 + i18n/lo.i18n.json | 4 ++-- packages/rocketchat-livechat/app/i18n/ar.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/cs.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/de.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/el.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/en.i18n.json | 7 +------ packages/rocketchat-livechat/app/i18n/es.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/fa.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/fi.i18n.json | 3 ++- packages/rocketchat-livechat/app/i18n/fr.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/he.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/hr.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/hu.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/it.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/ja.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/km.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/ko.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/lo.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/ms-MY.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/nl.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/pl.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/pt.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/ru.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/sq.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/sv.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/ta-IN.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/tr.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/ug.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/uk.i18n.json | 4 +++- packages/rocketchat-livechat/app/i18n/zh.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/ar.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/cs.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/el.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/es.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/fa.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/fi.i18n.json | 1 + packages/rocketchat-livechat/i18n/he.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/hr.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/hu.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/it.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/lo.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/ru.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/sq.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/sv.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/tr.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/ug.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/uk.i18n.json | 4 +++- packages/rocketchat-livechat/i18n/zh.i18n.json | 4 +++- 49 files changed, 139 insertions(+), 53 deletions(-) diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 01f48d5c754..c6aaef8871e 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -17,6 +17,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", diff --git a/i18n/lo.i18n.json b/i18n/lo.i18n.json index 11c7f733bb6..68943c27834 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/packages/rocketchat-livechat/app/i18n/ar.i18n.json b/packages/rocketchat-livechat/app/i18n/ar.i18n.json index 6f31cf5a2e6..e325035daf7 100644 --- a/packages/rocketchat-livechat/app/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ar.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/cs.i18n.json b/packages/rocketchat-livechat/app/i18n/cs.i18n.json index 6f31cf5a2e6..6aaa0ff01cc 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 6f31cf5a2e6..c7d0e51d44a 100644 --- a/packages/rocketchat-livechat/app/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/de.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Chat beginnen" +} \ 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 6f31cf5a2e6..14415269c85 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 b8a9e1d8a1b..437cfd80f94 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -1,20 +1,15 @@ { "Additional_Feedback" : "Additional Feedback", "Skip" : "Skip", - "E-mail" : "E-mail", "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", "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", "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 6f31cf5a2e6..01ccecd14b5 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 6f31cf5a2e6..81ee6d2f85e 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 f279ec41b30..ec1ed8a50b0 100644 --- a/packages/rocketchat-livechat/app/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fi.i18n.json @@ -10,5 +10,6 @@ "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 6f31cf5a2e6..48fec1b275a 100644 --- a/packages/rocketchat-livechat/app/i18n/fr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Démarrer un chat" +} \ 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 6f31cf5a2e6..5e8b9b574e5 100644 --- a/packages/rocketchat-livechat/app/i18n/he.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/he.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/hr.i18n.json b/packages/rocketchat-livechat/app/i18n/hr.i18n.json index 6f31cf5a2e6..7cfffb7eb71 100644 --- a/packages/rocketchat-livechat/app/i18n/hr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/hr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "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 6f31cf5a2e6..5e8b9b574e5 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 6f31cf5a2e6..dc6a25746c5 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 6f31cf5a2e6..70a58ee9e7c 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 6f31cf5a2e6..a5eb5069a36 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 6f31cf5a2e6..c343dee6ac0 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/lo.i18n.json b/packages/rocketchat-livechat/app/i18n/lo.i18n.json index 6f31cf5a2e6..88505c1c64a 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 6f31cf5a2e6..8dbe1bb222e 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 6f31cf5a2e6..5e8b9b574e5 100644 --- a/packages/rocketchat-livechat/app/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/nl.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/pl.i18n.json b/packages/rocketchat-livechat/app/i18n/pl.i18n.json index 6f31cf5a2e6..0c082b62370 100644 --- a/packages/rocketchat-livechat/app/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/pl.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Start_Chat" : "Rozpocznij czat" +} \ 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 6f31cf5a2e6..b7e65b0c74f 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/ru.i18n.json b/packages/rocketchat-livechat/app/i18n/ru.i18n.json index 6f31cf5a2e6..9a8fba30e6a 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 6f31cf5a2e6..91b65876930 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/sv.i18n.json b/packages/rocketchat-livechat/app/i18n/sv.i18n.json index 6f31cf5a2e6..504f8b76303 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 6f31cf5a2e6..279a5141a32 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 6f31cf5a2e6..370bbedcd2a 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 6f31cf5a2e6..5e8b9b574e5 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 6f31cf5a2e6..530dc71418b 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 6f31cf5a2e6..20a41fc2f8b 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/i18n/ar.i18n.json b/packages/rocketchat-livechat/i18n/ar.i18n.json index 6f31cf5a2e6..3607c7efa2a 100644 --- a/packages/rocketchat-livechat/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/i18n/ar.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/cs.i18n.json b/packages/rocketchat-livechat/i18n/cs.i18n.json index 6f31cf5a2e6..6ad288846f9 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/el.i18n.json b/packages/rocketchat-livechat/i18n/el.i18n.json index 6f31cf5a2e6..53f32128d56 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/es.i18n.json b/packages/rocketchat-livechat/i18n/es.i18n.json index 6f31cf5a2e6..b777b5b19e9 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 6f31cf5a2e6..f69ec3552e0 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 c3913e2b43c..0de5eebfc7f 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -16,6 +16,7 @@ "Enter_a_username" : "Syötä käyttäjätunnus", "Live_sessions" : "Live-istunnot", "Livechat_agents" : "Livechat agentit", + "Livechat_enabled" : "LiveChat käytössä", "Livechat_Manager" : "Livechat manageri", "Livechat_managers" : "Livechat managerit", "Livechat_title" : "Livechat otsikko", diff --git a/packages/rocketchat-livechat/i18n/he.i18n.json b/packages/rocketchat-livechat/i18n/he.i18n.json index 6f31cf5a2e6..a119b69e013 100644 --- a/packages/rocketchat-livechat/i18n/he.i18n.json +++ b/packages/rocketchat-livechat/i18n/he.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/hr.i18n.json b/packages/rocketchat-livechat/i18n/hr.i18n.json index 6f31cf5a2e6..94d44728829 100644 --- a/packages/rocketchat-livechat/i18n/hr.i18n.json +++ b/packages/rocketchat-livechat/i18n/hr.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Livechat_enabled" : "LiveChat omogućeno" +} \ 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 6f31cf5a2e6..049e289a6b8 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 6f31cf5a2e6..af31f8b3499 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/lo.i18n.json b/packages/rocketchat-livechat/i18n/lo.i18n.json index 6f31cf5a2e6..a9acf8c81be 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/ru.i18n.json b/packages/rocketchat-livechat/i18n/ru.i18n.json index 6f31cf5a2e6..bbece375a50 100644 --- a/packages/rocketchat-livechat/i18n/ru.i18n.json +++ b/packages/rocketchat-livechat/i18n/ru.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/sq.i18n.json b/packages/rocketchat-livechat/i18n/sq.i18n.json index 6f31cf5a2e6..4252cafab36 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/sv.i18n.json b/packages/rocketchat-livechat/i18n/sv.i18n.json index 6f31cf5a2e6..2a24e670215 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 6f31cf5a2e6..008b9ca305b 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 6f31cf5a2e6..7e724987836 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 6f31cf5a2e6..13a9ea9ca68 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 6f31cf5a2e6..c83357d2db2 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 -- GitLab From a690ea4267e4e13aa6e5311fd4d4e15175d835d3 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 14 Dec 2015 21:24:44 -0200 Subject: [PATCH 0850/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- packages/rocketchat-livechat/app/i18n/ku.i18n.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/app/i18n/ku.i18n.json b/packages/rocketchat-livechat/app/i18n/ku.i18n.json index 6f31cf5a2e6..5e8b9b574e5 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 -- GitLab From de82817573127d13e87e4fea41c7815907c3bf88 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 09:38:26 -0200 Subject: [PATCH 0851/1338] removed ES code --- packages/rocketchat-livechat/assets/rocket-livechat.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index bc9c1c0c2e9..3413c05d708 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -16,19 +16,18 @@ 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() { - // console.log('ready!!!'); ready = true; if (hookQueue.length > 0) { hookQueue.forEach(function(hookParams) { -- GitLab From dc8f4e34c5e463734675ee4bb33be38a9e249612 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 10:06:26 -0200 Subject: [PATCH 0852/1338] fix merge mess =P --- .../rocketchat-livechat/app/client/views/room.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/room.html index 0220ed9abfa..6cb419c8c79 100644 --- a/packages/rocketchat-livechat/app/client/views/room.html +++ b/packages/rocketchat-livechat/app/client/views/room.html @@ -10,14 +10,15 @@ </div> <h1>{{title}}</h1> </div> - {{#if currentUser}} - {{> messages}} - {{else}} - {{#if livechatEnabled}} - {{> register}} + + {{#if livechatEnabled}} + {{#if showMessages}} + {{> messages}} {{else}} - <div class="offline">{{_ "We_are_offline_Sorry_for_the_inconvenience"}}</div> + {{> register}} {{/if}} + {{else}} + <div class="offline">{{_ "We_are_offline_Sorry_for_the_inconvenience"}}</div> {{/if}} </div> {{/if}} -- GitLab From 62c0b86b7867321b435c2cd5e8f85c2723bb2120 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 10:09:09 -0200 Subject: [PATCH 0853/1338] code cleanup --- packages/rocketchat-livechat/app/client/lib/hooks.js | 1 - .../rocketchat-livechat/app/client/startup/triggers.js | 5 +---- packages/rocketchat-livechat/assets/rocket-livechat.js | 3 --- .../rocketchat-livechat/server/publications/trigger.js | 10 ---------- 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/lib/hooks.js b/packages/rocketchat-livechat/app/client/lib/hooks.js index 9d4dada5d80..9ca2792bbe3 100644 --- a/packages/rocketchat-livechat/app/client/lib/hooks.js +++ b/packages/rocketchat-livechat/app/client/lib/hooks.js @@ -1,6 +1,5 @@ var api = { pageVisited: function(info) { - console.log('pageVisited ->',info); Triggers.processRequest(info); } }; diff --git a/packages/rocketchat-livechat/app/client/startup/triggers.js b/packages/rocketchat-livechat/app/client/startup/triggers.js index 46b0e51ac6e..71cfdb1d0d9 100644 --- a/packages/rocketchat-livechat/app/client/startup/triggers.js +++ b/packages/rocketchat-livechat/app/client/startup/triggers.js @@ -1,8 +1,5 @@ -console.log('startup trigger'); Meteor.startup(function() { - console.log('go'); Meteor.subscribe('livechat:trigger', function() { - console.log('ready'); Triggers.init() - }) + }); }); diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index 7d25b4c8766..823152f797e 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -59,10 +59,8 @@ // hooks var callHook = function(action, params) { if (!ready) { - console.log('queueing hook ->',action); return hookQueue.push(arguments); } - // console.log('calling hook ->',action); var data = { src: 'rocketchat', fn: action, @@ -72,7 +70,6 @@ }; var pageVisited = function() { - // console.log('calling pageVisited'); callHook('pageVisited', JSON.parse(JSON.stringify(document.location))); }; diff --git a/packages/rocketchat-livechat/server/publications/trigger.js b/packages/rocketchat-livechat/server/publications/trigger.js index 981e16da6d5..61d7d6831f4 100644 --- a/packages/rocketchat-livechat/server/publications/trigger.js +++ b/packages/rocketchat-livechat/server/publications/trigger.js @@ -1,13 +1,3 @@ Meteor.publish('livechat:trigger', function() { - // if (!this.userId) { - // throw new Meteor.Error('not-authorized'); - // } - - // if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) { - // throw new Meteor.Error('not-authorized'); - // } - - // console.log('[publish] livechat:trigger -> '.green, 'arguments:', arguments); - return RocketChat.models.LivechatTrigger.find(); }); -- GitLab From 866a000e11e2febcf6851a2e2196cf2b90cf974b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 13:14:26 -0200 Subject: [PATCH 0854/1338] Save individual room settings --- .../client/stylesheets/channel-settings.less | 4 + .../client/views/channelSettings.coffee | 89 ++++++++++++++----- .../client/views/channelSettings.html | 14 +-- .../i18n/en.i18n.json | 6 +- .../server/methods/saveRoomSettings.coffee | 39 ++++---- .../rocketchat-lib/client/lib/roomExit.coffee | 9 +- 6 files changed, 109 insertions(+), 52 deletions(-) diff --git a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less index 05f745e0abc..a09d3ee179c 100644 --- a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less +++ b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less @@ -13,6 +13,10 @@ 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 a56bc8f54cb..7f5639384fe 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -1,40 +1,64 @@ Template.channelSettings.helpers canEdit: -> - return true + return RocketChat.authz.hasAllPermission('edit-room', @rid) editing: (field) -> - return false + return Template.instance().editing.get() is field notDirect: -> return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> return ChatRoom.findOne(@rid)?.t roomTypeDescription: -> - return if ChatRoom.findOne(@rid)?.t is 'c' then t('Channel') else t('Private_Group') + 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 Template.channelSettings.events - 'click .save': (e, t) -> - e.preventDefault() + # 'click .save': (e, t) -> + # e.preventDefault() + + # settings = + # roomType: t.$('input[name=roomType]:checked').val() + # roomName: t.$('input[name=roomName]').val() + # roomTopic: t.$('input[name=roomTopic]').val() + + # if t.validate() + # Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> + # if err + # if err.error in [ 'duplicate-name', 'name-invalid' ] + # return toastr.error TAPi18n.__(err.reason, err.details.channelName) + # 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.__ 'Settings_updated' - settings = - roomType: t.$('input[name=roomType]:checked').val() - roomName: t.$('input[name=roomName]').val() - roomTopic: t.$('input[name=roomTopic]').val() + 'keydown input[type=text]': (e, t) -> + if e.keyCode is 13 + e.preventDefault() + t.saveSetting() - if t.validate() - Meteor.call 'saveRoomSettings', t.data.rid, settings, (err, results) -> - if err - if err.error in [ 'duplicate-name', 'name-invalid' ] - return toastr.error TAPi18n.__(err.reason, err.details.channelName) - if err.error is 'invalid-room-type' - return toastr.error TAPi18n.__(err.reason, err.details.roomType) - return toastr.error TAPi18n.__(err.reason) + '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() - toastr.success TAPi18n.__ 'Settings_updated' + 'click .save': (e, t) -> + e.preventDefault() + t.saveSetting() Template.channelSettings.onCreated -> + @editing = new ReactiveVar + @validateRoomType = => type = @$('input[name=roomType]:checked').val() if type not in ['c', 'p'] @@ -45,7 +69,7 @@ Template.channelSettings.onCreated -> rid = Template.currentData()?.rid room = ChatRoom.findOne rid - if room.u._id isnt Meteor.userId() or room.t not in ['c', 'p'] + if not RocketChat.authz.hasAllPermission('edit-room', @rid) or room.t not in ['c', 'p'] toastr.error t('Not_allowed') return false @@ -59,5 +83,28 @@ Template.channelSettings.onCreated -> @validateRoomTopic = => return true - @validate = => - return @validateRoomType() and @validateRoomName() and @validateRoomTopic() + @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 36a5cc72b4b..042abb27614 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -12,9 +12,9 @@ <label>{{_ "Name"}}</label> <div> {{#if editing 'roomName'}} - <input type="text" name="roomName" value="{{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}} - {{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil"></i>{{/if}} + {{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomName"></i>{{/if}} {{/if}} </div> </div> @@ -23,9 +23,9 @@ <label>{{_ "Topic"}}</label> <div> {{#if editing 'roomTopic'}} - <input type="text" name="roomTopic" value="{{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}} - {{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil"></i>{{/if}} + {{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomTopic"></i>{{/if}} {{/if}} </div> </div> @@ -34,10 +34,12 @@ <label>{{_ "Type"}}</label> <div> {{#if editing 'roomType'}} - <label><input type="radio" name="roomType" value="c" checked="{{$eq roomType 'c'}}" /> {{_ "Channel"}}</label> + <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}} - {{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil"></i>{{/if}} + {{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomType"></i>{{/if}} {{/if}} </div> </div> diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index 1191953e3ba..f9b02ab82b5 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,10 +1,14 @@ { + "Cancel": "Cancel", "Channel": "Channel", "Private_Group": "Private Group", "Name": "Name", + "Save": "Save", "Topic": "Topic", "Type": "Type", "Room_Settings": "Room Settings", "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" } diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee index 9cc15ad6fb4..348d43afc66 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -1,11 +1,11 @@ Meteor.methods - saveRoomSettings: (rid, settings) -> - console.log '[method] saveRoomSettings'.green, rid, settings + saveRoomSettings: (rid, setting, value) -> + console.log '[method] saveRoomSettings'.green, rid, setting, value unless Match.test rid, String throw new Meteor.Error 'invalid-rid', 'Invalid room' - unless Match.test settings, Match.ObjectIncluding { roomName: String, roomTopic: String, roomType: String } + 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) @@ -13,22 +13,21 @@ Meteor.methods room = RocketChat.models.Rooms.findOneById rid if room? - if settings.roomName isnt room.name - name = RocketChat.saveRoomName rid, settings.roomName - RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser rid, name, Meteor.user() - - if settings.roomType isnt room.t - RocketChat.saveRoomType(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() - - if settings.roomTopic isnt room.topic - RocketChat.saveRoomTopic(rid, settings.roomTopic) - RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', rid, settings.roomTopic, 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-lib/client/lib/roomExit.coffee b/packages/rocketchat-lib/client/lib/roomExit.coffee index d8a44ae00a3..7ee736f5e2e 100644 --- a/packages/rocketchat-lib/client/lib/roomExit.coffee +++ b/packages/rocketchat-lib/client/lib/roomExit.coffee @@ -10,8 +10,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 -- GitLab From ddd3ed53830ff1f2627072f36407c39283b37a92 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 13:32:19 -0200 Subject: [PATCH 0855/1338] Fix errors --- packages/rocketchat-lib/server/models/Messages.coffee | 3 --- packages/rocketchat-ui/views/app/room.coffee | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index b7449cddf47..f39ffe2b9a5 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -266,9 +266,6 @@ 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 diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index f5fc19fde96..fa93c7f9c7d 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -177,7 +177,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 -- GitLab From c25d6172919eda67441d67f562b316360dd56cd1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 13:40:15 -0200 Subject: [PATCH 0856/1338] Allow emoji as avatar for webhooks/integrations --- i18n/en.i18n.json | 4 +++- .../client/views/integrationsIncoming.coffee | 4 ++++ .../client/views/integrationsIncoming.html | 8 ++++++++ packages/rocketchat-integrations/server/api/api.coffee | 5 +++-- .../server/methods/updateIntegration.coffee | 1 + packages/rocketchat-theme/assets/stylesheets/base.less | 4 ++++ packages/rocketchat-ui-message/message/message.coffee | 2 ++ packages/rocketchat-ui-message/message/message.html | 10 +++++++++- 8 files changed, 34 insertions(+), 4 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 56d73d095a8..7d8f0edb359 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -153,6 +153,7 @@ "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", @@ -516,6 +517,7 @@ "Yes_delete_it" : "Yes, delete it!", "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_can_use_an_emoji_as_avatar" : "You can use an emoji as avatar", "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.", @@ -523,4 +525,4 @@ "Your_entry_has_been_deleted" : "Your entry has been deleted.", "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/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index 28f19b530c6..fabb8463eba 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -25,6 +25,7 @@ Template.integrationsIncoming.helpers return {} = _id: Random.id() alias: record.alias + emoji: record.emoji avatar: record.avatar msg: 'Example message' bot: @@ -47,6 +48,7 @@ Template.integrationsIncoming.events 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() @@ -78,6 +80,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,6 +94,7 @@ 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 '' diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index d17db30e5c5..0e11cd72a63 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -47,6 +47,14 @@ <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> diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 33e991a1418..93ad5732930 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -71,8 +71,9 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, error: 'invalid-channel-type' message = - avatar: integration.avatar - alias: integration.alias + avatar: integration.avatar or @bodyParams.avatar or @bodyParams.icon_url + emoji: integration.emoji or @bodyParams.emoji or @bodyParams.icon_emoji + alias: integration.alias or @bodyParams.alias or @bodyParams.username msg: @bodyParams.text or '' attachments: @bodyParams.attachments parseUrls: false diff --git a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee index d41d0e3d145..e09c565efb0 100644 --- a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/updateIntegration.coffee @@ -40,6 +40,7 @@ Meteor.methods $set: name: integration.name avatar: integration.avatar + emoji: integration.emoji alias: integration.alias channel: integration.channel _updatedAt: new Date diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 55ecffa41af..dfae174ff75 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -867,6 +867,10 @@ a.github-fork { overflow: hidden; position: relative; border-radius: 4px; + .emojione { + height: 100%; + margin: 0px; + } .avatar-image { height: 100%; width: 100%; diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 444636664f4..cdd07703eae 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -5,6 +5,8 @@ Template.message.helpers 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() chatops: -> diff --git a/packages/rocketchat-ui-message/message/message.html b/packages/rocketchat-ui-message/message/message.html index 890ebd4e5a9..998d648209e 100644 --- a/packages/rocketchat-ui-message/message/message.html +++ b/packages/rocketchat-ui-message/message/message.html @@ -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> -- GitLab From 61aced6acb713761f38fb217e108222c537bef58 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 13:44:56 -0200 Subject: [PATCH 0857/1338] Fix error on parsing message --- packages/rocketchat-ui/lib/RoomManager.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 0a70060a78e..640b54f66ca 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -111,11 +111,11 @@ RocketChat.Notifications.onUser 'message', (msg) -> msgStream.on openedRooms[typeName].rid, (msg) -> if msg.t isnt 'command' ChatMessage.upsert { _id: msg._id }, msg - else - Meteor.defer -> - RoomManager.updateMentionsMarksOfRoom typeName - RocketChat.callbacks.run 'streamMessage', msg + Meteor.defer -> + RoomManager.updateMentionsMarksOfRoom typeName + + RocketChat.callbacks.run 'streamMessage', msg RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream -- GitLab From 2ba1a58cdd03857f8896ecb99f1b33880c169849 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 13:46:15 -0200 Subject: [PATCH 0858/1338] Fix checking if message is command --- packages/rocketchat-ui/lib/RoomManager.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 0a70060a78e..640b54f66ca 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -111,11 +111,11 @@ RocketChat.Notifications.onUser 'message', (msg) -> msgStream.on openedRooms[typeName].rid, (msg) -> if msg.t isnt 'command' ChatMessage.upsert { _id: msg._id }, msg - else - Meteor.defer -> - RoomManager.updateMentionsMarksOfRoom typeName - RocketChat.callbacks.run 'streamMessage', msg + Meteor.defer -> + RoomManager.updateMentionsMarksOfRoom typeName + + RocketChat.callbacks.run 'streamMessage', msg RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream -- GitLab From 932ae6b27dcf12d5b3686620aae75cd727924b24 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 14:24:11 -0200 Subject: [PATCH 0859/1338] Add examples of curl and json in integrations --- .../client/views/integrationsIncoming.coffee | 39 +++++++++++++++++++ .../client/views/integrationsIncoming.html | 8 ++++ packages/rocketchat-integrations/package.js | 1 + 3 files changed, 48 insertions(+) diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index fabb8463eba..2f6126ab3dc 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -42,6 +42,45 @@ 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) -> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index 0e11cd72a63..7efeb81ec8b 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -65,6 +65,14 @@ </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/package.js b/packages/rocketchat-integrations/package.js index ae298211d72..fe6df9670d8 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -11,6 +11,7 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); + api.use('simple:highlight.js'); api.use('rocketchat:lib@0.0.1'); api.use('kadira:flow-router', 'client'); -- GitLab From 724231744f9c61255f09549f34896fc673fb1e4e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 14:27:00 -0200 Subject: [PATCH 0860/1338] fix error "Cannot read property 'replace' of undefined" --- packages/rocketchat-oembed/client/oembedUrlWidget.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee index 3193a2df5a9..79e6127073a 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 -- GitLab From 1af1fe371ae4d1f24734b8493eb97019ea3c4103 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 14:45:58 -0200 Subject: [PATCH 0861/1338] New MAINTERRS --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 MAINTAINERS diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 00000000000..2f212b17aa1 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,10 @@ +engelgabriel +geekgonecrazy +gmsecrieru +graywolf336 +marceloschmidt +rcaferati +rodrigok +rwakida +sampaiodiego +Sing-Li -- GitLab From fb31a4d1a94a3bf32402f00548b3adb3fb76513d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 14:51:20 -0200 Subject: [PATCH 0862/1338] Configure LGTM approvals --- .lgtm | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .lgtm diff --git a/.lgtm b/.lgtm new file mode 100644 index 00000000000..3db37707374 --- /dev/null +++ b/.lgtm @@ -0,0 +1,2 @@ +approvals = 2 +pattern = "(?i)LGTM" -- GitLab From 45a85e5fe7fe10a3a29b838e956a940fdb66e7d9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 14:58:18 -0200 Subject: [PATCH 0863/1338] Room Info --- .../client/startup/tabBar.coffee | 14 +++++++------- .../client/views/channelSettings.html | 2 +- .../rocketchat-channel-settings/i18n/en.i18n.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-channel-settings/client/startup/tabBar.coffee b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee index 487be2c65a7..a78fd0ec324 100644 --- a/packages/rocketchat-channel-settings/client/startup/tabBar.coffee +++ b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee @@ -2,11 +2,11 @@ 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-info' - template: 'channelSettings' - order: 0 + RocketChat.TabBar.addButton + id: 'channel-settings' + i18nTitle: 'Room_Info' + icon: 'octicon octicon-info' + template: 'channelSettings' + order: 0 + , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-channel-settings' diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index 042abb27614..bba2381095c 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -1,7 +1,7 @@ <template name="channelSettings"> <div class="control"> <div class="header"> - <h2>{{_ "Room_Settings"}}</h2> + <h2>{{_ "Room_Info"}}</h2> </div> </div> <div class="channel-settings scrollable"> diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index f9b02ab82b5..44e8aa2ccb9 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -6,7 +6,7 @@ "Save": "Save", "Topic": "Topic", "Type": "Type", - "Room_Settings": "Room Settings", + "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_topic_changed_successfully": "Room topic changed successfully", -- GitLab From bb30308d66abc19d1188f01090d85595544925ed Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 14:45:58 -0200 Subject: [PATCH 0864/1338] New MAINTERRS --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 MAINTAINERS diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 00000000000..2f212b17aa1 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,10 @@ +engelgabriel +geekgonecrazy +gmsecrieru +graywolf336 +marceloschmidt +rcaferati +rodrigok +rwakida +sampaiodiego +Sing-Li -- GitLab From 23aeb614c47dd9ddb08683f392afb440e621bb6b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 14:51:20 -0200 Subject: [PATCH 0865/1338] Configure LGTM approvals --- .lgtm | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .lgtm diff --git a/.lgtm b/.lgtm new file mode 100644 index 00000000000..3db37707374 --- /dev/null +++ b/.lgtm @@ -0,0 +1,2 @@ +approvals = 2 +pattern = "(?i)LGTM" -- GitLab From b4d8f8e279eb2e1d7a0e2dce96fdfe6320ca842b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 16:57:01 -0200 Subject: [PATCH 0866/1338] Allow pass an array of roles to user in Acctouns.createUser --- server/lib/accounts.coffee | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index b9531f2ea1a..765e55ea8db 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -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.addUsersToRoles(_id, roles) - RocketChat.authz.addUsersToRoles(_id, roleName) RocketChat.callbacks.run 'afterCreateUser', options, user return _id -- GitLab From cf5a154c70125dd1339384f085ae11dc6dbf1fd8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 16:57:41 -0200 Subject: [PATCH 0867/1338] Pass role to user created via SAML integration --- packages/meteor-accounts-saml/saml_server.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/meteor-accounts-saml/saml_server.js b/packages/meteor-accounts-saml/saml_server.js index 030922b82b9..50f42a6c6d6 100644 --- a/packages/meteor-accounts-saml/saml_server.js +++ b/packages/meteor-accounts-saml/saml_server.js @@ -87,8 +87,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 +101,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 -- GitLab From cb609f02d892dd6b286afd0489039d397ce8dad6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 17:06:43 -0200 Subject: [PATCH 0868/1338] ui fix for livechat survey --- .../app/client/stylesheets/main.less | 85 +++++++------ .../app/client/views/survey.html | 119 +++++++++--------- 2 files changed, 105 insertions(+), 99 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 1335a011451..94064d9f020 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -397,6 +397,7 @@ input:focus { background-color: #FFF; border-left: 1px solid #E7E7E7; border-right: 1px solid #E7E7E7; + padding: 5px; input, button { display: block; @@ -425,54 +426,60 @@ 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; } } } diff --git a/packages/rocketchat-livechat/app/client/views/survey.html b/packages/rocketchat-livechat/app/client/views/survey.html index 07babef73d2..9c4a9b08f39 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> -- GitLab From 1df95850e0089d141cf3530c386728cf2b57e33d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 17:32:24 -0200 Subject: [PATCH 0869/1338] Improve error when closing window --- packages/meteor-accounts-saml/saml_server.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/meteor-accounts-saml/saml_server.js b/packages/meteor-accounts-saml/saml_server.js index 50f42a6c6d6..1dd3f227201 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 -- GitLab From bdf0e650c33b18c6c39a1581c11333588170c230 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 17:45:34 -0200 Subject: [PATCH 0870/1338] livechat manager fix and improvements --- .../rocketchat-livechat/app/i18n/en.i18n.json | 6 +- packages/rocketchat-livechat/client/route.js | 79 +++++++++++++------ .../client/stylesheets/livechat.less | 9 +++ packages/rocketchat-livechat/client/ui.js | 10 +-- .../client/views/app/livechatDashboard.html | 3 + .../client/views/app/livechatDepartments.html | 5 +- .../client/views/app/livechatDepartments.js | 7 +- .../views/app/livechatInstallation.html | 5 ++ .../client/views/app/livechatInstallation.js | 17 ++++ ...ivechatManager.html => livechatUsers.html} | 2 +- .../{livechatManager.js => livechatUsers.js} | 6 +- .../client/views/sideNav/livechatFlex.html | 13 ++- .../client/views/sideNav/livechatFlex.js | 10 ++- .../rocketchat-livechat/i18n/en.i18n.json | 5 +- packages/rocketchat-livechat/package.js | 12 ++- packages/rocketchat-ui/lib/accountBox.coffee | 18 +++-- .../views/app/pageContainer.html | 8 +- 17 files changed, 148 insertions(+), 67 deletions(-) create mode 100644 packages/rocketchat-livechat/client/views/app/livechatDashboard.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatInstallation.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatInstallation.js rename packages/rocketchat-livechat/client/views/app/{livechatManager.html => livechatUsers.html} (98%) rename packages/rocketchat-livechat/client/views/app/{livechatManager.js => livechatUsers.js} (96%) diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index 437cfd80f94..c921ee74e39 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -1,15 +1,17 @@ { "Additional_Feedback" : "Additional Feedback", - "Skip" : "Skip", + "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?", + "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", + "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", "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/client/route.js b/packages/rocketchat-livechat/client/route.js index 885ffecfd57..c8b6f69fac0 100644 --- a/packages/rocketchat-livechat/client/route.js +++ b/packages/rocketchat-livechat/client/route.js @@ -15,31 +15,66 @@ livechatManagerRoutes = FlowRouter.group({ name: 'livechat-manager' }); -livechatManagerRoutes.route('/departments', { - name: 'livechat-departments', +AccountBox.addRoute({ + name: 'livechat-dashboard', + path: '/dashboard', + sideNav: 'livechatFlex', + i18nPageTitle: 'Livechat_Dashboard', + pageTemplate: 'livechatDashboard' +}, livechatManagerRoutes); - action: function(params, queryParams) { - BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatDepartments', pageTitle: t('Departments') }); - } -}); +AccountBox.addRoute({ + name: 'livechat-users', + path: '/users', + sideNav: 'livechatFlex', + i18nPageTitle: 'Livechat_Users', + pageTemplate: 'livechatUsers' +}, livechatManagerRoutes); -livechatManagerRoutes.route('/department/:_id?', { - name: 'livechat-department', +AccountBox.addRoute({ + name: 'livechat-departments', + path: '/departments', + sideNav: 'livechatFlex', + i18nPageTitle: 'Departments', + pageTemplate: 'livechatDepartments' +}, livechatManagerRoutes); - 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-edit', + path: '/departments/:_id/edit', + sideNav: 'livechatFlex', + i18nPageTitle: 'Edit_Department', + pageTemplate: 'livechatDepartmentForm' +}, livechatManagerRoutes); + +AccountBox.addRoute({ + name: 'livechat-department-new', + path: '/departments/new', + sideNav: 'livechatFlex', + i18nPageTitle: 'New_Department', + pageTemplate: 'livechatDepartmentForm' +}, livechatManagerRoutes); -livechatManagerRoutes.route('/triggers', { +AccountBox.addRoute({ name: 'livechat-triggers', + path: '/triggers', + sideNav: 'livechatFlex', + i18nPageTitle: 'Triggers', + pageTemplate: 'livechatTriggers' +}, livechatManagerRoutes); - action: function(params, queryParams) { - BlazeLayout.render('main', { center: 'pageContainer', pageTemplate: 'livechatTriggers', pageTitle: t('Triggers') }); - } -}); +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 index d2cddae6c45..5db9d349047 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -17,3 +17,12 @@ width: auto !important; } } + +.livechat-code { + height: 200px; + background-color: #EFEFEF; + font-family: courier; + font-size: 12px; + width: 90%; + max-width: 750px; +} diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index ea863114c22..fd53097ea58 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -20,15 +20,7 @@ RocketChat.roomTypes.add('l', 5, { AccountBox.addItem({ name: 'Livechat', icon: 'icon-chat-empty', - href: 'livechat-manager', + href: 'livechat-dashboard', sideNav: 'livechatFlex', permissions: ['view-livechat-manager'], }); - -AccountBox.addRoute({ - name: 'livechat-manager', - path: '/livechat-manager', - sideNav: 'livechatFlex', - pageTitle: t('Livechat_Manager'), - pageTemplate: 'livechatManager' -}); 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 00000000000..ae5a2b7df4f --- /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/livechatDepartments.html b/packages/rocketchat-livechat/client/views/app/livechatDepartments.html index a334421e88e..2c92e7b07cc 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 274f1d1876e..eba12b82bc1 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js @@ -10,11 +10,6 @@ Template.livechatDepartments.helpers({ }); 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 +41,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 00000000000..0c6361dfaf6 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatInstallation.html @@ -0,0 +1,5 @@ +<template name="livechatInstallation"> + <p>{{{_ "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site"}}}</p> + + <textarea class="livechat-code clipboard" data-clipboard-target=".livechat-code">{{script}}</textarea> +</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 00000000000..cbedae2d3b0 --- /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/livechatManager.html b/packages/rocketchat-livechat/client/views/app/livechatUsers.html similarity index 98% rename from packages/rocketchat-livechat/client/views/app/livechatManager.html rename to packages/rocketchat-livechat/client/views/app/livechatUsers.html index fc90993a0c2..ebc48630388 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> diff --git a/packages/rocketchat-livechat/client/views/app/livechatManager.js b/packages/rocketchat-livechat/client/views/app/livechatUsers.js similarity index 96% rename from packages/rocketchat-livechat/client/views/app/livechatManager.js rename to packages/rocketchat-livechat/client/views/app/livechatUsers.js index 173cb633a50..5e29f332b93 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatManager.js +++ b/packages/rocketchat-livechat/client/views/app/livechatUsers.js @@ -6,7 +6,7 @@ Meteor.startup(function() { ManagerUsers = new Mongo.Collection('managerUsers'); }); -Template.livechatManager.helpers({ +Template.livechatUsers.helpers({ managers() { return ManagerUsers.find({}, { sort: { name: 1 } }); }, @@ -20,7 +20,7 @@ Template.livechatManager.helpers({ } }); -Template.livechatManager.events({ +Template.livechatUsers.events({ 'click .remove-manager' (e, instance) { e.preventDefault(); @@ -119,7 +119,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/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index b8c16f4b6e7..f5c4f888192 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -8,13 +8,12 @@ <div class="wrapper"> <ul> <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="{{pathFor 'livechat-triggers'}}" class="admin-link">{{_ "Triggers"}}</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'}}">{{_ "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 2fa2ed15adf..ff277d3d909 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js @@ -1,3 +1,11 @@ +Template.livechatFlex.helpers({ + active (route) { + if (FlowRouter.current().route.name === route) { + return 'active'; + } + } +}); + Template.livechatFlex.events({ 'mouseenter header' () { SideNav.overArrow() @@ -10,4 +18,4 @@ Template.livechatFlex.events({ 'click header' () { SideNav.closeFlex() } -}) +}); diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index d3b93f96ebb..a65a597911a 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -17,11 +17,13 @@ "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", "Message": "Message", @@ -37,8 +39,9 @@ "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", - "Triggers": "Triggers", + "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", "Visitor_page_URL": "Visitor page URL", diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 7166663a230..bcbda321713 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -40,14 +40,18 @@ Package.onUse(function(api) { api.addFiles('client/stylesheets/livechat.less', '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/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/sideNav/livechat.html', 'client'); api.addFiles('client/views/sideNav/livechat.js', 'client'); api.addFiles('client/views/sideNav/livechatFlex.html', 'client'); diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index 49c6a3c13d2..79e61faff4a 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -46,18 +46,24 @@ if not item.permissions? or RocketChat.authz.hasAllPermission item.permissions return true - addRoute = (newRoute) -> + addRoute = (newRoute, router = FlowRouter) -> # @TODO check for mandatory fields + routeConfig = + center: 'pageContainer' + pageTemplate: newRoute.pageTemplate - FlowRouter.route newRoute.path, + if newRoute.i18nPageTitle? + routeConfig.i18nPageTitle = newRoute.i18nPageTitle + + 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 + BlazeLayout.render 'main', routeConfig triggersEnter: [ -> if newRoute.sideNav? SideNav.setFlex newRoute.sideNav diff --git a/packages/rocketchat-ui/views/app/pageContainer.html b/packages/rocketchat-ui/views/app/pageContainer.html index 7c8af10e1c4..fdd8ce1e788 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"> -- GitLab From 53e93aa86c11b88d0b9fd29a1e925c8be0159ea0 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 15 Dec 2015 18:21:33 -0200 Subject: [PATCH 0871/1338] /kick command and button for kicking users from room --- .meteor/packages | 1 + .meteor/versions | 1 + i18n/en.i18n.json | 2 + .../server/startup.coffee | 3 ++ .../client.coffee | 11 +++++ .../i18n/en.i18n.json | 5 +++ .../rocketchat-slashcommands-kick/package.js | 37 +++++++++++++++++ .../server.coffee | 40 +++++++++++++++++++ .../flex-tab/tabs/userInfo.coffee | 16 ++++++++ .../flex-tab/tabs/userInfo.html | 5 ++- packages/rocketchat-ui/views/app/room.coffee | 2 +- server/methods/removeUserFromRoom.coffee | 26 +++++++----- 12 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 packages/rocketchat-slashcommands-kick/client.coffee create mode 100644 packages/rocketchat-slashcommands-kick/i18n/en.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/package.js create mode 100644 packages/rocketchat-slashcommands-kick/server.coffee diff --git a/.meteor/packages b/.meteor/packages index ad4d8c5a198..b56ad45f922 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -61,6 +61,7 @@ rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join rocketchat:slashcommands-leave +rocketchat:slashcommands-kick rocketchat:spotify rocketchat:statistics rocketchat:theme diff --git a/.meteor/versions b/.meteor/versions index 1a0b0849829..5ec2cf20d5f 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -150,6 +150,7 @@ rocketchat:message-star@0.0.1 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:spotify@0.0.1 rocketchat:statistics@0.0.1 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 85fb340d789..018e3f6aaef 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -368,6 +368,7 @@ "Remove" : "Remove", "Remove_Admin" : "Remove Admin", "Remove_custom_oauth" : "Remove custom oauth", + "Remove_from_room" : "Remove from room", "Reset_password" : "Reset password", "Restart" : "Restart", "Restart_the_server" : "Restart the server", @@ -494,6 +495,7 @@ "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_updated_successfully" : "User updated successfully", "Username" : "Username", diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 905a43410e6..d7043df9ba7 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -60,6 +60,9 @@ Meteor.startup -> { _id: 'delete-message', roles : ['admin', 'site-moderator', 'moderator']} + { _id: 'remove-user', + roles : ['admin', 'site-moderator', 'moderator']} + { _id: 'ban-user', roles : ['admin', 'site-moderator', 'moderator']} diff --git a/packages/rocketchat-slashcommands-kick/client.coffee b/packages/rocketchat-slashcommands-kick/client.coffee new file mode 100644 index 00000000000..acc40d33db0 --- /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/en.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json new file mode 100644 index 00000000000..5f448b30f89 --- /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" +} diff --git a/packages/rocketchat-slashcommands-kick/package.js b/packages/rocketchat-slashcommands-kick/package.js new file mode 100644 index 00000000000..a5ac2b24a42 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/package.js @@ -0,0 +1,37 @@ +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@0.0.1' + ]); + + 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@1.6.1', ['client', 'server']); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles, ['client', 'server']); +}); + +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 00000000000..112313be987 --- /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-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 341af443b10..00d323ef43c 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -33,6 +33,9 @@ Template.userInfo.helpers if @utcOffset? return Template.instance().now.get().utcOffset(@utcOffset).format('HH:mm') + canRemoveUser: -> + return RocketChat.authz.hasAllPermission('remove-user', Session.get('openedRoom')) + Template.userInfo.events 'click .pvt-msg': (e) -> Meteor.call 'createDirectMessage', Session.get('showUserInfo'), (error, result) -> @@ -72,6 +75,19 @@ Template.userInfo.events 'click .back': (e) -> Session.set('showUserInfo', null) + 'click .remove-user': (e, t) -> + e.preventDefault() + rid = Session.get('openedRoom') + room = ChatRoom.findOne rid + if RocketChat.authz.hasAllPermission('remove-user', rid) + Meteor.call 'removeUserFromRoom', { rid: rid, username: @user.username }, (err, result) -> + if err + return toastr.error(err.reason or err.message) + toastr.success TAPi18n.__ 'User_removed_from_room' + Session.set('showUserInfo', null) + else + toastr.error(TAPi18n.__ 'Not_allowed') + 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 844f5126c3e..85fa40e7a79 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html @@ -32,7 +32,10 @@ {{#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 pvt-msg'><span><i class='icon-chat'></i> {{_ "Conversation"}}</span></button> + {{/if}} + {{#if canRemoveUser}} + <button class="button remove-user red"><span>{{_ "Remove_from_room"}}</span></button> {{/if}} {{/if}} </nav> diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index b7c9ede601c..e382d70faa3 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -301,7 +301,7 @@ Template.room.events "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) diff --git a/server/methods/removeUserFromRoom.coffee b/server/methods/removeUserFromRoom.coffee index d600b6d991c..c77598660c0 100644 --- a/server/methods/removeUserFromRoom.coffee +++ b/server/methods/removeUserFromRoom.coffee @@ -1,25 +1,31 @@ Meteor.methods removeUserFromRoom: (data) -> fromId = Meteor.userId() - # console.log '[methods] removeUserFromRoom -> '.green, 'fromId:', fromId, 'data:', data + 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.removeUsersFromRoles(removedUser._id; 'moderator', 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 -- GitLab From 777dec5c5641690bcfab93b3a4fedd1b0b347b81 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 18:55:28 -0200 Subject: [PATCH 0872/1338] Show warning and allow admins to fix the Site URL --- i18n/en.i18n.json | 3 ++- .../rocketchat-lib/client/lib/settings.coffee | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 018e3f6aaef..586023bd54d 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -137,6 +137,7 @@ "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_channel_name" : "A Channel with name '%s' exists", "Duplicate_private_group_name" : "A Private Group with name '%s' exists", @@ -458,9 +459,9 @@ "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_field_is_required" : "The field %s is required.", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", + "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>!", "There_is_no_integrations" : "There is no integrations", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee index 16ce89cf20f..2e96a93d50e 100644 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ b/packages/rocketchat-lib/client/lib/settings.coffee @@ -43,6 +43,21 @@ Meteor.startup -> 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() -- GitLab From 26f68e9e8de3c3e3285931ba30b1c20bd75da133 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 19:21:53 -0200 Subject: [PATCH 0873/1338] livechat widget preview --- .../client/stylesheets/livechat.less | 331 ++++++++++++++++++ .../client/views/app/livechatAppearance.html | 40 +++ .../client/views/app/livechatAppearance.js | 19 + packages/rocketchat-livechat/package.js | 1 + 4 files changed, 391 insertions(+) create mode 100644 packages/rocketchat-livechat/client/views/app/livechatAppearance.html create mode 100644 packages/rocketchat-livechat/client/views/app/livechatAppearance.js diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index 5db9d349047..856c13e95b0 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -1,3 +1,29 @@ +.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; +} + .trigger-option, .trigger-value { float: left; display: inline-block; @@ -26,3 +52,308 @@ width: 90%; max-width: 750px; } + +.livechat-preview { + width: 340px; + height: 350px; + + border-bottom: 1px solid #CCC; + display: inline-block; + padding: 0 20px; + + @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; + } + + .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; + } + } +} 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 00000000000..99ceda12079 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html @@ -0,0 +1,40 @@ +<template name="livechatAppearance"> + <h1>{{_ "Preview"}}</h1> + + <div class="livechat-preview"> + {{#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> +</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 00000000000..057a36651b0 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js @@ -0,0 +1,19 @@ +Template.livechatAppearance.helpers({ + sampleData () { + return { + color: RocketChat.settings.get('Livechat_title_color'), + title: 'TITLE', + messages: [ + { + _id: Random.id(), + u: { + username: 'guest' + }, + time: moment(this.ts).format('HH:mm'), + date: moment(this.ts).format('LL'), + body: 'Testing' + } + ] + }; + } +}); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index bcbda321713..6225e9c90ea 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -41,6 +41,7 @@ Package.onUse(function(api) { // client views 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'); -- GitLab From f7178b433611a2666b206348e051baaf64c54f32 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 15 Dec 2015 19:22:04 -0200 Subject: [PATCH 0874/1338] livechat sidenav active item --- .../rocketchat-livechat/client/stylesheets/livechat.less | 6 ++++++ .../client/views/sideNav/livechatFlex.html | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index 856c13e95b0..b8fda75cc32 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -24,6 +24,12 @@ transform: @process; } +.flex-list { + .active { + background-color: rgba(255,255,255,0.075); + } +} + .trigger-option, .trigger-value { float: left; display: inline-block; diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index f5c4f888192..69a48249e3b 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -6,7 +6,7 @@ </header> <div class="content"> <div class="wrapper"> - <ul> + <ul class="flex-list"> <li> <a href="{{pathFor 'livechat-dashboard'}}" class="{{active 'livechat-dashboard'}}">{{_ "Dashboard"}}</a> <a href="{{pathFor 'livechat-users'}}" class="{{active 'livechat-users'}}">{{_ "User_management"}}</a> -- GitLab From 6d597114050a9504bf8b31cdaa6fbb704b3f1fe8 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Tue, 15 Dec 2015 17:08:40 -0500 Subject: [PATCH 0875/1338] Added "Room has been deleted" entry --- i18n/en.i18n.json | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 586023bd54d..16f1045b068 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -374,6 +374,7 @@ "Restart" : "Restart", "Restart_the_server" : "Restart the server", "Room" : "Room", + "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", -- GitLab From 163720c1c1bb2d02ba428620fe6bd83e34ffbc1c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 15 Dec 2015 20:22:57 -0200 Subject: [PATCH 0876/1338] Group message by time, default 5min --- i18n/en.i18n.json | 2 + .../server/startup/settings.coffee | 1 + .../message/message.coffee | 59 +++++++++++-------- .../message/message.html | 2 +- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 586023bd54d..0c59ffacfbc 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -268,6 +268,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", diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 93ffa8ae7bb..378f1271516 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -94,6 +94,7 @@ RocketChat.settings.add 'Message_KeepHistory', false, { type: 'boolean', group: 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.add 'Message_GroupingPeriod', 300, { type: 'int', group: 'Message', public: true, i18nDescription: 'Message_GroupingPeriodDescription' } RocketChat.settings.addGroup 'Meta' RocketChat.settings.add 'Meta_language', '', { type: 'string', group: 'Meta' } diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index cdd07703eae..7df5f15aea2 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -9,6 +9,8 @@ Template.message.helpers 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: -> @@ -113,29 +115,38 @@ 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?.username isnt lastNode.dataset.username - $(lastNode).removeClass('sequential') - - if lastNode.previousElementSibling?.dataset?.groupable is 'false' - $(lastNode).removeClass('sequential') - - if lastNode.nextElementSibling?.dataset?.date is lastNode.dataset.date - $(lastNode.nextElementSibling).removeClass('new-day') - 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) - if lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username - $(lastNode.nextElementSibling).removeClass('sequential') + if previousNode?.dataset? + previousDataset = previousNode.dataset - if not lastNode.nextElementSibling? - if lastNode.classList.contains('own') is true - view.parentView.parentView.parentView.parentView.parentView.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") - newMessage?.className = "new-message" + if previousDataset.date isnt currentDataset.date + $currentNode.addClass('new-day').removeClass('sequential') + + if previousDataset.groupable is 'false' or previousDataset.username isnt currentDataset.username or parseInt(currentDataset.timestamp) - parseInt(previousDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 + $currentNode.removeClass('sequential') + + if nextNode?.dataset? + nextDataset = nextNode.dataset + + if nextDataset.date isnt currentDataset.date + $nextNode.addClass('new-day').removeClass('sequential') + + if nextDataset.username isnt currentDataset.username or parseInt(nextDataset.timestamp) - parseInt(currentDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 + $nextNode.removeClass('sequential') + + if not nextNode? + templateInstance = view.parentView.parentView.parentView.parentView.parentView.templateInstance?() + + if currentNode.classList.contains('own') is true + templateInstance?.atBottom = true + else + 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 998d648209e..a2d6fd53f55 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 {{isSequential}} {{system}} {{t}} {{own}} {{isTemp}} {{chatops}}" data-username="{{u.username}}" data-groupable="{{isGroupable}}" 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"> -- GitLab From 431ba622dda3df3caf197a4a9eca2f9ddc48a73d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 16 Dec 2015 11:28:37 -0200 Subject: [PATCH 0877/1338] added copy to clipboard button on installation --- .../client/stylesheets/livechat.less | 15 +++++++++++---- .../client/views/app/livechatInstallation.html | 5 ++++- packages/rocketchat-livechat/i18n/en.i18n.json | 1 + 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index b8fda75cc32..3d466396247 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -51,12 +51,19 @@ } .livechat-code { - height: 200px; - background-color: #EFEFEF; - font-family: courier; - font-size: 12px; 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; + } } .livechat-preview { diff --git a/packages/rocketchat-livechat/client/views/app/livechatInstallation.html b/packages/rocketchat-livechat/client/views/app/livechatInstallation.html index 0c6361dfaf6..6d912bb3cca 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatInstallation.html +++ b/packages/rocketchat-livechat/client/views/app/livechatInstallation.html @@ -1,5 +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> - <textarea class="livechat-code clipboard" data-clipboard-target=".livechat-code">{{script}}</textarea> + <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/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index a65a597911a..58117943151 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -5,6 +5,7 @@ "Agent_added" : "Agent added", "Agent_removed" : "Agent removed", "Back" : "Back", + "Copy_to_clipboard": "Copy to clipboard", "Dashboard" : "Dashboard", "Department_not_found" : "Department not found", "Department_removed" : "Department removed", -- GitLab From 692ebbf42f2bb0fac34fa0485111e160dadd9255 Mon Sep 17 00:00:00 2001 From: bertrand jung <bertrand.jung@epitech.eu> Date: Mon, 14 Dec 2015 16:44:30 +0100 Subject: [PATCH 0878/1338] Add Scalingo Deploy button --- README.md | 12 ++++++++++++ scalingo.json | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 scalingo.json diff --git a/README.md b/README.md index 6f5ff72f957..49f57ceeb00 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ The Ultimate Open Source WebChat Platform * [Desktop apps](#desktop-apps) * [Deployment](#deployment) * [Heroku](#heroku) + * [Scalingo](#scalingo) * [Sandstorm.io](#sandstormio) * [Sloppy.io](#sloppyio) * [Docker](#docker) @@ -68,6 +69,17 @@ Branch **develop** (Newer but unstable): [](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) +## Scalingo +Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com) + +Branch **master** (Latest stable version): + +[](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#master) + +Branch **develop** (Newer but unstable): + +[](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#develop) + ## Sandstorm.io [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) diff --git a/scalingo.json b/scalingo.json new file mode 100644 index 00000000000..92ee06f04f6 --- /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"] +} -- GitLab From e10bebe72171c1a1c8f31aec1da9e5a90b037f2c Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 16 Dec 2015 12:08:55 -0200 Subject: [PATCH 0879/1338] livechat appearance preview --- .../client/stylesheets/livechat.less | 526 +++++++++--------- .../client/views/app/livechatAppearance.html | 69 +-- .../client/views/app/livechatAppearance.js | 68 ++- .../rocketchat-livechat/i18n/en.i18n.json | 2 + 4 files changed, 383 insertions(+), 282 deletions(-) diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index 3d466396247..c147598884f 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -66,307 +66,335 @@ } } +.preview-mode { + width: auto; + margin-bottom: 1em; +} + .livechat-preview { width: 340px; height: 350px; border-bottom: 1px solid #CCC; - display: inline-block; - padding: 0 20px; + position: relative; - @header-min-height: 30px; - @footer-min-height: 42px; - @link-font-color: #008CE3; - @primary-font-color: #444444; - @secondary-font-color: #7f7f7f; - @info-font-color: #AAAAAA; + .preview-wrapper { + position: absolute; + width: 100%; + padding: 0 20px; + height: 350px; + bottom: 0; - .livechat-room { - display: flex; - flex-direction: column; - height: 100%; + @header-min-height: 30px; + @footer-min-height: 42px; + @link-font-color: #008CE3; + @primary-font-color: #444444; + @secondary-font-color: #7f7f7f; + @info-font-color: #AAAAAA; - .title { - flex: 1 0 @header-min-height; + .livechat-room { + display: flex; + flex-direction: column; + height: 100%; - line-height: @header-min-height; + .title { + flex: 1 0 @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; - } + line-height: @header-min-height; - .toolbar { - display: inline-block; - float: right; - padding-right: 5px; + 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%; + .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; + 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 { + 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; + .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; } - &:after { - content: " "; - display: block; - position: absolute; - top: -20px; - left: 0; - width: 100%; - border-top: 1px solid #ddd; + &.new-day { + margin-top: 60px; } - } - .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; + &.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; + } } - } - .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 { + .edit-message { display: none; + cursor: pointer; } - .thumb { + &.own:hover:not(.system) .edit-message { + display: inline-block; + } + .delete-message { display: none; + cursor: pointer; } - .info { + &.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; - text-align: right; - left: -20px; - width: 55px; - .time { + 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; } - .edited { - display: inline-block; + .thumb { + display: none; } - .edit-message { - float: left; - margin-left: 1px; + .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; + } } - .delete-message { - float: left; + &:hover { + .time { + display: inline-block; + } + .edited { + display: none; + } } } - &:hover { - .time { - display: inline-block; + &.system { + .body { + color: @info-font-color; + font-style: italic; + text-transform: lowercase; + em { + font-weight: 600; + } } - .edited { - display: none; + } + .avatar-initials { + line-height: 40px; + } + a { + color: @link-font-color; + font-weight: 400; + &:hover { + color: darken(@link-font-color, 10%); + text-decoration: underline; } } - } - &.system { .body { - color: @info-font-color; - font-style: italic; - text-transform: lowercase; - em { - font-weight: 600; - } + opacity: 1; + .transition(opacity 1s linear); } - } - .avatar-initials { - line-height: 40px; - } - a { - color: @link-font-color; - font-weight: 400; - &:hover { - color: darken(@link-font-color, 10%); - text-decoration: underline; + &.temp .body { + opacity: .5; + } + &.msg-error .body { + text-decoration: line-through; } - } - .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; + .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%)); + .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; + .error { + bottom: 40px; + position: fixed; + width: 100%; + background-color: #F7D799; + padding: 5px; + z-index: 8; - .transition(transform 0.2s ease-out); - .transform(translateY(100%)); + .transition(transform 0.2s ease-out); + .transform(translateY(100%)); - &.show { - .transform(translateY(0)); + &.show { + .transform(translateY(0)); + } } } - } - .footer { - flex: 1 0 @footer-min-height; + .footer { + flex: 1 0 @footer-min-height; - z-index: 10; + z-index: 10; - background-color: #FCFCFC; - border-top: 1px solid #E7E7E7; - border-left: 1px solid #E7E7E7; - border-right: 1px solid #E7E7E7; + 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; + .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; + } } - .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; + } } } } diff --git a/packages/rocketchat-livechat/client/views/app/livechatAppearance.html b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html index 99ceda12079..bb7c79f8226 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatAppearance.html +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html @@ -1,40 +1,47 @@ <template name="livechatAppearance"> <h1>{{_ "Preview"}}</h1> - <div class="livechat-preview"> - {{#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> + <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> - <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 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> - <div class="footer"> - <div class="input-wrapper"> - <textarea class="input-message" placeholder="Type your message"></textarea> + <div class="footer"> + <div class="input-wrapper"> + <textarea class="input-message" placeholder="Type your message"></textarea> + </div> </div> </div> - </div> - {{/with}} + {{/with}} + </div> </div> </template> diff --git a/packages/rocketchat-livechat/client/views/app/livechatAppearance.js b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js index 057a36651b0..ebf00aa531c 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatAppearance.js +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js @@ -1,8 +1,11 @@ Template.livechatAppearance.helpers({ + previewState () { + return Template.instance().previewState.get(); + }, sampleData () { return { color: RocketChat.settings.get('Livechat_title_color'), - title: 'TITLE', + title: RocketChat.settings.get('Livechat_title'), messages: [ { _id: Random.id(), @@ -11,9 +14,70 @@ Template.livechatAppearance.helpers({ }, time: moment(this.ts).format('HH:mm'), date: moment(this.ts).format('LL'), - body: 'Testing' + body: 'Hello', + sequential: null + }, + { + _id: Random.id(), + u: { + username: 'rocketchat-agent' + }, + time: moment(this.ts).format('HH:mm'), + 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('HH:mm'), + 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('HH:mm'), + 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('HH:mm'), + 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('HH:mm'), + date: moment(this.ts).format('LL'), + body: 'You\'re welcome.', + sequential: null } ] }; } }); + +Template.livechatAppearance.onCreated(function() { + this.previewState = new ReactiveVar('opened'); +}); + +Template.livechatAppearance.events({ + 'change .preview-mode' (e, instance) { + instance.previewState.set(e.currentTarget.value); + } +}) diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 58117943151..a9a11219987 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -5,6 +5,7 @@ "Agent_added" : "Agent added", "Agent_removed" : "Agent removed", "Back" : "Back", + "Closed": "Closed", "Copy_to_clipboard": "Copy to clipboard", "Dashboard" : "Dashboard", "Department_not_found" : "Department not found", @@ -32,6 +33,7 @@ "Name_of_agent": "Name of agent", "New_Department" : "New Department", "Num_Agents" : "# Agents", + "Opened": "Opened", "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", -- GitLab From 0c3525778005ba4a72b4f92de6184d2710ba6649 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:53:19 -0200 Subject: [PATCH 0880/1338] Mover rocketchat.info into rocketchat:lib --- packages/rocketchat-lib/package.js | 4 ++++ rocketchat.info => packages/rocketchat-lib/rocketchat.info | 0 2 files changed, 4 insertions(+) rename rocketchat.info => packages/rocketchat-lib/rocketchat.info (100%) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 897bd0bab52..5f0e3487c78 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -22,6 +22,7 @@ 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 @@ -90,6 +91,9 @@ Package.onUse(function(api) { api.addFiles('client/MessageAction.coffee', 'client'); api.addFiles('client/MessageTypes.coffee', 'client'); + // VERSION + api.addFiles('rocketchat.info'); + // TAPi18n api.use('templating', 'client'); var _ = Npm.require('underscore'); diff --git a/rocketchat.info b/packages/rocketchat-lib/rocketchat.info similarity index 100% rename from rocketchat.info rename to packages/rocketchat-lib/rocketchat.info -- GitLab From 1ab02580ccb9a184982c3f4e47367bba04de4c14 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:54:04 -0200 Subject: [PATCH 0881/1338] Create method in settings to update options of one setting --- .../rocketchat-lib/server/functions/settings.coffee | 13 +++++++++++++ .../rocketchat-lib/server/models/Settings.coffee | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 34f829a6d9d..24a5c2d6648 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -91,6 +91,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 diff --git a/packages/rocketchat-lib/server/models/Settings.coffee b/packages/rocketchat-lib/server/models/Settings.coffee index 282c9262b6b..c16d51c8316 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 = -- GitLab From 7736e172b5747420e9ffdbca24b5fb1d4f51fcd9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:54:55 -0200 Subject: [PATCH 0882/1338] Change the rate limit of method setAvatarFromService from 1m to 5s --- server/methods/setAvatarFromService.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee index 0df26725a6b..b3d0be939d7 100644 --- a/server/methods/setAvatarFromService.coffee +++ b/server/methods/setAvatarFromService.coffee @@ -62,4 +62,4 @@ DDPRateLimiter.addRule type: 'method' name: 'setAvatarFromService' userId: -> return true -, 1, 60000 +, 1, 5000 -- GitLab From 12402e80dec349de99b29176d148a5dc1db1a323 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:55:42 -0200 Subject: [PATCH 0883/1338] Add an option to show warning in a setting --- i18n/en.i18n.json | 1 + packages/rocketchat-theme/assets/stylesheets/base.less | 8 ++++++++ packages/rocketchat-ui-admin/admin/admin.html | 3 +++ 3 files changed, 12 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e761fe82684..cbe1bda761c 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -463,6 +463,7 @@ "Submit" : "Submit", "Success" : "Success", "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 in your server.", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "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>!", "There_is_no_integrations" : "There is no integrations", diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index dfae174ff75..5c1811a02ba 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1813,6 +1813,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; + } } } } diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 492d539321b..d7753213e5d 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -101,6 +101,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}} -- GitLab From f61ed69d8fffc2bbd6046fa799d52e8b54bef1af Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:55:51 -0200 Subject: [PATCH 0884/1338] Fix a PT translation --- i18n/pt.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 8c93ccf86e1..a325142ef25 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -130,7 +130,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", -- GitLab From e6c9ee5c365072e25d746d01731eb21a95a92636 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:56:48 -0200 Subject: [PATCH 0885/1338] Detect if system is runing GM or IM, add info to RocketChat.Info and update setting to alert user --- packages/rocketchat-file/file.server.coffee | 38 +++++++++++++++++++++ packages/rocketchat-file/package.js | 8 +++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 00aa21319db..a47489fac24 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -4,12 +4,50 @@ 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'} + + +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 + RocketChatFile.bufferToStream = (buffer) -> bufferStream = new stream.PassThrough() diff --git a/packages/rocketchat-file/package.js b/packages/rocketchat-file/package.js index 7ed4a9d40ff..4efed24a52b 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({ -- GitLab From 2a8bac74cfcc6ff9336f1aa9ad5f3787bc5a43a0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:57:25 -0200 Subject: [PATCH 0886/1338] Set avatar resize enabled by default --- packages/rocketchat-lib/server/startup/settings.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 378f1271516..a901efc018f 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -16,7 +16,7 @@ RocketChat.settings.add 'Accounts_PasswordReset', true, { type: 'boolean', group 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_AvatarResize', true, { 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 } -- GitLab From 6f057e7b1b0f2d5dd30bbbc916df24453fd675b2 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 13:58:21 -0200 Subject: [PATCH 0887/1338] Improve avatar resize function to use GM detection and allow change setting on runtime --- server/startup/avatar.coffee | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server/startup/avatar.coffee b/server/startup/avatar.coffee index 45e9f590c99..4951142cb4f 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" -- GitLab From 59e86784a29ec1124edae8994e35f3c56b556ad1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 15:18:18 -0200 Subject: [PATCH 0888/1338] Detect file dimensions in uploads and set height of image in attachments --- lib/fileUpload.coffee | 21 +++++++++++++++++++ .../client/messageAttachment.coffee | 3 +++ .../client/messageAttachment.html | 4 ++-- .../client/oembedImageWidget.html | 2 +- .../client/oembedVideoWidget.html | 2 +- .../assets/stylesheets/base.less | 2 +- packages/rocketchat-ui/lib/fileUpload.coffee | 1 + 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index e927cc82cb2..f95df9507cd 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -46,6 +46,27 @@ 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? diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee index b0b01c8a6c5..a224b9a872f 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.coffee +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -12,3 +12,6 @@ Template.messageAttachment.helpers return false return true + + getImageHeight: (height) -> + return height or 200 diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 433029711e3..a4abddf4045 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -50,7 +50,7 @@ {{#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}}"> + <img src="{{fixCordova image_url}}" height="{{getImageHeight image_dimensions.height}}"> </div> </a> {{else}} @@ -73,7 +73,7 @@ {{#if video_url}} <div class="attachment-video"> - <video controls class="inline-video"> + <video controls class="inline-video" height="300"> <source src="{{fixCordova video_url}}" type="{{video_type}}"> Your browser does not support the video element. </video> diff --git a/packages/rocketchat-oembed/client/oembedImageWidget.html b/packages/rocketchat-oembed/client/oembedImageWidget.html index 8d277d96502..d17ed9ff03a 100644 --- a/packages/rocketchat-oembed/client/oembedImageWidget.html +++ b/packages/rocketchat-oembed/client/oembedImageWidget.html @@ -4,7 +4,7 @@ <div> <a href="{{url}}" class="swipebox" target="_blank"> <div class="inline-image" style="background-image: url({{url}});"> - <img src="{{url}}"> + <img src="{{url}}" height="200"> </div> </a> </div> diff --git a/packages/rocketchat-oembed/client/oembedVideoWidget.html b/packages/rocketchat-oembed/client/oembedVideoWidget.html index 5377b5bf837..6cb86b947ff 100644 --- a/packages/rocketchat-oembed/client/oembedVideoWidget.html +++ b/packages/rocketchat-oembed/client/oembedVideoWidget.html @@ -3,7 +3,7 @@ <blockquote> <div><a href="{{url}}">{{parsedUrl.host}}</a></div> <div>{{title}}</div> - <video controls class="inline-video"> + <video controls class="inline-video" height="300"> <source src="{{url}}" type="{{contentType}}"> Your browser does not support the video element. </video> diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 5c1811a02ba..b2ad807f329 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4207,7 +4207,7 @@ a.github-fork { } .inline-video { - max-height: 200px; + max-height: 300px; } .attention-message { diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index b60a417f77f..52560afe2fb 100644 --- a/packages/rocketchat-ui/lib/fileUpload.coffee +++ b/packages/rocketchat-ui/lib/fileUpload.coffee @@ -96,6 +96,7 @@ readAsArrayBuffer = (file, callback) -> 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 -- GitLab From 39ee0924a693e145d72cdf91dc691fc386b60b9b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 16 Dec 2015 15:25:43 -0200 Subject: [PATCH 0889/1338] appearance settings --- .../client/stylesheets/livechat.less | 13 +++ packages/rocketchat-livechat/client/ui.js | 2 +- .../client/views/app/livechatAppearance.html | 95 +++++++++++-------- .../client/views/app/livechatAppearance.js | 56 +++++++++++ .../client/views/app/livechatUsers.html | 4 +- .../client/views/sideNav/livechatFlex.html | 2 +- .../client/views/sideNav/livechatFlex.js | 1 + .../rocketchat-livechat/i18n/en.i18n.json | 1 + 8 files changed, 133 insertions(+), 41 deletions(-) diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index c147598884f..dc12fb153ec 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -71,9 +71,22 @@ 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; diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index fd53097ea58..f23b438a912 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -20,7 +20,7 @@ RocketChat.roomTypes.add('l', 5, { AccountBox.addItem({ name: 'Livechat', icon: 'icon-chat-empty', - href: 'livechat-dashboard', + href: 'livechat-users', sideNav: 'livechatFlex', permissions: ['view-livechat-manager'], }); diff --git a/packages/rocketchat-livechat/client/views/app/livechatAppearance.html b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html index bb7c79f8226..d6b03dd458d 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatAppearance.html +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.html @@ -1,47 +1,68 @@ <template name="livechatAppearance"> - <h1>{{_ "Preview"}}</h1> + <div class="livechat-settings-div"> + <h2>{{_ "Settings"}}</h2> - <select class="preview-mode"> - <option value="opened">{{_ "Opened"}}</option> - <option value="closed">{{_ "Closed"}}</option> - </select> + <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 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> - <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 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> - <div class="footer"> - <div class="input-wrapper"> - <textarea class="input-message" placeholder="Type your message"></textarea> + <div class="footer"> + <div class="input-wrapper"> + <textarea class="input-message" placeholder="Type your message"></textarea> + </div> </div> </div> - </div> - {{/with}} + {{/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 index ebf00aa531c..a8415b6be65 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatAppearance.js +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js @@ -2,6 +2,12 @@ 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'), @@ -74,10 +80,60 @@ Template.livechatAppearance.helpers({ 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/livechatUsers.html b/packages/rocketchat-livechat/client/views/app/livechatUsers.html index ebc48630388..9bdb3f99dbd 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatUsers.html +++ b/packages/rocketchat-livechat/client/views/app/livechatUsers.html @@ -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/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index 69a48249e3b..a859f5385a5 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -8,7 +8,7 @@ <div class="wrapper"> <ul class="flex-list"> <li> - <a href="{{pathFor 'livechat-dashboard'}}" class="{{active 'livechat-dashboard'}}">{{_ "Dashboard"}}</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'}}">{{_ "Departments"}}</a> <a href="{{pathFor 'livechat-triggers'}}" class="{{active 'livechat-triggers'}}">{{_ "Triggers"}}</a> diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js index ff277d3d909..4e2578cea84 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js @@ -1,5 +1,6 @@ Template.livechatFlex.helpers({ active (route) { + FlowRouter.watchPathChange(); if (FlowRouter.current().route.name === route) { return 'active'; } diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index a9a11219987..d64d472d807 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -42,6 +42,7 @@ "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", -- GitLab From 84eb2e0dff2817e969bf9fca08bb10c69c82b29a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 16 Dec 2015 15:45:17 -0200 Subject: [PATCH 0890/1338] fix deleting a message not deleting it's attachments --- packages/rocketchat-lib/server/models/Messages.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index b7449cddf47..8607765ce45 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -148,6 +148,7 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base msg: '' t: 'rm' urls: [] + attachments: [] editedAt: new Date() editedBy: _id: Meteor.userId() -- GitLab From 7fbc50e8d5ff7fb04186e4b3900f8abccd8f478b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 16 Dec 2015 16:11:45 -0200 Subject: [PATCH 0891/1338] Mute/Unmute commands and button --- .meteor/packages | 1 + .meteor/versions | 1 + i18n/en.i18n.json | 7 ++++ .../server/startup.coffee | 3 ++ .../rocketchat-lib/client/MessageTypes.coffee | 14 +++++++ .../server/methods/sendMessage.coffee | 11 +++++ .../server/models/Messages.coffee | 8 ++++ .../server/models/Subscriptions.coffee | 21 ++++++++++ .../client/mute.coffee | 3 ++ .../client/unmute.coffee | 3 ++ .../i18n/en.i18n.json | 6 +++ .../rocketchat-slashcommands-mute/package.js | 39 ++++++++++++++++++ .../server/mute.coffee | 40 +++++++++++++++++++ .../server/unmute.coffee | 40 +++++++++++++++++++ .../flex-tab/tabs/userInfo.coffee | 29 ++++++++++++++ .../flex-tab/tabs/userInfo.html | 7 ++++ .../message/popup/messagePopupConfig.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 2 +- server/methods/muteUserInRoom.coffee | 26 ++++++++++++ server/methods/unmuteUserInRoom.coffee | 26 ++++++++++++ server/publications/subscription.coffee | 1 + 21 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-slashcommands-mute/client/mute.coffee create mode 100644 packages/rocketchat-slashcommands-mute/client/unmute.coffee create mode 100644 packages/rocketchat-slashcommands-mute/i18n/en.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/package.js create mode 100644 packages/rocketchat-slashcommands-mute/server/mute.coffee create mode 100644 packages/rocketchat-slashcommands-mute/server/unmute.coffee create mode 100644 server/methods/muteUserInRoom.coffee create mode 100644 server/methods/unmuteUserInRoom.coffee diff --git a/.meteor/packages b/.meteor/packages index b56ad45f922..a97cca862ec 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -62,6 +62,7 @@ rocketchat:slashcommands-invite rocketchat:slashcommands-join rocketchat:slashcommands-leave rocketchat:slashcommands-kick +rocketchat:slashcommands-mute rocketchat:spotify rocketchat:statistics rocketchat:theme diff --git a/.meteor/versions b/.meteor/versions index 5ec2cf20d5f..65d76ada12a 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -152,6 +152,7 @@ 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/i18n/en.i18n.json b/i18n/en.i18n.json index e761fe82684..92ba3902f8e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -292,6 +292,8 @@ "More_unreads" : "More unreads", "Msgs" : "Msgs", "multi" : "multi", + "Mute_user" : "Mute user", + "Unmute_user" : "Unmute user", "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", @@ -496,9 +498,13 @@ "User_left_female" : "Has left the channel.", "User_left_male" : "Has left the channel.", "User_logged_out" : "User is logged out", + "User_muted_in_room" : "User muted in room", + "User_unmuted_in_room" : "User unmuted 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_muted_by" : "User <em>__user_muted__</em> muted by <em>__user_by__</em>.", + "User_unmuted_by" : "User <em>__user_unmuted__</em> unmuted by <em>__user_by__</em>.", "User_removed_from_room" : "The user has been removed from the room", "User_Settings" : "User Settings", "User_updated_successfully" : "User updated successfully", @@ -526,6 +532,7 @@ "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_can_use_an_emoji_as_avatar" : "You can use an emoji as 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.", diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index d7043df9ba7..1fc3643b4d2 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -63,6 +63,9 @@ Meteor.startup -> { _id: 'remove-user', roles : ['admin', 'site-moderator', 'moderator']} + { _id: 'mute-user', + roles : ['admin', 'site-moderator', 'moderator']} + { _id: 'ban-user', roles : ['admin', 'site-moderator', 'moderator']} diff --git a/packages/rocketchat-lib/client/MessageTypes.coffee b/packages/rocketchat-lib/client/MessageTypes.coffee index 3e374f4d7ca..3c6f3cea63a 100644 --- a/packages/rocketchat-lib/client/MessageTypes.coffee +++ b/packages/rocketchat-lib/client/MessageTypes.coffee @@ -68,3 +68,17 @@ 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 } diff --git a/packages/rocketchat-lib/server/methods/sendMessage.coffee b/packages/rocketchat-lib/server/methods/sendMessage.coffee index 527470eeb9e..6e55243fb45 100644 --- a/packages/rocketchat-lib/server/methods/sendMessage.coffee +++ b/packages/rocketchat-lib/server/methods/sendMessage.coffee @@ -15,6 +15,17 @@ Meteor.methods if not room return false + subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId room._id, user._id + console.log subscription + if not subscription or subscription.mute is true + 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/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index b7449cddf47..c1ef1ba654c 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -272,6 +272,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base 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 + # REMOVE removeById: (_id) -> query = diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 20910f4e03d..5fb46c37e1f 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -210,6 +210,27 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @update query, update, { multi: true } + muteUserByRoomIdAndUserId: (roomId, userId) -> + query = + rid: roomId + "u._id": userId + + update = + $set: + mute: true + + return @update query, update + + unmuteUserByRoomIdAndUserId: (roomId, userId) -> + query = + rid: roomId + "u._id": userId + + update = + $unset: + mute: true + + return @update query, update # INSERT createWithRoomAndUser: (room, user, extraData) -> diff --git a/packages/rocketchat-slashcommands-mute/client/mute.coffee b/packages/rocketchat-slashcommands-mute/client/mute.coffee new file mode 100644 index 00000000000..d812e0cc179 --- /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 00000000000..4d59ccb7de4 --- /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/en.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json new file mode 100644 index 00000000000..f20cd657298 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json @@ -0,0 +1,6 @@ +{ + "Username_doesnt_exist" : "The username `#%s` doesn't exist.", + "Username_is_not_in_this_room" : "The user `#%s` is not in this room.", + "Mute_someone_in_room" : "Mute someone in the room", + "Unmute_someone_in_room" : "Unmute someone in the room" +} diff --git a/packages/rocketchat-slashcommands-mute/package.js b/packages/rocketchat-slashcommands-mute/package.js new file mode 100644 index 00000000000..adc64c1d6dd --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/package.js @@ -0,0 +1,39 @@ +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@0.0.1' + ]); + + 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@1.6.1', ['client', 'server']); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles, ['client', 'server']); +}); + +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 00000000000..d8bc3d3bc51 --- /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 00000000000..e3b6ee25d82 --- /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-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 00d323ef43c..caeb439bdce 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -36,6 +36,12 @@ Template.userInfo.helpers canRemoveUser: -> return RocketChat.authz.hasAllPermission('remove-user', Session.get('openedRoom')) + canMuteUser: -> + return RocketChat.authz.hasAllPermission('mute-user', Session.get('openedRoom')) + + userMuted: -> + return ChatSubscription.findOne({rid: Session.get('openedRoom')})?.mute is true + Template.userInfo.events 'click .pvt-msg': (e) -> Meteor.call 'createDirectMessage', Session.get('showUserInfo'), (error, result) -> @@ -88,6 +94,29 @@ Template.userInfo.events else toastr.error(TAPi18n.__ 'Not_allowed') + 'click .mute-user': (e, t) -> + e.preventDefault() + rid = Session.get('openedRoom') + room = ChatRoom.findOne rid + if RocketChat.authz.hasAllPermission('mute-user', rid) + Meteor.call 'muteUserInRoom', { rid: rid, username: @user.username }, (err, result) -> + if err + return toastr.error(err.reason or err.message) + toastr.success TAPi18n.__ 'User_muted_in_room' + else + toastr.error(TAPi18n.__ 'Not_allowed') + + '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') 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 85fa40e7a79..bb18b652ccd 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html @@ -37,6 +37,13 @@ {{#if canRemoveUser}} <button class="button remove-user red"><span>{{_ "Remove_from_room"}}</span></button> {{/if}} + {{#if canMuteUser}} + {{#if userMuted}} + <button class="button unmute-user primary"><span>{{_ "Unmute_user"}}</span></button> + {{else}} + <button class="button mute-user red"><span>{{_ "Mute_user"}}</span></button> + {{/if}} + {{/if}} {{/if}} </nav> {{/if}} diff --git a/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee index e8a085eebea..022ff911f78 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/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index e382d70faa3..8dafd2e346c 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -540,7 +540,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 diff --git a/server/methods/muteUserInRoom.coffee b/server/methods/muteUserInRoom.coffee new file mode 100644 index 00000000000..7179738b3e9 --- /dev/null +++ b/server/methods/muteUserInRoom.coffee @@ -0,0 +1,26 @@ +Meteor.methods + muteUserInRoom: (data) -> + fromId = Meteor.userId() + console.log '[methods] muteUserInRoom -> '.green, 'fromId:', fromId, 'data:', data + + check(data, Match.ObjectIncluding({ rid: String, username: String })) + + unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) + throw new Meteor.Error 'not-allowed', 'Not allowed' + + room = RocketChat.models.Rooms.findOneById data.rid + + if data.username not in (room?.usernames or []) + throw new Meteor.Error 'not-in-room', 'User is not in this room' + + mutedUser = RocketChat.models.Users.findOneByUsername data.username + + RocketChat.models.Subscriptions.muteUserByRoomIdAndUserId data.rid, mutedUser._id + + 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/unmuteUserInRoom.coffee b/server/methods/unmuteUserInRoom.coffee new file mode 100644 index 00000000000..adfbaec666e --- /dev/null +++ b/server/methods/unmuteUserInRoom.coffee @@ -0,0 +1,26 @@ +Meteor.methods + unmuteUserInRoom: (data) -> + fromId = Meteor.userId() + console.log '[methods] unmuteUserInRoom -> '.green, 'fromId:', fromId, 'data:', data + + check(data, Match.ObjectIncluding({ rid: String, username: String })) + + unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) + throw new Meteor.Error 'not-allowed', 'Not allowed' + + room = RocketChat.models.Rooms.findOneById data.rid + + if data.username not in (room?.usernames or []) + throw new Meteor.Error 'not-in-room', 'User is not in this room' + + unmutedUser = RocketChat.models.Users.findOneByUsername data.username + + RocketChat.models.Subscriptions.unmuteUserByRoomIdAndUserId data.rid, unmutedUser._id + + 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/publications/subscription.coffee b/server/publications/subscription.coffee index f188e99522e..4cc8244a9e3 100644 --- a/server/publications/subscription.coffee +++ b/server/publications/subscription.coffee @@ -15,3 +15,4 @@ Meteor.publish 'subscription', -> open: 1 alert: 1 unread: 1 + mute: 1 -- GitLab From 880537353e408a4c8b87c59fb9934802c9181920 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 16 Dec 2015 17:12:01 -0200 Subject: [PATCH 0892/1338] fix guest permissions --- .../app/client/lib/chatMessages.coffee | 2 +- .../app/client/views/register.coffee | 2 +- packages/rocketchat-livechat/package.js | 13 ++-- packages/rocketchat-livechat/permissions.js | 3 + .../server/methods/registerGuest.js | 66 +++++++++++++++++++ .../sendMessageLivechat.js} | 56 ---------------- 6 files changed, 78 insertions(+), 64 deletions(-) create mode 100644 packages/rocketchat-livechat/server/methods/registerGuest.js rename packages/rocketchat-livechat/server/{methods.js => methods/sendMessageLivechat.js} (52%) diff --git a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee index 2cee37e8e78..d7c529a1c1a 100644 --- a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee +++ b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee @@ -97,7 +97,7 @@ class @ChatMessages 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/views/register.coffee b/packages/rocketchat-livechat/app/client/views/register.coffee index f815eab9013..72246a88cee 100644 --- a/packages/rocketchat-livechat/app/client/views/register.coffee +++ b/packages/rocketchat-livechat/app/client/views/register.coffee @@ -27,7 +27,7 @@ Template.register.events if error? return instance.showError error.reason - Meteor.loginWithPassword result.user, result.pass, (error) -> + Meteor.loginWithToken result.token, (error) -> if error return instance.showError error.reason diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 6225e9c90ea..b692038ae8d 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -28,7 +28,6 @@ Package.onUse(function(api) { 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'); @@ -66,14 +65,16 @@ Package.onUse(function(api) { // methods api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); - api.addFiles('server/methods/saveDepartment.js', 'server'); - api.addFiles('server/methods/saveSurveyFeedback.js', 'server'); - api.addFiles('server/methods/searchAgent.js', 'server'); + api.addFiles('server/methods/registerGuest.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/saveTrigger.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/sendMessageLivechat.js', 'server'); // models api.addFiles('server/models/Users.js', 'server'); diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index 98bf89e1be0..ea678f9abe6 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -6,6 +6,9 @@ Meteor.startup(() => { if (roles.indexOf('livechat-manager') === -1) { Roles.createRole('livechat-manager'); } + if (roles.indexOf('livechat-guest') === -1) { + Roles.createRole('livechat-guest'); + } if (RocketChat.models && RocketChat.models.Permissions) { RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager', 'admin']); RocketChat.models.Permissions.createOrUpdate('view-livechat-manager', ['livechat-manager', 'admin']); diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js new file mode 100644 index 00000000000..41d03d498aa --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -0,0 +1,66 @@ +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'); + } + 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, + globalRoles: 'livechat-guest' + }; + 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 + }); + return { + userId: userId, + token: stampedToken.token + }; + } +}); diff --git a/packages/rocketchat-livechat/server/methods.js b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js similarity index 52% rename from packages/rocketchat-livechat/server/methods.js rename to packages/rocketchat-livechat/server/methods/sendMessageLivechat.js index 8b7b0dd70e7..75ea02c52d7 100644 --- a/packages/rocketchat-livechat/server/methods.js +++ b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js @@ -1,60 +1,4 @@ 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); -- GitLab From a0e3558139dcd9152784ef21efc8361ebf38ee5d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 16 Dec 2015 17:27:27 -0200 Subject: [PATCH 0893/1338] Fix mute by setting mute on room instead of subscription --- .../server/methods/sendMessage.coffee | 4 +--- .../rocketchat-lib/server/models/Rooms.coffee | 20 +++++++++++++++++ .../server/models/Subscriptions.coffee | 22 ------------------- .../flex-tab/tabs/userInfo.coffee | 5 ++++- server/methods/canAccessRoom.coffee | 4 ++-- server/methods/muteUserInRoom.coffee | 11 +++++++--- server/methods/unmuteUserInRoom.coffee | 11 +++++++--- server/publications/adminRooms.coffee | 1 + server/publications/subscription.coffee | 1 - server/startup/cron.coffee | 5 +++-- server/startup/roomPublishes.coffee | 2 ++ 11 files changed, 49 insertions(+), 37 deletions(-) diff --git a/packages/rocketchat-lib/server/methods/sendMessage.coffee b/packages/rocketchat-lib/server/methods/sendMessage.coffee index 6e55243fb45..354c0e07b8c 100644 --- a/packages/rocketchat-lib/server/methods/sendMessage.coffee +++ b/packages/rocketchat-lib/server/methods/sendMessage.coffee @@ -15,9 +15,7 @@ Meteor.methods if not room return false - subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId room._id, user._id - console.log subscription - if not subscription or subscription.mute is true + if user.username in (room.muted or []) RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { _id: Random.id() rid: room._id diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index e1588bc5484..45c8ae03a19 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -310,6 +310,26 @@ RocketChat.models.Rooms = new class extends RocketChat.models._Base 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/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 5fb46c37e1f..209464bd1bb 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -210,28 +210,6 @@ RocketChat.models.Subscriptions = new class extends RocketChat.models._Base return @update query, update, { multi: true } - muteUserByRoomIdAndUserId: (roomId, userId) -> - query = - rid: roomId - "u._id": userId - - update = - $set: - mute: true - - return @update query, update - - unmuteUserByRoomIdAndUserId: (roomId, userId) -> - query = - rid: roomId - "u._id": userId - - update = - $unset: - mute: true - - return @update query, update - # INSERT createWithRoomAndUser: (room, user, extraData) -> subscription = diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index caeb439bdce..6c5672ee526 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -40,7 +40,10 @@ Template.userInfo.helpers return RocketChat.authz.hasAllPermission('mute-user', Session.get('openedRoom')) userMuted: -> - return ChatSubscription.findOne({rid: Session.get('openedRoom')})?.mute is true + room = ChatRoom.findOne(Session.get('openedRoom')) + if _.isArray(room?.muted) and room.muted.indexOf(Session.get('showUserInfo')) isnt -1 + return true + return false Template.userInfo.events 'click .pvt-msg': (e) -> diff --git a/server/methods/canAccessRoom.coffee b/server/methods/canAccessRoom.coffee index 2d5cd6ff330..514bc431b4d 100644 --- a/server/methods/canAccessRoom.coffee +++ b/server/methods/canAccessRoom.coffee @@ -10,7 +10,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 +21,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/muteUserInRoom.coffee b/server/methods/muteUserInRoom.coffee index 7179738b3e9..16554dcecfb 100644 --- a/server/methods/muteUserInRoom.coffee +++ b/server/methods/muteUserInRoom.coffee @@ -6,16 +6,21 @@ Meteor.methods check(data, Match.ObjectIncluding({ rid: String, username: String })) unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) - throw new Meteor.Error 'not-allowed', 'Not allowed' + 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', 'User is not in this room' + throw new Meteor.Error 'not-in-room', '[methods] muteUserInRoom -> User is not in this room' mutedUser = RocketChat.models.Users.findOneByUsername data.username - RocketChat.models.Subscriptions.muteUserByRoomIdAndUserId data.rid, mutedUser._id + RocketChat.models.Rooms.muteUsernameByRoomId data.rid, mutedUser.username fromUser = RocketChat.models.Users.findOneById fromId RocketChat.models.Messages.createUserMutedWithRoomIdAndUser data.rid, mutedUser, diff --git a/server/methods/unmuteUserInRoom.coffee b/server/methods/unmuteUserInRoom.coffee index adfbaec666e..f441d56de7a 100644 --- a/server/methods/unmuteUserInRoom.coffee +++ b/server/methods/unmuteUserInRoom.coffee @@ -6,16 +6,21 @@ Meteor.methods check(data, Match.ObjectIncluding({ rid: String, username: String })) unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) - throw new Meteor.Error 'not-allowed', 'Not allowed' + 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', 'User is not in this room' + throw new Meteor.Error 'not-in-room', '[methods] unmuteUserInRoom -> User is not in this room' unmutedUser = RocketChat.models.Users.findOneByUsername data.username - RocketChat.models.Subscriptions.unmuteUserByRoomIdAndUserId data.rid, unmutedUser._id + RocketChat.models.Rooms.unmuteUsernameByRoomId data.rid, unmutedUser.username fromUser = RocketChat.models.Users.findOneById fromId RocketChat.models.Messages.createUserUnmutedWithRoomIdAndUser data.rid, unmutedUser, diff --git a/server/publications/adminRooms.coffee b/server/publications/adminRooms.coffee index bceec2d8c51..afbd22e2460 100644 --- a/server/publications/adminRooms.coffee +++ b/server/publications/adminRooms.coffee @@ -15,6 +15,7 @@ Meteor.publish 'adminRooms', (filter, types, limit) -> cl: 1 u: 1 usernames: 1 + muted: 1 limit: limit sort: name: 1 diff --git a/server/publications/subscription.coffee b/server/publications/subscription.coffee index 4cc8244a9e3..f188e99522e 100644 --- a/server/publications/subscription.coffee +++ b/server/publications/subscription.coffee @@ -15,4 +15,3 @@ Meteor.publish 'subscription', -> open: 1 alert: 1 unread: 1 - mute: 1 diff --git a/server/startup/cron.coffee b/server/startup/cron.coffee index be643bcf42e..923f30dffeb 100644 --- a/server/startup/cron.coffee +++ b/server/startup/cron.coffee @@ -13,11 +13,12 @@ Meteor.startup -> job: -> statistics = RocketChat.statistics.save() statistics.host = Meteor.absoluteUrl() + # statistics.environment = 'tutum' if process.env.TUTUM_REDIS_HOST and Meteor.absoluteUrl() is *.rocket.chat unless RocketChat.settings.get 'Statistics_opt_out' console.log 'Sending statistics data to Rocket.Chat' - HTTP.post 'https://rocket.chat/stats', + HTTP.post 'https://rocket.chat/stats', data: statistics - + return SyncedCron.start() diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index 409131cc9b4..5517939f8b7 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -7,6 +7,7 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + muted: 1 return RocketChat.models.Rooms.findByTypeAndName 'c', identifier, options RocketChat.roomTypes.setPublish 'p', (identifier) -> @@ -17,6 +18,7 @@ Meteor.startup -> cl: 1 u: 1 usernames: 1 + muted: 1 user = RocketChat.models.Users.findOneById this.userId, fields: username: 1 return RocketChat.models.Rooms.findByTypeAndNameContainigUsername 'p', identifier, user.username, options -- GitLab From 2bdbfc5970a3d76820f2dd095e49d26711da251c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 16 Dec 2015 17:39:09 -0200 Subject: [PATCH 0894/1338] Updated muted usernames on setUsername --- .../rocketchat-lib/server/functions/setUsername.coffee | 1 + packages/rocketchat-lib/server/models/Rooms.coffee | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index da23f4970b5..cee48c9cad4 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/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee index 45c8ae03a19..63ab8422469 100644 --- a/packages/rocketchat-lib/server/models/Rooms.coffee +++ b/packages/rocketchat-lib/server/models/Rooms.coffee @@ -278,6 +278,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 -- GitLab From 3caab013df25d00d6b397ff474efd25c2e22cb32 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 16 Dec 2015 17:52:32 -0200 Subject: [PATCH 0895/1338] Undo wrongly commited file --- server/startup/cron.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/server/startup/cron.coffee b/server/startup/cron.coffee index 923f30dffeb..3cee5e37fe4 100644 --- a/server/startup/cron.coffee +++ b/server/startup/cron.coffee @@ -13,7 +13,6 @@ Meteor.startup -> job: -> statistics = RocketChat.statistics.save() statistics.host = Meteor.absoluteUrl() - # statistics.environment = 'tutum' if process.env.TUTUM_REDIS_HOST and Meteor.absoluteUrl() is *.rocket.chat unless RocketChat.settings.get 'Statistics_opt_out' console.log 'Sending statistics data to Rocket.Chat' HTTP.post 'https://rocket.chat/stats', -- GitLab From 48e7598fa04fa6f98051627bcf3040ddfa8e6fdf Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Wed, 16 Dec 2015 16:02:11 -0500 Subject: [PATCH 0896/1338] Missing language entries --- i18n/en.i18n.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index cbe1bda761c..7d443f1cc61 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -185,8 +185,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", @@ -462,6 +464,7 @@ "strike" : "strike", "Submit" : "Submit", "Success" : "Success", + "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 in your server.", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", -- GitLab From 2ed257fcc206a8bedce0c5e89d97be2278045761 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 16 Dec 2015 19:33:35 -0200 Subject: [PATCH 0897/1338] Add option to disable setting based in other setting and another improvements --- .../server/functions/settings.coffee | 3 + .../server/startup/settings.coffee | 40 ++++---- .../assets/stylesheets/base.less | 6 ++ .../rocketchat-ui-admin/admin/admin.coffee | 94 ++++++++++++++----- packages/rocketchat-ui-admin/admin/admin.html | 25 +++-- 5 files changed, 117 insertions(+), 51 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 24a5c2d6648..b8055d7793d 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,7 @@ RocketChat.settings.add = (_id, value, options = {}) -> options.valueSource = 'packageValue' options.ts = new Date options.hidden = false + options.sorter ?= RocketChat.settings._sorter++ if process?.env?[_id]? value = process.env[_id] diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index a901efc018f..445bd659196 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -14,32 +14,38 @@ RocketChat.settings.add 'Accounts_Registration_AuthenticationServices_Enabled', 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', true, { type: 'boolean', group: 'Accounts', section: 'Avatar' } -RocketChat.settings.add 'Accounts_AvatarSize', 200, { type: 'int', group: 'Accounts', section: 'Avatar' } +RocketChat.settings.add 'Accounts_AvatarSize', 200, { type: 'int', group: 'Accounts', section: 'Avatar', enableQuery: {_id: 'Accounts_AvatarResize', value: true} } +RocketChat.settings.add 'Accounts_AvatarStoreType', 'GridFS', { type: 'select', group: 'Accounts', section: 'Avatar', values: [ { key: 'GridFS', i18nLabel: 'GridFS' }, { key: 'FileSystem', i18nLabel: 'FileSystem' } ] } +RocketChat.settings.add 'Accounts_AvatarStorePath', '', { type: 'string', group: 'Accounts', section: 'Avatar', enableQuery: {_id: 'Accounts_AvatarStoreType', value: 'FileSystem'} } 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_Facebook_id', '', { type: 'string', group: 'Accounts', section: 'Facebook', enableQuery: {_id: 'Accounts_OAuth_Facebook', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Facebook_secret', '', { type: 'string', group: 'Accounts', section: 'Facebook', enableQuery: {_id: 'Accounts_OAuth_Facebook', value: true} } + 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_Google_id', '', { type: 'string', group: 'Accounts', section: 'Google', enableQuery: {_id: 'Accounts_OAuth_Google', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Google_secret', '', { type: 'string', group: 'Accounts', section: 'Google', enableQuery: {_id: 'Accounts_OAuth_Google', value: true} } + 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_Github_id', '', { type: 'string', group: 'Accounts', section: 'Github', enableQuery: {_id: 'Accounts_OAuth_Github', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Github_secret', '', { type: 'string', group: 'Accounts', section: 'Github', enableQuery: {_id: 'Accounts_OAuth_Github', value: true} } + 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_Gitlab_id', '', { type: 'string', group: 'Accounts', section: 'Gitlab', enableQuery: {_id: 'Accounts_OAuth_Gitlab', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Gitlab_secret', '', { type: 'string', group: 'Accounts', section: 'Gitlab', enableQuery: {_id: 'Accounts_OAuth_Gitlab', value: true} } + 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_Linkedin_id', '', { type: 'string', group: 'Accounts', section: 'Linkedin', enableQuery: {_id: 'Accounts_OAuth_Linkedin', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Linkedin_secret', '', { type: 'string', group: 'Accounts', section: 'Linkedin', enableQuery: {_id: 'Accounts_OAuth_Linkedin', value: true} } + 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_Meteor_id', '', { type: 'string', group: 'Accounts', section: 'Meteor', enableQuery: {_id: 'Accounts_OAuth_Meteor', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Meteor_secret', '', { type: 'string', group: 'Accounts', section: 'Meteor', enableQuery: {_id: 'Accounts_OAuth_Meteor', value: true} } + 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_OAuth_Twitter_id', '', { type: 'string', group: 'Accounts', section: 'Twitter', enableQuery: {_id: 'Accounts_OAuth_Twitter', value: true} } +RocketChat.settings.add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', group: 'Accounts', section: 'Twitter', enableQuery: {_id: 'Accounts_OAuth_Twitter', value: true} } 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 } diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index b2ad807f329..993de0a3c33 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1797,6 +1797,12 @@ a.github-fork { padding-top: 0; } + &.setting-changed { + > label { + color: #627CFF + } + } + input { color: #444; } diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 4e215e45f5e..b31dff886fb 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -1,12 +1,23 @@ +@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 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, sort: 1, i18nLabel: 1}}).fetch() + sections = {} for setting in settings sections[setting.section or ''] ?= [] @@ -20,6 +31,30 @@ Template.admin.helpers return sectionsArray + isDisabled: -> + if not @enableQuery? + return {} + + return if TempSettings.findOne(@enableQuery)? 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 + flexOpened: -> return 'opened' if RocketChat.TabBar.isFlexOpen() arrowPosition: -> @@ -44,28 +79,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' diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index d7753213e5d..264ac8d168f 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -42,28 +42,28 @@ {{/if}} {{/if}} {{#each settings}} - <div class="input-line double-col"> + <div class="input-line double-col {{#if changed}}setting-changed{{/if}}"> <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}} @@ -71,11 +71,11 @@ {{/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'}} @@ -115,6 +115,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}} @@ -123,7 +129,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}} -- GitLab From f9fe178182a40a2c39ebfe20b782d7c6c45ef79a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 17 Dec 2015 09:23:07 -0200 Subject: [PATCH 0898/1338] Fix some ldap problems and set reconnect to true --- packages/rocketchat-ldap/ldap_server.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index d12d9346940..94b42d285a6 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -64,7 +64,8 @@ LDAP.prototype.ldapCheck = function(options) { // Create ldap client var fullUrl = self.options.url + ':' + self.options.port; var client = self.ldapjs.createClient({ - url: fullUrl + url: fullUrl, + reconnect: true }); var bindSync = Meteor.wrapAsync(client.bind.bind(client)); @@ -142,7 +143,7 @@ LDAP.prototype.ldapCheck = function(options) { delete opts.password; } catch(e) { console.log('LDAP: Error', e); - ldapAsyncFut.return({ + return ldapAsyncFut.return({ error: e }); } @@ -153,7 +154,7 @@ 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 }); } -- GitLab From b572ef8ce71911ec687552f6c196df91cf1f630b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 17 Dec 2015 09:33:14 -0200 Subject: [PATCH 0899/1338] Fix sort of settings --- packages/rocketchat-ui-admin/admin/admin.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index b31dff886fb..df3c6352c6c 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -16,7 +16,7 @@ Template.admin.helpers sections: -> group = FlowRouter.getParam('group') group ?= TempSettings.findOne({ type: 'group' })?._id - settings = TempSettings.find({ group: group }, {sort: {section: 1, sort: 1, i18nLabel: 1}}).fetch() + settings = TempSettings.find({ group: group }, {sort: {section: 1, sorter: 1, i18nLabel: 1}}).fetch() sections = {} for setting in settings -- GitLab From aa5f230b6d6e5a10506ad52ec57e84ffc284c2aa Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 17 Dec 2015 09:33:39 -0200 Subject: [PATCH 0900/1338] Disable ldap settings when ldap is disabled --- packages/rocketchat-ldap/config_server.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index fd4f3f5f133..17bb045fbe3 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -3,12 +3,12 @@ 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.add 'LDAP_Url', 'ldap://', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } + RocketChat.settings.add 'LDAP_Port', '389', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } + RocketChat.settings.add 'LDAP_DN', '', { type: 'string' , group: 'LDAP', public: true, enableQuery: {_id: 'LDAP_Enable', value: true} } + RocketChat.settings.add 'LDAP_Bind_Search', '', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } + RocketChat.settings.add 'LDAP_Sync_User_Data', false, { type: 'boolean' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } + RocketChat.settings.add 'LDAP_Sync_User_Data_FieldMap', '{"cn":"name", "mail":"email"}', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } timer = undefined -- GitLab From 67cd71de0642f38b29c34c8a347dda349d21e422 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 17 Dec 2015 10:13:08 -0200 Subject: [PATCH 0901/1338] Allow cascade methods in settings creation --- packages/rocketchat-ldap/config_server.coffee | 16 +- .../server/functions/settings.coffee | 23 +- .../server/startup/settings.coffee | 284 ++++++++++-------- 3 files changed, 182 insertions(+), 141 deletions(-) diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index 17bb045fbe3..1964aaf48e3 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -1,14 +1,14 @@ 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', enableQuery: {_id: 'LDAP_Enable', value: true} } - RocketChat.settings.add 'LDAP_Port', '389', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } - RocketChat.settings.add 'LDAP_DN', '', { type: 'string' , group: 'LDAP', public: true, enableQuery: {_id: 'LDAP_Enable', value: true} } - RocketChat.settings.add 'LDAP_Bind_Search', '', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } - RocketChat.settings.add 'LDAP_Sync_User_Data', false, { type: 'boolean' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } - RocketChat.settings.add 'LDAP_Sync_User_Data_FieldMap', '{"cn":"name", "mail":"email"}', { type: 'string' , group: 'LDAP', enableQuery: {_id: 'LDAP_Enable', value: true} } + RocketChat.settings.addGroup 'LDAP', -> + @add 'LDAP_Enable', false, { type: 'boolean', public: true } + @add 'LDAP_Url', 'ldap://', { type: 'string' , enableQuery: {_id: 'LDAP_Enable', value: true} } + @add 'LDAP_Port', '389', { type: 'string' , enableQuery: {_id: 'LDAP_Enable', value: true} } + @add 'LDAP_DN', '', { type: 'string' , public: true, enableQuery: {_id: 'LDAP_Enable', value: true} } + @add 'LDAP_Bind_Search', '', { type: 'string' , enableQuery: {_id: 'LDAP_Enable', value: true} } + @add 'LDAP_Sync_User_Data', false, { type: 'boolean' , enableQuery: {_id: 'LDAP_Enable', value: true} } + @add 'LDAP_Sync_User_Data_FieldMap', '{"cn":"name", "mail":"email"}', { type: 'string', enableQuery: {_id: 'LDAP_Enable', value: true} } timer = undefined diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index b8055d7793d..7cb1a13ab79 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -46,12 +46,16 @@ RocketChat.settings.add = (_id, value, options = {}) -> # 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 @@ -61,12 +65,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 diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 445bd659196..0a4e79e09c2 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -2,137 +2,159 @@ 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_AvatarResize', true, { type: 'boolean', group: 'Accounts', section: 'Avatar' } -RocketChat.settings.add 'Accounts_AvatarSize', 200, { type: 'int', group: 'Accounts', section: 'Avatar', enableQuery: {_id: 'Accounts_AvatarResize', value: true} } -RocketChat.settings.add 'Accounts_AvatarStoreType', 'GridFS', { type: 'select', group: 'Accounts', section: 'Avatar', values: [ { key: 'GridFS', i18nLabel: 'GridFS' }, { key: 'FileSystem', i18nLabel: 'FileSystem' } ] } -RocketChat.settings.add 'Accounts_AvatarStorePath', '', { type: 'string', group: 'Accounts', section: 'Avatar', enableQuery: {_id: 'Accounts_AvatarStoreType', value: 'FileSystem'} } - -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', enableQuery: {_id: 'Accounts_OAuth_Facebook', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Facebook_secret', '', { type: 'string', group: 'Accounts', section: 'Facebook', enableQuery: {_id: 'Accounts_OAuth_Facebook', value: true} } - -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', enableQuery: {_id: 'Accounts_OAuth_Google', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Google_secret', '', { type: 'string', group: 'Accounts', section: 'Google', enableQuery: {_id: 'Accounts_OAuth_Google', value: true} } - -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', enableQuery: {_id: 'Accounts_OAuth_Github', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Github_secret', '', { type: 'string', group: 'Accounts', section: 'Github', enableQuery: {_id: 'Accounts_OAuth_Github', value: true} } - -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', enableQuery: {_id: 'Accounts_OAuth_Gitlab', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Gitlab_secret', '', { type: 'string', group: 'Accounts', section: 'Gitlab', enableQuery: {_id: 'Accounts_OAuth_Gitlab', value: true} } - -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', enableQuery: {_id: 'Accounts_OAuth_Linkedin', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Linkedin_secret', '', { type: 'string', group: 'Accounts', section: 'Linkedin', enableQuery: {_id: 'Accounts_OAuth_Linkedin', value: true} } - -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', enableQuery: {_id: 'Accounts_OAuth_Meteor', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Meteor_secret', '', { type: 'string', group: 'Accounts', section: 'Meteor', enableQuery: {_id: 'Accounts_OAuth_Meteor', value: true} } - -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', enableQuery: {_id: 'Accounts_OAuth_Twitter', value: true} } -RocketChat.settings.add 'Accounts_OAuth_Twitter_secret', '', { type: 'string', group: 'Accounts', section: 'Twitter', enableQuery: {_id: 'Accounts_OAuth_Twitter', value: true} } - -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.add 'FileUpload_ProtectFiles', true, { type: 'boolean', group: 'FileUpload', public: true, i18nDescription: 'FileUpload_ProtectFilesDescription' } - - -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.add 'Message_GroupingPeriod', 300, { type: 'int', group: 'Message', public: true, i18nDescription: 'Message_GroupingPeriodDescription' } - -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 } + + @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 'Allow_Invalid_SelfSigned_Certs', false, { type: 'boolean' } + @add 'Disable_Favorite_Rooms', false, { type: 'boolean' } + @add 'CDN_PREFIX', '', { type: 'string' } + @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' } + @add 'SMTP_Port', '', { type: 'string' } + @add 'SMTP_Username', '', { type: 'string' } + @add 'SMTP_Password', '', { type: 'string' } + @add 'From_Email', '', { type: 'string', placeholder: 'email@domain' } + + @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 } -- GitLab From afcf1679da0bcfa76a32dab3dc8e264718b4859a Mon Sep 17 00:00:00 2001 From: bertrand jung <bertrand.jung@epitech.eu> Date: Mon, 14 Dec 2015 16:44:30 +0100 Subject: [PATCH 0902/1338] Add Scalingo Deploy button --- README.md | 12 ++++++++++++ scalingo.json | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 scalingo.json diff --git a/README.md b/README.md index 6f5ff72f957..49f57ceeb00 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ The Ultimate Open Source WebChat Platform * [Desktop apps](#desktop-apps) * [Deployment](#deployment) * [Heroku](#heroku) + * [Scalingo](#scalingo) * [Sandstorm.io](#sandstormio) * [Sloppy.io](#sloppyio) * [Docker](#docker) @@ -68,6 +69,17 @@ Branch **develop** (Newer but unstable): [](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) +## Scalingo +Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com) + +Branch **master** (Latest stable version): + +[](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#master) + +Branch **develop** (Newer but unstable): + +[](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#develop) + ## Sandstorm.io [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) diff --git a/scalingo.json b/scalingo.json new file mode 100644 index 00000000000..92ee06f04f6 --- /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"] +} -- GitLab From 513034bd773ec1959e741b8c9ea7c3f9aeada2f5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 17 Dec 2015 15:10:37 -0200 Subject: [PATCH 0903/1338] Fix crash when connection reset from LDAP server --- packages/rocketchat-ldap/ldap_server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 94b42d285a6..1e6589c3d55 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -65,7 +65,11 @@ LDAP.prototype.ldapCheck = function(options) { var fullUrl = self.options.url + ':' + self.options.port; var client = self.ldapjs.createClient({ url: fullUrl, - reconnect: true + reconnect: false + }); + + client.on('error', function() { + console.log('Client Error:', arguments); }); var bindSync = Meteor.wrapAsync(client.bind.bind(client)); -- GitLab From 42796904cbc0f8d26d2cd4c7c832fca56544bfab Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 17 Dec 2015 15:43:53 -0200 Subject: [PATCH 0904/1338] Closes #1691; Fiz a grouping error in messages from history --- .../rocketchat-ui-message/message/message.coffee | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 7df5f15aea2..30c4d256e65 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -128,18 +128,29 @@ Template.message.onViewRendered = (context) -> if previousDataset.date isnt currentDataset.date $currentNode.addClass('new-day').removeClass('sequential') + else + $currentNode.removeClass('new-day') - if previousDataset.groupable is 'false' or previousDataset.username isnt currentDataset.username or parseInt(currentDataset.timestamp) - parseInt(previousDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 + if previousDataset.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 + $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.username isnt currentDataset.username or parseInt(nextDataset.timestamp) - parseInt(currentDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 $nextNode.removeClass('sequential') + else + $nextNode.addClass('sequential') if not nextNode? templateInstance = view.parentView.parentView.parentView.parentView.parentView.templateInstance?() -- GitLab From de58145d9f353162a61107955b8cd06dac8d7bab Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 17 Dec 2015 16:35:48 -0200 Subject: [PATCH 0905/1338] update aldeed:simple-schema to 1.5.1 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index 65d76ada12a..cad976bc063 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -7,7 +7,7 @@ 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.1 arunoda:streams@0.1.17 autoupdate@1.2.4 babel-compiler@5.8.24_1 -- GitLab From 626a100bb208230923a012cd19707300c19c40c9 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 17 Dec 2015 17:06:19 -0200 Subject: [PATCH 0906/1338] removed kadira package --- .meteor/packages | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index a97cca862ec..94ad617a195 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -100,7 +100,7 @@ kadira:blaze-layout kadira:flow-router kenton:accounts-sandstorm kevohagan:sweetalert -meteorhacks:kadira +#meteorhacks:kadira mizzao:autocomplete mizzao:timesync momentjs:moment diff --git a/build.sh b/build.sh index f60192ddad7..5e36ade4e4c 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat rocketchat:hubot +meteor add rocketchat:livechat 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 -- GitLab From ec5df83b69d6e788175b9a053fcde595e5608673 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Thu, 17 Dec 2015 18:12:30 -0500 Subject: [PATCH 0907/1338] Update Ansible link to beginners friendly deployment guide --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49f57ceeb00..63a6ac2e7af 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ 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) ## Ubuntu VPS Follow these [deployment instructions](https://github.com/RocketChat/Rocket.Chat/wiki/Deploy-Rocket.Chat-without-docker) -- GitLab From aced02185c5596270cd45ed9cbb2c2aa334553e4 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Thu, 17 Dec 2015 20:19:28 -0500 Subject: [PATCH 0908/1338] Adjust layout direction based on user's language This fixes the issue https://github.com/RocketChat/Rocket.Chat/issues/1623 So basically if a user login from a new machine and the language loaded from their profile is different from the local one then set the correct language and if it is an RTL language set the RTL class immediately. --- client/startup/startup.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee index c42fb6200e0..1d590b55508 100644 --- a/client/startup/startup.coffee +++ b/client/startup/startup.coffee @@ -39,8 +39,11 @@ Meteor.startup -> if Meteor.user()?.language? c.stop() - localStorage.setItem("userLanguage", Meteor.user().language) - setLanguage Meteor.user().language + if localStorage.getItem('userLanguage') isnt Meteor.user().language + localStorage.setItem("userLanguage", Meteor.user().language) + setLanguage Meteor.user().language + if isRtl localStorage.getItem "userLanguage" + $('html').addClass "rtl" userLanguage = localStorage.getItem("userLanguage") userLanguage ?= defaultUserLanguage() -- GitLab From 2463252093f5ec79b2f2436ebb5e6beced23da36 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 18 Dec 2015 01:01:34 -0200 Subject: [PATCH 0909/1338] change order of loading variables --- packages/rocketchat-integrations/server/api/api.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 93ad5732930..f7a226df089 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -71,9 +71,9 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, error: 'invalid-channel-type' message = - avatar: integration.avatar or @bodyParams.avatar or @bodyParams.icon_url - emoji: integration.emoji or @bodyParams.emoji or @bodyParams.icon_emoji - alias: integration.alias or @bodyParams.alias or @bodyParams.username + avatar: @bodyParams.icon_url or @bodyParams.avatar or integration.avatar + emoji: @bodyParams.icon_emoji or @bodyParams.emoji or integration.emoji + alias: @bodyParams.username or @bodyParams.alias or integration.alias msg: @bodyParams.text or '' attachments: @bodyParams.attachments parseUrls: false -- GitLab From 1fa24b2117ac3f9315236b54222c8eac765f5e99 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 18 Dec 2015 01:28:08 -0200 Subject: [PATCH 0910/1338] setting only one, either emoji or avatar, but never both --- .../rocketchat-integrations/server/api/api.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index f7a226df089..4a80598e041 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -71,8 +71,6 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, error: 'invalid-channel-type' message = - avatar: @bodyParams.icon_url or @bodyParams.avatar or integration.avatar - emoji: @bodyParams.icon_emoji or @bodyParams.emoji or integration.emoji alias: @bodyParams.username or @bodyParams.alias or integration.alias msg: @bodyParams.text or '' attachments: @bodyParams.attachments @@ -81,6 +79,15 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, i: integration._id groupable: false + if @bodyParams.icon_url? or @bodyParams.avatar? + message.avatar = @bodyParams.icon_url or @bodyParams.avatar + else if @bodyParams.icon_emoji? or @bodyParams.emoji? + message.emoji = @bodyParams.icon_emoji or @bodyParams.emoji + else if integration.avatar? + message.avatar = integration.avatar + else if integration.emoji? + message.emoji = integration.emoji + RocketChat.sendMessage user, message, room, {} return {} = -- GitLab From 4fcccd4dd62451329450c0d44894a219ac15509f Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 18 Dec 2015 02:05:19 -0200 Subject: [PATCH 0911/1338] Added msg property as an alternative for text --- packages/rocketchat-integrations/server/api/api.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 4a80598e041..b0eaeaeb3c4 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -72,7 +72,7 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, message = alias: @bodyParams.username or @bodyParams.alias or integration.alias - msg: @bodyParams.text or '' + msg: @bodyParams.text or @bodyParams.msg or '' attachments: @bodyParams.attachments parseUrls: false bot: -- GitLab From 9f5ccd9e1ca8db2a664734731c4adcdae97f127a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 18 Dec 2015 09:53:54 -0200 Subject: [PATCH 0912/1338] Accept property *msg* as text in attachments --- packages/rocketchat-integrations/server/api/api.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index b0eaeaeb3c4..2700dd9d553 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -88,6 +88,12 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, else if integration.emoji? message.emoji = integration.emoji + if _.isArray message.attachments + for attachment in message.attachments + if attachment.msg + attachment.text = attachment.msg + delete attachment.msg + RocketChat.sendMessage user, message, room, {} return {} = -- GitLab From 540ca6b8af3f97c9e648d9e95fe2e73f0a0e8352 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 18 Dec 2015 09:54:22 -0200 Subject: [PATCH 0913/1338] Add field to display the integration token --- .../client/views/integrationsIncoming.coffee | 2 ++ .../client/views/integrationsIncoming.html | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index 2f6126ab3dc..f61b55199dc 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 @@ -30,6 +31,7 @@ Template.integrationsIncoming.helpers msg: 'Example message' bot: i: Random.id() + groupable: false attachments: [{ title: "Rocket.Chat" title_link: "https://rocket.chat" diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index 7efeb81ec8b..75e690c9ce3 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -59,9 +59,16 @@ <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}} -- GitLab From 7125c05b3b66cdda5c86a9971afa954a5bb50d8e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 18 Dec 2015 10:00:13 -0200 Subject: [PATCH 0914/1338] More improvements in message grouping --- .../message/message.coffee | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 30c4d256e65..f4d7bf981a9 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -147,17 +147,18 @@ Template.message.onViewRendered = (context) -> else $nextNode.removeClass('new-day') - if nextDataset.username isnt currentDataset.username or parseInt(nextDataset.timestamp) - parseInt(currentDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 - $nextNode.removeClass('sequential') - else - $nextNode.addClass('sequential') + 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 + $nextNode.addClass('sequential') - if not nextNode? - templateInstance = view.parentView.parentView.parentView.parentView.parentView.templateInstance?() + if not nextNode? + templateInstance = view.parentView.parentView.parentView.parentView.parentView.templateInstance?() - if currentNode.classList.contains('own') is true - templateInstance?.atBottom = true - else - if templateInstance?.atBottom isnt true - newMessage = templateInstance?.find(".new-message") - newMessage?.className = "new-message" + if currentNode.classList.contains('own') is true + templateInstance?.atBottom = true + else + if templateInstance?.atBottom isnt true + newMessage = templateInstance?.find(".new-message") + newMessage?.className = "new-message" -- GitLab From 7cac1c4b2a228c50f1cfa03d1fde708124c693a0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 10:28:23 -0200 Subject: [PATCH 0915/1338] removed all console.logs from publishes and methods --- .../server/functions/addUsersToRoles.coffee | 1 - .../server/functions/getRolesForUser.coffee | 3 +-- .../server/functions/hasPermission.coffee | 4 +--- .../rocketchat-authorization/server/functions/hasRole.coffee | 3 +-- .../server/functions/removeUsersFromRoles.coffee | 3 +-- .../server/methods/addPermissionToRole.coffee | 2 -- .../server/methods/addUserToRole.coffee | 2 -- .../rocketchat-authorization/server/methods/deleteRole.coffee | 2 -- .../server/methods/removeRoleFromPermission.coffee | 2 -- .../server/methods/removeUserFromRole.coffee | 2 -- .../rocketchat-authorization/server/methods/saveRole.coffee | 2 -- packages/rocketchat-authorization/server/publication.coffee | 1 - .../server/methods/saveRoomSettings.coffee | 2 -- packages/rocketchat-lib/server/methods/addOAuthService.coffee | 2 -- .../server/methods/checkRegistrationSecretURL.coffee | 1 - .../rocketchat-lib/server/methods/joinDefaultChannels.coffee | 2 -- .../rocketchat-lib/server/methods/removeOAuthService.coffee | 2 -- packages/rocketchat-lib/server/methods/robotMethods.coffee | 2 -- packages/rocketchat-lib/server/methods/saveSetting.coffee | 1 - packages/rocketchat-lib/server/methods/sendMessage.coffee | 2 -- packages/rocketchat-lib/server/methods/setRealName.coffee | 2 -- packages/rocketchat-lib/server/methods/setUsername.coffee | 4 +--- packages/rocketchat-lib/server/methods/updateUser.coffee | 4 +--- packages/rocketchat-lib/server/publications/settings.coffee | 4 ---- packages/rocketchat-livechat/server/methods/addAgent.js | 2 -- packages/rocketchat-livechat/server/methods/addManager.js | 2 -- packages/rocketchat-livechat/server/methods/removeAgent.js | 2 -- .../rocketchat-livechat/server/methods/removeDepartment.js | 2 -- packages/rocketchat-livechat/server/methods/removeManager.js | 2 -- packages/rocketchat-livechat/server/methods/removeTrigger.js | 2 -- packages/rocketchat-livechat/server/methods/saveDepartment.js | 2 -- .../rocketchat-livechat/server/methods/saveSurveyFeedback.js | 2 -- packages/rocketchat-livechat/server/methods/saveTrigger.js | 2 -- packages/rocketchat-livechat/server/methods/searchAgent.js | 2 -- .../rocketchat-livechat/server/publications/livechatAgents.js | 2 -- .../server/publications/livechatDepartments.js | 2 -- .../server/publications/livechatManagers.js | 2 -- .../rocketchat-livechat/server/publications/visitorRoom.js | 2 -- packages/rocketchat-mailer/server/methods/sendMail.coffee | 2 -- packages/rocketchat-message-pin/server/pinMessage.coffee | 4 ---- .../server/publications/pinnedMessages.coffee | 2 -- .../server/publications/starredMessages.coffee | 2 -- packages/rocketchat-message-star/server/starMessage.coffee | 2 -- .../rocketchat-statistics/server/methods/getStatistics.coffee | 4 +--- server/methods/addUserToRoom.coffee | 2 -- server/methods/archiveRoom.coffee | 2 -- server/methods/canAccessRoom.coffee | 2 -- server/methods/createChannel.coffee | 2 -- server/methods/createDirectMessage.coffee | 2 -- server/methods/createPrivateGroup.coffee | 2 -- server/methods/deleteMessage.coffee | 2 -- server/methods/eraseRoom.coffee | 2 -- server/methods/getRoomIdByNameOrId.coffee | 2 -- server/methods/getTotalChannels.coffee | 1 - server/methods/hideRoom.coffee | 2 -- server/methods/joinRoom.coffee | 2 -- server/methods/leaveRoom.coffee | 2 -- server/methods/loadHistory.coffee | 2 -- server/methods/loadLocale.coffee | 1 - server/methods/loadMissedMessages.coffee | 2 -- server/methods/logoutCleanUp.coffee | 4 +--- server/methods/migrate.coffee | 3 +-- server/methods/muteUserInRoom.coffee | 2 -- server/methods/openRoom.coffee | 2 -- server/methods/readMessages.coffee | 2 -- server/methods/removeUserFromRoom.coffee | 2 -- server/methods/resetAvatar.coffee | 2 -- server/methods/saveUserPreferences.coffee | 2 -- server/methods/setAvatarFromService.coffee | 2 -- server/methods/toogleFavorite.coffee | 2 -- server/methods/unarchiveRoom.coffee | 2 -- server/methods/unmuteUserInRoom.coffee | 2 -- server/methods/updateMessage.coffee | 2 -- server/publications/activeUsers.coffee | 2 -- server/publications/adminRooms.coffee | 2 -- server/publications/channelAutocomplete.coffee | 2 -- server/publications/filteredUsers.coffee | 2 -- server/publications/fullUserData.coffee | 2 -- server/publications/messages.coffee | 2 -- server/publications/privateHistory.coffee | 2 -- server/publications/room.coffee | 2 -- server/publications/roomFiles.coffee | 2 -- server/publications/roomSearch.coffee | 2 -- server/publications/spotlight.coffee | 2 -- server/publications/subscription.coffee | 2 -- server/publications/userChannels.coffee | 2 -- server/publications/userData.coffee | 2 -- 87 files changed, 9 insertions(+), 177 deletions(-) diff --git a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee b/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee index 3af878e6814..ac2be57a546 100644 --- a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee @@ -1,5 +1,4 @@ RocketChat.authz.addUsersToRoles = (userIds, roleNames, scope ) -> - console.log '[methods] addUserToRoles -> '.green, 'arguments:', arguments if not userIds or not roleNames return false diff --git a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee b/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee index 40f8564a28e..800473a08bf 100644 --- a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee +++ b/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee @@ -1,7 +1,6 @@ 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 + return Roles.getRolesForUser(userId, scope) diff --git a/packages/rocketchat-authorization/server/functions/hasPermission.coffee b/packages/rocketchat-authorization/server/functions/hasPermission.coffee index f0d2d3ca2e9..b7c39299c7e 100644 --- a/packages/rocketchat-authorization/server/functions/hasPermission.coffee +++ b/packages/rocketchat-authorization/server/functions/hasPermission.coffee @@ -1,6 +1,4 @@ RocketChat.authz.hasPermission = (userId, permissionId, scope) -> - console.log '[methods] hasPermission -> '.green, 'arguments:', arguments - # get user's roles roles = RocketChat.authz.getRolesForUser(userId, scope) @@ -9,4 +7,4 @@ RocketChat.authz.hasPermission = (userId, permissionId, scope) -> 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 + return permissionId in permissions diff --git a/packages/rocketchat-authorization/server/functions/hasRole.coffee b/packages/rocketchat-authorization/server/functions/hasRole.coffee index 83d32ea862a..10ac10df442 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 + return Roles.userIsInRole(userId, [roleName], scope) diff --git a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee index a3f7c794d89..93f78b6ccad 100644 --- a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee @@ -1,5 +1,4 @@ RocketChat.authz.removeUsersFromRoles = (userIds, roleNames, scope ) -> - console.log '[methods] removeUsersFromRoles -> '.green, 'arguments:', arguments if not userIds or not roleNames return false @@ -23,4 +22,4 @@ RocketChat.authz.removeUsersFromRoles = (userIds, roleNames, scope ) -> Roles.removeUsersFromRoles( userIds, roleNames, scope) - return true \ No newline at end of file + return true diff --git a/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee b/packages/rocketchat-authorization/server/methods/addPermissionToRole.coffee index a6d52621a7d..6924414101c 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 98583682d75..a5340768b51 100644 --- a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addUserToRole.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:addUserToRole -> '.green, 'arguments:', arguments); - if not roleName or not _.isString(roleName) or not username or not _.isString(username) throw new Meteor.Error 'invalid-arguments' diff --git a/packages/rocketchat-authorization/server/methods/deleteRole.coffee b/packages/rocketchat-authorization/server/methods/deleteRole.coffee index ab6e554c112..0a928cb252b 100644 --- a/packages/rocketchat-authorization/server/methods/deleteRole.coffee +++ b/packages/rocketchat-authorization/server/methods/deleteRole.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:deleteRole -> '.green, 'arguments:', arguments - role = Meteor.roles.findOne _id if role.protected diff --git a/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee b/packages/rocketchat-authorization/server/methods/removeRoleFromPermission.coffee index 9efde6b9d17..ff5def0ad66 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 26d47a63b1a..6510c2f8b2b 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' diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee index 8df33ff81a5..7a30d9ecec6 100644 --- a/packages/rocketchat-authorization/server/methods/saveRole.coffee +++ b/packages/rocketchat-authorization/server/methods/saveRole.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:saveRole -> '.green, 'arguments:', arguments - saveData = description: roleData.description diff --git a/packages/rocketchat-authorization/server/publication.coffee b/packages/rocketchat-authorization/server/publication.coffee index 8f6e008e14c..9a4fa8cbfc1 100644 --- a/packages/rocketchat-authorization/server/publication.coffee +++ b/packages/rocketchat-authorization/server/publication.coffee @@ -1,3 +1,2 @@ Meteor.publish 'permissions', -> - console.log '[publish] permissions'.green return RocketChat.models.Permissions.find {} diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee index 6375bf5f289..4531f6978f2 100644 --- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee +++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee @@ -1,7 +1,5 @@ Meteor.methods saveRoomSettings: (rid, settings) -> - console.log '[method] saveRoomSettings'.green, rid, settings - unless Match.test rid, String throw new Meteor.Error 'invalid-rid' diff --git a/packages/rocketchat-lib/server/methods/addOAuthService.coffee b/packages/rocketchat-lib/server/methods/addOAuthService.coffee index 4545add5841..0a8a28070c7 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' diff --git a/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee b/packages/rocketchat-lib/server/methods/checkRegistrationSecretURL.coffee index a69c22fffe4..592b8547099 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 97218c2df15..3087fb387f4 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 60d94fef7ee..221b2495df2 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 664cb049bda..4a101fdacf1 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 b2775cb055c..0b6c1cad55a 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 354c0e07b8c..bec44f79f1a 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 diff --git a/packages/rocketchat-lib/server/methods/setRealName.coffee b/packages/rocketchat-lib/server/methods/setRealName.coffee index 2a913c93f3e..92a2c9b078e 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 f9e62785daf..c74ec4a6b21 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 9a20d410122..53f3536d0d8 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,4 @@ Meteor.methods Meteor.runAsUser userData._id, -> Meteor.call 'setUsername', userData.username - return true \ No newline at end of file + return true diff --git a/packages/rocketchat-lib/server/publications/settings.coffee b/packages/rocketchat-lib/server/publications/settings.coffee index c3d5beb0a4f..f5454f90107 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-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js index e94c5bee12f..cd924c14ce9 100644 --- a/packages/rocketchat-livechat/server/methods/addAgent.js +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -8,8 +8,6 @@ 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) { diff --git a/packages/rocketchat-livechat/server/methods/addManager.js b/packages/rocketchat-livechat/server/methods/addManager.js index 6519a406bf3..eb0f905ec40 100644 --- a/packages/rocketchat-livechat/server/methods/addManager.js +++ b/packages/rocketchat-livechat/server/methods/addManager.js @@ -8,8 +8,6 @@ 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) { diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js index bc6dd5bd4c9..141b7d3bf94 100644 --- a/packages/rocketchat-livechat/server/methods/removeAgent.js +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -8,8 +8,6 @@ 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) { diff --git a/packages/rocketchat-livechat/server/methods/removeDepartment.js b/packages/rocketchat-livechat/server/methods/removeDepartment.js index 8fb2b620dff..5419602088c 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 38e462d3f0e..32db557fd80 100644 --- a/packages/rocketchat-livechat/server/methods/removeManager.js +++ b/packages/rocketchat-livechat/server/methods/removeManager.js @@ -6,8 +6,6 @@ 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) { diff --git a/packages/rocketchat-livechat/server/methods/removeTrigger.js b/packages/rocketchat-livechat/server/methods/removeTrigger.js index bf09510d45d..a2249b14594 100644 --- a/packages/rocketchat-livechat/server/methods/removeTrigger.js +++ b/packages/rocketchat-livechat/server/methods/removeTrigger.js @@ -1,7 +1,5 @@ Meteor.methods({ 'livechat:removeTrigger' (trigger) { - console.log('[methods] livechat:removeTrigger -> '.green, 'arguments:', arguments); - if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { throw new Meteor.Error("not-authorized"); } diff --git a/packages/rocketchat-livechat/server/methods/saveDepartment.js b/packages/rocketchat-livechat/server/methods/saveDepartment.js index 526b32134f2..de3f656817b 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); - if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { throw new Meteor.Error("not-authorized"); } diff --git a/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js b/packages/rocketchat-livechat/server/methods/saveSurveyFeedback.js index 44d8fd05767..5d742187616 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 index fa721480016..4077fc46d5b 100644 --- a/packages/rocketchat-livechat/server/methods/saveTrigger.js +++ b/packages/rocketchat-livechat/server/methods/saveTrigger.js @@ -1,7 +1,5 @@ Meteor.methods({ 'livechat:saveTrigger' (trigger) { - console.log('[methods] livechat:saveTrigger -> '.green, 'arguments:', arguments); - if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { throw new Meteor.Error("not-authorized"); } diff --git a/packages/rocketchat-livechat/server/methods/searchAgent.js b/packages/rocketchat-livechat/server/methods/searchAgent.js index 72b9d3d9bb0..80bf6159bae 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/publications/livechatAgents.js b/packages/rocketchat-livechat/server/publications/livechatAgents.js index b68dba1459c..77be3cde55e 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 ab35d5dd88c..a7566722d58 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 639c1305c6d..042a2acb50a 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/visitorRoom.js b/packages/rocketchat-livechat/server/publications/visitorRoom.js index 52b4fab49f6..cb0570f7a7e 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/server/methods/sendMail.coffee b/packages/rocketchat-mailer/server/methods/sendMail.coffee index a4b7fd4194b..d12e7b18dff 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-message-pin/server/pinMessage.coffee b/packages/rocketchat-message-pin/server/pinMessage.coffee index 7a62e55f3da..01e65161143 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 7daf7a32bd5..044078e5599 100644 --- a/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee +++ b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee @@ -2,8 +2,6 @@ Meteor.publish 'pinnedMessages', (rid, options = {}) -> 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 diff --git a/packages/rocketchat-message-star/server/publications/starredMessages.coffee b/packages/rocketchat-message-star/server/publications/starredMessages.coffee index badaa2b3bdd..7bb020c7af1 100644 --- a/packages/rocketchat-message-star/server/publications/starredMessages.coffee +++ b/packages/rocketchat-message-star/server/publications/starredMessages.coffee @@ -2,8 +2,6 @@ Meteor.publish 'starredMessages', (rid, options = {}) -> 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 diff --git a/packages/rocketchat-message-star/server/starMessage.coffee b/packages/rocketchat-message-star/server/starMessage.coffee index 625f0539f91..6df1a37865a 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-statistics/server/methods/getStatistics.coffee b/packages/rocketchat-statistics/server/methods/getStatistics.coffee index 8bf3e8cb1d9..dfe10d205e7 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/server/methods/addUserToRoom.coffee b/server/methods/addUserToRoom.coffee index cf1dd539635..3cfd91d7346 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 abfcef70b12..e1d86612d1d 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 514bc431b4d..4d84b6a8d76 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 diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index 3c8319079d3..47f97d22d40 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() diff --git a/server/methods/createDirectMessage.coffee b/server/methods/createDirectMessage.coffee index 5fa5934680c..48dc97b1e5f 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 22080081372..d308e1e7ae9 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 diff --git a/server/methods/deleteMessage.coffee b/server/methods/deleteMessage.coffee index fbf66bb76b2..5e96a7cc4ab 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 a8c6f8248b7..5c82b18cb4c 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 50d6a4a0c64..4634081feb0 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/getTotalChannels.coffee b/server/methods/getTotalChannels.coffee index f791683e8c2..8c318d78a15 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 3537394aef4..cbb2d6023c0 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 81666400b14..42e9630474d 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 4ff40c087fb..d54faba3fb1 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 921bfae150a..ab8048e6e50 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 diff --git a/server/methods/loadLocale.coffee b/server/methods/loadLocale.coffee index f4ed82c228a..17f4c2d8758 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 e6c201aa77b..7d22fe1fd45 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/logoutCleanUp.coffee b/server/methods/logoutCleanUp.coffee index 4bf8d65487e..7d5615c3cb8 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/migrate.coffee b/server/methods/migrate.coffee index 915b4582f37..1e3210f9173 100644 --- a/server/methods/migrate.coffee +++ b/server/methods/migrate.coffee @@ -3,7 +3,6 @@ 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 this.unblock() @@ -11,4 +10,4 @@ Meteor.methods 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 index 16554dcecfb..1cff2d7de01 100644 --- a/server/methods/muteUserInRoom.coffee +++ b/server/methods/muteUserInRoom.coffee @@ -1,8 +1,6 @@ Meteor.methods muteUserInRoom: (data) -> fromId = Meteor.userId() - console.log '[methods] muteUserInRoom -> '.green, 'fromId:', fromId, 'data:', data - check(data, Match.ObjectIncluding({ rid: String, username: String })) unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) diff --git a/server/methods/openRoom.coffee b/server/methods/openRoom.coffee index 9dcb5d818d2..2b2536c87f4 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 35dc63a998d..985d6050505 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/removeUserFromRoom.coffee b/server/methods/removeUserFromRoom.coffee index c77598660c0..78a5137fe2a 100644 --- a/server/methods/removeUserFromRoom.coffee +++ b/server/methods/removeUserFromRoom.coffee @@ -1,8 +1,6 @@ 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) diff --git a/server/methods/resetAvatar.coffee b/server/methods/resetAvatar.coffee index 0bb66f0d140..e6ff5278eca 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/saveUserPreferences.coffee b/server/methods/saveUserPreferences.coffee index 5cf457a2315..39da131efdb 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 b3d0be939d7..045d17ab62e 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' diff --git a/server/methods/toogleFavorite.coffee b/server/methods/toogleFavorite.coffee index 853bfe00c77..58c4faa7535 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 eed9cbfdc2d..7b0ae819bf4 100644 --- a/server/methods/unarchiveRoom.coffee +++ b/server/methods/unarchiveRoom.coffee @@ -3,8 +3,6 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error 'invalid-user', '[methods] unArchiveRoom -> Invalid user' - console.log '[methods] unArchiveRoom -> '.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/unmuteUserInRoom.coffee b/server/methods/unmuteUserInRoom.coffee index f441d56de7a..cec5d061c34 100644 --- a/server/methods/unmuteUserInRoom.coffee +++ b/server/methods/unmuteUserInRoom.coffee @@ -1,8 +1,6 @@ Meteor.methods unmuteUserInRoom: (data) -> fromId = Meteor.userId() - console.log '[methods] unmuteUserInRoom -> '.green, 'fromId:', fromId, 'data:', data - check(data, Match.ObjectIncluding({ rid: String, username: String })) unless RocketChat.authz.hasPermission(fromId, 'mute-user', data.rid) diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 09ce1aa2d6f..f0439e370e3 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 diff --git a/server/publications/activeUsers.coffee b/server/publications/activeUsers.coffee index ba420634b09..65e3675b6a0 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 afbd22e2460..638077d5ee5 100644 --- a/server/publications/adminRooms.coffee +++ b/server/publications/adminRooms.coffee @@ -22,8 +22,6 @@ Meteor.publish 'adminRooms', (filter, types, limit) -> 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 eebbea4bc8f..7586b0242ef 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 fd93452f85c..d1316d71ea3 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 255a87542cf..95173f5edb8 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 b2ee7f04918..6e0feba1ccd 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 9f8eb31f871..115796f52c8 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 960f1c40de9..711ba33bc7b 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 38fce2de1f8..bdfdeaf7102 100644 --- a/server/publications/roomFiles.coffee +++ b/server/publications/roomFiles.coffee @@ -2,8 +2,6 @@ Meteor.publish 'roomFiles', (rid) -> unless this.userId return this.ready() - console.log '[publish] roomFiles '.green, rid - pub = this fileQuery = diff --git a/server/publications/roomSearch.coffee b/server/publications/roomSearch.coffee index c499c1a89f7..f3357511223 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 9921d4987e4..feec1ce6f65 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 f188e99522e..dc3245e2135 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 diff --git a/server/publications/userChannels.coffee b/server/publications/userChannels.coffee index dbacf03b444..9192dcc635d 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 f6e5eac5167..6f493433681 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 -- GitLab From 86035eaf4214c26eef2781cd9f729065f8475d8a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 10:29:20 -0200 Subject: [PATCH 0916/1338] added setting to turn on/off debug messages from methods and publishes --- packages/rocketchat-lib/i18n/en.i18n.json | 7 ++- packages/rocketchat-lib/package.js | 3 ++ packages/rocketchat-lib/server/lib/debug.js | 45 +++++++++++++++++++ .../server/startup/settings.coffee | 1 + 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-lib/server/lib/debug.js diff --git a/packages/rocketchat-lib/i18n/en.i18n.json b/packages/rocketchat-lib/i18n/en.i18n.json index b0e165dc996..4cd67500216 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" -} \ No newline at end of file + "Only_errors": "Only errors" +} diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 5f0e3487c78..e4a4f4c319d 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -25,6 +25,9 @@ Package.onUse(function(api) { api.use('rocketchat:version'); api.use('kadira:flow-router', 'client'); + // DEBUGGER + api.addFiles('server/lib/debug.js'); + // COMMON LIB api.addFiles('lib/core.coffee'); api.addFiles('lib/settings.coffee'); diff --git a/packages/rocketchat-lib/server/lib/debug.js b/packages/rocketchat-lib/server/lib/debug.js new file mode 100644 index 00000000000..243928778ac --- /dev/null +++ b/packages/rocketchat-lib/server/lib/debug.js @@ -0,0 +1,45 @@ +var debugLevel = 'debug'; + +Meteor.startup(function() { + RocketChat.settings.onload('Debug_Level', function(key, value, initialLoad) { + if (value) { + debugLevel = value; + } + }); + + var value = RocketChat.settings.get('Debug_Level'); + if (value) { + debugLevel = value; + } +}); + +var wrapMethods = function(name, originalHandler, methodsMap) { + methodsMap[name] = function() { + if (debugLevel === 'debug') { + console.log('[methods]'.green, name, '-> userId:', Meteor.userId(), ', arguments: ', arguments); + } + + 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 (debugLevel === 'debug') { + console.log('[publish]'.green, name, '-> userId:', this.userId, ', arguments: ', arguments); + } + + return func.apply(this, arguments); + }) +}; diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 0a4e79e09c2..7f7abc9d663 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -75,6 +75,7 @@ RocketChat.settings.addGroup 'General', -> @add 'Allow_Invalid_SelfSigned_Certs', false, { type: 'boolean' } @add 'Disable_Favorite_Rooms', false, { type: 'boolean' } @add 'CDN_PREFIX', '', { type: 'string' } + @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', -> -- GitLab From e9826a4f1918874ee0aca5316e4f838ef58a1276 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 10:30:00 -0200 Subject: [PATCH 0917/1338] added some docs about Settings API --- packages/rocketchat-lib/README.md | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/packages/rocketchat-lib/README.md b/packages/rocketchat-lib/README.md index b00630727af..6bd81b7d793 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): -- GitLab From aa26dbf12f2d0125e73ff79cfccd6b1732870899 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 18 Dec 2015 10:31:18 -0200 Subject: [PATCH 0918/1338] Return the correct error for unauthorized upload access --- lib/fileUpload.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index f95df9507cd..d60283c8ba5 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -74,6 +74,10 @@ if UploadFS? token = cookie.get('rc_token', rawCookies) if rawCookies? unless uid and token and RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) + res.statusCode = 403 + res.end('Not Allowed') + # Just to abort the request + # See https://github.com/jalik/jalik-ufs/issues/28 throw new Meteor.Error 403, 'Not Allowed' res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" -- GitLab From 13a14f63fa6eb433aa74316fa0ad0c0ef1332635 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 10:32:28 -0200 Subject: [PATCH 0919/1338] added kadira back --- .meteor/packages | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 94ad617a195..a97cca862ec 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -100,7 +100,7 @@ kadira:blaze-layout kadira:flow-router kenton:accounts-sandstorm kevohagan:sweetalert -#meteorhacks:kadira +meteorhacks:kadira mizzao:autocomplete mizzao:timesync momentjs:moment diff --git a/build.sh b/build.sh index 5e36ade4e4c..f60192ddad7 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat rocketchat:hubot meteorhacks:kadira +meteor add rocketchat:livechat rocketchat:hubot meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat cd /var/www/rocket.chat/bundle/programs/server npm install -- GitLab From 945187a764f36ed5b711289eed24ca7f41f9ce42 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 10:36:19 -0200 Subject: [PATCH 0920/1338] added an not-authorized exception instead of a console.log --- server/methods/migrate.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/methods/migrate.coffee b/server/methods/migrate.coffee index 1e3210f9173..3b01619a1c8 100644 --- a/server/methods/migrate.coffee +++ b/server/methods/migrate.coffee @@ -3,7 +3,7 @@ Meteor.methods user = Meteor.user() if not user? or RocketChat.authz.hasPermission(user._id, 'run-migration') isnt true - return + throw new Meteor.Error "not-authorized", '[methods] migrateTo' this.unblock() Migrations.migrateTo version -- GitLab From d291140c0d9fc748dd76f51a6fa0eca9fb242892 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 10:48:44 -0200 Subject: [PATCH 0921/1338] mentions sidenav; --- .meteor/packages | 1 + .meteor/versions | 1 + i18n/en.i18n.json | 1 + .../server/models/Messages.coffee | 7 ++ .../client/actionButton.coffee | 79 +++++++++++++++++++ .../client/lib/MentionedMessage.coffee | 1 + .../client/tabBar.coffee | 4 + .../client/views/mentionsFlexTab.coffee | 27 +++++++ .../client/views/mentionsFlexTab.html | 22 ++++++ .../views/stylesheets/mentionsFlexTab.less | 37 +++++++++ .../i18n/en.i18n.json | 5 ++ .../package-tap.i18n | 0 .../rocketchat-mentions-flextab/package.js | 46 +++++++++++ .../publications/mentionedMessages.coffee | 27 +++++++ .../assets/stylesheets/base.less | 27 +++++++ .../lib/RoomHistoryManager.coffee | 43 ++++++++-- packages/rocketchat-ui/lib/RoomManager.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 10 ++- packages/rocketchat-ui/views/app/room.html | 16 +++- server/methods/loadNextMessages.coffee | 28 +++++++ 20 files changed, 375 insertions(+), 9 deletions(-) create mode 100644 packages/rocketchat-mentions-flextab/client/actionButton.coffee create mode 100644 packages/rocketchat-mentions-flextab/client/lib/MentionedMessage.coffee create mode 100644 packages/rocketchat-mentions-flextab/client/tabBar.coffee create mode 100644 packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee create mode 100644 packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html create mode 100644 packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less create mode 100644 packages/rocketchat-mentions-flextab/i18n/en.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/package-tap.i18n create mode 100644 packages/rocketchat-mentions-flextab/package.js create mode 100644 packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee create mode 100644 server/methods/loadNextMessages.coffee diff --git a/.meteor/packages b/.meteor/packages index b56ad45f922..fb190fe0342 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -55,6 +55,7 @@ rocketchat:mailer rocketchat:markdown rocketchat:me rocketchat:mentions +rocketchat:mentions-flextab rocketchat:message-pin rocketchat:message-star rocketchat:oembed diff --git a/.meteor/versions b/.meteor/versions index 5ec2cf20d5f..9fffda34d70 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -144,6 +144,7 @@ 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 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index cbe1bda761c..c6104208be4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -213,6 +213,7 @@ "italics" : "italics", "join" : "Join", "Join_the_Community" : "Join the Community", + "Jump_to_recent_messages" : "Jump to recent messages", "Language" : "Language", "Language_Version" : "English Version", "Last_login" : "Last login", diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 8607765ce45..6b7814a3a77 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -24,6 +24,13 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find query, options + findByMentionAndRoomId: (username, rid, options) -> + query = + "mentions.username": username + "rid": rid + + return @find query, options + findVisibleByRoomId: (roomId, options) -> query = _hidden: diff --git a/packages/rocketchat-mentions-flextab/client/actionButton.coffee b/packages/rocketchat-mentions-flextab/client/actionButton.coffee new file mode 100644 index 00000000000..6ae7b2f18a6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/actionButton.coffee @@ -0,0 +1,79 @@ +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() + 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) + else + instance.atBottom = false + RoomHistoryManager.isLoading(message.rid, true) + ChatMessage.remove {} + ChatMessage.upsert { _id: message._id }, message + RoomHistoryManager.hasMoreNext(message.rid, true) + RoomHistoryManager.getMore(message.rid, 25, false) + RoomHistoryManager.getMoreNext(message.rid, 25, false) + + typeName = undefined + subscription = ChatSubscription.findOne rid: message.rid + if subscription? + typeName = subscription.t + subscription.name + else + curRoomDoc = ChatRoom.findOne(_id: message.rid) + typeName = curRoomDoc?.t + curRoomDoc?.name + + RoomManager.updateMentionsMarksOfRoom typeName + + Tracker.afterFlush -> + wrapper = $('.messages-box .wrapper') + msgElement = $("##{message._id}", wrapper) + pos = wrapper.scrollTop() + msgElement.offset().top - wrapper.height()/2 + wrapper.animate({ + scrollTop: pos + }, 500) + + RoomHistoryManager.isLoading(message.rid, false) + + # Meteor.call 'loadHistory', message.rid, message.ts, 25, (err, result) -> + # throw err if err + # ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] when item.t isnt 'command' + + # Meteor.call 'loadNextMessages', message.rid, message.ts, 25, (err, result) -> + # throw err if err + # ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] when item.t isnt 'command' + + # typeName = undefined + # subscription = ChatSubscription.findOne rid: message.rid + # if subscription? + # typeName = subscription.t + subscription.name + # else + # curRoomDoc = ChatRoom.findOne(_id: message.rid) + # typeName = curRoomDoc?.t + curRoomDoc?.name + # RoomManager.updateMentionsMarksOfRoom typeName + + # + + # Tracker.afterFlush -> + # wrapper = $('.messages-box .wrapper') + # msgElement = $("##{message._id}", wrapper) + # pos = wrapper.scrollTop() + msgElement.offset().top - wrapper.height()/2 + + # wrapper.animate({ + # scrollTop: pos + # }, 500) + + # instance.showJumpToRecent?.set true + # RoomHistoryManager.isLoading(message.rid, false) + + 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 00000000000..26dc11807b8 --- /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 00000000000..52c72abdc68 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/tabBar.coffee @@ -0,0 +1,4 @@ +Meteor.startup -> + RocketChat.callbacks.add 'enter-room', -> + RocketChat.TabBar.addButton({ id: 'mentions', i18nTitle: 'Mentions', icon: 'icon-at', template: 'mentionsFlexTab', order: 3 }) + , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-mentions' 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 00000000000..387221897d6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee @@ -0,0 +1,27 @@ +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() + +Template.mentionsFlexTab.onCreated -> + @autorun => + @subscribe 'mentionedMessages', @data.rid + +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() 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 00000000000..0df447c6aee --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html @@ -0,0 +1,22 @@ +<template name="mentionsFlexTab"> + <div class="control"> + <div class="header"> + <h2>{{_ "Mentions"}}</h2> + </div> + </div> + <ul class="mentioned-messages-list scrollable"> + {{#if Template.subscriptionsReady}} + {{#if hasMessages}} + {{#each messages}} + {{#nrr nrrargs 'message' .}}{{/nrr}} + {{/each}} + {{else}} + <li class="empty"> + {{_ "No_mentioned_messages"}} + </li> + {{/if}} + {{else}} + {{> loading}} + {{/if}} + </ul> +</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 00000000000..286c60f92b5 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less @@ -0,0 +1,37 @@ +.mentioned-messages-list { + padding: 70px 0 30px 0; + + &.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; + } + } + } +} 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 00000000000..0c7248f50bb --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json @@ -0,0 +1,5 @@ +{ + "Jump_to_message": "Jump to message", + "Mentions": "Mentions", + "No_mentioned_messages": "No mentioned messages" +} diff --git a/packages/rocketchat-mentions-flextab/package-tap.i18n b/packages/rocketchat-mentions-flextab/package-tap.i18n new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-mentions-flextab/package.js b/packages/rocketchat-mentions-flextab/package.js new file mode 100644 index 00000000000..856e52ebc3e --- /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', + 'less@2.5.0', + 'rocketchat:lib@0.0.1' + ]); + + 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@1.5.1"], ["client", "server"]); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles, ["client", "server"]); +}); + +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 00000000000..4fd9b05a28d --- /dev/null +++ b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee @@ -0,0 +1,27 @@ +Meteor.publish 'mentionedMessages', (rid, options = {}) -> + unless this.userId + return this.ready() + + console.log '[publish] mentionedMessages -> '.green, 'rid:', rid, 'options:', options + + publication = @ + + user = RocketChat.models.Users.findOneById this.userId + unless user + return this.ready() + + cursorHandle = RocketChat.models.Messages.findByMentionAndRoomId(user.username, rid, { sort: { ts: -1 }, limit: 50 }).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-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index b2ad807f329..1d46ab8ea3d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2397,6 +2397,9 @@ a.github-fork { width: 100%; .calc(height, ~'100% - 120px'); + .wrapper.has-more-next { + padding-bottom: 24px; + } ul { padding: 21px 0 10px; } @@ -2433,6 +2436,30 @@ 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; diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index aac7ca39f1f..6229da05545 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -7,18 +7,19 @@ if not histories[rid]? histories[rid] = hasMore: ReactiveVar true + hasMoreNext: ReactiveVar false isLoading: ReactiveVar false unreadNotLoaded: ReactiveVar 0 loaded: 0 return histories[rid] - getMore = (rid, limit=defaultLimit) -> + getMore = (rid, limit=defaultLimit, setLoading=true) -> room = getRoom rid if room.hasMore.curValue isnt true return - room.isLoading.set true + room.isLoading.set true if setLoading # ScrollListener.setLoader true lastMessage = ChatMessage.findOne({rid: rid}, {sort: {ts: 1}}) @@ -57,25 +58,55 @@ readMessage.refreshUnreadMark(rid, true) RoomManager.updateMentionsMarksOfRoom typeName - room.isLoading.set false + room.isLoading.set false if setLoading room.loaded += result?.messages?.length if result?.messages?.length < limit room.hasMore.set false + getMoreNext = (rid, limit=defaultLimit, setLoading=true) -> + room = getRoom rid + if room.hasMoreNext.curValue isnt true + return + + room.isLoading.set true if setLoading + + lastMessage = ChatMessage.findOne({rid: rid}, {sort: {ts: -1}}) + + 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 + room.isLoading.set false if setLoading + room.loaded += result.messages.length + if result.messages.length < limit + room.hasMoreNext.set false + hasMore = (rid) -> room = getRoom rid return room.hasMore.get() + hasMoreNext = (rid, override) -> + room = getRoom rid + if override? + room.hasMoreNext.set(override) + return room.hasMoreNext.get() + + getMoreIfIsEmpty = (rid) -> room = getRoom rid if room.loaded is 0 getMore rid - isLoading = (rid) -> - room = getRoom rid + isLoading = (rid, override) -> + room = getRoom rid + if override? + room.isLoading.set(override) return room.isLoading.get() clear = (rid) -> @@ -87,7 +118,9 @@ getRoom: getRoom getMore: getMore + getMoreNext: getMoreNext getMoreIfIsEmpty: getMoreIfIsEmpty hasMore: hasMore + hasMoreNext: hasMoreNext isLoading: isLoading clear: clear diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 640b54f66ca..c4b3bc64c0f 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -207,7 +207,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/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index e382d70faa3..c5007f17c56 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 @@ -313,9 +316,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 RoomHistoryManager.isLoading(@_id) is false and (RoomHistoryManager.hasMore(@_id) is true or RoomHistoryManager.hasMoreNext(@_id) is true) if e.target.scrollTop is 0 RoomHistoryManager.getMore(@_id) + else if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + RoomHistoryManager.getMoreNext(@_id) , 200 'click .load-more > a': -> @@ -428,6 +433,9 @@ Template.room.events 'load img': (e, template) -> template.sendToBottomIfNecessary?() + 'click .jump-recent .jump-link': (e, template) -> + e.preventDefault() + RoomHistoryManager.clear(template?.data?._id) Template.room.onCreated -> # this.scrollOnBottom = true diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index 010ab8427bf..d63dcc7dd97 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -52,7 +52,7 @@ </div> <div class="messages-box {{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/server/methods/loadNextMessages.coffee b/server/methods/loadNextMessages.coffee new file mode 100644 index 00000000000..111cb3b752f --- /dev/null +++ b/server/methods/loadNextMessages.coffee @@ -0,0 +1,28 @@ +Meteor.methods + loadNextMessages: (rid, end, limit=20) -> + 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 + + 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 + } -- GitLab From 39e77a398db6672a8677be7761e2ebd57729c9e4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 11:08:17 -0200 Subject: [PATCH 0922/1338] removed kadira package again --- .meteor/packages | 1 - .meteor/versions | 2 -- build.sh | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index a97cca862ec..128f30eea50 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -100,7 +100,6 @@ kadira:blaze-layout kadira:flow-router kenton:accounts-sandstorm kevohagan:sweetalert -meteorhacks:kadira mizzao:autocomplete mizzao:timesync momentjs:moment diff --git a/.meteor/versions b/.meteor/versions index cad976bc063..6ab00e1b3f4 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -79,8 +79,6 @@ mdg:validation-error@0.1.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 diff --git a/build.sh b/build.sh index f60192ddad7..5e36ade4e4c 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat rocketchat:hubot +meteor add rocketchat:livechat 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 -- GitLab From 98eb53e6e7a862ae931303ca7e52d82addbc0c76 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 14:58:39 -0200 Subject: [PATCH 0923/1338] LoadSurroundingMessages --- .../client/actionButton.coffee | 67 +------------------ .../lib/RoomHistoryManager.coffee | 67 +++++++++++++++++++ packages/rocketchat-ui/lib/RoomManager.coffee | 14 ++-- packages/rocketchat-ui/views/app/room.coffee | 5 +- server/methods/loadHistory.coffee | 2 +- server/methods/loadNextMessages.coffee | 2 +- server/methods/loadSurroundingMessages.coffee | 47 +++++++++++++ 7 files changed, 129 insertions(+), 75 deletions(-) create mode 100644 server/methods/loadSurroundingMessages.coffee diff --git a/packages/rocketchat-mentions-flextab/client/actionButton.coffee b/packages/rocketchat-mentions-flextab/client/actionButton.coffee index 6ae7b2f18a6..6d18189d7ca 100644 --- a/packages/rocketchat-mentions-flextab/client/actionButton.coffee +++ b/packages/rocketchat-mentions-flextab/client/actionButton.coffee @@ -6,72 +6,7 @@ Meteor.startup -> action: (event, instance) -> message = @_arguments[1] $('.message-dropdown:visible').hide() - 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) - else - instance.atBottom = false - RoomHistoryManager.isLoading(message.rid, true) - ChatMessage.remove {} - ChatMessage.upsert { _id: message._id }, message - RoomHistoryManager.hasMoreNext(message.rid, true) - RoomHistoryManager.getMore(message.rid, 25, false) - RoomHistoryManager.getMoreNext(message.rid, 25, false) - - typeName = undefined - subscription = ChatSubscription.findOne rid: message.rid - if subscription? - typeName = subscription.t + subscription.name - else - curRoomDoc = ChatRoom.findOne(_id: message.rid) - typeName = curRoomDoc?.t + curRoomDoc?.name - - RoomManager.updateMentionsMarksOfRoom typeName - - Tracker.afterFlush -> - wrapper = $('.messages-box .wrapper') - msgElement = $("##{message._id}", wrapper) - pos = wrapper.scrollTop() + msgElement.offset().top - wrapper.height()/2 - wrapper.animate({ - scrollTop: pos - }, 500) - - RoomHistoryManager.isLoading(message.rid, false) - - # Meteor.call 'loadHistory', message.rid, message.ts, 25, (err, result) -> - # throw err if err - # ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] when item.t isnt 'command' - - # Meteor.call 'loadNextMessages', message.rid, message.ts, 25, (err, result) -> - # throw err if err - # ChatMessage.upsert {_id: item._id}, item for item in result?.messages or [] when item.t isnt 'command' - - # typeName = undefined - # subscription = ChatSubscription.findOne rid: message.rid - # if subscription? - # typeName = subscription.t + subscription.name - # else - # curRoomDoc = ChatRoom.findOne(_id: message.rid) - # typeName = curRoomDoc?.t + curRoomDoc?.name - # RoomManager.updateMentionsMarksOfRoom typeName - - # - - # Tracker.afterFlush -> - # wrapper = $('.messages-box .wrapper') - # msgElement = $("##{message._id}", wrapper) - # pos = wrapper.scrollTop() + msgElement.offset().top - wrapper.height()/2 - - # wrapper.animate({ - # scrollTop: pos - # }, 500) - - # instance.showJumpToRecent?.set true - # RoomHistoryManager.isLoading(message.rid, false) + RoomHistoryManager.getSurroundingMessages(message, 50) validation: (message) -> return message.mentionedList is true diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index 6229da05545..b723525d950 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -68,10 +68,23 @@ if room.hasMoreNext.curValue isnt true return + instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() + instance.atBottom = false + room.isLoading.set true if setLoading 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 @@ -79,11 +92,64 @@ 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 if setLoading room.loaded += result.messages.length if result.messages.length < limit room.hasMoreNext.set false + getSurroundingMessages = (message, limit=defaultLimit) -> + unless message?.rid + return + + 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) + 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 + + instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() + Meteor.defer -> + 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) + setTimeout -> + room.isLoading.set false + instance.atBottom = !result.moreAfter + , 500 + + room.loaded += result.messages.length + room.hasMore.set result.moreBefore + room.hasMoreNext.set result.moreAfter + hasMore = (rid) -> room = getRoom rid @@ -124,3 +190,4 @@ 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 c4b3bc64c0f..51fcbfe5cab 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -109,13 +109,17 @@ RocketChat.Notifications.onUser 'message', (msg) -> Dep.changed() msgStream.on openedRooms[typeName].rid, (msg) -> - if msg.t isnt 'command' - ChatMessage.upsert { _id: msg._id }, msg + # Should not send message to room if room has not loaded all the current messages + if RoomHistoryManager.hasMoreNext(openedRooms[typeName].rid) is false - Meteor.defer -> - RoomManager.updateMentionsMarksOfRoom typeName + # Do not load command messages into channel + if msg.t isnt 'command' + ChatMessage.upsert { _id: msg._id }, msg - RocketChat.callbacks.run 'streamMessage', msg + Meteor.defer -> + RoomManager.updateMentionsMarksOfRoom typeName + + RocketChat.callbacks.run 'streamMessage', msg RocketChat.Notifications.onRoom openedRooms[typeName].rid, 'deleteMessage', onDeleteMessageStream diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 707bca16092..076f5b6f856 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -317,9 +317,9 @@ Template.room.events 'scroll .wrapper': _.throttle (e, instance) -> if RoomHistoryManager.isLoading(@_id) is false and (RoomHistoryManager.hasMore(@_id) is true or RoomHistoryManager.hasMoreNext(@_id) is true) - if e.target.scrollTop is 0 + if RoomHistoryManager.hasMore(@_id) is true and e.target.scrollTop is 0 RoomHistoryManager.getMore(@_id) - else if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight + else if RoomHistoryManager.hasMoreNext(@_id) is true and e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight RoomHistoryManager.getMoreNext(@_id) , 200 @@ -435,6 +435,7 @@ Template.room.events 'click .jump-recent .jump-link': (e, template) -> e.preventDefault() + template.atBottom = true RoomHistoryManager.clear(template?.data?._id) Template.room.onCreated -> diff --git a/server/methods/loadHistory.coffee b/server/methods/loadHistory.coffee index 921bfae150a..446591da7a2 100644 --- a/server/methods/loadHistory.coffee +++ b/server/methods/loadHistory.coffee @@ -1,7 +1,7 @@ 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 + console.log '[methods] loadHistory -> '.green, 'fromId:', fromId, 'rid:', rid, 'end:', end, 'limit:', limit, 'ls:', ls unless Meteor.call 'canAccessRoom', rid, fromId return false diff --git a/server/methods/loadNextMessages.coffee b/server/methods/loadNextMessages.coffee index 111cb3b752f..9f17a1eaeb1 100644 --- a/server/methods/loadNextMessages.coffee +++ b/server/methods/loadNextMessages.coffee @@ -1,7 +1,7 @@ Meteor.methods loadNextMessages: (rid, end, limit=20) -> fromId = Meteor.userId() - # console.log '[methods] loadHistory -> '.green, 'fromId:', fromId, 'rid:', rid, 'end:', end, 'limit:', limit, 'skip:', skip + console.log '[methods] loadNextMessages -> '.green, 'fromId:', fromId, 'rid:', rid, 'end:', end, 'limit:', limit unless Meteor.call 'canAccessRoom', rid, fromId return false diff --git a/server/methods/loadSurroundingMessages.coffee b/server/methods/loadSurroundingMessages.coffee new file mode 100644 index 00000000000..926cbfdc496 --- /dev/null +++ b/server/methods/loadSurroundingMessages.coffee @@ -0,0 +1,47 @@ +Meteor.methods + loadSurroundingMessages: (message, limit=50) -> + fromId = Meteor.userId() + console.log '[methods] loadSurroundingMessages -> '.green, 'fromId:', fromId, 'message:', message, 'limit:', limit + + 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 + } -- GitLab From 9c880872207d8e1b6ea26457448541234dc15ce8 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 15:03:02 -0200 Subject: [PATCH 0924/1338] removed logs --- .../server/publications/mentionedMessages.coffee | 2 -- server/methods/loadNextMessages.coffee | 1 - server/methods/loadSurroundingMessages.coffee | 1 - 3 files changed, 4 deletions(-) diff --git a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee index 4fd9b05a28d..eafac320362 100644 --- a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee +++ b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee @@ -2,8 +2,6 @@ Meteor.publish 'mentionedMessages', (rid, options = {}) -> unless this.userId return this.ready() - console.log '[publish] mentionedMessages -> '.green, 'rid:', rid, 'options:', options - publication = @ user = RocketChat.models.Users.findOneById this.userId diff --git a/server/methods/loadNextMessages.coffee b/server/methods/loadNextMessages.coffee index 9f17a1eaeb1..91a600bfc43 100644 --- a/server/methods/loadNextMessages.coffee +++ b/server/methods/loadNextMessages.coffee @@ -1,7 +1,6 @@ Meteor.methods loadNextMessages: (rid, end, limit=20) -> fromId = Meteor.userId() - console.log '[methods] loadNextMessages -> '.green, 'fromId:', fromId, 'rid:', rid, 'end:', end, 'limit:', limit unless Meteor.call 'canAccessRoom', rid, fromId return false diff --git a/server/methods/loadSurroundingMessages.coffee b/server/methods/loadSurroundingMessages.coffee index 926cbfdc496..0d63b37531c 100644 --- a/server/methods/loadSurroundingMessages.coffee +++ b/server/methods/loadSurroundingMessages.coffee @@ -1,7 +1,6 @@ Meteor.methods loadSurroundingMessages: (message, limit=50) -> fromId = Meteor.userId() - console.log '[methods] loadSurroundingMessages -> '.green, 'fromId:', fromId, 'message:', message, 'limit:', limit unless message?.rid return false -- GitLab From e32b23d39936c995f457f10fab2469864a6ea699 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 15:04:45 -0200 Subject: [PATCH 0925/1338] removed logs --- server/methods/messageSearch.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/methods/messageSearch.coffee b/server/methods/messageSearch.coffee index 0f1a714d392..acd9da18c67 100644 --- a/server/methods/messageSearch.coffee +++ b/server/methods/messageSearch.coffee @@ -4,8 +4,6 @@ Meteor.methods text = 'from:rodrigo mention:gabriel chat' ### - # console.log '[method] -> messageSearch', text - result = messages: [] users: [] -- GitLab From d2ec5ddf5a63a6cad6f67ee4089a5bc47fbd5021 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 15:09:55 -0200 Subject: [PATCH 0926/1338] Removed unused code --- packages/rocketchat-ui/lib/RoomHistoryManager.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index b723525d950..26637145a37 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -14,12 +14,12 @@ return histories[rid] - getMore = (rid, limit=defaultLimit, setLoading=true) -> + getMore = (rid, limit=defaultLimit) -> room = getRoom rid if room.hasMore.curValue isnt true return - room.isLoading.set true if setLoading + room.isLoading.set true # ScrollListener.setLoader true lastMessage = ChatMessage.findOne({rid: rid}, {sort: {ts: 1}}) @@ -58,12 +58,12 @@ readMessage.refreshUnreadMark(rid, true) RoomManager.updateMentionsMarksOfRoom typeName - room.isLoading.set false if setLoading + room.isLoading.set false room.loaded += result?.messages?.length if result?.messages?.length < limit room.hasMore.set false - getMoreNext = (rid, limit=defaultLimit, setLoading=true) -> + getMoreNext = (rid, limit=defaultLimit) -> room = getRoom rid if room.hasMoreNext.curValue isnt true return @@ -71,7 +71,7 @@ instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() instance.atBottom = false - room.isLoading.set true if setLoading + room.isLoading.set true lastMessage = ChatMessage.findOne({rid: rid}, {sort: {ts: -1}}) @@ -96,7 +96,7 @@ Meteor.defer -> RoomManager.updateMentionsMarksOfRoom typeName - room.isLoading.set false if setLoading + room.isLoading.set false room.loaded += result.messages.length if result.messages.length < limit room.hasMoreNext.set false -- GitLab From 82cc98887f18853966af619bcf886131c9769695 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 15:11:33 -0200 Subject: [PATCH 0927/1338] Removed unused code --- packages/rocketchat-ui/lib/RoomHistoryManager.coffee | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index 26637145a37..e6aa25d6bb6 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -155,10 +155,8 @@ return room.hasMore.get() - hasMoreNext = (rid, override) -> + hasMoreNext = (rid) -> room = getRoom rid - if override? - room.hasMoreNext.set(override) return room.hasMoreNext.get() @@ -169,10 +167,8 @@ getMore rid - isLoading = (rid, override) -> + isLoading = (rid) -> room = getRoom rid - if override? - room.isLoading.set(override) return room.isLoading.get() clear = (rid) -> -- GitLab From bbbbdca79747aa2410f3a92bd90312a7395dd020 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 16:52:56 -0200 Subject: [PATCH 0928/1338] Changes to layout and added infinite scroll to mentions bar --- .../server/models/Messages.coffee | 1 + .../client/views/mentionsFlexTab.coffee | 15 +++++++- .../client/views/mentionsFlexTab.html | 38 +++++++++++-------- .../views/stylesheets/mentionsFlexTab.less | 13 ++++++- .../i18n/en.i18n.json | 2 +- .../rocketchat-mentions-flextab/package.js | 1 + .../publications/mentionedMessages.coffee | 4 +- .../message/message.coffee | 5 ++- server/startup/migrations/v26.coffee | 5 +++ 9 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 server/startup/migrations/v26.coffee diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 86033b373ec..70c01de066b 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -155,6 +155,7 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base msg: '' t: 'rm' urls: [] + mentions: [] attachments: [] editedAt: new Date() editedBy: diff --git a/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee index 387221897d6..9d693cf3e5a 100644 --- a/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee +++ b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.coffee @@ -8,9 +8,17 @@ Template.mentionsFlexTab.helpers 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 => - @subscribe 'mentionedMessages', @data.rid + 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) -> @@ -25,3 +33,8 @@ Template.mentionsFlexTab.events $(".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 index 0df447c6aee..8675f5c251b 100644 --- a/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html +++ b/packages/rocketchat-mentions-flextab/client/views/mentionsFlexTab.html @@ -1,22 +1,28 @@ <template name="mentionsFlexTab"> - <div class="control"> - <div class="header"> - <h2>{{_ "Mentions"}}</h2> - </div> - </div> - <ul class="mentioned-messages-list scrollable"> - {{#if Template.subscriptionsReady}} - {{#if hasMessages}} + <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}} - {{else}} - <li class="empty"> - {{_ "No_mentioned_messages"}} - </li> + {{#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}} - {{else}} - {{> loading}} - {{/if}} - </ul> + </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 index 286c60f92b5..a8956d799c8 100644 --- a/packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less +++ b/packages/rocketchat-mentions-flextab/client/views/stylesheets/mentionsFlexTab.less @@ -1,6 +1,4 @@ .mentioned-messages-list { - padding: 70px 0 30px 0; - &.notready { background-image: url(/images/logo/loading.gif); background-repeat: no-repeat; @@ -34,4 +32,15 @@ } } } + + .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/en.i18n.json b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json index 0c7248f50bb..3926c286187 100644 --- a/packages/rocketchat-mentions-flextab/i18n/en.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json @@ -1,5 +1,5 @@ { "Jump_to_message": "Jump to message", "Mentions": "Mentions", - "No_mentioned_messages": "No mentioned messages" + "No_mentions_found": "No mentions found" } diff --git a/packages/rocketchat-mentions-flextab/package.js b/packages/rocketchat-mentions-flextab/package.js index 856e52ebc3e..d52f8ada438 100644 --- a/packages/rocketchat-mentions-flextab/package.js +++ b/packages/rocketchat-mentions-flextab/package.js @@ -10,6 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', + 'underscore', 'less@2.5.0', 'rocketchat:lib@0.0.1' ]); diff --git a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee index eafac320362..3294914cffe 100644 --- a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee +++ b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee @@ -1,4 +1,4 @@ -Meteor.publish 'mentionedMessages', (rid, options = {}) -> +Meteor.publish 'mentionedMessages', (rid, limit=50) -> unless this.userId return this.ready() @@ -8,7 +8,7 @@ Meteor.publish 'mentionedMessages', (rid, options = {}) -> unless user return this.ready() - cursorHandle = RocketChat.models.Messages.findByMentionAndRoomId(user.username, rid, { sort: { ts: -1 }, limit: 50 }).observeChanges + cursorHandle = RocketChat.models.Messages.findByMentionAndRoomId(user.username, rid, { sort: { ts: -1 }, limit: limit }).observeChanges added: (_id, record) -> record.mentionedList = true publication.added('rocketchat_mentioned_message', _id, record) diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index f4d7bf981a9..144ec4a3223 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -123,7 +123,10 @@ Template.message.onViewRendered = (context) -> $previousNode = $(previousNode) $nextNode = $(nextNode) - if previousNode?.dataset? + unless previousNode? + $currentNode.addClass('new-day').removeClass('sequential') + + else if previousNode?.dataset? previousDataset = previousNode.dataset if previousDataset.date isnt currentDataset.date diff --git a/server/startup/migrations/v26.coffee b/server/startup/migrations/v26.coffee new file mode 100644 index 00000000000..2e45ece8dcf --- /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 }) -- GitLab From 93d807cd9bb01b703cb150a3f6f7562fa8a0b819 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 18 Dec 2015 17:42:30 -0200 Subject: [PATCH 0929/1338] get next agent on queue --- .../server/lib/getNextAgent.js | 28 +++++++++ .../server/methods/registerGuest.js | 5 +- .../server/methods/sendMessageLivechat.js | 21 ++++--- .../server/models/Users.js | 59 +++++++++++++++++++ 4 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 packages/rocketchat-livechat/server/lib/getNextAgent.js diff --git a/packages/rocketchat-livechat/server/lib/getNextAgent.js b/packages/rocketchat-livechat/server/lib/getNextAgent.js new file mode 100644 index 00000000000..1e9aba08673 --- /dev/null +++ b/packages/rocketchat-livechat/server/lib/getNextAgent.js @@ -0,0 +1,28 @@ +this.getNextAgent = function(department) { + var agentFilter = {}; + + // find agents from that department + if (department) { + var agents = RocketChat.models.LivechatDepartment.getNextAgent(department); + + if (!agents) { + return; + } + + // sort = { + // count: 1, + // order: 1, + // 'user.name': 1 + // } + + // update = { + // $inc: { + // count: 1 + // } + // } + + // queueUser = findAndModify query, sort, update + } else { + return RocketChat.models.Users.getNextAgent(); + } +}; diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js index 41d03d498aa..c79b9c68761 100644 --- a/packages/rocketchat-livechat/server/methods/registerGuest.js +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -1,8 +1,9 @@ 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 }, { @@ -10,9 +11,11 @@ Meteor.methods({ _id: 1 } }); + if (user != null) { throw new Meteor.Error('token-already-exists', 'Token already exists'); } + while (true) { qt = Meteor.users.find({ 'profile.guest': true diff --git a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js index 75ea02c52d7..90125c25dee 100644 --- a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js +++ b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js @@ -1,29 +1,28 @@ Meteor.methods({ sendMessageLivechat: function(message) { - var guest, operator, room; - console.log('sendMessageLivechat ->', arguments); + var guest, agent, room; + 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'); + agent = getNextAgent(); + 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: [operator.username, guest.username], + usernames: [agent.username, guest.username], t: 'l', ts: new Date(), v: { @@ -38,8 +37,8 @@ Meteor.methods({ unread: 1, answered: false, u: { - _id: operator._id, - username: operator.username + _id: agent._id, + username: agent.username }, t: 'l' }); diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index 1481564cf1d..a485e921c2f 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -13,6 +13,65 @@ 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: {} + }; + + query.roles[Roles.GLOBAL_GROUP] = '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' + }; + + query['roles.' + Roles.GLOBAL_GROUP] = '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 + } + }; + + return findAndModify(query, sort, update); +}; + /** * Gets visitor by token * @param {string} token - Visitor token -- GitLab From ae95c03a6e40f14108ee4dbe150e3b74c3eb5dce Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 18 Dec 2015 14:53:36 -0500 Subject: [PATCH 0930/1338] Explain the available docker images --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 63a6ac2e7af..2ed068e5d15 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,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 in-development code](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:develop +``` + +OR the latest available stable (master) branch code: +``` +docker pull rocketchat/rocket.chat:lastest +``` + +OR our [official docker registry image](https://hub.docker.com/_/rocket.chat/), containing recent MAJOR release: + +``` +docker pull rocket.chat ``` ## FreeBSD -- GitLab From aace1ad7dcd0b2f815402162ea7343f610b54c70 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 18 Dec 2015 18:22:53 -0200 Subject: [PATCH 0931/1338] Fix pin and star --- i18n/en.i18n.json | 1 + .../i18n/en.i18n.json | 1 - .../client/actionButton.coffee | 17 +++++++- .../client/views/pinnedMessages.coffee | 32 +++++++++++--- .../client/views/pinnedMessages.html | 42 +++++++++++-------- .../client/views/stylesheets/messagepin.less | 28 +++++++++++-- packages/rocketchat-message-pin/package.js | 1 + .../server/publications/pinnedMessages.coffee | 8 +++- .../client/actionButton.coffee | 10 +++++ .../client/views/starredMessages.coffee | 29 ++++++++++--- .../client/views/starredMessages.html | 42 +++++++++++-------- .../client/views/stylesheets/messagestar.less | 28 +++++++++++-- packages/rocketchat-message-star/package.js | 1 + .../publications/starredMessages.coffee | 8 +++- packages/rocketchat-ui/views/app/room.coffee | 2 + 15 files changed, 192 insertions(+), 58 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9e3b6b9adc5..e5130c8b9fc 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -216,6 +216,7 @@ "join" : "Join", "Join_the_Community" : "Join the Community", "Jump_to_recent_messages" : "Jump to recent messages", + "Jump_to_message" : "Jump to message", "Language" : "Language", "Language_Version" : "English Version", "Last_login" : "Last login", diff --git a/packages/rocketchat-mentions-flextab/i18n/en.i18n.json b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json index 3926c286187..d10a1b3e70f 100644 --- a/packages/rocketchat-mentions-flextab/i18n/en.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json @@ -1,5 +1,4 @@ { - "Jump_to_message": "Jump to message", "Mentions": "Mentions", "No_mentions_found": "No mentions found" } diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index 78527e098fd..82ae2968caf 100644 --- a/packages/rocketchat-message-pin/client/actionButton.coffee +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -4,6 +4,8 @@ Meteor.startup -> icon: 'icon-pin' i18nLabel: 'Pin_Message' action: (event, instance) -> + event.preventDefault() + event.stopPropagation() message = @_arguments[1] message.pinned = true Meteor.call 'pinMessage', message, (error, result) -> @@ -21,9 +23,11 @@ Meteor.startup -> RocketChat.MessageAction.addButton id: 'unpin-message' - icon: 'icon-pin' + icon: 'icon-eraser' i18nLabel: 'Unpin_Message' action: (event, instance) -> + event.preventDefault() + event.stopPropagation() message = @_arguments[1] message.pinned = false Meteor.call 'unpinMessage', message, (error, result) -> @@ -38,3 +42,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/views/pinnedMessages.coffee b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee index c60783c49ef..85720f1dd35 100644 --- a/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee +++ b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee @@ -1,16 +1,27 @@ 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 +29,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 d1c470c7f41..8122f0c580b 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 de3c15683ba..7ae754328f4 100644 --- a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less +++ b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less @@ -1,6 +1,14 @@ -.pinned-messages-list { - padding: 30px 0; +.messages-box { + .message-cog-container { + .message-action { + &.jump-to-pin-message { + display: none !important; + } + } + } +} +.pinned-messages-list { &.notready { background-image: url(/images/logo/loading.gif); background-repeat: no-repeat; @@ -19,8 +27,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/package.js b/packages/rocketchat-message-pin/package.js index 69f0358da29..0d6c5deec59 100644 --- a/packages/rocketchat-message-pin/package.js +++ b/packages/rocketchat-message-pin/package.js @@ -9,6 +9,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', + 'underscore', 'less@2.5.0', 'rocketchat:lib@0.0.1' ]); diff --git a/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee index 044078e5599..efa77f81456 100644 --- a/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee +++ b/packages/rocketchat-message-pin/server/publications/pinnedMessages.coffee @@ -1,10 +1,14 @@ -Meteor.publish 'pinnedMessages', (rid, options = {}) -> +Meteor.publish 'pinnedMessages', (rid, limit=50) -> unless this.userId return this.ready() 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 02d25daf7e7..42d0f7a0172 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/views/starredMessages.coffee b/packages/rocketchat-message-star/client/views/starredMessages.coffee index 24124e12f4f..6565b5f8222 100644 --- a/packages/rocketchat-message-star/client/views/starredMessages.coffee +++ b/packages/rocketchat-message-star/client/views/starredMessages.coffee @@ -1,16 +1,24 @@ 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 +26,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 38724f43a20..b1bdc184762 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 b31cb69553a..718f1528d4d 100644 --- a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less +++ b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less @@ -1,6 +1,14 @@ -.starred-messages-list { - padding: 30px 0; +.messages-box { + .message-cog-container { + .message-action { + &.jump-to-star-message { + display: none !important; + } + } + } +} +.starred-messages-list { &.notready { background-image: url(/images/logo/loading.gif); background-repeat: no-repeat; @@ -19,8 +27,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/package.js b/packages/rocketchat-message-star/package.js index 6073d2bad81..5d8d80da318 100644 --- a/packages/rocketchat-message-star/package.js +++ b/packages/rocketchat-message-star/package.js @@ -10,6 +10,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', + 'underscore', 'less@2.5.0', 'rocketchat:lib@0.0.1' ]); diff --git a/packages/rocketchat-message-star/server/publications/starredMessages.coffee b/packages/rocketchat-message-star/server/publications/starredMessages.coffee index 7bb020c7af1..51d664d7653 100644 --- a/packages/rocketchat-message-star/server/publications/starredMessages.coffee +++ b/packages/rocketchat-message-star/server/publications/starredMessages.coffee @@ -1,10 +1,14 @@ -Meteor.publish 'starredMessages', (rid, options = {}) -> +Meteor.publish 'starredMessages', (rid, limit=50) -> unless this.userId return this.ready() 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-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 076f5b6f856..88bc0282ed7 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -352,6 +352,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') -- GitLab From db5370aeded4fbf34c4089dd9c685f10c26cdb06 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 18 Dec 2015 21:16:35 -0500 Subject: [PATCH 0932/1338] Support calls from client / browsers Most modern browser will issue a pre-flight request with HTTP OPTION method before the actual asynchronous POST. This adds a CORS supporting option endpoint. --- packages/rocketchat-integrations/server/api/api.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 2700dd9d553..068df884161 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -1,5 +1,5 @@ Api = new Restivus - enableCors: false + enableCors: true apiPath: 'hooks/' auth: user: -> -- GitLab From d0ac42bfd9e2154d1d97a9ef48c067a87d426237 Mon Sep 17 00:00:00 2001 From: "Christopher S. Case" <chris.case@g33xnexus.com> Date: Fri, 18 Dec 2015 22:28:24 -0600 Subject: [PATCH 0933/1338] Fixed several english issues. --- i18n/en.i18n.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9e3b6b9adc5..20b6e6757f3 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -423,7 +423,7 @@ "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_online_users" : "Showing <b>__total_online__</b> of __total__ users", "Showing_results" : "<p>Showing <b>%s</b> results</p>", "Silence" : "Silence", @@ -535,8 +535,8 @@ "Yes_clear_all" : "Yes, clear all!", "Yes_delete_it" : "Yes, delete it!", "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_can_use_an_emoji_as_avatar" : "You can use an emoji as avatar", + "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", -- GitLab From 7e9fa0a3e658dcf9e1c4b13aff40fb75d3fa539c Mon Sep 17 00:00:00 2001 From: sweetvvck <sweetvvck@gmail.com> Date: Sun, 20 Dec 2015 02:03:22 +0800 Subject: [PATCH 0934/1338] Settings for server default language #1614 Add the ability to set the default language for new users. Admin can set server default language in admin/General section. --- client/startup/startup.coffee | 26 +++++++++---------- .../server/startup/settings.coffee | 1 + .../account/accountProfile.coffee | 2 +- .../rocketchat-ui-admin/admin/admin.coffee | 11 ++++++++ packages/rocketchat-ui-admin/admin/admin.html | 8 ++++++ .../side-nav/accountBox.coffee | 3 +++ 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee index 1d590b55508..157f29fd2f3 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,6 +18,9 @@ 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) -> @@ -35,17 +38,14 @@ Meteor.startup -> Function(localeFn)() moment.locale(language) - Tracker.autorun (c) -> - if Meteor.user()?.language? - c.stop() - - if localStorage.getItem('userLanguage') isnt Meteor.user().language - localStorage.setItem("userLanguage", Meteor.user().language) - setLanguage Meteor.user().language - if isRtl localStorage.getItem "userLanguage" - $('html').addClass "rtl" + 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) + if isRtl localStorage.getItem 'userLanguage' + $('html').addClass "rtl" - setLanguage userLanguage + setLanguage userLanguage + ) diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 7f7abc9d663..0393c868e50 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -72,6 +72,7 @@ RocketChat.settings.addGroup 'FileUpload', -> 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' } diff --git a/packages/rocketchat-ui-account/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee index 78c1828d504..e0fecee6265 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 (localStorage.getItem('userLanguage') or Meteor.user().language or defaultUserLanguage())?.split('-').shift().toLowerCase() is key realname: -> return Meteor.user().name diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index df3c6352c6c..2025c3d4d09 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -9,6 +9,17 @@ Template.admin.helpers + languages: -> + languages = TAPi18n.getLanguages() + result = [] + for key, language of languages + result.push _.extend(language, { key: key }) + return _.sortBy(result, 'key') + + appLanguage: (key) -> + selected = (RocketChat.settings.get('Language') or defaultUserLanguage())?.split('-').shift().toLowerCase() is key + return selected + group: -> group = FlowRouter.getParam('group') group ?= TempSettings.findOne({ type: 'group' })?._id diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 264ac8d168f..beeafd6a11d 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -70,6 +70,14 @@ </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 class="input-monitor minicolors" type="text" name="{{_id}}" value="{{value}}" {{isDisabled}}/> {{/if}} diff --git a/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee index b5e470d32de..2f4fffa8872 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee @@ -36,6 +36,9 @@ Template.accountBox.events user = Meteor.user() Meteor.logout -> FlowRouter.go 'home' + # remove userLanguage in localStorage + # in case of another account with different language login + localStorage.removeItem('userLanguage') Meteor.call('logoutCleanUp', user) 'click #avatar': (event) -> -- GitLab From 24f5cc179a82c6f842753b2110311bcfb7ad8ba4 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 19 Dec 2015 20:32:20 -0200 Subject: [PATCH 0935/1338] Add hover background color for messages --- packages/rocketchat-theme/assets/stylesheets/base.less | 3 +++ packages/rocketchat-theme/i18n/en.i18n.json | 3 ++- packages/rocketchat-theme/server/variables.coffee | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 993de0a3c33..97a79762fce 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2483,6 +2483,9 @@ a.github-fork { &:nth-child(1) { margin-top: 0; } + &:hover { + background-color: @message-hover-background-color; + } &.new-day { margin-top: 60px; } diff --git a/packages/rocketchat-theme/i18n/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json index 1cac00320b1..c5fe1f01490 100644 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -8,6 +8,7 @@ "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-secondary-background-color" : "Secondary Background Color", @@ -20,4 +21,4 @@ "theme-color-status-online" : "Online Status Color", "theme-color-tertiary-background-color" : "Tertiary Background Color", "theme-color-tertiary-font-color" : "Tertiary Font Color" -} \ No newline at end of file +} diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee index 9830698b0e8..2ffe15d83d9 100644 --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -19,3 +19,4 @@ 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 "message-hover-background-color", "#f9f9f9" -- GitLab From 34e32e14139f108774ebd75da73efe8bc37e3efc Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Sun, 20 Dec 2015 01:01:36 -0200 Subject: [PATCH 0936/1338] Fixed pin and star --- client/methods/pinMessage.coffee | 21 --------------- client/methods/unpinMessage.coffee | 21 --------------- .../client/actionButton.coffee | 4 --- .../client/pinMessage.coffee | 26 +++++++++++++++++++ packages/rocketchat-message-pin/package.js | 1 + .../message/message.coffee | 6 ----- packages/rocketchat-ui/views/app/room.coffee | 8 ------ 7 files changed, 27 insertions(+), 60 deletions(-) delete mode 100644 client/methods/pinMessage.coffee delete mode 100644 client/methods/unpinMessage.coffee create mode 100644 packages/rocketchat-message-pin/client/pinMessage.coffee diff --git a/client/methods/pinMessage.coffee b/client/methods/pinMessage.coffee deleted file mode 100644 index a46e6bdde71..00000000000 --- 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/unpinMessage.coffee b/client/methods/unpinMessage.coffee deleted file mode 100644 index a60e28960e3..00000000000 --- 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/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index 82ae2968caf..c7c225c7c6a 100644 --- a/packages/rocketchat-message-pin/client/actionButton.coffee +++ b/packages/rocketchat-message-pin/client/actionButton.coffee @@ -4,8 +4,6 @@ Meteor.startup -> icon: 'icon-pin' i18nLabel: 'Pin_Message' action: (event, instance) -> - event.preventDefault() - event.stopPropagation() message = @_arguments[1] message.pinned = true Meteor.call 'pinMessage', message, (error, result) -> @@ -26,8 +24,6 @@ Meteor.startup -> icon: 'icon-eraser' i18nLabel: 'Unpin_Message' action: (event, instance) -> - event.preventDefault() - event.stopPropagation() message = @_arguments[1] message.pinned = false Meteor.call 'unpinMessage', message, (error, result) -> diff --git a/packages/rocketchat-message-pin/client/pinMessage.coffee b/packages/rocketchat-message-pin/client/pinMessage.coffee new file mode 100644 index 00000000000..7b934880ac4 --- /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/package.js b/packages/rocketchat-message-pin/package.js index 0d6c5deec59..1bd59584268 100644 --- a/packages/rocketchat-message-pin/package.js +++ b/packages/rocketchat-message-pin/package.js @@ -17,6 +17,7 @@ Package.onUse(function(api) { api.addFiles([ 'client/lib/PinnedMessage.coffee', 'client/actionButton.coffee', + 'client/pinMessage.coffee', 'client/tabBar.coffee', 'client/views/pinnedMessages.html', 'client/views/pinnedMessages.coffee', diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 144ec4a3223..3e1b3aef099 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -39,8 +39,6 @@ Template.message.helpers # 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' @@ -61,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: -> diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 88bc0282ed7..f7ea605894a 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -377,14 +377,6 @@ Template.room.events ChatMessage.update {_id: this._arguments[1]._id, 'urls.url': $(event.currentTarget).data('url')}, {$set: {'urls.$.downloadImages': true}} ChatMessage.update {_id: this._arguments[1]._id, 'attachments.image_url': $(event.currentTarget).data('url')}, {$set: {'attachments.$.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) - 'dragenter .dropzone': (e) -> e.currentTarget.classList.add 'over' -- GitLab From 575c6733e8269db2f94837bd04009ab7473c2695 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Sun, 20 Dec 2015 14:29:37 -0200 Subject: [PATCH 0937/1338] Removed logs --- .../server/functions/saveRoomTopic.coffee | 1 - .../server/functions/saveRoomType.coffee | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee b/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee index 6c08f38edfe..6f3a7f24020 100644 --- a/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomTopic.coffee @@ -2,5 +2,4 @@ RocketChat.saveRoomTopic = (rid, roomTopic) -> unless Match.test rid, String throw new Meteor.Error 'invalid-rid' - console.log '[function] RocketChat.saveRoomTopic'.green, rid, roomTopic 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 index 5cd6d4c5259..d990a4b3aee 100644 --- a/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee +++ b/packages/rocketchat-channel-settings/server/functions/saveRoomType.coffee @@ -1,6 +1,4 @@ RocketChat.saveRoomType = (rid, roomType) -> - console.log '[function] RocketChat.saveRoomType'.green, rid, roomType - unless Match.test rid, String throw new Meteor.Error 'invalid-rid' -- GitLab From d5a12dc0dbbff47f7e6f441dff2245d3a408ab36 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Sun, 20 Dec 2015 21:37:01 -0200 Subject: [PATCH 0938/1338] update jalik:ufs to 0.3.4 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index a53608b51cd..179bf18b1d6 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -52,7 +52,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.4 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 -- GitLab From 11b45230d3a0939ee75aabbf06648290e5bb4858 Mon Sep 17 00:00:00 2001 From: k0nsl <i.am@k0nsl.org> Date: Mon, 21 Dec 2015 11:08:28 +0100 Subject: [PATCH 0939/1338] fix URL needs a slash, else url will look like this: `j.src = 'https://domain.tldpackages/rocketchat_livechat/assets/rocket-livechat.js';` --- .../client/views/app/livechatInstallation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/client/views/app/livechatInstallation.js b/packages/rocketchat-livechat/client/views/app/livechatInstallation.js index cbedae2d3b0..339d894e690 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatInstallation.js +++ b/packages/rocketchat-livechat/client/views/app/livechatInstallation.js @@ -8,9 +8,9 @@ Template.livechatInstallation.helpers({ 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'; + 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'); +})(window, document, 'script', 'initRocket', '${RocketChat.settings.get('Site_Url')}/livechat'); </script> <!-- End of Rocket.Chat Livechat Script -->`; } -- GitLab From 870620dc4f4c54b1d1e0f55671e79b303c31fab9 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 21 Dec 2015 09:01:30 -0200 Subject: [PATCH 0940/1338] centralize messages --- packages/rocketchat-theme/assets/stylesheets/base.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 66148ffa0ae..9f15c4dfe6a 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2489,7 +2489,7 @@ a.github-fork { } .message { - padding: 18px 20px 4px 70px; + padding: 11px 20px 11px 70px; position: relative; line-height: 20px; min-height: 40px; @@ -2631,7 +2631,7 @@ a.github-fork { .thumb { position: absolute; left: 20px; - top: 20px; + top: 13px; display: block; width: 40px; height: 40px; -- GitLab From b915fe0f72b72a51be7c683587f8f6e58d6d30b3 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 21 Dec 2015 09:04:01 -0200 Subject: [PATCH 0941/1338] New icon for unpin --- packages/rocketchat-message-pin/client/actionButton.coffee | 2 +- .../client/views/stylesheets/messagepin.less | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-message-pin/client/actionButton.coffee b/packages/rocketchat-message-pin/client/actionButton.coffee index c7c225c7c6a..14f0129ceb8 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-eraser' + icon: 'icon-pin rotate-45' i18nLabel: 'Unpin_Message' action: (event, instance) -> message = @_arguments[1] diff --git a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less index 7ae754328f4..bab90b5664a 100644 --- a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less +++ b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less @@ -1,3 +1,9 @@ +.icon-pin.rotate-45:before { + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + .messages-box { .message-cog-container { .message-action { -- GitLab From 2f19aa1765fe5f71cb53eaa8ba72ee75cdada9a7 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 21 Dec 2015 09:04:25 -0200 Subject: [PATCH 0942/1338] centralize message better --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 9f15c4dfe6a..fe63d5271be 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2631,7 +2631,7 @@ a.github-fork { .thumb { position: absolute; left: 20px; - top: 13px; + top: 11px; display: block; width: 40px; height: 40px; -- GitLab From ac4fa327500e77a7265864a39358c064de99473d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 21 Dec 2015 09:16:26 -0200 Subject: [PATCH 0943/1338] fix avatar position on compact view --- packages/rocketchat-theme/assets/stylesheets/base.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index fe63d5271be..4ba647bb96d 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2762,8 +2762,8 @@ a.github-fork { .compact { .message { padding: 5px 20px 5px 70px; - .thumb:not(.thumb-small) .avatar { - margin-top: -15px; + .thumb { + top: 5px; } } } -- GitLab From 56b316e3bba86a95bc9c6a214bdae09b36629a19 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 21 Dec 2015 09:26:37 -0200 Subject: [PATCH 0944/1338] bump version to 0.10.0 --- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- packages/rocketchat-lib/rocketchat.info | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 908e6daf7f9..9b17fdd10bc 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 = 6, # Increment this for every release. - appMarketingVersion = (defaultText = "0.9.0"), + appMarketingVersion = (defaultText = "0.10.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index 49886ade63f..71143b9710f 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.9.0" + "version": "0.10.0" } -- GitLab From 0f61322047fa617480bb9e3ed0bc1ee63ba6a4df Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 21 Dec 2015 11:45:51 +0000 Subject: [PATCH 0945/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 4 + i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 2 +- i18n/ko.i18n.json | 134 ++++- i18n/pt.i18n.json | 3 +- i18n/ro.i18n.json | 549 ++++++++++++++++++ i18n/ru.i18n.json | 1 + i18n/sq.i18n.json | 4 +- i18n/sr.i18n.json | 67 +++ .../i18n/ko.i18n.json | 9 +- .../i18n/ro.i18n.json | 19 + .../i18n/sr.i18n.json | 4 + .../i18n/ko.i18n.json | 2 +- .../i18n/ro.i18n.json | 8 + .../i18n/sr.i18n.json | 1 + packages/rocketchat-chatops/i18n/ko.i18n.json | 6 +- packages/rocketchat-chatops/i18n/ro.i18n.json | 5 + packages/rocketchat-chatops/i18n/sr.i18n.json | 1 + .../i18n/ko.i18n.json | 5 +- .../i18n/ro.i18n.json | 7 + .../i18n/sr.i18n.json | 1 + packages/rocketchat-gitlab/i18n/ro.i18n.json | 3 + packages/rocketchat-gitlab/i18n/sr.i18n.json | 1 + packages/rocketchat-hubot/i18n/ro.i18n.json | 5 + packages/rocketchat-hubot/i18n/sr.i18n.json | 1 + packages/rocketchat-ldap/i18n/ro.i18n.json | 3 + packages/rocketchat-ldap/i18n/sr.i18n.json | 1 + packages/rocketchat-lib/i18n/de.i18n.json | 4 +- packages/rocketchat-lib/i18n/en.i18n.json | 8 +- packages/rocketchat-lib/i18n/fi.i18n.json | 4 +- packages/rocketchat-lib/i18n/fr.i18n.json | 4 +- packages/rocketchat-lib/i18n/hr.i18n.json | 4 +- packages/rocketchat-lib/i18n/km.i18n.json | 4 +- packages/rocketchat-lib/i18n/ko.i18n.json | 4 +- packages/rocketchat-lib/i18n/ms-MY.i18n.json | 4 +- packages/rocketchat-lib/i18n/pl.i18n.json | 4 +- packages/rocketchat-lib/i18n/pt.i18n.json | 4 +- packages/rocketchat-lib/i18n/ro.i18n.json | 7 + packages/rocketchat-lib/i18n/sr.i18n.json | 1 + packages/rocketchat-lib/i18n/tr.i18n.json | 4 +- packages/rocketchat-lib/i18n/zh.i18n.json | 4 +- .../rocketchat-livechat/app/i18n/en.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/fi.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/ko.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/ro.i18n.json | 17 + .../rocketchat-livechat/app/i18n/sr.i18n.json | 3 + .../rocketchat-livechat/i18n/en.i18n.json | 30 +- .../rocketchat-livechat/i18n/fi.i18n.json | 8 +- .../rocketchat-livechat/i18n/ko.i18n.json | 6 +- .../rocketchat-livechat/i18n/ro.i18n.json | 51 ++ .../rocketchat-livechat/i18n/sr.i18n.json | 1 + packages/rocketchat-mailer/i18n/ko.i18n.json | 4 +- packages/rocketchat-mailer/i18n/ro.i18n.json | 19 + packages/rocketchat-mailer/i18n/sr.i18n.json | 1 + .../i18n/ar.i18n.json | 1 + .../i18n/cs.i18n.json | 1 + .../i18n/de.i18n.json | 1 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 6 +- .../i18n/es.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 1 + .../i18n/fr.i18n.json | 1 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 1 + .../i18n/ko.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 1 + .../i18n/ro.i18n.json | 4 + .../i18n/ru.i18n.json | 1 + .../i18n/sq.i18n.json | 1 + .../i18n/sr.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + .../rocketchat-message-pin/i18n/ko.i18n.json | 1 + .../rocketchat-message-pin/i18n/ro.i18n.json | 10 + .../rocketchat-message-pin/i18n/sr.i18n.json | 1 + .../rocketchat-message-star/i18n/ko.i18n.json | 8 +- .../rocketchat-message-star/i18n/ro.i18n.json | 7 + .../rocketchat-message-star/i18n/sr.i18n.json | 1 + .../i18n/ko.i18n.json | 1 + .../i18n/ro.i18n.json | 5 + .../i18n/sr.i18n.json | 1 + .../i18n/ko.i18n.json | 3 +- .../i18n/ro.i18n.json | 4 + .../i18n/sr.i18n.json | 1 + .../i18n/ar.i18n.json | 1 + .../i18n/cs.i18n.json | 1 + .../i18n/de.i18n.json | 1 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 2 +- .../i18n/es.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 1 + .../i18n/fr.i18n.json | 1 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 1 + .../i18n/ko.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 1 + .../i18n/ro.i18n.json | 5 + .../i18n/ru.i18n.json | 1 + .../i18n/sq.i18n.json | 1 + .../i18n/sr.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + .../i18n/ar.i18n.json | 1 + .../i18n/cs.i18n.json | 1 + .../i18n/de.i18n.json | 1 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 4 +- .../i18n/es.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 1 + .../i18n/fr.i18n.json | 1 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 1 + .../i18n/ko.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 1 + .../i18n/ro.i18n.json | 4 + .../i18n/ru.i18n.json | 1 + .../i18n/sq.i18n.json | 1 + .../i18n/sr.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + packages/rocketchat-theme/i18n/en.i18n.json | 2 +- packages/rocketchat-theme/i18n/ko.i18n.json | 5 + packages/rocketchat-theme/i18n/ro.i18n.json | 24 + packages/rocketchat-theme/i18n/sr.i18n.json | 1 + packages/rocketchat-webrtc/i18n/ko.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/ro.i18n.json | 5 + packages/rocketchat-webrtc/i18n/sr.i18n.json | 1 + .../rocketchat-wordpress/i18n/ro.i18n.json | 6 + .../rocketchat-wordpress/i18n/sr.i18n.json | 1 + 171 files changed, 1161 insertions(+), 102 deletions(-) create mode 100644 i18n/ro.i18n.json create mode 100644 i18n/sr.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/ro.i18n.json create mode 100644 packages/rocketchat-authorization/i18n/sr.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/ro.i18n.json create mode 100644 packages/rocketchat-channel-settings/i18n/sr.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/ro.i18n.json create mode 100644 packages/rocketchat-chatops/i18n/sr.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/ro.i18n.json create mode 100644 packages/rocketchat-github-enterprise/i18n/sr.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/ro.i18n.json create mode 100644 packages/rocketchat-gitlab/i18n/sr.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/ro.i18n.json create mode 100644 packages/rocketchat-hubot/i18n/sr.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/ro.i18n.json create mode 100644 packages/rocketchat-ldap/i18n/sr.i18n.json create mode 100644 packages/rocketchat-lib/i18n/ro.i18n.json create mode 100644 packages/rocketchat-lib/i18n/sr.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/ro.i18n.json create mode 100644 packages/rocketchat-livechat/app/i18n/sr.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/ro.i18n.json create mode 100644 packages/rocketchat-livechat/i18n/sr.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/ro.i18n.json create mode 100644 packages/rocketchat-mailer/i18n/sr.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ar.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/cs.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/de.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/el.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/es.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/fa.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/fi.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/fr.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/he.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/hr.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/hu.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/it.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ja.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/km.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ko.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ku.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/lo.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/nl.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/pl.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/pt.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ro.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ru.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/sq.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/sr.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/sv.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/tr.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/ug.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/uk.i18n.json create mode 100644 packages/rocketchat-mentions-flextab/i18n/zh.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/ro.i18n.json create mode 100644 packages/rocketchat-message-pin/i18n/sr.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/ro.i18n.json create mode 100644 packages/rocketchat-message-star/i18n/sr.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/ro.i18n.json create mode 100644 packages/rocketchat-slashcommands-invite/i18n/sr.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/ro.i18n.json create mode 100644 packages/rocketchat-slashcommands-join/i18n/sr.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/cs.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/de.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/el.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/es.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/fa.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/he.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/hu.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/it.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ja.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/km.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ko.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ku.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/lo.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/pl.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/pt.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ro.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/sq.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/sr.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/sv.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/tr.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/ug.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/uk.i18n.json create mode 100644 packages/rocketchat-slashcommands-kick/i18n/zh.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/cs.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/de.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/el.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/es.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/fa.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/he.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/hr.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/hu.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/it.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ja.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/km.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ko.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ku.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/lo.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/pl.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/pt.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ro.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/sq.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/sr.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/sv.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/tr.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/ug.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/uk.i18n.json create mode 100644 packages/rocketchat-slashcommands-mute/i18n/zh.i18n.json create mode 100644 packages/rocketchat-theme/i18n/ro.i18n.json create mode 100644 packages/rocketchat-theme/i18n/sr.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/ro.i18n.json create mode 100644 packages/rocketchat-webrtc/i18n/sr.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/ro.i18n.json create mode 100644 packages/rocketchat-wordpress/i18n/sr.i18n.json diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index d2e04cbfc21..1a15ba521b0 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -70,7 +70,11 @@ "Invisible" : "Ø®ÙÙŠ", "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" : "إنظم للمجتمع", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index d2bb0502310..ac4a3d43827 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -546,4 +546,4 @@ "Your_entry_has_been_deleted" : "Your entry has been deleted.", "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 c6aaef8871e..6170d15aa97 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -369,6 +369,7 @@ "Restart" : "Käynnistä uudelleen", "Restart_the_server" : "Käynnistä palvelin uudelleen", "Room" : "Huone", + "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", @@ -454,7 +455,6 @@ "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_field_is_required" : "Kenttä %s vaaditaan.", "The_server_will_restart_in_s_seconds" : "Palvelin käynnistyy %s sekunnin kuluttua", "There_is_no_integrations" : "Integraatioita ei ole", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index b066ea7f2af..f75a22a35ac 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" : "최근", @@ -271,14 +327,23 @@ "Remove_Admin" : "ê´€ë¦¬ìž ê¶Œí•œ ì œê±°", "Remove_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth ì œê±°", "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 +368,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 +384,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 +407,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 +435,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 +458,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/pt.i18n.json b/i18n/pt.i18n.json index a325142ef25..e0b6c02842d 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -397,7 +397,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", @@ -458,4 +457,4 @@ "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source", "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" -} +} \ No newline at end of file diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json new file mode 100644 index 00000000000..659ff4c29e0 --- /dev/null +++ b/i18n/ro.i18n.json @@ -0,0 +1,549 @@ +{ + "Access_not_authorized" : "Acces neautorizat", + "Access_online_demo" : "AccesaÈ›i demo on-line", + "Access_Online_Demo" : "Accesati Demo Online", + "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_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", + "Activate" : "Activează", + "Add_custom_oauth" : "Adaugă OAuth personalizat", + "Add_Members" : "Adaugă membri", + "Add_users" : "Adaugă utilizatori", + "Administration" : "Administrare", + "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", + "are_also_typing" : "tastează", + "are_typing" : "tastează", + "Are_you_sure" : "Sigur doriÈ›i asta?", + "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" : "away", + "Away" : "Away", + "away_female" : "away", + "Away_female" : "Away", + "away_male" : "away", + "Away_male" : "Away", + "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?", + "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_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_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", + "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_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_the_Community" : "IntraÈ›i în comunitate", + "Jump_to_recent_messages" : "Salt la mesajele recente", + "Jump_to_message" : "Salt la mesaj", + "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. Detalilei 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...", + "Login" : "Login", + "Login_with" : "Autentifică-te cu %s", + "login_with" : "Sau de conectare direct cu", + "Logout" : "IeÈ™ire", + "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", + "Unmute_user" : "Deblochează mesajele utilizatorului", + "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_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_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ă", + "Old_and_new_password_required" : "Trebuie să introduceÈ›i È™i parola veche È™i cea nouă pentru a schimba parola.", + "Old_Password" : "Parola veche", + "Online" : "Doar online", + "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_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ă", + "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_custom_oauth" : "EliminaÈ›i OAuth personalizat", + "Remove_from_room" : "EliminaÈ›i din cameră", + "Reset_password" : "Resetează parola", + "Restart" : "Repornire", + "Restart_the_server" : "ReporniÈ›i serverul", + "Room" : "Cameră", + "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_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_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.", + "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_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_Username" : "Nume de utilizator SMTP ", + "Sound" : "Sunet", + "Start_of_conversation" : "ÃŽnceputul conversaÈ›iei", + "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 Online", + "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_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_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>!", + "There_is_no_integrations" : "Nu sunt integrări", + "This_is_a_push_test_messsage" : "Acesta este un test de notificare Push", + "True" : "Adevărat", + "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_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_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_in_room" : "Utilizator blocat în cameră", + "User_unmuted_in_room" : "Utilizator deblocat î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_muted_by" : "Utilizatorul <em>__user_muted__</em> a fost blocat de către  <em>__user_by__</em>.", + "User_unmuted_by" : "Utilizatorul <em>__user_muted__</em> a fost deblocat de către <em>__user_by__</em>.", + "User_removed_from_room" : "Utilizatorul a fost scos din cameră", + "User_Settings" : "Setări utilizator", + "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", + "With_whom" : "Cu cine", + "Yes" : "Da", + "Yes_clear_all" : "Da, È™terge toate!", + "Yes_delete_it" : "Da, È™terge-l!", + "you_are_in_preview_mode_of" : "Vă aflaÈ›i în modul de previzualizare a canalului #", + "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_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 4295b405854..4dba7e58655 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -13,6 +13,7 @@ "Accounts_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", "Add_Members" : "Добавить Пользователей", "Add_users" : "Добавить пользователей", + "Administration" : "ÐдминиÑтрациÑ", "All_channels" : "Ð’Ñе Чаты", "and" : "и", "API_Analytics" : "Ðналитика", diff --git a/i18n/sq.i18n.json b/i18n/sq.i18n.json index 364aaf1e358..b3a8f83dc98 100644 --- a/i18n/sq.i18n.json +++ b/i18n/sq.i18n.json @@ -12,7 +12,7 @@ "Contact" : "Kontakt", "Conversation" : "Bisedë", "Create_new_public_channel" : "Krijo një kanal të ri publik", - "Direct_Messages" : "Mesazhe të drejtpërdrejta", + "Direct_Messages" : "Mesazhe Private", "edited" : "edited", "Email_or_username" : "Email ose emrin e përdoruesit", "Email_verified" : "Email verifikuar", @@ -55,7 +55,7 @@ "Remove" : "Hiq", "Reset_password" : "Fjalëkalimi i ri", "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", "Search" : "Kërko", "See_all" : "Shih të gjithë", "See_only_online" : "Vetëm online", diff --git a/i18n/sr.i18n.json b/i18n/sr.i18n.json new file mode 100644 index 00000000000..39a02b9d8b4 --- /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/packages/rocketchat-authorization/i18n/ko.i18n.json b/packages/rocketchat-authorization/i18n/ko.i18n.json index a7ed67a8ddf..b7aba81e1d2 100644 --- a/packages/rocketchat-authorization/i18n/ko.i18n.json +++ b/packages/rocketchat-authorization/i18n/ko.i18n.json @@ -1,4 +1,11 @@ { + "Add_user" : "ì‚¬ìš©ìž ì¶”ê°€", + "New_role" : "새로운 ì—í• ", + "Permissions" : "권한", + "Removed" : "ì œê±°ë¨", "Save" : "ì €ìž¥", - "User_added" : "ì‚¬ìš©ìž <em>__user_added__</em> 추가함." + "Saving" : "ì €ìž¥ 중", + "User_added" : "ì‚¬ìš©ìž ì¶”ê°€í•¨.", + "User_not_found" : "사용ìžë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ", + "User_removed" : "ì‚¬ìš©ìž ì œê±°ë¨" } \ No newline at end of file diff --git a/packages/rocketchat-authorization/i18n/ro.i18n.json b/packages/rocketchat-authorization/i18n/ro.i18n.json new file mode 100644 index 00000000000..d842b044a7c --- /dev/null +++ b/packages/rocketchat-authorization/i18n/ro.i18n.json @@ -0,0 +1,19 @@ +{ + "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", + "Removed" : "Eliminat", + "Role" : "Rol", + "Role_Editing" : "Editare rol", + "Role_removed" : "Rol eliminat", + "Save" : "Salvează", + "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/sr.i18n.json b/packages/rocketchat-authorization/i18n/sr.i18n.json new file mode 100644 index 00000000000..4ac5844a96f --- /dev/null +++ b/packages/rocketchat-authorization/i18n/sr.i18n.json @@ -0,0 +1,4 @@ +{ + "Save" : "Сачувај", + "User_added" : "КориÑник/ца додат(а)" +} \ 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 dc45aca964f..ff0d7ecce17 100644 --- a/packages/rocketchat-channel-settings/i18n/ko.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ko.i18n.json @@ -1,6 +1,6 @@ { "Channel" : "채ë„", - "Private_Group" : "ê°œì¸ ê·¸ë£¹", + "Private_Group" : "비밀 그룹", "Room_Type" : "ë°© 종류", "Room_Settings" : "ë°© ì„¤ì •", "room_changed_privacy" : "ë°© 종류가 <em>__user_by__</em>ì—서 <em>__room_type__</em>ë¡œ 변경ë˜ì—ˆìŠµë‹ˆë‹¤.", 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 00000000000..22062b24489 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/ro.i18n.json @@ -0,0 +1,8 @@ +{ + "Channel" : "Canal", + "Private_Group" : "Grup privat", + "Room_Type" : "Tipul camerei", + "Room_Settings" : "Setări cameră", + "room_changed_privacy" : "Tipul camerei schimbat în: <em>__room_type__</em> by <em>__user_by__</em>", + "room_changed_topic" : "Subiectul camerei schimbat în: <em>__room_topic__</em> by <em>__user_by__</em>" +} \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..8d0449b61f8 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/ro.i18n.json b/packages/rocketchat-chatops/i18n/ro.i18n.json new file mode 100644 index 00000000000..62627119a9f --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-chatops/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 bf2ee2cce6a..29d25e822d5 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/ro.i18n.json b/packages/rocketchat-github-enterprise/i18n/ro.i18n.json new file mode 100644 index 00000000000..f685667cfd4 --- /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/sr.i18n.json b/packages/rocketchat-github-enterprise/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /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-gitlab/i18n/ro.i18n.json b/packages/rocketchat-gitlab/i18n/ro.i18n.json new file mode 100644 index 00000000000..aa29615cd10 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-gitlab/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..473424bfab9 --- /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/sr.i18n.json b/packages/rocketchat-hubot/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-hubot/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..22e1aec0e15 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-ldap/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 b0d162a99b6..856cc4134cb 100644 --- a/packages/rocketchat-lib/i18n/de.i18n.json +++ b/packages/rocketchat-lib/i18n/de.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Bearbeiten", - "Delete" : "Löschen" + "Delete" : "Löschen", + "Edit" : "Bearbeiten" } \ 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 4cd67500216..f8de802dbcd 100644 --- a/packages/rocketchat-lib/i18n/en.i18n.json +++ b/packages/rocketchat-lib/i18n/en.i18n.json @@ -1,7 +1,7 @@ { - "All_logs": "All logs", - "Debug_Level": "Debug Level", + "All_logs" : "All logs", + "Debug_Level" : "Debug Level", "Delete" : "Delete", "Edit" : "Edit", - "Only_errors": "Only errors" -} + "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 f283462d8f2..b09cf9fe341 100644 --- a/packages/rocketchat-lib/i18n/fi.i18n.json +++ b/packages/rocketchat-lib/i18n/fi.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Muokkaa", - "Delete" : "Poista" + "Delete" : "Poista", + "Edit" : "Muokkaa" } \ 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 6fcd2330c33..ff32a1bbe74 100644 --- a/packages/rocketchat-lib/i18n/fr.i18n.json +++ b/packages/rocketchat-lib/i18n/fr.i18n.json @@ -1,4 +1,4 @@ { - "Edit" : "Modifier", - "Delete" : "Supprimer" + "Delete" : "Supprimer", + "Edit" : "Modifier" } \ 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 247eb268a3c..487e25187be 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 0db86550f90..6e4efda1491 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 b454f6fb4a3..fc308db9155 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 1c06d12d0c6..bfe97c78cb2 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/pl.i18n.json b/packages/rocketchat-lib/i18n/pl.i18n.json index f0a5a7f12d2..9b98eea9a2a 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 7c1bc08766f..94accdb5b74 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 00000000000..974ae6298ae --- /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/sr.i18n.json b/packages/rocketchat-lib/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /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 230736a8535..fe60600ba2d 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 4a3796cadc9..297bc71c15e 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-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index c921ee74e39..758f3f7bc14 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -14,4 +14,4 @@ "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", "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/fi.i18n.json b/packages/rocketchat-livechat/app/i18n/fi.i18n.json index ec1ed8a50b0..eb1545f92f1 100644 --- a/packages/rocketchat-livechat/app/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fi.i18n.json @@ -1,12 +1,12 @@ { "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?", "Please_answer_survey" : "Käytä hetki vastataksesi pikakyselyyn tästä chatista", "Please_fill_name_and_email" : "Täytä nimi ja sähköpostiosoite", + "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.", diff --git a/packages/rocketchat-livechat/app/i18n/ko.i18n.json b/packages/rocketchat-livechat/app/i18n/ko.i18n.json index c343dee6ac0..4bfdf5366f3 100644 --- a/packages/rocketchat-livechat/app/i18n/ko.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ko.i18n.json @@ -1,3 +1,3 @@ { - "Start_Chat" : "시작 채팅" + "Start_Chat" : "채팅 시작" } \ 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 00000000000..4bfd179c9f7 --- /dev/null +++ b/packages/rocketchat-livechat/app/i18n/ro.i18n.json @@ -0,0 +1,17 @@ +{ + "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", + "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/sr.i18n.json b/packages/rocketchat-livechat/app/i18n/sr.i18n.json new file mode 100644 index 00000000000..65656ff7226 --- /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/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index d64d472d807..072aeddc320 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -5,8 +5,8 @@ "Agent_added" : "Agent added", "Agent_removed" : "Agent removed", "Back" : "Back", - "Closed": "Closed", - "Copy_to_clipboard": "Copy to clipboard", + "Closed" : "Closed", + "Copy_to_clipboard" : "Copy to clipboard", "Dashboard" : "Dashboard", "Department_not_found" : "Department not found", "Department_removed" : "Department removed", @@ -15,7 +15,7 @@ "Edit_Department" : "Edit Department", "Enable" : "Enable", "Enabled" : "Enabled", - "Enter_a_regex": "Enter a regex", + "Enter_a_regex" : "Enter a regex", "Enter_a_username" : "Enter a username", "Live_sessions" : "Live sessions", "Livechat_agents" : "Livechat agents", @@ -28,26 +28,24 @@ "Livechat_Users" : "Livechat Users", "Manager_added" : "Manager added", "Manager_removed" : "Manager removed", - "Message": "Message", - "Name" : "Name", - "Name_of_agent": "Name of agent", + "Name_of_agent" : "Name of agent", "New_Department" : "New Department", "Num_Agents" : "# Agents", - "Opened": "Opened", + "Opened" : "Opened", "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", - "Send_a_message": "Send a message", + "Send_a_message" : "Send a message", "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", + "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", - "Visitor_page_URL": "Visitor page URL", - "Visitor_time_on_site": "Visitor time on site" -} + "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/fi.i18n.json b/packages/rocketchat-livechat/i18n/fi.i18n.json index 0de5eebfc7f..38c2b8035fe 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -5,8 +5,8 @@ "Agent_added" : "Agentti lisätty", "Agent_removed" : "Agentti poistettu", "Back" : "Takaisin", - "Dashboard" : "Kojelauta", - "Department_not_found" : "Osasto ei löytynyt", + "Dashboard" : "Ohjauspaneeli", + "Department_not_found" : "Osastoa ei löytynyt", "Department_removed" : "Osasto poistettu", "Departments" : "Osastot", "Description" : "Kuvaus", @@ -29,8 +29,8 @@ "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", + "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", + "User_management" : "Käyttäjähallinta", "Username_not_found" : "Käyttäjätunnusta ei löydy" } \ 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 6a58a7a6ee1..27f11f7b385 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/ro.i18n.json b/packages/rocketchat-livechat/i18n/ro.i18n.json new file mode 100644 index 00000000000..bd7c08fdab4 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/ro.i18n.json @@ -0,0 +1,51 @@ +{ + "Add" : "Adăugă", + "Add_agent" : "Adaugă agent", + "Add_manager" : "Adauga manager", + "Agent_added" : "Agent adăugat", + "Agent_removed" : "Agent eliminat", + "Back" : "ÃŽnapoi", + "Closed" : "ÃŽnchis", + "Copy_to_clipboard" : "CopiaÈ›i în clipboard", + "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", + "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", + "New_Department" : "Departament nou", + "Num_Agents" : "# AgenÈ›i", + "Opened" : "Deschis", + "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", + "Send_a_message" : "Trimite un mesaj", + "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/sr.i18n.json b/packages/rocketchat-livechat/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-livechat/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 0b3dccd1255..ffc9e58b9aa 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/ro.i18n.json b/packages/rocketchat-mailer/i18n/ro.i18n.json new file mode 100644 index 00000000000..95738094620 --- /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/sr.i18n.json b/packages/rocketchat-mailer/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mailer/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 index d10a1b3e70f..e876e44ba98 100644 --- a/packages/rocketchat-mentions-flextab/i18n/en.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/en.i18n.json @@ -1,4 +1,4 @@ { - "Mentions": "Mentions", - "No_mentions_found": "No mentions found" -} + "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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..1e3a9946515 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-mentions-flextab/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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-message-pin/i18n/ko.i18n.json b/packages/rocketchat-message-pin/i18n/ko.i18n.json index 4feeebeb4f0..fbd8a50499a 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/ro.i18n.json b/packages/rocketchat-message-pin/i18n/ro.i18n.json new file mode 100644 index 00000000000..20534d184df --- /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/sr.i18n.json b/packages/rocketchat-message-pin/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /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-star/i18n/ko.i18n.json b/packages/rocketchat-message-star/i18n/ko.i18n.json index 6f31cf5a2e6..ab22552dc73 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 00000000000..a4e057d9f1d --- /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/sr.i18n.json b/packages/rocketchat-message-star/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /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-slashcommands-invite/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ko.i18n.json index 79dc107036c..784fb685f16 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/ro.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ro.i18n.json new file mode 100644 index 00000000000..ce218ea20e4 --- /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/sr.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /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-join/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ko.i18n.json index 061624dfd78..08976fe9f19 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/ro.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ro.i18n.json new file mode 100644 index 00000000000..e6d2e68d628 --- /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/sr.i18n.json b/packages/rocketchat-slashcommands-join/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /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-kick/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 index 5f448b30f89..4074198404a 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json @@ -2,4 +2,4 @@ "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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..967a28c53f6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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-mute/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/de.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 index f20cd657298..a4c14cecd20 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/en.i18n.json @@ -1,6 +1,4 @@ { - "Username_doesnt_exist" : "The username `#%s` doesn't exist.", - "Username_is_not_in_this_room" : "The user `#%s` is not in this room.", "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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..72303597425 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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-theme/i18n/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json index c5fe1f01490..ec3bfc800cc 100644 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -21,4 +21,4 @@ "theme-color-status-online" : "Online Status Color", "theme-color-tertiary-background-color" : "Tertiary Background Color", "theme-color-tertiary-font-color" : "Tertiary Font 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 eae4ba0da58..fa6ce4e77c6 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/ro.i18n.json b/packages/rocketchat-theme/i18n/ro.i18n.json new file mode 100644 index 00000000000..96f31644dc9 --- /dev/null +++ b/packages/rocketchat-theme/i18n/ro.i18n.json @@ -0,0 +1,24 @@ +{ + "theme-color-blockquote-background" : "Culoare de fundal Blockquote ", + "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-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-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ă" +} \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-theme/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 6f31cf5a2e6..122c0f35f3a 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/ro.i18n.json b/packages/rocketchat-webrtc/i18n/ro.i18n.json new file mode 100644 index 00000000000..c4481eb9923 --- /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/sr.i18n.json b/packages/rocketchat-webrtc/i18n/sr.i18n.json new file mode 100644 index 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-webrtc/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..18fe2bdf946 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-wordpress/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } \ No newline at end of file -- GitLab From a9febe8d13d2ebed8bb14b83b88cffd4f44013a3 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 21 Dec 2015 09:55:59 -0200 Subject: [PATCH 0946/1338] Fix #1709 hide mentions for edited messages when keep history is enabled --- packages/rocketchat-lib/server/models/Messages.coffee | 3 ++- .../server/publications/mentionedMessages.coffee | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 70c01de066b..13e3f8425fa 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -24,8 +24,9 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @find query, options - findByMentionAndRoomId: (username, rid, options) -> + findVisibleByMentionAndRoomId: (username, rid, options) -> query = + _hidden: { $ne: true } "mentions.username": username "rid": rid diff --git a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee index 3294914cffe..72a557e2df8 100644 --- a/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee +++ b/packages/rocketchat-mentions-flextab/server/publications/mentionedMessages.coffee @@ -8,7 +8,7 @@ Meteor.publish 'mentionedMessages', (rid, limit=50) -> unless user return this.ready() - cursorHandle = RocketChat.models.Messages.findByMentionAndRoomId(user.username, rid, { sort: { ts: -1 }, limit: limit }).observeChanges + 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) -- GitLab From 3317126fe245d0c5cc9ebe5d91cd23624ead4844 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 21 Dec 2015 09:57:57 -0200 Subject: [PATCH 0947/1338] code formatting --- .../rocketchat-livechat/i18n/en.i18n.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index d64d472d807..314b3241f0a 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -5,8 +5,8 @@ "Agent_added" : "Agent added", "Agent_removed" : "Agent removed", "Back" : "Back", - "Closed": "Closed", - "Copy_to_clipboard": "Copy to clipboard", + "Closed" : "Closed", + "Copy_to_clipboard" : "Copy to clipboard", "Dashboard" : "Dashboard", "Department_not_found" : "Department not found", "Department_removed" : "Department removed", @@ -15,7 +15,7 @@ "Edit_Department" : "Edit Department", "Enable" : "Enable", "Enabled" : "Enabled", - "Enter_a_regex": "Enter a regex", + "Enter_a_regex" : "Enter a regex", "Enter_a_username" : "Enter a username", "Live_sessions" : "Live sessions", "Livechat_agents" : "Livechat agents", @@ -28,26 +28,26 @@ "Livechat_Users" : "Livechat Users", "Manager_added" : "Manager added", "Manager_removed" : "Manager removed", - "Message": "Message", + "Message" : "Message", "Name" : "Name", - "Name_of_agent": "Name of agent", + "Name_of_agent" : "Name of agent", "New_Department" : "New Department", "Num_Agents" : "# Agents", - "Opened": "Opened", + "Opened" : "Opened", "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", - "Send_a_message": "Send a message", + "Send_a_message" : "Send a message", "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", + "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", - "Visitor_page_URL": "Visitor page URL", - "Visitor_time_on_site": "Visitor time on site" + "Visitor_page_URL" : "Visitor page URL", + "Visitor_time_on_site" : "Visitor time on site" } -- GitLab From f4da73e6e899537076622729c820091bdf24d6a0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 21 Dec 2015 10:04:37 -0200 Subject: [PATCH 0948/1338] Check if file is empty before upload --- i18n/en.i18n.json | 9 +++++---- packages/rocketchat-ui/lib/fileUpload.coffee | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9e3b6b9adc5..97936ce44e7 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -159,6 +159,7 @@ "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", @@ -296,7 +297,6 @@ "Msgs" : "Msgs", "multi" : "multi", "Mute_user" : "Mute user", - "Unmute_user" : "Unmute user", "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", @@ -475,6 +475,7 @@ "There_is_no_integrations" : "There is no integrations", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", + "Unmute_user" : "Unmute user", "Unnamed" : "Unnamed", "Unread_Rooms" : "Unread Rooms", "Unread_Rooms_Mode" : "Unread Rooms Mode", @@ -503,15 +504,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_unmuted_in_room" : "User unmuted 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_muted_by" : "User <em>__user_muted__</em> muted by <em>__user_by__</em>.", - "User_unmuted_by" : "User <em>__user_unmuted__</em> unmuted 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", diff --git a/packages/rocketchat-ui/lib/fileUpload.coffee b/packages/rocketchat-ui/lib/fileUpload.coffee index 52560afe2fb..548cc76437f 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' -- GitLab From 486be9d77a4a540f7eafce63acec7401daa80d3f Mon Sep 17 00:00:00 2001 From: sweetvvck <sweetvvck@gmail.com> Date: Mon, 21 Dec 2015 22:04:40 +0800 Subject: [PATCH 0949/1338] add ability to set app language to blank --- packages/rocketchat-ui-admin/admin/admin.coffee | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 2025c3d4d09..9658968c918 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -14,10 +14,18 @@ Template.admin.helpers result = [] for key, language of languages result.push _.extend(language, { key: key }) - return _.sortBy(result, 'key') + result = _.sortBy(result, 'key') + result.unshift { + "name": "Default", + "en": "Default", + "key": "" + } + return result; appLanguage: (key) -> - selected = (RocketChat.settings.get('Language') or defaultUserLanguage())?.split('-').shift().toLowerCase() is key + if !key + return !RocketChat.settings.get('Language') + selected = (RocketChat.settings.get('Language'))?.split('-').shift().toLowerCase() is key return selected group: -> -- GitLab From f46a607d0699a8ec7421a06a0527a4e0cebb16e0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 21 Dec 2015 15:21:36 -0200 Subject: [PATCH 0950/1338] show debug logs only on server --- packages/rocketchat-lib/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index e4a4f4c319d..aacfc1337ff 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -26,7 +26,7 @@ Package.onUse(function(api) { api.use('kadira:flow-router', 'client'); // DEBUGGER - api.addFiles('server/lib/debug.js'); + api.addFiles('server/lib/debug.js', 'server'); // COMMON LIB api.addFiles('lib/core.coffee'); -- GitLab From 4d818b48dfb49155cb9417d18617c6f64a44ebae Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 21 Dec 2015 16:28:15 -0200 Subject: [PATCH 0951/1338] removed living dead template --- client/views/app/room.html | 154 ------------------------------------- 1 file changed, 154 deletions(-) delete mode 100644 client/views/app/room.html diff --git a/client/views/app/room.html b/client/views/app/room.html deleted file mode 100644 index 3399c50d213..00000000000 --- a/client/views/app/room.html +++ /dev/null @@ -1,154 +0,0 @@ -<template name="room"> - <div class="dropzone"> - <div class="dropzone-overlay"> - <div> - {{_ "Drop_to_upload_file"}} - </div> - </div> - <section class="messages-container {{adminClass}}" id="{{windowId}}"> - <header class="fixed-title"> - {{> burger}} - <h2> - {{#if showToggleFavorite}} - <a href="#favorite" class="toggle-favorite"><i class="{{favorite}}"></i></a> - {{/if}} - <i class="{{roomIcon}} status-{{userStatus}}"></i> - <span class="room-title">{{roomName}}</span> - <span class="room-topic">{{roomTopic}}</span> - </h2> - </header> - <div class="container-bars"> - {{#each uploading}} - <div class="upload-progress {{#if error}}upload-error{{/if}}"> - {{#if error}} - {{error}} - <a> - close - </a> - {{else}} - <div class="upload-progress-progress" style="width: {{percentage}}%;"></div> - <div class="upload-progress-text"> - {{name}}... {{percentage}}% - <a> - cancel - </a> - </div> - {{/if}} - </div> - {{/each}} - {{#if unreadCount}} - {{#if unreadSince}} - <div class="unread-bar"> - {{_ "S_new_messages_since_s" unreadCount formatUnreadSince}} - <a> - {{_ "Mark_as_read"}} - </a> - </div> - {{/if}} - {{/if}} - </div> - <div class="messages-box {{compactView}}"> - <div class="ticks-bar"></div> - <div class="wrapper"> - <ul aria-live="polite"> - {{#if hasMore}} - <li class="load-more"> - {{#if isLoading}} - <div class="load-more-loading">{{_ "Loading_more_from_history"}}...</div> - {{else}} - <a href="">{{_ "Has_more"}}...</a> - {{/if}} - </li> - {{else}} - <li class="start"> - {{_ "Start_of_conversation"}} - </li> - {{/if}} - {{#each messagesHistory}} - {{#nrr nrrargs 'message' .}}{{/nrr}} - {{/each}} - </ul> - </div> - <div class="new-message not"> - <i class="icon-down-big"></i> - <span>{{_ "New_messages"}}</span> - </div> - </div> - <footer class="footer"> - {{#if subscribed}} - <form class="message-form" method="post" action="/"> - <div style="display: flex"> - <div class="file"> - <i class="octicon octicon-cloud-upload file"></i> - <input type="file" accept="{{fileUploadAllowedMediaTypes}}"> - </div> - <div class="input-message-container"> - {{> messagePopupConfig getPopupConfig}} - <textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea> - </div> - - {{#if canRecordAudio}} - <div class="mic"> - <i class="icon-mic" aria-label="{{_ "Record"}}"></i> - </div> - <div class="stop-mic hidden"> - <i class="icon-stop" aria-label="{{_ "Stop_Recording"}}"></i> - </div> - {{/if}} - </div> - <div class="users-typing"> - {{#with usersTyping}} - <strong>{{users}}</strong> - {{#if multi}} - {{#if selfTyping}} - {{_ "are_also_typing"}} - {{else}} - {{_ "are_typing"}} - {{/if}} - {{else}} - {{#if selfTyping}} - {{_ "is_also_typing" context="male"}} - {{else}} - {{_ "is_typing" context="male"}} - {{/if}} - {{/if}} - {{/with}} - </div> - - {{#if showFormattingTips}} - <div class="formatting-tips" aria-hidden="true" dir="auto"> - {{#if showMarkdown}} - <b>*{{_ "bold"}}*</b> - <i>_{{_ "italics"}}_</i> - <span>~<strike>{{_ "strike"}}</strike>~</span> - <code class="inline">`{{_ "inline_code"}}`</code> - {{/if}} - {{#if showHighlight}} - <code class="inline"><span class="hidden-br"><br></span>```<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "multi"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "line"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>```</code> - {{/if}} - {{#if showMarkdown}} - <q><span class="hidden-br"><br></span>>{{_ "quote"}}</q> - {{/if}} - - </div> - {{/if}} - <div class="editing-commands" aria-hidden="true" dir="auto"> - <div class="editing-commands-cancel">{{_ 'Esc_to'}} <a href="">{{_ 'Cancel'}}</a></div> - <div class="editing-commands-save">{{_ 'Enter_to'}} <a href="">{{_ 'Save_changes'}}</a></div> - </div> - </form> - {{else}} - {{#if canJoin}} - <div> - {{{_ "you_are_in_preview_mode_of" room_name=roomName}}} - <button class="button join"><span><i class="icon-login"></i> {{_ "join"}}</span></button> - </div> - {{/if}} - {{/if}} - </footer> - </section> - <section class="flex-tab"> - {{> Template.dynamic template=flexTemplate data=flexData}} - </section> - </div> -</template> -- GitLab From 1a3796fd06197d98cc5a060314b934733bb12690 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 21 Dec 2015 17:15:45 -0200 Subject: [PATCH 0952/1338] fix upload permissions introduced in raik:ufs 0.3.4 --- lib/fileUpload.coffee | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index d60283c8ba5..cb84a73bab3 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -74,13 +74,11 @@ if UploadFS? token = cookie.get('rc_token', rawCookies) if rawCookies? unless uid and token and RocketChat.models.Users.findOneByIdAndLoginToken(uid, token) - res.statusCode = 403 - res.end('Not Allowed') - # Just to abort the request - # See https://github.com/jalik/jalik-ufs/issues/28 - throw new Meteor.Error 403, 'Not Allowed' + res.writeHead 403 + return false res.setHeader 'content-disposition', "attachment; filename=\"#{ encodeURIComponent(file.name) }\"" + return true Meteor.startup -> if Meteor.isServer -- GitLab From bc3e20441163fb79af2f273a1b19d44d07a35fc4 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 21 Dec 2015 17:19:10 -0200 Subject: [PATCH 0953/1338] bump version to 0.10.1 --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- packages/rocketchat-lib/rocketchat.info | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 9b17fdd10bc..ec6a58efe8c 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -21,7 +21,7 @@ const pkgdef :Spk.PackageDefinition = ( appVersion = 6, # Increment this for every release. - appMarketingVersion = (defaultText = "0.10.0"), + appMarketingVersion = (defaultText = "0.10.1"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index 71143b9710f..506e7cd2a4c 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.10.0" + "version": "0.10.1" } -- GitLab From d694b010a7db8cf63b36a000d943c1aaf37df3c5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 21 Dec 2015 19:03:38 -0200 Subject: [PATCH 0954/1338] mail messages --- .meteor/packages | 1 + .meteor/versions | 1 + .../client/lib/ChannelSettings.coffee | 3 + ...cketChatChannelSettingsMailMessages.coffee | 12 +++ .../views/channelSettingsMailMessages.coffee | 10 +++ .../views/channelSettingsMailMessages.html | 8 ++ .../views/mailMessagesInstructions.coffee | 13 +++ .../views/mailMessagesInstructions.html | 14 ++++ .../i18n/en.i18n.json | 7 ++ .../package.js | 44 ++++++++++ .../client/lib/ChannelSettings.coffee | 29 +++++++ .../client/views/channelSettings.coffee | 2 + .../client/views/channelSettings.html | 3 + .../rocketchat-channel-settings/package.js | 3 + .../assets/stylesheets/base.less | 6 ++ packages/rocketchat-ui/views/app/room.coffee | 81 ++++++++++++++++++- packages/rocketchat-ui/views/app/room.html | 2 +- 17 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/package.js create mode 100644 packages/rocketchat-channel-settings/client/lib/ChannelSettings.coffee diff --git a/.meteor/packages b/.meteor/packages index 16ac606c7c0..2e0df8c465d 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -41,6 +41,7 @@ rocketchat:lib rocketchat:authorization rocketchat:autolinker rocketchat:channel-settings +rocketchat:channel-settings-mail-messages rocketchat:colors rocketchat:custom-oauth rocketchat:emojione diff --git a/.meteor/versions b/.meteor/versions index 179bf18b1d6..eef1815c7a4 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -125,6 +125,7 @@ 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 diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee new file mode 100644 index 00000000000..9c4e420f5e9 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee @@ -0,0 +1,3 @@ +RocketChat.ChannelSettings.addOption + id: 'mail-messages' + template: 'channelSettingsMailMessages' diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee new file mode 100644 index 00000000000..af7b8284173 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee @@ -0,0 +1,12 @@ +RocketChat.ChannelSettingsMailMessages = new class + addCheckboxes = -> + $('.messages-box .wrapper .message').each (index, item) -> + $item = $(item) + unless $item.find('input[type=checkbox]').length + $item.prepend(HTML.toHTML(HTML.INPUT({type: 'checkbox', class: 'send-message', style: 'position: absolute; left: 0' }))); + + removeCheckboxes = -> + $('.messages-box .wrapper .message input[type=checkbox].send-message').remove() + + addCheckboxes: addCheckboxes + removeCheckboxes: removeCheckboxes 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 00000000000..6fdfa79e6ad --- /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 00000000000..ff680914b12 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html @@ -0,0 +1,8 @@ +<template name="channelSettingsMailMessages"> + <div class="input-line double-col"> + <label>{{_ "Mail_Messages"}}</label> + <div> + <button type="button" class="button primary mail-messages">{{_ "Choose_messages"}}</button> + </div> + </div> +</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 00000000000..a70d7e925b8 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -0,0 +1,13 @@ +Template.mailMessagesInstructions.events + 'click .cancel': (e, t) -> + RocketChat.TabBar.setTemplate('channelSettings') + view = Blaze.getView($('.messages-box')[0]) + view?.templateInstance?().resetSelection(false) + + 'click .send': (e, t) -> + console.log 'sending' + +Template.mailMessagesInstructions.onCreated -> + @autorun => + if Session.get('channelSettingsMailMessages') isnt Session.get('openedRoom') + RocketChat.TabBar.setTemplate('channelSettings') 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 00000000000..0e344c76b31 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html @@ -0,0 +1,14 @@ +<template name="mailMessagesInstructions"> + <div class="content"> + <div class="list-view"> + <div class="status"> + <h2>{{_ "Mail_Messages"}}</h2> + </div> + <p>{{_ "Mail_Messages_Instructions"}}</p> + <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/en.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json new file mode 100644 index 00000000000..0e441d185b7 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json @@ -0,0 +1,7 @@ +{ + "Cancel" : "Cancel", + "Choose_messages" : "Choose messages", + "Mail_Messages" : "Mail Messages", + "Mail_Messages_Instructions" : "Choose which messages you want to send via e-mail by clicking the messages", + "Send" : "Send" +} 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 00000000000..b66d7d51415 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -0,0 +1,44 @@ +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@0.0.1', + 'rocketchat:channel-settings' + ]); + + api.addFiles([ + 'client/lib/ChannelSettings.coffee', + 'client/lib/RocketChatChannelSettingsMailMessages.coffee', + 'client/views/channelSettingsMailMessages.html', + 'client/views/channelSettingsMailMessages.coffee', + 'client/views/mailMessagesInstructions.html', + 'client/views/mailMessagesInstructions.coffee' + ], 'client'); + + // 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@1.6.1'); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); 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 00000000000..f9322fbb446 --- /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/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 4f9f5d344c5..2ef4d2850ef 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -3,6 +3,8 @@ Template.channelSettings.helpers return ChatRoom.findOne(@rid)?.t isnt 'd' roomType: -> return ChatRoom.findOne(@rid)?.t + channelSettings: -> + return RocketChat.ChannelSettings.getOptions() Template.channelSettings.events 'click .save': (e, t) -> diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index c72ecae4ad6..1fb7bbef4fc 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -16,6 +16,9 @@ </div> </div> {{/if}} + {{#each channelSettings}} + {{> Template.dynamic template=template data=data}} + {{/each}} </fieldset> <div class="submit"> <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 06b8f3fe128..e03b0f68e10 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' ]); api.addFiles([ + 'client/lib/ChannelSettings.coffee', 'client/startup/messageTypes.coffee', 'client/startup/tabBar.coffee', 'client/startup/trackSettingsChange.coffee', diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 4ba647bb96d..a9f1b74fbd5 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2471,6 +2471,12 @@ a.github-fork { border-radius: 4px; } } + &.selectable .message { + cursor: pointer; + &.selected { + background-color: #FFD; + } + } } .ticks-bar { diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index f7ea605894a..7917001e688 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -213,6 +213,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) -> @@ -432,17 +434,90 @@ Template.room.events template.atBottom = true RoomHistoryManager.clear(template?.data?._id) + 'click .message': (e, template) -> + e.preventDefault() + e.stopPropagation() + if template.selectable.get() + data = Blaze.getData(e.currentTarget) + _id = data?._arguments?[1]?._id + + if !template.selectablePointer or !e.shiftKey + template.selectablePointer = _id + template.selectableShiftPointer = null + + document.selection?.empty() or window.getSelection?().removeAllRanges() + template.selectMessages _id + Template.room.onCreated -> # this.scrollOnBottom = true # this.typing = new msgTyping this.data._id this.showUsersOffline = new ReactiveVar false this.atBottom = true this.unreadCount = new ReactiveVar 0 + this.selectable = new ReactiveVar false + this.selectedMessages = new ReactiveVar [] + this.selectablePointer = null + this.selectableShiftPointer = null + + this.resetSelection = (enabled) => + this.selectable.set(enabled) + $('.messages-box .message.selected').removeClass 'selected' + this.selectedMessages.set [] + this.selectablePointer = null + this.selectableShiftPointer = null + + this.selectMessages = (to) => + messages = this.selectedMessages.get() + if this.selectablePointer is to + this.selectablePointer = this.selectableShiftPointer or this.selectablePointer + if messages.indexOf(to) is -1 + messages.push to + $(".messages-box ##{to}").addClass 'selected' + else + messages = _.without messages, to + $(".messages-box ##{to}").removeClass 'selected' + else + includeFrom = true + addItems = messages.indexOf(to) is -1 + if addItems + fromMessage = ChatMessage.findOne this.selectablePointer + toMessage = ChatMessage.findOne to + # this.selectablePointer = this.selectableShiftPointer or this.selectablePointer + this.selectableShiftPointer = to + else + if this.selectableShiftPointer? + fromMessage = ChatMessage.findOne this.selectableShiftPointer + else + console.log 'set includeFrom = false' + includeFrom = false + fromMessage = ChatMessage.findOne this.selectablePointer + toMessage = ChatMessage.findOne to + this.selectableShiftPointer = null + + if fromMessage.ts <= toMessage.ts + if includeFrom + query = { rid: fromMessage.rid, ts: { $gte: fromMessage.ts, $lte: toMessage.ts } } + else + query = { rid: fromMessage.rid, ts: { $gt: fromMessage.ts, $lte: toMessage.ts } } + else + if includeFrom + query = { rid: fromMessage.rid, ts: { $lte: fromMessage.ts, $gte: toMessage.ts } } + else + query = { rid: fromMessage.rid, ts: { $lt: fromMessage.ts, $gte: toMessage.ts } } + + ChatMessage.find(query).forEach (message) -> + if addItems + messages.push message._id + $(".messages-box ##{message._id}").addClass 'selected' + else + messages = _.without messages, message._id + $(".messages-box ##{message._id}").removeClass 'selected' - self = @ + console.log addItems, this.selectablePointer, this.selectableShiftPointer + this.selectedMessages.set messages - @autorun -> - self.subscribe 'fullUserData', Session.get('showUserInfo'), 1 + @autorun => + @subscribe 'fullUserData', Session.get('showUserInfo'), 1 Template.room.onDestroyed -> diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index d63dcc7dd97..a8f9e0d6c4e 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -50,7 +50,7 @@ {{/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 {{#if hasMoreNext}}has-more-next{{/if}}"> <ul aria-live="polite"> -- GitLab From fd09727b392ae084d07593eceff63989db8210ae Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 21 Dec 2015 21:52:17 -0200 Subject: [PATCH 0955/1338] Init outgoing integrations --- .../client/route.coffee | 10 ++ .../client/views/integrationsIncoming.html | 2 +- .../client/views/integrationsNew.html | 4 +- .../client/views/integrationsOutgoing.coffee | 158 ++++++++++++++++++ .../client/views/integrationsOutgoing.html | 93 +++++++++++ packages/rocketchat-integrations/package.js | 2 + 6 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee create mode 100644 packages/rocketchat-integrations/client/views/integrationsOutgoing.html diff --git a/packages/rocketchat-integrations/client/route.coffee b/packages/rocketchat-integrations/client/route.coffee index 4a87624ca34..96c69e02cc1 100644 --- a/packages/rocketchat-integrations/client/route.coffee +++ b/packages/rocketchat-integrations/client/route.coffee @@ -24,3 +24,13 @@ FlowRouter.route '/admin/integrations/incoming/:id?', pageTitle: t('Integration_Incoming_WebHook') pageTemplate: 'integrationsIncoming' params: params + + +FlowRouter.route '/admin/integrations/outgoing/:id?', + name: 'admin-integrations-outgoing' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('Integration_Outgoing_WebHook') + pageTemplate: 'integrationsOutgoing' + params: params diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.html b/packages/rocketchat-integrations/client/views/integrationsIncoming.html index 75e690c9ce3..42ffe785ae7 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.html +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.html @@ -52,7 +52,7 @@ <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 class="settings-description">{{{_ "Example_s" ":ghost:"}}}</div> </div> </div> {{#if data.token}} diff --git a/packages/rocketchat-integrations/client/views/integrationsNew.html b/packages/rocketchat-integrations/client/views/integrationsNew.html index 496cf5112bb..f4425ff8c3d 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 00000000000..5f25822a3fa --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee @@ -0,0 +1,158 @@ +Template.integrationsOutgoing.onCreated -> + @record = new ReactiveVar + username: 'rocket.cat' + + +Template.integrationsOutgoing.helpers + + hasPermission: -> + return RocketChat.authz.hasAllPermission 'manage-integrations' + + data: -> + params = Template.instance().data.params?() + + if params?.id? + 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 + + 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: 'Example message' + 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: '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.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() + + "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 "deleteIntegration", 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() + + if channel is '' + return toastr.error TAPi18n.__("The_channel_name_is_required") + + if username is '' + return toastr.error TAPi18n.__("The_username_is_required") + + 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) -> + 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) -> + if err? + return toastr.error TAPi18n.__(err.error) + + toastr.success TAPi18n.__("Integration_added") + FlowRouter.go "admin-integrations-incoming", {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 00000000000..26a9b2acb1e --- /dev/null +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html @@ -0,0 +1,93 @@ +<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"}}</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</strong> channel"}}}</div> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Trigger_Words"}}</label> + <div> + <input type="text" name="username" value="{{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">{{_ "Optional if a channel is chosen"}}</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" rows="5">{{data.urls}}</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>{{_ "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</label> + <div> + <input type="text" name="completeToken" value="{{data.completeToken}}" /> + </div> + </div> + <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> + </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 fe6df9670d8..78a34f3168e 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -29,6 +29,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'); -- GitLab From 7f40155da5eb2dc315ecae1df9535e4a17b88946 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 21 Dec 2015 23:54:06 -0200 Subject: [PATCH 0956/1338] select messages to send e-mail --- .../views/channelSettingsMailMessages.coffee | 4 +- .../views/mailMessagesInstructions.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 95 +++++++++---------- 3 files changed, 46 insertions(+), 55 deletions(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee index 6fdfa79e6ad..855a105f0f4 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee @@ -3,8 +3,8 @@ Template.channelSettingsMailMessages.events Session.set 'channelSettingsMailMessages', Session.get('openedRoom') RocketChat.TabBar.setTemplate('mailMessagesInstructions') view = Blaze.getView($('.messages-box')[0]) - view?.templateInstance?().resetSelection(true) + view?.templateInstance?().resetSelection?(true) Template.channelSettingsMailMessages.onCreated -> view = Blaze.getView($('.messages-box')[0]) - view?.templateInstance?().resetSelection(false) + view?.templateInstance?().resetSelection?(false) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee index a70d7e925b8..a3c717f806d 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -2,7 +2,7 @@ Template.mailMessagesInstructions.events 'click .cancel': (e, t) -> RocketChat.TabBar.setTemplate('channelSettings') view = Blaze.getView($('.messages-box')[0]) - view?.templateInstance?().resetSelection(false) + view?.templateInstance?().resetSelection?(false) 'click .send': (e, t) -> console.log 'sending' diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 7917001e688..a8ebd7c1b4b 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -438,83 +438,74 @@ Template.room.events e.preventDefault() e.stopPropagation() if template.selectable.get() + document.selection?.empty() or window.getSelection?().removeAllRanges() data = Blaze.getData(e.currentTarget) _id = data?._arguments?[1]?._id - if !template.selectablePointer or !e.shiftKey + if !template.selectablePointer + template.selectablePointer = _id + + if !e.shiftKey + template.selectedMessages = template.getSelectedMessages() + template.selectedRange = [] template.selectablePointer = _id - template.selectableShiftPointer = null - document.selection?.empty() or window.getSelection?().removeAllRanges() 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 # this.typing = new msgTyping this.data._id this.showUsersOffline = new ReactiveVar false this.atBottom = true this.unreadCount = new ReactiveVar 0 + this.selectable = new ReactiveVar false - this.selectedMessages = new ReactiveVar [] + this.selectedMessages = [] + this.selectedRange = [] this.selectablePointer = null - this.selectableShiftPointer = null this.resetSelection = (enabled) => this.selectable.set(enabled) $('.messages-box .message.selected').removeClass 'selected' - this.selectedMessages.set [] + this.selectedMessages = [] + this.selectedRange = [] this.selectablePointer = null - this.selectableShiftPointer = null this.selectMessages = (to) => - messages = this.selectedMessages.get() - if this.selectablePointer is to - this.selectablePointer = this.selectableShiftPointer or this.selectablePointer - if messages.indexOf(to) is -1 - messages.push to - $(".messages-box ##{to}").addClass 'selected' - else - messages = _.without messages, to - $(".messages-box ##{to}").removeClass 'selected' + if this.selectablePointer is to and this.selectedRange.length > 0 + this.selectedRange = [] else - includeFrom = true - addItems = messages.indexOf(to) is -1 - if addItems - fromMessage = ChatMessage.findOne this.selectablePointer - toMessage = ChatMessage.findOne to - # this.selectablePointer = this.selectableShiftPointer or this.selectablePointer - this.selectableShiftPointer = to - else - if this.selectableShiftPointer? - fromMessage = ChatMessage.findOne this.selectableShiftPointer - else - console.log 'set includeFrom = false' - includeFrom = false - fromMessage = ChatMessage.findOne this.selectablePointer - toMessage = ChatMessage.findOne to - this.selectableShiftPointer = null - - if fromMessage.ts <= toMessage.ts - if includeFrom - query = { rid: fromMessage.rid, ts: { $gte: fromMessage.ts, $lte: toMessage.ts } } - else - query = { rid: fromMessage.rid, ts: { $gt: fromMessage.ts, $lte: toMessage.ts } } - else - if includeFrom - query = { rid: fromMessage.rid, ts: { $lte: fromMessage.ts, $gte: toMessage.ts } } - else - query = { rid: fromMessage.rid, ts: { $lt: fromMessage.ts, $gte: toMessage.ts } } + message1 = ChatMessage.findOne this.selectablePointer + message2 = ChatMessage.findOne to - ChatMessage.find(query).forEach (message) -> - if addItems - messages.push message._id - $(".messages-box ##{message._id}").addClass 'selected' - else - messages = _.without messages, message._id - $(".messages-box ##{message._id}").removeClass 'selected' + 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') + + this.getSelectedMessages = => + messages = this.selectedMessages + addMessages = false + for message in this.selectedRange + if messages.indexOf(message) is -1 + addMessages = true + break + + if addMessages + previewMessages = _.compact(_.uniq(this.selectedMessages.concat(this.selectedRange))) + else + previewMessages = _.compact(_.difference(this.selectedMessages, this.selectedRange)) - console.log addItems, this.selectablePointer, this.selectableShiftPointer - this.selectedMessages.set messages + return previewMessages @autorun => @subscribe 'fullUserData', Session.get('showUserInfo'), 1 -- GitLab From c32ccf901348cb9194c6d55193cd21a9b0981e08 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 22 Dec 2015 00:01:40 -0200 Subject: [PATCH 0957/1338] Show room topic --- packages/rocketchat-ui/views/app/room.html | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index d63dcc7dd97..a9e64a68ee0 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"> -- GitLab From a3d6215dd3d02ea15a3a8cf542157874cb43430c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@konecty.com> Date: Tue, 22 Dec 2015 00:09:10 -0200 Subject: [PATCH 0958/1338] Added fields for sending mail --- .../views/mailMessagesInstructions.coffee | 4 +++ .../views/mailMessagesInstructions.html | 28 +++++++++++++++++++ .../i18n/en.i18n.json | 6 +++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee index a3c717f806d..d8672a24efb 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -1,3 +1,7 @@ +Template.mailMessagesInstructions.helpers + body: -> + return '' + Template.mailMessagesInstructions.events 'click .cancel': (e, t) -> RocketChat.TabBar.setTemplate('channelSettings') diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html index 0e344c76b31..79d62505d1a 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html @@ -5,6 +5,34 @@ <h2>{{_ "Mail_Messages"}}</h2> </div> <p>{{_ "Mail_Messages_Instructions"}}</p> + <form> + <fieldset> + <div class="input-line double-col"> + <label>{{_ "From"}}</label> + <div> + <input type="text" name="from" value="" /> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "To"}}</label> + <div> + <input type="text" name="to" value="" /> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Subject"}}</label> + <div> + <input type="text" name="subject" value="" /> + </div> + </div> + <div class="input-line double-col"> + <label>{{_ "Body"}}</label> + <div> + {{body}} + </div> + </div> + </fieldset> + </form> <p style="margin-top: 30px"> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary send">{{_ "Send"}}</button> diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json index 0e441d185b7..64e39f5943c 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json @@ -1,7 +1,11 @@ { + "Body" : "Body", "Cancel" : "Cancel", "Choose_messages" : "Choose messages", + "From" : "From", "Mail_Messages" : "Mail Messages", "Mail_Messages_Instructions" : "Choose which messages you want to send via e-mail by clicking the messages", - "Send" : "Send" + "Send" : "Send", + "Subject" : "Subject", + "To" : "To" } -- GitLab From 476c40e901ff9a031ccc5bdcae1cd834f9f2eba7 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 09:13:47 -0200 Subject: [PATCH 0959/1338] moved collection definitions --- .../client/{lib => collections}/LivechatDepartment.js | 0 .../client/{lib => collections}/LivechatTrigger.js | 0 packages/rocketchat-livechat/package.js | 9 +++++---- 3 files changed, 5 insertions(+), 4 deletions(-) rename packages/rocketchat-livechat/client/{lib => collections}/LivechatDepartment.js (100%) rename packages/rocketchat-livechat/client/{lib => collections}/LivechatTrigger.js (100%) 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/lib/LivechatTrigger.js b/packages/rocketchat-livechat/client/collections/LivechatTrigger.js similarity index 100% rename from packages/rocketchat-livechat/client/lib/LivechatTrigger.js rename to packages/rocketchat-livechat/client/collections/LivechatTrigger.js diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index b692038ae8d..2f9a4d56037 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -38,6 +38,11 @@ Package.onUse(function(api) { api.addFiles('client/stylesheets/livechat.less', 'client'); + // collections + api.addFiles('client/collections/AgentUsers.js', 'client'); + api.addFiles('client/collections/LivechatDepartment.js', 'client'); + api.addFiles('client/collections/LivechatTrigger.js', 'client'); + // client views api.addFiles('client/views/app/livechatAppearance.html', 'client'); api.addFiles('client/views/app/livechatAppearance.js', 'client'); @@ -82,10 +87,6 @@ Package.onUse(function(api) { api.addFiles('server/models/LivechatDepartment.js', 'server'); api.addFiles('server/models/LivechatTrigger.js', 'server'); - // collections - api.addFiles('client/lib/LivechatDepartment.js', 'client'); - api.addFiles('client/lib/LivechatTrigger.js', 'client'); - // publications api.addFiles('server/publications/livechatAgents.js', 'server'); api.addFiles('server/publications/livechatManagers.js', 'server'); -- GitLab From 471706dfadcf1281db5af68422f3ff3660880e49 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 09:14:46 -0200 Subject: [PATCH 0960/1338] departments rework --- .../client/collections/AgentUsers.js | 1 + .../client/stylesheets/livechat.less | 12 ++ .../views/app/livechatDepartmentForm.html | 66 +++++++---- .../views/app/livechatDepartmentForm.js | 111 +++++++++++------- .../server/methods/saveDepartment.js | 4 +- .../server/models/LivechatDepartment.js | 89 ++++++++++++-- .../server/models/LivechatDepartmentAgents.js | 23 ++++ .../server/publications/departmentAgents.js | 11 ++ 8 files changed, 237 insertions(+), 80 deletions(-) create mode 100644 packages/rocketchat-livechat/client/collections/AgentUsers.js create mode 100644 packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js create mode 100644 packages/rocketchat-livechat/server/publications/departmentAgents.js diff --git a/packages/rocketchat-livechat/client/collections/AgentUsers.js b/packages/rocketchat-livechat/client/collections/AgentUsers.js new file mode 100644 index 00000000000..e571fad61d2 --- /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/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index dc12fb153ec..afdb9d63f78 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -411,3 +411,15 @@ } } } + +.department-agents { + list-style-type: none; + + li { + display: inline-block; + background-color: #DDD; + border-radius: 5px; + padding: 2px 7px; + margin: 1px 0; + } +} diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html index 5a82ac77c71..e0d0249d4d9 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -24,34 +24,50 @@ </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}}"> + + <fieldset> + <legend>{{_ "Available_agents"}}</legend> + + <ul class="department-agents available-agents"> + {{#each availableAgents}} + <li>{{username}}</li> + {{/each}} + </ul> + </fieldset> + + <fieldset> + <legend>{{_ "Selected_agents"}}</legend> + + <div class="list"> + <table> + <thead> + <tr> + <th width="25%">{{_ "Username"}}</th> + <th>{{_ "Count"}}</th> + <th>{{_ "Order"}}</th> + <th> </th> + </tr> + </thead> + <tbody> + {{#each selectedAgents}} + <tr class="agent-info"> <td>{{username}}</td> - <td><a href="#remove" class="remove-agent"><i class="icon-trash"></i></a></td> + <td><input type="text" class="count-{{_id}}" name="count" value="{{count}}" size="3"></td> + <td><input type="text" class="order-{{_id}}" name="order" value="{{order}}" size="3"></td> + <td><a href="#remove" class=""><i class="icon-trash remove-agent"></i></a></td> </tr> {{/each}} - {{else}} - <tr> - <td colspan="2">{{_ "There_are_no_agents_added_to_this_department_yet"}}</td> - </tr> - {{/if}} - </tbody> - </table> - </div> + <!-- {{else}} + <tr> + <td colspan="2">{{_ "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 d4ff6d0fcac..8e322bd3812 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js @@ -5,6 +5,13 @@ Template.livechatDepartmentForm.helpers({ }, 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 +36,26 @@ Template.livechatDepartmentForm.events({ var oldBtnValue = $btn.html(); $btn.html(t('Saving')); - agents = instance.department && !_.isEmpty(instance.department.get()) ? instance.department.get().agents : []; + // 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() + // agents: agents + }; + + var departmentAgents = []; + + instance.selectedAgents.get().forEach((agent) => { + agent.count = instance.$('.count-' + agent._id).val(); + agent.order = instance.$('.order-' + agent._id).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 +71,65 @@ Template.livechatDepartmentForm.events({ FlowRouter.go('livechat-departments'); }, - 'click button.add-agent' (e, instance) { + // 'click button.add-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(''); + // }); + // }, + + '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(); + selectedAgents.push(this); + 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); } } }); diff --git a/packages/rocketchat-livechat/server/methods/saveDepartment.js b/packages/rocketchat-livechat/server/methods/saveDepartment.js index de3f656817b..2f626c39572 100644 --- a/packages/rocketchat-livechat/server/methods/saveDepartment.js +++ b/packages/rocketchat-livechat/server/methods/saveDepartment.js @@ -1,5 +1,5 @@ Meteor.methods({ - 'livechat:saveDepartment' (_id, departmentData) { + 'livechat:saveDepartment' (_id, departmentData, departmentAgents) { if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) { throw new Meteor.Error("not-authorized"); } @@ -17,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/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index 41141b8d68e..61cac814cf2 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -21,21 +21,36 @@ class LivechatDepartment extends RocketChat.models._Base { // UPSERT createOrUpdateDepartment(_id, enabled, name, description, agents, extraData) { - record = { + var agents = [].concat(agents); + + var record = { enabled: enabled, name: name, description: description, - agents: [] - } + numAgents: agents.count() + }; - if (!_.isEmpty(agents)) { - for (agent of agents) { - record.agents.push({ _id: agent._id, username: agent.username }); - } - } + // if (agents.length > 0) { + // for (agent of agents) { + // record.agents.push({ _id: agent._id, username: agent.username }); + // } + // } _.extend(record, extraData); - this.upsert({ _id: _id }, { $set: record }); + + if (_id) { + this.update({ _id: _id }, { $set: record }); + } else { + _id = this.insert(record); + } + + agents.forEach((agent) => { + agent.departmentId = _id; + + RocketChat.models.LivechatDepartmentAgents.saveAgent(agent); + }); + + // this.upsert({ _id: _id }, { $set: record }); return _.extend(record, { _id: _id }); } @@ -44,6 +59,62 @@ class LivechatDepartment extends RocketChat.models._Base { query = { _id: _id }; return this.remove(query); } + + getNextAgent(departmentId) { + + var department = this.findOne({ _id: departmentId }, { fields: { agents: 1 } }) + + if (!department || !department.agents || department.agents.length === 0) { + return; + } + + var onlineUsers = RocketChat.models.Users.findOnlineUserFromList(_.pluck(department.agents, 'username')); + + var onlineUsernames = _.pluck(onlineUsers.fetch(), 'username'); + + console.log('onlineUsernames ->',onlineUsernames); + + var query = { + _id: departmentId, + "agents.username": { + $in: onlineUsernames + } + }; + + var sort = { + livechatCount: 1, + // sort: 1, + username: 1 + }; + var update = { + $inc: { + "agents.$.livechatCount": 1 + } + }; + + // var query = { + // status: 'online' + // }; + + // query['roles.' + Roles.GLOBAL_GROUP] = '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 + // } + // }; + + return findAndModify(query, sort, update); + // return RocketChat.models.Users.getNextAgent(department.agents); + } } 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 00000000000..27be6a1f046 --- /dev/null +++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js @@ -0,0 +1,23 @@ +/** + * 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.insert(agent); + } + } +} + +RocketChat.models.LivechatDepartmentAgents = new LivechatDepartmentAgents(); diff --git a/packages/rocketchat-livechat/server/publications/departmentAgents.js b/packages/rocketchat-livechat/server/publications/departmentAgents.js new file mode 100644 index 00000000000..b09f4fe3dd9 --- /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 }); +}); -- GitLab From 6f0e632267496c409f58709bf7a50151bf9e9d3d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 10:28:09 -0200 Subject: [PATCH 0961/1338] fix flex active link for multiple routes --- .../client/views/sideNav/livechatFlex.html | 2 +- .../rocketchat-livechat/client/views/sideNav/livechatFlex.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html index a859f5385a5..15d3ed86810 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html @@ -10,7 +10,7 @@ <li> <!-- <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'}}">{{_ "Departments"}}</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> diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js index 4e2578cea84..f7a8f2f0acc 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js @@ -1,7 +1,7 @@ Template.livechatFlex.helpers({ - active (route) { + active (...routes) { FlowRouter.watchPathChange(); - if (FlowRouter.current().route.name === route) { + if (routes.indexOf(FlowRouter.current().route.name) !== -1) { return 'active'; } } -- GitLab From ac13b6066133be1647e0320dbe4cd76286becbb0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 10:28:34 -0200 Subject: [PATCH 0962/1338] fix double collection declaration --- packages/rocketchat-livechat/client/views/app/livechatUsers.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rocketchat-livechat/client/views/app/livechatUsers.js b/packages/rocketchat-livechat/client/views/app/livechatUsers.js index 5e29f332b93..eeb2d1dfa78 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatUsers.js +++ b/packages/rocketchat-livechat/client/views/app/livechatUsers.js @@ -1,8 +1,6 @@ -var AgentUsers; var ManagerUsers; Meteor.startup(function() { - AgentUsers = new Mongo.Collection('agentUsers'); ManagerUsers = new Mongo.Collection('managerUsers'); }); -- GitLab From fd540cfbd9fe0f127c59461d44579a077c86d731 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 22 Dec 2015 10:40:37 -0200 Subject: [PATCH 0963/1338] update EmojiOne to 2.0.0 --- .meteor/versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 179bf18b1d6..570a7c1e373 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -39,7 +39,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.0 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 @@ -75,7 +75,7 @@ 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.2.0 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 -- GitLab From ec2d0547acaa1fefad1a5d7a2c2cabcb5464323a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 11:00:36 -0200 Subject: [PATCH 0964/1338] fixes preview issues --- .../client/messageAttachment.coffee | 7 +++++++ .../client/messageAttachment.html | 2 +- packages/rocketchat-oembed/client/oembedUrlWidget.coffee | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee index a224b9a872f..dc04117aabc 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.coffee +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -1,5 +1,12 @@ Template.messageAttachment.helpers fixCordova: (url) -> + slash = url.lastIndexOf('/') + 1 + + fileName = url.substr slash + filePath = url.substr 0, slash + + url = filePath + encodeURIComponent fileName + if Meteor.isCordova and url?[0] is '/' return Meteor.absoluteUrl().replace(/\/$/, '') + url return url diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index a4abddf4045..0d9f71b0ce4 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -9,7 +9,7 @@ {{#if author_link}} <div class="attachment-author"> {{#if author_icon}} - <img src="{{author_icon}}"> + <img src="{{fixCordova author_icon}}"> {{/if}} <a href="{{fixCordova author_link}}" target="_blank">{{author_name}}</a> </div> diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee index 79e6127073a..d3b1f1093a4 100644 --- a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee +++ b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee @@ -28,6 +28,13 @@ Template.oembedUrlWidget.helpers decodedOgImage = @meta.ogImage?.replace?(/&/g, '&') + slash = decodedOgImage.lastIndexOf('/') + 1 + + fileName = decodedOgImage.substr slash + filePath = decodedOgImage.substr 0, slash + + decodedOgImage = filePath + encodeURIComponent fileName + return decodedOgImage or this.meta.twitterImage show: -> -- GitLab From 5c0dec2ff3ff3a6133dda1feaf31753527afb8f8 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 11:36:19 -0200 Subject: [PATCH 0965/1338] proper fix preview images --- .../client/messageAttachment.coffee | 7 ------- .../client/messageAttachment.html | 2 +- packages/rocketchat-oembed/client/oembedImageWidget.html | 2 +- packages/rocketchat-oembed/client/oembedUrlWidget.coffee | 7 ------- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee index dc04117aabc..a224b9a872f 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.coffee +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -1,12 +1,5 @@ Template.messageAttachment.helpers fixCordova: (url) -> - slash = url.lastIndexOf('/') + 1 - - fileName = url.substr slash - filePath = url.substr 0, slash - - url = filePath + encodeURIComponent fileName - if Meteor.isCordova and url?[0] is '/' return Meteor.absoluteUrl().replace(/\/$/, '') + url return url diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 0d9f71b0ce4..dc02f0c03c9 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -49,7 +49,7 @@ <div class="attachment-image"> {{#if showImage}} <a href="{{fixCordova image_url}}" class="swipebox" target="_blank"> - <div class="inline-image" style="background-image: url({{fixCordova image_url}});"> + <div class="inline-image" style="background-image: url('{{fixCordova image_url}}');"> <img src="{{fixCordova image_url}}" height="{{getImageHeight image_dimensions.height}}"> </div> </a> diff --git a/packages/rocketchat-oembed/client/oembedImageWidget.html b/packages/rocketchat-oembed/client/oembedImageWidget.html index d17ed9ff03a..144dd766521 100644 --- a/packages/rocketchat-oembed/client/oembedImageWidget.html +++ b/packages/rocketchat-oembed/client/oembedImageWidget.html @@ -3,7 +3,7 @@ {{#if parsedUrl}} <div> <a href="{{url}}" class="swipebox" target="_blank"> - <div class="inline-image" style="background-image: url({{url}});"> + <div class="inline-image" style="background-image: url('{{url}}');"> <img src="{{url}}" height="200"> </div> </a> diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee index d3b1f1093a4..79e6127073a 100644 --- a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee +++ b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee @@ -28,13 +28,6 @@ Template.oembedUrlWidget.helpers decodedOgImage = @meta.ogImage?.replace?(/&/g, '&') - slash = decodedOgImage.lastIndexOf('/') + 1 - - fileName = decodedOgImage.substr slash - filePath = decodedOgImage.substr 0, slash - - decodedOgImage = filePath + encodeURIComponent fileName - return decodedOgImage or this.meta.twitterImage show: -> -- GitLab From 794ed7f56e4e9c4d86bed979917f18e0eacfa40a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 22 Dec 2015 11:46:08 -0200 Subject: [PATCH 0966/1338] fix title width --- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 34b5de48abc..33a92f34121 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1583,7 +1583,7 @@ a.github-fork { } } h2 { - max-width: 90%; + width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -- GitLab From a381bf5e433a2acc9717fc456417e198e518b25e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 11:36:19 -0200 Subject: [PATCH 0967/1338] proper fix preview images --- .../client/messageAttachment.coffee | 7 ------- .../client/messageAttachment.html | 2 +- packages/rocketchat-oembed/client/oembedImageWidget.html | 2 +- packages/rocketchat-oembed/client/oembedUrlWidget.coffee | 7 ------- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee index dc04117aabc..a224b9a872f 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.coffee +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -1,12 +1,5 @@ Template.messageAttachment.helpers fixCordova: (url) -> - slash = url.lastIndexOf('/') + 1 - - fileName = url.substr slash - filePath = url.substr 0, slash - - url = filePath + encodeURIComponent fileName - if Meteor.isCordova and url?[0] is '/' return Meteor.absoluteUrl().replace(/\/$/, '') + url return url diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index 0d9f71b0ce4..dc02f0c03c9 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -49,7 +49,7 @@ <div class="attachment-image"> {{#if showImage}} <a href="{{fixCordova image_url}}" class="swipebox" target="_blank"> - <div class="inline-image" style="background-image: url({{fixCordova image_url}});"> + <div class="inline-image" style="background-image: url('{{fixCordova image_url}}');"> <img src="{{fixCordova image_url}}" height="{{getImageHeight image_dimensions.height}}"> </div> </a> diff --git a/packages/rocketchat-oembed/client/oembedImageWidget.html b/packages/rocketchat-oembed/client/oembedImageWidget.html index d17ed9ff03a..144dd766521 100644 --- a/packages/rocketchat-oembed/client/oembedImageWidget.html +++ b/packages/rocketchat-oembed/client/oembedImageWidget.html @@ -3,7 +3,7 @@ {{#if parsedUrl}} <div> <a href="{{url}}" class="swipebox" target="_blank"> - <div class="inline-image" style="background-image: url({{url}});"> + <div class="inline-image" style="background-image: url('{{url}}');"> <img src="{{url}}" height="200"> </div> </a> diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee index d3b1f1093a4..79e6127073a 100644 --- a/packages/rocketchat-oembed/client/oembedUrlWidget.coffee +++ b/packages/rocketchat-oembed/client/oembedUrlWidget.coffee @@ -28,13 +28,6 @@ Template.oembedUrlWidget.helpers decodedOgImage = @meta.ogImage?.replace?(/&/g, '&') - slash = decodedOgImage.lastIndexOf('/') + 1 - - fileName = decodedOgImage.substr slash - filePath = decodedOgImage.substr 0, slash - - decodedOgImage = filePath + encodeURIComponent fileName - return decodedOgImage or this.meta.twitterImage show: -> -- GitLab From 6371cd7a1aec52dffa2574114d63fd2efecd9845 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 13:22:36 -0200 Subject: [PATCH 0968/1338] added new getNextAgent - fixes internal server error --- packages/rocketchat-livechat/package.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 2f9a4d56037..dbcac5dc322 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -87,6 +87,9 @@ Package.onUse(function(api) { api.addFiles('server/models/LivechatDepartment.js', 'server'); api.addFiles('server/models/LivechatTrigger.js', 'server'); + // server lib + api.addFiles('server/lib/getNextAgent.js', 'server'); + // publications api.addFiles('server/publications/livechatAgents.js', 'server'); api.addFiles('server/publications/livechatManagers.js', 'server'); -- GitLab From f9da7d01a7d0ec333a13f1bbfd6c7f597196b1bb Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Tue, 22 Dec 2015 10:36:30 -0500 Subject: [PATCH 0969/1338] Correct alignment for room icons in RTL --- packages/rocketchat-theme/assets/stylesheets/rtl.less | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 9f4d66fcd29..2ad79e63b2e 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); -- GitLab From 429893b4f5c9ced1b71dad872b99d1159c4cf2fa Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 14:28:16 -0200 Subject: [PATCH 0970/1338] Init save of outgoing hook --- .../client/views/integrationsOutgoing.coffee | 74 +++++++++-------- .../client/views/integrationsOutgoing.html | 10 +-- packages/rocketchat-integrations/package.js | 1 + .../outgoing/addOutgoingIntegration.coffee | 82 +++++++++++++++++++ 4 files changed, 126 insertions(+), 41 deletions(-) create mode 100644 packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee index 5f25822a3fa..63ac2cfc081 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee @@ -1,10 +1,20 @@ Template.integrationsOutgoing.onCreated -> @record = new ReactiveVar - username: 'rocket.cat' + name: 'name' + alias: 'alias' + channel: '#general' + triggerWords: ['send', 'sent'] + urls: ['https://www.google.com', 'https://www.google.com'] Template.integrationsOutgoing.helpers + join: (arr, sep) -> + if not arr?.join? + return arr + + return arr.join sep + hasPermission: -> return RocketChat.authz.hasAllPermission 'manage-integrations' @@ -14,9 +24,8 @@ Template.integrationsOutgoing.helpers if params?.id? 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 + if not data.token? + data.token = Random.id(24) return data return Template.instance().record.curValue @@ -28,7 +37,7 @@ Template.integrationsOutgoing.helpers alias: record.alias emoji: record.emoji avatar: record.avatar - msg: 'Example message' + msg: 'Response text' bot: i: Random.id() groupable: false @@ -50,7 +59,7 @@ Template.integrationsOutgoing.helpers username: record.alias icon_emoji: record.emoji icon_url: record.avatar - text: 'Example message' + text: 'Response text' attachments: [{ title: "Rocket.Chat" title_link: "https://rocket.chat" @@ -64,25 +73,6 @@ Template.integrationsOutgoing.helpers 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.integrationsOutgoing.events "blur input": (e, t) -> @@ -92,7 +82,10 @@ Template.integrationsOutgoing.events 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() @@ -124,13 +117,20 @@ Template.integrationsOutgoing.events 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 triggerWords is '' + return toastr.error TAPi18n.__("You should inform at least one trigger word if you do not inform a channel") - if channel is '' - return toastr.error TAPi18n.__("The_channel_name_is_required") + urlsArr = urls.split('\n') + urls = [] + for url in urlsArr + urls.push url.trim() if url.trim() isnt '' - if username is '' - return toastr.error TAPi18n.__("The_username_is_required") + if urls.length is 0 + return toastr.error TAPi18n.__("You_should_inform_one_url_at_least") integration = channel: channel @@ -138,21 +138,23 @@ Template.integrationsOutgoing.events 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 "updateIntegration", params.id, integration, (err, data) -> + Meteor.call "updateOutgoingIntegration", 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 + integration.type = 'webhook-outgoing' - Meteor.call "addIntegration", integration, (err, data) -> + Meteor.call "addOutgoingIntegration", integration, (err, data) -> if err? return toastr.error TAPi18n.__(err.error) toastr.success TAPi18n.__("Integration_added") - FlowRouter.go "admin-integrations-incoming", {id: data._id} + 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 index 26a9b2acb1e..1b83d457bf4 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html @@ -24,7 +24,7 @@ <div class="input-line double-col"> <label>{{_ "Trigger_Words"}}</label> <div> - <input type="text" name="username" value="{{data.triggerWords}}" /> + <input type="text" name="username" 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">{{_ "Optional if a channel is chosen"}}</div> <div class="settings-description">{{_ "Separate multiple words with commas"}}</div> @@ -33,7 +33,7 @@ <div class="input-line double-col"> <label>{{_ "URLs"}}</label> <div> - <textarea name="urls" rows="5">{{data.urls}}</textarea> + <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> @@ -67,11 +67,11 @@ </div> </div> <div class="input-line double-col"> - <label>{{_ "Example"}}</label> + <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> - <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 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"> diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index 78a34f3168e..e78c4dac421 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -45,6 +45,7 @@ Package.onUse(function(api) { 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/outgoing/addOutgoingIntegration.coffee', 'server'); // api api.addFiles('server/api/api.coffee', 'server'); 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 00000000000..e164c310dfc --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -0,0 +1,82 @@ +Meteor.methods + addOutgoingIntegration: (integration) -> + if not RocketChat.authz.hasPermission @userId, 'manage-integrations' + throw new Meteor.Error 'not_authorized' + + if Match.test integration.urls, [String] + throw new Meteor.Error 'invalid_urls', '[methods] addOutgoingIntegration -> urls must be an array' + + for url, index in urls + delete urls[index] if url.trim() is '' + + urls = _.without urls, [undefined] + + if integration.urls.length is 0 + throw new Meteor.Error 'invalid_urls', '[methods] addOutgoingIntegration -> urls is required' + + # if integration.channel.trim() is '' + # throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel can\'t be empty' + + # if integration.channel[0] not in ['@', '#'] + # throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel should start with # or @' + + # if not _.isString(integration.username) + # throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username must be string' + + # if integration.username.trim() is '' + # throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username can\'t be empty' + + + # urlsArr = urls.split('\n') + # urls = [] + # for url in urlsArr + # urls.push url.trim() if url.trim() isnt '' + + # if urls.length is 0 + # return toastr.error TAPi18n.__("You_should_inform_one_url_at_least") + + 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] addIntegration -> 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" + + stampedToken = Accounts._generateStampedLoginToken() + hashStampedToken = Accounts._hashStampedToken(stampedToken) + + updateObj = + $push: + 'services.resume.loginTokens': + hashedToken: hashStampedToken.hashedToken + integration: true + + integration.token = hashStampedToken.hashedToken + integration.userId = user._id + integration._createdAt = new Date + integration._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}} + + RocketChat.models.Users.update {_id: user._id}, updateObj + + integration._id = RocketChat.models.Integrations.insert integration + + return integration -- GitLab From 38a16d5fd27435e753a12a2f944757b9e4fb23d8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 14:31:25 -0200 Subject: [PATCH 0971/1338] Add logs about GM detection --- packages/rocketchat-file/file.server.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index a47489fac24..7c5d321aa4d 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -20,19 +20,24 @@ RocketChatFile = RocketChat.settings.updateOptionsById 'Accounts_AvatarResize', {alert: 'The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server'} +console.log 'GM: Getting GraphicsMagick version' exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> if not error? and stdout.indexOf('GraphicsMagick') > -1 + console.log 'GM: GraphicsMagick installed' RocketChatFile.enable() RocketChat.Info.GraphicsMagick = enabled: true version: stdout else + console.log 'GM: GraphicsMagick not installed' RocketChat.Info.GraphicsMagick = enabled: false + console.log 'GM: Getting ImageMagick version' exec 'convert -version', Meteor.bindEnvironment (error, stdout, stderr) -> if not error? and stdout.indexOf('ImageMagick') > -1 + console.log 'GM: ImageMagick installed' if RocketChatFile.enabled isnt true # Enable GM to work with ImageMagick if no GraphicsMagick RocketChatFile.gm = RocketChatFile.gm.subClass({imageMagick: true}) @@ -42,6 +47,7 @@ exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> enabled: true version: stdout else + console.log 'GM: ImageMagick installed' if RocketChatFile.enabled isnt true RocketChatFile.disable() -- GitLab From 6ad7f4454a23d3398eafb6a67d397ff095ac7f59 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 14:35:06 -0200 Subject: [PATCH 0972/1338] Email selected messages --- ...cketChatChannelSettingsMailMessages.coffee | 12 --- .../client/stylesheets/mail-messages.less | 24 ++++++ .../views/channelSettingsMailMessages.html | 4 +- .../views/mailMessagesInstructions.coffee | 74 +++++++++++++++++-- .../views/mailMessagesInstructions.html | 24 +++--- .../i18n/en.i18n.json | 8 +- .../package.js | 10 ++- .../server/methods/mailMessages.coffee | 40 ++++++++++ .../client/stylesheets/channel-settings.less | 30 ++++---- .../client/views/channelSettings.html | 62 ++++++++-------- packages/rocketchat-lib/lib/Message.coffee | 26 +++++++ .../{client => lib}/MessageTypes.coffee | 0 packages/rocketchat-lib/package.js | 3 +- .../server/models/Messages.coffee | 9 ++- 14 files changed, 243 insertions(+), 83 deletions(-) delete mode 100644 packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/stylesheets/mail-messages.less create mode 100644 packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee create mode 100644 packages/rocketchat-lib/lib/Message.coffee rename packages/rocketchat-lib/{client => lib}/MessageTypes.coffee (100%) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee deleted file mode 100644 index af7b8284173..00000000000 --- a/packages/rocketchat-channel-settings-mail-messages/client/lib/RocketChatChannelSettingsMailMessages.coffee +++ /dev/null @@ -1,12 +0,0 @@ -RocketChat.ChannelSettingsMailMessages = new class - addCheckboxes = -> - $('.messages-box .wrapper .message').each (index, item) -> - $item = $(item) - unless $item.find('input[type=checkbox]').length - $item.prepend(HTML.toHTML(HTML.INPUT({type: 'checkbox', class: 'send-message', style: 'position: absolute; left: 0' }))); - - removeCheckboxes = -> - $('.messages-box .wrapper .message input[type=checkbox].send-message').remove() - - addCheckboxes: addCheckboxes - removeCheckboxes: removeCheckboxes 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 00000000000..6b5e9dd4a5b --- /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.html b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html index ff680914b12..10b1cce82fe 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html @@ -1,8 +1,8 @@ <template name="channelSettingsMailMessages"> - <div class="input-line double-col"> + <li> <label>{{_ "Mail_Messages"}}</label> <div> <button type="button" class="button primary mail-messages">{{_ "Choose_messages"}}</button> </div> - </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 index d8672a24efb..f95e8f0aba5 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -1,17 +1,79 @@ Template.mailMessagesInstructions.helpers - body: -> - return '' + 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(', ') Template.mailMessagesInstructions.events 'click .cancel': (e, t) -> - RocketChat.TabBar.setTemplate('channelSettings') - view = Blaze.getView($('.messages-box')[0]) - view?.templateInstance?().resetSelection?(false) + t.reset() 'click .send': (e, t) -> - console.log 'sending' + 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]').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]').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 + t.$('.error-missing-to').show() + error = true + + if error + $btn.html(oldBtnValue) + else + data = + rid: Session.get('openedRoom') + to: t.$('input[name=to]').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) + + 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') Template.mailMessagesInstructions.onCreated -> + @erroredEmails = new ReactiveVar [] + + @reset = -> + RocketChat.TabBar.setTemplate('channelSettings') + view = Blaze.getView($('.messages-box')[0]) + view?.templateInstance?().resetSelection?(false) + @autorun => if Session.get('channelSettingsMailMessages') isnt Session.get('openedRoom') RocketChat.TabBar.setTemplate('channelSettings') diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html index 79d62505d1a..c8c27429f6d 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html @@ -1,6 +1,6 @@ <template name="mailMessagesInstructions"> <div class="content"> - <div class="list-view"> + <div class="list-view mail-message"> <div class="status"> <h2>{{_ "Mail_Messages"}}</h2> </div> @@ -9,9 +9,8 @@ <fieldset> <div class="input-line double-col"> <label>{{_ "From"}}</label> - <div> - <input type="text" name="from" value="" /> - </div> + <div>{{name}}</div> + <div>{{email}}</div> </div> <div class="input-line double-col"> <label>{{_ "To"}}</label> @@ -22,17 +21,20 @@ <div class="input-line double-col"> <label>{{_ "Subject"}}</label> <div> - <input type="text" name="subject" value="" /> - </div> - </div> - <div class="input-line double-col"> - <label>{{_ "Body"}}</label> - <div> - {{body}} + <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> diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json index 64e39f5943c..32ec45e9cdb 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json @@ -3,9 +3,15 @@ "Cancel" : "Cancel", "Choose_messages" : "Choose messages", "From" : "From", + "Mail_Message_Missing_to" : "You must provide one or more To 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", + "Mail_Message_Invalid_emails" : "You have provided one or more invalid e-mails: %s", "Send" : "Send", + "Sending" : "Sending...", "Subject" : "Subject", - "To" : "To" + "To" : "To", + "Your_email_has_been_queued_for_sending" : "Your email has been queued for sending" } diff --git a/packages/rocketchat-channel-settings-mail-messages/package.js b/packages/rocketchat-channel-settings-mail-messages/package.js index b66d7d51415..673d2f8b02e 100644 --- a/packages/rocketchat-channel-settings-mail-messages/package.js +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -14,18 +14,24 @@ Package.onUse(function(api) { 'reactive-var', 'less@2.5.0', 'rocketchat:lib@0.0.1', - 'rocketchat:channel-settings' + 'rocketchat:channel-settings', + 'momentjs:moment' ]); api.addFiles([ 'client/lib/ChannelSettings.coffee', - 'client/lib/RocketChatChannelSettingsMailMessages.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/methods/mailMessages.coffee' + ], 'server'); + // TAPi18n var _ = Npm.require('underscore'); var fs = Npm.require('fs'); 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 00000000000..0403b5aef15 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -0,0 +1,40 @@ +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: 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") + + 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 = data.to.trim().split(',') + for email in emails + unless rfcMailPatternWithName.test email.trim() + throw new Meteor.Error('invalid-email', "[methods] mailMessages -> Invalid e-mail") + + user = Meteor.user() + name = user.name + email = user.emails?[0]?.address + + moment(data.language) + + html = "" + RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) -> + dateTime = moment(message.ts).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 true diff --git a/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less b/packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less index a09d3ee179c..872c1a73318 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; + } } } @@ -19,15 +33,3 @@ } } } - -.input-line.double-col { - div { - line-height: 15px; - padding: 10px 20px 10px 0; - i.octicon { - font-size: 13px; - opacity: 0.4; - vertical-align: top; - } - } -} diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index bc809371fa5..4317cf72b55 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -1,36 +1,32 @@ <template name="channelSettings"> - <div class="control"> - <div class="header"> - <h2>{{_ "Room_Info"}}</h2> - </div> - </div> - <div class="channel-settings scrollable"> - <form> - <fieldset> - {{#if notDirect}} - <div class="input-line double-col"> + <div class="content"> + <div class="list-view channel-settings"> + <div class="status"> + <h2>{{_ "Room_Info"}}</h2> + </div> + <form> + <ul class="list clearfix"> + <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}} - {{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomName"></i>{{/if}} + <span>{{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomName"></i>{{/if}}</span> {{/if}} </div> - </div> - {{/if}} - <div class="input-line double-col"> - <label>{{_ "Topic"}}</label> - <div> - {{#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}} - {{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomTopic"></i>{{/if}} - {{/if}} - </div> - </div> - {{#if notDirect}} - <div class="input-line double-col"> + </li> + <li> + <label>{{_ "Topic"}}</label> + <div> + {{#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> + </li> + <li> <label>{{_ "Type"}}</label> <div> {{#if editing 'roomType'}} @@ -39,15 +35,15 @@ <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button> {{else}} - {{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomType"></i>{{/if}} + <span>{{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomType"></i>{{/if}}</span> {{/if}} </div> - </div> - {{/if}} - {{#each channelSettings}} - {{> Template.dynamic template=template data=data}} - {{/each}} - </fieldset> - </form> + </li> + {{#each channelSettings}} + {{> Template.dynamic template=template data=data}} + {{/each}} + </ul> + </form> + </div> </div> </template> diff --git a/packages/rocketchat-lib/lib/Message.coffee b/packages/rocketchat-lib/lib/Message.coffee new file mode 100644 index 00000000000..cbf6e92a89f --- /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 100% rename from packages/rocketchat-lib/client/MessageTypes.coffee rename to packages/rocketchat-lib/lib/MessageTypes.coffee diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index aacfc1337ff..34e49b1c7f3 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -33,6 +33,8 @@ Package.onUse(function(api) { 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'); @@ -92,7 +94,6 @@ 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'); // VERSION api.addFiles('rocketchat.info'); diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 5010fc05d4c..3c9375f075b 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -116,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 @@ -134,7 +142,6 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base return @insert record - # UPDATE setHiddenById: (_id, hidden=true) -> query = -- GitLab From b724a788cb4011318fe6a303070e677d2e23859d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 14:43:52 -0200 Subject: [PATCH 0973/1338] Fix logs --- packages/rocketchat-file/file.server.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 7c5d321aa4d..0492acda30d 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -47,7 +47,7 @@ exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> enabled: true version: stdout else - console.log 'GM: ImageMagick installed' + console.log 'GM: ImageMagick not installed' if RocketChatFile.enabled isnt true RocketChatFile.disable() -- GitLab From d71e99dbebe108ec20b1e838ed3326c8d4d8c005 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 14:47:44 -0200 Subject: [PATCH 0974/1338] Log arguments of GM detection --- packages/rocketchat-file/file.server.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 0492acda30d..27a49d1967a 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -22,6 +22,7 @@ RocketChatFile = console.log 'GM: Getting GraphicsMagick version' exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> + console.log 'GM: GraphicsMagick', arguments if not error? and stdout.indexOf('GraphicsMagick') > -1 console.log 'GM: GraphicsMagick installed' RocketChatFile.enable() @@ -36,6 +37,7 @@ exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> console.log 'GM: Getting ImageMagick version' exec 'convert -version', Meteor.bindEnvironment (error, stdout, stderr) -> + console.log 'GM: ImageMagick', arguments if not error? and stdout.indexOf('ImageMagick') > -1 console.log 'GM: ImageMagick installed' if RocketChatFile.enabled isnt true -- GitLab From da9c8c6387de58a5deb80714c6590e6d1a75c7ac Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 14:56:44 -0200 Subject: [PATCH 0975/1338] saving department agents in new collection --- .../collections/LivechatDepartmentAgents.js | 1 + .../views/app/livechatDepartmentForm.html | 4 +-- .../views/app/livechatDepartmentForm.js | 18 +++++++++--- .../client/views/app/livechatDepartments.js | 5 ---- packages/rocketchat-livechat/package.js | 3 ++ .../server/models/LivechatDepartment.js | 28 +++++++++++-------- .../server/models/LivechatDepartmentAgents.js | 15 +++++++++- 7 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js diff --git a/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js new file mode 100644 index 00000000000..08ea1741134 --- /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/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html index e0d0249d4d9..1dd1ecd0468 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -52,8 +52,8 @@ {{#each selectedAgents}} <tr class="agent-info"> <td>{{username}}</td> - <td><input type="text" class="count-{{_id}}" name="count" value="{{count}}" size="3"></td> - <td><input type="text" class="order-{{_id}}" name="order" value="{{order}}" size="3"></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=""><i class="icon-trash remove-agent"></i></a></td> </tr> {{/each}} diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js index 8e322bd3812..22e3693e12c 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js @@ -48,12 +48,13 @@ Template.livechatDepartmentForm.events({ var departmentAgents = []; instance.selectedAgents.get().forEach((agent) => { - agent.count = instance.$('.count-' + agent._id).val(); - agent.order = instance.$('.order-' + agent._id).val(); + agent.count = instance.$('.count-' + agent.agentId).val(); + agent.order = instance.$('.order-' + agent.agentId).val(); departmentAgents.push(agent); }); + console.log('save - departmentAgents ->',departmentAgents); Meteor.call('livechat:saveDepartment', _id, departmentData, departmentAgents, function(error, result) { $btn.html(oldBtnValue); @@ -111,7 +112,10 @@ Template.livechatDepartmentForm.events({ 'click .available-agents li' (e, instance) { var selectedAgents = instance.selectedAgents.get(); - selectedAgents.push(this); + var agent = _.clone(this); + agent.agentId = this._id; + delete agent._id; + selectedAgents.push(agent); instance.selectedAgents.set(selectedAgents); } }); @@ -129,7 +133,13 @@ Template.livechatDepartmentForm.onCreated(function() { if (department) { this.department.set(department); - this.subscribe('livechat:departmentAgents', department._id); + 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.js b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js index eba12b82bc1..e5d0746485d 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js @@ -1,11 +1,6 @@ Template.livechatDepartments.helpers({ "departments": () => { return LivechatDepartment.find(); - }, - "numAgents"() { - if (Array.isArray(this.agents)) { - return this.agents.length; - } } }); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index dbcac5dc322..f6b14d25635 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -41,6 +41,7 @@ Package.onUse(function(api) { // 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/LivechatTrigger.js', 'client'); // client views @@ -85,12 +86,14 @@ Package.onUse(function(api) { 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/LivechatTrigger.js', 'server'); // server lib api.addFiles('server/lib/getNextAgent.js', 'server'); // publications + 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'); diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index 61cac814cf2..86402792b6f 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -19,7 +19,6 @@ class LivechatDepartment extends RocketChat.models._Base { return this.find(query, options); } - // UPSERT createOrUpdateDepartment(_id, enabled, name, description, agents, extraData) { var agents = [].concat(agents); @@ -27,15 +26,9 @@ class LivechatDepartment extends RocketChat.models._Base { enabled: enabled, name: name, description: description, - numAgents: agents.count() + numAgents: agents.length }; - // if (agents.length > 0) { - // for (agent of agents) { - // record.agents.push({ _id: agent._id, username: agent.username }); - // } - // } - _.extend(record, extraData); if (_id) { @@ -44,13 +37,24 @@ class LivechatDepartment extends RocketChat.models._Base { _id = this.insert(record); } - agents.forEach((agent) => { - agent.departmentId = _id; + var savedAgents = _.pluck(RocketChat.models.LivechatDepartmentAgents.findByDepartmentId(_id).fetch(), 'agentId'); + var agentsToSave = _.pluck(agents, 'agentId'); - RocketChat.models.LivechatDepartmentAgents.saveAgent(agent); + // 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: agent.count, + order: agent.order + }); }); - // this.upsert({ _id: _id }, { $set: record }); return _.extend(record, { _id: _id }); } diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js index 27be6a1f046..0dc14e2d4d8 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js @@ -15,9 +15,22 @@ class LivechatDepartmentAgents extends RocketChat.models._Base { if (agent._id) { return this.update({ _id: _id }, { $set: agent }); } else { - return this.insert(agent); + return this.upsert({ + agentId: agent.agentId, + departmentId: agent.departmentId + }, { + $set: { + username: agent.username, + count: agent.count, + order: agent.order + } + }); } } + + removeByDepartmentIdAndAgentId(departmentId, agentId) { + this.remove({ departmentId: departmentId, agentId: agentId }); + } } RocketChat.models.LivechatDepartmentAgents = new LivechatDepartmentAgents(); -- GitLab From 1cc9e8205eacbe5d4bb7e99bb8cbfcb3e813a518 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 15:19:22 -0200 Subject: [PATCH 0976/1338] showing no agents in this department --- .../views/app/livechatDepartmentForm.html | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html index 1dd1ecd0468..3cd6adffd3b 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -49,19 +49,20 @@ </tr> </thead> <tbody> - {{#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=""><i class="icon-trash remove-agent"></i></a></td> - </tr> - {{/each}} - <!-- {{else}} + {{#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="2">{{_ "There_are_no_agents_added_to_this_department_yet"}}</td> + <td colspan="4">{{_ "There_are_no_agents_added_to_this_department_yet"}}</td> </tr> - {{/if}} --> + {{/if}} </tbody> </table> </div> -- GitLab From 42d57e76c8ca11c56189c51faa59b2f6f125d71a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 15:24:23 -0200 Subject: [PATCH 0977/1338] added missing translations --- packages/rocketchat-livechat/i18n/en.i18n.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 072aeddc320..754decc3449 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -4,9 +4,11 @@ "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", @@ -32,10 +34,12 @@ "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", "Theme" : "Theme", "There_are_no_agents_added_to_this_department_yet" : "There are no agents added to this department yet.", @@ -48,4 +52,4 @@ "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 +} -- GitLab From e33e82b9e49d64879dfbb8dc17ff8ca6b32eb3b0 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 15:26:12 -0200 Subject: [PATCH 0978/1338] Remove selection of messages on roomExit --- .../client/lib/ChannelSettings.coffee | 3 -- .../client/lib/startup.coffee | 9 ++++ .../views/mailMessagesInstructions.coffee | 2 +- .../package.js | 2 +- .../client/views/channelSettings.html | 50 ++++++++++--------- .../rocketchat-lib/client/lib/roomExit.coffee | 2 + 6 files changed, 40 insertions(+), 28 deletions(-) delete mode 100644 packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee create mode 100644 packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee deleted file mode 100644 index 9c4e420f5e9..00000000000 --- a/packages/rocketchat-channel-settings-mail-messages/client/lib/ChannelSettings.coffee +++ /dev/null @@ -1,3 +0,0 @@ -RocketChat.ChannelSettings.addOption - id: 'mail-messages' - template: 'channelSettingsMailMessages' 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 00000000000..ecdfc26de46 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee @@ -0,0 +1,9 @@ +Meteor.startup -> + RocketChat.ChannelSettings.addOption + id: 'mail-messages' + template: 'channelSettingsMailMessages' + + RocketChat.callbacks.add 'roomExit', (mainNode) -> + instance = Blaze.getView($('.messages-box')?[0])?.templateInstance() + instance?.resetSelection(false) + , RocketChat.callbacks.priority.MEDIUM, 'room-exit-mail-messages' diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee index f95e8f0aba5..ed30d543765 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -76,4 +76,4 @@ Template.mailMessagesInstructions.onCreated -> @autorun => if Session.get('channelSettingsMailMessages') isnt Session.get('openedRoom') - RocketChat.TabBar.setTemplate('channelSettings') + this.reset() diff --git a/packages/rocketchat-channel-settings-mail-messages/package.js b/packages/rocketchat-channel-settings-mail-messages/package.js index 673d2f8b02e..d5344ae5826 100644 --- a/packages/rocketchat-channel-settings-mail-messages/package.js +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -19,7 +19,7 @@ Package.onUse(function(api) { ]); api.addFiles([ - 'client/lib/ChannelSettings.coffee', + 'client/lib/startup.coffee', 'client/stylesheets/mail-messages.less', 'client/views/channelSettingsMailMessages.html', 'client/views/channelSettingsMailMessages.coffee', diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index 4317cf72b55..f2c87034387 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -6,16 +6,18 @@ </div> <form> <ul class="list clearfix"> - <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 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> @@ -26,19 +28,21 @@ {{/if}} </div> </li> - <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 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}} {{#each channelSettings}} {{> Template.dynamic template=template data=data}} {{/each}} diff --git a/packages/rocketchat-lib/client/lib/roomExit.coffee b/packages/rocketchat-lib/client/lib/roomExit.coffee index 7ee736f5e2e..d7da9ed4a87 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? -- GitLab From 34a1147a1d7017bfb33586b2d001f5fe4aff061b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 15:29:14 -0200 Subject: [PATCH 0979/1338] Set moment locale --- .../server/methods/mailMessages.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee index 0403b5aef15..df90132e223 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -19,7 +19,7 @@ Meteor.methods name = user.name email = user.emails?[0]?.address - moment(data.language) + moment.locale(data.language) html = "" RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) -> -- GitLab From ee4da05d5afcbd581a055b463c90045149ac4840 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 15:34:14 -0200 Subject: [PATCH 0980/1338] select agents UI improvements --- .../client/stylesheets/livechat.less | 17 +++++++++++++++-- .../views/app/livechatDepartmentForm.html | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index afdb9d63f78..7c23ac7dd6c 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -418,8 +418,21 @@ li { display: inline-block; background-color: #DDD; - border-radius: 5px; - padding: 2px 7px; + 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 { + width: auto; + line-height: 24px; } } diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html index 3cd6adffd3b..fccbaa7f071 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html @@ -30,7 +30,7 @@ <ul class="department-agents available-agents"> {{#each availableAgents}} - <li>{{username}}</li> + <li><i class="icon-plus-circled"></i>{{username}}</li> {{/each}} </ul> </fieldset> -- GitLab From 87eea53c7755e595cc96fc12b050123a166c4255 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 15:46:06 -0200 Subject: [PATCH 0981/1338] Add method to run the GM detection --- packages/rocketchat-file/file.server.coffee | 70 ++++++++++++--------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 27a49d1967a..80b6e64bfc7 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -20,42 +20,50 @@ RocketChatFile = RocketChat.settings.updateOptionsById 'Accounts_AvatarResize', {alert: 'The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server'} -console.log 'GM: Getting GraphicsMagick version' -exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> - console.log 'GM: GraphicsMagick', arguments - if not error? and stdout.indexOf('GraphicsMagick') > -1 - console.log 'GM: GraphicsMagick installed' - RocketChatFile.enable() - - RocketChat.Info.GraphicsMagick = - enabled: true - version: stdout - else - console.log 'GM: GraphicsMagick not installed' - RocketChat.Info.GraphicsMagick = - enabled: false - - console.log 'GM: Getting ImageMagick version' - exec 'convert -version', Meteor.bindEnvironment (error, stdout, stderr) -> - console.log 'GM: ImageMagick', arguments - if not error? and stdout.indexOf('ImageMagick') > -1 - console.log 'GM: ImageMagick installed' - 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 = +detectGM = -> + console.log 'GM: Getting GraphicsMagick version' + exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> + console.log 'GM: GraphicsMagick', arguments + if not error? and stdout.indexOf('GraphicsMagick') > -1 + console.log 'GM: GraphicsMagick installed' + RocketChatFile.enable() + + RocketChat.Info.GraphicsMagick = enabled: true version: stdout else - console.log 'GM: ImageMagick not installed' - if RocketChatFile.enabled isnt true - RocketChatFile.disable() - - RocketChat.Info.ImageMagick = + console.log 'GM: GraphicsMagick not installed' + RocketChat.Info.GraphicsMagick = enabled: false + console.log 'GM: Getting ImageMagick version' + exec 'convert -version', Meteor.bindEnvironment (error, stdout, stderr) -> + console.log 'GM: ImageMagick', arguments + if not error? and stdout.indexOf('ImageMagick') > -1 + console.log 'GM: ImageMagick installed' + 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 + console.log 'GM: ImageMagick not installed' + 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() -- GitLab From fb31335bea0636de528b484c8635929bb6383171 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 16:01:56 -0200 Subject: [PATCH 0982/1338] Load moment locale for formatting date on mail messages --- .../server/methods/mailMessages.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee index df90132e223..5fe2674159f 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -19,7 +19,11 @@ Meteor.methods name = user.name email = user.emails?[0]?.address - moment.locale(data.language) + if data.language isnt 'en' + localeFn = Meteor.call 'loadLocale', data.language + if localeFn + Function(localeFn)() + moment.locale(data.language) html = "" RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) -> -- GitLab From 7f08e48614b2d5b4e1420fd10552d936919be1b3 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 16:05:34 -0200 Subject: [PATCH 0983/1338] get next agent from a department queue --- .../client/stylesheets/livechat.less | 3 +- .../server/lib/getNextAgent.js | 21 +------ .../server/models/LivechatDepartment.js | 60 +------------------ .../server/models/LivechatDepartmentAgents.js | 39 +++++++++++- 4 files changed, 42 insertions(+), 81 deletions(-) diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index 7c23ac7dd6c..b389c38d398 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -431,8 +431,9 @@ } .agent-info { - input { + input[type='text'] { width: auto; line-height: 24px; + height: 24px; } } diff --git a/packages/rocketchat-livechat/server/lib/getNextAgent.js b/packages/rocketchat-livechat/server/lib/getNextAgent.js index 1e9aba08673..3259ab642d9 100644 --- a/packages/rocketchat-livechat/server/lib/getNextAgent.js +++ b/packages/rocketchat-livechat/server/lib/getNextAgent.js @@ -1,27 +1,8 @@ this.getNextAgent = function(department) { var agentFilter = {}; - // find agents from that department if (department) { - var agents = RocketChat.models.LivechatDepartment.getNextAgent(department); - - if (!agents) { - return; - } - - // sort = { - // count: 1, - // order: 1, - // 'user.name': 1 - // } - - // update = { - // $inc: { - // count: 1 - // } - // } - - // queueUser = findAndModify query, sort, update + return RocketChat.models.LivechatDepartment.getNextAgent(department); } else { return RocketChat.models.Users.getNextAgent(); } diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index 86402792b6f..d474415ea96 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -50,8 +50,8 @@ class LivechatDepartment extends RocketChat.models._Base { agentId: agent.agentId, departmentId: _id, username: agent.username, - count: agent.count, - order: agent.order + count: parseInt(agent.count), + order: parseInt(agent.order) }); }); @@ -63,62 +63,6 @@ class LivechatDepartment extends RocketChat.models._Base { query = { _id: _id }; return this.remove(query); } - - getNextAgent(departmentId) { - - var department = this.findOne({ _id: departmentId }, { fields: { agents: 1 } }) - - if (!department || !department.agents || department.agents.length === 0) { - return; - } - - var onlineUsers = RocketChat.models.Users.findOnlineUserFromList(_.pluck(department.agents, 'username')); - - var onlineUsernames = _.pluck(onlineUsers.fetch(), 'username'); - - console.log('onlineUsernames ->',onlineUsernames); - - var query = { - _id: departmentId, - "agents.username": { - $in: onlineUsernames - } - }; - - var sort = { - livechatCount: 1, - // sort: 1, - username: 1 - }; - var update = { - $inc: { - "agents.$.livechatCount": 1 - } - }; - - // var query = { - // status: 'online' - // }; - - // query['roles.' + Roles.GLOBAL_GROUP] = '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 - // } - // }; - - return findAndModify(query, sort, update); - // return RocketChat.models.Users.getNextAgent(department.agents); - } } RocketChat.models.LivechatDepartment = new LivechatDepartment(); diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js index 0dc14e2d4d8..a4d56fa7ba8 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js @@ -21,8 +21,8 @@ class LivechatDepartmentAgents extends RocketChat.models._Base { }, { $set: { username: agent.username, - count: agent.count, - order: agent.order + count: parseInt(agent.count), + order: parseInt(agent.order) } }); } @@ -31,6 +31,41 @@ class LivechatDepartmentAgents extends RocketChat.models._Base { 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); + + return findAndModify(query, sort, update); + } } RocketChat.models.LivechatDepartmentAgents = new LivechatDepartmentAgents(); -- GitLab From eb9195f9cdb00a50a57d8a4f155d55476974308b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 22 Dec 2015 16:10:32 -0200 Subject: [PATCH 0984/1338] code cleanup --- .../views/app/livechatDepartmentForm.js | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js index 22e3693e12c..6f5017e0ca2 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js +++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js @@ -1,6 +1,5 @@ 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() { @@ -36,13 +35,10 @@ Template.livechatDepartmentForm.events({ var oldBtnValue = $btn.html(); $btn.html(t('Saving')); - // agents = instance.department && !_.isEmpty(instance.department.get()) ? instance.department.get().agents : []; - var departmentData = { enabled: enabled === "1" ? true : false, name: name.trim(), description: description.trim() - // agents: agents }; var departmentAgents = []; @@ -54,8 +50,6 @@ Template.livechatDepartmentForm.events({ departmentAgents.push(agent); }); - console.log('save - departmentAgents ->',departmentAgents); - Meteor.call('livechat:saveDepartment', _id, departmentData, departmentAgents, function(error, result) { $btn.html(oldBtnValue); if (error) { @@ -72,36 +66,6 @@ Template.livechatDepartmentForm.events({ FlowRouter.go('livechat-departments'); }, - // 'click button.add-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(''); - // }); - // }, - 'click .remove-agent' (e, instance) { e.preventDefault(); -- GitLab From 4c1ea21ff46ea7b552e9ed4a4e5f1939bc86c58b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 16:24:38 -0200 Subject: [PATCH 0985/1338] Fix: don't change locale globally --- .../server/methods/mailMessages.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee index 5fe2674159f..505a21d9cc0 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -23,11 +23,10 @@ Meteor.methods localeFn = Meteor.call 'loadLocale', data.language if localeFn Function(localeFn)() - moment.locale(data.language) html = "" RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) -> - dateTime = moment(message.ts).format('L LT') + 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 -> -- GitLab From 55a31e3aa42c754d107d0554236466d63c08adb0 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 17:05:03 -0200 Subject: [PATCH 0986/1338] Add authorization for mail messages --- .../client/lib/startup.coffee | 2 ++ packages/rocketchat-channel-settings-mail-messages/package.js | 1 + .../server/lib/startup.coffee | 3 +++ .../server/methods/mailMessages.coffee | 3 +++ 4 files changed, 9 insertions(+) create mode 100644 packages/rocketchat-channel-settings-mail-messages/server/lib/startup.coffee diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee index ecdfc26de46..9cf0b622074 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee @@ -2,6 +2,8 @@ Meteor.startup -> RocketChat.ChannelSettings.addOption id: 'mail-messages' template: 'channelSettingsMailMessages' + validation: -> + return RocketChat.authz.hasAllPermission('mail-messages') RocketChat.callbacks.add 'roomExit', (mainNode) -> instance = Blaze.getView($('.messages-box')?[0])?.templateInstance() diff --git a/packages/rocketchat-channel-settings-mail-messages/package.js b/packages/rocketchat-channel-settings-mail-messages/package.js index d5344ae5826..b0fb444889d 100644 --- a/packages/rocketchat-channel-settings-mail-messages/package.js +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -29,6 +29,7 @@ Package.onUse(function(api) { api.addFiles([ + 'server/lib/startup.coffee', 'server/methods/mailMessages.coffee' ], 'server'); 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 00000000000..0a30dd195e4 --- /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 index 505a21d9cc0..499543047cd 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -9,6 +9,9 @@ Meteor.methods 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 = data.to.trim().split(',') for email in emails -- GitLab From 5cb767fe6bdf8f606244f2022efcaa6e10d02527 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 18:43:58 -0200 Subject: [PATCH 0987/1338] Allow editing user password --- packages/rocketchat-authorization/server/startup.coffee | 3 +++ packages/rocketchat-lib/server/methods/updateUser.coffee | 4 ++++ .../rocketchat-ui-admin/admin/users/adminUserEdit.coffee | 3 ++- .../rocketchat-ui-admin/admin/users/adminUserEdit.html | 8 +++++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 1fc3643b4d2..663f7354970 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -27,6 +27,9 @@ Meteor.startup -> { _id: 'edit-other-user-info', roles : ['admin']} + { _id: 'edit-other-user-password', + roles : ['admin']} + { _id: 'assign-admin-role', roles : ['admin']} diff --git a/packages/rocketchat-lib/server/methods/updateUser.coffee b/packages/rocketchat-lib/server/methods/updateUser.coffee index 53f3536d0d8..2416d3d1184 100644 --- a/packages/rocketchat-lib/server/methods/updateUser.coffee +++ b/packages/rocketchat-lib/server/methods/updateUser.coffee @@ -23,4 +23,8 @@ Meteor.methods Meteor.runAsUser userData._id, -> Meteor.call 'setUsername', userData.username + 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-ui-admin/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee index f089dff3bed..aeb9352b155 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 686f999ffdb..f1e620f95f9 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> -- GitLab From b98c77c1cc5374d7915a15ef207a859725dd99c7 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 18:53:13 -0200 Subject: [PATCH 0988/1338] Fix for links stopped working --- packages/rocketchat-ui/views/app/room.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 2d0e4ba0b08..2127c7662af 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -411,8 +411,6 @@ Template.room.events RoomHistoryManager.clear(template?.data?._id) 'click .message': (e, template) -> - e.preventDefault() - e.stopPropagation() if template.selectable.get() document.selection?.empty() or window.getSelection?().removeAllRanges() data = Blaze.getData(e.currentTarget) -- GitLab From cf296057928fbc025275ded1456bc1f0aaa19704 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 22 Dec 2015 18:53:47 -0200 Subject: [PATCH 0989/1338] move file to example --- build.sh => example-build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build.sh => example-build.sh (100%) diff --git a/build.sh b/example-build.sh similarity index 100% rename from build.sh rename to example-build.sh -- GitLab From 35ea9998590d2c770221ce61259b1e3903cb3939 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 22 Dec 2015 18:55:32 -0200 Subject: [PATCH 0990/1338] ignoring the customised build.sh --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2ae4ddd56cc..fdec437e0c5 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ tramp ecosystem.json pm2.json settings.json +build.sh -- GitLab From ad83f9778619e6548a8511d18174c22934f8b006 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 19:29:21 -0200 Subject: [PATCH 0991/1338] Finish the outgoing hook cadastre --- .../client/views/integrations.html | 50 +++++++---- .../client/views/integrationsIncoming.coffee | 6 +- .../client/views/integrationsOutgoing.coffee | 34 ++++--- .../client/views/integrationsOutgoing.html | 12 ++- packages/rocketchat-integrations/package.js | 8 +- .../addIncomingIntegration.coffee} | 16 ++-- .../deleteIncomingIntegration.coffee} | 4 +- .../updateIncomingIntegration.coffee} | 12 +-- .../outgoing/addOutgoingIntegration.coffee | 88 ++++++++----------- .../outgoing/deleteOutgoingIntegration.coffee | 13 +++ .../outgoing/updateOutgoingIntegration.coffee | 84 ++++++++++++++++++ 11 files changed, 228 insertions(+), 99 deletions(-) rename packages/rocketchat-integrations/server/methods/{addIntegration.coffee => incoming/addIncomingIntegration.coffee} (69%) rename packages/rocketchat-integrations/server/methods/{deleteIntegration.coffee => incoming/deleteIncomingIntegration.coffee} (75%) rename packages/rocketchat-integrations/server/methods/{updateIntegration.coffee => incoming/updateIncomingIntegration.coffee} (67%) create mode 100644 packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee create mode 100644 packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index d1075af7756..580b06e6ab1 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -7,26 +7,46 @@ <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> {{/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> </div> diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index f61b55199dc..b3aabfa5bc0 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -108,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') @@ -141,7 +141,7 @@ Template.integrationsIncoming.events 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) @@ -150,7 +150,7 @@ Template.integrationsIncoming.events 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/integrationsOutgoing.coffee b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee index 63ac2cfc081..5430d9c97d9 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee @@ -1,10 +1,7 @@ Template.integrationsOutgoing.onCreated -> @record = new ReactiveVar - name: 'name' - alias: 'alias' - channel: '#general' - triggerWords: ['send', 'sent'] - urls: ['https://www.google.com', 'https://www.google.com'] + username: 'rocket.cat' + token: Random.id(24) Template.integrationsOutgoing.helpers @@ -82,6 +79,7 @@ Template.integrationsOutgoing.events 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() @@ -101,7 +99,7 @@ Template.integrationsOutgoing.events closeOnConfirm: false html: false , -> - Meteor.call "deleteIntegration", params.id, (err, data) -> + Meteor.call "deleteOutgoingIntegration", params.id, (err, data) -> swal title: t('Deleted') text: t('Your_entry_has_been_deleted') @@ -117,23 +115,37 @@ Template.integrationsOutgoing.events 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 triggerWords is '' + 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] + + if triggerWords.length is 0 and channel.trim() is '' return toastr.error TAPi18n.__("You should inform at least one trigger word if you do not inform a channel") - urlsArr = urls.split('\n') - urls = [] - for url in urlsArr - urls.push url.trim() if url.trim() isnt '' + 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 = channel: channel + username: username alias: alias if alias isnt '' emoji: emoji if emoji isnt '' avatar: avatar if avatar isnt '' diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html index 1b83d457bf4..1b009cd93c0 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html @@ -24,7 +24,7 @@ <div class="input-line double-col"> <label>{{_ "Trigger_Words"}}</label> <div> - <input type="text" name="username" value="{{join data.triggerWords ','}}" /> + <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">{{_ "Optional if a channel is chosen"}}</div> <div class="settings-description">{{_ "Separate multiple words with commas"}}</div> @@ -37,6 +37,14 @@ <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> @@ -63,7 +71,7 @@ <div class="input-line double-col"> <label>Token</label> <div> - <input type="text" name="completeToken" value="{{data.completeToken}}" /> + <input type="text" name="token" value="{{data.token}}" /> </div> </div> <div class="input-line double-col"> diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index e78c4dac421..ff01a901293 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -42,10 +42,12 @@ 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'); diff --git a/packages/rocketchat-integrations/server/methods/addIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee similarity index 69% rename from packages/rocketchat-integrations/server/methods/addIntegration.coffee rename to packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee index 454b87d6bd2..316127e53ac 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) 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 d6f22c27701..692bb014d27 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 67% rename from packages/rocketchat-integrations/server/methods/updateIntegration.coffee rename to packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee index e09c565efb0..25787a28987 100644 --- a/packages/rocketchat-integrations/server/methods/updateIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee @@ -1,19 +1,19 @@ 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' + throw new Meteor.Error 'invalid_integration', '[methods] updateIncomingIntegration -> integration not found' record = undefined channelType = integration.channel[0] @@ -34,7 +34,7 @@ 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" RocketChat.models.Integrations.update integrationId, $set: diff --git a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee index e164c310dfc..be7e0372172 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -3,80 +3,70 @@ Meteor.methods if not RocketChat.authz.hasPermission @userId, 'manage-integrations' throw new Meteor.Error 'not_authorized' - if Match.test integration.urls, [String] + 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 urls - delete urls[index] if url.trim() is '' + for url, index in integration.urls + delete integration.urls[index] if url.trim() is '' - urls = _.without urls, [undefined] + 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.trim() is '' - # throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel can\'t be empty' + if integration.channel?.trim() isnt '' and integration.channel[0] not in ['@', '#'] + throw new Meteor.Error 'invalid_channel', '[methods] addOutgoingIntegration -> channel should start with # or @' - # if integration.channel[0] not in ['@', '#'] - # throw new Meteor.Error 'invalid_channel', '[methods] addIntegration -> channel should start with # or @' + if not integration.token? or integration.token?.trim() is '' + throw new Meteor.Error 'invalid_token', '[methods] addOutgoingIntegration -> token is required' - # if not _.isString(integration.username) - # throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username must be string' + if integration.triggerWords? + if not Match.test integration.triggerWords, [String] + throw new Meteor.Error 'invalid_triggerWords', '[methods] addOutgoingIntegration -> triggerWords must be an array' - # if integration.username.trim() is '' - # throw new Meteor.Error 'invalid_username', '[methods] addIntegration -> username can\'t be empty' + for triggerWord, index in integration.triggerWords + delete integration.triggerWords[index] if triggerWord.trim() is '' + integration.triggerWords = _.without integration.triggerWords, [undefined] - # urlsArr = urls.split('\n') - # urls = [] - # for url in urlsArr - # urls.push url.trim() if url.trim() isnt '' + if integration.triggerWords.length is 0 and not integration.channel? + throw new Meteor.Error 'invalid_triggerWords', '[methods] addOutgoingIntegration -> triggerWords is required if channel is empty' - # if urls.length is 0 - # return toastr.error TAPi18n.__("You_should_inform_one_url_at_least") - record = undefined - channelType = integration.channel[0] - channel = integration.channel.substr(1) + if integration.channel?.trim() isnt '' + 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} - ] + 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] addIntegration -> The channel does not exists" + 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] addIntegration -> The username does not exists" - - stampedToken = Accounts._generateStampedLoginToken() - hashStampedToken = Accounts._hashStampedToken(stampedToken) + throw new Meteor.Error 'user_does_not_exists', "[methods] addOutgoingIntegration -> The username does not exists" - updateObj = - $push: - 'services.resume.loginTokens': - hashedToken: hashStampedToken.hashedToken - integration: true - - integration.token = hashStampedToken.hashedToken integration.userId = user._id integration._createdAt = new Date integration._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}} - RocketChat.models.Users.update {_id: user._id}, updateObj - 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 00000000000..b13af8bdd51 --- /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' + 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 00000000000..d91c552aed1 --- /dev/null +++ b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee @@ -0,0 +1,84 @@ +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 integration.channel?.trim() isnt '' 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 integration.triggerWords.length is 0 and not integration.channel? + throw new Meteor.Error 'invalid_triggerWords', '[methods] updateOutgoingIntegration -> triggerWords is required if channel is empty' + + if not RocketChat.models.Integrations.findOne(integrationId)? + throw new Meteor.Error 'invalid_integration', '[methods] updateOutgoingIntegration -> integration not found' + + + if integration.channel?.trim() isnt '' + 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) -- GitLab From f5aae4f334d38c94a12171116c38edf91b3dc442 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 22 Dec 2015 19:31:45 -0200 Subject: [PATCH 0992/1338] Fix conflitcs --- .../client/views/channelSettings.html | 31 ++++++------------- .../i18n/en.i18n.json | 1 + 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index 35f3b002127..8a326bd4911 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -27,7 +27,6 @@ <span>{{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomTopic"></i>{{/if}}</span> {{/if}} </div> -<<<<<<< HEAD </li> {{#if notDirect}} <li> @@ -44,31 +43,21 @@ </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> - {{/if}} - </fieldset> - <div class="submit"> - <button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> - </div> - </form> - <form> - {{#if notDirect}} - <div class="submit"> - {{#if archived}} - <button class="button unarchive"><span>{{_ "Unarchive"}}</span></button> - {{else}} - <button class="button archive"><span>{{_ "Archive"}}</span></button> - {{/if}} - </div> - {{/if}} - </form> ->>>>>>> f838e9efb88902148d9cf0400d18802de24abc4c </div> </template> diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index 44e8aa2ccb9..c6ebf4e70dc 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,4 +1,5 @@ { + "Archive_Unarchive": "Archive / Unarchive", "Cancel": "Cancel", "Channel": "Channel", "Private_Group": "Private Group", -- GitLab From 1b73cd314c020fd591a853446d89eb62ded0274c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 22 Dec 2015 19:33:58 -0200 Subject: [PATCH 0993/1338] update aldeed:simple-schema to 1.5.2 and cosmos:browserify to 0.9.3 --- .meteor/versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 7fcf629285f..11a58480adc 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -7,7 +7,7 @@ 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.1 +aldeed:simple-schema@1.5.2 arunoda:streams@0.1.17 autoupdate@1.2.4 babel-compiler@5.8.24_1 @@ -25,7 +25,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 -- GitLab From 99403fed7028093fed8f54f49690f78d80ff7f36 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 22 Dec 2015 19:45:02 -0200 Subject: [PATCH 0994/1338] bump version to 0.10.2 --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- packages/rocketchat-lib/rocketchat.info | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index ec6a58efe8c..9e2a5f678ef 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -21,7 +21,7 @@ const pkgdef :Spk.PackageDefinition = ( appVersion = 6, # Increment this for every release. - appMarketingVersion = (defaultText = "0.10.1"), + appMarketingVersion = (defaultText = "0.10.2"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index 506e7cd2a4c..f8dc5a090df 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.10.1" + "version": "0.10.2" } -- GitLab From 280a9d8c9a38d98bfbf0b4d1446f91cfd5e0d939 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 22 Dec 2015 22:25:16 -0200 Subject: [PATCH 0995/1338] Execute outgoing triggers --- packages/rocketchat-integrations/package.js | 3 + .../server/triggers.coffee | 96 +++++++++++++++++++ .../server/functions/sendMessage.coffee | 2 +- 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-integrations/server/triggers.coffee diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index ff01a901293..beb7b8d849a 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -52,6 +52,9 @@ Package.onUse(function(api) { // api api.addFiles('server/api/api.coffee', 'server'); + + api.addFiles('server/triggers.coffee', 'server'); + var _ = Npm.require('underscore'); var fs = Npm.require('fs'); tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-integrations/i18n'), function(filename) { diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee new file mode 100644 index 00000000000..3d40bffe8e0 --- /dev/null +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -0,0 +1,96 @@ +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) -> + urlObj = URL.parse url + + console.log tries + 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 + # team_id=T0001 + # team_domain=example + 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) -> + console.log error, result + if not result? or result.statusCode isnt 200 + 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 + + # TODO process return and insert message if necessary + + + +ExecuteTrigger = (trigger, message, room) -> + for url in trigger.urls + ExecuteTriggerUrl url, trigger, message, room + + +ExecuteTriggers = (message, room) -> + if not room? + return + + triggersToExecute = [] + + if triggers[room._id]? + triggersToExecute.push trigger for key, trigger of triggers[room._id] + + if triggers[room.name]? + triggersToExecute.push trigger for key, trigger of triggers[room.name] + + if triggers.__any? + triggersToExecute.push trigger for key, trigger of triggers.__any + + for triggerToExecute in triggersToExecute + ExecuteTrigger triggerToExecute, message, room + + return message + + +RocketChat.callbacks.add 'afterSaveMessage', ExecuteTriggers, RocketChat.callbacks.priority.LOW diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index 20620d1c9dc..6b14009c97c 100644 --- a/packages/rocketchat-lib/server/functions/sendMessage.coffee +++ b/packages/rocketchat-lib/server/functions/sendMessage.coffee @@ -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 -- GitLab From 312347b9257573bd760ec06fe20fff954b737b2e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 23 Dec 2015 09:21:52 -0200 Subject: [PATCH 0996/1338] better message positioning --- .../rocketchat-theme/assets/stylesheets/base.less | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 33a92f34121..dcd4e3b6317 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2493,7 +2493,7 @@ a.github-fork { } .message { - padding: 11px 20px 11px 70px; + padding: 8px 20px 4px 70px; position: relative; line-height: 20px; min-height: 40px; @@ -2635,7 +2635,6 @@ a.github-fork { .thumb { position: absolute; left: 20px; - top: 11px; display: block; width: 40px; height: 40px; @@ -2671,6 +2670,7 @@ a.github-fork { min-height: 20px; padding-top: 4px; padding-bottom: 4px; + margin-top: 0px; .user { display: none; } @@ -2699,6 +2699,9 @@ a.github-fork { margin-left: 1px; } } + .body { + margin-top: 0px; + } // .message-dropdown { // top: 100%; @@ -2735,6 +2738,7 @@ a.github-fork { .body { opacity: 1; .transition(opacity 1s linear); + margin-top: 2px; .inline-image { background-size: contain; @@ -2765,9 +2769,9 @@ a.github-fork { .compact { .message { - padding: 5px 20px 5px 70px; - .thumb { - top: 5px; + padding: 4px 20px 4px 70px; + .body { + margin-top: 0px; } } } -- GitLab From 69a22342acedaa1233ccf2843fefbf0b8a26ada1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 11:13:06 -0200 Subject: [PATCH 0997/1338] Move set of integration type to server side --- .../client/views/integrationsIncoming.coffee | 1 - .../client/views/integrationsOutgoing.coffee | 2 -- .../server/methods/incoming/addIncomingIntegration.coffee | 1 + .../server/methods/outgoing/addOutgoingIntegration.coffee | 1 + 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee index b3aabfa5bc0..8e8f09dd0e1 100644 --- a/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsIncoming.coffee @@ -147,7 +147,6 @@ Template.integrationsIncoming.events toastr.success TAPi18n.__("Integration_updated") else - integration.type = 'webhook-incoming' integration.username = username Meteor.call "addIncomingIntegration", integration, (err, data) -> diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee index 5430d9c97d9..7a46f17ffb2 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee @@ -162,8 +162,6 @@ Template.integrationsOutgoing.events toastr.success TAPi18n.__("Integration_updated") else - integration.type = 'webhook-outgoing' - Meteor.call "addOutgoingIntegration", integration, (err, data) -> if err? return toastr.error TAPi18n.__(err.error) diff --git a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee index 316127e53ac..316c748ca19 100644 --- a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee @@ -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 diff --git a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee index be7e0372172..fe01c82b096 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -63,6 +63,7 @@ Meteor.methods 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}} -- GitLab From 3ca4af3e43c28e458438dddf97481ed5ce84e3f1 Mon Sep 17 00:00:00 2001 From: Christian Kniep <ckniep@gaikai.com> Date: Wed, 23 Dec 2015 14:13:36 +0100 Subject: [PATCH 0998/1338] adjust tgz filename --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 9980acc5751..361dbcb90f6 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 -- GitLab From 77122baa1b13243934664b90960b9ac3e019cb9e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 11:13:48 -0200 Subject: [PATCH 0999/1338] Add role bot to users of integrations in scope bot --- packages/rocketchat-authorization/server/startup.coffee | 2 +- packages/rocketchat-integrations/package.js | 1 + .../server/methods/incoming/addIncomingIntegration.coffee | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 663f7354970..81924e48b3a 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -103,7 +103,7 @@ Meteor.startup -> roles : ['admin']} { _id: 'manage-integrations', - roles : ['admin']} + roles : ['admin', 'bot']} ] #alanning:roles diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index beb7b8d849a..06aebfe354d 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -13,6 +13,7 @@ Package.onUse(function(api) { api.use('underscore'); api.use('simple:highlight.js'); api.use('rocketchat:lib@0.0.1'); + api.use('alanning:roles@1.2.12'); api.use('kadira:flow-router', 'client'); api.use('templating', 'client'); diff --git a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee index 316c748ca19..67c33d156f6 100644 --- a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee @@ -61,6 +61,8 @@ Meteor.methods RocketChat.models.Users.update {_id: user._id}, updateObj + Roles.addUsersToRoles user._id, 'bot', 'bot' + integration._id = RocketChat.models.Integrations.insert integration return integration -- GitLab From 0034c372be9114aa076b3b08f9d29b9a3f05d2f9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 11:14:06 -0200 Subject: [PATCH 1000/1338] Allow creation of outgoing integrations from bots --- .../server/methods/outgoing/addOutgoingIntegration.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee index fe01c82b096..c27c7c12441 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -1,6 +1,6 @@ Meteor.methods addOutgoingIntegration: (integration) -> - if not RocketChat.authz.hasPermission @userId, 'manage-integrations' + 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 '' -- GitLab From 4745f771cc612a4e1c97e7a3b7342b84c77dcaa5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 11:14:18 -0200 Subject: [PATCH 1001/1338] Fix update of permissions --- packages/rocketchat-authorization/server/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 81924e48b3a..7e347bdeffb 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -110,7 +110,7 @@ Meteor.startup -> roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); for permission in permissions - RocketChat.models.Permissions.upsert( permission._id, {$setOnInsert : permission }) + RocketChat.models.Permissions.upsert( permission._id, {$set: permission }) for role in permission.roles unless role in roles Roles.createRole role -- GitLab From 1790480840959b4ddc577e9d2acf501c60d7bbcf Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 11:14:36 -0200 Subject: [PATCH 1002/1338] Add route to cadastre new integrations via API --- .../server/api/api.coffee | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 068df884161..46cf791c1a7 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -100,3 +100,29 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, statusCode: 200 body: success: true + + +Api.addRoute 'manageintegrations/:integrationId/:userId/:token', authRequired: true, + post: -> + if @bodyParams?.payload? + @bodyParams = JSON.parse @bodyParams.payload + + integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) + user = RocketChat.models.Users.findOne(@userId) + + if not integration? + return {} = + statusCode: 400 + body: + success: false + error: 'Invalid integraiton id' + + switch @bodyParams.action + when 'addOutgoingIntegration' + Meteor.runAsUser user._id, => + Meteor.call 'addOutgoingIntegration', @bodyParams.data + + return {} = + statusCode: 200 + body: + success: true -- GitLab From 9dbde68d25e0fa0947f3ed521749752a67e4653f Mon Sep 17 00:00:00 2001 From: Christian Kniep <ckniep@gaikai.com> Date: Wed, 23 Dec 2015 14:15:32 +0100 Subject: [PATCH 1003/1338] adjust tgz filename in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d43c1d2cd2c..cbb9a7bfe12 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/develop.rocket.chat-v.latest.tgz" -o rocket.chat.tgz \ +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 \ -- GitLab From 8929012001aed057bf3cdf1c36a9c294e1e4fcfa Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 23 Dec 2015 12:33:08 -0200 Subject: [PATCH 1004/1338] enable/disable livechat pre registration form pick a department at livechat pre registration --- .../rocketchat-livechat/app/.meteor/packages | 2 + .../rocketchat-livechat/app/.meteor/versions | 1 + .../app/client/lib/collections.coffee | 1 + .../app/client/routes/router.coffee | 2 +- .../app/client/stylesheets/main.less | 23 ++++--- .../views/{room.html => livechatWindow.html} | 8 +-- .../views/{room.js => livechatWindow.js} | 40 +++++++------ .../app/client/views/register.coffee | 50 ---------------- .../app/client/views/register.html | 11 +++- .../app/client/views/register.js | 60 +++++++++++++++++++ .../rocketchat-livechat/app/i18n/en.i18n.json | 3 +- packages/rocketchat-livechat/config.js | 1 + .../rocketchat-livechat/i18n/en.i18n.json | 1 + packages/rocketchat-livechat/package.js | 1 + .../server/lib/getNextAgent.js | 2 +- .../server/methods/registerGuest.js | 5 +- .../server/methods/sendMessageLivechat.js | 5 +- .../server/models/LivechatDepartment.js | 8 +++ .../publications/availableDepartments.js | 3 + 19 files changed, 134 insertions(+), 93 deletions(-) rename packages/rocketchat-livechat/app/client/views/{room.html => livechatWindow.html} (89%) rename packages/rocketchat-livechat/app/client/views/{room.js => livechatWindow.js} (56%) delete mode 100644 packages/rocketchat-livechat/app/client/views/register.coffee create mode 100644 packages/rocketchat-livechat/app/client/views/register.js create mode 100644 packages/rocketchat-livechat/server/publications/availableDepartments.js diff --git a/packages/rocketchat-livechat/app/.meteor/packages b/packages/rocketchat-livechat/app/.meteor/packages index 2f093f91006..83352a667a8 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 34a2055ee61..3105a3bc809 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/collections.coffee b/packages/rocketchat-livechat/app/client/lib/collections.coffee index 788b96e4440..c86ad59f9dd 100644 --- a/packages/rocketchat-livechat/app/client/lib/collections.coffee +++ b/packages/rocketchat-livechat/app/client/lib/collections.coffee @@ -2,3 +2,4 @@ @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/routes/router.coffee b/packages/rocketchat-livechat/app/client/routes/router.coffee index 1105938efd9..6b171284921 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/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 94064d9f020..f355eca4e45 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; @@ -367,9 +370,7 @@ input:focus { 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; } } } @@ -399,11 +399,10 @@ input:focus { border-right: 1px solid #E7E7E7; padding: 5px; - input, button { + input, button, select { display: block; - padding: 5px; - margin: 5px; } + .error { display: none; // width: 100%; diff --git a/packages/rocketchat-livechat/app/client/views/room.html b/packages/rocketchat-livechat/app/client/views/livechatWindow.html similarity index 89% rename from packages/rocketchat-livechat/app/client/views/room.html rename to packages/rocketchat-livechat/app/client/views/livechatWindow.html index 6cb419c8c79..91618ab5226 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}}"> @@ -12,10 +12,10 @@ </div> {{#if livechatEnabled}} - {{#if showMessages}} - {{> messages}} - {{else}} + {{#if showRegisterForm}} {{> register}} + {{else}} + {{> messages}} {{/if}} {{else}} <div class="offline">{{_ "We_are_offline_Sorry_for_the_inconvenience"}}</div> 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 7029cc3f16d..c566d31ddd5 100644 --- a/packages/rocketchat-livechat/app/client/views/room.js +++ b/packages/rocketchat-livechat/app/client/views/livechatWindow.js @@ -1,60 +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'; }, - showMessages: function() { - return Session.get('triggered') || Meteor.userId(); + showRegisterForm() { + if (Session.get('triggered') || Meteor.userId()) { + return false; + } + var form = Settings.findOne('Livechat_registration_form'); + return form.value; }, - livechatStartedEnabled: function() { + 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/register.coffee b/packages/rocketchat-livechat/app/client/views/register.coffee deleted file mode 100644 index 72246a88cee..00000000000 --- 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.loginWithToken result.token, (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 39ef026bf5e..7dd5afb76a2 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 00000000000..5816d9d6320 --- /dev/null +++ b/packages/rocketchat-livechat/app/client/views/register.js @@ -0,0 +1,60 @@ +Template.register.helpers({ + error() { + return Template.instance().error.get(); + }, + welcomeMessage() { + return ""; + }, + hasDepartments() { + return Department.find().count() > 0; + }, + 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 guest = { + token: visitor.getToken(), + name: $name.val(), + email: $email.val(), + department: instance.$('select[name=department]').val() + }; + 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/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index 758f3f7bc14..e09be84fb29 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -8,10 +8,11 @@ "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", + "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", "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/config.js b/packages/rocketchat-livechat/config.js index 9ae62a8ecb1..fe222ec585f 100644 --- a/packages/rocketchat-livechat/config.js +++ b/packages/rocketchat-livechat/config.js @@ -3,4 +3,5 @@ Meteor.startup(function() { 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_registration_form' , true, { type: 'boolean', group: 'Livechat', public: true, i18nLabel: 'Show_preregistration_form' }); }); diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 754decc3449..871077a863b 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -41,6 +41,7 @@ "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", diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index f6b14d25635..f9bff5eec15 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -93,6 +93,7 @@ Package.onUse(function(api) { 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'); diff --git a/packages/rocketchat-livechat/server/lib/getNextAgent.js b/packages/rocketchat-livechat/server/lib/getNextAgent.js index 3259ab642d9..63a484b49b9 100644 --- a/packages/rocketchat-livechat/server/lib/getNextAgent.js +++ b/packages/rocketchat-livechat/server/lib/getNextAgent.js @@ -2,7 +2,7 @@ this.getNextAgent = function(department) { var agentFilter = {}; if (department) { - return RocketChat.models.LivechatDepartment.getNextAgent(department); + return RocketChat.models.LivechatDepartmentAgents.getNextAgentForDepartment(department); } else { return RocketChat.models.Users.getNextAgent(); } diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js index c79b9c68761..d6ec15da83c 100644 --- a/packages/rocketchat-livechat/server/methods/registerGuest.js +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -1,5 +1,5 @@ Meteor.methods({ - registerGuest: function(token, name, email) { + 'livechat:registerGuest': function({ token, name, email, department }) { var pass, qt, user, userData, userExists, userId, inc = 0; check(token, String); @@ -35,7 +35,8 @@ Meteor.methods({ } userData = { username: user, - globalRoles: 'livechat-guest' + globalRoles: 'livechat-guest', + department: department }; userId = Accounts.insertUserDoc({}, userData); diff --git a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js index 90125c25dee..1d55428cc70 100644 --- a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js +++ b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js @@ -7,13 +7,14 @@ Meteor.methods({ guest = Meteor.users.findOne(Meteor.userId(), { fields: { - username: 1 + username: 1, + department: 1 } }); room = RocketChat.models.Rooms.findOneById(message.rid); if (room == null) { - agent = getNextAgent(); + agent = getNextAgent(guest.department); if (!agent) { throw new Meteor.Error('no-agent-online', 'Sorry, no online agents'); } diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index d474415ea96..5cbd7f35bbd 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -63,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/publications/availableDepartments.js b/packages/rocketchat-livechat/server/publications/availableDepartments.js new file mode 100644 index 00000000000..6ab277d73ce --- /dev/null +++ b/packages/rocketchat-livechat/server/publications/availableDepartments.js @@ -0,0 +1,3 @@ +Meteor.publish('livechat:availableDepartments', function() { + return RocketChat.models.LivechatDepartment.findEnabledWithAgents(); +}); -- GitLab From e94577d72d8c419926df3078cca8459b2fc7ee1e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 12:33:46 -0200 Subject: [PATCH 1005/1338] Remove unused code --- packages/rocketchat-integrations/server/triggers.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 3d40bffe8e0..bb1dd825ab6 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -17,8 +17,6 @@ RocketChat.models.Integrations.find({type: 'webhook-outgoing'}).observe ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> - urlObj = URL.parse url - console.log tries word = undefined if trigger.triggerWords?.length > 0 -- GitLab From 261ff288c5a853ad08753746abbd66ddb50930c4 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 12:35:31 -0200 Subject: [PATCH 1006/1338] Change /invite to use addUserToRoom instead joinRoom --- packages/rocketchat-slashcommands-invite/server.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-slashcommands-invite/server.coffee b/packages/rocketchat-slashcommands-invite/server.coffee index 36ae07981e5..4b619023139 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 -- GitLab From 4c21d9331cc4a67df1bb10503819dc02daa7a57b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 12:36:50 -0200 Subject: [PATCH 1007/1338] Closes #1703; Create direct rooms correctly in incoming hook --- packages/rocketchat-integrations/server/api/api.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 46cf791c1a7..415754a6cb5 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -60,7 +60,7 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, if not room Meteor.runAsUser user._id, -> - Meteor.call 'createDirectMessage', roomUser._id + Meteor.call 'createDirectMessage', roomUser.username room = RocketChat.models.Rooms.findOne(rid) else -- GitLab From 87982b58e7fa1ce4d94e37b60ec43eea6bd9b36e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 12:40:12 -0200 Subject: [PATCH 1008/1338] Closes #1704; Only join user in public channels via integrations --- packages/rocketchat-integrations/server/api/api.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 415754a6cb5..c8043272fcc 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -38,8 +38,9 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, error: 'invalid-channel' rid = room._id - Meteor.runAsUser user._id, -> - Meteor.call 'joinRoom', room._id + if room.t is 'c' + Meteor.runAsUser user._id, -> + Meteor.call 'joinRoom', room._id when '@' roomUser = RocketChat.models.Users.findOne -- GitLab From bfa7d3fec05c7032c229d636969b8fe12ae87049 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 12:47:54 -0200 Subject: [PATCH 1009/1338] Closes #1705; Fix ungroup of messages after join message --- packages/rocketchat-ui-message/message/message.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 3e1b3aef099..bf417c06df4 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -128,7 +128,7 @@ Template.message.onViewRendered = (context) -> else $currentNode.removeClass('new-day') - if previousDataset.groupable is 'false' + 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 -- GitLab From 009c8eabb9ba75e2cdd0db927da3270230a62a10 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 13:14:35 -0200 Subject: [PATCH 1010/1338] Fix triggers with defined channels --- packages/rocketchat-integrations/server/triggers.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index bb1dd825ab6..9a610cbfc67 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -76,11 +76,11 @@ ExecuteTriggers = (message, room) -> triggersToExecute = [] - if triggers[room._id]? - triggersToExecute.push trigger for key, trigger of triggers[room._id] + if triggers['#'+room._id]? + triggersToExecute.push trigger for key, trigger of triggers['#'+room._id] - if triggers[room.name]? - triggersToExecute.push trigger for key, trigger of triggers[room.name] + if triggers['#'+room.name]? + triggersToExecute.push trigger for key, trigger of triggers['#'+room.name] if triggers.__any? triggersToExecute.push trigger for key, trigger of triggers.__any -- GitLab From 859c52a884320e6973a99a71f7fb9c2dc8bfe09a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 23 Dec 2015 13:23:59 -0200 Subject: [PATCH 1011/1338] always use a department if there is only one active --- .../app/client/lib/chatMessages.coffee | 2 +- .../rocketchat-livechat/app/client/views/register.js | 12 ++++++++++-- .../server/methods/registerGuest.js | 2 +- .../server/methods/sendMessageLivechat.js | 9 +++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee index d7c529a1c1a..842976af361 100644 --- a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee +++ b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee @@ -93,7 +93,7 @@ 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 diff --git a/packages/rocketchat-livechat/app/client/views/register.js b/packages/rocketchat-livechat/app/client/views/register.js index 5816d9d6320..df91839e23a 100644 --- a/packages/rocketchat-livechat/app/client/views/register.js +++ b/packages/rocketchat-livechat/app/client/views/register.js @@ -6,7 +6,7 @@ Template.register.helpers({ return ""; }, hasDepartments() { - return Department.find().count() > 0; + return Department.find().count() > 1; }, departments() { return Department.find(); @@ -22,11 +22,19 @@ Template.register.events({ 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: instance.$('select[name=department]').val() + department: departmentId }; Meteor.call('livechat:registerGuest', guest, function(error, result) { if (error != null) { diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js index d6ec15da83c..8131aa6aa8e 100644 --- a/packages/rocketchat-livechat/server/methods/registerGuest.js +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -1,5 +1,5 @@ Meteor.methods({ - 'livechat:registerGuest': function({ token, name, email, department }) { + 'livechat:registerGuest': function({ token, name, email, department } = {}) { var pass, qt, user, userData, userExists, userId, inc = 0; check(token, String); diff --git a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js index 1d55428cc70..183b404fe0e 100644 --- a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js +++ b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js @@ -14,6 +14,15 @@ Meteor.methods({ 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'); -- GitLab From 6a27d7bbca771508943127b3eaf0408955d126bc Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 23 Dec 2015 16:01:47 -0200 Subject: [PATCH 1012/1338] fix livechat agent subscription creation --- .../rocketchat-livechat/server/methods/sendMessageLivechat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js index 90125c25dee..eb1cf011412 100644 --- a/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js +++ b/packages/rocketchat-livechat/server/methods/sendMessageLivechat.js @@ -37,7 +37,7 @@ Meteor.methods({ unread: 1, answered: false, u: { - _id: agent._id, + _id: agent.agentId, username: agent.username }, t: 'l' -- GitLab From 64329e55bedcb5e0761927fa2853323e6a747f3c Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 23 Dec 2015 17:45:12 -0200 Subject: [PATCH 1013/1338] fix error on roomExit callback --- .../client/lib/startup.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee index 9cf0b622074..c55e6956b7b 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee @@ -6,6 +6,8 @@ Meteor.startup -> return RocketChat.authz.hasAllPermission('mail-messages') RocketChat.callbacks.add 'roomExit', (mainNode) -> - instance = Blaze.getView($('.messages-box')?[0])?.templateInstance() - instance?.resetSelection(false) + 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' -- GitLab From 1be53e0db57bda9f82a3b5a20fb9ab58289dd728 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 23 Dec 2015 17:46:43 -0200 Subject: [PATCH 1014/1338] removed livechat duplicated route definition --- packages/rocketchat-livechat/client/route.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/rocketchat-livechat/client/route.js b/packages/rocketchat-livechat/client/route.js index c8b6f69fac0..c5b0eb72ae7 100644 --- a/packages/rocketchat-livechat/client/route.js +++ b/packages/rocketchat-livechat/client/route.js @@ -1,15 +1,3 @@ -FlowRouter.route('/live/:name', { - name: 'live', - - action: function(params, queryParams) { - console.log('action route livechat'); - Session.set('showUserInfo'); - openRoom('l', params.name); - }, - - triggersExit: [roomExit] -}); - livechatManagerRoutes = FlowRouter.group({ prefix: '/livechat-manager', name: 'livechat-manager' -- GitLab From 8546e741ba97a727491d3413f850717493f88a14 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 23 Dec 2015 18:04:44 -0200 Subject: [PATCH 1015/1338] Select users to send messages to --- .../views/mailMessagesInstructions.coffee | 54 +++++++++++++++++-- .../views/mailMessagesInstructions.html | 15 +++++- .../i18n/en.i18n.json | 7 +-- .../server/methods/mailMessages.coffee | 17 ++++-- .../rocketchat-lib/server/models/Users.coffee | 18 +++++++ server/publications/userAutocomplete.coffee | 28 ++++++++++ 6 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 server/publications/userAutocomplete.coffee diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee index ed30d543765..d78a9c41f42 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee @@ -7,6 +7,29 @@ Template.mailMessagesInstructions.helpers 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) -> @@ -25,9 +48,9 @@ Template.mailMessagesInstructions.events t.$('.error-select').show() error = true - if t.$('input[name=to]').val().trim() + 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]').val().trim().split(',') + emails = t.$('input[name=to_emails]').val().trim().split(',') erroredEmails = [] for email in emails unless rfcMailPatternWithName.test email.trim() @@ -37,7 +60,7 @@ Template.mailMessagesInstructions.events if erroredEmails.length > 0 t.$('.error-invalid-emails').show() error = true - else + else if not t.selectedUsers.get().length t.$('.error-missing-to').show() error = true @@ -46,7 +69,8 @@ Template.mailMessagesInstructions.events else data = rid: Session.get('openedRoom') - to: t.$('input[name=to]').val().trim() + 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') @@ -56,6 +80,7 @@ Template.mailMessagesInstructions.events 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() @@ -66,10 +91,29 @@ Template.mailMessagesInstructions.events 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 = -> + @reset = => + @selectedUsers.set [] RocketChat.TabBar.setTemplate('channelSettings') view = Blaze.getView($('.messages-box')[0]) view?.templateInstance?().resetSelection?(false) diff --git a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html index c8c27429f6d..c2a8dd37da0 100644 --- a/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html +++ b/packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html @@ -13,9 +13,20 @@ <div>{{email}}</div> </div> <div class="input-line double-col"> - <label>{{_ "To"}}</label> + <label>{{_ "To_users"}}</label> <div> - <input type="text" name="to" value="" /> + {{> 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"> diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json index 32ec45e9cdb..832d3732cc1 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json @@ -1,17 +1,18 @@ { + "Additional_emails" : "Additional E-mails", "Body" : "Body", "Cancel" : "Cancel", "Choose_messages" : "Choose messages", "From" : "From", - "Mail_Message_Missing_to" : "You must provide one or more To e-mail addresses, separated by commas.", + "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", - "Mail_Message_Invalid_emails" : "You have provided one or more invalid e-mails: %s", "Send" : "Send", "Sending" : "Sending...", "Subject" : "Subject", - "To" : "To", + "To_users" : "To Users", "Your_email_has_been_queued_for_sending" : "Your email has been queued for sending" } diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee index 499543047cd..fe4591ddf38 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -3,7 +3,7 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] mailMessages -> Invalid user") - check(data, Match.ObjectIncluding({ rid: String, to: String, subject: String, messages: [ String ], language: String })) + 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 @@ -13,7 +13,17 @@ Meteor.methods 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 = data.to.trim().split(',') + emails = 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 + for email in emails unless rfcMailPatternWithName.test email.trim() throw new Meteor.Error('invalid-email', "[methods] mailMessages -> Invalid e-mail") @@ -42,5 +52,4 @@ Meteor.methods console.log 'Sending email to ' + emails.join(', ') - - return true + return { success: true, missing: missing } diff --git a/packages/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index bf8981793a7..9e9aaf502b3 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -71,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/server/publications/userAutocomplete.coffee b/server/publications/userAutocomplete.coffee new file mode 100644 index 00000000000..5af38c1f8dc --- /dev/null +++ b/server/publications/userAutocomplete.coffee @@ -0,0 +1,28 @@ +Meteor.publish 'userAutocomplete', (selector) -> + unless this.userId + return this.ready() + + pub = this + + options = + fields: + name: 1 + username: 1 + status: 1 + limit: 10 + + user = RocketChat.models.Users.findOneById this.userId + exceptions = selector.exceptions or [] + exceptions.push user.username + + 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 -- GitLab From d073e6e877928cb990425005750b510a84951b35 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 23 Dec 2015 18:11:04 -0200 Subject: [PATCH 1016/1338] no message --- .../server/methods/mailMessages.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee index fe4591ddf38..446df06f288 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -13,8 +13,8 @@ Meteor.methods 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 = data.to_emails.trim().split(',') + emails = _.compact(data.to_emails.trim().split(',')) missing = [] if data.to_users.length > 0 for username in data.to_users @@ -23,10 +23,10 @@ Meteor.methods 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") + throw new Meteor.Error('invalid-email', "[methods] mailMessages -> Invalid e-mail #{email}") user = Meteor.user() name = user.name -- GitLab From adb661aa7ca4295f7ebb7ac252ddf0a0d52e3f5a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 19:41:02 -0200 Subject: [PATCH 1017/1338] Remove integration if trigger response is 410 --- packages/rocketchat-integrations/server/triggers.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 9a610cbfc67..2717b1cdf44 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -54,6 +54,10 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> HTTP.call 'POST', url, opts, (error, result) -> console.log 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 -> -- GitLab From 6f149a6adef22e5d46997edf2d3e916101532088 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 19:41:35 -0200 Subject: [PATCH 1018/1338] If no channel in trigger listen all public channels --- packages/rocketchat-integrations/server/triggers.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 2717b1cdf44..62db7da5556 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -31,8 +31,6 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> data = token: trigger.token - # team_id=T0001 - # team_domain=example channel_id: room._id channel_name: room.name timestamp: message.ts @@ -86,7 +84,7 @@ ExecuteTriggers = (message, room) -> if triggers['#'+room.name]? triggersToExecute.push trigger for key, trigger of triggers['#'+room.name] - if triggers.__any? + if triggers.__any? and room.t is 'c' triggersToExecute.push trigger for key, trigger of triggers.__any for triggerToExecute in triggersToExecute -- GitLab From d77e07516b77084c863d92d5244327e1fbec2edc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 19:42:38 -0200 Subject: [PATCH 1019/1338] Turn channel and triggerWords optional in triggers --- .../client/views/integrationsOutgoing.coffee | 5 +---- .../client/views/integrationsOutgoing.html | 9 ++++----- .../methods/outgoing/addOutgoingIntegration.coffee | 14 +++++--------- .../outgoing/updateOutgoingIntegration.coffee | 3 --- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee index 7a46f17ffb2..2fdde670919 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee @@ -130,9 +130,6 @@ Template.integrationsOutgoing.events triggerWords = _.without triggerWords, [undefined] - if triggerWords.length is 0 and channel.trim() is '' - return toastr.error TAPi18n.__("You should inform at least one trigger word if you do not inform a channel") - urls = urls.split('\n') for url, index in urls urls[index] = url.trim() @@ -144,8 +141,8 @@ Template.integrationsOutgoing.events return toastr.error TAPi18n.__("You_should_inform_one_url_at_least") integration = - channel: channel username: username + channel: channel if channel isnt '' alias: alias if alias isnt '' emoji: emoji if emoji isnt '' avatar: avatar if avatar isnt '' diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html index 1b009cd93c0..afadc8b7bbe 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html @@ -13,20 +13,19 @@ </div> </div> <div class="input-line double-col"> - <label>{{_ "Channel"}}</label> + <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</strong> channel"}}}</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"}}</label> + <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">{{_ "Optional if a channel is chosen"}}</div> <div class="settings-description">{{_ "Separate multiple words with commas"}}</div> </div> </div> @@ -69,7 +68,7 @@ </div> </div> <div class="input-line double-col"> - <label>Token</label> + <label>Token ({{_ "optional"}})</label> <div> <input type="text" name="token" value="{{data.token}}" /> </div> diff --git a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee index c27c7c12441..6aab25ee634 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -1,5 +1,8 @@ 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' @@ -17,12 +20,9 @@ Meteor.methods if integration.urls.length is 0 throw new Meteor.Error 'invalid_urls', '[methods] addOutgoingIntegration -> urls is required' - if integration.channel?.trim() isnt '' and integration.channel[0] not in ['@', '#'] + if integration.channel? and integration.channel[0] not in ['@', '#'] throw new Meteor.Error 'invalid_channel', '[methods] addOutgoingIntegration -> channel should start with # or @' - if not integration.token? or integration.token?.trim() is '' - throw new Meteor.Error 'invalid_token', '[methods] addOutgoingIntegration -> token is required' - if integration.triggerWords? if not Match.test integration.triggerWords, [String] throw new Meteor.Error 'invalid_triggerWords', '[methods] addOutgoingIntegration -> triggerWords must be an array' @@ -32,11 +32,7 @@ Meteor.methods integration.triggerWords = _.without integration.triggerWords, [undefined] - if integration.triggerWords.length is 0 and not integration.channel? - throw new Meteor.Error 'invalid_triggerWords', '[methods] addOutgoingIntegration -> triggerWords is required if channel is empty' - - - if integration.channel?.trim() isnt '' + if integration.channel? record = undefined channelType = integration.channel[0] channel = integration.channel.substr(1) diff --git a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee index d91c552aed1..26610e89785 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee @@ -32,9 +32,6 @@ Meteor.methods integration.triggerWords = _.without integration.triggerWords, [undefined] - if integration.triggerWords.length is 0 and not integration.channel? - throw new Meteor.Error 'invalid_triggerWords', '[methods] updateOutgoingIntegration -> triggerWords is required if channel is empty' - if not RocketChat.models.Integrations.findOne(integrationId)? throw new Meteor.Error 'invalid_integration', '[methods] updateOutgoingIntegration -> integration not found' -- GitLab From 0453ff9e9b84aa0f3684d26d8a8313c64e92b3df Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 19:43:17 -0200 Subject: [PATCH 1020/1338] Allow bot call deleteOutgoingIntegration --- .../server/methods/outgoing/deleteOutgoingIntegration.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee index b13af8bdd51..1808b05c210 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/deleteOutgoingIntegration.coffee @@ -1,6 +1,6 @@ Meteor.methods deleteOutgoingIntegration: (integrationId) -> - if not RocketChat.authz.hasPermission @userId, 'manage-integrations' + 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) -- GitLab From f381e995f61a91b7446c72ddd24f2917ea0eee43 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 23 Dec 2015 19:44:01 -0200 Subject: [PATCH 1021/1338] Rename integration api routes, add apis remove, info and sample --- .../server/api/api.coffee | 89 +++++++++++++++++-- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index c8043272fcc..308ef4465c6 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -103,8 +103,59 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, success: true -Api.addRoute 'manageintegrations/:integrationId/:userId/:token', authRequired: true, +Api.addRoute 'add/:integrationId/:userId/:token', authRequired: true, post: -> + console.log 'Add integration' + console.log @bodyParams + + if @bodyParams?.payload? + @bodyParams = JSON.parse @bodyParams.payload + + integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) + user = RocketChat.models.Users.findOne(@userId) + + if not integration? + return {} = + statusCode: 400 + body: + success: false + error: 'Invalid integraiton id' + + Meteor.runAsUser user._id, => + switch @bodyParams['event'] + when 'newMessageOnChannel' + if @bodyParams.data.channel_name? and @bodyParams.data.channel_name.indexOf('#') is -1 + @bodyParams.data.channel_name = '#' + @bodyParams.data.channel_name + + Meteor.call 'addOutgoingIntegration', + username: 'rocket.cat' + urls: [@bodyParams.target_url] + name: @bodyParams.data.name + channel: @bodyParams.data.channel_name + triggerWords: @bodyParams.data.trigger_words + + when 'newMessageToUser' + if @bodyParams.data.username.indexOf('@') is -1 + @bodyParams.data.username = '@' + @bodyParams.data.username + + Meteor.call 'addOutgoingIntegration', + username: 'rocket.cat' + urls: [@bodyParams.target_url] + name: @bodyParams.data.name + channel: @bodyParams.data.username + triggerWords: @bodyParams.data.trigger_words + + return {} = + statusCode: 200 + body: + success: true + + +Api.addRoute 'remove/:integrationId/:userId/:token', authRequired: true, + post: -> + console.log 'Remove integration' + console.log @bodyParams + if @bodyParams?.payload? @bodyParams = JSON.parse @bodyParams.payload @@ -118,12 +169,40 @@ Api.addRoute 'manageintegrations/:integrationId/:userId/:token', authRequired: t success: false error: 'Invalid integraiton id' - switch @bodyParams.action - when 'addOutgoingIntegration' - Meteor.runAsUser user._id, => - Meteor.call 'addOutgoingIntegration', @bodyParams.data + + integrationToRemove = RocketChat.models.Integrations.findOne urls: @bodyParams.target_url + Meteor.runAsUser user._id, => + Meteor.call 'deleteOutgoingIntegration', integrationToRemove._id return {} = statusCode: 200 body: success: true + + +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' + trigger_word: 'Sample' + + +Api.addRoute 'info/:integrationId/:userId/:token', authRequired: true, + get: -> + console.log 'Info integration' + + return {} = + statusCode: 200 + body: + success: true + -- GitLab From ab707ed959efb16b73d7c29fc1864b8c8699613f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 24 Dec 2015 10:27:47 -0200 Subject: [PATCH 1022/1338] Enable triggers in messages to users --- .../server/triggers.coffee | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 62db7da5556..6c815d45758 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -17,7 +17,6 @@ RocketChat.models.Integrations.find({type: 'webhook-outgoing'}).observe ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> - console.log tries word = undefined if trigger.triggerWords?.length > 0 for triggerWord in trigger.triggerWords @@ -50,7 +49,6 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> '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) -> - console.log error, result if not result? or result.statusCode isnt 200 if result.statusCode is 410 RocketChat.models.Integrations.remove _id: trigger._id @@ -78,14 +76,30 @@ ExecuteTriggers = (message, room) -> triggersToExecute = [] - if triggers['#'+room._id]? - triggersToExecute.push trigger for key, trigger of triggers['#'+room._id] + switch room.t + when 'd' + id = room._id.replace(message.u._id, '') - if triggers['#'+room.name]? - triggersToExecute.push trigger for key, trigger of triggers['#'+room.name] + 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] - if triggers.__any? and room.t is 'c' - triggersToExecute.push trigger for key, trigger of triggers.__any for triggerToExecute in triggersToExecute ExecuteTrigger triggerToExecute, message, room -- GitLab From 5a80a0f501f1a8a818372e4eae15b681fb21fc92 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 24 Dec 2015 11:18:27 -0200 Subject: [PATCH 1023/1338] Added "Jump to" and infinite scroll to message search results --- i18n/en.i18n.json | 1 + .../client/views/pinnedMessages.coffee | 3 - .../client/views/stylesheets/messagepin.less | 11 --- .../client/views/starredMessages.coffee | 3 - .../client/views/stylesheets/messagestar.less | 11 --- .../assets/stylesheets/base.less | 36 +++++++++ .../flex-tab/tabs/messageSearch.coffee | 79 ++++++++++++++++--- .../flex-tab/tabs/messageSearch.html | 41 +++++++--- .../message/message.coffee | 4 +- server/methods/messageSearch.coffee | 11 ++- 10 files changed, 146 insertions(+), 54 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index bfe22fc2fd4..e70ed2ba3b4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -318,6 +318,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", diff --git a/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee index 85720f1dd35..ba6df0cada8 100644 --- a/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee +++ b/packages/rocketchat-message-pin/client/views/pinnedMessages.coffee @@ -5,9 +5,6 @@ Template.pinnedMessages.helpers messages: -> return PinnedMessage.find { rid: @rid }, { sort: { ts: -1 } } - notReadySubscription: -> - return 'notready' unless Template.instance().subscriptionsReady() - hasMore: -> return Template.instance().hasMore.get() diff --git a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less index bab90b5664a..94248d67b99 100644 --- a/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less +++ b/packages/rocketchat-message-pin/client/views/stylesheets/messagepin.less @@ -15,17 +15,6 @@ } .pinned-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; diff --git a/packages/rocketchat-message-star/client/views/starredMessages.coffee b/packages/rocketchat-message-star/client/views/starredMessages.coffee index 6565b5f8222..f51eb088a15 100644 --- a/packages/rocketchat-message-star/client/views/starredMessages.coffee +++ b/packages/rocketchat-message-star/client/views/starredMessages.coffee @@ -5,9 +5,6 @@ Template.starredMessages.helpers messages: -> return StarredMessage.find { rid: @rid }, { sort: { ts: -1 } } - notReadySubscription: -> - return 'notready' unless Template.instance().subscriptionsReady() - hasMore: -> return Template.instance().hasMore.get() diff --git a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less index 718f1528d4d..83e74cbb29b 100644 --- a/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less +++ b/packages/rocketchat-message-star/client/views/stylesheets/messagestar.less @@ -9,17 +9,6 @@ } .starred-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; diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 471f876ec52..4cb875a9bbe 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4271,3 +4271,39 @@ 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; + } +} + +.messages-box { + .message-cog-container { + .message-action { + &.jump-to-search-message { + display: none !important; + } + } + } +} diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee index 59d128eec8e..633e4e2e846 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,57 @@ 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 = Blaze.getData($("\.search-messages-list ##{message_id}")?[0])?._arguments?[1] + if message + 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 25931d64987..3b31486a97a 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-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index bf417c06df4..7d9bcffbe28 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -133,7 +133,7 @@ Template.message.onViewRendered = (context) -> else if previousDataset.username isnt currentDataset.username or parseInt(currentDataset.timestamp) - parseInt(previousDataset.timestamp) > RocketChat.settings.get('Message_GroupingPeriod') * 1000 $currentNode.removeClass('sequential') - else + else if not $currentNode.hasClass 'new-day' $currentNode.addClass('sequential') if nextNode?.dataset? @@ -147,7 +147,7 @@ Template.message.onViewRendered = (context) -> 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 + else if not $nextNode.hasClass 'new-day' $nextNode.addClass('sequential') if not nextNode? diff --git a/server/methods/messageSearch.coffee b/server/methods/messageSearch.coffee index acd9da18c67..4c5d99a6151 100644 --- a/server/methods/messageSearch.coffee +++ b/server/methods/messageSearch.coffee @@ -1,5 +1,5 @@ Meteor.methods - messageSearch: (text, rid) -> + messageSearch: (text, rid, limit) -> ### text = 'from:rodrigo mention:gabriel chat' ### @@ -13,7 +13,7 @@ Meteor.methods options = sort: ts: -1 - limit: 20 + limit: limit or 20 # Query for senders from = [] @@ -54,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 # ### -- GitLab From 7d503b4f931045f25652a097caddd23c0705aaa0 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 24 Dec 2015 11:54:20 -0200 Subject: [PATCH 1024/1338] Allow searching for logged in user in userAutocomplete --- server/publications/userAutocomplete.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/publications/userAutocomplete.coffee b/server/publications/userAutocomplete.coffee index 5af38c1f8dc..0f20eb20524 100644 --- a/server/publications/userAutocomplete.coffee +++ b/server/publications/userAutocomplete.coffee @@ -11,9 +11,7 @@ Meteor.publish 'userAutocomplete', (selector) -> status: 1 limit: 10 - user = RocketChat.models.Users.findOneById this.userId exceptions = selector.exceptions or [] - exceptions.push user.username cursorHandle = RocketChat.models.Users.findActiveByUsernameRegexWithExceptions(selector.username, exceptions, options).observeChanges added: (_id, record) -> -- GitLab From f189c95a76033918be7ab66b52491c0b9c96939c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 24 Dec 2015 11:47:57 -0200 Subject: [PATCH 1025/1338] Added infinite scroll to files list --- .../assets/stylesheets/base.less | 13 +++++ .../flex-tab/tabs/uploadedFilesList.coffee | 50 +++++++++++------ .../flex-tab/tabs/uploadedFilesList.html | 56 ++++++++++--------- server/publications/roomFiles.coffee | 53 +++++++++--------- 4 files changed, 104 insertions(+), 68 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 4cb875a9bbe..a13cb98307b 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4298,6 +4298,19 @@ a.github-fork { } } +.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 { diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index d46b484db5d..2d22e33107e 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 }).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 f50af8c5ad9..2ac19362308 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/server/publications/roomFiles.coffee b/server/publications/roomFiles.coffee index bdfdeaf7102..e905e740d22 100644 --- a/server/publications/roomFiles.coffee +++ b/server/publications/roomFiles.coffee @@ -1,32 +1,35 @@ -Meteor.publish 'roomFiles', (rid) -> - unless this.userId - return this.ready() +Meteor.publish 'roomFiles', (rid, limit = 50) -> + unless this.userId + return this.ready() - pub = this + pub = this - fileQuery = - rid: rid - complete: true - uploading: false + fileQuery = + rid: rid + complete: true + uploading: false - fileOptions = - fields: - _id: 1 - rid: 1 - name: 1 - type: 1 - url: 1 + 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) + cursorFileListHandle = fileCollection.find(fileQuery, fileOptions).observeChanges + added: (_id, record) -> + pub.added('room_files', _id, record) - changed: (_id, record) -> - pub.changed('room_files', _id, record) + changed: (_id, record) -> + pub.changed('room_files', _id, record) - removed: (_id, record) -> - pub.removed('room_files', _id, record) + removed: (_id, record) -> + pub.removed('room_files', _id, record) - this.ready() - this.onStop -> - cursorFileListHandle.stop() + this.ready() + this.onStop -> + cursorFileListHandle.stop() -- GitLab From 0ed8a58d48ed961a18f5e73372175098db2b3471 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 24 Dec 2015 12:11:32 -0200 Subject: [PATCH 1026/1338] added livechat branding --- .../app/client/stylesheets/_variables.less | 2 +- .../app/client/stylesheets/main.less | 27 ++++++- .../app/client/views/messages.html | 6 ++ .../app/public/logo-dark.svg | 77 +++++++++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-livechat/app/public/logo-dark.svg diff --git a/packages/rocketchat-livechat/app/client/stylesheets/_variables.less b/packages/rocketchat-livechat/app/client/stylesheets/_variables.less index e746bcf8cad..d054cb4339e 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 f355eca4e45..80e3b910a41 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -363,7 +363,7 @@ input:focus { border-right: 1px solid #E7E7E7; .input-wrapper { - padding: 6px; + padding: 6px 6px 0 6px; textarea { display: block; padding: 6px 8px; @@ -483,6 +483,31 @@ input:focus { } } +.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; + } + } +} + @media all and(max-height: 200px) { .livechat-room { .title { diff --git a/packages/rocketchat-livechat/app/client/views/messages.html b/packages/rocketchat-livechat/app/client/views/messages.html index 8bfbfd49b62..09a6658f0a7 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="/logo-dark.svg?v=1"> + </a> + </p> </div> </template> diff --git a/packages/rocketchat-livechat/app/public/logo-dark.svg b/packages/rocketchat-livechat/app/public/logo-dark.svg new file mode 100644 index 00000000000..4f6fa55412c --- /dev/null +++ b/packages/rocketchat-livechat/app/public/logo-dark.svg @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="435.721px" height="85.242px" viewBox="62.402 -18.766 435.721 85.242" + enable-background="new 62.402 -18.766 435.721 85.242" xml:space="preserve"> +<g> + <path fill="#04436A" d="M205.456,22.207c0,4.297-1.603,7.119-4.681,8.465l4.425,16.803c0.192,0.771-0.192,1.154-0.898,1.154h-6.67 + c-0.641,0-0.961-0.32-1.09-0.898l-4.297-16.289h-4.425v16.162c0,0.642-0.384,1.025-1.026,1.025h-6.67 + c-0.641,0-1.026-0.385-1.026-1.025V-1.651c0-0.641,0.385-1.026,1.026-1.026h16.097c6.028,0,9.235,3.207,9.235,9.235V22.207 + L205.456,22.207z M194.169,22.976c1.667,0,2.565-0.898,2.565-2.565V8.354c0-1.667-0.898-2.564-2.565-2.564h-6.349v17.187 + L194.169,22.976L194.169,22.976z"/> + <path fill="#04436A" d="M210.583,6.558c0-6.028,3.206-9.235,9.235-9.235h7.183c6.028,0,9.235,3.207,9.235,9.235v32.836 + c0,6.027-3.207,9.234-9.235,9.234h-7.183c-6.029,0-9.235-3.207-9.235-9.234V6.558z M225.397,40.355 + c1.667,0,2.565-0.834,2.565-2.565V8.162c0-1.667-0.898-2.565-2.565-2.565h-3.719c-1.667,0-2.565,0.898-2.565,2.565v29.629 + c0,1.73,0.898,2.564,2.565,2.564H225.397L225.397,40.355z"/> + <path fill="#04436A" d="M268.362,13.484c0,0.642-0.385,1.026-1.025,1.026h-6.413c-0.706,0-1.026-0.384-1.026-1.026v-5.13 + c0-1.667-0.897-2.564-2.564-2.564h-3.335c-1.731,0-2.565,0.897-2.565,2.564V37.6c0,1.731,0.897,2.563,2.565,2.563h3.335 + c1.667,0,2.564-0.833,2.564-2.563v-5.132c0-0.642,0.32-1.026,1.026-1.026h6.413c0.643,0,1.025,0.384,1.025,1.026v6.927 + c0,6.027-3.271,9.234-9.234,9.234h-7.183c-6.028,0-9.299-3.207-9.299-9.234V6.558c0-6.028,3.271-9.235,9.299-9.235h7.183 + c5.964,0,9.234,3.207,9.234,9.235V13.484z"/> + <path fill="#04436A" d="M295.422,48.629c-0.771,0-1.218-0.32-1.476-0.961l-8.079-19.048l-2.374,4.554v14.172 + c0,0.834-0.448,1.283-1.282,1.283h-6.157c-0.834,0-1.283-0.449-1.283-1.283v-48.74c0-0.833,0.449-1.283,1.283-1.283h6.157 + c0.833,0,1.282,0.449,1.282,1.283v19.881l9.876-20.202c0.321-0.641,0.771-0.962,1.476-0.962h6.733c0.962,0,1.347,0.642,0.897,1.539 + l-10.901,22.382l11.606,25.91c0.449,0.834,0.064,1.475-0.961,1.475H295.422z"/> + <path fill="#04436A" d="M333.45,4.763c0,0.641-0.257,1.09-1.026,1.09h-16.033v12.826h12.249c0.643,0,1.026,0.385,1.026,1.09v6.349 + c0,0.706-0.385,1.091-1.026,1.091h-12.249v12.954h16.033c0.771,0,1.026,0.321,1.026,1.026v6.414c0,0.641-0.257,1.024-1.026,1.024 + h-23.6c-0.578,0-0.963-0.385-0.963-1.024V-1.651c0-0.641,0.385-1.026,0.963-1.026h23.6c0.771,0,1.026,0.385,1.026,1.026V4.763z"/> + <path fill="#04436A" d="M363.204-2.677c0.705,0,1.026,0.385,1.026,1.026v6.414c0,0.641-0.321,1.026-1.026,1.026h-7.439v41.814 + c0,0.705-0.32,1.024-1.025,1.024h-6.67c-0.643,0-1.026-0.319-1.026-1.024V5.789h-7.438c-0.643,0-1.026-0.385-1.026-1.026v-6.414 + c0-0.641,0.385-1.026,1.026-1.026H363.204z"/> + <path fill="#04436A" d="M363.585,41.445c0-0.834,0.449-1.282,1.283-1.282h5.836c0.834,0,1.282,0.448,1.282,1.282v5.899 + c0,0.835-0.448,1.283-1.282,1.283h-5.836c-0.834,0-1.283-0.448-1.283-1.283V41.445z"/> + <path fill="#04436A" d="M404.114,13.484c0,0.642-0.386,1.026-1.026,1.026h-6.413c-0.705,0-1.025-0.384-1.025-1.026v-5.13 + c0-1.667-0.897-2.564-2.564-2.564h-3.335c-1.732,0-2.565,0.897-2.565,2.564V37.6c0,1.731,0.897,2.563,2.565,2.563h3.335 + c1.667,0,2.564-0.833,2.564-2.563v-5.132c0-0.642,0.32-1.026,1.025-1.026h6.413c0.643,0,1.026,0.384,1.026,1.026v6.927 + c0,6.027-3.271,9.234-9.235,9.234h-7.183c-6.028,0-9.299-3.207-9.299-9.234V6.558c0-6.028,3.271-9.235,9.299-9.235h7.183 + c5.965,0,9.235,3.207,9.235,9.235V13.484z"/> + <path fill="#04436A" d="M427.455-1.651c0-0.641,0.384-1.026,1.025-1.026h6.605c0.77,0,1.089,0.385,1.089,1.026v49.254 + c0,0.641-0.32,1.024-1.089,1.024h-6.605c-0.643,0-1.025-0.385-1.025-1.024V27.209h-8.209v20.395c0,0.642-0.385,1.025-1.026,1.025 + h-6.604c-0.771,0-1.091-0.385-1.091-1.025V-1.651c0-0.641,0.32-1.026,1.091-1.026h6.604c0.643,0,1.026,0.385,1.026,1.026v20.394 + h8.209V-1.651L427.455-1.651z"/> + <path fill="#04436A" d="M465.419,48.629c-0.577,0-0.897-0.32-1.026-0.898l-1.795-9.362h-11.416l-1.73,9.362 + c-0.129,0.578-0.449,0.898-1.026,0.898h-6.861c-0.705,0-1.026-0.385-0.835-1.09l10.646-49.318c0.129-0.641,0.513-0.898,1.09-0.898 + h8.915c0.577,0,0.962,0.257,1.09,0.898l10.646,49.318c0.129,0.705-0.128,1.09-0.897,1.09H465.419z M456.889,8.546l-4.104,22.382 + h8.209L456.889,8.546z"/> + <path fill="#04436A" d="M497.097-2.677c0.705,0,1.026,0.385,1.026,1.026v6.414c0,0.641-0.321,1.026-1.026,1.026h-7.438v41.814 + c0,0.705-0.321,1.024-1.026,1.024h-6.67c-0.641,0-1.025-0.319-1.025-1.024V5.789h-7.438c-0.642,0-1.025-0.385-1.025-1.026v-6.414 + c0-0.641,0.385-1.026,1.025-1.026H497.097z"/> +</g> +<path fill="#C1272D" d="M162.586,23.788c0-5.031-1.505-9.854-4.474-14.339c-2.666-4.025-6.401-7.588-11.1-10.591 + c-9.074-5.796-21-8.989-33.579-8.989c-4.202,0-8.344,0.355-12.361,1.059c-2.492-2.333-5.41-4.432-8.497-6.091 + c-16.494-7.994-30.172-0.188-30.172-0.188S75.12-4.904,73.052,4.253c-5.689,5.644-8.773,12.45-8.773,19.535 + c0,0.022,0.001,0.045,0.001,0.068c0,0.022-0.001,0.044-0.001,0.068c0,7.085,3.083,13.891,8.773,19.534 + c2.068,9.158-10.649,19.605-10.649,19.605s13.678,7.805,30.172-0.188c3.087-1.659,6.004-3.759,8.497-6.091 + c4.018,0.703,8.159,1.058,12.361,1.058c12.58,0,24.505-3.191,33.579-8.987c4.699-3.003,8.434-6.565,11.1-10.592 + c2.969-4.484,4.474-9.309,4.474-14.338c0-0.023-0.001-0.045-0.001-0.068S162.586,23.81,162.586,23.788z"/> +<path fill="#FFFFFF" d="M113.433-3.018c23.293,0,42.177,12.062,42.177,26.941c0,14.878-18.884,26.941-42.177,26.941 + c-5.187,0-10.154-0.6-14.743-1.693c-4.664,5.61-14.924,13.411-24.891,10.89c3.242-3.482,8.045-9.366,7.017-19.058 + c-5.974-4.648-9.56-10.597-9.56-17.08C71.255,9.043,90.139-3.018,113.433-3.018"/> +<g> + <g> + <circle fill="#C1272D" cx="113.433" cy="24.79" r="5.603"/> + </g> + <g> + <circle fill="#C1272D" cx="132.913" cy="24.79" r="5.603"/> + </g> + <g> + <circle fill="#C1272D" cx="93.952" cy="24.79" r="5.602"/> + </g> +</g> +<g> + <path fill="#CCCCCC" d="M113.433,47.319c-5.187,0-10.154-0.52-14.743-1.468c-4.118,4.294-12.6,10.066-21.39,9.854 + c-1.158,1.755-2.417,3.19-3.501,4.355c9.967,2.521,20.227-5.279,24.891-10.89c4.589,1.094,9.557,1.693,14.743,1.693 + c23.106,0,41.87-11.871,42.169-26.585C155.303,37.032,136.539,47.319,113.433,47.319z"/> +</g> +</svg> -- GitLab From 43c1189d3fe9ed641ee3108b4cdc526c0516642f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Thu, 24 Dec 2015 12:12:38 -0200 Subject: [PATCH 1027/1338] fix livechat triggers not triggering --- .../lib/fromApp/RoomHistoryManager.coffee | 2 ++ .../app/client/lib/triggers.js | 24 ++++++++++++++++--- .../assets/rocket-livechat.js | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee b/packages/rocketchat-livechat/app/client/lib/fromApp/RoomHistoryManager.coffee index c12bd00df8d..d21a2a29614 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/triggers.js b/packages/rocketchat-livechat/app/client/lib/triggers.js index 9d05e1845c0..f9f528cf1b3 100644 --- a/packages/rocketchat-livechat/app/client/lib/triggers.js +++ b/packages/rocketchat-livechat/app/client/lib/triggers.js @@ -1,9 +1,20 @@ 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 = []; + } }); }; @@ -14,13 +25,17 @@ this.Triggers = (function() { } actions.forEach(function(action) { if (action.name === 'send-message') { - var room = Random.id(); - visitor.setRoom(room); + var roomId = visitor.getRoom(); + + if (!roomId) { + roomId = Random.id(); + visitor.setRoom(roomId); + } Session.set('triggered', true); ChatMessage.insert({ msg: action.params.msg, - rid: room, + rid: roomId, u: { username: action.params.name } @@ -32,6 +47,9 @@ this.Triggers = (function() { }; var processRequest = function(request) { + if (!initiated) { + return requests.push(request); + } triggers.forEach(function(trigger) { trigger.conditions.forEach(function(condition) { switch (condition.name) { diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index 823152f797e..47e29c10333 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -119,7 +119,7 @@ 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); } } -- GitLab From c5837cf9727cf8da7329fe92a23ca57fffa7aded Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 24 Dec 2015 16:04:07 -0200 Subject: [PATCH 1028/1338] make sample data into array --- .../server/api/api.coffee | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 308ef4465c6..c45b719b328 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -182,19 +182,38 @@ Api.addRoute 'remove/:integrationId/:userId/:token', authRequired: true, Api.addRoute 'sample/:integrationId/:userId/:token', authRequired: true, get: -> - console.log 'Sample integration' + console.log 'Sample Integration' return {} = statusCode: 200 - body: + 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' + text: 'Sample text 3' trigger_word: 'Sample' + ] Api.addRoute 'info/:integrationId/:userId/:token', authRequired: true, -- GitLab From ec194a13b1a1dd951f2980c416a6d4e33906410d Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 24 Dec 2015 16:10:30 -0200 Subject: [PATCH 1029/1338] embarrassing mistake --- packages/rocketchat-integrations/server/api/api.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index c45b719b328..f2d9e11873a 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -195,7 +195,7 @@ Api.addRoute 'sample/:integrationId/:userId/:token', authRequired: true, user_name: 'rocket.cat' text: 'Sample text 1' trigger_word: 'Sample' - ],[ + , token: Random.id(24) channel_id: Random.id() channel_name: 'general' @@ -204,7 +204,7 @@ Api.addRoute 'sample/:integrationId/:userId/:token', authRequired: true, user_name: 'rocket.cat' text: 'Sample text 2' trigger_word: 'Sample' - ],[ + , token: Random.id(24) channel_id: Random.id() channel_name: 'general' -- GitLab From 9ea943e0a271e8a81e8d84e697e2a836d6832287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20S=C3=A1nchez?= <jsanchez1928@gmail.com> Date: Thu, 24 Dec 2015 13:13:12 -0500 Subject: [PATCH 1030/1338] Added new color variables to the theme editor --- .../stylesheets/utils/_colors.import.less | 41 +++++++++---------- packages/rocketchat-theme/i18n/en.i18n.json | 9 +++- .../rocketchat-theme/server/variables.coffee | 8 ++++ 3 files changed, 36 insertions(+), 22 deletions(-) mode change 100644 => 100755 packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less mode change 100644 => 100755 packages/rocketchat-theme/i18n/en.i18n.json mode change 100644 => 100755 packages/rocketchat-theme/server/variables.coffee 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 7bdb7b45f75..13141a7836e --- 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/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json old mode 100644 new mode 100755 index ec3bfc800cc..464bbbb1ea3 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -20,5 +20,12 @@ "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-quaternary-font-color": "Quaternary Font Color", + "theme-color-active-channel-background-color": "Active Channel Background Color", + "theme-color-active-channel-font-color": "Active Channel Font Color", + "theme-color-custom-scrollbar-color": "Custom Scrollbar Color", + "theme-color-action-buttons-color": "Actions Buttons Color", + "theme-color-clean-buttons-color": "Clean Buttons Color", + "theme-color-unread-notification-color": "Unread Notifications Color" } \ No newline at end of file diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee old mode 100644 new mode 100755 index 2ffe15d83d9..e194e55da62 --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -5,6 +5,7 @@ RocketChat.theme.addPublicColor "tertiary-background-color", "#EAEAEA" RocketChat.theme.addPublicColor "primary-font-color", "#444444" RocketChat.theme.addPublicColor "secondary-font-color", "#7F7F7F" RocketChat.theme.addPublicColor "tertiary-font-color", "rgba(255, 255, 255, 0.6)" +RocketChat.theme.addPublicColor "quaternary-font-color", "#FFF" 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" @@ -20,3 +21,10 @@ RocketChat.theme.addPublicColor "code-border", "#CCC" RocketChat.theme.addPublicColor "code-color", "#333" RocketChat.theme.addPublicColor "blockquote-background", "#CCC" RocketChat.theme.addPublicColor "message-hover-background-color", "#f9f9f9" +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 "custom-scrollbar-color", "rgba(255, 255, 255, 0.05)" +RocketChat.theme.addPublicColor "action-buttons-color", "#FFF" +RocketChat.theme.addPublicColor "clean-buttons-color", "rgba(0, 0, 0, 0.025)" +RocketChat.theme.addPublicColor "unread-notification-color", "#1dce73" + -- GitLab From cd9fbe6bce3199183b48da1e7c6f6007b68f3850 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 24 Dec 2015 16:24:55 -0200 Subject: [PATCH 1031/1338] Set user role in integration update too --- .../methods/incoming/updateIncomingIntegration.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee index 25787a28987..da7aa3dd15f 100644 --- a/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee @@ -12,7 +12,8 @@ Meteor.methods if integration.channel[0] not in ['@', '#'] throw new Meteor.Error 'invalid_channel', '[methods] updateIncomingIntegration -> channel should start with # or @' - if not RocketChat.models.Integrations.findOne(integrationId)? + currentIntegration = RocketChat.models.Integrations.findOne(integrationId) + if not currentIntegration? throw new Meteor.Error 'invalid_integration', '[methods] updateIncomingIntegration -> integration not found' record = undefined @@ -36,6 +37,9 @@ Meteor.methods if record is undefined throw new Meteor.Error 'channel_does_not_exists', "[methods] updateIncomingIntegration -> The channel does not exists" + user = RocketChat.models.Users.findOne({username: currentIntegration.username}) + Roles.addUsersToRoles user._id, 'bot', 'bot' + RocketChat.models.Integrations.update integrationId, $set: name: integration.name -- GitLab From 08593fc635bbad6538394fc74b6d78fde669b67e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 24 Dec 2015 16:25:24 -0200 Subject: [PATCH 1032/1338] Get integration name from body --- packages/rocketchat-integrations/server/api/api.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index f2d9e11873a..f5da4bf07f4 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -130,7 +130,7 @@ Api.addRoute 'add/:integrationId/:userId/:token', authRequired: true, Meteor.call 'addOutgoingIntegration', username: 'rocket.cat' urls: [@bodyParams.target_url] - name: @bodyParams.data.name + name: @bodyParams.name channel: @bodyParams.data.channel_name triggerWords: @bodyParams.data.trigger_words @@ -141,7 +141,7 @@ Api.addRoute 'add/:integrationId/:userId/:token', authRequired: true, Meteor.call 'addOutgoingIntegration', username: 'rocket.cat' urls: [@bodyParams.target_url] - name: @bodyParams.data.name + name: @bodyParams.name channel: @bodyParams.data.username triggerWords: @bodyParams.data.trigger_words -- GitLab From 9699e552caf875579c1a1885e64bf008f132fa31 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 24 Dec 2015 16:37:37 -0200 Subject: [PATCH 1033/1338] Enforce data in body params --- packages/rocketchat-integrations/server/api/api.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index f5da4bf07f4..a7321099b93 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -124,6 +124,8 @@ Api.addRoute 'add/:integrationId/:userId/:token', authRequired: true, Meteor.runAsUser user._id, => switch @bodyParams['event'] when 'newMessageOnChannel' + @bodyParams.data ?= {} + if @bodyParams.data.channel_name? and @bodyParams.data.channel_name.indexOf('#') is -1 @bodyParams.data.channel_name = '#' + @bodyParams.data.channel_name -- GitLab From f68d4cee761914e2365fa557040dc918dc95f433 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 24 Dec 2015 16:58:47 -0200 Subject: [PATCH 1034/1338] code formatting --- packages/rocketchat-theme/i18n/en.i18n.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-theme/i18n/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json index 464bbbb1ea3..10f2f83c636 100755 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -1,9 +1,14 @@ { + "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", @@ -11,6 +16,7 @@ "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", @@ -21,11 +27,5 @@ "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-quaternary-font-color": "Quaternary Font Color", - "theme-color-active-channel-background-color": "Active Channel Background Color", - "theme-color-active-channel-font-color": "Active Channel Font Color", - "theme-color-custom-scrollbar-color": "Custom Scrollbar Color", - "theme-color-action-buttons-color": "Actions Buttons Color", - "theme-color-clean-buttons-color": "Clean Buttons Color", - "theme-color-unread-notification-color": "Unread Notifications Color" -} \ No newline at end of file + "theme-color-unread-notification-color" : "Unread Notifications Color" +} -- GitLab From ee16950df53d1abc4d1a68b73f6c98d8e9b46eca Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 24 Dec 2015 17:18:35 -0200 Subject: [PATCH 1035/1338] re order settings --- .../rocketchat-theme/server/variables.coffee | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee index e194e55da62..ce01a462e00 100755 --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -1,30 +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-font-color", "#444444" +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", "#FFF" + +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", "#CCC" +RocketChat.theme.addPublicColor "clean-buttons-color", "rgba(0, 0, 0, 0.025)" +RocketChat.theme.addPublicColor "code-background", "#F8F8F8" +RocketChat.theme.addPublicColor "code-border", "#CCC" +RocketChat.theme.addPublicColor "code-color", "#333" +RocketChat.theme.addPublicColor "content-background-color", "#FFF" +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 "message-hover-background-color", "#f9f9f9" RocketChat.theme.addPublicColor "smallprint-font-color", "#C2E7FF" RocketChat.theme.addPublicColor "smallprint-hover-color", "#FFFFFF" -RocketChat.theme.addPublicColor "status-online", "#35AC19" -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 "message-hover-background-color", "#f9f9f9" -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 "custom-scrollbar-color", "rgba(255, 255, 255, 0.05)" -RocketChat.theme.addPublicColor "action-buttons-color", "#FFF" -RocketChat.theme.addPublicColor "clean-buttons-color", "rgba(0, 0, 0, 0.025)" +RocketChat.theme.addPublicColor "status-busy", "#D30230" +RocketChat.theme.addPublicColor "status-offline", "rgba(150, 150, 150, 0.50)" +RocketChat.theme.addPublicColor "status-online", "#35AC19" RocketChat.theme.addPublicColor "unread-notification-color", "#1dce73" - -- GitLab From 1e7e7015b72b5088403b9f27f1a5f6f4ec04a97a Mon Sep 17 00:00:00 2001 From: sweetvvck <sweetvvck@gmail.com> Date: Sat, 26 Dec 2015 15:00:41 +0800 Subject: [PATCH 1036/1338] 1. Set current app language to user's language after user login; If users language setting is different from default app language setting, front end app language should change to user's language once user login 2. Fix the wrong language display in the view of accountProfile. --- client/startup/startup.coffee | 6 +++--- .../rocketchat-ui-account/account/accountProfile.coffee | 2 +- packages/rocketchat-ui-login/login/form.coffee | 2 ++ packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee | 3 --- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee index 157f29fd2f3..1f3e3cf041b 100644 --- a/client/startup/startup.coffee +++ b/client/startup/startup.coffee @@ -23,12 +23,14 @@ Meteor.startup -> loadedLaguages = [] - setLanguage = (language) -> + @setLanguage = (language) -> if loadedLaguages.indexOf(language) > -1 return loadedLaguages.push language + if isRtl language + $('html').addClass "rtl" language = language.split('-').shift() TAPi18n.setLanguage(language) @@ -44,8 +46,6 @@ Meteor.startup -> if localStorage.getItem('userLanguage') isnt userLanguage localStorage.setItem('userLanguage', userLanguage) - if isRtl localStorage.getItem 'userLanguage' - $('html').addClass "rtl" setLanguage userLanguage ) diff --git a/packages/rocketchat-ui-account/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee index e0fecee6265..5a780f917a9 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 Meteor.user().language or defaultUserLanguage())?.split('-').shift().toLowerCase() is key + return (Meteor.user().language or defaultUserLanguage())?.split('-').shift().toLowerCase() is key realname: -> return Meteor.user().name diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 52ef48d4bcb..b1db2325dbb 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -115,6 +115,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-sidenav/side-nav/accountBox.coffee b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee index 2f4fffa8872..b5e470d32de 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee @@ -36,9 +36,6 @@ Template.accountBox.events user = Meteor.user() Meteor.logout -> FlowRouter.go 'home' - # remove userLanguage in localStorage - # in case of another account with different language login - localStorage.removeItem('userLanguage') Meteor.call('logoutCleanUp', user) 'click #avatar': (event) -> -- GitLab From 076d58af62f98ab6a509e981f771e0ede1b8b262 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 26 Dec 2015 14:39:04 -0200 Subject: [PATCH 1037/1338] Fix preview of images in mobile --- lib/fileUpload.coffee | 4 ++++ .../client/messageAttachment.coffee | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index cb84a73bab3..3ee0e68c276 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -73,6 +73,10 @@ if UploadFS? 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 diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee index a224b9a872f..5cf3138934c 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.coffee +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -1,7 +1,13 @@ Template.messageAttachment.helpers fixCordova: (url) -> if Meteor.isCordova and url?[0] is '/' - return Meteor.absoluteUrl().replace(/\/$/, '') + url + 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: -> -- GitLab From 0f3fa28662cc896dd43e246e52cc920ee1863439 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 26 Dec 2015 18:22:54 -0200 Subject: [PATCH 1038/1338] Do not load all settings to process.env --- packages/rocketchat-lib/server/functions/settings.coffee | 9 ++++++--- packages/rocketchat-lib/server/startup/settings.coffee | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 7cb1a13ab79..a0e48bade8a 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -147,14 +147,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/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 0393c868e50..aab77d73469 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -91,10 +91,10 @@ RocketChat.settings.addGroup 'API', -> RocketChat.settings.addGroup 'SMTP', -> - @add 'SMTP_Host', '', { type: 'string' } - @add 'SMTP_Port', '', { type: 'string' } - @add 'SMTP_Username', '', { type: 'string' } - @add 'SMTP_Password', '', { type: 'string' } + @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' } @section 'Invitation', -> -- GitLab From ea95b08013c9dc5967a260d58f2fde370bc2ab3d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 26 Dec 2015 18:25:41 -0200 Subject: [PATCH 1039/1338] Remove unecessary logs --- packages/rocketchat-file/file.server.coffee | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/rocketchat-file/file.server.coffee b/packages/rocketchat-file/file.server.coffee index 80b6e64bfc7..b974aff0ba4 100644 --- a/packages/rocketchat-file/file.server.coffee +++ b/packages/rocketchat-file/file.server.coffee @@ -21,26 +21,19 @@ RocketChatFile = detectGM = -> - console.log 'GM: Getting GraphicsMagick version' exec 'gm version', Meteor.bindEnvironment (error, stdout, stderr) -> - console.log 'GM: GraphicsMagick', arguments if not error? and stdout.indexOf('GraphicsMagick') > -1 - console.log 'GM: GraphicsMagick installed' RocketChatFile.enable() RocketChat.Info.GraphicsMagick = enabled: true version: stdout else - console.log 'GM: GraphicsMagick not installed' RocketChat.Info.GraphicsMagick = enabled: false - console.log 'GM: Getting ImageMagick version' exec 'convert -version', Meteor.bindEnvironment (error, stdout, stderr) -> - console.log 'GM: ImageMagick', arguments if not error? and stdout.indexOf('ImageMagick') > -1 - console.log 'GM: ImageMagick installed' if RocketChatFile.enabled isnt true # Enable GM to work with ImageMagick if no GraphicsMagick RocketChatFile.gm = RocketChatFile.gm.subClass({imageMagick: true}) @@ -50,7 +43,6 @@ detectGM = -> enabled: true version: stdout else - console.log 'GM: ImageMagick not installed' if RocketChatFile.enabled isnt true RocketChatFile.disable() -- GitLab From decaf1305ad71234038d4e6e1e041e35006db9ea Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 28 Dec 2015 09:16:31 -0200 Subject: [PATCH 1040/1338] using branding image from main app --- .../app/client/views/messages.html | 2 +- .../app/public/logo-dark.svg | 77 ------------------- 2 files changed, 1 insertion(+), 78 deletions(-) delete mode 100644 packages/rocketchat-livechat/app/public/logo-dark.svg diff --git a/packages/rocketchat-livechat/app/client/views/messages.html b/packages/rocketchat-livechat/app/client/views/messages.html index 09a6658f0a7..8e3fe168b7d 100644 --- a/packages/rocketchat-livechat/app/client/views/messages.html +++ b/packages/rocketchat-livechat/app/client/views/messages.html @@ -22,7 +22,7 @@ <p class="powered-by"> Powered by <a href="https://rocket.chat" target="_blank"> - <img class="logo" src="/logo-dark.svg?v=1"> + <img class="logo" src="/images/logo/logo-dark.svg?v=1"> </a> </p> </div> diff --git a/packages/rocketchat-livechat/app/public/logo-dark.svg b/packages/rocketchat-livechat/app/public/logo-dark.svg deleted file mode 100644 index 4f6fa55412c..00000000000 --- a/packages/rocketchat-livechat/app/public/logo-dark.svg +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" - width="435.721px" height="85.242px" viewBox="62.402 -18.766 435.721 85.242" - enable-background="new 62.402 -18.766 435.721 85.242" xml:space="preserve"> -<g> - <path fill="#04436A" d="M205.456,22.207c0,4.297-1.603,7.119-4.681,8.465l4.425,16.803c0.192,0.771-0.192,1.154-0.898,1.154h-6.67 - c-0.641,0-0.961-0.32-1.09-0.898l-4.297-16.289h-4.425v16.162c0,0.642-0.384,1.025-1.026,1.025h-6.67 - c-0.641,0-1.026-0.385-1.026-1.025V-1.651c0-0.641,0.385-1.026,1.026-1.026h16.097c6.028,0,9.235,3.207,9.235,9.235V22.207 - L205.456,22.207z M194.169,22.976c1.667,0,2.565-0.898,2.565-2.565V8.354c0-1.667-0.898-2.564-2.565-2.564h-6.349v17.187 - L194.169,22.976L194.169,22.976z"/> - <path fill="#04436A" d="M210.583,6.558c0-6.028,3.206-9.235,9.235-9.235h7.183c6.028,0,9.235,3.207,9.235,9.235v32.836 - c0,6.027-3.207,9.234-9.235,9.234h-7.183c-6.029,0-9.235-3.207-9.235-9.234V6.558z M225.397,40.355 - c1.667,0,2.565-0.834,2.565-2.565V8.162c0-1.667-0.898-2.565-2.565-2.565h-3.719c-1.667,0-2.565,0.898-2.565,2.565v29.629 - c0,1.73,0.898,2.564,2.565,2.564H225.397L225.397,40.355z"/> - <path fill="#04436A" d="M268.362,13.484c0,0.642-0.385,1.026-1.025,1.026h-6.413c-0.706,0-1.026-0.384-1.026-1.026v-5.13 - c0-1.667-0.897-2.564-2.564-2.564h-3.335c-1.731,0-2.565,0.897-2.565,2.564V37.6c0,1.731,0.897,2.563,2.565,2.563h3.335 - c1.667,0,2.564-0.833,2.564-2.563v-5.132c0-0.642,0.32-1.026,1.026-1.026h6.413c0.643,0,1.025,0.384,1.025,1.026v6.927 - c0,6.027-3.271,9.234-9.234,9.234h-7.183c-6.028,0-9.299-3.207-9.299-9.234V6.558c0-6.028,3.271-9.235,9.299-9.235h7.183 - c5.964,0,9.234,3.207,9.234,9.235V13.484z"/> - <path fill="#04436A" d="M295.422,48.629c-0.771,0-1.218-0.32-1.476-0.961l-8.079-19.048l-2.374,4.554v14.172 - c0,0.834-0.448,1.283-1.282,1.283h-6.157c-0.834,0-1.283-0.449-1.283-1.283v-48.74c0-0.833,0.449-1.283,1.283-1.283h6.157 - c0.833,0,1.282,0.449,1.282,1.283v19.881l9.876-20.202c0.321-0.641,0.771-0.962,1.476-0.962h6.733c0.962,0,1.347,0.642,0.897,1.539 - l-10.901,22.382l11.606,25.91c0.449,0.834,0.064,1.475-0.961,1.475H295.422z"/> - <path fill="#04436A" d="M333.45,4.763c0,0.641-0.257,1.09-1.026,1.09h-16.033v12.826h12.249c0.643,0,1.026,0.385,1.026,1.09v6.349 - c0,0.706-0.385,1.091-1.026,1.091h-12.249v12.954h16.033c0.771,0,1.026,0.321,1.026,1.026v6.414c0,0.641-0.257,1.024-1.026,1.024 - h-23.6c-0.578,0-0.963-0.385-0.963-1.024V-1.651c0-0.641,0.385-1.026,0.963-1.026h23.6c0.771,0,1.026,0.385,1.026,1.026V4.763z"/> - <path fill="#04436A" d="M363.204-2.677c0.705,0,1.026,0.385,1.026,1.026v6.414c0,0.641-0.321,1.026-1.026,1.026h-7.439v41.814 - c0,0.705-0.32,1.024-1.025,1.024h-6.67c-0.643,0-1.026-0.319-1.026-1.024V5.789h-7.438c-0.643,0-1.026-0.385-1.026-1.026v-6.414 - c0-0.641,0.385-1.026,1.026-1.026H363.204z"/> - <path fill="#04436A" d="M363.585,41.445c0-0.834,0.449-1.282,1.283-1.282h5.836c0.834,0,1.282,0.448,1.282,1.282v5.899 - c0,0.835-0.448,1.283-1.282,1.283h-5.836c-0.834,0-1.283-0.448-1.283-1.283V41.445z"/> - <path fill="#04436A" d="M404.114,13.484c0,0.642-0.386,1.026-1.026,1.026h-6.413c-0.705,0-1.025-0.384-1.025-1.026v-5.13 - c0-1.667-0.897-2.564-2.564-2.564h-3.335c-1.732,0-2.565,0.897-2.565,2.564V37.6c0,1.731,0.897,2.563,2.565,2.563h3.335 - c1.667,0,2.564-0.833,2.564-2.563v-5.132c0-0.642,0.32-1.026,1.025-1.026h6.413c0.643,0,1.026,0.384,1.026,1.026v6.927 - c0,6.027-3.271,9.234-9.235,9.234h-7.183c-6.028,0-9.299-3.207-9.299-9.234V6.558c0-6.028,3.271-9.235,9.299-9.235h7.183 - c5.965,0,9.235,3.207,9.235,9.235V13.484z"/> - <path fill="#04436A" d="M427.455-1.651c0-0.641,0.384-1.026,1.025-1.026h6.605c0.77,0,1.089,0.385,1.089,1.026v49.254 - c0,0.641-0.32,1.024-1.089,1.024h-6.605c-0.643,0-1.025-0.385-1.025-1.024V27.209h-8.209v20.395c0,0.642-0.385,1.025-1.026,1.025 - h-6.604c-0.771,0-1.091-0.385-1.091-1.025V-1.651c0-0.641,0.32-1.026,1.091-1.026h6.604c0.643,0,1.026,0.385,1.026,1.026v20.394 - h8.209V-1.651L427.455-1.651z"/> - <path fill="#04436A" d="M465.419,48.629c-0.577,0-0.897-0.32-1.026-0.898l-1.795-9.362h-11.416l-1.73,9.362 - c-0.129,0.578-0.449,0.898-1.026,0.898h-6.861c-0.705,0-1.026-0.385-0.835-1.09l10.646-49.318c0.129-0.641,0.513-0.898,1.09-0.898 - h8.915c0.577,0,0.962,0.257,1.09,0.898l10.646,49.318c0.129,0.705-0.128,1.09-0.897,1.09H465.419z M456.889,8.546l-4.104,22.382 - h8.209L456.889,8.546z"/> - <path fill="#04436A" d="M497.097-2.677c0.705,0,1.026,0.385,1.026,1.026v6.414c0,0.641-0.321,1.026-1.026,1.026h-7.438v41.814 - c0,0.705-0.321,1.024-1.026,1.024h-6.67c-0.641,0-1.025-0.319-1.025-1.024V5.789h-7.438c-0.642,0-1.025-0.385-1.025-1.026v-6.414 - c0-0.641,0.385-1.026,1.025-1.026H497.097z"/> -</g> -<path fill="#C1272D" d="M162.586,23.788c0-5.031-1.505-9.854-4.474-14.339c-2.666-4.025-6.401-7.588-11.1-10.591 - c-9.074-5.796-21-8.989-33.579-8.989c-4.202,0-8.344,0.355-12.361,1.059c-2.492-2.333-5.41-4.432-8.497-6.091 - c-16.494-7.994-30.172-0.188-30.172-0.188S75.12-4.904,73.052,4.253c-5.689,5.644-8.773,12.45-8.773,19.535 - c0,0.022,0.001,0.045,0.001,0.068c0,0.022-0.001,0.044-0.001,0.068c0,7.085,3.083,13.891,8.773,19.534 - c2.068,9.158-10.649,19.605-10.649,19.605s13.678,7.805,30.172-0.188c3.087-1.659,6.004-3.759,8.497-6.091 - c4.018,0.703,8.159,1.058,12.361,1.058c12.58,0,24.505-3.191,33.579-8.987c4.699-3.003,8.434-6.565,11.1-10.592 - c2.969-4.484,4.474-9.309,4.474-14.338c0-0.023-0.001-0.045-0.001-0.068S162.586,23.81,162.586,23.788z"/> -<path fill="#FFFFFF" d="M113.433-3.018c23.293,0,42.177,12.062,42.177,26.941c0,14.878-18.884,26.941-42.177,26.941 - c-5.187,0-10.154-0.6-14.743-1.693c-4.664,5.61-14.924,13.411-24.891,10.89c3.242-3.482,8.045-9.366,7.017-19.058 - c-5.974-4.648-9.56-10.597-9.56-17.08C71.255,9.043,90.139-3.018,113.433-3.018"/> -<g> - <g> - <circle fill="#C1272D" cx="113.433" cy="24.79" r="5.603"/> - </g> - <g> - <circle fill="#C1272D" cx="132.913" cy="24.79" r="5.603"/> - </g> - <g> - <circle fill="#C1272D" cx="93.952" cy="24.79" r="5.602"/> - </g> -</g> -<g> - <path fill="#CCCCCC" d="M113.433,47.319c-5.187,0-10.154-0.52-14.743-1.468c-4.118,4.294-12.6,10.066-21.39,9.854 - c-1.158,1.755-2.417,3.19-3.501,4.355c9.967,2.521,20.227-5.279,24.891-10.89c4.589,1.094,9.557,1.693,14.743,1.693 - c23.106,0,41.87-11.871,42.169-26.585C155.303,37.032,136.539,47.319,113.433,47.319z"/> -</g> -</svg> -- GitLab From 8f3576fbd647ed9168658d3006e3b815a512b99d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 28 Dec 2015 10:21:28 -0200 Subject: [PATCH 1041/1338] Tokenize message on message render to prevent re processing --- packages/rocketchat-highlight/highlight.coffee | 11 ++++++++++- packages/rocketchat-markdown/markdown.coffee | 17 ++++++++++++++--- .../message/message.coffee | 4 ++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-highlight/highlight.coffee b/packages/rocketchat-highlight/highlight.coffee index c98270151ae..57944340bcd 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-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index c578fec7160..f33c817e527 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-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 7d9bcffbe28..dff309fa1fb 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -102,6 +102,10 @@ Template.message.onCreated -> msg.html = _.escapeHTML msg.html message = RocketChat.callbacks.run 'renderMessage', msg + if message.tokens?.length > 0 + for token in message.tokens + 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 -- GitLab From c6cc6153eecc1e23f5101460883f11b6e72d52db Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 28 Dec 2015 11:58:51 -0200 Subject: [PATCH 1042/1338] version bump --- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- packages/rocketchat-lib/rocketchat.info | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 9e2a5f678ef..3e5d7aa10f0 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 6, # Increment this for every release. + appVersion = 7, # Increment this for every release. - appMarketingVersion = (defaultText = "0.10.2"), + appMarketingVersion = (defaultText = "0.11.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index f8dc5a090df..e6581973d84 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.10.2" + "version": "0.11.0" } -- GitLab From 19ca589b74a99c5de66d197b851244951b1eb2b6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 28 Dec 2015 18:38:53 -0200 Subject: [PATCH 1043/1338] fix reset password - closes #1502 --- packages/rocketchat-ui/lib/accounts.coffee | 29 +++++++++++----------- packages/rocketchat-ui/package.js | 1 + server/lib/accounts.coffee | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/rocketchat-ui/lib/accounts.coffee b/packages/rocketchat-ui/lib/accounts.coffee index d81d0e7c5a4..62675f20ba2 100644 --- a/packages/rocketchat-ui/lib/accounts.coffee +++ b/packages/rocketchat-ui/lib/accounts.coffee @@ -1,17 +1,16 @@ -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() + 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 +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() diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index dd89a410e5b..eec1c93b7c3 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', diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 765e55ea8db..94dddcb05ad 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -25,7 +25,7 @@ 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 + resetPasswordText user, url if RocketChat.settings.get 'Accounts_Enrollment_Email' Accounts.emailTemplates.enrollAccount.text = (user, url) -> -- GitLab From 5e723762a3cdd13a0e2d6befd14428e1a8de0497 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 28 Dec 2015 23:55:55 -0200 Subject: [PATCH 1044/1338] new password reset screen --- i18n/en.i18n.json | 3 +++ .../rocketchat-ui-login/login/layout.html | 2 +- packages/rocketchat-ui-login/package.js | 9 ++++++- .../reset-password/resetPassword.html | 15 +++++++++++ .../reset-password/resetPassword.js | 26 +++++++++++++++++++ packages/rocketchat-ui-login/routes.js | 6 +++++ .../rocketchat-ui-master/master/main.html | 2 +- packages/rocketchat-ui/lib/accounts.coffee | 10 ------- server/lib/accounts.coffee | 2 +- 9 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 packages/rocketchat-ui-login/reset-password/resetPassword.html create mode 100644 packages/rocketchat-ui-login/reset-password/resetPassword.js create mode 100644 packages/rocketchat-ui-login/routes.js diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e70ed2ba3b4..b38261d54de 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -340,6 +340,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.", @@ -383,6 +384,7 @@ "Remove_Admin" : "Remove Admin", "Remove_custom_oauth" : "Remove custom oauth", "Remove_from_room" : "Remove from room", + "Reset" : "Reset", "Reset_password" : "Reset password", "Restart" : "Restart", "Restart_the_server" : "Restart the server", @@ -484,6 +486,7 @@ "There_is_no_integrations" : "There is 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", diff --git a/packages/rocketchat-ui-login/login/layout.html b/packages/rocketchat-ui-login/login/layout.html index 3cf9cd1bb29..a097d5834bb 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 5b2c11042cb..f2f5a02e8c0 100644 --- a/packages/rocketchat-ui-login/package.js +++ b/packages/rocketchat-ui-login/package.js @@ -20,6 +20,13 @@ Package.onUse(function(api) { 'rocketchat:lib@0.0.1' ]); + 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 00000000000..56d24686730 --- /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 00000000000..ae91df07180 --- /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 00000000000..a6ac9f5b22f --- /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.html b/packages/rocketchat-ui-master/master/main.html index abf74f660a8..e8229fc6d27 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -43,7 +43,7 @@ <template name="main"> {{#if subsReady}} {{#unless logged}} - {{> loginLayout}} + {{> loginLayout center="loginForm"}} {{else}} {{#unless hasUsername}} {{> username}} diff --git a/packages/rocketchat-ui/lib/accounts.coffee b/packages/rocketchat-ui/lib/accounts.coffee index 62675f20ba2..17f3828de2f 100644 --- a/packages/rocketchat-ui/lib/accounts.coffee +++ b/packages/rocketchat-ui/lib/accounts.coffee @@ -4,13 +4,3 @@ Accounts.onEmailVerificationLink (token, done) -> 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() diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 94dddcb05ad..e68658e7dec 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -24,7 +24,7 @@ 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/' + url = url.replace /\/#\//, '/' resetPasswordText user, url if RocketChat.settings.get 'Accounts_Enrollment_Email' -- GitLab From badb058241ae7df9d4110e9788dc224986ceebe7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 29 Dec 2015 16:44:58 -0200 Subject: [PATCH 1045/1338] Try to parse all request bodies as JSON --- packages/rocketchat-cors/cors.coffee | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index ea47d21760e..e23cf4b15ea 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -1,5 +1,25 @@ # 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() + + buf = '' + req.setEncoding('utf8') + req.on 'data', (chunk) -> buf += chunk + req.on 'end', -> + try + req.body = JSON.parse(buf) + catch err + req.body = buf + + next() + + WebApp.rawConnectHandlers.use (req, res, next) -> res.setHeader("Access-Control-Allow-Origin", "*") res.setHeader("X-Rocket-Chat-Version", VERSION) -- GitLab From 9990033632c9f8b605db06e1559bdb0f12c3853f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 29 Dec 2015 17:17:27 -0200 Subject: [PATCH 1046/1338] trim integration messages --- packages/rocketchat-integrations/server/api/api.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index a7321099b93..508b3c7e77f 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -73,7 +73,7 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, message = alias: @bodyParams.username or @bodyParams.alias or integration.alias - msg: @bodyParams.text or @bodyParams.msg or '' + msg: _.trim(@bodyParams.text or @bodyParams.msg or '') attachments: @bodyParams.attachments parseUrls: false bot: @@ -92,7 +92,7 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, if _.isArray message.attachments for attachment in message.attachments if attachment.msg - attachment.text = attachment.msg + attachment.text = _.trim(attachment.msg) delete attachment.msg RocketChat.sendMessage user, message, room, {} -- GitLab From 167209df5a6897e9a43a1802534b1476501c2f23 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 29 Dec 2015 17:17:44 -0200 Subject: [PATCH 1047/1338] added request debug messages --- packages/rocketchat-cors/cors.coffee | 3 +++ packages/rocketchat-lib/package.js | 3 ++- packages/rocketchat-lib/server/lib/debug.js | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index e23cf4b15ea..971777d4952 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -12,6 +12,9 @@ WebApp.rawConnectHandlers.use (req, res, next) -> 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 diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 34e49b1c7f3..5f4c60fb135 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -25,11 +25,12 @@ Package.onUse(function(api) { api.use('rocketchat:version'); api.use('kadira:flow-router', 'client'); + api.addFiles('lib/core.coffee'); + // DEBUGGER api.addFiles('server/lib/debug.js', 'server'); // COMMON LIB - api.addFiles('lib/core.coffee'); api.addFiles('lib/settings.coffee'); api.addFiles('lib/callbacks.coffee'); api.addFiles('lib/slashCommand.coffee'); diff --git a/packages/rocketchat-lib/server/lib/debug.js b/packages/rocketchat-lib/server/lib/debug.js index 243928778ac..c63fc96bf72 100644 --- a/packages/rocketchat-lib/server/lib/debug.js +++ b/packages/rocketchat-lib/server/lib/debug.js @@ -1,21 +1,21 @@ -var debugLevel = 'debug'; +RocketChat.debugLevel = 'debug'; Meteor.startup(function() { RocketChat.settings.onload('Debug_Level', function(key, value, initialLoad) { if (value) { - debugLevel = value; + RocketChat.debugLevel = value; } }); var value = RocketChat.settings.get('Debug_Level'); if (value) { - debugLevel = value; + RocketChat.debugLevel = value; } }); var wrapMethods = function(name, originalHandler, methodsMap) { methodsMap[name] = function() { - if (debugLevel === 'debug') { + if (RocketChat.debugLevel === 'debug') { console.log('[methods]'.green, name, '-> userId:', Meteor.userId(), ', arguments: ', arguments); } @@ -36,7 +36,7 @@ var originalMeteorPublish = Meteor.publish; Meteor.publish = function(name, func) { return originalMeteorPublish(name, function() { - if (debugLevel === 'debug') { + if (RocketChat.debugLevel === 'debug') { console.log('[publish]'.green, name, '-> userId:', this.userId, ', arguments: ', arguments); } -- GitLab From f972c9363a40511056ef4666e1902210aa2c2f99 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 29 Dec 2015 17:17:59 -0200 Subject: [PATCH 1048/1338] support named color for message attachments --- .../client/messageAttachment.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.coffee b/packages/rocketchat-message-attachments/client/messageAttachment.coffee index 5cf3138934c..4bfee816da8 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.coffee +++ b/packages/rocketchat-message-attachments/client/messageAttachment.coffee @@ -21,3 +21,10 @@ Template.messageAttachment.helpers 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 -- GitLab From b8f7a16e8800ed1899018993791853dab3ad3b4c Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 29 Dec 2015 17:46:43 -0200 Subject: [PATCH 1049/1338] improved clean button color --- packages/rocketchat-theme/server/variables.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee index ce01a462e00..272bd59e361 100755 --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -10,7 +10,7 @@ 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", "#CCC" -RocketChat.theme.addPublicColor "clean-buttons-color", "rgba(0, 0, 0, 0.025)" +RocketChat.theme.addPublicColor "clean-buttons-color", "rgba(0, 0, 0, 0.25)" RocketChat.theme.addPublicColor "code-background", "#F8F8F8" RocketChat.theme.addPublicColor "code-border", "#CCC" RocketChat.theme.addPublicColor "code-color", "#333" -- GitLab From 2f0d8ef0ba0fe2b132f35344c88fe6f2292e9488 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 29 Dec 2015 17:47:52 -0200 Subject: [PATCH 1050/1338] standardize colors definition --- .../rocketchat-theme/server/variables.coffee | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee index 272bd59e361..3a0557a4e66 100755 --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -1,30 +1,30 @@ -RocketChat.theme.addPublicColor "primary-background-color", "#04436A" +RocketChat.theme.addPublicColor "primary-background-color", "#04436a" RocketChat.theme.addPublicColor "primary-font-color", "#444444" -RocketChat.theme.addPublicColor "secondary-background-color", "#F4F4F4" -RocketChat.theme.addPublicColor "secondary-font-color", "#7F7F7F" -RocketChat.theme.addPublicColor "tertiary-background-color", "#EAEAEA" +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", "#FFF" +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", "#CCC" +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", "#CCC" -RocketChat.theme.addPublicColor "code-color", "#333" -RocketChat.theme.addPublicColor "content-background-color", "#FFF" +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 "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 "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 "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-online", "#35AC19" +RocketChat.theme.addPublicColor "status-online", "#35ac19" RocketChat.theme.addPublicColor "unread-notification-color", "#1dce73" -- GitLab From a053afd920e3c1ffdcd7d25680fee1c45eb488a7 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 29 Dec 2015 17:48:54 -0200 Subject: [PATCH 1051/1338] fix guest users default role --- packages/rocketchat-livechat/server/methods/registerGuest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js index 8131aa6aa8e..1187eae6ef3 100644 --- a/packages/rocketchat-livechat/server/methods/registerGuest.js +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -35,7 +35,7 @@ Meteor.methods({ } userData = { username: user, - globalRoles: 'livechat-guest', + globalRoles: ['livechat-guest'], department: department }; userId = Accounts.insertUserDoc({}, userData); -- GitLab From b95356b50e8afdfde3f50cc21b0f3566456fb322 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 29 Dec 2015 18:36:36 -0200 Subject: [PATCH 1052/1338] Increase the delay to render color fields --- packages/rocketchat-ui-admin/admin/admin.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 9658968c918..8c3105542a4 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -224,10 +224,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 -- GitLab From 045535455290b22ee187f1c2ebf4dbd36876c922 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 29 Dec 2015 19:05:30 -0200 Subject: [PATCH 1053/1338] clean up tap:i18n definitions on packages --- packages/rocketchat-authorization/package.js | 4 +- .../package.js | 3 +- .../rocketchat-channel-settings/package.js | 3 +- packages/rocketchat-chatops/package.js | 5 +-- .../rocketchat-github-enterprise/package.js | 7 ++- packages/rocketchat-gitlab/package.js | 5 +-- packages/rocketchat-hubot/package.js | 5 +-- packages/rocketchat-integrations/package.js | 4 +- packages/rocketchat-ldap/package.js | 2 +- packages/rocketchat-lib/package.js | 5 +-- packages/rocketchat-livechat/package.js | 5 +-- packages/rocketchat-mailer/package.js | 5 +-- .../rocketchat-mentions-flextab/package.js | 5 +-- packages/rocketchat-message-pin/package.js | 5 +-- packages/rocketchat-message-star/package.js | 5 +-- .../package.js | 5 +-- .../rocketchat-slashcommands-join/package.js | 5 +-- .../rocketchat-slashcommands-kick/package.js | 5 +-- .../rocketchat-slashcommands-mute/package.js | 5 +-- packages/rocketchat-statistics/package.js | 5 +-- packages/rocketchat-theme/i18n/ro.i18n.json | 4 +- packages/rocketchat-theme/package.js | 5 +-- packages/rocketchat-webrtc/package.js | 5 +-- packages/rocketchat-wordpress/package.js | 45 +++++++++---------- 24 files changed, 66 insertions(+), 86 deletions(-) diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 90a13112d92..e416cd4118e 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -71,6 +71,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-channel-settings-mail-messages/package.js b/packages/rocketchat-channel-settings-mail-messages/package.js index b0fb444889d..b7ff606e064 100644 --- a/packages/rocketchat-channel-settings-mail-messages/package.js +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -41,8 +41,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/package.js b/packages/rocketchat-channel-settings/package.js index c6f17e5b597..6ca7c4a9026 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -43,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-chatops/package.js b/packages/rocketchat-chatops/package.js index 2b8585bce63..347f4a3f265 100644 --- a/packages/rocketchat-chatops/package.js +++ b/packages/rocketchat-chatops/package.js @@ -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-github-enterprise/package.js b/packages/rocketchat-github-enterprise/package.js index cca18ff40e3..7031b8a12dc 100644 --- a/packages/rocketchat-github-enterprise/package.js +++ b/packages/rocketchat-github-enterprise/package.js @@ -15,7 +15,7 @@ Package.onUse(function(api) { 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/package.js b/packages/rocketchat-gitlab/package.js index c8a0e62d3a8..6f7b900eddc 100644 --- a/packages/rocketchat-gitlab/package.js +++ b/packages/rocketchat-gitlab/package.js @@ -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-hubot/package.js b/packages/rocketchat-hubot/package.js index 62d91694a3f..213fc5ece22 100644 --- a/packages/rocketchat-hubot/package.js +++ b/packages/rocketchat-hubot/package.js @@ -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/package.js b/packages/rocketchat-integrations/package.js index 06aebfe354d..0f532edc0aa 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -63,6 +63,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-ldap/package.js b/packages/rocketchat-ldap/package.js index f832514eb3d..0f01f0152f0 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -23,7 +23,7 @@ Package.onUse(function(api) { // Commom api.use('rocketchat:lib@0.0.1'); - api.use('tap:i18n@1.5.1'); + api.use('tap:i18n'); api.use('yasaricli:slugify'); api.use('coffeescript'); // Client diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 34e49b1c7f3..78f6a244835 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -107,9 +107,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-livechat/package.js b/packages/rocketchat-livechat/package.js index f9bff5eec15..ba6ad05214e 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -116,7 +116,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-mailer/package.js b/packages/rocketchat-mailer/package.js index 7dd1c4cd5a8..9de07383c65 100644 --- a/packages/rocketchat-mailer/package.js +++ b/packages/rocketchat-mailer/package.js @@ -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-mentions-flextab/package.js b/packages/rocketchat-mentions-flextab/package.js index d52f8ada438..1ae50b98edf 100644 --- a/packages/rocketchat-mentions-flextab/package.js +++ b/packages/rocketchat-mentions-flextab/package.js @@ -37,9 +37,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/package.js b/packages/rocketchat-message-pin/package.js index 1bd59584268..394cc8f875b 100644 --- a/packages/rocketchat-message-pin/package.js +++ b/packages/rocketchat-message-pin/package.js @@ -40,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-star/package.js b/packages/rocketchat-message-star/package.js index 5d8d80da318..f4824b7374f 100644 --- a/packages/rocketchat-message-star/package.js +++ b/packages/rocketchat-message-star/package.js @@ -41,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-slashcommands-invite/package.js b/packages/rocketchat-slashcommands-invite/package.js index a73b9e87f4e..d2192e63018 100644 --- a/packages/rocketchat-slashcommands-invite/package.js +++ b/packages/rocketchat-slashcommands-invite/package.js @@ -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-join/package.js b/packages/rocketchat-slashcommands-join/package.js index 04690ded85c..db31822eeb2 100644 --- a/packages/rocketchat-slashcommands-join/package.js +++ b/packages/rocketchat-slashcommands-join/package.js @@ -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/package.js b/packages/rocketchat-slashcommands-kick/package.js index a5ac2b24a42..11f5dba4a72 100644 --- a/packages/rocketchat-slashcommands-kick/package.js +++ b/packages/rocketchat-slashcommands-kick/package.js @@ -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-mute/package.js b/packages/rocketchat-slashcommands-mute/package.js index adc64c1d6dd..4a45f31978a 100644 --- a/packages/rocketchat-slashcommands-mute/package.js +++ b/packages/rocketchat-slashcommands-mute/package.js @@ -29,9 +29,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-statistics/package.js b/packages/rocketchat-statistics/package.js index 47133065781..753a1086eb5 100644 --- a/packages/rocketchat-statistics/package.js +++ b/packages/rocketchat-statistics/package.js @@ -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-theme/i18n/ro.i18n.json b/packages/rocketchat-theme/i18n/ro.i18n.json index 96f31644dc9..50ee2c3dcd4 100644 --- a/packages/rocketchat-theme/i18n/ro.i18n.json +++ b/packages/rocketchat-theme/i18n/ro.i18n.json @@ -8,7 +8,7 @@ "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-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-secondary-background-color" : "Culoare de fundal secundară", @@ -21,4 +21,4 @@ "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ă" -} \ No newline at end of file +} diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 0cfa009d7ce..027f9d264f3 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-webrtc/package.js b/packages/rocketchat-webrtc/package.js index 5ed915027e3..cd19b3a958b 100644 --- a/packages/rocketchat-webrtc/package.js +++ b/packages/rocketchat-webrtc/package.js @@ -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/package.js b/packages/rocketchat-wordpress/package.js index 6bd7e5d6bf2..fb798631433 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@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'); + api.addFiles(tapi18nFiles); }); Package.onTest(function(api) { -- GitLab From 6a6f8b29a4adb9a813ad490992dbc014f2b238ed Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 29 Dec 2015 19:12:02 -0200 Subject: [PATCH 1054/1338] update aldeed:simple-schema to 1.5.3 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index 11a58480adc..3aa07540ddb 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -7,7 +7,7 @@ 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.2 +aldeed:simple-schema@1.5.3 arunoda:streams@0.1.17 autoupdate@1.2.4 babel-compiler@5.8.24_1 -- GitLab From 4413e968a8603e418262027242882e891a387c9a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 29 Dec 2015 19:23:23 -0200 Subject: [PATCH 1055/1338] chmod 644 --- packages/rocketchat-theme/i18n/en.i18n.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 packages/rocketchat-theme/i18n/en.i18n.json diff --git a/packages/rocketchat-theme/i18n/en.i18n.json b/packages/rocketchat-theme/i18n/en.i18n.json old mode 100755 new mode 100644 -- GitLab From 1ee762e8db2eebf23c27429b8abbffb3f8aa1fa0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 30 Dec 2015 08:44:42 -0200 Subject: [PATCH 1056/1338] fix livechat trigger by url --- packages/rocketchat-livechat/app/client/lib/triggers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/app/client/lib/triggers.js b/packages/rocketchat-livechat/app/client/lib/triggers.js index f9f528cf1b3..a742d469977 100644 --- a/packages/rocketchat-livechat/app/client/lib/triggers.js +++ b/packages/rocketchat-livechat/app/client/lib/triggers.js @@ -54,7 +54,7 @@ this.Triggers = (function() { trigger.conditions.forEach(function(condition) { switch (condition.name) { case 'page-url': - if (request.href.match(new RegExp(urlRegex))) { + if (request.href.match(new RegExp(condition.value))) { fire(trigger.actions); } break; -- GitLab From 8d04d3c2c4fcd47f17359347ef9c138901394d6e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 30 Dec 2015 11:30:14 -0200 Subject: [PATCH 1057/1338] tabbar display/hide rework --- client/routes/adminRouter.coffee | 22 +++++------- client/routes/router.coffee | 9 +++-- client/startup/defaultRoomTypes.coffee | 3 ++ .../client/route.coffee | 3 ++ .../client/startup/tabBar.coffee | 18 ++++------ .../rocketchat-chatops/client/tabBar.coffee | 18 ++++------ .../client/route.coffee | 7 ++-- packages/rocketchat-lib/client/TabBar.coffee | 11 ++++++ .../rocketchat-lib/client/defaultTabBars.js | 35 +++++++++++++++++++ .../rocketchat-lib/client/lib/openRoom.coffee | 13 ++----- packages/rocketchat-lib/package.js | 2 ++ .../rocketchat-mailer/client/router.coffee | 6 +--- .../client/tabBar.coffee | 11 ++++-- .../client/tabBar.coffee | 13 ++++--- .../client/tabBar.coffee | 11 ++++-- .../admin/users/adminUsers.coffee | 29 +++++++++++---- .../admin/users/adminUsers.html | 2 +- .../flex-tab/flexTabBar.coffee | 16 +++++---- .../flex-tab/flexTabBar.html | 2 +- packages/rocketchat-ui/lib/accountBox.coffee | 2 +- .../views/app/privateHistory.coffee | 3 -- packages/rocketchat-ui/views/app/room.coffee | 4 --- 22 files changed, 147 insertions(+), 93 deletions(-) create mode 100644 packages/rocketchat-lib/client/defaultTabBars.js diff --git a/client/routes/adminRouter.coffee b/client/routes/adminRouter.coffee index ee8a4ed0e1e..50543bea309 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 'rooms' 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 74873c70a05..9757366bfa5 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 832cbd2f21c..d22c964cc48 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -11,6 +11,7 @@ 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' ] @@ -24,6 +25,7 @@ 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' ] @@ -37,6 +39,7 @@ 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' ] diff --git a/packages/rocketchat-authorization/client/route.coffee b/packages/rocketchat-authorization/client/route.coffee index fe115fedcff..fce94d5ad7d 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-channel-settings/client/startup/tabBar.coffee b/packages/rocketchat-channel-settings/client/startup/tabBar.coffee index a78fd0ec324..0381dcf755f 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) -> - - RocketChat.TabBar.addButton - id: 'channel-settings' - i18nTitle: 'Room_Info' - icon: 'octicon octicon-info' - 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-chatops/client/tabBar.coffee b/packages/rocketchat-chatops/client/tabBar.coffee index 5daff0a8915..c6e65f4895a 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-integrations/client/route.coffee b/packages/rocketchat-integrations/client/route.coffee index 96c69e02cc1..c5c6311d662 100644 --- a/packages/rocketchat-integrations/client/route.coffee +++ b/packages/rocketchat-integrations/client/route.coffee @@ -1,34 +1,35 @@ 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') diff --git a/packages/rocketchat-lib/client/TabBar.coffee b/packages/rocketchat-lib/client/TabBar.coffee index 237024dbdd7..61209889548 100644 --- a/packages/rocketchat-lib/client/TabBar.coffee +++ b/packages/rocketchat-lib/client/TabBar.coffee @@ -9,6 +9,8 @@ RocketChat.TabBar = new class template = new ReactiveVar '' data = new ReactiveVar {} + visibleGroup = new ReactiveVar '' + setTemplate = (t, callback) -> return if animating is true template.set t @@ -93,6 +95,12 @@ RocketChat.TabBar = new class resetButtons = -> buttons.set {} + showGroup = (group) -> + visibleGroup.set group + + getVisibleGroup = -> + visibleGroup.get() + setTemplate: setTemplate setData: setData getTemplate: getTemplate @@ -108,3 +116,6 @@ RocketChat.TabBar = new class getButtons: getButtons reset: reset resetButtons: resetButtons + + showGroup: showGroup + getVisibleGroup: getVisibleGroup diff --git a/packages/rocketchat-lib/client/defaultTabBars.js b/packages/rocketchat-lib/client/defaultTabBars.js new file mode 100644 index 00000000000..5121374b6d3 --- /dev/null +++ b/packages/rocketchat-lib/client/defaultTabBars.js @@ -0,0 +1,35 @@ +RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'message-search', + i18nTitle: TAPi18n.__('Search'), + icon: 'octicon octicon-search', + template: 'messageSearch', + order: 1 +}); + +RocketChat.TabBar.addButton({ + groups: ['directmessage'], + id: 'members-list', + i18nTitle: TAPi18n.__('User_Info'), + icon: 'octicon octicon-person', + template: 'membersList', + order: 2 +}); + +RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup'], + id: 'members-list', + i18nTitle: TAPi18n.__('Members_List'), + icon: 'octicon octicon-organization', + template: 'membersList', + order: 2 +}); + +RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'uploaded-files-list', + i18nTitle: TAPi18n.__('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 545dce131b8..0d3a594583c 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -50,16 +50,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/package.js b/packages/rocketchat-lib/package.js index f2d0eb226c9..97a7073d0d7 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -96,6 +96,8 @@ Package.onUse(function(api) { api.addFiles('client/TabBar.coffee', 'client'); api.addFiles('client/MessageAction.coffee', 'client'); + api.addFiles('client/defaultTabBars.js', 'client'); + // VERSION api.addFiles('rocketchat.info'); diff --git a/packages/rocketchat-mailer/client/router.coffee b/packages/rocketchat-mailer/client/router.coffee index 5205c1f2a69..4260c1719c3 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-mentions-flextab/client/tabBar.coffee b/packages/rocketchat-mentions-flextab/client/tabBar.coffee index 52c72abdc68..93da941b2ec 100644 --- a/packages/rocketchat-mentions-flextab/client/tabBar.coffee +++ b/packages/rocketchat-mentions-flextab/client/tabBar.coffee @@ -1,4 +1,9 @@ Meteor.startup -> - RocketChat.callbacks.add 'enter-room', -> - RocketChat.TabBar.addButton({ id: 'mentions', i18nTitle: 'Mentions', icon: 'icon-at', template: 'mentionsFlexTab', order: 3 }) - , RocketChat.callbacks.priority.MEDIUM, 'enter-room-tabbar-mentions' + RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup'], + id: 'mentions', + i18nTitle: 'Mentions', + icon: 'icon-at', + template: 'mentionsFlexTab', + order: 3 + }) diff --git a/packages/rocketchat-message-pin/client/tabBar.coffee b/packages/rocketchat-message-pin/client/tabBar.coffee index f4b8d24a66b..1a2e5dc532c 100644 --- a/packages/rocketchat-message-pin/client/tabBar.coffee +++ b/packages/rocketchat-message-pin/client/tabBar.coffee @@ -1,5 +1,10 @@ Meteor.startup -> - RocketChat.callbacks.add 'enter-room', -> - 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' + if RocketChat.settings.get 'Message_AllowPinning' + RocketChat.TabBar.addButton({ + groups: ['channel', 'privategroup', 'directmessage'], + id: 'pinned-messages', + i18nTitle: 'Pinned_Messages', + icon: 'icon-pin', + template: 'pinnedMessages', + order: 10 + }) diff --git a/packages/rocketchat-message-star/client/tabBar.coffee b/packages/rocketchat-message-star/client/tabBar.coffee index b2b2d969d1a..9e34add34ab 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-ui-admin/admin/users/adminUsers.coffee b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee index 098901fb5b2..eb15c19cce5 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: t('Invite_Users'), + icon: 'icon-plus', + template: 'adminInviteUser', + order: 1 + }) + + RocketChat.TabBar.addButton({ + groups: ['adminusers-selected'] + id: 'user-info', + i18nTitle: t('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 828ca152200..aa410e3c987 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-flextab/flex-tab/flexTabBar.coffee b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee index 0177eb907c6..64a3d047751 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee @@ -6,22 +6,26 @@ Template.flexTabBar.helpers return RocketChat.TabBar.getButtons() title: -> return t(@i18nTitle) or @title + visible: -> + if @groups.indexOf(RocketChat.TabBar.getVisibleGroup()) is -1 + # if it was active, close it + if @template is RocketChat.TabBar.getTemplate() and RocketChat.TabBar.isFlexOpen() + RocketChat.TabBar.closeFlex() + 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) diff --git a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.html index 8a971f49990..10baeed54db 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/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index 79e61faff4a..250246a76f4 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -63,6 +63,7 @@ name: newRoute.name action: -> Session.set 'openedRoom' + RocketChat.TabBar.showGroup newRoute.name BlazeLayout.render 'main', routeConfig triggersEnter: [ -> if newRoute.sideNav? @@ -70,7 +71,6 @@ SideNav.openFlex() ] - setStatus: setStatus toggle: toggle open: open diff --git a/packages/rocketchat-ui/views/app/privateHistory.coffee b/packages/rocketchat-ui/views/app/privateHistory.coffee index 97a45d9aca7..b59fdc7c23e 100644 --- a/packages/rocketchat-ui/views/app/privateHistory.coffee +++ b/packages/rocketchat-ui/views/app/privateHistory.coffee @@ -37,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/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 2127c7662af..6e96ec59e2a 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -484,13 +484,9 @@ Template.room.onCreated -> @autorun => @subscribe 'fullUserData', Session.get('showUserInfo'), 1 - Template.room.onDestroyed -> - RocketChat.TabBar.resetButtons() - window.removeEventListener 'resize', this.onWindowResize - Template.room.onRendered -> unless window.chatMessages window.chatMessages = {} -- GitLab From 665da97c28f6f4cf7b12aaa26c65bee9ea11a9ad Mon Sep 17 00:00:00 2001 From: Antoine <AntoineGa@users.noreply.github.com> Date: Wed, 30 Dec 2015 15:48:40 +0100 Subject: [PATCH 1058/1338] Update README.md fix typo on docker tag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ed068e5d15..4169ea44fa4 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ docker pull rocketchat/rocket.chat:develop OR the latest available stable (master) branch code: ``` -docker pull rocketchat/rocket.chat:lastest +docker pull rocketchat/rocket.chat:latest ``` OR our [official docker registry image](https://hub.docker.com/_/rocket.chat/), containing recent MAJOR release: -- GitLab From 147ce2d626a37c462de8592c39d2d8ca54e4067e Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 30 Dec 2015 13:28:37 -0200 Subject: [PATCH 1059/1338] Button to test SMTP settings; No need to reload server for SMTP settings to take effect; Closes #1246 Checks SMTP Settings in #1492 --- i18n/en.i18n.json | 3 ++ packages/rocketchat-lib/package.js | 2 ++ .../server/methods/sendSMTPTestEmail.coffee | 29 +++++++++++++++++++ .../server/startup/settings.coffee | 8 +---- .../server/startup/settingsOnLoadSMTP.coffee | 25 ++++++++++++++++ 5 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee create mode 100644 packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index b38261d54de..45776fd72cb 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -420,6 +420,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.", @@ -446,6 +447,7 @@ "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_of_conversation" : "Start of conversation", @@ -558,5 +560,6 @@ "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_Open_Source_solution" : "Your own Open Source chat solution", + "Your_mail_was_sent_to_s" : "Your mail was sent to %s", "Your_push_was_sent_to_s_devices" : "Your push was sent to %s devices" } diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index f2d0eb226c9..687d35430b4 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -69,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'); @@ -77,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'); diff --git a/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee b/packages/rocketchat-lib/server/methods/sendSMTPTestEmail.coffee new file mode 100644 index 00000000000..d766f129c99 --- /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/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index aab77d73469..8d27a2e6e06 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -96,6 +96,7 @@ RocketChat.settings.addGroup 'SMTP', -> @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' } @@ -162,13 +163,6 @@ RocketChat.settings.add 'Statistics_opt_out', false, { type: 'boolean', group: f 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 00000000000..8047dd24417 --- /dev/null +++ b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee @@ -0,0 +1,25 @@ +buildMailURL = _.debounce -> + console.log 'Updating process.env.MAIL_URL' + if 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')) +, 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() -- GitLab From 8c36dd9bd5d6ef102135bde438a8dfd092a82d4a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 30 Dec 2015 14:58:57 -0200 Subject: [PATCH 1060/1338] use different ids for members info and user info tabbars --- packages/rocketchat-lib/client/defaultTabBars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/client/defaultTabBars.js b/packages/rocketchat-lib/client/defaultTabBars.js index 5121374b6d3..ca8d5803b6a 100644 --- a/packages/rocketchat-lib/client/defaultTabBars.js +++ b/packages/rocketchat-lib/client/defaultTabBars.js @@ -9,7 +9,7 @@ RocketChat.TabBar.addButton({ RocketChat.TabBar.addButton({ groups: ['directmessage'], - id: 'members-list', + id: 'user-info', i18nTitle: TAPi18n.__('User_Info'), icon: 'octicon octicon-person', template: 'membersList', -- GitLab From ad9862160d3d2391c7a7c656df6ec877baafe343 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 30 Dec 2015 14:59:21 -0200 Subject: [PATCH 1061/1338] improved closeFlex logic when switching tabbars --- .../flex-tab/flexTabBar.coffee | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee index 64a3d047751..f308646ffbb 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee @@ -2,15 +2,11 @@ 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 - # if it was active, close it - if @template is RocketChat.TabBar.getTemplate() and RocketChat.TabBar.isFlexOpen() - RocketChat.TabBar.closeFlex() return 'hidden' Template.flexTabBar.events @@ -29,3 +25,18 @@ Template.flexTabBar.events 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() -- GitLab From ade9932b6fc943d7e580caa32b46e20f72da1881 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 30 Dec 2015 17:38:09 -0200 Subject: [PATCH 1062/1338] added visitor info into tabbar --- .../client/lib/ua-parser.js | 8 +++++ .../client/stylesheets/livechat.less | 9 ++++++ packages/rocketchat-livechat/client/ui.js | 14 ++++++++ .../client/views/app/tabbar/visitorInfo.html | 32 +++++++++++++++++++ .../client/views/app/tabbar/visitorInfo.js | 28 ++++++++++++++++ packages/rocketchat-livechat/package.js | 5 +++ .../server/methods/registerGuest.js | 5 +++ .../server/models/Users.js | 13 ++++++++ .../server/publications/visitorInfo.js | 17 ++++++++++ 9 files changed, 131 insertions(+) create mode 100644 packages/rocketchat-livechat/client/lib/ua-parser.js create mode 100644 packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html create mode 100644 packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js create mode 100644 packages/rocketchat-livechat/server/publications/visitorInfo.js 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 00000000000..2f34b32f8f0 --- /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/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index b389c38d398..44b19e5adee 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -437,3 +437,12 @@ height: 24px; } } + +.user-view { + li { + color: #7f7f7f; + line-height: 18px; + font-size: 12px; + font-weight: 300; + } +} diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index f23b438a912..6b4eb3e1e70 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 { @@ -24,3 +25,16 @@ AccountBox.addItem({ sideNav: 'livechatFlex', permissions: ['view-livechat-manager'], }); + +RocketChat.TabBar.addButton({ + groups: ['livechat'], + id: 'visitor-info', + i18nTitle: 'Visitor_Info', + icon: 'icon-chat', + 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/tabbar/visitorInfo.html b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html new file mode 100644 index 00000000000..cfa3865cfa8 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html @@ -0,0 +1,32 @@ +<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> + </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 00000000000..40c70998f46 --- /dev/null +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js @@ -0,0 +1,28 @@ +Template.visitorInfo.helpers({ + user() { + var user = Meteor.users.findOne({ username: 'guest-54' }); + // user.ip = user.ip; + + if (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; + } +}); + +Template.visitorInfo.onCreated(function() { + this.autorun(() => { + this.subscribe('livechat:visitorInfo', Session.get('openedRoom')); + }); +}) diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index ba6ad05214e..d2de8be339a 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -58,6 +58,10 @@ Package.onUse(function(api) { 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'); @@ -99,6 +103,7 @@ Package.onUse(function(api) { api.addFiles('server/publications/livechatManagers.js', 'server'); api.addFiles('server/publications/livechatDepartments.js', 'server'); api.addFiles('server/publications/trigger.js', 'server'); + api.addFiles('server/publications/visitorInfo.js', 'server'); api.addFiles('server/publications/visitorRoom.js', 'server'); // livechat app diff --git a/packages/rocketchat-livechat/server/methods/registerGuest.js b/packages/rocketchat-livechat/server/methods/registerGuest.js index 1187eae6ef3..8f306afa9cf 100644 --- a/packages/rocketchat-livechat/server/methods/registerGuest.js +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -38,6 +38,11 @@ Meteor.methods({ 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 = { diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index a485e921c2f..e6046e8ba95 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -84,3 +84,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/visitorInfo.js b/packages/rocketchat-livechat/server/publications/visitorInfo.js new file mode 100644 index 00000000000..a4fe7a17761 --- /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(); + } +}); -- GitLab From ce36665d8cc6de2ed5d7c7922993a2889ec3eacb Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 30 Dec 2015 18:08:07 -0200 Subject: [PATCH 1063/1338] fix when don't get user data --- .../rocketchat-livechat/client/views/app/tabbar/visitorInfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js index 40c70998f46..a1ffa11ce09 100644 --- a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js @@ -3,7 +3,7 @@ Template.visitorInfo.helpers({ var user = Meteor.users.findOne({ username: 'guest-54' }); // user.ip = user.ip; - if (user.userAgent) { + if (user && user.userAgent) { var ua = new UAParser(); ua.setUA(user.userAgent); -- GitLab From a65224739a66eeddcd89ea6cb254758ca7affacd Mon Sep 17 00:00:00 2001 From: jeffreywescott <jeffrey@learnersguild.org> Date: Wed, 30 Dec 2015 12:57:58 -0800 Subject: [PATCH 1064/1338] add a setting to disable form-based login --- i18n/en.i18n.json | 1 + i18n/fi.i18n.json | 3 ++- i18n/pl.i18n.json | 3 ++- i18n/pt.i18n.json | 3 ++- i18n/ro.i18n.json | 3 ++- packages/rocketchat-lib/server/startup/settings.coffee | 1 + packages/rocketchat-ui-login/login/form.coffee | 3 +++ packages/rocketchat-ui-login/login/form.html | 2 ++ 8 files changed, 15 insertions(+), 4 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e70ed2ba3b4..551fee78338 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -61,6 +61,7 @@ "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", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 6170d15aa97..d698ecaa267 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -61,6 +61,7 @@ "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ä lomake Kirjaudu", "Activate" : "Aktivoi", "Add_custom_oauth" : "Lisää mukautettu oauth", "Add_Members" : "Lisää osallistujia", @@ -523,4 +524,4 @@ "Your_entry_has_been_deleted" : "Your entry has been deleted.", "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/pl.i18n.json b/i18n/pl.i18n.json index 040ad0cf694..8dedcd4e377 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -58,6 +58,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", @@ -463,4 +464,4 @@ "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" -} \ No newline at end of file +} diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index e0b6c02842d..2aaa4c39680 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", @@ -457,4 +458,4 @@ "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source", "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" -} \ No newline at end of file +} diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index 659ff4c29e0..f40860aaddb 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -61,6 +61,7 @@ "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", @@ -546,4 +547,4 @@ "Your_entry_has_been_deleted" : "Mesajul dumneavoastră a fost È™ters.", "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/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index aab77d73469..ba16ea2d802 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -9,6 +9,7 @@ RocketChat.settings.addGroup 'Accounts', -> @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 } diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 52ef48d4bcb..4296da4fc17 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' diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index 575459711cf..bb7a0f024f8 100644 --- a/packages/rocketchat-ui-login/login/form.html +++ b/packages/rocketchat-ui-login/login/form.html @@ -18,6 +18,7 @@ {{_ "You_need_confirm_email"}} </div> {{/if}} + {{#if showFormLogin}} <div class="fields"> <div class='input-text active {{showName}}'> <input type="text" name='name' placeholder='{{namePlaceholder}}' dir="auto" /> @@ -38,6 +39,7 @@ <div class="submit"> <button data-loading-text="{{_ "Please_wait"}}..." class='button primary login'><span>{{btnLoginSave}}</span></button> </div> + {{/if}} {{#if registrationAllowed}} <div class="register {{showRegisterLink}}"> <a href="">{{_ 'Register'}}</a> -- GitLab From 7c31b56a22b6e3e734af86e81f0334fc1ef2cb9f Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Thu, 31 Dec 2015 00:50:46 -0500 Subject: [PATCH 1065/1338] upload build artifacts to GitHub and sign tgz for docker images --- .travis.yml | 38 +++++++++++++++++++++++--------------- .travis/namefiles.sh | 8 +++++--- .travis/sandstorm.sh | 2 +- .travis/setbranch.sh | 3 +++ .travis/setdeploydir.sh | 2 ++ .travis/setupsig.sh | 8 ++++++++ .travis/sign.key.gpg | Bin 0 -> 5119 bytes 7 files changed, 42 insertions(+), 19 deletions(-) create mode 100755 .travis/setbranch.sh create mode 100755 .travis/setdeploydir.sh create mode 100755 .travis/setupsig.sh create mode 100644 .travis/sign.key.gpg diff --git a/.travis.yml b/.travis.yml index 6d5742f1429..045e1423f99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,14 @@ branches: only: - develop - master + - /^v(\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 +22,24 @@ before_script: script: - meteor build /tmp/build before_deploy: -- mkdir /tmp/deploy -- .travis/namefiles.sh -- .travis/sandstorm.sh +- source ".travis/setbranch.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: releases + api_key: + secure: SLtbGv9vL6qC3rKGwKuXfUSFuRCeLsBFiRA1nBDWoyua7F3rLy8fBvhS3sXRDCqAF6hJgXQwZzX2pS1Lljwjjmwi/80Ns7VDtreX5QstHukFAxaJh2E0Lz5zQdSqAb61KdAipZmYfp2fgCr8T+xztE/mvtPD5R8CcIQIjJpl9rh+mrkkshkcaNOY4JQrqyrcTeCOeBQMXTZSkkbdJr4gb9++A2c61K0txfid9+VwqGm5MwvaT80JC5wLQkL8rS9OUcNJHFf90ELFZpRZnZnI2lsfmTBAxRKL994UZgzru3XNMhUTsJPh7OyVn/xSlyjLcvsn4dSon1PE9t3RkuxsbTxx/XY+gIkXSGl38jZlhextaJoV0gTFkEg33tF/aZ4+I+iZM8LYfRAoUuZU0fSzGnFtFZp4xptF2ECLKmI/3dmuE6iwr+G1xUer9g2Rq9fXXrHgUA164544IdY4aDisxd9U78U0K7WaPtbvphiVl4GbgVnfTEgNVdpXcQxUtcXPZMiBRz5+E+1fExmCfO6+7mZ/yzDrsFYoRdmuo1SMGRI4iqb5jl/PImZ9ukTqRmQdqd3WJp3zzPbIEJPwhMtS5LMxzBMSfugXwjEajkXybcH5CWQ7jo+ogNqcM/CcJ3q4ahYuLTN7VeZWZ8h5kwr9bPxPooZuhWw0WPRa+XUM22o= + file: + - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" + - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz.asc" + - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.spk" + on: + tags: true + all_branches: true after_deploy: -- .travis/docker.sh +- ".travis/docker.sh" +env: + global: + secure: y9LYMUBDtiAUlIwJEvubBrYLVrjPsPg7ClY5HcFisdm7OwOzMqHcjTFX8Sj2tN/6IXNcZLqFOhHcwuSdM0uUbBIDooTVnwMVSIy6ExZFOaZNrvAf/Axf2k6p15iAmtPmVo7o+us5SRVRQvuP6GqdUPMYIYn71jHrrjUKQp3/hgRZBlpIn7dyPs5WuLVXZda5hVjIjJpSfK1RZDoGd/b7o8jywvFgSdvBiB+lX1VXCVisRJU9yS28CGIcpoxeQg9AFk4Uez6+8+b/koLp3imQddY9VjYyYx2D8fNxRcUujUHux24VG5MSzQRtJh9JwLlJ+pyAN1KUSvoam6R3MQGoKJg0AH3UxikmSQ4yGZwsSkPSqWbRCRgSVmNtq/YLuTJjQEUHmMCxXUb53HdJisAaxaQiOfg/IfqMVtUWeeIfSDDNEhO9WgpuNvf4fOltdwlL2N1YwubR/fGw8/W/to9jSu94FxJHw6c2V4KQOJqq1XA+KtwMMYak82NjfS2DIhcwyf4EaKagkg4HD3z5BYpuxQdeQnkQkvvkvkI26kV+jPkqUGRlejS7AXG4PrhcUUf/nBvvWjUFrLwvk+epkMP3D2k94r2XUl7apyrANTfyTVyOCc1ogUu9N2XC4ShF2uxu5hoNxk+hNTo1D7uSrFE7aM1GpDFRPOUjtpt2E0mqOoQ= diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index 4848dea2b11..18d2dc26da6 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,7 +1,9 @@ -#!/bin/bash -set -euo pipefail +#!/bin/bash +set -xeuo 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" +cp /tmp/build/Rocket.Chat.tar.gz "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" +gpg --armor --detach-sign "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" +ls -l $ROCKET_DEPLOY_DIR diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 43250534b7e..4c74593ac06 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-$ROCKET_BRANCH.spk diff --git a/.travis/setbranch.sh b/.travis/setbranch.sh new file mode 100755 index 00000000000..cb6a3d7c7a0 --- /dev/null +++ b/.travis/setbranch.sh @@ -0,0 +1,3 @@ +export ROCKET_BRANCH="master" +echo $ROCKET_BRANCH + diff --git a/.travis/setdeploydir.sh b/.travis/setdeploydir.sh new file mode 100755 index 00000000000..2c49e4a7027 --- /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 00000000000..72bcd8ade04 --- /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..6f149e0d544a3242e489f9f0babf3b6bb92a65a1 GIT binary patch literal 5119 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 literal 0 HcmV?d00001 -- GitLab From edac1b020f689f51f193b781ba1ca1e0331c6cca Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 31 Dec 2015 18:08:15 -0200 Subject: [PATCH 1066/1338] Fix title of custom oauth in admin --- packages/rocketchat-ui-admin/admin/admin.coffee | 6 ++++++ packages/rocketchat-ui-admin/admin/admin.html | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 8c3105542a4..f13e0941b6e 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -74,6 +74,12 @@ Template.admin.helpers 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: -> diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index beeafd6a11d..07089f30947 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> -- GitLab From acf996f8f92e1667c524a373731af99d46494789 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 31 Dec 2015 18:08:52 -0200 Subject: [PATCH 1067/1338] Add option to select the login style of custom oauth --- i18n/en.i18n.json | 1 + packages/rocketchat-lib/server/methods/addOAuthService.coffee | 1 + .../rocketchat-lib/server/startup/oAuthServicesUpdate.coffee | 2 ++ 3 files changed, 4 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index b38261d54de..005e306eb02 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -26,6 +26,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", diff --git a/packages/rocketchat-lib/server/methods/addOAuthService.coffee b/packages/rocketchat-lib/server/methods/addOAuthService.coffee index 0a8a28070c7..b115a6d4bb3 100644 --- a/packages/rocketchat-lib/server/methods/addOAuthService.coffee +++ b/packages/rocketchat-lib/server/methods/addOAuthService.coffee @@ -15,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/startup/oAuthServicesUpdate.coffee b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee index eb796abc309..75b30d643e2 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 -- GitLab From 2ba6612f98cb2f0ea7e1ddd70888ce30039f076c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 31 Dec 2015 19:07:02 -0200 Subject: [PATCH 1068/1338] Add option to render main view as modal --- .../rocketchat-theme/assets/stylesheets/base.less | 4 ++++ packages/rocketchat-ui-master/master/main.html | 14 +++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index a13cb98307b..1afa2f4913e 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1726,6 +1726,10 @@ a.github-fork { .transform(translateX(0)); } } + &.main-modal { + left: 0px; + margin-right: 0px; + } .container-fluid { padding-top: 0; } diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index e8229fc6d27..27828f551fc 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -56,13 +56,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}} -- GitLab From 6c6801af0b5ffb942bb4e342e34c3b93c043f68a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 31 Dec 2015 19:07:26 -0200 Subject: [PATCH 1069/1338] Do not try to parse requests with content type --- packages/rocketchat-cors/cors.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index 971777d4952..38e411e857b 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -8,6 +8,9 @@ WebApp.rawConnectHandlers.use (req, res, 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 @@ -20,6 +23,7 @@ WebApp.rawConnectHandlers.use (req, res, next) -> catch err req.body = buf + req._body = true next() -- GitLab From 51e44fa408372e71d6cb48c9a67031c5b5e913d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 31 Dec 2015 19:08:34 -0200 Subject: [PATCH 1070/1338] Add oauth2-server and oauth2-server-config --- .meteor/packages | 1 + .meteor/versions | 2 ++ .../.gitignore | 1 + .../client/oauth2-client.coffee | 25 +++++++++++++++++++ .../client/oauth2-client.html | 18 +++++++++++++ .../package.js | 21 ++++++++++++++++ .../server/oauth2-server.coffee | 22 ++++++++++++++++ 7 files changed, 90 insertions(+) create mode 100644 packages/rocketchat-oauth2-server-config/.gitignore create mode 100644 packages/rocketchat-oauth2-server-config/client/oauth2-client.coffee create mode 100644 packages/rocketchat-oauth2-server-config/client/oauth2-client.html create mode 100644 packages/rocketchat-oauth2-server-config/package.js create mode 100644 packages/rocketchat-oauth2-server-config/server/oauth2-server.coffee diff --git a/.meteor/packages b/.meteor/packages index 2e0df8c465d..fe4fe62442a 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -34,6 +34,7 @@ session spacebars standard-minifiers tracker +rocketchat:oauth2-server-config arunoda:streams rocketchat:lib diff --git a/.meteor/versions b/.meteor/versions index 3aa07540ddb..e9490c2bc1f 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -147,6 +147,8 @@ 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.0.1 +rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 diff --git a/packages/rocketchat-oauth2-server-config/.gitignore b/packages/rocketchat-oauth2-server-config/.gitignore new file mode 100644 index 00000000000..677a6fc2637 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/.gitignore @@ -0,0 +1 @@ +.build* diff --git a/packages/rocketchat-oauth2-server-config/client/oauth2-client.coffee b/packages/rocketchat-oauth2-server-config/client/oauth2-client.coffee new file mode 100644 index 00000000000..32b83f95637 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/client/oauth2-client.coffee @@ -0,0 +1,25 @@ +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 + + +Template.authorize.onCreated -> + @subscribe 'authorizedOAuth' + + +Template.authorize.helpers + getToken: -> + return localStorage.getItem('Meteor.loginToken') + + +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/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/client/oauth2-client.html new file mode 100644 index 00000000000..11ab80a236a --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/client/oauth2-client.html @@ -0,0 +1,18 @@ +<template name="authorize"> + {{#if currentUser}} + <form method="post" action="" role="form" class="{{#unless Template.subscriptionsReady}}hidden{{/unless}}"> + <h2>Authorise</h2> + <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"> + <button type="submit">Authorise</button> + </form> + {{#unless Template.subscriptionsReady}} + loading + {{/unless}} + {{else}} + {{> loginButtons}} + {{/if}} +</template> diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js new file mode 100644 index 00000000000..5ae15157447 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -0,0 +1,21 @@ +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:oauth2-server'); + + api.use('templating', 'client'); + api.use('kadira:flow-router', 'client'); + + api.addFiles('server/oauth2-server.coffee', 'server'); + + api.addFiles('client/oauth2-client.html', 'client'); + api.addFiles('client/oauth2-client.coffee', 'client'); +}); diff --git a/packages/rocketchat-oauth2-server-config/server/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/server/oauth2-server.coffee new file mode 100644 index 00000000000..855abbcb08c --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/server/oauth2-server.coffee @@ -0,0 +1,22 @@ +oauth2server = new OAuth2Server + accessTokensCollectionName: 'rocketchat-oauth-access-tokens' + refreshTokensCollectionName: 'rocketchat-oauth-refresh-tokens' + clientsCollectionName: 'rocketchat-oauth-clients' + authCodesCollectionName: 'rocketchat-oauth-auth-codes' + debug: true + +WebApp.rawConnectHandlers.use oauth2server.app +# JsonRoutes.Middleware.use oauth2server.app + +if not oauth2server.model.Clients.findOne() + oauth2server.model.Clients.insert + clientId: 'papers3' + clientSecret: '123' + redirectUri: 'http://localhost:3000/_oauth/rc' + +oauth2server.routes.get '/account', oauth2server.oauth.authorise(), (req, res, next) -> + user = Meteor.users.findOne req.user.id + + res.send + id: user._id + name: user.name -- GitLab From 6046439b2b287c979a905b53dda56ae28431b75d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 09:04:16 -0200 Subject: [PATCH 1071/1338] add group to tabbar buttons --- packages/rocketchat-lib/client/TabBar.coffee | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/rocketchat-lib/client/TabBar.coffee b/packages/rocketchat-lib/client/TabBar.coffee index 61209889548..5228f2e5502 100644 --- a/packages/rocketchat-lib/client/TabBar.coffee +++ b/packages/rocketchat-lib/client/TabBar.coffee @@ -4,6 +4,8 @@ RocketChat.TabBar = new class buttons = new ReactiveVar {} + extraGroups = {} + animating = false open = new ReactiveVar false template = new ReactiveVar '' @@ -67,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) -> @@ -101,6 +109,17 @@ RocketChat.TabBar = new class 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 @@ -119,3 +138,4 @@ RocketChat.TabBar = new class showGroup: showGroup getVisibleGroup: getVisibleGroup + addGroup: addGroup -- GitLab From 114aa95048f31c8b0e39e746556a1f59583b8504 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 11:20:06 -0200 Subject: [PATCH 1072/1338] get and check roomTypes at template level --- .../rocketchat-lib/client/lib/roomTypes.coffee | 13 +++++++++++-- .../side-nav/sideNav.coffee | 17 ++++++++++------- .../rocketchat-ui-sidenav/side-nav/sideNav.html | 6 ++++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index 2e3773a8122..0b7d6c541f4 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ b/packages/rocketchat-lib/client/lib/roomTypes.coffee @@ -58,12 +58,17 @@ RocketChat.roomTypes = new class return FlowRouter.path roomTypes[roomType].route.name, roomTypes[roomType].route.link(subData) + checkPermission = (roomType) -> + return not roomType.permissions? or RocketChat.authz.hasAtLeastOnePermission roomType.permissions + + checkCondition = (roomType) -> + return not roomType.condition? or roomType.condition() + getAllTypes = -> typesPermitted = [] _.sortBy(roomTypesOrder, 'order').forEach (type) -> - if not roomTypes[type.identifier].permissions? or RocketChat.authz.hasAtLeastOnePermission roomTypes[type.identifier].permissions - typesPermitted.push roomTypes[type.identifier] + typesPermitted.push roomTypes[type.identifier] return typesPermitted @@ -85,4 +90,8 @@ RocketChat.roomTypes = new class # setRoute: setRoute getRouteLink: getRouteLink + checkCondition: checkCondition + + checkPermission: checkPermission + add: add diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 1f6f5958a07..07a1ecb3cde 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -14,6 +14,16 @@ Template.sideNav.helpers return true if favoritesEnabled and hasFavoriteRoomOpened + roomType: -> + console.log 'roomType ->',RocketChat.roomTypes.getTypes() + return RocketChat.roomTypes.getTypes() + + canShowRoomType: -> + return RocketChat.roomTypes.checkPermission(@) and RocketChat.roomTypes.checkCondition(@) + + templateName: -> + return @template + Template.sideNav.events 'click .close-flex': -> SideNav.closeFlex() @@ -36,10 +46,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 80b0454af9c..20446d87f20 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> -- GitLab From 30bf990cb34e61816e3a071d28285177c9341f96 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 13:11:36 -0200 Subject: [PATCH 1073/1338] removed permission paremeter from roomTypes and accountBox now it only on `condition` parameter which implements their own logic, including checking for permission =) --- client/startup/defaultRoomTypes.coffee | 9 ++++--- packages/rocketchat-lib/README.md | 20 +++++---------- .../client/lib/roomTypes.coffee | 25 +++---------------- packages/rocketchat-livechat/client/ui.js | 8 ++++-- .../side-nav/sideNav.coffee | 2 +- packages/rocketchat-ui/lib/accountBox.coffee | 5 +++- 6 files changed, 27 insertions(+), 42 deletions(-) diff --git a/client/startup/defaultRoomTypes.coffee b/client/startup/defaultRoomTypes.coffee index 832cbd2f21c..b4fc8f3b6c6 100644 --- a/client/startup/defaultRoomTypes.coffee +++ b/client/startup/defaultRoomTypes.coffee @@ -13,7 +13,8 @@ RocketChat.roomTypes.add 'c', 10, openRoom 'c', params.name 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' @@ -26,7 +27,8 @@ RocketChat.roomTypes.add 'd', 20, openRoom 'd', params.username 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' @@ -39,4 +41,5 @@ RocketChat.roomTypes.add 'p', 30, openRoom 'p', params.name link: (sub) -> return { name: sub.name } - permissions: [ 'view-p-room' ] + condition: -> + return RocketChat.authz.hasAllPermission 'view-p-room' diff --git a/packages/rocketchat-lib/README.md b/packages/rocketchat-lib/README.md index 6bd81b7d793..68ab59d17c7 100644 --- a/packages/rocketchat-lib/README.md +++ b/packages/rocketchat-lib/README.md @@ -66,7 +66,9 @@ RocketChat.roomTypes.add('l', 5, { return { name: sub.name } } }, - permissions: [ 'view-l-room' ] + condition: () => { + return RocketChat.authz.hasAllPermission('view-l-room'); + } }); ``` @@ -95,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/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee index 0b7d6c541f4..02843ea4702 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,19 +46,16 @@ RocketChat.roomTypes = new class return FlowRouter.path roomTypes[roomType].route.name, roomTypes[roomType].route.link(subData) - checkPermission = (roomType) -> - return not roomType.permissions? or RocketChat.authz.hasAtLeastOnePermission roomType.permissions - checkCondition = (roomType) -> return not roomType.condition? or roomType.condition() getAllTypes = -> - typesPermitted = [] + orderedTypes = [] _.sortBy(roomTypesOrder, 'order').forEach (type) -> - typesPermitted.push roomTypes[type.identifier] + orderedTypes.push roomTypes[type.identifier] - return typesPermitted + return orderedTypes getIcon = (roomType) -> return roomTypes[roomType]?.icon @@ -92,6 +77,4 @@ RocketChat.roomTypes = new class checkCondition: checkCondition - checkPermission: checkPermission - add: add diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index f23b438a912..a2fc414d9f1 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -14,7 +14,9 @@ RocketChat.roomTypes.add('l', 5, { } } }, - permissions: ['view-l-room'] + condition: () => { + return RocketChat.settings.get('Livechat_enabled') && RocketChat.authz.hasAllPermission('view-l-room'); + } }); AccountBox.addItem({ @@ -22,5 +24,7 @@ AccountBox.addItem({ icon: 'icon-chat-empty', href: 'livechat-users', sideNav: 'livechatFlex', - permissions: ['view-livechat-manager'], + condition: () => { + return RocketChat.settings.get('Livechat_enabled') && RocketChat.authz.hasAllPermission('view-livechat-manager'); + }, }); diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 07a1ecb3cde..7f7b55970dc 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -19,7 +19,7 @@ Template.sideNav.helpers return RocketChat.roomTypes.getTypes() canShowRoomType: -> - return RocketChat.roomTypes.checkPermission(@) and RocketChat.roomTypes.checkCondition(@) + return RocketChat.roomTypes.checkCondition(@) templateName: -> return @template diff --git a/packages/rocketchat-ui/lib/accountBox.coffee b/packages/rocketchat-ui/lib/accountBox.coffee index 79e61faff4a..2f33fe14207 100644 --- a/packages/rocketchat-ui/lib/accountBox.coffee +++ b/packages/rocketchat-ui/lib/accountBox.coffee @@ -41,9 +41,12 @@ 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, router = FlowRouter) -> -- GitLab From 1e93b16396ba89645aea8a37e19f332ae1c75df2 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 13:12:48 -0200 Subject: [PATCH 1074/1338] disabling livechat by default --- packages/rocketchat-livechat/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/config.js b/packages/rocketchat-livechat/config.js index fe222ec585f..424768e39a9 100644 --- a/packages/rocketchat-livechat/config.js +++ b/packages/rocketchat-livechat/config.js @@ -2,6 +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' }); }); -- GitLab From 52b72a5ef8fd6f1ae42a51ddbf9ee1b2a20f15af Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 13:13:01 -0200 Subject: [PATCH 1075/1338] adding livechat package as default --- .meteor/packages | 2 +- .meteor/versions | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index 2e0df8c465d..d045992b1c4 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -83,7 +83,7 @@ rocketchat:wordpress #rocketchat:chatops #rocketchat:hubot #rocketchat:irc -#rocketchat:livechat +rocketchat:livechat konecty:change-case konecty:delayed-task diff --git a/.meteor/versions b/.meteor/versions index 3aa07540ddb..5124ef1fc47 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -138,6 +138,7 @@ 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 -- GitLab From 4c03559baf16d89bb0e94ab101a0f7be5f540e2a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 13:13:47 -0200 Subject: [PATCH 1076/1338] code cleanup --- packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee index 7f7b55970dc..8b1bfb25b6c 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/sideNav.coffee @@ -15,7 +15,6 @@ Template.sideNav.helpers return true if favoritesEnabled and hasFavoriteRoomOpened roomType: -> - console.log 'roomType ->',RocketChat.roomTypes.getTypes() return RocketChat.roomTypes.getTypes() canShowRoomType: -> -- GitLab From 39265137c03d04ae2a850d0d04ca0b724b1cf74c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 4 Jan 2016 13:32:08 -0200 Subject: [PATCH 1077/1338] Hide registration and forgot password links when hidding login form --- packages/rocketchat-ui-login/login/form.html | 58 ++++++++++---------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index bb7a0f024f8..f6abf99633f 100644 --- a/packages/rocketchat-ui-login/login/form.html +++ b/packages/rocketchat-ui-login/login/form.html @@ -19,38 +19,40 @@ </div> {{/if}} {{#if showFormLogin}} - <div class="fields"> - <div class='input-text active {{showName}}'> - <input type="text" name='name' placeholder='{{namePlaceholder}}' dir="auto" /> + <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}} - {{#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}}"> -- GitLab From ab69fdd575521ec1611c83848a77fbd63161bc8f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 14:09:19 -0200 Subject: [PATCH 1078/1338] fix getting livechat agent with no department --- .../server/models/LivechatDepartmentAgents.js | 10 +++++++++- packages/rocketchat-livechat/server/models/Users.js | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js index a4d56fa7ba8..551a00e1aeb 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js @@ -64,7 +64,15 @@ class LivechatDepartmentAgents extends RocketChat.models._Base { var collectionObj = this.model.rawCollection(); var findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj); - return findAndModify(query, sort, update); + var agent = findAndModify(query, sort, update); + if (agent) { + return { + agentId: agent.agentId, + username: agent.username + } + } else { + return null; + } } } diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index a485e921c2f..0c3d85af0a0 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -69,7 +69,15 @@ RocketChat.models.Users.getNextAgent = function() { } }; - return findAndModify(query, sort, update); + var user = findAndModify(query, sort, update); + if (user) { + return { + agentId: user._id, + username: user.username + } + } else { + return null; + } }; /** -- GitLab From cf424cb67e595e77486ab12bd668298525683c09 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 4 Jan 2016 14:19:06 -0200 Subject: [PATCH 1079/1338] Settings: unset section if none is given on update --- packages/rocketchat-lib/server/functions/settings.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index a0e48bade8a..fc9df927563 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -35,12 +35,18 @@ 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 -- GitLab From 423a0918ce07bde1c906f570681065e382b093bc Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 4 Jan 2016 16:29:52 +0000 Subject: [PATCH 1080/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 201 +++++- i18n/de.i18n.json | 612 +++++++++++------- i18n/en.i18n.json | 4 +- i18n/fi.i18n.json | 2 +- i18n/fr.i18n.json | 149 ++++- i18n/he.i18n.json | 16 +- i18n/hr.i18n.json | 29 + i18n/km.i18n.json | 5 + i18n/nl.i18n.json | 38 ++ i18n/pl.i18n.json | 11 +- i18n/pt.i18n.json | 2 +- i18n/ro.i18n.json | 28 +- i18n/sq.i18n.json | 123 +++- .../i18n/ar.i18n.json | 8 +- .../i18n/cs.i18n.json | 4 +- .../i18n/de.i18n.json | 18 +- .../i18n/el.i18n.json | 1 - .../i18n/en.i18n.json | 1 - .../i18n/es.i18n.json | 1 - .../i18n/fi.i18n.json | 1 - .../i18n/fr.i18n.json | 1 - .../i18n/he.i18n.json | 3 +- .../i18n/hr.i18n.json | 13 +- .../i18n/hu.i18n.json | 1 - .../i18n/it.i18n.json | 1 - .../i18n/ja.i18n.json | 1 - .../i18n/km.i18n.json | 1 - .../i18n/ko.i18n.json | 1 - .../i18n/ku.i18n.json | 1 - .../i18n/ms-MY.i18n.json | 1 - .../i18n/nl.i18n.json | 1 - .../i18n/pl.i18n.json | 13 +- .../i18n/pt.i18n.json | 1 - .../i18n/ro.i18n.json | 1 - .../i18n/ru.i18n.json | 1 - .../i18n/sq.i18n.json | 4 +- .../i18n/sr.i18n.json | 1 - .../i18n/sv.i18n.json | 4 +- .../i18n/ta-IN.i18n.json | 1 - .../i18n/tr.i18n.json | 1 - .../i18n/ug.i18n.json | 1 - .../i18n/uk.i18n.json | 1 - .../i18n/zh.i18n.json | 1 - .../i18n/ar.i18n.json | 6 + .../i18n/cs.i18n.json | 1 + .../i18n/de.i18n.json | 16 + .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 32 +- .../i18n/es.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 1 + .../i18n/fr.i18n.json | 14 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 8 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 1 + .../i18n/ko.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 1 + .../i18n/ro.i18n.json | 16 + .../i18n/ru.i18n.json | 1 + .../i18n/sq.i18n.json | 1 + .../i18n/sr.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + .../i18n/ar.i18n.json | 14 +- .../i18n/cs.i18n.json | 4 +- .../i18n/de.i18n.json | 14 +- .../i18n/el.i18n.json | 4 +- .../i18n/en.i18n.json | 26 +- .../i18n/es.i18n.json | 4 +- .../i18n/fi.i18n.json | 3 +- .../i18n/fr.i18n.json | 14 +- .../i18n/he.i18n.json | 4 +- .../i18n/hr.i18n.json | 7 +- .../i18n/hu.i18n.json | 4 +- .../i18n/it.i18n.json | 4 +- .../i18n/ja.i18n.json | 4 +- .../i18n/km.i18n.json | 6 +- .../i18n/ko.i18n.json | 3 +- .../i18n/ku.i18n.json | 4 +- .../i18n/ms-MY.i18n.json | 4 +- .../i18n/nl.i18n.json | 9 +- .../i18n/pl.i18n.json | 3 +- .../i18n/pt.i18n.json | 3 +- .../i18n/ro.i18n.json | 13 +- .../i18n/ru.i18n.json | 4 +- .../i18n/sq.i18n.json | 4 +- .../i18n/sr.i18n.json | 4 +- .../i18n/sv.i18n.json | 4 +- .../i18n/ta-IN.i18n.json | 4 +- .../i18n/tr.i18n.json | 4 +- .../i18n/ug.i18n.json | 4 +- .../i18n/uk.i18n.json | 4 +- .../i18n/zh.i18n.json | 4 +- packages/rocketchat-chatops/i18n/de.i18n.json | 5 +- packages/rocketchat-chatops/i18n/fr.i18n.json | 3 +- .../i18n/ar.i18n.json | 4 +- .../i18n/de.i18n.json | 8 +- .../i18n/fr.i18n.json | 5 +- packages/rocketchat-gitlab/i18n/de.i18n.json | 2 +- packages/rocketchat-hubot/i18n/de.i18n.json | 6 +- packages/rocketchat-ldap/i18n/de.i18n.json | 2 +- packages/rocketchat-lib/i18n/ar.i18n.json | 6 +- packages/rocketchat-lib/i18n/de.i18n.json | 5 +- packages/rocketchat-lib/i18n/fr.i18n.json | 4 +- packages/rocketchat-lib/i18n/nl.i18n.json | 6 +- .../rocketchat-livechat/app/i18n/ar.i18n.json | 3 +- .../rocketchat-livechat/app/i18n/de.i18n.json | 17 +- .../rocketchat-livechat/app/i18n/en.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/fr.i18n.json | 15 +- .../rocketchat-livechat/app/i18n/hr.i18n.json | 2 + .../rocketchat-livechat/app/i18n/nl.i18n.json | 16 +- .../rocketchat-livechat/app/i18n/ro.i18n.json | 1 + .../rocketchat-livechat/i18n/ar.i18n.json | 15 +- .../rocketchat-livechat/i18n/de.i18n.json | 56 +- .../rocketchat-livechat/i18n/en.i18n.json | 2 +- .../rocketchat-livechat/i18n/fr.i18n.json | 25 +- .../rocketchat-livechat/i18n/hr.i18n.json | 15 +- .../rocketchat-livechat/i18n/nl.i18n.json | 34 +- .../rocketchat-livechat/i18n/pl.i18n.json | 7 +- .../rocketchat-livechat/i18n/ro.i18n.json | 5 + packages/rocketchat-mailer/i18n/ar.i18n.json | 10 +- packages/rocketchat-mailer/i18n/de.i18n.json | 20 +- packages/rocketchat-mailer/i18n/fr.i18n.json | 15 +- packages/rocketchat-mailer/i18n/hr.i18n.json | 7 +- packages/rocketchat-mailer/i18n/km.i18n.json | 12 +- .../i18n/de.i18n.json | 5 +- .../i18n/fr.i18n.json | 5 +- .../i18n/nl.i18n.json | 5 +- .../rocketchat-message-pin/i18n/ar.i18n.json | 3 + .../rocketchat-message-pin/i18n/de.i18n.json | 9 +- .../rocketchat-message-pin/i18n/fr.i18n.json | 9 +- .../rocketchat-message-pin/i18n/km.i18n.json | 8 +- .../rocketchat-message-star/i18n/de.i18n.json | 10 +- .../rocketchat-message-star/i18n/hr.i18n.json | 3 +- .../i18n/de.i18n.json | 6 +- .../i18n/hr.i18n.json | 6 +- .../i18n/ar.i18n.json | 4 +- .../i18n/de.i18n.json | 2 +- .../i18n/fr.i18n.json | 3 +- .../i18n/hr.i18n.json | 4 +- .../i18n/ar.i18n.json | 4 +- .../i18n/de.i18n.json | 6 +- .../i18n/fr.i18n.json | 6 +- .../i18n/hr.i18n.json | 6 +- .../i18n/nl.i18n.json | 6 +- .../i18n/ar.i18n.json | 5 +- .../i18n/de.i18n.json | 5 +- .../i18n/fr.i18n.json | 5 +- .../i18n/nl.i18n.json | 5 +- packages/rocketchat-theme/i18n/ar.i18n.json | 3 +- packages/rocketchat-theme/i18n/de.i18n.json | 32 +- packages/rocketchat-theme/i18n/en.i18n.json | 2 +- packages/rocketchat-theme/i18n/fr.i18n.json | 24 +- packages/rocketchat-theme/i18n/km.i18n.json | 7 +- packages/rocketchat-theme/i18n/nl.i18n.json | 4 +- packages/rocketchat-theme/i18n/ro.i18n.json | 11 +- packages/rocketchat-webrtc/i18n/ar.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/de.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/fr.i18n.json | 6 +- .../rocketchat-wordpress/i18n/de.i18n.json | 8 +- .../rocketchat-wordpress/i18n/fr.i18n.json | 2 +- 173 files changed, 1700 insertions(+), 490 deletions(-) create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/cs.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/el.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/es.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/fa.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/fr.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/hr.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/hu.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/it.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ja.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/km.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ko.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ku.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/lo.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/pt.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ro.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/sq.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/sr.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/sv.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/tr.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/ug.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/uk.i18n.json create mode 100644 packages/rocketchat-channel-settings-mail-messages/i18n/zh.i18n.json diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index 1a15ba521b0..2a8dd4c25d5 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,58 @@ "Channels" : "القنوات", "Channels_list" : "قائمة القنوات العامة", "Chat_Rooms" : "غر٠المØادثة", - "close" : "أغلق", + "Clear_all_unreads_question" : "Ù…Ø³Ø ÙƒØ§ÙØ© الغير مقروءة؟", + "close" : "غلق", "coming_soon" : "قريبا", + "Commands" : "الأوامر", "Confirm_password" : "تأكيد كلمة السر", "Conversation" : "Ù…Øادثة", + "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,6 +112,7 @@ "Invalid_pass" : "لا يجب أن تكون كلمة السر Ùارغة", "invisible" : "Ø®ÙÙŠ", "Invisible" : "Ø®ÙÙŠ", + "Invitation_Subject" : "موضوع الدعوة", "Invite_Users" : "دعوة المستخدمين", "is_also_typing" : "هو أيضا يكتب", "is_also_typing_female" : "هي أيضا تكتب", @@ -78,28 +123,61 @@ "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" : "تسجيل خروج", + "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" : "لست جزء من أي قناة Øتى الآن.", @@ -107,58 +185,120 @@ "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_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" : "إزالة من الغرÙØ©", + "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" : "ØÙظ التغيرات", "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> of __total__ users", "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" : "استخدام Emojis", "Use_initials_avatar" : "استخدم الأØر٠الأولى من اسم المستخدم", "use_menu" : "استخدم القائمة الجانبية للوصول إلى الغر٠الخاصة بك والمØادثات", "Use_service_avatar" : "استخدام %s الرمزية", @@ -166,24 +306,47 @@ "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_description" : "يتم استخدام اسم المستخدم Ù„Ù„Ø³Ù…Ø§Ø Ù„Ù„Ø¢Ø®Ø±ÙŠÙ† بذكرك ÙÙŠ الرسائل.", "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_clear_all" : "نعم، Øذ٠الكل!", + "Yes_delete_it" : "نعم، Ø£ØØ°Ù!", + "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 22c80008b85..20dfc85f5ea 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -1,73 +1,96 @@ { - "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", + "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_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.", "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", + "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", + "Archive" : "Archivieren", "are_also_typing" : "schreiben auch", "are_typing" : "schreiben", "Are_you_sure" : "Sind Sie sicher?", "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_integrations" : "Zurück zu Integrationen", "Back_to_login" : "Zurück zum Login", "bold" : "fett", "busy" : "beschäftigt", @@ -77,89 +100,116 @@ "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" : "Ändere dein 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?", + "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" : "Erstellen Sie einen neuen privaten Nachrichtenraum.", + "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", "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" : "Desktop-Benachrichtigungen 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_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.", "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", + "Incorrect_Password" : "Das angegebene Passwort ist falsch.", "inline_code" : "inline_code", - "Install_FxOs" : "Installiere Rocket.Chat auf deinem Firefox", + "Install_Extension" : "Erweiterung installieren", + "Install_FxOs" : "Installiere Rocket.Chat in deinem Firefox-Browser", "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", @@ -170,264 +220,346 @@ "italics" : "kursiv", "join" : "Beitreten", "Join_the_Community" : "Trete der Community bei", + "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_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_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_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", + "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", + "Make_Admin" : "Benutzer zum Admin machen", "Mark_as_read" : "Als gelesen markieren", - "Markdown_Headers" : "Markdown-Headers", + "Markdown_Headers" : "Markdown-Ãœberschriften", "Members" : "Mitglieder", "Members_List" : "Mitgliederliste", "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", "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_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", + "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" : "Sende meine anonymen Statistiken nicht an Rocket.Chat.", + "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. 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", + "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_custom_oauth" : "Entferne das OAuth-Konto", + "Remove_from_room" : "Aus dem Raum entfernen", + "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_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" : "Dateiliste", - "Room_uploaded_file_list_empty" : "Keine Dateien zur Verfügung.", + "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" : "Wählen Sie ein Profilbild aus.", "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.", "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>", "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_of_conversation" : "Beginn der Konversation", + "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_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_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!", + "There_is_no_integrations" : "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" : "Ungelesener-Raum-Modus", + "Upload_file_question" : "Möchten Sie eine Datei hochladen?", + "Uploading_file" : "Datei wird hochgeladen...", + "Use_Emojis" : "Emojis verwenden", + "Use_initials_avatar" : "Benutze die Initialien deines Nutzernamens.", + "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_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_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", "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!", + "you_are_in_preview_mode_of" : "Sie befinden sich im Vorschaumodus des Kanals #<strong>__room_name__</strong>.", + "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_Open_Source_solution" : "Deine eigene Open-Source-Chat-Lösung.", + "Your_mail_was_sent_to_s" : "Ihre E-Mail wurde an %s gesendet.", + "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 5f43d541e87..5b5f2e098e4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -483,7 +483,7 @@ "Success" : "Success", "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 in your server.", + "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_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "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>!", "There_is_no_integrations" : "There is no integrations", @@ -563,4 +563,4 @@ "Your_Open_Source_solution" : "Your own Open Source chat solution", "Your_mail_was_sent_to_s" : "Your mail was sent to %s", "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 d698ecaa267..9bee99c4582 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -524,4 +524,4 @@ "Your_entry_has_been_deleted" : "Your entry has been deleted.", "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 31144e2a9c0..a534eea244b 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 0a641b93d4d..6c8e8f5e2b8 100644 --- a/i18n/he.i18n.json +++ b/i18n/he.i18n.json @@ -30,9 +30,9 @@ "Direct_Messages" : "הודעות ישירות", "edited" : "× ×¢×¨×š", "Email_or_username" : "כתובת ×ימייל ×ו ×©× ×ž×©×ª×ž×©", - "Email_verified" : "כתובת ×”×ימייל ×ומתה", + "Email_verified" : "כתובת הדו×״ל ×ומתה", "Enter_info" : "הזן ×ת פרטי ההתחברות שלך", - "Error_changing_password" : "×”×¡×™×¡×ž× ×©×•× ×ª×”", + "Error_changing_password" : "הססמה הוחלפה", "Favorites" : "מועדפי×", "Follow_social_profiles" : "עקוב ×חר ×”×¤×¨×•×¤×™×œ×™× ×©×œ× ×• ברשתות החברתיות, עשה fork לפרויקט ×©×œ× ×• ב-github ושתף ×ת המחשבות שלך על ×פליקציית rocket.chat בלוח trello ×©×œ× ×•.", "Forgot_password" : "שכחת ×ת הסיסמ×?", @@ -40,7 +40,7 @@ "Get_to_know_the_team" : "הכר ×ת הצוות שמ×חורי Rocket.Chat", "github_no_public_email" : "×ין לך ××£ כתובת ×ימייל פומבית בחשבון ×”-GitHub שלך", "Have_your_own_chat" : "תהיה בעל שרת צ'×ט. פותחה ×¢× meteor.com, ×”×פליקציה Rocket.Chat ×”×™× ×¤×ª×¨×•×Ÿ מעולה עבור ×ž×¤×ª×—×™× ×”×ž×—×¤×©×™× ×œ×‘× ×•×ª ולשפר ×ת פלפורמת הצ'×ט שלה×.", - "Hide_room" : "הסתר ×ת החדר", + "Hide_room" : "להסתיר ×ת החדר", "History" : "היסטוריה", "inline_code" : "קוד", "Invalid_confirm_pass" : "×ימות ×”×¡×™×¡×ž× ××™× ×• ×–×”×” לסיסמ×", @@ -58,7 +58,7 @@ "Language" : "שפה", "Language_Version" : "גרסה ×× ×’×œ×™×ª", "Last_message" : "ההודעה ×”××—×¨×•× ×”", - "Leave_room" : "עזוב ×ת החדר", + "Leave_room" : "לעזוב ×ת החדר", "line" : "שורה", "Load_more" : "טען עוד", "Loading_suggestion" : "טוען הצעות...", @@ -75,7 +75,7 @@ "n_messages" : "%s הודעות", "Name" : "ש×", "New_messages" : "הודעות חדשות", - "New_password" : "×¡×™×¡×ž× ×—×“×©×”", + "New_password" : "ססמה חדשה", "No_channels_yet" : "××™× ×š חבר ב××£ ערוץ עד ×›×”.", "No_direct_messages_yet" : "×œ× ×”×ª×—×œ×ª ××£ שיחה עד ×›×”.", "No_favorites_yet" : "×ין לך מועדפי×.", @@ -88,7 +88,7 @@ "Oops!" : "×ופס", "Password" : "סיסמ×", "Please_wait" : "×× × ×”×ž×ª×Ÿ", - "Powered_by" : "מופעל על ידי", + "Powered_by" : "מופעל על גבי", "Privacy" : "פרטיות", "Private_Groups" : "קבוצות פרטיות", "Proudly_developed" : "פותח בג×ווה ×¢× Meteor", @@ -127,7 +127,7 @@ "Use_uploaded_avatar" : "השתמש ב×וו×טר שהועלה", "User_added_by" : "המשתמש <em>__user_added__</em> × ×•×¡×£ על ידי <em>__user_by__</em>", "User_joined_channel" : "הצטרף לערוץ.", - "User_left" : "המשתמש <em>__user_left__</em> עזב ×ת השיחה.", + "User_left" : "המשתמש עזב ×ת השיחה.", "User_logged_out" : "המשתמש ×œ× ×ž×—×•×‘×¨", "User_removed_by" : "המשתמש <em>__user_removed__</em> הוסר על ידי <em>__user_by__</em>", "Username" : "×©× ×ž×©×ª×ž×©", @@ -139,7 +139,7 @@ "View_All" : "הצג הכל", "We_have_sent_password_email" : "×”×™× ×š צריך לקבל בדקות הקרובות מייל ×¢× ×”×•×¨×ות ל×יפוס הסיסמ×. ×× ××™× ×š רו××” ×ותו, ×× × × ×¡×” ×©× ×™×ª.", "We_have_sent_registration_email" : "×©×œ×—× ×• לך מייל ל×ישור ההרשמה. ×× ××™× ×š מקבל ×ת המייל בדקות הקרובות, ×× × × ×¡×” ×©× ×™×ª.", - "Welcome" : "ברוך ×”×‘× <em>%s</em>.", + "Welcome" : "ברוך בו×ך <em>%s</em>.", "Welcome_to_the" : "ברוך ×”×‘× ×œ-", "you_are_in_preview_mode_of" : "×”× ×š בתצוגה מוקדמת של ערוץ #<strong>__rom_name__</strong>", "You_need_confirm_email" : "×”×™× ×š צריך ל×מת ×ת כתובת ×”×ימייל על ×ž× ×ª להתחבר!", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 1af3a9b6f94..6507783c957 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,17 @@ "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", "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 +242,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 +264,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 +295,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 +328,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 +346,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 696cdec725e..1051095f4d3 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/nl.i18n.json b/i18n/nl.i18n.json index 0e333939023..1f29104465d 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -3,6 +3,7 @@ "Access_Online_Demo" : "Toegang tot de online demo", "Accounts_denyUnverifiedEmail" : "Weiger ongeverifieerde e-mail", "Accounts_EmailVerification" : "Email verificatie", + "Accounts_LoginExpiration" : "Login Vervaltermijn in Dagen", "Accounts_OAuth_Facebook" : "Facebook Inloggen", "Accounts_OAuth_Facebook_id" : "Facebook App Id", "Accounts_OAuth_Facebook_secret" : "Facebook Secret", @@ -25,6 +26,7 @@ "Add_Members" : "Voeg leden toe", "Add_users" : "Gebruikers toevoegen", "Administration" : "Administratie", + "Alias" : "Alias", "All_channels" : "Alle kanalen", "and" : "en", "API_Analytics" : "Analytics", @@ -33,6 +35,7 @@ "are_typing" : "zijn aan het typen", "Are_you_sure" : "Weet u het zeker?", "Avatar_changed_successfully" : "Afbeelding is gewijzigd", + "Avatar_URL" : "Afbeelding URL", "away" : "Afwezig", "Away" : "Afwezig", "away_female" : "afwezig", @@ -52,6 +55,7 @@ "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.", "close" : "Sluiten", "coming_soon" : "binnekort beschikbaar", "Confirm_password" : "Bevestig uw wachtwoord", @@ -66,6 +70,7 @@ "Delete_User_Warning" : "Een gebruiker verwijderen betekent dat alle berichten van die gebruiker ook verwijderd worden. Dit kan niet ongedaan gemaakt worden.", "Deleted" : "Verwijderd!", "Direct_Messages" : "Directe berichten", + "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_channel_name" : "Een kanaal met de naam '%s' bestaat reeds", "Duplicate_private_group_name" : "Een privé-groep met de naam '%s' bestaat reeds", @@ -76,8 +81,12 @@ "Email_verified" : "E-mail geverifiëerd", "Enter_info" : "Voer uw gegevens in", "Error_changing_password" : "Fout bij het veranderen van het wachtwoord", + "Example_s" : "Voorbeeld: <code class=\"inline\">%s</code>", "False" : "False", "Favorites" : "Favorieten", + "FileUpload_File_Empty" : "Bestand leeg", + "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", @@ -88,11 +97,15 @@ "History" : "Geschiedenis", "hours" : "uur", "inline_code" : "inline_code", + "Install_Extension" : "Installeer Uitbreiding", + "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_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", "is_also_typing" : "is ook aan het typen", @@ -104,6 +117,8 @@ "italics" : "cursief", "join" : "Toetreden", "Join_the_Community" : "Word lid", + "Jump_to_message" : "Ga naar bericht", + "Jump_to_recent_messages" : "Ga naar recente berichten", "Language" : "Taal", "Language_Version" : "Nederlndse versie", "Last_login" : "Laatste aanmelding", @@ -133,6 +148,8 @@ "Message_AllowEditing" : "Bericht bewerken toestaan", "Message_deleting_not_allowed" : "Bericht verwijderen niet toegestaan", "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_removed" : "Bericht verwijderd", "Message_ShowDeletedStatus" : "Toon Verwijderde Status", @@ -146,6 +163,7 @@ "More_channels" : "Meer kanalen", "Msgs" : "Berichten", "multi" : "multi", + "Mute_user" : "Maak gebruiker stil", "My_Account" : "Mijn account", "n_messages" : "%s berichten", "Name" : "Naam", @@ -189,18 +207,22 @@ "Quick_Search" : "Snelzoeken", "quote" : "citaat", "Recents" : "Recente", + "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", + "Remove_from_room" : "Verwijderen uit de kamer", "Reset_password" : "Nieuw Wachtwoord", "Room" : "Kamer", + "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_user_count" : "%s gebruikers", "Save_changes" : "Wijzigingen opslaan", + "Screen_Share" : "Scherm delen", "Search" : "Zoeken", "Search_settings" : "Zoekinstellingen", "seconds" : "secondes", @@ -214,6 +236,7 @@ "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.", "Showing_online_users" : "Toont <b>__total_online__</b> van de __total__ gebruikers", "Showing_results" : "<p>Toon <b>%s</b> resultaten</p>", "Silence" : "Stilte", @@ -246,8 +269,12 @@ "Stats_Total_Users" : "Totaal aantal leden", "strike" : "doorhalen", "Submit" : "Verzenden", + "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_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>!", "True" : "True", + "Unmute_user" : "Laat iemand weer praten", "Unnamed" : "Naamloos", "Upload_file_question" : "Bestand uploaden?", "Use_initials_avatar" : "Gebruik de initialen van uw gebruikersnaam", @@ -269,8 +296,14 @@ "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_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", @@ -278,6 +311,7 @@ "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 :(", + "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.", @@ -287,7 +321,11 @@ "With_whom" : "Met wie", "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" diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 8dedcd4e377..42ccf79d1fd 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", @@ -71,7 +72,7 @@ "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", "are_also_typing" : "również piszÄ…", "are_typing" : "piszÄ…", @@ -95,6 +96,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", @@ -170,9 +172,11 @@ "Install_FxOs_follow_instructions" : "Potwierdź instalowanie aplikacji na twoim urzÄ…dzeniu (gdy wyskoczy pytanie naciÅ›nij przycisk \"Zainstaluj\").", "Invalid_confirm_pass" : "Podane hasÅ‚a nie sÄ… jednakowe", "Invalid_email" : "E-mail jest nieprawidÅ‚owy", + "Invalid_file_type" : "NieprawidÅ‚owy typ 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", @@ -316,6 +320,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", @@ -414,6 +420,7 @@ "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", @@ -464,4 +471,4 @@ "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" -} +} \ No newline at end of file diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 2aaa4c39680..737b5fe3a2e 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -458,4 +458,4 @@ "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source", "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" -} +} \ No newline at end of file diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index f40860aaddb..e6ffca0d243 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -77,6 +77,7 @@ "API_Embed" : "Embed", "API_EmbedDisabledFor" : "DezactivaÈ›i Embed pentru utilizatori", "API_EmbedDisabledFor_Description" : "Lista separată cu virgule a numelor de utilizator", + "Archive" : "Arhivează", "are_also_typing" : "tastează", "are_typing" : "tastează", "Are_you_sure" : "Sigur doriÈ›i asta?", @@ -140,6 +141,8 @@ "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", @@ -160,6 +163,7 @@ "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", @@ -200,6 +204,7 @@ "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", @@ -216,8 +221,8 @@ "italics" : "cursive", "join" : "AlăturaÈ›i-vă", "Join_the_Community" : "IntraÈ›i în comunitate", - "Jump_to_recent_messages" : "Salt la mesajele recente", "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", @@ -298,7 +303,6 @@ "Msgs" : "Mesaje", "multi" : "multi", "Mute_user" : "Blochează mesajele utilizatorului", - "Unmute_user" : "Deblochează mesajele utilizatorului", "My_Account" : "Contul meu", "n_messages" : "%s mesaje", "Name" : "Nume", @@ -315,6 +319,7 @@ "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", @@ -336,6 +341,7 @@ "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.", @@ -379,14 +385,17 @@ "Remove_Admin" : "EliminaÈ›i utilizator de tip Admin", "Remove_custom_oauth" : "EliminaÈ›i OAuth personalizat", "Remove_from_room" : "EliminaÈ›i din cameră", + "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", @@ -412,6 +421,7 @@ "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.", @@ -426,6 +436,7 @@ "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", @@ -437,6 +448,7 @@ "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_of_conversation" : "ÃŽnceputul conversaÈ›iei", @@ -477,6 +489,9 @@ "There_is_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", @@ -505,15 +520,15 @@ "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_unmuted_in_room" : "Utilizator deblocat î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_muted_by" : "Utilizatorul <em>__user_muted__</em> a fost blocat de către  <em>__user_by__</em>.", - "User_unmuted_by" : "Utilizatorul <em>__user_muted__</em> a fost deblocat 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", @@ -546,5 +561,6 @@ "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_Open_Source_solution" : "Propria soluÈ›ie de chat Open Source", + "Your_mail_was_sent_to_s" : "E-mail-ul a fost trimis la %s", "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/sq.i18n.json b/i18n/sq.i18n.json index b3a8f83dc98..a76109b0e15 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", + "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ë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/packages/rocketchat-authorization/i18n/ar.i18n.json b/packages/rocketchat-authorization/i18n/ar.i18n.json index 6983bb7d0fe..243fae72104 100644 --- a/packages/rocketchat-authorization/i18n/ar.i18n.json +++ b/packages/rocketchat-authorization/i18n/ar.i18n.json @@ -1,6 +1,10 @@ { "Add_user" : "إضاÙØ© مستخدم", - "Save" : "ØÙظ", + "Back_to_permissions" : "العودة إلى التصريØات", + "Permissions" : "التصريØات", + "Removed" : "تمت اﻹزالة", + "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 84eb3ce32fd..6f31cf5a2e6 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 e13943efa3e..790d9a22876 100644 --- a/packages/rocketchat-authorization/i18n/de.i18n.json +++ b/packages/rocketchat-authorization/i18n/de.i18n.json @@ -1,4 +1,18 @@ { - "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", + "Removed" : "Entfernt", + "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" : "Dieser Rolle zugeordneten Benutzer" } \ 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 c0b916f189e..8743d1a9706 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 46367ea0176..89f68bed6c9 100644 --- a/packages/rocketchat-authorization/i18n/en.i18n.json +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -9,7 +9,6 @@ "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 9ace70c0a3c..1c2eaf55885 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 041ed788cf1..488fab46a3f 100644 --- a/packages/rocketchat-authorization/i18n/fi.i18n.json +++ b/packages/rocketchat-authorization/i18n/fi.i18n.json @@ -9,7 +9,6 @@ "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 ee7fabae8a3..adcc0c34d11 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 ed313b29364..c2e33fd83bc 100644 --- a/packages/rocketchat-authorization/i18n/he.i18n.json +++ b/packages/rocketchat-authorization/i18n/he.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "שמור", - "User_added" : "המשתמש <em>__user_added__</em> × ×•×¡×£." + "User_added" : "המשתמש × ×•×¡×£." } \ 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 6b72824ca23..22aa475a059 100644 --- a/packages/rocketchat-authorization/i18n/hr.i18n.json +++ b/packages/rocketchat-authorization/i18n/hr.i18n.json @@ -1,4 +1,13 @@ { - "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", + "Removed" : "Uklonjeno", + "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 9f88a36530a..cd097103a5a 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 73b11372f50..d95b3cf085c 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 846240cce4b..63994876ab0 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 d3ce4c6f879..f252b47a08b 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 b7aba81e1d2..c0502addf31 100644 --- a/packages/rocketchat-authorization/i18n/ko.i18n.json +++ b/packages/rocketchat-authorization/i18n/ko.i18n.json @@ -3,7 +3,6 @@ "New_role" : "새로운 ì—í• ", "Permissions" : "권한", "Removed" : "ì œê±°ë¨", - "Save" : "ì €ìž¥", "Saving" : "ì €ìž¥ 중", "User_added" : "ì‚¬ìš©ìž ì¶”ê°€í•¨.", "User_not_found" : "사용ìžë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ", diff --git a/packages/rocketchat-authorization/i18n/ku.i18n.json b/packages/rocketchat-authorization/i18n/ku.i18n.json index 1e7dd6a0876..1b1b8096a8e 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 07811f70be0..e34b443be0e 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 039425c06c5..d57a643f6ff 100644 --- a/packages/rocketchat-authorization/i18n/nl.i18n.json +++ b/packages/rocketchat-authorization/i18n/nl.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Bewaren", "User_added" : "Gebruiker toegevoegd" } \ 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 14ea715b8ec..03956a989db 100644 --- a/packages/rocketchat-authorization/i18n/pl.i18n.json +++ b/packages/rocketchat-authorization/i18n/pl.i18n.json @@ -1,4 +1,13 @@ { - "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", + "Removed" : "UsuniÄ™to", + "Role" : "Rola", + "Role_removed" : "Rola usuniÄ™ta", + "Saving" : "Zapisywanie", + "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 8664e27746f..e1152abd2c3 100644 --- a/packages/rocketchat-authorization/i18n/pt.i18n.json +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -9,7 +9,6 @@ "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 index d842b044a7c..10f94926353 100644 --- a/packages/rocketchat-authorization/i18n/ro.i18n.json +++ b/packages/rocketchat-authorization/i18n/ro.i18n.json @@ -9,7 +9,6 @@ "Role" : "Rol", "Role_Editing" : "Editare rol", "Role_removed" : "Rol eliminat", - "Save" : "Salvează", "Saving" : "Salvare...", "There_are_no_users_in_this_role" : "Nu există utilizatori în acest rol.", "User_added" : "Utilizator adăugat", diff --git a/packages/rocketchat-authorization/i18n/ru.i18n.json b/packages/rocketchat-authorization/i18n/ru.i18n.json index a1e844169a3..7a05e5a48d1 100644 --- a/packages/rocketchat-authorization/i18n/ru.i18n.json +++ b/packages/rocketchat-authorization/i18n/ru.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/sq.i18n.json b/packages/rocketchat-authorization/i18n/sq.i18n.json index b01a59cc8c1..6f31cf5a2e6 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 index 4ac5844a96f..e50b8a1469c 100644 --- a/packages/rocketchat-authorization/i18n/sr.i18n.json +++ b/packages/rocketchat-authorization/i18n/sr.i18n.json @@ -1,4 +1,3 @@ { - "Save" : "Сачувај", "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 7bc9d5f5301..6f31cf5a2e6 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 24a652c5f05..6feacff35eb 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 87c7ba45b61..c8fe5872ecd 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 64384b7a94a..e2d8791b127 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 c1ac4e32dd6..0bfea7a4c0c 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 5b7a5b62c1e..0504f9957b4 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-channel-settings-mail-messages/i18n/ar.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json new file mode 100644 index 00000000000..ad10bc3dc16 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..dde249f42d9 --- /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" : "Von", + "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" : "E-Mail-Nachrichten", + "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 00000000000..6f31cf5a2e6 --- /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 index 832d3732cc1..9383ba9a910 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json @@ -1,18 +1,16 @@ { - "Additional_emails" : "Additional E-mails", - "Body" : "Body", - "Cancel" : "Cancel", - "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", - "Send" : "Send", - "Sending" : "Sending...", - "Subject" : "Subject", - "To_users" : "To Users", - "Your_email_has_been_queued_for_sending" : "Your email has been queued for sending" -} + "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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..3092354611a --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6bbb424d86f --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..a51eb844469 --- /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 00000000000..6f31cf5a2e6 --- /dev/null +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } \ 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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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 00000000000..6f31cf5a2e6 --- /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/i18n/ar.i18n.json b/packages/rocketchat-channel-settings/i18n/ar.i18n.json index 6f31cf5a2e6..5f097c9f566 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 6f31cf5a2e6..84eb3ce32fd 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 6f31cf5a2e6..eae7402de33 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" : "Rauminformationen", + "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 6f31cf5a2e6..8fe65b23381 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 c6ebf4e70dc..7fa82c45dcb 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -1,15 +1,13 @@ { - "Archive_Unarchive": "Archive / Unarchive", - "Cancel": "Cancel", - "Channel": "Channel", - "Private_Group": "Private Group", - "Name": "Name", - "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_topic_changed_successfully": "Room topic changed successfully", - "Room_type_changed_successfully": "Room type changed successfully" -} + "Archive_Unarchive" : "Archive / Unarchive", + "Channel" : "Channel", + "Private_Group" : "Private Group", + "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_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 6f31cf5a2e6..05a125952dd 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 ba9ae6c0008..5e3906804a6 100644 --- a/packages/rocketchat-channel-settings/i18n/fi.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/fi.i18n.json @@ -1,8 +1,7 @@ { "Channel" : "Kanava", "Private_Group" : "Privaattiryhmä", - "Room_Type" : "Huoneen tyyppi", - "Room_Settings" : "Huoneen asetukset", + "Save" : "Tallenna", "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" } \ 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 6f31cf5a2e6..0e4908b96a1 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 6f31cf5a2e6..a1c59cc1412 100644 --- a/packages/rocketchat-channel-settings/i18n/he.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/he.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/hr.i18n.json b/packages/rocketchat-channel-settings/i18n/hr.i18n.json index 6f31cf5a2e6..3ee66adf8f1 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 6f31cf5a2e6..f9fac2321e0 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 6f31cf5a2e6..48008e60a7d 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 6f31cf5a2e6..70cdb7bff67 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 6f31cf5a2e6..598c01accce 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 ff0d7ecce17..3c26cdb5093 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" : "ë°© ì„¤ì •", + "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 6f31cf5a2e6..5647eb663af 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 6f31cf5a2e6..c672c3727d8 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 6f31cf5a2e6..d71e4a6712c 100644 --- a/packages/rocketchat-channel-settings/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/nl.i18n.json @@ -1 +1,8 @@ -{ } \ No newline at end of file +{ + "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 f93465d0f99..1258e187316 100644 --- a/packages/rocketchat-channel-settings/i18n/pl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/pl.i18n.json @@ -1,8 +1,7 @@ { "Channel" : "KanaÅ‚", "Private_Group" : "Grupa Prywatna", - "Room_Type" : "Rodzaj pokoju", - "Room_Settings" : "Ustawienia pokoju", + "Save" : "Zapisz", "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>" } \ 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 f9d1b2c38cc..e41c8a68b54 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 index 22062b24489..f730f467410 100644 --- a/packages/rocketchat-channel-settings/i18n/ro.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ro.i18n.json @@ -1,8 +1,13 @@ { + "Archive_Unarchive" : "Arhivează / Dezarhivează", "Channel" : "Canal", "Private_Group" : "Grup privat", - "Room_Type" : "Tipul camerei", - "Room_Settings" : "Setări cameră", - "room_changed_privacy" : "Tipul camerei schimbat în: <em>__room_type__</em> by <em>__user_by__</em>", - "room_changed_topic" : "Subiectul camerei schimbat în: <em>__room_topic__</em> by <em>__user_by__</em>" + "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 6f31cf5a2e6..7f95f40d311 100644 --- a/packages/rocketchat-channel-settings/i18n/ru.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ru.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/sq.i18n.json b/packages/rocketchat-channel-settings/i18n/sq.i18n.json index 6f31cf5a2e6..b01a59cc8c1 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 index 6f31cf5a2e6..dabebdbb00a 100644 --- a/packages/rocketchat-channel-settings/i18n/sr.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/sr.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/sv.i18n.json b/packages/rocketchat-channel-settings/i18n/sv.i18n.json index 6f31cf5a2e6..7bc9d5f5301 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 6f31cf5a2e6..9a9ac953658 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 6f31cf5a2e6..17b9fac70d2 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 6f31cf5a2e6..54117dbd0a5 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 6f31cf5a2e6..73f4e68da76 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 6f31cf5a2e6..70cdb7bff67 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-chatops/i18n/de.i18n.json b/packages/rocketchat-chatops/i18n/de.i18n.json index 92a7ee53ca8..0bb37873b18 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 36d9014b31a..c504b432ac9 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-github-enterprise/i18n/ar.i18n.json b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json index 6f31cf5a2e6..16216ec3e86 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 22bde54918d..aecb8bb77fc 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 06dd996c99c..dfaef650cc1 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-gitlab/i18n/de.i18n.json b/packages/rocketchat-gitlab/i18n/de.i18n.json index ce7e0675b85..3e6c591d696 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-hubot/i18n/de.i18n.json b/packages/rocketchat-hubot/i18n/de.i18n.json index e077ae8144f..a840ae5c5db 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-ldap/i18n/de.i18n.json b/packages/rocketchat-ldap/i18n/de.i18n.json index 22e1aec0e15..77df8c918f8 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-lib/i18n/ar.i18n.json b/packages/rocketchat-lib/i18n/ar.i18n.json index 6f31cf5a2e6..b2b4bbb3106 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 856cc4134cb..061db4135c9 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" + "Edit" : "Bearbeiten", + "Only_errors" : "Nur Fehler" } \ 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 ff32a1bbe74..af1d286560d 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" + "Edit" : "Modifier", + "Only_errors" : "Seules les erreurs" } \ 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 6f31cf5a2e6..d32584ebeaf 100644 --- a/packages/rocketchat-lib/i18n/nl.i18n.json +++ b/packages/rocketchat-lib/i18n/nl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "All_logs" : "Alle logs", + "Debug_Level" : "Debug Level", + "Only_errors" : "Alleen fouten" +} \ No newline at end of file diff --git a/packages/rocketchat-livechat/app/i18n/ar.i18n.json b/packages/rocketchat-livechat/app/i18n/ar.i18n.json index e325035daf7..6f3586ed429 100644 --- a/packages/rocketchat-livechat/app/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ar.i18n.json @@ -1,3 +1,4 @@ { - "Start_Chat" : "ابدأ الدردشة" + "Skip" : "تخطي", + "Start_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 c7d0e51d44a..3924286d3a1 100644 --- a/packages/rocketchat-livechat/app/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/de.i18n.json @@ -1,3 +1,18 @@ { - "Start_Chat" : "Chat beginnen" + "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, 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/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index e09be84fb29..e31bf14dbe7 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -15,4 +15,4 @@ "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", "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/fr.i18n.json b/packages/rocketchat-livechat/app/i18n/fr.i18n.json index 48fec1b275a..80b42a8c814 100644 --- a/packages/rocketchat-livechat/app/i18n/fr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fr.i18n.json @@ -1,3 +1,16 @@ { - "Start_Chat" : "Démarrer un chat" + "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/hr.i18n.json b/packages/rocketchat-livechat/app/i18n/hr.i18n.json index 7cfffb7eb71..0f5f0fa415b 100644 --- a/packages/rocketchat-livechat/app/i18n/hr.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/hr.i18n.json @@ -1,3 +1,5 @@ { + "Appearance" : "Izgled", + "Installation" : "Instalacija", "Start_Chat" : "PoÄetak 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 5e8b9b574e5..1c12392e2e3 100644 --- a/packages/rocketchat-livechat/app/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/nl.i18n.json @@ -1,3 +1,17 @@ { - "Start_Chat" : "Start Chat" + "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", + "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/ro.i18n.json b/packages/rocketchat-livechat/app/i18n/ro.i18n.json index 4bfd179c9f7..ab72db26d5d 100644 --- a/packages/rocketchat-livechat/app/i18n/ro.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ro.i18n.json @@ -8,6 +8,7 @@ "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", diff --git a/packages/rocketchat-livechat/i18n/ar.i18n.json b/packages/rocketchat-livechat/i18n/ar.i18n.json index 3607c7efa2a..3685d82004b 100644 --- a/packages/rocketchat-livechat/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/i18n/ar.i18n.json @@ -1,3 +1,16 @@ { - "Livechat_enabled" : "مكنت LIVECHAT" + "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" : "إرسال رسالة", + "Time_in_seconds" : "الوقت بالثواني" } \ 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 30411a053d4..3a7fa80532b 100644 --- a/packages/rocketchat-livechat/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/i18n/de.i18n.json @@ -1,4 +1,56 @@ { - "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", + "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", + "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/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 871077a863b..bf4f5c5a702 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -53,4 +53,4 @@ "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/fr.i18n.json b/packages/rocketchat-livechat/i18n/fr.i18n.json index 27798a2d834..5a5f097e8ba 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/hr.i18n.json b/packages/rocketchat-livechat/i18n/hr.i18n.json index 94d44728829..99a14df1af0 100644 --- a/packages/rocketchat-livechat/i18n/hr.i18n.json +++ b/packages/rocketchat-livechat/i18n/hr.i18n.json @@ -1,3 +1,16 @@ { - "Livechat_enabled" : "LiveChat omogućeno" + "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/nl.i18n.json b/packages/rocketchat-livechat/i18n/nl.i18n.json index 6f31cf5a2e6..26c59d6b1b6 100644 --- a/packages/rocketchat-livechat/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/i18n/nl.i18n.json @@ -1 +1,33 @@ -{ } \ No newline at end of file +{ + "Back" : "Terug", + "Closed" : "Gesloten", + "Copy_to_clipboard" : "Kopieer naar klembord", + "Dashboard" : "Dashboard", + "Department_not_found" : "Afdeling niet gevonden", + "Department_removed" : "Afdeling verwijderd", + "Departments" : "Afdelingen", + "Edit_Department" : "Afdeling bewerken", + "Enable" : "Inschakelen", + "Enabled" : "Ingeschakeld", + "Enter_a_regex" : "Voer een reguliere expressie in", + "Live_sessions" : "Live sessies", + "Livechat_Dashboard" : "Livechat Dashboard", + "Livechat_enabled" : "Livechat beschikbaar", + "Livechat_Users" : "Livechat Gebruikers", + "Name_of_agent" : "Naam agent", + "New_Department" : "Nieuwe afdeling", + "Opened" : "Geopend", + "Please_fill_a_name" : "Vul een naam in", + "Please_select_enabled_yes_or_no" : "Selecteer een optie voor Ingeschakeld", + "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", + "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 743f3732748..ce4ab92fc99 100644 --- a/packages/rocketchat-livechat/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/i18n/pl.i18n.json @@ -1,4 +1,9 @@ { + "Add" : "Dodaj", + "Description" : "Opis", + "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" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ro.i18n.json b/packages/rocketchat-livechat/i18n/ro.i18n.json index bd7c08fdab4..1e83701edf4 100644 --- a/packages/rocketchat-livechat/i18n/ro.i18n.json +++ b/packages/rocketchat-livechat/i18n/ro.i18n.json @@ -4,9 +4,11 @@ "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", @@ -32,11 +34,14 @@ "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", diff --git a/packages/rocketchat-mailer/i18n/ar.i18n.json b/packages/rocketchat-mailer/i18n/ar.i18n.json index 6f31cf5a2e6..7301eab2102 100644 --- a/packages/rocketchat-mailer/i18n/ar.i18n.json +++ b/packages/rocketchat-mailer/i18n/ar.i18n.json @@ -1 +1,9 @@ -{ } \ No newline at end of file +{ + "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 6f31cf5a2e6..beff3d9920e 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" : "Von:", + "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 6f31cf5a2e6..71edb96248f 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 6f31cf5a2e6..6408a16fb88 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 6f31cf5a2e6..a99a6eb6c8c 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-mentions-flextab/i18n/de.i18n.json b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json index 6f31cf5a2e6..2b44208f91c 100644 --- a/packages/rocketchat-mentions-flextab/i18n/de.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "Erwähnungen", + "No_mentions_found" : "Keine Erwähnungen gefunden" +} \ 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 index 6f31cf5a2e6..78d945fe3d7 100644 --- a/packages/rocketchat-mentions-flextab/i18n/fr.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/fr.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "Mentions", + "No_mentions_found" : "Aucune mention trouvée" +} \ 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 index 6f31cf5a2e6..52e805767b3 100644 --- a/packages/rocketchat-mentions-flextab/i18n/nl.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/nl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "Vermeldingen", + "No_mentions_found" : "Geen vermeldingen gevonden" +} \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ar.i18n.json b/packages/rocketchat-message-pin/i18n/ar.i18n.json index ab3b6e37c08..3a3ddcfed54 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 b8e3131562d..8b9e0cff9f6 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" : "Keine fixierten Nachrichten vorhanden." } \ 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 19f10ea3b8a..1b4a150a1f2 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/km.i18n.json b/packages/rocketchat-message-pin/i18n/km.i18n.json index 4b0abbe9742..a61185894bc 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-star/i18n/de.i18n.json b/packages/rocketchat-message-star/i18n/de.i18n.json index bb056d4d81b..606cfee7304 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" : "Keine Nachrichten wurden 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 f57e88dc1e8..3a488fb0689 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-slashcommands-invite/i18n/de.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/de.i18n.json index 7ed315a21cd..03bf1dcfbe8 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 6f31cf5a2e6..6e8a0bf75bc 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-join/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ar.i18n.json index 6f31cf5a2e6..6f532cbd1fb 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 ad6c15152fa..034bede9ed7 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" : "Trete dem vorgeschlagenen Kanal bei." } \ 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 9565cca54e7..900f6a3c2c9 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 6f31cf5a2e6..709ab51b4ad 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-kick/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json index 6f31cf5a2e6..fb056a5215e 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Remove_someone_from_room" : "إزالة شخص من الغرÙØ©" +} \ 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 index 6f31cf5a2e6..033f4cec499 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "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/fr.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json index 6f31cf5a2e6..f005e4a0b51 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/fr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "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/hr.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json index 6f31cf5a2e6..f4880e1c7ea 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/hr.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "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/nl.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json index 6f31cf5a2e6..a7e2c8e2068 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/nl.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "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-mute/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json index 6f31cf5a2e6..36dd351ae48 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mute_someone_in_room" : "اسكات شخص ÙÙŠ هذه الغرÙØ©", + "Unmute_someone_in_room" : "إلغاء اسكات شخص ÙÙŠ هذه الغرÙØ©" +} \ 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 index 6f31cf5a2e6..d1a8bdcde1f 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/de.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "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/fr.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json index 6f31cf5a2e6..f11bb2e01a3 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/fr.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "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/nl.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json index 6f31cf5a2e6..0493e2a91aa 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/nl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "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-theme/i18n/ar.i18n.json b/packages/rocketchat-theme/i18n/ar.i18n.json index 7275473661d..bdfad243ecf 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 6f31cf5a2e6..93f6faa9c45 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 10f2f83c636..5535a7a7ecb 100644 --- a/packages/rocketchat-theme/i18n/en.i18n.json +++ b/packages/rocketchat-theme/i18n/en.i18n.json @@ -28,4 +28,4 @@ "theme-color-tertiary-background-color" : "Tertiary Background 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/fr.i18n.json b/packages/rocketchat-theme/i18n/fr.i18n.json index 6f31cf5a2e6..e9164f9d59b 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 6f31cf5a2e6..c1235a4596e 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/nl.i18n.json b/packages/rocketchat-theme/i18n/nl.i18n.json index 6f31cf5a2e6..ea9b5b77aeb 100644 --- a/packages/rocketchat-theme/i18n/nl.i18n.json +++ b/packages/rocketchat-theme/i18n/nl.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "theme-color-message-hover-background-color" : "Achtergrondkleur als muis er boven is" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ro.i18n.json b/packages/rocketchat-theme/i18n/ro.i18n.json index 50ee2c3dcd4..48d9bc9c492 100644 --- a/packages/rocketchat-theme/i18n/ro.i18n.json +++ b/packages/rocketchat-theme/i18n/ro.i18n.json @@ -1,9 +1,14 @@ { + "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", @@ -11,6 +16,7 @@ "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", @@ -20,5 +26,6 @@ "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-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-webrtc/i18n/ar.i18n.json b/packages/rocketchat-webrtc/i18n/ar.i18n.json index 6f31cf5a2e6..0e117a1ef1e 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 4f6f648650c..7376b712967 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 6f31cf5a2e6..588bdc0b4b2 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-wordpress/i18n/de.i18n.json b/packages/rocketchat-wordpress/i18n/de.i18n.json index f269571244d..a95a71ed381 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 315cdb25a08..abda39cd125 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 -- GitLab From 01e5e1434d56f23f27e465f0b7a46bc6454120ef Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 4 Jan 2016 14:54:28 -0200 Subject: [PATCH 1081/1338] Should also remove rtl when default is rtl but user language is not. --- client/startup/startup.coffee | 3 +++ packages/rocketchat-ui-master/master/main.coffee | 2 ++ 2 files changed, 5 insertions(+) diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee index 1f3e3cf041b..f7043af4946 100644 --- a/client/startup/startup.coffee +++ b/client/startup/startup.coffee @@ -31,6 +31,9 @@ Meteor.startup -> if isRtl language $('html').addClass "rtl" + else + $('html').removeClass "rtl" + language = language.split('-').shift() TAPi18n.setLanguage(language) diff --git a/packages/rocketchat-ui-master/master/main.coffee b/packages/rocketchat-ui-master/master/main.coffee index 14ec9d986b2..a5896523f8a 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" -- GitLab From 44f7e58a040dd27a9baa3ab722764ef84ed295f8 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 4 Jan 2016 15:07:53 -0200 Subject: [PATCH 1082/1338] added content to HISTORY.md --- HISTORY.md | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index e69de29bb2d..a8154652031 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -0,0 +1,231 @@ +## v.NEXT + + + +## v0.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 + +## v0.10.2, 2015-Dec-22 + +- Fixes image preview bugs with filenames containing spaces + +## v0.10.1, 2015-Dec-21 + +- Fix upload permissions introduced in raik:ufs 0.3.4 + +## v0.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 added 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 + +## v0.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 +- Added 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 + +## v0.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 +- Added 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 +- Added 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 + +## v0.1.0, 2015-May-19 + +- Initial public launch -- GitLab From 663dc7b86fffaca562c5d4f3d7537515987a2eca Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 4 Jan 2016 15:20:01 -0200 Subject: [PATCH 1083/1338] version bump --- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- HISTORY.md | 17 +++++++++++++++++ packages/rocketchat-lib/rocketchat.info | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 3e5d7aa10f0..b41b7ff7568 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 7, # Increment this for every release. + appVersion = 8, # Increment this for every release. - appMarketingVersion = (defaultText = "0.11.0"), + appMarketingVersion = (defaultText = "0.12.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/HISTORY.md b/HISTORY.md index a8154652031..625dae07616 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,23 @@ ## v.NEXT +## v0.12.0, 2016-Jan-04 + +- Settings: unset section if none is given on update +- Hide registration and forgot password links when hidding login form +- Upload build artifacts to GitHub and sign tgz for docker images +- Add a setting to disable form-based login +- Button to test SMTP settings +- No need to reload server for SMTP settings to take effect +- Fix livechat trigger by url +- Increase the delay to render color fields +- Fix guest users default role +- Improved clean button color +- Support named color for message attachments +- Added request debug messages +- Trim integration messages +- Try to parse all request bodies as JSON +- New password reset screen ## v0.11.0, 2015-Dec-28 diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index e6581973d84..0b9615cb010 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.11.0" + "version": "0.12.0" } -- GitLab From d5f9ef7fb498f719bc6d22844c5aa9ff53d55d14 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 4 Jan 2016 13:11:29 -0500 Subject: [PATCH 1084/1338] fix key typo --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 045e1423f99..80d1b2001a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ branches: only: - develop - master - - /^v(\d+\.)?(\d+\.)?(\*|\d+)$/ + - "/^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/" git: depth: 1 node_js: @@ -31,7 +31,7 @@ deploy: provider: releases api_key: secure: SLtbGv9vL6qC3rKGwKuXfUSFuRCeLsBFiRA1nBDWoyua7F3rLy8fBvhS3sXRDCqAF6hJgXQwZzX2pS1Lljwjjmwi/80Ns7VDtreX5QstHukFAxaJh2E0Lz5zQdSqAb61KdAipZmYfp2fgCr8T+xztE/mvtPD5R8CcIQIjJpl9rh+mrkkshkcaNOY4JQrqyrcTeCOeBQMXTZSkkbdJr4gb9++A2c61K0txfid9+VwqGm5MwvaT80JC5wLQkL8rS9OUcNJHFf90ELFZpRZnZnI2lsfmTBAxRKL994UZgzru3XNMhUTsJPh7OyVn/xSlyjLcvsn4dSon1PE9t3RkuxsbTxx/XY+gIkXSGl38jZlhextaJoV0gTFkEg33tF/aZ4+I+iZM8LYfRAoUuZU0fSzGnFtFZp4xptF2ECLKmI/3dmuE6iwr+G1xUer9g2Rq9fXXrHgUA164544IdY4aDisxd9U78U0K7WaPtbvphiVl4GbgVnfTEgNVdpXcQxUtcXPZMiBRz5+E+1fExmCfO6+7mZ/yzDrsFYoRdmuo1SMGRI4iqb5jl/PImZ9ukTqRmQdqd3WJp3zzPbIEJPwhMtS5LMxzBMSfugXwjEajkXybcH5CWQ7jo+ogNqcM/CcJ3q4ahYuLTN7VeZWZ8h5kwr9bPxPooZuhWw0WPRa+XUM22o= - file: + file: - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz.asc" - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.spk" @@ -42,4 +42,5 @@ after_deploy: - ".travis/docker.sh" env: global: - secure: y9LYMUBDtiAUlIwJEvubBrYLVrjPsPg7ClY5HcFisdm7OwOzMqHcjTFX8Sj2tN/6IXNcZLqFOhHcwuSdM0uUbBIDooTVnwMVSIy6ExZFOaZNrvAf/Axf2k6p15iAmtPmVo7o+us5SRVRQvuP6GqdUPMYIYn71jHrrjUKQp3/hgRZBlpIn7dyPs5WuLVXZda5hVjIjJpSfK1RZDoGd/b7o8jywvFgSdvBiB+lX1VXCVisRJU9yS28CGIcpoxeQg9AFk4Uez6+8+b/koLp3imQddY9VjYyYx2D8fNxRcUujUHux24VG5MSzQRtJh9JwLlJ+pyAN1KUSvoam6R3MQGoKJg0AH3UxikmSQ4yGZwsSkPSqWbRCRgSVmNtq/YLuTJjQEUHmMCxXUb53HdJisAaxaQiOfg/IfqMVtUWeeIfSDDNEhO9WgpuNvf4fOltdwlL2N1YwubR/fGw8/W/to9jSu94FxJHw6c2V4KQOJqq1XA+KtwMMYak82NjfS2DIhcwyf4EaKagkg4HD3z5BYpuxQdeQnkQkvvkvkI26kV+jPkqUGRlejS7AXG4PrhcUUf/nBvvWjUFrLwvk+epkMP3D2k94r2XUl7apyrANTfyTVyOCc1ogUu9N2XC4ShF2uxu5hoNxk+hNTo1D7uSrFE7aM1GpDFRPOUjtpt2E0mqOoQ= + - secure: y9LYMUBDtiAUlIwJEvubBrYLVrjPsPg7ClY5HcFisdm7OwOzMqHcjTFX8Sj2tN/6IXNcZLqFOhHcwuSdM0uUbBIDooTVnwMVSIy6ExZFOaZNrvAf/Axf2k6p15iAmtPmVo7o+us5SRVRQvuP6GqdUPMYIYn71jHrrjUKQp3/hgRZBlpIn7dyPs5WuLVXZda5hVjIjJpSfK1RZDoGd/b7o8jywvFgSdvBiB+lX1VXCVisRJU9yS28CGIcpoxeQg9AFk4Uez6+8+b/koLp3imQddY9VjYyYx2D8fNxRcUujUHux24VG5MSzQRtJh9JwLlJ+pyAN1KUSvoam6R3MQGoKJg0AH3UxikmSQ4yGZwsSkPSqWbRCRgSVmNtq/YLuTJjQEUHmMCxXUb53HdJisAaxaQiOfg/IfqMVtUWeeIfSDDNEhO9WgpuNvf4fOltdwlL2N1YwubR/fGw8/W/to9jSu94FxJHw6c2V4KQOJqq1XA+KtwMMYak82NjfS2DIhcwyf4EaKagkg4HD3z5BYpuxQdeQnkQkvvkvkI26kV+jPkqUGRlejS7AXG4PrhcUUf/nBvvWjUFrLwvk+epkMP3D2k94r2XUl7apyrANTfyTVyOCc1ogUu9N2XC4ShF2uxu5hoNxk+hNTo1D7uSrFE7aM1GpDFRPOUjtpt2E0mqOoQ= + - secure: UzXkeAMYzlEyncgUtos6/mwjUc3uMRT+1c6XzjdCBXaA/WkJoWH6KgZni1SSc/fS/LsvlVOb/8TusokUcIIup+BvQ7/GIoe17XqODG9nflmfJI6nXRK79D+Ux1N/coHKIIq+byyvYYp0jYptxL3M5YfOVp0gRffhO17cKxUknjjD4rVjro5FCmQw+sEbAmU+bMBjiWt6XqPnaxQa3QYIvDBqnBTqOl24iNUEEckBTJsYxTYTAh3r423Lh//K0ae/Hz8FEclBMGwwwr4gAwFUXS2ipkh7iJUEy/kp33/+Ivb6GqhigCMOry7t9Flfvd6t8usdB3K7pqrIfpKXZ8Y292meG4F7SwmQiRp23vxCKWvFqrnQMDqeK4NuoemobxaFhiAyN3mdY1gl8dDiAjowylIz4/lw8WY9XCDwUsrYNXd3NZ5B0H8F+DLW0y541Q89suD4kfdtQtKLfHWjEZjPLSvz5zMZcJGt1AMOOFGFk4e6JJ1zJpIhLBdqCnaC0lW29EbaadT3gKldmaj2Ru6M783H3sL8gmyLs/0SdM8dUuA7HdpTWHI/KhJAQyPdMz6/kq8wyd1iN8t1p3wjmth89Et9HecYDAW3uelxoiR9Um5nm33w41Ukv+AOlEyheNT1uure+iMelXZJZVP0/9AZqxDEsALaARa4JhHEEOkniO0= -- GitLab From f8ce957da6dbda565b734b33436b9cb23561219a Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 4 Jan 2016 13:16:00 -0500 Subject: [PATCH 1085/1338] fix key typo - tested --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80d1b2001a2..263f92b5b53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,5 +42,4 @@ after_deploy: - ".travis/docker.sh" env: global: - - secure: y9LYMUBDtiAUlIwJEvubBrYLVrjPsPg7ClY5HcFisdm7OwOzMqHcjTFX8Sj2tN/6IXNcZLqFOhHcwuSdM0uUbBIDooTVnwMVSIy6ExZFOaZNrvAf/Axf2k6p15iAmtPmVo7o+us5SRVRQvuP6GqdUPMYIYn71jHrrjUKQp3/hgRZBlpIn7dyPs5WuLVXZda5hVjIjJpSfK1RZDoGd/b7o8jywvFgSdvBiB+lX1VXCVisRJU9yS28CGIcpoxeQg9AFk4Uez6+8+b/koLp3imQddY9VjYyYx2D8fNxRcUujUHux24VG5MSzQRtJh9JwLlJ+pyAN1KUSvoam6R3MQGoKJg0AH3UxikmSQ4yGZwsSkPSqWbRCRgSVmNtq/YLuTJjQEUHmMCxXUb53HdJisAaxaQiOfg/IfqMVtUWeeIfSDDNEhO9WgpuNvf4fOltdwlL2N1YwubR/fGw8/W/to9jSu94FxJHw6c2V4KQOJqq1XA+KtwMMYak82NjfS2DIhcwyf4EaKagkg4HD3z5BYpuxQdeQnkQkvvkvkI26kV+jPkqUGRlejS7AXG4PrhcUUf/nBvvWjUFrLwvk+epkMP3D2k94r2XUl7apyrANTfyTVyOCc1ogUu9N2XC4ShF2uxu5hoNxk+hNTo1D7uSrFE7aM1GpDFRPOUjtpt2E0mqOoQ= - - secure: UzXkeAMYzlEyncgUtos6/mwjUc3uMRT+1c6XzjdCBXaA/WkJoWH6KgZni1SSc/fS/LsvlVOb/8TusokUcIIup+BvQ7/GIoe17XqODG9nflmfJI6nXRK79D+Ux1N/coHKIIq+byyvYYp0jYptxL3M5YfOVp0gRffhO17cKxUknjjD4rVjro5FCmQw+sEbAmU+bMBjiWt6XqPnaxQa3QYIvDBqnBTqOl24iNUEEckBTJsYxTYTAh3r423Lh//K0ae/Hz8FEclBMGwwwr4gAwFUXS2ipkh7iJUEy/kp33/+Ivb6GqhigCMOry7t9Flfvd6t8usdB3K7pqrIfpKXZ8Y292meG4F7SwmQiRp23vxCKWvFqrnQMDqeK4NuoemobxaFhiAyN3mdY1gl8dDiAjowylIz4/lw8WY9XCDwUsrYNXd3NZ5B0H8F+DLW0y541Q89suD4kfdtQtKLfHWjEZjPLSvz5zMZcJGt1AMOOFGFk4e6JJ1zJpIhLBdqCnaC0lW29EbaadT3gKldmaj2Ru6M783H3sL8gmyLs/0SdM8dUuA7HdpTWHI/KhJAQyPdMz6/kq8wyd1iN8t1p3wjmth89Et9HecYDAW3uelxoiR9Um5nm33w41Ukv+AOlEyheNT1uure+iMelXZJZVP0/9AZqxDEsALaARa4JhHEEOkniO0= + secure: lDiDmo2SGHx1v4G49wsCp8kvg84SFAsAvPuFd5ngba7j038GwgcIVfqgc+7Vgi007gUL86Z74B124mtV4rQjyXhgoSxyg482FDoOx1Hh4vKzcnW3xWI/Du0epyl3MVDijDh1Y34WTWLH7YST1ViDk4GKk+Nvwv+sydac3IwsRHLRtUnzAIwa9DigE+wA9vChBqPL2kAdGlnpkl8bWUhMB8MYtyQY9gR2jVxaTGBLIJKIy1mVEAg8MOVGEKZ7POQQ/yP29MfNd7GvGt8Gz+k09z4iMJrU4Plq4UCGPXM3QVSh6yG4CXXFkMsv8TwFBNrdmkxmUK33IP8XT4B15tUirbSNUvf0BQ1+WHdgHiv1omhmBnp4c3b+CI4Mzh7FBVmQYdkkucS/v7n+HJk25MRWdg43VXyxib/fkIS5vx4pTokbA/ftOvZOCA3fM5wc5McFalwefn9SEia0zDgKJM+aoxgB4wIACUJcjzI0hfclDUn7SzSTuXxaCYLM47EgKBN0I0D4GCITKKm8wlNwUnm6n+f3PqVykzKIYt08iFNI3SlVgTRMHGWYQlWR/HjYRkpq8wEdL21scTVz2652AP2/tbKqok26fFbphrgHxzhYG2xp2HOT3NMpCC0oprTaUFSWHru7bLAmbwBJL4VWwiVCN35rG9SU6X2Zq2StXbaM6B0= -- GitLab From f95311d2324db71c833f73245d2273e9c79fb858 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 4 Jan 2016 16:24:38 -0200 Subject: [PATCH 1086/1338] Small fixes --- client/routes/adminRouter.coffee | 2 +- packages/rocketchat-lib/client/defaultTabBars.js | 8 ++++---- .../rocketchat-ui-admin/admin/users/adminUsers.coffee | 6 +++--- server/startup/roomPublishes.coffee | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/client/routes/adminRouter.coffee b/client/routes/adminRouter.coffee index 50543bea309..c226715e635 100644 --- a/client/routes/adminRouter.coffee +++ b/client/routes/adminRouter.coffee @@ -11,7 +11,7 @@ FlowRouter.route '/admin/users', FlowRouter.route '/admin/rooms', name: 'admin-rooms' action: -> - RocketChat.TabBar.showGroup 'rooms' + RocketChat.TabBar.showGroup 'adminrooms' BlazeLayout.render 'main', {center: 'adminRooms'} FlowRouter.route '/admin/statistics', diff --git a/packages/rocketchat-lib/client/defaultTabBars.js b/packages/rocketchat-lib/client/defaultTabBars.js index ca8d5803b6a..6737d36c587 100644 --- a/packages/rocketchat-lib/client/defaultTabBars.js +++ b/packages/rocketchat-lib/client/defaultTabBars.js @@ -1,7 +1,7 @@ RocketChat.TabBar.addButton({ groups: ['channel', 'privategroup', 'directmessage'], id: 'message-search', - i18nTitle: TAPi18n.__('Search'), + i18nTitle: 'Search', icon: 'octicon octicon-search', template: 'messageSearch', order: 1 @@ -10,7 +10,7 @@ RocketChat.TabBar.addButton({ RocketChat.TabBar.addButton({ groups: ['directmessage'], id: 'user-info', - i18nTitle: TAPi18n.__('User_Info'), + i18nTitle: 'User_Info', icon: 'octicon octicon-person', template: 'membersList', order: 2 @@ -19,7 +19,7 @@ RocketChat.TabBar.addButton({ RocketChat.TabBar.addButton({ groups: ['channel', 'privategroup'], id: 'members-list', - i18nTitle: TAPi18n.__('Members_List'), + i18nTitle: 'Members_List', icon: 'octicon octicon-organization', template: 'membersList', order: 2 @@ -28,7 +28,7 @@ RocketChat.TabBar.addButton({ RocketChat.TabBar.addButton({ groups: ['channel', 'privategroup', 'directmessage'], id: 'uploaded-files-list', - i18nTitle: TAPi18n.__('Room_uploaded_file_list'), + i18nTitle: 'Room_uploaded_file_list', icon: 'octicon octicon-file-symlink-directory', template: 'uploadedFilesList', order: 3 diff --git a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee index eb15c19cce5..e09e66e2a09 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee @@ -40,7 +40,7 @@ Template.adminUsers.onCreated -> RocketChat.TabBar.addButton({ groups: ['adminusers', 'adminusers-selected'], id: 'invite-user', - i18nTitle: t('Invite_Users'), + i18nTitle: 'Invite_Users', icon: 'icon-plus', template: 'adminInviteUser', order: 1 @@ -48,8 +48,8 @@ Template.adminUsers.onCreated -> RocketChat.TabBar.addButton({ groups: ['adminusers-selected'] - id: 'user-info', - i18nTitle: t('User_Info'), + id: 'admin-user-info', + i18nTitle: 'User_Info', icon: 'icon-user', template: 'adminUserInfo', order: 2 diff --git a/server/startup/roomPublishes.coffee b/server/startup/roomPublishes.coffee index e8a7ab2ad94..85abbe2d8cc 100644 --- a/server/startup/roomPublishes.coffee +++ b/server/startup/roomPublishes.coffee @@ -36,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 -- GitLab From 5beff1319c06a82a8246a51570b295d2b4232665 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 18:00:31 -0200 Subject: [PATCH 1087/1338] show correct info from visitor --- .../client/views/app/tabbar/visitorInfo.js | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js index a1ffa11ce09..6f7166684b5 100644 --- a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js @@ -1,23 +1,25 @@ Template.visitorInfo.helpers({ user() { - var user = Meteor.users.findOne({ username: 'guest-54' }); - // user.ip = user.ip; + var room = ChatRoom.findOne(Session.get('openedRoom')); - if (user && user.userAgent) { - var ua = new UAParser(); - ua.setUA(user.userAgent); + if (room && room.v && room.v.token) { + var user = Meteor.users.findOne({ "profile.token": room.v.token }); + 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.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(); } - user.browser = ua.getBrowser().name + ' ' + ua.getBrowser().version; - user.browserIcon = 'icon-' + ua.getBrowser().name.toLowerCase(); - } - return user; + return user; + } } }); -- GitLab From 1ddcf184cf41e2b8bb9377fac7b0cf39a10ed757 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 4 Jan 2016 18:00:55 -0200 Subject: [PATCH 1088/1338] added visitor status colors --- .../client/stylesheets/livechat.less | 16 ++++++++++++++++ .../client/stylesheets/load.js | 3 +++ packages/rocketchat-livechat/package.js | 4 +++- .../side-nav/chatRoomItem.coffee | 3 +-- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 packages/rocketchat-livechat/client/stylesheets/load.js diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index 44b19e5adee..c48742a810f 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -446,3 +446,19 @@ 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; +} diff --git a/packages/rocketchat-livechat/client/stylesheets/load.js b/packages/rocketchat-livechat/client/stylesheets/load.js new file mode 100644 index 00000000000..3376dd0f6fd --- /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/package.js b/packages/rocketchat-livechat/package.js index d2de8be339a..5e3b7d9ad8e 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -36,7 +36,9 @@ Package.onUse(function(api) { api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); - api.addFiles('client/stylesheets/livechat.less', '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'); diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee index 6b0aa396d44..4db2d7e0494 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 -- GitLab From 5f584714427271cac161799ee2a8224a89147472 Mon Sep 17 00:00:00 2001 From: Mark Ide <mark@cranstonide.com> Date: Mon, 4 Jan 2016 18:32:41 -0500 Subject: [PATCH 1089/1338] Minor grammar fixup in both interface and source. There_is_no_integrations should be There_are_no_integrations --- i18n/de.i18n.json | 2 +- i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 2 +- i18n/ro.i18n.json | 2 +- packages/rocketchat-integrations/client/views/integrations.html | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 20dfc85f5ea..ba2d30d4b88 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -485,7 +485,7 @@ "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_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!", - "There_is_no_integrations" : "Keine Integrationen vorhanden.", + "There_are_no_integrations" : "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", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 5b5f2e098e4..4b0af0ec8b2 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -486,7 +486,7 @@ "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_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "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>!", - "There_is_no_integrations" : "There is no integrations", + "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", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 9bee99c4582..d4b38c13df3 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -458,7 +458,7 @@ "Success" : "Onnistui", "The_field_is_required" : "Kenttä %s vaaditaan.", "The_server_will_restart_in_s_seconds" : "Palvelin käynnistyy %s sekunnin kuluttua", - "There_is_no_integrations" : "Integraatioita ei ole", + "There_are_no_integrations" : "Integraatioita ei ole", "This_is_a_push_test_messsage" : "Tämä on testi-pushviesti", "True" : "Kyllä", "Unnamed" : "Nimetön", diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index e6ffca0d243..d0b8611a695 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -486,7 +486,7 @@ "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_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>!", - "There_is_no_integrations" : "Nu sunt integrări", + "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ă", diff --git a/packages/rocketchat-integrations/client/views/integrations.html b/packages/rocketchat-integrations/client/views/integrations.html index 580b06e6ab1..52f196b1c8b 100644 --- a/packages/rocketchat-integrations/client/views/integrations.html +++ b/packages/rocketchat-integrations/client/views/integrations.html @@ -27,7 +27,7 @@ </a> {{/if}} {{else}} - <h1>{{_ "There_is_no_integrations"}}</h1> + <h1>{{_ "There_are_no_integrations"}}</h1> {{/each}} {{#each integrations}} {{#if $eq type 'webhook-outgoing'}} -- GitLab From 6bc41c67c7e97ae09ab0bf048b0dbdb108107b83 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 4 Jan 2016 19:38:33 -0500 Subject: [PATCH 1090/1338] change build artifact names to remove branch reference --- .docker/dockerfiles/develop/Dockerfile | 37 -------------------------- .docker/dockerfiles/master/Dockerfile | 37 -------------------------- .travis.yml | 7 +++-- .travis/docker.sh | 12 ++------- .travis/namefiles.sh | 4 +-- .travis/sandstorm.sh | 2 +- .travis/setbranch.sh | 3 --- 7 files changed, 8 insertions(+), 94 deletions(-) delete mode 100644 .docker/dockerfiles/develop/Dockerfile delete mode 100644 .docker/dockerfiles/master/Dockerfile delete mode 100755 .travis/setbranch.sh diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile deleted file mode 100644 index cbb9a7bfe12..00000000000 --- a/.docker/dockerfiles/develop/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-develop.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/.docker/dockerfiles/master/Dockerfile b/.docker/dockerfiles/master/Dockerfile deleted file mode 100644 index dd62d8cc71e..00000000000 --- 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/.travis.yml b/.travis.yml index 263f92b5b53..d890c909217 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ before_script: script: - meteor build /tmp/build before_deploy: -- source ".travis/setbranch.sh" - source ".travis/setdeploydir.sh" - ".travis/setupsig.sh" - ".travis/namefiles.sh" @@ -32,9 +31,9 @@ deploy: api_key: secure: SLtbGv9vL6qC3rKGwKuXfUSFuRCeLsBFiRA1nBDWoyua7F3rLy8fBvhS3sXRDCqAF6hJgXQwZzX2pS1Lljwjjmwi/80Ns7VDtreX5QstHukFAxaJh2E0Lz5zQdSqAb61KdAipZmYfp2fgCr8T+xztE/mvtPD5R8CcIQIjJpl9rh+mrkkshkcaNOY4JQrqyrcTeCOeBQMXTZSkkbdJr4gb9++A2c61K0txfid9+VwqGm5MwvaT80JC5wLQkL8rS9OUcNJHFf90ELFZpRZnZnI2lsfmTBAxRKL994UZgzru3XNMhUTsJPh7OyVn/xSlyjLcvsn4dSon1PE9t3RkuxsbTxx/XY+gIkXSGl38jZlhextaJoV0gTFkEg33tF/aZ4+I+iZM8LYfRAoUuZU0fSzGnFtFZp4xptF2ECLKmI/3dmuE6iwr+G1xUer9g2Rq9fXXrHgUA164544IdY4aDisxd9U78U0K7WaPtbvphiVl4GbgVnfTEgNVdpXcQxUtcXPZMiBRz5+E+1fExmCfO6+7mZ/yzDrsFYoRdmuo1SMGRI4iqb5jl/PImZ9ukTqRmQdqd3WJp3zzPbIEJPwhMtS5LMxzBMSfugXwjEajkXybcH5CWQ7jo+ogNqcM/CcJ3q4ahYuLTN7VeZWZ8h5kwr9bPxPooZuhWw0WPRa+XUM22o= file: - - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" - - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz.asc" - - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.spk" + - "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" + - "$ROCKET_DEPLOY_DIR/rocket.chat.tgz.asc" + - "$ROCKET_DEPLOY_DIR/rocket.chat.spk" on: tags: true all_branches: true diff --git a/.travis/docker.sh b/.travis/docker.sh index 255601ef0f5..f3955d255a9 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -4,15 +4,7 @@ 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"'"}'; -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 -fi +CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; 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 18d2dc26da6..f71334fb7f2 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -4,6 +4,6 @@ IFS=$'\n\t' #cd $TRAVIS_BUILD_DIR #export TAG=$(git describe --abbrev=0 --tags) -cp /tmp/build/Rocket.Chat.tar.gz "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" -gpg --armor --detach-sign "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" +cp /tmp/build/Rocket.Chat.tar.gz "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" +gpg --armor --detach-sign "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" ls -l $ROCKET_DEPLOY_DIR diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 4c74593ac06..9ec3b97b0e6 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 $ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.spk +spk pack $ROCKET_DEPLOY_DIR/rocket.chat.spk diff --git a/.travis/setbranch.sh b/.travis/setbranch.sh deleted file mode 100755 index cb6a3d7c7a0..00000000000 --- a/.travis/setbranch.sh +++ /dev/null @@ -1,3 +0,0 @@ -export ROCKET_BRANCH="master" -echo $ROCKET_BRANCH - -- GitLab From 28c0a17612e3ead5c286ebfe1b8873146716bcd2 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 5 Jan 2016 09:57:49 -0200 Subject: [PATCH 1091/1338] Adds a link in the unread bar to jump to first unread message --- i18n/en.i18n.json | 3 ++- .../rocketchat-theme/assets/stylesheets/base.less | 10 +++++++++- packages/rocketchat-theme/assets/stylesheets/rtl.less | 11 +++++++---- packages/rocketchat-ui/lib/RoomHistoryManager.coffee | 3 +++ packages/rocketchat-ui/views/app/room.coffee | 11 ++++++++++- packages/rocketchat-ui/views/app/room.html | 5 ++++- server/methods/loadHistory.coffee | 5 ++++- 7 files changed, 39 insertions(+), 9 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 5b5f2e098e4..38cdf4b8763 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -221,6 +221,7 @@ "italics" : "italics", "join" : "Join", "Join_the_Community" : "Join the Community", + "Jump_to_first_unread" : "Jump to first unread", "Jump_to_message" : "Jump to message", "Jump_to_recent_messages" : "Jump to recent messages", "Language" : "Language", @@ -563,4 +564,4 @@ "Your_Open_Source_solution" : "Your own Open Source chat solution", "Your_mail_was_sent_to_s" : "Your mail was sent to %s", "Your_push_was_sent_to_s_devices" : "Your push was sent to %s devices" -} \ No newline at end of file +} diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index a13cb98307b..3f0b97d1d8c 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2130,13 +2130,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; + } + } } } diff --git a/packages/rocketchat-theme/assets/stylesheets/rtl.less b/packages/rocketchat-theme/assets/stylesheets/rtl.less index 2ad79e63b2e..b67ceb3652f 100644 --- a/packages/rocketchat-theme/assets/stylesheets/rtl.less +++ b/packages/rocketchat-theme/assets/stylesheets/rtl.less @@ -196,9 +196,12 @@ } } .unread-bar { - > a { + > a.mark-read { float: left; } + > a.jump-to { + float: right; + } } } @@ -297,7 +300,7 @@ } } } - + .flex-opened { .flex-tab { .control { @@ -387,7 +390,7 @@ } } } - + @media all and(max-width: 1100px) { #rocket-chat { .flex-opened { @@ -629,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-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index e6aa25d6bb6..aae87a8d192 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -10,6 +10,7 @@ hasMoreNext: ReactiveVar false isLoading: ReactiveVar false unreadNotLoaded: ReactiveVar 0 + firstUnread: ReactiveVar {} loaded: 0 return histories[rid] @@ -43,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? @@ -134,6 +136,7 @@ instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() Meteor.defer -> + readMessage.refreshUnreadMark(message.rid, true) RoomManager.updateMentionsMarksOfRoom typeName wrapper = $('.messages-box .wrapper') msgElement = $("##{message._id}", wrapper) diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 6e96ec59e2a..f585577091a 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -229,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) diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index 9f7f7f0fd91..483ef9d4565 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -39,8 +39,11 @@ {{#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> diff --git a/server/methods/loadHistory.coffee b/server/methods/loadHistory.coffee index ab8048e6e50..3c3fea22132 100644 --- a/server/methods/loadHistory.coffee +++ b/server/methods/loadHistory.coffee @@ -27,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 } -- GitLab From 22d4d90e495fc42cbe1349ce985391ce728c5710 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 11:01:29 -0200 Subject: [PATCH 1092/1338] Fix problem with middleware that tries to parse json body --- packages/rocketchat-cors/cors.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index 971777d4952..38e411e857b 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -8,6 +8,9 @@ WebApp.rawConnectHandlers.use (req, res, 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 @@ -20,6 +23,7 @@ WebApp.rawConnectHandlers.use (req, res, next) -> catch err req.body = buf + req._body = true next() -- GitLab From e5f03576678ebdbd19e8a2287d89ea2a0703ecfb Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 11:01:29 -0200 Subject: [PATCH 1093/1338] Fix problem with middleware that tries to parse json body --- packages/rocketchat-cors/cors.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index 971777d4952..38e411e857b 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -8,6 +8,9 @@ WebApp.rawConnectHandlers.use (req, res, 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 @@ -20,6 +23,7 @@ WebApp.rawConnectHandlers.use (req, res, next) -> catch err req.body = buf + req._body = true next() -- GitLab From a57d33022b20ab0e0c271e41a111633b26b59c29 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Tue, 5 Jan 2016 11:08:16 -0500 Subject: [PATCH 1094/1338] regen key --- .travis.yml | 2 +- .travis/sign.key.gpg | Bin 5119 -> 5117 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d890c909217..36845c11e7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,4 +41,4 @@ after_deploy: - ".travis/docker.sh" env: global: - secure: lDiDmo2SGHx1v4G49wsCp8kvg84SFAsAvPuFd5ngba7j038GwgcIVfqgc+7Vgi007gUL86Z74B124mtV4rQjyXhgoSxyg482FDoOx1Hh4vKzcnW3xWI/Du0epyl3MVDijDh1Y34WTWLH7YST1ViDk4GKk+Nvwv+sydac3IwsRHLRtUnzAIwa9DigE+wA9vChBqPL2kAdGlnpkl8bWUhMB8MYtyQY9gR2jVxaTGBLIJKIy1mVEAg8MOVGEKZ7POQQ/yP29MfNd7GvGt8Gz+k09z4iMJrU4Plq4UCGPXM3QVSh6yG4CXXFkMsv8TwFBNrdmkxmUK33IP8XT4B15tUirbSNUvf0BQ1+WHdgHiv1omhmBnp4c3b+CI4Mzh7FBVmQYdkkucS/v7n+HJk25MRWdg43VXyxib/fkIS5vx4pTokbA/ftOvZOCA3fM5wc5McFalwefn9SEia0zDgKJM+aoxgB4wIACUJcjzI0hfclDUn7SzSTuXxaCYLM47EgKBN0I0D4GCITKKm8wlNwUnm6n+f3PqVykzKIYt08iFNI3SlVgTRMHGWYQlWR/HjYRkpq8wEdL21scTVz2652AP2/tbKqok26fFbphrgHxzhYG2xp2HOT3NMpCC0oprTaUFSWHru7bLAmbwBJL4VWwiVCN35rG9SU6X2Zq2StXbaM6B0= + secure: HrPOM5sBibYkMcf9aeQThYPCDiXeLkg0Xgv0HvH88/ku/gphDpNEjHNReHZM3cyfm9y3RhHpVdD+Zzy38S2goKyewRzpXJsuyerOYkjND0v3tivhs9CAX8PAUxj1U5zllTyH4bgW2ZwRtNnwnmtIM/JJlnySMpKVDqIZBpbhn3ph9bJ2J+BW3D3Jw8meQ1vCX8szIibyJK/5QX6HG2RBFXJGYoQ8DmR8jQv0aJQvT1Az5DO4yImk8tX4NP95qOc19Jywr1DsbaSBZeJ8lFJAmBpIGx7KAmUVCcxSxfbXGRhs2K4iEYb3rJ/dU6KiyPsKGUG4aYNGgbvcX0ZxX/BZ6ZU9ff0E4IIf43IxoN3ElrOqOFk5msJAXbrJEreINSzDqKOy8NFYtCQ49E2gwzfage4ZXkhFyx3wMPa5bzpr3ncsTceMjMVz03uL781X6NLuCkUmXv+n8K2MNhJU9Xinpdx1GRJm+0lXJspNNJ1ruHeJtls4epj4bmCwKmmZbFKPXqa5e8xVcMIkwt1LMiHduhE+WgKNHdOMhXrCcTxF62ybLlsHXmyLLJeNjTeKS8QG2XSoonClDAz/1R41I1DsMPblcgz9uvYCf7UtyftbhJ83bnJeEmOYQiwijLG0+QMq+B2+mmZan3Z7Hl7O53dnwuLxz7EO7EhQhY+CqHVgc6s= diff --git a/.travis/sign.key.gpg b/.travis/sign.key.gpg index 6f149e0d544a3242e489f9f0babf3b6bb92a65a1..488e275998d505474fd6a93c263b4931885d7d00 100644 GIT binary patch literal 5117 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 literal 5119 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 -- GitLab From 0a66283fa6fb4f1bb4b2a2e5a6df091d9a23a444 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Tue, 5 Jan 2016 11:08:16 -0500 Subject: [PATCH 1095/1338] regen key --- .travis.yml | 13 ++++++------- .travis/sign.key.gpg | Bin 5119 -> 5117 bytes 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 045e1423f99..36845c11e7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ branches: only: - develop - master - - /^v(\d+\.)?(\d+\.)?(\*|\d+)$/ + - "/^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/" git: depth: 1 node_js: @@ -22,7 +22,6 @@ before_script: script: - meteor build /tmp/build before_deploy: -- source ".travis/setbranch.sh" - source ".travis/setdeploydir.sh" - ".travis/setupsig.sh" - ".travis/namefiles.sh" @@ -31,10 +30,10 @@ deploy: provider: releases api_key: secure: SLtbGv9vL6qC3rKGwKuXfUSFuRCeLsBFiRA1nBDWoyua7F3rLy8fBvhS3sXRDCqAF6hJgXQwZzX2pS1Lljwjjmwi/80Ns7VDtreX5QstHukFAxaJh2E0Lz5zQdSqAb61KdAipZmYfp2fgCr8T+xztE/mvtPD5R8CcIQIjJpl9rh+mrkkshkcaNOY4JQrqyrcTeCOeBQMXTZSkkbdJr4gb9++A2c61K0txfid9+VwqGm5MwvaT80JC5wLQkL8rS9OUcNJHFf90ELFZpRZnZnI2lsfmTBAxRKL994UZgzru3XNMhUTsJPh7OyVn/xSlyjLcvsn4dSon1PE9t3RkuxsbTxx/XY+gIkXSGl38jZlhextaJoV0gTFkEg33tF/aZ4+I+iZM8LYfRAoUuZU0fSzGnFtFZp4xptF2ECLKmI/3dmuE6iwr+G1xUer9g2Rq9fXXrHgUA164544IdY4aDisxd9U78U0K7WaPtbvphiVl4GbgVnfTEgNVdpXcQxUtcXPZMiBRz5+E+1fExmCfO6+7mZ/yzDrsFYoRdmuo1SMGRI4iqb5jl/PImZ9ukTqRmQdqd3WJp3zzPbIEJPwhMtS5LMxzBMSfugXwjEajkXybcH5CWQ7jo+ogNqcM/CcJ3q4ahYuLTN7VeZWZ8h5kwr9bPxPooZuhWw0WPRa+XUM22o= - file: - - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" - - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz.asc" - - "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.spk" + file: + - "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" + - "$ROCKET_DEPLOY_DIR/rocket.chat.tgz.asc" + - "$ROCKET_DEPLOY_DIR/rocket.chat.spk" on: tags: true all_branches: true @@ -42,4 +41,4 @@ after_deploy: - ".travis/docker.sh" env: global: - secure: y9LYMUBDtiAUlIwJEvubBrYLVrjPsPg7ClY5HcFisdm7OwOzMqHcjTFX8Sj2tN/6IXNcZLqFOhHcwuSdM0uUbBIDooTVnwMVSIy6ExZFOaZNrvAf/Axf2k6p15iAmtPmVo7o+us5SRVRQvuP6GqdUPMYIYn71jHrrjUKQp3/hgRZBlpIn7dyPs5WuLVXZda5hVjIjJpSfK1RZDoGd/b7o8jywvFgSdvBiB+lX1VXCVisRJU9yS28CGIcpoxeQg9AFk4Uez6+8+b/koLp3imQddY9VjYyYx2D8fNxRcUujUHux24VG5MSzQRtJh9JwLlJ+pyAN1KUSvoam6R3MQGoKJg0AH3UxikmSQ4yGZwsSkPSqWbRCRgSVmNtq/YLuTJjQEUHmMCxXUb53HdJisAaxaQiOfg/IfqMVtUWeeIfSDDNEhO9WgpuNvf4fOltdwlL2N1YwubR/fGw8/W/to9jSu94FxJHw6c2V4KQOJqq1XA+KtwMMYak82NjfS2DIhcwyf4EaKagkg4HD3z5BYpuxQdeQnkQkvvkvkI26kV+jPkqUGRlejS7AXG4PrhcUUf/nBvvWjUFrLwvk+epkMP3D2k94r2XUl7apyrANTfyTVyOCc1ogUu9N2XC4ShF2uxu5hoNxk+hNTo1D7uSrFE7aM1GpDFRPOUjtpt2E0mqOoQ= + secure: HrPOM5sBibYkMcf9aeQThYPCDiXeLkg0Xgv0HvH88/ku/gphDpNEjHNReHZM3cyfm9y3RhHpVdD+Zzy38S2goKyewRzpXJsuyerOYkjND0v3tivhs9CAX8PAUxj1U5zllTyH4bgW2ZwRtNnwnmtIM/JJlnySMpKVDqIZBpbhn3ph9bJ2J+BW3D3Jw8meQ1vCX8szIibyJK/5QX6HG2RBFXJGYoQ8DmR8jQv0aJQvT1Az5DO4yImk8tX4NP95qOc19Jywr1DsbaSBZeJ8lFJAmBpIGx7KAmUVCcxSxfbXGRhs2K4iEYb3rJ/dU6KiyPsKGUG4aYNGgbvcX0ZxX/BZ6ZU9ff0E4IIf43IxoN3ElrOqOFk5msJAXbrJEreINSzDqKOy8NFYtCQ49E2gwzfage4ZXkhFyx3wMPa5bzpr3ncsTceMjMVz03uL781X6NLuCkUmXv+n8K2MNhJU9Xinpdx1GRJm+0lXJspNNJ1ruHeJtls4epj4bmCwKmmZbFKPXqa5e8xVcMIkwt1LMiHduhE+WgKNHdOMhXrCcTxF62ybLlsHXmyLLJeNjTeKS8QG2XSoonClDAz/1R41I1DsMPblcgz9uvYCf7UtyftbhJ83bnJeEmOYQiwijLG0+QMq+B2+mmZan3Z7Hl7O53dnwuLxz7EO7EhQhY+CqHVgc6s= diff --git a/.travis/sign.key.gpg b/.travis/sign.key.gpg index 6f149e0d544a3242e489f9f0babf3b6bb92a65a1..488e275998d505474fd6a93c263b4931885d7d00 100644 GIT binary patch literal 5117 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 literal 5119 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 -- GitLab From 54aaead278b8087c5f1d1234af18905e88cf369f Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Mon, 4 Jan 2016 19:38:33 -0500 Subject: [PATCH 1096/1338] change build artifact names to remove branch reference --- .docker/dockerfiles/develop/Dockerfile | 37 -------------------------- .docker/dockerfiles/master/Dockerfile | 37 -------------------------- .travis/docker.sh | 12 ++------- .travis/namefiles.sh | 4 +-- .travis/sandstorm.sh | 2 +- .travis/setbranch.sh | 3 --- 6 files changed, 5 insertions(+), 90 deletions(-) delete mode 100644 .docker/dockerfiles/develop/Dockerfile delete mode 100644 .docker/dockerfiles/master/Dockerfile delete mode 100755 .travis/setbranch.sh diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile deleted file mode 100644 index cbb9a7bfe12..00000000000 --- a/.docker/dockerfiles/develop/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-develop.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/.docker/dockerfiles/master/Dockerfile b/.docker/dockerfiles/master/Dockerfile deleted file mode 100644 index dd62d8cc71e..00000000000 --- 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/.travis/docker.sh b/.travis/docker.sh index 255601ef0f5..f3955d255a9 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -4,15 +4,7 @@ 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"'"}'; -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 -fi +CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; 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 18d2dc26da6..f71334fb7f2 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -4,6 +4,6 @@ IFS=$'\n\t' #cd $TRAVIS_BUILD_DIR #export TAG=$(git describe --abbrev=0 --tags) -cp /tmp/build/Rocket.Chat.tar.gz "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" -gpg --armor --detach-sign "$ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.tgz" +cp /tmp/build/Rocket.Chat.tar.gz "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" +gpg --armor --detach-sign "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" ls -l $ROCKET_DEPLOY_DIR diff --git a/.travis/sandstorm.sh b/.travis/sandstorm.sh index 4c74593ac06..9ec3b97b0e6 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 $ROCKET_DEPLOY_DIR/rocket.chat-$ROCKET_BRANCH.spk +spk pack $ROCKET_DEPLOY_DIR/rocket.chat.spk diff --git a/.travis/setbranch.sh b/.travis/setbranch.sh deleted file mode 100755 index cb6a3d7c7a0..00000000000 --- a/.travis/setbranch.sh +++ /dev/null @@ -1,3 +0,0 @@ -export ROCKET_BRANCH="master" -echo $ROCKET_BRANCH - -- GitLab From 8f0cbd83bb3b602e28bf14a403368ee887344edd Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 5 Jan 2016 16:38:28 -0200 Subject: [PATCH 1097/1338] copied alanning:roles package to rocketchat:authorization --- .meteor/versions | 1 - .../rocketchat-authorization/client/roles.js | 132 ++++ .../rocketchat-authorization/lib/roles.js | 716 ++++++++++++++++++ packages/rocketchat-authorization/package.js | 11 +- .../rocketchat-authorization/server/roles.js | 32 + packages/rocketchat-integrations/package.js | 4 +- packages/rocketchat-livechat/package.js | 2 +- 7 files changed, 892 insertions(+), 6 deletions(-) create mode 100644 packages/rocketchat-authorization/client/roles.js create mode 100644 packages/rocketchat-authorization/lib/roles.js create mode 100644 packages/rocketchat-authorization/server/roles.js diff --git a/.meteor/versions b/.meteor/versions index 5124ef1fc47..b177355e558 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,7 +6,6 @@ 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.3 arunoda:streams@0.1.17 autoupdate@1.2.4 diff --git a/packages/rocketchat-authorization/client/roles.js b/packages/rocketchat-authorization/client/roles.js new file mode 100644 index 00000000000..3fb90a5633e --- /dev/null +++ b/packages/rocketchat-authorization/client/roles.js @@ -0,0 +1,132 @@ +"use strict" + + +//////////////////////////////////////////////////////////// +// Debugging helpers +// +// Run this in your browser console to turn on debugging +// for this package: +// +// localstorage.setItem('Roles.debug', true) +// + +Roles.debug = false + +if (localStorage) { + var temp = localStorage.getItem("Roles.debug") + + if ('undefined' !== typeof temp) { + Roles.debug = !!temp + } +} + +/** + * Convenience functions for use on client. + * + * NOTE: You must restrict user actions on the server-side; any + * client-side checks are strictly for convenience and must not be + * trusted. + * + * @module UIHelpers + */ + + +//////////////////////////////////////////////////////////// +// UI helpers +// +// Use a semi-private variable rather than declaring UI +// helpers directly so that we can unit test the helpers. +// XXX For some reason, the UI helpers are not registered +// before the tests run. +// +Roles._uiHelpers = { + + /** + * UI helper to check if current user is in at least one + * of the target roles. For use in client-side templates. + * + * @example + * {{#if isInRole 'admin'}} + * {{/if}} + * + * {{#if isInRole 'editor,user'}} + * {{/if}} + * + * {{#if isInRole 'editor,user' 'group1'}} + * {{/if}} + * + * @method isInRole + * @param {String} role Name of role or comma-seperated list of roles + * @param {String} [group] Optional, name of group to check + * @return {Boolean} true if current user is in at least one of the target roles + * @static + * @for UIHelpers + */ + isInRole: function (role, group) { + var user = Meteor.user(), + comma = (role || '').indexOf(','), + roles + + if (!user) return false + if (!Match.test(role, String)) return false + + if (comma !== -1) { + roles = _.reduce(role.split(','), function (memo, r) { + if (!r || !r.trim()) { + return memo + } + memo.push(r.trim()) + return memo + }, []) + } else { + roles = [role] + } + + if (Match.test(group, String)) { + return Roles.userIsInRole(user, roles, group) + } + + return Roles.userIsInRole(user, roles) + } +} + + + +//////////////////////////////////////////////////////////// +// Register UI helpers +// + +if (Roles.debug && console.log) { + console.log("[roles] Roles.debug =", Roles.debug) +} + +if ('undefined' !== typeof Package.blaze && + 'undefined' !== typeof Package.blaze.Blaze && + 'function' === typeof Package.blaze.Blaze.registerHelper) { + _.each(Roles._uiHelpers, function (func, name) { + if (Roles.debug && console.log) { + console.log("[roles] registering Blaze helper '" + name + "'") + } + Package.blaze.Blaze.registerHelper(name, func) + }) +} + +/** + * Subscription handle for the currently logged in user's permissions. + * + * NOTE: The corresponding publish function, `_roles`, depends on + * `this.userId` so it will automatically re-run when the currently + * logged-in user changes. + * + * @example + * + * `Roles.subscription.ready()` // => `true` if user roles have been loaded + * + * @property subscription + * @type Object + * @for Roles + */ + +Tracker.autorun(function () { + Roles.subscription = Meteor.subscribe("_roles") +}) diff --git a/packages/rocketchat-authorization/lib/roles.js b/packages/rocketchat-authorization/lib/roles.js new file mode 100644 index 00000000000..034b5cf29dc --- /dev/null +++ b/packages/rocketchat-authorization/lib/roles.js @@ -0,0 +1,716 @@ +;(function () { + +/** + * Provides functions related to user authorization. Compatible with built-in Meteor accounts packages. + * + * @module Roles + */ + +/** + * Roles collection documents consist only of an id and a role name. + * ex: { _id:<uuid>, name: "admin" } + */ +if (!Meteor.roles) { + Meteor.roles = new Mongo.Collection("roles") +} + +/** + * Authorization package compatible with built-in Meteor accounts system. + * + * Stores user's current roles in a 'roles' field on the user object. + * + * @class Roles + * @constructor + */ +if ('undefined' === typeof Roles) { + Roles = {} +} + +"use strict"; + +var mixingGroupAndNonGroupErrorMsg = "Roles error: Can't mix grouped and non-grouped roles for same user"; + +_.extend(Roles, { + + /** + * Constant used to reference the special 'global' group that + * can be used to apply blanket permissions across all groups. + * + * @example + * Roles.addUsersToRoles(user, 'admin', Roles.GLOBAL_GROUP) + * Roles.userIsInRole(user, 'admin') // => true + * + * Roles.setUserRoles(user, 'support-staff', Roles.GLOBAL_GROUP) + * Roles.userIsInRole(user, 'support-staff') // => true + * Roles.userIsInRole(user, 'admin') // => false + * + * @property GLOBAL_GROUP + * @type String + * @static + * @final + */ + GLOBAL_GROUP: '__global_roles__', + + + /** + * Create a new role. Whitespace will be trimmed. + * + * @method createRole + * @param {String} role Name of role + * @return {String} id of new role + */ + createRole: function (role) { + var id, + match + + if (!role + || 'string' !== typeof role + || role.trim().length === 0) { + return + } + + try { + id = Meteor.roles.insert({'name': role.trim()}) + return id + } catch (e) { + // (from Meteor accounts-base package, insertUserDoc func) + // XXX string parsing sucks, maybe + // https://jira.mongodb.org/browse/SERVER-3069 will get fixed one day + if (e.name !== 'MongoError') throw e + match = e.err.match(/^E11000 duplicate key error index: ([^ ]+)/) + if (!match) throw e + if (match[1].indexOf('$name') !== -1) + throw new Meteor.Error(403, "Role already exists.") + throw e + } + }, + + /** + * Delete an existing role. Will throw "Role in use" error if any users + * are currently assigned to the target role. + * + * @method deleteRole + * @param {String} role Name of role + */ + deleteRole: function (role) { + if (!role) return + + var foundExistingUser = Meteor.users.findOne( + {roles: {$in: [role]}}, + {fields: {_id: 1}}) + + if (foundExistingUser) { + throw new Meteor.Error(403, 'Role in use') + } + + var thisRole = Meteor.roles.findOne({name: role}) + if (thisRole) { + Meteor.roles.remove({_id: thisRole._id}) + } + }, + + /** + * Add users to roles. Will create roles as needed. + * + * NOTE: Mixing grouped and non-grouped roles for the same user + * is not supported and will throw an error. + * + * Makes 2 calls to database: + * 1. retrieve list of all existing roles + * 2. update users' roles + * + * @example + * Roles.addUsersToRoles(userId, 'admin') + * Roles.addUsersToRoles(userId, ['view-secrets'], 'example.com') + * Roles.addUsersToRoles([user1, user2], ['user','editor']) + * Roles.addUsersToRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') + * Roles.addUsersToRoles(userId, 'admin', Roles.GLOBAL_GROUP) + * + * @method addUsersToRoles + * @param {Array|String} users User id(s) or object(s) with an _id field + * @param {Array|String} roles Name(s) of roles/permissions to add users to + * @param {String} [group] Optional group name. If supplied, roles will be + * specific to that group. + * Group names can not start with a '$' or contain + * null characters. Periods in names '.' are + * automatically converted to underscores. + * The special group Roles.GLOBAL_GROUP provides + * a convenient way to assign blanket roles/permissions + * across all groups. The roles/permissions in the + * Roles.GLOBAL_GROUP group will be automatically + * included in checks for any group. + */ + addUsersToRoles: function (users, roles, group) { + // use Template pattern to update user roles + Roles._updateUserRoles(users, roles, group, Roles._update_$addToSet_fn) + }, + + /** + * Set a users roles/permissions. + * + * @example + * Roles.setUserRoles(userId, 'admin') + * Roles.setUserRoles(userId, ['view-secrets'], 'example.com') + * Roles.setUserRoles([user1, user2], ['user','editor']) + * Roles.setUserRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') + * Roles.setUserRoles(userId, 'admin', Roles.GLOBAL_GROUP) + * + * @method setUserRoles + * @param {Array|String} users User id(s) or object(s) with an _id field + * @param {Array|String} roles Name(s) of roles/permissions to add users to + * @param {String} [group] Optional group name. If supplied, roles will be + * specific to that group. + * Group names can not start with '$'. + * Periods in names '.' are automatically converted + * to underscores. + * The special group Roles.GLOBAL_GROUP provides + * a convenient way to assign blanket roles/permissions + * across all groups. The roles/permissions in the + * Roles.GLOBAL_GROUP group will be automatically + * included in checks for any group. + */ + setUserRoles: function (users, roles, group) { + // use Template pattern to update user roles + Roles._updateUserRoles(users, roles, group, Roles._update_$set_fn) + }, + + /** + * Remove users from roles + * + * @example + * Roles.removeUsersFromRoles(users.bob, 'admin') + * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor']) + * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor', 'user']) + * Roles.removeUsersFromRoles(users.eve, ['user'], 'group1') + * + * @method removeUsersFromRoles + * @param {Array|String} users User id(s) or object(s) with an _id field + * @param {Array|String} roles Name(s) of roles to add users to + * @param {String} [group] Optional. Group name. If supplied, only that + * group will have roles removed. + */ + removeUsersFromRoles: function (users, roles, group) { + var update + + if (!users) throw new Error ("Missing 'users' param") + if (!roles) throw new Error ("Missing 'roles' param") + if (group) { + if ('string' !== typeof group) + throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") + if ('$' === group[0]) + throw new Error ("Roles error: groups can not start with '$'") + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + // ensure arrays + if (!_.isArray(users)) users = [users] + if (!_.isArray(roles)) roles = [roles] + + // ensure users is an array of user ids + users = _.reduce(users, function (memo, user) { + var _id + if ('string' === typeof user) { + memo.push(user) + } else if ('object' === typeof user) { + _id = user._id + if ('string' === typeof _id) { + memo.push(_id) + } + } + return memo + }, []) + + // update all users, remove from roles set + + if (group) { + update = {$pullAll: {}} + update.$pullAll['roles.'+group] = roles + } else { + update = {$pullAll: {roles: roles}} + } + + try { + if (Meteor.isClient) { + // Iterate over each user to fulfill Meteor's 'one update per ID' policy + _.each(users, function (user) { + Meteor.users.update({_id:user}, update) + }) + } else { + // On the server we can leverage MongoDB's $in operator for performance + Meteor.users.update({_id:{$in:users}}, update, {multi: true}) + } + } + catch (ex) { + if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { + throw new Error (mixingGroupAndNonGroupErrorMsg) + } + + throw ex + } + }, + + /** + * Check if user has specified permissions/roles + * + * @example + * // non-group usage + * Roles.userIsInRole(user, 'admin') + * Roles.userIsInRole(user, ['admin','editor']) + * Roles.userIsInRole(userId, 'admin') + * Roles.userIsInRole(userId, ['admin','editor']) + * + * // per-group usage + * Roles.userIsInRole(user, ['admin','editor'], 'group1') + * Roles.userIsInRole(userId, ['admin','editor'], 'group1') + * Roles.userIsInRole(userId, ['admin','editor'], Roles.GLOBAL_GROUP) + * + * // this format can also be used as short-hand for Roles.GLOBAL_GROUP + * Roles.userIsInRole(user, 'admin') + * + * @method userIsInRole + * @param {String|Object} user User Id or actual user object + * @param {String|Array} roles Name of role/permission or Array of + * roles/permissions to check against. If array, + * will return true if user is in _any_ role. + * @param {String} [group] Optional. Name of group. If supplied, limits check + * to just that group. + * The user's Roles.GLOBAL_GROUP will always be checked + * whether group is specified or not. + * @return {Boolean} true if user is in _any_ of the target roles + */ + userIsInRole: function (user, roles, group) { + var id, + userRoles, + query, + groupQuery, + found = false + + // ensure array to simplify code + if (!_.isArray(roles)) { + roles = [roles] + } + + if (!user) return false + if (group) { + if ('string' !== typeof group) return false + if ('$' === group[0]) return false + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + if ('object' === typeof user) { + userRoles = user.roles + if (_.isArray(userRoles)) { + return _.some(roles, function (role) { + return _.contains(userRoles, role) + }) + } else if ('object' === typeof userRoles) { + // roles field is dictionary of groups + found = _.isArray(userRoles[group]) && _.some(roles, function (role) { + return _.contains(userRoles[group], role) + }) + if (!found) { + // not found in regular group or group not specified. + // check Roles.GLOBAL_GROUP, if it exists + found = _.isArray(userRoles[Roles.GLOBAL_GROUP]) && _.some(roles, function (role) { + return _.contains(userRoles[Roles.GLOBAL_GROUP], role) + }) + } + return found + } + + // missing roles field, try going direct via id + id = user._id + } else if ('string' === typeof user) { + id = user + } + + if (!id) return false + + + query = {_id: id, $or: []} + + // always check Roles.GLOBAL_GROUP + groupQuery = {} + groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} + query.$or.push(groupQuery) + + if (group) { + // structure of query, when group specified including Roles.GLOBAL_GROUP + // {_id: id, + // $or: [ + // {'roles.group1':{$in: ['admin']}}, + // {'roles.__global_roles__':{$in: ['admin']}} + // ]} + groupQuery = {} + groupQuery['roles.'+group] = {$in: roles} + query.$or.push(groupQuery) + } else { + // structure of query, where group not specified. includes + // Roles.GLOBAL_GROUP + // {_id: id, + // $or: [ + // {roles: {$in: ['admin']}}, + // {'roles.__global_roles__': {$in: ['admin']}} + // ]} + query.$or.push({roles: {$in: roles}}) + } + + found = Meteor.users.findOne(query, {fields: {_id: 1}}) + return found ? true : false + }, + + /** + * Retrieve users roles + * + * @method getRolesForUser + * @param {String|Object} user User Id or actual user object + * @param {String} [group] Optional name of group to restrict roles to. + * User's Roles.GLOBAL_GROUP will also be included. + * @return {Array} Array of user's roles, unsorted. + */ + getRolesForUser: function (user, group) { + if (!user) return [] + if (group) { + if ('string' !== typeof group) return [] + if ('$' === group[0]) return [] + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + if ('string' === typeof user) { + user = Meteor.users.findOne( + {_id: user}, + {fields: {roles: 1}}) + + } else if ('object' !== typeof user) { + // invalid user object + return [] + } + + if (!user || !user.roles) return [] + + if (group) { + return _.union(user.roles[group] || [], user.roles[Roles.GLOBAL_GROUP] || []) + } + + if (_.isArray(user.roles)) + return user.roles + + // using groups but group not specified. return global group, if exists + return user.roles[Roles.GLOBAL_GROUP] || [] + }, + + /** + * Retrieve set of all existing roles + * + * @method getAllRoles + * @return {Cursor} cursor of existing roles + */ + getAllRoles: function () { + return Meteor.roles.find({}, {sort: {name: 1}}) + }, + + /** + * Retrieve all users who are in target role. + * + * NOTE: This is an expensive query; it performs a full collection scan + * on the users collection since there is no index set on the 'roles' field. + * This is by design as most queries will specify an _id so the _id index is + * used automatically. + * + * @method getUsersInRole + * @param {Array|String} role Name of role/permission. If array, users + * returned will have at least one of the roles + * specified but need not have _all_ roles. + * @param {String} [group] Optional name of group to restrict roles to. + * User's Roles.GLOBAL_GROUP will also be checked. + * @param {Object} [options] Optional options which are passed directly + * through to `Meteor.users.find(query, options)` + * @return {Cursor} cursor of users in role + */ + getUsersInRole: function (role, group, options) { + var query, + roles = role, + groupQuery + + // ensure array to simplify query logic + if (!_.isArray(roles)) roles = [roles] + + if (group) { + if ('string' !== typeof group) + throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") + if ('$' === group[0]) + throw new Error ("Roles error: groups can not start with '$'") + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + query = {$or: []} + + // always check Roles.GLOBAL_GROUP + groupQuery = {} + groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} + query.$or.push(groupQuery) + + if (group) { + // structure of query, when group specified including Roles.GLOBAL_GROUP + // { + // $or: [ + // {'roles.group1':{$in: ['admin']}}, + // {'roles.__global_roles__':{$in: ['admin']}} + // ]} + groupQuery = {} + groupQuery['roles.'+group] = {$in: roles} + query.$or.push(groupQuery) + } else { + // structure of query, where group not specified. includes + // Roles.GLOBAL_GROUP + // { + // $or: [ + // {roles: {$in: ['admin']}}, + // {'roles.__global_roles__': {$in: ['admin']}} + // ]} + query.$or.push({roles: {$in: roles}}) + } + + return Meteor.users.find(query, options); + }, // end getUsersInRole + + /** + * Retrieve users groups, if any + * + * @method getGroupsForUser + * @param {String|Object} user User Id or actual user object + * @param {String} [role] Optional name of roles to restrict groups to. + * + * @return {Array} Array of user's groups, unsorted. Roles.GLOBAL_GROUP will be omitted + */ + getGroupsForUser: function (user, role) { + var userGroups = []; + + if (!user) return [] + if (role) { + if ('string' !== typeof role) return [] + if ('$' === role[0]) return [] + + // convert any periods to underscores + role = role.replace('.', '_') + } + + if ('string' === typeof user) { + user = Meteor.users.findOne( + {_id: user}, + {fields: {roles: 1}}) + + }else if ('object' !== typeof user) { + // invalid user object + return [] + } + + //User has no roles or is not using groups + if (!user || !user.roles || _.isArray(user.roles)) return [] + + if (role) { + _.each(user.roles, function(groupRoles, groupName) { + if (_.contains(groupRoles, role) && groupName !== Roles.GLOBAL_GROUP) { + userGroups.push(groupName); + } + }); + return userGroups; + }else { + return _.without(_.keys(user.roles), Roles.GLOBAL_GROUP); + } + + }, //End getGroupsForUser + + + /** + * Private function 'template' that uses $set to construct an update object + * for MongoDB. Passed to _updateUserRoles + * + * @method _update_$set_fn + * @protected + * @param {Array} roles + * @param {String} [group] + * @return {Object} update object for use in MongoDB update command + */ + _update_$set_fn: function (roles, group) { + var update = {} + + if (group) { + // roles is a key/value dict object + update.$set = {} + update.$set['roles.' + group] = roles + } else { + // roles is an array of strings + update.$set = {roles: roles} + } + + return update + }, // end _update_$set_fn + + /** + * Private function 'template' that uses $addToSet to construct an update + * object for MongoDB. Passed to _updateUserRoles + * + * @method _update_$addToSet_fn + * @protected + * @param {Array} roles + * @param {String} [group] + * @return {Object} update object for use in MongoDB update command + */ + _update_$addToSet_fn: function (roles, group) { + var update = {} + + if (group) { + // roles is a key/value dict object + update.$addToSet = {} + update.$addToSet['roles.' + group] = {$each: roles} + } else { + // roles is an array of strings + update.$addToSet = {roles: {$each: roles}} + } + + return update + }, // end _update_$addToSet_fn + + + /** + * Internal function that uses the Template pattern to adds or sets roles + * for users. + * + * @method _updateUserRoles + * @protected + * @param {Array|String} users user id(s) or object(s) with an _id field + * @param {Array|String} roles name(s) of roles/permissions to add users to + * @param {String} group Group name. If not null or undefined, roles will be + * specific to that group. + * Group names can not start with '$'. + * Periods in names '.' are automatically converted + * to underscores. + * The special group Roles.GLOBAL_GROUP provides + * a convenient way to assign blanket roles/permissions + * across all groups. The roles/permissions in the + * Roles.GLOBAL_GROUP group will be automatically + * included in checks for any group. + * @param {Function} updateFactory Func which returns an update object that + * will be passed to Mongo. + * @param {Array} roles + * @param {String} [group] + */ + _updateUserRoles: function (users, roles, group, updateFactory) { + if (!users) throw new Error ("Missing 'users' param") + if (!roles) throw new Error ("Missing 'roles' param") + if (group) { + if ('string' !== typeof group) + throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") + if ('$' === group[0]) + throw new Error ("Roles error: groups can not start with '$'") + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + var existingRoles, + query, + update + + // ensure arrays to simplify code + if (!_.isArray(users)) users = [users] + if (!_.isArray(roles)) roles = [roles] + + // remove invalid roles + roles = _.reduce(roles, function (memo, role) { + if (role + && 'string' === typeof role + && role.trim().length > 0) { + memo.push(role.trim()) + } + return memo + }, []) + + // empty roles array is ok, since it might be a $set operation to clear roles + //if (roles.length === 0) return + + // ensure all roles exist in 'roles' collection + existingRoles = _.reduce(Meteor.roles.find({}).fetch(), function (memo, role) { + memo[role.name] = true + return memo + }, {}) + _.each(roles, function (role) { + if (!existingRoles[role]) { + Roles.createRole(role) + } + }) + + // ensure users is an array of user ids + users = _.reduce(users, function (memo, user) { + var _id + if ('string' === typeof user) { + memo.push(user) + } else if ('object' === typeof user) { + _id = user._id + if ('string' === typeof _id) { + memo.push(_id) + } + } + return memo + }, []) + + // update all users + update = updateFactory(roles, group) + + try { + if (Meteor.isClient) { + // On client, iterate over each user to fulfill Meteor's + // 'one update per ID' policy + _.each(users, function (user) { + Meteor.users.update({_id: user}, update) + }) + } else { + // On the server we can use MongoDB's $in operator for + // better performance + Meteor.users.update( + {_id: {$in: users}}, + update, + {multi: true}) + } + } + catch (ex) { + if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { + throw new Error (mixingGroupAndNonGroupErrorMsg) + } + + throw ex + } + } // end _updateUserRoles + +}) // end _.extend(Roles ...) + + +function isMongoMixError (errorMsg) { + var expectedMessages = [ + 'Cannot apply $addToSet modifier to non-array', + 'Cannot apply $addToSet to a non-array field', + 'Can only apply $pullAll to an array', + 'Cannot apply $pull/$pullAll modifier to non-array', + "can't append to array using string field name", + 'to traverse the element' + ] + + return _.some(expectedMessages, function (snippet) { + return strContains(errorMsg, snippet) + }) +} + +function strContains (haystack, needle) { + return -1 !== haystack.indexOf(needle) +} + +}()); diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index e416cd4118e..57a4b8f8430 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -11,16 +11,21 @@ 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('kadira:flow-router', 'client'); api.use('less@2.5.1', 'client'); + api.use('tracker', 'client'); api.use('templating', 'client'); + // roles + api.addFiles('server/roles.js', ['server']); + api.addFiles('lib/roles.js', ['client', 'server']); + api.addFiles('client/roles.js', ['client']); + api.addFiles('lib/rocketchat.coffee', ['server','client']); api.addFiles('client/collection.coffee', ['client']); api.addFiles('client/startup.coffee', ['client']); @@ -73,4 +78,6 @@ Package.onUse(function(api) { })); api.use('tap:i18n'); api.addFiles(tapi18nFiles); + + api.export('Roles'); }); diff --git a/packages/rocketchat-authorization/server/roles.js b/packages/rocketchat-authorization/server/roles.js new file mode 100644 index 00000000000..4e35318e3b7 --- /dev/null +++ b/packages/rocketchat-authorization/server/roles.js @@ -0,0 +1,32 @@ +"use strict" + + +/** + * Roles collection documents consist only of an id and a role name. + * ex: { _id: "123", name: "admin" } + */ +if (!Meteor.roles) { + Meteor.roles = new Meteor.Collection("roles") + + // Create default indexes for roles collection + Meteor.roles._ensureIndex('name', {unique: 1}) +} + + +/** + * Publish logged-in user's roles so client-side checks can work. + * + * Use a named publish function so clients can check `ready()` state. + */ +Meteor.publish('_roles', function () { + var loggedInUserId = this.userId, + fields = {roles: 1} + + if (!loggedInUserId) { + this.ready() + return + } + + return Meteor.users.find({_id: loggedInUserId}, + {fields: fields}) +}) diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index 0f532edc0aa..dc2b48f48e4 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -12,8 +12,8 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); api.use('simple:highlight.js'); - api.use('rocketchat:lib@0.0.1'); - api.use('alanning:roles@1.2.12'); + api.use('rocketchat:lib'); + api.use('rocketchat:authorization'); api.use('kadira:flow-router', 'client'); api.use('templating', 'client'); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index ba6ad05214e..f4bc85d93f7 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -20,8 +20,8 @@ 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('kadira:flow-router', 'client'); api.use('templating', 'client'); api.use('mongo'); -- GitLab From dfa4358a6a2ef34d95161b91d46dd7512b73a471 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 16:58:13 -0200 Subject: [PATCH 1098/1338] Init style of oauth popup --- .../client/oauth2-client.html | 12 ++++++----- .../client/stylesheets/load.coffee | 2 ++ .../client/stylesheets/oauth2.less | 20 +++++++++++++++++++ .../package.js | 5 +++++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee create mode 100644 packages/rocketchat-oauth2-server-config/client/stylesheets/oauth2.less diff --git a/packages/rocketchat-oauth2-server-config/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/client/oauth2-client.html index 11ab80a236a..8251d160dc6 100644 --- a/packages/rocketchat-oauth2-server-config/client/oauth2-client.html +++ b/packages/rocketchat-oauth2-server-config/client/oauth2-client.html @@ -1,17 +1,19 @@ <template name="authorize"> {{#if currentUser}} + <div class="oauth-panel"> <form method="post" action="" role="form" class="{{#unless Template.subscriptionsReady}}hidden{{/unless}}"> - <h2>Authorise</h2> + <h2>Authorize?</h2> <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"> - <button type="submit">Authorise</button> + <button type="submit" class="button">Authorize</button> </form> - {{#unless Template.subscriptionsReady}} - loading - {{/unless}} + {{#unless Template.subscriptionsReady}} + loading... + {{/unless}} + </div> {{else}} {{> loginButtons}} {{/if}} diff --git a/packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee b/packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee new file mode 100644 index 00000000000..794b9ecd4a0 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee @@ -0,0 +1,2 @@ +RocketChat.theme.addPackageAsset -> + return Assets.getText 'client/stylesheets/oauth2.less' diff --git a/packages/rocketchat-oauth2-server-config/client/stylesheets/oauth2.less b/packages/rocketchat-oauth2-server-config/client/stylesheets/oauth2.less new file mode 100644 index 00000000000..1a047954699 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/client/stylesheets/oauth2.less @@ -0,0 +1,20 @@ +.oauth-panel { + position: absolute; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + left: 0px; + right: 0px; + top: 0px; + bottom: 0px; + + form { + min-width: 400px; + text-align: center; + background-color: #fafafa; + border: 1px solid #eee; + border-radius: 6px; + padding: 40px; + } +} diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js index 5ae15157447..ac5f7ee5319 100644 --- a/packages/rocketchat-oauth2-server-config/package.js +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -9,6 +9,8 @@ Package.onUse(function(api) { api.use('webapp'); api.use('coffeescript'); + api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:theme'); api.use('rocketchat:oauth2-server'); api.use('templating', 'client'); @@ -18,4 +20,7 @@ Package.onUse(function(api) { api.addFiles('client/oauth2-client.html', 'client'); api.addFiles('client/oauth2-client.coffee', 'client'); + + api.addAssets('client/stylesheets/oauth2.less', 'server'); + api.addFiles('client/stylesheets/load.coffee', 'server'); }); -- GitLab From 6ee6124b57bf26fcb24a9b177a51f273bcb72ffa Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 5 Jan 2016 17:34:41 -0200 Subject: [PATCH 1099/1338] fix download URL --- .docker/dockerfiles/latest/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index 6e52e7fdf7f..db4b87bc445 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -18,7 +18,7 @@ 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') \ +&& HEADER=$(curl -I -s "$URL" | grep -Fi Location: | sed -En 's/.*(https?:\/\/[a-zA-Z0-9\/.-_]*).*$/\1/p') | sed 's/\/tag\//\/download\//' \ && curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ -- GitLab From ef83ce39dd2a642cc81b8bca81030e02a5061441 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 5 Jan 2016 18:03:54 -0200 Subject: [PATCH 1100/1338] Create publication to populate roles field in model scopes --- .meteor/versions | 2 +- .../rocketchat-authorization/client/roles.js | 114 +- .../rocketchat-authorization/lib/roles.js | 1343 ++++++++--------- packages/rocketchat-authorization/package.js | 5 +- .../server/models/Users.js | 13 + .../server/publications/integrations.coffee | 0 .../rocketchat-authorization/server/roles.js | 26 +- .../server/startup.coffee | 17 +- 8 files changed, 710 insertions(+), 810 deletions(-) create mode 100644 packages/rocketchat-authorization/server/models/Users.js delete mode 100644 packages/rocketchat-authorization/server/publications/integrations.coffee diff --git a/.meteor/versions b/.meteor/versions index b177355e558..fbe33574b40 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -85,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.0 monbro:mongodb-mapreduce-aggregation@1.0.1 mongo@1.1.3 mongo-id@1.0.1 diff --git a/packages/rocketchat-authorization/client/roles.js b/packages/rocketchat-authorization/client/roles.js index 3fb90a5633e..30daddeed72 100644 --- a/packages/rocketchat-authorization/client/roles.js +++ b/packages/rocketchat-authorization/client/roles.js @@ -1,116 +1,5 @@ "use strict" - -//////////////////////////////////////////////////////////// -// Debugging helpers -// -// Run this in your browser console to turn on debugging -// for this package: -// -// localstorage.setItem('Roles.debug', true) -// - -Roles.debug = false - -if (localStorage) { - var temp = localStorage.getItem("Roles.debug") - - if ('undefined' !== typeof temp) { - Roles.debug = !!temp - } -} - -/** - * Convenience functions for use on client. - * - * NOTE: You must restrict user actions on the server-side; any - * client-side checks are strictly for convenience and must not be - * trusted. - * - * @module UIHelpers - */ - - -//////////////////////////////////////////////////////////// -// UI helpers -// -// Use a semi-private variable rather than declaring UI -// helpers directly so that we can unit test the helpers. -// XXX For some reason, the UI helpers are not registered -// before the tests run. -// -Roles._uiHelpers = { - - /** - * UI helper to check if current user is in at least one - * of the target roles. For use in client-side templates. - * - * @example - * {{#if isInRole 'admin'}} - * {{/if}} - * - * {{#if isInRole 'editor,user'}} - * {{/if}} - * - * {{#if isInRole 'editor,user' 'group1'}} - * {{/if}} - * - * @method isInRole - * @param {String} role Name of role or comma-seperated list of roles - * @param {String} [group] Optional, name of group to check - * @return {Boolean} true if current user is in at least one of the target roles - * @static - * @for UIHelpers - */ - isInRole: function (role, group) { - var user = Meteor.user(), - comma = (role || '').indexOf(','), - roles - - if (!user) return false - if (!Match.test(role, String)) return false - - if (comma !== -1) { - roles = _.reduce(role.split(','), function (memo, r) { - if (!r || !r.trim()) { - return memo - } - memo.push(r.trim()) - return memo - }, []) - } else { - roles = [role] - } - - if (Match.test(group, String)) { - return Roles.userIsInRole(user, roles, group) - } - - return Roles.userIsInRole(user, roles) - } -} - - - -//////////////////////////////////////////////////////////// -// Register UI helpers -// - -if (Roles.debug && console.log) { - console.log("[roles] Roles.debug =", Roles.debug) -} - -if ('undefined' !== typeof Package.blaze && - 'undefined' !== typeof Package.blaze.Blaze && - 'function' === typeof Package.blaze.Blaze.registerHelper) { - _.each(Roles._uiHelpers, function (func, name) { - if (Roles.debug && console.log) { - console.log("[roles] registering Blaze helper '" + name + "'") - } - Package.blaze.Blaze.registerHelper(name, func) - }) -} - /** * Subscription handle for the currently logged in user's permissions. * @@ -128,5 +17,6 @@ if ('undefined' !== typeof Package.blaze && */ Tracker.autorun(function () { - Roles.subscription = Meteor.subscribe("_roles") + // Subscribe to global user roles + Meteor.subscribe("scope-roles", "Users") }) diff --git a/packages/rocketchat-authorization/lib/roles.js b/packages/rocketchat-authorization/lib/roles.js index 034b5cf29dc..daa8bf6d904 100644 --- a/packages/rocketchat-authorization/lib/roles.js +++ b/packages/rocketchat-authorization/lib/roles.js @@ -11,7 +11,7 @@ * ex: { _id:<uuid>, name: "admin" } */ if (!Meteor.roles) { - Meteor.roles = new Mongo.Collection("roles") + Meteor.roles = new Mongo.Collection("roles") } /** @@ -23,7 +23,7 @@ if (!Meteor.roles) { * @constructor */ if ('undefined' === typeof Roles) { - Roles = {} + Roles = {} } "use strict"; @@ -32,685 +32,682 @@ var mixingGroupAndNonGroupErrorMsg = "Roles error: Can't mix grouped and non-gro _.extend(Roles, { - /** - * Constant used to reference the special 'global' group that - * can be used to apply blanket permissions across all groups. - * - * @example - * Roles.addUsersToRoles(user, 'admin', Roles.GLOBAL_GROUP) - * Roles.userIsInRole(user, 'admin') // => true - * - * Roles.setUserRoles(user, 'support-staff', Roles.GLOBAL_GROUP) - * Roles.userIsInRole(user, 'support-staff') // => true - * Roles.userIsInRole(user, 'admin') // => false - * - * @property GLOBAL_GROUP - * @type String - * @static - * @final - */ - GLOBAL_GROUP: '__global_roles__', - - - /** - * Create a new role. Whitespace will be trimmed. - * - * @method createRole - * @param {String} role Name of role - * @return {String} id of new role - */ - createRole: function (role) { - var id, - match - - if (!role - || 'string' !== typeof role - || role.trim().length === 0) { - return - } - - try { - id = Meteor.roles.insert({'name': role.trim()}) - return id - } catch (e) { - // (from Meteor accounts-base package, insertUserDoc func) - // XXX string parsing sucks, maybe - // https://jira.mongodb.org/browse/SERVER-3069 will get fixed one day - if (e.name !== 'MongoError') throw e - match = e.err.match(/^E11000 duplicate key error index: ([^ ]+)/) - if (!match) throw e - if (match[1].indexOf('$name') !== -1) - throw new Meteor.Error(403, "Role already exists.") - throw e - } - }, - - /** - * Delete an existing role. Will throw "Role in use" error if any users - * are currently assigned to the target role. - * - * @method deleteRole - * @param {String} role Name of role - */ - deleteRole: function (role) { - if (!role) return - - var foundExistingUser = Meteor.users.findOne( - {roles: {$in: [role]}}, - {fields: {_id: 1}}) - - if (foundExistingUser) { - throw new Meteor.Error(403, 'Role in use') - } - - var thisRole = Meteor.roles.findOne({name: role}) - if (thisRole) { - Meteor.roles.remove({_id: thisRole._id}) - } - }, - - /** - * Add users to roles. Will create roles as needed. - * - * NOTE: Mixing grouped and non-grouped roles for the same user - * is not supported and will throw an error. - * - * Makes 2 calls to database: - * 1. retrieve list of all existing roles - * 2. update users' roles - * - * @example - * Roles.addUsersToRoles(userId, 'admin') - * Roles.addUsersToRoles(userId, ['view-secrets'], 'example.com') - * Roles.addUsersToRoles([user1, user2], ['user','editor']) - * Roles.addUsersToRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') - * Roles.addUsersToRoles(userId, 'admin', Roles.GLOBAL_GROUP) - * - * @method addUsersToRoles - * @param {Array|String} users User id(s) or object(s) with an _id field - * @param {Array|String} roles Name(s) of roles/permissions to add users to - * @param {String} [group] Optional group name. If supplied, roles will be - * specific to that group. - * Group names can not start with a '$' or contain - * null characters. Periods in names '.' are - * automatically converted to underscores. - * The special group Roles.GLOBAL_GROUP provides - * a convenient way to assign blanket roles/permissions - * across all groups. The roles/permissions in the - * Roles.GLOBAL_GROUP group will be automatically - * included in checks for any group. - */ - addUsersToRoles: function (users, roles, group) { - // use Template pattern to update user roles - Roles._updateUserRoles(users, roles, group, Roles._update_$addToSet_fn) - }, - - /** - * Set a users roles/permissions. - * - * @example - * Roles.setUserRoles(userId, 'admin') - * Roles.setUserRoles(userId, ['view-secrets'], 'example.com') - * Roles.setUserRoles([user1, user2], ['user','editor']) - * Roles.setUserRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') - * Roles.setUserRoles(userId, 'admin', Roles.GLOBAL_GROUP) - * - * @method setUserRoles - * @param {Array|String} users User id(s) or object(s) with an _id field - * @param {Array|String} roles Name(s) of roles/permissions to add users to - * @param {String} [group] Optional group name. If supplied, roles will be - * specific to that group. - * Group names can not start with '$'. - * Periods in names '.' are automatically converted - * to underscores. - * The special group Roles.GLOBAL_GROUP provides - * a convenient way to assign blanket roles/permissions - * across all groups. The roles/permissions in the - * Roles.GLOBAL_GROUP group will be automatically - * included in checks for any group. - */ - setUserRoles: function (users, roles, group) { - // use Template pattern to update user roles - Roles._updateUserRoles(users, roles, group, Roles._update_$set_fn) - }, - - /** - * Remove users from roles - * - * @example - * Roles.removeUsersFromRoles(users.bob, 'admin') - * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor']) - * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor', 'user']) - * Roles.removeUsersFromRoles(users.eve, ['user'], 'group1') - * - * @method removeUsersFromRoles - * @param {Array|String} users User id(s) or object(s) with an _id field - * @param {Array|String} roles Name(s) of roles to add users to - * @param {String} [group] Optional. Group name. If supplied, only that - * group will have roles removed. - */ - removeUsersFromRoles: function (users, roles, group) { - var update - - if (!users) throw new Error ("Missing 'users' param") - if (!roles) throw new Error ("Missing 'roles' param") - if (group) { - if ('string' !== typeof group) - throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") - if ('$' === group[0]) - throw new Error ("Roles error: groups can not start with '$'") - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - // ensure arrays - if (!_.isArray(users)) users = [users] - if (!_.isArray(roles)) roles = [roles] - - // ensure users is an array of user ids - users = _.reduce(users, function (memo, user) { - var _id - if ('string' === typeof user) { - memo.push(user) - } else if ('object' === typeof user) { - _id = user._id - if ('string' === typeof _id) { - memo.push(_id) - } - } - return memo - }, []) - - // update all users, remove from roles set - - if (group) { - update = {$pullAll: {}} - update.$pullAll['roles.'+group] = roles - } else { - update = {$pullAll: {roles: roles}} - } - - try { - if (Meteor.isClient) { - // Iterate over each user to fulfill Meteor's 'one update per ID' policy - _.each(users, function (user) { - Meteor.users.update({_id:user}, update) - }) - } else { - // On the server we can leverage MongoDB's $in operator for performance - Meteor.users.update({_id:{$in:users}}, update, {multi: true}) - } - } - catch (ex) { - if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { - throw new Error (mixingGroupAndNonGroupErrorMsg) - } - - throw ex - } - }, - - /** - * Check if user has specified permissions/roles - * - * @example - * // non-group usage - * Roles.userIsInRole(user, 'admin') - * Roles.userIsInRole(user, ['admin','editor']) - * Roles.userIsInRole(userId, 'admin') - * Roles.userIsInRole(userId, ['admin','editor']) - * - * // per-group usage - * Roles.userIsInRole(user, ['admin','editor'], 'group1') - * Roles.userIsInRole(userId, ['admin','editor'], 'group1') - * Roles.userIsInRole(userId, ['admin','editor'], Roles.GLOBAL_GROUP) - * - * // this format can also be used as short-hand for Roles.GLOBAL_GROUP - * Roles.userIsInRole(user, 'admin') - * - * @method userIsInRole - * @param {String|Object} user User Id or actual user object - * @param {String|Array} roles Name of role/permission or Array of - * roles/permissions to check against. If array, - * will return true if user is in _any_ role. - * @param {String} [group] Optional. Name of group. If supplied, limits check - * to just that group. - * The user's Roles.GLOBAL_GROUP will always be checked - * whether group is specified or not. - * @return {Boolean} true if user is in _any_ of the target roles - */ - userIsInRole: function (user, roles, group) { - var id, - userRoles, - query, - groupQuery, - found = false - - // ensure array to simplify code - if (!_.isArray(roles)) { - roles = [roles] - } - - if (!user) return false - if (group) { - if ('string' !== typeof group) return false - if ('$' === group[0]) return false - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - if ('object' === typeof user) { - userRoles = user.roles - if (_.isArray(userRoles)) { - return _.some(roles, function (role) { - return _.contains(userRoles, role) - }) - } else if ('object' === typeof userRoles) { - // roles field is dictionary of groups - found = _.isArray(userRoles[group]) && _.some(roles, function (role) { - return _.contains(userRoles[group], role) - }) - if (!found) { - // not found in regular group or group not specified. - // check Roles.GLOBAL_GROUP, if it exists - found = _.isArray(userRoles[Roles.GLOBAL_GROUP]) && _.some(roles, function (role) { - return _.contains(userRoles[Roles.GLOBAL_GROUP], role) - }) - } - return found - } - - // missing roles field, try going direct via id - id = user._id - } else if ('string' === typeof user) { - id = user - } - - if (!id) return false - - - query = {_id: id, $or: []} - - // always check Roles.GLOBAL_GROUP - groupQuery = {} - groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} - query.$or.push(groupQuery) - - if (group) { - // structure of query, when group specified including Roles.GLOBAL_GROUP - // {_id: id, - // $or: [ - // {'roles.group1':{$in: ['admin']}}, - // {'roles.__global_roles__':{$in: ['admin']}} - // ]} - groupQuery = {} - groupQuery['roles.'+group] = {$in: roles} - query.$or.push(groupQuery) - } else { - // structure of query, where group not specified. includes - // Roles.GLOBAL_GROUP - // {_id: id, - // $or: [ - // {roles: {$in: ['admin']}}, - // {'roles.__global_roles__': {$in: ['admin']}} - // ]} - query.$or.push({roles: {$in: roles}}) - } - - found = Meteor.users.findOne(query, {fields: {_id: 1}}) - return found ? true : false - }, - - /** - * Retrieve users roles - * - * @method getRolesForUser - * @param {String|Object} user User Id or actual user object - * @param {String} [group] Optional name of group to restrict roles to. - * User's Roles.GLOBAL_GROUP will also be included. - * @return {Array} Array of user's roles, unsorted. - */ - getRolesForUser: function (user, group) { - if (!user) return [] - if (group) { - if ('string' !== typeof group) return [] - if ('$' === group[0]) return [] - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - if ('string' === typeof user) { - user = Meteor.users.findOne( - {_id: user}, - {fields: {roles: 1}}) - - } else if ('object' !== typeof user) { - // invalid user object - return [] - } - - if (!user || !user.roles) return [] - - if (group) { - return _.union(user.roles[group] || [], user.roles[Roles.GLOBAL_GROUP] || []) - } - - if (_.isArray(user.roles)) - return user.roles - - // using groups but group not specified. return global group, if exists - return user.roles[Roles.GLOBAL_GROUP] || [] - }, - - /** - * Retrieve set of all existing roles - * - * @method getAllRoles - * @return {Cursor} cursor of existing roles - */ - getAllRoles: function () { - return Meteor.roles.find({}, {sort: {name: 1}}) - }, - - /** - * Retrieve all users who are in target role. - * - * NOTE: This is an expensive query; it performs a full collection scan - * on the users collection since there is no index set on the 'roles' field. - * This is by design as most queries will specify an _id so the _id index is - * used automatically. - * - * @method getUsersInRole - * @param {Array|String} role Name of role/permission. If array, users - * returned will have at least one of the roles - * specified but need not have _all_ roles. - * @param {String} [group] Optional name of group to restrict roles to. - * User's Roles.GLOBAL_GROUP will also be checked. - * @param {Object} [options] Optional options which are passed directly - * through to `Meteor.users.find(query, options)` - * @return {Cursor} cursor of users in role - */ - getUsersInRole: function (role, group, options) { - var query, - roles = role, - groupQuery - - // ensure array to simplify query logic - if (!_.isArray(roles)) roles = [roles] - - if (group) { - if ('string' !== typeof group) - throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") - if ('$' === group[0]) - throw new Error ("Roles error: groups can not start with '$'") - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - query = {$or: []} - - // always check Roles.GLOBAL_GROUP - groupQuery = {} - groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} - query.$or.push(groupQuery) - - if (group) { - // structure of query, when group specified including Roles.GLOBAL_GROUP - // { - // $or: [ - // {'roles.group1':{$in: ['admin']}}, - // {'roles.__global_roles__':{$in: ['admin']}} - // ]} - groupQuery = {} - groupQuery['roles.'+group] = {$in: roles} - query.$or.push(groupQuery) - } else { - // structure of query, where group not specified. includes - // Roles.GLOBAL_GROUP - // { - // $or: [ - // {roles: {$in: ['admin']}}, - // {'roles.__global_roles__': {$in: ['admin']}} - // ]} - query.$or.push({roles: {$in: roles}}) - } - - return Meteor.users.find(query, options); - }, // end getUsersInRole - - /** - * Retrieve users groups, if any - * - * @method getGroupsForUser - * @param {String|Object} user User Id or actual user object - * @param {String} [role] Optional name of roles to restrict groups to. - * - * @return {Array} Array of user's groups, unsorted. Roles.GLOBAL_GROUP will be omitted - */ - getGroupsForUser: function (user, role) { - var userGroups = []; - - if (!user) return [] - if (role) { - if ('string' !== typeof role) return [] - if ('$' === role[0]) return [] - - // convert any periods to underscores - role = role.replace('.', '_') - } - - if ('string' === typeof user) { - user = Meteor.users.findOne( - {_id: user}, - {fields: {roles: 1}}) - - }else if ('object' !== typeof user) { - // invalid user object - return [] - } - - //User has no roles or is not using groups - if (!user || !user.roles || _.isArray(user.roles)) return [] - - if (role) { - _.each(user.roles, function(groupRoles, groupName) { - if (_.contains(groupRoles, role) && groupName !== Roles.GLOBAL_GROUP) { - userGroups.push(groupName); - } - }); - return userGroups; - }else { - return _.without(_.keys(user.roles), Roles.GLOBAL_GROUP); - } - - }, //End getGroupsForUser - - - /** - * Private function 'template' that uses $set to construct an update object - * for MongoDB. Passed to _updateUserRoles - * - * @method _update_$set_fn - * @protected - * @param {Array} roles - * @param {String} [group] - * @return {Object} update object for use in MongoDB update command - */ - _update_$set_fn: function (roles, group) { - var update = {} - - if (group) { - // roles is a key/value dict object - update.$set = {} - update.$set['roles.' + group] = roles - } else { - // roles is an array of strings - update.$set = {roles: roles} - } - - return update - }, // end _update_$set_fn - - /** - * Private function 'template' that uses $addToSet to construct an update - * object for MongoDB. Passed to _updateUserRoles - * - * @method _update_$addToSet_fn - * @protected - * @param {Array} roles - * @param {String} [group] - * @return {Object} update object for use in MongoDB update command - */ - _update_$addToSet_fn: function (roles, group) { - var update = {} - - if (group) { - // roles is a key/value dict object - update.$addToSet = {} - update.$addToSet['roles.' + group] = {$each: roles} - } else { - // roles is an array of strings - update.$addToSet = {roles: {$each: roles}} - } - - return update - }, // end _update_$addToSet_fn - - - /** - * Internal function that uses the Template pattern to adds or sets roles - * for users. - * - * @method _updateUserRoles - * @protected - * @param {Array|String} users user id(s) or object(s) with an _id field - * @param {Array|String} roles name(s) of roles/permissions to add users to - * @param {String} group Group name. If not null or undefined, roles will be - * specific to that group. - * Group names can not start with '$'. - * Periods in names '.' are automatically converted - * to underscores. - * The special group Roles.GLOBAL_GROUP provides - * a convenient way to assign blanket roles/permissions - * across all groups. The roles/permissions in the - * Roles.GLOBAL_GROUP group will be automatically - * included in checks for any group. - * @param {Function} updateFactory Func which returns an update object that - * will be passed to Mongo. - * @param {Array} roles - * @param {String} [group] - */ - _updateUserRoles: function (users, roles, group, updateFactory) { - if (!users) throw new Error ("Missing 'users' param") - if (!roles) throw new Error ("Missing 'roles' param") - if (group) { - if ('string' !== typeof group) - throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") - if ('$' === group[0]) - throw new Error ("Roles error: groups can not start with '$'") - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - var existingRoles, - query, - update - - // ensure arrays to simplify code - if (!_.isArray(users)) users = [users] - if (!_.isArray(roles)) roles = [roles] - - // remove invalid roles - roles = _.reduce(roles, function (memo, role) { - if (role - && 'string' === typeof role - && role.trim().length > 0) { - memo.push(role.trim()) - } - return memo - }, []) - - // empty roles array is ok, since it might be a $set operation to clear roles - //if (roles.length === 0) return - - // ensure all roles exist in 'roles' collection - existingRoles = _.reduce(Meteor.roles.find({}).fetch(), function (memo, role) { - memo[role.name] = true - return memo - }, {}) - _.each(roles, function (role) { - if (!existingRoles[role]) { - Roles.createRole(role) - } - }) - - // ensure users is an array of user ids - users = _.reduce(users, function (memo, user) { - var _id - if ('string' === typeof user) { - memo.push(user) - } else if ('object' === typeof user) { - _id = user._id - if ('string' === typeof _id) { - memo.push(_id) - } - } - return memo - }, []) - - // update all users - update = updateFactory(roles, group) - - try { - if (Meteor.isClient) { - // On client, iterate over each user to fulfill Meteor's - // 'one update per ID' policy - _.each(users, function (user) { - Meteor.users.update({_id: user}, update) - }) - } else { - // On the server we can use MongoDB's $in operator for - // better performance - Meteor.users.update( - {_id: {$in: users}}, - update, - {multi: true}) - } - } - catch (ex) { - if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { - throw new Error (mixingGroupAndNonGroupErrorMsg) - } - - throw ex - } - } // end _updateUserRoles + /** + * Constant used to reference the special 'global' group that + * can be used to apply blanket permissions across all groups. + * + * @example + * Roles.addUsersToRoles(user, 'admin', Roles.GLOBAL_GROUP) + * Roles.userIsInRole(user, 'admin') // => true + * + * Roles.setUserRoles(user, 'support-staff', Roles.GLOBAL_GROUP) + * Roles.userIsInRole(user, 'support-staff') // => true + * Roles.userIsInRole(user, 'admin') // => false + * + * @property GLOBAL_GROUP + * @type String + * @static + * @final + */ + GLOBAL_GROUP: '__global_roles__', + + + /** + * Create a new role. Whitespace will be trimmed. + * + * @method createRole + * @param {String} role Name of role + * @param {String} collection Name of collection storing roles + * @return {String} id of new role + */ + createRole: function (role, collection) { + var id, match; + + if (!role || 'string' !== typeof role || 'string' !== typeof collection || role.trim().length === 0 || collection.trim().length === 0) { + return + } + + try { + id = Meteor.roles.insert({'name': role.trim(), 'collection': collection.trim()}) + return id + } catch (e) { + // (from Meteor accounts-base package, insertUserDoc func) + // XXX string parsing sucks, maybe + // https://jira.mongodb.org/browse/SERVER-3069 will get fixed one day + if (e.name !== 'MongoError') throw e + match = e.err.match(/^E11000 duplicate key error index: ([^ ]+)/) + if (!match) throw e + if (match[1].indexOf('$name') !== -1) + throw new Meteor.Error(403, "Role already exists.") + throw e + } + }, + + /** + * Delete an existing role. Will throw "Role in use" error if any users + * are currently assigned to the target role. + * + * @method deleteRole + * @param {String} role Name of role + */ + deleteRole: function (role) { + if (!role) return + + var thisRole = Meteor.roles.findOne({name: role}) + if (thisRole) { + if (Meteor.isServer && "undefined" !== typeof RocketChat.models[thisRole.collection] && "function" === typeof RocketChat.models[thisRole.collection].getUsersInRole ) { + var users = RocketChat.models[thisRole.collection].getUsersInRole(role) + var foundExistingUser = users.length !== 0 + if (foundExistingUser) { + throw new Meteor.Error(403, 'Role in use') + } + } + Meteor.roles.remove({_id: thisRole._id}) + } + }, + + /** + * Add users to roles. Will create roles as needed. + * + * NOTE: Mixing grouped and non-grouped roles for the same user + * is not supported and will throw an error. + * + * Makes 2 calls to database: + * 1. retrieve list of all existing roles + * 2. update users' roles + * + * @example + * Roles.addUsersToRoles(userId, 'admin') + * Roles.addUsersToRoles(userId, ['view-secrets'], 'example.com') + * Roles.addUsersToRoles([user1, user2], ['user','editor']) + * Roles.addUsersToRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') + * Roles.addUsersToRoles(userId, 'admin', Roles.GLOBAL_GROUP) + * + * @method addUsersToRoles + * @param {Array|String} users User id(s) or object(s) with an _id field + * @param {Array|String} roles Name(s) of roles/permissions to add users to + * @param {String} [group] Optional group name. If supplied, roles will be + * specific to that group. + * Group names can not start with a '$' or contain + * null characters. Periods in names '.' are + * automatically converted to underscores. + * The special group Roles.GLOBAL_GROUP provides + * a convenient way to assign blanket roles/permissions + * across all groups. The roles/permissions in the + * Roles.GLOBAL_GROUP group will be automatically + * included in checks for any group. + */ + addUsersToRoles: function (users, roles, group) { + // use Template pattern to update user roles + Roles._updateUserRoles(users, roles, group, Roles._update_$addToSet_fn) + }, + + /** + * Set a users roles/permissions. + * + * @example + * Roles.setUserRoles(userId, 'admin') + * Roles.setUserRoles(userId, ['view-secrets'], 'example.com') + * Roles.setUserRoles([user1, user2], ['user','editor']) + * Roles.setUserRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') + * Roles.setUserRoles(userId, 'admin', Roles.GLOBAL_GROUP) + * + * @method setUserRoles + * @param {Array|String} users User id(s) or object(s) with an _id field + * @param {Array|String} roles Name(s) of roles/permissions to add users to + * @param {String} [group] Optional group name. If supplied, roles will be + * specific to that group. + * Group names can not start with '$'. + * Periods in names '.' are automatically converted + * to underscores. + * The special group Roles.GLOBAL_GROUP provides + * a convenient way to assign blanket roles/permissions + * across all groups. The roles/permissions in the + * Roles.GLOBAL_GROUP group will be automatically + * included in checks for any group. + */ + setUserRoles: function (users, roles, group) { + // use Template pattern to update user roles + Roles._updateUserRoles(users, roles, group, Roles._update_$set_fn) + }, + + /** + * Remove users from roles + * + * @example + * Roles.removeUsersFromRoles(users.bob, 'admin') + * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor']) + * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor', 'user']) + * Roles.removeUsersFromRoles(users.eve, ['user'], 'group1') + * + * @method removeUsersFromRoles + * @param {Array|String} users User id(s) or object(s) with an _id field + * @param {Array|String} roles Name(s) of roles to add users to + * @param {String} [group] Optional. Group name. If supplied, only that + * group will have roles removed. + */ + removeUsersFromRoles: function (users, roles, group) { + var update + + if (!users) throw new Error ("Missing 'users' param") + if (!roles) throw new Error ("Missing 'roles' param") + if (group) { + if ('string' !== typeof group) + throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") + if ('$' === group[0]) + throw new Error ("Roles error: groups can not start with '$'") + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + // ensure arrays + if (!_.isArray(users)) users = [users] + if (!_.isArray(roles)) roles = [roles] + + // ensure users is an array of user ids + users = _.reduce(users, function (memo, user) { + var _id + if ('string' === typeof user) { + memo.push(user) + } else if ('object' === typeof user) { + _id = user._id + if ('string' === typeof _id) { + memo.push(_id) + } + } + return memo + }, []) + + // update all users, remove from roles set + + if (group) { + update = {$pullAll: {}} + update.$pullAll['roles.'+group] = roles + } else { + update = {$pullAll: {roles: roles}} + } + + try { + if (Meteor.isClient) { + // Iterate over each user to fulfill Meteor's 'one update per ID' policy + _.each(users, function (user) { + Meteor.users.update({_id:user}, update) + }) + } else { + // On the server we can leverage MongoDB's $in operator for performance + Meteor.users.update({_id:{$in:users}}, update, {multi: true}) + } + } + catch (ex) { + if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { + throw new Error (mixingGroupAndNonGroupErrorMsg) + } + + throw ex + } + }, + + /** + * Check if user has specified permissions/roles + * + * @example + * // non-group usage + * Roles.userIsInRole(user, 'admin') + * Roles.userIsInRole(user, ['admin','editor']) + * Roles.userIsInRole(userId, 'admin') + * Roles.userIsInRole(userId, ['admin','editor']) + * + * // per-group usage + * Roles.userIsInRole(user, ['admin','editor'], 'group1') + * Roles.userIsInRole(userId, ['admin','editor'], 'group1') + * Roles.userIsInRole(userId, ['admin','editor'], Roles.GLOBAL_GROUP) + * + * // this format can also be used as short-hand for Roles.GLOBAL_GROUP + * Roles.userIsInRole(user, 'admin') + * + * @method userIsInRole + * @param {String|Object} user User Id or actual user object + * @param {String|Array} roles Name of role/permission or Array of + * roles/permissions to check against. If array, + * will return true if user is in _any_ role. + * @param {String} [group] Optional. Name of group. If supplied, limits check + * to just that group. + * The user's Roles.GLOBAL_GROUP will always be checked + * whether group is specified or not. + * @return {Boolean} true if user is in _any_ of the target roles + */ + userIsInRole: function (user, roles, group) { + var id, + userRoles, + query, + groupQuery, + found = false + + // ensure array to simplify code + if (!_.isArray(roles)) { + roles = [roles] + } + + if (!user) return false + if (group) { + if ('string' !== typeof group) return false + if ('$' === group[0]) return false + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + if ('object' === typeof user) { + userRoles = user.roles + if (_.isArray(userRoles)) { + return _.some(roles, function (role) { + return _.contains(userRoles, role) + }) + } else if ('object' === typeof userRoles) { + // roles field is dictionary of groups + found = _.isArray(userRoles[group]) && _.some(roles, function (role) { + return _.contains(userRoles[group], role) + }) + if (!found) { + // not found in regular group or group not specified. + // check Roles.GLOBAL_GROUP, if it exists + found = _.isArray(userRoles[Roles.GLOBAL_GROUP]) && _.some(roles, function (role) { + return _.contains(userRoles[Roles.GLOBAL_GROUP], role) + }) + } + return found + } + + // missing roles field, try going direct via id + id = user._id + } else if ('string' === typeof user) { + id = user + } + + if (!id) return false + + + query = {_id: id, $or: []} + + // always check Roles.GLOBAL_GROUP + groupQuery = {} + groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} + query.$or.push(groupQuery) + + if (group) { + // structure of query, when group specified including Roles.GLOBAL_GROUP + // {_id: id, + // $or: [ + // {'roles.group1':{$in: ['admin']}}, + // {'roles.__global_roles__':{$in: ['admin']}} + // ]} + groupQuery = {} + groupQuery['roles.'+group] = {$in: roles} + query.$or.push(groupQuery) + } else { + // structure of query, where group not specified. includes + // Roles.GLOBAL_GROUP + // {_id: id, + // $or: [ + // {roles: {$in: ['admin']}}, + // {'roles.__global_roles__': {$in: ['admin']}} + // ]} + query.$or.push({roles: {$in: roles}}) + } + + found = Meteor.users.findOne(query, {fields: {_id: 1}}) + return found ? true : false + }, + + /** + * Retrieve users roles + * + * @method getRolesForUser + * @param {String|Object} user User Id or actual user object + * @param {String} [group] Optional name of group to restrict roles to. + * User's Roles.GLOBAL_GROUP will also be included. + * @return {Array} Array of user's roles, unsorted. + */ + getRolesForUser: function (user, group) { + if (!user) return [] + if (group) { + if ('string' !== typeof group) return [] + if ('$' === group[0]) return [] + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + if ('string' === typeof user) { + user = Meteor.users.findOne( + {_id: user}, + {fields: {roles: 1}}) + + } else if ('object' !== typeof user) { + // invalid user object + return [] + } + + if (!user || !user.roles) return [] + + if (group) { + return _.union(user.roles[group] || [], user.roles[Roles.GLOBAL_GROUP] || []) + } + + if (_.isArray(user.roles)) + return user.roles + + // using groups but group not specified. return global group, if exists + return user.roles[Roles.GLOBAL_GROUP] || [] + }, + + /** + * Retrieve set of all existing roles + * + * @method getAllRoles + * @return {Cursor} cursor of existing roles + */ + getAllRoles: function () { + return Meteor.roles.find({}, {sort: {name: 1}}) + }, + + /** + * Retrieve all users who are in target role. + * + * NOTE: This is an expensive query; it performs a full collection scan + * on the users collection since there is no index set on the 'roles' field. + * This is by design as most queries will specify an _id so the _id index is + * used automatically. + * + * @method getUsersInRole + * @param {Array|String} role Name of role/permission. If array, users + * returned will have at least one of the roles + * specified but need not have _all_ roles. + * @param {String} [group] Optional name of group to restrict roles to. + * User's Roles.GLOBAL_GROUP will also be checked. + * @param {Object} [options] Optional options which are passed directly + * through to `Meteor.users.find(query, options)` + * @return {Cursor} cursor of users in role + */ + getUsersInRole: function (role, group, options) { + var query, + roles = role, + groupQuery + + // ensure array to simplify query logic + if (!_.isArray(roles)) roles = [roles] + + if (group) { + if ('string' !== typeof group) + throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") + if ('$' === group[0]) + throw new Error ("Roles error: groups can not start with '$'") + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + query = {$or: []} + + // always check Roles.GLOBAL_GROUP + groupQuery = {} + groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} + query.$or.push(groupQuery) + + if (group) { + // structure of query, when group specified including Roles.GLOBAL_GROUP + // { + // $or: [ + // {'roles.group1':{$in: ['admin']}}, + // {'roles.__global_roles__':{$in: ['admin']}} + // ]} + groupQuery = {} + groupQuery['roles.'+group] = {$in: roles} + query.$or.push(groupQuery) + } else { + // structure of query, where group not specified. includes + // Roles.GLOBAL_GROUP + // { + // $or: [ + // {roles: {$in: ['admin']}}, + // {'roles.__global_roles__': {$in: ['admin']}} + // ]} + query.$or.push({roles: {$in: roles}}) + } + + return Meteor.users.find(query, options); + }, // end getUsersInRole + + /** + * Retrieve users groups, if any + * + * @method getGroupsForUser + * @param {String|Object} user User Id or actual user object + * @param {String} [role] Optional name of roles to restrict groups to. + * + * @return {Array} Array of user's groups, unsorted. Roles.GLOBAL_GROUP will be omitted + */ + getGroupsForUser: function (user, role) { + var userGroups = []; + + if (!user) return [] + if (role) { + if ('string' !== typeof role) return [] + if ('$' === role[0]) return [] + + // convert any periods to underscores + role = role.replace('.', '_') + } + + if ('string' === typeof user) { + user = Meteor.users.findOne( + {_id: user}, + {fields: {roles: 1}}) + + }else if ('object' !== typeof user) { + // invalid user object + return [] + } + + //User has no roles or is not using groups + if (!user || !user.roles || _.isArray(user.roles)) return [] + + if (role) { + _.each(user.roles, function(groupRoles, groupName) { + if (_.contains(groupRoles, role) && groupName !== Roles.GLOBAL_GROUP) { + userGroups.push(groupName); + } + }); + return userGroups; + }else { + return _.without(_.keys(user.roles), Roles.GLOBAL_GROUP); + } + + }, //End getGroupsForUser + + + /** + * Private function 'template' that uses $set to construct an update object + * for MongoDB. Passed to _updateUserRoles + * + * @method _update_$set_fn + * @protected + * @param {Array} roles + * @param {String} [group] + * @return {Object} update object for use in MongoDB update command + */ + _update_$set_fn: function (roles, group) { + var update = {} + + if (group) { + // roles is a key/value dict object + update.$set = {} + update.$set['roles.' + group] = roles + } else { + // roles is an array of strings + update.$set = {roles: roles} + } + + return update + }, // end _update_$set_fn + + /** + * Private function 'template' that uses $addToSet to construct an update + * object for MongoDB. Passed to _updateUserRoles + * + * @method _update_$addToSet_fn + * @protected + * @param {Array} roles + * @param {String} [group] + * @return {Object} update object for use in MongoDB update command + */ + _update_$addToSet_fn: function (roles, group) { + var update = {} + + if (group) { + // roles is a key/value dict object + update.$addToSet = {} + update.$addToSet['roles.' + group] = {$each: roles} + } else { + // roles is an array of strings + update.$addToSet = {roles: {$each: roles}} + } + + return update + }, // end _update_$addToSet_fn + + + /** + * Internal function that uses the Template pattern to adds or sets roles + * for users. + * + * @method _updateUserRoles + * @protected + * @param {Array|String} users user id(s) or object(s) with an _id field + * @param {Array|String} roles name(s) of roles/permissions to add users to + * @param {String} group Group name. If not null or undefined, roles will be + * specific to that group. + * Group names can not start with '$'. + * Periods in names '.' are automatically converted + * to underscores. + * The special group Roles.GLOBAL_GROUP provides + * a convenient way to assign blanket roles/permissions + * across all groups. The roles/permissions in the + * Roles.GLOBAL_GROUP group will be automatically + * included in checks for any group. + * @param {Function} updateFactory Func which returns an update object that + * will be passed to Mongo. + * @param {Array} roles + * @param {String} [group] + */ + _updateUserRoles: function (users, roles, group, updateFactory) { + if (!users) throw new Error ("Missing 'users' param") + if (!roles) throw new Error ("Missing 'roles' param") + if (group) { + if ('string' !== typeof group) + throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") + if ('$' === group[0]) + throw new Error ("Roles error: groups can not start with '$'") + + // convert any periods to underscores + group = group.replace(/\./g, '_') + } + + var existingRoles, + query, + update + + // ensure arrays to simplify code + if (!_.isArray(users)) users = [users] + if (!_.isArray(roles)) roles = [roles] + + // remove invalid roles + roles = _.reduce(roles, function (memo, role) { + if (role + && 'string' === typeof role + && role.trim().length > 0) { + memo.push(role.trim()) + } + return memo + }, []) + + // empty roles array is ok, since it might be a $set operation to clear roles + //if (roles.length === 0) return + + // ensure all roles exist in 'roles' collection + existingRoles = _.reduce(Meteor.roles.find({}).fetch(), function (memo, role) { + memo[role.name] = true + return memo + }, {}) + _.each(roles, function (role) { + if (!existingRoles[role]) { + Roles.createRole(role) + } + }) + + // ensure users is an array of user ids + users = _.reduce(users, function (memo, user) { + var _id + if ('string' === typeof user) { + memo.push(user) + } else if ('object' === typeof user) { + _id = user._id + if ('string' === typeof _id) { + memo.push(_id) + } + } + return memo + }, []) + + // update all users + update = updateFactory(roles, group) + + try { + if (Meteor.isClient) { + // On client, iterate over each user to fulfill Meteor's + // 'one update per ID' policy + _.each(users, function (user) { + Meteor.users.update({_id: user}, update) + }) + } else { + // On the server we can use MongoDB's $in operator for + // better performance + Meteor.users.update( + {_id: {$in: users}}, + update, + {multi: true}) + } + } + catch (ex) { + if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { + throw new Error (mixingGroupAndNonGroupErrorMsg) + } + + throw ex + } + } // end _updateUserRoles }) // end _.extend(Roles ...) function isMongoMixError (errorMsg) { - var expectedMessages = [ - 'Cannot apply $addToSet modifier to non-array', - 'Cannot apply $addToSet to a non-array field', - 'Can only apply $pullAll to an array', - 'Cannot apply $pull/$pullAll modifier to non-array', - "can't append to array using string field name", - 'to traverse the element' - ] - - return _.some(expectedMessages, function (snippet) { - return strContains(errorMsg, snippet) - }) + var expectedMessages = [ + 'Cannot apply $addToSet modifier to non-array', + 'Cannot apply $addToSet to a non-array field', + 'Can only apply $pullAll to an array', + 'Cannot apply $pull/$pullAll modifier to non-array', + "can't append to array using string field name", + 'to traverse the element' + ] + + return _.some(expectedMessages, function (snippet) { + return strContains(errorMsg, snippet) + }) } function strContains (haystack, needle) { - return -1 !== haystack.indexOf(needle) + return -1 !== haystack.indexOf(needle) } }()); diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 57a4b8f8430..01c08fcba8e 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -14,7 +14,7 @@ Package.onUse(function(api) { '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'); @@ -25,6 +25,7 @@ Package.onUse(function(api) { api.addFiles('server/roles.js', ['server']); api.addFiles('lib/roles.js', ['client', 'server']); api.addFiles('client/roles.js', ['client']); + api.addFiles('server/models/Users.js', ['server']); api.addFiles('lib/rocketchat.coffee', ['server','client']); api.addFiles('client/collection.coffee', ['client']); @@ -79,5 +80,5 @@ Package.onUse(function(api) { api.use('tap:i18n'); api.addFiles(tapi18nFiles); - api.export('Roles'); + api.export('Roles', 'server'); }); diff --git a/packages/rocketchat-authorization/server/models/Users.js b/packages/rocketchat-authorization/server/models/Users.js new file mode 100644 index 00000000000..0d04ea7ad14 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Users.js @@ -0,0 +1,13 @@ +RocketChat.models.Users.findRolesByUserId = function(userId, options) { + query = { + _id: userId + }; + + if ("object" !== typeof options) { + options = {} + } + + options.fields = { roles: 1 } + + return this.find(query, options); +}; diff --git a/packages/rocketchat-authorization/server/publications/integrations.coffee b/packages/rocketchat-authorization/server/publications/integrations.coffee deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/rocketchat-authorization/server/roles.js b/packages/rocketchat-authorization/server/roles.js index 4e35318e3b7..fe98a742d34 100644 --- a/packages/rocketchat-authorization/server/roles.js +++ b/packages/rocketchat-authorization/server/roles.js @@ -6,27 +6,23 @@ * ex: { _id: "123", name: "admin" } */ if (!Meteor.roles) { - Meteor.roles = new Meteor.Collection("roles") + Meteor.roles = new Mongo.Collection("roles") - // Create default indexes for roles collection - Meteor.roles._ensureIndex('name', {unique: 1}) + // Create default indexes for roles collection + Meteor.roles._ensureIndex('name', {unique: 1}) } /** - * Publish logged-in user's roles so client-side checks can work. + * Publish logged-in user's roles (global) so client-side checks can work. * * Use a named publish function so clients can check `ready()` state. */ -Meteor.publish('_roles', function () { - var loggedInUserId = this.userId, - fields = {roles: 1} +Meteor.publish('scope-roles', function (scope) { + if (!this.userId || "undefined" === typeof RocketChat.models[scope] || "function" !== typeof RocketChat.models[scope].findRolesByUserId) { + this.ready() + return + } - if (!loggedInUserId) { - this.ready() - return - } - - return Meteor.users.find({_id: loggedInUserId}, - {fields: fields}) -}) + return RocketChat.models[scope].findRolesByUserId(this.userId); +}); diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 7e347bdeffb..4bc8c430310 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -106,14 +106,17 @@ Meteor.startup -> roles : ['admin', 'bot']} ] - #alanning:roles - roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); - for permission in permissions RocketChat.models.Permissions.upsert( permission._id, {$set: permission }) - for role in permission.roles - unless role in roles - Roles.createRole role - roles.push(role) + roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); + defaultRoles = [ + { name: 'admin', scope: 'Users' } + { name: 'moderator', scope: 'Subscriptions' } + { name: 'user', scope: 'Users' } + { name: 'bot', scope: 'Users' } + ] + for role in defaultRoles + unless role.name in roles + Roles.createRole role -- GitLab From b47e50e91c4c6c955c2ef00ff50295171504e6b5 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 5 Jan 2016 18:25:33 -0200 Subject: [PATCH 1101/1338] fix download URL --- .docker/dockerfiles/latest/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index db4b87bc445..30353fc9df2 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -18,7 +18,7 @@ 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') | sed 's/\/tag\//\/download\//' \ +&& HEADER=$(curl -I -s "$URL" | grep -Fi Location: | sed -En 's/.*(https?:\/\/[a-zA-Z0-9\/.-_]*).*$/\1/p' | sed 's/\/tag\//\/download\//' ) \ && curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ -- GitLab From 199fa2f7c1909f591e81e5329824e0bd9d2de551 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 18:52:28 -0200 Subject: [PATCH 1102/1338] Implement an interface to manage oauth apps --- i18n/en.i18n.json | 4 +- .../server/startup.coffee | 3 + .../admin/client/collection.coffee | 1 + .../admin/client/route.coffee | 17 +++++ .../admin/client/startup.coffee | 7 ++ .../admin/client/views/oauthApp.coffee | 73 +++++++++++++++++++ .../admin/client/views/oauthApp.html | 51 +++++++++++++ .../admin/client/views/oauthApps.coffee | 9 +++ .../admin/client/views/oauthApps.html | 33 +++++++++ .../admin/server/methods/addOAuthApp.coffee | 25 +++++++ .../server/methods/deleteOAuthApp.coffee | 13 ++++ .../server/methods/updateOAuthApp.coffee | 29 ++++++++ .../admin/server/models/OAuthApps.coffee | 13 ++++ .../server/publications/oauthApps.coffee | 8 ++ .../client/stylesheets/load.coffee | 2 - .../{ => oauth}/client/oauth2-client.coffee | 0 .../{ => oauth}/client/oauth2-client.html | 0 .../oauth/client/stylesheets/load.coffee | 2 + .../client/stylesheets/oauth2.less | 0 .../{ => oauth}/server/oauth2-server.coffee | 0 .../package.js | 24 ++++-- 21 files changed, 306 insertions(+), 8 deletions(-) create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/collection.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/route.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/startup.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.html create mode 100644 packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/server/methods/deleteOAuthApp.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/server/models/OAuthApps.coffee create mode 100644 packages/rocketchat-oauth2-server-config/admin/server/publications/oauthApps.coffee delete mode 100644 packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee rename packages/rocketchat-oauth2-server-config/{ => oauth}/client/oauth2-client.coffee (100%) rename packages/rocketchat-oauth2-server-config/{ => oauth}/client/oauth2-client.html (100%) create mode 100644 packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/load.coffee rename packages/rocketchat-oauth2-server-config/{ => oauth}/client/stylesheets/oauth2.less (100%) rename packages/rocketchat-oauth2-server-config/{ => oauth}/server/oauth2-server.coffee (100%) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 1853674bef4..d6f8e9c56a2 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -67,6 +67,7 @@ "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", @@ -178,6 +179,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", @@ -560,7 +562,7 @@ "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_Open_Source_solution" : "Your own Open Source chat solution", "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" } diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 7e347bdeffb..fbaf7bdb701 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -104,6 +104,9 @@ Meteor.startup -> { _id: 'manage-integrations', roles : ['admin', 'bot']} + + { _id: 'manage-oauth-apps', + roles : ['admin']} ] #alanning:roles 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 00000000000..4004f7cde99 --- /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 00000000000..f2fcc3b8365 --- /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 00000000000..1619a366a3d --- /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 00000000000..d8d3b415c34 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee @@ -0,0 +1,73 @@ +Template.oauthApp.onCreated -> + @record = new ReactiveVar {} + + +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? + 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() + 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 + 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 00000000000..fab7358c217 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html @@ -0,0 +1,51 @@ +<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>{{_ "Application_Name"}}</label> + <div> + <input type="text" name="name" value="{{data.name}}" placeholder="{{_ 'Optional'}}" /> + <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> + {{/if}} + </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-oauth2-server-config/admin/client/views/oauthApps.coffee b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApps.coffee new file mode 100644 index 00000000000..0dca6796b28 --- /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 00000000000..f0dc3df3364 --- /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 00000000000..9215823802d --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee @@ -0,0 +1,25 @@ +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' + + 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 00000000000..704dfed09c5 --- /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 00000000000..300259b18a0 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee @@ -0,0 +1,29 @@ +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' + + 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: integration.name + redirectUri: integration.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/models/OAuthApps.coffee b/packages/rocketchat-oauth2-server-config/admin/server/models/OAuthApps.coffee new file mode 100644 index 00000000000..5f95a6c2d32 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/admin/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-oauth2-server-config/admin/server/publications/oauthApps.coffee b/packages/rocketchat-oauth2-server-config/admin/server/publications/oauthApps.coffee new file mode 100644 index 00000000000..d29a5cbdcdb --- /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/client/stylesheets/load.coffee b/packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee deleted file mode 100644 index 794b9ecd4a0..00000000000 --- a/packages/rocketchat-oauth2-server-config/client/stylesheets/load.coffee +++ /dev/null @@ -1,2 +0,0 @@ -RocketChat.theme.addPackageAsset -> - return Assets.getText 'client/stylesheets/oauth2.less' diff --git a/packages/rocketchat-oauth2-server-config/client/oauth2-client.coffee b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee similarity index 100% rename from packages/rocketchat-oauth2-server-config/client/oauth2-client.coffee rename to packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee diff --git a/packages/rocketchat-oauth2-server-config/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html similarity index 100% rename from packages/rocketchat-oauth2-server-config/client/oauth2-client.html rename to packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html 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 00000000000..631ef382a4e --- /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/client/stylesheets/oauth2.less b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less similarity index 100% rename from packages/rocketchat-oauth2-server-config/client/stylesheets/oauth2.less rename to packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less diff --git a/packages/rocketchat-oauth2-server-config/server/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee similarity index 100% rename from packages/rocketchat-oauth2-server-config/server/oauth2-server.coffee rename to packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js index ac5f7ee5319..d1e152e4a11 100644 --- a/packages/rocketchat-oauth2-server-config/package.js +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -16,11 +16,25 @@ Package.onUse(function(api) { api.use('templating', 'client'); api.use('kadira:flow-router', 'client'); - api.addFiles('server/oauth2-server.coffee', 'server'); + api.addFiles('oauth/server/oauth2-server.coffee', 'server'); - api.addFiles('client/oauth2-client.html', 'client'); - api.addFiles('client/oauth2-client.coffee', 'client'); + api.addFiles('oauth/client/oauth2-client.html', 'client'); + api.addFiles('oauth/client/oauth2-client.coffee', 'client'); - api.addAssets('client/stylesheets/oauth2.less', 'server'); - api.addFiles('client/stylesheets/load.coffee', 'server'); + api.addAssets('oauth/client/stylesheets/oauth2.less', 'server'); + api.addFiles('oauth/client/stylesheets/load.coffee', 'server'); + + 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'); + + api.addFiles('admin/server/models/OAuthApps.coffee', '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'); }); -- GitLab From 1e8741ac0bb2041c463ebfdd0a607401f5adafd1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 19:16:31 -0200 Subject: [PATCH 1103/1338] Fix little bugs --- .../admin/server/methods/updateOAuthApp.coffee | 4 ++-- .../oauth/server/oauth2-server.coffee | 10 +++++----- .../rocketchat-oauth2-server-config/package.js | 16 +++++++++++++--- .../{admin => }/server/models/OAuthApps.coffee | 0 4 files changed, 20 insertions(+), 10 deletions(-) rename packages/rocketchat-oauth2-server-config/{admin => }/server/models/OAuthApps.coffee (100%) diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee index 300259b18a0..6cfd200145c 100644 --- a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee @@ -21,8 +21,8 @@ Meteor.methods RocketChat.models.OAuthApps.update applicationId, $set: - name: integration.name - redirectUri: integration.redirectUri + name: application.name + redirectUri: application.redirectUri _updatedAt: new Date _updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}} diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee index 855abbcb08c..96940151b58 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee @@ -1,11 +1,11 @@ oauth2server = new OAuth2Server - accessTokensCollectionName: 'rocketchat-oauth-access-tokens' - refreshTokensCollectionName: 'rocketchat-oauth-refresh-tokens' - clientsCollectionName: 'rocketchat-oauth-clients' - authCodesCollectionName: 'rocketchat-oauth-auth-codes' + accessTokensCollectionName: 'rocketchat_oauth_access_tokens' + refreshTokensCollectionName: 'rocketchat_oauth_refresh_tokens' + authCodesCollectionName: 'rocketchat_oauth_auth_codes' + clientsCollection: RocketChat.models.OAuthApps.model debug: true -WebApp.rawConnectHandlers.use oauth2server.app +WebApp.connectHandlers.use oauth2server.app # JsonRoutes.Middleware.use oauth2server.app if not oauth2server.model.Clients.findOne() diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js index d1e152e4a11..c5cc4e44abd 100644 --- a/packages/rocketchat-oauth2-server-config/package.js +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -16,14 +16,24 @@ Package.onUse(function(api) { 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.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'); - api.addAssets('oauth/client/stylesheets/oauth2.less', 'server'); - api.addFiles('oauth/client/stylesheets/load.coffee', 'server'); + //// Admin // + // Client api.addFiles('admin/client/startup.coffee', 'client'); api.addFiles('admin/client/collection.coffee', 'client'); api.addFiles('admin/client/route.coffee', 'client'); @@ -32,7 +42,7 @@ Package.onUse(function(api) { api.addFiles('admin/client/views/oauthApps.html', 'client'); api.addFiles('admin/client/views/oauthApps.coffee', 'client'); - api.addFiles('admin/server/models/OAuthApps.coffee', 'server'); + // 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'); diff --git a/packages/rocketchat-oauth2-server-config/admin/server/models/OAuthApps.coffee b/packages/rocketchat-oauth2-server-config/server/models/OAuthApps.coffee similarity index 100% rename from packages/rocketchat-oauth2-server-config/admin/server/models/OAuthApps.coffee rename to packages/rocketchat-oauth2-server-config/server/models/OAuthApps.coffee -- GitLab From eb29eaaae86f8f5727b0abf741e98090214842e5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 19:20:17 -0200 Subject: [PATCH 1104/1338] Update package oauth2-server to 1.1.0 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index e9490c2bc1f..12b0386f528 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -147,7 +147,7 @@ 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.0.1 +rocketchat:oauth2-server@1.1.0 rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 -- GitLab From 42167a09aaa3c64dd8f9dd8efea8bbba7f101ddc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 19:26:10 -0200 Subject: [PATCH 1105/1338] Add i18n strings --- i18n/en.i18n.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index d6f8e9c56a2..bc37ba97d74 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -78,6 +78,9 @@ "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", @@ -92,6 +95,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", @@ -111,6 +115,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", @@ -310,6 +316,7 @@ "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", @@ -329,6 +336,7 @@ "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_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", @@ -379,6 +387,7 @@ "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", @@ -483,9 +492,11 @@ "strike" : "strike", "Submit" : "Submit", "Success" : "Success", + "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 in your server.", + "The_redirectUri_is_required" : "The redirectUri is required", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "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>!", "There_is_no_integrations" : "There is no integrations", -- GitLab From ed075956463944bf78ed02572e28d8c23d9f6c06 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 5 Jan 2016 19:27:18 -0200 Subject: [PATCH 1106/1338] remove docker dependency on graphicsmagick --- .docker/dockerfiles/latest/Dockerfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index 30353fc9df2..72c9a4ea913 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -2,10 +2,6 @@ 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 \ -- GitLab From 9650d24ea8dd24dad484050ddf1225fb760ae42c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 19:27:38 -0200 Subject: [PATCH 1107/1338] Add i18n string --- i18n/en.i18n.json | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index bc37ba97d74..64ef16c859c 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -336,6 +336,7 @@ "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", -- GitLab From a295da429fafaef750671fdec6a63087f27176b1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 19:55:43 -0200 Subject: [PATCH 1108/1338] Add more logs on integrations --- packages/rocketchat-integrations/server/api/api.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 508b3c7e77f..706ebe40903 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -15,6 +15,10 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, 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) -- GitLab From 25418856edb4887cac7806207885cb267452ad0e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 5 Jan 2016 20:31:43 -0200 Subject: [PATCH 1109/1338] Fix #1491 via code from @miscs --- packages/rocketchat-ldap/ldap_server.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 1e6589c3d55..197c21a9f98 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -162,8 +162,10 @@ LDAP.prototype.ldapCheck = function(options) { 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) { @@ -173,7 +175,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) { -- GitLab From 35d087cfcaec8ac7b6ba77e25cfbff8c2bcb60aa Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 5 Jan 2016 22:58:16 -0500 Subject: [PATCH 1110/1338] Updated to handle release-by-tag --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7fc1a9f81e0..33a72bd0126 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ mongo: command: mongod --smallfiles --oplogSize 128 rocketchat: - image: rocketchat/rocket.chat:develop + image: rocketchat/rocket.chat:latest # volumes: # - ./uploads:/app/uploads environment: @@ -35,4 +35,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 -- GitLab From 90de28d5cbff6223c9227cbea4fa5ba120b4af0a Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 5 Jan 2016 23:01:51 -0500 Subject: [PATCH 1111/1338] Updated to use latest GitHub release-by-tag TGZ --- Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index cbb9a7bfe12..30353fc9df2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,10 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/rocketchatbuild/rocket.chat-develop.tgz" -o rocket.chat.tgz \ +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' | sed 's/\/tag\//\/download\//' ) \ +&& curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ -- GitLab From c09e059b2993f3d375e96f65629284e7f1996d2f Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 5 Jan 2016 23:27:09 -0500 Subject: [PATCH 1112/1338] Updated for new release-by-tag builds --- README.md | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 4169ea44fa4..fafb4fa2b3a 100644 --- a/README.md +++ b/README.md @@ -61,23 +61,11 @@ 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) - -Branch **develop** (Newer but unstable): - [](https://heroku.com/deploy?template=https://github.com/RocketChat/Rocket.Chat/tree/develop) ## Scalingo Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com) -Branch **master** (Latest stable version): - -[](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#master) - -Branch **develop** (Newer but unstable): - [](https://my.scalingo.com/deploy?source=https://github.com/RocketChat/Rocket.Chat#develop) ## Sandstorm.io @@ -93,20 +81,20 @@ Host your docker container at [sloppy.io](http://sloppy.io). Get an account and or -Use the automated build image of our [most recent in-development code](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:develop +docker pull rocketchat/rocket.chat:lastest ``` -OR the latest available stable (master) branch code: +OR select a specific release ([details of releases available](https://github.com/RocketChat/Rocket.Chat/releases)): ``` -docker pull rocketchat/rocket.chat:latest +docker pull rocketchat/rocket.chat:vX.X.X ``` -OR our [official docker registry image](https://hub.docker.com/_/rocket.chat/), containing recent MAJOR release: +OR our [official docker registry image](https://hub.docker.com/_/rocket.chat/), containing recent stable release build approved by Docker: ``` docker pull rocket.chat -- GitLab From 1fca093db18b483d301d2ffbb2ee27142f62db7a Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 5 Jan 2016 23:35:16 -0500 Subject: [PATCH 1113/1338] Update Sandstorm SPK download information (GitHub, not S3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fafb4fa2b3a..0826156deca 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com) ## 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://github.com/RocketChat/Rocket.Chat/releases/latest) 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) -- GitLab From 6597320e8eca0ac6e2ac2fe0220cdbeaf9880b55 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 10:12:59 -0200 Subject: [PATCH 1114/1338] fix livechat error message position --- packages/rocketchat-livechat/app/client/stylesheets/main.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index 80e3b910a41..afcc4fcf35a 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -337,7 +337,7 @@ input:focus { } .error { - bottom: 40px; + bottom: @footer-min-height; position: fixed; width: 100%; background-color: #F7D799; -- GitLab From c33a446759c4a33bb898581c5e64f4fecd0f9433 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 6 Jan 2016 10:22:26 -0200 Subject: [PATCH 1115/1338] Fix open links for Android --- packages/rocketchat-ui/lib/cordova/urls.coffee | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui/lib/cordova/urls.coffee b/packages/rocketchat-ui/lib/cordova/urls.coffee index 59bcf5d22f6..aeed6e9604b 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() -- GitLab From 483b95bb8e691a7e20a225597e9ed5fd799fac25 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 6 Jan 2016 11:15:24 -0200 Subject: [PATCH 1116/1338] Update version of oauth2-server to 1.1.1 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index 2eee4761c61..7565a4f2395 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -148,7 +148,7 @@ 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.1.0 +rocketchat:oauth2-server@1.1.1 rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 -- GitLab From 39af25226b8177319c251b6a88aa60c5e6fbb127 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 6 Jan 2016 13:47:34 -0200 Subject: [PATCH 1117/1338] jalik:ufs upgraded from 0.3.4 to 0.3.5 momentjs:moment upgraded from 2.10.6 to 2.11.0 --- .meteor/packages | 4 ++-- .meteor/versions | 4 ++-- .travis.yml | 3 ++- Dockerfile | 4 ---- example-build.sh | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index e8b67c13f0a..6b640c8b585 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -52,6 +52,7 @@ rocketchat:github-enterprise rocketchat:gitlab rocketchat:highlight rocketchat:ldap +rocketchat:livechat rocketchat:logger rocketchat:mailer rocketchat:markdown @@ -63,8 +64,8 @@ rocketchat:message-star rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join -rocketchat:slashcommands-leave rocketchat:slashcommands-kick +rocketchat:slashcommands-leave rocketchat:slashcommands-mute rocketchat:spotify rocketchat:statistics @@ -84,7 +85,6 @@ rocketchat:wordpress #rocketchat:chatops #rocketchat:hubot #rocketchat:irc -rocketchat:livechat konecty:change-case konecty:delayed-task diff --git a/.meteor/versions b/.meteor/versions index 7565a4f2395..a894cf14bf3 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -52,7 +52,7 @@ htmljs@1.0.5 http@1.1.1 id-map@1.0.4 idorecall:email-normalize@1.0.0 -jalik:ufs@0.3.4 +jalik:ufs@0.3.5 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 @@ -86,7 +86,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.0 monbro:mongodb-mapreduce-aggregation@1.0.1 mongo@1.1.3 mongo-id@1.0.1 diff --git a/.travis.yml b/.travis.yml index 36845c11e7d..8ce22734161 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,9 @@ sudo: required language: node_js branches: only: - - develop - master + - develop + - beta - "/^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/" git: depth: 1 diff --git a/Dockerfile b/Dockerfile index 30353fc9df2..72c9a4ea913 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,6 @@ 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 \ diff --git a/example-build.sh b/example-build.sh index 5e36ade4e4c..579353a01a3 100755 --- a/example-build.sh +++ b/example-build.sh @@ -1,6 +1,6 @@ #!/bin/bash export METEOR_SETTINGS=$(cat settings.json) -meteor add rocketchat:livechat rocketchat:hubot meteorhacks:kadira +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 -- GitLab From c0c087e09ccffcd4c3a2c0f9dc8b8c7d00d1c67f Mon Sep 17 00:00:00 2001 From: Aaron Ogle <geekgonecrazy@users.noreply.github.com> Date: Wed, 6 Jan 2016 10:40:32 -0600 Subject: [PATCH 1118/1338] Fix min-height on link oembed. Because of the 10px top and 10px bottom padding the min-height for the content really is only 40. So this causes the image to bleed over when there is no description. --- packages/rocketchat-oembed/client/oembedUrlWidget.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-oembed/client/oembedUrlWidget.html b/packages/rocketchat-oembed/client/oembedUrlWidget.html index 56115decb6d..9d749d7f6c8 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> -- GitLab From f1c32a26042fd22d4693b2d7d703dc999eb7bd4e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 15:46:40 -0200 Subject: [PATCH 1119/1338] save visitor's page navigation history --- .../app/client/lib/hooks.js | 2 + .../assets/rocket-livechat.js | 4 +- packages/rocketchat-livechat/package.js | 2 + .../server/methods/pageVisited.js | 5 ++ .../server/methods/registerGuest.js | 8 +++- .../server/models/LivechatPageVisited.js | 48 +++++++++++++++++++ 6 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 packages/rocketchat-livechat/server/methods/pageVisited.js create mode 100644 packages/rocketchat-livechat/server/models/LivechatPageVisited.js diff --git a/packages/rocketchat-livechat/app/client/lib/hooks.js b/packages/rocketchat-livechat/app/client/lib/hooks.js index 9ca2792bbe3..1342000e2ed 100644 --- a/packages/rocketchat-livechat/app/client/lib/hooks.js +++ b/packages/rocketchat-livechat/app/client/lib/hooks.js @@ -1,6 +1,8 @@ var api = { pageVisited: function(info) { Triggers.processRequest(info); + + Meteor.call('livechat:pageVisited', visitor.getToken(), info); } }; diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index 47e29c10333..edb29e6bc0f 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -79,13 +79,13 @@ }; var trackNavigation = function() { setInterval(function() { - if (document.title !== currentPage.title) { + if (document.location.href !== currentPage.href) { pageVisited(); currentPage.href = document.location.href; currentPage.title = document.title; } - }, 500); + }, 800); }; var initRocket = function(url) { diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 5e3b7d9ad8e..9771af9ee62 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -77,6 +77,7 @@ Package.onUse(function(api) { // 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'); @@ -93,6 +94,7 @@ Package.onUse(function(api) { 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'); // server lib diff --git a/packages/rocketchat-livechat/server/methods/pageVisited.js b/packages/rocketchat-livechat/server/methods/pageVisited.js new file mode 100644 index 00000000000..97729d57f55 --- /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 index 8f306afa9cf..ee258a8a345 100644 --- a/packages/rocketchat-livechat/server/methods/registerGuest.js +++ b/packages/rocketchat-livechat/server/methods/registerGuest.js @@ -20,7 +20,9 @@ Meteor.methods({ qt = Meteor.users.find({ 'profile.guest': true }).count() + 1; + user = 'guest-' + (qt + inc++); + userExists = Meteor.users.findOne({ 'username': user }, { @@ -28,7 +30,7 @@ Meteor.methods({ _id: 1 } }); - console.log('userExists ->',userExists); + if (!userExists) { break; } @@ -67,6 +69,10 @@ Meteor.methods({ 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/models/LivechatPageVisited.js b/packages/rocketchat-livechat/server/models/LivechatPageVisited.js new file mode 100644 index 00000000000..8917e0167b3 --- /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 }); + } + + keepHistoryForToken(token) { + return this.update({ + token: token, + expireAt: { + $exists: true + } + }, { + $unset: { + expireAt: 1 + } + }, { + multi: true + }); + } +} + +RocketChat.models.LivechatPageVisitied = new LivechatPageVisitied(); -- GitLab From e398b3e7d0bfe592a734528de57c88e5049d7af0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 15:47:05 -0200 Subject: [PATCH 1120/1338] updated demo page with links to generate some navigation history --- packages/rocketchat-livechat/assets/demo.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/rocketchat-livechat/assets/demo.html b/packages/rocketchat-livechat/assets/demo.html index 8b3929901c4..df2c77e02c6 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">page 0</a><br> + <a href="#page-1">page 1</a><br> + <a href="#page-2">page 2</a><br> + <a href="#page-3">page 3</a><br> + <a href="#page-4">page 4</a><br> + <a href="#page-5">page 5</a><br> + <a href="#page-6">page 6</a><br> </body> </html> -- GitLab From 83dc0b828ad4fc9f983c2fd7f64b13490e969a4e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 6 Jan 2016 17:55:02 -0200 Subject: [PATCH 1121/1338] Init the class Logger for server logging --- packages/rocketchat-logger/package.js | 7 +- packages/rocketchat-logger/server.coffee | 114 +++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 packages/rocketchat-logger/server.coffee diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js index f4a1ea48c4c..39a3c4e39d0 100644 --- a/packages/rocketchat-logger/package.js +++ b/packages/rocketchat-logger/package.js @@ -8,8 +8,13 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); - api.use('coffeescript', 'client'); + api.use('coffeescript'); + api.use('logging'); + api.use('nooitaf:colors'); api.use('templating', 'client', {weak: true}); api.addFiles('logger.coffee', 'client'); + api.addFiles('server.coffee', 'server'); + + api.export('Logger'); }); diff --git a/packages/rocketchat-logger/server.coffee b/packages/rocketchat-logger/server.coffee new file mode 100644 index 00000000000..3d155936e2f --- /dev/null +++ b/packages/rocketchat-logger/server.coffee @@ -0,0 +1,114 @@ +LoggerManager = new class + loggers: {} + +@Logger = class Logger + defaultTypes: + log: 'blue' + warn: 'magenta' + error: 'red' + + constructor: (@name, @config={}) -> + if LoggerManager.loggers[@name]? + LoggerManager.loggers[@name].warn 'Duplicated instance' + return LoggerManager.loggers[@name] + + for type, color of @defaultTypes + do (type, color) => + @[type] = (args...) => + @_log + type: type + arguments: args + + if @config.methods? + for method, type of @config.methods + do (method, type) => + if @[method]? + @warn "Method", method, "already exists" + + if not @defaultTypes[type]? + @warn "Method type", type, "doest not exists" + + @[method] = (args...) => + @_log + type: type + method: method + arguments: args + + return @ + + getPrefix: (options) -> + prefix = "" + + if options.method? + prefix = "[#{@name}->#{options.method}]" + else + prefix = "[#{@name}]" + + details = @_getCallerDetails() + + detailParts = [] + if details.package? then detailParts.push details.package + if details.file? then detailParts.push details.file + if details.line? then detailParts.push details.line + + if detailParts.length > 0 + prefix = "(#{detailParts.join(':')})#{prefix}" + + if @defaultTypes[options.type]? + return prefix[@defaultTypes[options.type]] + + return prefix + + # @returns {Object: { line: Number, file: String }} + _getCallerDetails: -> + getStack = () -> + # We do NOT use Error.prepareStackTrace here (a V8 extension that gets us a + # pre-parsed stack) since it's impossible to compose it with the use of + # Error.prepareStackTrace used on the server for source maps. + err = new Error + stack = err.stack + return stack + + stack = getStack() + + if not stack + return {} + + lines = stack.split('\n') + + # looking for the first line outside the logging package (or an + # eval if we find that first) + line = undefined + for item, index in lines when index > 0 + line = item + if line.match(/^\s*at eval \(eval/) + return {file: "eval"} + + if not line.match(/packages\/rocketchat_logger(?:\/|\.js)/) + break + + details = {} + + # The format for FF is 'functionName@filePath:lineNumber' + # The format for V8 is 'functionName (packages/logging/logging.js:81)' or + # 'packages/logging/logging.js:81' + match = /(?:[@(]| at )([^(]+?):([0-9:]+)(?:\)|$)/.exec(line) + if not match + return details + # in case the matched block here is line:column + details.line = match[2].split(':')[0] + + # Possible format: https://foo.bar.com/scripts/file.js?random=foobar + # XXX: if you can write the following in better way, please do it + # XXX: what about evals? + details.file = match[1].split('/').slice(-1)[0].split('?')[0] + + packageMatch = match[1].match(/packages\/([^\.\/]+)(?:\/|\.)/) + if packageMatch? + details.package = packageMatch[1] + + return details + + _log: (options) -> + options.arguments.unshift @getPrefix(options) + console.log.apply console, options.arguments -- GitLab From eaf025ec372ea52121d702aeba4432d5901cc7c2 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 6 Jan 2016 18:10:37 -0200 Subject: [PATCH 1122/1338] Rework --- client/startup/startup.coffee | 3 + packages/rocketchat-authorization/README.md | 15 +- .../client/hasPermission.coffee | 44 +- .../client/hasRole.coffee | 11 +- .../ChatPermissions.coffee} | 2 +- .../client/lib/models/Roles.coffee | 14 + .../client/lib/models/Subscriptions.js | 95 +++ .../client/lib/models/Users.js | 80 ++ .../rocketchat-authorization/client/roles.js | 22 - .../client/startup.coffee | 3 + .../client/views/permissions.coffee | 5 +- .../client/views/permissionsRole.coffee | 2 +- .../rocketchat-authorization/lib/roles.js | 713 ------------------ packages/rocketchat-authorization/package.js | 25 +- .../server/functions/addUserRoles.coffee | 19 + .../server/functions/addUsersToRoles.coffee | 27 - .../functions/getPermissionsForRole.coffee | 6 +- .../server/functions/getRoles.coffee | 2 +- .../server/functions/getRolesForUser.coffee | 6 - .../server/functions/getUsersInRole.coffee | 6 +- .../server/functions/hasPermission.coffee | 11 +- .../server/functions/hasRole.coffee | 6 +- .../functions/removeUserFromRoles.coffee | 18 + .../functions/removeUsersFromRoles.coffee | 25 - .../server/methods/addUserToRole.coffee | 7 +- .../server/methods/deleteRole.coffee | 13 +- .../server/methods/removeUserFromRole.coffee | 2 +- .../server/methods/saveRole.coffee | 5 +- .../server/models/Permissions.coffee | 1 - .../server/models/Roles.coffee | 42 ++ .../server/models/Subscriptions.js | 91 +++ .../server/models/Users.js | 75 +- .../server/publication.coffee | 2 - .../server/publications/permissions.js | 3 + .../server/publications/roles.coffee | 4 +- .../server/publications/scopedRoles.js | 11 + .../rocketchat-authorization/server/roles.js | 28 - .../server/startup.coffee | 36 +- .../incoming/addIncomingIntegration.coffee | 2 +- .../incoming/updateIncomingIntegration.coffee | 2 +- .../server/methods/setAdminStatus.coffee | 4 +- packages/rocketchat-livechat/permissions.js | 8 +- .../server/methods/addAgent.js | 2 +- .../server/methods/addManager.js | 2 +- .../server/methods/removeAgent.js | 2 +- .../server/methods/removeManager.js | 2 +- .../server/models/Users.js | 9 +- packages/rocketchat-ui/lib/collections.coffee | 5 + server/lib/accounts.coffee | 2 +- server/methods/createChannel.coffee | 2 +- server/methods/createPrivateGroup.coffee | 2 +- server/methods/removeUserFromRoom.coffee | 2 +- server/startup/initialData.coffee | 4 +- server/startup/migrations/v27.coffee | 11 + 54 files changed, 572 insertions(+), 969 deletions(-) rename packages/rocketchat-authorization/client/{collection.coffee => lib/ChatPermissions.coffee} (96%) create mode 100644 packages/rocketchat-authorization/client/lib/models/Roles.coffee create mode 100644 packages/rocketchat-authorization/client/lib/models/Subscriptions.js create mode 100644 packages/rocketchat-authorization/client/lib/models/Users.js delete mode 100644 packages/rocketchat-authorization/client/roles.js delete mode 100644 packages/rocketchat-authorization/lib/roles.js create mode 100644 packages/rocketchat-authorization/server/functions/addUserRoles.coffee delete mode 100644 packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee delete mode 100644 packages/rocketchat-authorization/server/functions/getRolesForUser.coffee create mode 100644 packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee delete mode 100644 packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee create mode 100644 packages/rocketchat-authorization/server/models/Roles.coffee create mode 100644 packages/rocketchat-authorization/server/models/Subscriptions.js delete mode 100644 packages/rocketchat-authorization/server/publication.coffee create mode 100644 packages/rocketchat-authorization/server/publications/permissions.js create mode 100644 packages/rocketchat-authorization/server/publications/scopedRoles.js delete mode 100644 packages/rocketchat-authorization/server/roles.js create mode 100644 server/startup/migrations/v27.coffee diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee index f7043af4946..ed209ee71b3 100644 --- a/client/startup/startup.coffee +++ b/client/startup/startup.coffee @@ -24,6 +24,9 @@ Meteor.startup -> loadedLaguages = [] @setLanguage = (language) -> + if !language + return + if loadedLaguages.indexOf(language) > -1 return diff --git a/packages/rocketchat-authorization/README.md b/packages/rocketchat-authorization/README.md index 239b085c856..c2365d83f69 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 9d636b9552e..015ec854ee7 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 3140a74bfe6..aff335e48b2 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 b719f7f9ed6..e9adaae10f2 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 00000000000..5d94d584c61 --- /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 00000000000..3c1f3a4819a --- /dev/null +++ b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js @@ -0,0 +1,95 @@ +if (_.isUndefined(RocketChat.models.Subscriptions)) { + RocketChat.models.Subscriptions = {} +} + +RocketChat.models.Subscriptions.findRolesByUserId = function(userId) { + query = { + "u._id": userId + }; + + options = { fields: { roles: 1 } } + + return this.find(query, options); +} + +RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId) { + query = { + "u._id": userId, + rid: roomId, + roles: roleName + }; + + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models.Subscriptions.setRolesByUserId = function(userId, roles, roomId) { + roles = [].concat(roles); + + var query = { + "u._id": userId, + rid: roomId + } + + var update = { + $set: { + roles: roles + } + } + + return this.update(query, update); +} + +RocketChat.models.Subscriptions.addRolesByUserId = function(userId, roles, roomId) { + roles = [].concat(roles); + + var query = { + "u._id": userId, + rid: roomId + } + + var update = { + $addToSet: { + roles: { $each: roles } + } + } + + return this.update(query, update); +} + +RocketChat.models.Subscriptions.removeRolesByUserId = function(userId, roles, roomId) { + roles = [].concat(roles); + + var query = { + "u._id": userId, + rid: roomId + } + + var update = { + $pullAll: { + roles: roles + } + } + + return this.update(query, update); +} + +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 00000000000..c00fb3cf9cf --- /dev/null +++ b/packages/rocketchat-authorization/client/lib/models/Users.js @@ -0,0 +1,80 @@ +if (_.isUndefined(RocketChat.models.Users)) { + RocketChat.models.Users = {} +} + +RocketChat.models.Users.findRolesByUserId = function(userId) { + var query = { + _id: userId + }; + + options = { fields: { roles: 1 } } + + return this.find(query, options); +}; + +RocketChat.models.Users.isUserInRole = function(userId, roleName) { + query = { + _id: userId, + roles: roleName + }; + + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models.Users.setRolesByUserId = function(userId, roles) { + roles = [].concat(roles); + + var query = { + _id: userId + } + + var update = { + $set: { + roles: roles + } + } + + return this.update(query, update); +} + +RocketChat.models.Users.addRolesByUserId = function(userId, roles) { + roles = [].concat(roles); + + var query = { + _id: userId + } + + var update = { + $addToSet: { + roles: { $each: roles } + } + } + + return this.update(query, update); +} + +RocketChat.models.Users.removeRolesByUserId = function(userId, roles) { + roles = [].concat(roles); + + var query = { + _id: userId + } + + var update = { + $pullAll: { + roles: roles + } + } + + return this.update(query, update); +} + +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/roles.js b/packages/rocketchat-authorization/client/roles.js deleted file mode 100644 index 30daddeed72..00000000000 --- a/packages/rocketchat-authorization/client/roles.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict" - -/** - * Subscription handle for the currently logged in user's permissions. - * - * NOTE: The corresponding publish function, `_roles`, depends on - * `this.userId` so it will automatically re-run when the currently - * logged-in user changes. - * - * @example - * - * `Roles.subscription.ready()` // => `true` if user roles have been loaded - * - * @property subscription - * @type Object - * @for Roles - */ - -Tracker.autorun(function () { - // Subscribe to global user roles - Meteor.subscribe("scope-roles", "Users") -}) diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 144f7ea88f9..2c9482c5458 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -1,3 +1,6 @@ +Meteor.subscribe 'roles' +Meteor.subscribe 'scopedRoles', 'Users' + 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 0e134582401..a4366fd638f 100644 --- a/packages/rocketchat-authorization/client/views/permissions.coffee +++ b/packages/rocketchat-authorization/client/views/permissions.coffee @@ -31,11 +31,8 @@ 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() diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee index bb754ced89c..a15e33587f5 100644 --- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee +++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee @@ -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/lib/roles.js b/packages/rocketchat-authorization/lib/roles.js deleted file mode 100644 index daa8bf6d904..00000000000 --- a/packages/rocketchat-authorization/lib/roles.js +++ /dev/null @@ -1,713 +0,0 @@ -;(function () { - -/** - * Provides functions related to user authorization. Compatible with built-in Meteor accounts packages. - * - * @module Roles - */ - -/** - * Roles collection documents consist only of an id and a role name. - * ex: { _id:<uuid>, name: "admin" } - */ -if (!Meteor.roles) { - Meteor.roles = new Mongo.Collection("roles") -} - -/** - * Authorization package compatible with built-in Meteor accounts system. - * - * Stores user's current roles in a 'roles' field on the user object. - * - * @class Roles - * @constructor - */ -if ('undefined' === typeof Roles) { - Roles = {} -} - -"use strict"; - -var mixingGroupAndNonGroupErrorMsg = "Roles error: Can't mix grouped and non-grouped roles for same user"; - -_.extend(Roles, { - - /** - * Constant used to reference the special 'global' group that - * can be used to apply blanket permissions across all groups. - * - * @example - * Roles.addUsersToRoles(user, 'admin', Roles.GLOBAL_GROUP) - * Roles.userIsInRole(user, 'admin') // => true - * - * Roles.setUserRoles(user, 'support-staff', Roles.GLOBAL_GROUP) - * Roles.userIsInRole(user, 'support-staff') // => true - * Roles.userIsInRole(user, 'admin') // => false - * - * @property GLOBAL_GROUP - * @type String - * @static - * @final - */ - GLOBAL_GROUP: '__global_roles__', - - - /** - * Create a new role. Whitespace will be trimmed. - * - * @method createRole - * @param {String} role Name of role - * @param {String} collection Name of collection storing roles - * @return {String} id of new role - */ - createRole: function (role, collection) { - var id, match; - - if (!role || 'string' !== typeof role || 'string' !== typeof collection || role.trim().length === 0 || collection.trim().length === 0) { - return - } - - try { - id = Meteor.roles.insert({'name': role.trim(), 'collection': collection.trim()}) - return id - } catch (e) { - // (from Meteor accounts-base package, insertUserDoc func) - // XXX string parsing sucks, maybe - // https://jira.mongodb.org/browse/SERVER-3069 will get fixed one day - if (e.name !== 'MongoError') throw e - match = e.err.match(/^E11000 duplicate key error index: ([^ ]+)/) - if (!match) throw e - if (match[1].indexOf('$name') !== -1) - throw new Meteor.Error(403, "Role already exists.") - throw e - } - }, - - /** - * Delete an existing role. Will throw "Role in use" error if any users - * are currently assigned to the target role. - * - * @method deleteRole - * @param {String} role Name of role - */ - deleteRole: function (role) { - if (!role) return - - var thisRole = Meteor.roles.findOne({name: role}) - if (thisRole) { - if (Meteor.isServer && "undefined" !== typeof RocketChat.models[thisRole.collection] && "function" === typeof RocketChat.models[thisRole.collection].getUsersInRole ) { - var users = RocketChat.models[thisRole.collection].getUsersInRole(role) - var foundExistingUser = users.length !== 0 - if (foundExistingUser) { - throw new Meteor.Error(403, 'Role in use') - } - } - Meteor.roles.remove({_id: thisRole._id}) - } - }, - - /** - * Add users to roles. Will create roles as needed. - * - * NOTE: Mixing grouped and non-grouped roles for the same user - * is not supported and will throw an error. - * - * Makes 2 calls to database: - * 1. retrieve list of all existing roles - * 2. update users' roles - * - * @example - * Roles.addUsersToRoles(userId, 'admin') - * Roles.addUsersToRoles(userId, ['view-secrets'], 'example.com') - * Roles.addUsersToRoles([user1, user2], ['user','editor']) - * Roles.addUsersToRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') - * Roles.addUsersToRoles(userId, 'admin', Roles.GLOBAL_GROUP) - * - * @method addUsersToRoles - * @param {Array|String} users User id(s) or object(s) with an _id field - * @param {Array|String} roles Name(s) of roles/permissions to add users to - * @param {String} [group] Optional group name. If supplied, roles will be - * specific to that group. - * Group names can not start with a '$' or contain - * null characters. Periods in names '.' are - * automatically converted to underscores. - * The special group Roles.GLOBAL_GROUP provides - * a convenient way to assign blanket roles/permissions - * across all groups. The roles/permissions in the - * Roles.GLOBAL_GROUP group will be automatically - * included in checks for any group. - */ - addUsersToRoles: function (users, roles, group) { - // use Template pattern to update user roles - Roles._updateUserRoles(users, roles, group, Roles._update_$addToSet_fn) - }, - - /** - * Set a users roles/permissions. - * - * @example - * Roles.setUserRoles(userId, 'admin') - * Roles.setUserRoles(userId, ['view-secrets'], 'example.com') - * Roles.setUserRoles([user1, user2], ['user','editor']) - * Roles.setUserRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') - * Roles.setUserRoles(userId, 'admin', Roles.GLOBAL_GROUP) - * - * @method setUserRoles - * @param {Array|String} users User id(s) or object(s) with an _id field - * @param {Array|String} roles Name(s) of roles/permissions to add users to - * @param {String} [group] Optional group name. If supplied, roles will be - * specific to that group. - * Group names can not start with '$'. - * Periods in names '.' are automatically converted - * to underscores. - * The special group Roles.GLOBAL_GROUP provides - * a convenient way to assign blanket roles/permissions - * across all groups. The roles/permissions in the - * Roles.GLOBAL_GROUP group will be automatically - * included in checks for any group. - */ - setUserRoles: function (users, roles, group) { - // use Template pattern to update user roles - Roles._updateUserRoles(users, roles, group, Roles._update_$set_fn) - }, - - /** - * Remove users from roles - * - * @example - * Roles.removeUsersFromRoles(users.bob, 'admin') - * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor']) - * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor', 'user']) - * Roles.removeUsersFromRoles(users.eve, ['user'], 'group1') - * - * @method removeUsersFromRoles - * @param {Array|String} users User id(s) or object(s) with an _id field - * @param {Array|String} roles Name(s) of roles to add users to - * @param {String} [group] Optional. Group name. If supplied, only that - * group will have roles removed. - */ - removeUsersFromRoles: function (users, roles, group) { - var update - - if (!users) throw new Error ("Missing 'users' param") - if (!roles) throw new Error ("Missing 'roles' param") - if (group) { - if ('string' !== typeof group) - throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") - if ('$' === group[0]) - throw new Error ("Roles error: groups can not start with '$'") - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - // ensure arrays - if (!_.isArray(users)) users = [users] - if (!_.isArray(roles)) roles = [roles] - - // ensure users is an array of user ids - users = _.reduce(users, function (memo, user) { - var _id - if ('string' === typeof user) { - memo.push(user) - } else if ('object' === typeof user) { - _id = user._id - if ('string' === typeof _id) { - memo.push(_id) - } - } - return memo - }, []) - - // update all users, remove from roles set - - if (group) { - update = {$pullAll: {}} - update.$pullAll['roles.'+group] = roles - } else { - update = {$pullAll: {roles: roles}} - } - - try { - if (Meteor.isClient) { - // Iterate over each user to fulfill Meteor's 'one update per ID' policy - _.each(users, function (user) { - Meteor.users.update({_id:user}, update) - }) - } else { - // On the server we can leverage MongoDB's $in operator for performance - Meteor.users.update({_id:{$in:users}}, update, {multi: true}) - } - } - catch (ex) { - if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { - throw new Error (mixingGroupAndNonGroupErrorMsg) - } - - throw ex - } - }, - - /** - * Check if user has specified permissions/roles - * - * @example - * // non-group usage - * Roles.userIsInRole(user, 'admin') - * Roles.userIsInRole(user, ['admin','editor']) - * Roles.userIsInRole(userId, 'admin') - * Roles.userIsInRole(userId, ['admin','editor']) - * - * // per-group usage - * Roles.userIsInRole(user, ['admin','editor'], 'group1') - * Roles.userIsInRole(userId, ['admin','editor'], 'group1') - * Roles.userIsInRole(userId, ['admin','editor'], Roles.GLOBAL_GROUP) - * - * // this format can also be used as short-hand for Roles.GLOBAL_GROUP - * Roles.userIsInRole(user, 'admin') - * - * @method userIsInRole - * @param {String|Object} user User Id or actual user object - * @param {String|Array} roles Name of role/permission or Array of - * roles/permissions to check against. If array, - * will return true if user is in _any_ role. - * @param {String} [group] Optional. Name of group. If supplied, limits check - * to just that group. - * The user's Roles.GLOBAL_GROUP will always be checked - * whether group is specified or not. - * @return {Boolean} true if user is in _any_ of the target roles - */ - userIsInRole: function (user, roles, group) { - var id, - userRoles, - query, - groupQuery, - found = false - - // ensure array to simplify code - if (!_.isArray(roles)) { - roles = [roles] - } - - if (!user) return false - if (group) { - if ('string' !== typeof group) return false - if ('$' === group[0]) return false - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - if ('object' === typeof user) { - userRoles = user.roles - if (_.isArray(userRoles)) { - return _.some(roles, function (role) { - return _.contains(userRoles, role) - }) - } else if ('object' === typeof userRoles) { - // roles field is dictionary of groups - found = _.isArray(userRoles[group]) && _.some(roles, function (role) { - return _.contains(userRoles[group], role) - }) - if (!found) { - // not found in regular group or group not specified. - // check Roles.GLOBAL_GROUP, if it exists - found = _.isArray(userRoles[Roles.GLOBAL_GROUP]) && _.some(roles, function (role) { - return _.contains(userRoles[Roles.GLOBAL_GROUP], role) - }) - } - return found - } - - // missing roles field, try going direct via id - id = user._id - } else if ('string' === typeof user) { - id = user - } - - if (!id) return false - - - query = {_id: id, $or: []} - - // always check Roles.GLOBAL_GROUP - groupQuery = {} - groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} - query.$or.push(groupQuery) - - if (group) { - // structure of query, when group specified including Roles.GLOBAL_GROUP - // {_id: id, - // $or: [ - // {'roles.group1':{$in: ['admin']}}, - // {'roles.__global_roles__':{$in: ['admin']}} - // ]} - groupQuery = {} - groupQuery['roles.'+group] = {$in: roles} - query.$or.push(groupQuery) - } else { - // structure of query, where group not specified. includes - // Roles.GLOBAL_GROUP - // {_id: id, - // $or: [ - // {roles: {$in: ['admin']}}, - // {'roles.__global_roles__': {$in: ['admin']}} - // ]} - query.$or.push({roles: {$in: roles}}) - } - - found = Meteor.users.findOne(query, {fields: {_id: 1}}) - return found ? true : false - }, - - /** - * Retrieve users roles - * - * @method getRolesForUser - * @param {String|Object} user User Id or actual user object - * @param {String} [group] Optional name of group to restrict roles to. - * User's Roles.GLOBAL_GROUP will also be included. - * @return {Array} Array of user's roles, unsorted. - */ - getRolesForUser: function (user, group) { - if (!user) return [] - if (group) { - if ('string' !== typeof group) return [] - if ('$' === group[0]) return [] - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - if ('string' === typeof user) { - user = Meteor.users.findOne( - {_id: user}, - {fields: {roles: 1}}) - - } else if ('object' !== typeof user) { - // invalid user object - return [] - } - - if (!user || !user.roles) return [] - - if (group) { - return _.union(user.roles[group] || [], user.roles[Roles.GLOBAL_GROUP] || []) - } - - if (_.isArray(user.roles)) - return user.roles - - // using groups but group not specified. return global group, if exists - return user.roles[Roles.GLOBAL_GROUP] || [] - }, - - /** - * Retrieve set of all existing roles - * - * @method getAllRoles - * @return {Cursor} cursor of existing roles - */ - getAllRoles: function () { - return Meteor.roles.find({}, {sort: {name: 1}}) - }, - - /** - * Retrieve all users who are in target role. - * - * NOTE: This is an expensive query; it performs a full collection scan - * on the users collection since there is no index set on the 'roles' field. - * This is by design as most queries will specify an _id so the _id index is - * used automatically. - * - * @method getUsersInRole - * @param {Array|String} role Name of role/permission. If array, users - * returned will have at least one of the roles - * specified but need not have _all_ roles. - * @param {String} [group] Optional name of group to restrict roles to. - * User's Roles.GLOBAL_GROUP will also be checked. - * @param {Object} [options] Optional options which are passed directly - * through to `Meteor.users.find(query, options)` - * @return {Cursor} cursor of users in role - */ - getUsersInRole: function (role, group, options) { - var query, - roles = role, - groupQuery - - // ensure array to simplify query logic - if (!_.isArray(roles)) roles = [roles] - - if (group) { - if ('string' !== typeof group) - throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") - if ('$' === group[0]) - throw new Error ("Roles error: groups can not start with '$'") - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - query = {$or: []} - - // always check Roles.GLOBAL_GROUP - groupQuery = {} - groupQuery['roles.'+Roles.GLOBAL_GROUP] = {$in: roles} - query.$or.push(groupQuery) - - if (group) { - // structure of query, when group specified including Roles.GLOBAL_GROUP - // { - // $or: [ - // {'roles.group1':{$in: ['admin']}}, - // {'roles.__global_roles__':{$in: ['admin']}} - // ]} - groupQuery = {} - groupQuery['roles.'+group] = {$in: roles} - query.$or.push(groupQuery) - } else { - // structure of query, where group not specified. includes - // Roles.GLOBAL_GROUP - // { - // $or: [ - // {roles: {$in: ['admin']}}, - // {'roles.__global_roles__': {$in: ['admin']}} - // ]} - query.$or.push({roles: {$in: roles}}) - } - - return Meteor.users.find(query, options); - }, // end getUsersInRole - - /** - * Retrieve users groups, if any - * - * @method getGroupsForUser - * @param {String|Object} user User Id or actual user object - * @param {String} [role] Optional name of roles to restrict groups to. - * - * @return {Array} Array of user's groups, unsorted. Roles.GLOBAL_GROUP will be omitted - */ - getGroupsForUser: function (user, role) { - var userGroups = []; - - if (!user) return [] - if (role) { - if ('string' !== typeof role) return [] - if ('$' === role[0]) return [] - - // convert any periods to underscores - role = role.replace('.', '_') - } - - if ('string' === typeof user) { - user = Meteor.users.findOne( - {_id: user}, - {fields: {roles: 1}}) - - }else if ('object' !== typeof user) { - // invalid user object - return [] - } - - //User has no roles or is not using groups - if (!user || !user.roles || _.isArray(user.roles)) return [] - - if (role) { - _.each(user.roles, function(groupRoles, groupName) { - if (_.contains(groupRoles, role) && groupName !== Roles.GLOBAL_GROUP) { - userGroups.push(groupName); - } - }); - return userGroups; - }else { - return _.without(_.keys(user.roles), Roles.GLOBAL_GROUP); - } - - }, //End getGroupsForUser - - - /** - * Private function 'template' that uses $set to construct an update object - * for MongoDB. Passed to _updateUserRoles - * - * @method _update_$set_fn - * @protected - * @param {Array} roles - * @param {String} [group] - * @return {Object} update object for use in MongoDB update command - */ - _update_$set_fn: function (roles, group) { - var update = {} - - if (group) { - // roles is a key/value dict object - update.$set = {} - update.$set['roles.' + group] = roles - } else { - // roles is an array of strings - update.$set = {roles: roles} - } - - return update - }, // end _update_$set_fn - - /** - * Private function 'template' that uses $addToSet to construct an update - * object for MongoDB. Passed to _updateUserRoles - * - * @method _update_$addToSet_fn - * @protected - * @param {Array} roles - * @param {String} [group] - * @return {Object} update object for use in MongoDB update command - */ - _update_$addToSet_fn: function (roles, group) { - var update = {} - - if (group) { - // roles is a key/value dict object - update.$addToSet = {} - update.$addToSet['roles.' + group] = {$each: roles} - } else { - // roles is an array of strings - update.$addToSet = {roles: {$each: roles}} - } - - return update - }, // end _update_$addToSet_fn - - - /** - * Internal function that uses the Template pattern to adds or sets roles - * for users. - * - * @method _updateUserRoles - * @protected - * @param {Array|String} users user id(s) or object(s) with an _id field - * @param {Array|String} roles name(s) of roles/permissions to add users to - * @param {String} group Group name. If not null or undefined, roles will be - * specific to that group. - * Group names can not start with '$'. - * Periods in names '.' are automatically converted - * to underscores. - * The special group Roles.GLOBAL_GROUP provides - * a convenient way to assign blanket roles/permissions - * across all groups. The roles/permissions in the - * Roles.GLOBAL_GROUP group will be automatically - * included in checks for any group. - * @param {Function} updateFactory Func which returns an update object that - * will be passed to Mongo. - * @param {Array} roles - * @param {String} [group] - */ - _updateUserRoles: function (users, roles, group, updateFactory) { - if (!users) throw new Error ("Missing 'users' param") - if (!roles) throw new Error ("Missing 'roles' param") - if (group) { - if ('string' !== typeof group) - throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type") - if ('$' === group[0]) - throw new Error ("Roles error: groups can not start with '$'") - - // convert any periods to underscores - group = group.replace(/\./g, '_') - } - - var existingRoles, - query, - update - - // ensure arrays to simplify code - if (!_.isArray(users)) users = [users] - if (!_.isArray(roles)) roles = [roles] - - // remove invalid roles - roles = _.reduce(roles, function (memo, role) { - if (role - && 'string' === typeof role - && role.trim().length > 0) { - memo.push(role.trim()) - } - return memo - }, []) - - // empty roles array is ok, since it might be a $set operation to clear roles - //if (roles.length === 0) return - - // ensure all roles exist in 'roles' collection - existingRoles = _.reduce(Meteor.roles.find({}).fetch(), function (memo, role) { - memo[role.name] = true - return memo - }, {}) - _.each(roles, function (role) { - if (!existingRoles[role]) { - Roles.createRole(role) - } - }) - - // ensure users is an array of user ids - users = _.reduce(users, function (memo, user) { - var _id - if ('string' === typeof user) { - memo.push(user) - } else if ('object' === typeof user) { - _id = user._id - if ('string' === typeof _id) { - memo.push(_id) - } - } - return memo - }, []) - - // update all users - update = updateFactory(roles, group) - - try { - if (Meteor.isClient) { - // On client, iterate over each user to fulfill Meteor's - // 'one update per ID' policy - _.each(users, function (user) { - Meteor.users.update({_id: user}, update) - }) - } else { - // On the server we can use MongoDB's $in operator for - // better performance - Meteor.users.update( - {_id: {$in: users}}, - update, - {multi: true}) - } - } - catch (ex) { - if (ex.name === 'MongoError' && isMongoMixError(ex.err)) { - throw new Error (mixingGroupAndNonGroupErrorMsg) - } - - throw ex - } - } // end _updateUserRoles - -}) // end _.extend(Roles ...) - - -function isMongoMixError (errorMsg) { - var expectedMessages = [ - 'Cannot apply $addToSet modifier to non-array', - 'Cannot apply $addToSet to a non-array field', - 'Can only apply $pullAll to an array', - 'Cannot apply $pull/$pullAll modifier to non-array', - "can't append to array using string field name", - 'to traverse the element' - ] - - return _.some(expectedMessages, function (snippet) { - return strContains(errorMsg, snippet) - }) -} - -function strContains (haystack, needle) { - return -1 !== haystack.indexOf(needle) -} - -}()); diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index 01c08fcba8e..bc0361b701d 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -21,14 +21,12 @@ Package.onUse(function(api) { api.use('templating', 'client'); - // roles - api.addFiles('server/roles.js', ['server']); - api.addFiles('lib/roles.js', ['client', 'server']); - api.addFiles('client/roles.js', ['client']); - api.addFiles('server/models/Users.js', ['server']); - 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']); @@ -45,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/Users.js', ['server']); + api.addFiles('server/models/Subscriptions.js', ['server']); - api.addFiles('server/functions/addUsersToRoles.coffee', ['server']); + api.addFiles('server/functions/addUserRoles.coffee', ['server']); api.addFiles('server/functions/getPermissionsForRole.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 @@ -79,6 +80,4 @@ Package.onUse(function(api) { })); api.use('tap:i18n'); api.addFiles(tapi18nFiles); - - api.export('Roles', 'server'); }); diff --git a/packages/rocketchat-authorization/server/functions/addUserRoles.coffee b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee new file mode 100644 index 00000000000..e3635f6b4ef --- /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(), 'name') + 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 ac2be57a546..00000000000 --- a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee +++ /dev/null @@ -1,27 +0,0 @@ -RocketChat.authz.addUsersToRoles = (userIds, roleNames, scope ) -> - 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 index 7023d120265..dd55acb226c 100644 --- a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee +++ b/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee @@ -2,8 +2,8 @@ RocketChat.authz.getPermissionsForRole = (roleName) -> unless roleName throw new Meteor.Error 'invalid-role' - roleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name') - unless roleName in roleNames + role = RocketChat.models.Roles.findOne roleName + if not role throw new Meteor.Error 'invalid-role', "Role #{roleName} not found" - return _.pluck(RocketChat.models.Permissions.findByRole( roleName ).fetch(), '_id') + 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 37c3d2537fd..895dcc532c1 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 800473a08bf..00000000000 --- a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee +++ /dev/null @@ -1,6 +0,0 @@ -RocketChat.authz.getRolesForUser = (userId, scope) -> - # returns roles for the given scope as well as the global scope - unless scope - scope = Roles.GLOBAL_GROUP - - return Roles.getRolesForUser(userId, scope) diff --git a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee index ee416c3e902..b8fc11a51fb 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 b7c39299c7e..7ae014453d0 100644 --- a/packages/rocketchat-authorization/server/functions/hasPermission.coffee +++ b/packages/rocketchat-authorization/server/functions/hasPermission.coffee @@ -1,10 +1,3 @@ RocketChat.authz.hasPermission = (userId, permissionId, scope) -> - # 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 + 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 10ac10df442..aff335e48b2 100644 --- a/packages/rocketchat-authorization/server/functions/hasRole.coffee +++ b/packages/rocketchat-authorization/server/functions/hasRole.coffee @@ -1,3 +1,3 @@ -RocketChat.authz.hasRole = (userId, roleName, scope) -> - # 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/server/functions/removeUserFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee new file mode 100644 index 00000000000..f05bcf70471 --- /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.removeUserFromRoles(userIds, 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 93f78b6ccad..00000000000 --- a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee +++ /dev/null @@ -1,25 +0,0 @@ -RocketChat.authz.removeUsersFromRoles = (userIds, roleNames, scope ) -> - 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 diff --git a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee index a5340768b51..74ba6bbea53 100644 --- a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee +++ b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee @@ -1,15 +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" 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 0a928cb252b..39ca53a3502 100644 --- a/packages/rocketchat-authorization/server/methods/deleteRole.coffee +++ b/packages/rocketchat-authorization/server/methods/deleteRole.coffee @@ -1,16 +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" - 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/removeUserFromRole.coffee b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee index 6510c2f8b2b..bc5e0504266 100644 --- a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee +++ b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee @@ -11,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.removeUserRole user._id, roleName diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee index 7a30d9ecec6..2fe6f208e9a 100644 --- a/packages/rocketchat-authorization/server/methods/saveRole.coffee +++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee @@ -9,7 +9,4 @@ Meteor.methods 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 saveData.name, 'Users', roleData.description diff --git a/packages/rocketchat-authorization/server/models/Permissions.coffee b/packages/rocketchat-authorization/server/models/Permissions.coffee index 3e1c6eef96a..ec763d94b71 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 00000000000..0ad0caee122 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Roles.coffee @@ -0,0 +1,42 @@ +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.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 os '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 00000000000..3d3048a10d3 --- /dev/null +++ b/packages/rocketchat-authorization/server/models/Subscriptions.js @@ -0,0 +1,91 @@ +RocketChat.models.Subscriptions.findRolesByUserId = function(userId) { + query = { + "u._id": userId + }; + + options = { fields: { roles: 1 } } + + return this.find(query, options); +} + +RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId) { + query = { + "u._id": userId, + rid: roomId, + roles: roleName + }; + + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models.Subscriptions.setRolesByUserId = function(userId, roles, roomId) { + roles = [].concat(roles); + + var query = { + "u._id": userId, + rid: roomId + } + + var update = { + $set: { + roles: roles + } + } + + return this.update(query, update); +} + +RocketChat.models.Subscriptions.addRolesByUserId = function(userId, roles, roomId) { + roles = [].concat(roles); + + var query = { + "u._id": userId, + rid: roomId + } + + var update = { + $addToSet: { + roles: { $each: roles } + } + } + + return this.update(query, update); +} + +RocketChat.models.Subscriptions.removeRolesByUserId = function(userId, roles, roomId) { + roles = [].concat(roles); + + var query = { + "u._id": userId, + rid: roomId + } + + var update = { + $pullAll: { + roles: roles + } + } + + return this.update(query, update); +} + +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 index 0d04ea7ad14..ed88b6dbd20 100644 --- a/packages/rocketchat-authorization/server/models/Users.js +++ b/packages/rocketchat-authorization/server/models/Users.js @@ -1,13 +1,76 @@ -RocketChat.models.Users.findRolesByUserId = function(userId, options) { - query = { +RocketChat.models.Users.findRolesByUserId = function(userId) { + var query = { _id: userId }; - if ("object" !== typeof options) { - options = {} + options = { fields: { roles: 1 } } + + return this.find(query, options); +}; + +RocketChat.models.Users.isUserInRole = function(userId, roleName) { + query = { + _id: userId, + roles: roleName + }; + + return !_.isUndefined(this.findOne(query)); +} + +RocketChat.models.Users.setRolesByUserId = function(userId, roles) { + roles = [].concat(roles); + + var query = { + _id: userId + } + + var update = { + $set: { + roles: roles + } } - options.fields = { roles: 1 } + return this.update(query, update); +} + +RocketChat.models.Users.addRolesByUserId = function(userId, roles) { + roles = [].concat(roles); + + var query = { + _id: userId + } + + var update = { + $addToSet: { + roles: { $each: roles } + } + } + + return this.update(query, update); +} + +RocketChat.models.Users.removeRolesByUserId = function(userId, roles) { + roles = [].concat(roles); + + var query = { + _id: userId + } + + var update = { + $pullAll: { + roles: roles + } + } + + return this.update(query, update); +} + +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 9a4fa8cbfc1..00000000000 --- a/packages/rocketchat-authorization/server/publication.coffee +++ /dev/null @@ -1,2 +0,0 @@ -Meteor.publish 'permissions', -> - 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 00000000000..0872d3b4db0 --- /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 6357a62510e..b3eafb56d3e 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 00000000000..bd6247697b0 --- /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/roles.js b/packages/rocketchat-authorization/server/roles.js deleted file mode 100644 index fe98a742d34..00000000000 --- a/packages/rocketchat-authorization/server/roles.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict" - - -/** - * Roles collection documents consist only of an id and a role name. - * ex: { _id: "123", name: "admin" } - */ -if (!Meteor.roles) { - Meteor.roles = new Mongo.Collection("roles") - - // Create default indexes for roles collection - Meteor.roles._ensureIndex('name', {unique: 1}) -} - - -/** - * Publish logged-in user's roles (global) so client-side checks can work. - * - * Use a named publish function so clients can check `ready()` state. - */ -Meteor.publish('scope-roles', function (scope) { - if (!this.userId || "undefined" === typeof RocketChat.models[scope] || "function" !== typeof 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 4bc8c430310..cd37963dcd4 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']} @@ -34,7 +34,7 @@ Meteor.startup -> roles : ['admin']} { _id: 'edit-other-user-active-status', - roles : ['admin', 'site-moderator']} + roles : ['admin']} { _id: 'delete-user', roles : ['admin']} @@ -49,37 +49,37 @@ 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']} { _id: 'edit-message', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator']} { _id: 'delete-message', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator']} { _id: 'remove-user', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator']} { _id: 'mute-user', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator']} { _id: 'ban-user', - roles : ['admin', 'site-moderator', 'moderator']} + roles : ['admin', 'moderator']} { _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']} @@ -88,13 +88,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']} @@ -109,7 +109,6 @@ Meteor.startup -> for permission in permissions RocketChat.models.Permissions.upsert( permission._id, {$set: permission }) - roles = _.pluck(Roles.getAllRoles().fetch(), 'name'); defaultRoles = [ { name: 'admin', scope: 'Users' } { name: 'moderator', scope: 'Subscriptions' } @@ -118,5 +117,4 @@ Meteor.startup -> ] for role in defaultRoles - unless role.name in roles - Roles.createRole role + RocketChat.models.Roles.createOrUpdate role.name, role.scope diff --git a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee index 67c33d156f6..54efaf76006 100644 --- a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee @@ -61,7 +61,7 @@ Meteor.methods RocketChat.models.Users.update {_id: user._id}, updateObj - Roles.addUsersToRoles user._id, 'bot', 'bot' + RocketChat.models.Roles.addUserRoles user._id, 'bot' integration._id = RocketChat.models.Integrations.insert integration diff --git a/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee index da7aa3dd15f..59a93bdbbaf 100644 --- a/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee @@ -38,7 +38,7 @@ Meteor.methods throw new Meteor.Error 'channel_does_not_exists', "[methods] updateIncomingIntegration -> The channel does not exists" user = RocketChat.models.Users.findOne({username: currentIntegration.username}) - Roles.addUsersToRoles user._id, 'bot', 'bot' + RocketChat.models.Roles.addUserRoles user._id, 'bot' RocketChat.models.Integrations.update integrationId, $set: diff --git a/packages/rocketchat-lib/server/methods/setAdminStatus.coffee b/packages/rocketchat-lib/server/methods/setAdminStatus.coffee index b81d6d9f04f..542c5853fd0 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-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js index ea678f9abe6..ad5a5a3c843 100644 --- a/packages/rocketchat-livechat/permissions.js +++ b/packages/rocketchat-livechat/permissions.js @@ -1,13 +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) { - Roles.createRole('livechat-guest'); + 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/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js index cd924c14ce9..e236bc2c41a 100644 --- a/packages/rocketchat-livechat/server/methods/addAgent.js +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -14,7 +14,7 @@ Meteor.methods({ 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 eb0f905ec40..9f4af3713a4 100644 --- a/packages/rocketchat-livechat/server/methods/addManager.js +++ b/packages/rocketchat-livechat/server/methods/addManager.js @@ -14,6 +14,6 @@ Meteor.methods({ 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/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js index 141b7d3bf94..adbf4ae4773 100644 --- a/packages/rocketchat-livechat/server/methods/removeAgent.js +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -14,7 +14,7 @@ Meteor.methods({ 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/removeManager.js b/packages/rocketchat-livechat/server/methods/removeManager.js index 32db557fd80..31ad6cd337b 100644 --- a/packages/rocketchat-livechat/server/methods/removeManager.js +++ b/packages/rocketchat-livechat/server/methods/removeManager.js @@ -12,6 +12,6 @@ Meteor.methods({ 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/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index 0c3d85af0a0..be4011d4f50 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -20,11 +20,9 @@ RocketChat.models.Users.setOperator = function(_id, operator) { RocketChat.models.Users.findOnlineAgents = function() { var query = { status: 'online', - roles: {} + roles: 'livechat-agent' }; - query.roles[Roles.GLOBAL_GROUP] = 'livechat-agent'; - return this.find(query); }; @@ -50,11 +48,10 @@ RocketChat.models.Users.findOnlineUserFromList = function(userList) { */ RocketChat.models.Users.getNextAgent = function() { var query = { - status: 'online' + status: 'online', + roles: 'livechat-agent' }; - query['roles.' + Roles.GLOBAL_GROUP] = 'livechat-agent'; - var collectionObj = this.model.rawCollection(); var findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj); diff --git a/packages/rocketchat-ui/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee index 4c77cee3d1a..a1f8bd13879 100644 --- a/packages/rocketchat-ui/lib/collections.coffee +++ b/packages/rocketchat-ui/lib/collections.coffee @@ -3,3 +3,8 @@ @ChatSubscription = new Meteor.Collection 'rocketchat_subscription' @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/server/lib/accounts.coffee b/server/lib/accounts.coffee index e68658e7dec..cc51761cb35 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -86,7 +86,7 @@ Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc, options, else roles.push 'user' - RocketChat.authz.addUsersToRoles(_id, roles) + RocketChat.authz.addUserRoles(_id, roles) RocketChat.callbacks.run 'afterCreateUser', options, user return _id diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index c2e8db8ce1d..98291882421 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -42,7 +42,7 @@ Meteor.methods ts: now # set creator as channel moderator. permission limited to channel by scoping to rid - RocketChat.authz.addUsersToRoles(Meteor.userId(), 'moderator', room._id) + RocketChat.authz.addUserRoles(Meteor.userId(), 'moderator', room._id) for username in members member = RocketChat.models.Users.findOneByUsername username diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 8bfa8304d98..3a0dd23fa4c 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -34,7 +34,7 @@ Meteor.methods 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', room._id) for username in members member = RocketChat.models.Users.findOneByUsername(username, { fields: { username: 1 }}) diff --git a/server/methods/removeUserFromRoom.coffee b/server/methods/removeUserFromRoom.coffee index 78a5137fe2a..f45e43a5bab 100644 --- a/server/methods/removeUserFromRoom.coffee +++ b/server/methods/removeUserFromRoom.coffee @@ -18,7 +18,7 @@ Meteor.methods RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, removedUser._id if room.t in [ 'c', 'p' ] - RocketChat.authz.removeUsersFromRoles(removedUser._id; 'moderator', data.rid) + RocketChat.authz.removeUserFromRoles(removedUser._id; 'moderator', data.rid) fromUser = RocketChat.models.Users.findOneById fromId RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser, diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee index 47ba296a93f..045b6d0673a 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/v27.coffee b/server/startup/migrations/v27.coffee new file mode 100644 index 00000000000..3333a8896c7 --- /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 }) -- GitLab From 628ba2b367ef1cc47dea0bfc2c11bd3177ff4c2e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 18:16:06 -0200 Subject: [PATCH 1123/1338] stores visited page title --- packages/rocketchat-livechat/app/client/lib/triggers.js | 2 +- packages/rocketchat-livechat/assets/rocket-livechat.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/lib/triggers.js b/packages/rocketchat-livechat/app/client/lib/triggers.js index a742d469977..354e55d986d 100644 --- a/packages/rocketchat-livechat/app/client/lib/triggers.js +++ b/packages/rocketchat-livechat/app/client/lib/triggers.js @@ -54,7 +54,7 @@ this.Triggers = (function() { trigger.conditions.forEach(function(condition) { switch (condition.name) { case 'page-url': - if (request.href.match(new RegExp(condition.value))) { + if (request.location.href.match(new RegExp(condition.value))) { fire(trigger.actions); } break; diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index edb29e6bc0f..f27762a53e0 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -70,7 +70,10 @@ }; var pageVisited = function() { - callHook('pageVisited', JSON.parse(JSON.stringify(document.location))); + callHook('pageVisited', { + location: JSON.parse(JSON.stringify(document.location)), + title: document.title + }); }; var currentPage = { -- GitLab From 4c0e50d49875617c970ca6309255c5288a77f649 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 18:16:41 -0200 Subject: [PATCH 1124/1338] shows visitor's navigation history --- .../rocketchat-livechat/app/i18n/en.i18n.json | 2 +- .../client/collections/LivechatPageVisited.js | 1 + .../client/stylesheets/livechat.less | 30 ++++++- .../client/views/app/tabbar/visitorInfo.html | 14 ++++ .../client/views/app/tabbar/visitorInfo.js | 80 ++++++++++++++----- .../rocketchat-livechat/i18n/en.i18n.json | 4 +- packages/rocketchat-livechat/package.js | 4 +- .../server/models/LivechatPageVisited.js | 2 +- .../server/publications/visitorPageVisited.js | 17 ++++ 9 files changed, 129 insertions(+), 25 deletions(-) create mode 100644 packages/rocketchat-livechat/client/collections/LivechatPageVisited.js create mode 100644 packages/rocketchat-livechat/server/publications/visitorPageVisited.js diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index e31bf14dbe7..e09be84fb29 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -15,4 +15,4 @@ "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", "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/client/collections/LivechatPageVisited.js b/packages/rocketchat-livechat/client/collections/LivechatPageVisited.js new file mode 100644 index 00000000000..f2f4fc2a60d --- /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/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index c48742a810f..24c80d0d808 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -440,7 +440,7 @@ .user-view { li { - color: #7f7f7f; + color: @secondary-font-color; line-height: 18px; font-size: 12px; font-weight: 300; @@ -462,3 +462,31 @@ .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/views/app/tabbar/visitorInfo.html b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html index cfa3865cfa8..77872c89773 100644 --- a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.html @@ -27,6 +27,20 @@ <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 index 6f7166684b5..48feb1fdd12 100644 --- a/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js +++ b/packages/rocketchat-livechat/client/views/app/tabbar/visitorInfo.js @@ -1,30 +1,70 @@ Template.visitorInfo.helpers({ user() { - var room = ChatRoom.findOne(Session.get('openedRoom')); - - if (room && room.v && room.v.token) { - var user = Meteor.users.findOne({ "profile.token": room.v.token }); - 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(); + 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'); + }, - return user; + 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.autorun(() => { - this.subscribe('livechat:visitorInfo', Session.get('openedRoom')); - }); + 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/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index bf4f5c5a702..5b4ce502ab1 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -15,6 +15,7 @@ "Departments" : "Departments", "Description" : "Description", "Edit_Department" : "Edit Department", + "Empty_title" : "Empty title", "Enable" : "Enable", "Enabled" : "Enabled", "Enter_a_regex" : "Enter a regex", @@ -31,6 +32,7 @@ "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", @@ -53,4 +55,4 @@ "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/package.js b/packages/rocketchat-livechat/package.js index 9771af9ee62..6820ee375ae 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -44,6 +44,7 @@ Package.onUse(function(api) { 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 @@ -104,10 +105,11 @@ Package.onUse(function(api) { 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 diff --git a/packages/rocketchat-livechat/server/models/LivechatPageVisited.js b/packages/rocketchat-livechat/server/models/LivechatPageVisited.js index 8917e0167b3..36ecd827265 100644 --- a/packages/rocketchat-livechat/server/models/LivechatPageVisited.js +++ b/packages/rocketchat-livechat/server/models/LivechatPageVisited.js @@ -26,7 +26,7 @@ class LivechatPageVisitied extends RocketChat.models._Base { } findByToken(token) { - return this.find({ token: token }); + return this.find({ token: token }, { sort : { ts: -1 }, limit: 20 }); } keepHistoryForToken(token) { diff --git a/packages/rocketchat-livechat/server/publications/visitorPageVisited.js b/packages/rocketchat-livechat/server/publications/visitorPageVisited.js new file mode 100644 index 00000000000..72aa424c673 --- /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(); + } +}); -- GitLab From 64b35434a3a376483a4a65376924c646cf441b4d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 18:16:59 -0200 Subject: [PATCH 1125/1338] force add title to page on links --- packages/rocketchat-livechat/assets/demo.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-livechat/assets/demo.html b/packages/rocketchat-livechat/assets/demo.html index df2c77e02c6..99cfead8c1e 100644 --- a/packages/rocketchat-livechat/assets/demo.html +++ b/packages/rocketchat-livechat/assets/demo.html @@ -20,13 +20,13 @@ <h1 style="color:#000">test</h1> <p style="color:#000">Talk to us.</p> - <a href="#page-0">page 0</a><br> - <a href="#page-1">page 1</a><br> - <a href="#page-2">page 2</a><br> - <a href="#page-3">page 3</a><br> - <a href="#page-4">page 4</a><br> - <a href="#page-5">page 5</a><br> - <a href="#page-6">page 6</a><br> + <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> -- GitLab From b77cbb524b8c5bc0740e60ae0e627cafadd4819e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 18:19:50 -0200 Subject: [PATCH 1126/1338] changed icon for visitor information tabbar --- packages/rocketchat-livechat/client/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index e6e390818fc..198a4d17d38 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -22,7 +22,7 @@ RocketChat.roomTypes.add('l', 5, { AccountBox.addItem({ name: 'Livechat', - icon: 'icon-chat-empty', + icon: 'octicon octicon-info', href: 'livechat-users', sideNav: 'livechatFlex', condition: () => { -- GitLab From c699704c622d836aabd2baa7caa87ed56e1f33ea Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 18:23:21 -0200 Subject: [PATCH 1127/1338] =?UTF-8?q?changed=20wrong=20icon=20=C2=AC=C2=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/rocketchat-livechat/client/ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/client/ui.js b/packages/rocketchat-livechat/client/ui.js index 198a4d17d38..1041cfc75e6 100644 --- a/packages/rocketchat-livechat/client/ui.js +++ b/packages/rocketchat-livechat/client/ui.js @@ -22,7 +22,7 @@ RocketChat.roomTypes.add('l', 5, { AccountBox.addItem({ name: 'Livechat', - icon: 'octicon octicon-info', + icon: 'icon-chat-empty', href: 'livechat-users', sideNav: 'livechatFlex', condition: () => { @@ -34,7 +34,7 @@ RocketChat.TabBar.addButton({ groups: ['livechat'], id: 'visitor-info', i18nTitle: 'Visitor_Info', - icon: 'icon-chat', + icon: 'octicon octicon-info', template: 'visitorInfo', order: 0 }); -- GitLab From 3f6f27d8d05b8aebec824a2bfbe64995b4822486 Mon Sep 17 00:00:00 2001 From: Julian Popescu <jpopesculian@gmail.com> Date: Wed, 6 Jan 2016 16:08:24 -0500 Subject: [PATCH 1128/1338] removed byte array for debug statements for ufsWrite --- packages/rocketchat-lib/server/lib/debug.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/lib/debug.js b/packages/rocketchat-lib/server/lib/debug.js index c63fc96bf72..1ccc9791d31 100644 --- a/packages/rocketchat-lib/server/lib/debug.js +++ b/packages/rocketchat-lib/server/lib/debug.js @@ -16,7 +16,8 @@ Meteor.startup(function() { var wrapMethods = function(name, originalHandler, methodsMap) { methodsMap[name] = function() { if (RocketChat.debugLevel === 'debug') { - console.log('[methods]'.green, name, '-> userId:', Meteor.userId(), ', arguments: ', arguments); + 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); -- GitLab From 04f013034a2c6bbf24a112097b29b97f2177aaad Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 6 Jan 2016 19:13:41 -0200 Subject: [PATCH 1129/1338] Add some options to logger and use it in some places --- .../saml_rocketchat.coffee | 6 +++++- .../server/startup/oAuthServicesUpdate.coffee | 6 +++++- packages/rocketchat-logger/package.js | 1 + packages/rocketchat-logger/server.coffee | 19 ++++++++++++++----- .../rocketchat-theme/server/server.coffee | 7 ++++++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/packages/meteor-accounts-saml/saml_rocketchat.coffee b/packages/meteor-accounts-saml/saml_rocketchat.coffee index c75bddf38d9..16022a7f7ac 100644 --- a/packages/meteor-accounts-saml/saml_rocketchat.coffee +++ b/packages/meteor-accounts-saml/saml_rocketchat.coffee @@ -1,3 +1,7 @@ +logger = new Logger 'steffo:meteor-accounts-saml', + methods: + updated: 'log' + RocketChat.settings.addGroup 'SAML' Meteor.methods addSamlService: (name) -> @@ -21,7 +25,7 @@ updateServices = -> Accounts.saml.settings.providers = [] for service in services - console.log "Updating login service #{service._id}".blue + logger.updated service._id serviceName = 'saml' diff --git a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee index 75b30d643e2..0305dc42969 100644 --- a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee +++ b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee @@ -1,3 +1,7 @@ +logger = new Logger 'rocketchat:lib', + methods: + oauth_updated: 'log' + timer = undefined oAuthServicesUpdate = -> Meteor.clearTimeout timer if timer? @@ -5,7 +9,7 @@ oAuthServicesUpdate = -> timer = Meteor.setTimeout -> services = RocketChat.models.Settings.find({_id: /^(Accounts_OAuth_|Accounts_OAuth_Custom_)[a-z_-]+$/i}).fetch() for service in services - console.log "Updating login service #{service._id}".blue + logger.oauth_updated service._id serviceName = service._id.replace('Accounts_OAuth_', '') diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js index 39a3c4e39d0..61036e648f9 100644 --- a/packages/rocketchat-logger/package.js +++ b/packages/rocketchat-logger/package.js @@ -9,6 +9,7 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use('coffeescript'); + api.use('underscore'); api.use('logging'); api.use('nooitaf:colors'); api.use('templating', 'client', {weak: true}); diff --git a/packages/rocketchat-logger/server.coffee b/packages/rocketchat-logger/server.coffee index 3d155936e2f..2a38507c59d 100644 --- a/packages/rocketchat-logger/server.coffee +++ b/packages/rocketchat-logger/server.coffee @@ -1,5 +1,7 @@ LoggerManager = new class loggers: {} + showPackage: false + showFileAndLine: false @Logger = class Logger defaultTypes: @@ -7,7 +9,11 @@ LoggerManager = new class warn: 'magenta' error: 'red' - constructor: (@name, @config={}) -> + config: {} + + constructor: (@name, config={}) -> + _.extend @config, config + if LoggerManager.loggers[@name]? LoggerManager.loggers[@name].warn 'Duplicated instance' return LoggerManager.loggers[@name] @@ -40,16 +46,19 @@ LoggerManager = new class prefix = "" if options.method? - prefix = "[#{@name}->#{options.method}]" + prefix = "[#{@name} #{options.method}]" else prefix = "[#{@name}]" details = @_getCallerDetails() detailParts = [] - if details.package? then detailParts.push details.package - if details.file? then detailParts.push details.file - if details.line? then detailParts.push details.line + if details.package? and LoggerManager.showPackage is true + detailParts.push details.package + if details.file? and LoggerManager.showFileAndLine is true + detailParts.push details.file + if details.line? and LoggerManager.showFileAndLine is true + detailParts.push details.line if detailParts.length > 0 prefix = "(#{detailParts.join(':')})#{prefix}" diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 1cb6a376e9e..190c46e8529 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -2,6 +2,11 @@ less = Npm.require('less') autoprefixer = Npm.require('less-plugin-autoprefix') crypto = Npm.require('crypto') +logger = new Logger 'rocketchat:theme', + methods: + stop_rendering: 'log' + + calculateClientHash = WebAppHashing.calculateClientHash WebAppHashing.calculateClientHash = (manifest, includeFilter, runtimeConfigOverride) -> css = RocketChat.theme.getCss() @@ -87,7 +92,7 @@ RocketChat.theme = new class start = Date.now() less.render content, options, (err, data) -> - console.log 'stop rendering', Date.now() - start + logger.stop_rendering Date.now() - start if err? return console.log err -- GitLab From f34624f1f5841216a5a928f8e3d346829174a97b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 6 Jan 2016 19:39:04 -0200 Subject: [PATCH 1130/1338] Fix some package dependencies --- packages/rocketchat-livechat/package.js | 1 + packages/rocketchat-ui-sidenav/package.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 6820ee375ae..216d35f0243 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -22,6 +22,7 @@ Package.onUse(function(api) { api.use('ecmascript'); api.use('alanning:roles@1.2.12'); api.use('rocketchat:lib'); + api.use('rocketchat:ui'); api.use('kadira:flow-router', 'client'); api.use('templating', 'client'); api.use('mongo'); diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index f0c3872b146..3da5274a07e 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@0.0.1', + 'rocketchat:ui' ]); api.addFiles('side-nav/accountBox.html', 'client'); -- GitLab From 35a330000ae4d1d7e1e6072a6859a45b5a92f415 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 6 Jan 2016 20:04:25 -0200 Subject: [PATCH 1131/1338] removing @0.0.1 from rocketchat:ldap --- packages/rocketchat-assets/package.js | 2 +- packages/rocketchat-authorization/package.js | 2 +- packages/rocketchat-autolinker/package.js | 2 +- packages/rocketchat-channel-settings-mail-messages/package.js | 2 +- packages/rocketchat-channel-settings/package.js | 2 +- packages/rocketchat-chatops/package.js | 2 +- packages/rocketchat-colors/package.js | 2 +- packages/rocketchat-emojione/package.js | 2 +- packages/rocketchat-github-enterprise/package.js | 2 +- packages/rocketchat-gitlab/package.js | 2 +- packages/rocketchat-highlight/package.js | 2 +- packages/rocketchat-hubot/package.js | 2 +- packages/rocketchat-integrations/package.js | 2 +- packages/rocketchat-ldap/package.js | 2 +- packages/rocketchat-mailer/package.js | 2 +- packages/rocketchat-markdown/package.js | 2 +- packages/rocketchat-me/package.js | 2 +- packages/rocketchat-mentions-flextab/package.js | 2 +- packages/rocketchat-mentions/package.js | 2 +- packages/rocketchat-message-attachments/package.js | 2 +- packages/rocketchat-message-pin/package.js | 2 +- packages/rocketchat-message-star/package.js | 2 +- packages/rocketchat-oauth2-server-config/package.js | 2 +- packages/rocketchat-oembed/package.js | 2 +- packages/rocketchat-sharedsecret/package.js | 2 +- packages/rocketchat-slashcommands-invite/package.js | 2 +- packages/rocketchat-slashcommands-join/package.js | 2 +- packages/rocketchat-slashcommands-kick/package.js | 2 +- packages/rocketchat-slashcommands-leave/package.js | 2 +- packages/rocketchat-slashcommands-mute/package.js | 2 +- packages/rocketchat-spotify/package.js | 2 +- packages/rocketchat-statistics/package.js | 2 +- packages/rocketchat-ui-account/package.js | 4 ++-- packages/rocketchat-ui-admin/package.js | 2 +- packages/rocketchat-ui-login/package.js | 2 +- packages/rocketchat-ui-sidenav/package.js | 2 +- packages/rocketchat-ui/package.js | 2 +- packages/rocketchat-webrtc/package.js | 2 +- packages/rocketchat-wordpress/package.js | 2 +- 39 files changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/rocketchat-assets/package.js b/packages/rocketchat-assets/package.js index e5f75eaf3d2..ea0504827fe 100644 --- a/packages/rocketchat-assets/package.js +++ b/packages/rocketchat-assets/package.js @@ -13,7 +13,7 @@ Package.onUse(function(api) { 'underscore', 'webapp', 'rocketchat:file', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('server/assets.coffee', 'server'); diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js index e416cd4118e..62fa6b7fe64 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'alanning:roles@1.2.12' ]); diff --git a/packages/rocketchat-autolinker/package.js b/packages/rocketchat-autolinker/package.js index af2c1419915..26e5d0a3f02 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/package.js b/packages/rocketchat-channel-settings-mail-messages/package.js index b7ff606e064..76b23988382 100644 --- a/packages/rocketchat-channel-settings-mail-messages/package.js +++ b/packages/rocketchat-channel-settings-mail-messages/package.js @@ -13,7 +13,7 @@ Package.onUse(function(api) { 'templating', 'reactive-var', 'less@2.5.0', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'rocketchat:channel-settings', 'momentjs:moment' ]); diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js index 6ca7c4a9026..a551aa5cde9 100644 --- a/packages/rocketchat-channel-settings/package.js +++ b/packages/rocketchat-channel-settings/package.js @@ -14,7 +14,7 @@ Package.onUse(function(api) { 'tracker', 'templating', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ diff --git a/packages/rocketchat-chatops/package.js b/packages/rocketchat-chatops/package.js index 347f4a3f265..17a28280945 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' ]); diff --git a/packages/rocketchat-colors/package.js b/packages/rocketchat-colors/package.js index 45899a9b7da..48b47b04ffe 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-emojione/package.js b/packages/rocketchat-emojione/package.js index 761d9d0ff87..a89c2d31b66 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-github-enterprise/package.js b/packages/rocketchat-github-enterprise/package.js index 7031b8a12dc..cbb6321723b 100644 --- a/packages/rocketchat-github-enterprise/package.js +++ b/packages/rocketchat-github-enterprise/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('startup.coffee', 'server'); diff --git a/packages/rocketchat-gitlab/package.js b/packages/rocketchat-gitlab/package.js index 6f7b900eddc..8e1b7250e60 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"); diff --git a/packages/rocketchat-highlight/package.js b/packages/rocketchat-highlight/package.js index a8587bff10e..40c87c35671 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/package.js b/packages/rocketchat-hubot/package.js index 213fc5ece22..55074e51a48 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([ diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index 0f532edc0aa..8c00200f332 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); api.use('simple:highlight.js'); - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.use('alanning:roles@1.2.12'); api.use('kadira:flow-router', 'client'); diff --git a/packages/rocketchat-ldap/package.js b/packages/rocketchat-ldap/package.js index 0f01f0152f0..7c6b23a79d0 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -22,7 +22,7 @@ Package.onUse(function(api) { api.versionsFrom('1.0.3.1'); // Commom - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.use('tap:i18n'); api.use('yasaricli:slugify'); api.use('coffeescript'); diff --git a/packages/rocketchat-mailer/package.js b/packages/rocketchat-mailer/package.js index 9de07383c65..ab47e1a98ef 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' ]); diff --git a/packages/rocketchat-markdown/package.js b/packages/rocketchat-markdown/package.js index aca6f0d8415..ef87d1cc43c 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 c23a5d916f9..a123d4e98ed 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/package.js b/packages/rocketchat-mentions-flextab/package.js index 1ae50b98edf..320ff8098d1 100644 --- a/packages/rocketchat-mentions-flextab/package.js +++ b/packages/rocketchat-mentions-flextab/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { 'coffeescript', 'underscore', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ diff --git a/packages/rocketchat-mentions/package.js b/packages/rocketchat-mentions/package.js index 51266c3fd9c..bc10d0e3e7c 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/package.js b/packages/rocketchat-message-attachments/package.js index a5b5873903d..9c9945e868a 100644 --- a/packages/rocketchat-message-attachments/package.js +++ b/packages/rocketchat-message-attachments/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client/messageAttachment.html', 'client'); diff --git a/packages/rocketchat-message-pin/package.js b/packages/rocketchat-message-pin/package.js index 394cc8f875b..b70908ef0bd 100644 --- a/packages/rocketchat-message-pin/package.js +++ b/packages/rocketchat-message-pin/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { 'coffeescript', 'underscore', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ diff --git a/packages/rocketchat-message-star/package.js b/packages/rocketchat-message-star/package.js index f4824b7374f..a05a6a1767a 100644 --- a/packages/rocketchat-message-star/package.js +++ b/packages/rocketchat-message-star/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { 'coffeescript', 'underscore', 'less@2.5.0', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles([ diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js index c5cc4e44abd..479ba8b40b3 100644 --- a/packages/rocketchat-oauth2-server-config/package.js +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -9,7 +9,7 @@ Package.onUse(function(api) { api.use('webapp'); api.use('coffeescript'); - api.use('rocketchat:lib@0.0.1'); + api.use('rocketchat:lib'); api.use('rocketchat:theme'); api.use('rocketchat:oauth2-server'); diff --git a/packages/rocketchat-oembed/package.js b/packages/rocketchat-oembed/package.js index ace7d0496be..3bb4babd591 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-sharedsecret/package.js b/packages/rocketchat-sharedsecret/package.js index 4371ff0846a..d0547036c7a 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/package.js b/packages/rocketchat-slashcommands-invite/package.js index d2192e63018..1f78c040243 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'); diff --git a/packages/rocketchat-slashcommands-join/package.js b/packages/rocketchat-slashcommands-join/package.js index db31822eeb2..08f72676382 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'); diff --git a/packages/rocketchat-slashcommands-kick/package.js b/packages/rocketchat-slashcommands-kick/package.js index 11f5dba4a72..a2878a1f7d4 100644 --- a/packages/rocketchat-slashcommands-kick/package.js +++ b/packages/rocketchat-slashcommands-kick/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'); diff --git a/packages/rocketchat-slashcommands-leave/package.js b/packages/rocketchat-slashcommands-leave/package.js index 678f15b5593..ac66b78c464 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/package.js b/packages/rocketchat-slashcommands-mute/package.js index 4a45f31978a..3d776dd74e1 100644 --- a/packages/rocketchat-slashcommands-mute/package.js +++ b/packages/rocketchat-slashcommands-mute/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { api.use([ 'coffeescript', 'check', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.addFiles('client/mute.coffee', 'client'); diff --git a/packages/rocketchat-spotify/package.js b/packages/rocketchat-spotify/package.js index 4940ac69ed8..c4829d6eb67 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 753a1086eb5..31216ca1612 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 diff --git a/packages/rocketchat-ui-account/package.js b/packages/rocketchat-ui-account/package.js index 77b86dc6268..5e818f1b6b8 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/package.js b/packages/rocketchat-ui-admin/package.js index bebed82fd63..6fc80872456 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-login/package.js b/packages/rocketchat-ui-login/package.js index f2f5a02e8c0..750c1a7736d 100644 --- a/packages/rocketchat-ui-login/package.js +++ b/packages/rocketchat-ui-login/package.js @@ -17,7 +17,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1' + 'rocketchat:lib' ]); api.use('kadira:flow-router', 'client'); diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index 3da5274a07e..6136ef7e087 100644 --- a/packages/rocketchat-ui-sidenav/package.js +++ b/packages/rocketchat-ui-sidenav/package.js @@ -18,7 +18,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'rocketchat:ui' ]); diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index eec1c93b7c3..80e0abaa6f1 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -24,7 +24,7 @@ Package.onUse(function(api) { 'templating', 'coffeescript', 'underscore', - 'rocketchat:lib@0.0.1', + 'rocketchat:lib', 'raix:push', 'raix:ui-dropped-event' ]); diff --git a/packages/rocketchat-webrtc/package.js b/packages/rocketchat-webrtc/package.js index cd19b3a958b..555b1db1f24 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'); diff --git a/packages/rocketchat-wordpress/package.js b/packages/rocketchat-wordpress/package.js index fb798631433..a219fc6b77a 100644 --- a/packages/rocketchat-wordpress/package.js +++ b/packages/rocketchat-wordpress/package.js @@ -7,7 +7,7 @@ Package.describe({ 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"); api.addFiles('wordpress-login-button.css', 'client'); -- GitLab From 8a1ad195375630169e83bd234cb37d4442c11a07 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 6 Jan 2016 22:29:42 -0200 Subject: [PATCH 1132/1338] fix pinned tabbar button not showing sometimes --- .../client/tabBar.coffee | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-message-pin/client/tabBar.coffee b/packages/rocketchat-message-pin/client/tabBar.coffee index 1a2e5dc532c..f434a26bf6e 100644 --- a/packages/rocketchat-message-pin/client/tabBar.coffee +++ b/packages/rocketchat-message-pin/client/tabBar.coffee @@ -1,10 +1,13 @@ Meteor.startup -> - if RocketChat.settings.get 'Message_AllowPinning' - RocketChat.TabBar.addButton({ - groups: ['channel', 'privategroup', 'directmessage'], - id: 'pinned-messages', - i18nTitle: 'Pinned_Messages', - icon: 'icon-pin', - template: 'pinnedMessages', - order: 10 - }) + Tracker.autorun -> + if RocketChat.settings.get 'Message_AllowPinning' + 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' -- GitLab From 47b23b324d0b059b910e8730c62029a8025bc9b9 Mon Sep 17 00:00:00 2001 From: "S. Li" <sli@makawave.com> Date: Thu, 7 Jan 2016 01:47:32 -0500 Subject: [PATCH 1133/1338] manage our own artifacts on S3 and host release page plus latest lookup server --- .docker/dockerfiles/develop/Dockerfile | 37 ++++++++++++++++++++++++++ .docker/dockerfiles/latest/Dockerfile | 2 +- .travis.yml | 21 +++++++-------- .travis/docker.sh | 7 +++-- .travis/namefiles.sh | 16 ++++++----- .travis/sandstorm.sh | 2 +- .travis/setartname.sh | 6 +++++ 7 files changed, 69 insertions(+), 22 deletions(-) create mode 100644 .docker/dockerfiles/develop/Dockerfile create mode 100755 .travis/setartname.sh diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile new file mode 100644 index 00000000000..bbce2753d91 --- /dev/null +++ b/.docker/dockerfiles/develop/Dockerfile @@ -0,0 +1,37 @@ +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/build/rocket.chat-develop.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/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index 72c9a4ea913..296f2e76dc4 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -12,7 +12,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN URL="https://github.com/RocketChat/Rocket.Chat/releases/latest" \ +RUN URL="https://builds.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' | sed 's/\/tag\//\/download\//' ) \ && curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ diff --git a/.travis.yml b/.travis.yml index 8ce22734161..8e97faa6422 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,8 @@ sudo: required language: node_js branches: only: - - master - develop - - beta - - "/^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/" + - "/^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/" git: depth: 1 node_js: @@ -23,20 +21,21 @@ before_script: script: - meteor build /tmp/build before_deploy: +- source ".travis/setartname.sh" - source ".travis/setdeploydir.sh" - ".travis/setupsig.sh" - ".travis/namefiles.sh" - ".travis/sandstorm.sh" deploy: - provider: releases - api_key: - secure: SLtbGv9vL6qC3rKGwKuXfUSFuRCeLsBFiRA1nBDWoyua7F3rLy8fBvhS3sXRDCqAF6hJgXQwZzX2pS1Lljwjjmwi/80Ns7VDtreX5QstHukFAxaJh2E0Lz5zQdSqAb61KdAipZmYfp2fgCr8T+xztE/mvtPD5R8CcIQIjJpl9rh+mrkkshkcaNOY4JQrqyrcTeCOeBQMXTZSkkbdJr4gb9++A2c61K0txfid9+VwqGm5MwvaT80JC5wLQkL8rS9OUcNJHFf90ELFZpRZnZnI2lsfmTBAxRKL994UZgzru3XNMhUTsJPh7OyVn/xSlyjLcvsn4dSon1PE9t3RkuxsbTxx/XY+gIkXSGl38jZlhextaJoV0gTFkEg33tF/aZ4+I+iZM8LYfRAoUuZU0fSzGnFtFZp4xptF2ECLKmI/3dmuE6iwr+G1xUer9g2Rq9fXXrHgUA164544IdY4aDisxd9U78U0K7WaPtbvphiVl4GbgVnfTEgNVdpXcQxUtcXPZMiBRz5+E+1fExmCfO6+7mZ/yzDrsFYoRdmuo1SMGRI4iqb5jl/PImZ9ukTqRmQdqd3WJp3zzPbIEJPwhMtS5LMxzBMSfugXwjEajkXybcH5CWQ7jo+ogNqcM/CcJ3q4ahYuLTN7VeZWZ8h5kwr9bPxPooZuhWw0WPRa+XUM22o= - file: - - "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" - - "$ROCKET_DEPLOY_DIR/rocket.chat.tgz.asc" - - "$ROCKET_DEPLOY_DIR/rocket.chat.spk" + provider: s3 + access_key_id: "AKIAIKIA7H7D47KUHYCA" + secret_access_key: $ACCESSKEY + bucket: "rocketchat" + skip_cleanup: true + upload_dir: build + local_dir: $ROCKET_DEPLOY_DIR on: - tags: true + condition: "$TRAVIS_PULL_REQUEST=false" all_branches: true after_deploy: - ".travis/docker.sh" diff --git a/.travis/docker.sh b/.travis/docker.sh index f3955d255a9..84eb7f7463d 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -4,7 +4,10 @@ IFS=$'\n\t' CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" -CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; +if [[ -v "$TRAVIS_TAG" ]]; then + CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; +else + CURL_DATA='{"docker_tag":"develop"}'; +fi curl -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "$CURL_URL" - diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh index f71334fb7f2..6bc9fe1c0aa 100755 --- a/.travis/namefiles.sh +++ b/.travis/namefiles.sh @@ -1,9 +1,11 @@ -#!/bin/bash -set -xeuo pipefail +#!/bin/bash +set -euvo pipefail IFS=$'\n\t' -#cd $TRAVIS_BUILD_DIR -#export TAG=$(git describe --abbrev=0 --tags) -cp /tmp/build/Rocket.Chat.tar.gz "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" -gpg --armor --detach-sign "$ROCKET_DEPLOY_DIR/rocket.chat.tgz" -ls -l $ROCKET_DEPLOY_DIR +# 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 9ec3b97b0e6..ae9b43854b6 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 $ROCKET_DEPLOY_DIR/rocket.chat.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 00000000000..0d7f3518c46 --- /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 -- GitLab From df98a791e5747b1d2667347e91c11555902d9321 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 7 Jan 2016 13:42:04 -0200 Subject: [PATCH 1134/1338] Add logger as dependencies for theme and lib packages --- packages/rocketchat-lib/package.js | 1 + packages/rocketchat-theme/package.js | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 5f2639f86fd..41ceefd1eb1 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -23,6 +23,7 @@ Package.onUse(function(api) { api.use('check'); api.use('arunoda:streams'); api.use('rocketchat:version'); + api.use('rocketchat:logger'); api.use('kadira:flow-router', 'client'); api.addFiles('lib/core.coffee'); diff --git a/packages/rocketchat-theme/package.js b/packages/rocketchat-theme/package.js index 027f9d264f3..91a0c53692e 100644 --- a/packages/rocketchat-theme/package.js +++ b/packages/rocketchat-theme/package.js @@ -9,6 +9,7 @@ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use('rocketchat:lib'); + api.use('rocketchat:logger'); api.use('coffeescript'); api.use('underscore'); api.use('webapp'); -- GitLab From 566fe9f20d77296743d6ca40ea80e0b7627eddb3 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 7 Jan 2016 14:05:08 -0200 Subject: [PATCH 1135/1338] Show the auth and token urls in oauth admin page --- i18n/en.i18n.json | 2 ++ .../admin/client/views/oauthApp.coffee | 3 +++ .../admin/client/views/oauthApp.html | 16 +++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 6c2d6a8f756..482eea38ba6 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", @@ -86,6 +87,7 @@ "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", + "Authorization_URL" : "Authorization URL", "Auto_Load_Images" : "Auto Load Images", "Avatar_changed_successfully" : "Avatar changed successfully", "Avatar_URL" : "Avatar URL", diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee index d8d3b415c34..e4ccf538bc4 100644 --- a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee @@ -12,6 +12,9 @@ Template.oauthApp.helpers 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 diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html index fab7358c217..ed83a04f59d 100644 --- a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html @@ -34,11 +34,25 @@ <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.token}} + {{#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> -- GitLab From 14b824058d8577b6179b9bc799ff8941884ff282 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 7 Jan 2016 14:05:22 -0200 Subject: [PATCH 1136/1338] Insert the zapier default server --- .../oauth/server/default-services.coffee | 12 ++++++++++++ .../oauth/server/oauth2-server.coffee | 6 ------ packages/rocketchat-oauth2-server-config/package.js | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee 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 00000000000..19934be1936 --- /dev/null +++ b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee @@ -0,0 +1,12 @@ +if not RocketChat.models.OAuthApps.findOne('default-zapier') + RocketChat.models.OAuthApps.insert + _id: 'default-zapier' + name: 'Default: Zapier' + default: true + clientId: 'default-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 index 96940151b58..770cb583682 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee @@ -8,12 +8,6 @@ oauth2server = new OAuth2Server WebApp.connectHandlers.use oauth2server.app # JsonRoutes.Middleware.use oauth2server.app -if not oauth2server.model.Clients.findOne() - oauth2server.model.Clients.insert - clientId: 'papers3' - clientSecret: '123' - redirectUri: 'http://localhost:3000/_oauth/rc' - oauth2server.routes.get '/account', oauth2server.oauth.authorise(), (req, res, next) -> user = Meteor.users.findOne req.user.id diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js index 479ba8b40b3..310bebaeed5 100644 --- a/packages/rocketchat-oauth2-server-config/package.js +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -23,6 +23,7 @@ Package.onUse(function(api) { //// 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'); -- GitLab From d156abdc295094b8377ce616485a198dabde8291 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 7 Jan 2016 14:06:55 -0200 Subject: [PATCH 1137/1338] Permissions rework --- .../client/lib/models/Subscriptions.js | 64 +--------------- .../client/lib/models/Users.js | 60 +-------------- .../client/startup.coffee | 1 - .../client/views/permissions.coffee | 17 ++--- .../client/views/permissions.html | 6 +- .../client/views/permissionsRole.coffee | 2 +- .../client/views/permissionsRole.html | 2 +- packages/rocketchat-authorization/package.js | 2 +- .../server/functions/addUserRoles.coffee | 2 +- .../functions/getPermissionsForRole.coffee | 9 --- .../functions/removeUserFromRoles.coffee | 2 +- .../server/methods/removeUserFromRole.coffee | 2 +- .../server/methods/saveRole.coffee | 9 +-- .../server/models/Base.js | 38 ++++++++++ .../server/models/Roles.coffee | 3 +- .../server/models/Subscriptions.js | 73 ++----------------- .../server/models/Users.js | 67 +---------------- server/methods/createChannel.coffee | 6 +- 18 files changed, 74 insertions(+), 291 deletions(-) delete mode 100644 packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee create mode 100644 packages/rocketchat-authorization/server/models/Base.js diff --git a/packages/rocketchat-authorization/client/lib/models/Subscriptions.js b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js index 3c1f3a4819a..7ff02a80103 100644 --- a/packages/rocketchat-authorization/client/lib/models/Subscriptions.js +++ b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js @@ -1,20 +1,11 @@ +Meteor.subscribe('scopedRoles', 'Subscriptions'); + if (_.isUndefined(RocketChat.models.Subscriptions)) { RocketChat.models.Subscriptions = {} } -RocketChat.models.Subscriptions.findRolesByUserId = function(userId) { - query = { - "u._id": userId - }; - - options = { fields: { roles: 1 } } - - return this.find(query, options); -} - RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId) { query = { - "u._id": userId, rid: roomId, roles: roleName }; @@ -22,57 +13,6 @@ RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId return !_.isUndefined(this.findOne(query)); } -RocketChat.models.Subscriptions.setRolesByUserId = function(userId, roles, roomId) { - roles = [].concat(roles); - - var query = { - "u._id": userId, - rid: roomId - } - - var update = { - $set: { - roles: roles - } - } - - return this.update(query, update); -} - -RocketChat.models.Subscriptions.addRolesByUserId = function(userId, roles, roomId) { - roles = [].concat(roles); - - var query = { - "u._id": userId, - rid: roomId - } - - var update = { - $addToSet: { - roles: { $each: roles } - } - } - - return this.update(query, update); -} - -RocketChat.models.Subscriptions.removeRolesByUserId = function(userId, roles, roomId) { - roles = [].concat(roles); - - var query = { - "u._id": userId, - rid: roomId - } - - var update = { - $pullAll: { - roles: roles - } - } - - return this.update(query, update); -} - RocketChat.models.Subscriptions.findUsersInRoles = function(roles, scope, options) { roles = [].concat(roles); diff --git a/packages/rocketchat-authorization/client/lib/models/Users.js b/packages/rocketchat-authorization/client/lib/models/Users.js index c00fb3cf9cf..e7f61495105 100644 --- a/packages/rocketchat-authorization/client/lib/models/Users.js +++ b/packages/rocketchat-authorization/client/lib/models/Users.js @@ -1,17 +1,9 @@ +Meteor.subscribe('scopedRoles', 'Users'); + if (_.isUndefined(RocketChat.models.Users)) { RocketChat.models.Users = {} } -RocketChat.models.Users.findRolesByUserId = function(userId) { - var query = { - _id: userId - }; - - options = { fields: { roles: 1 } } - - return this.find(query, options); -}; - RocketChat.models.Users.isUserInRole = function(userId, roleName) { query = { _id: userId, @@ -21,54 +13,6 @@ RocketChat.models.Users.isUserInRole = function(userId, roleName) { return !_.isUndefined(this.findOne(query)); } -RocketChat.models.Users.setRolesByUserId = function(userId, roles) { - roles = [].concat(roles); - - var query = { - _id: userId - } - - var update = { - $set: { - roles: roles - } - } - - return this.update(query, update); -} - -RocketChat.models.Users.addRolesByUserId = function(userId, roles) { - roles = [].concat(roles); - - var query = { - _id: userId - } - - var update = { - $addToSet: { - roles: { $each: roles } - } - } - - return this.update(query, update); -} - -RocketChat.models.Users.removeRolesByUserId = function(userId, roles) { - roles = [].concat(roles); - - var query = { - _id: userId - } - - var update = { - $pullAll: { - roles: roles - } - } - - return this.update(query, update); -} - RocketChat.models.Users.findUsersInRoles = function(roles, scope, options) { roles = [].concat(roles); diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee index 2c9482c5458..61f0527598d 100644 --- a/packages/rocketchat-authorization/client/startup.coffee +++ b/packages/rocketchat-authorization/client/startup.coffee @@ -1,5 +1,4 @@ Meteor.subscribe 'roles' -Meteor.subscribe 'scopedRoles', 'Users' RocketChat.authz.subscription = Meteor.subscribe 'permissions' diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee index a4366fd638f..af92f2c1266 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' @@ -35,11 +35,10 @@ Template.permissions.onCreated -> @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 f95b309f24a..c895fea4c2d 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 a15e33587f5..739fa26afad 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 diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html index a824390e886..18382fdb3c6 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/package.js b/packages/rocketchat-authorization/package.js index bc0361b701d..69682e47db3 100644 --- a/packages/rocketchat-authorization/package.js +++ b/packages/rocketchat-authorization/package.js @@ -44,11 +44,11 @@ Package.onUse(function(api) { 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/addUserRoles.coffee', ['server']); - api.addFiles('server/functions/getPermissionsForRole.coffee', ['server']); api.addFiles('server/functions/getRoles.coffee', ['server']); api.addFiles('server/functions/getUsersInRole.coffee', ['server']); api.addFiles('server/functions/hasPermission.coffee', ['server']); diff --git a/packages/rocketchat-authorization/server/functions/addUserRoles.coffee b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee index e3635f6b4ef..c715153ce32 100644 --- a/packages/rocketchat-authorization/server/functions/addUserRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee @@ -8,7 +8,7 @@ RocketChat.authz.addUserRoles = (userId, roleNames, scope) -> roleNames = [].concat roleNames - existingRoleNames = _.pluck(RocketChat.authz.getRoles(), 'name') + existingRoleNames = _.pluck(RocketChat.authz.getRoles(), '_id') invalidRoleNames = _.difference(roleNames, existingRoleNames) unless _.isEmpty(invalidRoleNames) for role in invalidRoleNames diff --git a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee b/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee deleted file mode 100644 index dd55acb226c..00000000000 --- 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' - - role = RocketChat.models.Roles.findOne roleName - if not role - 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/removeUserFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee index f05bcf70471..f721c0cd44e 100644 --- a/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee @@ -13,6 +13,6 @@ RocketChat.authz.removeUserFromRoles = (userId, roleNames, scope) -> unless _.isEmpty(invalidRoleNames) throw new Meteor.Error 'invalid-role' - RocketChat.models.Roles.removeUserFromRoles(userIds, roleNames, scope) + RocketChat.models.Roles.removeUserRoles(userIds, roleNames, scope) return true diff --git a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee index bc5e0504266..26da340af6f 100644 --- a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee +++ b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee @@ -11,4 +11,4 @@ Meteor.methods if not user?._id? throw new Meteor.Error 'user-not-found' - return RocketChat.models.Roles.removeUserRole user._id, roleName + 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 2fe6f208e9a..874fe0eaa6d 100644 --- a/packages/rocketchat-authorization/server/methods/saveRole.coffee +++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee @@ -3,10 +3,7 @@ Meteor.methods if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions' throw new Meteor.Error "not-authorized" - saveData = - description: roleData.description + if not roleData.name? + throw new Meteor.Error 'invalid-data', 'Role name is required' - if not _id? and roleData.name? - saveData.name = roleData.name - - return RocketChat.models.Roles.createOrUpdate saveData.name, 'Users', roleData.description + 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 00000000000..5977c644667 --- /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/Roles.coffee b/packages/rocketchat-authorization/server/models/Roles.coffee index 0ad0caee122..8489afa1d47 100644 --- a/packages/rocketchat-authorization/server/models/Roles.coffee +++ b/packages/rocketchat-authorization/server/models/Roles.coffee @@ -19,6 +19,7 @@ RocketChat.models.Roles = new class extends RocketChat.models._Base createOrUpdate: (name, scope, description, protectedRole) -> scope ?= 'Users' updateData = {} + updateData.name = name updateData.scope = scope if description? updateData.description = description @@ -38,5 +39,5 @@ RocketChat.models.Roles = new class extends RocketChat.models._Base roles = [].concat roles for roleName in roles role = @findOne roleName - roleScope = role?.scope os 'Users' + 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 index 3d3048a10d3..9c7d4a16fc7 100644 --- a/packages/rocketchat-authorization/server/models/Subscriptions.js +++ b/packages/rocketchat-authorization/server/models/Subscriptions.js @@ -1,72 +1,9 @@ -RocketChat.models.Subscriptions.findRolesByUserId = function(userId) { - query = { - "u._id": userId - }; - - options = { fields: { roles: 1 } } - - return this.find(query, options); -} - -RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId) { - query = { - "u._id": userId, - rid: roomId, - roles: roleName - }; - - return !_.isUndefined(this.findOne(query)); -} - -RocketChat.models.Subscriptions.setRolesByUserId = function(userId, roles, roomId) { - roles = [].concat(roles); - - var query = { - "u._id": userId, - rid: roomId - } - - var update = { - $set: { - roles: roles - } - } - - return this.update(query, update); -} - -RocketChat.models.Subscriptions.addRolesByUserId = function(userId, roles, roomId) { - roles = [].concat(roles); - - var query = { - "u._id": userId, - rid: roomId - } - - var update = { - $addToSet: { - roles: { $each: roles } - } - } - - return this.update(query, update); -} - -RocketChat.models.Subscriptions.removeRolesByUserId = function(userId, roles, roomId) { - roles = [].concat(roles); - - var query = { - "u._id": userId, - rid: roomId - } - - var update = { - $pullAll: { - roles: roles - } +RocketChat.models.Subscriptions.roleBaseQuery = function(userId, scope) { + var query = { "u._id": userId } + if (!_.isUndefined(scope)) { + query.rid = scope; } - - return this.update(query, update); + return query; } RocketChat.models.Subscriptions.findUsersInRoles = function(roles, scope, options) { diff --git a/packages/rocketchat-authorization/server/models/Users.js b/packages/rocketchat-authorization/server/models/Users.js index ed88b6dbd20..315ab7e9acf 100644 --- a/packages/rocketchat-authorization/server/models/Users.js +++ b/packages/rocketchat-authorization/server/models/Users.js @@ -1,68 +1,5 @@ -RocketChat.models.Users.findRolesByUserId = function(userId) { - var query = { - _id: userId - }; - - options = { fields: { roles: 1 } } - - return this.find(query, options); -}; - -RocketChat.models.Users.isUserInRole = function(userId, roleName) { - query = { - _id: userId, - roles: roleName - }; - - return !_.isUndefined(this.findOne(query)); -} - -RocketChat.models.Users.setRolesByUserId = function(userId, roles) { - roles = [].concat(roles); - - var query = { - _id: userId - } - - var update = { - $set: { - roles: roles - } - } - - return this.update(query, update); -} - -RocketChat.models.Users.addRolesByUserId = function(userId, roles) { - roles = [].concat(roles); - - var query = { - _id: userId - } - - var update = { - $addToSet: { - roles: { $each: roles } - } - } - - return this.update(query, update); -} - -RocketChat.models.Users.removeRolesByUserId = function(userId, roles) { - roles = [].concat(roles); - - var query = { - _id: userId - } - - var update = { - $pullAll: { - roles: roles - } - } - - return this.update(query, update); +RocketChat.models.Users.roleBaseQuery = function(userId, scope) { + return { _id: userId } } RocketChat.models.Users.findUsersInRoles = function(roles, scope, options) { diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee index 98291882421..570d85bfa22 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -41,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.addUserRoles(Meteor.userId(), 'moderator', room._id) - for username in members member = RocketChat.models.Users.findOneByUsername username if not member? @@ -57,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', room._id) + Meteor.defer -> RocketChat.callbacks.run 'afterCreateChannel', user, room -- GitLab From 3f32921affea660f0068677b88a7c4c7bfe8fa76 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 7 Jan 2016 14:26:35 -0200 Subject: [PATCH 1138/1338] Add option to disable oauth apps, default is enabled --- .meteor/versions | 2 +- .../admin/client/views/oauthApp.coffee | 5 ++++- .../admin/client/views/oauthApp.html | 9 ++++++++- .../admin/server/methods/addOAuthApp.coffee | 3 +++ .../admin/server/methods/updateOAuthApp.coffee | 4 ++++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index a894cf14bf3..7f09aaaa23c 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -148,7 +148,7 @@ 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.1.1 +rocketchat:oauth2-server@1.2.0 rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee index e4ccf538bc4..4ced37677bb 100644 --- a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee @@ -1,5 +1,6 @@ Template.oauthApp.onCreated -> - @record = new ReactiveVar {} + @record = new ReactiveVar + active: true Template.oauthApp.helpers @@ -48,6 +49,7 @@ Template.oauthApp.events "click .submit > .save": -> name = $('[name=name]').val().trim() + active = $('[name=active]:checked').val().trim() is "1" redirectUri = $('[name=redirectUri]').val().trim() if name is '' @@ -58,6 +60,7 @@ Template.oauthApp.events app = name: name + active: active redirectUri: redirectUri params = Template.instance().data.params?() diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html index ed83a04f59d..d9d722ddd49 100644 --- a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html +++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html @@ -5,10 +5,17 @@ <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}}" placeholder="{{_ 'Optional'}}" /> + <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> diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee index 9215823802d..21e189664dc 100644 --- a/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee @@ -15,6 +15,9 @@ Meteor.methods 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 diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee index 6cfd200145c..e50cbf11611 100644 --- a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee +++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee @@ -15,6 +15,9 @@ Meteor.methods 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' @@ -22,6 +25,7 @@ Meteor.methods 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}} -- GitLab From c3d4a62d1c5cfbface4235ef3dd7193227c3c238 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 7 Jan 2016 14:26:51 -0200 Subject: [PATCH 1139/1338] Set default integratins as inactive by default --- .../oauth/server/default-services.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee index 19934be1936..b82e2964770 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee @@ -2,6 +2,7 @@ if not RocketChat.models.OAuthApps.findOne('default-zapier') RocketChat.models.OAuthApps.insert _id: 'default-zapier' name: 'Default: Zapier' + active: false default: true clientId: 'default-zapier' clientSecret: 'RTK6TlndaCIolhQhZ7_KHIGOKj41RnlaOq_o-7JKwLr' -- GitLab From 34548cd338c82a0e59ef95e41e17d5a0fe09e23d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 7 Jan 2016 14:33:52 -0200 Subject: [PATCH 1140/1338] no message --- server/startup/migrations/v27.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/startup/migrations/v27.coffee b/server/startup/migrations/v27.coffee index 3333a8896c7..b3f6f7d7716 100644 --- a/server/startup/migrations/v27.coffee +++ b/server/startup/migrations/v27.coffee @@ -8,4 +8,4 @@ Meteor.startup -> for scope, roles of user._roles RocketChat.models.Roles.addUserRoles(user._id, roles, scope) - # RocketChat.models.Users.update({}, { $unset: { _roles: 1 } }, { multi: true }) + RocketChat.models.Users.update({}, { $unset: { _roles: 1 } }, { multi: true }) -- GitLab From 065a319f23ddea282243b8363a67be1b70b64a1e Mon Sep 17 00:00:00 2001 From: Julian Di Leonardo <DiJu519@users.noreply.github.com> Date: Thu, 7 Jan 2016 11:53:00 -0500 Subject: [PATCH 1141/1338] Fixed typo in docker commaned (lastest -> latest) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0826156deca..2abb716a596 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Use the automated build image of our [most recent release](https://hub.docker.co [](https://hub.docker.com/r/rocketchat/rocket.chat/) ``` -docker pull rocketchat/rocket.chat:lastest +docker pull rocketchat/rocket.chat:latest ``` OR select a specific release ([details of releases available](https://github.com/RocketChat/Rocket.Chat/releases)): -- GitLab From 5088b475f60838e8a45ff731e76071c93e1fa5f4 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 7 Jan 2016 14:55:48 -0200 Subject: [PATCH 1142/1338] Fixed typo --- .../server/functions/removeUserFromRoles.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee index f721c0cd44e..64df765f67f 100644 --- a/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee +++ b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee @@ -13,6 +13,6 @@ RocketChat.authz.removeUserFromRoles = (userId, roleNames, scope) -> unless _.isEmpty(invalidRoleNames) throw new Meteor.Error 'invalid-role' - RocketChat.models.Roles.removeUserRoles(userIds, roleNames, scope) + RocketChat.models.Roles.removeUserRoles(userId, roleNames, scope) return true -- GitLab From d0c02dbf0d15dff0fa8ab45373f0353d22706012 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 7 Jan 2016 15:00:40 -0200 Subject: [PATCH 1143/1338] Remove "default" --- .../oauth/server/default-services.coffee | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee index b82e2964770..41fee6a9a86 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee @@ -1,10 +1,9 @@ -if not RocketChat.models.OAuthApps.findOne('default-zapier') +if not RocketChat.models.OAuthApps.findOne('zapier') RocketChat.models.OAuthApps.insert - _id: 'default-zapier' - name: 'Default: Zapier' + _id: 'zapier' + name: 'Zapier' active: false - default: true - clientId: 'default-zapier' + clientId: 'zapier' clientSecret: 'RTK6TlndaCIolhQhZ7_KHIGOKj41RnlaOq_o-7JKwLr' redirectUri: 'https://zapier.com/dashboard/auth/oauth/return/AppIDAPI/' _createdAt: new Date -- GitLab From fd7599c240bd1ffc0bf748753c48d3308652c88e Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 7 Jan 2016 18:02:20 -0200 Subject: [PATCH 1144/1338] Highlight messages when jump-to is used Allow selecting user info text --- .../assets/stylesheets/base.less | 16 ++++++++++++++ .../lib/RoomHistoryManager.coffee | 21 +++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index dd46ff3ebf0..1a323d7e600 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2516,6 +2516,13 @@ a.github-fork { 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; @@ -3073,7 +3080,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; @@ -3109,6 +3121,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; diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee index aae87a8d192..cb79f341e3c 100644 --- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee +++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee @@ -107,6 +107,8 @@ 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) @@ -114,6 +116,15 @@ 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 @@ -134,7 +145,6 @@ if item.t isnt 'command' ChatMessage.upsert {_id: item._id}, item - instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance() Meteor.defer -> readMessage.refreshUnreadMark(message.rid, true) RoomManager.updateMentionsMarksOfRoom typeName @@ -144,11 +154,18 @@ wrapper.animate({ scrollTop: pos }, 500) + + msgElement.addClass('highlight') + setTimeout -> room.isLoading.set false - instance.atBottom = !result.moreAfter + 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 -- GitLab From 00d69c3bfb8248aaab09bf60816d90bfee092056 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 8 Jan 2016 14:15:40 -0200 Subject: [PATCH 1145/1338] update links to use our release page --- .docker/dockerfiles/develop/Dockerfile | 6 +----- .docker/dockerfiles/latest/Dockerfile | 5 +---- Dockerfile | 5 +---- docker-compose.yml | 4 +--- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index bbce2753d91..5707cfbc017 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -2,10 +2,6 @@ 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 \ @@ -16,7 +12,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN curl -fSL "https://s3.amazonaws.com/build/rocket.chat-develop.tgz" -o rocket.chat.tgz \ +RUN curl -fSL https://rocket.chat/releases/develop/download -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index 296f2e76dc4..ed09ceb5bf8 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -12,10 +12,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app -RUN URL="https://builds.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' | sed 's/\/tag\//\/download\//' ) \ -&& curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ +RUN curl -fSL https://rocket.chat/releases/latest/download -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ diff --git a/Dockerfile b/Dockerfile index 72c9a4ea913..ed09ceb5bf8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,10 +12,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB 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' | sed 's/\/tag\//\/download\//' ) \ -&& curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \ +RUN curl -fSL https://rocket.chat/releases/latest/download -o rocket.chat.tgz \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ diff --git a/docker-compose.yml b/docker-compose.yml index 33a72bd0126..2637c3c86a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,8 +13,6 @@ rocketchat: - 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 -- GitLab From 14f74c217e9f5c4b97d34c979d6a3ec5974eb635 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 8 Jan 2016 14:54:16 -0200 Subject: [PATCH 1146/1338] removed duplicated Dockerfile --- .travis/docker.sh | 2 +- Dockerfile | 33 --------------------------------- HISTORY.md | 23 ++++++++++++++--------- 3 files changed, 15 insertions(+), 43 deletions(-) delete mode 100644 Dockerfile diff --git a/.travis/docker.sh b/.travis/docker.sh index 84eb7f7463d..1982a9ef008 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -7,7 +7,7 @@ CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSH if [[ -v "$TRAVIS_TAG" ]]; then CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; else - CURL_DATA='{"docker_tag":"develop"}'; + CURL_DATA='{"source_type":"Branch","source_name":"develop"}'; fi curl -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "$CURL_URL" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index ed09ceb5bf8..00000000000 --- a/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM node:0.10 - -MAINTAINER buildmaster@rocket.chat - -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://rocket.chat/releases/latest/download -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 625dae07616..a1e5feccfb9 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,7 +1,12 @@ -## v.NEXT +## NEXT +- -## v0.12.0, 2016-Jan-04 +## 0.12.1, 2016-Jan-05 + +- Fix problem with middleware that tries to parse json body + +## 0.12.0, 2016-Jan-04 - Settings: unset section if none is given on update - Hide registration and forgot password links when hidding login form @@ -19,7 +24,7 @@ - Try to parse all request bodies as JSON - New password reset screen -## v0.11.0, 2015-Dec-28 +## 0.11.0, 2015-Dec-28 - Add role bot to users of integrations in scope bot - Add route to cadastre new integrations via API @@ -62,15 +67,15 @@ - Turn channel and triggerWords optional in triggers - Using branding image from main APP -## v0.10.2, 2015-Dec-22 +## 0.10.2, 2015-Dec-22 - Fixes image preview bugs with filenames containing spaces -## v0.10.1, 2015-Dec-21 +## 0.10.1, 2015-Dec-21 - Fix upload permissions introduced in raik:ufs 0.3.4 -## v0.10.0, 2015-Dec-21 +## 0.10.0, 2015-Dec-21 - Accept property *msg* as text in attachments - Add "Room has been deleted" entry @@ -170,7 +175,7 @@ - Use attachments to render preview of uploads and use relative paths - Using flow-router group routes -## v0.9.0, 2015-Dec-14 +## 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 @@ -212,7 +217,7 @@ - Fixed blockquote non-continous border - Moved accountBox HTML to new separated template -## v0.8.0, 2015-Dec-8 +## 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 @@ -243,6 +248,6 @@ - Clear iOS app badge on app startup - Fix for image swipebox to show in RTL interface -## v0.1.0, 2015-May-19 +## 0.1.0, 2015-May-19 - Initial public launch -- GitLab From 33bc71f883582909f381d2831a5c0d3df56598c0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 8 Jan 2016 16:31:26 -0200 Subject: [PATCH 1147/1338] ping an update releases after_deploy --- .travis.yml | 1 + .travis/update-releases.sh | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 .travis/update-releases.sh diff --git a/.travis.yml b/.travis.yml index 8e97faa6422..9c514e8bd3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ deploy: all_branches: true after_deploy: - ".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/update-releases.sh b/.travis/update-releases.sh new file mode 100644 index 00000000000..2bb8f11c564 --- /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" -- GitLab From 0620f0361d44c2f94aec07aa81d04d2a85a0c97a Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Fri, 8 Jan 2016 16:55:25 -0200 Subject: [PATCH 1148/1338] fix travis script chmod permission --- .travis/update-releases.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .travis/update-releases.sh diff --git a/.travis/update-releases.sh b/.travis/update-releases.sh old mode 100644 new mode 100755 -- GitLab From aa31d1eccb4094cfa74469f23db33e0e7652ab40 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 8 Jan 2016 18:21:41 -0200 Subject: [PATCH 1149/1338] added gpg verification --- .docker/dockerfiles/develop/Dockerfile | 2 ++ .docker/dockerfiles/latest/Dockerfile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index 5707cfbc017..e99c7450981 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -13,6 +13,8 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app RUN curl -fSL https://rocket.chat/releases/develop/download -o rocket.chat.tgz \ +&& curl -fSL https://rocket.chat/releases/develop/asc -o rocket.chat.tgz.asc \ +&& gpg --verify rocket.chat.tgz.asc \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index ed09ceb5bf8..f1fd8026f2a 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -13,6 +13,8 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB WORKDIR /app RUN curl -fSL https://rocket.chat/releases/latest/download -o rocket.chat.tgz \ +&& curl -fSL https://rocket.chat/releases/latest/asc -o rocket.chat.tgz.asc \ +&& gpg --verify rocket.chat.tgz.asc \ && tar zxvf ./rocket.chat.tgz \ && rm ./rocket.chat.tgz \ && cd /app/bundle/programs/server \ -- GitLab From fb97b3ecd2c64ac3ff39c55cb3b68f1f51faa0a7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 18:40:23 -0200 Subject: [PATCH 1150/1338] Create package rocketchat:api --- .meteor/packages | 1 + .meteor/versions | 1 + packages/rocketchat-api/package.js | 24 +++++++++++++++ packages/rocketchat-api/server/api.coffee | 31 ++++++++++++++++++++ packages/rocketchat-api/server/routes.coffee | 17 +++++++++++ 5 files changed, 74 insertions(+) create mode 100644 packages/rocketchat-api/package.js create mode 100644 packages/rocketchat-api/server/api.coffee create mode 100644 packages/rocketchat-api/server/routes.coffee diff --git a/.meteor/packages b/.meteor/packages index 6b640c8b585..d75f1e099a6 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -132,3 +132,4 @@ yasinuslu:blaze-meta rocketchat:assets rocketchat:integrations rocketchat:message-attachments +rocketchat:api diff --git a/.meteor/versions b/.meteor/versions index 7f09aaaa23c..455eba81d24 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -121,6 +121,7 @@ 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 diff --git a/packages/rocketchat-api/package.js b/packages/rocketchat-api/package.js new file mode 100644 index 00000000000..52d8ed89601 --- /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@0.8.4' + ]); + + 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 00000000000..d07aa999798 --- /dev/null +++ b/packages/rocketchat-api/server/api.coffee @@ -0,0 +1,31 @@ +class API extends Restivus + constructor: -> + @authMethods = [] + super + + addAuthMethod: (method) -> + @authMethods.push method + + +RocketChat.API = {} + + +RocketChat.API.v1 = new API + version: 'v1' + useDefaultAuth: true + prettyJson: false + enableCors: false + auth: + token: 'services.resume.loginTokens.hashedToken' + user: -> + 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 00000000000..ec4b7a89ad0 --- /dev/null +++ b/packages/rocketchat-api/server/routes.coffee @@ -0,0 +1,17 @@ +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' + ] -- GitLab From f445a2bffbbdd120027438b88e0b4cbf6eca11f4 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 18:41:04 -0200 Subject: [PATCH 1151/1338] Add method to athenticate api via oauth --- .../oauth/server/oauth2-server.coffee | 45 ++++++++++++++++--- .../package.js | 1 + 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee index 770cb583682..58160488362 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee @@ -5,12 +5,45 @@ oauth2server = new OAuth2Server clientsCollection: RocketChat.models.OAuthApps.model debug: true + WebApp.connectHandlers.use oauth2server.app -# JsonRoutes.Middleware.use oauth2server.app -oauth2server.routes.get '/account', oauth2server.oauth.authorise(), (req, res, next) -> - user = Meteor.users.findOne req.user.id - res.send - id: user._id - name: user.name +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 index 310bebaeed5..3d7b2f10c2a 100644 --- a/packages/rocketchat-oauth2-server-config/package.js +++ b/packages/rocketchat-oauth2-server-config/package.js @@ -10,6 +10,7 @@ Package.onUse(function(api) { api.use('webapp'); api.use('coffeescript'); api.use('rocketchat:lib'); + api.use('rocketchat:api'); api.use('rocketchat:theme'); api.use('rocketchat:oauth2-server'); -- GitLab From d7762996e2d3db903c32c83c5ca5827c77617647 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 18:42:13 -0200 Subject: [PATCH 1152/1338] Update rocketchat:oauth2-server to 1.4.0 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index 455eba81d24..97cc95f053e 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -149,7 +149,7 @@ 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.2.0 +rocketchat:oauth2-server@1.4.0 rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 -- GitLab From ff11d58e5bd633d8a7b370318915b0002a70b415 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 18:42:35 -0200 Subject: [PATCH 1153/1338] Create template to show errors from oauth login --- .../oauth/client/oauth2-client.coffee | 8 ++++++++ .../oauth/client/oauth2-client.html | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee index 32b83f95637..b64a1fc4996 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee @@ -9,6 +9,14 @@ FlowRouter.route '/oauth/authorize', 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' diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html index 8251d160dc6..91ab42de7bd 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html @@ -18,3 +18,16 @@ {{> 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> -- GitLab From 577e9feb213a09cd2e05dfdfb00cca0a3394eb54 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 20:06:26 -0200 Subject: [PATCH 1154/1338] Remove restivus package version --- packages/rocketchat-api/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-api/package.js b/packages/rocketchat-api/package.js index 52d8ed89601..bc639498450 100644 --- a/packages/rocketchat-api/package.js +++ b/packages/rocketchat-api/package.js @@ -12,7 +12,7 @@ Package.onUse(function(api) { 'coffeescript', 'underscore', 'rocketchat:lib', - 'nimble:restivus@0.8.4' + 'nimble:restivus' ]); api.addFiles('server/api.coffee', 'server'); -- GitLab From ecce78a0bce0b2ea3233fb555aa7c1efe24b3e48 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 20:06:45 -0200 Subject: [PATCH 1155/1338] Add helper methods to return data as success, failure, etc --- packages/rocketchat-api/server/api.coffee | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/rocketchat-api/server/api.coffee b/packages/rocketchat-api/server/api.coffee index d07aa999798..7f271de4a6f 100644 --- a/packages/rocketchat-api/server/api.coffee +++ b/packages/rocketchat-api/server/api.coffee @@ -6,6 +6,33 @@ class API extends Restivus 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 = {} -- GitLab From 4ac3f3d31e2131f6d014f5a84327976289354374 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 20:07:07 -0200 Subject: [PATCH 1156/1338] Create routes `channels.setTopic` and `channels.create` --- packages/rocketchat-api/server/routes.coffee | 67 ++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/packages/rocketchat-api/server/routes.coffee b/packages/rocketchat-api/server/routes.coffee index ec4b7a89ad0..7084100aa13 100644 --- a/packages/rocketchat-api/server/routes.coffee +++ b/packages/rocketchat-api/server/routes.coffee @@ -15,3 +15,70 @@ RocketChat.API.v1.addRoute 'me', authRequired: true, 'active' 'language' ] + + +# Send Channel Message +# params +# channel +# text +# username +# as_user +# parse +# link_names +# attachments +# unfurl_links +# unfurl_media +# icon_url +# icon_emoji +# +# response +# { +# "ok": true, +# "ts": "1405895017.000506", +# "channel": "C024BE91L", +# "message": { +# … +# } +# } +RocketChat.API.v1.addRoute 'chat.postMessage', authRequired: true, + get: -> + # TODO + + +# 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}) -- GitLab From 7e1f6fe12a281f8bf51eb9c372138d3c77761d35 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 20:51:49 -0200 Subject: [PATCH 1157/1338] Parse bodyParams.payload as json if it exists --- packages/rocketchat-api/server/api.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-api/server/api.coffee b/packages/rocketchat-api/server/api.coffee index 7f271de4a6f..1f2ee3baeb6 100644 --- a/packages/rocketchat-api/server/api.coffee +++ b/packages/rocketchat-api/server/api.coffee @@ -45,6 +45,9 @@ RocketChat.API.v1 = new API 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] -- GitLab From 782b24757a8a5d000a0ba4c225d6c2e5468d366a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 20:52:04 -0200 Subject: [PATCH 1158/1338] Implement api chat.postMessage --- packages/rocketchat-api/server/routes.coffee | 92 +++++++++++++++----- 1 file changed, 68 insertions(+), 24 deletions(-) diff --git a/packages/rocketchat-api/server/routes.coffee b/packages/rocketchat-api/server/routes.coffee index 7084100aa13..ac4f99d1e62 100644 --- a/packages/rocketchat-api/server/routes.coffee +++ b/packages/rocketchat-api/server/routes.coffee @@ -18,31 +18,75 @@ RocketChat.API.v1.addRoute 'me', authRequired: true, # Send Channel Message -# params -# channel -# text -# username -# as_user -# parse -# link_names -# attachments -# unfurl_links -# unfurl_media -# icon_url -# icon_emoji -# -# response -# { -# "ok": true, -# "ts": "1405895017.000506", -# "channel": "C024BE91L", -# "message": { -# … -# } -# } RocketChat.API.v1.addRoute 'chat.postMessage', authRequired: true, - get: -> - # TODO + post: -> + channel = @bodyParams.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 RocketChat.API.v1.failure 'invalid-channel' + + rid = room._id + if room.t is 'c' + Meteor.runAsUser @userId, -> + Meteor.call 'joinRoom', room._id + + when '@' + roomUser = RocketChat.models.Users.findOne + $or: [ + {_id: channel} + {username: channel} + ] + + if not roomUser? + return RocketChat.API.v1.failure 'invalid-channel' + + rid = [@useId, roomUser._id].sort().join('') + room = RocketChat.models.Rooms.findOne(rid) + + if not room + Meteor.runAsUser @userId, -> + Meteor.call 'createDirectMessage', roomUser.username + room = RocketChat.models.Rooms.findOne(rid) + + else + return RocketChat.API.v1.failure 'invalid-channel-type' + + message = + alias: @bodyParams.username or @bodyParams.alias + msg: _.trim(@bodyParams.text or @bodyParams.msg or '') + attachments: @bodyParams.attachments + parseUrls: false + bot: + u: @userId + groupable: false + + if @bodyParams.icon_url? or @bodyParams.avatar? + message.avatar = @bodyParams.icon_url or @bodyParams.avatar + else if @bodyParams.icon_emoji? or @bodyParams.emoji? + message.emoji = @bodyParams.icon_emoji or @bodyParams.emoji + + if _.isArray message.attachments + for attachment in message.attachments + if attachment.msg + attachment.text = _.trim(attachment.msg) + delete attachment.msg + + message = RocketChat.sendMessage @user, message, room, {} + + return RocketChat.API.v1.success + ts: Date.now() + channel: channel + message: message # Set Channel Topic -- GitLab From ea2bffc8be18a7422e8d9bcfddd3ca6cb8ca698c Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 21:17:48 -0200 Subject: [PATCH 1159/1338] Add apis 'integrations.create' and 'integrations.remove' --- packages/rocketchat-api/server/api.coffee | 2 +- .../server/api/api.coffee | 125 +++++++++--------- 2 files changed, 63 insertions(+), 64 deletions(-) diff --git a/packages/rocketchat-api/server/api.coffee b/packages/rocketchat-api/server/api.coffee index 1f2ee3baeb6..e15db14f1fa 100644 --- a/packages/rocketchat-api/server/api.coffee +++ b/packages/rocketchat-api/server/api.coffee @@ -6,7 +6,7 @@ class API extends Restivus addAuthMethod: (method) -> @authMethods.push method - success: (result) -> + success: (result={}) -> if _.isObject(result) result.success = true diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 706ebe40903..54e564e7264 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -3,6 +3,9 @@ Api = new Restivus 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,9 +15,6 @@ 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 @@ -107,83 +107,82 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, success: true -Api.addRoute 'add/:integrationId/:userId/:token', authRequired: true, - post: -> - console.log 'Add integration' - console.log @bodyParams +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 - if @bodyParams?.payload? - @bodyParams = JSON.parse @bodyParams.payload + 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) - user = RocketChat.models.Users.findOne(@userId) if not integration? - return {} = - statusCode: 400 - body: - success: false - error: 'Invalid integraiton id' - - Meteor.runAsUser user._id, => - switch @bodyParams['event'] - when 'newMessageOnChannel' - @bodyParams.data ?= {} - - if @bodyParams.data.channel_name? and @bodyParams.data.channel_name.indexOf('#') is -1 - @bodyParams.data.channel_name = '#' + @bodyParams.data.channel_name - - Meteor.call 'addOutgoingIntegration', - username: 'rocket.cat' - urls: [@bodyParams.target_url] - name: @bodyParams.name - channel: @bodyParams.data.channel_name - triggerWords: @bodyParams.data.trigger_words - - when 'newMessageToUser' - if @bodyParams.data.username.indexOf('@') is -1 - @bodyParams.data.username = '@' + @bodyParams.data.username - - Meteor.call 'addOutgoingIntegration', - username: 'rocket.cat' - urls: [@bodyParams.target_url] - name: @bodyParams.name - channel: @bodyParams.data.username - triggerWords: @bodyParams.data.trigger_words + return RocketChat.API.v1.failure 'Invalid integraiton id' - return {} = - statusCode: 200 - body: - success: true + user = RocketChat.models.Users.findOne(@userId) + + return createIntegration @bodyParams, user Api.addRoute 'remove/:integrationId/:userId/:token', authRequired: true, post: -> - console.log 'Remove integration' - console.log @bodyParams + integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) - if @bodyParams?.payload? - @bodyParams = JSON.parse @bodyParams.payload + if not integration? + return RocketChat.API.v1.failure 'Invalid integraiton id' - integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) user = RocketChat.models.Users.findOne(@userId) - if not integration? - return {} = - statusCode: 400 - body: - success: false - error: 'Invalid integraiton id' + return removeIntegration @bodyParams, user - integrationToRemove = RocketChat.models.Integrations.findOne urls: @bodyParams.target_url - Meteor.runAsUser user._id, => - Meteor.call 'deleteOutgoingIntegration', integrationToRemove._id +RocketChat.API.v1.addRoute 'integrations.create', authRequired: true, + post: -> + return createIntegration @bodyParams, @user - return {} = - statusCode: 200 - body: - success: true + +RocketChat.API.v1.addRoute 'integrations.remove', authRequired: true, + post: -> + return removeIntegration @bodyParams, @user Api.addRoute 'sample/:integrationId/:userId/:token', authRequired: true, -- GitLab From 878e35c336bcb8572c1e7173337b7c0109e708b7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 8 Jan 2016 21:55:31 -0200 Subject: [PATCH 1160/1338] Add api `chat.messageExample` --- packages/rocketchat-api/server/routes.coffee | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/rocketchat-api/server/routes.coffee b/packages/rocketchat-api/server/routes.coffee index ac4f99d1e62..b7cafb17220 100644 --- a/packages/rocketchat-api/server/routes.coffee +++ b/packages/rocketchat-api/server/routes.coffee @@ -17,6 +17,40 @@ RocketChat.API.v1.addRoute 'me', authRequired: true, ] +# 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: -> -- GitLab From 395b60f50f5f58507b5608ed93337cac90bc833b Mon Sep 17 00:00:00 2001 From: Ben Jones <benjaminpeterjonesesquire@gmail.com> Date: Sat, 9 Jan 2016 12:05:16 +0100 Subject: [PATCH 1161/1338] Update log.coffee --- client/helpers/log.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/helpers/log.coffee b/client/helpers/log.coffee index f00b503c8d3..bc666674930 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 -- GitLab From a8150c794b6497f84d23fc7328c04a24b9569280 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 11 Jan 2016 09:19:18 -0200 Subject: [PATCH 1162/1338] Add/Remove Room Moderators --- i18n/en.i18n.json | 14 ++++ .../server/startup.coffee | 2 + .../rocketchat-lib/lib/MessageTypes.coffee | 14 ++++ .../server/models/Messages.coffee | 8 ++ .../server/models/Subscriptions.coffee | 20 +++++ .../flex-tab/tabs/userInfo.coffee | 82 ++++++++++++++++--- .../flex-tab/tabs/userInfo.html | 17 ++-- packages/rocketchat-ui/views/app/room.coffee | 5 ++ server/methods/addRoomModerator.coffee | 22 +++++ server/methods/getRoomModerators.coffee | 16 ++++ server/methods/removeRoomModerator.coffee | 22 +++++ server/publications/roomModerators.coffee | 31 +++++++ 12 files changed, 235 insertions(+), 18 deletions(-) create mode 100644 server/methods/addRoomModerator.coffee create mode 100644 server/methods/getRoomModerators.coffee create mode 100644 server/methods/removeRoomModerator.coffee create mode 100644 server/publications/roomModerators.coffee diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 482eea38ba6..791ba7e3ca0 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -314,6 +314,7 @@ "More_unreads" : "More unreads", "Msgs" : "Msgs", "multi" : "multi", + "Muted" : "Muted", "Mute_user" : "Mute user", "My_Account" : "My Account", "n_messages" : "%s messages", @@ -398,7 +399,9 @@ "Registration_Succeeded" : "Registration Succeeded", "Remember_me" : "Remember me", "Remove" : "Remove", + "Removed" : "Removed", "Remove_Admin" : "Remove Admin", + "Remove_as_moderator" : "Remove as moderator", "Remove_custom_oauth" : "Remove custom oauth", "Remove_from_room" : "Remove from room", "Reset" : "Reset", @@ -450,6 +453,7 @@ "Send_your_JSON_payloads_to_this_URL" : "Send your JSON payloads to this URL.", "Settings" : "Settings", "Settings_updated" : "Settings updated", + "Set_as_moderator" : "Set as moderator", "Should_be_a_URL_of_an_image" : "Should be a URL of an image.", "Should_exists_a_user_with_this_username" : "The user must already exist.", "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", @@ -504,6 +508,8 @@ "The_redirectUri_is_required" : "The redirectUri is required", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "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_wont_be_able_to_type_in_s" : "The user won't be able to type in %s", + "The_user_will_be_removed_from_s" : "The user will be removed from %s", "There_are_no_integrations" : "There are no integrations", "This_is_a_push_test_messsage" : "This is a push test messsage", "True" : "True", @@ -527,6 +533,8 @@ "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", @@ -544,10 +552,14 @@ "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__username__removed_from__room_name__moderators" : "User __username__ removed from __room_name__ moderators", "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", + "User__username__is_now_a_moderator_of__room_name_" : "User __username__ is now a moderator of __room_name__", + "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_removed_as_a_moderator_by__user_by_" : "User <em>__username__</em> was removed as a moderator by <em>__user_by__</em>", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", @@ -569,6 +581,8 @@ "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 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.", diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index d9bd6b1a7b1..b2b0942c3bd 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -72,6 +72,8 @@ Meteor.startup -> { _id: 'ban-user', roles : ['admin', 'moderator']} + { _id: 'set-moderator', + roles : ['admin', 'moderator']} { _id: 'create-p', roles : ['admin', 'user']} diff --git a/packages/rocketchat-lib/lib/MessageTypes.coffee b/packages/rocketchat-lib/lib/MessageTypes.coffee index 3c6f3cea63a..a9407e0cc1a 100644 --- a/packages/rocketchat-lib/lib/MessageTypes.coffee +++ b/packages/rocketchat-lib/lib/MessageTypes.coffee @@ -82,3 +82,17 @@ Meteor.startup -> 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 } diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 3c9375f075b..6591b251d22 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -294,6 +294,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base 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 + # REMOVE removeById: (_id) -> query = diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 77c697dd41a..76e10ec3da9 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.coffee +++ b/packages/rocketchat-lib/server/models/Subscriptions.coffee @@ -210,6 +210,26 @@ 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) -> subscription = diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 6c5672ee526..f0d97465ff1 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -45,6 +45,12 @@ Template.userInfo.helpers return true return false + canSetModerator: -> + return RocketChat.authz.hasAllPermission('set-moderator', Session.get('openedRoom')) + + isModerator: -> + return !!RoomModerators.findOne({ "u._id": @user?._id }) + Template.userInfo.events 'click .pvt-msg': (e) -> Meteor.call 'createDirectMessage', Session.get('showUserInfo'), (error, result) -> @@ -84,30 +90,60 @@ Template.userInfo.events 'click .back': (e) -> Session.set('showUserInfo', null) - 'click .remove-user': (e, t) -> + 'click .remove-user': (e) -> e.preventDefault() rid = Session.get('openedRoom') room = ChatRoom.findOne rid if RocketChat.authz.hasAllPermission('remove-user', rid) - Meteor.call 'removeUserFromRoom', { rid: rid, username: @user.username }, (err, result) -> - if err - return toastr.error(err.reason or err.message) - toastr.success TAPi18n.__ 'User_removed_from_room' - Session.set('showUserInfo', null) + 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, t) -> + 'click .mute-user': (e) -> e.preventDefault() rid = Session.get('openedRoom') room = ChatRoom.findOne rid if RocketChat.authz.hasAllPermission('mute-user', rid) - Meteor.call 'muteUserInRoom', { rid: rid, username: @user.username }, (err, result) -> - if err - return toastr.error(err.reason or err.message) - toastr.success TAPi18n.__ 'User_muted_in_room' - else - toastr.error(TAPi18n.__ 'Not_allowed') + 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() @@ -121,6 +157,26 @@ Template.userInfo.events else toastr.error(TAPi18n.__ 'Not_allowed') + 'click .set-moderator': (e, t) -> + e.preventDefault() + room = ChatRoom.findOne(Session.get('openedRoom')) + moderators = _.map RoomModerators.find().fetch(), (moderator) -> return moderator.u?._id + if @user._id not in moderators + Meteor.call 'addRoomModerator', Session.get('openedRoom'), @user._id, (err, results) => + if err + return toastr.error(err.reason or err.message) + 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() + room = ChatRoom.findOne(Session.get('openedRoom')) + moderators = _.map RoomModerators.find().fetch(), (moderator) -> return moderator.u?._id + if @user._id in moderators + Meteor.call 'removeRoomModerator', Session.get('openedRoom'), @user._id, (err, results) => + if err + return toastr.error(err.reason or err.message) + toastr.success TAPi18n.__ 'User__username__removed_from__room_name__moderators', { username: @user.username, room_name: room.name } + Template.userInfo.onCreated -> @now = new ReactiveVar moment() self = @ diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html index bb18b652ccd..c4e3e9b2e68 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html @@ -30,20 +30,27 @@ {{> 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 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 remove-user red"><span>{{_ "Remove_from_room"}}</span></button> + <button class="button button-block remove-user red"><span>{{_ "Remove_from_room"}}</span></button> {{/if}} {{#if canMuteUser}} {{#if userMuted}} - <button class="button unmute-user primary"><span>{{_ "Unmute_user"}}</span></button> + <button class="button button-block unmute-user primary"><span>{{_ "Unmute_user"}}</span></button> {{else}} - <button class="button mute-user red"><span>{{_ "Mute_user"}}</span></button> + <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/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index f585577091a..6bf4bdfd72a 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -1,3 +1,5 @@ +@RoomModerators = new Mongo.Collection 'room_moderators' + isSubscribed = (_id) -> return ChatSubscription.find({ rid: _id }).count() > 0 @@ -493,6 +495,9 @@ Template.room.onCreated -> @autorun => @subscribe 'fullUserData', Session.get('showUserInfo'), 1 + @autorun => + @subscribe 'roomModerators', Session.get('openedRoom') + Template.room.onDestroyed -> window.removeEventListener 'resize', this.onWindowResize diff --git a/server/methods/addRoomModerator.coffee b/server/methods/addRoomModerator.coffee new file mode 100644 index 00000000000..d9f6dfb2fb3 --- /dev/null +++ b/server/methods/addRoomModerator.coffee @@ -0,0 +1,22 @@ +Meteor.methods + addRoomModerator: (rid, userId) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] addRoomModerator -> Invalid user' + + check rid, String + check userId, String + + 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/getRoomModerators.coffee b/server/methods/getRoomModerators.coffee new file mode 100644 index 00000000000..496acd99785 --- /dev/null +++ b/server/methods/getRoomModerators.coffee @@ -0,0 +1,16 @@ +Meteor.methods + getRoomModerators: (rid) -> + unless Meteor.userId() + throw new Meteor.Error(403, "[methods] getRoomModerators -> Invalid user") + + query = + rid: rid + roles: 'moderator' + + options = + sort: + "u.username": 1 + fields: + u: 1 + + return _.map(RocketChat.models.Subscriptions.find(query, options).fetch(), (subscription) -> return subscription.u) diff --git a/server/methods/removeRoomModerator.coffee b/server/methods/removeRoomModerator.coffee new file mode 100644 index 00000000000..b5a8dc3cdea --- /dev/null +++ b/server/methods/removeRoomModerator.coffee @@ -0,0 +1,22 @@ +Meteor.methods + removeRoomModerator: (rid, userId) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] removeRoomModerator -> Invalid user' + + check rid, String + check userId, String + + 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/publications/roomModerators.coffee b/server/publications/roomModerators.coffee new file mode 100644 index 00000000000..4e20286701c --- /dev/null +++ b/server/publications/roomModerators.coffee @@ -0,0 +1,31 @@ +Meteor.publish 'roomModerators', (rid, limit = 50) -> + unless this.userId + return this.ready() + + pub = this + + query = + rid: rid + roles: 'moderator' + + options = + limit: limit + sort: + "u.username": 1 + fields: + u: 1 + + cursor = RocketChat.models.Subscriptions.find(query, options).observeChanges + added: (_id, record) -> + pub.added('room_moderators', _id, record) + + changed: (_id, record) -> + pub.changed('room_moderators', _id, record) + + removed: (_id, record) -> + pub.removed('room_moderators', _id, record) + + this.ready() + this.onStop -> + cursor.stop() + -- GitLab From f79357fc774671fa79ec3a3f1327178105450b91 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 11 Jan 2016 09:38:10 -0200 Subject: [PATCH 1163/1338] Add permission checks --- server/methods/addRoomModerator.coffee | 3 +++ server/methods/removeRoomModerator.coffee | 3 +++ 2 files changed, 6 insertions(+) diff --git a/server/methods/addRoomModerator.coffee b/server/methods/addRoomModerator.coffee index d9f6dfb2fb3..eca8b3af439 100644 --- a/server/methods/addRoomModerator.coffee +++ b/server/methods/addRoomModerator.coffee @@ -6,6 +6,9 @@ Meteor.methods 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' diff --git a/server/methods/removeRoomModerator.coffee b/server/methods/removeRoomModerator.coffee index b5a8dc3cdea..50ee2aa570e 100644 --- a/server/methods/removeRoomModerator.coffee +++ b/server/methods/removeRoomModerator.coffee @@ -6,6 +6,9 @@ Meteor.methods 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' -- GitLab From 7deef73a87cf554b6564dd6e75fc69d01779092c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 11 Jan 2016 10:49:26 -0200 Subject: [PATCH 1164/1338] Removed unused file --- server/methods/getRoomModerators.coffee | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 server/methods/getRoomModerators.coffee diff --git a/server/methods/getRoomModerators.coffee b/server/methods/getRoomModerators.coffee deleted file mode 100644 index 496acd99785..00000000000 --- a/server/methods/getRoomModerators.coffee +++ /dev/null @@ -1,16 +0,0 @@ -Meteor.methods - getRoomModerators: (rid) -> - unless Meteor.userId() - throw new Meteor.Error(403, "[methods] getRoomModerators -> Invalid user") - - query = - rid: rid - roles: 'moderator' - - options = - sort: - "u.username": 1 - fields: - u: 1 - - return _.map(RocketChat.models.Subscriptions.find(query, options).fetch(), (subscription) -> return subscription.u) -- GitLab From 69213310e9e9a64b64a34c2dd371123723c693d8 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 11 Jan 2016 11:01:10 -0200 Subject: [PATCH 1165/1338] version bump to 0.13.0 --- .sandstorm/sandstorm-pkgdef.capnp | 4 +- HISTORY.md | 66 ++++++++++++++++++++----- packages/rocketchat-lib/rocketchat.info | 2 +- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index b41b7ff7568..b3c374ef195 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 8, # Increment this for every release. + appVersion = 9, # Increment this for every release. - appMarketingVersion = (defaultText = "0.12.0"), + appMarketingVersion = (defaultText = "0.13.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/HISTORY.md b/HISTORY.md index a1e5feccfb9..2643ad63d78 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,27 +2,69 @@ - +## 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 -- Settings: unset section if none is given on update -- Hide registration and forgot password links when hidding login form -- Upload build artifacts to GitHub and sign tgz for docker images - Add a setting to disable form-based login +- Add request debug messages - Button to test SMTP settings -- No need to reload server for SMTP settings to take effect -- Fix livechat trigger by url -- Increase the delay to render color fields - 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 -- Added request debug messages - Trim integration messages - Try to parse all request bodies as JSON -- New password reset screen +- Upload build artifacts to GitHub and sign tgz for docker images ## 0.11.0, 2015-Dec-28 @@ -104,7 +146,7 @@ - Centralize messages - Change order of loading variables - Change the rate limit of method setAvatarFromService from 1m to 5s -- Changes to layout and added infinite scroll to mentions bar +- 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 @@ -179,7 +221,7 @@ - Fix broken image-link when og:image contains "&" (e.g. Google Maps) - Error message when file upload media type it not accepted -- Added setting Accounts_LoginExpiration +- Add setting Accounts_LoginExpiration - Fix 'create new' in private group list opening 'create channel' flex - Moved RocketMailer to Mailer - Move avatars on username change @@ -229,7 +271,7 @@ - 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 -- Added option to disable "Forgot Password" link on login page +- Add option to disable "Forgot Password" link on login page - New RocketChat.RateLimiter - Favico.js update - Better RTL support @@ -237,7 +279,7 @@ - Improve Settings layout - Collapse sub groups of settings - Change translations in PT for False and True -- Added Secret URL +- 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 diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index 0b9615cb010..66995195a75 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.12.0" + "version": "0.13.0" } -- GitLab From 180aa167d5da028caa05655021c45697341230df Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 11 Jan 2016 13:56:04 +0000 Subject: [PATCH 1166/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 2 +- i18n/de.i18n.json | 57 ++-- i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 63 ++++- i18n/he.i18n.json | 247 +++++++++++++----- i18n/nl.i18n.json | 177 ++++++++++++- i18n/ro.i18n.json | 42 ++- i18n/ru.i18n.json | 134 +++++++++- .../i18n/de.i18n.json | 2 +- .../i18n/he.i18n.json | 15 +- .../i18n/nl.i18n.json | 17 +- .../i18n/ru.i18n.json | 5 +- .../i18n/de.i18n.json | 2 +- .../i18n/fi.i18n.json | 17 +- .../i18n/he.i18n.json | 5 +- .../i18n/nl.i18n.json | 14 +- .../i18n/ru.i18n.json | 5 +- .../i18n/de.i18n.json | 2 +- .../i18n/fi.i18n.json | 8 +- .../i18n/he.i18n.json | 9 +- .../i18n/nl.i18n.json | 3 + .../i18n/ru.i18n.json | 8 +- packages/rocketchat-chatops/i18n/nl.i18n.json | 6 +- .../i18n/nl.i18n.json | 8 +- .../i18n/ru.i18n.json | 4 +- packages/rocketchat-hubot/i18n/nl.i18n.json | 6 +- packages/rocketchat-hubot/i18n/ru.i18n.json | 6 +- packages/rocketchat-lib/i18n/fi.i18n.json | 5 +- packages/rocketchat-lib/i18n/he.i18n.json | 7 +- packages/rocketchat-lib/i18n/nl.i18n.json | 2 + packages/rocketchat-lib/i18n/ru.i18n.json | 5 +- .../rocketchat-livechat/app/i18n/de.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/en.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/fi.i18n.json | 11 +- .../rocketchat-livechat/app/i18n/he.i18n.json | 7 +- .../rocketchat-livechat/app/i18n/nl.i18n.json | 1 + .../rocketchat-livechat/i18n/de.i18n.json | 2 + .../rocketchat-livechat/i18n/en.i18n.json | 2 +- .../rocketchat-livechat/i18n/fi.i18n.json | 24 +- .../rocketchat-livechat/i18n/he.i18n.json | 24 +- .../rocketchat-livechat/i18n/nl.i18n.json | 14 + .../rocketchat-livechat/i18n/ro.i18n.json | 2 + .../rocketchat-livechat/i18n/ru.i18n.json | 3 +- packages/rocketchat-mailer/i18n/de.i18n.json | 6 +- packages/rocketchat-mailer/i18n/nl.i18n.json | 12 +- packages/rocketchat-mailer/i18n/ru.i18n.json | 4 +- .../i18n/de.i18n.json | 2 +- .../i18n/fi.i18n.json | 5 +- .../i18n/he.i18n.json | 5 +- .../i18n/ru.i18n.json | 5 +- .../rocketchat-message-pin/i18n/de.i18n.json | 2 +- .../rocketchat-message-pin/i18n/he.i18n.json | 7 +- .../rocketchat-message-pin/i18n/nl.i18n.json | 4 +- .../rocketchat-message-pin/i18n/ru.i18n.json | 7 +- .../rocketchat-message-star/i18n/de.i18n.json | 2 +- .../rocketchat-message-star/i18n/ru.i18n.json | 1 + .../i18n/nl.i18n.json | 6 +- .../i18n/ru.i18n.json | 6 +- .../i18n/de.i18n.json | 2 +- .../i18n/nl.i18n.json | 5 +- .../i18n/ru.i18n.json | 5 +- .../i18n/fi.i18n.json | 6 +- .../i18n/ru.i18n.json | 5 +- .../i18n/fi.i18n.json | 5 +- .../i18n/ru.i18n.json | 4 +- packages/rocketchat-theme/i18n/fi.i18n.json | 1 + packages/rocketchat-theme/i18n/nl.i18n.json | 5 +- packages/rocketchat-webrtc/i18n/nl.i18n.json | 6 +- packages/rocketchat-webrtc/i18n/ru.i18n.json | 6 +- .../rocketchat-wordpress/i18n/nl.i18n.json | 7 +- 70 files changed, 930 insertions(+), 180 deletions(-) diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index 2a8dd4c25d5..fd1ca738d36 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -290,7 +290,7 @@ "Submit" : "تقديم", "The_channel_name_is_required" : "اسم القناة مطلوب", "The_field_is_required" : "هذا الØقل %s مطلوب.", - "The_server_will_restart_in_s_seconds" : "سيتم إعادة تشغيل السيرÙر Ùي٪ s ثانية", + "The_server_will_restart_in_s_seconds" : "سيتم إعادة تشغيل السيرÙر ÙÙŠ Ùªs ثانية", "True" : "نعم", "Type_your_new_password" : "اكتب كلمة المرور الجديدة", "Unmute_user" : "إلغاء اسكات المستخدم", diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index ba2d30d4b88..6e9a76cccb4 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -2,6 +2,7 @@ "Access_not_authorized" : "Der Zugriff ist nicht gestattet.", "Access_online_demo" : "Öffne die Online-Demo", "Access_Online_Demo" : "Öffne die Online Demo", + "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", @@ -26,6 +27,7 @@ "Accounts_OAuth_Custom_Enable" : "Aktivieren", "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" : "Pfad des Token", "Accounts_OAuth_Custom_URL" : "URL", @@ -61,11 +63,13 @@ "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" : "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" : "Ungültige und selbstsignierte SSL-Zertifikate erlauben", @@ -76,10 +80,14 @@ "API_Embed" : "Einbetten", "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", "Auto_Load_Images" : "Automatisches Laden der Bilder", "Avatar_changed_successfully" : "Das Profilbild wurde erfolgreich geändert.", "Avatar_URL" : "URL des Profilbilds", @@ -90,6 +98,7 @@ "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", @@ -102,13 +111,15 @@ "Cancel" : "Abbrechen", "CDN_PREFIX" : "CDN-Präfix", "Certificates_and_Keys" : "Zertifikate und Schlüssel", - "Change_avatar" : "Ändere dein Profilbild", + "Change_avatar" : "Profilbild", "Channels" : "Kanäle", "Channels_list" : "Liste der öffentlichen Kanäle", "Chat_Rooms" : "Chaträume", "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", @@ -119,7 +130,7 @@ "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 privaten Nachrichtenraum.", + "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", @@ -133,7 +144,7 @@ "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" : "Benachrichtigungen bei neuen Nachrichten deaktivieren", @@ -150,7 +161,7 @@ "Email_or_username" : "E-Mail-Adresse oder Nutzername", "Email_verified" : "Die E-Mail-Adresse wurde bestätigt.", "Emoji" : "Emoji", - "Enable_Desktop_Notifications" : "Desktop-Benachrichtigungen aktivieren", + "Enable_Desktop_Notifications" : "Aktivieren", "Enter_info" : "Geben Sie Ihre Anmeldedaten an.", "Enter_to" : "Betreten, um", "Error" : "Fehler", @@ -160,8 +171,8 @@ "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_MediaType_NotAccepted" : "Medientypen werden nicht akzeptiert", @@ -177,15 +188,16 @@ "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" : "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" : "Das angegebene Passwort ist falsch.", - "inline_code" : "inline_code", + "inline_code" : "Code", "Install_Extension" : "Erweiterung installieren", - "Install_FxOs" : "Installiere Rocket.Chat in deinem Firefox-Browser", + "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, indem du auf \"Installieren\" klickst.", @@ -220,6 +232,7 @@ "italics" : "kursiv", "join" : "Beitreten", "Join_the_Community" : "Trete der Community bei", + "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", @@ -261,11 +274,11 @@ "Login_with" : "Anmelden mit %s", "login_with" : "Oder melden Sie sich direkt mit folgenden Accounts an", "Logout" : "Abmelden", - "Make_Admin" : "Benutzer zum Admin machen", + "Make_Admin" : "Benutzer zum Admin ernennen", "Mark_as_read" : "Als gelesen markieren", "Markdown_Headers" : "Markdown-Ãœberschriften", "Members" : "Mitglieder", - "Members_List" : "Mitgliederliste", + "Members_List" : "Mitglieder", "Members_placeholder" : "Mitglieder", "Message" : "Nachricht", "Message_AllowDeleting" : "Das Löschen von Nachrichten erlauben", @@ -307,6 +320,7 @@ "Name" : "Name", "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", @@ -326,12 +340,14 @@ "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!" : "Hoppla", - "Opt_out_statistics" : "Sende meine anonymen Statistiken nicht an Rocket.Chat.", + "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. Wenn Sie weiterhin anonyme Statistiken an uns senden möchten, deaktivieren Sie bitte das Kontrollkästchen oben. Vielen Dank.", "optional" : "optional", "others" : "andere", @@ -376,13 +392,14 @@ "quote" : "Zitat", "Recents" : "Aktuell", "Record" : "Aufnehmen", + "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 das OAuth-Konto", + "Remove_custom_oauth" : "OAuth-Konto entfernen", "Remove_from_room" : "Aus dem Raum entfernen", "Reset" : "Zurücksetzen", "Reset_password" : "Passwort zurücksetzen", @@ -395,7 +412,7 @@ "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" : "Dateiliste", + "Room_uploaded_file_list" : "Dateien", "Room_uploaded_file_list_empty" : "Es wurden noch keine Dateien hochgeladen.", "room_user_count" : "%s Benutzer", "Rooms" : "Räume", @@ -415,7 +432,7 @@ "seconds" : "Sekunden", "See_all" : "Alle anzeigen", "See_only_online" : "Nur online", - "Select_an_avatar" : "Wählen Sie ein Profilbild aus.", + "Select_an_avatar" : "Profilbild auswählen", "Select_file" : "Datei wählen", "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", @@ -437,7 +454,7 @@ "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", @@ -480,12 +497,14 @@ "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.", "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!", - "There_are_no_integrations" : "Keine Integrationen vorhanden.", + "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", @@ -493,11 +512,11 @@ "Unmute_user" : "Benutzern das Chatten erlauben ", "Unnamed" : "Unbenannt", "Unread_Rooms" : "Ungelesene Räume", - "Unread_Rooms_Mode" : "Ungelesener-Raum-Modus", + "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" : "Benutze die Initialien deines Nutzernamens.", + "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", @@ -559,7 +578,7 @@ "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 482eea38ba6..e17e14d18a4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -581,4 +581,4 @@ "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 d4b38c13df3..77a8acfa104 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", @@ -26,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", @@ -61,12 +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ä lomake Kirjaudu", + "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", @@ -77,9 +80,14 @@ "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", "Auto_Load_Images" : "Lataa kuvat automaattisesti\n", "Avatar_changed_successfully" : "Avatar vaihdettu onnistuneesti", "Avatar_URL" : "Avatarin URL", @@ -90,6 +98,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", @@ -109,6 +118,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", @@ -138,7 +149,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", @@ -154,14 +168,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", @@ -170,6 +188,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", @@ -182,8 +201,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ää", @@ -194,6 +215,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", @@ -210,6 +232,9 @@ "italics" : "kursivoitu", "join" : "Liity", "Join_the_Community" : "Liity yhteisöön", + "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", @@ -265,6 +290,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", @@ -287,11 +314,13 @@ "More_unreads" : "Lisää lukemattomia", "Msgs" : "Viestit", "multi" : "monta", + "Mute_user" : "Mykistä käyttäjä", "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", @@ -303,6 +332,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", @@ -310,6 +340,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", @@ -324,6 +356,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.", @@ -359,6 +392,7 @@ "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", @@ -366,14 +400,18 @@ "Remove" : "Poista", "Remove_Admin" : "Poista ylläpitäjyys", "Remove_custom_oauth" : "Poista mukautettu oauth", + "Remove_from_room" : "Poista huoneesta", + "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ää", @@ -399,6 +437,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", @@ -413,6 +452,7 @@ "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", @@ -424,6 +464,7 @@ "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_of_conversation" : "Keskustelun alku", @@ -456,11 +497,19 @@ "strike" : "yliviivaa", "Submit" : "Lähetä", "Success" : "Onnistui", + "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_are_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>!", + "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", @@ -489,10 +538,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ä", @@ -516,12 +570,15 @@ "Yes_clear_all" : "Jep, tyhjennä kaikki!", "Yes_delete_it" : "Kyllä, poista!", "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_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/he.i18n.json b/i18n/he.i18n.json index 6c8e8f5e2b8..4dceb39fb3d 100644 --- a/i18n/he.i18n.json +++ b/i18n/he.i18n.json @@ -1,77 +1,140 @@ { - "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_Secret" : "סוד", + "Accounts_OAuth_Custom_URL" : "כתובת", + "Accounts_PasswordReset" : "×יפוס ססמה", + "Accounts_RegistrationForm" : "טופס הרשמה", + "Accounts_RegistrationForm_Secret_URL" : "כתובת סודית", + "Accounts_RegistrationRequired" : "× ×“×¨×©×ª הרשמה", + "Add_Members" : "הוספת חברי×", + "Add_users" : "הוספת משתמשי×", "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" : "× ×•×¦×¨ ב-", + "COPY_TO_CLIPBOARD" : "העתקה ללוח הגזירי×", + "Create_new" : "יצירת חדש", + "Create_new_direct_message_room" : "יצירת חדר הודעה ישירה חדש", + "Create_new_private_group" : "יצירת קבוצה פרטית חדשה", + "Create_new_public_channel" : "יצירת ערוץ ציבורי חדש", + "Created_at" : "× ×•×¦×¨ ב־", + "days" : "ימי×", + "Deleted" : "× ×ž×—×§!", "Direct_Messages" : "הודעות ישירות", + "Drop_to_upload_file" : "יש להשליך לכ×ן כדי להעלות קובץ", + "Duplicate_channel_name" : "כבר ×§×™×™× ×¢×¨×•×¥ ×‘×©× â€š%s‘", + "Duplicate_private_group_name" : "כבר קיימת קבוצה פרטית בש× ‚%s‘", + "E-mail" : "דו×״ל", "edited" : "× ×¢×¨×š", - "Email_or_username" : "כתובת ×ימייל ×ו ×©× ×ž×©×ª×ž×©", + "Email_already_exists" : "כתובת הדו×״ל כבר קיימת", + "Email_or_username" : "כתובת דו×״ל ×ו ×©× ×ž×©×ª×ž×©", "Email_verified" : "כתובת הדו×״ל ×ומתה", - "Enter_info" : "הזן ×ת פרטי ההתחברות שלך", + "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 ×”×™× ×¤×ª×¨×•×Ÿ מעולה עבור ×ž×¤×ª×—×™× ×”×ž×—×¤×©×™× ×œ×‘× ×•×ª ולשפר ×ת פלפורמת הצ'×ט שלה×.", + "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 שלך", + "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_message" : "ההודעה ×”××—×¨×•× ×”", + "Layout" : "פריסה", + "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_suggestion" : "ההצעות × ×˜×¢× ×•×ªâ€¦", + "Login" : "התחברות", + "Login_with" : "×›× ×™×¡×” ×¢× %s", + "login_with" : "×ו ×œ×”×™×›× ×¡ ישירות ×¢×", + "Logout" : "יצי××”", "Members" : "חברי×", "Members_List" : "רשימת חברי×", "Members_placeholder" : "חברי×", + "Message" : "הודעה", + "Message_AllowDeleting" : "ל×פשר מחיקת הודעות", + "Message_AllowEditing" : "ל×פשר עריכת הודעות", + "Message_MaxAllowedSize" : "גודל ההודעה המרבי המותר", + "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" : "הודעות חדשות", @@ -81,67 +144,113 @@ "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" : "×× × ×”×ž×ª×Ÿ", + "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_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" : "בחר שירות להתחבר דרכו כדי לטעון ×ת ×”×ª×ž×•× ×” שלך ×ו העלה ×חת ישירות מהמחשב שלך", + "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" : "הגדרות", "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", + "Sound" : "שמע", "Start_of_conversation" : "התחלת השיחה", + "Statistics" : "סטטיסטיקה", "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" : "השרת יפעיל ×ת עצמו מחדש בעוד ", + "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_joined_channel" : "הצטרף לערוץ.", + "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" : "×©×œ×—× ×• לך מייל ל×ישור ההרשמה. ×× ××™× ×š מקבל ×ת המייל בדקות הקרובות, ×× × × ×¡×” ×©× ×™×ª.", + "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" : "ברוך ×”×‘× ×œ-", - "you_are_in_preview_mode_of" : "×”× ×š בתצוגה מוקדמת של ערוץ #<strong>__rom_name__</strong>", - "You_need_confirm_email" : "×”×™× ×š צריך ל×מת ×ת כתובת ×”×ימייל על ×ž× ×ª להתחבר!", - "Your_Open_Source_solution" : "פתרון הקוד הפתוח שלך לצ'×ט" + "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/nl.i18n.json b/i18n/nl.i18n.json index 1f29104465d..15ab951691a 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -1,15 +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", @@ -22,18 +42,34 @@ "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", @@ -42,6 +78,7 @@ "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", @@ -56,22 +93,38 @@ "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", @@ -79,35 +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", @@ -117,16 +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", @@ -134,26 +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", @@ -161,12 +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", @@ -176,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", @@ -202,28 +318,44 @@ "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", + "Remove_custom_oauth" : "Verwijder aangepaste OAuth", "Remove_from_room" : "Verwijderen uit de kamer", - "Reset_password" : "Nieuw Wachtwoord", + "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", @@ -232,23 +364,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", @@ -264,28 +413,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", @@ -298,6 +461,7 @@ "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", @@ -307,10 +471,12 @@ "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.", @@ -319,6 +485,7 @@ "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.", @@ -328,5 +495,7 @@ "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/ro.i18n.json b/i18n/ro.i18n.json index d0b8611a695..ab846688091 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -26,6 +26,7 @@ "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", @@ -61,12 +62,13 @@ "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", + "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", @@ -77,6 +79,9 @@ "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ă", @@ -85,12 +90,13 @@ "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" : "away", - "Away" : "Away", - "away_female" : "away", - "Away_female" : "Away", - "away_male" : "away", - "Away_male" : "Away", + "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", @@ -110,6 +116,8 @@ "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", @@ -178,6 +186,7 @@ "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", @@ -221,6 +230,7 @@ "italics" : "cursive", "join" : "AlăturaÈ›i-vă", "Join_the_Community" : "IntraÈ›i în comunitate", + "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", @@ -249,7 +259,7 @@ "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. Detalilei disponibile includ numele È™i e-mail.", + "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", @@ -258,9 +268,9 @@ "Loading..." : "Se încarcă...", "Loading_more_from_history" : "Se încarcă mai multe din istoric", "Loading_suggestion" : "Se încarcă sugestii...", - "Login" : "Login", + "Login" : "Autentificare", "Login_with" : "Autentifică-te cu %s", - "login_with" : "Sau de conectare direct cu", + "login_with" : "Sau conectare direct cu", "Logout" : "IeÈ™ire", "Make_Admin" : "Fă utilizator de tip Admin", "Mark_as_read" : "Marchează ca citit", @@ -308,6 +318,7 @@ "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ă", @@ -327,9 +338,11 @@ "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" : "Doar online", + "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", @@ -377,6 +390,7 @@ "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", @@ -461,7 +475,7 @@ "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 Online", + "Stats_Online_Users" : "Utilizatori Activi", "Stats_OS_Arch" : "OS Arch", "Stats_OS_Cpus" : "OS număr CPU ", "Stats_OS_Freemem" : "OS Free Memory", @@ -481,9 +495,11 @@ "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>!", "There_are_no_integrations" : "Nu sunt integrări", @@ -560,7 +576,7 @@ "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_Open_Source_solution" : "Propria soluÈ›ie de chat Open Source", "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 4dba7e58655..ee1c1597ec3 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -1,27 +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" : "ÐдминиÑтрациÑ", + "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" : "отошла", @@ -47,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' ÑущеÑтвует", @@ -62,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" : "ПриглаÑить пользователей", @@ -93,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" : "Покинуть чат", @@ -119,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" : "ПожалуйÑта, подождите, ÑтатиÑтика генерируютÑÑ.", @@ -161,6 +235,7 @@ "Preferences_saved" : "ÐаÑтройки Ñохранены", "Privacy" : "ПриватноÑÑ‚ÑŒ", "Private_Groups" : "Приватные чаты", + "Private_Groups_list" : "СпиÑок приватных чатов", "Profile" : "Профиль", "Profile_saved_successfully" : "Профиль уÑпешно Ñохранен", "Proudly_developed" : "Разработано Ñ Meteor", @@ -169,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" : "ПоиÑк Ñообщений", @@ -189,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" : "ÐаÑтройки обновлены", @@ -205,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" : "ПриÑоединилÑÑ Ðº чату.", @@ -245,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" : "Ðа вашу почту было отправлено пиÑьмо Ñ Ð¸Ð½ÑтрукциÑми. ЕÑли по каким-то причинам пиÑьмо не пришло, попробуйте еще раз и/или напишите нам.", @@ -263,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/packages/rocketchat-authorization/i18n/de.i18n.json b/packages/rocketchat-authorization/i18n/de.i18n.json index 790d9a22876..1ac87a82351 100644 --- a/packages/rocketchat-authorization/i18n/de.i18n.json +++ b/packages/rocketchat-authorization/i18n/de.i18n.json @@ -14,5 +14,5 @@ "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" : "Dieser Rolle zugeordneten Benutzer" + "Users_in_role" : "Zugeordnete Nutzer" } \ 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 c2e33fd83bc..e8843caf9e5 100644 --- a/packages/rocketchat-authorization/i18n/he.i18n.json +++ b/packages/rocketchat-authorization/i18n/he.i18n.json @@ -1,3 +1,16 @@ { - "User_added" : "המשתמש × ×•×¡×£." + "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/nl.i18n.json b/packages/rocketchat-authorization/i18n/nl.i18n.json index d57a643f6ff..5e8bfb8e955 100644 --- a/packages/rocketchat-authorization/i18n/nl.i18n.json +++ b/packages/rocketchat-authorization/i18n/nl.i18n.json @@ -1,3 +1,18 @@ { - "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", + "Removed" : "Verwijderd", + "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/ru.i18n.json b/packages/rocketchat-authorization/i18n/ru.i18n.json index 7a05e5a48d1..60691f938cd 100644 --- a/packages/rocketchat-authorization/i18n/ru.i18n.json +++ b/packages/rocketchat-authorization/i18n/ru.i18n.json @@ -1,3 +1,6 @@ { - "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-channel-settings-mail-messages/i18n/de.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json index dde249f42d9..f22508aa5a5 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json @@ -2,7 +2,7 @@ "Additional_emails" : "Zusätzliche E-Mails", "Body" : "Body", "Choose_messages" : "Nachrichten auswählen", - "From" : "Von", + "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?", diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json index 6f31cf5a2e6..062abf85041 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/fi.i18n.json @@ -1 +1,16 @@ -{ } \ No newline at end of file +{ + "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/he.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json index 6f31cf5a2e6..0ee4017b43e 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/he.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Choose_messages" : "בחירת הודעות", + "To_users" : "למשתמשי×" +} \ 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 index 6f31cf5a2e6..ab0b7fd7daa 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json @@ -1 +1,13 @@ -{ } \ No newline at end of file +{ + "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/ru.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json index 6f31cf5a2e6..3cb700b27ab 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ru.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mail_Message_Missing_to" : "Ð’Ñ‹ должны выбрать одного или неÑкольких пользователей или указать один или неÑколько адреÑов Ñлектронной почты, разделенных запÑтыми.", + "To_users" : "ПользователÑм" +} \ 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 eae7402de33..05456b08e2c 100644 --- a/packages/rocketchat-channel-settings/i18n/de.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/de.i18n.json @@ -5,7 +5,7 @@ "Save" : "Speichern", "Topic" : "Thema", "Type" : "Typ", - "Room_Info" : "Rauminformationen", + "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.", diff --git a/packages/rocketchat-channel-settings/i18n/fi.i18n.json b/packages/rocketchat-channel-settings/i18n/fi.i18n.json index 5e3906804a6..578c094a27a 100644 --- a/packages/rocketchat-channel-settings/i18n/fi.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/fi.i18n.json @@ -1,7 +1,13 @@ { + "Archive_Unarchive" : "Arkistoi / palauta arkistosta", "Channel" : "Kanava", "Private_Group" : "Privaattiryhmä", "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/he.i18n.json b/packages/rocketchat-channel-settings/i18n/he.i18n.json index a1c59cc1412..68f6f6ea7b8 100644 --- a/packages/rocketchat-channel-settings/i18n/he.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/he.i18n.json @@ -1,3 +1,10 @@ { - "Save" : "שמירה" + "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/nl.i18n.json b/packages/rocketchat-channel-settings/i18n/nl.i18n.json index d71e4a6712c..80b675a4377 100644 --- a/packages/rocketchat-channel-settings/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/nl.i18n.json @@ -1,4 +1,7 @@ { + "Archive_Unarchive" : "Archief / Uit archief", + "Channel" : "Kanaal", + "Private_Group" : "Privé-groep", "Save" : "Bewaren", "Topic" : "Onderwerp", "Type" : "Type", diff --git a/packages/rocketchat-channel-settings/i18n/ru.i18n.json b/packages/rocketchat-channel-settings/i18n/ru.i18n.json index 7f95f40d311..99a76b5c0d7 100644 --- a/packages/rocketchat-channel-settings/i18n/ru.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ru.i18n.json @@ -1,3 +1,9 @@ { - "Save" : "Сохранить" + "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-chatops/i18n/nl.i18n.json b/packages/rocketchat-chatops/i18n/nl.i18n.json index 6f31cf5a2e6..c4049dda949 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-github-enterprise/i18n/nl.i18n.json b/packages/rocketchat-github-enterprise/i18n/nl.i18n.json index 6f31cf5a2e6..1163d7a6d0b 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/ru.i18n.json b/packages/rocketchat-github-enterprise/i18n/ru.i18n.json index 6f31cf5a2e6..d3a57474db4 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-hubot/i18n/nl.i18n.json b/packages/rocketchat-hubot/i18n/nl.i18n.json index 6f31cf5a2e6..4c365fdd09d 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/ru.i18n.json b/packages/rocketchat-hubot/i18n/ru.i18n.json index 6f31cf5a2e6..48f9516bddb 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-lib/i18n/fi.i18n.json b/packages/rocketchat-lib/i18n/fi.i18n.json index b09cf9fe341..22892d14afc 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" + "Edit" : "Muokkaa", + "Only_errors" : "Vain virheet" } \ 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 6f31cf5a2e6..53b1d1e98eb 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/nl.i18n.json b/packages/rocketchat-lib/i18n/nl.i18n.json index d32584ebeaf..39d4c63986e 100644 --- a/packages/rocketchat-lib/i18n/nl.i18n.json +++ b/packages/rocketchat-lib/i18n/nl.i18n.json @@ -1,5 +1,7 @@ { "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/ru.i18n.json b/packages/rocketchat-lib/i18n/ru.i18n.json index 6f31cf5a2e6..1a0f7a2f5aa 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-livechat/app/i18n/de.i18n.json b/packages/rocketchat-livechat/app/i18n/de.i18n.json index 3924286d3a1..dffe62cd175 100644 --- a/packages/rocketchat-livechat/app/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/de.i18n.json @@ -6,7 +6,7 @@ "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, um kurz einige Fragen zu dem Chat zu beantworten.", + "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", diff --git a/packages/rocketchat-livechat/app/i18n/en.i18n.json b/packages/rocketchat-livechat/app/i18n/en.i18n.json index e09be84fb29..e31bf14dbe7 100644 --- a/packages/rocketchat-livechat/app/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/en.i18n.json @@ -15,4 +15,4 @@ "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", "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/fi.i18n.json b/packages/rocketchat-livechat/app/i18n/fi.i18n.json index eb1545f92f1..b5820e4af81 100644 --- a/packages/rocketchat-livechat/app/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/fi.i18n.json @@ -1,11 +1,14 @@ { "Additional_Feedback" : "Lisäpalaute", - "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", diff --git a/packages/rocketchat-livechat/app/i18n/he.i18n.json b/packages/rocketchat-livechat/app/i18n/he.i18n.json index 5e8b9b574e5..7aacaa2a49c 100644 --- a/packages/rocketchat-livechat/app/i18n/he.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/he.i18n.json @@ -1,3 +1,8 @@ { - "Start_Chat" : "Start Chat" + "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/nl.i18n.json b/packages/rocketchat-livechat/app/i18n/nl.i18n.json index 1c12392e2e3..2bf171f8b5d 100644 --- a/packages/rocketchat-livechat/app/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/nl.i18n.json @@ -8,6 +8,7 @@ "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", diff --git a/packages/rocketchat-livechat/i18n/de.i18n.json b/packages/rocketchat-livechat/i18n/de.i18n.json index 3a7fa80532b..cf1cb71ca41 100644 --- a/packages/rocketchat-livechat/i18n/de.i18n.json +++ b/packages/rocketchat-livechat/i18n/de.i18n.json @@ -15,6 +15,7 @@ "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.", @@ -31,6 +32,7 @@ "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", diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json index 5b4ce502ab1..58602f022d7 100644 --- a/packages/rocketchat-livechat/i18n/en.i18n.json +++ b/packages/rocketchat-livechat/i18n/en.i18n.json @@ -55,4 +55,4 @@ "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/fi.i18n.json b/packages/rocketchat-livechat/i18n/fi.i18n.json index 38c2b8035fe..deac2b104c7 100644 --- a/packages/rocketchat-livechat/i18n/fi.i18n.json +++ b/packages/rocketchat-livechat/i18n/fi.i18n.json @@ -4,33 +4,55 @@ "Add_manager" : "Lisää manageri", "Agent_added" : "Agentti lisätty", "Agent_removed" : "Agentti poistettu", + "Available_agents" : "Vapaat agentit", "Back" : "Takaisin", + "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", + "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.", + "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" + "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/he.i18n.json b/packages/rocketchat-livechat/i18n/he.i18n.json index a119b69e013..3efd17b9562 100644 --- a/packages/rocketchat-livechat/i18n/he.i18n.json +++ b/packages/rocketchat-livechat/i18n/he.i18n.json @@ -1,3 +1,25 @@ { - "Livechat_enabled" : "Livechat enabled" + "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/nl.i18n.json b/packages/rocketchat-livechat/i18n/nl.i18n.json index 26c59d6b1b6..f185cf0c6c3 100644 --- a/packages/rocketchat-livechat/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/i18n/nl.i18n.json @@ -1,24 +1,37 @@ { + "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.", @@ -28,6 +41,7 @@ "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/ro.i18n.json b/packages/rocketchat-livechat/i18n/ro.i18n.json index 1e83701edf4..83a8cd26cca 100644 --- a/packages/rocketchat-livechat/i18n/ro.i18n.json +++ b/packages/rocketchat-livechat/i18n/ro.i18n.json @@ -15,6 +15,7 @@ "Departments" : "Departamente", "Description" : "Descriere", "Edit_Department" : "Editează departament", + "Empty_title" : "Titlu gol", "Enable" : "Activează", "Enabled" : "Activat", "Enter_a_regex" : "IntroduceÈ›i un regex", @@ -31,6 +32,7 @@ "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", diff --git a/packages/rocketchat-livechat/i18n/ru.i18n.json b/packages/rocketchat-livechat/i18n/ru.i18n.json index bbece375a50..ea345d96bfe 100644 --- a/packages/rocketchat-livechat/i18n/ru.i18n.json +++ b/packages/rocketchat-livechat/i18n/ru.i18n.json @@ -1,3 +1,4 @@ { - "Livechat_enabled" : "Включен Livechat" + "Livechat_enabled" : "Включен Livechat", + "Livechat_title" : "Ðазвание чата" } \ 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 beff3d9920e..d70199a35e4 100644 --- a/packages/rocketchat-mailer/i18n/de.i18n.json +++ b/packages/rocketchat-mailer/i18n/de.i18n.json @@ -3,9 +3,9 @@ "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" : "Von:", - "Email_subject" : "Betreff:", - "Email_body" : "Nachricht:", + "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", diff --git a/packages/rocketchat-mailer/i18n/nl.i18n.json b/packages/rocketchat-mailer/i18n/nl.i18n.json index 6f31cf5a2e6..3c6d8dec0b9 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/ru.i18n.json b/packages/rocketchat-mailer/i18n/ru.i18n.json index 6f31cf5a2e6..980d68b0494 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-mentions-flextab/i18n/de.i18n.json b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json index 2b44208f91c..cdf69c577fd 100644 --- a/packages/rocketchat-mentions-flextab/i18n/de.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/de.i18n.json @@ -1,4 +1,4 @@ { "Mentions" : "Erwähnungen", - "No_mentions_found" : "Keine Erwähnungen gefunden" + "No_mentions_found" : "Sie wurden bisher nirgendwo erwähnt." } \ 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 index 6f31cf5a2e6..003f29ff22a 100644 --- a/packages/rocketchat-mentions-flextab/i18n/fi.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/fi.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "Maininnat", + "No_mentions_found" : "Mainintoja ei löytynyt" +} \ 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 index 6f31cf5a2e6..f76342a759c 100644 --- a/packages/rocketchat-mentions-flextab/i18n/he.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/he.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "×זכורי×", + "No_mentions_found" : "×œ× × ×ž×¦×ו ×זכורי×" +} \ 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 index 6f31cf5a2e6..1a95e01b2d5 100644 --- a/packages/rocketchat-mentions-flextab/i18n/ru.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/ru.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "УпоминаниÑ", + "No_mentions_found" : "Ð£Ð¿Ð¾Ð¼Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½Ðµ найдены" +} \ 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 8b9e0cff9f6..1f6aa825c53 100644 --- a/packages/rocketchat-message-pin/i18n/de.i18n.json +++ b/packages/rocketchat-message-pin/i18n/de.i18n.json @@ -6,5 +6,5 @@ "Pin_Message" : "Nachricht fixieren", "Unpin_Message" : "Nachicht nicht mehr fixieren", "Pinned_Messages" : "Fixierte Nachrichten", - "No_pinned_messages" : "Keine fixierten Nachrichten vorhanden." + "No_pinned_messages" : "Es wurden bisher keine Nachrichten fixiert." } \ 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 6f31cf5a2e6..8523fea7c8d 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/nl.i18n.json b/packages/rocketchat-message-pin/i18n/nl.i18n.json index 6f31cf5a2e6..721e551b321 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/ru.i18n.json b/packages/rocketchat-message-pin/i18n/ru.i18n.json index 6f31cf5a2e6..a83261331d9 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-star/i18n/de.i18n.json b/packages/rocketchat-message-star/i18n/de.i18n.json index 606cfee7304..e7a604c0076 100644 --- a/packages/rocketchat-message-star/i18n/de.i18n.json +++ b/packages/rocketchat-message-star/i18n/de.i18n.json @@ -3,5 +3,5 @@ "Star_Message" : "Nachricht markieren", "Unstar_Message" : "Markierung entfernen", "Starred_Messages" : "Markierte Nachrichten", - "No_starred_messages" : "Keine Nachrichten wurden markiert." + "No_starred_messages" : "Es wurden bisher keine Nachrichten markiert." } \ 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 24843cb079a..a34c4a5791a 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-slashcommands-invite/i18n/nl.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/nl.i18n.json index 6f31cf5a2e6..35a6d518000 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/ru.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ru.i18n.json index 6f31cf5a2e6..dba0f289799 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-join/i18n/de.i18n.json b/packages/rocketchat-slashcommands-join/i18n/de.i18n.json index 034bede9ed7..af31e778a80 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/nl.i18n.json b/packages/rocketchat-slashcommands-join/i18n/nl.i18n.json index 6f31cf5a2e6..0c0dd584e3c 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/ru.i18n.json b/packages/rocketchat-slashcommands-join/i18n/ru.i18n.json index 6f31cf5a2e6..aaaaf72ef99 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-kick/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json index 6f31cf5a2e6..63a5726744e 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/fi.i18n.json @@ -1 +1,5 @@ -{ } \ No newline at end of file +{ + "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/ru.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json index 6f31cf5a2e6..56c56d4f03e 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/ru.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Username_is_not_in_this_room" : "Пользователь `#%s` не в Ñтом чате.", + "Remove_someone_from_room" : "Удалить кого-то из чата" +} \ 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 index 6f31cf5a2e6..9058f325133 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/fi.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "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/ru.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json index 6f31cf5a2e6..55e8952a1a7 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/ru.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "Mute_someone_in_room" : "Заглу" +} \ 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 83ead2db3d3..51b788b0eb7 100644 --- a/packages/rocketchat-theme/i18n/fi.i18n.json +++ b/packages/rocketchat-theme/i18n/fi.i18n.json @@ -8,6 +8,7 @@ "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-secondary-background-color" : "Toissijainen taustaväri", diff --git a/packages/rocketchat-theme/i18n/nl.i18n.json b/packages/rocketchat-theme/i18n/nl.i18n.json index ea9b5b77aeb..70a0eeb7d0b 100644 --- a/packages/rocketchat-theme/i18n/nl.i18n.json +++ b/packages/rocketchat-theme/i18n/nl.i18n.json @@ -1,3 +1,6 @@ { - "theme-color-message-hover-background-color" : "Achtergrondkleur als muis er boven is" + "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-webrtc/i18n/nl.i18n.json b/packages/rocketchat-webrtc/i18n/nl.i18n.json index 6f31cf5a2e6..4df60fc80b8 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/ru.i18n.json b/packages/rocketchat-webrtc/i18n/ru.i18n.json index 6f31cf5a2e6..4fa80361495 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-wordpress/i18n/nl.i18n.json b/packages/rocketchat-wordpress/i18n/nl.i18n.json index 6f31cf5a2e6..1de9bd9e80c 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 -- GitLab From bc84827960704f367082feccdbe3735a86baa718 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 11 Jan 2016 12:09:00 -0200 Subject: [PATCH 1167/1338] fixing branch docker image build --- .docker/dockerfiles/develop/Dockerfile | 17 +++++++++++------ .docker/dockerfiles/latest/Dockerfile | 17 +++++++++++------ .travis/docker.sh | 3 ++- .travis/setartname.sh | 2 +- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index e99c7450981..2adc1194716 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -1,5 +1,6 @@ FROM node:0.10 +# crafted and tuned by pierre@ozoux.net and sing.li@rocket.chat MAINTAINER buildmaster@rocket.chat RUN groupadd -r rocketchat \ @@ -7,22 +8,25 @@ RUN groupadd -r rocketchat \ && mkdir /app \ && mkdir /app/uploads +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://rocket.chat/releases/develop/download -o rocket.chat.tgz \ -&& curl -fSL https://rocket.chat/releases/develop/asc -o rocket.chat.tgz.asc \ +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 /app/bundle/programs/server \ +&& 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' @@ -32,4 +36,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 f1fd8026f2a..58332d6c3ff 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -1,5 +1,6 @@ FROM node:0.10 +# crafted and tuned by pierre@ozoux.net and sing.li@rocket.chat MAINTAINER buildmaster@rocket.chat RUN groupadd -r rocketchat \ @@ -7,22 +8,25 @@ RUN groupadd -r rocketchat \ && mkdir /app \ && mkdir /app/uploads +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 curl -fSL https://rocket.chat/releases/latest/download -o rocket.chat.tgz \ -&& curl -fSL https://rocket.chat/releases/latest/asc -o rocket.chat.tgz.asc \ +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 /app/bundle/programs/server \ +&& 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' @@ -32,4 +36,5 @@ ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ Accounts_AvatarStorePath=/app/uploads EXPOSE 3000 + CMD ["node", "main.js"] diff --git a/.travis/docker.sh b/.travis/docker.sh index 1982a9ef008..66a9189c50c 100755 --- a/.travis/docker.sh +++ b/.travis/docker.sh @@ -4,7 +4,8 @@ IFS=$'\n\t' CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/" -if [[ -v "$TRAVIS_TAG" ]]; then +if [[ $TRAVIS_TAG ]] + then CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}'; else CURL_DATA='{"source_type":"Branch","source_name":"develop"}'; diff --git a/.travis/setartname.sh b/.travis/setartname.sh index 0d7f3518c46..5d5839b6a5e 100755 --- a/.travis/setartname.sh +++ b/.travis/setartname.sh @@ -1,4 +1,4 @@ -if [[ $TRAVIS_TAG ]] +if [[ $TRAVIS_TAG ]] then export ARTIFACT_NAME="$TRAVIS_TAG"; else -- GitLab From 6b2ce9e1b54a14065df39b983a725fbfa85f6cc6 Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Mon, 11 Jan 2016 11:59:23 -0500 Subject: [PATCH 1168/1338] Prevent misunderstanding for new devs --- .docker/dockerfiles/develop/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index 2adc1194716..7e6a2c6b250 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -1,5 +1,8 @@ FROM node:0.10 +# IMPORTANT - this is a release + deployment dockerfile +# Please DO NOT attempt to use this for development. + # crafted and tuned by pierre@ozoux.net and sing.li@rocket.chat MAINTAINER buildmaster@rocket.chat -- GitLab From 8e442f48eb9d9d4565fe12a8f12ef7ac6dd2f52e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 11 Jan 2016 15:49:45 -0200 Subject: [PATCH 1169/1338] Closes #1856; Parse urls with fragments correctly --- packages/rocketchat-lib/server/functions/sendMessage.coffee | 2 +- server/methods/updateMessage.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index 6b14009c97c..fa30388ff35 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 diff --git a/server/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index f0439e370e3..966c52399d5 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -33,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 -- GitLab From 4646a4287423e23aa846940959fc604f026968fb Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 11 Jan 2016 17:43:41 -0200 Subject: [PATCH 1170/1338] moved collection definition to a better place --- packages/rocketchat-ui/lib/collections.coffee | 1 + packages/rocketchat-ui/views/app/room.coffee | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rocketchat-ui/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee index a1f8bd13879..f238e04b016 100644 --- a/packages/rocketchat-ui/lib/collections.coffee +++ b/packages/rocketchat-ui/lib/collections.coffee @@ -1,6 +1,7 @@ @ChatMessage = new Meteor.Collection null @ChatRoom = new Meteor.Collection 'rocketchat_room' @ChatSubscription = new Meteor.Collection 'rocketchat_subscription' +@RoomModerators = new Mongo.Collection 'room_moderators' @UserAndRoom = new Meteor.Collection null @CachedChannelList = new Meteor.Collection null diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 6bf4bdfd72a..b3ef4680afc 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -1,5 +1,3 @@ -@RoomModerators = new Mongo.Collection 'room_moderators' - isSubscribed = (_id) -> return ChatSubscription.find({ rid: _id }).count() > 0 -- GitLab From 7c9633fdacabce783fa22dfc8326b1b872fc5a3f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 11 Jan 2016 17:43:56 -0200 Subject: [PATCH 1171/1338] added package dependecy because of RoomModerators collection --- packages/rocketchat-ui-flextab/package.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-ui-flextab/package.js b/packages/rocketchat-ui-flextab/package.js index e508f10d508..98a1b68a2c0 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'); -- GitLab From b4ed3682399904c64751596d8b7c718fcb24358b Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 11 Jan 2016 17:44:39 -0200 Subject: [PATCH 1172/1338] improved room moderator subscription and tests --- .../flex-tab/tabs/userInfo.coffee | 18 +++++++++++------- packages/rocketchat-ui/views/app/room.coffee | 3 +-- server/publications/roomModerators.coffee | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index f0d97465ff1..1e798f6ee39 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -49,7 +49,7 @@ Template.userInfo.helpers return RocketChat.authz.hasAllPermission('set-moderator', Session.get('openedRoom')) isModerator: -> - return !!RoomModerators.findOne({ "u._id": @user?._id }) + return !!RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user?._id }) Template.userInfo.events 'click .pvt-msg': (e) -> @@ -159,22 +159,26 @@ Template.userInfo.events 'click .set-moderator': (e, t) -> e.preventDefault() - room = ChatRoom.findOne(Session.get('openedRoom')) - moderators = _.map RoomModerators.find().fetch(), (moderator) -> return moderator.u?._id - if @user._id not in moderators + + userModerator = RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id }, { 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() - room = ChatRoom.findOne(Session.get('openedRoom')) - moderators = _.map RoomModerators.find().fetch(), (moderator) -> return moderator.u?._id - if @user._id in moderators + + userModerator = RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id }, { fields: { _id: 1 } }) + unless 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 } Template.userInfo.onCreated -> diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index b3ef4680afc..9156d07e1f1 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -493,8 +493,7 @@ Template.room.onCreated -> @autorun => @subscribe 'fullUserData', Session.get('showUserInfo'), 1 - @autorun => - @subscribe 'roomModerators', Session.get('openedRoom') + @subscribe 'roomModerators', @data._id Template.room.onDestroyed -> window.removeEventListener 'resize', this.onWindowResize diff --git a/server/publications/roomModerators.coffee b/server/publications/roomModerators.coffee index 4e20286701c..2d293914d3c 100644 --- a/server/publications/roomModerators.coffee +++ b/server/publications/roomModerators.coffee @@ -13,6 +13,7 @@ Meteor.publish 'roomModerators', (rid, limit = 50) -> sort: "u.username": 1 fields: + rid: 1 u: 1 cursor = RocketChat.models.Subscriptions.find(query, options).observeChanges -- GitLab From e5ce78f2feee02ac28607c702b966cf316017373 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Mon, 11 Jan 2016 17:52:07 -0200 Subject: [PATCH 1173/1338] fix unset moderator test --- packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 1e798f6ee39..2b1a1754027 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -161,7 +161,7 @@ Template.userInfo.events e.preventDefault() userModerator = RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id }, { fields: { _id: 1 } }) - unless userModerator + unless userModerator? Meteor.call 'addRoomModerator', Session.get('openedRoom'), @user._id, (err, results) => if err return toastr.error(err.reason or err.message) @@ -173,7 +173,7 @@ Template.userInfo.events e.preventDefault() userModerator = RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id }, { fields: { _id: 1 } }) - unless userModerator + if userModerator? Meteor.call 'removeRoomModerator', Session.get('openedRoom'), @user._id, (err, results) => if err return toastr.error(err.reason or err.message) -- GitLab From aa6d0265e0734aaa4acad80474e17cc13ac12001 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 11 Jan 2016 20:38:11 -0200 Subject: [PATCH 1174/1338] cleanup --- .docker/dockerfiles/develop/Dockerfile | 9 ++------- .docker/dockerfiles/latest/Dockerfile | 4 +--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile index 7e6a2c6b250..14e23628e99 100644 --- a/.docker/dockerfiles/develop/Dockerfile +++ b/.docker/dockerfiles/develop/Dockerfile @@ -1,15 +1,10 @@ FROM node:0.10 -# IMPORTANT - this is a release + deployment dockerfile -# Please DO NOT attempt to use this for development. - -# crafted and tuned by pierre@ozoux.net and sing.li@rocket.chat +# IMPORTANT - FOR TESTING ONLY - DO NOT USE THIS FOR DEVELOPMENT OR PRODUCTION! MAINTAINER buildmaster@rocket.chat RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat \ -&& mkdir /app \ -&& mkdir /app/uploads +&& useradd -r -g rocketchat rocketchat VOLUME /app/uploads diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile index 58332d6c3ff..286962d174d 100644 --- a/.docker/dockerfiles/latest/Dockerfile +++ b/.docker/dockerfiles/latest/Dockerfile @@ -4,9 +4,7 @@ FROM node:0.10 MAINTAINER buildmaster@rocket.chat RUN groupadd -r rocketchat \ -&& useradd -r -g rocketchat rocketchat \ -&& mkdir /app \ -&& mkdir /app/uploads +&& useradd -r -g rocketchat rocketchat VOLUME /app/uploads -- GitLab From b57bbd02f31229874550038f0133209f5f4a1b08 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 12 Jan 2016 13:35:22 -0200 Subject: [PATCH 1175/1338] Closes #1860; Escape dollar before message token replacement --- packages/rocketchat-ui-message/message/message.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index dff309fa1fb..f3cbfedf32c 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -104,6 +104,7 @@ Template.message.onCreated -> 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 -- GitLab From a92ab84bdf7618105ac2a2be3a783b48aacfffab Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 12 Jan 2016 16:02:12 -0200 Subject: [PATCH 1176/1338] Closes #1866; Do not close Desktop Notifications to keep them in notification center --- packages/rocketchat-ui/lib/notification.coffee | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/rocketchat-ui/lib/notification.coffee b/packages/rocketchat-ui/lib/notification.coffee index c6822dd846b..0785236f5de 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() -- GitLab From 59a37fd19c3dce63268ad9040c0fb3ed7c2096c4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 12 Jan 2016 16:12:46 -0200 Subject: [PATCH 1177/1338] changed statistics behavior --- server/startup/cron.coffee | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/server/startup/cron.coffee b/server/startup/cron.coffee index 3cee5e37fe4..9bd2f8dd958 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() -- GitLab From 94c9ef3f5b4a78ac058a31c2c786489631cc51be Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Tue, 12 Jan 2016 16:12:46 -0200 Subject: [PATCH 1178/1338] changed statistics behavior --- server/startup/cron.coffee | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/server/startup/cron.coffee b/server/startup/cron.coffee index 3cee5e37fe4..9bd2f8dd958 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() -- GitLab From e826d4906403533ca0178cd8c1cddf226d32f3af Mon Sep 17 00:00:00 2001 From: alayek <arijit.layek1991@gmail.com> Date: Wed, 13 Jan 2016 00:19:20 +0530 Subject: [PATCH 1179/1338] Implement logging out of other logged-in clients --- .../rocketchat-ui-account/account/accountProfile.coffee | 6 ++++++ packages/rocketchat-ui-account/account/accountProfile.html | 3 +++ 2 files changed, 9 insertions(+) diff --git a/packages/rocketchat-ui-account/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee index 5a780f917a9..f9f2bba86ac 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.coffee +++ b/packages/rocketchat-ui-account/account/accountProfile.coffee @@ -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 8a6dbfab5d4..98751efcc26 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> -- GitLab From 6789facdfcfd67765570fac6b529a9bf1002abcd Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 12 Jan 2016 17:16:16 -0200 Subject: [PATCH 1180/1338] Set/Unset moderator via streams --- .../server/models/Subscriptions.coffee | 9 ++++++ packages/rocketchat-ui/lib/collections.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 17 +++++++++- server/methods/getRoomModerators.coffee | 15 +++++++++ server/publications/roomModerators.coffee | 32 ------------------- 5 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 server/methods/getRoomModerators.coffee delete mode 100644 server/publications/roomModerators.coffee diff --git a/packages/rocketchat-lib/server/models/Subscriptions.coffee b/packages/rocketchat-lib/server/models/Subscriptions.coffee index 76e10ec3da9..5a324807120 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 } diff --git a/packages/rocketchat-ui/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee index f238e04b016..1ac9008435f 100644 --- a/packages/rocketchat-ui/lib/collections.coffee +++ b/packages/rocketchat-ui/lib/collections.coffee @@ -1,7 +1,7 @@ @ChatMessage = new Meteor.Collection null @ChatRoom = new Meteor.Collection 'rocketchat_room' @ChatSubscription = new Meteor.Collection 'rocketchat_subscription' -@RoomModerators = new Mongo.Collection 'room_moderators' +@RoomModerators = new Mongo.Collection null @UserAndRoom = new Meteor.Collection null @CachedChannelList = new Meteor.Collection null diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 9156d07e1f1..d26c22594c7 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -493,7 +493,22 @@ Template.room.onCreated -> @autorun => @subscribe 'fullUserData', Session.get('showUserInfo'), 1 - @subscribe 'roomModerators', @data._id + Meteor.call 'getRoomModerators', @data._id, (error, results) -> + if error + return toastr.error error.reason + + for record in results + RoomModerators.insert record + + RocketChat.callbacks.add('streamMessage', (msg) -> + if msg.t is 'new-moderator' + user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }) + RoomModerators.upsert({ _id: msg._id }, { $set: { rid: msg.rid, u: user } }) # use message _id to prevent from running it twice (https://github.com/RocketChat/Rocket.Chat/issues/1876) + else if msg.t is 'moderator-removed' + user = Meteor.users.findOne({ username: msg.msg }) + RoomModerators.remove({ rid: msg.rid, "u._id": user._id }); + return msg + , RocketChat.callbacks.priority.LOW, 'addOrRemoveModerator') Template.room.onDestroyed -> window.removeEventListener 'resize', this.onWindowResize diff --git a/server/methods/getRoomModerators.coffee b/server/methods/getRoomModerators.coffee new file mode 100644 index 00000000000..2cd263ac2db --- /dev/null +++ b/server/methods/getRoomModerators.coffee @@ -0,0 +1,15 @@ +Meteor.methods + getRoomModerators: (rid) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', '[methods] getRoomModerators -> Invalid user' + + check rid, String + + options = + sort: + "u.username": 1 + fields: + rid: 1 + u: 1 + + return RocketChat.models.Subscriptions.findByRoomIdAndRoles(rid, 'moderator', options).fetch() diff --git a/server/publications/roomModerators.coffee b/server/publications/roomModerators.coffee deleted file mode 100644 index 2d293914d3c..00000000000 --- a/server/publications/roomModerators.coffee +++ /dev/null @@ -1,32 +0,0 @@ -Meteor.publish 'roomModerators', (rid, limit = 50) -> - unless this.userId - return this.ready() - - pub = this - - query = - rid: rid - roles: 'moderator' - - options = - limit: limit - sort: - "u.username": 1 - fields: - rid: 1 - u: 1 - - cursor = RocketChat.models.Subscriptions.find(query, options).observeChanges - added: (_id, record) -> - pub.added('room_moderators', _id, record) - - changed: (_id, record) -> - pub.changed('room_moderators', _id, record) - - removed: (_id, record) -> - pub.removed('room_moderators', _id, record) - - this.ready() - this.onStop -> - cursor.stop() - -- GitLab From 08142d2693c8c1b1f5fbe67cb25af76b389a3a0b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 12 Jan 2016 17:57:53 -0200 Subject: [PATCH 1181/1338] Prevent multiple listeners on message stream per room --- packages/rocketchat-ui/lib/RoomManager.coffee | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 25a22193e1e..383f2893b6f 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 @@ -108,21 +108,23 @@ RocketChat.Notifications.onUser 'message', (msg) -> record.ready = RoomHistoryManager.isLoading(room._id) is false Dep.changed() - msgStream.on openedRooms[typeName].rid, (msg) -> + 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 + # 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 + # Do not load command messages into channel + if msg.t isnt 'command' + ChatMessage.upsert { _id: msg._id }, msg - Meteor.defer -> - RoomManager.updateMentionsMarksOfRoom typeName + 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() -- GitLab From efdffa9407c74b992bb0fec5681d4e9f235aafa9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 12 Jan 2016 18:20:07 -0200 Subject: [PATCH 1182/1338] Do for owners as for moderators --- i18n/en.i18n.json | 8 ++++- .../server/startup.coffee | 19 ++++++---- .../rocketchat-lib/lib/MessageTypes.coffee | 14 ++++++++ .../server/models/Messages.coffee | 8 +++++ .../flex-tab/tabs/userInfo.coffee | 36 +++++++++++++++++-- .../flex-tab/tabs/userInfo.html | 7 ++++ packages/rocketchat-ui/lib/collections.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 18 +++++++--- server/methods/addRoomOwner.coffee | 25 +++++++++++++ server/methods/createChannel.coffee | 2 +- server/methods/createPrivateGroup.coffee | 2 +- ...ffee => getRoomModeratorsAndOwners.coffee} | 7 ++-- server/methods/removeRoomOwner.coffee | 25 +++++++++++++ server/methods/removeUserFromRoom.coffee | 2 +- 14 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 server/methods/addRoomOwner.coffee rename server/methods/{getRoomModerators.coffee => getRoomModeratorsAndOwners.coffee} (67%) create mode 100644 server/methods/removeRoomOwner.coffee diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index b694485e80e..a64d5fd799b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -402,6 +402,7 @@ "Removed" : "Removed", "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", "Reset" : "Reset", @@ -454,6 +455,7 @@ "Settings" : "Settings", "Settings_updated" : "Settings updated", "Set_as_moderator" : "Set as moderator", + "Set_as_owner" : "Set as owner", "Should_be_a_URL_of_an_image" : "Should be a URL of an image.", "Should_exists_a_user_with_this_username" : "The user must already exist.", "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", @@ -553,13 +555,17 @@ "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__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_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", "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__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>", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", @@ -595,4 +601,4 @@ "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/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index b2b0942c3bd..7febc408c37 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -55,25 +55,29 @@ Meteor.startup -> roles : ['admin']} { _id: 'edit-room', - roles : ['admin', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'edit-message', - roles : ['admin', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'delete-message', - roles : ['admin', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'remove-user', - roles : ['admin', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'mute-user', - roles : ['admin', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'ban-user', - roles : ['admin', 'moderator']} + roles : ['admin', 'moderator', 'owner']} { _id: 'set-moderator', - roles : ['admin', 'moderator']} + roles : ['admin', 'owner']} + + { _id: 'set-owner', + roles : ['admin']} + { _id: 'create-p', roles : ['admin', 'user']} @@ -117,6 +121,7 @@ Meteor.startup -> defaultRoles = [ { name: 'admin', scope: 'Users' } { name: 'moderator', scope: 'Subscriptions' } + { name: 'owner', scope: 'Subscriptions' } { name: 'user', scope: 'Users' } { name: 'bot', scope: 'Users' } ] diff --git a/packages/rocketchat-lib/lib/MessageTypes.coffee b/packages/rocketchat-lib/lib/MessageTypes.coffee index a9407e0cc1a..58f651d4586 100644 --- a/packages/rocketchat-lib/lib/MessageTypes.coffee +++ b/packages/rocketchat-lib/lib/MessageTypes.coffee @@ -96,3 +96,17 @@ Meteor.startup -> 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/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee index 6591b251d22..c7e7bf5ba00 100644 --- a/packages/rocketchat-lib/server/models/Messages.coffee +++ b/packages/rocketchat-lib/server/models/Messages.coffee @@ -302,6 +302,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base 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-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 2b1a1754027..16af8660d7e 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -49,7 +49,13 @@ Template.userInfo.helpers return RocketChat.authz.hasAllPermission('set-moderator', Session.get('openedRoom')) isModerator: -> - return !!RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user?._id }) + 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, role: 'owner' }) Template.userInfo.events 'click .pvt-msg': (e) -> @@ -160,7 +166,7 @@ Template.userInfo.events 'click .set-moderator': (e, t) -> e.preventDefault() - userModerator = RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id }, { fields: { _id: 1 } }) + 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 @@ -172,7 +178,7 @@ Template.userInfo.events 'click .unset-moderator': (e, t) -> e.preventDefault() - userModerator = RoomModerators.findOne({ rid: Session.get('openedRoom'), "u._id": @user._id }, { fields: { _id: 1 } }) + 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 @@ -181,6 +187,30 @@ Template.userInfo.events 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() self = @ diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html index c4e3e9b2e68..bad3b31f478 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html @@ -33,6 +33,13 @@ {{#if canDirectMessage user.username}} <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> diff --git a/packages/rocketchat-ui/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee index 1ac9008435f..f02353c5501 100644 --- a/packages/rocketchat-ui/lib/collections.coffee +++ b/packages/rocketchat-ui/lib/collections.coffee @@ -1,7 +1,7 @@ @ChatMessage = new Meteor.Collection null @ChatRoom = new Meteor.Collection 'rocketchat_room' @ChatSubscription = new Meteor.Collection 'rocketchat_subscription' -@RoomModerators = new Mongo.Collection null +@RoomModeratorsAndOwners = new Mongo.Collection null @UserAndRoom = new Meteor.Collection null @CachedChannelList = new Meteor.Collection null diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index d26c22594c7..dcc25cac967 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -493,23 +493,33 @@ Template.room.onCreated -> @autorun => @subscribe 'fullUserData', Session.get('showUserInfo'), 1 - Meteor.call 'getRoomModerators', @data._id, (error, results) -> + Meteor.call 'getRoomModeratorsAndOwners', @data._id, (error, results) -> if error return toastr.error error.reason for record in results - RoomModerators.insert record + RoomModeratorsAndOwners.insert record RocketChat.callbacks.add('streamMessage', (msg) -> if msg.t is 'new-moderator' user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }) - RoomModerators.upsert({ _id: msg._id }, { $set: { rid: msg.rid, u: user } }) # use message _id to prevent from running it twice (https://github.com/RocketChat/Rocket.Chat/issues/1876) + RoomModeratorsAndOwners.upsert({ _id: msg._id }, { $set: { rid: msg.rid, u: user }, $addToSet: { roles: 'moderator' } }) # use message _id to prevent from running it twice (https://github.com/RocketChat/Rocket.Chat/issues/1876) else if msg.t is 'moderator-removed' user = Meteor.users.findOne({ username: msg.msg }) - RoomModerators.remove({ rid: msg.rid, "u._id": user._id }); + RoomModeratorsAndOwners.remove({ rid: msg.rid, "u._id": user._id }); return msg , RocketChat.callbacks.priority.LOW, 'addOrRemoveModerator') + RocketChat.callbacks.add('streamMessage', (msg) -> + if msg.t is 'new-owner' + user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }) + RoomModeratorsAndOwners.upsert({ _id: msg._id }, { $set: { rid: msg.rid, u: user }, $addToSet: { roles: 'owner' } }) # use message _id to prevent from running it twice (https://github.com/RocketChat/Rocket.Chat/issues/1876) + else if msg.t is 'owner-removed' + user = Meteor.users.findOne({ username: msg.msg }) + RoomModeratorsAndOwners.remove({ rid: msg.rid, "u._id": user._id }); + return msg + , RocketChat.callbacks.priority.LOW, 'addOrRemoveOwner') + Template.room.onDestroyed -> window.removeEventListener 'resize', this.onWindowResize diff --git a/server/methods/addRoomOwner.coffee b/server/methods/addRoomOwner.coffee new file mode 100644 index 00000000000..d3838be0b03 --- /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/createChannel.coffee b/server/methods/createChannel.coffee index 570d85bfa22..3edf800ec94 100644 --- a/server/methods/createChannel.coffee +++ b/server/methods/createChannel.coffee @@ -55,7 +55,7 @@ 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', room._id) + RocketChat.authz.addUserRoles(Meteor.userId(), ['moderator','owner'], room._id) Meteor.defer -> RocketChat.callbacks.run 'afterCreateChannel', user, room diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee index 3a0dd23fa4c..657fa879463 100644 --- a/server/methods/createPrivateGroup.coffee +++ b/server/methods/createPrivateGroup.coffee @@ -34,7 +34,7 @@ Meteor.methods ts: now # set creator as group moderator. permission limited to group by scoping to rid - RocketChat.authz.addUserRoles(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/getRoomModerators.coffee b/server/methods/getRoomModeratorsAndOwners.coffee similarity index 67% rename from server/methods/getRoomModerators.coffee rename to server/methods/getRoomModeratorsAndOwners.coffee index 2cd263ac2db..37adf060156 100644 --- a/server/methods/getRoomModerators.coffee +++ b/server/methods/getRoomModeratorsAndOwners.coffee @@ -1,7 +1,7 @@ Meteor.methods - getRoomModerators: (rid) -> + getRoomModeratorsAndOwners: (rid) -> unless Meteor.userId() - throw new Meteor.Error 'invalid-user', '[methods] getRoomModerators -> Invalid user' + throw new Meteor.Error 'invalid-user', '[methods] getRoomModeratorsAndOwners -> Invalid user' check rid, String @@ -11,5 +11,6 @@ Meteor.methods fields: rid: 1 u: 1 + roles: 1 - return RocketChat.models.Subscriptions.findByRoomIdAndRoles(rid, 'moderator', options).fetch() + return RocketChat.models.Subscriptions.findByRoomIdAndRoles(rid, ['moderator', 'owner'], options).fetch() diff --git a/server/methods/removeRoomOwner.coffee b/server/methods/removeRoomOwner.coffee new file mode 100644 index 00000000000..b29a5f431ec --- /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 f45e43a5bab..2c737d9e83d 100644 --- a/server/methods/removeUserFromRoom.coffee +++ b/server/methods/removeUserFromRoom.coffee @@ -18,7 +18,7 @@ Meteor.methods RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, removedUser._id if room.t in [ 'c', 'p' ] - RocketChat.authz.removeUserFromRoles(removedUser._id; 'moderator', data.rid) + RocketChat.authz.removeUserFromRoles(removedUser._id, ['moderator', 'owner'], data.rid) fromUser = RocketChat.models.Users.findOneById fromId RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser, -- GitLab From 8f3484be0f92c2ec78fbaee42f4cddfeeabb6f62 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 12 Jan 2016 18:22:48 -0200 Subject: [PATCH 1183/1338] Improve code execution on open room computation --- packages/rocketchat-ui/lib/RoomManager.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 383f2893b6f..d5b15660788 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -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 -- GitLab From 6d0194f420ebb887c8e1b20802f29e1fc4150c51 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 12 Jan 2016 20:16:29 -0200 Subject: [PATCH 1184/1338] Closes #1879; Get the correct language when senging messages via email --- .../server/methods/mailMessages.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee index 446df06f288..f1c07f4bb78 100644 --- a/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee +++ b/packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee @@ -32,6 +32,8 @@ Meteor.methods 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 -- GitLab From 07866148e1fe57fe0ba279c5866a921c13e1afca Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 13 Jan 2016 09:31:42 -0200 Subject: [PATCH 1185/1338] emojione:emojione upgraded from 2.0.0 to 2.0.1 momentjs:moment upgraded from 2.11.0 to 2.11.1 percolate:migrations upgraded from 0.9.7 to 0.9.8 mdg:validation-error upgraded from 0.2.0 to 0.3.0 --- .meteor/versions | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index bcc646ddc33..ff8301b12be 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -38,7 +38,7 @@ ecmascript@0.1.6 ecmascript-runtime@0.2.6 ejson@1.0.7 email@1.0.8 -emojione:emojione@2.0.0 +emojione:emojione@2.0.1 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.0 @@ -74,7 +74,7 @@ livedata@1.0.15 localstorage@1.0.5 logging@1.0.8 matb33:collection-hooks@0.8.1 -mdg:validation-error@0.2.0 +mdg:validation-error@0.3.0 meteor@1.1.10 meteor-base@1.0.1 meteor-developer@1.1.5 @@ -85,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.11.0 +momentjs:moment@2.11.1 monbro:mongodb-mapreduce-aggregation@1.0.1 mongo@1.1.3 mongo-id@1.0.1 @@ -105,7 +105,7 @@ 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 -- GitLab From bc47d2a6bcb2082cfb6095f6cd61ee8bd5fb3325 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 13 Jan 2016 09:44:34 -0200 Subject: [PATCH 1186/1338] Fixes adding/removing owners and moderators --- .../flex-tab/tabs/userInfo.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 16af8660d7e..0a8514faeb1 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -55,7 +55,7 @@ Template.userInfo.helpers return RocketChat.authz.hasAllPermission('set-owner', Session.get('openedRoom')) isOwner: -> - return !!RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user?._id, role: 'owner' }) + return !!RoomModeratorsAndOwners.findOne({ rid: Session.get('openedRoom'), "u._id": @user?._id, roles: 'owner' }) Template.userInfo.events 'click .pvt-msg': (e) -> diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index dcc25cac967..50eb391f669 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -503,20 +503,28 @@ Template.room.onCreated -> RocketChat.callbacks.add('streamMessage', (msg) -> if msg.t is 'new-moderator' user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }) - RoomModeratorsAndOwners.upsert({ _id: msg._id }, { $set: { rid: msg.rid, u: user }, $addToSet: { roles: 'moderator' } }) # use message _id to prevent from running it twice (https://github.com/RocketChat/Rocket.Chat/issues/1876) + RoomModeratorsAndOwners.upsert({ rid: msg.rid, "u._id": user._id }, { $setOnInsert: { u: user }, $addToSet: { roles: 'moderator' } }) else if msg.t is 'moderator-removed' user = Meteor.users.findOne({ username: msg.msg }) - RoomModeratorsAndOwners.remove({ rid: msg.rid, "u._id": user._id }); + moderator = RoomModeratorsAndOwners.findOne({ rid: msg.rid, "u._id": user._id, roles: 'moderator' }) + if moderator?.roles?.length is 1 and moderator.roles[0] is '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', (msg) -> if msg.t is 'new-owner' user = Meteor.users.findOne({ username: msg.msg }, { fields: { username: 1 } }) - RoomModeratorsAndOwners.upsert({ _id: msg._id }, { $set: { rid: msg.rid, u: user }, $addToSet: { roles: 'owner' } }) # use message _id to prevent from running it twice (https://github.com/RocketChat/Rocket.Chat/issues/1876) + RoomModeratorsAndOwners.upsert({ rid: msg.rid, "u._id": user._id }, { $setOnInsert: { u: user }, $addToSet: { roles: 'owner' } }) else if msg.t is 'owner-removed' user = Meteor.users.findOne({ username: msg.msg }) - RoomModeratorsAndOwners.remove({ rid: msg.rid, "u._id": user._id }); + owner = RoomModeratorsAndOwners.findOne({ rid: msg.rid, "u._id": user._id, roles: 'owner' }) + if owner?.roles?.length is 1 and owner.roles[0] is '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') -- GitLab From 57b0e01eb557cc5e8ef5e5d5a39c962d04fbbd5a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 13 Jan 2016 14:12:12 -0200 Subject: [PATCH 1187/1338] Use 'mim-types' ty check content type and compare to extension --- .../.npm/package/npm-shrinkwrap.json | 8 ++++++ packages/rocketchat-assets/package.js | 3 ++- .../rocketchat-assets/server/assets.coffee | 27 +++++++------------ .../rocketchat-ui-admin/admin/admin.coffee | 10 +++---- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json index f69e18d8fe1..78afe4f3ae8 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 ea0504827fe..7f299bb33aa 100644 --- a/packages/rocketchat-assets/package.js +++ b/packages/rocketchat-assets/package.js @@ -20,7 +20,8 @@ Package.onUse(function(api) { }); 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 acf9d258456..4c99b703d1d 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-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index f13e0941b6e..eeced50c745 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -186,17 +186,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' -- GitLab From c4c89733c722d61908bc0a52fdb1be26850e7df8 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 14:39:08 -0200 Subject: [PATCH 1188/1338] moved logic to create a message from webhooks to a new file --- packages/rocketchat-integrations/package.js | 2 + .../server/api/api.coffee | 84 +------------ .../server/processWebhookMessage.js | 115 ++++++++++++++++++ 3 files changed, 118 insertions(+), 83 deletions(-) create mode 100644 packages/rocketchat-integrations/server/processWebhookMessage.js diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index dc2b48f48e4..babf2fc8074 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -56,6 +56,8 @@ Package.onUse(function(api) { 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) { diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 54e564e7264..8315f795f58 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -22,89 +22,7 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, 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 - if room.t is 'c' - 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.username - room = RocketChat.models.Rooms.findOne(rid) - - else - return {} = - statusCode: 400 - body: - success: false - error: 'invalid-channel-type' - - message = - alias: @bodyParams.username or @bodyParams.alias or integration.alias - msg: _.trim(@bodyParams.text or @bodyParams.msg or '') - attachments: @bodyParams.attachments - parseUrls: false - bot: - i: integration._id - groupable: false - - if @bodyParams.icon_url? or @bodyParams.avatar? - message.avatar = @bodyParams.icon_url or @bodyParams.avatar - else if @bodyParams.icon_emoji? or @bodyParams.emoji? - message.emoji = @bodyParams.icon_emoji or @bodyParams.emoji - else if integration.avatar? - message.avatar = integration.avatar - else if integration.emoji? - message.emoji = integration.emoji - - if _.isArray message.attachments - for attachment in message.attachments - if attachment.msg - attachment.text = _.trim(attachment.msg) - delete attachment.msg - - RocketChat.sendMessage user, message, room, {} - - return {} = - statusCode: 200 - body: - success: true + return processWebhookMessage integration, @bodyParams, user createIntegration = (options, user) -> diff --git a/packages/rocketchat-integrations/server/processWebhookMessage.js b/packages/rocketchat-integrations/server/processWebhookMessage.js new file mode 100644 index 00000000000..5b1938080ac --- /dev/null +++ b/packages/rocketchat-integrations/server/processWebhookMessage.js @@ -0,0 +1,115 @@ +this.processWebhookMessage = function(integration, messageObj, user) { + var attachment, channel, channelType, i, len, message, ref, rid, room, roomUser; + + channel = messageObj.channel || integration.channel; + + channelType = channel[0]; + + channel = channel.substr(1); + + switch (channelType) { + case '#': + room = RocketChat.models.Rooms.findOne({ + $or: [ + { + _id: channel + }, { + name: channel + } + ] + }); + if (room == null) { + return { + statusCode: 400, + body: { + success: false, + 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) { + return { + statusCode: 400, + body: { + success: false, + 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: + return { + statusCode: 400, + body: { + success: false, + error: 'invalid-channel-type' + } + }; + } + + message = { + alias: messageObj.username || messageObj.alias || integration.alias, + msg: _.trim(messageObj.text || messageObj.msg || ''), + attachments: messageObj.attachments, + parseUrls: false, + bot: { + i: integration._id + }, + 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 (integration.avatar != null) { + message.avatar = integration.avatar; + } else if (integration.emoji != null) { + message.emoji = integration.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; + } + } + } + + RocketChat.sendMessage(user, message, room, {}); + + return { + statusCode: 200, + body: { + success: true + } + }; +}; -- GitLab From fe1c83cd300f1c74876f5e9fdb2015011121242e Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 14:39:26 -0200 Subject: [PATCH 1189/1338] process outgoing webhook response as a new message --- packages/rocketchat-integrations/server/triggers.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 6c815d45758..caa9bc23cd8 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -61,8 +61,12 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> , Math.pow(10, tries+2) return - # TODO process return and insert message if necessary + # 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) + if result.data?.text? or result.data?.attachments? + return processWebhookMessage trigger, result.data, user ExecuteTrigger = (trigger, message, room) -> -- GitLab From 00ff7b79b3aaddcb279a0f752e2332fa54436a2a Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 13 Jan 2016 15:08:41 -0200 Subject: [PATCH 1190/1338] Closes #1882 --- packages/rocketchat-lib/client/lib/settings.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee index 2e96a93d50e..7a19eb1d3fb 100644 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ b/packages/rocketchat-lib/client/lib/settings.coffee @@ -38,7 +38,7 @@ 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 /\/$/, '' -- GitLab From 06546ce0a302d1fcbd202e7040cb867b2345e04a Mon Sep 17 00:00:00 2001 From: alayek <arijit.layek1991@gmail.com> Date: Wed, 13 Jan 2016 22:51:27 +0530 Subject: [PATCH 1191/1338] Update strings with localized strings in en --- i18n/en.i18n.json | 2 ++ packages/rocketchat-ui-account/account/accountProfile.coffee | 2 +- packages/rocketchat-ui-account/account/accountProfile.html | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index b694485e80e..9958a1da2ec 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -274,6 +274,8 @@ "Login_with" : "Login with %s", "login_with" : "Or login directly with", "Logout" : "Logout", + "Logout_Others" : "Logout Others", + "Logged_out_of_other_clients_successfully" : "Logged out of other clients successfully", "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", "Markdown_Headers" : "Markdown Headers", diff --git a/packages/rocketchat-ui-account/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee index f9f2bba86ac..8895b85c344 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.coffee +++ b/packages/rocketchat-ui-account/account/accountProfile.coffee @@ -111,4 +111,4 @@ Template.accountProfile.events if error toastr.error error.reason else - toastr.success t('Logged out of other clients successfully') + 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 98751efcc26..b407102a772 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.html +++ b/packages/rocketchat-ui-account/account/accountProfile.html @@ -60,7 +60,7 @@ <button class="button"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> </div> <div class="logoutOthers"> - <button class="button">Logout Others</button> + <button class="button">{{_ "Logout_Others"}}</button> </div> </div> </div> -- GitLab From b5e40c34f817f5159d8ed3205aaea1892331413c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 13 Jan 2016 15:35:12 -0200 Subject: [PATCH 1192/1338] Fixes #1360 --- server/lib/accounts.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index cc51761cb35..061af1ad935 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 -- GitLab From 3f75e8bb2e066f1d678825b358343eac295da455 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 13 Jan 2016 15:41:44 -0200 Subject: [PATCH 1193/1338] Fixes #1445 - Display burger icon on History page --- packages/rocketchat-ui/views/app/privateHistory.html | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-ui/views/app/privateHistory.html b/packages/rocketchat-ui/views/app/privateHistory.html index fd8d6caa3a4..0d0acc27482 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> -- GitLab From 65779a43fb6ff955d07bd3f79daafa3b2130625d Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 16:31:38 -0200 Subject: [PATCH 1194/1338] using default values instead of integration data --- .../server/processWebhookMessage.js | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-integrations/server/processWebhookMessage.js b/packages/rocketchat-integrations/server/processWebhookMessage.js index 5b1938080ac..fa3607d11ac 100644 --- a/packages/rocketchat-integrations/server/processWebhookMessage.js +++ b/packages/rocketchat-integrations/server/processWebhookMessage.js @@ -1,7 +1,16 @@ -this.processWebhookMessage = function(integration, messageObj, user) { +this.processWebhookMessage = function(messageObj, user, defaultValues) { var attachment, channel, channelType, i, len, message, ref, rid, room, roomUser; - channel = messageObj.channel || integration.channel; + if (!defaultValues) { + defaultValues = { + channel: '', + alias: '', + avatar: '', + emoji: '' + }; + } + + channel = messageObj.channel || defaultValues.channel; channelType = channel[0]; @@ -73,13 +82,11 @@ this.processWebhookMessage = function(integration, messageObj, user) { } message = { - alias: messageObj.username || messageObj.alias || integration.alias, + alias: messageObj.username || messageObj.alias || defaultValues.alias, msg: _.trim(messageObj.text || messageObj.msg || ''), attachments: messageObj.attachments, parseUrls: false, - bot: { - i: integration._id - }, + bot: messageObj.bot, groupable: false }; @@ -87,10 +94,10 @@ this.processWebhookMessage = function(integration, messageObj, user) { 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 (integration.avatar != null) { - message.avatar = integration.avatar; - } else if (integration.emoji != null) { - message.emoji = integration.emoji; + } else if (defaultValues.avatar != null) { + message.avatar = defaultValues.avatar; + } else if (defaultValues.emoji != null) { + message.emoji = defaultValues.emoji; } if (_.isArray(message.attachments)) { -- GitLab From b9545bb11366061e5e92030944bfe10464e4053f Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 16:32:15 -0200 Subject: [PATCH 1195/1338] moved response logic outside of processWebhookMessage --- packages/rocketchat-integrations/package.js | 1 + .../server/api/api.coffee | 17 +++++++++- .../server/processWebhookMessage.js | 31 +++---------------- .../server/triggers.coffee | 19 ++++++++++-- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index babf2fc8074..f5ce2880e3e 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -14,6 +14,7 @@ Package.onUse(function(api) { 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'); diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 8315f795f58..d98040a43e3 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -22,7 +22,22 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, integration = RocketChat.models.Integrations.findOne(@urlParams.integrationId) user = RocketChat.models.Users.findOne(@userId) - return processWebhookMessage integration, @bodyParams, user + @bodyParams.bot = + i: integration._id + + defaultValues = + channel: integration.channel + alias: integration.alias + avatar: integration.avatar + emoji: integration.emoji + + try + if processWebhookMessage @bodyParams, user, defaultValues + return RocketChat.API.v1.success() + else + return RocketChat.API.v1.failure 'unknown-error' + catch e + return RocketChat.API.v1.failure e.error createIntegration = (options, user) -> diff --git a/packages/rocketchat-integrations/server/processWebhookMessage.js b/packages/rocketchat-integrations/server/processWebhookMessage.js index fa3607d11ac..95a39510d12 100644 --- a/packages/rocketchat-integrations/server/processWebhookMessage.js +++ b/packages/rocketchat-integrations/server/processWebhookMessage.js @@ -28,13 +28,7 @@ this.processWebhookMessage = function(messageObj, user, defaultValues) { ] }); if (room == null) { - return { - statusCode: 400, - body: { - success: false, - error: 'invalid-channel' - } - }; + throw new Meteor.Error('invalid-channel'); } rid = room._id; if (room.t === 'c') { @@ -54,13 +48,7 @@ this.processWebhookMessage = function(messageObj, user, defaultValues) { ] }); if (roomUser == null) { - return { - statusCode: 400, - body: { - success: false, - error: 'invalid-channel' - } - }; + throw new Meteor.Error('invalid-channel'); } rid = [user._id, roomUser._id].sort().join(''); room = RocketChat.models.Rooms.findOne(rid); @@ -72,13 +60,7 @@ this.processWebhookMessage = function(messageObj, user, defaultValues) { } break; default: - return { - statusCode: 400, - body: { - success: false, - error: 'invalid-channel-type' - } - }; + throw new Meteor.Error('invalid-channel-type'); } message = { @@ -113,10 +95,5 @@ this.processWebhookMessage = function(messageObj, user, defaultValues) { RocketChat.sendMessage(user, message, room, {}); - return { - statusCode: 200, - body: { - success: true - } - }; + return true; }; diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index caa9bc23cd8..27b71484847 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -65,9 +65,22 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> else if result?.statusCode is 200 and (result.data?.text? or result.data?.attachments?) user = RocketChat.models.Users.findOneByUsername(trigger.username) - if result.data?.text? or result.data?.attachments? - return processWebhookMessage trigger, result.data, user - + result.data.bot = + i: trigger._id + + defaultValues = + channel: trigger.channel + alias: trigger.alias + avatar: trigger.avatar + emoji: trigger.emoji + + try + if processWebhookMessage result.data, user, defaultValues + return RocketChat.API.v1.success() + else + return RocketChat.API.v1.failure 'unknown-error' + catch e + return RocketChat.API.v1.failure e.error ExecuteTrigger = (trigger, message, room) -> for url in trigger.urls -- GitLab From 841656b5060a002f6b5c89059668413ca1b780f3 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 16:56:43 -0200 Subject: [PATCH 1196/1338] improved processWebhookMessage return --- packages/rocketchat-integrations/server/api/api.coffee | 8 +++++--- .../server/processWebhookMessage.js | 7 +++++-- packages/rocketchat-integrations/server/triggers.coffee | 8 +++++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index d98040a43e3..98e926b07de 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -32,10 +32,12 @@ Api.addRoute ':integrationId/:userId/:token', authRequired: true, emoji: integration.emoji try - if processWebhookMessage @bodyParams, user, defaultValues - return RocketChat.API.v1.success() - else + 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 diff --git a/packages/rocketchat-integrations/server/processWebhookMessage.js b/packages/rocketchat-integrations/server/processWebhookMessage.js index 95a39510d12..ee684f4d59a 100644 --- a/packages/rocketchat-integrations/server/processWebhookMessage.js +++ b/packages/rocketchat-integrations/server/processWebhookMessage.js @@ -93,7 +93,10 @@ this.processWebhookMessage = function(messageObj, user, defaultValues) { } } - RocketChat.sendMessage(user, message, room, {}); + var messageReturn = RocketChat.sendMessage(user, message, room, {}); - return true; + return { + channel: channel, + message: messageReturn + } }; diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 27b71484847..72fae25524a 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -75,10 +75,12 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> emoji: trigger.emoji try - if processWebhookMessage result.data, user, defaultValues - return RocketChat.API.v1.success() - else + 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 -- GitLab From 6092fc516c26918a8ec20b738df17561ea45976f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Wed, 13 Jan 2016 16:56:50 -0200 Subject: [PATCH 1197/1338] Fixes a bug with search results, where sometimes cog wasn't displayed. --- .../flex-tab/tabs/messageSearch.coffee | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee index 633e4e2e846..0d3113623d8 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee @@ -53,13 +53,12 @@ Template.messageSearch.events message_id = $(e.currentTarget).closest('.message').attr('id') $('.message-dropdown:visible').hide() $(".search-messages-list \##{message_id} .message-dropdown").remove() - message = Blaze.getData($("\.search-messages-list ##{message_id}")?[0])?._arguments?[1] - if message - 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() + 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 -- GitLab From 5b93937fb81034053686d562296c75853a7bb809 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 16:56:54 -0200 Subject: [PATCH 1198/1338] using processWebhookMessage on V1 APIs --- packages/rocketchat-api/server/routes.coffee | 75 +++----------------- 1 file changed, 11 insertions(+), 64 deletions(-) diff --git a/packages/rocketchat-api/server/routes.coffee b/packages/rocketchat-api/server/routes.coffee index b7cafb17220..16a3efc14ae 100644 --- a/packages/rocketchat-api/server/routes.coffee +++ b/packages/rocketchat-api/server/routes.coffee @@ -54,74 +54,21 @@ RocketChat.API.v1.addRoute 'chat.messageExamples', authRequired: true, # Send Channel Message RocketChat.API.v1.addRoute 'chat.postMessage', authRequired: true, post: -> - channel = @bodyParams.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 RocketChat.API.v1.failure 'invalid-channel' - - rid = room._id - if room.t is 'c' - Meteor.runAsUser @userId, -> - Meteor.call 'joinRoom', room._id - - when '@' - roomUser = RocketChat.models.Users.findOne - $or: [ - {_id: channel} - {username: channel} - ] - - if not roomUser? - return RocketChat.API.v1.failure 'invalid-channel' - - rid = [@useId, roomUser._id].sort().join('') - room = RocketChat.models.Rooms.findOne(rid) - - if not room - Meteor.runAsUser @userId, -> - Meteor.call 'createDirectMessage', roomUser.username - room = RocketChat.models.Rooms.findOne(rid) - - else - return RocketChat.API.v1.failure 'invalid-channel-type' - - message = - alias: @bodyParams.username or @bodyParams.alias - msg: _.trim(@bodyParams.text or @bodyParams.msg or '') - attachments: @bodyParams.attachments - parseUrls: false - bot: + try + @bodyParams.bot = u: @userId - groupable: false - - if @bodyParams.icon_url? or @bodyParams.avatar? - message.avatar = @bodyParams.icon_url or @bodyParams.avatar - else if @bodyParams.icon_emoji? or @bodyParams.emoji? - message.emoji = @bodyParams.icon_emoji or @bodyParams.emoji - if _.isArray message.attachments - for attachment in message.attachments - if attachment.msg - attachment.text = _.trim(attachment.msg) - delete attachment.msg + messageReturn = processWebhookMessage @bodyParams, @user - message = RocketChat.sendMessage @user, message, room, {} - - return RocketChat.API.v1.success - ts: Date.now() - channel: channel - message: message + 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, -- GitLab From 486fd0a457976da69fad3630db35ab2130514adc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 13 Jan 2016 17:32:09 -0200 Subject: [PATCH 1199/1338] Improve the layout and info of the oauth popup --- i18n/en.i18n.json | 19 +++--- i18n/pt.i18n.json | 5 +- .../oauth/client/oauth2-client.coffee | 14 +++++ .../oauth/client/oauth2-client.html | 32 +++++++++- .../oauth/client/stylesheets/oauth2.less | 60 +++++++++++++++++-- .../oauth/server/oauth2-server.coffee | 9 +++ 6 files changed, 123 insertions(+), 16 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 98709220f04..7f16044d5ab 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -88,6 +88,7 @@ "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", @@ -316,8 +317,8 @@ "More_unreads" : "More unreads", "Msgs" : "Msgs", "multi" : "multi", - "Muted" : "Muted", "Mute_user" : "Mute user", + "Muted" : "Muted", "My_Account" : "My Account", "n_messages" : "%s messages", "Name" : "Name", @@ -401,11 +402,11 @@ "Registration_Succeeded" : "Registration Succeeded", "Remember_me" : "Remember me", "Remove" : "Remove", - "Removed" : "Removed", "Remove_Admin" : "Remove Admin", "Remove_as_moderator" : "Remove as moderator", "Remove_custom_oauth" : "Remove custom oauth", "Remove_from_room" : "Remove from room", + "Removed" : "Removed", "Reset" : "Reset", "Reset_password" : "Reset password", "Restart" : "Restart", @@ -453,9 +454,9 @@ "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", "Settings" : "Settings", "Settings_updated" : "Settings updated", - "Set_as_moderator" : "Set as moderator", "Should_be_a_URL_of_an_image" : "Should be a URL of an image.", "Should_exists_a_user_with_this_username" : "The user must already exist.", "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", @@ -512,8 +513,8 @@ "The_redirectUri_is_required" : "The redirectUri is required", "The_server_will_restart_in_s_seconds" : "The server will restart in %s seconds", "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_wont_be_able_to_type_in_s" : "The user won't be able to type in %s", "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", @@ -532,6 +533,10 @@ "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__removed_from__room_name__moderators" : "User __username__ removed from __room_name__ moderators", + "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_removed_as_a_moderator_by__user_by_" : "User <em>__username__</em> was removed as a moderator 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", @@ -556,14 +561,10 @@ "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__username__removed_from__room_name__moderators" : "User __username__ removed from __room_name__ moderators", "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", - "User__username__is_now_a_moderator_of__room_name_" : "User __username__ is now a moderator of __room_name__", - "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_removed_as_a_moderator_by__user_by_" : "User <em>__username__</em> was removed as a moderator by <em>__user_by__</em>", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", @@ -581,6 +582,7 @@ "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!", @@ -588,6 +590,7 @@ "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_are_logged_as" : "You are logged 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", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 737b5fe3a2e..9eee1bf3e72 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -66,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.", @@ -448,14 +449,16 @@ "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_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.", "Your_Open_Source_solution" : "Sua própria solução Open Source", "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" -} \ No newline at end of file +} diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee index b64a1fc4996..c2acdd899d1 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.coffee @@ -1,3 +1,5 @@ +# @ChatOAuthApps = new Meteor.Collection 'rocketchat_oauth_apps' + FlowRouter.route '/oauth/authorize', action: (params, queryParams) -> BlazeLayout.render 'main', @@ -19,12 +21,24 @@ FlowRouter.route '/oauth/error/: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) => diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html index 91ab42de7bd..7819c7ec48d 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html @@ -2,16 +2,42 @@ {{#if currentUser}} <div class="oauth-panel"> <form method="post" action="" role="form" class="{{#unless Template.subscriptionsReady}}hidden{{/unless}}"> - <h2>Authorize?</h2> + {{#if currentUser}} + <div class="user-info"> + <div class="thumb"> + {{> avatar username=currentUser.username}} + </div> + <div class="username"> + {{_ "You_are_logged_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"> - <button type="submit" class="button">Authorize</button> + <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... + {{_ "loading"}}... {{/unless}} </div> {{else}} diff --git a/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less index 1a047954699..e83fecf16ff 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less +++ b/packages/rocketchat-oauth2-server-config/oauth/client/stylesheets/oauth2.less @@ -9,12 +9,64 @@ top: 0px; bottom: 0px; + ul, li, ol { + list-style: initial; + } + + ul { + padding-left: 10px; + margin-left: 6px; + } + form { min-width: 400px; - text-align: center; - background-color: #fafafa; - border: 1px solid #eee; - border-radius: 6px; 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/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee index 58160488362..7fb13851d20 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee +++ b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee @@ -9,6 +9,15 @@ oauth2server = new OAuth2Server 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 -- GitLab From 76e07f2e481323ed709cf67e50f3837d36ce8938 Mon Sep 17 00:00:00 2001 From: alayek <arijit.layek1991@gmail.com> Date: Thu, 14 Jan 2016 01:14:39 +0530 Subject: [PATCH 1200/1338] Make button text more descriptive --- i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9958a1da2ec..a626091a29b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -274,7 +274,7 @@ "Login_with" : "Login with %s", "login_with" : "Or login directly with", "Logout" : "Logout", - "Logout_Others" : "Logout Others", + "Logout_Others" : "Logout From Other Logged In Locations", "Logged_out_of_other_clients_successfully" : "Logged out of other clients successfully", "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", -- GitLab From f4eb6edd47cbf4ec133ca555a4bf50bd091dd865 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 13 Jan 2016 18:56:31 -0200 Subject: [PATCH 1201/1338] Fix typo --- i18n/en.i18n.json | 2 +- i18n/pt.i18n.json | 2 +- .../oauth/client/oauth2-client.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 7f16044d5ab..7fb885ecd6e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -590,7 +590,7 @@ "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_are_logged_as" : "You are logged as", + "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", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 9eee1bf3e72..cff4290e37d 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -455,7 +455,7 @@ "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_as" : "Vocês está logado como", + "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/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html index 7819c7ec48d..ce886eca1ff 100644 --- a/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html +++ b/packages/rocketchat-oauth2-server-config/oauth/client/oauth2-client.html @@ -8,7 +8,7 @@ {{> avatar username=currentUser.username}} </div> <div class="username"> - {{_ "You_are_logged_as"}} + {{_ "You_are_logged_in_as"}} <h1>{{currentUser.username}}</h1> </div> </div> -- GitLab From 99d0c2817b47055824965bbab98e39071c32fa47 Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Wed, 13 Jan 2016 17:45:11 -0500 Subject: [PATCH 1202/1338] Allow SMTP server with no login Only require smtp host to be present. And include username and password if they are provided. --- .../server/startup/settingsOnLoadSMTP.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee index 8047dd24417..67dfa65a82d 100644 --- a/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee +++ b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee @@ -1,7 +1,10 @@ buildMailURL = _.debounce -> console.log 'Updating process.env.MAIL_URL' - if 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_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 -- GitLab From af4f6f4aa2f5165c4c9197395df6a9d13926942a Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Wed, 13 Jan 2016 18:00:27 -0500 Subject: [PATCH 1203/1338] Update to avoid confusion for new devs --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2abb716a596..e5ecdb3f500 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,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) @@ -252,7 +252,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) @@ -266,13 +266,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 -- GitLab From e5760ec88f7f954cd74bdf854c90d9dd802a59e7 Mon Sep 17 00:00:00 2001 From: Diego Sampaio <chinello@gmail.com> Date: Wed, 13 Jan 2016 22:01:13 -0200 Subject: [PATCH 1204/1338] updated SPK download link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5ecdb3f500..1c8172913e2 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Deploy your own Rocket.Chat server instantly on [Scalingo](https://scalingo.com) ## Sandstorm.io [](https://apps.sandstorm.io/app/vfnwptfn02ty21w715snyyczw0nqxkv3jvawcah10c6z7hj1hnu0) -_*Grab*_ the [Sandstorm SPK for the latest Rocket.Chat release](https://github.com/RocketChat/Rocket.Chat/releases/latest) 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) -- GitLab From a38b2dcb291c8a511819e464dc224ee6d842bdd7 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 14 Jan 2016 12:07:44 +0000 Subject: [PATCH 1205/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 3 +- i18n/de.i18n.json | 1 + i18n/en.i18n.json | 2 +- i18n/fi.i18n.json | 23 ++++++++++ i18n/he.i18n.json | 46 +++++++++++++++++++ i18n/hr.i18n.json | 1 + i18n/ko.i18n.json | 1 + i18n/nl.i18n.json | 1 + i18n/pl.i18n.json | 25 +++++++++- i18n/pt.i18n.json | 3 +- i18n/ro.i18n.json | 16 +++++++ .../i18n/ar.i18n.json | 1 - .../i18n/de.i18n.json | 1 - .../i18n/en.i18n.json | 1 - .../i18n/fi.i18n.json | 1 - .../i18n/hr.i18n.json | 1 - .../i18n/ko.i18n.json | 1 - .../i18n/nl.i18n.json | 1 - .../i18n/pl.i18n.json | 3 +- .../i18n/pt.i18n.json | 1 - .../i18n/ro.i18n.json | 1 - .../i18n/pl.i18n.json | 5 +- .../i18n/pl.i18n.json | 7 ++- .../rocketchat-livechat/app/i18n/pl.i18n.json | 4 +- .../rocketchat-livechat/i18n/pl.i18n.json | 6 ++- packages/rocketchat-mailer/i18n/pl.i18n.json | 1 + .../i18n/pl.i18n.json | 5 +- packages/rocketchat-theme/i18n/fi.i18n.json | 5 ++ 28 files changed, 148 insertions(+), 19 deletions(-) diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index fd1ca738d36..f685f669f11 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -224,6 +224,7 @@ "Remove" : "إزالة", "Remove_Admin" : "إزالة مدير", "Remove_from_room" : "إزالة من الغرÙØ©", + "Removed" : "تمت اﻹزالة", "Reset" : "إعادة التعيين", "Reset_password" : "إعادة تعيين كلمة السر", "Restart" : "إعادة التشغيل", @@ -290,7 +291,7 @@ "Submit" : "تقديم", "The_channel_name_is_required" : "اسم القناة مطلوب", "The_field_is_required" : "هذا الØقل %s مطلوب.", - "The_server_will_restart_in_s_seconds" : "سيتم إعادة تشغيل السيرÙر ÙÙŠ Ùªs ثانية", + "The_server_will_restart_in_s_seconds" : "سيتم إعادة تشغيل الخادم ÙÙŠ %s ثانية", "True" : "نعم", "Type_your_new_password" : "اكتب كلمة المرور الجديدة", "Unmute_user" : "إلغاء اسكات المستخدم", diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 6e9a76cccb4..2c7e3d237f9 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -401,6 +401,7 @@ "Remove_Admin" : "Admin 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", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 58783321491..4a44a7672df 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -604,4 +604,4 @@ "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 77a8acfa104..4cb23b2942e 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -88,6 +88,7 @@ "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", @@ -231,7 +232,9 @@ "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", @@ -274,6 +277,8 @@ "Login_with" : "Kirjaudu käyttäen %s", "login_with" : "tai kirjaudu suoraan", "Logout" : "Kirjaudu ulos", + "Logout_Others" : "Kirjaa ulos muut sessiot", + "Logged_out_of_other_clients_successfully" : "Muut sessiot kirjattu ulos onnistuneesti", "Make_Admin" : "Tee ylläpitäjäksi", "Mark_as_read" : "Merkitse luetuksi", "Markdown_Headers" : "Markdown otsikot", @@ -315,6 +320,7 @@ "Msgs" : "Viestit", "multi" : "monta", "Mute_user" : "Mykistä käyttäjä", + "Muted" : "Mykistetty", "My_Account" : "Käyttäjätilini", "n_messages" : "%s viestiä", "Name" : "Nimi", @@ -399,8 +405,10 @@ "Remember_me" : "Muista minut", "Remove" : "Poista", "Remove_Admin" : "Poista ylläpitäjyys", + "Remove_as_moderator" : "Poista moderaattoristatus", "Remove_custom_oauth" : "Poista mukautettu oauth", "Remove_from_room" : "Poista huoneesta", + "Removed" : "Poistettu", "Reset" : "Nollaa", "Reset_password" : "Nollaa salasana", "Restart" : "Käynnistä uudelleen", @@ -448,6 +456,7 @@ "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", "Settings" : "Asetukset", "Settings_updated" : "Asetukset päivitetty", "Should_be_a_URL_of_an_image" : "Kuvan URL-osoite", @@ -467,7 +476,9 @@ "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ä", @@ -504,6 +515,8 @@ "The_redirectUri_is_required" : "Ohjaus URI on pakollinen", "The_server_will_restart_in_s_seconds" : "Palvelin käynnistyy %s sekunnin kuluttua", "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ä", @@ -522,11 +535,17 @@ "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__removed_from__room_name__moderators" : "Käyttäjän __username__ moderaattoristatus __room_name__  on poistettu", + "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_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_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", @@ -565,11 +584,15 @@ "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_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.", diff --git a/i18n/he.i18n.json b/i18n/he.i18n.json index 4dceb39fb3d..fdd4e9b7b7f 100644 --- a/i18n/he.i18n.json +++ b/i18n/he.i18n.json @@ -4,14 +4,33 @@ "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" : "הטמעה", @@ -45,6 +64,7 @@ "Confirm_password" : "×ימות הססמה", "Contact" : "יצירת קשר", "Conversation" : "שיחה", + "Convert_Ascii_Emojis" : "המרת ASCII ל×ימוג׳י", "COPY_TO_CLIPBOARD" : "העתקה ללוח הגזירי×", "Create_new" : "יצירת חדש", "Create_new_direct_message_room" : "יצירת חדר הודעה ישירה חדש", @@ -54,6 +74,8 @@ "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‘", @@ -75,6 +97,7 @@ "General" : "כללי", "Get_to_know_the_team" : "היכרות ×¢× ×”×¦×•×•×ª שמ×חורי Rocket.Chat", "github_no_public_email" : "×ין לך ××£ כתובת דו×״ל פומבית בחשבון ×”Ö¾GitHub שלך", + "Has_more" : "יש עוד", "Have_your_own_chat" : "קח ×ת ×”×¢× ×™×™× ×™× ×œ×™×“×™×™×. ×”×פליקציה Rocket.Chat, ש", "Hide_room" : "להסתיר ×ת החדר", "History" : "היסטוריה", @@ -101,8 +124,13 @@ "Jump_to_recent_messages" : "מעבר להודעות ×”××—×¨×•× ×•×ª", "Language" : "שפה", "Language_Version" : "גרסה ×× ×’×œ×™×ª", + "Last_login" : "×›× ×™×¡×” ××—×¨×•× ×”", "Last_message" : "ההודעה ×”××—×¨×•× ×”", "Layout" : "פריסה", + "Layout_Home_Body" : "גוף עמוד הבית", + "Layout_Home_Title" : "כותרת עמוד הבית", + "Layout_Login_Header" : "כותרת ×›× ×™×¡×”", + "Layout_Login_Terms" : "×ª× ××™ ×›× ×™×¡×”", "Layout_Privacy_Policy" : "×ž×“×™× ×™×•×ª פרטיות", "Layout_Terms_of_Service" : "×ª× ××™ השירות", "LDAP" : "LDAP", @@ -112,18 +140,23 @@ "Leave_room" : "לעזוב ×ת החדר", "line" : "שורה", "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" : "שפה", @@ -152,6 +185,7 @@ "Notify_all_in_this_room" : "להודיע לכל מי שבחדר", "Online" : "מחובר", "Oops!" : "×ופס", + "Opt_out_statistics" : "×œ× ×œ×©×œ×•×— ×ת הסטטיסטיקה שלי ל־Rocket.Chat", "others" : "×חרי×", "Password" : "ססמה", "Password_changed_successfully" : "הססמה הוחלפה בהצלחה", @@ -167,6 +201,7 @@ "Profile_saved_successfully" : "הפרופיל × ×©×ž×¨ בהצלחה", "Proudly_developed" : "פותח בג×ווה ×¢× Meteor", "Push" : "דחיפה", + "Push_debug" : "× ×™×¤×•×™ שגי×ות", "Push_enable_gateway" : "הפעלת שער גישה", "Push_gateway" : "שער גישה", "Push_test_push" : "בדיקה", @@ -183,6 +218,7 @@ "Room" : "חדר", "Room_name_changed" : "×©× ×”×—×“×¨ ×©×•× ×” ל: <em>__room_name__</em> על ידי המשתמש <em>__user_by__</em>", "Room_name_changed_successfully" : "×©× ×”×—×“×¨ ×©×•× ×” בהצלחה", + "room_user_count" : "משתמשי %s", "Rooms" : "חדרי×", "SAML" : "SAML", "Save_changes" : "שמירת ×”×©×™× ×•×™×™×", @@ -201,21 +237,29 @@ "Send_confirmation_email" : "שליחת דו×״ל ×ימות", "Send_Message" : "שליחת הודעה", "Settings" : "הגדרות", + "Settings_updated" : "ההגדרות ×¢×•×“×›× ×•", "Showing_online_users" : "מציג <b>__total_online__</b> מתוך __total__ משתמשי×", "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" : "שליחה", "Success" : "הצליח", "The_channel_name_is_required" : "×©× ×”×¢×¨×•×¥ × ×“×¨×©", "The_field_is_required" : "השדה %s ×”×•× ×—×•×‘×”.", "The_server_will_restart_in_s_seconds" : "השרת יפעיל ×ת עצמו מחדש בעוד ", + "Upload_file_question" : "להעלות קובץ?", "Use_Emojis" : "שימוש ב×ימוג׳י", "Use_initials_avatar" : "שימוש בר×שי התיבות של ×©× ×”×ž×©×ª×ž×© שלך", "use_menu" : "× ×™×ª×Ÿ להשתמש בתפריט הצד כדי לגשת ×œ×—×“×¨×™× ×•×œ×¦×³××˜×™× ×©×œ×š.", @@ -223,6 +267,8 @@ "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_joined_channel_female" : "הצטרפה לערוץ.", "User_joined_channel_male" : "הצטרף לערוץ.", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index 6507783c957..c70aaf9488d 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -230,6 +230,7 @@ "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", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index f75a22a35ac..3804dedd2f5 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -326,6 +326,7 @@ "Remove" : "ì‚ì œ", "Remove_Admin" : "ê´€ë¦¬ìž ê¶Œí•œ ì œê±°", "Remove_custom_oauth" : "ì‚¬ìš©ìž ì •ì˜ OAuth ì œê±°", + "Removed" : "ì œê±°ë¨", "Reset_password" : "암호 ìž¬ì„¤ì •", "Restart" : "재시작", "Room" : "ë°©", diff --git a/i18n/nl.i18n.json b/i18n/nl.i18n.json index 15ab951691a..6a04b1d6d65 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -334,6 +334,7 @@ "Remove_Admin" : "Verwijder Admin", "Remove_custom_oauth" : "Verwijder aangepaste OAuth", "Remove_from_room" : "Verwijderen uit de kamer", + "Removed" : "Verwijderd", "Reset" : "Reset", "Reset_password" : "Reset Wachtwoord", "Restart" : "Herstart", diff --git a/i18n/pl.i18n.json b/i18n/pl.i18n.json index 42ccf79d1fd..59a316acc47 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -59,7 +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", + "Accounts_ShowFormLogin" : "Pokaż formularz logowania", "Activate" : "Aktywuj", "Add_custom_oauth" : "Dodaj wÅ‚asne OAuth", "Add_Members" : "Dodaj czÅ‚onków", @@ -74,6 +74,7 @@ "API_Embed" : "Osadź", "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?", @@ -86,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", @@ -110,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Ä™", @@ -141,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: ", @@ -166,13 +170,18 @@ "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", @@ -191,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", @@ -270,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>!", @@ -293,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Å‚", @@ -329,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", @@ -353,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", @@ -414,8 +433,11 @@ "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", @@ -468,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 cff4290e37d..e4af9ea8aba 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -318,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", @@ -461,4 +462,4 @@ "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source", "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" -} +} \ No newline at end of file diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index ab846688091..e13ee498a39 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -2,6 +2,7 @@ "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", @@ -86,6 +87,7 @@ "are_also_typing" : "tastează", "are_typing" : "tastează", "Are_you_sure" : "Sigur doriÈ›i asta?", + "Authorization_URL" : "URL de autorizare", "Auto_Load_Images" : "Auto-încarcă imagini", "Avatar_changed_successfully" : "Avatar schimbat cu succes", "Avatar_URL" : "URL Avatar ", @@ -313,6 +315,7 @@ "Msgs" : "Mesaje", "multi" : "multi", "Mute_user" : "Blochează mesajele utilizatorului", + "Muted" : "SilenÈ›ios", "My_Account" : "Contul meu", "n_messages" : "%s mesaje", "Name" : "Nume", @@ -397,8 +400,10 @@ "Remember_me" : "Èšine-mă minte", "Remove" : "Elimină", "Remove_Admin" : "EliminaÈ›i utilizator de tip Admin", + "Remove_as_moderator" : "EliminaÈ›i ca moderator", "Remove_custom_oauth" : "EliminaÈ›i OAuth personalizat", "Remove_from_room" : "EliminaÈ›i din cameră", + "Removed" : "Eliminat", "Reset" : "Reset", "Reset_password" : "Resetează parola", "Restart" : "Repornire", @@ -446,6 +451,7 @@ "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", "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.", @@ -502,6 +508,8 @@ "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", @@ -520,11 +528,17 @@ "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__removed_from__room_name__moderators" : "Utilizatorul __username__ a fost eliminat din moderatorii  __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_removed_as_a_moderator_by__user_by_" : "Utilizatorul <em>__username__</em> a fost scos ca moderator 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", @@ -567,6 +581,8 @@ "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_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", diff --git a/packages/rocketchat-authorization/i18n/ar.i18n.json b/packages/rocketchat-authorization/i18n/ar.i18n.json index 243fae72104..2c88e2e3004 100644 --- a/packages/rocketchat-authorization/i18n/ar.i18n.json +++ b/packages/rocketchat-authorization/i18n/ar.i18n.json @@ -2,7 +2,6 @@ "Add_user" : "إضاÙØ© مستخدم", "Back_to_permissions" : "العودة إلى التصريØات", "Permissions" : "التصريØات", - "Removed" : "تمت اﻹزالة", "Saving" : "جاري الØÙظ", "User_added" : "وأضا٠العضو <em>__user_added__</em>.", "User_not_found" : "لم يتم العثور على المستخدم", diff --git a/packages/rocketchat-authorization/i18n/de.i18n.json b/packages/rocketchat-authorization/i18n/de.i18n.json index 1ac87a82351..18f0ee3d481 100644 --- a/packages/rocketchat-authorization/i18n/de.i18n.json +++ b/packages/rocketchat-authorization/i18n/de.i18n.json @@ -5,7 +5,6 @@ "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", - "Removed" : "Entfernt", "Role" : "Rolle", "Role_Editing" : "Rolle bearbeiten", "Role_removed" : "Die Rolle wurde entfernt.", diff --git a/packages/rocketchat-authorization/i18n/en.i18n.json b/packages/rocketchat-authorization/i18n/en.i18n.json index 89f68bed6c9..1a2b7b7080a 100644 --- a/packages/rocketchat-authorization/i18n/en.i18n.json +++ b/packages/rocketchat-authorization/i18n/en.i18n.json @@ -5,7 +5,6 @@ "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", diff --git a/packages/rocketchat-authorization/i18n/fi.i18n.json b/packages/rocketchat-authorization/i18n/fi.i18n.json index 488fab46a3f..989d23b26ef 100644 --- a/packages/rocketchat-authorization/i18n/fi.i18n.json +++ b/packages/rocketchat-authorization/i18n/fi.i18n.json @@ -5,7 +5,6 @@ "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", diff --git a/packages/rocketchat-authorization/i18n/hr.i18n.json b/packages/rocketchat-authorization/i18n/hr.i18n.json index 22aa475a059..4bf37f94d0c 100644 --- a/packages/rocketchat-authorization/i18n/hr.i18n.json +++ b/packages/rocketchat-authorization/i18n/hr.i18n.json @@ -2,7 +2,6 @@ "Add_user" : "Dodaj korisnika", "Back_to_permissions" : "Povratak na dozvole", "Permissions" : "DopuÅ¡tenja", - "Removed" : "Uklonjeno", "Role" : "Uloga", "Saving" : "Spremanje", "There_are_no_users_in_this_role" : "Nema korisnika u toj ulozi.", diff --git a/packages/rocketchat-authorization/i18n/ko.i18n.json b/packages/rocketchat-authorization/i18n/ko.i18n.json index c0502addf31..d55848ec945 100644 --- a/packages/rocketchat-authorization/i18n/ko.i18n.json +++ b/packages/rocketchat-authorization/i18n/ko.i18n.json @@ -2,7 +2,6 @@ "Add_user" : "ì‚¬ìš©ìž ì¶”ê°€", "New_role" : "새로운 ì—í• ", "Permissions" : "권한", - "Removed" : "ì œê±°ë¨", "Saving" : "ì €ìž¥ 중", "User_added" : "ì‚¬ìš©ìž ì¶”ê°€í•¨.", "User_not_found" : "사용ìžë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ", diff --git a/packages/rocketchat-authorization/i18n/nl.i18n.json b/packages/rocketchat-authorization/i18n/nl.i18n.json index 5e8bfb8e955..5b85b6b0984 100644 --- a/packages/rocketchat-authorization/i18n/nl.i18n.json +++ b/packages/rocketchat-authorization/i18n/nl.i18n.json @@ -5,7 +5,6 @@ "Cannot_delete_role_because_its_in_use" : "Kan rol niet verwijderen omdat het in gebruik is", "New_role" : "Nieuwe rol", "Permissions" : "Machtigingen", - "Removed" : "Verwijderd", "Role" : "Rol", "Role_Editing" : "Rol bewerken", "Role_removed" : "Rol verwijderd", diff --git a/packages/rocketchat-authorization/i18n/pl.i18n.json b/packages/rocketchat-authorization/i18n/pl.i18n.json index 03956a989db..a022338c789 100644 --- a/packages/rocketchat-authorization/i18n/pl.i18n.json +++ b/packages/rocketchat-authorization/i18n/pl.i18n.json @@ -3,10 +3,11 @@ "Back_to_permissions" : "Powrót do uprawnieÅ„", "New_role" : "Nowa rola", "Permissions" : "Uprawnienia", - "Removed" : "UsuniÄ™to", "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" diff --git a/packages/rocketchat-authorization/i18n/pt.i18n.json b/packages/rocketchat-authorization/i18n/pt.i18n.json index e1152abd2c3..b0bb242a6c7 100644 --- a/packages/rocketchat-authorization/i18n/pt.i18n.json +++ b/packages/rocketchat-authorization/i18n/pt.i18n.json @@ -5,7 +5,6 @@ "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", diff --git a/packages/rocketchat-authorization/i18n/ro.i18n.json b/packages/rocketchat-authorization/i18n/ro.i18n.json index 10f94926353..30f9bb1036b 100644 --- a/packages/rocketchat-authorization/i18n/ro.i18n.json +++ b/packages/rocketchat-authorization/i18n/ro.i18n.json @@ -5,7 +5,6 @@ "Cannot_delete_role_because_its_in_use" : "Nu se poate È™terge rol, deoarece este în uz", "New_role" : "Rol nou", "Permissions" : "Permisiuni", - "Removed" : "Eliminat", "Role" : "Rol", "Role_Editing" : "Editare rol", "Role_removed" : "Rol eliminat", diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json index 6f31cf5a2e6..ba59cee84fe 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/pl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "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/i18n/pl.i18n.json b/packages/rocketchat-channel-settings/i18n/pl.i18n.json index 1258e187316..8200c8c1f59 100644 --- a/packages/rocketchat-channel-settings/i18n/pl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/pl.i18n.json @@ -1,7 +1,12 @@ { + "Archive_Unarchive" : "Przeniesienie do archiwum", "Channel" : "KanaÅ‚", "Private_Group" : "Grupa Prywatna", "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-livechat/app/i18n/pl.i18n.json b/packages/rocketchat-livechat/app/i18n/pl.i18n.json index 0c082b62370..f3e5e78e699 100644 --- a/packages/rocketchat-livechat/app/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/pl.i18n.json @@ -1,3 +1,5 @@ { - "Start_Chat" : "Rozpocznij czat" + "Skip" : "PomiÅ„", + "Start_Chat" : "Rozpocznij czat", + "Survey" : "Ankieta" } \ 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 ce4ab92fc99..9a1059cc5e7 100644 --- a/packages/rocketchat-livechat/i18n/pl.i18n.json +++ b/packages/rocketchat-livechat/i18n/pl.i18n.json @@ -1,9 +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", "Please_fill_a_username" : "ProszÄ™ wypeÅ‚nić nazwÄ™ użytkownika", - "Saved" : "Zapisano" + "Saved" : "Zapisano", + "Send_a_message" : "WyÅ›lij wiadomość", + "Theme" : "Motyw" } \ 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 292bea7592f..e44e595d29f 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-mentions-flextab/i18n/pl.i18n.json b/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json index 6f31cf5a2e6..4668ec4afa7 100644 --- a/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json +++ b/packages/rocketchat-mentions-flextab/i18n/pl.i18n.json @@ -1 +1,4 @@ -{ } \ No newline at end of file +{ + "Mentions" : "Wzmianki o tobie", + "No_mentions_found" : "Nie znaleziono wzmianek o tobie" +} \ 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 51b788b0eb7..2ed1a051ebc 100644 --- a/packages/rocketchat-theme/i18n/fi.i18n.json +++ b/packages/rocketchat-theme/i18n/fi.i18n.json @@ -1,9 +1,13 @@ { + "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", @@ -11,6 +15,7 @@ "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", -- GitLab From 9ea7597268c872096e6939e58c0ea790c21832a3 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 14 Jan 2016 13:46:45 -0200 Subject: [PATCH 1206/1338] Fixes suggested by @rodrigok on PR #1889 --- .../lib/updateModeratorsAndOwners.js | 33 +++++++++++++++++++ packages/rocketchat-ui/package.js | 1 + packages/rocketchat-ui/views/app/room.coffee | 31 ++--------------- 3 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 packages/rocketchat-ui/lib/updateModeratorsAndOwners.js diff --git a/packages/rocketchat-ui/lib/updateModeratorsAndOwners.js b/packages/rocketchat-ui/lib/updateModeratorsAndOwners.js new file mode 100644 index 00000000000..da6e309b975 --- /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 80e0abaa6f1..6badab97367 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -56,6 +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/updateModeratorsAndOwners.js', 'client'); // LIB CORDOVA api.addFiles('lib/cordova/facebook-login.coffee', 'client'); diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index 50eb391f669..a50f595194f 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -498,35 +498,8 @@ Template.room.onCreated -> return toastr.error error.reason for record in results - RoomModeratorsAndOwners.insert record - - RocketChat.callbacks.add('streamMessage', (msg) -> - if msg.t is '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 is 'moderator-removed' - user = Meteor.users.findOne({ username: msg.msg }) - moderator = RoomModeratorsAndOwners.findOne({ rid: msg.rid, "u._id": user._id, roles: 'moderator' }) - if moderator?.roles?.length is 1 and moderator.roles[0] is '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', (msg) -> - if msg.t is '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 is 'owner-removed' - user = Meteor.users.findOne({ username: msg.msg }) - owner = RoomModeratorsAndOwners.findOne({ rid: msg.rid, "u._id": user._id, roles: 'owner' }) - if owner?.roles?.length is 1 and owner.roles[0] is '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') + delete record._id + RoomModeratorsAndOwners.upsert { rid: record.rid, "u._id": record.u._id }, record Template.room.onDestroyed -> window.removeEventListener 'resize', this.onWindowResize -- GitLab From 6fd89bb3610015e9adf014e429d68da9b6ef719a Mon Sep 17 00:00:00 2001 From: Fahad Alduraibi <fadnix@gmail.com> Date: Thu, 14 Jan 2016 11:23:38 -0500 Subject: [PATCH 1207/1338] Prevent browsers from trying to validate the input field This will stop the browsers such as Firefox from trying to validate the input field since they are handled by the javascript. --- packages/rocketchat-ui-login/login/form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-login/login/form.html b/packages/rocketchat-ui-login/login/form.html index f6abf99633f..d84200d3914 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> -- GitLab From 0fdb6fcc184e4506329c9e4cd4016cae1a1d555a Mon Sep 17 00:00:00 2001 From: Brent <github@hl2central.net> Date: Thu, 14 Jan 2016 12:19:25 -0500 Subject: [PATCH 1208/1338] Update oembedVideoWidget removing static height --- packages/rocketchat-oembed/client/oembedVideoWidget.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/client/oembedVideoWidget.html b/packages/rocketchat-oembed/client/oembedVideoWidget.html index 6cb86b947ff..5377b5bf837 100644 --- a/packages/rocketchat-oembed/client/oembedVideoWidget.html +++ b/packages/rocketchat-oembed/client/oembedVideoWidget.html @@ -3,7 +3,7 @@ <blockquote> <div><a href="{{url}}">{{parsedUrl.host}}</a></div> <div>{{title}}</div> - <video controls class="inline-video" height="300"> + <video controls class="inline-video"> <source src="{{url}}" type="{{contentType}}"> Your browser does not support the video element. </video> -- GitLab From 83b19dbd6dbd83a3f13fbe4d2221878c3f26f9d8 Mon Sep 17 00:00:00 2001 From: Brent <github@hl2central.net> Date: Thu, 14 Jan 2016 12:21:38 -0500 Subject: [PATCH 1209/1338] Update messageAttachment removing static height --- .../client/messageAttachment.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-message-attachments/client/messageAttachment.html b/packages/rocketchat-message-attachments/client/messageAttachment.html index dc02f0c03c9..06fc30ea37c 100644 --- a/packages/rocketchat-message-attachments/client/messageAttachment.html +++ b/packages/rocketchat-message-attachments/client/messageAttachment.html @@ -73,7 +73,7 @@ {{#if video_url}} <div class="attachment-video"> - <video controls class="inline-video" height="300"> + <video controls class="inline-video"> <source src="{{fixCordova video_url}}" type="{{video_type}}"> Your browser does not support the video element. </video> -- GitLab From 07b1a2b422ba26a578da6a082e13864b6e078d26 Mon Sep 17 00:00:00 2001 From: Brent <github@hl2central.net> Date: Thu, 14 Jan 2016 12:23:27 -0500 Subject: [PATCH 1210/1338] Update base.less adding responsive video support This only impacts inline-videos, I did not alter code for responsive iframe embeds (YouTube). --- packages/rocketchat-theme/assets/stylesheets/base.less | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 1a323d7e600..a12d1e2eec8 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4285,7 +4285,10 @@ a.github-fork { } .inline-video { - max-height: 300px; + height: auto; + width: 100%; + max-width: 640px; + max-height: 380px; } .attention-message { -- GitLab From 5671a612ef04c18866ddf4f077e744dfa169e712 Mon Sep 17 00:00:00 2001 From: Brent <github@hl2central.net> Date: Thu, 14 Jan 2016 12:25:44 -0500 Subject: [PATCH 1211/1338] Updated bass.less inline-video max-width/height Altered to 512 x 288 (16:9) --- packages/rocketchat-theme/assets/stylesheets/base.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index a12d1e2eec8..c86a25b23ce 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4287,8 +4287,8 @@ a.github-fork { .inline-video { height: auto; width: 100%; - max-width: 640px; - max-height: 380px; + max-width: 512px; + max-height: 288px; } .attention-message { -- GitLab From 6610520c9d75c4a4f6a80d49b1da0c76ae69af59 Mon Sep 17 00:00:00 2001 From: Brent <github@hl2central.net> Date: Thu, 14 Jan 2016 16:56:19 -0500 Subject: [PATCH 1212/1338] Updated base.less to use 480x270 --- packages/rocketchat-theme/assets/stylesheets/base.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c86a25b23ce..e80db374a38 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4287,8 +4287,8 @@ a.github-fork { .inline-video { height: auto; width: 100%; - max-width: 512px; - max-height: 288px; + max-width: 480px; + max-height: 270px; } .attention-message { -- GitLab From e68dacdf10180f5a75b7a189936a2e5e0f73a1ac Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Fri, 15 Jan 2016 00:33:36 -0500 Subject: [PATCH 1213/1338] Add Raspberry Pi support announcement --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 1c8172913e2..731063addc3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ The Ultimate Open Source WebChat Platform * [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) @@ -110,6 +111,11 @@ Automated production-grade deployment in minutes, for RHEL / CentOS 7 or Ubuntu [](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) -- GitLab From 6e4c847f6b99579a7f2222f22041d6f1dab961cc Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 15 Jan 2016 13:10:46 -0200 Subject: [PATCH 1214/1338] Fix overlapping windows --- packages/rocketchat-lib/client/lib/openRoom.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 0d3a594583c..7e74d9fd949 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 -- GitLab From ffeeded2e708f7ae091d8bf7936e5082ce6345bf Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 15 Jan 2016 15:32:24 -0200 Subject: [PATCH 1215/1338] Close #1923; Prevent erros update outgoing webhooks with empty channel --- .../methods/outgoing/updateOutgoingIntegration.coffee | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee index 26610e89785..2e2d7afb2d1 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee @@ -17,7 +17,12 @@ Meteor.methods if integration.urls.length is 0 throw new Meteor.Error 'invalid_urls', '[methods] updateOutgoingIntegration -> urls is required' - if integration.channel?.trim() isnt '' and integration.channel[0] not in ['@', '#'] + 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 '' @@ -36,7 +41,7 @@ Meteor.methods throw new Meteor.Error 'invalid_integration', '[methods] updateOutgoingIntegration -> integration not found' - if integration.channel?.trim() isnt '' + if integration.channel? record = undefined channelType = integration.channel[0] channel = integration.channel.substr(1) -- GitLab From dbdc7e478d1e31ce065903c1f0241532b72e778d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 15 Jan 2016 16:33:14 -0200 Subject: [PATCH 1216/1338] Improve admin disbleQuery --- .../server/functions/settings.coffee | 3 +++ .../rocketchat-theme/assets/stylesheets/base.less | 9 ++++++++- packages/rocketchat-ui-admin/admin/admin.coffee | 15 ++++++++++++++- packages/rocketchat-ui-admin/admin/admin.html | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index fc9df927563..81b4099fe66 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -18,6 +18,9 @@ RocketChat.settings.add = (_id, value, options = {}) -> 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] options.processEnvValue = value diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index e80db374a38..cd454102936 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; } @@ -1807,6 +1808,12 @@ a.github-fork { } } + &[disabled] { + label { + color: #888; + } + } + input { color: #444; } diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index eeced50c745..b637991cd32 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -54,7 +54,20 @@ Template.admin.helpers if not @enableQuery? return {} - return if TempSettings.findOne(@enableQuery)? then {} else {disabled: 'disabled'} + 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') diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 07089f30947..195d38f296b 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -42,7 +42,7 @@ {{/if}} {{/if}} {{#each settings}} - <div class="input-line double-col {{#if changed}}setting-changed{{/if}}"> + <div class="input-line double-col {{#if changed}}setting-changed{{/if}}" {{isDisabled}}> <label>{{label}}</label> <div> {{#if $eq type 'string'}} -- GitLab From b83f07ad291c15cfade597fc7654c4f5dcad6758 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 15 Jan 2016 16:34:00 -0200 Subject: [PATCH 1217/1338] Close #1925; Add options to enable TLS on LDAP --- packages/rocketchat-ldap/config_server.coffee | 27 ++++++++++++++----- packages/rocketchat-ldap/ldap_server.js | 24 +++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index 1964aaf48e3..66e79c07854 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -2,13 +2,22 @@ MeteorWrapperLdapjs = Npm.require 'ldapjs' Meteor.startup -> 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_Url', 'ldap://', { type: 'string' , enableQuery: {_id: 'LDAP_Enable', value: true} } - @add 'LDAP_Port', '389', { type: 'string' , enableQuery: {_id: 'LDAP_Enable', value: true} } - @add 'LDAP_DN', '', { type: 'string' , public: true, enableQuery: {_id: 'LDAP_Enable', value: true} } - @add 'LDAP_Bind_Search', '', { type: 'string' , enableQuery: {_id: 'LDAP_Enable', value: true} } - @add 'LDAP_Sync_User_Data', false, { type: 'boolean' , enableQuery: {_id: 'LDAP_Enable', value: true} } - @add 'LDAP_Sync_User_Data_FieldMap', '{"cn":"name", "mail":"email"}', { type: 'string', enableQuery: {_id: 'LDAP_Enable', value: 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/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 197c21a9f98..6bc9aec83f1 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 @@ -68,6 +88,10 @@ LDAP.prototype.ldapCheck = function(options) { reconnect: false }); + if (LDAP_DEFAULTS.TLS == true) { + startTLS(client); + } + client.on('error', function() { console.log('Client Error:', arguments); }); -- GitLab From 3a2a6b59d1d1f57ce19e623911ea05ef1dd387ad Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 15 Jan 2016 17:52:42 -0200 Subject: [PATCH 1218/1338] Close #1768; Force SSL --- i18n/en.i18n.json | 23 ++++++------ packages/rocketchat-cors/cors.coffee | 35 +++++++++++++++++++ .../server/startup/settings.coffee | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3c09e15d689..332a6232ac2 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -182,6 +182,7 @@ "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", @@ -273,12 +274,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", - "Logged_out_of_other_clients_successfully" : "Logged out of other clients successfully", "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", "Markdown_Headers" : "Markdown Headers", @@ -458,10 +459,10 @@ "Send_Message" : "Send Message", "Send_your_JSON_payloads_to_this_URL" : "Send your JSON payloads to this URL.", "Set_as_moderator" : "Set as moderator", - "Settings" : "Settings", - "Settings_updated" : "Settings updated", "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" : "The user must already exist.", "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", @@ -539,9 +540,17 @@ "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_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__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_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_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", @@ -566,18 +575,10 @@ "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__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_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", - "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__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>", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index 38e411e857b..1f5e11632d9 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -47,3 +47,38 @@ 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) -> + if RocketChat.settings.get('Force_SSL') isnt true + 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 = url.parse(Meteor.absoluteUrl()).hostname + + host = host.replace(/:\d+$/, '') + + res.writeHead 302, + 'Location': 'https://' + host + req.url + res.end() + return + + +for oldListener in oldHttpServerListeners + httpServer.addListener 'request', oldListener diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 36d5778fee5..4f3bf96d8cb 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -77,6 +77,7 @@ RocketChat.settings.addGroup 'General', -> @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' } -- GitLab From 5c6af5aa3d4e5eeaa755f7f9bd6fb17fe6cb81bd Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 15 Jan 2016 18:03:50 -0200 Subject: [PATCH 1219/1338] Add i18n strings --- i18n/en.i18n.json | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3c09e15d689..d02c39a65b7 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -254,6 +254,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", @@ -261,10 +262,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", @@ -273,12 +276,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", - "Logged_out_of_other_clients_successfully" : "Logged out of other clients successfully", "Make_Admin" : "Make Admin", "Mark_as_read" : "Mark as read", "Markdown_Headers" : "Markdown Headers", @@ -458,10 +461,10 @@ "Send_Message" : "Send Message", "Send_your_JSON_payloads_to_this_URL" : "Send your JSON payloads to this URL.", "Set_as_moderator" : "Set as moderator", - "Settings" : "Settings", - "Settings_updated" : "Settings updated", "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" : "The user must already exist.", "Showing_archived_results" : "<p>Showing <b>%s</b> archived results</p>", @@ -539,9 +542,17 @@ "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_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__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_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_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", @@ -566,18 +577,10 @@ "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__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_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", - "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__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>", "Username" : "Username", "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", -- GitLab From 32b227f17a0d7768745dd053c949940126ee30fe Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 16 Jan 2016 10:36:47 -0200 Subject: [PATCH 1220/1338] Fix redirect exceptions --- packages/rocketchat-cors/cors.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index 1f5e11632d9..b7b557fbb82 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -56,7 +56,13 @@ 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 @@ -70,7 +76,7 @@ httpServer.addListener 'request', (req, res) -> 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 = url.parse(Meteor.absoluteUrl()).hostname + host = req.headers['host'] or url.parse(Meteor.absoluteUrl()).hostname host = host.replace(/:\d+$/, '') @@ -79,6 +85,4 @@ httpServer.addListener 'request', (req, res) -> res.end() return - -for oldListener in oldHttpServerListeners - httpServer.addListener 'request', oldListener + next() -- GitLab From d9cee1c1f146c464d68df2d6def5b6391cc27cf2 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 09:31:34 -0200 Subject: [PATCH 1221/1338] send correct content-type for livechat. fixes #1951 --- packages/rocketchat-livechat/livechat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/livechat.js b/packages/rocketchat-livechat/livechat.js index b33e6eb5909..1e854bd8f64 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'); -- GitLab From ff2432fee37c3b5a2bde53589db9a7765a2780a0 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 18 Jan 2016 12:09:26 +0000 Subject: [PATCH 1222/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 14 ++++++-- i18n/de.i18n.json | 33 ++++++++++++++++++- i18n/en.i18n.json | 7 +--- i18n/fi.i18n.json | 8 ++++- i18n/ro.i18n.json | 15 +++++++++ .../i18n/de.i18n.json | 2 +- .../rocketchat-livechat/i18n/ar.i18n.json | 1 + packages/rocketchat-mailer/i18n/ar.i18n.json | 2 ++ .../i18n/ar.i18n.json | 4 ++- .../i18n/ar.i18n.json | 1 + .../i18n/ar.i18n.json | 4 +-- 11 files changed, 76 insertions(+), 15 deletions(-) diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index f685f669f11..bc196b60c39 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -56,8 +56,10 @@ "close" : "غلق", "coming_soon" : "قريبا", "Commands" : "الأوامر", + "Compact_View" : "عرض متراص", "Confirm_password" : "تأكيد كلمة السر", "Conversation" : "Ù…Øادثة", + "Convert_Ascii_Emojis" : "Øول Ù…Øار٠الأسكي إلى اموجي", "COPY_TO_CLIPBOARD" : "نسخ", "Create_new" : "إنشاء جديد", "Create_new_direct_message_room" : "إنشاء غرÙØ© رسالة مباشرة جديدة", @@ -81,7 +83,7 @@ "Email_already_exists" : "البريد الالكتروني موجود مسبقا", "Email_or_username" : "البريد الإلكتروني أو اسم المستخدم", "Email_verified" : "تم التØقق من البريد الإلكتروني", - "Emoji" : "الرموز التعبيرية", + "Emoji" : "رمز تعبيري (اموجي)", "Enable_Desktop_Notifications" : "تÙعيل تنبيهات Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨", "Enter_info" : "ادخل المعلومات الخاصة بك", "Enter_to" : "ادخل الى", @@ -144,6 +146,7 @@ "Login_with" : "تسجيل الدخول بـ %s", "login_with" : "أو الدخول مباشرة بـ", "Logout" : "تسجيل خروج", + "Logout_Others" : "تسجيل الخروج من الأجهزة الأخرى", "Make_Admin" : "جعل مدير", "Mark_as_read" : "تعليم كمقروء", "Members" : "الأعضاء", @@ -200,6 +203,7 @@ "optional" : "اختياري", "others" : "آخرون", "Password" : "كلمة السر", + "Password_Change_Disabled" : "مدير الموقع منع تغيير كلمة السر", "Password_changed_successfully" : "تم تغيير كلمة السر بنجاØ", "People" : "الناس", "Please_enter_your_new_password_below" : "الرجاء إدخال كلمة المرور الجديدة أدناه:", @@ -240,6 +244,7 @@ "Rooms" : "الغرÙ", "S_new_messages_since_s" : "% رسالة جديدة منذ %", "Save_changes" : "ØÙظ التغيرات", + "Save_Mobile_Bandwidth" : "توÙير استهلاك الانترنت", "Search" : "بØØ«", "Search_Messages" : "بØØ« الرسائل", "Search_settings" : "إعدادات البØØ«", @@ -255,7 +260,7 @@ "Send_Message" : "أرسل رسالة", "Settings" : "اﻹعدادات", "Settings_updated" : "تم تØديث الإعدادات", - "Showing_online_users" : "عرض <b>__total_online__</b> of __total__ users", + "Showing_online_users" : "عرض <b>__total_online__</b>من __total__ عضو", "Showing_results" : "<p>يعرض <b>%s</b> نتائج</p>", "Silence" : "الصمت", "since_creation" : "منذ %s", @@ -299,7 +304,7 @@ "Unread_Rooms_Mode" : "وضع الغر٠الغير مقروءة", "Upload_file_question" : "تØميل الملÙØŸ", "Uploading_file" : "تØميل المل٠...", - "Use_Emojis" : "استخدام Emojis", + "Use_Emojis" : "استخدم الرموز التعبيرية (ايموجي)", "Use_initials_avatar" : "استخدم الأØر٠الأولى من اسم المستخدم", "use_menu" : "استخدم القائمة الجانبية للوصول إلى الغر٠الخاصة بك والمØادثات", "Use_service_avatar" : "استخدام %s الرمزية", @@ -331,11 +336,13 @@ "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" : "لقد قمنا بإرسال رسالة بريد إلكتروني لتأكيد تسجيلك. إذا لم يصلك البريد الإلكتروني قريبا، يرجى العودة والمØاولة مرة أخرى.", @@ -345,6 +352,7 @@ "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" : "لن تستطيع استرداد هذه الرسالة!", diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 2c7e3d237f9..ebca809b478 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -88,6 +88,7 @@ "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" : "Das Profilbild wurde erfolgreich geändert.", "Avatar_URL" : "URL des Profilbilds", @@ -231,7 +232,9 @@ "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", @@ -251,6 +254,7 @@ "LDAP" : "LDAP", "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", @@ -258,10 +262,12 @@ "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", @@ -270,10 +276,12 @@ "Loading..." : "Wird geladen ...", "Loading_more_from_history" : "Mehr Nachrichten aus dem Verlauf anzeigen", "Loading_suggestion" : "Vorschläge werden geladen...", + "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", + "Logout_Others" : "Von anderen Geräten abmelden", "Make_Admin" : "Benutzer zum Admin ernennen", "Mark_as_read" : "Als gelesen markieren", "Markdown_Headers" : "Markdown-Ãœberschriften", @@ -315,6 +323,7 @@ "Msgs" : "Nachrichten", "multi" : "mehrere", "Mute_user" : "Benutzern das Chatten verbieten", + "Muted" : "Stumm geschaltet", "My_Account" : "Mein Konto", "n_messages" : "%s Nachrichten", "Name" : "Name", @@ -348,7 +357,7 @@ "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. Wenn Sie weiterhin anonyme Statistiken an uns senden möchten, deaktivieren Sie bitte das Kontrollkästchen oben. Vielen Dank.", + "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", @@ -399,6 +408,8 @@ "Remember_me" : "Erinnere mich", "Remove" : "Entfernen", "Remove_Admin" : "Admin entfernen", + "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", @@ -449,6 +460,8 @@ "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" : "Die Einstellungen wurden aktualisiert.", "Should_be_a_URL_of_an_image" : "Dies soll die URL des Bildes sein.", @@ -468,7 +481,9 @@ "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", @@ -505,6 +520,8 @@ "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", @@ -523,11 +540,21 @@ "Use_this_username" : "Benutzen Sie folgenden Benutzernamen", "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.", @@ -566,11 +593,15 @@ "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" : "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. ", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 6478ba8b86a..75144642647 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -462,7 +462,6 @@ "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_moderator" : "Set as moderator", "Set_as_owner" : "Set as owner", "Settings" : "Settings", "Settings_updated" : "Settings updated", @@ -543,16 +542,12 @@ "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_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__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_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_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", @@ -619,4 +614,4 @@ "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 4cb23b2942e..83fdccc6647 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -273,12 +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", - "Logged_out_of_other_clients_successfully" : "Muut sessiot kirjattu ulos onnistuneesti", "Make_Admin" : "Tee ylläpitäjäksi", "Mark_as_read" : "Merkitse luetuksi", "Markdown_Headers" : "Markdown otsikot", @@ -406,6 +406,7 @@ "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", @@ -457,6 +458,7 @@ "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", @@ -536,9 +538,13 @@ "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", diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index e13ee498a39..15571b9486e 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -88,6 +88,7 @@ "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 ", @@ -231,7 +232,9 @@ "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", @@ -270,10 +273,12 @@ "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", @@ -401,6 +406,7 @@ "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", @@ -452,6 +458,7 @@ "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.", @@ -471,7 +478,9 @@ "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", @@ -529,9 +538,13 @@ "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", @@ -577,6 +590,7 @@ "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!", @@ -584,6 +598,7 @@ "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ă", diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json index f22508aa5a5..5e5f1ba3fb4 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/de.i18n.json @@ -6,7 +6,7 @@ "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" : "E-Mail-Nachrichten", + "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...", diff --git a/packages/rocketchat-livechat/i18n/ar.i18n.json b/packages/rocketchat-livechat/i18n/ar.i18n.json index 3685d82004b..5d22fd60b4c 100644 --- a/packages/rocketchat-livechat/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/i18n/ar.i18n.json @@ -12,5 +12,6 @@ "Please_fill_a_username" : "يرجى ملء اسم المستخدم", "Saved" : "تم الØÙظ", "Send_a_message" : "إرسال رسالة", + "Theme" : "سمات", "Time_in_seconds" : "الوقت بالثواني" } \ No newline at end of file diff --git a/packages/rocketchat-mailer/i18n/ar.i18n.json b/packages/rocketchat-mailer/i18n/ar.i18n.json index 7301eab2102..d93ff17e2ea 100644 --- a/packages/rocketchat-mailer/i18n/ar.i18n.json +++ b/packages/rocketchat-mailer/i18n/ar.i18n.json @@ -1,4 +1,6 @@ { + "Dry_run" : "تنÙيذ تجريبي", + "Dry_run_description" : "سيتم إرسال رسالة بريدية واØدة إلى Ù†Ùس العنوان الموجود ÙÙŠ خانة \"من\". تأكد من كون ذلك العنوان البريدي Ùعال", "Email_from" : "من", "Email_subject" : "الموضوع", "Send_email" : "إرسال البريد الإلكتروني", diff --git a/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-invite/i18n/ar.i18n.json index 6f31cf5a2e6..6912464b1a1 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-kick/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json index fb056a5215e..8a0f48baf89 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/ar.i18n.json @@ -1,3 +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-mute/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json index 36dd351ae48..093fc95cd56 100644 --- a/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json +++ b/packages/rocketchat-slashcommands-mute/i18n/ar.i18n.json @@ -1,4 +1,4 @@ { - "Mute_someone_in_room" : "اسكات شخص ÙÙŠ هذه الغرÙØ©", - "Unmute_someone_in_room" : "إلغاء اسكات شخص ÙÙŠ هذه الغرÙØ©" + "Mute_someone_in_room" : "إسكات شخص ÙÙŠ الغرÙØ©", + "Unmute_someone_in_room" : "إلغاء إسكات شخص ÙÙŠ هذه الغرÙØ©" } \ No newline at end of file -- GitLab From 45f9c676c0f4a452bb7485f7e9480644fb5d1974 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 10:28:13 -0200 Subject: [PATCH 1223/1338] Add connections status bar to login page --- packages/rocketchat-ui-master/master/main.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index 27828f551fc..68d5ba17aef 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -43,6 +43,9 @@ <template name="main"> {{#if subsReady}} {{#unless logged}} + <div class="connection-status"> + {{> status}} + </div> {{> loginLayout center="loginForm"}} {{else}} {{#unless hasUsername}} -- GitLab From ad989f85aff1f3de20fee0735dc63a647129fe72 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 10:29:07 -0200 Subject: [PATCH 1224/1338] Fallback LDAP login to local account if LDAP fails --- packages/rocketchat-ldap/ldap_server.js | 57 ++++++++++++++++--------- packages/rocketchat-ldap/package.js | 1 + 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 6bc9aec83f1..0e6d2b97fe5 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -76,26 +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, - reconnect: false - }); + // 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); - } + if (LDAP_DEFAULTS.TLS == true) { + startTLS(client); + } - client.on('error', function() { - console.log('Client Error:', arguments); - }); + 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 @@ -219,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(); }; @@ -234,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) { @@ -256,7 +256,22 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { var ldapResponse = ldapObj.ldapCheck(loginRequest); if (ldapResponse.error) { - throw new Meteor.Error("LDAP-login-error", ldapResponse.error); + 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 7c6b23a79d0..38720bb37dd 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -26,6 +26,7 @@ Package.onUse(function(api) { api.use('tap:i18n'); api.use('yasaricli:slugify'); api.use('coffeescript'); + api.use('sha'); // Client api.use('templating', 'client'); // Server -- GitLab From 8aebe83cf3074063a56a1b8edad7533a00de8a29 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 10:36:03 -0200 Subject: [PATCH 1225/1338] Add some logs --- packages/rocketchat-ldap/ldap_server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 0e6d2b97fe5..7cf5ff8c44f 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -256,6 +256,8 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { var ldapResponse = ldapObj.ldapCheck(loginRequest); if (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}; -- GitLab From c3fbfada7896bf00650e8219600d5f870c5fe541 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 10:36:24 -0200 Subject: [PATCH 1226/1338] Allow multi-line title on oembed --- packages/rocketchat-oembed/server/server.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 7696e42b770..6c30843dbfd 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) -> -- GitLab From 3f50123a944bc0161af73289e9eddf2ec392afa1 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 10:47:21 -0200 Subject: [PATCH 1227/1338] Sort room files by uploadedAt. Closes #1932 --- .../flex-tab/tabs/uploadedFilesList.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index 2d22e33107e..1f8b59a0cbf 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -2,7 +2,7 @@ roomFiles = new Mongo.Collection 'room_files' Template.uploadedFilesList.helpers files: -> - return roomFiles.find({ rid: @rid }).fetch() + return roomFiles.find({ rid: @rid }, { sort: {uploadedAt : -1} }).fetch() hasFiles: -> return roomFiles.find({ rid: @rid }).count() > 0 -- GitLab From 3a82beb8ef46540199cfc69e1c9c7bfbda534f9f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 11:37:04 -0200 Subject: [PATCH 1228/1338] Fix audio-recorder not stoping. Closes #1941. --- packages/rocketchat-ui-message/message/messageBox.coffee | 1 - packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-ui-message/message/messageBox.coffee b/packages/rocketchat-ui-message/message/messageBox.coffee index dd9ae3c8d74..00f3cad3a06 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/lib/recorderjs/audioRecorder.coffee b/packages/rocketchat-ui/lib/recorderjs/audioRecorder.coffee index c2cad918796..013af2a24e5 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() -- GitLab From 26fd849adbbce6ccf20587d6fbc25e1ba0b0b53c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 13:31:16 -0200 Subject: [PATCH 1229/1338] Display time based on locale instead of using fixed 24h format --- .../app/client/views/message.coffee | 2 +- .../client/views/app/livechatAppearance.js | 12 ++++++------ .../flex-tab/tabs/userInfo.coffee | 2 +- .../rocketchat-ui-message/message/message.coffee | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index 1b49884bd82..87cc3d9164e 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/client/views/app/livechatAppearance.js b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js index a8415b6be65..94e56f6f9ca 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatAppearance.js +++ b/packages/rocketchat-livechat/client/views/app/livechatAppearance.js @@ -18,7 +18,7 @@ Template.livechatAppearance.helpers({ u: { username: 'guest' }, - time: moment(this.ts).format('HH:mm'), + time: moment(this.ts).format('LT'), date: moment(this.ts).format('LL'), body: 'Hello', sequential: null @@ -28,7 +28,7 @@ Template.livechatAppearance.helpers({ u: { username: 'rocketchat-agent' }, - time: moment(this.ts).format('HH:mm'), + time: moment(this.ts).format('LT'), date: moment(this.ts).format('LL'), body: 'Hey, what can I help you with?', sequential: null @@ -38,7 +38,7 @@ Template.livechatAppearance.helpers({ u: { username: 'guest' }, - time: moment(this.ts).format('HH:mm'), + time: moment(this.ts).format('LT'), date: moment(this.ts).format('LL'), body: 'I\'m looking for informations about your product.', sequential: null @@ -48,7 +48,7 @@ Template.livechatAppearance.helpers({ u: { username: 'rocketchat-agent' }, - time: moment(this.ts).format('HH:mm'), + 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 @@ -58,7 +58,7 @@ Template.livechatAppearance.helpers({ u: { username: 'guest' }, - time: moment(this.ts).format('HH:mm'), + time: moment(this.ts).format('LT'), date: moment(this.ts).format('LL'), body: 'Yay, thanks. That\'s awesome.', sequential: null @@ -68,7 +68,7 @@ Template.livechatAppearance.helpers({ u: { username: 'rocketchat-agent' }, - time: moment(this.ts).format('HH:mm'), + time: moment(this.ts).format('LT'), date: moment(this.ts).format('LL'), body: 'You\'re welcome.', sequential: null diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 0a8514faeb1..3c3dc4c6da3 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -31,7 +31,7 @@ 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')) diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index f3cbfedf32c..6295dd6b957 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -14,7 +14,7 @@ Template.message.helpers 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: -> @@ -32,7 +32,7 @@ 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, -- GitLab From eb4da933f3926e2acc635c14ebc468b40d365e8c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 13:52:59 -0200 Subject: [PATCH 1230/1338] Make oembed parse title in ungreedy form --- packages/rocketchat-oembed/server/server.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/server/server.coffee b/packages/rocketchat-oembed/server/server.coffee index 6c30843dbfd..95266e478ab 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>((.|\n)+)<\/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) -> -- GitLab From c6d1814d810af91499aa9b8c7ed7ea4fc97cc6cb Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 14:27:33 -0200 Subject: [PATCH 1231/1338] Remove toUpperCase from emojione popup config; Fixes #1955 --- .../message/popup/messagePopupEmoji.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupEmoji.coffee index 4f47569fd26..d50a31f2c23 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] -- GitLab From eca800582ad6fc9769149284803a124dd3720cb3 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 18 Jan 2016 14:54:54 -0200 Subject: [PATCH 1232/1338] version bump to 0.14.0 --- .sandstorm/sandstorm-pkgdef.capnp | 4 +- HISTORY.md | 49 +++++++++++++++++++++++++ packages/rocketchat-lib/rocketchat.info | 2 +- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index b3c374ef195..8efc4b1b3b2 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 9, # Increment this for every release. + appVersion = 10, # Increment this for every release. - appMarketingVersion = (defaultText = "0.13.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/HISTORY.md b/HISTORY.md index 2643ad63d78..9264452677d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,55 @@ - +## 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` diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index 66995195a75..37f939dff5b 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.13.0" + "version": "0.14.0" } -- GitLab From 134ed42360835f6a0d149525b854415fe4fa41d2 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 15:45:08 -0200 Subject: [PATCH 1233/1338] Allow changing e-mail; invalidates verification on e-mail change --- i18n/en.i18n.json | 2 ++ packages/rocketchat-lib/package.js | 3 +++ .../functions/checkEmailAvailability.coffee | 2 ++ .../server/functions/setEmail.coffee | 26 ++++++++++++++++++ .../server/functions/setUsername.coffee | 2 +- .../server/methods/setEmail.coffee | 27 +++++++++++++++++++ .../rocketchat-lib/server/models/Users.coffee | 8 ++++++ .../server/startup/settings.coffee | 1 + .../account/accountProfile.coffee | 16 ++++++++++- .../account/accountProfile.html | 16 ++++++++--- server/methods/saveUserProfile.coffee | 3 +++ 11 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee create mode 100644 packages/rocketchat-lib/server/functions/setEmail.coffee create mode 100644 packages/rocketchat-lib/server/methods/setEmail.coffee diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 75144642647..94ba211ceef 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -6,6 +6,7 @@ "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Allowed Domains List", "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains", + "Accounts_AllowEmailChange" : "Allow E-mail Change", "Accounts_AllowPasswordChange" : "Allow Password Change", "Accounts_AllowUserAvatarChange" : "Allow User Avatar Change", "Accounts_AllowUsernameChange" : "Allow Username Change", @@ -159,6 +160,7 @@ "E-mail" : "E-mail", "edited" : "edited", "Email_already_exists" : "Email already exists", + "Email_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of e-mail", "Email_or_username" : "Email or username", "Email_verified" : "Email verified", "Emoji" : "Emoji", diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 5f2639f86fd..ccaa8127c50 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -55,9 +55,11 @@ Package.onUse(function(api) { // SERVER FUNCTIONS api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); + api.addFiles('server/functions/checkEmailAvailability.coffee', 'server'); api.addFiles('server/functions/sendMessage.coffee', 'server'); api.addFiles('server/functions/settings.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); + api.addFiles('server/functions/setEmail.coffee', 'server'); api.addFiles('server/functions/Notifications.coffee', 'server'); // SERVER METHODS @@ -73,6 +75,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); + api.addFiles('server/methods/setEmail.coffee', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); api.addFiles('server/methods/restartServer.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee b/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee new file mode 100644 index 00000000000..fcdd7bdb237 --- /dev/null +++ b/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee @@ -0,0 +1,2 @@ +RocketChat.checkEmailAvailability = (email) -> + return not Meteor.users.findOne({ "emails.address": { $regex : new RegExp("^" + s.trim(email) + "$", "i") } }) diff --git a/packages/rocketchat-lib/server/functions/setEmail.coffee b/packages/rocketchat-lib/server/functions/setEmail.coffee new file mode 100644 index 00000000000..a947436d7a0 --- /dev/null +++ b/packages/rocketchat-lib/server/functions/setEmail.coffee @@ -0,0 +1,26 @@ +RocketChat._setEmail = (userId, email) -> + email = s.trim email + if not userId or not email + return false + + emailValidation = /^[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])?)*$/ + if not emailValidation.test email + return false + + user = RocketChat.models.Users.findOneById userId + + # User already has desired username, return + if user.emails?[0]?.address is email + return user + + # Check e-mail availability + unless RocketChat.checkEmailAvailability email + return false + + # Set new email + RocketChat.models.Users.setEmail user._id, email + user.email = email + return user + +RocketChat.setEmail = RocketChat.RateLimiter.limitFunction RocketChat._setEmail, 1, 60000, + 0: (userId) -> return not RocketChat.authz.hasPermission(userId, 'edit-other-user-info') # Administrators have permission to change others emails, so don't limit those diff --git a/packages/rocketchat-lib/server/functions/setUsername.coffee b/packages/rocketchat-lib/server/functions/setUsername.coffee index cee48c9cad4..0ce3accfbff 100644 --- a/packages/rocketchat-lib/server/functions/setUsername.coffee +++ b/packages/rocketchat-lib/server/functions/setUsername.coffee @@ -60,4 +60,4 @@ RocketChat._setUsername = (userId, username) -> return user RocketChat.setUsername = RocketChat.RateLimiter.limitFunction RocketChat._setUsername, 1, 60000, - 0: (userId) -> return true; return not RocketChat.authz.hasPermission(userId, 'edit-other-user-info') # Administrators have permission to change others usernames, so don't limit those + 0: (userId) -> return not RocketChat.authz.hasPermission(userId, 'edit-other-user-info') # Administrators have permission to change others usernames, so don't limit those diff --git a/packages/rocketchat-lib/server/methods/setEmail.coffee b/packages/rocketchat-lib/server/methods/setEmail.coffee new file mode 100644 index 00000000000..c4030c517cb --- /dev/null +++ b/packages/rocketchat-lib/server/methods/setEmail.coffee @@ -0,0 +1,27 @@ +Meteor.methods + setEmail: (email) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] setEmail -> Invalid user") + + user = Meteor.user() + + if not RocketChat.settings.get("Accounts_AllowEmailChange") + throw new Meteor.Error(403, "[methods] setEmail -> E-mail change not allowed") + + if user.emails?[0]?.address is email + return email + + emailValidation = /^[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])?)*$/ + if not emailValidation.test email + throw new Meteor.Error 'email-invalid', "#{email} is not a valid e-mail" + + if not RocketChat.checkEmailAvailability email + throw new Meteor.Error 'email-unavailable', "#{email} is already in use :(" + + unless RocketChat.setEmail user._id, email + throw new Meteor.Error 'could-not-change-email', "Could not change email" + + return email + +RocketChat.RateLimiter.limitMethod 'setEmail', 1, 1000, + userId: (userId) -> return true diff --git a/packages/rocketchat-lib/server/models/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index 9e9aaf502b3..67bc2c9a3b7 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -154,6 +154,14 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @update _id, update + setEmail: (_id, email) -> + update = + $set: + 'emails.0.address': email + 'emails.0.verified': false + + return @update _id, update + setName: (_id, name) -> update = $set: diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 4f3bf96d8cb..523b1fab60a 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -6,6 +6,7 @@ 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_AllowEmailChange', 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 } diff --git a/packages/rocketchat-ui-account/account/accountProfile.coffee b/packages/rocketchat-ui-account/account/accountProfile.coffee index 8895b85c344..301ff734aba 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.coffee +++ b/packages/rocketchat-ui-account/account/accountProfile.coffee @@ -15,9 +15,15 @@ Template.accountProfile.helpers username: -> return Meteor.user().username + email: -> + return Meteor.user().emails?[0]?.address + allowUsernameChange: -> return RocketChat.settings.get("Accounts_AllowUsernameChange") + allowEmailChange: -> + return RocketChat.settings.get("Accounts_AllowEmailChange") + usernameChangeDisabled: -> return t('Username_Change_Disabled') @@ -84,6 +90,14 @@ Template.accountProfile.onCreated -> else data.username = _.trim $('#username').val() + if _.trim $('#email').val() + if !RocketChat.settings.get("Accounts_AllowEmailChange") + toastr.error t('Email_Change_Disabled') + instance.clearForm() + return + else + data.email = _.trim $('#email').val() + Meteor.call 'saveUserProfile', data, (error, results) -> if results toastr.success t('Profile_saved_successfully') @@ -107,7 +121,7 @@ Template.accountProfile.events 'click .submit button': (e, t) -> t.save() 'click .logoutOthers button': (event, templateInstance) -> - Meteor.logoutOtherClients (error) -> + Meteor.logoutOtherClients (error) -> if error toastr.error error.reason else diff --git a/packages/rocketchat-ui-account/account/accountProfile.html b/packages/rocketchat-ui-account/account/accountProfile.html index b407102a772..cee25c23d20 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.html +++ b/packages/rocketchat-ui-account/account/accountProfile.html @@ -19,9 +19,19 @@ <label for="username">{{_ "Username"}}</label> <div> {{#if allowUsernameChange}} - <input type="text" name="username" id="username" placeholder="{{username}}" /> + <input type="text" name="username" id="username" placeholder="{{username}}" /> {{else}} - <input type="text" name="username" id="username" placeholder="{{username}}" disabled="disabled" title="{{usernameChangeDisabled}}" /> + <input type="text" name="username" id="username" placeholder="{{username}}" disabled="disabled" title="{{usernameChangeDisabled}}" /> + {{/if}} + </div> + </div> + <div class="input-line"> + <label for="email">{{_ "E-mail"}}</label> + <div> + {{#if allowEmailChange}} + <input type="text" name="email" id="email" placeholder="{{email}}" /> + {{else}} + <input type="text" name="email" id="email" placeholder="{{email}}" disabled="disabled" title="{{emailChangeDisabled}}" /> {{/if}} </div> </div> @@ -60,7 +70,7 @@ <button class="button"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button> </div> <div class="logoutOthers"> - <button class="button">{{_ "Logout_Others"}}</button> + <button class="button">{{_ "Logout_Others"}}</button> </div> </div> </div> diff --git a/server/methods/saveUserProfile.coffee b/server/methods/saveUserProfile.coffee index 46b39972fba..cf4697f1c05 100644 --- a/server/methods/saveUserProfile.coffee +++ b/server/methods/saveUserProfile.coffee @@ -16,6 +16,9 @@ Meteor.methods if settings.username? Meteor.call 'setUsername', settings.username + if settings.email? + Meteor.call 'setEmail', settings.email + profile = {} RocketChat.models.Users.setProfile Meteor.userId(), profile -- GitLab From 14aed06ebcda01e5d9300b32ca58ef2b149672a5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 16:17:59 -0200 Subject: [PATCH 1234/1338] Enable editing via admin / users --- packages/rocketchat-lib/server/methods/updateUser.coffee | 4 ++++ packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee | 1 + packages/rocketchat-ui-admin/admin/users/adminUserEdit.html | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/packages/rocketchat-lib/server/methods/updateUser.coffee b/packages/rocketchat-lib/server/methods/updateUser.coffee index 2416d3d1184..1e9ae054034 100644 --- a/packages/rocketchat-lib/server/methods/updateUser.coffee +++ b/packages/rocketchat-lib/server/methods/updateUser.coffee @@ -23,6 +23,10 @@ Meteor.methods Meteor.runAsUser userData._id, -> Meteor.call 'setUsername', userData.username + if userData.email + Meteor.runAsUser userData._id, -> + Meteor.call 'setEmail', userData.email + canEditUserPassword = RocketChat.authz.hasPermission( user._id, 'edit-other-user-password') if canEditUserPassword and userData.password.trim() Accounts.setPassword userData._id, userData.password.trim() diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee index aeb9352b155..20f62c26ff9 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.email = $("#email", ".edit-form").val() userData.password = $("#password", ".edit-form").val() unless userData._id and userData.name diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html index f1e620f95f9..8cacbfae9ca 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -13,6 +13,10 @@ <label for="username">{{_ "Username"}}</label> <input type="text" id="username" autocomplete="off" value="{{username}}"> </div> + <div class="input-line"> + <label for="email">{{_ "E-mail"}}</label> + <input type="text" id="email" autocomplete="off" value="{{email}}"> + </div> {{#if hasPermission 'edit-other-user-password'}} <div class="input-line"> <label for="password">{{_ "Password"}}</label> -- GitLab From 4fdfcf713ddb0d5244f1936a0d14716928cfaa3b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 16:21:33 -0200 Subject: [PATCH 1235/1338] Add info to HISTORY.md --- HISTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.md b/HISTORY.md index 9264452677d..d662cf889e6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,6 @@ ## NEXT +- Ability to change email on account #1462 - ## 0.14.0, 2016-Jan-18 -- GitLab From e31bcdbc5861e183d4a701261cef16ea3d7319cb Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 18 Jan 2016 17:52:43 -0200 Subject: [PATCH 1236/1338] Add ability for admins to add user --- i18n/en.i18n.json | 2 ++ .../server/startup.coffee | 3 +++ .../admin/users/adminUserEdit.coffee | 7 ++++-- .../admin/users/adminUserEdit.html | 22 +++++++++++++++---- .../admin/users/adminUsers.coffee | 16 ++++++++++++-- .../flex-tab/flexTabBar.coffee | 15 +++++++------ 6 files changed, 50 insertions(+), 15 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 75144642647..bacfd3fded4 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -67,6 +67,7 @@ "Activate" : "Activate", "Add_custom_oauth" : "Add custom oauth", "Add_Members" : "Add Members", + "Add_User" : "Add User", "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", @@ -414,6 +415,7 @@ "Remove_custom_oauth" : "Remove custom oauth", "Remove_from_room" : "Remove from room", "Removed" : "Removed", + "Require_password_change" : "Require password change", "Reset" : "Reset", "Reset_password" : "Reset password", "Restart" : "Restart", diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 7febc408c37..5a418ef66a6 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -24,6 +24,9 @@ Meteor.startup -> { _id: 'view-full-other-user-info', roles : ['admin']} + { _id: 'add-user', + roles : ['admin']} + { _id: 'edit-other-user-info', roles : ['admin']} diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee index aeb9352b155..4706fbe11b1 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee @@ -1,6 +1,9 @@ Template.adminUserEdit.helpers - email: -> - return @emails?[0]?.address + canEditOrAdd: -> + return (Session.get('adminSelectedUser') and RocketChat.authz.hasAtLeastOnePermission('edit-other-user-info')) or (not Session.get('adminSelectedUser') and RocketChat.authz.hasAtLeastOnePermission('add-user')) + + user: -> + return Meteor.users.findOne(Session.get('adminSelectedUser')) Template.adminUserEdit.events 'click .cancel': (e, t) -> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html index f1e620f95f9..34b3d5b5d4a 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -1,23 +1,37 @@ <template name="adminUserEdit"> - {{#unless hasPermission 'edit-other-user-info'}} + {{#unless canEditOrAdd}} <p>You are not authorized to view this page.</p> {{else}} <div class="about clearfix"> <form class="edit-form"> - <h3>{{name}}</h3> + {{#if user}} + <h3>{{user.name}}</h3> + {{else}} + <h3>{{_ "Add_User"}}</h3> + {{/if}} <div class="input-line"> <label for="name">{{_ "Name"}}</label> - <input type="text" id="name" autocomplete="off" value="{{name}}"> + <input type="text" id="name" autocomplete="off" value="{{user.name}}"> </div> <div class="input-line"> <label for="username">{{_ "Username"}}</label> - <input type="text" id="username" autocomplete="off" value="{{username}}"> + <input type="text" id="username" autocomplete="off" value="{{user.username}}"> + </div> + <div class="input-line"> + <label for="email">{{_ "E-mail"}}</label> + <input type="text" id="email" autocomplete="off" value="{{user.emails.[0].address}}"> </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> + <div class="input-line"> + <label for="changePassword"> + <input type="checkbox" id="changePassword" value="1" checked="{{user.requirePasswordChange}}"> + {{_ "Require_password_change"}} + </label> + </div> {{/if}} </form> </div> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee index e09e66e2a09..077be9bc825 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee @@ -41,18 +41,30 @@ Template.adminUsers.onCreated -> groups: ['adminusers', 'adminusers-selected'], id: 'invite-user', i18nTitle: 'Invite_Users', - icon: 'icon-plus', + icon: 'icon-paper-plane', template: 'adminInviteUser', order: 1 }) + RocketChat.TabBar.addButton({ + groups: ['adminusers', 'adminusers-selected'], + id: 'add-user', + i18nTitle: 'Add_User', + icon: 'icon-plus', + template: 'adminUserEdit', + openClick: (e, t) -> + Session.set('adminSelectedUser') + return true + order: 2 + }) + RocketChat.TabBar.addButton({ groups: ['adminusers-selected'] id: 'admin-user-info', i18nTitle: 'User_Info', icon: 'icon-user', template: 'adminUserInfo', - order: 2 + order: 3 }) @autorun -> diff --git a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee index f308646ffbb..d4b4a4cdd16 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/flexTabBar.coffee @@ -17,14 +17,15 @@ Template.flexTabBar.events RocketChat.TabBar.closeFlex() $('.flex-tab').css('max-width', '') else - if @width? - $('.flex-tab').css('max-width', "#{@width}px") - else - $('.flex-tab').css('max-width', '') + if not @openClick? or @openClick(e,t) + if @width? + $('.flex-tab').css('max-width', "#{@width}px") + else + $('.flex-tab').css('max-width', '') - RocketChat.TabBar.setTemplate @template, -> - $('.flex-tab')?.find("input[type='text']:first")?.focus() - $('.flex-tab .content')?.scrollTop(0) + 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 -- GitLab From 4ffc4ee5db0caf1885974903c2e48af8032a47fc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 18:51:57 -0200 Subject: [PATCH 1237/1338] Log error when trigger url returns 500 --- packages/rocketchat-integrations/server/triggers.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 72fae25524a..bf9245606ab 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -54,6 +54,11 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> RocketChat.models.Integrations.remove _id: trigger._id return + if result.statusCode is 500 + console.log 'Request Error [500]', url + console.log result.content + return + if tries <= 6 # Try again in 0.1s, 1s, 10s, 1m40s, 16m40s, 2h46m40s and 27h46m40s Meteor.setTimeout -> -- GitLab From 19d37190c14c7deb81c99c4f171566d8fc24425b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 20:11:28 -0200 Subject: [PATCH 1238/1338] Allow pass room id to direct rooms --- .../server/processWebhookMessage.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-integrations/server/processWebhookMessage.js b/packages/rocketchat-integrations/server/processWebhookMessage.js index ee684f4d59a..78cbf1f63aa 100644 --- a/packages/rocketchat-integrations/server/processWebhookMessage.js +++ b/packages/rocketchat-integrations/server/processWebhookMessage.js @@ -46,12 +46,16 @@ this.processWebhookMessage = function(messageObj, user, defaultValues) { username: channel } ] + }) || {}; + rid = [user._id, roomUser._id].sort().join(''); + room = RocketChat.models.Rooms.findOne({ + _id: { + $in: [rid, channel] + } }); - if (roomUser == null) { + if (roomUser == null && room == 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); -- GitLab From ef5028e66d5dfd3d3d9e66cdca9d509f1c37ef29 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 20:12:08 -0200 Subject: [PATCH 1239/1338] Outgoing: Get the room from posted message to reply --- .../rocketchat-integrations/server/triggers.coffee | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 72fae25524a..659252cdca6 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -69,20 +69,17 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) -> i: trigger._id defaultValues = - channel: trigger.channel alias: trigger.alias avatar: trigger.avatar emoji: trigger.emoji - try - message = processWebhookMessage result.data, user, defaultValues + if room.t is 'd' + defaultValues.channel = '@'+room._id + else + defaultValues.channel = '#'+room._id - if not message? - return RocketChat.API.v1.failure 'unknown-error' + message = processWebhookMessage result.data, user, defaultValues - return RocketChat.API.v1.success() - catch e - return RocketChat.API.v1.failure e.error ExecuteTrigger = (trigger, message, room) -> for url in trigger.urls -- GitLab From 8ce91bf308f56b260c1693729ed81a4e7fe7a0d8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 18 Jan 2016 20:31:50 -0200 Subject: [PATCH 1240/1338] Change Meteor.absoluteUrl to force SSL if Force_SSL is true --- packages/rocketchat-cors/common.coffee | 3 +++ packages/rocketchat-cors/package.js | 1 + 2 files changed, 4 insertions(+) create mode 100644 packages/rocketchat-cors/common.coffee diff --git a/packages/rocketchat-cors/common.coffee b/packages/rocketchat-cors/common.coffee new file mode 100644 index 00000000000..0a3e8e19e0e --- /dev/null +++ b/packages/rocketchat-cors/common.coffee @@ -0,0 +1,3 @@ +Meteor.startup -> + RocketChat.settings.onload 'Force_SSL', (key, value) -> + Meteor.absoluteUrl.defaultOptions.secure = value diff --git a/packages/rocketchat-cors/package.js b/packages/rocketchat-cors/package.js index ee7a5bf3f28..d954b4953cb 100644 --- a/packages/rocketchat-cors/package.js +++ b/packages/rocketchat-cors/package.js @@ -14,6 +14,7 @@ Package.onUse(function(api) { ]); api.addFiles('cors.coffee', 'server'); + api.addFiles('common.coffee'); }); Package.onTest(function(api) { -- GitLab From 07141ff9d98e13408ba1600d1ba46a17c7ed7329 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 09:53:14 -0200 Subject: [PATCH 1241/1338] Escape regexp on checking email availability; change type of input to email --- .../server/functions/checkEmailAvailability.coffee | 2 +- packages/rocketchat-ui-account/account/accountProfile.html | 4 ++-- packages/rocketchat-ui-admin/admin/users/adminUserEdit.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee b/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee index fcdd7bdb237..e6c95d7702a 100644 --- a/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee +++ b/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee @@ -1,2 +1,2 @@ RocketChat.checkEmailAvailability = (email) -> - return not Meteor.users.findOne({ "emails.address": { $regex : new RegExp("^" + s.trim(email) + "$", "i") } }) + return not Meteor.users.findOne({ "emails.address": { $regex : new RegExp("^" + s.trim(s.escapeRegExp(email)) + "$", "i") } }) diff --git a/packages/rocketchat-ui-account/account/accountProfile.html b/packages/rocketchat-ui-account/account/accountProfile.html index cee25c23d20..1943323b2cd 100644 --- a/packages/rocketchat-ui-account/account/accountProfile.html +++ b/packages/rocketchat-ui-account/account/accountProfile.html @@ -29,9 +29,9 @@ <label for="email">{{_ "E-mail"}}</label> <div> {{#if allowEmailChange}} - <input type="text" name="email" id="email" placeholder="{{email}}" /> + <input type="email" name="email" id="email" placeholder="{{email}}" /> {{else}} - <input type="text" name="email" id="email" placeholder="{{email}}" disabled="disabled" title="{{emailChangeDisabled}}" /> + <input type="email" name="email" id="email" placeholder="{{email}}" disabled="disabled" title="{{emailChangeDisabled}}" /> {{/if}} </div> </div> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html index 8cacbfae9ca..86a01c07b97 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -15,7 +15,7 @@ </div> <div class="input-line"> <label for="email">{{_ "E-mail"}}</label> - <input type="text" id="email" autocomplete="off" value="{{email}}"> + <input type="email" id="email" autocomplete="off" value="{{email}}"> </div> {{#if hasPermission 'edit-other-user-password'}} <div class="input-line"> -- GitLab From 87e87331286a632bf85c033b1664e2b65ae4459f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 10:07:31 -0200 Subject: [PATCH 1242/1338] Fix indentation --- .../rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee index 67dfa65a82d..823460e03c1 100644 --- a/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee +++ b/packages/rocketchat-lib/server/startup/settingsOnLoadSMTP.coffee @@ -3,8 +3,8 @@ buildMailURL = _.debounce -> 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')) + 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 -- GitLab From 2519ad9604c9441eec2f360f7761ecb5cf41e4e1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 19 Jan 2016 11:01:11 -0200 Subject: [PATCH 1243/1338] Add logs of Force_SSL --- packages/rocketchat-cors/cors.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/rocketchat-cors/cors.coffee b/packages/rocketchat-cors/cors.coffee index b7b557fbb82..45f65548a51 100644 --- a/packages/rocketchat-cors/cors.coffee +++ b/packages/rocketchat-cors/cors.coffee @@ -75,6 +75,13 @@ httpServer.addListener 'request', (req, res) -> isSsl = req.connection.pair or (req.headers['x-forwarded-proto'] and req.headers['x-forwarded-proto'].indexOf('https') isnt -1) + if RocketChat?.debugLevel? and RocketChat.debugLevel is 'debug' + console.log 'req.url', req.url + console.log 'remoteAddress', remoteAddress + console.log 'isLocal', isLocal + console.log 'isSsl', isSsl + console.log 'req.headers', req.headers + if not isLocal and not isSsl host = req.headers['host'] or url.parse(Meteor.absoluteUrl()).hostname -- GitLab From cdf762270455b9fb0d351074798dd3f85b184dc5 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 19 Jan 2016 11:03:45 -0200 Subject: [PATCH 1244/1338] Try to fix LDAP exception --- packages/rocketchat-ldap/ldap_server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 7cf5ff8c44f..7a75abc7e58 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -98,7 +98,7 @@ LDAP.prototype.ldapCheck = function(options) { ldapAsyncFut.return({error: e}); }); - client.on('connect', function(e) { + client.on('connect', Meteor.bindEnvironment(function(e) { var bindSync = Meteor.wrapAsync(client.bind.bind(client)); // Slide @xyz.whatever from username if it was passed in @@ -222,7 +222,7 @@ LDAP.prototype.ldapCheck = function(options) { } else { bind(self.options.dn); } - }); + })); return ldapAsyncFut.wait(); }; -- GitLab From bc99ed1d51b83ea6e07f1df6872acbb4897d80e1 Mon Sep 17 00:00:00 2001 From: Omar Qunsul <omar.qunsul@expertiger.de> Date: Tue, 19 Jan 2016 16:29:01 +0100 Subject: [PATCH 1245/1338] Custom oAuth supporting json or plain content_types responses of the identity --- .../rocketchat-custom-oauth/custom_oauth_server.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-custom-oauth/custom_oauth_server.coffee b/packages/rocketchat-custom-oauth/custom_oauth_server.coffee index 039d41eb04f..c36bb47ba87 100644 --- a/packages/rocketchat-custom-oauth/custom_oauth_server.coffee +++ b/packages/rocketchat-custom-oauth/custom_oauth_server.coffee @@ -82,7 +82,10 @@ class CustomOAuth params: access_token: accessToken - return response.content + if response.data + return response.data + else + return JSON.parse response.content catch err error = new Error("Failed to fetch identity from #{@name} at #{@identityPath}. " + err.message) @@ -94,7 +97,7 @@ class CustomOAuth accessToken = self.getAccessToken query console.log 'at:', accessToken - identity = JSON.parse(self.getIdentity(accessToken)) + identity = self.getIdentity accessToken # Fix WordPress-like identities having 'ID' instead of 'id' if identity?.ID and not identity.id -- GitLab From 5443507df8c0879c201393e41b51694eb633f67f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 15:03:51 -0200 Subject: [PATCH 1246/1338] Add user and option to force user to change password --- client/routes/adminRouter.coffee | 2 + i18n/en.i18n.json | 1 + packages/rocketchat-lib/package.js | 4 +- .../functions/checkEmailAvailability.js | 3 ++ .../methods/clearRequestPasswordChange.js | 9 ++++ .../server/methods/insertOrUpdateUser.coffee | 53 +++++++++++++++++++ .../server/methods/updateUser.coffee | 30 ----------- .../rocketchat-lib/server/models/Users.coffee | 7 +++ .../assets/stylesheets/base.less | 22 +++++++- .../stylesheets/utils/_colors.import.less | 9 +++- .../admin/users/adminUserEdit.coffee | 42 ++++++++++----- .../admin/users/adminUserEdit.html | 2 +- .../admin/users/adminUserInfo.coffee | 14 ++--- .../admin/users/adminUsers.coffee | 9 ++-- .../rocketchat-ui-master/master/main.coffee | 3 ++ .../rocketchat-ui-master/master/main.html | 42 ++++++++------- packages/rocketchat-ui/package.js | 2 + .../views/app/requestPasswordChange.html | 19 +++++++ .../views/app/requestPasswordChange.js | 31 +++++++++++ server/publications/fullUserData.coffee | 1 + server/publications/userData.coffee | 1 + 21 files changed, 229 insertions(+), 77 deletions(-) create mode 100644 packages/rocketchat-lib/server/functions/checkEmailAvailability.js create mode 100644 packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js create mode 100644 packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee delete mode 100644 packages/rocketchat-lib/server/methods/updateUser.coffee create mode 100644 packages/rocketchat-ui/views/app/requestPasswordChange.html create mode 100644 packages/rocketchat-ui/views/app/requestPasswordChange.js diff --git a/client/routes/adminRouter.coffee b/client/routes/adminRouter.coffee index c226715e635..63b03b9d917 100644 --- a/client/routes/adminRouter.coffee +++ b/client/routes/adminRouter.coffee @@ -2,9 +2,11 @@ FlowRouter.route '/admin/users', name: 'admin-users' triggersExit: [ -> Session.set 'adminSelectedUser' + Session.set 'showUserInfo' ] action: -> Session.set 'adminSelectedUser' + Session.set 'showUserInfo' RocketChat.TabBar.showGroup 'adminusers' BlazeLayout.render 'main', {center: 'adminUsers'} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index bacfd3fded4..59d343dde70 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -610,6 +610,7 @@ "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_need_to_change_your_password" : "You need to change your password", "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.", diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 5f2639f86fd..fb17e59f92f 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -55,6 +55,7 @@ Package.onUse(function(api) { // SERVER FUNCTIONS api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); + api.addFiles('server/functions/checkEmailAvailability.js', 'server'); api.addFiles('server/functions/sendMessage.coffee', 'server'); api.addFiles('server/functions/settings.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); @@ -63,6 +64,7 @@ Package.onUse(function(api) { // SERVER METHODS api.addFiles('server/methods/addOAuthService.coffee', 'server'); api.addFiles('server/methods/checkRegistrationSecretURL.coffee', 'server'); + api.addFiles('server/methods/clearRequestPasswordChange.js', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); api.addFiles('server/methods/removeOAuthService.coffee', 'server'); api.addFiles('server/methods/robotMethods.coffee', 'server'); @@ -73,7 +75,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); - api.addFiles('server/methods/updateUser.coffee', 'server'); + api.addFiles('server/methods/insertOrUpdateUser.coffee', 'server'); api.addFiles('server/methods/restartServer.coffee', 'server'); // SERVER STARTUP diff --git a/packages/rocketchat-lib/server/functions/checkEmailAvailability.js b/packages/rocketchat-lib/server/functions/checkEmailAvailability.js new file mode 100644 index 00000000000..1176500aaf0 --- /dev/null +++ b/packages/rocketchat-lib/server/functions/checkEmailAvailability.js @@ -0,0 +1,3 @@ +RocketChat.checkEmailAvailability = function(email) { + return !Meteor.users.findOne({ "emails.address": { $regex : new RegExp("^" + s.trim(s.escapeRegExp(email)) + "$", "i") } }) +} diff --git a/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js b/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js new file mode 100644 index 00000000000..93c0d4dd770 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js @@ -0,0 +1,9 @@ +Meteor.methods({ + clearRequestPasswordChange: function() { + if (!Meteor.userId()) { + throw new Meteor.Error('invalid-user', "[methods] clearRequestPasswordChange -> Invalid user"); + } + + return RocketChat.models.Users.unsetRequirePasswordChange(Meteor.userId()); + } +}) \ No newline at end of file diff --git a/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee b/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee new file mode 100644 index 00000000000..5efe00eb1ef --- /dev/null +++ b/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee @@ -0,0 +1,53 @@ +Meteor.methods + insertOrUpdateUser: (userData) -> + if not Meteor.userId() + throw new Meteor.Error('invalid-user', "[methods] updateUser -> Invalid user") + + user = Meteor.user() + + canEditUser = RocketChat.authz.hasPermission( user._id, 'edit-other-user-info') + canAddUser = RocketChat.authz.hasPermission( user._id, 'add-user') + + if userData._id and user._id isnt userData._id and canEditUser isnt true + throw new Meteor.Error 'not-authorized', '[methods] updateUser -> Not authorized' + + if not userData._id and canAddUser isnt true + throw new Meteor.Error 'not-authorized', '[methods] updateUser -> Not authorized' + + unless userData.name + throw new Meteor.Error 'name-is-required', 'Name field is required' + + unless userData.username + throw new Meteor.Error 'user-name-is-required', 'Username field is required' + + if not userData._id and not userData.password + throw new Meteor.Error 'password-is-required', 'Password is required when adding a user' + + if not userData._id + if not RocketChat.checkUsernameAvailability userData.username + throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" + + if userData.email and not RocketChat.checkEmailAvailability userData.email + throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" + + # insert user + createUser = { username: userData.username, password: userData.password } + if userData.email + createUser.email = userData.email + + _id = Accounts.createUser(createUser) + if userData.requirePasswordChange + Meteor.users.update { _id: _id }, { $set: { name: userData.name, requirePasswordChange: userData.requirePasswordChange } } + + else + #update user + Meteor.users.update { _id: userData._id }, { $set: { name: userData.name, requirePasswordChange: userData.requirePasswordChange } } + + Meteor.runAsUser userData._id, -> + Meteor.call 'setUsername', userData.username + + 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/methods/updateUser.coffee b/packages/rocketchat-lib/server/methods/updateUser.coffee deleted file mode 100644 index 2416d3d1184..00000000000 --- a/packages/rocketchat-lib/server/methods/updateUser.coffee +++ /dev/null @@ -1,30 +0,0 @@ -Meteor.methods - updateUser: (userData) -> - if not Meteor.userId() - throw new Meteor.Error('invalid-user', "[methods] updateUser -> Invalid user") - - user = Meteor.user() - - canEditUserPermission = RocketChat.authz.hasPermission( user._id, 'edit-other-user-info') - if user._id isnt userData._id and canEditUserPermission isnt true - throw new Meteor.Error 'not-authorized', '[methods] updateUser -> Not authorized' - - unless userData._id - throw new Meteor.Error 'id-is-required', '[methods] updateUser -> User id is required' - - unless userData.name - throw new Meteor.Error 'name-is-required', 'Name field is required' - - unless userData.username - throw new Meteor.Error 'user-name-is-required', 'Username field is required' - - Meteor.users.update { _id: userData._id }, { $set: { name: userData.name } } - - Meteor.runAsUser userData._id, -> - Meteor.call 'setUsername', userData.username - - 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/Users.coffee b/packages/rocketchat-lib/server/models/Users.coffee index 9e9aaf502b3..2bba9aef91d 100644 --- a/packages/rocketchat-lib/server/models/Users.coffee +++ b/packages/rocketchat-lib/server/models/Users.coffee @@ -196,6 +196,13 @@ RocketChat.models.Users = new class extends RocketChat.models._Base return @update _id, update + unsetRequirePasswordChange: (_id) -> + update = + $unset: + "requirePasswordChange" : true + + return @update _id, update + setLanguage: (_id, language) -> update = $set: diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index cd454102936..00ac3f096aa 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -261,6 +261,23 @@ blockquote { margin-top: 20px; text-align: right; } + + &.request-password { + margin: 0 auto; + + fieldset { + margin-top: 20px; + + label { + display: block; + margin-top: 20px; + } + } + + .submit { + text-align: center; + } + } } .input-line { @@ -4299,7 +4316,6 @@ a.github-fork { } .attention-message { - color: white; padding-top: 50px; font-size: 24px; @@ -4308,6 +4324,10 @@ a.github-fork { margin-bottom: 20px; font-size: 40px; } + + span { + display: block; + } } .search-messages-list { diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index 13141a7836e..aed17bcef85 100755 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -100,6 +100,9 @@ blockquote { background-color: #DFDFDF; } } + &.request-password { + color: white; + } } .input-line { @@ -383,7 +386,7 @@ a.github-fork { border-color: #9f0030; background-color: #D30230; } - } + } } span.soon { color: #aaa; @@ -1208,3 +1211,7 @@ a.github-fork { } } } + +.attention-message { + color: white; +} \ No newline at end of file diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee index 4706fbe11b1..7c6748ebc02 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee @@ -17,23 +17,39 @@ Template.adminUserEdit.events t.save() Template.adminUserEdit.onCreated -> - instance = @ - - @cancel = -> + @cancel = => RocketChat.TabBar.setTemplate 'adminUserInfo' - @save = -> - userData = { _id: Template.currentData()._id } - userData.name = $("#name", ".edit-form").val() - userData.username = $("#username", ".edit-form").val() - userData.password = $("#password", ".edit-form").val() + @getUserData = => + userData = { _id: Session.get('adminSelectedUser') } + userData.name = s.trim(this.$("#name").val()) + userData.username = s.trim(this.$("#username").val()) + userData.email = s.trim(this.$("#email").val()) + userData.password = s.trim(this.$("#password").val()) + userData.requirePasswordChange = this.$("#changePassword:checked").length > 0 + return userData + + @validate = => + userData = this.getUserData() + + errors = [] + unless userData.name + errors.push 'Name' + unless userData.username + errors.push 'Username' + unless userData.email + errors.push 'E-mail' + + for error in errors + toastr.error(TAPi18n.__('The_field_is_required', TAPi18n.__(error))) + + return errors.length is 0 - unless userData._id and userData.name - toastr.error TAPi18n.__('The_field_is_required'), TAPi18n.__('Name') - else - Meteor.call 'updateUser', userData, (error, result) -> + @save = => + if this.validate() + Meteor.call 'insertOrUpdateUser', this.getUserData(), (error, result) => if result toastr.success t('User_updated_successfully') - instance.cancel() + this.cancel() if error 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 34b3d5b5d4a..002135df0ed 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -19,7 +19,7 @@ </div> <div class="input-line"> <label for="email">{{_ "E-mail"}}</label> - <input type="text" id="email" autocomplete="off" value="{{user.emails.[0].address}}"> + <input type="email" id="email" autocomplete="off" value="{{user.emails.[0].address}}"> </div> {{#if hasPermission 'edit-other-user-password'}} <div class="input-line"> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserInfo.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserInfo.coffee index bf27f68b74e..31bfe5626ec 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserInfo.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUserInfo.coffee @@ -19,7 +19,6 @@ Template.adminUserInfo.helpers return "UTC #{@utcOffset}" hasAdminRole: -> - console.log 'hasAdmin: ', RocketChat.authz.hasRole(@_id, 'admin') return RocketChat.authz.hasRole(@_id, 'admin') Template.adminUserInfo.events @@ -31,7 +30,7 @@ Template.adminUserInfo.events toastr.success t('User_has_been_deactivated') if error toastr.error error.reason - + 'click .activate': (e) -> e.stopPropagation() e.preventDefault() @@ -40,7 +39,7 @@ Template.adminUserInfo.events toastr.success t('User_has_been_activated') if error toastr.error error.reason - + 'click .make-admin': (e) -> e.stopPropagation() e.preventDefault() @@ -49,7 +48,7 @@ Template.adminUserInfo.events toastr.success t('User_is_now_an_admin') if error toastr.error error.reason - + 'click .remove-admin': (e) -> e.stopPropagation() e.preventDefault() @@ -74,18 +73,19 @@ Template.adminUserInfo.events closeOnConfirm: false html: false }, -> - swal + swal title: t('Deleted') text: t('User_has_been_deleted') type: 'success' timer: 2000 - showConfirmButton: false + showConfirmButton: false Meteor.call 'deleteUser', _id, (error, result) -> if error toastr.error error.reason Session.set 'adminSelectedUser' - + Session.set 'showUserInfo' + 'click .edit-user': (e) -> e.stopPropagation() e.preventDefault() diff --git a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee index 077be9bc825..d9634577365 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUsers.coffee @@ -9,8 +9,6 @@ Template.adminUsers.helpers return 'left' unless RocketChat.TabBar.isFlexOpen() userData: -> return Meteor.users.findOne Session.get 'adminSelectedUser' - userChannels: -> - return ChatSubscription.find({ "u._id": Session.get 'adminSelectedUser' }, { fields: { rid: 1, name: 1, t: 1 }, sort: { t: 1, name: 1 } }).fetch() isLoading: -> return 'btn-loading' unless Template.instance().ready?.get() hasMore: -> @@ -54,6 +52,7 @@ Template.adminUsers.onCreated -> template: 'adminUserEdit', openClick: (e, t) -> Session.set('adminSelectedUser') + Session.set('showUserInfo') return true order: 2 }) @@ -75,7 +74,9 @@ Template.adminUsers.onCreated -> @autorun -> if Session.get 'adminSelectedUser' - channelSubscription = instance.subscribe 'userChannels', Session.get 'adminSelectedUser' + instance.subscribe 'fullUserData', Session.get('adminSelectedUser'), 1 + Session.set 'showUserInfo', Session.get('adminSelectedUser') + RocketChat.TabBar.setData Meteor.users.findOne Session.get 'adminSelectedUser' RocketChat.TabBar.showGroup 'adminusers-selected' @@ -117,7 +118,7 @@ Template.adminUsers.events 'click .user-info': (e) -> e.preventDefault() Session.set 'adminSelectedUser', @_id - Session.set 'showUserInfo', Meteor.users.findOne(@_id)?.username or true + Session.set 'showUserInfo', Meteor.users.findOne(@_id)?.username RocketChat.TabBar.setTemplate 'adminUserInfo' RocketChat.TabBar.openFlex() diff --git a/packages/rocketchat-ui-master/master/main.coffee b/packages/rocketchat-ui-master/master/main.coffee index a5896523f8a..758a12a3399 100644 --- a/packages/rocketchat-ui-master/master/main.coffee +++ b/packages/rocketchat-ui-master/master/main.coffee @@ -143,6 +143,9 @@ Template.main.helpers console.log 'layout.helpers flexOpenedRTC2' if window.rocketDebug return 'layout2' if (Session.get('rtcLayoutmode') > 1) + requirePasswordChange: -> + return Meteor.user()?.requirePasswordChange is true + Template.main.events diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index 68d5ba17aef..8d8b9d369c0 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -51,27 +51,31 @@ {{#unless hasUsername}} {{> username}} {{else}} - {{> spotlight}} - {{> mobileMessageMenu}} - {{> videoCall overlay=true}} - <div id="user-card-popover"></div> - <div id="rocket-chat" class="menu-nav menu-closed"> - <div class="connection-status"> - {{> status}} - </div> - {{#unless modal}} - <div class="flex-tab-bar" role="toolbar"> - {{> flexTabBar}} + {{#if requirePasswordChange}} + {{> logoLayout render="requestPasswordChange"}} + {{else}} + {{> spotlight}} + {{> mobileMessageMenu}} + {{> videoCall overlay=true}} + <div id="user-card-popover"></div> + <div id="rocket-chat" class="menu-nav menu-closed"> + <div class="connection-status"> + {{> status}} + </div> + {{#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> - {{/unless}} - <div class="main-content {{flexOpened}} {{flexOpenedRTC1}} {{flexOpenedRTC2}} {{#if modal}}main-modal{{/if}}"> - {{> Template.dynamic template=center}} + {{#unless modal}} + {{> sideNav }} + {{/unless}} </div> - {{#unless modal}} - {{> sideNav }} - {{/unless}} - </div> - {{> audioNotification }} + {{> audioNotification }} + {{/if}} {{/unless}} {{/unless}} {{/if}} diff --git a/packages/rocketchat-ui/package.js b/packages/rocketchat-ui/package.js index 6badab97367..1cb447bc32b 100644 --- a/packages/rocketchat-ui/package.js +++ b/packages/rocketchat-ui/package.js @@ -85,6 +85,7 @@ Package.onUse(function(api) { api.addFiles('views/app/pageContainer.html', 'client'); api.addFiles('views/app/pageSettingsContainer.html', 'client'); api.addFiles('views/app/privateHistory.html', 'client'); + api.addFiles('views/app/requestPasswordChange.html', 'client'); api.addFiles('views/app/room.html', 'client'); api.addFiles('views/app/roomSearch.html', 'client'); api.addFiles('views/app/secretURL.html', 'client'); @@ -101,6 +102,7 @@ Package.onUse(function(api) { api.addFiles('views/app/burguer.coffee', 'client'); api.addFiles('views/app/home.coffee', 'client'); api.addFiles('views/app/privateHistory.coffee', 'client'); + api.addFiles('views/app/requestPasswordChange.js', 'client'); api.addFiles('views/app/room.coffee', 'client'); api.addFiles('views/app/roomSearch.coffee', 'client'); api.addFiles('views/app/secretURL.coffee', 'client'); diff --git a/packages/rocketchat-ui/views/app/requestPasswordChange.html b/packages/rocketchat-ui/views/app/requestPasswordChange.html new file mode 100644 index 00000000000..d07896e466b --- /dev/null +++ b/packages/rocketchat-ui/views/app/requestPasswordChange.html @@ -0,0 +1,19 @@ +<template name="requestPasswordChange"> + <div class="content"> + <div class="attention-message"> + <i class="icon-attention"></i> + <span>{{_ 'You_need_to_change_your_password'}}</span> + </div> + <div class="rocket-form request-password"> + <form> + <fieldset> + <label for="oldPassword">{{_ "Old_Password"}}</label><input type="password" name="oldPassword" id="oldPassword" /> + <label for="newPassword">{{_ "Password"}}</label><input type="password" name="newPassword" id="newPassword" /> + <div class="submit"> + <button type="submit" class="button save"><i class="icon-send"></i><span>{{_ "Save"}}</span></button> + </div> + </fieldset> + </form> + </div> + </div> +</template> diff --git a/packages/rocketchat-ui/views/app/requestPasswordChange.js b/packages/rocketchat-ui/views/app/requestPasswordChange.js new file mode 100644 index 00000000000..2b6eb1426cb --- /dev/null +++ b/packages/rocketchat-ui/views/app/requestPasswordChange.js @@ -0,0 +1,31 @@ +Template.requestPasswordChange.events({ + 'submit'(e, instance) { + e.preventDefault(); + oldPassword = s.trim(instance.$('#oldPassword').val()); + newPassword = s.trim(instance.$('#newPassword').val()); + instance.changePassword(oldPassword, newPassword); + } +}) + +Template.requestPasswordChange.onCreated(function() { + this.changePassword = function(oldPassword, newPassword) { + if (!oldPassword || !newPassword) { + toastr.warning(t('Old_and_new_password_required')); + } else { + Accounts.changePassword(oldPassword, newPassword, function(error) { + if(error) { + toastr.error(t('Incorrect_Password')); + } else { + Meteor.call('clearRequestPasswordChange', function() { + toastr.success(t('Password_changed_successfully')) + return true; + }); + } + }); + } + } +}) + +Template.requestPasswordChange.onRendered(function() { + this.$('#oldPassword').focus(); +}) \ No newline at end of file diff --git a/server/publications/fullUserData.coffee b/server/publications/fullUserData.coffee index 95173f5edb8..1fe73458955 100644 --- a/server/publications/fullUserData.coffee +++ b/server/publications/fullUserData.coffee @@ -18,6 +18,7 @@ Meteor.publish 'fullUserData', (filter, limit) -> active: 1 services: 1 roles : 1 + requirePasswordChange : 1 else limit = 1 diff --git a/server/publications/userData.coffee b/server/publications/userData.coffee index 6f493433681..1b9ea9e8a1f 100644 --- a/server/publications/userData.coffee +++ b/server/publications/userData.coffee @@ -16,3 +16,4 @@ Meteor.publish 'userData', -> defaultRoom: 1 'services.github.id': 1 'services.gitlab.id': 1 + requirePasswordChange: 1 -- GitLab From 725fa7680a2b32fd265334da0a4b4142ac14e08e Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Tue, 19 Jan 2016 15:21:49 -0200 Subject: [PATCH 1247/1338] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 731063addc3..3feb6070e37 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,7 @@ Emoji provided free by [Emoji One](http://emojione.com) Performance monitoring provided by [Kadira](https://kadira.io) +Hosting powered by [Rackspace](https://rackspace.com) # Donate -- GitLab From 6f49e8c4c096cd269575304698b2b394be6ecadf Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 15:53:22 -0200 Subject: [PATCH 1248/1338] Select user after inserting; old and new password must differ --- i18n/en.i18n.json | 2 ++ .../server/methods/insertOrUpdateUser.coffee | 7 ++++--- .../admin/users/adminUserEdit.coffee | 12 ++++++++++-- .../rocketchat-ui/views/app/requestPasswordChange.js | 2 ++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 59d343dde70..35bcd86fd25 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -353,6 +353,7 @@ "Notify_all_in_this_room" : "Notify all in this room", "OAuth_Application" : "OAuth Application", "OAuth_Applications" : "OAuth Applications", + "Old_and_new_password_must_be_different" : "The new password must be different from the old password.", "Old_and_new_password_required" : "You need to provide both old and new password for changing your password.", "Old_Password" : "Old Password", "Online" : "Online", @@ -552,6 +553,7 @@ "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_added_successfully" : "User added successfully", "User_Channels" : "User Channels", "User_has_been_activated" : "User has been activated", "User_has_been_deactivated" : "User has been deactivated", diff --git a/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee b/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee index 5efe00eb1ef..5823fcacf4c 100644 --- a/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee +++ b/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee @@ -25,10 +25,10 @@ Meteor.methods if not userData._id if not RocketChat.checkUsernameAvailability userData.username - throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" + throw new Meteor.Error 'username-unavailable', "#{userData.username} is already in use :(" if userData.email and not RocketChat.checkEmailAvailability userData.email - throw new Meteor.Error 'username-unavailable', "#{username} is already in use :(" + throw new Meteor.Error 'email-unavailable', "#{userData.email} is already in use :(" # insert user createUser = { username: userData.username, password: userData.password } @@ -39,6 +39,7 @@ Meteor.methods if userData.requirePasswordChange Meteor.users.update { _id: _id }, { $set: { name: userData.name, requirePasswordChange: userData.requirePasswordChange } } + return _id else #update user Meteor.users.update { _id: userData._id }, { $set: { name: userData.name, requirePasswordChange: userData.requirePasswordChange } } @@ -50,4 +51,4 @@ Meteor.methods if canEditUserPassword and userData.password.trim() Accounts.setPassword userData._id, userData.password.trim() - return true + return true diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee index 7c6748ebc02..efcaefd5b7f 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.coffee @@ -47,9 +47,17 @@ Template.adminUserEdit.onCreated -> @save = => if this.validate() - Meteor.call 'insertOrUpdateUser', this.getUserData(), (error, result) => + userData = this.getUserData() + Meteor.call 'insertOrUpdateUser', userData, (error, result) => if result - toastr.success t('User_updated_successfully') + if userData._id + toastr.success t('User_updated_successfully') + else + toastr.success t('User_added_successfully') + Session.set('adminSelectedUser', result); + Session.set('showUserInfo', result); + Meteor.subscribe 'fullUserData', userData.username, 1 + this.cancel() if error toastr.error error.reason diff --git a/packages/rocketchat-ui/views/app/requestPasswordChange.js b/packages/rocketchat-ui/views/app/requestPasswordChange.js index 2b6eb1426cb..3797ae72c46 100644 --- a/packages/rocketchat-ui/views/app/requestPasswordChange.js +++ b/packages/rocketchat-ui/views/app/requestPasswordChange.js @@ -11,6 +11,8 @@ Template.requestPasswordChange.onCreated(function() { this.changePassword = function(oldPassword, newPassword) { if (!oldPassword || !newPassword) { toastr.warning(t('Old_and_new_password_required')); + } else if (oldPassword === newPassword) { + toastr.warning(t('Old_and_new_password_must_be_different')); } else { Accounts.changePassword(oldPassword, newPassword, function(error) { if(error) { -- GitLab From 81deddc4b8fd0132e6d50f327d40f02f7db05a0b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 15:56:20 -0200 Subject: [PATCH 1249/1338] Amended history --- HISTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 9264452677d..e29a1d0cb25 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,7 @@ ## NEXT +- Added option for admins to manually add new users +- Added option for admin to require user to change password - ## 0.14.0, 2016-Jan-18 -- GitLab From ba6d5afa52739555dd3fee4ba444485671eac614 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 15:59:48 -0200 Subject: [PATCH 1250/1338] rename method --- packages/rocketchat-lib/package.js | 2 +- .../server/methods/clearRequestPasswordChange.js | 4 ++-- packages/rocketchat-ui/views/app/requestPasswordChange.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index fb17e59f92f..f29b4e8763d 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -64,7 +64,7 @@ Package.onUse(function(api) { // SERVER METHODS api.addFiles('server/methods/addOAuthService.coffee', 'server'); api.addFiles('server/methods/checkRegistrationSecretURL.coffee', 'server'); - api.addFiles('server/methods/clearRequestPasswordChange.js', 'server'); + api.addFiles('server/methods/clearRequirePasswordChange.js', 'server'); api.addFiles('server/methods/joinDefaultChannels.coffee', 'server'); api.addFiles('server/methods/removeOAuthService.coffee', 'server'); api.addFiles('server/methods/robotMethods.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js b/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js index 93c0d4dd770..715e236b5e5 100644 --- a/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js +++ b/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js @@ -1,7 +1,7 @@ Meteor.methods({ - clearRequestPasswordChange: function() { + clearRequirePasswordChange: function() { if (!Meteor.userId()) { - throw new Meteor.Error('invalid-user', "[methods] clearRequestPasswordChange -> Invalid user"); + throw new Meteor.Error('invalid-user', "[methods] clearRequirePasswordChange -> Invalid user"); } return RocketChat.models.Users.unsetRequirePasswordChange(Meteor.userId()); diff --git a/packages/rocketchat-ui/views/app/requestPasswordChange.js b/packages/rocketchat-ui/views/app/requestPasswordChange.js index 3797ae72c46..f78f8b4fb79 100644 --- a/packages/rocketchat-ui/views/app/requestPasswordChange.js +++ b/packages/rocketchat-ui/views/app/requestPasswordChange.js @@ -18,7 +18,7 @@ Template.requestPasswordChange.onCreated(function() { if(error) { toastr.error(t('Incorrect_Password')); } else { - Meteor.call('clearRequestPasswordChange', function() { + Meteor.call('clearRequirePasswordChange', function() { toastr.success(t('Password_changed_successfully')) return true; }); -- GitLab From 0627cbe7abf7f697bf257eb3a221f0878531e07f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 16:01:14 -0200 Subject: [PATCH 1251/1338] rename method --- ...learRequestPasswordChange.js => clearRequirePasswordChange.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/rocketchat-lib/server/methods/{clearRequestPasswordChange.js => clearRequirePasswordChange.js} (100%) diff --git a/packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js b/packages/rocketchat-lib/server/methods/clearRequirePasswordChange.js similarity index 100% rename from packages/rocketchat-lib/server/methods/clearRequestPasswordChange.js rename to packages/rocketchat-lib/server/methods/clearRequirePasswordChange.js -- GitLab From 22661cbb26aac8686a1fddf02bd2e55db56d2a98 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Tue, 19 Jan 2016 16:56:52 -0200 Subject: [PATCH 1252/1338] Functions should throw errors instead of returning false; Switched new files to .js instead of .coffee; --- packages/rocketchat-lib/package.js | 6 ++-- .../functions/checkEmailAvailability.coffee | 2 -- .../functions/checkEmailAvailability.js | 3 ++ .../server/functions/setEmail.coffee | 26 -------------- .../server/functions/setEmail.js | 36 +++++++++++++++++++ .../server/methods/setEmail.coffee | 27 -------------- .../rocketchat-lib/server/methods/setEmail.js | 36 +++++++++++++++++++ 7 files changed, 78 insertions(+), 58 deletions(-) delete mode 100644 packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee create mode 100644 packages/rocketchat-lib/server/functions/checkEmailAvailability.js delete mode 100644 packages/rocketchat-lib/server/functions/setEmail.coffee create mode 100644 packages/rocketchat-lib/server/functions/setEmail.js delete mode 100644 packages/rocketchat-lib/server/methods/setEmail.coffee create mode 100644 packages/rocketchat-lib/server/methods/setEmail.js diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index ccaa8127c50..dc99cec694a 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -55,11 +55,11 @@ Package.onUse(function(api) { // SERVER FUNCTIONS api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); - api.addFiles('server/functions/checkEmailAvailability.coffee', 'server'); + api.addFiles('server/functions/checkEmailAvailability.js', 'server'); api.addFiles('server/functions/sendMessage.coffee', 'server'); api.addFiles('server/functions/settings.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); - api.addFiles('server/functions/setEmail.coffee', 'server'); + api.addFiles('server/functions/setEmail.js', 'server'); api.addFiles('server/functions/Notifications.coffee', 'server'); // SERVER METHODS @@ -75,7 +75,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/setAdminStatus.coffee', 'server'); api.addFiles('server/methods/setRealName.coffee', 'server'); api.addFiles('server/methods/setUsername.coffee', 'server'); - api.addFiles('server/methods/setEmail.coffee', 'server'); + api.addFiles('server/methods/setEmail.js', 'server'); api.addFiles('server/methods/updateUser.coffee', 'server'); api.addFiles('server/methods/restartServer.coffee', 'server'); diff --git a/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee b/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee deleted file mode 100644 index e6c95d7702a..00000000000 --- a/packages/rocketchat-lib/server/functions/checkEmailAvailability.coffee +++ /dev/null @@ -1,2 +0,0 @@ -RocketChat.checkEmailAvailability = (email) -> - return not Meteor.users.findOne({ "emails.address": { $regex : new RegExp("^" + s.trim(s.escapeRegExp(email)) + "$", "i") } }) diff --git a/packages/rocketchat-lib/server/functions/checkEmailAvailability.js b/packages/rocketchat-lib/server/functions/checkEmailAvailability.js new file mode 100644 index 00000000000..1176500aaf0 --- /dev/null +++ b/packages/rocketchat-lib/server/functions/checkEmailAvailability.js @@ -0,0 +1,3 @@ +RocketChat.checkEmailAvailability = function(email) { + return !Meteor.users.findOne({ "emails.address": { $regex : new RegExp("^" + s.trim(s.escapeRegExp(email)) + "$", "i") } }) +} diff --git a/packages/rocketchat-lib/server/functions/setEmail.coffee b/packages/rocketchat-lib/server/functions/setEmail.coffee deleted file mode 100644 index a947436d7a0..00000000000 --- a/packages/rocketchat-lib/server/functions/setEmail.coffee +++ /dev/null @@ -1,26 +0,0 @@ -RocketChat._setEmail = (userId, email) -> - email = s.trim email - if not userId or not email - return false - - emailValidation = /^[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])?)*$/ - if not emailValidation.test email - return false - - user = RocketChat.models.Users.findOneById userId - - # User already has desired username, return - if user.emails?[0]?.address is email - return user - - # Check e-mail availability - unless RocketChat.checkEmailAvailability email - return false - - # Set new email - RocketChat.models.Users.setEmail user._id, email - user.email = email - return user - -RocketChat.setEmail = RocketChat.RateLimiter.limitFunction RocketChat._setEmail, 1, 60000, - 0: (userId) -> return not RocketChat.authz.hasPermission(userId, 'edit-other-user-info') # Administrators have permission to change others emails, so don't limit those diff --git a/packages/rocketchat-lib/server/functions/setEmail.js b/packages/rocketchat-lib/server/functions/setEmail.js new file mode 100644 index 00000000000..e5af486d5f8 --- /dev/null +++ b/packages/rocketchat-lib/server/functions/setEmail.js @@ -0,0 +1,36 @@ +RocketChat._setEmail = function(userId, email) { + email = s.trim(email) + if (!userId) { + throw new Meteor.Error('invalid-user', "[methods] setEmail -> Invalid user"); + } + + if (!email) { + throw new Meteor.Error('invalid-email', "[methods] setEmail -> Invalid email"); + } + + emailValidation = /^[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])?)*$/; + if (!emailValidation.test(email)) { + throw new Meteor.Error('email-invalid', "#{email} is not a valid e-mail"); + } + + user = RocketChat.models.Users.findOneById(userId); + + // User already has desired username, return + if (user.emails && user.emails[0] && user.emails[0].address === email) { + return user; + } + + // Check e-mail availability + if (!RocketChat.checkEmailAvailability(email)) { + throw new Meteor.Error('email-unavailable', "#{email} is already in use :("); + } + + // Set new email + RocketChat.models.Users.setEmail(user._id, email); + user.email = email; + return user; +} + +RocketChat.setEmail = RocketChat.RateLimiter.limitFunction(RocketChat._setEmail, 1, 60000, { + 0: function(userId) { return !RocketChat.authz.hasPermission(userId, 'edit-other-user-info') } // Administrators have permission to change others emails, so don't limit those +}); diff --git a/packages/rocketchat-lib/server/methods/setEmail.coffee b/packages/rocketchat-lib/server/methods/setEmail.coffee deleted file mode 100644 index c4030c517cb..00000000000 --- a/packages/rocketchat-lib/server/methods/setEmail.coffee +++ /dev/null @@ -1,27 +0,0 @@ -Meteor.methods - setEmail: (email) -> - if not Meteor.userId() - throw new Meteor.Error('invalid-user', "[methods] setEmail -> Invalid user") - - user = Meteor.user() - - if not RocketChat.settings.get("Accounts_AllowEmailChange") - throw new Meteor.Error(403, "[methods] setEmail -> E-mail change not allowed") - - if user.emails?[0]?.address is email - return email - - emailValidation = /^[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])?)*$/ - if not emailValidation.test email - throw new Meteor.Error 'email-invalid', "#{email} is not a valid e-mail" - - if not RocketChat.checkEmailAvailability email - throw new Meteor.Error 'email-unavailable', "#{email} is already in use :(" - - unless RocketChat.setEmail user._id, email - throw new Meteor.Error 'could-not-change-email', "Could not change email" - - return email - -RocketChat.RateLimiter.limitMethod 'setEmail', 1, 1000, - userId: (userId) -> return true diff --git a/packages/rocketchat-lib/server/methods/setEmail.js b/packages/rocketchat-lib/server/methods/setEmail.js new file mode 100644 index 00000000000..18a04155b46 --- /dev/null +++ b/packages/rocketchat-lib/server/methods/setEmail.js @@ -0,0 +1,36 @@ +Meteor.methods({ + setEmail: function(email) { + if (!Meteor.userId()) { + throw new Meteor.Error('invalid-user', "[methods] setEmail -> Invalid user"); + } + + user = Meteor.user(); + + if (!RocketChat.settings.get("Accounts_AllowEmailChange")) { + throw new Meteor.Error(403, "[methods] setEmail -> E-mail change not allowed"); + } + + if (user.emails && user.emails[0] && user.emails[0].address === email) { + return email; + } + + emailValidation = /^[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])?)*$/; + if (!emailValidation.test(email)) { + throw new Meteor.Error('email-invalid', "#{email} is not a valid e-mail"); + } + + if (!RocketChat.checkEmailAvailability(email)) { + throw new Meteor.Error('email-unavailable', "#{email} is already in use :("); + } + + if (!RocketChat.setEmail(user._id, email)) { + throw new Meteor.Error('could-not-change-email', "Could not change email"); + } + + return email; + } +}); + +RocketChat.RateLimiter.limitMethod('setEmail', 1, 1000, { + userId: function(userId) { return true } +}); -- GitLab From d751e67fe6441e092966f05b8e19e07b6b488312 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Tue, 19 Jan 2016 17:22:03 -0200 Subject: [PATCH 1253/1338] Update S3 bucket --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9c514e8bd3e..d8dd244bf1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ deploy: provider: s3 access_key_id: "AKIAIKIA7H7D47KUHYCA" secret_access_key: $ACCESSKEY - bucket: "rocketchat" + bucket: "download.rocket.chat" skip_cleanup: true upload_dir: build local_dir: $ROCKET_DEPLOY_DIR -- GitLab From b27fb15ef374e7fbd7ec08531a7e9780a17191bf Mon Sep 17 00:00:00 2001 From: ZergRael <zergrael@gmail.com> Date: Tue, 19 Jan 2016 20:30:34 +0100 Subject: [PATCH 1254/1338] Fixed typo in oembed widget Missing mustaches for author url --- packages/rocketchat-oembed/client/oembedFrameWidget.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-oembed/client/oembedFrameWidget.html b/packages/rocketchat-oembed/client/oembedFrameWidget.html index 6965b8e6102..de1f2d79534 100644 --- a/packages/rocketchat-oembed/client/oembedFrameWidget.html +++ b/packages/rocketchat-oembed/client/oembedFrameWidget.html @@ -8,7 +8,7 @@ {{/if}} {{#if meta.oembedAuthorName}} {{#if meta.oembedAuthorUrl}} - <a href="meta.oembedAuthorUrl">{{meta.oembedAuthorName}}</a><br/> + <a href="{{meta.oembedAuthorUrl}}">{{meta.oembedAuthorName}}</a><br/> {{/if}} {{/if}} {{#if meta.oembedTitle}} -- GitLab From 522ad571c5ef704865282b081d4f135e2188e170 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 20 Jan 2016 15:00:16 -0200 Subject: [PATCH 1255/1338] code cleanup --- packages/rocketchat-ldap/ldap_client.js | 22 ++++++++++------------ packages/rocketchat-ldap/ldap_server.js | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/rocketchat-ldap/ldap_client.js b/packages/rocketchat-ldap/ldap_client.js index 18b377f630c..71fd4111ab7 100644 --- a/packages/rocketchat-ldap/ldap_client.js +++ b/packages/rocketchat-ldap/ldap_client.js @@ -2,31 +2,29 @@ // customLdapOptions should be passed in if you want to override LDAP_DEFAULTS // on any particular call (if you have multiple ldap servers you'd like to connect to) // You'll likely want to set the dn value here {dn: "..."} -Meteor.loginWithLDAP = function(user, password, customLdapOptions, callback) { +Meteor.loginWithLDAP = function(username, password, customLdapOptions, callback) { // Retrieve arguments as array var args = []; for (var i = 0; i < arguments.length; i++) { - args.push(arguments[i]); + args.push(arguments[i]); } // Pull username and password - user = args.shift(); + username = args.shift(); password = args.shift(); - + // Check if last argument is a function // if it is, pop it off and set callback to it if (typeof args[args.length-1] == 'function') callback = args.pop(); else callback = null; - + // if args still holds options item, grab it if (args.length > 0) customLdapOptions = args.shift(); else customLdapOptions = {}; // Set up loginRequest object - var loginRequest = _.defaults({ - username: user, - ldapPass: password - }, { - ldap: true, + var loginRequest = { + username: username, + ldapPass: password, ldapOptions: customLdapOptions - }); + }; Accounts.callLoginMethod({ // Call login method with ldap = true @@ -40,4 +38,4 @@ Meteor.loginWithLDAP = function(user, password, customLdapOptions, callback) { } } }); -} \ No newline at end of file +} diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 7a75abc7e58..aba0e351ade 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -236,7 +236,7 @@ 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) { + if (!loginRequest.ldapOptions) { return undefined; } -- GitLab From c56d3a06ffd01415f4a377f16aea690868874801 Mon Sep 17 00:00:00 2001 From: Eric Breidbart <ebreidbart@gmail.com> Date: Wed, 20 Jan 2016 16:02:03 -0500 Subject: [PATCH 1256/1338] Include a fallback click event for loading more messages If the scroll event does not get triggered, the "has more..." link does nothing. This adds the capability to click the "has more..." link and load more message search results --- .../rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee index 0d3113623d8..098c1873573 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/messageSearch.coffee @@ -59,6 +59,10 @@ Template.messageSearch.events $(".search-messages-list \##{message_id} .message-cog-container").append el dropDown = $(".search-messages-list \##{message_id} .message-dropdown") dropDown.show() + + 'click .load-more a': (e, t) -> + t.limit.set(t.limit.get() + 20) + t.search() 'scroll .content': _.throttle (e, t) -> if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight -- GitLab From 72a8b0ca4257eb9b08ccdb06871381469ad8c18b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 20 Jan 2016 19:28:08 -0200 Subject: [PATCH 1257/1338] Bind starttls correctly --- packages/rocketchat-ldap/ldap_server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index aba0e351ade..917c1db951f 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -53,7 +53,7 @@ function startTLS(client) { opts.ca = [LDAP_DEFAULTS.CACert]; } - var starttlsSync = Meteor.wrapAsync(client.starttls); + var starttlsSync = Meteor.wrapAsync(client.starttls.bind(client)); var res = starttlsSync(opts , null); if (res) { -- GitLab From 9e42d5f2080392640d2a5e4fc128764dd26c435e Mon Sep 17 00:00:00 2001 From: Dumeni Degunda <Steibock@users.noreply.github.com> Date: Thu, 21 Jan 2016 10:38:08 +0100 Subject: [PATCH 1258/1338] html h3 tag was closed with </h4> --- packages/rocketchat-markdown/markdown.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index f33c817e527..5248d9b66e3 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -44,7 +44,7 @@ class Markdown msg = msg.replace(/^## (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h2>$1</h2>') # Support # Text for h3 - msg = msg.replace(/^### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h3>$1</h4>') + msg = msg.replace(/^### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h3>$1</h3>') # Support # Text for h4 msg = msg.replace(/^#### (([\w\d-_\/\*\.,\\] ?)+)/gm, '<h4>$1</h4>') -- GitLab From d2dcab302f0a1409fdd0a44ba2de3a6b8845abfe Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 21 Jan 2016 12:55:25 -0200 Subject: [PATCH 1259/1338] Add "Default Domain" to LDAP config --- i18n/en.i18n.json | 3 ++- packages/rocketchat-ldap/config_server.coffee | 3 +++ packages/rocketchat-ldap/ldap_server.js | 10 ++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 75144642647..a9dcc003535 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -256,6 +256,7 @@ "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_Default_Domain" : "Default Domain", "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", @@ -614,4 +615,4 @@ "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/packages/rocketchat-ldap/config_server.coffee b/packages/rocketchat-ldap/config_server.coffee index 66e79c07854..2b9f7547dda 100644 --- a/packages/rocketchat-ldap/config_server.coffee +++ b/packages/rocketchat-ldap/config_server.coffee @@ -18,6 +18,7 @@ Meteor.startup -> @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 } + @add 'LDAP_Default_Domain', '', { type: 'string' , enableQuery: enableQuery } timer = undefined @@ -36,6 +37,7 @@ updateServices = -> 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 '' + LDAP_DEFAULTS.defaultDomain = RocketChat.settings.get 'LDAP_Default_Domain' or '' else LDAP_DEFAULTS.TLS = undefined LDAP_DEFAULTS.CACert = undefined @@ -44,6 +46,7 @@ updateServices = -> LDAP_DEFAULTS.port = undefined LDAP_DEFAULTS.dn = undefined LDAP_DEFAULTS.bindSearch = undefined + LDAP_DEFAULTS.defaultDomain = undefined , 2000 RocketChat.models.Settings.find().observe diff --git a/packages/rocketchat-ldap/ldap_server.js b/packages/rocketchat-ldap/ldap_server.js index 917c1db951f..9f0311d0139 100644 --- a/packages/rocketchat-ldap/ldap_server.js +++ b/packages/rocketchat-ldap/ldap_server.js @@ -15,7 +15,7 @@ LDAP_DEFAULTS = { port: '389', dn: false, createNewUser: true, - defaultDomain: false, + defaultDomain: '', searchResultsProfileMap: false, bindSearch: undefined }; @@ -49,7 +49,7 @@ function startTLS(client) { rejectUnauthorized: LDAP_DEFAULTS.rejectUnauthorized }; - if ( LDAP_DEFAULTS.CACert && LDAP_DEFAULTS.CACert != '' ){ + if ( LDAP_DEFAULTS.CACert && LDAP_DEFAULTS.CACert !== '' ){ opts.ca = [LDAP_DEFAULTS.CACert]; } @@ -76,6 +76,8 @@ LDAP.prototype.ldapCheck = function(options) { options = options || {}; + options.defaultDomain = options.defaultDomain || LDAP_DEFAULTS.defaultDomain; + if (!options.hasOwnProperty('username') || !options.hasOwnProperty('ldapPass')) { throw new Meteor.Error(403, "Missing LDAP Auth Parameter"); } @@ -111,7 +113,7 @@ LDAP.prototype.ldapCheck = function(options) { // And use the defaults.defaultDomain if set if (emailSliceIndex !== -1) { username = options.username.substring(0, emailSliceIndex); - domain = domain || options.username.substring((emailSliceIndex + 1), options.username.length); + domain = options.username.substring((emailSliceIndex + 1), options.username.length) || domain; } else { username = options.username; } @@ -270,7 +272,7 @@ Accounts.registerLoginHandler("ldap", function(loginRequest) { digest: SHA256(loginRequest.ldapPass), algorithm: "sha-256" } - } + }; return Accounts._runLoginHandlers(self, loginRequest); // throw new Meteor.Error("LDAP-login-error", ldapResponse.error); -- GitLab From 270e558cab582692f19405f12efb1519a8724153 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 21 Jan 2016 16:20:02 -0200 Subject: [PATCH 1260/1338] Change to process.exit(1) to restart server --- packages/rocketchat-lib/server/methods/restartServer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/methods/restartServer.coffee b/packages/rocketchat-lib/server/methods/restartServer.coffee index 4b15cf58488..0104726d836 100644 --- a/packages/rocketchat-lib/server/methods/restartServer.coffee +++ b/packages/rocketchat-lib/server/methods/restartServer.coffee @@ -7,7 +7,7 @@ Meteor.methods throw new Meteor.Error 'not-authorized', '[methods] restart_server -> Not authorized' Meteor.setTimeout -> - process.exit(0) + process.exit(1) , 2000 return {} = -- GitLab From 60ca71f840eb3234e8f6755c02f045b840ee4c7b Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Thu, 21 Jan 2016 16:41:09 -0200 Subject: [PATCH 1261/1338] fix boolean environment variables --- packages/rocketchat-lib/server/functions/settings.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 81b4099fe66..7996d482ebc 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -23,6 +23,10 @@ RocketChat.settings.add = (_id, value, options = {}) -> if process?.env?[_id]? value = process.env[_id] + if value.toLowerCase() is "true" + value = true + else if value.toLowerCase() is "false" + value = false options.processEnvValue = value options.valueSource = 'processEnvValue' -- GitLab From eed3fadb94ed74f83f5b8263c69cc57609550b89 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 21 Jan 2016 19:21:05 -0200 Subject: [PATCH 1262/1338] Tutum: Add code to exit process after 30 days inactive --- packages/rocketchat-tutum/package.js | 1 + packages/rocketchat-tutum/startup.coffee | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/rocketchat-tutum/package.js b/packages/rocketchat-tutum/package.js index 34a218788a3..f59c2868429 100644 --- a/packages/rocketchat-tutum/package.js +++ b/packages/rocketchat-tutum/package.js @@ -7,6 +7,7 @@ Package.describe({ Package.onUse(function(api) { api.versionsFrom('1.0'); api.use('coffeescript'); + api.use('rocketchat:lib'); api.addFiles('startup.coffee', 'server'); }); diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee index 6757de359fc..ecfaf1f4fae 100644 --- a/packages/rocketchat-tutum/startup.coffee +++ b/packages/rocketchat-tutum/startup.coffee @@ -13,3 +13,24 @@ if process.env.TUTUM_REDIS_HOST? client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", process.env.TUTUM_CLIENT_NAME) client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", "http://#{process.env.TUTUM_IP_ADDRESS.split('/')[0]}:3000") + + day = 3600000 + + inactiveDays = 30 + + if not isNaN(parseInt(process.env.TUTUM_REDIS_INACTIVE_DAYS)) + inactiveDays = parseInt(process.env.TUTUM_REDIS_INACTIVE_DAYS) + + terminateAppIfInactive = -> + subscription = RocketChat.models.Subscriptions.findOne({ls: {$exists: true}}, {sort: {ls: -1}, fields: {ls: 1}}) + + if subscription? + if Date.now() - subscription.ls > inactiveDays * day + client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") + process.exit 0 + + Meteor.setInterval -> + now = new Date() + if now.getHours() is 4 and now.getMinutes() is 0 + terminateAppIfInactive() + , 60000 -- GitLab From 0b9c1247adfc6934f702e2bf3c0aa2e6f56e4358 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 21 Jan 2016 19:44:48 -0200 Subject: [PATCH 1263/1338] Tutum: improve exit --- packages/rocketchat-tutum/startup.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee index ecfaf1f4fae..8af71f33c52 100644 --- a/packages/rocketchat-tutum/startup.coffee +++ b/packages/rocketchat-tutum/startup.coffee @@ -24,10 +24,9 @@ if process.env.TUTUM_REDIS_HOST? terminateAppIfInactive = -> subscription = RocketChat.models.Subscriptions.findOne({ls: {$exists: true}}, {sort: {ls: -1}, fields: {ls: 1}}) - if subscription? - if Date.now() - subscription.ls > inactiveDays * day - client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") - process.exit 0 + if not subscription? or Date.now() - subscription.ls > inactiveDays * day + client.del("frontend:#{process.env.TUTUM_CLIENT_HOST}") + process.exit 0 Meteor.setInterval -> now = new Date() -- GitLab From 6af0d51fa183af953ddbef0225ca29a1ea58fa0e Mon Sep 17 00:00:00 2001 From: Sven Mueller <mueller@synyx.de> Date: Fri, 22 Jan 2016 15:19:20 +0100 Subject: [PATCH 1264/1338] Added /msg slash command for IRC-style direct message --- .../client.coffee | 14 ++++++++ .../i18n/ar.i18n.json | 1 + .../i18n/cs.i18n.json | 1 + .../i18n/de.i18n.json | 4 +++ .../i18n/el.i18n.json | 1 + .../i18n/en.i18n.json | 4 +++ .../i18n/es.i18n.json | 1 + .../i18n/fa.i18n.json | 1 + .../i18n/fi.i18n.json | 1 + .../i18n/fr.i18n.json | 1 + .../i18n/he.i18n.json | 1 + .../i18n/hr.i18n.json | 1 + .../i18n/hu.i18n.json | 1 + .../i18n/it.i18n.json | 1 + .../i18n/ja.i18n.json | 1 + .../i18n/km.i18n.json | 1 + .../i18n/ko.i18n.json | 1 + .../i18n/ku.i18n.json | 1 + .../i18n/lo.i18n.json | 1 + .../i18n/ms-MY.i18n.json | 1 + .../i18n/nl.i18n.json | 1 + .../i18n/pl.i18n.json | 1 + .../i18n/pt.i18n.json | 1 + .../i18n/ro.i18n.json | 1 + .../i18n/ru.i18n.json | 1 + .../i18n/sq.i18n.json | 1 + .../i18n/sr.i18n.json | 1 + .../i18n/sv.i18n.json | 1 + .../i18n/ta-IN.i18n.json | 1 + .../i18n/tr.i18n.json | 1 + .../i18n/ug.i18n.json | 1 + .../i18n/uk.i18n.json | 1 + .../i18n/zh.i18n.json | 1 + .../rocketchat-slashcommands-msg/package.js | 36 +++++++++++++++++++ .../server.coffee | 36 +++++++++++++++++++ 35 files changed, 124 insertions(+) create mode 100644 packages/rocketchat-slashcommands-msg/client.coffee create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ar.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/cs.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/de.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/el.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/en.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/es.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/fa.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/fi.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/fr.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/he.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/hr.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/hu.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/it.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ja.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/km.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ko.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ku.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/lo.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/nl.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/pl.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/pt.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ro.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ru.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/sq.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/sr.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/sv.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/tr.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/ug.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/uk.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/i18n/zh.i18n.json create mode 100644 packages/rocketchat-slashcommands-msg/package.js create mode 100644 packages/rocketchat-slashcommands-msg/server.coffee diff --git a/packages/rocketchat-slashcommands-msg/client.coffee b/packages/rocketchat-slashcommands-msg/client.coffee new file mode 100644 index 00000000000..d8d8bc51e3e --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/client.coffee @@ -0,0 +1,14 @@ +RocketChat.slashCommands.add 'msg', (command, params, item) -> + trimmedParams = params.trim() + + username = trimmedParams.slice(0, trimmedParams.indexOf(' ')) + + if username is '' + return + username = username.replace('@', '') + + if Session.get('showUserInfo') is username + Session.set('showUserInfo', null) +, + description: TAPi18n.__ 'Direct_message_someone' + params: '@username <message>' diff --git a/packages/rocketchat-slashcommands-msg/i18n/ar.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ar.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ar.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/cs.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/cs.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/cs.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json new file mode 100644 index 00000000000..98a21d1147b --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json @@ -0,0 +1,4 @@ +{ + "Username_doesnt_exist" : "Der Benutzername `%s` existiert nicht.", + "Direct_message_someone" : "Jemandem eine private Nachricht schicken" +} diff --git a/packages/rocketchat-slashcommands-msg/i18n/el.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/el.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/el.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json new file mode 100644 index 00000000000..03addd53f03 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json @@ -0,0 +1,4 @@ +{ + "Username_doesnt_exist" : "The username `%s` doesn't exist.", + "Direct_message_someone" : "Direct message someone" +} diff --git a/packages/rocketchat-slashcommands-msg/i18n/es.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/es.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/es.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/fa.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/fa.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/fa.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/fi.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/fi.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/fi.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/fr.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/fr.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/fr.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/he.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/he.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/he.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/hr.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/hr.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/hr.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/hu.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/hu.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/hu.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/it.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/it.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/it.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ja.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ja.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ja.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/km.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/km.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/km.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ko.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ko.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ko.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ku.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ku.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ku.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/lo.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/lo.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/lo.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ms-MY.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/nl.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/nl.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/nl.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/pl.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/pl.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/pl.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/pt.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/pt.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/pt.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ro.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ro.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ro.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ru.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ru.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ru.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/sq.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/sq.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/sq.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/sr.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/sr.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/sr.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/sv.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/sv.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/sv.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ta-IN.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/tr.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/tr.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/tr.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/ug.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/ug.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/ug.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/uk.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/uk.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/uk.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/zh.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/zh.i18n.json new file mode 100644 index 00000000000..ffcd4415b08 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/i18n/zh.i18n.json @@ -0,0 +1 @@ +{ } diff --git a/packages/rocketchat-slashcommands-msg/package.js b/packages/rocketchat-slashcommands-msg/package.js new file mode 100644 index 00000000000..69f46aa0730 --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/package.js @@ -0,0 +1,36 @@ +Package.describe({ + name: 'rocketchat:slashcommands-msg', + version: '0.0.1', + summary: 'Command handler for the /msg 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-msg/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-slashcommands-msg/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-slashcommands-msg/server.coffee b/packages/rocketchat-slashcommands-msg/server.coffee new file mode 100644 index 00000000000..4825bd1b74b --- /dev/null +++ b/packages/rocketchat-slashcommands-msg/server.coffee @@ -0,0 +1,36 @@ +### +# Msg is a named function that will replace /msg commands +### + +class Msg + constructor: (command, params, item) -> + if command isnt 'msg' or not Match.test params, String + return + + trimmedParams = params.trim() + + usernameOrig = trimmedParams.slice(0, trimmedParams.indexOf(' ')) + message = trimmedParams.slice(trimmedParams.indexOf(' ') + 1) + + if username is '' + return + + username = usernameOrig.replace('@', '') + + user = Meteor.users.findOne Meteor.userId() + msgUser = RocketChat.models.Users.findOneByUsername username + + if not msgUser? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ usernameOrig ] }, user.language) + } + return + + rid = Meteor.call 'createDirectMessage', username + msgObject = { _id: Random.id(), rid: rid.rid, msg: message} + Meteor.call 'sendMessage', msgObject + +RocketChat.slashCommands.add 'msg', Msg -- GitLab From d802a5d4d89b010b29d33664b4fcc4c061b99104 Mon Sep 17 00:00:00 2001 From: Matthias Brun <dev.matthias.brun@gmail.com> Date: Fri, 22 Jan 2016 17:27:57 +0100 Subject: [PATCH 1265/1338] Fix archiving button being shown to users who don't have the permissions --- .../client/views/channelSettings.html | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index 8a326bd4911..efd7879d1f9 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -44,14 +44,16 @@ </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 canEdit}} + <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}} {{/if}} {{#each channelSettings}} {{> Template.dynamic template=template data=data}} -- GitLab From 79a3745ddf361d1182a9b0bc4d7cacefe7224265 Mon Sep 17 00:00:00 2001 From: Matthias Brun <dev.matthias.brun@gmail.com> Date: Fri, 22 Jan 2016 17:49:55 +0100 Subject: [PATCH 1266/1338] Replace archiving button with radio buttons and show current room state to unprivileged users --- .../client/views/channelSettings.coffee | 31 ++++++++++--------- .../client/views/channelSettings.html | 19 +++++++----- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index 30529f9a809..ac6d3536b6e 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -19,8 +19,14 @@ Template.channelSettings.helpers return ChatRoom.findOne(@rid)?.name roomTopic: -> return ChatRoom.findOne(@rid)?.topic - archived: -> + archivationState: -> return ChatRoom.findOne(@rid)?.archived + archivationStateDescription: -> + archivationState = ChatRoom.findOne(@rid)?.archived + if archivationState is true + return t('Room_archivation_state_true') + else + return t('Room_archivation_state_false') Template.channelSettings.events 'keydown input[type=text]': (e, t) -> @@ -41,20 +47,6 @@ Template.channelSettings.events 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' - - 'click .unarchive': (e, t) -> - e.preventDefault() - - Meteor.call 'unarchiveRoom', t.data.rid, true, (err, results) -> - return toastr.error err.reason if err - toastr.success TAPi18n.__ 'Room_unarchived' - Template.channelSettings.onCreated -> @editing = new ReactiveVar @@ -106,4 +98,13 @@ Template.channelSettings.onCreated -> return toastr.error TAPi18n.__(err.reason, err.details.roomType) return toastr.error TAPi18n.__(err.reason) toastr.success TAPi18n.__ 'Room_type_changed_successfully' + when 'archivationState' + if @$('input[name=archivationState]:checked').val() is 'true' + Meteor.call 'archiveRoom', @data?.rid, (err, results) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__ 'Room_archived' + else + Meteor.call 'unarchiveRoom', @data?.rid, (err, results) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__ 'Room_unarchived' @editing.set() diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index efd7879d1f9..cf20528f348 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -44,16 +44,19 @@ </li> {{/if}} {{#if notDirect}} - {{#if canEdit}} - <li> - <label>{{_ "Archive_Unarchive"}}</label> - {{#if archived}} - <button class="button unarchive"><span>{{_ "Unarchive"}}</span></button> + <li> + <label>{{_ "Room_archivation_state"}}</label> + <div> + {{#if editing 'archivationState'}} + <label><input type="radio" name="archivationState" class="editing" value="true" checked="{{$eq archivationState true}}" /> {{_ "Room_archivation_state_true"}}</label> + <label><input type="radio" name="archivationState" value="false" checked="{{$neq archivationState true}}" /> {{_ "Room_archivation_state_false"}}</label> + <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> + <button type="button" class="button primary save">{{_ "Save"}}</button> {{else}} - <button class="button archive"><span>{{_ "Archive"}}</span></button> + <span>{{archivationStateDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="archivationState"></i>{{/if}}</span> {{/if}} - </li> - {{/if}} + </div> + </li> {{/if}} {{#each channelSettings}} {{> Template.dynamic template=template data=data}} -- GitLab From e33521f9048d34a6974ca4325ea0a5ede932c495 Mon Sep 17 00:00:00 2001 From: Matthias Brun <dev.matthias.brun@gmail.com> Date: Fri, 22 Jan 2016 17:55:17 +0100 Subject: [PATCH 1267/1338] Add i18n entries for room archivation --- packages/rocketchat-channel-settings/i18n/en.i18n.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index 7fa82c45dcb..ea28753a13e 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -5,9 +5,12 @@ "Save" : "Save", "Topic" : "Topic", "Type" : "Type", + "Room_archivation_state" : "State", + "Room_archivation_state_false" : "Active", + "Room_archivation_state_true" : "Archived", "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_topic_changed_successfully" : "Room topic changed successfully", "Room_type_changed_successfully" : "Room type changed successfully" -} \ No newline at end of file +} -- GitLab From ab84f06f2ffed2c7204943e5864d932b74746769 Mon Sep 17 00:00:00 2001 From: Jonathan Zeppettini <jonzep@gmail.com> Date: Sat, 23 Jan 2016 17:47:52 -0500 Subject: [PATCH 1268/1338] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 517d8220b70..49e79938b97 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 RocketChat +Copyright (c) 2015-2016 RocketChat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal -- GitLab From 6a97e184662fe01555281d97344d33cb1eecaed7 Mon Sep 17 00:00:00 2001 From: Jonathan Zeppettini <jonzep@gmail.com> Date: Sat, 23 Jan 2016 18:03:34 -0500 Subject: [PATCH 1269/1338] Update README.md Fixed Google Play image/language. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3feb6070e37..fe7f6bf4512 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron] ### Available from the AppStore [](https://itunes.apple.com/us/app/rocket.chat/id1028869439?mt=8) -### Available from the Google Play -[](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) +### Available from Google Play +[](https://play.google.com/store/apps/details?id=com.konecty.rocket.chat) Now compatible with all Android devices as old as version 4.0.x - [download here](https://github.com/RocketChat/Rocket.Chat/wiki/Build-the-Android-Cordova-Web-App-and-connect-to-your-own-Rocket.Chat-Server), even on BlackBerry Passport! -- GitLab From a81ebed465f4b9c67869f38e5d609231b4191811 Mon Sep 17 00:00:00 2001 From: Sven Mueller <mueller@synyx.de> Date: Sun, 24 Jan 2016 14:17:49 +0100 Subject: [PATCH 1270/1338] fix line mix up --- packages/rocketchat-slashcommands-msg/server.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-slashcommands-msg/server.coffee b/packages/rocketchat-slashcommands-msg/server.coffee index 4825bd1b74b..339edfaa062 100644 --- a/packages/rocketchat-slashcommands-msg/server.coffee +++ b/packages/rocketchat-slashcommands-msg/server.coffee @@ -12,11 +12,11 @@ class Msg usernameOrig = trimmedParams.slice(0, trimmedParams.indexOf(' ')) message = trimmedParams.slice(trimmedParams.indexOf(' ') + 1) + username = usernameOrig.replace('@', '') + if username is '' return - username = usernameOrig.replace('@', '') - user = Meteor.users.findOne Meteor.userId() msgUser = RocketChat.models.Users.findOneByUsername username -- GitLab From 215af22e402fec5ab65f250a0f74bc09ad4a073f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 25 Jan 2016 09:14:08 -0200 Subject: [PATCH 1271/1338] Fix: check if name and username are not empty strings Added check on username according to app settings for name validation. --- .../server/methods/insertOrUpdateUser.coffee | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee b/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee index 5823fcacf4c..bc923207e13 100644 --- a/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee +++ b/packages/rocketchat-lib/server/methods/insertOrUpdateUser.coffee @@ -14,12 +14,20 @@ Meteor.methods if not userData._id and canAddUser isnt true throw new Meteor.Error 'not-authorized', '[methods] updateUser -> Not authorized' - unless userData.name + unless s.trim(userData.name) throw new Meteor.Error 'name-is-required', 'Name field is required' - unless userData.username + unless s.trim(userData.username) throw new Meteor.Error 'user-name-is-required', 'Username field is required' + try + nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$' + catch + nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$' + + if not nameValidation.test userData.username + throw new Meteor.Error 'username-invalid', "#{username} is not a valid username" + if not userData._id and not userData.password throw new Meteor.Error 'password-is-required', 'Password is required when adding a user' -- GitLab From fbee979455a735a3a30cabc59c55e212bed2094e Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 25 Jan 2016 10:41:46 -0200 Subject: [PATCH 1272/1338] Fix #2002. Should not check for MAIL_URL as it's server side only --- .../admin/users/adminInviteUser.coffee | 3 -- .../admin/users/adminInviteUser.html | 49 +++++++++---------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/users/adminInviteUser.coffee b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.coffee index e0dc564bd06..90567ec9600 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminInviteUser.coffee +++ b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.coffee @@ -1,9 +1,6 @@ Template.adminInviteUser.helpers isAdmin: -> return RocketChat.authz.hasRole(Meteor.userId(), 'admin') - emailEnabled: -> - console.log 'emailEnabled', RocketChat.settings.get('MAIL_URL') or (RocketChat.settings.get('SMTP_Host') and RocketChat.settings.get('SMTP_Username') and RocketChat.settings.get('SMTP_Password')) - return RocketChat.settings.get('MAIL_URL') or (RocketChat.settings.get('SMTP_Host') and RocketChat.settings.get('SMTP_Username') and RocketChat.settings.get('SMTP_Password')) inviteEmails: -> return Template.instance().inviteEmails.get() diff --git a/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html index 82740a313f0..9c27bcdfa4c 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html +++ b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html @@ -1,31 +1,26 @@ <template name="adminInviteUser"> {{#if isAdmin}} - {{#if emailEnabled}} - <div class="about clearfix"> - <form class="edit-form"> - <h3>{{_ "Send_invitation_email"}}</h3> - <div class="input-line"> - <label for="inviteEmails">{{_ "Send_invitation_email_info"}}</label> - <textarea id="inviteEmails" rows="3" style="height: auto"></textarea> - </div> - </form> - </div> - <nav> - <button class='button button-block cancel secondary'><span>{{_ "Cancel"}}</span></button> - <button class='button button-block blue send' data-loading-text="{{_ "Please_wait"}}"><span>{{_ "Send"}}</span></button> - </nav> - {{#if inviteEmails.length}} - <div class="about clearfix" style="margin-top: 30px"> - <p style="color: #51a351"> {{_ "Send_invitation_email_success"}} </p> - <ul style="margin: 5px 10px"> - {{#each inviteEmails}} - <li style="margin-top: 5px">{{.}}</li> - {{/each}} - </ul> - </div> - {{/if}} - {{else}} - {{_ "Send_invitation_email_warning"}} - {{/if}} + <div class="about clearfix"> + <form class="edit-form"> + <h3>{{_ "Send_invitation_email"}}</h3> + <div class="input-line"> + <label for="inviteEmails">{{_ "Send_invitation_email_info"}}</label> + <textarea id="inviteEmails" rows="3" style="height: auto"></textarea> + </div> + </form> + </div> + <nav> + <button class='button button-block cancel secondary'><span>{{_ "Cancel"}}</span></button> + <button class='button button-block blue send' data-loading-text="{{_ "Please_wait"}}"><span>{{_ "Send"}}</span></button> + </nav> + {{#if inviteEmails.length}} + <div class="about clearfix" style="margin-top: 30px"> + <p style="color: #51a351"> {{_ "Send_invitation_email_success"}} </p> + <ul style="margin: 5px 10px"> + {{#each inviteEmails}} + <li style="margin-top: 5px">{{.}}</li> + {{/each}} + </ul> + </div> {{/if}} </template> \ No newline at end of file -- GitLab From a08c7736083b4e97afd9455e060535127617af78 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 25 Jan 2016 11:08:20 -0200 Subject: [PATCH 1273/1338] Fix #2002. Should not check for MAIL_URL as it's server side only --- packages/rocketchat-ui-admin/admin/users/adminInviteUser.html | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html index 9c27bcdfa4c..e9cdab95258 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html +++ b/packages/rocketchat-ui-admin/admin/users/adminInviteUser.html @@ -22,5 +22,6 @@ {{/each}} </ul> </div> + {{/if}} {{/if}} </template> \ No newline at end of file -- GitLab From 5a77f89f60ddae21a6f0147cd76e5d9386e1db23 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 25 Jan 2016 11:13:51 -0200 Subject: [PATCH 1274/1338] Temporary fix for AM/PM timestamp breaking cog --- packages/rocketchat-livechat/app/client/views/message.coffee | 2 +- packages/rocketchat-ui-message/message/message.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index 87cc3d9164e..45fd4aa745b 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('LT') + return moment(this.ts).format('LT').replace(/(AM|PM)$/i, '') date: -> return moment(this.ts).format('LL') diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 6295dd6b957..ddaea051209 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -14,7 +14,7 @@ Template.message.helpers chatops: -> return 'chatops-message' if this.u?.username is RocketChat.settings.get('Chatops_Username') time: -> - return moment(this.ts).format('LT') + return moment(this.ts).format('LT').replace(/(AM|PM)$/i, '') date: -> return moment(this.ts).format('LL') isTemp: -> -- GitLab From 01dd59b67d86db368a2c106c45c67f855b53821b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 25 Jan 2016 11:49:09 -0200 Subject: [PATCH 1275/1338] Temporary fix for AM/PM timestamp breaking cog --- packages/rocketchat-livechat/app/client/views/message.coffee | 2 +- packages/rocketchat-theme/assets/stylesheets/base.less | 2 +- packages/rocketchat-ui-message/message/message.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/views/message.coffee b/packages/rocketchat-livechat/app/client/views/message.coffee index 45fd4aa745b..87cc3d9164e 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('LT').replace(/(AM|PM)$/i, '') + return moment(this.ts).format('LT') date: -> return moment(this.ts).format('LL') diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index cd454102936..ee4c1853c5e 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -2742,7 +2742,7 @@ a.github-fork { &:hover { .time { - display: inline-block; + // display: inline-block; } .edited { display: none; diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index ddaea051209..6295dd6b957 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -14,7 +14,7 @@ Template.message.helpers chatops: -> return 'chatops-message' if this.u?.username is RocketChat.settings.get('Chatops_Username') time: -> - return moment(this.ts).format('LT').replace(/(AM|PM)$/i, '') + return moment(this.ts).format('LT') date: -> return moment(this.ts).format('LL') isTemp: -> -- GitLab From b4ed23a7deded50e2aa856f17ed719af14ba1507 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Mon, 25 Jan 2016 13:56:21 +0000 Subject: [PATCH 1276/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 12 +- i18n/de.i18n.json | 10 +- i18n/en.i18n.json | 2 +- i18n/nl.i18n.json | 125 +++++++++++++++++- i18n/pt.i18n.json | 10 ++ i18n/ru.i18n.json | 19 +++ .../i18n/ar.i18n.json | 2 +- .../i18n/ru.i18n.json | 3 + .../i18n/ar.i18n.json | 1 + .../i18n/nl.i18n.json | 3 + .../i18n/nl.i18n.json | 2 + .../i18n/ru.i18n.json | 3 + .../i18n/ar.i18n.json | 2 +- .../i18n/pt.i18n.json | 1 + packages/rocketchat-ldap/i18n/nl.i18n.json | 4 +- packages/rocketchat-lib/i18n/nl.i18n.json | 2 +- .../rocketchat-livechat/app/i18n/ru.i18n.json | 1 + .../rocketchat-livechat/i18n/ar.i18n.json | 26 +++- .../rocketchat-livechat/i18n/nl.i18n.json | 11 ++ .../rocketchat-livechat/i18n/ru.i18n.json | 5 +- packages/rocketchat-mailer/i18n/nl.i18n.json | 10 +- packages/rocketchat-mailer/i18n/ru.i18n.json | 5 +- .../rocketchat-message-pin/i18n/ar.i18n.json | 3 +- .../rocketchat-message-pin/i18n/nl.i18n.json | 9 +- .../rocketchat-message-pin/i18n/ru.i18n.json | 2 + .../rocketchat-message-star/i18n/nl.i18n.json | 8 +- packages/rocketchat-theme/i18n/ar.i18n.json | 1 + packages/rocketchat-theme/i18n/nl.i18n.json | 25 ++++ 28 files changed, 281 insertions(+), 26 deletions(-) diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index bc196b60c39..37da6c949c6 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -2,7 +2,10 @@ "Access_online_demo" : "الدخول إلى العرض التجريبي", "Access_Online_Demo" : "الدخول إلى العرض التجريبي", "Accounts" : "الØسابات", + "Accounts_AllowedDomainsList" : "قائمة النطاقات المسموØØ©", + "Accounts_AllowEmailChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± البريد الاليكتروني", "Accounts_AllowPasswordChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± كلمة السر", + "Accounts_AllowUserAvatarChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± الصورة الرمزية", "Accounts_AllowUsernameChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØºÙŠÙŠØ± اسم المستخدم", "Accounts_AllowUserProfileChange" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ¹Ø¯ÙŠÙ„ المل٠الشخصي للعضو", "Accounts_AvatarResize" : "تغيير Øجم الصور الرمزية", @@ -27,6 +30,7 @@ "All_channels" : "جميع القنوات", "and" : "Ùˆ", "API_Analytics" : "التØليلات", + "Application_added" : "تمت إضاÙØ© التطبيق", "Archive" : "الأرشيÙ", "are_also_typing" : "هم أيضا يكتبون", "are_typing" : "يكتبون", @@ -90,7 +94,7 @@ "Error" : "خطأ", "Error_changing_password" : "خطأ ÙÙŠ تغيير كلمة السر", "Error_too_many_requests" : "خطأ، الكثير من الطلبات. من Ùضلك أبطء السرعة. عليك الانتظار٪ s ثانية قبل المØاولة مرة أخرى", - "False" : "خاطئة", + "False" : "لا", "Favorites" : "المÙضلة", "FileUpload" : "تØميل الملÙ", "FileUpload_Enabled" : "تØميل الملÙات Ù…Ùعلة", @@ -125,6 +129,7 @@ "italics" : "مائل", "join" : "انضم", "Join_the_Community" : "إنظم للمجتمع", + "Jump_to_first_unread" : "الذهاب إلى أول رسالة غير مقرؤة", "Jump_to_message" : "القÙز إلى الرسالة", "Jump_to_recent_messages" : "اذهب إلى الرسائل الأخيرة", "Language" : "اللغة", @@ -155,11 +160,13 @@ "Message" : "رسالة", "Message_AllowDeleting" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨Øذ٠الرسائل", "Message_AllowEditing" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ¹Ø¯ÙŠÙ„ الرسائل", + "Message_AllowEditing_BlockEditInMinutes" : "امنع تعديل الرسائل بعد هذا العدد من الدقائق", "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" : "تم Øذ٠الرسالة", @@ -187,6 +194,7 @@ "No_direct_messages_yet" : "لم تبدأ أي Ù…Øادثات Øتى الآن.", "No_favorites_yet" : "لم تقم بإضاÙØ© Ù…Ùضلات بعد.", "No_groups_yet" : "لا يوجد لديك مجموعات خاصة Øتى الآن.", + "No_livechats" : "ليس لديك Ù…Øادثات Øية", "No_permission_to_view_room" : "ليس لديك صلاØية لرؤية هذه الغرÙØ©", "No_results_found" : "لا توجد نتائج", "Not_allowed" : "غير مسموØ", @@ -266,7 +274,7 @@ "since_creation" : "منذ %s", "Site_Name" : "اسم الموقع", "Site_Url" : "رابط الموقع", - "Site_Url_Description" : "مثال: https://chat.domain.com/", + "Site_Url_Description" : "مثال: https://chat.domain.com", "Sound" : "الصوت", "Start_of_conversation" : "بداية المØادثة", "Statistics" : "الإØصائيات", diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index ebca809b478..0c92ffa5177 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -6,6 +6,7 @@ "Accounts" : "Konten", "Accounts_AllowedDomainsList" : "Liste von erlaubten Domains", "Accounts_AllowedDomainsList_Description" : "Durch Kommata getrennte Liste von erlaubten Domains", + "Accounts_AllowEmailChange" : "Ändern der E-Mail-Adresse erlauben", "Accounts_AllowPasswordChange" : "Ändern des Passworts zulassen", "Accounts_AllowUserAvatarChange" : "Benutzern das Ändern des Profilbilds erlauben", "Accounts_AllowUsernameChange" : "Ändern von Benutzernamen erlauben", @@ -133,7 +134,7 @@ "Create_new" : "Neu erstellen", "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", + "Create_new_public_channel" : "Neuen öffentlichen Kanal erstellen", "Created_at" : "Erstellt am", "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>", @@ -159,6 +160,7 @@ "E-mail" : "E-Mail", "edited" : "bearbeitet", "Email_already_exists" : "Die E-Mail-Adresse existiert bereits.", + "Email_Change_Disabled" : "Der Rocket.Chat-Administrator hat das Ändern der E-Mail-Adresse deaktiviert.", "Email_or_username" : "E-Mail-Adresse oder Nutzername", "Email_verified" : "Die E-Mail-Adresse wurde bestätigt.", "Emoji" : "Emoji", @@ -182,6 +184,7 @@ "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.", + "Force_SSL" : "SSL erzwingen", "Forgot_password" : "Passwort vergessen?", "Fork_it_on_github" : "Fork es auf GitHub", "From_Email" : "Absender", @@ -255,6 +258,7 @@ "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_Default_Domain" : "Standard-Domain", "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", @@ -420,7 +424,7 @@ "Room" : "Raum", "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" : "<em>__user_by__</em> hat den Raumnamen 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.", @@ -467,7 +471,7 @@ "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_online_users" : "<b>__total_online__</b> von __total__ Nutzer sind online", "Showing_results" : "<p><b>%s</b> Ergebnisse</p>", "Silence" : "Ruhe", "since_creation" : "seit %s", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 95565c281b9..98af0ccf725 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -617,4 +617,4 @@ "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/nl.i18n.json b/i18n/nl.i18n.json index 6a04b1d6d65..3b371d39d27 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -2,14 +2,22 @@ "Access_not_authorized" : "Toegang niet geautoriseerd", "Access_online_demo" : "Toegang tot de online demo", "Access_Online_Demo" : "Toegang tot de online demo", + "Access_Token_URL" : "Access Token URL", "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Toegestaan ​​Domeinen Lijst", + "Accounts_AllowedDomainsList_Description" : "Komma-gescheiden lijst van toegestande domeinen", "Accounts_AllowPasswordChange" : "Toestaan wachtwoord wijzigen", + "Accounts_AllowUserAvatarChange" : "Sta wijzigen van gebruikers Avatar toe", "Accounts_AllowUsernameChange" : "Toestaan wijzigen gebruikersnaam", + "Accounts_AllowUserProfileChange" : "Sta wijzen van gebruikers profiel toe", "Accounts_AvatarResize" : "Wijzig Avatar grootte", "Accounts_AvatarSize" : "Avatar grootte", + "Accounts_AvatarStorePath" : "Avatar opslag pad", + "Accounts_AvatarStoreType" : "Avatar opslag type", "Accounts_denyUnverifiedEmail" : "Weiger ongeverifieerde e-mail", - "Accounts_EmailVerification" : "Email verificatie", + "Accounts_EmailVerification" : "E-mail verificatie", + "Accounts_Enrollment_Email" : "Registratie E-mail", + "Accounts_Enrollment_Email_Description" : "You may use [name], [fname], [lname] for the user's full name, first name or last name, respectively.<br />You may use [email] for the user's e-mail.", "Accounts_LoginExpiration" : "Login Vervaltermijn in Dagen", "Accounts_ManuallyApproveNewUsers" : "Handmatig goedkeuren Nieuwe Gebruikers", "Accounts_OAuth_Custom_Authorize_Path" : "Machtigen Path", @@ -29,7 +37,9 @@ "Accounts_OAuth_Github" : "OAuth Ingeschakeld", "Accounts_OAuth_Github_id" : "Client Id", "Accounts_OAuth_Github_secret" : "Client Secret", + "Accounts_OAuth_Gitlab" : "OAuth Enabled", "Accounts_OAuth_Gitlab_id" : "Gitlab Id", + "Accounts_OAuth_Gitlab_secret" : "Client Secret", "Accounts_OAuth_Google" : "Google Inloggen", "Accounts_OAuth_Google_id" : "Google Id", "Accounts_OAuth_Google_secret" : "Google Secret", @@ -43,19 +53,27 @@ "Accounts_OAuth_Twitter_id" : "Twitter Id", "Accounts_OAuth_Twitter_secret" : "Twitter Secret", "Accounts_PasswordReset" : "Wachtwoord reset", + "Accounts_Registration_AuthenticationServices_Enabled" : "Registration with Authentication Services", "Accounts_RegistrationForm" : "Registratieformulier", "Accounts_RegistrationForm_Disabled" : "Uitgeschakeld", + "Accounts_RegistrationForm_LinkReplacementText" : "Registration Form Link Replacement Text", "Accounts_RegistrationForm_Public" : "Openbaar", "Accounts_RegistrationForm_Secret_URL" : "Geheime URL", + "Accounts_RegistrationForm_SecretURL" : "Registration Form Secret URL", + "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" : "Registratie vereist", + "Accounts_RequireNameForSignUp" : "Vereis naam tijdens registratie", + "Accounts_ShowFormLogin" : "Laat formulier-gebaseerd loginscherm zien", "Activate" : "Activeren", "Add_custom_oauth" : "Voeg aangepaste OAuth toe", "Add_Members" : "Voeg leden toe", "Add_users" : "Gebruikers toevoegen", "Administration" : "Administratie", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "After OAuth2 authentication, users will be redirected to this URL", "Alias" : "Alias", "All_channels" : "Alle kanalen", "Allow_Invalid_SelfSigned_Certs" : "Sta Ongeldige Self-Signed Certs toe", + "Allow_Invalid_SelfSigned_Certs_Description" : "Allow invalid and self-signed SSL certificate's for link validation and previews.", "and" : "en", "API" : "API", "API_Analytics" : "Analytics", @@ -69,9 +87,12 @@ "are_also_typing" : "zijn ook aan het typen", "are_typing" : "zijn aan het typen", "Are_you_sure" : "Weet u het zeker?", + "Authorization_URL" : "Authorization URL", + "Authorize" : "Authorizeren", "Auto_Load_Images" : "Automatisch afbeeldingen laden", "Avatar_changed_successfully" : "Afbeelding is gewijzigd", "Avatar_URL" : "Afbeelding URL", + "Avatar_url_invalid_or_error" : "De gegeven URL us ongeldig of niet bereikbaar. Probeer het opnieuw met een andere URL.", "away" : "Afwezig", "Away" : "Afwezig", "away_female" : "afwezig", @@ -79,6 +100,7 @@ "away_male" : "afwezig", "Away_male" : "Afwezig", "Back_to_applications" : "Terug naar toepassingen", + "Back_to_integrations" : "Terug naar integraties", "Back_to_login" : "Terug naar Inloggen", "bold" : "vetgedrukt", "busy" : "Bezet", @@ -88,30 +110,37 @@ "busy_male" : "bezet", "Busy_male" : "Bezet", "Cancel" : "Annuleren", + "CDN_PREFIX" : "CDN Prefix", + "Certificates_and_Keys" : "Certificaten en sleutels", "Change_avatar" : "Verander uw foto", "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.", + "Choose_the_username_that_this_integration_will_post_as" : "Kies de gebruikersnaam als welke deze integratie zal posten.", "Clear_all_unreads_question" : "Wis alle ongelezen?", "Client_ID" : "Client ID", + "Client_Secret" : "Client Secret", "close" : "Sluiten", - "coming_soon" : "binnekort beschikbaar", + "coming_soon" : "binnenkort beschikbaar", "Commands" : "Commando's", "Compact_View" : "Compacte weergave", "Confirm_password" : "Bevestig uw wachtwoord", "Contact" : "Contact", "Conversation" : "Gesprek", "Convert_Ascii_Emojis" : "ASCII naar Emoji Converteren ", + "COPY_TO_CLIPBOARD" : "KOPIEER NAAR KLEMBOARD", "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_helper" : "Bij het instellen van uw OAuth Provider, moet u een Callback URL geven. Gebruik <pre>%s</pre> .", "Custom_oauth_unique_name" : "Aangepaste OAuth unieke naam", "days" : "dagen", "Deactivate" : "Deactiveren", + "Delete_Room_Warning" : "Het verwijderen van een kamer verwijdert ook alle in deze kamer geplaatste berichten. Dat kan niet ongedaan gemaakt worden!", "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", @@ -149,9 +178,11 @@ "FileUpload_MaxFileSize" : "Maximale bestandgsgrootte voor uploads (in bytes)", "FileUpload_MediaType_NotAccepted" : "Mediatypen niet geaccepteerd", "FileUpload_MediaTypeWhiteList" : "Geaccepteerde Media Types", + "FileUpload_MediaTypeWhiteListDescription" : "Komma-gescheiden lijst van 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.", + "Force_SSL" : "Dwing SSL af", "Forgot_password" : "Wachtwoord vergeten", "Fork_it_on_github" : "Kopieer ons op GitHub", "From_Email" : "Afzender e-mail", @@ -168,10 +199,16 @@ "inline_code" : "inline_code", "Install_Extension" : "Installeer Uitbreiding", "Install_FxOs" : "Rocket.Chat installeren op uw Firefox-", + "Install_FxOs_done" : "Super! Je kunt Rocket.Chat gebruiker d.m.v. het ikoon op je beginscherm. Veel plezier met Rocket.Chat!", "Install_FxOs_error" : "Sorry, dat werkte niet zoals de bedoeling! De volgende fout is verschenen:", + "Install_FxOs_follow_instructions" : "S.v.p. de app installatie op uw apparaten bevestigen (druk op \"Installeer\" wanneer daar om gevraagd wordt).", "Integration_added" : "Integratie is toegevoegd", + "Integration_Incoming_WebHook" : "Binnenkomende WebHook Integratie", + "Integration_New" : "Nieuwe Integratie", "Integration_updated" : "Integratie is bijgewerkt", - "Invalid_confirm_pass" : "De wachtwoorden zijn niet gelijk", + "Integrations" : "Integraties", + "Invalid_asset" : "Invalid asset", + "Invalid_confirm_pass" : "De wachtwoorden zijn verschillend", "Invalid_email" : "Ongeldig e-mail adres", "Invalid_file_height" : "Ongeldige hoogte", "Invalid_file_type" : "Ongeldig bestandstype", @@ -180,6 +217,8 @@ "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", + "Invalid_Secret_URL" : "Ongeldige geheime URL", + "Invalid_secret_URL_message" : "De gegeven URL is ongeldig.", "invisible" : "onzichtbaar", "Invisible" : "Onzichtbaar", "Invitation_HTML" : "Uitnodiging HTML", @@ -193,12 +232,14 @@ "is_typing_male" : "is aan het typen", "italics" : "cursief", "join" : "Toetreden", + "Join_audio_call" : "Voeg me toe aan audio gesprek", "Join_the_Community" : "Word lid", + "Join_video_call" : "Voeg me toe aan video gesprek", "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", + "Language_Version" : "Nederlandse versie", "Last_login" : "Laatste aanmelding", "Last_message" : "Laatste bericht", "Layout" : "Lay-out", @@ -211,21 +252,38 @@ "Layout_Sidenav_Footer_description" : "Footer afmetingen is 260 x 70px", "Layout_Terms_of_Service" : "Algemene Voorwaarden", "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", + "LDAP_Enable" : "Enable LDAP", + "LDAP_Enable_Description" : "Probeer LDAP te gebruiken voor authenticatie.", "LDAP_Port" : "LDAP Port", + "LDAP_Port_Description" : "Poort om LDAP te benaderen. bijv. 389", + "LDAP_Reject_Unauthorized" : "Reject Unauthorized", + "LDAP_Sync_User_Data_Description" : "Houd gebruikersdata synchroon met de server tijdens login (bijv. naam en 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" : "URLvan de LDAP server; bijv: ldap://company.dns.com", "Leave_room" : "Kamer verlaten", "line" : "lijn", "Load_more" : "Meer laden", "Loading..." : "Laden ...", "Loading_more_from_history" : "Meer oude berichten laden", "Loading_suggestion" : "Suggesties laden...", + "Logged_out_of_other_clients_successfully" : "Uitgeloggen van andere plekken was succevol", "Login" : "Log In", "Login_with" : "Login met %s", "login_with" : "Of log in met", "Logout" : "Uitloggen", + "Logout_Others" : "Uitloggen van andere plekken", "Make_Admin" : "Maak Admin", "Mark_as_read" : "Markeer als gelezen", + "Markdown_Headers" : "Markdown kopteksten", "Members" : "Leden", "Members_List" : "Ledenlijst", "Members_placeholder" : "Leden", @@ -233,7 +291,9 @@ "Message_AllowDeleting" : "Bericht verwijderen toestaan", "Message_AllowEditing" : "Bericht bewerken toestaan", "Message_AllowEditing_BlockEditInMinutes" : "Blokkeer berichtbewerkingen na (n) minuten", + "Message_AllowEditing_BlockEditInMinutesDescription" : "Vul 0 in om blokkeren uit te schakelen.", "Message_AudioRecorderEnabled" : "Audio Recorder Ingeschakeld", + "Message_AudioRecorderEnabledDescription" : "Vereist 'audio/wav' bestanden als geaccepteerd mediatype binnen de 'File Upload' instellingen.", "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", @@ -248,6 +308,7 @@ "Message_ShowEditedStatus" : "Toon Gewijzigde Status", "Message_ShowFormattingTips" : "Toon opmaaktips", "Messages" : "Berichten", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here" : "Berichten die worden verstuurd naar de binnenkomende WebHook zullen hier gepost worden.", "Meta" : "Meta", "Meta_fb_app_id" : "Facebook App Id", "Meta_google-site-verification" : "Google Site Verification", @@ -261,11 +322,14 @@ "Msgs" : "Berichten", "multi" : "multi", "Mute_user" : "Maak gebruiker stil", + "Muted" : "Mond Snoeren", "My_Account" : "Mijn account", "n_messages" : "%s berichten", "Name" : "Naam", "Name_cant_be_empty" : "De naam mag niet leeg zijn", + "Name_optional" : "Naam (optioneel)", "New_Application" : "Nieuwe toepassing", + "New_integration" : "Nieuwe intergratie", "New_messages" : "Nieuwe berichten", "New_password" : "Nieuw Wachtwoord", "No_channel_with_name_%s_was_found" : "Geen kanaal met de naam <strong>\"%s\"</strong> gevonden", @@ -274,6 +338,7 @@ "No_favorites_yet" : "U heeft nog geen favorieten toegevoegd.", "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_livechats" : "Je hebt geen livechats.", "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", @@ -283,6 +348,8 @@ "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", + "OAuth_Application" : "OAuth Application", + "OAuth_Applications" : "OAuth Applications", "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", @@ -290,15 +357,18 @@ "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.", + "optional" : "optioneel", "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_value_for_url" : "Vul s.v.p. een URL voor uw Avatar in.", "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_as" : "Stuur als", "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", @@ -320,18 +390,25 @@ "Push_debug" : "Debug", "push_disabled" : "Push notificaties uitgeschakeld", "Push_enable" : "Enable", + "Push_enable_gateway" : "Enable Gateway", + "Push_gateway" : "Gateway", + "Push_gcm_api_key" : "GCM API Sleutel", + "Push_gcm_project_number" : "GCM Projektnummer", "Push_production" : "Productie", "Push_test_push" : "Test", "Quick_Search" : "Snelzoeken", "quote" : "citaat", "Recents" : "Recente", "Record" : "Opnemen", + "Redirect_URI" : "Redirect URI", "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", + "Remove_as_moderator" : "Verwijder als moderator", + "Remove_as_owner" : "Verwijder als eigenaar", "Remove_custom_oauth" : "Verwijder aangepaste OAuth", "Remove_from_room" : "Verwijderen uit de kamer", "Removed" : "Verwijderd", @@ -352,13 +429,18 @@ "Rooms" : "Kamers", "S_new_messages_since_s" : "%s nieuwe berichten sinds %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" : "Wijzigingen opslaan", "Save_Mobile_Bandwidth" : "Bespaar op mobile bandbreedte", "Screen_Share" : "Scherm delen", "Search" : "Zoeken", "Search_Messages" : "Berichten zoeken", "Search_settings" : "Zoekinstellingen", - "seconds" : "secondes", + "seconds" : "seconden", "See_all" : "Alles zien", "See_only_online" : "Alleen online", "Select_an_avatar" : "Selecteer een afbeelding", @@ -376,14 +458,18 @@ "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", + "Send_your_JSON_payloads_to_this_URL" : "Verstuur je JSON payload naar deze URL.", + "Set_as_moderator" : "Stel in als moderator", + "Set_as_owner" : "Maak eigenaar", "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_archived_results" : "<p>Zichtbaar: <b>%s</b> gearchiveerde resultaten</p>", "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", + "since_creation" : "sinds %s", "Site_Name" : "Site naam", "Site_Url" : "URL van de site", "Site_Url_Description" : "Voorbeeld: https://chat.domain.com/", @@ -391,9 +477,13 @@ "SMTP_Host" : "SMTP Host", "SMTP_Password" : "SMTP-wachtwoord", "SMTP_Port" : "SMTP Poort", + "SMTP_Test_Button" : "Test SMTP Instellingen", "SMTP_Username" : "SMTP Gebruikersnaam", "Sound" : "Geluid", + "Start_audio_call" : "Begin audio gesprek", "Start_of_conversation" : "Begin van het gesprek", + "Start_video_call" : "Begin video gesprek", + "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" : "Begin met <code class=\"inline\">%s</code> voor gebruiker of <code class=\"inline\">%s</code> voor kanaal. Bijv.: <code class=\"inline\">%s</code> of <code class=\"inline\">%s</code>", "Statistics" : "Statistieken", "Stats_Active_Users" : "Actieve gebruikers", "Stats_Avg_Channel_Users" : "Gemiddeld aantal Kanaal Gebruikers", @@ -422,11 +512,16 @@ "strike" : "doorhalen", "Submit" : "Verzenden", "Success" : "Succes", + "The_application_name_is_required" : "Th _application name is required", "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_redirectUri_is_required" : "The redirectUri is required", "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>!", + "The_user_will_be_removed_from_s" : "De gebruiker zal worden verwijderd van %s", + "The_user_wont_be_able_to_type_in_s" : "De gebruiker kan niet typen in %s", + "There_are_no_integrations" : "Er zijn geen integraties", "This_is_a_push_test_messsage" : "Dit is een push-test messsage", "True" : "True", "Type_your_new_password" : "Typ uw nieuwe wachtwoord", @@ -444,11 +539,21 @@ "Use_this_username" : "Gebruik deze gebruikersnaam", "Use_uploaded_avatar" : "Gebruik geüploade afbeelding", "Use_url_for_avatar" : "Gebruik url voor 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" : "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_has_been_muted_in_s" : "Gebruiker is de mond gesnoerd in %s", + "User_has_been_removed_from_s" : "Gebruiker is verwijderd van %s", "User_Info" : "Gebruikers informatie", "User_is_no_longer_an_admin" : "Gebruiker is niet langer een admin", "User_is_not_activated" : "Gebruiker is niet geactiveerd", @@ -478,6 +583,8 @@ "Username_title" : "Registreer Gebruikersnaam", "Username_unavaliable" : "<strong>%s</strong> is al in gebruik :(", "Users" : "Gebruikers", + "UTF8_Names_Slugify" : "UTF8 Names Slugify", + "UTF8_Names_Validation" : "UTF8 Names Validation", "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.", @@ -485,15 +592,21 @@ "We_have_sent_registration_email" : "Wij hebben een e-mail gestuurd om uw registratie te bevestigen. Als u deze e-mail niet snel ontvangt, ook niet in uw spam-folder, kom dan terug en probeer het opnieuw.", "Welcome" : "Welkom <em>%s</em>.", "Welcome_to_the" : "Welkom bij de", + "will_be_able_to" : "zal in staat zijn om", "With_whom" : "Met wie", + "Yes" : "Ja", "Yes_clear_all" : "Ja, alles wissen!", "Yes_delete_it" : "Ja, verwijder het!", + "Yes_mute_user" : "Ja, snoer gebruiker de mond!", + "Yes_remove_user" : "Ja, verwijder gebruiker!", "you_are_in_preview_mode_of" : "U kijkt naar de voorbeschouwing van kanaal #<strong>__room_name__</strong>", + "You_are_logged_in_as" : "Je bent ingelogd als", "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_should_name_it_to_easily_manage_your_integrations" : "Je moet het een naam geven om je integraties eenvoudig te kunnen beheren.", "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_mail_was_sent_to_s" : "Uw e-mail werd verzonden naar %s", diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index e4af9ea8aba..74cecc34220 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -31,6 +31,7 @@ "Accounts_OAuth_Github_secret" : "GitHub Secret", "Accounts_OAuth_Gitlab" : "OAuth Ativado", "Accounts_OAuth_Gitlab_id" : "Gitlab Id", + "Accounts_OAuth_Gitlab_secret" : "Segredo", "Accounts_OAuth_Google" : "Login do Google", "Accounts_OAuth_Google_id" : "Google Id", "Accounts_OAuth_Google_secret" : "Google Secret", @@ -85,6 +86,7 @@ "busy_male" : "ocupado", "Busy_male" : "Ocupado", "Cancel" : "Cancelar", + "CDN_PREFIX" : "Prefixo CDN", "Certificates_and_Keys" : "Certificados e Chaves", "Change_avatar" : "Alterar avatar", "Channels" : "Canais", @@ -144,6 +146,7 @@ "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.", + "Force_SSL" : "Forçar SSL", "Forgot_password" : "Esqueceu sua senha", "Fork_it_on_github" : "Fork it on github", "From_Email" : "Email De", @@ -159,6 +162,7 @@ "Incorrect_Password" : "Senha incorreta", "inline_code" : "código", "Install_FxOs" : "Instale o Rocket.Chat em seu Firefox", + "Invalid_asset" : "Arquivo Inválido", "Invalid_confirm_pass" : "A confirmação de senha não é igual à senha", "Invalid_email" : "O e-mail informado é inválido", "Invalid_file_height" : "Altura de arquivo inválida", @@ -197,11 +201,16 @@ "Layout_Sidenav_Footer_description" : "Tamanho do rodapé é 260x70", "Layout_Terms_of_Service" : "Termos de Serviço", "LDAP" : "LDAP", + "LDAP_Bind_Search" : "Busca Cega", + "LDAP_CA_Cert" : "Certificado CA", "LDAP_DN" : "DN LDAP", + "LDAP_DN_Description" : "Busca RaÃz; exemplo: dc=domain,dc=com", "LDAP_Enable" : "Ativar LDAP", "LDAP_Port" : "Porta LDAP", + "LDAP_Reject_Unauthorized" : "Rejeitar Não Autorizados", "LDAP_Sync_User_Data" : "Manter dados dos usuários sincronizados", "LDAP_Sync_User_Data_FieldMap" : "Mapeamento de campos do usuário", + "LDAP_TLS" : "TLS", "LDAP_Url" : "URL LDAP", "Leave_room" : "Sair da sala", "line" : "linha", @@ -215,6 +224,7 @@ "Logout" : "Sair", "Make_Admin" : "Tornar Administrador", "Mark_as_read" : "Marcar como lido", + "Markdown_Headers" : "Cabeçalhos", "Members" : "Membros", "Members_List" : "Lista de Membros", "Members_placeholder" : "Membros", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index ee1c1597ec3..3d021115ca8 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -21,10 +21,12 @@ "Accounts_OAuth_Custom_Enable" : "Включить", "Accounts_OAuth_Custom_Secret" : "Ключ", "Accounts_OAuth_Custom_URL" : "URL", + "Accounts_OAuth_Facebook" : "Facebook логин", "Accounts_OAuth_Gitlab" : "OAuth включен", "Accounts_OAuth_Google" : "Google логин", "Accounts_OAuth_Google_id" : "Google ID", "Accounts_OAuth_Google_secret" : "Google пароль", + "Accounts_PasswordReset" : "ВоÑÑтановить пароль", "Accounts_RegistrationRequired" : "ТребуетÑÑ Ñ€ÐµÐ³Ð¸ÑтрациÑ", "Activate" : "Ðктивировать", "Add_custom_oauth" : "Добавить пользовательÑкий OAuth", @@ -32,6 +34,7 @@ "Add_users" : "Добавить пользователей", "Administration" : "ÐдминиÑтрирование", "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "ПоÑле аутентификации OAuth2, пользователи будут перенаправлÑÑ‚ÑŒÑÑ Ð½Ð° Ñтот URL", + "Alias" : "ÐлиаÑ", "All_channels" : "Ð’Ñе Чаты", "Allow_Invalid_SelfSigned_Certs" : "Разрешить невалидные ÑамоподпиÑанные Ñертификаты", "Allow_Invalid_SelfSigned_Certs_Description" : "Разрешить некорректные и ÑамоподпиÑанные SSL Ñертификаты Ð´Ð»Ñ ÑвÑзи валидации и предпроÑмотра", @@ -59,6 +62,7 @@ "busy_male" : "занÑÑ‚", "Busy_male" : "ЗанÑÑ‚", "Cancel" : "Отмена", + "Certificates_and_Keys" : "Ключи и Ñертификаты", "Change_avatar" : "Сменить аватар", "Channels" : "Чаты", "Channels_list" : "СпиÑок общих чатов", @@ -70,6 +74,7 @@ "Contact" : "Контакт", "Conversation" : "Диалог", "Convert_Ascii_Emojis" : "Конвертировать ASCII в Emoji", + "COPY_TO_CLIPBOARD" : "Скопировать в буфер обмена", "Create_new" : "Создать новый", "Create_new_direct_message_room" : "Создать комнату Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… Ñообщений", "Create_new_private_group" : "Создать новый приватный чат", @@ -96,9 +101,11 @@ "Email_already_exists" : "Ðл. Ð°Ð´Ñ€ÐµÑ ÑƒÐ¶Ðµ ÑущеÑтвует", "Email_or_username" : "Почтовый Ñщик или логин", "Email_verified" : "E-mail проверÑетÑÑ", + "Emoji" : "Emoji", "Enable_Desktop_Notifications" : "Включить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ Ñтола", "Enter_info" : "Введите Ñвои данные", "Enter_to" : "Войти в", + "Error" : "Ошибка", "Error_changing_password" : "Ошибка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ", "Error_too_many_requests" : "Ошибка, Ñлишком много запроÑов. ПожалуйÑта, помедленнее. Ð’Ñ‹ должны подождать%s Ñекунд, прежде чем попробовать Ñнова", "Esc_to" : "Выйти из", @@ -123,6 +130,9 @@ "hours" : "чаÑ(Ñ‹)", "Incorrect_Password" : "Ðеверный пароль", "inline_code" : "внутренний код", + "Install_FxOs" : "УÑтановить Rocket.Chat на Firefox", + "Integration_New" : "ÐÐ¾Ð²Ð°Ñ Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ", + "Integrations" : "Интеграции", "Invalid_confirm_pass" : "Пароли не Ñовпадают", "Invalid_email" : "Ðеверный e-mail", "Invalid_file_type" : "Ðеверный тип файла", @@ -201,6 +211,7 @@ "n_messages" : "%s Ñообщений", "Name" : "ИмÑ", "Name_cant_be_empty" : "Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым", + "New_integration" : "ÐÐ¾Ð²Ð°Ñ Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ", "New_messages" : "Ðовые ÑообщениÑ", "New_password" : "Ðовый пароль", "No_channel_with_name_%s_was_found" : "Чат Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ <strong>\"%s\"</strong> не найден!", @@ -241,6 +252,7 @@ "Proudly_developed" : "Разработано Ñ Meteor", "Push_debug" : "Отладка", "Push_enable" : "Включить", + "Push_test_push" : "ТеÑÑ‚", "Quick_Search" : "БыÑтрый поиÑк", "quote" : "цитата", "Recents" : "Ðедавние", @@ -253,16 +265,20 @@ "Remove_custom_oauth" : "Удалить пользовательÑкий OAuth", "Remove_from_room" : "Удалить из чата", "Reset_password" : "СброÑить пароль", + "Restart" : "ПерезапуÑтить", + "Restart_the_server" : "ПерезапуÑтить Ñервер", "Room" : "Чат", "Room_name_changed" : "Ðазвание чата изменено: <em>__room_name__</em> пользователем <em>__user_by__</em>", "Room_name_changed_successfully" : "Ðазвание чата уÑпешно изменено", "Room_not_found" : "Комната не найдена", + "Room_unarchived" : "Комната в архиве", "Room_uploaded_file_list" : "СпиÑок файлов", "Room_uploaded_file_list_empty" : "Ðет доÑтупных файлов", "room_user_count" : "%s пользователей", "Rooms" : "Чаты", "S_new_messages_since_s" : "%s новых Ñообщений Ñ %s", "Save_changes" : "Сохранить изменениÑ", + "Save_Mobile_Bandwidth" : "Включить режим Ñкономии трафика", "Search" : "ПоиÑк", "Search_Messages" : "ПоиÑк Ñообщений", "Search_settings" : "ÐаÑтройки поиÑка", @@ -271,6 +287,7 @@ "See_only_online" : "Только в Ñети", "Select_an_avatar" : "Выбор автара", "Select_file" : "Выберите файл", + "Select_service_to_login" : "Выберите ÑÐµÑ€Ð²Ð¸Ñ Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð° или загрузите изображение Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°", "Selected_users" : "Выбранные учаÑтники", "Send" : "Отправить", "Send_confirmation_email" : "Отправить пиÑьмо Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸ÐµÐ¼", @@ -322,6 +339,7 @@ "The_field_is_required" : "Поле %s обÑзательно.", "True" : "Да", "Type_your_new_password" : "Введите новый пароль", + "Unarchive" : "ВоÑÑтановить", "Unnamed" : "Без названиÑ", "Upload_file_question" : "Загрузить файл?", "Use_Emojis" : "ИÑпользовать Emojis", @@ -371,6 +389,7 @@ "Welcome" : "Добро пожаловать, <em>%s</em>.", "Welcome_to_the" : "Добро пожаловать в", "With_whom" : "C кем", + "Yes" : "Да", "Yes_delete_it" : "Да, удалить его!", "you_are_in_preview_mode_of" : "Ð’Ñ‹ находитеÑÑŒ в режиме предварительного проÑмотра канала # <strong>__room_name__</strong>", "You_can_use_an_emoji_as_avatar" : "Ð’Ñ‹ также можете иÑпользовать emoji в качеÑтве аватара.", diff --git a/packages/rocketchat-authorization/i18n/ar.i18n.json b/packages/rocketchat-authorization/i18n/ar.i18n.json index 2c88e2e3004..a1884b20bcd 100644 --- a/packages/rocketchat-authorization/i18n/ar.i18n.json +++ b/packages/rocketchat-authorization/i18n/ar.i18n.json @@ -3,7 +3,7 @@ "Back_to_permissions" : "العودة إلى التصريØات", "Permissions" : "التصريØات", "Saving" : "جاري الØÙظ", - "User_added" : "وأضا٠العضو <em>__user_added__</em>.", + "User_added" : "تمت إضاÙØ© المستخدم", "User_not_found" : "لم يتم العثور على المستخدم", "User_removed" : "تم إزالة المستخدم" } \ 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 60691f938cd..d2e16b8687c 100644 --- a/packages/rocketchat-authorization/i18n/ru.i18n.json +++ b/packages/rocketchat-authorization/i18n/ru.i18n.json @@ -1,6 +1,9 @@ { "Back_to_permissions" : "Ðазад к наÑтройкам прав", "Permissions" : "ÐаÑтройка прав", + "Saving" : "Сохранение", "User_added" : "Пользователь <em>__user_added__</em> добавлен.", + "User_not_found" : "Пользователь не найден", + "User_removed" : "Пользователь удален", "Users_in_role" : "Пользователи Ñ Ñ€Ð¾Ð»ÑŒÑŽ" } \ No newline at end of file diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json index ad10bc3dc16..c7209e3877d 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/ar.i18n.json @@ -1,4 +1,5 @@ { + "Additional_emails" : "عناوين إلكترونية إضاÙية", "Choose_messages" : "اختر الرسائل", "From" : "من", "Sending" : "جار الإرسال...", diff --git a/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json b/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json index ab0b7fd7daa..4da1563f4db 100644 --- a/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings-mail-messages/i18n/nl.i18n.json @@ -3,9 +3,12 @@ "Body" : "Body", "Choose_messages" : "Kies berichten", "From" : "Afzender", + "Mail_Message_Invalid_emails" : "Je hebt één of meer ongeldige e-mails gegeven: %s", "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", + "Mail_Messages_Instructions" : "Kies welke berichten je wil versturen via e-mail door te klikken op de berichten", + "Mail_Messages_Subject" : "Hier is een geselecteerd deel van %s berichten", "Sending" : "Verzenden ...", "Subject" : "Onderwerp", "To_users" : "Aan Gebruikers", diff --git a/packages/rocketchat-channel-settings/i18n/nl.i18n.json b/packages/rocketchat-channel-settings/i18n/nl.i18n.json index 80b675a4377..9bf8f2e51fb 100644 --- a/packages/rocketchat-channel-settings/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/nl.i18n.json @@ -6,6 +6,8 @@ "Topic" : "Onderwerp", "Type" : "Type", "Room_Info" : "Kamer 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_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/ru.i18n.json b/packages/rocketchat-channel-settings/i18n/ru.i18n.json index 99a76b5c0d7..a64567e5286 100644 --- a/packages/rocketchat-channel-settings/i18n/ru.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/ru.i18n.json @@ -1,9 +1,12 @@ { "Archive_Unarchive" : "Удалить / ВоÑÑтановить", + "Channel" : "Публичный чат", + "Private_Group" : "Приватный чат", "Save" : "Сохранить", "Topic" : "Тема", "Type" : "Тип", "room_changed_privacy" : "Тип чата изменен на: <em>__room_type__</em> by <em>__user_by__</em>", + "room_changed_topic" : "Тема чата Ñменена <em>__user_by__</em> на: <em>__room_topic__</em>", "Room_topic_changed_successfully" : "Тема чата уÑпешно изменена", "Room_type_changed_successfully" : "Тип чата уÑпешно изменен" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/ar.i18n.json b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json index 16216ec3e86..955429f5c8f 100644 --- a/packages/rocketchat-github-enterprise/i18n/ar.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/ar.i18n.json @@ -1,3 +1,3 @@ { - "Github_Enterprise_Url_No_Trail" : "مثال: http://domain.com (باستثناء زائدة مائل)" + "Github_Enterprise_Url_No_Trail" : "مثال: http://domain.com (بدون الشرطة المائلة ÙÙŠ الأخير)" } \ No newline at end of file diff --git a/packages/rocketchat-github-enterprise/i18n/pt.i18n.json b/packages/rocketchat-github-enterprise/i18n/pt.i18n.json index d10b177181f..166d33df332 100644 --- a/packages/rocketchat-github-enterprise/i18n/pt.i18n.json +++ b/packages/rocketchat-github-enterprise/i18n/pt.i18n.json @@ -2,5 +2,6 @@ "Accounts_OAuth_GitHub_Enterprise" : "OAuth Ativado", "API_GitHub_Enterprise_URL" : "URL do servidor", "Accounts_OAuth_GitHub_Enterprise_id" : "GitHub Id", + "Accounts_OAuth_GitHub_Enterprise_secret" : "Segredo", "Github_Enterprise_Url_No_Trail" : "Nota: excluir barra final" } \ No newline at end of file diff --git a/packages/rocketchat-ldap/i18n/nl.i18n.json b/packages/rocketchat-ldap/i18n/nl.i18n.json index 6f31cf5a2e6..22e1aec0e15 100644 --- a/packages/rocketchat-ldap/i18n/nl.i18n.json +++ b/packages/rocketchat-ldap/i18n/nl.i18n.json @@ -1 +1,3 @@ -{ } \ No newline at end of file +{ + "LDAP_Dn" : "LDAP DN" +} \ 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 39d4c63986e..a006a3d947d 100644 --- a/packages/rocketchat-lib/i18n/nl.i18n.json +++ b/packages/rocketchat-lib/i18n/nl.i18n.json @@ -1,6 +1,6 @@ { "All_logs" : "Alle logs", - "Debug_Level" : "Debug Level", + "Debug_Level" : "Debug Nivo", "Delete" : "Verwijder", "Edit" : "Wijzig", "Only_errors" : "Alleen fouten" diff --git a/packages/rocketchat-livechat/app/i18n/ru.i18n.json b/packages/rocketchat-livechat/app/i18n/ru.i18n.json index 9a8fba30e6a..68485e4d4b5 100644 --- a/packages/rocketchat-livechat/app/i18n/ru.i18n.json +++ b/packages/rocketchat-livechat/app/i18n/ru.i18n.json @@ -1,3 +1,4 @@ { + "Skip" : "ПропуÑтить", "Start_Chat" : "Ðачать Чат" } \ No newline at end of file diff --git a/packages/rocketchat-livechat/i18n/ar.i18n.json b/packages/rocketchat-livechat/i18n/ar.i18n.json index 5d22fd60b4c..f0cd8f5e397 100644 --- a/packages/rocketchat-livechat/i18n/ar.i18n.json +++ b/packages/rocketchat-livechat/i18n/ar.i18n.json @@ -1,17 +1,35 @@ { "Add" : "إضاÙØ©", + "Add_agent" : "أض٠وكيل", + "Add_manager" : "أض٠مدير", + "Agent_added" : "تمت إضاÙØ© الوكيل", + "Agent_removed" : "تمت إزالة الوكيل", + "Available_agents" : "الوكلاء الموجودون", "Back" : "العودة", "Closed" : "مغلق", "Copy_to_clipboard" : "نسخ إلى الØاÙظة", + "Departments" : "الأقسام", "Description" : "الوصÙ", "Enable" : "تمكين", + "Enabled" : "Ù…Ùعل", "Enter_a_username" : "أدخل اسم المستخدم", - "Livechat_enabled" : "مكنت LIVECHAT", - "Livechat_title" : "عنوان الدردشة الØية", - "Livechat_title_color" : "لون خلÙية عنوان الدردشة الØية", + "Livechat_agents" : "وكلاء المØادثات الØية", + "Livechat_Dashboard" : "لوØØ© المØادثات الØية", + "Livechat_enabled" : "تÙعيل المØادثات الØية", + "Livechat_Manager" : "مدير المØادثات الØية", + "Livechat_managers" : "مدراء المØادثات الØية", + "Livechat_title" : "عنوان المØادثة الØية", + "Livechat_title_color" : "لون خلÙية عنوان المØادثة الØية", + "Livechat_Users" : "مستخدمي المØادثات الØية", + "Manager_added" : "تمت إضاÙØ© المدير", + "Name_of_agent" : "اسم الوكيل", + "Num_Agents" : "وكلاء", "Please_fill_a_username" : "يرجى ملء اسم المستخدم", "Saved" : "تم الØÙظ", + "Selected_agents" : "الوكلاء المختارون", "Send_a_message" : "إرسال رسالة", "Theme" : "سمات", - "Time_in_seconds" : "الوقت بالثواني" + "There_are_no_agents_added_to_this_department_yet" : "لا يوجد وكلاء مضاÙون لهذا القسم", + "Time_in_seconds" : "الوقت بالثواني", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site" : "لتركيب المØادثات الØية ÙÙŠ موقعك انسخ Ùˆ الصق النص التالي قبل آخر علامة <strong></body></strong> ÙÙŠ موقعك." } \ 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 f185cf0c6c3..05e49d4a425 100644 --- a/packages/rocketchat-livechat/i18n/nl.i18n.json +++ b/packages/rocketchat-livechat/i18n/nl.i18n.json @@ -1,6 +1,10 @@ { "Add" : "Toevoegen", + "Add_agent" : "Voeg agent toe", "Add_manager" : "Manager toevoegen", + "Agent_added" : "Agent toegevoegd", + "Agent_removed" : "Agent verwijderd", + "Available_agents" : "Beschikbare agenten", "Back" : "Terug", "Closed" : "Gesloten", "Copy_to_clipboard" : "Kopieer naar klembord", @@ -11,11 +15,13 @@ "Departments" : "Afdelingen", "Description" : "Beschrijving", "Edit_Department" : "Afdeling bewerken", + "Empty_title" : "Lege titel", "Enable" : "Inschakelen", "Enabled" : "Ingeschakeld", "Enter_a_regex" : "Voer een reguliere expressie in", "Enter_a_username" : "Voer een gebruikersnaam in", "Live_sessions" : "Live sessies", + "Livechat_agents" : "Livechat agenten", "Livechat_Dashboard" : "Livechat Dashboard", "Livechat_enabled" : "Livechat beschikbaar", "Livechat_Manager" : "Livechat Manager", @@ -26,13 +32,18 @@ "Manager_added" : "Manager toegevoegd", "Manager_removed" : "Manager verwijderd", "Name_of_agent" : "Naam agent", + "Navigation_History_20_last_pages" : "Navigatie Geschiedenis (20 laatste pagina's)", "New_Department" : "Nieuwe afdeling", + "Num_Agents" : "# Agenten", "Opened" : "Geopend", + "Order" : "Bestelling", "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", + "Selected_agents" : "Geselecteerde agenten", "Send_a_message" : "Stuur een bericht", + "Show_preregistration_form" : "<p>Showing <b>%s</b> archived results</p>", "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", diff --git a/packages/rocketchat-livechat/i18n/ru.i18n.json b/packages/rocketchat-livechat/i18n/ru.i18n.json index ea345d96bfe..a50eda105f2 100644 --- a/packages/rocketchat-livechat/i18n/ru.i18n.json +++ b/packages/rocketchat-livechat/i18n/ru.i18n.json @@ -1,4 +1,7 @@ { + "Back" : "Ðазад", + "Dashboard" : "Панель", "Livechat_enabled" : "Включен Livechat", - "Livechat_title" : "Ðазвание чата" + "Livechat_title" : "Ðазвание чата", + "Saved" : "Сохранено" } \ 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 3c6d8dec0b9..b9565675e4a 100644 --- a/packages/rocketchat-mailer/i18n/nl.i18n.json +++ b/packages/rocketchat-mailer/i18n/nl.i18n.json @@ -1,11 +1,19 @@ { + "From_email_warning" : "<b>Waarschuwing</b>: Het veld <b>Afzender</b> is afhankelijk van je mail mail server instellingen.", "From_email_is_required" : "Afzender e-mailadres is verplicht", + "Dry_run" : "Testrun", "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", + "Mailer" : "Mailer", + "Mailer_body_tags" : "Je <b>moet</b> [unsubscribe] gebruiken voor een unsubscribe link.<br />Je kunt [name], [fname], [lname] gebruiken voor een gebruikers volledige naam, voorname of achtername.<br />Je kunt [email] gebruiken voor het email adres van de gebruiker.", + "Query" : "Query/vraag", + "Query_description" : "Additional conditions for determining which users to send the e-mail to. Unsubscribed users are automatically removed from the query. It must be a valid JSON. Example: \"{\"createdAt\":{\"$gt\":{\"$date\": \"2015-01-01T00:00:00.000Z\"}}}\"", "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." + "You_have_successfully_unsubscribed" : "U bent uitgeschreven van onze mailinglijst.", + "You_informed_an_invalid_FROM_address" : "You informed an invalid FROM address.", + "You_must_provide_the_unsubscribe_link" : "Je moet een [unsubscribe] link toevoegen." } \ 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 980d68b0494..8cc4c4bbbb1 100644 --- a/packages/rocketchat-mailer/i18n/ru.i18n.json +++ b/packages/rocketchat-mailer/i18n/ru.i18n.json @@ -1,3 +1,6 @@ { - "Dry_run_description" : "Мы отправим только один e-mail на Ð°Ð´Ñ€ÐµÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¹ в поле \"От\". E-mail Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ принадлежать дейÑтвительному пользователю." + "Dry_run_description" : "Мы отправим только один e-mail на Ð°Ð´Ñ€ÐµÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¹ в поле \"От\". E-mail Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ принадлежать дейÑтвительному пользователю.", + "Email_from" : "От", + "Email_subject" : "Тема", + "Email_body" : "Тело ÑообщениÑ" } \ No newline at end of file diff --git a/packages/rocketchat-message-pin/i18n/ar.i18n.json b/packages/rocketchat-message-pin/i18n/ar.i18n.json index 3a3ddcfed54..0c807dd507f 100644 --- a/packages/rocketchat-message-pin/i18n/ar.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ar.i18n.json @@ -1,5 +1,6 @@ { - "Message_AllowPinning" : "Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ«Ø¨ÙŠØ« الرسائل", + "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 721e551b321..c65f611f26f 100644 --- a/packages/rocketchat-message-pin/i18n/nl.i18n.json +++ b/packages/rocketchat-message-pin/i18n/nl.i18n.json @@ -1,3 +1,10 @@ { - "Message_AllowPinning" : "Bericht vastzetten toestaan" + "Message_AllowPinning" : "Bericht vastzetten toestaan", + "Message_AllowPinning_Description" : "Sta berichten vastzetten toe op elk kanaal.", + "Message_AllowPinningByAnyone" : "Sta iedereen toe om berichten vast te zetten", + "Message_AllowPinningByAnyone_Description" : "Sta iedereen toe om berichten vast te zetten op een kanaal, niet alleen beheerders.", + "Pin_Message" : "Zet bericht vast", + "Unpin_Message" : "Bericht niet meer vastzetten", + "Pinned_Messages" : "Vastgezette berichten", + "No_pinned_messages" : "Geen vastgezette berichten" } \ 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 a83261331d9..3186de821e3 100644 --- a/packages/rocketchat-message-pin/i18n/ru.i18n.json +++ b/packages/rocketchat-message-pin/i18n/ru.i18n.json @@ -1,6 +1,8 @@ { "Message_AllowPinning" : "Разрешить прикреплÑÑ‚ÑŒ ÑообщениÑ", "Message_AllowPinning_Description" : "Разрешить прикреплÑÑ‚ÑŒ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ðº любому из каналов", + "Pin_Message" : "Прикрепить Ñообщение", + "Unpin_Message" : "Открепить Ñообщение", "Pinned_Messages" : "Прикрепленные ÑообщениÑ", "No_pinned_messages" : "Ðет прикрепленных Ñообщений" } \ No newline at end of file diff --git a/packages/rocketchat-message-star/i18n/nl.i18n.json b/packages/rocketchat-message-star/i18n/nl.i18n.json index 6f31cf5a2e6..c0c10c77fd7 100644 --- a/packages/rocketchat-message-star/i18n/nl.i18n.json +++ b/packages/rocketchat-message-star/i18n/nl.i18n.json @@ -1 +1,7 @@ -{ } \ No newline at end of file +{ + "Message_AllowStarring" : "Sta markeren toe", + "Star_Message" : "Markeer bericht", + "Unstar_Message" : "Verwijder markering", + "Starred_Messages" : "Gemarkeerde berichten", + "No_starred_messages" : "Geen gemarkeerde berichten" +} \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/ar.i18n.json b/packages/rocketchat-theme/i18n/ar.i18n.json index bdfad243ecf..8994fffc24c 100644 --- a/packages/rocketchat-theme/i18n/ar.i18n.json +++ b/packages/rocketchat-theme/i18n/ar.i18n.json @@ -1,4 +1,5 @@ { + "theme-color-blockquote-background" : "لون خلÙية الاقتباس", "theme-color-status-away" : "لون Øالة بعيد", "theme-color-status-busy" : "لون Øالة مشغول" } \ No newline at end of file diff --git a/packages/rocketchat-theme/i18n/nl.i18n.json b/packages/rocketchat-theme/i18n/nl.i18n.json index 70a0eeb7d0b..711f97279e7 100644 --- a/packages/rocketchat-theme/i18n/nl.i18n.json +++ b/packages/rocketchat-theme/i18n/nl.i18n.json @@ -1,6 +1,31 @@ { + "theme-color-action-buttons-color" : "Aktie knoppen kleur", "theme-color-active-channel-background-color" : "Actieve Kanaal Achtergrondkleur", "theme-color-active-channel-font-color" : "Actieve Kanaal Tekstkleur", + "theme-color-blockquote-background" : "Blockquote Achtergrondkleur", + "theme-color-clean-buttons-color" : "Clean Buttons Color", + "theme-color-code-background" : "Code Achtergrondkleur", + "theme-color-code-border" : "Code Randkleur", + "theme-color-code-color" : "Code Kleur", + "theme-color-content-background-color" : "Inhoud Achtergrondkleur", + "theme-color-custom-scrollbar-color" : "Handmatige Scrollbarkleur", + "theme-color-info-active-font-color" : "Aktieve Info Tekstkleur", + "theme-color-info-font-color" : "Info Tekstkleur", + "theme-color-input-font-color" : "Input Tekstkleur", + "theme-color-link-font-color" : "Link Tekstkleur", "theme-color-message-hover-background-color" : "Achtergrondkleur als muis er boven is", + "theme-color-primary-background-color" : "Primaire Achtergrondkleur", + "theme-color-primary-font-color" : "Primaire Tekstkleur", + "theme-color-quaternary-font-color" : "Quaternary Font Color", + "theme-color-secondary-background-color" : "Secondaire Achtergrondkleur", + "theme-color-secondary-font-color" : "Secondaire Tekstkleur", + "theme-color-smallprint-font-color" : "Kleine-tekst Tekstkleur", + "theme-color-smallprint-hover-color" : "Small Print Hover Color", + "theme-color-status-away" : "Afwezig Statuskleur", + "theme-color-status-busy" : "Bezet Statuskleur", + "theme-color-status-offline" : "Offline Statuskleur", + "theme-color-status-online" : "Online Statuskleur", + "theme-color-tertiary-background-color" : "Tertiaire Achtergronkleur", + "theme-color-tertiary-font-color" : "Tertiaire Tekstkleur ", "theme-color-unread-notification-color" : "Ongelezen Notificaties Kleur" } \ No newline at end of file -- GitLab From a38d58936659c52e81ded46c3ef0277f09d64faf Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 25 Jan 2016 12:07:36 -0200 Subject: [PATCH 1277/1338] version bump to 0.15.0 --- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- HISTORY.md | 22 +++++++++++++++++++++- packages/rocketchat-lib/rocketchat.info | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 8efc4b1b3b2..8aaf0efe2b0 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 10, # Increment this for every release. + appVersion = 11, # Increment this for every release. - appMarketingVersion = (defaultText = "0.14.0"), + appMarketingVersion = (defaultText = "0.15.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/HISTORY.md b/HISTORY.md index d662cf889e6..dee3e05d488 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,8 +1,28 @@ ## NEXT -- Ability to change email on account #1462 - +## 0.15.0, 2016-Jan-25 + +- Ability to change email on account +- Temporary fix for AM/PM timestamp breaking cog +- Fixed typo in oembed widget +- Change to process.exit(1) to restart server +- Add "Default Domain" to LDAP config +- Fix boolean environment variables +- Include a fallback click event for loading more messages +- Fix html h3 tag was closed with h4 +- Allow changing e-mail; invalidates verification on e-mail change +- Enable editing via admin / users +- Log error when trigger url returns 500 +- Bind starttls correctly for LDAP +- Custom oAuth supporting json or plain content_types responses of the identity +- Allow pass room id to direct rooms +- Outgoing: Get the room from posted message to reply +- Change Meteor.absoluteUrl to force SSL if Force_SSL is true +- Escape regexp on checking email availability; change type of input to email +- Fix check for MAIL_URL when it's server side only + ## 0.14.0, 2016-Jan-18 - Added admin setting to Force SSL diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index 37f939dff5b..cbdbae8748e 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.14.0" + "version": "0.15.0" } -- GitLab From 3fe5ae9ce9d3b315c79b5d2c41db44b16cc9ab60 Mon Sep 17 00:00:00 2001 From: Sven Mueller <mueller@synyx.de> Date: Mon, 25 Jan 2016 17:45:43 +0100 Subject: [PATCH 1278/1338] Code review fixes * Client-side showUserInfo is no longer cleared * Server-side now handles empty messages * Added error message if username or message are empty --- .../client.coffee | 13 +-------- .../i18n/de.i18n.json | 3 ++- .../i18n/en.i18n.json | 3 ++- .../server.coffee | 27 ++++++++++++------- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/packages/rocketchat-slashcommands-msg/client.coffee b/packages/rocketchat-slashcommands-msg/client.coffee index d8d8bc51e3e..56b79bded35 100644 --- a/packages/rocketchat-slashcommands-msg/client.coffee +++ b/packages/rocketchat-slashcommands-msg/client.coffee @@ -1,14 +1,3 @@ -RocketChat.slashCommands.add 'msg', (command, params, item) -> - trimmedParams = params.trim() - - username = trimmedParams.slice(0, trimmedParams.indexOf(' ')) - - if username is '' - return - username = username.replace('@', '') - - if Session.get('showUserInfo') is username - Session.set('showUserInfo', null) -, +RocketChat.slashCommands.add 'msg', null, description: TAPi18n.__ 'Direct_message_someone' params: '@username <message>' diff --git a/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json index 98a21d1147b..83dbe92c591 100644 --- a/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json @@ -1,4 +1,5 @@ { + "Direct_message_someone" : "Jemandem eine private Nachricht schicken", "Username_doesnt_exist" : "Der Benutzername `%s` existiert nicht.", - "Direct_message_someone" : "Jemandem eine private Nachricht schicken" + "Username_and_message_must_not_be_empty" : "Benutzername und Nachricht dürfen nicht leer sein." } diff --git a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json index 03addd53f03..0a4f3ed90a4 100644 --- a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json @@ -1,4 +1,5 @@ { + "Direct_message_someone" : "Direct message someone", "Username_doesnt_exist" : "The username `%s` doesn't exist.", - "Direct_message_someone" : "Direct message someone" + "Username_and_message_must_not_be_empty" : "Username and message must not be empty." } diff --git a/packages/rocketchat-slashcommands-msg/server.coffee b/packages/rocketchat-slashcommands-msg/server.coffee index 339edfaa062..59a7062515a 100644 --- a/packages/rocketchat-slashcommands-msg/server.coffee +++ b/packages/rocketchat-slashcommands-msg/server.coffee @@ -8,28 +8,35 @@ class Msg return trimmedParams = params.trim() + separator = trimmedParams.indexOf(' ') - usernameOrig = trimmedParams.slice(0, trimmedParams.indexOf(' ')) - message = trimmedParams.slice(trimmedParams.indexOf(' ') + 1) - - username = usernameOrig.replace('@', '') + user = Meteor.users.findOne Meteor.userId() - if username is '' + if separator is -1 + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_and_message_must_not_be_empty', null, user.language) + } return - user = Meteor.users.findOne Meteor.userId() - msgUser = RocketChat.models.Users.findOneByUsername username + message = trimmedParams.slice(separator + 1) + + targetUsernameOrig = trimmedParams.slice(0, separator) + targetUsername = targetUsernameOrig.replace('@', '') + targetUser = RocketChat.models.Users.findOneByUsername targetUsername - if not msgUser? + if not targetUser? RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { _id: Random.id() rid: item.rid ts: new Date - msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ usernameOrig ] }, user.language) + msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ targetUsernameOrig ] }, user.language) } return - rid = Meteor.call 'createDirectMessage', username + rid = Meteor.call 'createDirectMessage', targetUsername msgObject = { _id: Random.id(), rid: rid.rid, msg: message} Meteor.call 'sendMessage', msgObject -- GitLab From 5bb440d7766ca4e28f35114ab5825609059d2b0b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 25 Jan 2016 16:11:51 -0200 Subject: [PATCH 1279/1338] Merge fixes --- packages/rocketchat-ui-admin/admin/users/adminUserEdit.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html index 34def5b28e2..002135df0ed 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -21,10 +21,6 @@ <label for="email">{{_ "E-mail"}}</label> <input type="email" id="email" autocomplete="off" value="{{user.emails.[0].address}}"> </div> - <div class="input-line"> - <label for="email">{{_ "E-mail"}}</label> - <input type="email" id="email" autocomplete="off" value="{{email}}"> - </div> {{#if hasPermission 'edit-other-user-password'}} <div class="input-line"> <label for="password">{{_ "Password"}}</label> -- GitLab From 6519c20ed7ac92fa8fe28f0af7eec61ee86082a7 Mon Sep 17 00:00:00 2001 From: jf-guillou <jean.f.guillou@gmail.com> Date: Tue, 26 Jan 2016 11:38:33 +0100 Subject: [PATCH 1280/1338] Improved url parser regex to include fragment with # only Allows better matches on markdown formatted urls --- packages/rocketchat-lib/server/functions/sendMessage.coffee | 2 +- server/methods/updateMessage.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index fa30388ff35..720c150c03a 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]+)?#?([^\s]+)?)?/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/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 966c52399d5..9b362f73558 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -33,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]+)?#?([^\s]+)?)?/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 -- GitLab From a059b05aaf122e35a486e86577741a9fdb4c64c8 Mon Sep 17 00:00:00 2001 From: Matthias Brun <dev.matthias.brun@gmail.com> Date: Tue, 26 Jan 2016 17:23:00 +0100 Subject: [PATCH 1281/1338] Only call archive/unarchive if necessary --- .../client/views/channelSettings.coffee | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee index ac6d3536b6e..417b2aa91e3 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee @@ -100,11 +100,13 @@ Template.channelSettings.onCreated -> toastr.success TAPi18n.__ 'Room_type_changed_successfully' when 'archivationState' if @$('input[name=archivationState]:checked').val() is 'true' - Meteor.call 'archiveRoom', @data?.rid, (err, results) -> - return toastr.error err.reason if err - toastr.success TAPi18n.__ 'Room_archived' + if ChatRoom.findOne(@data.rid)?.archived isnt true + Meteor.call 'archiveRoom', @data?.rid, (err, results) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__ 'Room_archived' else - Meteor.call 'unarchiveRoom', @data?.rid, (err, results) -> - return toastr.error err.reason if err - toastr.success TAPi18n.__ 'Room_unarchived' + if ChatRoom.findOne(@data.rid)?.archived is true + Meteor.call 'unarchiveRoom', @data?.rid, (err, results) -> + return toastr.error err.reason if err + toastr.success TAPi18n.__ 'Room_unarchived' @editing.set() -- GitLab From 4481b51ecb3a17dbc518703bb3ef39e8c7b31e82 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Tue, 26 Jan 2016 15:48:19 -0200 Subject: [PATCH 1282/1338] Update konecty:multiple-instances-status to 1.0.5 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index ff8301b12be..bbe1042f562 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -65,7 +65,7 @@ konecty:autolinker@1.0.3 konecty:change-case@2.3.0 konecty:delayed-task@1.0.0 konecty:mongo-counter@0.0.3 -konecty:multiple-instances-status@1.0.3 +konecty:multiple-instances-status@1.0.5 konecty:nrr@2.0.2 konecty:user-presence@1.2.6 launch-screen@1.0.4 -- GitLab From d7900901ead676e12adfccbc6344adf0054adeec Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 27 Jan 2016 17:25:23 -0200 Subject: [PATCH 1283/1338] Closes #1888; Add mimetye image/vnd.microsoft.icon to mimtype list --- packages/rocketchat-assets/server/assets.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-assets/server/assets.coffee b/packages/rocketchat-assets/server/assets.coffee index 4c99b703d1d..950b628c801 100644 --- a/packages/rocketchat-assets/server/assets.coffee +++ b/packages/rocketchat-assets/server/assets.coffee @@ -1,6 +1,8 @@ sizeOf = Npm.require 'image-size' mime = Npm.require 'mime-types' +mime.extensions['image/vnd.microsoft.icon'] = ['ico'] + @RocketChatAssetsInstance = new RocketChatFile.GridFS name: 'assets' -- GitLab From 42bd3cced27390e3745cfd1d5bd4a9d32d106eb6 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Wed, 27 Jan 2016 19:36:46 -0200 Subject: [PATCH 1284/1338] fixing indentation --- .../message/popup/messagePopupConfig.coffee | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee index 022ff911f78..3d8cf6ef6f0 100644 --- a/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee +++ b/packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee @@ -121,18 +121,18 @@ Template.messagePopupConfig.helpers # show common used emojis, when use input a single ':' if filter == '' commonEmojis = [ - ':laughing:', - ':smiley:', - ':stuck_out_tongue:', - ':sunglasses:', - ':wink:', - ':innocent:', - ':flushed:', - ':disappointed:', - ':cry:', - ':heart:', - ':broken_heart:' - ] + ':laughing:', + ':smiley:', + ':stuck_out_tongue:', + ':sunglasses:', + ':wink:', + ':innocent:', + ':flushed:', + ':disappointed:', + ':cry:', + ':heart:', + ':broken_heart:' + ] for shortname in commonEmojis results.push _id: shortname -- GitLab From ec10d366ea06bade6d985a59321265ccaeee1f53 Mon Sep 17 00:00:00 2001 From: jf-guillou <jean.f.guillou@gmail.com> Date: Thu, 28 Jan 2016 08:49:44 +0100 Subject: [PATCH 1285/1338] Exclude parenthesis from matching in url fragment --- packages/rocketchat-lib/server/functions/sendMessage.coffee | 2 +- server/methods/updateMessage.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/server/functions/sendMessage.coffee b/packages/rocketchat-lib/server/functions/sendMessage.coffee index 720c150c03a..fcb2666b535 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]+)?(?:#([^\s]+))?)?/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/methods/updateMessage.coffee b/server/methods/updateMessage.coffee index 9b362f73558..dfc4659c903 100644 --- a/server/methods/updateMessage.coffee +++ b/server/methods/updateMessage.coffee @@ -33,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]+)?(?:#([^\s]+))?)?/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 -- GitLab From 5735ff2b37564ea37fe61fc86b92dade3a067b96 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 28 Jan 2016 12:58:51 -0200 Subject: [PATCH 1286/1338] New package rocketchat:migrations --- .meteor/packages | 2 +- .meteor/versions | 8 +- packages/rocketchat-migrations/migrations.js | 276 +++++++++++++++++++ packages/rocketchat-migrations/package.js | 22 ++ 4 files changed, 303 insertions(+), 5 deletions(-) create mode 100644 packages/rocketchat-migrations/migrations.js create mode 100644 packages/rocketchat-migrations/package.js diff --git a/.meteor/packages b/.meteor/packages index d75f1e099a6..37a7fa26482 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -61,6 +61,7 @@ rocketchat:mentions rocketchat:mentions-flextab rocketchat:message-pin rocketchat:message-star +rocketchat:migrations rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join @@ -114,7 +115,6 @@ nooitaf:colors ostrio:cookies@2.0.1 pauli:accounts-linkedin perak:codemirror -percolate:migrations percolate:synced-cron raix:handlebar-helpers raix:push diff --git a/.meteor/versions b/.meteor/versions index bbe1042f562..d2b7f9cb6b5 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -41,7 +41,7 @@ email@1.0.8 emojione:emojione@2.0.1 facebook@1.2.2 fastclick@1.0.7 -francocatena:status@1.5.0 +francocatena:status@1.5.1 geojson-utils@1.0.4 github@1.1.4 google@1.1.7 @@ -51,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.5 +jalik:ufs@0.5.0 jalik:ufs-gridfs@0.1.1 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 @@ -105,7 +105,6 @@ 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.8 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 promise@0.5.1 @@ -148,6 +147,7 @@ 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:migrations@0.0.1 rocketchat:oauth2-server@1.4.0 rocketchat:oauth2-server-config@1.0.0 rocketchat:oembed@0.0.1 @@ -193,7 +193,7 @@ tracker@1.0.9 twitter@1.1.5 ui@1.0.8 underscore@1.0.4 -underscorestring:underscore.string@3.2.2 +underscorestring:underscore.string@3.2.3 url@1.0.5 webapp@1.2.3 webapp-hashing@1.0.5 diff --git a/packages/rocketchat-migrations/migrations.js b/packages/rocketchat-migrations/migrations.js new file mode 100644 index 00000000000..e405abb244f --- /dev/null +++ b/packages/rocketchat-migrations/migrations.js @@ -0,0 +1,276 @@ +/* + Adds migration capabilities. Migrations are defined like: + + Migrations.add({ + up: function() {}, //*required* code to run to migrate upwards + version: 1, //*required* number to identify migration order + down: function() {}, //*optional* code to run to migrate downwards + name: 'Something' //*optional* display name for the migration + }); + + The ordering of migrations is determined by the version you set. + + To run the migrations, set the MIGRATE environment variable to either + 'latest' or the version number you want to migrate to. Optionally, append + ',exit' if you want the migrations to exit the meteor process, e.g if you're + migrating from a script (remember to pass the --once parameter). + + e.g: + MIGRATE="latest" mrt # ensure we'll be at the latest version and run the app + MIGRATE="latest,exit" mrt --once # ensure we'll be at the latest version and exit + MIGRATE="2,exit" mrt --once # migrate to version 2 and exit + + Note: Migrations will lock ensuring only 1 app can be migrating at once. If + a migration crashes, the control record in the migrations collection will + remain locked and at the version it was at previously, however the db could + be in an inconsistant state. +*/ + +// since we'll be at version 0 by default, we should have a migration set for +// it. +var DefaultMigration = {version: 0, up: function(){}}; + +Migrations = { + _list: [DefaultMigration], + options: { + // false disables logging + log: true, + // null or a function + logger: null, + // enable/disable info log "already at latest." + logIfLatest: true, + // migrations collection name + collectionName: "migrations" + }, + config: function(opts) { + this.options = _.extend({}, this.options, opts); + }, +} + +/* + Logger factory function. Takes a prefix string and options object + and uses an injected `logger` if provided, else falls back to + Meteor's `Log` package. + Will send a log object to the injected logger, on the following form: + message: String + level: String (info, warn, error, debug) + tag: 'Migrations' +*/ +function createLogger(prefix) { + check(prefix, String); + + // Return noop if logging is disabled. + if(Migrations.options.log === false) { + return function() {}; + } + + return function(level, message) { + check(level, Match.OneOf('info', 'error', 'warn', 'debug')); + check(message, String); + + var logger = Migrations.options && Migrations.options.logger; + + if(logger && _.isFunction(logger)) { + + logger({ + level: level, + message: message, + tag: prefix + }); + + } else { + Log[level]({ message: prefix + ': ' + message }); + } + } +} + +var log; + +Meteor.startup(function () { + var options = Migrations.options; + + // collection holding the control record + Migrations._collection = new Mongo.Collection(options.collectionName); + + log = createLogger('Migrations'); + + ['info', 'warn', 'error', 'debug'].forEach(function(level) { + log[level] = _.partial(log, level); + }); + + if (process.env.MIGRATE) + Migrations.migrateTo(process.env.MIGRATE); +}); + +// Add a new migration: +// {up: function *required +// version: Number *required +// down: function *optional +// name: String *optional +// } +Migrations.add = function(migration) { + if (typeof migration.up !== 'function') + throw new Meteor.Error('Migration must supply an up function.'); + + if (typeof migration.version !== 'number') + throw new Meteor.Error('Migration must supply a version number.'); + + if (migration.version <= 0) + throw new Meteor.Error('Migration version must be greater than 0'); + + // Freeze the migration object to make it hereafter immutable + Object.freeze(migration); + + this._list.push(migration); + this._list = _.sortBy(this._list, function(m) {return m.version;}); +} + +// Attempts to run the migrations using command in the form of: +// e.g 'latest', 'latest,exit', 2 +// use 'XX,rerun' to re-run the migration at that version +Migrations.migrateTo = function(command) { + if (_.isUndefined(command) || command === '' || this._list.length === 0) + throw new Error("Cannot migrate using invalid command: " + command); + + if (typeof command === 'number') { + var version = command; + } else { + var version = command.split(',')[0]; + var subcommand = command.split(',')[1]; + } + + if (version === 'latest') { + this._migrateTo(_.last(this._list).version); + } else { + this._migrateTo(parseInt(version), (subcommand === 'rerun')); + } + + // remember to run meteor with --once otherwise it will restart + if (subcommand === 'exit') + process.exit(0); +} + +// just returns the current version +Migrations.getVersion = function() { + return this._getControl().version; +} + +// migrates to the specific version passed in +Migrations._migrateTo = function(version, rerun) { + var self = this; + var control = this._getControl(); // Side effect: upserts control document. + var currentVersion = control.version; + + if (lock() === false) { + log.info('Not migrating, control is locked.'); + return; + } + + if (rerun) { + log.info('Rerunning version ' + version); + migrate('up', version); + log.info('Finished migrating.'); + unlock(); + return; + } + + if (currentVersion === version) { + if (Migrations.options.logIfLatest) { + log.info('Not migrating, already at version ' + version); + } + unlock(); + return; + } + + var startIdx = this._findIndexByVersion(currentVersion); + var endIdx = this._findIndexByVersion(version); + + // log.info('startIdx:' + startIdx + ' endIdx:' + endIdx); + log.info('Migrating from version ' + this._list[startIdx].version + + ' -> ' + this._list[endIdx].version); + + // run the actual migration + function migrate(direction, idx) { + var migration = self._list[idx]; + + if (typeof migration[direction] !== 'function') { + unlock(); + throw new Meteor.Error('Cannot migrate ' + direction + ' on version ' + + migration.version); + } + + function maybeName() { + return migration.name ? ' (' + migration.name + ')' : ''; + } + + log.info('Running ' + direction + '() on version ' + + migration.version + maybeName()); + + migration[direction](migration); + } + + // Returns true if lock was acquired. + function lock() { + // This is atomic. The selector ensures only one caller at a time will see + // the unlocked control, and locking occurs in the same update's modifier. + // All other simultaneous callers will get false back from the update. + return self._collection.update( + {_id: 'control', locked: false}, {$set: {locked: true, lockedAt: new Date()}} + ) === 1; + } + + // Side effect: saves version. + function unlock() { + self._setControl({locked: false, version: currentVersion}); + } + + if (currentVersion < version) { + for (var i = startIdx;i < endIdx;i++) { + migrate('up', i + 1); + currentVersion = self._list[i + 1].version; + } + } else { + for (var i = startIdx;i > endIdx;i--) { + migrate('down', i); + currentVersion = self._list[i - 1].version; + } + } + + unlock(); + log.info('Finished migrating.'); +} + +// gets the current control record, optionally creating it if non-existant +Migrations._getControl = function() { + var control = this._collection.findOne({_id: 'control'}); + + return control || this._setControl({version: 0, locked: false}); +} + +// sets the control record +Migrations._setControl = function(control) { + // be quite strict + check(control.version, Number); + check(control.locked, Boolean); + + this._collection.update({_id: 'control'}, + {$set: {version: control.version, locked: control.locked}}, {upsert: true}); + + return control; +} + +// returns the migration index in _list or throws if not found +Migrations._findIndexByVersion = function(version) { + for (var i = 0;i < this._list.length;i++) { + if (this._list[i].version === version) + return i; + } + + throw new Meteor.Error('Can\'t find migration version ' + version); +} + +//reset (mainly intended for tests) +Migrations._reset = function() { + this._list = [{version: 0, up: function(){}}]; + this._collection.remove({}); +} \ No newline at end of file diff --git a/packages/rocketchat-migrations/package.js b/packages/rocketchat-migrations/package.js new file mode 100644 index 00000000000..ac8da025f63 --- /dev/null +++ b/packages/rocketchat-migrations/package.js @@ -0,0 +1,22 @@ +Package.describe({ + name: 'rocketchat:migrations', + version: '0.0.1', + summary: '', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use('rocketchat:lib'); + api.use('rocketchat:version'); + api.use('coffeescript'); + + api.addFiles('migrations.js', 'server'); + + api.export('Migrations', 'server'); +}); + +Package.onTest(function(api) { + +}); -- GitLab From cd829c3f92ab6ef2bca8270afbfddadf2ad7eacc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 28 Jan 2016 13:46:48 -0200 Subject: [PATCH 1287/1338] Disable WebRTC broadcastStatus --- packages/rocketchat-webrtc/WebRTCClass.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-webrtc/WebRTCClass.coffee b/packages/rocketchat-webrtc/WebRTCClass.coffee index b57170eb620..a9b63054694 100644 --- a/packages/rocketchat-webrtc/WebRTCClass.coffee +++ b/packages/rocketchat-webrtc/WebRTCClass.coffee @@ -159,7 +159,7 @@ class WebRTCClass Meteor.setInterval @checkPeerConnections.bind(@), 1000 - Meteor.setInterval @broadcastStatus.bind(@), 1000 + # Meteor.setInterval @broadcastStatus.bind(@), 1000 log: -> if @debug is true -- GitLab From 0e6466787d736439f492b476932f0b6000139c88 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 28 Jan 2016 18:04:55 -0200 Subject: [PATCH 1288/1338] New error / warning messages for migrations --- .meteor/packages | 2 +- .meteor/versions | 1 - packages/rocketchat-migrations/migrations.js | 145 ++++++++++++++---- packages/rocketchat-migrations/package.js | 8 +- .../plugin/compile-version.coffee | 6 +- server/methods/migrate.coffee | 4 +- server/startup/migrations/v1.coffee | 19 ++- server/startup/migrations/v10.coffee | 27 ++-- server/startup/migrations/v11.coffee | 17 +- server/startup/migrations/v12.coffee | 23 ++- server/startup/migrations/v13.coffee | 13 +- server/startup/migrations/v14.coffee | 69 ++++----- server/startup/migrations/v15.coffee | 123 ++++++++------- server/startup/migrations/v16.coffee | 9 +- server/startup/migrations/v17.coffee | 9 +- server/startup/migrations/v18.coffee | 65 ++++---- server/startup/migrations/v19.coffee | 59 ++++--- server/startup/migrations/v2.coffee | 35 ++--- server/startup/migrations/v20.coffee | 47 +++--- server/startup/migrations/v21.coffee | 19 ++- server/startup/migrations/v22.coffee | 17 +- server/startup/migrations/v23.coffee | 11 +- server/startup/migrations/v24.coffee | 9 +- server/startup/migrations/v25.coffee | 9 +- server/startup/migrations/v26.coffee | 9 +- server/startup/migrations/v27.coffee | 17 +- server/startup/migrations/v3.coffee | 117 +++++++------- server/startup/migrations/v4.coffee | 39 +++-- server/startup/migrations/v5.coffee | 121 ++++++++------- server/startup/migrations/v6.coffee | 25 ++- server/startup/migrations/v7.coffee | 29 ++-- server/startup/migrations/v8.coffee | 29 ++-- server/startup/migrations/v9.coffee | 95 ++++++------ server/startup/migrations/xrun.coffee | 14 +- 34 files changed, 647 insertions(+), 594 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 37a7fa26482..903db389d81 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -52,7 +52,7 @@ rocketchat:github-enterprise rocketchat:gitlab rocketchat:highlight rocketchat:ldap -rocketchat:livechat +# rocketchat:livechat rocketchat:logger rocketchat:mailer rocketchat:markdown diff --git a/.meteor/versions b/.meteor/versions index d2b7f9cb6b5..ba58623294a 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -137,7 +137,6 @@ 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 diff --git a/packages/rocketchat-migrations/migrations.js b/packages/rocketchat-migrations/migrations.js index e405abb244f..b3d752ac8bb 100644 --- a/packages/rocketchat-migrations/migrations.js +++ b/packages/rocketchat-migrations/migrations.js @@ -28,7 +28,10 @@ // since we'll be at version 0 by default, we should have a migration set for // it. -var DefaultMigration = {version: 0, up: function(){}}; +var DefaultMigration = {version: 0, up: function(){ + // @TODO: check if collection "migrations" exist + // If exists, rename and rerun _migrateTo +}}; Migrations = { _list: [DefaultMigration], @@ -39,14 +42,34 @@ Migrations = { logger: null, // enable/disable info log "already at latest." logIfLatest: true, + // retry interval in seconds + retryInterval: 10, + // max number of attempts to retry unlock + maxAttempts: 5, // migrations collection name collectionName: "migrations" + // collectionName: "rocketchat_migrations" }, config: function(opts) { this.options = _.extend({}, this.options, opts); }, } +Migrations._collection = new Mongo.Collection(Migrations.options.collectionName); + +/* Create a box around messages for displaying on a console.log */ +function makeABox(message, color = 'red') { + if (!_.isArray(message)) { + message = message.split("\n"); + } + let len = _(message).reduce(function(memo, msg) { return Math.max(memo, msg.length) }, 0) + 4; + let text = message.map((msg) => { return "|"[color] + s.lrpad(msg, len)[color] + "|"[color] }).join("\n"); + let topLine = "+"[color] + s.pad('', len, '-')[color] + "+"[color]; + let separator = "|"[color] + s.pad('', len, '') + "|"[color]; + let bottomLine = "+"[color] + s.pad('', len, '-')[color] + "+"[color]; + return `\n${topLine}\n${separator}\n${text}\n${separator}\n${bottomLine}\n`; +} + /* Logger factory function. Takes a prefix string and options object and uses an injected `logger` if provided, else falls back to @@ -66,7 +89,7 @@ function createLogger(prefix) { return function(level, message) { check(level, Match.OneOf('info', 'error', 'warn', 'debug')); - check(message, String); + check(message, Match.OneOf(String, [String])); var logger = Migrations.options && Migrations.options.logger; @@ -86,22 +109,19 @@ function createLogger(prefix) { var log; -Meteor.startup(function () { - var options = Migrations.options; +var options = Migrations.options; - // collection holding the control record - Migrations._collection = new Mongo.Collection(options.collectionName); +// collection holding the control record - log = createLogger('Migrations'); +log = createLogger('Migrations'); - ['info', 'warn', 'error', 'debug'].forEach(function(level) { - log[level] = _.partial(log, level); - }); - - if (process.env.MIGRATE) - Migrations.migrateTo(process.env.MIGRATE); +['info', 'warn', 'error', 'debug'].forEach(function(level) { + log[level] = _.partial(log, level); }); + // if (process.env.MIGRATE) + // Migrations.migrateTo(process.env.MIGRATE); + // Add a new migration: // {up: function *required // version: Number *required @@ -139,10 +159,46 @@ Migrations.migrateTo = function(command) { var subcommand = command.split(',')[1]; } - if (version === 'latest') { - this._migrateTo(_.last(this._list).version); - } else { - this._migrateTo(parseInt(version), (subcommand === 'rerun')); + const maxAttempts = Migrations.options.maxAttempts; + const retryInterval = Migrations.options.retryInterval; + for (let attempts = 1; attempts <= maxAttempts; attempts++) { + if (version === 'latest') { + migrated = this._migrateTo(_.last(this._list).version); + } else { + migrated = this._migrateTo(parseInt(version), (subcommand === 'rerun')); + } + if (migrated) { + break; + } else { + let willRetry; + if (attempts < maxAttempts) { + willRetry = ` Trying again in ${retryInterval} seconds.`; + Meteor._sleepForMs(retryInterval * 1000); + } else { + willRetry = ""; + } + console.log(`Not migrating, control is locked. Attempt ${attempts}/${maxAttempts}.${willRetry}`.yellow); + } + } + if (!migrated) { + let control = this._getControl(); // Side effect: upserts control document. + console.log(makeABox([ + "ERROR! SERVER STOPPED", + "", + "Your database migration control is locked.", + "Please make sure you are running the latest version and try again.", + "If the problem persists, please contact support.", + "", + "This Rocket.Chat version: " + RocketChat.Info.version, + "Database locked at version: " + control.version, + "Database target version: " + (version === 'latest' ? _.last(this._list).version : version), + "", + "Commit: " + RocketChat.Info.commit.hash, + "Date: " + RocketChat.Info.commit.date, + "Branch: " + RocketChat.Info.commit.branch, + "Tag: " + RocketChat.Info.commit.tag + ])); + process.exit(1); } // remember to run meteor with --once otherwise it will restart @@ -162,8 +218,9 @@ Migrations._migrateTo = function(version, rerun) { var currentVersion = control.version; if (lock() === false) { - log.info('Not migrating, control is locked.'); - return; + // log.info('Not migrating, control is locked.'); + // Warning + return false; } if (rerun) { @@ -171,23 +228,22 @@ Migrations._migrateTo = function(version, rerun) { migrate('up', version); log.info('Finished migrating.'); unlock(); - return; + return true; } if (currentVersion === version) { - if (Migrations.options.logIfLatest) { + if (this.options.logIfLatest) { log.info('Not migrating, already at version ' + version); } unlock(); - return; + return true; } var startIdx = this._findIndexByVersion(currentVersion); var endIdx = this._findIndexByVersion(version); // log.info('startIdx:' + startIdx + ' endIdx:' + endIdx); - log.info('Migrating from version ' + this._list[startIdx].version - + ' -> ' + this._list[endIdx].version); + log.info('Migrating from version ' + this._list[startIdx].version + ' -> ' + this._list[endIdx].version); // run the actual migration function migrate(direction, idx) { @@ -195,27 +251,50 @@ Migrations._migrateTo = function(version, rerun) { if (typeof migration[direction] !== 'function') { unlock(); - throw new Meteor.Error('Cannot migrate ' + direction + ' on version ' - + migration.version); + throw new Meteor.Error('Cannot migrate ' + direction + ' on version ' + migration.version); } function maybeName() { return migration.name ? ' (' + migration.name + ')' : ''; } - log.info('Running ' + direction + '() on version ' - + migration.version + maybeName()); - - migration[direction](migration); + log.info('Running ' + direction + '() on version ' + migration.version + maybeName()); + + try { + migration[direction](migration); + } catch (e) { + console.log(makeABox([ + "ERROR! SERVER STOPPED", + "", + "Your database migration failed:", + e.message, + "", + "Please make sure you are running the latest version and try again.", + "If the problem persists, please contact support.", + "", + "This Rocket.Chat version: " + RocketChat.Info.version, + "Database locked at version: " + control.version, + "Database target version: " + version, + "", + "Commit: " + RocketChat.Info.commit.hash, + "Date: " + RocketChat.Info.commit.date, + "Branch: " + RocketChat.Info.commit.branch, + "Tag: " + RocketChat.Info.commit.tag + ])); + process.exit(1); + } } // Returns true if lock was acquired. function lock() { + const date = new Date(); + const dateMinusInterval = moment(date).subtract(self.options.retryInterval, 'minutes').toDate(); + // This is atomic. The selector ensures only one caller at a time will see // the unlocked control, and locking occurs in the same update's modifier. // All other simultaneous callers will get false back from the update. return self._collection.update( - {_id: 'control', locked: false}, {$set: {locked: true, lockedAt: new Date()}} + {_id: 'control', $or: [ { locked: false }, { lockedAt: { $lt: dateMinusInterval } } ] }, {$set: {locked: true, lockedAt: date}} ) === 1; } @@ -273,4 +352,6 @@ Migrations._findIndexByVersion = function(version) { Migrations._reset = function() { this._list = [{version: 0, up: function(){}}]; this._collection.remove({}); -} \ No newline at end of file +} + +RocketChat.Migrations = Migrations; \ No newline at end of file diff --git a/packages/rocketchat-migrations/package.js b/packages/rocketchat-migrations/package.js index ac8da025f63..116f7501f0a 100644 --- a/packages/rocketchat-migrations/package.js +++ b/packages/rocketchat-migrations/package.js @@ -10,11 +10,13 @@ Package.onUse(function(api) { api.use('rocketchat:lib'); api.use('rocketchat:version'); - api.use('coffeescript'); + api.use('ecmascript'); + api.use('underscore'); + api.use('check'); + api.use('mongo'); + api.use('momentjs:moment'); api.addFiles('migrations.js', 'server'); - - api.export('Migrations', 'server'); }); Package.onTest(function(api) { diff --git a/packages/rocketchat-version/plugin/compile-version.coffee b/packages/rocketchat-version/plugin/compile-version.coffee index 54e72fc2339..4f18987e15f 100644 --- a/packages/rocketchat-version/plugin/compile-version.coffee +++ b/packages/rocketchat-version/plugin/compile-version.coffee @@ -10,7 +10,7 @@ class VersionCompiler processFilesForTarget: (files) -> files.forEach (file) -> output = JSON.parse file.getContentsAsString() - output.compile = + output.build = date: new Date().toISOString() nodeVersion: process.version arch: process.arch @@ -38,11 +38,11 @@ class VersionCompiler exec "git describe --abbrev=0 --tags", (err, result) -> if not err? - output.tag = result.replace('\n', '') + output.commit?.tag = result.replace('\n', '') exec "git rev-parse --abbrev-ref HEAD", (err, result) -> if not err? - output.branch = result.replace('\n', '') + output.commit?.branch = result.replace('\n', '') output = """ RocketChat.Info = #{JSON.stringify(output, null, 4)} diff --git a/server/methods/migrate.coffee b/server/methods/migrate.coffee index 3b01619a1c8..cec14dc959d 100644 --- a/server/methods/migrate.coffee +++ b/server/methods/migrate.coffee @@ -6,8 +6,8 @@ Meteor.methods throw new Meteor.Error "not-authorized", '[methods] migrateTo' this.unblock() - Migrations.migrateTo version + RocketChat.Migrations.migrateTo version return version getMigrationVersion: -> - return Migrations.getVersion() + return RocketChat.Migrations.getVersion() diff --git a/server/startup/migrations/v1.coffee b/server/startup/migrations/v1.coffee index e2f1756dd10..e33267f068e 100644 --- a/server/startup/migrations/v1.coffee +++ b/server/startup/migrations/v1.coffee @@ -1,10 +1,9 @@ -Meteor.startup -> - Migrations.add - version: 1 - up: -> - RocketChat.models.Users.find({username: {$exists: false}, lastLogin: {$exists: true}}).forEach (user) -> - username = generateSuggestion(user) - if username? and username.trim() isnt '' - RocketChat.models.Users.setUsername user._id, username - else - console.log "User without username", JSON.stringify(user, null, ' ') +RocketChat.Migrations.add + version: 1 + up: -> + RocketChat.models.Users.find({username: {$exists: false}, lastLogin: {$exists: true}}).forEach (user) -> + username = generateSuggestion(user) + if username? and username.trim() isnt '' + RocketChat.models.Users.setUsername user._id, username + else + console.log "User without username", JSON.stringify(user, null, ' ') diff --git a/server/startup/migrations/v10.coffee b/server/startup/migrations/v10.coffee index c441914c2b5..9aa4dbe5be6 100644 --- a/server/startup/migrations/v10.coffee +++ b/server/startup/migrations/v10.coffee @@ -1,16 +1,15 @@ -Meteor.startup -> - Migrations.add - version: 10 - up: -> - ### - # Remove duplicated usernames from rooms - ### +RocketChat.Migrations.add + version: 10 + up: -> + ### + # Remove duplicated usernames from rooms + ### - count = 0 - RocketChat.models.Rooms.find({'usernames.0': {$exists: true}}, {fields: {usernames: 1}}).forEach (room) -> - newUsernames = _.uniq room.usernames - if newUsernames.length isnt room.usernames.length - count++ - RocketChat.models.Rooms.update {_id: room._id}, {$set: {usernames: newUsernames}} + count = 0 + RocketChat.models.Rooms.find({'usernames.0': {$exists: true}}, {fields: {usernames: 1}}).forEach (room) -> + newUsernames = _.uniq room.usernames + if newUsernames.length isnt room.usernames.length + count++ + RocketChat.models.Rooms.update {_id: room._id}, {$set: {usernames: newUsernames}} - console.log "Removed duplicated usernames from #{count} rooms" + console.log "Removed duplicated usernames from #{count} rooms" diff --git a/server/startup/migrations/v11.coffee b/server/startup/migrations/v11.coffee index ed3d14cf799..89dccca8800 100644 --- a/server/startup/migrations/v11.coffee +++ b/server/startup/migrations/v11.coffee @@ -1,10 +1,9 @@ -Meteor.startup -> - Migrations.add - version: 11 - up: -> - ### - # Set GENERAL room to be default - ### +RocketChat.Migrations.add + version: 11 + up: -> + ### + # Set GENERAL room to be default + ### - RocketChat.models.Rooms.update({_id: 'GENERAL'}, {$set: {default: true}}) - console.log "Set GENERAL room to be default" + RocketChat.models.Rooms.update({_id: 'GENERAL'}, {$set: {default: true}}) + console.log "Set GENERAL room to be default" diff --git a/server/startup/migrations/v12.coffee b/server/startup/migrations/v12.coffee index bfb96bc2c0d..f9cb65965c3 100644 --- a/server/startup/migrations/v12.coffee +++ b/server/startup/migrations/v12.coffee @@ -1,13 +1,12 @@ -Meteor.startup -> - Migrations.add - version: 12 - up: -> - # Set oldest user as admin, if none exists yet - admin = RocketChat.models.Users.findOneAdmin true, { fields: { _id: 1 } } - unless admin - # get oldest user - oldestUser = RocketChat.models.Users.findOne({}, { fields: { username: 1 }, sort: {createdAt: 1}}) - if oldestUser - Meteor.users.update {_id: oldestUser._id}, {$set: {admin: true}} +RocketChat.Migrations.add + version: 12 + up: -> + # Set oldest user as admin, if none exists yet + admin = RocketChat.models.Users.findOneAdmin true, { fields: { _id: 1 } } + unless admin + # get oldest user + oldestUser = RocketChat.models.Users.findOne({}, { fields: { username: 1 }, sort: {createdAt: 1}}) + if oldestUser + Meteor.users.update {_id: oldestUser._id}, {$set: {admin: true}} - console.log "Set #{oldestUser.username} as admin for being the oldest user" + console.log "Set #{oldestUser.username} as admin for being the oldest user" diff --git a/server/startup/migrations/v13.coffee b/server/startup/migrations/v13.coffee index 0d7c18d745e..da42a9dbc89 100644 --- a/server/startup/migrations/v13.coffee +++ b/server/startup/migrations/v13.coffee @@ -1,7 +1,6 @@ -Meteor.startup -> - Migrations.add - version: 13 - up: -> - # Set all current users as active - RocketChat.models.Users.setAllUsersActive true - console.log "Set all users as active" +RocketChat.Migrations.add + version: 13 + up: -> + # Set all current users as active + RocketChat.models.Users.setAllUsersActive true + console.log "Set all users as active" diff --git a/server/startup/migrations/v14.coffee b/server/startup/migrations/v14.coffee index 2ac5724be84..5c0a8ea3107 100644 --- a/server/startup/migrations/v14.coffee +++ b/server/startup/migrations/v14.coffee @@ -1,42 +1,41 @@ -Meteor.startup -> - Migrations.add - version: 14 - up: -> - # Remove unused settings - RocketChat.models.Settings.remove { _id: "API_Piwik_URL" } - RocketChat.models.Settings.remove { _id: "API_Piwik_ID" } +RocketChat.Migrations.add + version: 14 + up: -> + # Remove unused settings + RocketChat.models.Settings.remove { _id: "API_Piwik_URL" } + RocketChat.models.Settings.remove { _id: "API_Piwik_ID" } - RocketChat.models.Settings.remove { _id: "Message_Edit" } - RocketChat.models.Settings.remove { _id: "Message_Delete" } - RocketChat.models.Settings.remove { _id: "Message_KeepStatusHistory" } + RocketChat.models.Settings.remove { _id: "Message_Edit" } + RocketChat.models.Settings.remove { _id: "Message_Delete" } + RocketChat.models.Settings.remove { _id: "Message_KeepStatusHistory" } - RocketChat.models.Settings.update { _id: "Message_ShowEditedStatus" }, { $set: { type: "boolean", value: true } } - RocketChat.models.Settings.update { _id: "Message_ShowDeletedStatus" }, { $set: { type: "boolean", value: false } } + RocketChat.models.Settings.update { _id: "Message_ShowEditedStatus" }, { $set: { type: "boolean", value: true } } + RocketChat.models.Settings.update { _id: "Message_ShowDeletedStatus" }, { $set: { type: "boolean", value: false } } - metaKeys = [ - 'old': 'Meta:language' - 'new': 'Meta_language' - , - 'old': 'Meta:fb:app_id' - 'new': 'Meta_fb_app_id' - , - 'old': 'Meta:robots' - 'new': 'Meta_robots' - , - 'old': 'Meta:google-site-verification' - 'new': 'Meta_google-site-verification' - , - 'old': 'Meta:msvalidate.01' - 'new': 'Meta_msvalidate01' - ] + metaKeys = [ + 'old': 'Meta:language' + 'new': 'Meta_language' + , + 'old': 'Meta:fb:app_id' + 'new': 'Meta_fb_app_id' + , + 'old': 'Meta:robots' + 'new': 'Meta_robots' + , + 'old': 'Meta:google-site-verification' + 'new': 'Meta_google-site-verification' + , + 'old': 'Meta:msvalidate.01' + 'new': 'Meta_msvalidate01' + ] - for oldAndNew in metaKeys - oldValue = RocketChat.models.Settings.findOne({_id: oldAndNew.old})?.value - newValue = RocketChat.models.Settings.findOne({_id: oldAndNew.new})?.value - if oldValue? and not newValue? - RocketChat.models.Settings.update { _id: oldAndNew.new }, { $set: { value: newValue } } + for oldAndNew in metaKeys + oldValue = RocketChat.models.Settings.findOne({_id: oldAndNew.old})?.value + newValue = RocketChat.models.Settings.findOne({_id: oldAndNew.new})?.value + if oldValue? and not newValue? + RocketChat.models.Settings.update { _id: oldAndNew.new }, { $set: { value: newValue } } - RocketChat.models.Settings.remove { _id: oldAndNew.old } + RocketChat.models.Settings.remove { _id: oldAndNew.old } - RocketChat.models.Settings.remove { _id: "SMTP_Security" } + RocketChat.models.Settings.remove { _id: "SMTP_Security" } diff --git a/server/startup/migrations/v15.coffee b/server/startup/migrations/v15.coffee index 4ded09bff6e..bc587a10758 100644 --- a/server/startup/migrations/v15.coffee +++ b/server/startup/migrations/v15.coffee @@ -1,77 +1,76 @@ -Meteor.startup -> - Migrations.add - version: 15 - up: -> +RocketChat.Migrations.add + version: 15 + up: -> - console.log 'Starting file migration' - oldFilesCollection = new Meteor.Collection 'cfs.Files.filerecord' - oldGridFSCollection = new Meteor.Collection 'cfs_gridfs.files.files' - oldChunkCollection = new Meteor.Collection 'cfs_gridfs.files.chunks' + console.log 'Starting file migration' + oldFilesCollection = new Meteor.Collection 'cfs.Files.filerecord' + oldGridFSCollection = new Meteor.Collection 'cfs_gridfs.files.files' + oldChunkCollection = new Meteor.Collection 'cfs_gridfs.files.chunks' - newFilesCollection = fileCollection - newGridFSCollection = new Meteor.Collection 'rocketchat_uploads.files' - newChunkCollection = new Meteor.Collection 'rocketchat_uploads.chunks' + newFilesCollection = fileCollection + newGridFSCollection = new Meteor.Collection 'rocketchat_uploads.files' + newChunkCollection = new Meteor.Collection 'rocketchat_uploads.chunks' - oldFilesCollection.find({'copies.files.key': {$exists: true}}).forEach (cfsRecord) -> - nameParts = cfsRecord.original.name?.split('.') - extension = '' - url = "ufs/rocketchat_uploads/#{cfsRecord._id}" + oldFilesCollection.find({'copies.files.key': {$exists: true}}).forEach (cfsRecord) -> + nameParts = cfsRecord.original.name?.split('.') + extension = '' + url = "ufs/rocketchat_uploads/#{cfsRecord._id}" - console.log 'migrating file', url + console.log 'migrating file', url - if nameParts?.length > 1 - extension = nameParts.pop() - url = url + '.' + extension + if nameParts?.length > 1 + extension = nameParts.pop() + url = url + '.' + extension - record = - _id: cfsRecord._id - name: cfsRecord.original.name or '' - size: cfsRecord.original.size - type: cfsRecord.original.type - complete: true - uploading: false - store: "rocketchat_uploads" - extension: extension - userId: cfsRecord.userId - uploadedAt: cfsRecord.updatedAt - url: Meteor.absoluteUrl() + url + record = + _id: cfsRecord._id + name: cfsRecord.original.name or '' + size: cfsRecord.original.size + type: cfsRecord.original.type + complete: true + uploading: false + store: "rocketchat_uploads" + extension: extension + userId: cfsRecord.userId + uploadedAt: cfsRecord.updatedAt + url: Meteor.absoluteUrl() + url - newFilesCollection.insert record + newFilesCollection.insert record - oldGridFsFile = oldGridFSCollection.findOne({_id: new Meteor.Collection.ObjectID(cfsRecord.copies.files.key)}) + oldGridFsFile = oldGridFSCollection.findOne({_id: new Meteor.Collection.ObjectID(cfsRecord.copies.files.key)}) - newGridFSCollection.insert - _id: cfsRecord._id - filename: cfsRecord._id - contentType: oldGridFsFile.contentType - length: oldGridFsFile.length - chunkSize: oldGridFsFile.chunkSize - uploadDate: oldGridFsFile.uploadDate - aliases: null - metadata: null - md5: oldGridFsFile.md5 + newGridFSCollection.insert + _id: cfsRecord._id + filename: cfsRecord._id + contentType: oldGridFsFile.contentType + length: oldGridFsFile.length + chunkSize: oldGridFsFile.chunkSize + uploadDate: oldGridFsFile.uploadDate + aliases: null + metadata: null + md5: oldGridFsFile.md5 - oldChunkCollection.find({files_id: new Meteor.Collection.ObjectID(cfsRecord.copies.files.key)}).forEach (oldChunk) -> - newChunkCollection.insert - _id: oldChunk._id - files_id: cfsRecord._id - n: oldChunk.n - data: oldChunk.data + oldChunkCollection.find({files_id: new Meteor.Collection.ObjectID(cfsRecord.copies.files.key)}).forEach (oldChunk) -> + newChunkCollection.insert + _id: oldChunk._id + files_id: cfsRecord._id + n: oldChunk.n + data: oldChunk.data - RocketChat.models.Messages.find({$or: [{ 'urls.url': "https://demo.rocket.chat/cfs/files/Files/#{cfsRecord._id}" }, { 'urls.url': "https://rocket.chat/cfs/files/Files/#{cfsRecord._id}" }]}).forEach (message) -> - for urlsItem in message.urls - if urlsItem.url is "https://demo.rocket.chat/cfs/files/Files/#{cfsRecord._id}" or urlsItem.url is "https://rocket.chat/cfs/files/Files/#{cfsRecord._id}" - urlsItem.url = Meteor.absoluteUrl() + url - if urlsItem.parsedUrl?.pathname? - urlsItem.parsedUrl.pathname = "/#{url}" - message.msg = message.msg.replace "https://demo.rocket.chat/cfs/files/Files/#{cfsRecord._id}", Meteor.absoluteUrl() + url - message.msg = message.msg.replace "https://rocket.chat/cfs/files/Files/#{cfsRecord._id}", Meteor.absoluteUrl() + url + RocketChat.models.Messages.find({$or: [{ 'urls.url': "https://demo.rocket.chat/cfs/files/Files/#{cfsRecord._id}" }, { 'urls.url': "https://rocket.chat/cfs/files/Files/#{cfsRecord._id}" }]}).forEach (message) -> + for urlsItem in message.urls + if urlsItem.url is "https://demo.rocket.chat/cfs/files/Files/#{cfsRecord._id}" or urlsItem.url is "https://rocket.chat/cfs/files/Files/#{cfsRecord._id}" + urlsItem.url = Meteor.absoluteUrl() + url + if urlsItem.parsedUrl?.pathname? + urlsItem.parsedUrl.pathname = "/#{url}" + message.msg = message.msg.replace "https://demo.rocket.chat/cfs/files/Files/#{cfsRecord._id}", Meteor.absoluteUrl() + url + message.msg = message.msg.replace "https://rocket.chat/cfs/files/Files/#{cfsRecord._id}", Meteor.absoluteUrl() + url - RocketChat.models.Messages.update {_id: message._id}, {$set: {urls: message.urls, msg: message.msg}} + RocketChat.models.Messages.update {_id: message._id}, {$set: {urls: message.urls, msg: message.msg}} - oldFilesCollection.remove _id: cfsRecord._id - oldGridFSCollection.remove _id: oldGridFsFile._id - oldChunkCollection.remove files_id: new Meteor.Collection.ObjectID(cfsRecord.copies.files.key) + oldFilesCollection.remove _id: cfsRecord._id + oldGridFSCollection.remove _id: oldGridFsFile._id + oldChunkCollection.remove files_id: new Meteor.Collection.ObjectID(cfsRecord.copies.files.key) - console.log 'End of file migration' + console.log 'End of file migration' diff --git a/server/startup/migrations/v16.coffee b/server/startup/migrations/v16.coffee index 25ecafec6a9..63b83121016 100644 --- a/server/startup/migrations/v16.coffee +++ b/server/startup/migrations/v16.coffee @@ -1,5 +1,4 @@ -Meteor.startup -> - Migrations.add - version: 16 - up: -> - RocketChat.models.Messages.tryDropIndex({ _hidden: 1 }) +RocketChat.Migrations.add + version: 16 + up: -> + RocketChat.models.Messages.tryDropIndex({ _hidden: 1 }) diff --git a/server/startup/migrations/v17.coffee b/server/startup/migrations/v17.coffee index f0d1cf540bc..8233d193e5b 100644 --- a/server/startup/migrations/v17.coffee +++ b/server/startup/migrations/v17.coffee @@ -1,5 +1,4 @@ -Meteor.startup -> - Migrations.add - version: 17 - up: -> - RocketChat.models.Messages.tryDropIndex({ _hidden: 1 }) +RocketChat.Migrations.add + version: 17 + up: -> + RocketChat.models.Messages.tryDropIndex({ _hidden: 1 }) diff --git a/server/startup/migrations/v18.coffee b/server/startup/migrations/v18.coffee index f9293c59bfa..a64e6c1fdc7 100644 --- a/server/startup/migrations/v18.coffee +++ b/server/startup/migrations/v18.coffee @@ -1,35 +1,34 @@ -Meteor.startup -> - Migrations.add - version: 18 - up: -> - changes = - Accounts_Facebook: 'Accounts_OAuth_Facebook' - Accounts_Facebook_id: 'Accounts_OAuth_Facebook_id' - Accounts_Facebook_secret: 'Accounts_OAuth_Facebook_secret' - Accounts_Google: 'Accounts_OAuth_Google' - Accounts_Google_id: 'Accounts_OAuth_Google_id' - Accounts_Google_secret: 'Accounts_OAuth_Google_secret' - Accounts_Github: 'Accounts_OAuth_Github' - Accounts_Github_id: 'Accounts_OAuth_Github_id' - Accounts_Github_secret: 'Accounts_OAuth_Github_secret' - Accounts_Gitlab: 'Accounts_OAuth_Gitlab' - Accounts_Gitlab_id: 'Accounts_OAuth_Gitlab_id' - Accounts_Gitlab_secret: 'Accounts_OAuth_Gitlab_secret' - Accounts_Linkedin: 'Accounts_OAuth_Linkedin' - Accounts_Linkedin_id: 'Accounts_OAuth_Linkedin_id' - Accounts_Linkedin_secret: 'Accounts_OAuth_Linkedin_secret' - Accounts_Meteor: 'Accounts_OAuth_Meteor' - Accounts_Meteor_id: 'Accounts_OAuth_Meteor_id' - Accounts_Meteor_secret: 'Accounts_OAuth_Meteor_secret' - Accounts_Twitter: 'Accounts_OAuth_Twitter' - Accounts_Twitter_id: 'Accounts_OAuth_Twitter_id' - Accounts_Twitter_secret: 'Accounts_OAuth_Twitter_secret' +RocketChat.Migrations.add + version: 18 + up: -> + changes = + Accounts_Facebook: 'Accounts_OAuth_Facebook' + Accounts_Facebook_id: 'Accounts_OAuth_Facebook_id' + Accounts_Facebook_secret: 'Accounts_OAuth_Facebook_secret' + Accounts_Google: 'Accounts_OAuth_Google' + Accounts_Google_id: 'Accounts_OAuth_Google_id' + Accounts_Google_secret: 'Accounts_OAuth_Google_secret' + Accounts_Github: 'Accounts_OAuth_Github' + Accounts_Github_id: 'Accounts_OAuth_Github_id' + Accounts_Github_secret: 'Accounts_OAuth_Github_secret' + Accounts_Gitlab: 'Accounts_OAuth_Gitlab' + Accounts_Gitlab_id: 'Accounts_OAuth_Gitlab_id' + Accounts_Gitlab_secret: 'Accounts_OAuth_Gitlab_secret' + Accounts_Linkedin: 'Accounts_OAuth_Linkedin' + Accounts_Linkedin_id: 'Accounts_OAuth_Linkedin_id' + Accounts_Linkedin_secret: 'Accounts_OAuth_Linkedin_secret' + Accounts_Meteor: 'Accounts_OAuth_Meteor' + Accounts_Meteor_id: 'Accounts_OAuth_Meteor_id' + Accounts_Meteor_secret: 'Accounts_OAuth_Meteor_secret' + Accounts_Twitter: 'Accounts_OAuth_Twitter' + Accounts_Twitter_id: 'Accounts_OAuth_Twitter_id' + Accounts_Twitter_secret: 'Accounts_OAuth_Twitter_secret' - for from, to of changes - record = RocketChat.models.Settings.findOne _id: from - if record? - delete record._id - RocketChat.models.Settings.upsert {_id: to}, record - RocketChat.models.Settings.remove _id: from + for from, to of changes + record = RocketChat.models.Settings.findOne _id: from + if record? + delete record._id + RocketChat.models.Settings.upsert {_id: to}, record + RocketChat.models.Settings.remove _id: from - ServiceConfiguration.configurations.remove({}) + ServiceConfiguration.configurations.remove({}) diff --git a/server/startup/migrations/v19.coffee b/server/startup/migrations/v19.coffee index 8658bf3f740..ce3a0bcad41 100644 --- a/server/startup/migrations/v19.coffee +++ b/server/startup/migrations/v19.coffee @@ -1,32 +1,31 @@ -Meteor.startup -> - Migrations.add - version: 19 - up: -> - ### - # Migrate existing admin users to Role based admin functionality - # 'admin' role applies to global scope - ### - admins = Meteor.users.find({ admin: true }, { fields: { _id: 1, username:1 } }).fetch() - RocketChat.authz.addUsersToRoles( _.pluck(admins, '_id'), ['admin']) - Meteor.users.update({}, { $unset :{admin:''}}, {multi:true}) - usernames = _.pluck( admins, 'username').join(', ') - console.log "Migrate #{usernames} from admin field to 'admin' role".green +RocketChat.Migrations.add + version: 19 + up: -> + ### + # Migrate existing admin users to Role based admin functionality + # 'admin' role applies to global scope + ### + admins = Meteor.users.find({ admin: true }, { fields: { _id: 1, username:1 } }).fetch() + RocketChat.authz.addUsersToRoles( _.pluck(admins, '_id'), ['admin']) + Meteor.users.update({}, { $unset :{admin:''}}, {multi:true}) + usernames = _.pluck( admins, 'username').join(', ') + console.log "Migrate #{usernames} from admin field to 'admin' role".green - # Add 'user' role to all users - users = Meteor.users.find().fetch() - RocketChat.authz.addUsersToRoles( _.pluck(users, '_id'), ['user']) - usernames = _.pluck( users, 'username').join(', ') - console.log "Add #{usernames} to 'user' role".green + # Add 'user' role to all users + users = Meteor.users.find().fetch() + RocketChat.authz.addUsersToRoles( _.pluck(users, '_id'), ['user']) + usernames = _.pluck( users, 'username').join(', ') + console.log "Add #{usernames} to 'user' role".green - # Add 'moderator' role to channel/group creators - rooms = RocketChat.models.Rooms.findByTypes(['c','p']).fetch() - _.each rooms, (room) -> - creator = room?.u?._id - if creator - if Meteor.users.findOne({_id: creator}) - RocketChat.authz.addUsersToRoles( creator, ['moderator'], room._id) - console.log "Add #{room.u.username} to 'moderator' role".green - else - RocketChat.models.Subscriptions.removeByRoomId room._id - RocketChat.models.Messages.removeByRoomId room._id - RocketChat.models.Rooms.removeById room._id + # Add 'moderator' role to channel/group creators + rooms = RocketChat.models.Rooms.findByTypes(['c','p']).fetch() + _.each rooms, (room) -> + creator = room?.u?._id + if creator + if Meteor.users.findOne({_id: creator}) + RocketChat.authz.addUsersToRoles( creator, ['moderator'], room._id) + console.log "Add #{room.u.username} to 'moderator' role".green + else + RocketChat.models.Subscriptions.removeByRoomId room._id + RocketChat.models.Messages.removeByRoomId room._id + RocketChat.models.Rooms.removeById room._id diff --git a/server/startup/migrations/v2.coffee b/server/startup/migrations/v2.coffee index baf7777b185..61a9b96569c 100644 --- a/server/startup/migrations/v2.coffee +++ b/server/startup/migrations/v2.coffee @@ -1,25 +1,24 @@ -Meteor.startup -> - Migrations.add - version: 2 - up: -> - RocketChat.models.Users.find({avatarOrigin: {$exists: false}, username: {$exists: true}}).forEach (user) -> - avatars = getAvatarSuggestionForUser user +RocketChat.Migrations.add + version: 2 + up: -> + RocketChat.models.Users.find({avatarOrigin: {$exists: false}, username: {$exists: true}}).forEach (user) -> + avatars = getAvatarSuggestionForUser user - services = Object.keys avatars + services = Object.keys avatars - if services.length is 0 - return + if services.length is 0 + return - service = services[0] - console.log user.username, '->', service + service = services[0] + console.log user.username, '->', service - dataURI = avatars[service].blob + dataURI = avatars[service].blob - {image, contentType} = RocketChatFile.dataURIParse dataURI + {image, contentType} = RocketChatFile.dataURIParse dataURI - rs = RocketChatFile.bufferToStream new Buffer(image, 'base64') - ws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", contentType - ws.on 'end', Meteor.bindEnvironment -> - RocketChat.models.Users.setAvatarOrigin user._id, service + rs = RocketChatFile.bufferToStream new Buffer(image, 'base64') + ws = RocketChatFileAvatarInstance.createWriteStream "#{user.username}.jpg", contentType + ws.on 'end', Meteor.bindEnvironment -> + RocketChat.models.Users.setAvatarOrigin user._id, service - rs.pipe(ws) + rs.pipe(ws) diff --git a/server/startup/migrations/v20.coffee b/server/startup/migrations/v20.coffee index 19c569551ec..532e4523bc9 100644 --- a/server/startup/migrations/v20.coffee +++ b/server/startup/migrations/v20.coffee @@ -1,27 +1,26 @@ -Meteor.startup -> - Migrations.add - version: 20 - up: -> - ### - # Migrate existing `rocketchat_uploads` documents to include the room Id - # where the file was uploaded to. The room Id is retrieved from the message - # document created after the file upload. - ### +RocketChat.Migrations.add + version: 20 + up: -> + ### + # Migrate existing `rocketchat_uploads` documents to include the room Id + # where the file was uploaded to. The room Id is retrieved from the message + # document created after the file upload. + ### - # list of channel messages which were created after uploading a file - msgQuery = - rid: { $exists: true } - 'file._id': { $exists: true } - msgOptions = - fields: - _id: 1 - rid: 1 - 'file._id': 1 - cursorFileMessages = RocketChat.models.Messages.find(msgQuery, msgOptions); - return unless cursorFileMessages.count() + # list of channel messages which were created after uploading a file + msgQuery = + rid: { $exists: true } + 'file._id': { $exists: true } + msgOptions = + fields: + _id: 1 + rid: 1 + 'file._id': 1 + cursorFileMessages = RocketChat.models.Messages.find(msgQuery, msgOptions); + return unless cursorFileMessages.count() - _.each( cursorFileMessages.fetch(), (msg) -> - fileCollection.update({ _id: msg?.file?._id }, { $set: { rid: msg.rid } }, { $multi: true }) - ) + _.each( cursorFileMessages.fetch(), (msg) -> + fileCollection.update({ _id: msg?.file?._id }, { $set: { rid: msg.rid } }, { $multi: true }) + ) - console.log 'Updated rocketchat_uploads documents to include the room Id in which they were sent.' + console.log 'Updated rocketchat_uploads documents to include the room Id in which they were sent.' diff --git a/server/startup/migrations/v21.coffee b/server/startup/migrations/v21.coffee index 1be1536c0f5..f5887980450 100644 --- a/server/startup/migrations/v21.coffee +++ b/server/startup/migrations/v21.coffee @@ -1,12 +1,11 @@ -Meteor.startup -> - Migrations.add - version: 21 - up: -> - ### - # Remove any i18nLabel from rocketchat_settings - # They will be added again where necessary on next restart - ### +RocketChat.Migrations.add + version: 21 + up: -> + ### + # Remove any i18nLabel from rocketchat_settings + # They will be added again where necessary on next restart + ### - RocketChat.models.Settings.update { i18nLabel: { $exists: true } }, { $unset: { i18nLabel: 1 } }, { multi: true } + RocketChat.models.Settings.update { i18nLabel: { $exists: true } }, { $unset: { i18nLabel: 1 } }, { multi: true } - console.log 'Removed i18nLabel from Settings. New labels will be added on next restart! Please restart your server.' + console.log 'Removed i18nLabel from Settings. New labels will be added on next restart! Please restart your server.' diff --git a/server/startup/migrations/v22.coffee b/server/startup/migrations/v22.coffee index 8ee08ea3e79..da4f972b74d 100644 --- a/server/startup/migrations/v22.coffee +++ b/server/startup/migrations/v22.coffee @@ -1,10 +1,9 @@ -Meteor.startup -> - Migrations.add - version: 22 - up: -> - ### - # Update message edit field - ### +RocketChat.Migrations.add + version: 22 + up: -> + ### + # Update message edit field + ### - RocketChat.models.Messages.upgradeEtsToEditAt() - console.log 'Updated old messages\' ets edited timestamp to new editedAt timestamp.' + RocketChat.models.Messages.upgradeEtsToEditAt() + console.log 'Updated old messages\' ets edited timestamp to new editedAt timestamp.' diff --git a/server/startup/migrations/v23.coffee b/server/startup/migrations/v23.coffee index 303f024acca..5f2420b6c2d 100644 --- a/server/startup/migrations/v23.coffee +++ b/server/startup/migrations/v23.coffee @@ -1,6 +1,5 @@ -Meteor.startup -> - Migrations.add - version: 23 - up: -> - RocketChat.models.Settings.remove { _id: 'Accounts_denyUnverifiedEmails' } - console.log 'Deleting not used setting Accounts_denyUnverifiedEmails' +RocketChat.Migrations.add + version: 23 + up: -> + RocketChat.models.Settings.remove { _id: 'Accounts_denyUnverifiedEmails' } + console.log 'Deleting not used setting Accounts_denyUnverifiedEmails' diff --git a/server/startup/migrations/v24.coffee b/server/startup/migrations/v24.coffee index 1d473a03d3f..0e18965cafc 100644 --- a/server/startup/migrations/v24.coffee +++ b/server/startup/migrations/v24.coffee @@ -1,5 +1,4 @@ -Meteor.startup -> - Migrations.add - version: 24 - up: -> - RocketChat.models.Permissions.remove({ _id: 'access-rocket-permissions' }) +RocketChat.Migrations.add + version: 24 + up: -> + RocketChat.models.Permissions.remove({ _id: 'access-rocket-permissions' }) diff --git a/server/startup/migrations/v25.coffee b/server/startup/migrations/v25.coffee index cb4301fcec6..9b54dcede46 100644 --- a/server/startup/migrations/v25.coffee +++ b/server/startup/migrations/v25.coffee @@ -1,5 +1,4 @@ -Meteor.startup -> - Migrations.add - version: 25 - up: -> - RocketChat.models.Settings.update({ _id: /Accounts_OAuth_Custom/ }, { $set: { persistent: true }, $unset: {hidden: true} }, { multi: true }) +RocketChat.Migrations.add + version: 25 + up: -> + RocketChat.models.Settings.update({ _id: /Accounts_OAuth_Custom/ }, { $set: { persistent: true }, $unset: {hidden: true} }, { multi: true }) diff --git a/server/startup/migrations/v26.coffee b/server/startup/migrations/v26.coffee index 2e45ece8dcf..22b0507c10c 100644 --- a/server/startup/migrations/v26.coffee +++ b/server/startup/migrations/v26.coffee @@ -1,5 +1,4 @@ -Meteor.startup -> - Migrations.add - version: 26 - up: -> - RocketChat.models.Messages.update({ t: 'rm' }, { $set: { mentions: [] } }, { multi: true }) +RocketChat.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 index b3f6f7d7716..8e17b170998 100644 --- a/server/startup/migrations/v27.coffee +++ b/server/startup/migrations/v27.coffee @@ -1,11 +1,10 @@ -Meteor.startup -> - Migrations.add - version: 27 - up: -> - RocketChat.models.Users.update({}, { $rename: { roles: '_roles' } }, { multi: true }) +RocketChat.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.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 }) + RocketChat.models.Users.update({}, { $unset: { _roles: 1 } }, { multi: true }) diff --git a/server/startup/migrations/v3.coffee b/server/startup/migrations/v3.coffee index 90ca4b46339..67a62f06cd2 100644 --- a/server/startup/migrations/v3.coffee +++ b/server/startup/migrations/v3.coffee @@ -1,74 +1,73 @@ -Meteor.startup -> - Migrations.add - version: 3 - up: -> +RocketChat.Migrations.add + version: 3 + up: -> - RocketChat.models.Subscriptions.tryDropIndex 'uid_1' - RocketChat.models.Subscriptions.tryDropIndex 'rid_1_uid_1' + RocketChat.models.Subscriptions.tryDropIndex 'uid_1' + RocketChat.models.Subscriptions.tryDropIndex 'rid_1_uid_1' - console.log 'Fixing ChatSubscription uid' - RocketChat.models.Subscriptions.find({uid: {$exists: true}}, {nonreactive: true}).forEach (sub) -> - update = {} - user = RocketChat.models.Users.findOneById(sub.uid, {fields: {username: 1}}) - if user? - update.$set ?= {} - update.$unset ?= {} - update.$set['u._id'] = user._id - update.$set['u.username'] = user.username - update.$unset.uid = 1 + console.log 'Fixing ChatSubscription uid' + RocketChat.models.Subscriptions.find({uid: {$exists: true}}, {nonreactive: true}).forEach (sub) -> + update = {} + user = RocketChat.models.Users.findOneById(sub.uid, {fields: {username: 1}}) + if user? + update.$set ?= {} + update.$unset ?= {} + update.$set['u._id'] = user._id + update.$set['u.username'] = user.username + update.$unset.uid = 1 - if Object.keys(update).length > 0 - RocketChat.models.Subscriptions.update(sub._id, update) + if Object.keys(update).length > 0 + RocketChat.models.Subscriptions.update(sub._id, update) - console.log 'Fixing ChatRoom uids' - RocketChat.models.Rooms.find({'uids.0': {$exists: true}}, {nonreactive: true}).forEach (room) -> - update = {} - users = RocketChat.models.Users.find {_id: {$in: room.uids}, username: {$exists: true}}, {fields: {username: 1}} - usernames = users.map (user) -> - return user.username + console.log 'Fixing ChatRoom uids' + RocketChat.models.Rooms.find({'uids.0': {$exists: true}}, {nonreactive: true}).forEach (room) -> + update = {} + users = RocketChat.models.Users.find {_id: {$in: room.uids}, username: {$exists: true}}, {fields: {username: 1}} + usernames = users.map (user) -> + return user.username - update.$set ?= {} - update.$unset ?= {} - update.$set.usernames = usernames - update.$unset.uids = 1 + update.$set ?= {} + update.$unset ?= {} + update.$set.usernames = usernames + update.$unset.uids = 1 - user = RocketChat.models.Users.findOneById(room.uid, {fields: {username: 1}}) - if user? - update.$set['u._id'] = user._id - update.$set['u.username'] = user.username - update.$unset.uid = 1 + user = RocketChat.models.Users.findOneById(room.uid, {fields: {username: 1}}) + if user? + update.$set['u._id'] = user._id + update.$set['u.username'] = user.username + update.$unset.uid = 1 - if room.t is 'd' and usernames.length is 2 - for k, v of update.$set - room[k] = v - for k, v of update.$unset - delete room[k] + if room.t is 'd' and usernames.length is 2 + for k, v of update.$set + room[k] = v + for k, v of update.$unset + delete room[k] - oldId = room._id - room._id = usernames.sort().join(',') - RocketChat.models.Rooms.insert(room) - RocketChat.models.Rooms.removeById(oldId) - RocketChat.models.Subscriptions.update({rid: oldId}, {$set: {rid: room._id}}, {multi: true}) - RocketChat.models.Messages.update({rid: oldId}, {$set: {rid: room._id}}, {multi: true}) - else - RocketChat.models.Rooms.update(room._id, update) + oldId = room._id + room._id = usernames.sort().join(',') + RocketChat.models.Rooms.insert(room) + RocketChat.models.Rooms.removeById(oldId) + RocketChat.models.Subscriptions.update({rid: oldId}, {$set: {rid: room._id}}, {multi: true}) + RocketChat.models.Messages.update({rid: oldId}, {$set: {rid: room._id}}, {multi: true}) + else + RocketChat.models.Rooms.update(room._id, update) - console.log 'Fixing ChatMessage uid' - RocketChat.models.Messages.find({uid: {$exists: true}}, {nonreactive: true}).forEach (message) -> - update = {} - user = RocketChat.models.Users.findOneById(message.uid, {fields: {username: 1}}) - if user? - update.$set ?= {} - update.$unset ?= {} - update.$set['u._id'] = user._id - update.$set['u.username'] = user.username - update.$unset.uid = 1 + console.log 'Fixing ChatMessage uid' + RocketChat.models.Messages.find({uid: {$exists: true}}, {nonreactive: true}).forEach (message) -> + update = {} + user = RocketChat.models.Users.findOneById(message.uid, {fields: {username: 1}}) + if user? + update.$set ?= {} + update.$unset ?= {} + update.$set['u._id'] = user._id + update.$set['u.username'] = user.username + update.$unset.uid = 1 - if Object.keys(update).length > 0 - RocketChat.models.Messages.update(message._id, update) + if Object.keys(update).length > 0 + RocketChat.models.Messages.update(message._id, update) - console.log 'End' + console.log 'End' diff --git a/server/startup/migrations/v4.coffee b/server/startup/migrations/v4.coffee index b61f13563f7..cc2fb25c1aa 100644 --- a/server/startup/migrations/v4.coffee +++ b/server/startup/migrations/v4.coffee @@ -1,29 +1,28 @@ -Meteor.startup -> - Migrations.add - version: 4 - up: -> +RocketChat.Migrations.add + version: 4 + up: -> - RocketChat.models.Messages.tryDropIndex 'rid_1' - RocketChat.models.Subscriptions.tryDropIndex 'u._id_1' + RocketChat.models.Messages.tryDropIndex 'rid_1' + RocketChat.models.Subscriptions.tryDropIndex 'u._id_1' - console.log 'Rename rn to name' - RocketChat.models.Subscriptions.update({rn: {$exists: true}}, {$rename: {rn: 'name'}}, {multi: true}) + console.log 'Rename rn to name' + RocketChat.models.Subscriptions.update({rn: {$exists: true}}, {$rename: {rn: 'name'}}, {multi: true}) - console.log 'Adding names to rooms without name' - RocketChat.models.Rooms.find({name: ''}).forEach (item) -> - name = Random.id().toLowerCase() - RocketChat.models.Rooms.setNameById item._id, name - RocketChat.models.Subscriptions.update {rid: item._id}, {$set: {name: name}}, {multi: true} + console.log 'Adding names to rooms without name' + RocketChat.models.Rooms.find({name: ''}).forEach (item) -> + name = Random.id().toLowerCase() + RocketChat.models.Rooms.setNameById item._id, name + RocketChat.models.Subscriptions.update {rid: item._id}, {$set: {name: name}}, {multi: true} - console.log 'Making room names unique' - RocketChat.models.Rooms.find().forEach (room) -> - RocketChat.models.Rooms.find({name: room.name, _id: {$ne: room._id}}).forEach (item) -> - name = room.name + '-' + Random.id(2).toLowerCase() - RocketChat.models.Rooms.setNameById item._id, name - RocketChat.models.Subscriptions.update {rid: item._id}, {$set: {name: name}}, {multi: true} + console.log 'Making room names unique' + RocketChat.models.Rooms.find().forEach (room) -> + RocketChat.models.Rooms.find({name: room.name, _id: {$ne: room._id}}).forEach (item) -> + name = room.name + '-' + Random.id(2).toLowerCase() + RocketChat.models.Rooms.setNameById item._id, name + RocketChat.models.Subscriptions.update {rid: item._id}, {$set: {name: name}}, {multi: true} - console.log 'End' + console.log 'End' diff --git a/server/startup/migrations/v5.coffee b/server/startup/migrations/v5.coffee index b3886f4dea7..f9e7e49c79a 100644 --- a/server/startup/migrations/v5.coffee +++ b/server/startup/migrations/v5.coffee @@ -1,64 +1,63 @@ -Meteor.startup -> - Migrations.add - version: 5 - up: -> - - console.log 'Dropping test rooms with less than 2 messages' - RocketChat.models.Rooms.find({msgs: {'$lt': 2}}).forEach (room) -> - console.log 'Dropped: ', room.name - RocketChat.models.Rooms.removeById room._id - RocketChat.models.Messages.removeByRoomId room._id - RocketChat.models.Subscriptions.removeByRoomId room._id - - - console.log 'Dropping test rooms with less than 2 user' - RocketChat.models.Rooms.find({usernames: {'$size':1}}).forEach (room) -> - console.log 'Dropped: ', room.name - RocketChat.models.Rooms.removeById room._id - RocketChat.models.Messages.removeByRoomId room._id - RocketChat.models.Subscriptions.removeByRoomId room._id - - - console.log 'Adding username to all users' - RocketChat.models.Users.find({ 'username': {'$exists':0}, 'emails': {'$exists':1} }).forEach (user) -> - newUserName = user.emails[0].address.split("@")[0] +RocketChat.Migrations.add + version: 5 + up: -> + + console.log 'Dropping test rooms with less than 2 messages' + RocketChat.models.Rooms.find({msgs: {'$lt': 2}}).forEach (room) -> + console.log 'Dropped: ', room.name + RocketChat.models.Rooms.removeById room._id + RocketChat.models.Messages.removeByRoomId room._id + RocketChat.models.Subscriptions.removeByRoomId room._id + + + console.log 'Dropping test rooms with less than 2 user' + RocketChat.models.Rooms.find({usernames: {'$size':1}}).forEach (room) -> + console.log 'Dropped: ', room.name + RocketChat.models.Rooms.removeById room._id + RocketChat.models.Messages.removeByRoomId room._id + RocketChat.models.Subscriptions.removeByRoomId room._id + + + console.log 'Adding username to all users' + RocketChat.models.Users.find({ 'username': {'$exists':0}, 'emails': {'$exists':1} }).forEach (user) -> + newUserName = user.emails[0].address.split("@")[0] + if RocketChat.models.Users.findOneByUsername(newUserName) + newUserName = newUserName + Math.floor((Math.random() * 10) + 1) if RocketChat.models.Users.findOneByUsername(newUserName) newUserName = newUserName + Math.floor((Math.random() * 10) + 1) if RocketChat.models.Users.findOneByUsername(newUserName) - newUserName = newUserName + Math.floor((Math.random() * 10) + 1) - if RocketChat.models.Users.findOneByUsername(newUserName) - newUserName = newUserName + Math.floor((Math.random() * 10) + 1); - console.log 'Adding: username ' + newUserName + ' to all user ' + user._id; - RocketChat.models.Users.setUsername user._id, newUserName - - - console.log 'Fixing _id of direct messages rooms' - RocketChat.models.Rooms.findByType('d').forEach (room) -> - newId = '' - id0 = RocketChat.models.Users.findOneByUsername(room.usernames[0])._id - id1 = RocketChat.models.Users.findOneByUsername(room.usernames[1])._id - ids = [id0,id1] - newId = ids.sort().join('') - if (newId != room._id) - console.log 'Fixing: _id ' + room._id + ' to ' + newId - RocketChat.models.Subscriptions.update({'rid':room._id},{'$set':{'rid':newId}},{'multi':1}) - RocketChat.models.Messages.update({'rid':room._id},{'$set':{'rid':newId}},{'multi':1}) - RocketChat.models.Rooms.removeById(room._id) - room._id = newId - RocketChat.models.Rooms.insert(room) - RocketChat.models.Subscriptions.update({'rid':room._id,'u._id':id0},{'$set':{'name':room.usernames[1]}}) - RocketChat.models.Subscriptions.update({'rid':room._id,'u._id':id1},{'$set':{'name':room.usernames[0]}}) - - - console.log 'Adding u.username to all documents' - RocketChat.models.Users.find({},{'username':1}).forEach (user) -> - console.log 'Adding: u.username ' + user.username + ' to all document' - RocketChat.models.Rooms.update({'u._id':user._id},{'$set':{'u.username':user.username}},{'multi':1}) - RocketChat.models.Subscriptions.update({'u._id':user._id},{'$set':{'u.username':user.username}},{'multi':1}) - RocketChat.models.Messages.update({'u._id':user._id},{'$set':{'u.username':user.username}},{'multi':1}) - RocketChat.models.Messages.update({'uid':user._id},{'$set':{'u':user}},{'multi':1}) - RocketChat.models.Messages.update({'by':user._id},{'$set':{'u':user}},{'multi':1}) - RocketChat.models.Messages.update({'uid':{'$exists':1}},{'$unset':{'uid':1,'by':1}},{'multi':1}) - - - console.log 'End' + newUserName = newUserName + Math.floor((Math.random() * 10) + 1); + console.log 'Adding: username ' + newUserName + ' to all user ' + user._id; + RocketChat.models.Users.setUsername user._id, newUserName + + + console.log 'Fixing _id of direct messages rooms' + RocketChat.models.Rooms.findByType('d').forEach (room) -> + newId = '' + id0 = RocketChat.models.Users.findOneByUsername(room.usernames[0])._id + id1 = RocketChat.models.Users.findOneByUsername(room.usernames[1])._id + ids = [id0,id1] + newId = ids.sort().join('') + if (newId != room._id) + console.log 'Fixing: _id ' + room._id + ' to ' + newId + RocketChat.models.Subscriptions.update({'rid':room._id},{'$set':{'rid':newId}},{'multi':1}) + RocketChat.models.Messages.update({'rid':room._id},{'$set':{'rid':newId}},{'multi':1}) + RocketChat.models.Rooms.removeById(room._id) + room._id = newId + RocketChat.models.Rooms.insert(room) + RocketChat.models.Subscriptions.update({'rid':room._id,'u._id':id0},{'$set':{'name':room.usernames[1]}}) + RocketChat.models.Subscriptions.update({'rid':room._id,'u._id':id1},{'$set':{'name':room.usernames[0]}}) + + + console.log 'Adding u.username to all documents' + RocketChat.models.Users.find({},{'username':1}).forEach (user) -> + console.log 'Adding: u.username ' + user.username + ' to all document' + RocketChat.models.Rooms.update({'u._id':user._id},{'$set':{'u.username':user.username}},{'multi':1}) + RocketChat.models.Subscriptions.update({'u._id':user._id},{'$set':{'u.username':user.username}},{'multi':1}) + RocketChat.models.Messages.update({'u._id':user._id},{'$set':{'u.username':user.username}},{'multi':1}) + RocketChat.models.Messages.update({'uid':user._id},{'$set':{'u':user}},{'multi':1}) + RocketChat.models.Messages.update({'by':user._id},{'$set':{'u':user}},{'multi':1}) + RocketChat.models.Messages.update({'uid':{'$exists':1}},{'$unset':{'uid':1,'by':1}},{'multi':1}) + + + console.log 'End' diff --git a/server/startup/migrations/v6.coffee b/server/startup/migrations/v6.coffee index a9a505ee003..13f6b46f9d6 100644 --- a/server/startup/migrations/v6.coffee +++ b/server/startup/migrations/v6.coffee @@ -1,16 +1,15 @@ -Meteor.startup -> - Migrations.add - version: 6 - up: -> +RocketChat.Migrations.add + version: 6 + up: -> - console.log 'Changin _id of #general channel room from XXX to GENERAL' - room = RocketChat.models.Rooms.findOneByName('general') - if room?._id is not 'GENERAL' - RocketChat.models.Subscriptions.update({'rid':room._id},{'$set':{'rid':'GENERAL'}},{'multi':1}) - RocketChat.models.Messages.update({'rid':room._id},{'$set':{'rid':'GENERAL'}},{'multi':1}) - RocketChat.models.Rooms.removeById(room._id) - delete room._id - RocketChat.models.Rooms.upsert({'_id':'GENERAL'},{$set: room}) + console.log 'Changin _id of #general channel room from XXX to GENERAL' + room = RocketChat.models.Rooms.findOneByName('general') + if room?._id is not 'GENERAL' + RocketChat.models.Subscriptions.update({'rid':room._id},{'$set':{'rid':'GENERAL'}},{'multi':1}) + RocketChat.models.Messages.update({'rid':room._id},{'$set':{'rid':'GENERAL'}},{'multi':1}) + RocketChat.models.Rooms.removeById(room._id) + delete room._id + RocketChat.models.Rooms.upsert({'_id':'GENERAL'},{$set: room}) - console.log 'End' + console.log 'End' diff --git a/server/startup/migrations/v7.coffee b/server/startup/migrations/v7.coffee index 2f85268ffef..86bf2ca1d9c 100644 --- a/server/startup/migrations/v7.coffee +++ b/server/startup/migrations/v7.coffee @@ -1,19 +1,18 @@ -Meteor.startup -> - Migrations.add - version: 7 - up: -> +RocketChat.Migrations.add + version: 7 + up: -> - console.log 'Populate urls in messages' - query = RocketChat.models.Messages.find({ 'urls.0': { $exists: true } }) - count = query.count() - query.forEach (message, index) -> - console.log "#{index + 1} / #{count}" + console.log 'Populate urls in messages' + query = RocketChat.models.Messages.find({ 'urls.0': { $exists: true } }) + count = query.count() + query.forEach (message, index) -> + console.log "#{index + 1} / #{count}" - message.urls = message.urls.map (url) -> - if _.isString url - return {url: url} - return url + message.urls = message.urls.map (url) -> + if _.isString url + return {url: url} + return url - OEmbed.RocketUrlParser message + OEmbed.RocketUrlParser message - console.log 'End' + console.log 'End' diff --git a/server/startup/migrations/v8.coffee b/server/startup/migrations/v8.coffee index 87d210f5ad9..fa7e02ad425 100644 --- a/server/startup/migrations/v8.coffee +++ b/server/startup/migrations/v8.coffee @@ -1,15 +1,14 @@ -Meteor.startup -> - Migrations.add - version: 8 - up: -> - console.log 'Load old settings record' - settings = RocketChat.models.Settings.findOne({ _id: 'settings' }) - if settings - RocketChat.models.Settings.insert { _id: 'CDN_PREFIX', value: settings.CDN_PREFIX, type: 'string', group: 'General' } if settings.CDN_PREFIX? - RocketChat.models.Settings.insert { _id: 'MAIL_URL', value: settings.ENV.MAIL_URL, type: 'string', group: 'SMTP' } if settings.ENV?.MAIL_URL? - RocketChat.models.Settings.insert { _id: 'Accounts_denyUnverifiedEmails', value: settings.denyUnverifiedEmails, type: 'boolean', group: 'Accounts' } if settings.denyUnverifiedEmails? - RocketChat.models.Settings.insert { _id: 'KADIRA_APP_ID', value: settings.kadira.appId, type: 'string', group: 'API' } if settings.kadira?.appId? - RocketChat.models.Settings.insert { _id: 'KADIRA_APP_SECRET', value: settings.kadira.appSecret, type: 'string', group: 'API' } if settings.kadira?.appSecret? - RocketChat.models.Settings.insert { _id: 'avatarStore_type', value: settings.public.avatarStore.type, type: 'string', group: 'API' } if settings.public?.avatarStore?.type? - RocketChat.models.Settings.insert { _id: 'avatarStore_path', value: settings.public.avatarStore.path, type: 'string', group: 'API' } if settings.public?.avatarStore?.path? - RocketChat.models.Settings.remove { _id: 'settings' } +RocketChat.Migrations.add + version: 8 + up: -> + console.log 'Load old settings record' + settings = RocketChat.models.Settings.findOne({ _id: 'settings' }) + if settings + RocketChat.models.Settings.insert { _id: 'CDN_PREFIX', value: settings.CDN_PREFIX, type: 'string', group: 'General' } if settings.CDN_PREFIX? + RocketChat.models.Settings.insert { _id: 'MAIL_URL', value: settings.ENV.MAIL_URL, type: 'string', group: 'SMTP' } if settings.ENV?.MAIL_URL? + RocketChat.models.Settings.insert { _id: 'Accounts_denyUnverifiedEmails', value: settings.denyUnverifiedEmails, type: 'boolean', group: 'Accounts' } if settings.denyUnverifiedEmails? + RocketChat.models.Settings.insert { _id: 'KADIRA_APP_ID', value: settings.kadira.appId, type: 'string', group: 'API' } if settings.kadira?.appId? + RocketChat.models.Settings.insert { _id: 'KADIRA_APP_SECRET', value: settings.kadira.appSecret, type: 'string', group: 'API' } if settings.kadira?.appSecret? + RocketChat.models.Settings.insert { _id: 'avatarStore_type', value: settings.public.avatarStore.type, type: 'string', group: 'API' } if settings.public?.avatarStore?.type? + RocketChat.models.Settings.insert { _id: 'avatarStore_path', value: settings.public.avatarStore.path, type: 'string', group: 'API' } if settings.public?.avatarStore?.path? + RocketChat.models.Settings.remove { _id: 'settings' } diff --git a/server/startup/migrations/v9.coffee b/server/startup/migrations/v9.coffee index 45628dd5647..7199bc0a457 100644 --- a/server/startup/migrations/v9.coffee +++ b/server/startup/migrations/v9.coffee @@ -1,53 +1,52 @@ -Meteor.startup -> - Migrations.add - version: 9 - up: -> - # Migrate existing source collection data to target collection - # target collection is defined in collections.coffee using the new collection name - # source collection is dropped after data migration - toMigrate = [ - { - source: new Meteor.Collection 'data.ChatRoom' - target: RocketChat.models.Rooms.model - } - { - source: new Meteor.Collection 'data.ChatSubscription' - target: RocketChat.models.Subscriptions.model - } - { - source: new Meteor.Collection 'data.ChatMessage' - target: RocketChat.models.Messages.model - } - { - source: new Meteor.Collection 'settings' - target: Settings - } - { - # this collection may not exit - source: new Meteor.Collection 'oembed_cache' - target: OEmbed.cache - } - ] +RocketChat.Migrations.add + version: 9 + up: -> + # Migrate existing source collection data to target collection + # target collection is defined in collections.coffee using the new collection name + # source collection is dropped after data migration + toMigrate = [ + { + source: new Meteor.Collection 'data.ChatRoom' + target: RocketChat.models.Rooms.model + } + { + source: new Meteor.Collection 'data.ChatSubscription' + target: RocketChat.models.Subscriptions.model + } + { + source: new Meteor.Collection 'data.ChatMessage' + target: RocketChat.models.Messages.model + } + { + source: new Meteor.Collection 'settings' + target: Settings + } + { + # this collection may not exit + source: new Meteor.Collection 'oembed_cache' + target: OEmbed.cache + } + ] - toMigrate.forEach ( collection ) -> - source = collection.source - target = collection.target + toMigrate.forEach ( collection ) -> + source = collection.source + target = collection.target - # rawCollection available as of Meteor 1.0.4 - console.log 'Migrating data from: ' + source.rawCollection().collectionName + ' to: ' + target.rawCollection().collectionName - source.find().forEach ( doc ) -> - # use upsert to account for GENERAL room created by initialData - target.upsert({_id: doc._id}, doc ) + # rawCollection available as of Meteor 1.0.4 + console.log 'Migrating data from: ' + source.rawCollection().collectionName + ' to: ' + target.rawCollection().collectionName + source.find().forEach ( doc ) -> + # use upsert to account for GENERAL room created by initialData + target.upsert({_id: doc._id}, doc ) - rawSource = source.rawCollection() - # drop old collection - Meteor.wrapAsync(rawSource.drop, rawSource )((err,res) -> - if err - console.log 'Error dropping ' + rawSource.collectionName + ' collection due to: ' + err.errmsg - ) + rawSource = source.rawCollection() + # drop old collection + Meteor.wrapAsync(rawSource.drop, rawSource )((err,res) -> + if err + console.log 'Error dropping ' + rawSource.collectionName + ' collection due to: ' + err.errmsg + ) - # Note: the following would have been much easier, but didn't work. The serverside - # data was not published to the client for some reason. - # newName = target.rawCollection().collectionName - # Meteor.wrapAsync(rawSource.rename, rawSource )(newName, {dropTarget:true}) + # Note: the following would have been much easier, but didn't work. The serverside + # data was not published to the client for some reason. + # newName = target.rawCollection().collectionName + # Meteor.wrapAsync(rawSource.rename, rawSource )(newName, {dropTarget:true}) diff --git a/server/startup/migrations/xrun.coffee b/server/startup/migrations/xrun.coffee index 9554d54968e..b0bc8bcb2a1 100644 --- a/server/startup/migrations/xrun.coffee +++ b/server/startup/migrations/xrun.coffee @@ -1,8 +1,6 @@ -Meteor.startup -> - Meteor.defer -> - if Migrations.getVersion() isnt 0 - Migrations.migrateTo 'latest' - else - control = Migrations._getControl() - control.version = _.last(Migrations._list).version - Migrations._setControl control +if RocketChat.Migrations.getVersion() isnt 0 + RocketChat.Migrations.migrateTo 'latest' +else + control = RocketChat.Migrations._getControl() + control.version = _.last(RocketChat.Migrations._list).version + RocketChat.Migrations._setControl control -- GitLab From 9bbc8d840a85f11c63614e0f767aa701a896b63b Mon Sep 17 00:00:00 2001 From: Sven Mueller <mueller@synyx.de> Date: Fri, 29 Jan 2016 15:31:48 +0100 Subject: [PATCH 1289/1338] Closes #1981; Message edit mode remains after deleting the message --- packages/rocketchat-lib/client/MessageAction.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee index 43af02e4689..3f90651ea4e 100644 --- a/packages/rocketchat-lib/client/MessageAction.coffee +++ b/packages/rocketchat-lib/client/MessageAction.coffee @@ -113,6 +113,8 @@ Meteor.startup -> timer: 1000 showConfirmButton: false + if chatMessages[Session.get('openedRoom')].editing.id is message._id + chatMessages[Session.get('openedRoom')].clearEditing(message) chatMessages[Session.get('openedRoom')].deleteMsg(message) validation: (message) -> return RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid ) or RocketChat.settings.get('Message_AllowDeleting') and message.u?._id is Meteor.userId() -- GitLab From d83259919fb378161fbbb4f3dae78e67f3f5c560 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 29 Jan 2016 13:17:53 -0200 Subject: [PATCH 1290/1338] Prevent server from starting if migration is locked --- packages/rocketchat-migrations/migrations.js | 600 ++++++++++--------- 1 file changed, 325 insertions(+), 275 deletions(-) diff --git a/packages/rocketchat-migrations/migrations.js b/packages/rocketchat-migrations/migrations.js index b3d752ac8bb..b725f8ac53b 100644 --- a/packages/rocketchat-migrations/migrations.js +++ b/packages/rocketchat-migrations/migrations.js @@ -1,110 +1,121 @@ /* - Adds migration capabilities. Migrations are defined like: - - Migrations.add({ - up: function() {}, //*required* code to run to migrate upwards - version: 1, //*required* number to identify migration order - down: function() {}, //*optional* code to run to migrate downwards - name: 'Something' //*optional* display name for the migration - }); - - The ordering of migrations is determined by the version you set. - - To run the migrations, set the MIGRATE environment variable to either - 'latest' or the version number you want to migrate to. Optionally, append - ',exit' if you want the migrations to exit the meteor process, e.g if you're - migrating from a script (remember to pass the --once parameter). - - e.g: - MIGRATE="latest" mrt # ensure we'll be at the latest version and run the app - MIGRATE="latest,exit" mrt --once # ensure we'll be at the latest version and exit - MIGRATE="2,exit" mrt --once # migrate to version 2 and exit - - Note: Migrations will lock ensuring only 1 app can be migrating at once. If - a migration crashes, the control record in the migrations collection will - remain locked and at the version it was at previously, however the db could - be in an inconsistant state. + Adds migration capabilities. Migrations are defined like: + + Migrations.add({ + up: function() {}, //*required* code to run to migrate upwards + version: 1, //*required* number to identify migration order + down: function() {}, //*optional* code to run to migrate downwards + name: 'Something' //*optional* display name for the migration + }); + + The ordering of migrations is determined by the version you set. + + To run the migrations, set the MIGRATE environment variable to either + 'latest' or the version number you want to migrate to. Optionally, append + ',exit' if you want the migrations to exit the meteor process, e.g if you're + migrating from a script (remember to pass the --once parameter). + + e.g: + MIGRATE="latest" mrt # ensure we'll be at the latest version and run the app + MIGRATE="latest,exit" mrt --once # ensure we'll be at the latest version and exit + MIGRATE="2,exit" mrt --once # migrate to version 2 and exit + + Note: Migrations will lock ensuring only 1 app can be migrating at once. If + a migration crashes, the control record in the migrations collection will + remain locked and at the version it was at previously, however the db could + be in an inconsistant state. */ // since we'll be at version 0 by default, we should have a migration set for // it. -var DefaultMigration = {version: 0, up: function(){ - // @TODO: check if collection "migrations" exist - // If exists, rename and rerun _migrateTo -}}; +var DefaultMigration = { + version: 0, + up: function() { + // @TODO: check if collection "migrations" exist + // If exists, rename and rerun _migrateTo + } +}; Migrations = { - _list: [DefaultMigration], - options: { - // false disables logging - log: true, - // null or a function - logger: null, - // enable/disable info log "already at latest." - logIfLatest: true, - // retry interval in seconds - retryInterval: 10, - // max number of attempts to retry unlock - maxAttempts: 5, - // migrations collection name - collectionName: "migrations" - // collectionName: "rocketchat_migrations" - }, - config: function(opts) { - this.options = _.extend({}, this.options, opts); - }, + _list: [DefaultMigration], + options: { + // false disables logging + log: true, + // null or a function + logger: null, + // enable/disable info log "already at latest." + logIfLatest: true, + // lock will be valid for this amount of minutes + lockExpiration: 5, + // retry interval in seconds + retryInterval: 10, + // max number of attempts to retry unlock + maxAttempts: 30, + // migrations collection name + collectionName: "migrations" + // collectionName: "rocketchat_migrations" + }, + config: function(opts) { + this.options = _.extend({}, this.options, opts); + }, } Migrations._collection = new Mongo.Collection(Migrations.options.collectionName); /* Create a box around messages for displaying on a console.log */ function makeABox(message, color = 'red') { - if (!_.isArray(message)) { - message = message.split("\n"); - } - let len = _(message).reduce(function(memo, msg) { return Math.max(memo, msg.length) }, 0) + 4; - let text = message.map((msg) => { return "|"[color] + s.lrpad(msg, len)[color] + "|"[color] }).join("\n"); - let topLine = "+"[color] + s.pad('', len, '-')[color] + "+"[color]; - let separator = "|"[color] + s.pad('', len, '') + "|"[color]; - let bottomLine = "+"[color] + s.pad('', len, '-')[color] + "+"[color]; - return `\n${topLine}\n${separator}\n${text}\n${separator}\n${bottomLine}\n`; + if (!_.isArray(message)) { + message = message.split("\n"); + } + let len = _(message).reduce(function(memo, msg) { + return Math.max(memo, msg.length) + }, 0) + 4; + let text = message.map((msg) => { + return "|" [color] + s.lrpad(msg, len)[color] + "|" [color] + }).join("\n"); + let topLine = "+" [color] + s.pad('', len, '-')[color] + "+" [color]; + let separator = "|" [color] + s.pad('', len, '') + "|" [color]; + let bottomLine = "+" [color] + s.pad('', len, '-')[color] + "+" [color]; + return `\n${topLine}\n${separator}\n${text}\n${separator}\n${bottomLine}\n`; } /* - Logger factory function. Takes a prefix string and options object - and uses an injected `logger` if provided, else falls back to - Meteor's `Log` package. - Will send a log object to the injected logger, on the following form: - message: String - level: String (info, warn, error, debug) - tag: 'Migrations' + Logger factory function. Takes a prefix string and options object + and uses an injected `logger` if provided, else falls back to + Meteor's `Log` package. + Will send a log object to the injected logger, on the following form: + message: String + level: String (info, warn, error, debug) + tag: 'Migrations' */ function createLogger(prefix) { - check(prefix, String); + check(prefix, String); - // Return noop if logging is disabled. - if(Migrations.options.log === false) { - return function() {}; - } + // Return noop if logging is disabled. + if (Migrations.options.log === false) { + return function() {}; + } - return function(level, message) { - check(level, Match.OneOf('info', 'error', 'warn', 'debug')); - check(message, Match.OneOf(String, [String])); + return function(level, message) { + check(level, Match.OneOf('info', 'error', 'warn', 'debug')); + check(message, Match.OneOf(String, [String])); - var logger = Migrations.options && Migrations.options.logger; + var logger = Migrations.options && Migrations.options.logger; - if(logger && _.isFunction(logger)) { + if (logger && _.isFunction(logger)) { - logger({ - level: level, - message: message, - tag: prefix - }); + logger({ + level: level, + message: message, + tag: prefix + }); - } else { - Log[level]({ message: prefix + ': ' + message }); - } - } + } else { + Log[level]({ + message: prefix + ': ' + message + }); + } + } } var log; @@ -116,11 +127,11 @@ var options = Migrations.options; log = createLogger('Migrations'); ['info', 'warn', 'error', 'debug'].forEach(function(level) { - log[level] = _.partial(log, level); + log[level] = _.partial(log, level); }); - // if (process.env.MIGRATE) - // Migrations.migrateTo(process.env.MIGRATE); +// if (process.env.MIGRATE) +// Migrations.migrateTo(process.env.MIGRATE); // Add a new migration: // {up: function *required @@ -129,229 +140,268 @@ log = createLogger('Migrations'); // name: String *optional // } Migrations.add = function(migration) { - if (typeof migration.up !== 'function') - throw new Meteor.Error('Migration must supply an up function.'); + if (typeof migration.up !== 'function') + throw new Meteor.Error('Migration must supply an up function.'); - if (typeof migration.version !== 'number') - throw new Meteor.Error('Migration must supply a version number.'); + if (typeof migration.version !== 'number') + throw new Meteor.Error('Migration must supply a version number.'); - if (migration.version <= 0) - throw new Meteor.Error('Migration version must be greater than 0'); + if (migration.version <= 0) + throw new Meteor.Error('Migration version must be greater than 0'); - // Freeze the migration object to make it hereafter immutable - Object.freeze(migration); + // Freeze the migration object to make it hereafter immutable + Object.freeze(migration); - this._list.push(migration); - this._list = _.sortBy(this._list, function(m) {return m.version;}); + this._list.push(migration); + this._list = _.sortBy(this._list, function(m) { + return m.version; + }); } // Attempts to run the migrations using command in the form of: // e.g 'latest', 'latest,exit', 2 // use 'XX,rerun' to re-run the migration at that version Migrations.migrateTo = function(command) { - if (_.isUndefined(command) || command === '' || this._list.length === 0) - throw new Error("Cannot migrate using invalid command: " + command); - - if (typeof command === 'number') { - var version = command; - } else { - var version = command.split(',')[0]; - var subcommand = command.split(',')[1]; - } - - const maxAttempts = Migrations.options.maxAttempts; - const retryInterval = Migrations.options.retryInterval; - for (let attempts = 1; attempts <= maxAttempts; attempts++) { - if (version === 'latest') { - migrated = this._migrateTo(_.last(this._list).version); - } else { - migrated = this._migrateTo(parseInt(version), (subcommand === 'rerun')); - } - if (migrated) { - break; - } else { - let willRetry; - if (attempts < maxAttempts) { - willRetry = ` Trying again in ${retryInterval} seconds.`; - Meteor._sleepForMs(retryInterval * 1000); - } else { - willRetry = ""; - } - console.log(`Not migrating, control is locked. Attempt ${attempts}/${maxAttempts}.${willRetry}`.yellow); - } - } - if (!migrated) { - let control = this._getControl(); // Side effect: upserts control document. - console.log(makeABox([ - "ERROR! SERVER STOPPED", - "", - "Your database migration control is locked.", - "Please make sure you are running the latest version and try again.", - "If the problem persists, please contact support.", - "", - "This Rocket.Chat version: " + RocketChat.Info.version, - "Database locked at version: " + control.version, - "Database target version: " + (version === 'latest' ? _.last(this._list).version : version), - "", - "Commit: " + RocketChat.Info.commit.hash, - "Date: " + RocketChat.Info.commit.date, - "Branch: " + RocketChat.Info.commit.branch, - "Tag: " + RocketChat.Info.commit.tag - ])); - process.exit(1); - } - - // remember to run meteor with --once otherwise it will restart - if (subcommand === 'exit') - process.exit(0); + if (_.isUndefined(command) || command === '' || this._list.length === 0) + throw new Error("Cannot migrate using invalid command: " + command); + + if (typeof command === 'number') { + var version = command; + } else { + var version = command.split(',')[0]; + var subcommand = command.split(',')[1]; + } + + const maxAttempts = Migrations.options.maxAttempts; + const retryInterval = Migrations.options.retryInterval; + for (let attempts = 1; attempts <= maxAttempts; attempts++) { + if (version === 'latest') { + migrated = this._migrateTo(_.last(this._list).version); + } else { + migrated = this._migrateTo(parseInt(version), (subcommand === 'rerun')); + } + if (migrated) { + break; + } else { + let willRetry; + if (attempts < maxAttempts) { + willRetry = ` Trying again in ${retryInterval} seconds.`; + Meteor._sleepForMs(retryInterval * 1000); + } else { + willRetry = ""; + } + console.log(`Not migrating, control is locked. Attempt ${attempts}/${maxAttempts}.${willRetry}`.yellow); + } + } + if (!migrated) { + let control = this._getControl(); // Side effect: upserts control document. + console.log(makeABox([ + "ERROR! SERVER STOPPED", + "", + "Your database migration control is locked.", + "Please make sure you are running the latest version and try again.", + "If the problem persists, please contact support.", + "", + "This Rocket.Chat version: " + RocketChat.Info.version, + "Database locked at version: " + control.version, + "Database target version: " + (version === 'latest' ? _.last(this._list).version : version), + "", + "Commit: " + RocketChat.Info.commit.hash, + "Date: " + RocketChat.Info.commit.date, + "Branch: " + RocketChat.Info.commit.branch, + "Tag: " + RocketChat.Info.commit.tag + ])); + process.exit(1); + } + + // remember to run meteor with --once otherwise it will restart + if (subcommand === 'exit') + process.exit(0); } // just returns the current version Migrations.getVersion = function() { - return this._getControl().version; + return this._getControl().version; } // migrates to the specific version passed in Migrations._migrateTo = function(version, rerun) { - var self = this; - var control = this._getControl(); // Side effect: upserts control document. - var currentVersion = control.version; - - if (lock() === false) { - // log.info('Not migrating, control is locked.'); - // Warning - return false; - } - - if (rerun) { - log.info('Rerunning version ' + version); - migrate('up', version); - log.info('Finished migrating.'); - unlock(); - return true; - } - - if (currentVersion === version) { - if (this.options.logIfLatest) { - log.info('Not migrating, already at version ' + version); - } - unlock(); - return true; - } - - var startIdx = this._findIndexByVersion(currentVersion); - var endIdx = this._findIndexByVersion(version); - - // log.info('startIdx:' + startIdx + ' endIdx:' + endIdx); - log.info('Migrating from version ' + this._list[startIdx].version + ' -> ' + this._list[endIdx].version); - - // run the actual migration - function migrate(direction, idx) { - var migration = self._list[idx]; - - if (typeof migration[direction] !== 'function') { - unlock(); - throw new Meteor.Error('Cannot migrate ' + direction + ' on version ' + migration.version); - } - - function maybeName() { - return migration.name ? ' (' + migration.name + ')' : ''; - } - - log.info('Running ' + direction + '() on version ' + migration.version + maybeName()); - - try { - migration[direction](migration); - } catch (e) { - console.log(makeABox([ - "ERROR! SERVER STOPPED", - "", - "Your database migration failed:", - e.message, - "", - "Please make sure you are running the latest version and try again.", - "If the problem persists, please contact support.", - "", - "This Rocket.Chat version: " + RocketChat.Info.version, - "Database locked at version: " + control.version, - "Database target version: " + version, - "", - "Commit: " + RocketChat.Info.commit.hash, - "Date: " + RocketChat.Info.commit.date, - "Branch: " + RocketChat.Info.commit.branch, - "Tag: " + RocketChat.Info.commit.tag - ])); - process.exit(1); - } - } - - // Returns true if lock was acquired. - function lock() { - const date = new Date(); - const dateMinusInterval = moment(date).subtract(self.options.retryInterval, 'minutes').toDate(); - - // This is atomic. The selector ensures only one caller at a time will see - // the unlocked control, and locking occurs in the same update's modifier. - // All other simultaneous callers will get false back from the update. - return self._collection.update( - {_id: 'control', $or: [ { locked: false }, { lockedAt: { $lt: dateMinusInterval } } ] }, {$set: {locked: true, lockedAt: date}} - ) === 1; - } - - // Side effect: saves version. - function unlock() { - self._setControl({locked: false, version: currentVersion}); - } - - if (currentVersion < version) { - for (var i = startIdx;i < endIdx;i++) { - migrate('up', i + 1); - currentVersion = self._list[i + 1].version; - } - } else { - for (var i = startIdx;i > endIdx;i--) { - migrate('down', i); - currentVersion = self._list[i - 1].version; - } - } - - unlock(); - log.info('Finished migrating.'); + var self = this; + var control = this._getControl(); // Side effect: upserts control document. + var currentVersion = control.version; + + if (lock() === false) { + // log.info('Not migrating, control is locked.'); + // Warning + return false; + } + + if (rerun) { + log.info('Rerunning version ' + version); + migrate('up', version); + log.info('Finished migrating.'); + unlock(); + return true; + } + + if (currentVersion === version) { + if (this.options.logIfLatest) { + log.info('Not migrating, already at version ' + version); + } + unlock(); + return true; + } + + var startIdx = this._findIndexByVersion(currentVersion); + var endIdx = this._findIndexByVersion(version); + + // log.info('startIdx:' + startIdx + ' endIdx:' + endIdx); + log.info('Migrating from version ' + this._list[startIdx].version + ' -> ' + this._list[endIdx].version); + + // run the actual migration + function migrate(direction, idx) { + var migration = self._list[idx]; + + if (typeof migration[direction] !== 'function') { + unlock(); + throw new Meteor.Error('Cannot migrate ' + direction + ' on version ' + migration.version); + } + + function maybeName() { + return migration.name ? ' (' + migration.name + ')' : ''; + } + + log.info('Running ' + direction + '() on version ' + migration.version + maybeName()); + + try { + migration[direction](migration); + } catch (e) { + console.log(makeABox([ + "ERROR! SERVER STOPPED", + "", + "Your database migration failed:", + e.message, + "", + "Please make sure you are running the latest version and try again.", + "If the problem persists, please contact support.", + "", + "This Rocket.Chat version: " + RocketChat.Info.version, + "Database locked at version: " + control.version, + "Database target version: " + version, + "", + "Commit: " + RocketChat.Info.commit.hash, + "Date: " + RocketChat.Info.commit.date, + "Branch: " + RocketChat.Info.commit.branch, + "Tag: " + RocketChat.Info.commit.tag + ])); + process.exit(1); + } + } + + // Returns true if lock was acquired. + function lock() { + const date = new Date(); + const dateMinusInterval = moment(date).subtract(self.options.lockExpiration, 'minutes').toDate(); + + // This is atomic. The selector ensures only one caller at a time will see + // the unlocked control, and locking occurs in the same update's modifier. + // All other simultaneous callers will get false back from the update. + return self._collection.update({ + _id: 'control', + $or: [{ + locked: false + }, { + lockedAt: { + $lt: dateMinusInterval + } + }, { + buildAt: { + $ne: RocketChat.Info.build.date + } + }] + }, { + $set: { + locked: true, + lockedAt: date, + buildAt: RocketChat.Info.build.date + } + }) === 1; + } + + + // Side effect: saves version. + function unlock() { + self._setControl({ + locked: false, + version: currentVersion + }); + } + + if (currentVersion < version) { + for (var i = startIdx; i < endIdx; i++) { + migrate('up', i + 1); + currentVersion = self._list[i + 1].version; + } + } else { + for (var i = startIdx; i > endIdx; i--) { + migrate('down', i); + currentVersion = self._list[i - 1].version; + } + } + + unlock(); + log.info('Finished migrating.'); } // gets the current control record, optionally creating it if non-existant Migrations._getControl = function() { - var control = this._collection.findOne({_id: 'control'}); - - return control || this._setControl({version: 0, locked: false}); + var control = this._collection.findOne({ + _id: 'control' + }); + + return control || this._setControl({ + version: 0, + locked: false + }); } // sets the control record Migrations._setControl = function(control) { - // be quite strict - check(control.version, Number); - check(control.locked, Boolean); - - this._collection.update({_id: 'control'}, - {$set: {version: control.version, locked: control.locked}}, {upsert: true}); - - return control; + // be quite strict + check(control.version, Number); + check(control.locked, Boolean); + + this._collection.update({ + _id: 'control' + }, { + $set: { + version: control.version, + locked: control.locked + } + }, { + upsert: true + }); + + return control; } // returns the migration index in _list or throws if not found Migrations._findIndexByVersion = function(version) { - for (var i = 0;i < this._list.length;i++) { - if (this._list[i].version === version) - return i; - } + for (var i = 0; i < this._list.length; i++) { + if (this._list[i].version === version) + return i; + } - throw new Meteor.Error('Can\'t find migration version ' + version); + throw new Meteor.Error('Can\'t find migration version ' + version); } //reset (mainly intended for tests) Migrations._reset = function() { - this._list = [{version: 0, up: function(){}}]; - this._collection.remove({}); + this._list = [{ + version: 0, + up: function() {} + }]; + this._collection.remove({}); } -RocketChat.Migrations = Migrations; \ No newline at end of file +RocketChat.Migrations = Migrations; -- GitLab From 8c9d6733e92e9cca98b277012e4685153bc29e8a Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 29 Jan 2016 13:18:04 -0200 Subject: [PATCH 1291/1338] Re-enabled rocketchat:livechat --- .meteor/packages | 2 +- .meteor/versions | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.meteor/packages b/.meteor/packages index 903db389d81..37a7fa26482 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -52,7 +52,7 @@ rocketchat:github-enterprise rocketchat:gitlab rocketchat:highlight rocketchat:ldap -# rocketchat:livechat +rocketchat:livechat rocketchat:logger rocketchat:mailer rocketchat:markdown diff --git a/.meteor/versions b/.meteor/versions index ba58623294a..d2b7f9cb6b5 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -137,6 +137,7 @@ 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 -- GitLab From 5da434b65dec98c26614ff02cfabb9db194baa30 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 16:47:24 -0200 Subject: [PATCH 1292/1338] Closes #2078; ObserveChanges on rocketchat_room Not Using Oplog --- server/publications/spotlight.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/publications/spotlight.coffee b/server/publications/spotlight.coffee index feec1ce6f65..62fe104a703 100644 --- a/server/publications/spotlight.coffee +++ b/server/publications/spotlight.coffee @@ -13,7 +13,7 @@ Meteor.publish 'spotlight', (selector, options, collName) -> removed: (id) -> self.removed("autocompleteRecords", id) - subHandleRooms = RocketChat.models.Rooms.findByNameContainingAndTypes(selector.name.$regex, ['c'], { limit: 10, fields: { t: 1, name: 1 } }).observeChanges + subHandleRooms = RocketChat.models.Rooms.findByNameContainingAndTypes(selector.name.$regex, ['c'], { limit: 10, fields: { t: 1, name: 1 }, sort: {name: 1}}).observeChanges added: (id, fields) -> data = { type: 'r', rid: id, name: fields.name, t: fields.t } self.added("autocompleteRecords", id, data) -- GitLab From b5c9a8a45ed4faf9314ccfebf0ce2a2ca4d64fb0 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 16:52:37 -0200 Subject: [PATCH 1293/1338] Add sort for all queries with limit --- server/publications/channelAutocomplete.coffee | 2 ++ server/publications/roomSearch.coffee | 4 ++-- server/publications/spotlight.coffee | 2 +- server/publications/userAutocomplete.coffee | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/server/publications/channelAutocomplete.coffee b/server/publications/channelAutocomplete.coffee index 7586b0242ef..6f6b3350283 100644 --- a/server/publications/channelAutocomplete.coffee +++ b/server/publications/channelAutocomplete.coffee @@ -9,6 +9,8 @@ Meteor.publish 'channelAutocomplete', (name) -> _id: 1 name: 1 limit: 5 + sort: + name: 1 cursorHandle = RocketChat.models.Rooms.findByNameContainingAndTypes(name, ['c'], options).observeChanges added: (_id, record) -> diff --git a/server/publications/roomSearch.coffee b/server/publications/roomSearch.coffee index f3357511223..308e0e3a869 100644 --- a/server/publications/roomSearch.coffee +++ b/server/publications/roomSearch.coffee @@ -12,7 +12,7 @@ Meteor.publish 'roomSearch', (selector, options, collName) -> delete selector.type if not searchType? or searchType is 'u' - subHandleUsers = RocketChat.models.Users.find(selector, { limit: 10, fields: { name: 1, username: 1, status: 1 } }).observeChanges + subHandleUsers = RocketChat.models.Users.find(selector, { limit: 10, fields: { name: 1, username: 1, status: 1 }, sort: { name: 1 } }).observeChanges added: (id, fields) -> data = { type: 'u', uid: id, name: fields.name, username: fields.username, status: fields.status } self.added("autocompleteRecords", id, data) @@ -22,7 +22,7 @@ Meteor.publish 'roomSearch', (selector, options, collName) -> self.removed("autocompleteRecords", id) if not searchType? or searchType is 'r' - subHandleRooms = RocketChat.models.Rooms.findByTypesAndNotUserIdContainingUsername(RocketChat.roomTypes.getIdentifiers('d'), selector.uid?.$ne, RocketChat.models.Users.findOneById(this.userId).username, { limit: 10, fields: { t: 1, name: 1 } }).observeChanges + subHandleRooms = RocketChat.models.Rooms.findByTypesAndNotUserIdContainingUsername(RocketChat.roomTypes.getIdentifiers('d'), selector.uid?.$ne, RocketChat.models.Users.findOneById(this.userId).username, { limit: 10, fields: { t: 1, name: 1 }, sort: { name: 1 } }).observeChanges added: (id, fields) -> data = { type: 'r', rid: id, name: fields.name, t: fields.t } self.added("autocompleteRecords", id, data) diff --git a/server/publications/spotlight.coffee b/server/publications/spotlight.coffee index 62fe104a703..6d95171eea3 100644 --- a/server/publications/spotlight.coffee +++ b/server/publications/spotlight.coffee @@ -6,7 +6,7 @@ Meteor.publish 'spotlight', (selector, options, collName) -> subHandleUsers = null subHandleRooms = null - subHandleUsers = RocketChat.models.Users.findUsersByNameOrUsername(new RegExp(selector.name.$regex, 'i'), { limit: 10, fields: { name: 1, username: 1, status: 1 } }).observeChanges + subHandleUsers = RocketChat.models.Users.findUsersByNameOrUsername(new RegExp(selector.name.$regex, 'i'), { limit: 10, fields: { name: 1, username: 1, status: 1 }, sort: { name: 1 } }).observeChanges added: (id, fields) -> data = { type: 'u', uid: id, name: fields.username + ' - ' + fields.name, status: fields.status } self.added("autocompleteRecords", id, data) diff --git a/server/publications/userAutocomplete.coffee b/server/publications/userAutocomplete.coffee index 0f20eb20524..1be9ad7d5bf 100644 --- a/server/publications/userAutocomplete.coffee +++ b/server/publications/userAutocomplete.coffee @@ -10,6 +10,8 @@ Meteor.publish 'userAutocomplete', (selector) -> username: 1 status: 1 limit: 10 + sort: + name: 1 exceptions = selector.exceptions or [] -- GitLab From d1afe6a728ec9fb4657c58e3fb882e087401a64a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 17:06:40 -0200 Subject: [PATCH 1294/1338] Do not get field `usernames` with room on joinDefaultChannel --- .../rocketchat-lib/server/methods/joinDefaultChannels.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee b/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee index 3087fb387f4..fd49fe4df26 100644 --- a/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee +++ b/packages/rocketchat-lib/server/methods/joinDefaultChannels.coffee @@ -7,7 +7,7 @@ Meteor.methods RocketChat.callbacks.run 'beforeJoinDefaultChannels', user - RocketChat.models.Rooms.findByDefaultAndTypes(true, ['c', 'p']).forEach (room) -> + RocketChat.models.Rooms.findByDefaultAndTypes(true, ['c', 'p'], {fields: {usernames: 0}}).forEach (room) -> # put user in default rooms RocketChat.models.Rooms.addUsernameById room._id, user.username -- GitLab From 3eb4ed97de7cf4e3f7aac81d207a6abab7d1d6f4 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 29 Jan 2016 17:47:49 -0200 Subject: [PATCH 1295/1338] Change admin statistics for admin info. --- client/routes/adminRouter.coffee | 8 +- i18n/en.i18n.json | 36 ++-- .../server/startup/settings.coffee | 4 +- packages/rocketchat-mailer/i18n/en.i18n.json | 1 - .../server/methods/getStatistics.coffee | 8 +- .../server/models/Statistics.coffee | 5 + .../assets/stylesheets/base.less | 7 + packages/rocketchat-ui-admin/admin/admin.html | 2 +- .../rocketchat-ui-admin/admin/adminFlex.html | 9 +- ...dminStatistics.coffee => adminInfo.coffee} | 32 +++- .../{adminStatistics.html => adminInfo.html} | 158 +++++++++++++----- .../admin/rooms/adminRoomInfo.html | 2 +- .../admin/rooms/adminRooms.html | 2 +- .../admin/users/adminUserChannels.html | 2 +- .../admin/users/adminUserEdit.html | 2 +- .../admin/users/adminUsers.html | 2 +- packages/rocketchat-ui-admin/package.js | 4 +- .../side-nav/accountBox.coffee | 1 + 18 files changed, 201 insertions(+), 84 deletions(-) rename packages/rocketchat-ui-admin/admin/{adminStatistics.coffee => adminInfo.coffee} (68%) rename packages/rocketchat-ui-admin/admin/{adminStatistics.html => adminInfo.html} (56%) diff --git a/client/routes/adminRouter.coffee b/client/routes/adminRouter.coffee index 63b03b9d917..e8d6c87d3cf 100644 --- a/client/routes/adminRouter.coffee +++ b/client/routes/adminRouter.coffee @@ -16,11 +16,11 @@ FlowRouter.route '/admin/rooms', RocketChat.TabBar.showGroup 'adminrooms' BlazeLayout.render 'main', {center: 'adminRooms'} -FlowRouter.route '/admin/statistics', - name: 'admin-statistics' +FlowRouter.route '/admin/info', + name: 'admin-info' action: -> - RocketChat.TabBar.showGroup 'adminstatistics' - BlazeLayout.render 'main', {center: 'adminStatistics'} + RocketChat.TabBar.showGroup 'adminInfo' + BlazeLayout.render 'main', {center: 'adminInfo'} FlowRouter.route '/admin/:group?', name: 'admin' diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index f01624f27a1..24f6620c41e 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -89,6 +89,7 @@ "are_also_typing" : "are also typing", "are_typing" : "are typing", "Are_you_sure" : "Are you sure?", + "Author" : "Author", "Authorization_URL" : "Authorization URL", "Authorize" : "Authorize", "Auto_Load_Images" : "Auto Load Images", @@ -105,6 +106,8 @@ "Back_to_integrations" : "Back to integrations", "Back_to_login" : "Back to login", "bold" : "bold", + "Branch" : "Branch", + "Build_Environment" : "Build Environment", "busy" : "busy", "Busy" : "Busy", "busy_female" : "busy", @@ -126,6 +129,7 @@ "close" : "close", "coming_soon" : "coming soon", "Commands" : "Commands", + "Commit" : "Commit", "Compact_View" : "Compact View", "Confirm_password" : "Confirm your password", "Contact" : "Contact", @@ -140,7 +144,9 @@ "Created_at_s_by_s" : "Created at <strong>%s</strong> by <strong>%s</strong>", "Custom_oauth_helper" : "When setting up your OAuth Provider, you'll have to inform a Callback URL. Use <pre>%s</pre> .", "Custom_oauth_unique_name" : "Custom oauth unique name", + "Date" : "Date", "days" : "days", + "DB_Schema_Version" : "DB Schema Version", "Deactivate" : "Deactivate", "Delete_Room_Warning" : "Deleting a room will delete all messages posted within the room. This cannot be undone.", "Delete_User_Warning" : "Deleting a user will delete all messages from that user as well. This cannot be undone.", @@ -194,12 +200,14 @@ "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.", + "Hash" : "Hash", "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", "History" : "History", "hours" : "hours", "Incorrect_Password" : "Incorrect Password", + "Info" : "Info", "inline_code" : "inline_code", "Install_Extension" : "Install Extension", "Install_FxOs" : "Install Rocket.Chat on your Firefox", @@ -349,6 +357,7 @@ "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!", + "Node_version" : "Node version", "Not_allowed" : "Not allowed", "Not_authorized" : "Not authorized", "Not_found_or_not_allowed" : "Not Found or Not Allowed", @@ -424,6 +433,7 @@ "Reset_password" : "Reset password", "Restart" : "Restart", "Restart_the_server" : "Restart the server", + "Rocket.Chat" : "Rocket.Chat", "Room" : "Room", "Room_archived" : "Room archived", "Room_has_been_deleted" : "Room has been deleted", @@ -435,6 +445,7 @@ "Room_uploaded_file_list_empty" : "No files available.", "room_user_count" : "%s users", "Rooms" : "Rooms", + "Runtime_Environment" : "Runtime Environment", "S_new_messages_since_s" : "%s new messages since %s", "SAML" : "SAML", "SAML_Custom_Cert" : "Custom Certificate", @@ -501,15 +512,15 @@ "Stats_Non_Active_Users" : "Inactive Users", "Stats_Offline_Users" : "Offline Users", "Stats_Online_Users" : "Online Users", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS CPU Count", - "Stats_OS_Freemem" : "OS Free Memory", - "Stats_OS_Loadavg" : "OS Load Average", - "Stats_OS_Platform" : "OS Platform", - "Stats_OS_Release" : "OS Release", - "Stats_OS_Totalmem" : "OS Total Memory", - "Stats_OS_Type" : "OS Type", - "Stats_OS_Uptime" : "OS Uptime", + "Arch" : "Arch", + "Cpus" : "CPU Count", + "Freemem" : "Free Memory", + "Loadavg" : "Load Average", + "Platform" : "Platform", + "Release" : "Release", + "Totalmem" : "Total Memory", + "Type" : "Type", + "Uptime" : "Uptime", "Stats_Total_Channels" : "Total Channels", "Stats_Total_Direct_Messages" : "Total Direct Message Rooms", "Stats_Total_Messages" : "Total Messages", @@ -518,9 +529,11 @@ "Stats_Total_Users" : "Total Users", "Stop_Recording" : "Stop Recording", "strike" : "strike", + "Subject" : "Subject", "Submit" : "Submit", "Success" : "Success", - "The_application_name_is_required" : "Th _application name is required", + "Tag" : "Tag", + "The_application_name_is_required" : "The _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.", @@ -540,6 +553,7 @@ "Unread_Rooms_Mode" : "Unread Rooms Mode", "Upload_file_question" : "Upload file?", "Uploading_file" : "Uploading file...", + "Usage" : "Usage", "Use_Emojis" : "Use Emojis", "Use_initials_avatar" : "Use your username initials", "use_menu" : "Use the side menu to access your rooms and chats", @@ -595,6 +609,7 @@ "UTF8_Names_Slugify" : "UTF8 Names Slugify", "UTF8_Names_Validation" : "UTF8 Names Validation", "UTF8_Names_Validation_Description" : "Do not allow special characters and spaces. You can use - _ and . but not at the end of the name", + "Version" : "Version", "View_All" : "View All", "Wait_activation_warning" : "Before you can login, your account must be manually activated by an administrator.", "We_have_sent_password_email" : "We have sent you an e-mail with password reset instructions. If you do not receive an e-mail shortly, please come back and try again.", @@ -610,6 +625,7 @@ "Yes_remove_user" : "Yes, remove user!", "you_are_in_preview_mode_of" : "You are in preview mode of channel #<strong>__room_name__</strong>", "You_are_logged_in_as" : "You are logged in as", + "You_are_not_authorized_to_view_this_page" : "You are not authorized to view this page.", "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", diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 523b1fab60a..af91d9ec18d 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -86,6 +86,8 @@ RocketChat.settings.addGroup 'General', -> @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 } + @section 'Reporting', -> + @add 'Statistics_opt_out', false, { type: 'boolean', i18nLabel: "Opt_out_statistics" } RocketChat.settings.addGroup 'API', -> @add 'API_Analytics', '', { type: 'string', public: true } @@ -162,8 +164,6 @@ RocketChat.settings.addGroup 'Layout', -> @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() # Remove runtime settings (non-persistent) diff --git a/packages/rocketchat-mailer/i18n/en.i18n.json b/packages/rocketchat-mailer/i18n/en.i18n.json index dd87fef341f..a1efdae9cc3 100644 --- a/packages/rocketchat-mailer/i18n/en.i18n.json +++ b/packages/rocketchat-mailer/i18n/en.i18n.json @@ -12,7 +12,6 @@ "Query_description" : "Additional conditions for determining which users to send the e-mail to. Unsubscribed users are automatically removed from the query. It must be a valid JSON. Example: \"{\"createdAt\":{\"$gt\":{\"$date\": \"2015-01-01T00:00:00.000Z\"}}}\"", "Send_email" : "Send E-mail", "The_emails_are_being_sent" : "The e-mails are being sent.", - "You_are_not_authorized_to_view_this_page" : "You are not authorized to view this page.", "You_have_successfully_unsubscribed" : "You have successfully unsubscribed from our Mailling List.", "You_informed_an_invalid_FROM_address" : "You informed an invalid FROM address.", "You_must_provide_the_unsubscribe_link" : "You must provide the [unsubscribe] link." diff --git a/packages/rocketchat-statistics/server/methods/getStatistics.coffee b/packages/rocketchat-statistics/server/methods/getStatistics.coffee index dfe10d205e7..03c983a5e8c 100644 --- a/packages/rocketchat-statistics/server/methods/getStatistics.coffee +++ b/packages/rocketchat-statistics/server/methods/getStatistics.coffee @@ -1,9 +1,13 @@ Meteor.methods - getStatistics: -> + getStatistics: (refresh) -> if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] getStatistics -> Invalid user") unless RocketChat.authz.hasPermission(Meteor.userId(), 'view-statistics') is true throw new Meteor.Error 'not-authorized', '[methods] getStatistics -> Not authorized' - return RocketChat.statistics.get() + if refresh + return RocketChat.statistics.save() + else + return RocketChat.models.Statistics.findLast() + diff --git a/packages/rocketchat-statistics/server/models/Statistics.coffee b/packages/rocketchat-statistics/server/models/Statistics.coffee index 79ae41e7869..8a645adb3d8 100644 --- a/packages/rocketchat-statistics/server/models/Statistics.coffee +++ b/packages/rocketchat-statistics/server/models/Statistics.coffee @@ -9,3 +9,8 @@ RocketChat.models.Statistics = new class extends RocketChat.models._Base _id: _id return @findOne query, options + + findLast: -> + query = {} + options = sort: createdAt: -1 + return @find(query, options).fetch()?[0] \ No newline at end of file diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 3cb40160396..c94be79f39f 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -3918,6 +3918,7 @@ a.github-fork { } .statistics-table { + margin-bottom: 30px; border: 1px solid; width:100%; tr { @@ -3931,6 +3932,12 @@ a.github-fork { text-align: left; padding: 3px 10px; } + th { + width: 20%; + } + td { + width: 80%; + } } .rocket-team { diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index 195d38f296b..b5865952fa0 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -9,7 +9,7 @@ <div class="content"> {{#unless hasPermission 'view-privileged-setting'}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} {{#with group}} {{#if description}} diff --git a/packages/rocketchat-ui-admin/admin/adminFlex.html b/packages/rocketchat-ui-admin/admin/adminFlex.html index c5c7b917f4d..633b7320bee 100644 --- a/packages/rocketchat-ui-admin/admin/adminFlex.html +++ b/packages/rocketchat-ui-admin/admin/adminFlex.html @@ -7,12 +7,9 @@ <div class="content"> <div class="wrapper"> <ul> - {{#if hasPermission 'view-statistics'}} - <li> - <a href="{{pathFor 'admin-statistics'}}" class="admin-link">{{_ "Statistics"}}</a> - </li> - {{/if}} - + <li> + <a href="{{pathFor 'admin-info'}}" class="admin-link">{{_ "Info"}}</a> + </li> {{#if hasPermission 'view-room-administration'}} <li> <a href="{{pathFor 'admin-rooms'}}" class="admin-link">{{_ "Rooms"}}</a> diff --git a/packages/rocketchat-ui-admin/admin/adminStatistics.coffee b/packages/rocketchat-ui-admin/admin/adminInfo.coffee similarity index 68% rename from packages/rocketchat-ui-admin/admin/adminStatistics.coffee rename to packages/rocketchat-ui-admin/admin/adminInfo.coffee index 7cc8a41bde6..495e6eab854 100644 --- a/packages/rocketchat-ui-admin/admin/adminStatistics.coffee +++ b/packages/rocketchat-ui-admin/admin/adminInfo.coffee @@ -1,4 +1,4 @@ -Template.adminStatistics.helpers +Template.adminInfo.helpers isReady: -> return Template.instance().ready.get() statistics: -> @@ -7,7 +7,7 @@ Template.adminStatistics.helpers if size > 1073741824 return _.numberFormat(size / 1024 / 1024 / 1024, 2) + ' GB' return _.numberFormat(size / 1024 / 1024, 2) + ' MB' - humanReadable: (time) -> + humanReadableTime: (time) -> days = Math.floor time / 86400 hours = Math.floor (time % 86400) / 3600 minutes = Math.floor ((time % 86400) % 3600) / 60 @@ -22,12 +22,23 @@ Template.adminStatistics.helpers if seconds > 0 out += "#{seconds} #{TAPi18n.__ 'seconds'}" return out + formatDate: (date) -> + if date + return moment(date).format("LLL") numFormat: (number) -> return _.numberFormat(number, 2) optOut: -> return RocketChat.settings.get 'Statistics_opt_out' + server: -> + return RocketChat.Info + commit: -> + return _.extend(RocketChat.Info?.commit, { tag: RocketChat.Info?.tag, branch: RocketChat.Info?.branch }) + migration: -> + return Template.instance().migration.get() + build: -> + return RocketChat.Info?.compile || RocketChat.Info?.build -Template.adminStatistics.events +Template.adminInfo.events 'click input[name=opt-out-statistics]': (e) -> if $(e.currentTarget).prop('checked') $('#opt-out-warning').show() @@ -38,7 +49,16 @@ Template.adminStatistics.events RocketChat.settings.set 'Statistics_opt_out', false, -> toastr.success TAPi18n.__ 'Settings_updated' -Template.adminStatistics.onRendered -> + 'click .refresh': (e, instance) -> + instance.ready.set false + Meteor.call 'getStatistics', true, (error, statistics) -> + instance.ready.set true + if error + toastr.error error.reason + else + instance.statistics.set statistics + +Template.adminInfo.onRendered -> Tracker.afterFlush -> SideNav.setFlex "adminFlex" SideNav.openFlex() @@ -48,9 +68,10 @@ Template.adminStatistics.onRendered -> else $('#opt-out-warning').hide() -Template.adminStatistics.onCreated -> +Template.adminInfo.onCreated -> instance = @ @statistics = new ReactiveVar {} + @migration = new ReactiveVar {} @ready = new ReactiveVar false Meteor.call 'getStatistics', (error, statistics) -> @@ -59,3 +80,4 @@ Template.adminStatistics.onCreated -> toastr.error error.reason else instance.statistics.set statistics + diff --git a/packages/rocketchat-ui-admin/admin/adminStatistics.html b/packages/rocketchat-ui-admin/admin/adminInfo.html similarity index 56% rename from packages/rocketchat-ui-admin/admin/adminStatistics.html rename to packages/rocketchat-ui-admin/admin/adminInfo.html index f039362a8ea..0eb3ba57087 100644 --- a/packages/rocketchat-ui-admin/admin/adminStatistics.html +++ b/packages/rocketchat-ui-admin/admin/adminInfo.html @@ -1,16 +1,122 @@ -<template name="adminStatistics"> +<template name="adminInfo"> <section class="page-container page-list"> <head class="fixed-title"> {{> burger}} <h2> - <span class="room-title">{{_ "Statistics"}}</span> + <span class="room-title">{{_ "Info"}}</span> </h2> </head> <div class="content"> + <h3>{{_ "Rocket.Chat"}}</h3> + <table class="statistics-table"> + <tr> + <th>{{_ "Version"}}</th> + <td>{{server.version}}</td> + </tr> + <tr> + <th>{{_ "DB_Schema_Version"}}</th> + <td>{{migration.version}}</td> + </tr> + </table> + + <h3>{{_ "Commit"}}</h3> + <table class="statistics-table"> + <tr> + <th>{{_ "Hash"}}</th> + <td>{{commit.hash}}</td> + </tr> + <tr> + <th>{{_ "Date"}}</th> + <td>{{commit.date}}</td> + </tr> + <tr> + <th>{{_ "Branch"}}</th> + <td>{{commit.branch}}</td> + </tr> + <tr> + <th>{{_ "Tag"}}</th> + <td>{{commit.tag}}</td> + </tr> + <tr> + <th>{{_ "Author"}}</th> + <td>{{commit.author}}</td> + </tr> + <tr> + <th>{{_ "Subject"}}</th> + <td>{{commit.subject}}</td> + </tr> + </table> + {{#unless hasPermission 'view-statistics'}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} {{#if isReady}} + <h3>{{_ "Runtime_Environment"}}</h3> + <table class="statistics-table"> + <tr> + <th>{{_ "Type"}}</th> + <td>{{statistics.os.type}}</td> + </tr> + <tr> + <th>{{_ "Platform"}}</th> + <td>{{statistics.os.platform}}</td> + </tr> + <tr> + <th>{{_ "Arch"}}</th> + <td>{{statistics.os.arch}}</td> + </tr> + <tr> + <th>{{_ "Release"}}</th> + <td>{{statistics.os.release}}</td> + </tr> + <tr> + <th>{{_ "Uptime"}}</th> + <td>{{humanReadableTime statistics.os.uptime}}</td> + </tr> + <tr> + <th>{{_ "Loadavg"}}</th> + <td>{{numFormat statistics.os.loadavg.[0]}}, {{numFormat statistics.os.loadavg.[1]}}, {{numFormat statistics.os.loadavg.[2]}}</td> + </tr> + <tr> + <th>{{_ "Totalmem"}}</th> + <td>{{inGB statistics.os.totalmem}}</td> + </tr> + <tr> + <th>{{_ "Freemem"}}</th> + <td>{{inGB statistics.os.freemem}}</td> + </tr> + <tr> + <th>{{_ "Cpus"}}</th> + <td>{{statistics.os.cpus.length}}</td> + </tr> + </table> + + <h3>{{_ "Build_Environment"}}</h3> + <table class="statistics-table"> + <tr> + <th>{{_ "Platform"}}</th> + <td>{{build.platform}}</td> + </tr> + <tr> + <th>{{_ "Arch"}}</th> + <td>{{build.arch}}</td> + </tr> + <tr> + <th>{{_ "Release"}}</th> + <td>{{build.osRelease}}</td> + </tr> + <tr> + <th>{{_ "Node_version"}}</th> + <td>{{build.nodeVersion}}</td> + </tr> + <tr> + <th>{{_ "Date"}}</th> + <td>{{formatDate build.date}}</td> + </tr> + </table> + + + <h3>{{_ "Usage"}}</h3> <table class="statistics-table"> <tr> <th>{{_ "Stats_Total_Users"}}</th> @@ -68,53 +174,13 @@ <th>{{_ "Stats_Avg_Private_Group_Users"}}</th> <td>{{numFormat statistics.avgPrivateGroupUsers}}</td> </tr> - <tr> - <th>{{_ "Stats_OS_Type"}}</th> - <td>{{statistics.os.type}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Platform"}}</th> - <td>{{statistics.os.platform}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Arch"}}</th> - <td>{{statistics.os.arch}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Release"}}</th> - <td>{{statistics.os.release}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Uptime"}}</th> - <td>{{humanReadable statistics.os.uptime}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Loadavg"}}</th> - <td>{{numFormat statistics.os.loadavg.[0]}}, {{numFormat statistics.os.loadavg.[1]}}, {{numFormat statistics.os.loadavg.[2]}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Totalmem"}}</th> - <td>{{inGB statistics.os.totalmem}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Freemem"}}</th> - <td>{{inGB statistics.os.freemem}}</td> - </tr> - <tr> - <th>{{_ "Stats_OS_Cpus"}}</th> - <td>{{statistics.os.cpus.length}}</td> - </tr> </table> + + <button type="button" class="button refresh">Refresh</button> {{else}} - {{_ "Please_wait_statistics"}} + {{_ "Loading..."}} {{/if}} {{/unless}} - <div style="margin: 30px 0"> - <label for="opt-out-statistics"><input type="checkbox" value="1" name="opt-out-statistics" id="opt-out-statistics" checked="{{optOut}}"> {{_ "Opt_out_statistics"}}</label> - <div id="opt-out-warning" class="alert-warning" style="margin-top: 10px; padding: 10px;"> - {{_ "Opt_out_statistics_warning"}} - </div> - </div> </div> </section> </template> \ No newline at end of file diff --git a/packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.html b/packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.html index 090f36d5e89..cb469535dea 100644 --- a/packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.html +++ b/packages/rocketchat-ui-admin/admin/rooms/adminRoomInfo.html @@ -1,6 +1,6 @@ <template name="adminRoomInfo"> {{#unless hasPermission 'view-room-administration'}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} <div> <h3><a href="{{route}}"><i class="icon-{{type}}"></i> {{name}}</a></h3> diff --git a/packages/rocketchat-ui-admin/admin/rooms/adminRooms.html b/packages/rocketchat-ui-admin/admin/rooms/adminRooms.html index cc39896ec68..2b43a742e6d 100644 --- a/packages/rocketchat-ui-admin/admin/rooms/adminRooms.html +++ b/packages/rocketchat-ui-admin/admin/rooms/adminRooms.html @@ -8,7 +8,7 @@ </head> <div class="content"> {{#unless hasPermission 'view-room-administration'}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} <form class="search-form" role="form"> <div class="input-line search"> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserChannels.html b/packages/rocketchat-ui-admin/admin/users/adminUserChannels.html index af72dcbbad0..a1b85e7fc76 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserChannels.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserChannels.html @@ -1,6 +1,6 @@ <template name="adminUserChannels"> {{#unless hasPermission 'view-full-other-user-info'}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} <div class="user-info-channel"> <h3><a href="{{route}}"><i class="icon-{{type}}"></i> {{name}}</a></h3> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html index 002135df0ed..1dc74289548 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUserEdit.html @@ -1,6 +1,6 @@ <template name="adminUserEdit"> {{#unless canEditOrAdd}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} <div class="about clearfix"> <form class="edit-form"> diff --git a/packages/rocketchat-ui-admin/admin/users/adminUsers.html b/packages/rocketchat-ui-admin/admin/users/adminUsers.html index aa410e3c987..55c27f5f1bd 100644 --- a/packages/rocketchat-ui-admin/admin/users/adminUsers.html +++ b/packages/rocketchat-ui-admin/admin/users/adminUsers.html @@ -8,7 +8,7 @@ </head> <div class="content"> {{#unless hasPermission 'view-user-administration'}} - <p>You are not authorized to view this page.</p> + <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> {{else}} <form class="search-form" role="form"> <div class="input-line search"> diff --git a/packages/rocketchat-ui-admin/package.js b/packages/rocketchat-ui-admin/package.js index 6fc80872456..e72b2bdb71d 100644 --- a/packages/rocketchat-ui-admin/package.js +++ b/packages/rocketchat-ui-admin/package.js @@ -24,7 +24,7 @@ Package.onUse(function(api) { // template files api.addFiles('admin/admin.html', 'client'); api.addFiles('admin/adminFlex.html', 'client'); - api.addFiles('admin/adminStatistics.html', 'client'); + api.addFiles('admin/adminInfo.html', 'client'); api.addFiles('admin/rooms/adminRoomInfo.html', 'client'); api.addFiles('admin/rooms/adminRooms.html', 'client'); @@ -38,7 +38,7 @@ Package.onUse(function(api) { // coffee files api.addFiles('admin/admin.coffee', 'client'); api.addFiles('admin/adminFlex.coffee', 'client'); - api.addFiles('admin/adminStatistics.coffee', 'client'); + api.addFiles('admin/adminInfo.coffee', 'client'); api.addFiles('admin/rooms/adminRoomInfo.coffee', 'client'); api.addFiles('admin/rooms/adminRooms.coffee', 'client'); diff --git a/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee index b5e470d32de..047b56e2e58 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/accountBox.coffee @@ -49,6 +49,7 @@ Template.accountBox.events 'click #admin': -> SideNav.setFlex "adminFlex" SideNav.openFlex() + FlowRouter.go 'admin-info' 'click .account-link': -> menu.close() -- GitLab From 342637e10406da43633462712b80bd661d3f2993 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Fri, 29 Jan 2016 17:48:37 -0200 Subject: [PATCH 1296/1338] Add history --- HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 112c878cd8b..5ff5315bf9d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,7 +2,7 @@ - Added option for admins to manually add new users - Added option for admin to require user to change password -- +- Changed admin statistics with admin info ## 0.15.0, 2016-Jan-25 -- GitLab From db8db791c135b768a2e3101878a440e624e72cf1 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 29 Jan 2016 18:32:26 -0200 Subject: [PATCH 1297/1338] Moving some translations to main local file --- i18n/de.i18n.json | 10 ++++++++-- i18n/en.i18n.json | 8 +++++++- .../rocketchat-slashcommands-kick/i18n/de.i18n.json | 6 +----- .../rocketchat-slashcommands-kick/i18n/en.i18n.json | 5 +---- .../rocketchat-slashcommands-msg/i18n/de.i18n.json | 3 --- .../rocketchat-slashcommands-msg/i18n/en.i18n.json | 3 --- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 0c92ffa5177..f1ea4c41b38 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -1,7 +1,7 @@ { "Access_not_authorized" : "Der Zugriff ist nicht gestattet.", - "Access_online_demo" : "Öffne die Online-Demo", "Access_Online_Demo" : "Öffne die Online Demo", + "Access_online_demo" : "Öffne die Online-Demo", "Access_Token_URL" : "URL des Access-Token", "Accounts" : "Konten", "Accounts_AllowedDomainsList" : "Liste von erlaubten Domains", @@ -147,6 +147,7 @@ "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 bereits aktiviert.", + "Direct_message_someone" : "Jemandem eine private Nachricht schicken", "Direct_Messages" : "Private Nachrichten", "Disable_Favorite_Rooms" : "Favoriten deaktivieren", "Disable_New_Message_Notification" : "Benachrichtigungen bei neuen Nachrichten deaktivieren", @@ -416,6 +417,7 @@ "Remove_as_owner" : "als Besitzer entfernen", "Remove_custom_oauth" : "OAuth-Konto entfernen", "Remove_from_room" : "Aus dem Raum entfernen", + "Remove_someone_from_room" : "Jemanden aus dem Raum entfernen", "Removed" : "Entfernt", "Reset" : "Zurücksetzen", "Reset_password" : "Passwort zurücksetzen", @@ -581,10 +583,14 @@ "User_unmuted_in_room" : "Dem Benutzer wurde das Chatten wieder erlaubt.", "User_updated_successfully" : "Der Benutzer wurde erfolgreich aktualisiert.", "Username" : "Benutzername", + "Username_and_message_must_not_be_empty" : "Benutzername und Nachricht dürfen nicht leer sein.", "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_doesnt_exist" : "Der Benutzername `#%s` existiert nicht.", + "Username_doesnt_exist" : "Der Benutzername `%s` existiert nicht.", "Username_invalid" : "<strong>%s</strong> ist kein zulässiger Benutzername.<br/> Benutzen Sie nur Buchstaben, Nummern, Punkte oder Bindestriche.", + "Username_is_not_in_this_room" : "Der Benutzer `#%s` ist nicht in diesem Raum.", "Username_title" : "Benutzernamen festlegen", "Username_unavaliable" : "<strong>%s</strong> wird leider schon verwendet. ", "Users" : "Benutzer", @@ -617,4 +623,4 @@ "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 f01624f27a1..3e32e31a9ad 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -148,6 +148,7 @@ "Desktop_Notifications" : "Desktop Notifications", "Desktop_Notifications_Disabled" : "Desktop Notifications are Disabled. Change your browser preferences if you need Notifications enabled.", "Desktop_Notifications_Enabled" : "Desktop Notifications are Enabled", + "Direct_message_someone" : "Direct message someone", "Direct_Messages" : "Direct Messages", "Disable_Favorite_Rooms" : "Disable Favorites", "Disable_New_Message_Notification" : "Disable New Message Notification", @@ -418,6 +419,7 @@ "Remove_as_owner" : "Remove as owner", "Remove_custom_oauth" : "Remove custom oauth", "Remove_from_room" : "Remove from room", + "Remove_someone_from_room" : "Remove someone from the room", "Removed" : "Removed", "Require_password_change" : "Require password change", "Reset" : "Reset", @@ -585,10 +587,14 @@ "User_unmuted_in_room" : "User unmuted in room", "User_updated_successfully" : "User updated successfully", "Username" : "Username", + "Username_and_message_must_not_be_empty" : "Username and message must not be empty.", "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "Username_description" : "The username is used to allow others to mention you in messages.", + "Username_doesnt_exist" : "The username `#%s` doesn't exist.", + "Username_doesnt_exist" : "The username `%s` doesn't exist.", "Username_invalid" : "<strong>%s</strong> is not a valid username,<br/> use only letters, numbers, dots and dashes", + "Username_is_not_in_this_room" : "The user `#%s` is not in this room.", "Username_title" : "Register username", "Username_unavaliable" : "<strong>%s</strong> is already in use :(", "Users" : "Users", @@ -622,4 +628,4 @@ "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/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json index 033f4cec499..ffcd4415b08 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/de.i18n.json @@ -1,5 +1 @@ -{ - "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/en.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json index 4074198404a..2c63c085104 100644 --- a/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json @@ -1,5 +1,2 @@ { - "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-msg/i18n/de.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json index 83dbe92c591..2c63c085104 100644 --- a/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json @@ -1,5 +1,2 @@ { - "Direct_message_someone" : "Jemandem eine private Nachricht schicken", - "Username_doesnt_exist" : "Der Benutzername `%s` existiert nicht.", - "Username_and_message_must_not_be_empty" : "Benutzername und Nachricht dürfen nicht leer sein." } diff --git a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json index 0a4f3ed90a4..2c63c085104 100644 --- a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json @@ -1,5 +1,2 @@ { - "Direct_message_someone" : "Direct message someone", - "Username_doesnt_exist" : "The username `%s` doesn't exist.", - "Username_and_message_must_not_be_empty" : "Username and message must not be empty." } -- GitLab From bc7ac82c856fd547255f1b4c6f1ef2e5286d05d9 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Fri, 29 Jan 2016 20:37:45 +0000 Subject: [PATCH 1298/1338] Created and pushed by LingoHub. Project: 'Rocket.Chat' by User: 'gabriel.engel@gmail.com'. --- i18n/ar.i18n.json | 2 ++ i18n/de.i18n.json | 14 +++++++++----- i18n/en.i18n.json | 3 +-- i18n/fi.i18n.json | 3 +++ i18n/fr.i18n.json | 3 +++ i18n/hr.i18n.json | 3 +++ i18n/km.i18n.json | 3 +++ i18n/nl.i18n.json | 13 +++++++++++++ i18n/ro.i18n.json | 3 +++ i18n/ru.i18n.json | 2 ++ .../rocketchat-channel-settings/i18n/de.i18n.json | 3 +++ .../rocketchat-channel-settings/i18n/en.i18n.json | 2 +- .../rocketchat-channel-settings/i18n/km.i18n.json | 4 +++- .../rocketchat-channel-settings/i18n/nl.i18n.json | 3 +++ packages/rocketchat-mailer/i18n/km.i18n.json | 2 ++ packages/rocketchat-message-pin/i18n/km.i18n.json | 1 + packages/rocketchat-theme/i18n/km.i18n.json | 5 ++++- packages/rocketchat-webrtc/i18n/nl.i18n.json | 2 +- 18 files changed, 60 insertions(+), 11 deletions(-) diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index 37da6c949c6..9c3fa43d5c4 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -236,6 +236,7 @@ "Remove" : "إزالة", "Remove_Admin" : "إزالة مدير", "Remove_from_room" : "إزالة من الغرÙØ©", + "Remove_someone_from_room" : "إزالة شخص من الغرÙØ©", "Removed" : "تمت اﻹزالة", "Reset" : "إعادة التعيين", "Reset_password" : "إعادة تعيين كلمة السر", @@ -347,6 +348,7 @@ "Username_Change_Disabled" : "مدير الموقع منع تغيير اسم المستخدم", "Username_description" : "يتم استخدام اسم المستخدم Ù„Ù„Ø³Ù…Ø§Ø Ù„Ù„Ø¢Ø®Ø±ÙŠÙ† بذكرك ÙÙŠ الرسائل.", "Username_invalid" : "<strong>%s</strong> لا ÙŠØµÙ„Ø ÙƒØ¥Ø³Ù… مستخدم،<br/> استخدم Ùقط ØروÙا وأرقاما وشرطات", + "Username_is_not_in_this_room" : "المستخدم `#%s` غير موجود ÙÙŠ الغرÙØ©", "Username_title" : "تسجيل اسم المستخدم", "Username_unavaliable" : "<strong>%s</strong> مستخدم مسبقا :(", "Users" : "المستخدمين", diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index f1ea4c41b38..500cc087838 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -1,7 +1,7 @@ { "Access_not_authorized" : "Der Zugriff ist nicht gestattet.", - "Access_Online_Demo" : "Öffne die Online Demo", "Access_online_demo" : "Öffne die Online-Demo", + "Access_Online_Demo" : "Öffne die Online Demo", "Access_Token_URL" : "URL des Access-Token", "Accounts" : "Konten", "Accounts_AllowedDomainsList" : "Liste von erlaubten Domains", @@ -68,6 +68,7 @@ "Activate" : "Aktivieren", "Add_custom_oauth" : "Benutzerdefiniertes OAuth-Konto hinzufügen", "Add_Members" : "Mitglieder hinzufügen", + "Add_User" : "Benutzer 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.", @@ -356,6 +357,7 @@ "Notify_all_in_this_room" : "Alle Benutzer in diesem Raum benachrichtigen", "OAuth_Application" : "OAuth-Anwendung", "OAuth_Applications" : "OAuth-Anwendungen", + "Old_and_new_password_must_be_different" : "Das neue Passwort muss sich vom dem alten Passwort unterscheiden.", "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", @@ -419,6 +421,7 @@ "Remove_from_room" : "Aus dem Raum entfernen", "Remove_someone_from_room" : "Jemanden aus dem Raum entfernen", "Removed" : "Entfernt", + "Require_password_change" : "Passwortänderung verlangen", "Reset" : "Zurücksetzen", "Reset_password" : "Passwort zurücksetzen", "Restart" : "Neustart", @@ -555,6 +558,7 @@ "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_added_successfully" : "Benutzer erfolgreich hinzugefügt", "User_Channels" : "Benutzerkanäle", "User_has_been_activated" : "Der Benutzer wurde aktiviert.", "User_has_been_deactivated" : "Der Benutzer wurde deaktiviert.", @@ -583,12 +587,11 @@ "User_unmuted_in_room" : "Dem Benutzer wurde das Chatten wieder erlaubt.", "User_updated_successfully" : "Der Benutzer wurde erfolgreich aktualisiert.", "Username" : "Benutzername", - "Username_and_message_must_not_be_empty" : "Benutzername und Nachricht dürfen nicht leer sein.", + "Username_and_message_must_not_be_empty" : "Die Felder \"Benutzername\" und \"Nachricht\" dürfen nicht leer sein.", "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_doesnt_exist" : "Der Benutzername `#%s` existiert nicht.", - "Username_doesnt_exist" : "Der Benutzername `%s` existiert nicht.", + "Username_doesnt_exist" : "Der Benutzer \"%s\" existiert nicht.", "Username_invalid" : "<strong>%s</strong> ist kein zulässiger Benutzername.<br/> Benutzen Sie nur Buchstaben, Nummern, Punkte oder Bindestriche.", "Username_is_not_in_this_room" : "Der Benutzer `#%s` ist nicht in diesem Raum.", "Username_title" : "Benutzernamen festlegen", @@ -617,10 +620,11 @@ "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_need_to_change_your_password" : "Sie müssen ihr Passwort ändern.", "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_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 3e32e31a9ad..2189c504643 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -591,7 +591,6 @@ "Username_cant_be_empty" : "The username cannot be empty", "Username_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of usernames", "Username_description" : "The username is used to allow others to mention you in messages.", - "Username_doesnt_exist" : "The username `#%s` doesn't exist.", "Username_doesnt_exist" : "The username `%s` doesn't exist.", "Username_invalid" : "<strong>%s</strong> is not a valid username,<br/> use only letters, numbers, dots and dashes", "Username_is_not_in_this_room" : "The user `#%s` is not in this room.", @@ -628,4 +627,4 @@ "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 83fdccc6647..ac15fa99f0d 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -409,6 +409,7 @@ "Remove_as_owner" : "Poista omistajuus", "Remove_custom_oauth" : "Poista mukautettu oauth", "Remove_from_room" : "Poista huoneesta", + "Remove_someone_from_room" : "Poista joku huoneesta", "Removed" : "Poistettu", "Reset" : "Nollaa", "Reset_password" : "Nollaa salasana", @@ -577,7 +578,9 @@ "Username_cant_be_empty" : "Käyttäjänimi ei voi olla tyhjä", "Username_Change_Disabled" : "Rocket.Chat ylläpitäjäsi on poistanut käyttäjätunnuksen vaihtamismahdollisuuden", "Username_description" : "Käyttäjänimeä käytetään sinun mainitsemiseen muiden viesteissä.", + "Username_doesnt_exist" : "Käyttäjätunnusta  `#% s` ei ole olemassa.", "Username_invalid" : "<strong>%s</strong> ei ole kelvollinen käyttäjänimi,<br/> käytä vain kirjaimia, numeroita, pistettä ja viivaa", + "Username_is_not_in_this_room" : "Käyttäjä `#% s` ei ole tässä huoneessa.", "Username_title" : "Rekisteröi käyttäjänimi", "Username_unavaliable" : "<strong>%s</strong> on jo käytössä :(", "Users" : "Käyttäjät", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index a534eea244b..b112a388522 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -356,6 +356,7 @@ "Remove_Admin" : "Supprimer administrateur", "Remove_custom_oauth" : "Supprimer OAuth personnalisé ", "Remove_from_room" : "Retirer du salon", + "Remove_someone_from_room" : "Retirer quelqu'un du salon.", "Reset_password" : "Réinitialiser le mot de passe", "Room" : "Salon", "Room_archived" : "Salon archivé", @@ -483,7 +484,9 @@ "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_doesnt_exist" : "L'utilisateur `#%s` n'existe pas.", "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_is_not_in_this_room" : "L'utilisateur `#%s` est pas dans ce salon.", "Username_title" : "Enregistrer un nom d'utilisateur", "Username_unavaliable" : "<strong>%s</strong> est déjà utilisé :(", "Users" : "Utilisateurs", diff --git a/i18n/hr.i18n.json b/i18n/hr.i18n.json index c70aaf9488d..7d6663da24c 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -230,6 +230,7 @@ "Remove" : "Makni", "Remove_Admin" : "Makni Administratora", "Remove_from_room" : "Uklonite iz sobe", + "Remove_someone_from_room" : "Uklonite nekoga iz sobe", "Removed" : "Uklonjeno", "Reset_password" : "Resetiraj lozinku", "Room" : "Soba", @@ -336,7 +337,9 @@ "Username_cant_be_empty" : "KorisniÄko ime ne može ostati prazno.", "Username_Change_Disabled" : "VaÅ¡ Rocket.Chat Administrator je onemogućio izmjenu korisniÄkih imena", "Username_description" : "KorisniÄko ime se koristi kako bi te drugi mogli spomenuti u porukama.", + "Username_doesnt_exist" : "KorisniÄko ime '#% s` ne postoji.", "Username_invalid" : "<strong>%s</strong> nije valjano korisniÄko ime,<br/> koristi samo slova, brojeve, toÄke i crtice", + "Username_is_not_in_this_room" : "Korisnik `#% s` nije u ovoj sobi.", "Username_title" : "Registriraj korisniÄko ime", "Username_unavaliable" : "<strong>%s</strong> je već zauzeto :(", "Users" : "Korisnici", diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index 1051095f4d3..f3b963b2607 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -11,6 +11,8 @@ "Accounts_AvatarStoreType" : "ប្រភáŸáž‘បន្ទុក Avatar", "Accounts_denyUnverifiedEmail" : "រាំងážáŸ’ទប់អ្នកមិនបានផ្ទៀážáž•áŸ’ទាážáŸ‹áž¢áŸŠáž¸áž˜áŸ‚áž›", "Accounts_EmailVerification" : "ការ​ផ្ទៀងផ្ទាážáŸ‹â€‹ážáž¶áž˜â€‹â€‹áž¢áŸŠáž¸â€‹áž˜áŸ‰áŸ‚​ល", + "Accounts_Enrollment_Email" : "ការចូលអ៊ីមែល", + "Accounts_Enrollment_Email_Description" : "អ្នកប្រហែលប្រើ [name], [fname], [lname] ពីឈ្មោះពáŸáž‰ážšáž”ស់អ្នកប្រើប្រាស់ គោážáŸ’ážáž“ាម ឬនាមážáŸ’លួន។ <br /> អ្នកប្រហែលប្រើប្រាស់ [email] ពីអ៊ីមែលរបស់អញនកប្រើប្រាស់។", "Accounts_ManuallyApproveNewUsers" : "ទទួល​អ្នក​ប្រើប្រាស់​ážáŸ’មី​ដោយ​ផ្ទាល់", "Accounts_OAuth_Custom_Authorize_Path" : "ទីážáž¶áŸ†áž„ផ្ទៀážáž•áŸ’ទាážáŸ‹", "Accounts_OAuth_Custom_Button_Color" : "ពណ៌ប៊ូážáž»áž„", @@ -195,6 +197,7 @@ "LDAP_Sync_User_Data" : "រក្សាទិន្ននáŸáž™ User ដោយ Sync ជាមួយ Server", "LDAP_Sync_User_Data_Description" : "រក្សាទិន្ននáŸáž™áž¢áŸ’នកប្រើប្រាស់ក្នុងការ Sync ជាមួយម៉ាស៊ីនមáŸáž€áŸ’នុងការ Login (eg: name, email)។", "LDAP_Url" : "URL របស់ LDAP", + "LDAP_Url_Description" : "ážáŸ†ážŽáž—្ជាប់នៃម៉ាស៊ីនម០LDAP ឧទាហរណáŸáŸ– ldap://company.dns.com", "Leave_room" : "áž…áŸáž‰â€‹áž–ីបន្ទប់", "line" : "ជួរ", "Load_more" : "មើល​ទៀáž", diff --git a/i18n/nl.i18n.json b/i18n/nl.i18n.json index 3b371d39d27..b3181fcdf57 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -6,6 +6,7 @@ "Accounts" : "Accounts", "Accounts_AllowedDomainsList" : "Toegestaan ​​Domeinen Lijst", "Accounts_AllowedDomainsList_Description" : "Komma-gescheiden lijst van toegestande domeinen", + "Accounts_AllowEmailChange" : "Sta e-mail wijzigen toe", "Accounts_AllowPasswordChange" : "Toestaan wachtwoord wijzigen", "Accounts_AllowUserAvatarChange" : "Sta wijzigen van gebruikers Avatar toe", "Accounts_AllowUsernameChange" : "Toestaan wijzigen gebruikersnaam", @@ -67,6 +68,7 @@ "Activate" : "Activeren", "Add_custom_oauth" : "Voeg aangepaste OAuth toe", "Add_Members" : "Voeg leden toe", + "Add_User" : "Voeg gebruiker toe", "Add_users" : "Gebruikers toevoegen", "Administration" : "Administratie", "After_OAuth2_authentication_users_will_be_redirected_to_this_URL" : "After OAuth2 authentication, users will be redirected to this URL", @@ -146,6 +148,7 @@ "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_message_someone" : "Stuur iemand een direct bericht", "Direct_Messages" : "Directe berichten", "Disable_Favorite_Rooms" : "Favorieten Uitschakelen", "Disable_New_Message_Notification" : "Notificatie voor nieuwe berichten uitzetten", @@ -159,6 +162,7 @@ "E-mail" : "E-mail", "edited" : "bewerkt", "Email_already_exists" : "Emailadres bestaat al", + "Email_Change_Disabled" : "Je Rocket.Chat administrator heeft het wijzigen van e-mail adressen uitgezet", "Email_or_username" : "E-mail of gebruikersnaam", "Email_verified" : "E-mail geverifiëerd", "Emoji" : "Emoji", @@ -255,6 +259,7 @@ "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_Default_Domain" : "Default Domain", "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", @@ -350,6 +355,7 @@ "Notify_all_in_this_room" : "Meld aan iederen in deze kamer", "OAuth_Application" : "OAuth Application", "OAuth_Applications" : "OAuth Applications", + "Old_and_new_password_must_be_different" : "Het oude en nieuwe paswoord moeten verschillen.", "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", @@ -411,7 +417,9 @@ "Remove_as_owner" : "Verwijder als eigenaar", "Remove_custom_oauth" : "Verwijder aangepaste OAuth", "Remove_from_room" : "Verwijderen uit de kamer", + "Remove_someone_from_room" : "Verwijder iemand uit de kamer", "Removed" : "Verwijderd", + "Require_password_change" : "Vereis paswoord wijziging", "Reset" : "Reset", "Reset_password" : "Reset Wachtwoord", "Restart" : "Herstart", @@ -548,6 +556,7 @@ "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" : "Gebruiker <em>__user_added__</em> toegevoegd door <em>__user_by__</em>", + "User_added_successfully" : "Nieuwe gebruiker succesvol toegevoegd", "User_Channels" : "Gebruikers Kanalen", "User_has_been_activated" : "Gebruiker is geactiveerd", "User_has_been_deactivated" : "Gebruiker is gedeactiveerd", @@ -576,10 +585,13 @@ "User_unmuted_in_room" : "Gebruiker kan weer spreken in de kamer", "User_updated_successfully" : "Gebruiker succesvol bijgewerkt", "Username" : "Gebruikersnaam", + "Username_and_message_must_not_be_empty" : "Gebruikersnaam en bericht moeten ingevuld zijn.", "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_doesnt_exist" : "De gebruikersnaam `%s` bestaat niet.", "Username_invalid" : "<strong>%s</strong> is geen geldige gebruikersnaam,<br/> gebruik uitsluitend letters, cijfers, punten en streepjes", + "Username_is_not_in_this_room" : "De gebruiker `#%s` is niet in deze kamer.", "Username_title" : "Registreer Gebruikersnaam", "Username_unavaliable" : "<strong>%s</strong> is al in gebruik :(", "Users" : "Gebruikers", @@ -606,6 +618,7 @@ "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_need_to_change_your_password" : "Je moet je paswoord wijzigen", "You_should_name_it_to_easily_manage_your_integrations" : "Je moet het een naam geven om je integraties eenvoudig te kunnen beheren.", "You_will_not_be_able_to_recover" : "Dit bericht zal niet meer te herstellen zijn!", "Your_entry_has_been_deleted" : "Uw bericht is verwijderd.", diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index 15571b9486e..b121a295c2b 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -409,6 +409,7 @@ "Remove_as_owner" : "EliminaÈ›i ca proprietar", "Remove_custom_oauth" : "EliminaÈ›i OAuth personalizat", "Remove_from_room" : "EliminaÈ›i din cameră", + "Remove_someone_from_room" : "ScoateÈ›i pe cineva din camera", "Removed" : "Eliminat", "Reset" : "Reset", "Reset_password" : "Resetează parola", @@ -577,7 +578,9 @@ "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_doesnt_exist" : "Numele de utilizator `#% s` nu există.", "Username_invalid" : "<strong>%s</strong>nu e un nume de utilizator valid,<br/> folosiÈ›i doar litere, cifre È™i cratime", + "Username_is_not_in_this_room" : "Utilizatorul `#% s` nu este în această cameră.", "Username_title" : "ÃŽnregistrează nume de utilizator", "Username_unavaliable" : "<strong>%s</strong> e deja folosit :(", "Users" : "Utilizatori", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 3d021115ca8..f52d87424bc 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -264,6 +264,7 @@ "Remove_Admin" : "Разжаловать админиÑтратора", "Remove_custom_oauth" : "Удалить пользовательÑкий OAuth", "Remove_from_room" : "Удалить из чата", + "Remove_someone_from_room" : "Удалить кого-то из чата", "Reset_password" : "СброÑить пароль", "Restart" : "ПерезапуÑтить", "Restart_the_server" : "ПерезапуÑтить Ñервер", @@ -378,6 +379,7 @@ "Username_Change_Disabled" : "ÐдминиÑтратор отключил возможноÑÑ‚ÑŒ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¸Ð¼ÐµÐ½ пользователей", "Username_description" : "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтников к вам.", "Username_invalid" : "<strong>%s</strong> неправильное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ, <br/> можно иÑпользовать только цифры, точки, Ð¿Ð¾Ð´Ñ‡ÐµÑ€ÐºÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¸ латинÑкие буквы", + "Username_is_not_in_this_room" : "Пользователь `#%s` не в Ñтом чате.", "Username_title" : "ЗарегиÑтрировать логин", "Username_unavaliable" : "<strong>%s</strong> уже иÑпользуетÑÑ :(", "Users" : "Пользователи", diff --git a/packages/rocketchat-channel-settings/i18n/de.i18n.json b/packages/rocketchat-channel-settings/i18n/de.i18n.json index 05456b08e2c..49cb2bfa53d 100644 --- a/packages/rocketchat-channel-settings/i18n/de.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/de.i18n.json @@ -5,6 +5,9 @@ "Save" : "Speichern", "Topic" : "Thema", "Type" : "Typ", + "Room_archivation_state" : "Status", + "Room_archivation_state_false" : "aktiv", + "Room_archivation_state_true" : "archiviert", "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.", diff --git a/packages/rocketchat-channel-settings/i18n/en.i18n.json b/packages/rocketchat-channel-settings/i18n/en.i18n.json index ea28753a13e..15c96cd3188 100644 --- a/packages/rocketchat-channel-settings/i18n/en.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/en.i18n.json @@ -13,4 +13,4 @@ "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/km.i18n.json b/packages/rocketchat-channel-settings/i18n/km.i18n.json index 598c01accce..9f65042e067 100644 --- a/packages/rocketchat-channel-settings/i18n/km.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/km.i18n.json @@ -1,5 +1,7 @@ { "Channel" : "ប៉ុស្ážáž·áŸ", "Private_Group" : "ក្រុម​ឯកជន", - "Save" : "រក្សាទុក" + "Save" : "រក្សាទុក", + "room_changed_privacy" : "ប្រភáŸáž‘បន្ទប់បានផ្លាស់ប្ážáž¼ážšáž‘ៅជា: <em>__room_type__</em> ដោយ <em>__user_by__</em>", + "room_changed_topic" : "អážáŸ’ážáž”ទបន្ទប់បានផ្លាស់ប្ážáž¼ážšáž‘ៅជា: <em>__room_topic__</em> ដោយ <em>__user_by__</em>" } \ 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 9bf8f2e51fb..235f597c9a1 100644 --- a/packages/rocketchat-channel-settings/i18n/nl.i18n.json +++ b/packages/rocketchat-channel-settings/i18n/nl.i18n.json @@ -5,6 +5,9 @@ "Save" : "Bewaren", "Topic" : "Onderwerp", "Type" : "Type", + "Room_archivation_state" : "State", + "Room_archivation_state_false" : "Aktief", + "Room_archivation_state_true" : "Gearchiveerd", "Room_Info" : "Kamer 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>", diff --git a/packages/rocketchat-mailer/i18n/km.i18n.json b/packages/rocketchat-mailer/i18n/km.i18n.json index a99a6eb6c8c..fd81dda6c41 100644 --- a/packages/rocketchat-mailer/i18n/km.i18n.json +++ b/packages/rocketchat-mailer/i18n/km.i18n.json @@ -1,4 +1,5 @@ { + "From_email_warning" : "<b>ព្រមាន៖</b>ចន្លោះ<b>FROM</b> គឺជាចំណងជើងទៅម៉ាស៊ីនមáŸáž¢áŸŠáž¸áž˜áŸ‚លរបស់អ្នកកំណážáŸ‹áŸ”", "From_email_is_required" : "From អ៊ីមែលគឺážáŸ’រូវបំពáŸáž‰", "Email_from" : "ពី", "Email_subject" : "ប្រធានបទ", @@ -7,5 +8,6 @@ "The_emails_are_being_sent" : "áž“áŸáŸ‡â€‹áž¢áŸŠáž¸áž˜áŸ‚ល​ážáŸ’រូវ​បាន​បញ្ជូន​។", "You_are_not_authorized_to_view_this_page" : "អ្នក​មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážâ€‹áž±áŸ’យ​មើល​ទំពáŸážšâ€‹áž“áŸáŸ‡â€‹áŸ”", "You_have_successfully_unsubscribed" : "អ្នក​បាន unsubscribed ដោយ​ជោគជáŸáž™â€‹áž–ី​បញ្ជី Mailling របស់​យើង​។", + "You_informed_an_invalid_FROM_address" : "អ្នកបានបំពáŸáž‰áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវក្នុងចន្លោះ FROM អាសáŸáž™ážŠáŸ’ឋាន", "You_must_provide_the_unsubscribe_link" : "អ្នកážáŸ’រូវážáŸ‚ផ្ដល់ážáŸ†ážŽáž—្ជាប់ [unsubscribe] ។" } \ 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 a61185894bc..b126a273ebb 100644 --- a/packages/rocketchat-message-pin/i18n/km.i18n.json +++ b/packages/rocketchat-message-pin/i18n/km.i18n.json @@ -4,6 +4,7 @@ "Message_AllowPinningByAnyone" : "អនុញ្ញាážáž±áŸ’យគ្រាប់គ្នាážáŸ’ទាស់សារ", "Message_AllowPinningByAnyone_Description" : "អនុញ្ញាážáž·áž²áŸ’យគ្រប់គ្នាអាចážáŸ’ទាស់សារទៅកាន់ប៉ុស្ážáž·áŸážŽáž¶áž˜áž½áž™ ដោយមិនចាំបាច់សិទ្ធជាអ្នកគ្រប់គ្រង។", "Pin_Message" : "ážáŸ’ទាស់សារ", + "Unpin_Message" : "សារមិនážáŸ’ទាស់", "Pinned_Messages" : "មិនážáŸ’ទាស់សារ", "No_pinned_messages" : "មិនមានសារបានážáŸ’ទាស់" } \ 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 c1235a4596e..3f8de1f1fcc 100644 --- a/packages/rocketchat-theme/i18n/km.i18n.json +++ b/packages/rocketchat-theme/i18n/km.i18n.json @@ -1,6 +1,9 @@ { + "theme-color-blockquote-background" : "ពណ៌ផ្ទៃážáž¶áž„ក្រោយនៃ Blockquote", "theme-color-code-background" : "កូដពណ៌ផ្ទៃážáž¶áž„ក្រោម", "theme-color-code-border" : "កូដពណ៌ជាយ", "theme-color-code-color" : "កូដពណ៌", - "theme-color-content-background-color" : "ពណ៌ផ្ទៃážáž¶áž„ក្រោយអážáŸ’ážáž”áž‘" + "theme-color-content-background-color" : "ពណ៌ផ្ទៃážáž¶áž„ក្រោយអážáŸ’ážáž”áž‘", + "theme-color-info-active-font-color" : "ពណ៌ពុម្ពអក្សររបស់ Active Info", + "theme-color-info-font-color" : "ពណ៌ពុម្ពអក្សររបស់ Info" } \ 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 4df60fc80b8..de4eebd8f7d 100644 --- a/packages/rocketchat-webrtc/i18n/nl.i18n.json +++ b/packages/rocketchat-webrtc/i18n/nl.i18n.json @@ -1,5 +1,5 @@ { "WebRTC_Enable_Channel" : "Toestaan voor openbare kanalen", - "WebRTC_Enable_Direct" : "Toestaan directe-berichten", + "WebRTC_Enable_Direct" : "Toestaan directe berichten", "WebRTC_Enable_Private" : "Toestaan voor privé-berichten" } \ No newline at end of file -- GitLab From 88f84cddb3160209a24094e0020ee69c7739d14a Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 29 Jan 2016 18:56:35 -0200 Subject: [PATCH 1299/1338] code formatting --- packages/rocketchat-slashcommands-msg/i18n/de.i18n.json | 3 +-- packages/rocketchat-slashcommands-msg/i18n/en.i18n.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json index 2c63c085104..ffcd4415b08 100644 --- a/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json +++ b/packages/rocketchat-slashcommands-msg/i18n/de.i18n.json @@ -1,2 +1 @@ -{ -} +{ } diff --git a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json index 2c63c085104..ffcd4415b08 100644 --- a/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json +++ b/packages/rocketchat-slashcommands-msg/i18n/en.i18n.json @@ -1,2 +1 @@ -{ -} +{ } -- GitLab From a072c691697ca677f2b0a841d851b983f2b16387 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 29 Jan 2016 19:10:42 -0200 Subject: [PATCH 1300/1338] Rename prefix Stats_OS_ to OS_ --- i18n/ar.i18n.json | 16 +++++++-------- i18n/de.i18n.json | 20 +++++++++---------- i18n/el.i18n.json | 20 +++++++++---------- i18n/en.i18n.json | 20 +++++++++---------- i18n/fi.i18n.json | 20 +++++++++---------- i18n/fr.i18n.json | 20 +++++++++---------- i18n/hr.i18n.json | 12 +++++------ i18n/km.i18n.json | 18 ++++++++--------- i18n/ko.i18n.json | 20 +++++++++---------- i18n/ms-MY.i18n.json | 20 +++++++++---------- i18n/nl.i18n.json | 20 +++++++++---------- i18n/pl.i18n.json | 20 +++++++++---------- i18n/pt.i18n.json | 20 +++++++++---------- i18n/ro.i18n.json | 20 +++++++++---------- i18n/ru.i18n.json | 20 +++++++++---------- i18n/tr.i18n.json | 16 +++++++-------- .../admin/adminStatistics.html | 20 +++++++++---------- 17 files changed, 161 insertions(+), 161 deletions(-) diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index 9c3fa43d5c4..ed504b6b928 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -287,13 +287,13 @@ "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" : "نوع النظام", + "OS_Arch" : "بنية النظام", + "OS_Cpus" : "عدد أنوية النظام", + "OS_Freemem" : "الذاكرة الØرة", + "OS_Loadavg" : "متوسط التØميل", + "OS_Platform" : "منصة النظام", + "OS_Release" : "إصدار النظام", + "OS_Type" : "نوع النظام", "Stats_Total_Channels" : "مجموع القنوات", "Stats_Total_Direct_Messages" : "إجمالي عدد غر٠الرسالة المباشرة", "Stats_Total_Messages" : "مجموع الرسائل", @@ -368,4 +368,4 @@ "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 500cc087838..52b90b9690b 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -503,15 +503,15 @@ "Stats_Non_Active_Users" : "Nicht aktive Benutzer", "Stats_Offline_Users" : "Benutzer offline", "Stats_Online_Users" : "Benutzer online", - "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", + "OS_Arch" : "Systemtyp", + "OS_Cpus" : "CPU-Zähler", + "OS_Freemem" : "Freier Speicherplatz", + "OS_Loadavg" : "Durchschnittliche Systemauslastung (\"Load\")", + "OS_Platform" : "Plattform", + "OS_Release" : "Version", + "OS_Totalmem" : "Gesamtspeicherplatz", + "OS_Type" : "Betriebssystem", + "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", @@ -627,4 +627,4 @@ "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/el.i18n.json b/i18n/el.i18n.json index e10c119709d..3f44af10882 100644 --- a/i18n/el.i18n.json +++ b/i18n/el.i18n.json @@ -225,15 +225,15 @@ "Stats_Non_Active_Users" : "ΑνενεÏγοί χÏήστες", "Stats_Offline_Users" : "ΑποσυνδεδεμÎνοι ΧÏήστες", "Stats_Online_Users" : "ΣυνδεδεμÎνοι ΧÏήστες", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS ΑÏιθμός CPU", - "Stats_OS_Freemem" : "OS ΕλεÏθεÏη Μνήμη", - "Stats_OS_Loadavg" : "OS ÎœÎσος φόÏτος", - "Stats_OS_Platform" : "OS ΠλατφόÏμα", - "Stats_OS_Release" : "OS Release", - "Stats_OS_Totalmem" : "OS Συνολική μνήμη", - "Stats_OS_Type" : "OS ΤÏπος", - "Stats_OS_Uptime" : "OS Uptime", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS ΑÏιθμός CPU", + "OS_Freemem" : "OS ΕλεÏθεÏη Μνήμη", + "OS_Loadavg" : "OS ÎœÎσος φόÏτος", + "OS_Platform" : "OS ΠλατφόÏμα", + "OS_Release" : "OS Release", + "OS_Totalmem" : "OS Συνολική μνήμη", + "OS_Type" : "OS ΤÏπος", + "OS_Uptime" : "OS Uptime", "Stats_Total_Channels" : "Συνολικά Κανάλια", "Stats_Total_Direct_Messages" : "Συνολικά άμεσα μηνÏματα", "Stats_Total_Private_Groups" : "ΣυνολικÎÏ‚ κλειστÎÏ‚ ομάδες", @@ -286,4 +286,4 @@ "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/en.i18n.json b/i18n/en.i18n.json index 2189c504643..0074f4dbb23 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -503,15 +503,15 @@ "Stats_Non_Active_Users" : "Inactive Users", "Stats_Offline_Users" : "Offline Users", "Stats_Online_Users" : "Online Users", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS CPU Count", - "Stats_OS_Freemem" : "OS Free Memory", - "Stats_OS_Loadavg" : "OS Load Average", - "Stats_OS_Platform" : "OS Platform", - "Stats_OS_Release" : "OS Release", - "Stats_OS_Totalmem" : "OS Total Memory", - "Stats_OS_Type" : "OS Type", - "Stats_OS_Uptime" : "OS Uptime", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS CPU Count", + "OS_Freemem" : "OS Free Memory", + "OS_Loadavg" : "OS Load Average", + "OS_Platform" : "OS Platform", + "OS_Release" : "OS Release", + "OS_Totalmem" : "OS Total Memory", + "OS_Type" : "OS Type", + "OS_Uptime" : "OS Uptime", "Stats_Total_Channels" : "Total Channels", "Stats_Total_Direct_Messages" : "Total Direct Message Rooms", "Stats_Total_Messages" : "Total Messages", @@ -627,4 +627,4 @@ "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 ac15fa99f0d..5c894148e9b 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -492,15 +492,15 @@ "Stats_Non_Active_Users" : "Passiivisia käyttäjiä", "Stats_Offline_Users" : "Offline-käyttäjiä", "Stats_Online_Users" : "Online-käyttäjiä", - "Stats_OS_Arch" : "OS Arkkitehtuuri", - "Stats_OS_Cpus" : "OS CPU määrä", - "Stats_OS_Freemem" : "OS Vapaa muisti", - "Stats_OS_Loadavg" : "OS Keskimääräinen kuorma", - "Stats_OS_Platform" : "OS Alusta", - "Stats_OS_Release" : "OS Julkaisu", - "Stats_OS_Totalmem" : "OS Muisti yhteensä", - "Stats_OS_Type" : "OS Tyyppi", - "Stats_OS_Uptime" : "OS Päälläoloaika", + "OS_Arch" : "OS Arkkitehtuuri", + "OS_Cpus" : "OS CPU määrä", + "OS_Freemem" : "OS Vapaa muisti", + "OS_Loadavg" : "OS Keskimääräinen kuorma", + "OS_Platform" : "OS Alusta", + "OS_Release" : "OS Julkaisu", + "OS_Totalmem" : "OS Muisti yhteensä", + "OS_Type" : "OS Tyyppi", + "OS_Uptime" : "OS Päälläoloaika", "Stats_Total_Channels" : "Kanavia yhteensä", "Stats_Total_Direct_Messages" : "Yksityisviestikeskustelujen määrä", "Stats_Total_Messages" : "Viestejä yhteensä", @@ -613,4 +613,4 @@ "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 b112a388522..88c7ad1d881 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -421,15 +421,15 @@ "Stats_Non_Active_Users" : "Utilisateurs inactifs", "Stats_Offline_Users" : "Utilisateurs hors ligne", "Stats_Online_Users" : "Utilisateurs en ligne", - "Stats_OS_Arch" : "Architecture", - "Stats_OS_Cpus" : "Nombre de CPU", - "Stats_OS_Freemem" : "Mémoire disponible", - "Stats_OS_Loadavg" : "Charge moyenne", - "Stats_OS_Platform" : "Plate-forme", - "Stats_OS_Release" : "Version", - "Stats_OS_Totalmem" : "Mémoire totale", - "Stats_OS_Type" : "Type", - "Stats_OS_Uptime" : "Durée de fonctionnement", + "OS_Arch" : "Architecture", + "OS_Cpus" : "Nombre de CPU", + "OS_Freemem" : "Mémoire disponible", + "OS_Loadavg" : "Charge moyenne", + "OS_Platform" : "Plate-forme", + "OS_Release" : "Version", + "OS_Totalmem" : "Mémoire totale", + "OS_Type" : "Type", + "OS_Uptime" : "Durée de fonctionnement", "Stats_Total_Channels" : "Nombre total de canaux", "Stats_Total_Direct_Messages" : "Nombre total de messages directs", "Stats_Total_Messages" : "Nombre total de messages", @@ -508,4 +508,4 @@ "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/hr.i18n.json b/i18n/hr.i18n.json index 7d6663da24c..7a11b69d3de 100644 --- a/i18n/hr.i18n.json +++ b/i18n/hr.i18n.json @@ -287,11 +287,11 @@ "Stats_Non_Active_Users" : "Neaktivni korisnici", "Stats_Offline_Users" : "Offline Korisnici", "Stats_Online_Users" : "Online Korisnici", - "Stats_OS_Freemem" : "OS Slobodna Memorija", - "Stats_OS_Platform" : "OS platforma", - "Stats_OS_Release" : "OS Izdanje", - "Stats_OS_Totalmem" : "OS Ukupno memorije", - "Stats_OS_Type" : "Vrsta OS-a", + "OS_Freemem" : "OS Slobodna Memorija", + "OS_Platform" : "OS platforma", + "OS_Release" : "OS Izdanje", + "OS_Totalmem" : "OS Ukupno memorije", + "OS_Type" : "Vrsta OS-a", "Stats_Total_Channels" : "Ukupno kanala", "Stats_Total_Messages" : "Ukupno poruka", "Stats_Total_Private_Groups" : "Ukupno Privatnih Grupa", @@ -358,4 +358,4 @@ "You_will_not_be_able_to_recover" : "Ovo nećeÅ¡ moći promijeniti!", "Your_entry_has_been_deleted" : "Tvoj unos je obrisan.", "Your_Open_Source_solution" : "VaÅ¡e vlastito Open Source chat rjeÅ¡enje" -} \ No newline at end of file +} diff --git a/i18n/km.i18n.json b/i18n/km.i18n.json index f3b963b2607..123a812fd78 100644 --- a/i18n/km.i18n.json +++ b/i18n/km.i18n.json @@ -366,14 +366,14 @@ "Stats_Non_Active_Users" : "អ្នក​ប្រើ​អសកម្ម", "Stats_Offline_Users" : "អ្នក​ប្រើ​ក្រៅ​ប​ណ្ážáž¶â€‹áž‰", "Stats_Online_Users" : "អ្នក​ប្រើ​លើ​បណ្ដាញ", - "Stats_OS_Cpus" : "រាប់ CPU ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", - "Stats_OS_Freemem" : "អង្គចងចាំប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšážŠáŸ‚លនៅទំនáŸážš", - "Stats_OS_Loadavg" : "ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž’្វើការមធ្យម", - "Stats_OS_Platform" : "ទម្រង់ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", - "Stats_OS_Release" : "ជំនាន់ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", - "Stats_OS_Totalmem" : "ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž”្រើអង្គចងចាំសរុប", - "Stats_OS_Type" : "ប្រភáŸáž‘​ប្រពáŸáž“្ធ​ប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", - "Stats_OS_Uptime" : "ប្រពáŸáž“្ធ​ប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšâ€‹áž¢ážŸáŸ‹â€‹áž–áŸáž›", + "OS_Cpus" : "រាប់ CPU ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", + "OS_Freemem" : "អង្គចងចាំប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšážŠáŸ‚លនៅទំនáŸážš", + "OS_Loadavg" : "ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž’្វើការមធ្យម", + "OS_Platform" : "ទម្រង់ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", + "OS_Release" : "ជំនាន់ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", + "OS_Totalmem" : "ប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž”្រើអង្គចងចាំសរុប", + "OS_Type" : "ប្រភáŸáž‘​ប្រពáŸáž“្ធ​ប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš", + "OS_Uptime" : "ប្រពáŸáž“្ធ​ប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšâ€‹áž¢ážŸáŸ‹â€‹áž–áŸáž›", "Stats_Total_Channels" : "ប៉ុស្ážáž·áŸážŸážšáž»áž”", "Stats_Total_Messages" : "សារ​សរុប", "Stats_Total_Private_Groups" : "ក្រុម​ឯកជន​សរុប", @@ -437,4 +437,4 @@ "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/ko.i18n.json b/i18n/ko.i18n.json index 3804dedd2f5..d365043a917 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -390,15 +390,15 @@ "Stats_Non_Active_Users" : "비활성 사용ìž", "Stats_Offline_Users" : "오프ë¼ì¸ 사용ìž", "Stats_Online_Users" : "온ë¼ì¸ 사용ìž", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS CPU 갯수", - "Stats_OS_Freemem" : "OS 빈 메모리", - "Stats_OS_Loadavg" : "OS 부하 í‰ê· ", - "Stats_OS_Platform" : "OS 플랫í¼", - "Stats_OS_Release" : "OS 릴리즈", - "Stats_OS_Totalmem" : "OS ì „ì²´ 메모리", - "Stats_OS_Type" : "OS ìœ í˜•", - "Stats_OS_Uptime" : "OS 사용 시간", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS CPU 갯수", + "OS_Freemem" : "OS 빈 메모리", + "OS_Loadavg" : "OS 부하 í‰ê· ", + "OS_Platform" : "OS 플랫í¼", + "OS_Release" : "OS 릴리즈", + "OS_Totalmem" : "OS ì „ì²´ 메모리", + "OS_Type" : "OS ìœ í˜•", + "OS_Uptime" : "OS 사용 시간", "Stats_Total_Channels" : "ì „ì²´ 채ë„", "Stats_Total_Direct_Messages" : "ì „ì²´ ê·“ì†ë§", "Stats_Total_Messages" : "ì „ì²´ 메시지", @@ -468,4 +468,4 @@ "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/ms-MY.i18n.json b/i18n/ms-MY.i18n.json index 6af1ed50e0f..ff325cb6173 100644 --- a/i18n/ms-MY.i18n.json +++ b/i18n/ms-MY.i18n.json @@ -307,15 +307,15 @@ "Stats_Non_Active_Users" : "Pengguna Tidak Aktif", "Stats_Offline_Users" : "Pengguna Luar talian", "Stats_Online_Users" : "Pengguna Dalam talian", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS CPU Count", - "Stats_OS_Freemem" : "OS Free Memory", - "Stats_OS_Loadavg" : "OS Load Average", - "Stats_OS_Platform" : "OS Platform", - "Stats_OS_Release" : "OS Release", - "Stats_OS_Totalmem" : "OS Total Memory", - "Stats_OS_Type" : "OS Type", - "Stats_OS_Uptime" : "OS Uptime", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS CPU Count", + "OS_Freemem" : "OS Free Memory", + "OS_Loadavg" : "OS Load Average", + "OS_Platform" : "OS Platform", + "OS_Release" : "OS Release", + "OS_Totalmem" : "OS Total Memory", + "OS_Type" : "OS Type", + "OS_Uptime" : "OS Uptime", "Stats_Total_Channels" : "Jumlah Saluran", "Stats_Total_Direct_Messages" : "Jumlah Bilik Mesej Langsung", "Stats_Total_Messages" : "Jumlah Mesej", @@ -373,4 +373,4 @@ "You_need_confirm_email" : "Anda perlu mengesahkan e-mel anda untuk melog masuk!", "You_will_not_be_able_to_recover" : "Anda tidak boleh membaik pulih.", "Your_entry_has_been_deleted" : "Entri anda telah dipadam." -} \ No newline at end of file +} diff --git a/i18n/nl.i18n.json b/i18n/nl.i18n.json index b3181fcdf57..5131e44ae61 100644 --- a/i18n/nl.i18n.json +++ b/i18n/nl.i18n.json @@ -501,15 +501,15 @@ "Stats_Non_Active_Users" : "Inactieve Gebruikers", "Stats_Offline_Users" : "Offline Gebruikers", "Stats_Online_Users" : "Online Gebruikers", - "Stats_OS_Arch" : "OS Arch", - "Stats_OS_Cpus" : "OS CPU Count", - "Stats_OS_Freemem" : "OS Free Memory", - "Stats_OS_Loadavg" : "OS Load Gemiddeld", - "Stats_OS_Platform" : "OS Platform", - "Stats_OS_Release" : "OS Versie", - "Stats_OS_Totalmem" : "OS Totaal geheugen", - "Stats_OS_Type" : "OS Type", - "Stats_OS_Uptime" : "OS Uptime", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS CPU Count", + "OS_Freemem" : "OS Free Memory", + "OS_Loadavg" : "OS Load Gemiddeld", + "OS_Platform" : "OS Platform", + "OS_Release" : "OS Versie", + "OS_Totalmem" : "OS Totaal geheugen", + "OS_Type" : "OS Type", + "OS_Uptime" : "OS Uptime", "Stats_Total_Channels" : "Totaal Kanalen", "Stats_Total_Direct_Messages" : "Totaal Directe Berichten Kamers", "Stats_Total_Messages" : "Totaal aantal berichten", @@ -625,4 +625,4 @@ "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 59a316acc47..6649ee3e9bc 100644 --- a/i18n/pl.i18n.json +++ b/i18n/pl.i18n.json @@ -415,15 +415,15 @@ "Stats_Non_Active_Users" : "Nieaktywni użytkownicy", "Stats_Offline_Users" : "NiepodÅ‚Ä…czeni użytkownicy", "Stats_Online_Users" : "PodÅ‚Ä…czeni użytkownicy", - "Stats_OS_Arch" : "Architektura systemu", - "Stats_OS_Cpus" : "Ilość procesorów", - "Stats_OS_Freemem" : "Ilość wolnej pamiÄ™ci", - "Stats_OS_Loadavg" : "Åšrednie obciążenie systemu", - "Stats_OS_Platform" : "Platforma systemu", - "Stats_OS_Release" : "Wydanie systemu", - "Stats_OS_Totalmem" : "CaÅ‚kowita ilość pamiÄ™ci systemu", - "Stats_OS_Type" : "Typ systemu ", - "Stats_OS_Uptime" : "Czas pracy systemu", + "OS_Arch" : "Architektura systemu", + "OS_Cpus" : "Ilość procesorów", + "OS_Freemem" : "Ilość wolnej pamiÄ™ci", + "OS_Loadavg" : "Åšrednie obciążenie systemu", + "OS_Platform" : "Platforma systemu", + "OS_Release" : "Wydanie systemu", + "OS_Totalmem" : "CaÅ‚kowita ilość pamiÄ™ci systemu", + "OS_Type" : "Typ systemu ", + "OS_Uptime" : "Czas pracy systemu", "Stats_Total_Channels" : "Liczba kanałów", "Stats_Total_Direct_Messages" : "Liczba sesji prywatnych", "Stats_Total_Messages" : "Liczba wiadomoÅ›ci", @@ -494,4 +494,4 @@ "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" -} \ No newline at end of file +} diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 74cecc34220..7ba3ba6e9ee 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -391,15 +391,15 @@ "Stats_Non_Active_Users" : "Usuários Inativos", "Stats_Offline_Users" : "Usuários Offline", "Stats_Online_Users" : "Usuários Online", - "Stats_OS_Arch" : "Arquitetura", - "Stats_OS_Cpus" : "Número de CPUs", - "Stats_OS_Freemem" : "Memória DisponÃvel", - "Stats_OS_Loadavg" : "Carga Média", - "Stats_OS_Platform" : "Plataforma", - "Stats_OS_Release" : "Release", - "Stats_OS_Totalmem" : "Memória Total", - "Stats_OS_Type" : "Tipo de Sistema Operacional", - "Stats_OS_Uptime" : "Tempo ligado", + "OS_Arch" : "Arquitetura", + "OS_Cpus" : "Número de CPUs", + "OS_Freemem" : "Memória DisponÃvel", + "OS_Loadavg" : "Carga Média", + "OS_Platform" : "Plataforma", + "OS_Release" : "Release", + "OS_Totalmem" : "Memória Total", + "OS_Type" : "Tipo de Sistema Operacional", + "OS_Uptime" : "Tempo ligado", "Stats_Total_Channels" : "Quantidade de Canais", "Stats_Total_Direct_Messages" : "Total de Salas de Mensagem Direta", "Stats_Total_Messages" : "Quantidade de Mensagens", @@ -472,4 +472,4 @@ "Your_entry_has_been_deleted" : "Sua mensagem foi excluÃda.", "Your_Open_Source_solution" : "Sua própria solução Open Source", "Your_push_was_sent_to_s_devices" : "Sua natificação foi enviada para %s dispositivos" -} \ No newline at end of file +} diff --git a/i18n/ro.i18n.json b/i18n/ro.i18n.json index b121a295c2b..7b396781077 100644 --- a/i18n/ro.i18n.json +++ b/i18n/ro.i18n.json @@ -492,15 +492,15 @@ "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", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS număr CPU ", + "OS_Freemem" : "OS Free Memory", + "OS_Loadavg" : "OS Load Media", + "OS_Platform" : "OS Platform", + "OS_Release" : "OS Release", + "OS_Totalmem" : "OS Total Memory", + "OS_Type" : "Tip sistem de operare", + "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", @@ -613,4 +613,4 @@ "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 f52d87424bc..849d8f28f4e 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -319,15 +319,15 @@ "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" : "Ðптайм ÑиÑтемы", + "OS_Arch" : "Ðрхитектура ОС", + "OS_Cpus" : "КоличеÑтво процеÑÑоров в ОС", + "OS_Freemem" : "Свободное кол-во памÑти", + "OS_Loadavg" : "Загрузка ОС", + "OS_Platform" : "Платформа ОС", + "OS_Release" : "ВерÑÐ¸Ñ ÐžÐ¡", + "OS_Totalmem" : "Общее кол-во памÑти в ОС", + "OS_Type" : "Тип СиÑтемы", + "OS_Uptime" : "Ðптайм ÑиÑтемы", "Stats_Total_Channels" : "Ð’Ñего публичных чатов", "Stats_Total_Direct_Messages" : "Общее количеÑтво Ñообщений в личных чатах", "Stats_Total_Messages" : "Ð’Ñего Ñообщений", @@ -399,4 +399,4 @@ "You_need_confirm_email" : "Ðеобходимо подтвердить email Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°!", "You_will_not_be_able_to_recover" : "Ð’Ñ‹ не Ñможете воÑÑтановить Ñто Ñообщение!", "Your_Open_Source_solution" : "Ваш ÑобÑтвенный чат на базе Open Source-технологий" -} \ No newline at end of file +} diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 6e8f5807bbe..d6ad0595d22 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -207,13 +207,13 @@ "Stats_Non_Active_Users" : "Aktif Olmayan Kullanıcılar", "Stats_Offline_Users" : "Çevrimdışı Kullanıcılar", "Stats_Online_Users" : "Çevrimiçi Kullanıcılar", - "Stats_OS_Cpus" : "OS Ä°ÅŸlemci Sayısı", - "Stats_OS_Freemem" : "OS BoÅŸ Bellek", - "Stats_OS_Loadavg" : "Ä°S Yük Ortalaması", - "Stats_OS_Platform" : "Ä°ÅŸletim Sistemi", - "Stats_OS_Release" : "Ä°ÅŸletim Sistemi Sürümü", - "Stats_OS_Totalmem" : "Ä°ÅŸletim sistemi belleÄŸi", - "Stats_OS_Type" : "Ä°ÅŸletim Sistemi Tipi", + "OS_Cpus" : "OS Ä°ÅŸlemci Sayısı", + "OS_Freemem" : "OS BoÅŸ Bellek", + "OS_Loadavg" : "Ä°S Yük Ortalaması", + "OS_Platform" : "Ä°ÅŸletim Sistemi", + "OS_Release" : "Ä°ÅŸletim Sistemi Sürümü", + "OS_Totalmem" : "Ä°ÅŸletim sistemi belleÄŸi", + "OS_Type" : "Ä°ÅŸletim Sistemi Tipi", "Stats_Total_Channels" : "Toplam Kanal", "Stats_Total_Direct_Messages" : "Toplam Direkt Mesajlar", "Stats_Total_Messages" : "Toplam Ä°leti", @@ -265,4 +265,4 @@ "You_will_not_be_able_to_recover" : "Sen kurtarmak mümkün olmayacaktır!", "Your_entry_has_been_deleted" : "Sizin kaydınız silindi.", "Your_Open_Source_solution" : "Açık Kaynak Sohbet Uygulaması" -} \ No newline at end of file +} diff --git a/packages/rocketchat-ui-admin/admin/adminStatistics.html b/packages/rocketchat-ui-admin/admin/adminStatistics.html index f039362a8ea..21ffca67375 100644 --- a/packages/rocketchat-ui-admin/admin/adminStatistics.html +++ b/packages/rocketchat-ui-admin/admin/adminStatistics.html @@ -69,39 +69,39 @@ <td>{{numFormat statistics.avgPrivateGroupUsers}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Type"}}</th> + <th>{{_ "OS_Type"}}</th> <td>{{statistics.os.type}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Platform"}}</th> + <th>{{_ "OS_Platform"}}</th> <td>{{statistics.os.platform}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Arch"}}</th> + <th>{{_ "OS_Arch"}}</th> <td>{{statistics.os.arch}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Release"}}</th> + <th>{{_ "OS_Release"}}</th> <td>{{statistics.os.release}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Uptime"}}</th> + <th>{{_ "OS_Uptime"}}</th> <td>{{humanReadable statistics.os.uptime}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Loadavg"}}</th> + <th>{{_ "OS_Loadavg"}}</th> <td>{{numFormat statistics.os.loadavg.[0]}}, {{numFormat statistics.os.loadavg.[1]}}, {{numFormat statistics.os.loadavg.[2]}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Totalmem"}}</th> + <th>{{_ "OS_Totalmem"}}</th> <td>{{inGB statistics.os.totalmem}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Freemem"}}</th> + <th>{{_ "OS_Freemem"}}</th> <td>{{inGB statistics.os.freemem}}</td> </tr> <tr> - <th>{{_ "Stats_OS_Cpus"}}</th> + <th>{{_ "OS_Cpus"}}</th> <td>{{statistics.os.cpus.length}}</td> </tr> </table> @@ -117,4 +117,4 @@ </div> </div> </section> -</template> \ No newline at end of file +</template> -- GitLab From 21343900870d960a19fe1282f10f719d4cc51983 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 19:22:00 -0200 Subject: [PATCH 1301/1338] Improve logs of stream broadcast --- server/stream/streamBroadcast.coffee | 42 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/server/stream/streamBroadcast.coffee b/server/stream/streamBroadcast.coffee index 5357cf94a4a..cc2eff8c3c6 100644 --- a/server/stream/streamBroadcast.coffee +++ b/server/stream/streamBroadcast.coffee @@ -23,9 +23,30 @@ broadcast = (streamName, args, userId) -> for port, connection of connections - if connection.status().connected is true - console.log 'broadcast to', port, streamName, args - connection.call 'stream', streamName, args + do (port, connection) -> + if connection.status().connected is true + connection.call 'stream', streamName, args, (error, response) -> + if error? + console.log "Stream broadcast error", error + + switch response + when 'self-not-authorized' + console.log "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} to self is not authorized".red + console.log " -> connection authorized".red, connection.broadcastAuth + console.log " -> connection status".red, connection.status() + console.log " -> arguments".red, args + + when 'not-authorized' + console.log "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} not authorized".red + console.log " -> connection authorized".red, connection.broadcastAuth + console.log " -> connection status".red, connection.status() + console.log " -> arguments".red, args + + when 'stream-not-exists' + console.log "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} does not exists".red + console.log " -> connection authorized".red, connection.broadcastAuth + console.log " -> connection status".red, connection.status() + console.log " -> arguments".red, args Meteor.methods @@ -62,19 +83,18 @@ stream: (streamName, args) -> # Prevent call from self and client if not @connection? - console.log "Stream for broadcast with name #{streamName} from self is not authorized".red, @connection - return + return 'self-not-authorized' # Prevent call from unauthrorized connections if @connection.broadcastAuth isnt true - console.log "Stream for broadcast with name #{streamName} not authorized".red - return + return 'not-authorized' - console.log 'method stream', streamName, args if not emitters[streamName]? - console.log "Stream for broadcast with name #{streamName} does not exists".red - else - emitters[streamName].call null, args, 'broadcasted' + return 'stream-not-exists' + + emitters[streamName].call null, args, 'broadcasted' + + return undefined Meteor.startup -> -- GitLab From a18959402e2a625c675804a847e72f1676b9606a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 19:22:45 -0200 Subject: [PATCH 1302/1338] Remove logs of stream.permissions.read --- server/stream/messages.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/stream/messages.coffee b/server/stream/messages.coffee index d82a0c1d164..5ffa4023355 100644 --- a/server/stream/messages.coffee +++ b/server/stream/messages.coffee @@ -6,7 +6,7 @@ msgStream.permissions.write (eventName) -> return false msgStream.permissions.read (eventName) -> - console.log('stream.permissions.read', this.userId, eventName); + # console.log('stream.permissions.read', this.userId, eventName); # return this.userId == eventName; try -- GitLab From 8e4b599bb27e853b36932cf871f24eea6a2664be Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 19:23:06 -0200 Subject: [PATCH 1303/1338] Remove logs of stream.permissions.write --- server/stream/messages.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/stream/messages.coffee b/server/stream/messages.coffee index 5ffa4023355..0dc2cb4d16d 100644 --- a/server/stream/messages.coffee +++ b/server/stream/messages.coffee @@ -1,7 +1,7 @@ @msgStream = new Meteor.Stream 'messages' msgStream.permissions.write (eventName) -> - console.log('stream.permissions.write', this.userId); + # console.log('stream.permissions.write', this.userId); # return eventName == 'send' && this.userId; return false -- GitLab From 3945da8708b6a02459f97c62aefa51c07e30095c Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 29 Jan 2016 19:43:29 -0200 Subject: [PATCH 1304/1338] Added more info placeholders --- .../rocketchat-ui-admin/admin/adminInfo.html | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-admin/admin/adminInfo.html b/packages/rocketchat-ui-admin/admin/adminInfo.html index d31b8f9cfd6..bd1d11e8637 100644 --- a/packages/rocketchat-ui-admin/admin/adminInfo.html +++ b/packages/rocketchat-ui-admin/admin/adminInfo.html @@ -14,9 +14,29 @@ <td>{{server.version}}</td> </tr> <tr> - <th>{{_ "DB_Schema_Version"}}</th> + <th>{{_ "DB_Migration"}}</th> <td>{{migration.version}}</td> </tr> + <tr> + <th>{{_ "Installed_at"}}</th> + <td></td> + </tr> + <tr> + <th>{{_ "Started_at"}}</th> + <td></td> + </tr> + <tr> + <th>{{_ "Deployment_ID"}}</th> + <td></td> + </tr> + <tr> + <th>{{_ "Instance_ID"}}</th> + <td></td> + </tr> + <tr> + <th>{{_ "Running_Instances"}}</th> + <td></td> + </tr> </table> <h3>{{_ "Commit"}}</h3> @@ -69,6 +89,10 @@ <th>{{_ "OS_Release"}}</th> <td>{{statistics.os.release}}</td> </tr> + <tr> + <th>{{_ "Node_version"}}</th> + <td></td> + </tr> <tr> <th>{{_ "OS_Uptime"}}</th> <td>{{humanReadableTime statistics.os.uptime}}</td> -- GitLab From 6694c085e50fa4cc86a3263aa45e887e54c92f83 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Fri, 29 Jan 2016 20:56:28 -0200 Subject: [PATCH 1305/1338] Add more data and improve layout of admin info --- .../server/models/Settings.coffee | 1 + .../server/functions/get.coffee | 10 ++++++ .../assets/stylesheets/base.less | 15 ++++---- .../stylesheets/utils/_colors.import.less | 4 +-- .../admin/adminInfo.coffee | 7 +--- .../rocketchat-ui-admin/admin/adminInfo.html | 36 ++++++++++--------- 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/packages/rocketchat-lib/server/models/Settings.coffee b/packages/rocketchat-lib/server/models/Settings.coffee index c16d51c8316..eff7591e658 100644 --- a/packages/rocketchat-lib/server/models/Settings.coffee +++ b/packages/rocketchat-lib/server/models/Settings.coffee @@ -52,6 +52,7 @@ RocketChat.models.Settings = new class extends RocketChat.models._Base record = _id: _id value: value + _createdAt: new Date return @insert record diff --git a/packages/rocketchat-statistics/server/functions/get.coffee b/packages/rocketchat-statistics/server/functions/get.coffee index 4343f6d25c0..33edc8efc41 100644 --- a/packages/rocketchat-statistics/server/functions/get.coffee +++ b/packages/rocketchat-statistics/server/functions/get.coffee @@ -3,6 +3,7 @@ RocketChat.statistics.get = -> # Version statistics.uniqueId = RocketChat.settings.get("uniqueID") + statistics.createdAt = RocketChat.models.Settings.findOne("uniqueID")?._createdAt statistics.version = RocketChat.Info?.version statistics.tag = RocketChat.Info?.tag statistics.branch = RocketChat.Info?.branch @@ -85,4 +86,13 @@ RocketChat.statistics.get = -> freemem: os.freemem() cpus: os.cpus() + statistics.process = + nodeVersion: process.version + pid: process.pid + uptime: process.uptime() + + statistics.migration = RocketChat.Migrations._getControl() + + statistics.instanceCount = InstanceStatus.getCollection().find().count() + return statistics diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c94be79f39f..c8137ee15c4 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -3919,24 +3919,25 @@ a.github-fork { .statistics-table { margin-bottom: 30px; - border: 1px solid; - width:100%; + border: 2px solid #F5F5F5; + width: 100%; tr { - background-color:#FFFFFF; + background-color: #FFFFFF; &:nth-of-type(even) { - background-color:#FBFBFB; + background-color: #F5F5F5; } } th, td { text-align: left; - padding: 3px 10px; + padding: 6px 8px; } th { - width: 20%; + text-align: right; + width: 30%; } td { - width: 80%; + width: 70%; } } diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index aed17bcef85..49cfce5d7d9 100755 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -1183,7 +1183,7 @@ a.github-fork { } .statistics-table { - border-color: #F9F9F9; + border-color: #eee; } @media all and(max-width: 780px) { @@ -1214,4 +1214,4 @@ a.github-fork { .attention-message { color: white; -} \ No newline at end of file +} diff --git a/packages/rocketchat-ui-admin/admin/adminInfo.coffee b/packages/rocketchat-ui-admin/admin/adminInfo.coffee index 495e6eab854..767734e8485 100644 --- a/packages/rocketchat-ui-admin/admin/adminInfo.coffee +++ b/packages/rocketchat-ui-admin/admin/adminInfo.coffee @@ -29,12 +29,8 @@ Template.adminInfo.helpers return _.numberFormat(number, 2) optOut: -> return RocketChat.settings.get 'Statistics_opt_out' - server: -> + info: -> return RocketChat.Info - commit: -> - return _.extend(RocketChat.Info?.commit, { tag: RocketChat.Info?.tag, branch: RocketChat.Info?.branch }) - migration: -> - return Template.instance().migration.get() build: -> return RocketChat.Info?.compile || RocketChat.Info?.build @@ -71,7 +67,6 @@ Template.adminInfo.onRendered -> Template.adminInfo.onCreated -> instance = @ @statistics = new ReactiveVar {} - @migration = new ReactiveVar {} @ready = new ReactiveVar false Meteor.call 'getStatistics', (error, statistics) -> diff --git a/packages/rocketchat-ui-admin/admin/adminInfo.html b/packages/rocketchat-ui-admin/admin/adminInfo.html index bd1d11e8637..3bd2b70bfa6 100644 --- a/packages/rocketchat-ui-admin/admin/adminInfo.html +++ b/packages/rocketchat-ui-admin/admin/adminInfo.html @@ -11,31 +11,35 @@ <table class="statistics-table"> <tr> <th>{{_ "Version"}}</th> - <td>{{server.version}}</td> + <td>{{statistics.version}}</td> </tr> <tr> <th>{{_ "DB_Migration"}}</th> - <td>{{migration.version}}</td> + <td>{{statistics.migration.version}}</td> + </tr> + <tr> + <th>{{_ "DB_Migration_Date"}}</th> + <td>{{statistics.migration.lockedAt}}</td> </tr> <tr> <th>{{_ "Installed_at"}}</th> - <td></td> + <td>{{statistics.createdAt}}</td> </tr> <tr> - <th>{{_ "Started_at"}}</th> - <td></td> + <th>{{_ "Uptime"}}</th> + <td>{{humanReadableTime statistics.process.uptime}}</td> </tr> <tr> <th>{{_ "Deployment_ID"}}</th> - <td></td> + <td>{{statistics.uniqueId}}</td> </tr> <tr> - <th>{{_ "Instance_ID"}}</th> - <td></td> + <th>{{_ "PID"}}</th> + <td>{{statistics.process.pid}}</td> </tr> <tr> <th>{{_ "Running_Instances"}}</th> - <td></td> + <td>{{statistics.instanceCount}}</td> </tr> </table> @@ -43,27 +47,27 @@ <table class="statistics-table"> <tr> <th>{{_ "Hash"}}</th> - <td>{{commit.hash}}</td> + <td>{{info.commit.hash}}</td> </tr> <tr> <th>{{_ "Date"}}</th> - <td>{{commit.date}}</td> + <td>{{info.commit.date}}</td> </tr> <tr> <th>{{_ "Branch"}}</th> - <td>{{commit.branch}}</td> + <td>{{info.commit.branch}}</td> </tr> <tr> <th>{{_ "Tag"}}</th> - <td>{{commit.tag}}</td> + <td>{{info.commit.tag}}</td> </tr> <tr> <th>{{_ "Author"}}</th> - <td>{{commit.author}}</td> + <td>{{info.commit.author}}</td> </tr> <tr> <th>{{_ "Subject"}}</th> - <td>{{commit.subject}}</td> + <td>{{info.commit.subject}}</td> </tr> </table> @@ -91,7 +95,7 @@ </tr> <tr> <th>{{_ "Node_version"}}</th> - <td></td> + <td>{{statistics.process.nodeVersion}}</td> </tr> <tr> <th>{{_ "OS_Uptime"}}</th> -- GitLab From 18617047861c7d571aa692bf966af1ef26a3d7d4 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 30 Jan 2016 20:28:27 -0200 Subject: [PATCH 1306/1338] Update konecty:multiple-instances-status to 1.0.6 --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index d2b7f9cb6b5..b2b627e7ee1 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -65,7 +65,7 @@ konecty:autolinker@1.0.3 konecty:change-case@2.3.0 konecty:delayed-task@1.0.0 konecty:mongo-counter@0.0.3 -konecty:multiple-instances-status@1.0.5 +konecty:multiple-instances-status@1.0.6 konecty:nrr@2.0.2 konecty:user-presence@1.2.6 launch-screen@1.0.4 -- GitLab From 62fe5c830b40fbacef100e36cdd6f00ce2ec2e49 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 30 Jan 2016 21:21:33 -0200 Subject: [PATCH 1307/1338] Create script to build livechat on windows --- .../plugin/build-livechat.js | 8 ++++++-- packages/rocketchat-livechat/plugin/build.bat | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-livechat/plugin/build.bat diff --git a/packages/rocketchat-livechat/plugin/build-livechat.js b/packages/rocketchat-livechat/plugin/build-livechat.js index d2ff6d3d0ab..35311b2fef4 100644 --- a/packages/rocketchat-livechat/plugin/build-livechat.js +++ b/packages/rocketchat-livechat/plugin/build-livechat.js @@ -2,8 +2,12 @@ var fs = Npm.require('fs'); var path = Npm.require('path'); var shell = Npm.require('shelljs'); -var curPath = path.resolve('.') +var curPath = path.resolve('.'); var packagePath = path.join(path.resolve('.'), 'packages', 'rocketchat-livechat'); var pluginPath = path.join(packagePath, 'plugin'); -shell.exec('sh '+pluginPath+'/build.sh'); +if (process.platform === 'win32') { + shell.exec(pluginPath+'/build.bat'); +} else { + shell.exec('sh '+pluginPath+'/build.sh'); +} diff --git a/packages/rocketchat-livechat/plugin/build.bat b/packages/rocketchat-livechat/plugin/build.bat new file mode 100644 index 00000000000..ab37008c971 --- /dev/null +++ b/packages/rocketchat-livechat/plugin/build.bat @@ -0,0 +1,19 @@ +@echo off + +cd packages/rocketchat-livechat/app +meteor build .meteor/build/ --directory + +cd .. +mkdir public + +rm -f public/livechat.css +rm -f public/livechat.js +rm -f public/head.html + +cp app/.meteor/build/bundle/programs/web.browser/*.css public/livechat.css +cp app/.meteor/build/bundle/programs/web.browser/*.js public/livechat.js +cp app/.meteor/build/bundle/programs/web.browser/head.html public/head.html + +::echo "body {background-color: red;}" > livechat.css + +rm -rf app/.meteor/build/ -- GitLab From 20ea2b19a28fd6be3affaf4b7a5e902732e8086f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Sat, 30 Jan 2016 21:52:00 -0200 Subject: [PATCH 1308/1338] Fix call in livechat build.bat --- packages/rocketchat-livechat/plugin/build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/plugin/build.bat b/packages/rocketchat-livechat/plugin/build.bat index ab37008c971..b11b9668476 100644 --- a/packages/rocketchat-livechat/plugin/build.bat +++ b/packages/rocketchat-livechat/plugin/build.bat @@ -1,7 +1,7 @@ @echo off cd packages/rocketchat-livechat/app -meteor build .meteor/build/ --directory +call meteor build .meteor/build/ --directory cd .. mkdir public -- GitLab From 22def793c923d2db3e453188d061f62c3bbea379 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 1 Feb 2016 13:00:55 -0200 Subject: [PATCH 1309/1338] Don't redirect to home after registration; --- packages/rocketchat-lib/client/lib/openRoom.coffee | 11 ++++++++--- packages/rocketchat-ui-login/username/username.coffee | 2 +- packages/rocketchat-ui/lib/RoomManager.coffee | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 7e74d9fd949..93f3573be35 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -23,9 +23,14 @@ currentTracker = undefined room = ChatRoom.findOne(query) if not room? - Session.set 'roomNotFound', {type: type, name: name} - BlazeLayout.render 'main', {center: 'roomNotFound'} - return + + if type is 'd' + Meteor.call 'createDirectMessage', name, -> + openRoom('d', name) + else + Session.set 'roomNotFound', {type: type, name: name} + BlazeLayout.render 'main', {center: 'roomNotFound'} + return $('.rocket-loader').remove(); mainNode = document.querySelector('.main-content') diff --git a/packages/rocketchat-ui-login/username/username.coffee b/packages/rocketchat-ui-login/username/username.coffee index eef6c844c90..935aaf0ad65 100644 --- a/packages/rocketchat-ui-login/username/username.coffee +++ b/packages/rocketchat-ui-login/username/username.coffee @@ -47,4 +47,4 @@ Template.username.events if not err? Meteor.call 'joinDefaultChannels' - FlowRouter.go 'index' + diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index d5b15660788..93b0753c977 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -155,7 +155,7 @@ RocketChat.Notifications.onUser 'message', (msg) -> if openedRooms[typeName].ready closeOlderRooms() - if subscription.ready() + if subscription.ready() && Meteor.userId() if openedRooms[typeName].active isnt true openedRooms[typeName].active = true -- GitLab From 7b47e690a92108d7900e94aab5694b98cc089a31 Mon Sep 17 00:00:00 2001 From: Travis Odom <travis.a.odom@gmail.com> Date: Fri, 29 Jan 2016 21:09:36 -0600 Subject: [PATCH 1310/1338] Add a button to allow deleting an uploaded file --- .../flex-tab/tabs/uploadedFilesList.coffee | 31 ++++++++++++++++++- .../flex-tab/tabs/uploadedFilesList.html | 10 ++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index 1f8b59a0cbf..6144bb3fb7b 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -2,7 +2,7 @@ roomFiles = new Mongo.Collection 'room_files' Template.uploadedFilesList.helpers files: -> - return roomFiles.find({ rid: @rid }, { sort: {uploadedAt : -1} }).fetch() + return roomFiles.find({ rid: @rid }, { sort: { uploadedAt: -1 } }).fetch() hasFiles: -> return roomFiles.find({ rid: @rid }).count() > 0 @@ -23,11 +23,40 @@ Template.uploadedFilesList.helpers escapedName: -> return s.escapeHTML @name + canDelete: -> + msg = ChatMessage.findOne { file: { _id: @_id } } + if msg + return RocketChat.authz.hasAtLeastOnePermission('delete-message', msg.rid) or RocketChat.settings.get('Message_AllowDeleting') and msg.u?._id is Meteor.userId() + Template.uploadedFilesList.events 'click .room-file-item': (e, t) -> if $(e.currentTarget).siblings('.icon-picture').length e.preventDefault() + 'click .icon-trash': (e, t) -> + self = this + swal { + title: 'Are you sure?' + text: 'You will not be able to recover this file.' + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: 'Yes delete it' + cancelButtonText: 'Cancel' + closeOnConfirm: false + html: false + }, -> + swal + title: 'Deleted' + text: 'Your file has been deleted.' + type: 'success' + timer: 1000 + showConfirmButton: false + + msg = ChatMessage.findOne { file: { _id: self._id } } + fileCollection.remove self._id, () -> + chatMessages[Session.get('openedRoom')].deleteMsg(msg); + 'scroll .content': _.throttle (e, t) -> if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight t.limit.set(t.limit.get() + 50) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html index 2ac19362308..b5fb40165e0 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html @@ -1,4 +1,11 @@ <template name="uploadedFilesList"> + <style> + i.red-hover:hover + { + color: red; + cursor: pointer; + } + </style> <div class="content"> <div class="list-view uploaded-files-list"> <div class="status"> @@ -7,6 +14,9 @@ <ul class="list clearfix lines"> {{#each files}} <li> + {{#if canDelete}} + <i class="icon-trash red-hover" style="float: right; padding-top: 10px;"></i> + {{/if}} <a title="{{escapedName}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> <i class="{{getFileIcon type}}"></i> <p>{{name}}</p> -- GitLab From 42aca5c448d8d471f980615d11a7577e2ba541d0 Mon Sep 17 00:00:00 2001 From: Travis Odom <travis.a.odom@gmail.com> Date: Sat, 30 Jan 2016 14:26:48 -0600 Subject: [PATCH 1311/1338] Move delete button style to base.less in theme package --- packages/rocketchat-theme/assets/stylesheets/base.less | 9 +++++++++ .../flex-tab/tabs/uploadedFilesList.html | 9 +-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index c8137ee15c4..84cd915490e 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -3079,6 +3079,15 @@ a.github-fork { float: left; color: #444; margin-right: 10px; + + &.file-delete { + float: right; + padding-top: 10px; + &:hover { + color: red; + cursor: pointer; + } + } } } } diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html index b5fb40165e0..83a194d4669 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html @@ -1,11 +1,4 @@ <template name="uploadedFilesList"> - <style> - i.red-hover:hover - { - color: red; - cursor: pointer; - } - </style> <div class="content"> <div class="list-view uploaded-files-list"> <div class="status"> @@ -15,7 +8,7 @@ {{#each files}} <li> {{#if canDelete}} - <i class="icon-trash red-hover" style="float: right; padding-top: 10px;"></i> + <i class="icon-trash file-delete"></i> {{/if}} <a title="{{escapedName}}" href="{{url}}" target="_blank" class="room-file-item {{customClassForFileType}}"> <i class="{{getFileIcon type}}"></i> -- GitLab From 5331057ebddd27650416218f44ee2cd672137924 Mon Sep 17 00:00:00 2001 From: Travis Odom <travis.a.odom@gmail.com> Date: Mon, 1 Feb 2016 10:08:30 -0600 Subject: [PATCH 1312/1338] Add i18n to rocketchat-ui-flextab package, with default strings for file deletion dialogue --- .../flex-tab/tabs/uploadedFilesList.coffee | 12 ++++++------ packages/rocketchat-ui-flextab/i18n/ar.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/cs.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/de.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/el.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/en.i18n.json | 6 ++++++ packages/rocketchat-ui-flextab/i18n/es.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/fa.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/fi.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/fr.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/he.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/hr.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/hu.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/it.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ja.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/km.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ko.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ku.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/lo.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ms-MY.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/nl.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/pl.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/pt.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ro.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ru.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/sq.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/sr.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/sv.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ta-IN.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/tr.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/ug.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/uk.i18n.json | 1 + packages/rocketchat-ui-flextab/i18n/zh.i18n.json | 1 + packages/rocketchat-ui-flextab/package.js | 11 +++++++++++ 34 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 packages/rocketchat-ui-flextab/i18n/ar.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/cs.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/de.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/el.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/en.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/es.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/fa.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/fi.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/fr.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/he.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/hr.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/hu.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/it.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ja.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/km.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ko.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ku.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/lo.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ms-MY.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/nl.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/pl.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/pt.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ro.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ru.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/sq.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/sr.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/sv.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ta-IN.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/tr.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/ug.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/uk.i18n.json create mode 100644 packages/rocketchat-ui-flextab/i18n/zh.i18n.json diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index 6144bb3fb7b..40690a19086 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -36,19 +36,19 @@ Template.uploadedFilesList.events 'click .icon-trash': (e, t) -> self = this swal { - title: 'Are you sure?' - text: 'You will not be able to recover this file.' + title: TAPi18n.__('Are_you_sure') + text: TAPi18n.__('You_will_not_be_able_to_recover_file') type: 'warning' showCancelButton: true confirmButtonColor: '#DD6B55' - confirmButtonText: 'Yes delete it' - cancelButtonText: 'Cancel' + confirmButtonText: TAPi18n.__('Yes_delete_it') + cancelButtonText: TAPi18n.__('Cancel') closeOnConfirm: false html: false }, -> swal - title: 'Deleted' - text: 'Your file has been deleted.' + title: TAPi18n.__('Deleted') + text: TAPi18n.__('Your_file_has_been_deleted') type: 'success' timer: 1000 showConfirmButton: false diff --git a/packages/rocketchat-ui-flextab/i18n/ar.i18n.json b/packages/rocketchat-ui-flextab/i18n/ar.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ar.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/cs.i18n.json b/packages/rocketchat-ui-flextab/i18n/cs.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/cs.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/de.i18n.json b/packages/rocketchat-ui-flextab/i18n/de.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/de.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/el.i18n.json b/packages/rocketchat-ui-flextab/i18n/el.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/el.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/en.i18n.json b/packages/rocketchat-ui-flextab/i18n/en.i18n.json new file mode 100644 index 00000000000..6ebd19c81e9 --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/en.i18n.json @@ -0,0 +1,6 @@ +{ + "You_will_not_be_able_to_recover_file" : "You will not be able to recover this file!", + "Your_file_has_been_deleted" : "Your file has been deleted.", + "Deleted": "Deleted" +} + diff --git a/packages/rocketchat-ui-flextab/i18n/es.i18n.json b/packages/rocketchat-ui-flextab/i18n/es.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/es.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/fa.i18n.json b/packages/rocketchat-ui-flextab/i18n/fa.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/fa.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/fi.i18n.json b/packages/rocketchat-ui-flextab/i18n/fi.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/fi.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/fr.i18n.json b/packages/rocketchat-ui-flextab/i18n/fr.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/fr.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/he.i18n.json b/packages/rocketchat-ui-flextab/i18n/he.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/he.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/hr.i18n.json b/packages/rocketchat-ui-flextab/i18n/hr.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/hr.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/hu.i18n.json b/packages/rocketchat-ui-flextab/i18n/hu.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/hu.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/it.i18n.json b/packages/rocketchat-ui-flextab/i18n/it.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/it.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ja.i18n.json b/packages/rocketchat-ui-flextab/i18n/ja.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ja.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/km.i18n.json b/packages/rocketchat-ui-flextab/i18n/km.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/km.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ko.i18n.json b/packages/rocketchat-ui-flextab/i18n/ko.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ko.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ku.i18n.json b/packages/rocketchat-ui-flextab/i18n/ku.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ku.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/lo.i18n.json b/packages/rocketchat-ui-flextab/i18n/lo.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/lo.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ms-MY.i18n.json b/packages/rocketchat-ui-flextab/i18n/ms-MY.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ms-MY.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/nl.i18n.json b/packages/rocketchat-ui-flextab/i18n/nl.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/nl.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/pl.i18n.json b/packages/rocketchat-ui-flextab/i18n/pl.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/pl.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/pt.i18n.json b/packages/rocketchat-ui-flextab/i18n/pt.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/pt.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ro.i18n.json b/packages/rocketchat-ui-flextab/i18n/ro.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ro.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ru.i18n.json b/packages/rocketchat-ui-flextab/i18n/ru.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ru.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/sq.i18n.json b/packages/rocketchat-ui-flextab/i18n/sq.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/sq.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/sr.i18n.json b/packages/rocketchat-ui-flextab/i18n/sr.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/sr.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/sv.i18n.json b/packages/rocketchat-ui-flextab/i18n/sv.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/sv.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ta-IN.i18n.json b/packages/rocketchat-ui-flextab/i18n/ta-IN.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ta-IN.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/tr.i18n.json b/packages/rocketchat-ui-flextab/i18n/tr.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/tr.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/ug.i18n.json b/packages/rocketchat-ui-flextab/i18n/ug.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/ug.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/uk.i18n.json b/packages/rocketchat-ui-flextab/i18n/uk.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/uk.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/i18n/zh.i18n.json b/packages/rocketchat-ui-flextab/i18n/zh.i18n.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/rocketchat-ui-flextab/i18n/zh.i18n.json @@ -0,0 +1 @@ +{} diff --git a/packages/rocketchat-ui-flextab/package.js b/packages/rocketchat-ui-flextab/package.js index 98a1b68a2c0..c0dc863caca 100644 --- a/packages/rocketchat-ui-flextab/package.js +++ b/packages/rocketchat-ui-flextab/package.js @@ -36,4 +36,15 @@ Package.onUse(function(api) { api.addFiles('flex-tab/tabs/uploadedFilesList.coffee', 'client'); api.addFiles('flex-tab/tabs/userInfo.coffee', 'client'); + // TAPi18n + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-lib/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-lib/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n'); + api.addFiles(tapi18nFiles); + }); -- GitLab From a05c2b51d76f2c99ad5b2d66f92ba40aa401b6fa Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 1 Feb 2016 15:48:46 -0200 Subject: [PATCH 1313/1338] Allow voice recording when media types whitelist is empty; --- i18n/en.i18n.json | 2 +- packages/rocketchat-ui-message/message/messageBox.coffee | 2 +- packages/rocketchat-ui/views/app/room.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 0074f4dbb23..dcdd7f1b5f9 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -182,7 +182,7 @@ "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_MediaTypeWhiteListDescription" : "Comma-separated list of media types. Leave it blank for accepting all 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.", diff --git a/packages/rocketchat-ui-message/message/messageBox.coffee b/packages/rocketchat-ui-message/message/messageBox.coffee index 00f3cad3a06..0d11010c62a 100644 --- a/packages/rocketchat-ui-message/message/messageBox.coffee +++ b/packages/rocketchat-ui-message/message/messageBox.coffee @@ -26,7 +26,7 @@ Template.messageBox.helpers } canRecordAudio: -> wavRegex = /audio\/wav|audio\/\*/i - wavEnabled = RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) + wavEnabled = !RocketChat.settings.get("FileUpload_MediaTypeWhiteList") || RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) and wavEnabled and RocketChat.settings.get('FileUpload_Enabled') usersTyping: -> users = MsgTyping.get @_id diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index a50f595194f..e564998150f 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -167,7 +167,7 @@ Template.room.helpers canRecordAudio: -> wavRegex = /audio\/wav|audio\/\*/i - wavEnabled = RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) + wavEnabled = !RocketChat.settings.get("FileUpload_MediaTypeWhiteList") || RocketChat.settings.get("FileUpload_MediaTypeWhiteList").match(wavRegex) return RocketChat.settings.get('Message_AudioRecorderEnabled') and (navigator.getUserMedia? or navigator.webkitGetUserMedia?) and wavEnabled and RocketChat.settings.get('FileUpload_Enabled') unreadSince: -> -- GitLab From c89110df8f20492c779626fc63394f77331cbc23 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 1 Feb 2016 15:50:11 -0200 Subject: [PATCH 1314/1338] Show "Room not Found" correctly --- packages/rocketchat-ui/lib/RoomManager.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-ui/lib/RoomManager.coffee b/packages/rocketchat-ui/lib/RoomManager.coffee index 93b0753c977..7efe74cc0f8 100644 --- a/packages/rocketchat-ui/lib/RoomManager.coffee +++ b/packages/rocketchat-ui/lib/RoomManager.coffee @@ -67,7 +67,8 @@ RocketChat.Notifications.onUser 'message', (msg) -> openedRooms[typeName].ready = false openedRooms[typeName].active = false - Blaze.remove openedRooms[typeName].template + if openedRooms[typeName].template? + Blaze.remove openedRooms[typeName].template delete openedRooms[typeName].dom delete openedRooms[typeName].template @@ -104,7 +105,9 @@ RocketChat.Notifications.onUser 'message', (msg) -> room = ChatRoom.findOne query, { reactive: false } - if room? + if not room? + record.ready = true + else openedRooms[typeName].rid = room._id RoomHistoryManager.getMoreIfIsEmpty room._id -- GitLab From 56adb20e38ae54661dceabbe8db360e15c58a13f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 1 Feb 2016 15:50:17 -0200 Subject: [PATCH 1315/1338] Update History.md --- HISTORY.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 5ff5315bf9d..ecfeeccb63a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,15 @@ - Added option for admins to manually add new users - Added option for admin to require user to change password - Changed admin statistics with admin info +- Show "Room not Found" correctly +- Update konecty:multiple-instances-status to 1.0.5 +- Closes #1888; Add mimetye image/vnd.microsoft.icon to mimtype list +- Disable WebRTC broadcastStatus +- Closes #2078; ObserveChanges on rocketchat_room Not Using Oplog +- Add sort for all queries with limit +- Do not get field `usernames` with room on joinDefaultChannel +- Improve logs of stream broadcast +- Create script to build livechat on windows ## 0.15.0, 2016-Jan-25 -- GitLab From d3b03da70faea3e65ce75a45cc57a535eca19b1f Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Mon, 1 Feb 2016 16:27:25 -0200 Subject: [PATCH 1316/1338] Fix showing room not found when direct messaging a non-existing user --- packages/rocketchat-lib/client/lib/openRoom.coffee | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 93f3573be35..6b0f5f882de 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -23,10 +23,14 @@ currentTracker = undefined room = ChatRoom.findOne(query) if not room? - if type is 'd' - Meteor.call 'createDirectMessage', name, -> - openRoom('d', name) + Meteor.call 'createDirectMessage', name, (err) -> + if !err + openRoom('d', name) + else + Session.set 'roomNotFound', {type: type, name: name} + BlazeLayout.render 'main', {center: 'roomNotFound'} + return else Session.set 'roomNotFound', {type: type, name: name} BlazeLayout.render 'main', {center: 'roomNotFound'} -- GitLab From 2e047a4a155fd5b2a3f848693941cb0768e62828 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Mon, 1 Feb 2016 17:11:36 -0200 Subject: [PATCH 1317/1338] version bump to 0.16.0 --- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- HISTORY.md | 2 ++ packages/rocketchat-lib/rocketchat.info | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index 8aaf0efe2b0..48969bbf157 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 11, # Increment this for every release. + appVersion = 12, # Increment this for every release. - appMarketingVersion = (defaultText = "0.15.0"), + appMarketingVersion = (defaultText = "0.16.0"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/HISTORY.md b/HISTORY.md index ecfeeccb63a..dec1c366c6f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,7 @@ ## NEXT +## 0.16.0, 2016-Feb-01 + - Added option for admins to manually add new users - Added option for admin to require user to change password - Changed admin statistics with admin info diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index cbdbae8748e..51d31c60f26 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.15.0" + "version": "0.16.0" } -- GitLab From 696dae5879f717de6b57d7e99e1b87acc8931d41 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 1 Feb 2016 17:18:24 -0200 Subject: [PATCH 1318/1338] Prevent error when trying to open a new direct room --- packages/rocketchat-lib/client/lib/openRoom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee index 6b0f5f882de..bae3a1b0132 100644 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ b/packages/rocketchat-lib/client/lib/openRoom.coffee @@ -34,7 +34,7 @@ currentTracker = undefined else Session.set 'roomNotFound', {type: type, name: name} BlazeLayout.render 'main', {center: 'roomNotFound'} - return + return $('.rocket-loader').remove(); mainNode = document.querySelector('.main-content') -- GitLab From 546ad88ca071ac71f8d9d5508ab1954ff72cc54a Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Mon, 1 Feb 2016 18:26:47 -0200 Subject: [PATCH 1319/1338] Fix auth shutdown to correct idle time (30 days) --- packages/rocketchat-tutum/startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-tutum/startup.coffee b/packages/rocketchat-tutum/startup.coffee index 8af71f33c52..9c2be138de6 100644 --- a/packages/rocketchat-tutum/startup.coffee +++ b/packages/rocketchat-tutum/startup.coffee @@ -14,7 +14,7 @@ if process.env.TUTUM_REDIS_HOST? client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", process.env.TUTUM_CLIENT_NAME) client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", "http://#{process.env.TUTUM_IP_ADDRESS.split('/')[0]}:3000") - day = 3600000 + day = 86400000 inactiveDays = 30 -- GitLab From 63cef436899a33a657197fc34c55080748bcb0ee Mon Sep 17 00:00:00 2001 From: SingLi <Sing-Li@users.noreply.github.com> Date: Tue, 2 Feb 2016 18:01:19 -0500 Subject: [PATCH 1320/1338] Roadmap updates --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fe7f6bf4512..ad67fac5402 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,8 @@ It is a great solution for communities and companies wanting to privately host t ## Roadmap #### In Progress +- XMPP Support via [Webhook bridge](https://github.com/saqura/xmppwb) [Issue #404](https://github.com/RocketChat/Rocket.Chat/issues/404) +- Federation via [matrix.org](https://www.matrix.org/), see [hubot-freddie](https://www.npmjs.com/package/hubot-freddie) and [Federation project](https://github.com/RocketChat/Rocket.Chat.Federation) : [Issue #520](https://github.com/RocketChat/Rocket.Chat/issues/520), [Issue #601](https://github.com/RocketChat/Rocket.Chat/issues/601) - Support multiple teams on the same instance / same VPS infrastructure: [Issue #658](https://github.com/RocketChat/Rocket.Chat/issues/658), [Issue #630](https://github.com/RocketChat/Rocket.Chat/issues/630) - Support for PostgreSQL: [Issue #533](https://github.com/RocketChat/Rocket.Chat/issues/533), [Issue #822](https://github.com/RocketChat/Rocket.Chat/pull/822) - Native iOS Application [Issue #270](https://github.com/RocketChat/Rocket.Chat/issues/270), [Rocket.Chat.iOS - HELP WANTED](https://github.com/RocketChat/Rocket.Chat.iOS) @@ -217,9 +219,7 @@ It is a great solution for communities and companies wanting to privately host t #### Planned - Kerberos Authentication: [Issue #839](https://github.com/RocketChat/Rocket.Chat/issues/839) -- XMPP Multi-user chat (MUC): [Issue #404](https://github.com/RocketChat/Rocket.Chat/issues/404) - More webhooks: GitLab, Confluence, Jira, Piwik, Wordpress: [Issue #233](https://github.com/RocketChat/Rocket.Chat/issues/233), [Issue #525](https://github.com/RocketChat/Rocket.Chat/issues/525), [Issue #637](https://github.com/RocketChat/Rocket.Chat/issues/637), [Issue #638](https://github.com/RocketChat/Rocket.Chat/issues/638), [Issue #747](https://github.com/RocketChat/Rocket.Chat/issues/747) -- Clusterize / Decentralize: [Issue #520](https://github.com/RocketChat/Rocket.Chat/issues/520), [Issue #601](https://github.com/RocketChat/Rocket.Chat/issues/601) - Anonymous use of Rocket.Chat: [Issue #604](https://github.com/RocketChat/Rocket.Chat/issues/604) - File Sharing via P2P and Scalable Multicast: [Issue #369](https://github.com/RocketChat/Rocket.Chat/issues/369), [Issue #370](https://github.com/RocketChat/Rocket.Chat/issues/370) - Anti-virus checking on file uploads: [Issue #757](https://github.com/RocketChat/Rocket.Chat/issues/757) -- GitLab From 2d4d630b5b2c8b9bf4d04bca8fa7d27e0e53a645 Mon Sep 17 00:00:00 2001 From: Dennis Brakhane <dennis.brakhane@inoio.de> Date: Wed, 3 Feb 2016 14:58:50 +0100 Subject: [PATCH 1321/1338] hide "leave/hide room" buttons when showing unread message counter The unread message counter overlapped the "leave room" button, but if a user clicked on the counter, the "leave room" button was still active, causing users to accidentially leave the room. Prevent this by hiding the leave buttons if unread messages are shown. --- .../side-nav/chatRoomItem.html | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html index 4a45dae2fda..276fad3e500 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.html @@ -6,12 +6,14 @@ {{/if}} <i class="{{roomIcon}} {{userStatus}}" aria-label=""></i> <span class='name'>{{name}}</span> - <span class='opt'> - <i class="icon-eye-off hide-room" title="{{_ "Hide_room"}}" aria-label="{{_ "Hide_room"}}"></i> - {{#if canLeave}} - <i class="octicon octicon-sign-out leave-room" title="{{_ "Leave_room"}}" aria-label="{{_ "Leave_room"}}"></i> - {{/if}} - </span> + {{#if $not unread}} + <span class='opt'> + <i class="icon-eye-off hide-room" title="{{_ "Hide_room"}}" aria-label="{{_ "Hide_room"}}"></i> + {{#if canLeave}} + <i class="octicon octicon-sign-out leave-room" title="{{_ "Leave_room"}}" aria-label="{{_ "Leave_room"}}"></i> + {{/if}} + </span> + {{/if}} </a> </li> </template> -- GitLab From 997ef54d3bda7c604f28eb1982d7143dfdd8feab Mon Sep 17 00:00:00 2001 From: Dennis Brakhane <dennis.brakhane@inoio.de> Date: Wed, 3 Feb 2016 15:00:35 +0100 Subject: [PATCH 1322/1338] Show confirmation dialog on leave/hide room Fixes #1543 --- i18n/en.i18n.json | 8 +++ .../side-nav/chatRoomItem.coffee | 58 +++++++++++++++---- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index dcdd7f1b5f9..fbcb3db8a32 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -198,6 +198,9 @@ "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", + "Hide_Room_Warning": "Are you sure you want to hide the room \"%s\"?", + "Hide_Group_Warning": "Are you sure you want to hide the group \"%s\"?", + "Hide_Private_Warning": "Are you sure you want to hide the discussion with \"%s\"?", "History" : "History", "hours" : "hours", "Incorrect_Password" : "Incorrect Password", @@ -256,6 +259,9 @@ "Layout_Sidenav_Footer" : "Side Navigation Footer", "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", + "Leave_Room_Warning": "Are you sure you want to leave the room \"%s\"?", + "Leave_Group_Warning": "Are you sure you want to leave the group \"%s\"?", + "Leave_Private_Warning": "Are you sure you want to leave the discussion with \"%s\"?", "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\"}", @@ -611,6 +617,8 @@ "Yes" : "Yes", "Yes_clear_all" : "Yes, clear all!", "Yes_delete_it" : "Yes, delete it!", + "Yes_hide_it": "Yes, hide it!", + "Yes_leave_it": "Yes, leave 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>", diff --git a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee index 4db2d7e0494..d102936a742 100644 --- a/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee +++ b/packages/rocketchat-ui-sidenav/side-nav/chatRoomItem.coffee @@ -47,18 +47,56 @@ Template.chatRoomItem.events e.stopPropagation() e.preventDefault() - if FlowRouter.getRouteName() in ['channel', 'group', 'direct'] and Session.get('openedRoom') is this.rid - FlowRouter.go 'home' - - Meteor.call 'hideRoom', this.rid + rid = this.rid + name = this.name + + warnText = switch + when this.t == 'c' then 'Hide_Room_Warning' + when this.t == 'p' then 'Hide_Group_Warning' + when this.t == 'd' then 'Hide_Private_Warning' + + + swal { + title: t('Are_you_sure') + text: t(warnText, name) + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_hide_it') + cancelButtonText: t('Cancel') + closeOnConfirm: true + html: false + }, -> + if FlowRouter.getRouteName() in ['channel', 'group', 'direct'] and Session.get('openedRoom') is rid + FlowRouter.go 'home' + + Meteor.call 'hideRoom', rid 'click .leave-room': (e) -> e.stopPropagation() e.preventDefault() - if FlowRouter.getRouteName() in ['channel', 'group', 'direct'] and Session.get('openedRoom') is this.rid - FlowRouter.go 'home' - - RoomManager.close this.rid - - Meteor.call 'leaveRoom', this.rid + rid = this.rid + name = this.name + + warnText = switch + when this.t == 'c' then 'Leave_Room_Warning' + when this.t == 'p' then 'Leave_Group_Warning' + when this.t == 'd' then 'Leave_Private_Warning' + swal { + title: t('Are_you_sure') + text: t(warnText, name) + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_leave_it') + cancelButtonText: t('Cancel') + closeOnConfirm: true + html: false + }, -> + if FlowRouter.getRouteName() in ['channel', 'group', 'direct'] and Session.get('openedRoom') is rid + FlowRouter.go 'home' + + RoomManager.close rid + + Meteor.call 'leaveRoom', rid -- GitLab From 06560541ec3959fb0e5abd811cc23b44e7d981aa Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 3 Feb 2016 13:45:43 -0200 Subject: [PATCH 1323/1338] Closes #1367; Add ability to delete files --- server/methods/deleteMessage.coffee | 9 ++++++++- server/publications/roomFiles.coffee | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server/methods/deleteMessage.coffee b/server/methods/deleteMessage.coffee index 5e96a7cc4ab..5b28f11bcc6 100644 --- a/server/methods/deleteMessage.coffee +++ b/server/methods/deleteMessage.coffee @@ -3,7 +3,7 @@ Meteor.methods if not Meteor.userId() throw new Meteor.Error('invalid-user', "[methods] deleteMessage -> Invalid user") - originalMessage = RocketChat.models.Messages.findOneById message._id, {fields: {u: 1, rid: 1}} + originalMessage = RocketChat.models.Messages.findOneById message._id, {fields: {u: 1, rid: 1, file: 1}} if not originalMessage? throw new Meteor.Error 'message-deleting-not-allowed', "[methods] deleteMessage -> Message with id [#{message._id} dos not exists]" @@ -24,10 +24,17 @@ Meteor.methods else RocketChat.models.Messages.setHiddenById originalMessage._id, true + if originalMessage.file?._id? + fileCollection.update originalMessage.file._id, {$set: {_hidden: true}} + else if not showDeletedStatus RocketChat.models.Messages.removeById originalMessage._id + if originalMessage.file?._id? + fileCollection.remove originalMessage.file._id + Meteor.fileStore.delete originalMessage.file._id + if showDeletedStatus RocketChat.models.Messages.setAsDeletedById originalMessage._id else diff --git a/server/publications/roomFiles.coffee b/server/publications/roomFiles.coffee index e905e740d22..f83702f4a44 100644 --- a/server/publications/roomFiles.coffee +++ b/server/publications/roomFiles.coffee @@ -8,6 +8,8 @@ Meteor.publish 'roomFiles', (rid, limit = 50) -> rid: rid complete: true uploading: false + _hidden: + $ne: true fileOptions = limit: limit -- GitLab From 244f8f02a9328810b31529788646e2301b0c0384 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 3 Feb 2016 13:48:56 -0200 Subject: [PATCH 1324/1338] Update history --- HISTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index dec1c366c6f..a03651d14fc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,7 @@ ## NEXT +- Closes #1367; Add ability to delete files + ## 0.16.0, 2016-Feb-01 - Added option for admins to manually add new users -- GitLab From ea9d00835480f971511d94d270b906942d2f713e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 3 Feb 2016 14:40:37 -0200 Subject: [PATCH 1325/1338] Convert file uploads to model style --- lib/fileUpload.coffee | 5 ++--- packages/rocketchat-lib/package.js | 3 +++ packages/rocketchat-lib/server/models/Uploads.coffee | 6 ++++++ packages/rocketchat-lib/server/models/_Base.coffee | 2 +- server/methods/deleteMessage.coffee | 4 ++-- server/publications/roomFiles.coffee | 2 +- server/startup/migrations/v15.coffee | 2 +- server/startup/migrations/v20.coffee | 2 +- 8 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 packages/rocketchat-lib/server/models/Uploads.coffee diff --git a/lib/fileUpload.coffee b/lib/fileUpload.coffee index 3ee0e68c276..e9251a51497 100644 --- a/lib/fileUpload.coffee +++ b/lib/fileUpload.coffee @@ -1,6 +1,5 @@ if UploadFS? - @fileCollection = new Mongo.Collection 'rocketchat_uploads' - fileCollection.allow + RocketChat.models.Uploads.model.allow insert: (userId, doc) -> return userId @@ -38,7 +37,7 @@ if UploadFS? cookie.send() Meteor.fileStore = new UploadFS.store.GridFS - collection: fileCollection + collection: RocketChat.models.Uploads.model name: 'rocketchat_uploads' collectionName: 'rocketchat_uploads' filter: new UploadFS.Filter diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 02821ae8486..6d052fc28ab 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -17,8 +17,10 @@ Package.onUse(function(api) { api.use('tracker'); api.use('ddp-rate-limiter'); api.use('underscore'); + api.use('mongo'); api.use('underscorestring:underscore.string'); api.use('monbro:mongodb-mapreduce-aggregation@1.0.1'); + api.use('matb33:collection-hooks'); api.use('service-configuration'); api.use('check'); api.use('arunoda:streams'); @@ -48,6 +50,7 @@ Package.onUse(function(api) { api.addFiles('server/models/Rooms.coffee', 'server'); api.addFiles('server/models/Settings.coffee', 'server'); api.addFiles('server/models/Subscriptions.coffee', 'server'); + api.addFiles('server/models/Uploads.coffee', 'server'); api.addFiles('server/models/Users.coffee', 'server'); // SERVER PUBLICATIONS diff --git a/packages/rocketchat-lib/server/models/Uploads.coffee b/packages/rocketchat-lib/server/models/Uploads.coffee new file mode 100644 index 00000000000..1037ee84157 --- /dev/null +++ b/packages/rocketchat-lib/server/models/Uploads.coffee @@ -0,0 +1,6 @@ +RocketChat.models.Uploads = new class extends RocketChat.models._Base + constructor: -> + @_initModel 'uploads' + + @tryEnsureIndex { 'rid': 1 } + @tryEnsureIndex { 'uploadedAt': 1 } diff --git a/packages/rocketchat-lib/server/models/_Base.coffee b/packages/rocketchat-lib/server/models/_Base.coffee index 9c91ac7380d..8dfb475dcd6 100644 --- a/packages/rocketchat-lib/server/models/_Base.coffee +++ b/packages/rocketchat-lib/server/models/_Base.coffee @@ -5,7 +5,7 @@ RocketChat.models._Base = class _initModel: (name) -> check name, String - @model = new Meteor.Collection @_baseName() + name + @model = new Mongo.Collection @_baseName() + name find: -> return @model.find.apply @model, arguments diff --git a/server/methods/deleteMessage.coffee b/server/methods/deleteMessage.coffee index 5b28f11bcc6..7244a1350f2 100644 --- a/server/methods/deleteMessage.coffee +++ b/server/methods/deleteMessage.coffee @@ -25,14 +25,14 @@ Meteor.methods RocketChat.models.Messages.setHiddenById originalMessage._id, true if originalMessage.file?._id? - fileCollection.update originalMessage.file._id, {$set: {_hidden: true}} + RocketChat.models.Uploads.update originalMessage.file._id, {$set: {_hidden: true}} else if not showDeletedStatus RocketChat.models.Messages.removeById originalMessage._id if originalMessage.file?._id? - fileCollection.remove originalMessage.file._id + RocketChat.models.Uploads.remove originalMessage.file._id Meteor.fileStore.delete originalMessage.file._id if showDeletedStatus diff --git a/server/publications/roomFiles.coffee b/server/publications/roomFiles.coffee index f83702f4a44..e69b75a4006 100644 --- a/server/publications/roomFiles.coffee +++ b/server/publications/roomFiles.coffee @@ -22,7 +22,7 @@ Meteor.publish 'roomFiles', (rid, limit = 50) -> type: 1 url: 1 - cursorFileListHandle = fileCollection.find(fileQuery, fileOptions).observeChanges + cursorFileListHandle = RocketChat.models.Uploads.find(fileQuery, fileOptions).observeChanges added: (_id, record) -> pub.added('room_files', _id, record) diff --git a/server/startup/migrations/v15.coffee b/server/startup/migrations/v15.coffee index bc587a10758..2de92bcb935 100644 --- a/server/startup/migrations/v15.coffee +++ b/server/startup/migrations/v15.coffee @@ -7,7 +7,7 @@ RocketChat.Migrations.add oldGridFSCollection = new Meteor.Collection 'cfs_gridfs.files.files' oldChunkCollection = new Meteor.Collection 'cfs_gridfs.files.chunks' - newFilesCollection = fileCollection + newFilesCollection = RocketChat.models.Uploads newGridFSCollection = new Meteor.Collection 'rocketchat_uploads.files' newChunkCollection = new Meteor.Collection 'rocketchat_uploads.chunks' diff --git a/server/startup/migrations/v20.coffee b/server/startup/migrations/v20.coffee index 532e4523bc9..af6bb98edc9 100644 --- a/server/startup/migrations/v20.coffee +++ b/server/startup/migrations/v20.coffee @@ -20,7 +20,7 @@ RocketChat.Migrations.add return unless cursorFileMessages.count() _.each( cursorFileMessages.fetch(), (msg) -> - fileCollection.update({ _id: msg?.file?._id }, { $set: { rid: msg.rid } }, { $multi: true }) + RocketChat.models.Uploads.update({ _id: msg?.file?._id }, { $set: { rid: msg.rid } }, { $multi: true }) ) console.log 'Updated rocketchat_uploads documents to include the room Id in which they were sent.' -- GitLab From a555af1c23feac6c2f65ac8d47ed0178534d1898 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 3 Feb 2016 14:48:37 -0200 Subject: [PATCH 1326/1338] Add Uploads model at client side too --- .../client/models/Uploads.coffee | 3 ++ .../rocketchat-lib/client/models/_Base.coffee | 44 +++++++++++++++++++ packages/rocketchat-lib/package.js | 4 ++ 3 files changed, 51 insertions(+) create mode 100644 packages/rocketchat-lib/client/models/Uploads.coffee create mode 100644 packages/rocketchat-lib/client/models/_Base.coffee diff --git a/packages/rocketchat-lib/client/models/Uploads.coffee b/packages/rocketchat-lib/client/models/Uploads.coffee new file mode 100644 index 00000000000..4572e735b99 --- /dev/null +++ b/packages/rocketchat-lib/client/models/Uploads.coffee @@ -0,0 +1,3 @@ +RocketChat.models.Uploads = new class extends RocketChat.models._Base + constructor: -> + @_initModel 'uploads' diff --git a/packages/rocketchat-lib/client/models/_Base.coffee b/packages/rocketchat-lib/client/models/_Base.coffee new file mode 100644 index 00000000000..fb485723241 --- /dev/null +++ b/packages/rocketchat-lib/client/models/_Base.coffee @@ -0,0 +1,44 @@ +RocketChat.models._Base = class + _baseName: -> + return 'rocketchat_' + + _initModel: (name) -> + check name, String + + @model = new Mongo.Collection @_baseName() + name + + find: -> + return @model.find.apply @model, arguments + + findOne: -> + return @model.findOne.apply @model, arguments + + insert: -> + return @model.insert.apply @model, arguments + + update: -> + return @model.update.apply @model, arguments + + upsert: -> + return @model.upsert.apply @model, arguments + + remove: -> + return @model.remove.apply @model, arguments + + allow: -> + return @model.allow.apply @model, arguments + + deny: -> + return @model.deny.apply @model, arguments + + ensureIndex: -> + return + + dropIndex: -> + return + + tryEnsureIndex: -> + return + + tryDropIndex: -> + return diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 6d052fc28ab..00bad9a32c1 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -107,6 +107,10 @@ Package.onUse(function(api) { api.addFiles('client/defaultTabBars.js', 'client'); + // CLIENT MODELS + api.addFiles('client/models/_Base.coffee', 'client'); + api.addFiles('client/models/Uploads.coffee', 'client'); + // VERSION api.addFiles('rocketchat.info'); -- GitLab From e399653e6bd0d7fa053c82a8b8a3a2b52c7fae6e Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 3 Feb 2016 16:22:23 -0200 Subject: [PATCH 1327/1338] Allow send hooks from a specific public channel --- packages/rocketchat-integrations/server/triggers.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 3cb39a2daf6..feaafa3ab9b 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -114,6 +114,12 @@ ExecuteTriggers = (message, room) -> if triggers.__any? triggersToExecute.push trigger for key, trigger of triggers.__any + 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] + else if triggers['#'+room._id]? triggersToExecute.push trigger for key, trigger of triggers['#'+room._id] -- GitLab From 5a0af98e12970729b58385ef60afb2500b30d0e9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Wed, 3 Feb 2016 21:09:48 -0200 Subject: [PATCH 1328/1338] Add new logger types; Implement LoggerManager as an EventEmmiter; Filter logs by level; Improve log layout --- .../saml_rocketchat.coffee | 3 +- .../server/startup/oAuthServicesUpdate.coffee | 3 +- packages/rocketchat-logger/package.js | 1 + packages/rocketchat-logger/server.coffee | 99 +++++++++++++------ .../rocketchat-theme/server/server.coffee | 3 +- 5 files changed, 76 insertions(+), 33 deletions(-) diff --git a/packages/meteor-accounts-saml/saml_rocketchat.coffee b/packages/meteor-accounts-saml/saml_rocketchat.coffee index 16022a7f7ac..ce8b5015415 100644 --- a/packages/meteor-accounts-saml/saml_rocketchat.coffee +++ b/packages/meteor-accounts-saml/saml_rocketchat.coffee @@ -1,6 +1,7 @@ logger = new Logger 'steffo:meteor-accounts-saml', methods: - updated: 'log' + updated: + type: 'info' RocketChat.settings.addGroup 'SAML' Meteor.methods diff --git a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee index 0305dc42969..b3754bd9284 100644 --- a/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee +++ b/packages/rocketchat-lib/server/startup/oAuthServicesUpdate.coffee @@ -1,6 +1,7 @@ logger = new Logger 'rocketchat:lib', methods: - oauth_updated: 'log' + oauth_updated: + type: 'info' timer = undefined oAuthServicesUpdate = -> diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js index 61036e648f9..5906ab12465 100644 --- a/packages/rocketchat-logger/package.js +++ b/packages/rocketchat-logger/package.js @@ -12,6 +12,7 @@ Package.onUse(function(api) { api.use('underscore'); api.use('logging'); api.use('nooitaf:colors'); + api.use('raix:eventemitter'); api.use('templating', 'client', {weak: true}); api.addFiles('logger.coffee', 'client'); diff --git a/packages/rocketchat-logger/server.coffee b/packages/rocketchat-logger/server.coffee index 2a38507c59d..97b36b93056 100644 --- a/packages/rocketchat-logger/server.coffee +++ b/packages/rocketchat-logger/server.coffee @@ -1,70 +1,104 @@ -LoggerManager = new class - loggers: {} - showPackage: false - showFileAndLine: false +@LoggerManager = new class extends EventEmitter + constructor: -> + @loggers = {} + @showPackage = true + @showFileAndLine = true + @logLevel = 2 + + register: (logger) -> + if not logger instanceof Logger + return + + @loggers[logger.name] = logger + + @emit 'register', logger + +@LoggerManager.on 'register', -> + console.log('on register', arguments) + @Logger = class Logger defaultTypes: - log: 'blue' - warn: 'magenta' - error: 'red' - - config: {} + log: + name: 'info' + color: 'blue' + level: 1 + info: + name: 'info' + color: 'blue' + level: 1 + debug: + name: 'debug' + color: 'blue' + level: 2 + warn: + name: 'warn' + color: 'magenta' + level: 1 + error: + name: 'error' + color: 'red' + level: 0 constructor: (@name, config={}) -> + @config = {} + _.extend @config, config if LoggerManager.loggers[@name]? LoggerManager.loggers[@name].warn 'Duplicated instance' return LoggerManager.loggers[@name] - for type, color of @defaultTypes - do (type, color) => + for type, typeConfig of @defaultTypes + do (type, typeConfig) => @[type] = (args...) => @_log type: type + level: typeConfig.level + method: typeConfig.name arguments: args if @config.methods? - for method, type of @config.methods - do (method, type) => + for method, typeConfig of @config.methods + do (method, typeConfig) => if @[method]? @warn "Method", method, "already exists" - if not @defaultTypes[type]? - @warn "Method type", type, "doest not exists" + if not @defaultTypes[typeConfig.type]? + @warn "Method type", typeConfig.type, "doest not exists" @[method] = (args...) => @_log - type: type + type: typeConfig.type + level: if typeConfig.level? then typeConfig.level? else @defaultTypes[typeConfig.type]?.level method: method arguments: args + LoggerManager.register @ return @ getPrefix: (options) -> - prefix = "" - - if options.method? - prefix = "[#{@name} #{options.method}]" - else - prefix = "[#{@name}]" + prefix = "#{@name} âž” #{options.method}" details = @_getCallerDetails() detailParts = [] if details.package? and LoggerManager.showPackage is true detailParts.push details.package - if details.file? and LoggerManager.showFileAndLine is true - detailParts.push details.file - if details.line? and LoggerManager.showFileAndLine is true - detailParts.push details.line - - if detailParts.length > 0 - prefix = "(#{detailParts.join(':')})#{prefix}" + if LoggerManager.showFileAndLine is true + if details.file? and details.line? + detailParts.push "#{details.file}:#{details.line}" + else + if details.file? + detailParts.push details.file + if details.line? + detailParts.push details.line if @defaultTypes[options.type]? - return prefix[@defaultTypes[options.type]] + prefix = prefix[@defaultTypes[options.type].color] + + if detailParts.length > 0 + prefix = "#{detailParts.join(' ')} #{prefix}" return prefix @@ -119,5 +153,10 @@ LoggerManager = new class return details _log: (options) -> + options.level ?= 1 + + if LoggerManager.logLevel < options.level + return + options.arguments.unshift @getPrefix(options) console.log.apply console, options.arguments diff --git a/packages/rocketchat-theme/server/server.coffee b/packages/rocketchat-theme/server/server.coffee index 190c46e8529..31783161df4 100644 --- a/packages/rocketchat-theme/server/server.coffee +++ b/packages/rocketchat-theme/server/server.coffee @@ -4,7 +4,8 @@ crypto = Npm.require('crypto') logger = new Logger 'rocketchat:theme', methods: - stop_rendering: 'log' + stop_rendering: + type: 'info' calculateClientHash = WebAppHashing.calculateClientHash -- GitLab From d3cfeb5ba4d0065e662286be56cca30763beba64 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 4 Feb 2016 09:02:56 -0200 Subject: [PATCH 1329/1338] Fix problem removing file via side bar --- .../flex-tab/tabs/uploadedFilesList.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index 40690a19086..edb45b8d693 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -54,7 +54,7 @@ Template.uploadedFilesList.events showConfirmButton: false msg = ChatMessage.findOne { file: { _id: self._id } } - fileCollection.remove self._id, () -> + RocketChat.models.Uploads.remove self._id, () -> chatMessages[Session.get('openedRoom')].deleteMsg(msg); 'scroll .content': _.throttle (e, t) -> -- GitLab From a970502d295f7ee490d66ccfc15fc1438a82ef07 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 4 Feb 2016 10:07:56 -0200 Subject: [PATCH 1330/1338] Add an example of how to send logs from server to client --- packages/rocketchat-logger/ansispan.js | 41 ++++++++++++++++++++++++ packages/rocketchat-logger/logger.coffee | 8 +++++ packages/rocketchat-logger/package.js | 1 + packages/rocketchat-logger/server.coffee | 10 ++++++ 4 files changed, 60 insertions(+) create mode 100644 packages/rocketchat-logger/ansispan.js diff --git a/packages/rocketchat-logger/ansispan.js b/packages/rocketchat-logger/ansispan.js new file mode 100644 index 00000000000..8f9948f195e --- /dev/null +++ b/packages/rocketchat-logger/ansispan.js @@ -0,0 +1,41 @@ +ansispan = function (str) { + Object.keys(ansispan.foregroundColors).forEach(function (ansi) { + var span = '<span style="color: ' + ansispan.foregroundColors[ansi] + '">'; + + // + // `\033[Xm` == `\033[0;Xm` sets foreground color to `X`. + // + + str = str.replace( + new RegExp('\033\\[' + ansi + 'm', 'g'), + span + ).replace( + new RegExp('\033\\[0;' + ansi + 'm', 'g'), + span + ); + }); + // + // `\033[1m` enables bold font, `\033[22m` disables it + // + str = str.replace(/\033\[1m/g, '<b>').replace(/\033\[22m/g, '</b>'); + + // + // `\033[3m` enables italics font, `\033[23m` disables it + // + str = str.replace(/\033\[3m/g, '<i>').replace(/\033\[23m/g, '</i>'); + + str = str.replace(/\033\[m/g, '</span>'); + str = str.replace(/\033\[0m/g, '</span>'); + return str.replace(/\033\[39m/g, '</span>'); +}; + +ansispan.foregroundColors = { + '30': 'black', + '31': 'red', + '32': 'green', + '33': 'yellow', + '34': 'blue', + '35': 'purple', + '36': 'cyan', + '37': 'white' +}; diff --git a/packages/rocketchat-logger/logger.coffee b/packages/rocketchat-logger/logger.coffee index 4f6795b2e66..3317996c970 100644 --- a/packages/rocketchat-logger/logger.coffee +++ b/packages/rocketchat-logger/logger.coffee @@ -63,3 +63,11 @@ wrapLifeCycle = (original, prefix, color) -> Template.prototype.onCreated = wrapLifeCycle Template.prototype.onCreated, 'onCreated', 'blue' Template.prototype.onRendered = wrapLifeCycle Template.prototype.onRendered, 'onRendered', 'green' Template.prototype.onDestroyed = wrapLifeCycle Template.prototype.onDestroyed, 'onDestroyed', 'red' + +# stdout = new Meteor.Collection 'stdout' + +# Meteor.subscribe 'stdout' + +# stdout.find().observe +# added: (record) -> +# console.log ansispan record.string diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js index 5906ab12465..8566a71aad8 100644 --- a/packages/rocketchat-logger/package.js +++ b/packages/rocketchat-logger/package.js @@ -15,6 +15,7 @@ Package.onUse(function(api) { api.use('raix:eventemitter'); api.use('templating', 'client', {weak: true}); + api.addFiles('ansispan.js', 'client'); api.addFiles('logger.coffee', 'client'); api.addFiles('server.coffee', 'server'); diff --git a/packages/rocketchat-logger/server.coffee b/packages/rocketchat-logger/server.coffee index 97b36b93056..c8da998332b 100644 --- a/packages/rocketchat-logger/server.coffee +++ b/packages/rocketchat-logger/server.coffee @@ -160,3 +160,13 @@ options.arguments.unshift @getPrefix(options) console.log.apply console, options.arguments + +# Meteor.publish 'stdout', -> +# write = process.stdout.write +# process.stdout.write = (string, encoding, fd) => +# write.apply(process.stdout, arguments) +# id = Random.id() +# @added 'stdout', id, {string: string} +# @removed 'stdout', id + +# @ready() -- GitLab From 8c471cb347fd99bf71fa7b641ce2903d53238a7d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 4 Feb 2016 12:19:36 -0200 Subject: [PATCH 1331/1338] Fixed trying to read build from RocketChat.Info when it is not available. --- packages/rocketchat-migrations/migrations.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-migrations/migrations.js b/packages/rocketchat-migrations/migrations.js index b725f8ac53b..0e7048c0b65 100644 --- a/packages/rocketchat-migrations/migrations.js +++ b/packages/rocketchat-migrations/migrations.js @@ -302,6 +302,7 @@ Migrations._migrateTo = function(version, rerun) { function lock() { const date = new Date(); const dateMinusInterval = moment(date).subtract(self.options.lockExpiration, 'minutes').toDate(); + const build = RocketChat.Info ? RocketChat.Info.build.date : date; // This is atomic. The selector ensures only one caller at a time will see // the unlocked control, and locking occurs in the same update's modifier. @@ -316,14 +317,14 @@ Migrations._migrateTo = function(version, rerun) { } }, { buildAt: { - $ne: RocketChat.Info.build.date + $ne: build } }] }, { $set: { locked: true, lockedAt: date, - buildAt: RocketChat.Info.build.date + buildAt: build } }) === 1; } -- GitLab From 286058e78d63f84be34046fe23ad6441aea8a3bd Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 4 Feb 2016 14:12:33 -0200 Subject: [PATCH 1332/1338] Remove the need for server restart after changing registration domain whitelist --- server/lib/accounts.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 061af1ad935..d3a9b56c455 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -1,9 +1,10 @@ # Deny Account.createUser in client and set Meteor.loginTokenExpires accountsConfig = { forbidClientAccountCreation: true, loginExpirationInDays: RocketChat.settings.get 'Accounts_LoginExpiration' } +Accounts.config accountsConfig -if RocketChat.settings.get('Accounts_AllowedDomainsList') +RocketChat.settings.onload 'Accounts_AllowedDomainsList', -> domainWhiteList = _.map RocketChat.settings.get('Accounts_AllowedDomainsList').split(','), (domain) -> domain.trim() - accountsConfig.restrictCreationByEmailDomain = (email) -> + restrictCreationByEmailDomain = (email) -> ret = false for domain in domainWhiteList if email.match(domain + '$') @@ -11,8 +12,8 @@ if RocketChat.settings.get('Accounts_AllowedDomainsList') break; return ret - -Accounts.config accountsConfig + delete Accounts._options['restrictCreationByEmailDomain'] + Accounts.config({ restrictCreationByEmailDomain: restrictCreationByEmailDomain }); Accounts.emailTemplates.siteName = RocketChat.settings.get 'Site_Name'; Accounts.emailTemplates.from = "#{RocketChat.settings.get 'Site_Name'} <#{RocketChat.settings.get 'From_Email'}>"; -- GitLab From 9598b587c3e866ee9e0655f70808462be86e8132 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt <marcelo.schmidt@gmail.com> Date: Thu, 4 Feb 2016 14:50:22 -0200 Subject: [PATCH 1333/1338] Changed settings.get to automatically setup and call a specifed callback --- packages/rocketchat-lib/lib/settings.coffee | 8 ++++++++ server/lib/accounts.coffee | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-lib/lib/settings.coffee b/packages/rocketchat-lib/lib/settings.coffee index 91d58ae475e..6591e0253dd 100644 --- a/packages/rocketchat-lib/lib/settings.coffee +++ b/packages/rocketchat-lib/lib/settings.coffee @@ -9,6 +9,14 @@ RocketChat.settings = get: (_id) -> return Meteor.settings?[_id] + get: (_id, callback) -> + if callback? + RocketChat.settings.onload _id, callback + if Meteor.settings?[_id]? + callback _id, Meteor.settings?[_id] + else + return Meteor.settings?[_id] + set: (_id, value, callback) -> Meteor.call 'saveSetting', _id, value, callback diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index d3a9b56c455..6fc3b5a8415 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -2,8 +2,8 @@ accountsConfig = { forbidClientAccountCreation: true, loginExpirationInDays: RocketChat.settings.get 'Accounts_LoginExpiration' } Accounts.config accountsConfig -RocketChat.settings.onload 'Accounts_AllowedDomainsList', -> - domainWhiteList = _.map RocketChat.settings.get('Accounts_AllowedDomainsList').split(','), (domain) -> domain.trim() +RocketChat.settings.get 'Accounts_AllowedDomainsList', (_id, value) -> + domainWhiteList = _.map value.split(','), (domain) -> domain.trim() restrictCreationByEmailDomain = (email) -> ret = false for domain in domainWhiteList -- GitLab From f03327ebb1e0d2fc9fdd438836d14e1f8ad72644 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@gmail.com> Date: Thu, 4 Feb 2016 15:59:08 -0200 Subject: [PATCH 1334/1338] Remove the LDAP string as it is irrelevant to end users. --- packages/rocketchat-ui-login/login/form.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rocketchat-ui-login/login/form.coffee b/packages/rocketchat-ui-login/login/form.coffee index 5d9946acac2..5170a286b04 100644 --- a/packages/rocketchat-ui-login/login/form.coffee +++ b/packages/rocketchat-ui-login/login/form.coffee @@ -40,8 +40,6 @@ Template.loginForm.helpers when 'register' return t('Submit') when 'login' - if RocketChat.settings.get('LDAP_Enable') - return t('Login') + ' (LDAP)' return t('Login') when 'email-verification' return t('Send_confirmation_email') -- GitLab From cc4604f230f773c60f613f18c2ed5d47a45b7fb6 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 4 Feb 2016 16:52:19 -0200 Subject: [PATCH 1335/1338] Create settings for logger --- .../rocketchat-lib/lib/configLogger.coffee | 12 ++++ packages/rocketchat-lib/package.js | 1 + .../server/startup/settings.coffee | 6 ++ packages/rocketchat-logger/server.coffee | 55 +++++++++++++++---- 4 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 packages/rocketchat-lib/lib/configLogger.coffee diff --git a/packages/rocketchat-lib/lib/configLogger.coffee b/packages/rocketchat-lib/lib/configLogger.coffee new file mode 100644 index 00000000000..37496802ad5 --- /dev/null +++ b/packages/rocketchat-lib/lib/configLogger.coffee @@ -0,0 +1,12 @@ +RocketChat.settings.get 'Log_Package', (key, value) -> + LoggerManager?.showPackage = value + +RocketChat.settings.get 'Log_File', (key, value) -> + LoggerManager?.showFileAndLine = value + +RocketChat.settings.get 'Log_Level', (key, value) -> + if value? + LoggerManager?.logLevel = parseInt value + Meteor.setTimeout -> + LoggerManager?.enable(true) + , 200 diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index c901325a8af..65aabf8cce3 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -35,6 +35,7 @@ Package.onUse(function(api) { // COMMON LIB api.addFiles('lib/settings.coffee'); + api.addFiles('lib/configLogger.coffee'); api.addFiles('lib/callbacks.coffee'); api.addFiles('lib/slashCommand.coffee'); api.addFiles('lib/Message.coffee'); diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index af91d9ec18d..20a6e48712c 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -164,6 +164,12 @@ RocketChat.settings.addGroup 'Layout', -> @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.addGroup 'Logs', -> + @add 'Log_Level', '0', { type: 'select', values: [ { key: '0', i18nLabel: '0_Errors_Only' }, { key: '1', i18nLabel: '1_Errors_and_Information' }, { key: '2', i18nLabel: '2_Erros_Information_and_Debug' } ] , public: true } + @add 'Log_Package', false, { type: 'boolean', public: true } + @add 'Log_File', false, { type: 'boolean', public: true } + + RocketChat.settings.init() # Remove runtime settings (non-persistent) diff --git a/packages/rocketchat-logger/server.coffee b/packages/rocketchat-logger/server.coffee index c8da998332b..3d5f1eb5753 100644 --- a/packages/rocketchat-logger/server.coffee +++ b/packages/rocketchat-logger/server.coffee @@ -1,9 +1,12 @@ @LoggerManager = new class extends EventEmitter constructor: -> + @enabled = false @loggers = {} - @showPackage = true - @showFileAndLine = true - @logLevel = 2 + @queue = [] + + @showPackage = false + @showFileAndLine = false + @logLevel = 0 register: (logger) -> if not logger instanceof Logger @@ -13,12 +16,41 @@ @emit 'register', logger -@LoggerManager.on 'register', -> - console.log('on register', arguments) + addToQueue: (logger, args)-> + @queue.push + logger: logger + args: args + + dispatchQueue: -> + for item in @queue + item.logger._log.apply item.logger, item.args + + @clearQueue() + + clearQueue: -> + @queue = [] + + disable: -> + @enabled = false + + enable: (dispatchQueue=false) -> + @enabled = true + if dispatchQueue is true + @dispatchQueue() + else + @clearQueue() + + +# @LoggerManager.on 'register', -> +# console.log('on register', arguments) @Logger = class Logger defaultTypes: + debug: + name: 'debug' + color: 'blue' + level: 2 log: name: 'info' color: 'blue' @@ -27,10 +59,6 @@ name: 'info' color: 'blue' level: 1 - debug: - name: 'debug' - color: 'blue' - level: 2 warn: name: 'warn' color: 'magenta' @@ -83,9 +111,10 @@ details = @_getCallerDetails() detailParts = [] - if details.package? and LoggerManager.showPackage is true + if details.package? and (LoggerManager.showPackage is true or options.type is 'error') detailParts.push details.package - if LoggerManager.showFileAndLine is true + + if LoggerManager.showFileAndLine is true or options.type is 'error' if details.file? and details.line? detailParts.push "#{details.file}:#{details.line}" else @@ -153,6 +182,10 @@ return details _log: (options) -> + if LoggerManager.enabled is false + LoggerManager.addToQueue @, arguments + return + options.level ?= 1 if LoggerManager.logLevel < options.level -- GitLab From 7be1830939fe3a510cd42d05e69b44b44c36db30 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 4 Feb 2016 19:51:12 -0200 Subject: [PATCH 1336/1338] Init view to show server logs on client side --- .../server/startup.coffee | 3 + .../server/startup/settings.coffee | 1 + packages/rocketchat-logger/ansispan.js | 6 +- .../rocketchat-logger/client/viewLogs.coffee | 16 +++++ .../client/views/viewLogs.coffee | 15 +++++ .../client/views/viewLogs.html | 14 +++++ packages/rocketchat-logger/package.js | 8 ++- packages/rocketchat-logger/server.coffee | 61 ++++++++++++++++--- .../assets/stylesheets/base.less | 33 ++++++++++ 9 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 packages/rocketchat-logger/client/viewLogs.coffee create mode 100644 packages/rocketchat-logger/client/views/viewLogs.coffee create mode 100644 packages/rocketchat-logger/client/views/viewLogs.html diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 5a418ef66a6..8f662bd5f15 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -115,6 +115,9 @@ Meteor.startup -> roles : ['admin', 'bot']} { _id: 'manage-oauth-apps', + roles : ['admin']}, + + { _id: 'view-logs', roles : ['admin']} ] diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 20a6e48712c..1a276f34004 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -168,6 +168,7 @@ RocketChat.settings.addGroup 'Logs', -> @add 'Log_Level', '0', { type: 'select', values: [ { key: '0', i18nLabel: '0_Errors_Only' }, { key: '1', i18nLabel: '1_Errors_and_Information' }, { key: '2', i18nLabel: '2_Erros_Information_and_Debug' } ] , public: true } @add 'Log_Package', false, { type: 'boolean', public: true } @add 'Log_File', false, { type: 'boolean', public: true } + @add 'Log_View_Limit', 10000, { type: 'int' } RocketChat.settings.init() diff --git a/packages/rocketchat-logger/ansispan.js b/packages/rocketchat-logger/ansispan.js index 8f9948f195e..294fd3603a3 100644 --- a/packages/rocketchat-logger/ansispan.js +++ b/packages/rocketchat-logger/ansispan.js @@ -30,12 +30,12 @@ ansispan = function (str) { }; ansispan.foregroundColors = { - '30': 'black', + '30': 'gray', '31': 'red', '32': 'green', '33': 'yellow', - '34': 'blue', - '35': 'purple', + '34': '#6B98FF', + '35': '#FF00FF', '36': 'cyan', '37': 'white' }; diff --git a/packages/rocketchat-logger/client/viewLogs.coffee b/packages/rocketchat-logger/client/viewLogs.coffee new file mode 100644 index 00000000000..4928818c093 --- /dev/null +++ b/packages/rocketchat-logger/client/viewLogs.coffee @@ -0,0 +1,16 @@ +@stdout = new Meteor.Collection 'stdout' + +Meteor.startup -> + RocketChat.AdminBox.addOption + href: 'admin-view-logs' + i18nLabel: 'View_Logs' + permissionGranted: -> + return RocketChat.authz.hasAllPermission('view-logs') + +FlowRouter.route '/admin/view-logs', + name: 'admin-view-logs' + action: (params) -> + BlazeLayout.render 'main', + center: 'pageSettingsContainer' + pageTitle: t('Logs') + pageTemplate: 'viewLogs' diff --git a/packages/rocketchat-logger/client/views/viewLogs.coffee b/packages/rocketchat-logger/client/views/viewLogs.coffee new file mode 100644 index 00000000000..01c6d00b05a --- /dev/null +++ b/packages/rocketchat-logger/client/views/viewLogs.coffee @@ -0,0 +1,15 @@ +Template.viewLogs.onCreated -> + @subscribe 'stdout' + +Template.viewLogs.helpers + hasPermission: -> + return RocketChat.authz.hasAllPermission 'view-logs' + + logs: -> + return stdout.find({}, {sort: {ts: 1}}) + + ansispan: (string) -> + return ansispan(string.replace(/\s/g, ' ').replace(/(\\n|\n)/g, '<br>')) + + formatTS: (date) -> + return moment(date).format('YMMDD-HH:mm:ss.SSS(ZZ)') diff --git a/packages/rocketchat-logger/client/views/viewLogs.html b/packages/rocketchat-logger/client/views/viewLogs.html new file mode 100644 index 00000000000..47a80729815 --- /dev/null +++ b/packages/rocketchat-logger/client/views/viewLogs.html @@ -0,0 +1,14 @@ +<template name="viewLogs"> + {{#if hasPermission}} + <div class="section terminal"> + {{#each logs}} + <div> + <!-- <span class="time">{{formatTS ts}}</span> --> + {{{ansispan string}}} + </div> + {{/each}} + </div> + {{else}} + {{_ "Not_authorized"}} + {{/if}} +</template> diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js index 8566a71aad8..f8a9ddb8d09 100644 --- a/packages/rocketchat-logger/package.js +++ b/packages/rocketchat-logger/package.js @@ -10,13 +10,19 @@ Package.onUse(function(api) { api.use('coffeescript'); api.use('underscore'); + api.use('random'); api.use('logging'); api.use('nooitaf:colors'); api.use('raix:eventemitter'); - api.use('templating', 'client', {weak: true}); + api.use('templating', 'client'); + api.use('kadira:flow-router', 'client'); api.addFiles('ansispan.js', 'client'); api.addFiles('logger.coffee', 'client'); + api.addFiles('client/viewLogs.coffee', 'client'); + api.addFiles('client/views/viewLogs.html', 'client'); + api.addFiles('client/views/viewLogs.coffee', 'client'); + api.addFiles('server.coffee', 'server'); api.export('Logger'); diff --git a/packages/rocketchat-logger/server.coffee b/packages/rocketchat-logger/server.coffee index 3d5f1eb5753..5c7fdce8349 100644 --- a/packages/rocketchat-logger/server.coffee +++ b/packages/rocketchat-logger/server.coffee @@ -194,12 +194,55 @@ options.arguments.unshift @getPrefix(options) console.log.apply console, options.arguments -# Meteor.publish 'stdout', -> -# write = process.stdout.write -# process.stdout.write = (string, encoding, fd) => -# write.apply(process.stdout, arguments) -# id = Random.id() -# @added 'stdout', id, {string: string} -# @removed 'stdout', id - -# @ready() +processString = (string, date) -> + if string[0] is '{' + try + return Log.format EJSON.parse(string), {color: true} + + try + return Log.format {message: string, time: date, level: 'info'}, {color: true} + + return string + +StdOut = new class extends EventEmitter + constructor: -> + @queue = [] + write = process.stdout.write + process.stdout.write = (string, encoding, fd) => + write.apply(process.stdout, arguments) + date = new Date + string = processString string, date + + item = + id: Random.id() + string: string + ts: date + + @queue.push item + + if RocketChat?.settings?.get('Log_View_Limit')? and @queue.length > RocketChat.settings.get('Log_View_Limit') + @queue.shift() + + @emit 'write', string, item + + +Meteor.publish 'stdout', -> + unless @userId + return @ready() + + if RocketChat.authz.hasPermission(@userId, 'view-logs') isnt true + return @ready() + + for item in StdOut.queue + @added 'stdout', item.id, + string: item.string + ts: item.ts + + @ready() + + StdOut.on 'write', (string, item) => + @added 'stdout', item.id, + string: item.string + ts: item.ts + + return diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 84cd915490e..c7ea5b08534 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -4395,3 +4395,36 @@ a.github-fork { } } } + +.terminal { + background-color: #000 !important; + color: #fff; + position: absolute; + top: 0px; + bottom: 0px; + margin: 0; + right: 0; + left: 0; + overflow-y: scroll; + border: none !important; + padding: 8px 10px !important; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + + * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + } + + > div { + word-break: break-all; + + > .time { + color: #666; + } + } +} -- GitLab From 7abc444e1bf65a9973014c0fc96585df86f6aac9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento <rodrigoknascimento@gmail.com> Date: Thu, 4 Feb 2016 21:55:36 -0200 Subject: [PATCH 1337/1338] Translate strings --- i18n/en.i18n.json | 36 +++++++++++-------- .../server/startup/settings.coffee | 2 +- .../rocketchat-logger/client/viewLogs.coffee | 2 +- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index fbcb3db8a32..70902a285e1 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1,4 +1,7 @@ { + "0_Errors_Only" : "0 - Errors Only", + "1_Errors_and_Information" : "1 - Errors and Information", + "2_Erros_Information_and_Debug" : "2 - Erros, Information and Debug", "Access_not_authorized" : "Access not authorized", "Access_online_demo" : "Access the online demo", "Access_Online_Demo" : "Access the Online Demo", @@ -197,10 +200,10 @@ "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", - "Hide_Room_Warning": "Are you sure you want to hide the room \"%s\"?", "Hide_Group_Warning": "Are you sure you want to hide the group \"%s\"?", "Hide_Private_Warning": "Are you sure you want to hide the discussion with \"%s\"?", + "Hide_room" : "Hide room", + "Hide_Room_Warning": "Are you sure you want to hide the room \"%s\"?", "History" : "History", "hours" : "hours", "Incorrect_Password" : "Incorrect Password", @@ -259,9 +262,6 @@ "Layout_Sidenav_Footer" : "Side Navigation Footer", "Layout_Sidenav_Footer_description" : "Footer size is 260 x 70px", "Layout_Terms_of_Service" : "Terms of Service", - "Leave_Room_Warning": "Are you sure you want to leave the room \"%s\"?", - "Leave_Group_Warning": "Are you sure you want to leave the group \"%s\"?", - "Leave_Private_Warning": "Are you sure you want to leave the discussion with \"%s\"?", "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\"}", @@ -282,12 +282,19 @@ "LDAP_TLS" : "TLS", "LDAP_Url" : "LDAP URL", "LDAP_Url_Description" : "URL of the LDAP server; example: ldap://company.dns.com", + "Leave_Group_Warning": "Are you sure you want to leave the group \"%s\"?", + "Leave_Private_Warning": "Are you sure you want to leave the discussion with \"%s\"?", "Leave_room" : "Leave room", + "Leave_Room_Warning": "Are you sure you want to leave the room \"%s\"?", "line" : "line", "Load_more" : "Load more", "Loading..." : "Loading...", "Loading_more_from_history" : "Loading more from history", "Loading_suggestion" : "Loading suggestions...", + "Log_File" : "Show File and Line", + "Log_Level" : "Log Level", + "Log_Package" : "Show Package", + "Log_View_Limit" : "Log View Limit", "Logged_out_of_other_clients_successfully" : "Logged out of other clients successfully", "Login" : "Login", "Login_with" : "Login with %s", @@ -372,6 +379,15 @@ "Opt_out_statistics" : "Don't send my statistics to Rocket.Chat", "Opt_out_statistics_warning" : "By sending your statistics, you'll help us identify how many instances of Rocket.Chat are deployed, as well as how good the system is behaving, so we can further improve it. Don't worry, as no user information is sent and all the information we receive is kept confidential. If you want to continue sending us your statistics, uncheck the above checkbox. Thank you.", "optional" : "optional", + "OS_Arch" : "OS Arch", + "OS_Cpus" : "OS CPU Count", + "OS_Freemem" : "OS Free Memory", + "OS_Loadavg" : "OS Load Average", + "OS_Platform" : "OS Platform", + "OS_Release" : "OS Release", + "OS_Totalmem" : "OS Total Memory", + "OS_Type" : "OS Type", + "OS_Uptime" : "OS Uptime", "others" : "others", "Password" : "Password", "Password_Change_Disabled" : "Your Rocket.Chat administrator has disabled the changing of passwords", @@ -509,15 +525,6 @@ "Stats_Non_Active_Users" : "Inactive Users", "Stats_Offline_Users" : "Offline Users", "Stats_Online_Users" : "Online Users", - "OS_Arch" : "OS Arch", - "OS_Cpus" : "OS CPU Count", - "OS_Freemem" : "OS Free Memory", - "OS_Loadavg" : "OS Load Average", - "OS_Platform" : "OS Platform", - "OS_Release" : "OS Release", - "OS_Totalmem" : "OS Total Memory", - "OS_Type" : "OS Type", - "OS_Uptime" : "OS Uptime", "Stats_Total_Channels" : "Total Channels", "Stats_Total_Direct_Messages" : "Total Direct Message Rooms", "Stats_Total_Messages" : "Total Messages", @@ -607,6 +614,7 @@ "UTF8_Names_Validation" : "UTF8 Names Validation", "UTF8_Names_Validation_Description" : "Do not allow special characters and spaces. You can use - _ and . but not at the end of the name", "View_All" : "View All", + "View_Logs" : "View Logs", "Wait_activation_warning" : "Before you can login, your account must be manually activated by an administrator.", "We_have_sent_password_email" : "We have sent you an e-mail with password reset instructions. If you do not receive an e-mail shortly, please come back and try again.", "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.", diff --git a/packages/rocketchat-lib/server/startup/settings.coffee b/packages/rocketchat-lib/server/startup/settings.coffee index 1a276f34004..be203007fcc 100644 --- a/packages/rocketchat-lib/server/startup/settings.coffee +++ b/packages/rocketchat-lib/server/startup/settings.coffee @@ -168,7 +168,7 @@ RocketChat.settings.addGroup 'Logs', -> @add 'Log_Level', '0', { type: 'select', values: [ { key: '0', i18nLabel: '0_Errors_Only' }, { key: '1', i18nLabel: '1_Errors_and_Information' }, { key: '2', i18nLabel: '2_Erros_Information_and_Debug' } ] , public: true } @add 'Log_Package', false, { type: 'boolean', public: true } @add 'Log_File', false, { type: 'boolean', public: true } - @add 'Log_View_Limit', 10000, { type: 'int' } + @add 'Log_View_Limit', 1000, { type: 'int' } RocketChat.settings.init() diff --git a/packages/rocketchat-logger/client/viewLogs.coffee b/packages/rocketchat-logger/client/viewLogs.coffee index 4928818c093..bda272953af 100644 --- a/packages/rocketchat-logger/client/viewLogs.coffee +++ b/packages/rocketchat-logger/client/viewLogs.coffee @@ -12,5 +12,5 @@ FlowRouter.route '/admin/view-logs', action: (params) -> BlazeLayout.render 'main', center: 'pageSettingsContainer' - pageTitle: t('Logs') + pageTitle: t('View_Logs') pageTemplate: 'viewLogs' -- GitLab From 6935e037f38615f3b855cc41718414a15a99de04 Mon Sep 17 00:00:00 2001 From: Gabriel Engel <gabriel.engel@fgsys.com> Date: Fri, 5 Feb 2016 00:18:32 -0200 Subject: [PATCH 1338/1338] no comments... :( --- packages/rocketchat-logger/package.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rocketchat-logger/package.js b/packages/rocketchat-logger/package.js index f8a9ddb8d09..e621241c580 100644 --- a/packages/rocketchat-logger/package.js +++ b/packages/rocketchat-logger/package.js @@ -1,8 +1,7 @@ Package.describe({ name: 'rocketchat:logger', version: '0.0.1', - summary: 'Logger for Rocket.Chat', - debugOnly: true + summary: 'Logger for Rocket.Chat' }); Package.onUse(function(api) { -- GitLab