From 82291d44535d74aae5da7ecb547d3ee8ef8baf31 Mon Sep 17 00:00:00 2001 From: RuslanTarasov Date: Fri, 18 Aug 2017 12:28:55 +0300 Subject: [PATCH] upgrade version from 9.1.0 to 9.1.1 --- build/install/deb/Files/god/conf.d/nginx.god | 5 +- ...-communityserver-common-init.conf.template | 43 ++ ...e-communityserver-common-ssl.conf.template | 120 ++++ ...ffice-communityserver-common.conf.template | 38 ++ ...office-communityserver-nginx.conf.template | 32 + .../deb/Files/tools/default-onlyoffice-ssl.sh | 49 ++ .../deb/Files/tools/default-onlyoffice.sh | 12 + build/install/deb/Files/tools/letsencrypt.sh | 25 + .../debian/onlyoffice-communityserver.install | 1 + build/install/deb/debian/postinst | 66 +- ...-communityserver-common-init.conf.template | 43 ++ ...e-communityserver-common-ssl.conf.template | 120 ++++ .../onlyoffice-communityserver-common.conf | 5 +- ...ffice-communityserver-common.conf.template | 38 ++ ...office-communityserver-nginx.conf.template | 32 + ...server-proxy-to-controlpanel.conf.template | 5 +- .../rpm/Files/tools/default-onlyoffice-ssl.sh | 49 ++ .../rpm/Files/tools/default-onlyoffice.sh | 12 + build/install/rpm/Files/tools/letsencrypt.sh | 25 + build/install/rpm/onlyoffice.spec | 7 +- .../Tasks/Modules/CrmModuleSpecifics.cs | 2 + .../ASC.Api.Mail/MailApi.MailService.cs | 92 ++- .../ASC.Api/ASC.Specific/ASC.Specific.csproj | 8 + .../CapabilitiesApi/CapabilitiesEntryPoint.cs | 36 +- .../GoogleDrive/GoogleDriveStorage.cs | 29 +- ...C.Mail.Aggregator.CollectionService.csproj | 1 + .../AggregatorService.cs | 50 +- .../Queue/Data/TaskData.cs | 18 + module/ASC.MessagingSystem/MessageAction.cs | 2 +- .../WhiteLabel/TenantInfoSettings.cs | 21 + .../WhiteLabel/TenantLogoManager.cs | 66 +- .../WhiteLabel/TenantWhiteLabelSettings.cs | 43 ++ web/studio/ASC.Web.Studio/About.aspx | 2 +- .../Core/Notify/NotifyConfiguration.cs | 75 ++- .../Products/Files/ASC.Web.Files.csproj | 11 - .../Controls/AccessRights/accessrights.js | 53 +- .../Controls/EmptyFolder/EmptyFolder.ascx | 2 +- .../Products/Files/Helpers/Global.cs | 2 - .../ClientScripts/FilesConstantsResources.cs | 2 - .../Resources/FilesCommonResource.Designer.cs | 18 - .../Files/Resources/FilesCommonResource.resx | 6 - .../Resources/FilesJSResource.Designer.cs | 30 +- .../Files/Resources/FilesJSResource.resx | 14 +- .../Resources/FilesUCResource.Designer.cs | 36 - .../Files/Resources/FilesUCResource.resx | 12 - .../FilesPatternResource.Designer.cs | 22 - .../NotifyService/FilesPatternResource.resx | 10 - .../Services/NotifyService/NotifyClient.cs | 26 - .../Services/NotifyService/NotifyConstants.cs | 2 - .../Services/NotifyService/NotifySource.cs | 3 +- .../Files/Services/NotifyService/patterns.xml | 16 - .../FileStorageServiceController.cs | 39 -- .../WCFService/IFileStorageService.cs | 2 - .../Products/Files/js/servicemanager.js | 6 - .../ASC.Web.Studio/Products/Files/js/ui.js | 5 +- .../Products/People/ASC.Web.People.csproj | 8 +- .../ProjectsTemplates/ListTasksTemplates.html | 22 +- .../Common/AuthorizeDocs/js/authorizedocs.js | 2 +- .../Common/AuthorizeDocs/js/reviews.json | 390 +++-------- .../Users/UserProfile/css/images/flags.png | Bin 4026 -> 6770 bytes .../Users/UserProfile/css/userlanguages.less | 1 + .../ASC.Web.Studio/Web.consumers.config | 4 + .../addons/calendar/ASC.Web.Calendar.csproj | 12 +- .../addons/mail/ASC.Web.Mail.csproj | 12 +- .../ASC.Web.Studio/addons/talk/Default.aspx | 2 +- .../talk/UserControls/ContactsContainer.ascx | 1 + .../talk/UserControls/RoomsContainer.ascx | 23 +- .../talk/UserControls/TabsContainerPart.ascx | 14 +- .../talk/css/default/imagescss/chatsmiles.png | Bin 786 -> 363 bytes .../talk/css/default/imagescss/groupchat.png | Bin 874 -> 309 bytes .../css/default/imagescss/groupchat_tab.png | Bin 0 -> 255 bytes .../talk/css/default/imagescss/logo-label.png | Bin 0 -> 826 bytes .../talk/css/default/imagescss/logo.png | Bin 0 -> 561 bytes .../talk/css/default/imagescss/mailing.png | Bin 0 -> 173 bytes .../talk/css/default/imagescss/search-msg.png | Bin 671 -> 321 bytes .../talk/css/default/imagescss/sendfile.png | Bin 757 -> 389 bytes .../talk/css/default/imagescss/settings.png | Bin 954 -> 322 bytes .../addons/talk/css/default/talk.style.css | 619 +++++++++++++----- .../addons/talk/js/talk.common.js | 105 +-- .../addons/talk/js/talk.contactscontainer.js | 251 ++++++- .../addons/talk/js/talk.default.js | 3 + .../addons/talk/js/talk.meseditorcontainer.js | 4 +- .../addons/talk/js/talk.navigationitem.js | 3 +- .../addons/talk/js/talk.roomscontainer.js | 13 +- .../addons/talk/js/talk.tabscontainer.js | 54 +- .../js/asc/plugins/jquery.tlcombobox.js | 12 - .../ASC.Web.Studio/web.appsettings.config | 2 +- 87 files changed, 2015 insertions(+), 1031 deletions(-) create mode 100644 build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-init.conf.template create mode 100644 build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template create mode 100644 build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common.conf.template create mode 100644 build/install/deb/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template create mode 100644 build/install/deb/Files/tools/default-onlyoffice-ssl.sh create mode 100644 build/install/deb/Files/tools/default-onlyoffice.sh create mode 100644 build/install/deb/Files/tools/letsencrypt.sh create mode 100644 build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common-init.conf.template create mode 100644 build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template create mode 100644 build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf.template create mode 100644 build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template create mode 100644 build/install/rpm/Files/tools/default-onlyoffice-ssl.sh create mode 100644 build/install/rpm/Files/tools/default-onlyoffice.sh create mode 100644 build/install/rpm/Files/tools/letsencrypt.sh create mode 100644 module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/Queue/Data/TaskData.cs create mode 100644 web/studio/ASC.Web.Studio/addons/talk/css/default/imagescss/groupchat_tab.png create mode 100644 web/studio/ASC.Web.Studio/addons/talk/css/default/imagescss/logo-label.png create mode 100644 web/studio/ASC.Web.Studio/addons/talk/css/default/imagescss/logo.png create mode 100644 web/studio/ASC.Web.Studio/addons/talk/css/default/imagescss/mailing.png diff --git a/build/install/deb/Files/god/conf.d/nginx.god b/build/install/deb/Files/god/conf.d/nginx.god index 0442f7490..c5c2fd2e4 100644 --- a/build/install/deb/Files/god/conf.d/nginx.god +++ b/build/install/deb/Files/god/conf.d/nginx.god @@ -7,11 +7,12 @@ God.watch do |w| w.restart = "/etc/init.d/nginx restart" w.pid_file = "/var/run/nginx.pid" w.behavior(:clean_pid_file) - + w.keepalive + w.start_if do |start| start.condition(:process_running) do |c| c.interval = 10.seconds c.running = false end end -end \ No newline at end of file +end diff --git a/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-init.conf.template b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-init.conf.template new file mode 100644 index 000000000..e713c3312 --- /dev/null +++ b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-init.conf.template @@ -0,0 +1,43 @@ +upstream fastcgi_backend { + server unix:/var/run/onlyoffice/onlyoffice.socket; + keepalive 32; +} + +server { + listen 80; + + fastcgi_keep_conn on; + fastcgi_index Default.aspx; + fastcgi_intercept_errors on; + + + include fastcgi_params; + + fastcgi_param HTTP_X_REWRITER_URL $http_x_rewriter_url; + fastcgi_param SERVER_NAME $host; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO ""; + + fastcgi_read_timeout 600; + fastcgi_send_timeout 600; + + + location / { + root /var/www/onlyoffice/WebStudio/; + expires 0; + add_header Cache-Control no-cache; + rewrite ^(.*)$ /StartConfigure.htm break; + } + + location /api { + fastcgi_pass fastcgi_backend; + break; + } + + location ~* ^/(warmup[2-9]?)/ { + rewrite /warmup([^/]*)/(.*) /$2 break; + fastcgi_pass unix:/var/run/onlyoffice/onlyoffice$1.socket; + } +} + + diff --git a/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template new file mode 100644 index 000000000..f422bc157 --- /dev/null +++ b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template @@ -0,0 +1,120 @@ +upstream fastcgi_backend_apisystem { + server unix:/var/run/onlyoffice/onlyofficeApiSystem.socket; + keepalive 32; +} + +upstream fastcgi_backend { + server unix:/var/run/onlyoffice/onlyoffice.socket; + keepalive {{ONLYOFFICE_NIGNX_KEEPLIVE}}; +} + +fastcgi_cache_path /var/cache/nginx/onlyoffice + levels=1:2 + keys_zone=onlyoffice:16m + max_size=256m + inactive=1d; + +geo $ip_external { + default 1; + {{DOCKER_ONLYOFFICE_SUBNET}} 0; + 127.0.0.1 0; +} + +map $http_host $this_host { + "" $host; + default $http_host; +} + +map $http_x_forwarded_proto $the_scheme { + default $http_x_forwarded_proto; + "" $scheme; +} + +map $http_x_forwarded_host $the_host { + default $http_x_forwarded_host; + "" $this_host; +} + +## Normal HTTP host +server { + listen 0.0.0.0:80; + listen [::]:80 default_server; + server_name _; + server_tokens off; + + root /nowhere; ## root doesn't have to be a valid path since we are redirecting + + location / { + if ($ip_external) { + ## Redirects all traffic to the HTTPS host + rewrite ^ https://$host$request_uri? permanent; + } + + + client_max_body_size 100m; + + proxy_pass https://127.0.0.1; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_ssl_verify off; + } +} + +## HTTPS host +server { + listen 0.0.0.0:443 ssl http2; + listen [::]:443 ssl http2 default_server; + server_tokens off; + root /usr/share/nginx/html; + + ## Increase this if you want to upload large attachments + client_max_body_size 100m; + + ## Strong SSL Security + ## https://cipherli.st/ + ssl on; + ssl_certificate {{SSL_CERTIFICATE_PATH}}; + ssl_certificate_key {{SSL_KEY_PATH}}; + ssl_verify_client {{SSL_VERIFY_CLIENT}}; + ssl_client_certificate {{CA_CERTIFICATES_PATH}}; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; + ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0 + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; # Requires nginx >= 1.5.9 + + add_header Strict-Transport-Security "max-age={{ONLYOFFICE_HTTPS_HSTS_MAXAGE}}; includeSubDomains; preload" always; +# add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Access-Control-Allow-Origin *; + + ## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL. + ## Replace with your ssl_trusted_certificate. For more info see: + ## - https://medium.com/devops-programming/4445f4862461 + ## - https://www.ruby-forum.com/topic/4419319 + ## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate {{SSL_OCSP_CERTIFICATE_PATH}}; + resolver 8.8.8.8 8.8.4.4 127.0.0.11 valid=300s; # Can change to your DNS resolver if desired + resolver_timeout 10s; + + ## [Optional] Generate a stronger DHE parameter: + ## cd /etc/ssl/certs + ## sudo openssl dhparam -out dhparam.pem 4096 + ## + ssl_dhparam {{SSL_DHPARAM_PATH}}; + + include /etc/nginx/includes/onlyoffice-communityserver-*.conf; +} + + + diff --git a/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common.conf.template b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common.conf.template new file mode 100644 index 000000000..c86174e1c --- /dev/null +++ b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-common.conf.template @@ -0,0 +1,38 @@ +upstream fastcgi_backend_apisystem { + server unix:/var/run/onlyoffice/onlyofficeApiSystem.socket; + keepalive 32; +} + +upstream fastcgi_backend { + server unix:/var/run/onlyoffice/onlyoffice.socket; + keepalive {{ONLYOFFICE_NIGNX_KEEPLIVE}}; +} + +fastcgi_cache_path /var/cache/nginx/onlyoffice + levels=1:2 + keys_zone=onlyoffice:16m + max_size=256m + inactive=1d; + +map $http_host $this_host { + "" $host; + default $http_host; +} + +map $http_x_forwarded_proto $the_scheme { + default $http_x_forwarded_proto; + "" $scheme; +} + +map $http_x_forwarded_host $the_host { + default $http_x_forwarded_host; + "" $this_host; +} + +server { + listen 80; + + add_header Access-Control-Allow-Origin *; + + include /etc/nginx/includes/onlyoffice-communityserver-*.conf; +} diff --git a/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template new file mode 100644 index 000000000..a61a6b92d --- /dev/null +++ b/build/install/deb/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template @@ -0,0 +1,32 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + include /etc/nginx/sites-enabled/*; + include /etc/nginx/conf.d/*.conf; +} + diff --git a/build/install/deb/Files/tools/default-onlyoffice-ssl.sh b/build/install/deb/Files/tools/default-onlyoffice-ssl.sh new file mode 100644 index 000000000..9078d91f1 --- /dev/null +++ b/build/install/deb/Files/tools/default-onlyoffice-ssl.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +if [ ! -f /var/www/onlyoffice/Data/certs/dhparam.pem ]; then + sudo openssl dhparam -out dhparam.pem 2048 + + mv dhparam.pem /var/www/onlyoffice/Data/certs/dhparam.pem; +fi + +DOCKER_ONLYOFFICE_SUBNET=$(ip -o -f inet addr show | awk '/scope global/ {print $4}'); + +cp /etc/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template default-onlyoffice-ssl.conf; + +SSL_CERTIFICATE_PATH="/var/www/onlyoffice/Data/certs/onlyoffice.crt" +SSL_KEY_PATH="/var/www/onlyoffice/Data/certs/onlyoffice.key" +ONLYOFFICE_SERVICES_DIR="/var/www/onlyoffice/Services" + +sed "s,{{SSL_CERTIFICATE_PATH}},${SSL_CERTIFICATE_PATH}," -i default-onlyoffice-ssl.conf; +sed "s,{{SSL_KEY_PATH}},${SSL_KEY_PATH}," -i default-onlyoffice-ssl.conf; +sed 's,{{SSL_DHPARAM_PATH}},/var/www/onlyoffice/Data/certs/dhparam.pem,' -i default-onlyoffice-ssl.conf; +sed 's,{{SSL_VERIFY_CLIENT}},off,' -i default-onlyoffice-ssl.conf; +sed '/{{CA_CERTIFICATES_PATH}}/d' -i default-onlyoffice-ssl.conf; +sed 's/{{ONLYOFFICE_HTTPS_HSTS_MAXAGE}}/63072000/' -i default-onlyoffice-ssl.conf; +sed 's,{{DOCKER_ONLYOFFICE_SUBNET}},'"${DOCKER_ONLYOFFICE_SUBNET}"',' -i default-onlyoffice-ssl.conf; +sed 's/{{ONLYOFFICE_NIGNX_KEEPLIVE}}/64/g' -i default-onlyoffice-ssl.conf; + +SSL_OCSP_CERTIFICATE_PATH="/var/www/onlyoffice/Data/certs/stapling.trusted.crt" + +# if dhparam path is valid, add to the config, otherwise remove the option +if [ -r "${SSL_OCSP_CERTIFICATE_PATH}" ]; then + sed 's,{{SSL_OCSP_CERTIFICATE_PATH}},'"${SSL_OCSP_CERTIFICATE_PATH}"',' -i default-onlyoffice-ssl.conf; +else + sed '/ssl_stapling/d' -i default-onlyoffice-ssl.conf; + sed '/ssl_stapling_verify/d' -i default-onlyoffice-ssl.conf; + sed '/ssl_trusted_certificate/d' -i default-onlyoffice-ssl.conf; + sed '/resolver/d' -i default-onlyoffice-ssl.conf; + sed '/resolver_timeout/d' -i default-onlyoffice-ssl.conf; +fi + +# sed '/certificate/s/\(value\s*=\s*\"\).*\"/\1${SSL_CERTIFICATE_PATH}"\"/' -i ${ONLYOFFICE_SERVICES_DIR}/TeamLabSvc/TeamLabSvc.exe.Config +# sed '/certificatePrivateKey/s/\(value\s*=\s*\"\).*\"/\1${SSL_KEY_PATH}"\"/' -i ${ONLYOFFICE_SERVICES_DIR}/TeamLabSvc/TeamLabSvc.exe.Config; +# sed '/startTls/s/\(value\s*=\s*\"\).*\"/\1optional"\"/' -i ${ONLYOFFICE_SERVICES_DIR}/TeamLabSvc/TeamLabSvc.exe.Config; + +sed '/mail\.default-api-scheme/s/\(value\s*=\s*\"\).*\"/\1https\"/' -i /var/www/onlyoffice/Services/MailAggregator/ASC.Mail.Aggregator.CollectionService.exe.config; + +mv default-onlyoffice-ssl.conf /etc/nginx/sites-enabled/onlyoffice + +service onlyofficeMailAggregator restart +# service onlyofficeJabber restart +service nginx reload diff --git a/build/install/deb/Files/tools/default-onlyoffice.sh b/build/install/deb/Files/tools/default-onlyoffice.sh new file mode 100644 index 000000000..e09d6b212 --- /dev/null +++ b/build/install/deb/Files/tools/default-onlyoffice.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +cp /etc/nginx/includes/onlyoffice-communityserver-common.conf.template default-onlyoffice.conf; + +sed 's/{{ONLYOFFICE_NIGNX_KEEPLIVE}}/64/g' -i default-onlyoffice.conf; +sed '/mail\.default-api-scheme/s/\(value\s*=\s*\"\).*\"/\1http\"/' -i /var/www/onlyoffice/Services/MailAggregator/ASC.Mail.Aggregator.CollectionService.exe.config; + +mv default-onlyoffice.conf /etc/nginx/sites-enabled/onlyoffice + +service onlyofficeMailAggregator restart +service nginx reload + diff --git a/build/install/deb/Files/tools/letsencrypt.sh b/build/install/deb/Files/tools/letsencrypt.sh new file mode 100644 index 000000000..ef6d0f3a9 --- /dev/null +++ b/build/install/deb/Files/tools/letsencrypt.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +_domains=""; + +for arg; do + _domains="$_domains -d $arg"; +done + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +certbot certonly --expand --webroot -w /var/www/onlyoffice/Data/certs --noninteractive --agree-tos --email support@$1 $_domains; + +cp /etc/letsencrypt/live/$1/fullchain.pem /var/www/onlyoffice/Data/certs/onlyoffice.crt +cp /etc/letsencrypt/live/$1/privkey.pem /var/www/onlyoffice/Data/certs/onlyoffice.key +cp /etc/letsencrypt/live/$1/chain.pem /var/www/onlyoffice/Data/certs/stapling.trusted.crt + +cat > /etc/cron.d/letsencrypt <> /var/log/le-renew.log +@weekly root cp /etc/letsencrypt/live/$1/fullchain.pem /var/www/onlyoffice/Data/certs/onlyoffice.crt +@weekly root cp /etc/letsencrypt/live/$1/privkey.pem /var/www/onlyoffice/Data/certs/onlyoffice.key +@weekly root cp /etc/letsencrypt/live/$1/chain.pem /var/www/onlyoffice/Data/certs/stapling.trusted.crt +@weekly root nginx reload +END + +source $DIR/default-onlyoffice-ssl.sh diff --git a/build/install/deb/debian/onlyoffice-communityserver.install b/build/install/deb/debian/onlyoffice-communityserver.install index 2aa4b71b7..8601685ae 100644 --- a/build/install/deb/debian/onlyoffice-communityserver.install +++ b/build/install/deb/debian/onlyoffice-communityserver.install @@ -5,5 +5,6 @@ Files/god/* etc/god/ Files/Services/* var/www/onlyoffice/Services/ Files/WebStudio/* var/www/onlyoffice/WebStudio/ Files/sql/* var/www/onlyoffice/Sql/ +Files/tools/* var/www/onlyoffice/Tools/ Files/licenses/* usr/share/doc/onlyoffice-communityserver/licenses/ Files/ApiSystem/* var/www/onlyoffice/ApiSystem/ diff --git a/build/install/deb/debian/postinst b/build/install/deb/debian/postinst index cfba7015f..982774e35 100644 --- a/build/install/deb/debian/postinst +++ b/build/install/deb/debian/postinst @@ -45,53 +45,69 @@ install_db(){ sed "s/#max_connections.*/max_connections = 1000/" -i /etc/mysql/my.cnf || true # ignore errors - if [ -e /etc/mysql/mysql.conf.d/mysqld.cnf ]; then - if ! grep -q "^sql_mode" /etc/mysql/mysql.conf.d/mysqld.cnf; then - sed "/\[mysqld\]/a sql_mode = 'NO_ENGINE_SUBSTITUTION'" -i /etc/mysql/mysql.conf.d/mysqld.cnf # disable new STRICT mode in mysql 5.7 + CNF_PATH="/etc/mysql/mysql.conf.d/mysqld.cnf"; + CNF_SERVICE_PATH="/lib/systemd/system/mysql.service"; + + if mysql -V | grep -q "MariaDB"; then + CNF_PATH="/etc/mysql/mariadb.conf.d/50-server.cnf"; + CNF_SERVICE_PATH="/lib/systemd/system/mariadb.service"; + fi + + + if [ -e ${CNF_PATH} ]; then + if ! grep -q "^sql_mode" ${CNF_PATH}; then + sed "/\[mysqld\]/a sql_mode = 'NO_ENGINE_SUBSTITUTION'" -i ${CNF_PATH} # disable new STRICT mode in mysql 5.7 else - sed "s/sql_mode.*/sql_mode = 'NO_ENGINE_SUBSTITUTION'/" -i /etc/mysql/mysql.conf.d/mysqld.cnf || true # ignore errors + sed "s/sql_mode.*/sql_mode = 'NO_ENGINE_SUBSTITUTION'/" -i ${CNF_PATH} || true # ignore errors fi - if ! grep -q "^max_connections" /etc/mysql/mysql.conf.d/mysqld.cnf; then - sed '/\[mysqld\]/a max_connections = 1000' -i /etc/mysql/mysql.conf.d/mysqld.cnf + if ! grep -q "^max_connections" ${CNF_PATH}; then + sed '/\[mysqld\]/a max_connections = 1000' -i ${CNF_PATH} else - sed "s/max_connections.*/max_connections = 1000/" -i /etc/mysql/mysql.conf.d/mysqld.cnf || true # ignore errors + sed "s/max_connections.*/max_connections = 1000/" -i ${CNF_PATH} || true # ignore errors fi - if ! grep -q "^max_allowed_packet" /etc/mysql/mysql.conf.d/mysqld.cnf; then - sed '/\[mysqld\]/a max_allowed_packet = 1048576000' -i /etc/mysql/mysql.conf.d/mysqld.cnf + if ! grep -q "^max_allowed_packet" ${CNF_PATH}; then + sed '/\[mysqld\]/a max_allowed_packet = 1048576000' -i ${CNF_PATH} else - sed "s/max_allowed_packet.*/max_allowed_packet = 1048576000/" -i /etc/mysql/mysql.conf.d/mysqld.cnf || true # ignore errors + sed "s/max_allowed_packet.*/max_allowed_packet = 1048576000/" -i ${CNF_PATH} || true # ignore errors fi - if [ -e /lib/systemd/system/mysql.service ]; then - if ! grep -q "^LimitNOFILE" /lib/systemd/system/mysql.service; then - sed '/\[Service\]/a LimitNOFILE = infinity' -i /lib/systemd/system/mysql.service + if [ -e ${CNF_SERVICE_PATH} ]; then + if ! grep -q "^LimitNOFILE" ${CNF_SERVICE_PATH}; then + sed '/\[Service\]/a LimitNOFILE = infinity' -i ${CNF_SERVICE_PATH} else - sed "s/LimitNOFILE.*/LimitNOFILE = infinity/" -i /lib/systemd/system/mysql.service || true # ignore errors + sed "s/LimitNOFILE.*/LimitNOFILE = infinity/" -i ${CNF_SERVICE_PATH} || true # ignore errors fi - if ! grep -q "^LimitMEMLOCK" /lib/systemd/system/mysql.service; then - sed '/\[Service\]/a LimitMEMLOCK = infinity' -i /lib/systemd/system/mysql.service + if ! grep -q "^LimitMEMLOCK" ${CNF_SERVICE_PATH}; then + sed '/\[Service\]/a LimitMEMLOCK = infinity' -i ${CNF_SERVICE_PATH} else - sed "s/LimitMEMLOCK.*/LimitMEMLOCK = infinity/" -i /lib/systemd/system/mysql.service || true # ignore errors + sed "s/LimitMEMLOCK.*/LimitMEMLOCK = infinity/" -i ${CNF_SERVICE_PATH} || true # ignore errors fi systemctl daemon-reload fi + fi - service mysql restart - - if [ -z "$DB_PWD" ] && [ "$DB_USER" = "root" ]; then - # allow MySql.Data.dll connect via mysql_native_password with root and empty password - $MYSQL -D "mysql" -e "update user set plugin='mysql_native_password' where user='root';" - fi + $MYSQL -e ";" >/dev/null 2>&1 || ( service mysql start >/dev/null 2>&1 && $MYSQL -e ";" >/dev/null ) + if [ "${DB_USER}" = "root" ]; then + # allow MySql.Data.dll connect via mysql_native_password with root and empty password + $MYSQL -D "mysql" -e "UPDATE user SET plugin='mysql_native_password' WHERE user='${DB_USER}' and host='localhost';" fi - # test mysql connection - $MYSQL -e ";" &>/dev/null || ( service mysql start &>/dev/null && $MYSQL -e ";" >/dev/null ) + service mysql restart + + # hack for Debian 9 (mariadb) + if [ -n "${DB_PWD}" ] && [ "${DB_USER}" = "root" ] && mysql -e ";" >/dev/null 2>&1; then + +mysql <= 1.1.0 + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; # Requires nginx >= 1.5.9 + + add_header Strict-Transport-Security "max-age={{ONLYOFFICE_HTTPS_HSTS_MAXAGE}}; includeSubDomains; preload" always; +# add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header Access-Control-Allow-Origin *; + + ## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL. + ## Replace with your ssl_trusted_certificate. For more info see: + ## - https://medium.com/devops-programming/4445f4862461 + ## - https://www.ruby-forum.com/topic/4419319 + ## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate {{SSL_OCSP_CERTIFICATE_PATH}}; + resolver 8.8.8.8 8.8.4.4 127.0.0.11 valid=300s; # Can change to your DNS resolver if desired + resolver_timeout 10s; + + ## [Optional] Generate a stronger DHE parameter: + ## cd /etc/ssl/certs + ## sudo openssl dhparam -out dhparam.pem 4096 + ## + ssl_dhparam {{SSL_DHPARAM_PATH}}; + + include /etc/nginx/includes/onlyoffice-communityserver-*.conf; +} + + + diff --git a/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf index 8f2fb70d8..3bf2f1e1b 100644 --- a/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf +++ b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf @@ -43,6 +43,7 @@ location / { fastcgi_pass unix:/var/run/onlyoffice/onlyoffice$1.socket; } + location ~* (^\/(?:skins|products|addons).*\.(?:jpg|jpeg|gif|png|svg|ico)$)|(.*bundle/(?!clientscript).*) { fastcgi_pass fastcgi_backend; @@ -97,7 +98,7 @@ location /apisystem { } location /filesData { - rewrite /filesData(.*) /$1 break; - root /; + rewrite /filesData/var/www/onlyoffice/Data/Products/Files(.*) /$1 break; + root /var/www/onlyoffice/Data/Products/Files; internal; } diff --git a/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf.template b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf.template new file mode 100644 index 000000000..c86174e1c --- /dev/null +++ b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-common.conf.template @@ -0,0 +1,38 @@ +upstream fastcgi_backend_apisystem { + server unix:/var/run/onlyoffice/onlyofficeApiSystem.socket; + keepalive 32; +} + +upstream fastcgi_backend { + server unix:/var/run/onlyoffice/onlyoffice.socket; + keepalive {{ONLYOFFICE_NIGNX_KEEPLIVE}}; +} + +fastcgi_cache_path /var/cache/nginx/onlyoffice + levels=1:2 + keys_zone=onlyoffice:16m + max_size=256m + inactive=1d; + +map $http_host $this_host { + "" $host; + default $http_host; +} + +map $http_x_forwarded_proto $the_scheme { + default $http_x_forwarded_proto; + "" $scheme; +} + +map $http_x_forwarded_host $the_host { + default $http_x_forwarded_host; + "" $this_host; +} + +server { + listen 80; + + add_header Access-Control-Allow-Origin *; + + include /etc/nginx/includes/onlyoffice-communityserver-*.conf; +} diff --git a/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template new file mode 100644 index 000000000..a61a6b92d --- /dev/null +++ b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-nginx.conf.template @@ -0,0 +1,32 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + include /etc/nginx/sites-enabled/*; + include /etc/nginx/conf.d/*.conf; +} + diff --git a/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-proxy-to-controlpanel.conf.template b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-proxy-to-controlpanel.conf.template index 6279a9428..4cf7da5e5 100644 --- a/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-proxy-to-controlpanel.conf.template +++ b/build/install/rpm/Files/nginx/includes/onlyoffice-communityserver-proxy-to-controlpanel.conf.template @@ -16,7 +16,7 @@ location /controlpanel { } location /sso/ { - proxy_pass http://{{SERVICE_SSO_AUTH_HOST_ADDR}}:9834; + proxy_pass http://{{SERVICE_SSO_AUTH_HOST_ADDR}}:9834; client_max_body_size 100m; @@ -30,6 +30,7 @@ location /sso/ { proxy_set_header X-Forwarded-Host $server_name; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-REWRITER-URL $scheme://$http_host; - + proxy_redirect / /; + } diff --git a/build/install/rpm/Files/tools/default-onlyoffice-ssl.sh b/build/install/rpm/Files/tools/default-onlyoffice-ssl.sh new file mode 100644 index 000000000..9078d91f1 --- /dev/null +++ b/build/install/rpm/Files/tools/default-onlyoffice-ssl.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +if [ ! -f /var/www/onlyoffice/Data/certs/dhparam.pem ]; then + sudo openssl dhparam -out dhparam.pem 2048 + + mv dhparam.pem /var/www/onlyoffice/Data/certs/dhparam.pem; +fi + +DOCKER_ONLYOFFICE_SUBNET=$(ip -o -f inet addr show | awk '/scope global/ {print $4}'); + +cp /etc/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template default-onlyoffice-ssl.conf; + +SSL_CERTIFICATE_PATH="/var/www/onlyoffice/Data/certs/onlyoffice.crt" +SSL_KEY_PATH="/var/www/onlyoffice/Data/certs/onlyoffice.key" +ONLYOFFICE_SERVICES_DIR="/var/www/onlyoffice/Services" + +sed "s,{{SSL_CERTIFICATE_PATH}},${SSL_CERTIFICATE_PATH}," -i default-onlyoffice-ssl.conf; +sed "s,{{SSL_KEY_PATH}},${SSL_KEY_PATH}," -i default-onlyoffice-ssl.conf; +sed 's,{{SSL_DHPARAM_PATH}},/var/www/onlyoffice/Data/certs/dhparam.pem,' -i default-onlyoffice-ssl.conf; +sed 's,{{SSL_VERIFY_CLIENT}},off,' -i default-onlyoffice-ssl.conf; +sed '/{{CA_CERTIFICATES_PATH}}/d' -i default-onlyoffice-ssl.conf; +sed 's/{{ONLYOFFICE_HTTPS_HSTS_MAXAGE}}/63072000/' -i default-onlyoffice-ssl.conf; +sed 's,{{DOCKER_ONLYOFFICE_SUBNET}},'"${DOCKER_ONLYOFFICE_SUBNET}"',' -i default-onlyoffice-ssl.conf; +sed 's/{{ONLYOFFICE_NIGNX_KEEPLIVE}}/64/g' -i default-onlyoffice-ssl.conf; + +SSL_OCSP_CERTIFICATE_PATH="/var/www/onlyoffice/Data/certs/stapling.trusted.crt" + +# if dhparam path is valid, add to the config, otherwise remove the option +if [ -r "${SSL_OCSP_CERTIFICATE_PATH}" ]; then + sed 's,{{SSL_OCSP_CERTIFICATE_PATH}},'"${SSL_OCSP_CERTIFICATE_PATH}"',' -i default-onlyoffice-ssl.conf; +else + sed '/ssl_stapling/d' -i default-onlyoffice-ssl.conf; + sed '/ssl_stapling_verify/d' -i default-onlyoffice-ssl.conf; + sed '/ssl_trusted_certificate/d' -i default-onlyoffice-ssl.conf; + sed '/resolver/d' -i default-onlyoffice-ssl.conf; + sed '/resolver_timeout/d' -i default-onlyoffice-ssl.conf; +fi + +# sed '/certificate/s/\(value\s*=\s*\"\).*\"/\1${SSL_CERTIFICATE_PATH}"\"/' -i ${ONLYOFFICE_SERVICES_DIR}/TeamLabSvc/TeamLabSvc.exe.Config +# sed '/certificatePrivateKey/s/\(value\s*=\s*\"\).*\"/\1${SSL_KEY_PATH}"\"/' -i ${ONLYOFFICE_SERVICES_DIR}/TeamLabSvc/TeamLabSvc.exe.Config; +# sed '/startTls/s/\(value\s*=\s*\"\).*\"/\1optional"\"/' -i ${ONLYOFFICE_SERVICES_DIR}/TeamLabSvc/TeamLabSvc.exe.Config; + +sed '/mail\.default-api-scheme/s/\(value\s*=\s*\"\).*\"/\1https\"/' -i /var/www/onlyoffice/Services/MailAggregator/ASC.Mail.Aggregator.CollectionService.exe.config; + +mv default-onlyoffice-ssl.conf /etc/nginx/sites-enabled/onlyoffice + +service onlyofficeMailAggregator restart +# service onlyofficeJabber restart +service nginx reload diff --git a/build/install/rpm/Files/tools/default-onlyoffice.sh b/build/install/rpm/Files/tools/default-onlyoffice.sh new file mode 100644 index 000000000..e09d6b212 --- /dev/null +++ b/build/install/rpm/Files/tools/default-onlyoffice.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +cp /etc/nginx/includes/onlyoffice-communityserver-common.conf.template default-onlyoffice.conf; + +sed 's/{{ONLYOFFICE_NIGNX_KEEPLIVE}}/64/g' -i default-onlyoffice.conf; +sed '/mail\.default-api-scheme/s/\(value\s*=\s*\"\).*\"/\1http\"/' -i /var/www/onlyoffice/Services/MailAggregator/ASC.Mail.Aggregator.CollectionService.exe.config; + +mv default-onlyoffice.conf /etc/nginx/sites-enabled/onlyoffice + +service onlyofficeMailAggregator restart +service nginx reload + diff --git a/build/install/rpm/Files/tools/letsencrypt.sh b/build/install/rpm/Files/tools/letsencrypt.sh new file mode 100644 index 000000000..ef6d0f3a9 --- /dev/null +++ b/build/install/rpm/Files/tools/letsencrypt.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +_domains=""; + +for arg; do + _domains="$_domains -d $arg"; +done + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +certbot certonly --expand --webroot -w /var/www/onlyoffice/Data/certs --noninteractive --agree-tos --email support@$1 $_domains; + +cp /etc/letsencrypt/live/$1/fullchain.pem /var/www/onlyoffice/Data/certs/onlyoffice.crt +cp /etc/letsencrypt/live/$1/privkey.pem /var/www/onlyoffice/Data/certs/onlyoffice.key +cp /etc/letsencrypt/live/$1/chain.pem /var/www/onlyoffice/Data/certs/stapling.trusted.crt + +cat > /etc/cron.d/letsencrypt <> /var/log/le-renew.log +@weekly root cp /etc/letsencrypt/live/$1/fullchain.pem /var/www/onlyoffice/Data/certs/onlyoffice.crt +@weekly root cp /etc/letsencrypt/live/$1/privkey.pem /var/www/onlyoffice/Data/certs/onlyoffice.key +@weekly root cp /etc/letsencrypt/live/$1/chain.pem /var/www/onlyoffice/Data/certs/stapling.trusted.crt +@weekly root nginx reload +END + +source $DIR/default-onlyoffice-ssl.sh diff --git a/build/install/rpm/onlyoffice.spec b/build/install/rpm/onlyoffice.spec index 834968241..920755642 100644 --- a/build/install/rpm/onlyoffice.spec +++ b/build/install/rpm/onlyoffice.spec @@ -24,9 +24,11 @@ rm -rf "$RPM_BUILD_ROOT" %install #install onlyoffice files mkdir -p "$RPM_BUILD_ROOT/var/www/onlyoffice/" +mkdir -p "$RPM_BUILD_ROOT/var/www/onlyoffice/Tools/" mkdir -p "$RPM_BUILD_ROOT/usr/bin/" cp -r ../../Files/bin/*.sh "$RPM_BUILD_ROOT/usr/bin/" cp -r ../../Files/onlyoffice/. "$RPM_BUILD_ROOT/var/www/onlyoffice/" +cp -r ../../Files/tools/. "$RPM_BUILD_ROOT/var/www/onlyoffice/Tools/" mkdir -p "$RPM_BUILD_ROOT/var/log/onlyoffice/" #install init scripts @@ -80,10 +82,13 @@ rm -rf "$RPM_BUILD_ROOT" %config %attr(-, root, root) /usr/lib/systemd/system/*.service %config %attr(-, root, root) /etc/nginx/conf.d/onlyoffice.conf %config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-common.conf +%config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-common.conf.template +%config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-common-init.conf.template +%config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-common-ssl.conf.template +%config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-nginx.conf.template %config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-services.conf %config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-letsencrypt.conf %config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-proxy-to-controlpanel.conf.template -%config %attr(-, root, root) /etc/nginx/includes/onlyoffice-ssl.template %config %attr(-, root, root) /etc/nginx/includes/onlyoffice-communityserver-proxy-to-documentserver.conf.template %config %attr(-, root, root) /etc/hyperfastcgi/onlyoffice %config %attr(-, root, root) /etc/hyperfastcgi/onlyofficeApiSystem diff --git a/common/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs b/common/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs index 53b67aea6..a75365aa5 100644 --- a/common/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs +++ b/common/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs @@ -329,6 +329,8 @@ public override IEnumerable TableRelations protected override bool TryPrepareValue(IDbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value) { + if (value == null) return false; + if (table.Name == "crm_invoice" && columnName == "json_data") { var data = JObject.Parse((string)value); diff --git a/module/ASC.Api/ASC.Api.Mail/MailApi.MailService.cs b/module/ASC.Api/ASC.Api.Mail/MailApi.MailService.cs index d87424b0f..627dab763 100644 --- a/module/ASC.Api/ASC.Api.Mail/MailApi.MailService.cs +++ b/module/ASC.Api/ASC.Api.Mail/MailApi.MailService.cs @@ -54,15 +54,15 @@ public object ConnectMailServer(string ip, string user, string password) if (string.IsNullOrEmpty(ip)) throw new ArgumentException("ip"); - if (!PingHost(ip, 3306)) - throw new Exception(string.Format(Resource.MailServicePingErrorMsg, ip)); - if (string.IsNullOrEmpty(user)) throw new ArgumentException("user"); if (string.IsNullOrEmpty(password)) throw new ArgumentException("password"); + if (!PingHost(ip, 3306)) + throw new Exception(string.Format(Resource.MailServicePingErrorMsg, ip)); + var connectionString = string.Format(MailServiceHelper.ConnectionStringFormat, ip, MailServiceHelper.DefaultDatabase, user, password); var data = GetAuthData(connectionString, ip); @@ -142,27 +142,20 @@ public object ConnectAndSaveMailServerInfo(string host, string user, string pass if (string.IsNullOrEmpty(host)) throw new ArgumentException("host"); - var ipList = new DnsLookup().GetDomainIPs(host).ToList(); + if (string.IsNullOrEmpty(user)) + throw new ArgumentException("user"); - if (!ipList.Any()) - throw new Exception("could not get host ip"); + if (string.IsNullOrEmpty(password)) + throw new ArgumentException("password"); - var firstIpItem = ipList.FirstOrDefault(); + var ip = GetHostIp(host); - if (firstIpItem == null) + if (string.IsNullOrEmpty(ip)) throw new Exception("could not get host ip"); - var ip = firstIpItem.ToString(); - if (!PingHost(ip, 3306)) throw new Exception(string.Format(Resource.MailServicePingErrorMsg, ip)); - if (string.IsNullOrEmpty(user)) - throw new ArgumentException("user"); - - if (string.IsNullOrEmpty(password)) - throw new ArgumentException("password"); - var connectionString = string.Format(MailServiceHelper.ConnectionStringFormat, ip, MailServiceHelper.DefaultDatabase, user, password); var data = GetAuthData(connectionString, ip); @@ -187,6 +180,60 @@ public object ConnectAndSaveMailServerInfo(string host, string user, string pass } } + /// false + [Create("mailservice/connectandsavepartitional")] + public object ConnectAndSavePartitionalMailServerInfo(string mailHost, string mysqlHost, string mysqlUser, string mysqlPassword) + { + try + { + if (string.IsNullOrEmpty(mailHost)) + throw new ArgumentException("mailHost"); + + if (string.IsNullOrEmpty(mysqlHost)) + throw new ArgumentException("mysqlHost"); + + if (string.IsNullOrEmpty(mysqlUser)) + throw new ArgumentException("mysqlUser"); + + if (string.IsNullOrEmpty(mysqlPassword)) + throw new ArgumentException("mysqlPassword"); + + var mailIp = GetHostIp(mailHost); + + if (string.IsNullOrEmpty(mailIp)) + throw new Exception("could not get mailHost ip"); + + var mysqlIp = GetHostIp(mysqlHost); + + if (string.IsNullOrEmpty(mysqlIp)) + throw new Exception("could not get mysqlHost ip"); + + if (!PingHost(mysqlIp, 3306)) + throw new Exception(string.Format(Resource.MailServicePingErrorMsg, mysqlIp)); + + var connectionString = string.Format(MailServiceHelper.ConnectionStringFormat, mysqlIp, MailServiceHelper.DefaultDatabase, mysqlUser, mysqlPassword); + + var data = GetAuthData(connectionString, mailIp); + + Save(connectionString, mailIp, data[0], data[1]); + + return new + { + status = "success", + message = Resource.MailServiceSaveSuccessMsg + }; + } + catch (Exception exception) + { + Logger.Error(exception.Message, exception); + + return new + { + status = "error", + message = exception.Message.HtmlEncode() + }; + } + } private static bool PingHost(string host, int port) { @@ -201,6 +248,19 @@ private static bool PingHost(string host, int port) } } + private static string GetHostIp(string host) + { + try + { + var ip = new DnsLookup().GetDomainIPs(host).FirstOrDefault(); + return ip == null ? null : ip.ToString(); + } + catch (Exception) + { + return null; + } + } + private static string[] GetAuthData(string connectionString, string ip) { var data = MailServiceHelper.GetDataFromExternalDatabase(MailServiceHelper.MailServiceDbId, connectionString, ip); diff --git a/module/ASC.Api/ASC.Specific/ASC.Specific.csproj b/module/ASC.Api/ASC.Specific/ASC.Specific.csproj index f7d66b435..d87ea9fc2 100644 --- a/module/ASC.Api/ASC.Specific/ASC.Specific.csproj +++ b/module/ASC.Api/ASC.Specific/ASC.Specific.csproj @@ -91,6 +91,10 @@ + + {e588e818-f163-470c-802c-3a6e45b36080} + ASC.ActiveDirectory + {76de7717-3d4b-4a5b-b740-15b8913df0cb} ASC.Common @@ -105,6 +109,10 @@ {2FF2177F-2D1A-4396-84EB-51F14FD99385} ASC.IPSecurity + + {ef3ae6b9-4503-42a3-88bc-c622e178a59e} + ASC.SingleSignOn + {02c40a64-fe22-41d0-9037-69f0d6f787a9} ASC.Web.Core diff --git a/module/ASC.Api/ASC.Specific/CapabilitiesApi/CapabilitiesEntryPoint.cs b/module/ASC.Api/ASC.Specific/CapabilitiesApi/CapabilitiesEntryPoint.cs index 6d5ed7c1d..2061647be 100644 --- a/module/ASC.Api/ASC.Specific/CapabilitiesApi/CapabilitiesEntryPoint.cs +++ b/module/ASC.Api/ASC.Specific/CapabilitiesApi/CapabilitiesEntryPoint.cs @@ -27,10 +27,13 @@ using System; using System.Configuration; using System.Web; +using ASC.ActiveDirectory; using ASC.Api.Attributes; using ASC.Api.Impl; using ASC.Api.Interfaces; using ASC.Core; +using ASC.Core.Common.Settings; +using ASC.SingleSignOn.Common; using ASC.Web.Studio.Core; using ASC.Web.Studio.Utility; using log4net; @@ -70,21 +73,38 @@ public CapabilitiesData GetPortalCapabilities() { try { - var ldapEnabled = false; + bool ldapEnabled; - if (SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString())) + if (!SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString()) || + (CoreContext.Configuration.Standalone && + !CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Ldap)) { - ldapEnabled = !CoreContext.Configuration.Standalone || - CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Ldap; + ldapEnabled = false; + } + else + { + var settings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + + ldapEnabled = settings.EnableLdapAuthentication; } - var ssoUrl = string.Empty; + string ssoUrl; - if (SetupInfo.IsVisibleSettings(ManagementType.SingleSignOnSettings.ToString())) + if (!SetupInfo.IsVisibleSettings(ManagementType.SingleSignOnSettings.ToString()) || + (CoreContext.Configuration.Standalone && + !CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Sso)) { - var ssoEnabled = !CoreContext.Configuration.Standalone || CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Sso; + ssoUrl = string.Empty; + } + else + { + var settings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - if (ssoEnabled) + if (!settings.EnableSso) + { + ssoUrl = string.Empty; + } + else { var uri = HttpContext.Current.Request.GetUrlRewriter(); diff --git a/module/ASC.Files.Thirdparty/GoogleDrive/GoogleDriveStorage.cs b/module/ASC.Files.Thirdparty/GoogleDrive/GoogleDriveStorage.cs index 7975a6beb..275c10d78 100644 --- a/module/ASC.Files.Thirdparty/GoogleDrive/GoogleDriveStorage.cs +++ b/module/ASC.Files.Thirdparty/GoogleDrive/GoogleDriveStorage.cs @@ -204,25 +204,22 @@ public Stream DownloadStream(DriveFile file) request.Method = "GET"; request.Headers.Add("Authorization", "Bearer " + AccessToken); - using (var response = (HttpWebResponse)request.GetResponse()) + var response = (HttpWebResponse)request.GetResponse(); + + if (file.Size.HasValue && file.Size > 0) { - if (file.Size.HasValue && file.Size > 0) - { - return new ResponseStream(response.GetResponseStream(), file.Size.Value); - } + return new ResponseStream(response.GetResponseStream(), file.Size.Value); + } - var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); - using (var str = response.GetResponseStream()) - { - if (str != null) - { - str.CopyTo(tempBuffer); - tempBuffer.Flush(); - tempBuffer.Seek(0, SeekOrigin.Begin); - } - } - return tempBuffer; + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + var str = response.GetResponseStream(); + if (str != null) + { + str.CopyTo(tempBuffer); + tempBuffer.Flush(); + tempBuffer.Seek(0, SeekOrigin.Begin); } + return tempBuffer; } public DriveFile InsertEntry(Stream fileStream, string title, string parentId, bool folder = false) diff --git a/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/ASC.Mail.Aggregator.CollectionService.csproj b/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/ASC.Mail.Aggregator.CollectionService.csproj index 1dc4d3aa5..fc3f7210d 100644 --- a/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/ASC.Mail.Aggregator.CollectionService.csproj +++ b/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/ASC.Mail.Aggregator.CollectionService.csproj @@ -166,6 +166,7 @@ + diff --git a/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/AggregatorService.cs b/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/AggregatorService.cs index d5402f071..11d789767 100644 --- a/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/AggregatorService.cs +++ b/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/AggregatorService.cs @@ -38,11 +38,11 @@ using System.Threading.Tasks; using ASC.Core; using ASC.Mail.Aggregator.CollectionService.Queue; +using ASC.Mail.Aggregator.CollectionService.Queue.Data; using ASC.Mail.Aggregator.Common; using ASC.Mail.Aggregator.Common.Clients; using ASC.Mail.Aggregator.Common.Extension; using ASC.Mail.Aggregator.Common.Logging; -using DotNetOpenAuth.Messaging; using MailKit.Security; using ASC.Mail.Aggregator.Common.DataStorage; using ASC.Mail.Aggregator.Common.Utils; @@ -52,7 +52,6 @@ using MailKit.Net.Pop3; using MimeKit; using MySql.Data.MySqlClient; -using TimeoutException = System.TimeoutException; namespace ASC.Mail.Aggregator.CollectionService { @@ -307,7 +306,7 @@ private void workTimer_Elapsed(object state) while (tasks.Any()) { // Identify the first task that completes. - var indexTask = Task.WaitAny(tasks.ToArray(), (int)_tsTaskStateCheckInterval.TotalMilliseconds, cancelToken); + var indexTask = Task.WaitAny(tasks.Select(t => t.Task).ToArray(), (int)_tsTaskStateCheckInterval.TotalMilliseconds, cancelToken); if (indexTask > -1) { // ***Remove the selected task from the list so that you don't @@ -323,20 +322,20 @@ private void workTimer_Elapsed(object state) tasks.Select( t => string.Format("Id: {0} Status: {1}, MailboxId: {2} Address: '{3}'", - t.Id, t.Status, t.Result.MailBoxId, t.Result.EMail)))); + t.Task.Id, t.Task.Status, t.Mailbox.MailBoxId, t.Mailbox.EMail)))); } var tasks2Free = tasks.Where( t => - t.Status == TaskStatus.Canceled || t.Status == TaskStatus.Faulted || - t.Status == TaskStatus.RanToCompletion).ToList(); + t.Task.Status == TaskStatus.Canceled || t.Task.Status == TaskStatus.Faulted || + t.Task.Status == TaskStatus.RanToCompletion).ToList(); if (tasks2Free.Any()) { _log.Info("Need free next tasks = {0}: ({1})", tasks2Free.Count, string.Join(",", - tasks2Free.Select(t => t.Id.ToString(CultureInfo.InvariantCulture)))); + tasks2Free.Select(t => t.Task.Id.ToString(CultureInfo.InvariantCulture)))); tasks2Free.ForEach(task => FreeTask(task, tasks)); } @@ -350,7 +349,7 @@ private void workTimer_Elapsed(object state) tasks.AddRange(newTasks); _log.Info("Total tasks count = {0} ({1}).", tasks.Count, - string.Join(",", tasks.Select(t => t.Id))); + string.Join(",", tasks.Select(t => t.Task.Id))); } _log.Info("All mailboxes were processed. Go back to timer."); @@ -428,13 +427,13 @@ private void NotifySignalrIfNeed(MailBox mailbox, ILogger log) } } - private List> CreateTasks(int needCount, CancellationToken cancelToken) + private List CreateTasks(int needCount, CancellationToken cancelToken) { _log.Info("CreateTasks(need {0} tasks).", needCount); var mailboxes = _queueManager.GetLockedMailboxes(needCount); - var tasks = new List>(); + var tasks = new List(); foreach (var mailbox in mailboxes) { @@ -458,7 +457,7 @@ private List> CreateTasks(int needCount, CancellationToken cancelT var task = _taskFactory.StartNew(() => ProcessMailbox(client, _tasksConfig), commonCancelToken); - tasks.Add(task); + tasks.Add(new TaskData(mailbox, task)); } if (tasks.Any()) @@ -502,7 +501,7 @@ private MailClient CreateMailClient(MailBox mailbox, ILogger log, CancellationTo client.LoginImapPop(); } - catch (TimeoutException exTimeout) + catch (System.TimeoutException exTimeout) { log.Warn( "[TIMEOUT] CreateTasks->client.LoginImapPop(Tenant = {0}, MailboxId = {1}, Address = '{2}') Exception: {3}", @@ -604,7 +603,7 @@ private void CloseMailClient(MailClient client, MailBox mailbox, ILogger log) } } - private MailBox ProcessMailbox(MailClient client, TasksConfig tasksConfig) + private void ProcessMailbox(MailClient client, TasksConfig tasksConfig) { var mailbox = client.Account; @@ -698,8 +697,6 @@ private MailBox ProcessMailbox(MailClient client, TasksConfig tasksConfig) } taskLogger.Info("Mailbox '{0}' has been processed.", mailbox.EMail); - - return mailbox; } private void ClientOnAuthenticated(object sender, MailClientEventArgs mailClientEventArgs) @@ -1089,7 +1086,7 @@ public string StoreMailEml(int tenant, string user, string streamId, MimeMessage return string.Empty; } - private bool TryStoreMailData(MailMessage message, MailBox mailbox, ILogger log) + private static bool TryStoreMailData(MailMessage message, MailBox mailbox, ILogger log) { var manager = new MailBoxManager(log); @@ -1129,18 +1126,25 @@ private bool TryStoreMailData(MailMessage message, MailBox mailbox, ILogger log) return true; } - private void FreeTask(Task task, ICollection> tasks) + private void FreeTask(TaskData taskData, ICollection tasks) { - _log.Debug("End Task {0} with status = '{1}'.", task.Id, task.Status); + try + { + _log.Debug("End Task {0} with status = '{1}'.", taskData.Task.Id, taskData.Task.Status); - if (!tasks.Remove(task)) - _log.Error("Task not exists in tasks array."); + if (!tasks.Remove(taskData)) + _log.Error("Task not exists in tasks array."); - var mailbox = task.Result; + var mailbox = taskData.Mailbox; - ReleaseMailbox(mailbox); + ReleaseMailbox(mailbox); - task.Dispose(); + taskData.Task.Dispose(); + } + catch (Exception ex) + { + _log.Error("FreeTask(id:'{0}', email:'{1}'): Exception:\r\n{2}\r\n", taskData.Mailbox.MailBoxId, taskData.Mailbox.EMail, ex.ToString()); + } } private void ReleaseMailbox(MailBox mailbox) diff --git a/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/Queue/Data/TaskData.cs b/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/Queue/Data/TaskData.cs new file mode 100644 index 000000000..912fed9b7 --- /dev/null +++ b/module/ASC.Mail.Aggregator/ASC.Mail.Aggregator.CollectionService/Queue/Data/TaskData.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using ASC.Mail.Aggregator.Common; + +namespace ASC.Mail.Aggregator.CollectionService.Queue.Data +{ + public class TaskData + { + public TaskData(MailBox mailBox, Task task) + { + Mailbox = mailBox; + Task = task; + } + + public MailBox Mailbox { get; private set; } + + public Task Task { get; private set; } + } +} diff --git a/module/ASC.MessagingSystem/MessageAction.cs b/module/ASC.MessagingSystem/MessageAction.cs index 627d97050..6105bae56 100644 --- a/module/ASC.MessagingSystem/MessageAction.cs +++ b/module/ASC.MessagingSystem/MessageAction.cs @@ -380,7 +380,7 @@ public enum MessageAction FileLocked = 5006, FileUnlocked = 5007, FileUpdatedAccess = 5008, - FileSendAccessLink = 5036, + FileSendAccessLink = 5036, // not used FileDownloaded = 5009, FileDownloadedAs = 5010, diff --git a/web/core/ASC.Web.Core/WhiteLabel/TenantInfoSettings.cs b/web/core/ASC.Web.Core/WhiteLabel/TenantInfoSettings.cs index 37d382081..112948ceb 100644 --- a/web/core/ASC.Web.Core/WhiteLabel/TenantInfoSettings.cs +++ b/web/core/ASC.Web.Core/WhiteLabel/TenantInfoSettings.cs @@ -27,6 +27,7 @@ using System; using System.Configuration; using System.Drawing; +using System.Globalization; using System.IO; using System.Runtime.Serialization; using ASC.Core; @@ -85,6 +86,8 @@ public void RestoreDefaultLogo() { } CompanyLogoSize = default(Size); + + TenantLogoManager.RemoveMailLogoDataFromCache(); } public void SetCompanyLogo(string companyLogoFileName, byte[] data) @@ -110,6 +113,8 @@ public void SetCompanyLogo(string companyLogoFileName, byte[] data) _companyLogoFileName = companyLogoFileName; } _isDefault = false; + + TenantLogoManager.RemoveMailLogoDataFromCache(); } public string GetAbsoluteCompanyLogoPath() @@ -123,6 +128,22 @@ public string GetAbsoluteCompanyLogoPath() return store.GetUri(_companyLogoFileName ?? "").ToString(); } + /// + /// Get logo stream or null in case of default logo + /// + public Stream GetStorageLogoData() + { + if (_isDefault) return null; + + var storage = StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(CultureInfo.InvariantCulture), "logo"); + + if (storage == null) return null; + + var fileName = _companyLogoFileName ?? ""; + + return storage.IsFile(fileName) ? storage.GetReadStream(fileName) : null; + } + public Guid ID { get { return new Guid("{5116B892-CCDD-4406-98CD-4F18297C0C0A}"); } diff --git a/web/core/ASC.Web.Core/WhiteLabel/TenantLogoManager.cs b/web/core/ASC.Web.Core/WhiteLabel/TenantLogoManager.cs index 28efdedbc..1a7a6bc33 100644 --- a/web/core/ASC.Web.Core/WhiteLabel/TenantLogoManager.cs +++ b/web/core/ASC.Web.Core/WhiteLabel/TenantLogoManager.cs @@ -25,9 +25,11 @@ using System; +using System.IO; using System.Linq; using System.Web; using System.Web.Configuration; +using ASC.Common.Caching; using ASC.Core; using ASC.Core.Common.Settings; using ASC.Web.Studio.Utility; @@ -36,6 +38,9 @@ namespace ASC.Web.Core.WhiteLabel { public class TenantLogoManager { + private static readonly ICache Cache = AscCache.Default; + private const string CacheKey = "letterlogodata"; + public static bool WhiteLabelEnabled { get; @@ -52,11 +57,11 @@ static TenantLogoManager() public static string GetFavicon(bool general, bool timeParam) { - var faviconPath = ""; + string faviconPath; if (WhiteLabelEnabled) { - var _tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - faviconPath = _tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.Favicon, general); + var tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + faviconPath = tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.Favicon, general); if (timeParam) { var now = DateTime.Now; faviconPath = String.Format("{0}?t={1}", faviconPath, now.Ticks); @@ -74,9 +79,9 @@ public static string GetTopLogo(bool general)//LogoLightSmall { if (WhiteLabelEnabled) { - var _tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + var tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - return _tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.LightSmall, general); + return tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.LightSmall, general); } return TenantWhiteLabelSettings.GetAbsoluteDefaultLogoPath(WhiteLabelLogoTypeEnum.LightSmall, general); } @@ -84,13 +89,13 @@ public static string GetTopLogo(bool general)//LogoLightSmall public static string GetLogoDark(bool general) { if (WhiteLabelEnabled) { - var _tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - return _tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.Dark, general); + var tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + return tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.Dark, general); } /*** simple scheme ***/ - var _tenantInfoSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - return _tenantInfoSettings.GetAbsoluteCompanyLogoPath(); + var tenantInfoSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + return tenantInfoSettings.GetAbsoluteCompanyLogoPath(); /***/ } @@ -98,8 +103,8 @@ public static string GetLogoDocsEditor(bool general) { if (WhiteLabelEnabled) { - var _tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - return _tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.DocsEditor, general); + var tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + return tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.DocsEditor, general); } return TenantWhiteLabelSettings.GetAbsoluteDefaultLogoPath(WhiteLabelLogoTypeEnum.DocsEditor, general); } @@ -108,9 +113,9 @@ public static string GetLogoText() { if (WhiteLabelEnabled) { - var _tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + var tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); - return _tenantWhiteLabelSettings.LogoText != null ? _tenantWhiteLabelSettings.LogoText : TenantWhiteLabelSettings.DefaultLogoText; + return tenantWhiteLabelSettings.LogoText ?? TenantWhiteLabelSettings.DefaultLogoText; } return TenantWhiteLabelSettings.DefaultLogoText; } @@ -118,7 +123,7 @@ public static string GetLogoText() public static bool IsRetina(HttpRequest request) { var isRetina = false; - if (request != null && request.Cookies != null) + if (request != null) { var cookie = request.Cookies["is_retina"]; if (cookie != null && !String.IsNullOrEmpty(cookie.Value)) @@ -140,5 +145,38 @@ public static bool WhiteLabelPaid return CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).WhiteLabel; } } + + /// + /// Get logo stream or null in case of default logo + /// + public static Stream GetWhitelabelMailLogo() + { + if (WhiteLabelEnabled) + { + var tenantWhiteLabelSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + return tenantWhiteLabelSettings.GetWhitelabelLogoData(WhiteLabelLogoTypeEnum.Dark, true); + } + + /*** simple scheme ***/ + var tenantInfoSettings = SettingsManager.Instance.LoadSettings(TenantProvider.CurrentTenantID); + return tenantInfoSettings.GetStorageLogoData(); + /***/ + } + + + public static byte[] GetMailLogoDataFromCache() + { + return Cache.Get(CacheKey); + } + + public static void InsertMailLogoDataToCache(byte[] data) + { + Cache.Insert(CacheKey, data, DateTime.UtcNow.Add(TimeSpan.FromDays(1))); + } + + public static void RemoveMailLogoDataFromCache() + { + Cache.Remove(CacheKey); + } } } \ No newline at end of file diff --git a/web/core/ASC.Web.Core/WhiteLabel/TenantWhiteLabelSettings.cs b/web/core/ASC.Web.Core/WhiteLabel/TenantWhiteLabelSettings.cs index 3e4b7d94d..2fc7580df 100644 --- a/web/core/ASC.Web.Core/WhiteLabel/TenantWhiteLabelSettings.cs +++ b/web/core/ASC.Web.Core/WhiteLabel/TenantWhiteLabelSettings.cs @@ -404,6 +404,47 @@ private static string GetPartnerStorageLogoPath(WhiteLabelLogoTypeEnum type, boo #endregion + #region Get Whitelabel Logo Stream + + /// + /// Get logo stream or null in case of default whitelabel + /// + public Stream GetWhitelabelLogoData(WhiteLabelLogoTypeEnum type, bool general) + { + if (GetIsDefault(type)) + return GetPartnerStorageLogoData(type, general); + + return GetStorageLogoData(type, general); + } + + private Stream GetStorageLogoData(WhiteLabelLogoTypeEnum type, bool general) + { + var storage = StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(CultureInfo.InvariantCulture), moduleName); + + if (storage == null) return null; + + var fileName = BuildLogoFileName(type, GetExt(type), general); + + return storage.IsFile(fileName) ? storage.GetReadStream(fileName) : null; + } + + private Stream GetPartnerStorageLogoData(WhiteLabelLogoTypeEnum type, bool general) + { + var partnerSettings = SettingsManager.Instance.LoadSettings(Tenant.DEFAULT_TENANT); + + if (partnerSettings.GetIsDefault(type)) return null; + + var partnerStorage = StorageFactory.GetStorage(Tenant.DEFAULT_TENANT.ToString(CultureInfo.InvariantCulture), "static_partnerdata"); + + if (partnerStorage == null) return null; + + var fileName = BuildLogoFileName(type, partnerSettings.GetExt(type), general); + + return partnerStorage.IsFile(fileName) ? partnerStorage.GetReadStream(fileName) : null; + } + + #endregion + public static string BuildLogoFileName(WhiteLabelLogoTypeEnum type, String fileExt, bool general) { return String.Format("logo_{0}{2}.{1}", type.ToString().ToLowerInvariant(), fileExt, general ? "_general" : ""); @@ -500,6 +541,8 @@ public void Save(int tenantId, bool restore = false) { SettingsManager.Instance.SaveSettings(this, tenantId); SetNewLogoText(tenantId, restore); + + TenantLogoManager.RemoveMailLogoDataFromCache(); } private void SetNewLogoText(int tenantId, bool restore = false) diff --git a/web/studio/ASC.Web.Studio/About.aspx b/web/studio/ASC.Web.Studio/About.aspx index ff2c56851..a1114b8ae 100644 --- a/web/studio/ASC.Web.Studio/About.aspx +++ b/web/studio/ASC.Web.Studio/About.aspx @@ -28,7 +28,7 @@

<%: Resource.AboutPersonalQuestionHeader %>

<%= String.Format(Resource.AboutPersonalQuestionText.HtmlEncode(), - "", "","") %>

+ "", "","") %>

\ No newline at end of file diff --git a/web/studio/ASC.Web.Studio/Core/Notify/NotifyConfiguration.cs b/web/studio/ASC.Web.Studio/Core/Notify/NotifyConfiguration.cs index 0f5019581..c43f78edc 100644 --- a/web/studio/ASC.Web.Studio/Core/Notify/NotifyConfiguration.cs +++ b/web/studio/ASC.Web.Studio/Core/Notify/NotifyConfiguration.cs @@ -28,7 +28,6 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Net; using System.Runtime.Remoting.Messaging; using System.Text.RegularExpressions; using System.Threading; @@ -285,49 +284,65 @@ private static void BeforeTransferRequest(NotifyEngine sender, NotifyRequest req private static void AddLetterLogo(NotifyRequest request) { - var logoUrl = CommonLinkUtility.GetFullAbsolutePath(TenantLogoManager.GetLogoDark(true)); - if (CoreContext.Configuration.Standalone) { - var attachment = ConvertImageUrlToAttachment(logoUrl); + try + { + var logoData = TenantLogoManager.GetMailLogoDataFromCache(); + + if (logoData == null) + { + var logoStream = TenantLogoManager.GetWhitelabelMailLogo(); + logoData = ReadStreamToByteArray(logoStream) ?? GetDefaultMailLogo(); + + if (logoData != null) + TenantLogoManager.InsertMailLogoDataToCache(logoData); + } - if (attachment != null) + if (logoData != null) + { + var attachment = new NotifyMessageAttachment + { + FileName = "logo.png", + Content = logoData, + ContentId = MimeUtils.GenerateMessageId() + }; + + request.Arguments.Add(new TagValue(Constants.LetterLogo, "cid:" + attachment.ContentId)); + request.Arguments.Add(new TagValue(Constants.EmbeddedAttachments, new[] { attachment })); + return; + } + } + catch (Exception error) { - request.Arguments.Add(new TagValue(Constants.LetterLogo, "cid:" + attachment.ContentId)); - request.Arguments.Add(new TagValue(Constants.EmbeddedAttachments, new[] {attachment})); - return; + LogManager.GetLogger(typeof(NotifyConfiguration)).Error(error); } } + var logoUrl = CommonLinkUtility.GetFullAbsolutePath(TenantLogoManager.GetLogoDark(true)); + request.Arguments.Add(new TagValue(Constants.LetterLogo, logoUrl)); } - private static NotifyMessageAttachment ConvertImageUrlToAttachment(string url) + private static byte[] ReadStreamToByteArray(Stream inputStream) { - try - { - var uri = new Uri(url).AbsoluteUri; - - var filename = Path.GetFileName(uri) ?? "logo.png"; - - byte[] imageData; - - using (var wc = new WebClient()) - imageData = wc.DownloadData(url); + if (inputStream == null) return null; - if (imageData == null) return null; - - return new NotifyMessageAttachment - { - FileName = filename, - Content = imageData, - ContentId = MimeUtils.GenerateMessageId() - }; - } - catch (Exception) + using (inputStream) { - return null; + using (var memoryStream = new MemoryStream()) + { + inputStream.CopyTo(memoryStream); + return memoryStream.ToArray(); + } } } + + public static byte[] GetDefaultMailLogo() + { + var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "skins", "default", "images", "onlyoffice_logo", "dark_general.png"); + + return File.Exists(filePath) ? File.ReadAllBytes(filePath) : null; + } } } diff --git a/web/studio/ASC.Web.Studio/Products/Files/ASC.Web.Files.csproj b/web/studio/ASC.Web.Studio/Products/Files/ASC.Web.Files.csproj index c6ef0fa2b..30fa8ec85 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/ASC.Web.Files.csproj +++ b/web/studio/ASC.Web.Studio/Products/Files/ASC.Web.Files.csproj @@ -149,13 +149,6 @@ docusignhandler.ashx - - ShareLink.aspx - ASPXCodeBehind - - - ShareLink.aspx - Box.aspx ASPXCodeBehind @@ -264,7 +257,6 @@ - @@ -291,8 +283,6 @@ - - @@ -371,7 +361,6 @@ -
diff --git a/web/studio/ASC.Web.Studio/Products/Files/Controls/AccessRights/accessrights.js b/web/studio/ASC.Web.Studio/Products/Files/Controls/AccessRights/accessrights.js index 5f7dff955..8fe5081a7 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Controls/AccessRights/accessrights.js +++ b/web/studio/ASC.Web.Studio/Products/Files/Controls/AccessRights/accessrights.js @@ -135,10 +135,13 @@ window.ASC.Files.Share = (function () { var link = encodeURIComponent(shareLinkShort); linkPanel.find(".google").attr("href", ASC.Resources.Master.UrlShareGooglePlus.format(link)); - linkPanel.find(".facebook").attr("href", ASC.Resources.Master.UrlShareFacebook.format(link, objectTitle, "", "")); + linkPanel.find(".facebook").attr("href", ASC.Resources.Master.UrlShareFacebook.format(link, encodeURIComponent(objectTitle), "", "")); linkPanel.find(".twitter").attr("href", ASC.Resources.Master.UrlShareTwitter.format(link)); - var fileId = ASC.Files.UI.parseItemId(objectID).entryId; - linkPanel.find(".mail").attr("href", ASC.Files.Constants.UrlShareLink.format(fileId)); + + var urlShareMail = "mailto:?subject={1}&body={0}"; + var subject = ASC.Files.FilesJSResources.shareLinkMailSubject.format(objectTitle); + var body = ASC.Files.FilesJSResources.shareLinkMailBody.format(objectTitle, shareLinkShort); + linkPanel.find(".mail").attr("href", urlShareMail.format(encodeURIComponent(body), encodeURIComponent(subject))); }; var openShareLinkAce = function () { @@ -188,11 +191,53 @@ window.ASC.Files.Share = (function () { if (jq("#studio_sharingSettingsDialog #shareLinkBody").length == 0) { jq("#sharingSettingsDialogBody").prepend(jq("#shareLinkBody")); - jq("#shareViaSocPanel").on("click", "a", function () { + jq("#shareViaSocPanel").on("click", "a:not(.mail)", function () { window.open(jq(this).attr("href"), "new", "height=600,width=1020,fullscreen=0,resizable=0,status=0,toolbar=0,menubar=0,location=1"); return false; }); + if (!ASC.Resources.Master.Personal) { + jq("#shareViaSocPanel").on("click", "a.mail", function () { + + var openLink = jq(this).attr("href"); + + var winMail = window.open(""); + try { + if (winMail) { + winMail.document.write(ASC.Resources.Master.Resource.LoadingPleaseWait); + winMail.document.close(); + } + } catch (e) { + } + + var message = new ASC.Mail.Message(); + message.subject = ASC.Files.FilesJSResources.shareLinkMailSubject.format(objectTitle); + + var linkFormat = "{1}"; + var linkName = linkFormat.format(Encoder.htmlEncode(shareLinkShort), Encoder.htmlEncode(objectTitle)); + var link = linkFormat.format(Encoder.htmlEncode(shareLinkShort), Encoder.htmlEncode(shareLinkShort)); + var body = ASC.Files.FilesJSResources.shareLinkMailBody.format(linkName, link); + + message.body = body; + + ASC.Mail.Utility.SaveMessageInDrafts(message) + .done(function (_, data) { + var url = data.messageUrl; + if (winMail && winMail.location) { + winMail.location.href = url; + } else { + winMail = window.open(url, "_blank"); + } + }) + .fail(function () { + winMail.close(); + window.location.href = openLink; + }); + + return false; + }); + } + jq("#shareLinkOpen").on("click", openShareLinkAce); jq("#sharingLinkAce select").on("change", changeShareLinkAce); } diff --git a/web/studio/ASC.Web.Studio/Products/Files/Controls/EmptyFolder/EmptyFolder.ascx b/web/studio/ASC.Web.Studio/Products/Files/Controls/EmptyFolder/EmptyFolder.ascx index 0fb8437ac..6fd1279f7 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Controls/EmptyFolder/EmptyFolder.ascx +++ b/web/studio/ASC.Web.Studio/Products/Files/Controls/EmptyFolder/EmptyFolder.ascx @@ -16,7 +16,7 @@ FileUtility.InternalExtension[FileType.Presentation]) %> <% if (!string.IsNullOrEmpty(CommonLinkUtility.GetHelpLink())) { %> - " target="_blank"><%= FilesUCResource.ButtonLearnMore %> + " target="_blank"><%= FilesUCResource.ButtonLearnMore %> <% } %>
diff --git a/web/studio/ASC.Web.Studio/Products/Files/Helpers/Global.cs b/web/studio/ASC.Web.Studio/Products/Files/Helpers/Global.cs index 16a4f4203..8d5c7910b 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Helpers/Global.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Helpers/Global.cs @@ -74,8 +74,6 @@ static Global() public const int MaxTitle = 170; - public const int MaxEmailCount = 10; - public static readonly Regex InvalidTitleChars = new Regex("[\t*\\+:\"<>?|\\\\/]"); public static bool EnableUploadFilter diff --git a/web/studio/ASC.Web.Studio/Products/Files/Masters/ClientScripts/FilesConstantsResources.cs b/web/studio/ASC.Web.Studio/Products/Files/Masters/ClientScripts/FilesConstantsResources.cs index 4abc0372f..3d3f24c54 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Masters/ClientScripts/FilesConstantsResources.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Masters/ClientScripts/FilesConstantsResources.cs @@ -115,8 +115,6 @@ protected override IEnumerable> GetClientVariables( }, DocuSignFormats = DocuSignHelper.SupportedFormats, - - UrlShareLink = ShareLink.Location + "?" + FilesLinkUtility.FileId + "={0}", }) }; } diff --git a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.Designer.cs b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.Designer.cs index 3264b95a3..a68e7fd76 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.Designer.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.Designer.cs @@ -708,15 +708,6 @@ public static string ErrorMassage_ManyDownloads { } } - /// - /// Looks up a localized string similar to Too many addresses. - /// - public static string ErrorMassage_ManyEmailAddresses { - get { - return ResourceManager.GetString("ErrorMassage_ManyEmailAddresses", resourceCulture); - } - } - /// /// Looks up a localized string similar to Sorry, this file format isn't supported. /// @@ -1185,15 +1176,6 @@ public static string ShareFolder { } } - /// - /// Looks up a localized string similar to Sending link. - /// - public static string ShareLinkMail { - get { - return ResourceManager.GetString("ShareLinkMail", resourceCulture); - } - } - /// /// Looks up a localized string similar to Show Versions. /// diff --git a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.resx b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.resx index 606396131..d770d1653 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.resx +++ b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesCommonResource.resx @@ -330,9 +330,6 @@ Too many downloads. - - Too many addresses - Sorry, this file format isn't supported @@ -486,9 +483,6 @@ Share - - Sending link - Shared with Me diff --git a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.Designer.cs b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.Designer.cs index 8daf571d6..607d14dd9 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.Designer.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.Designer.cs @@ -519,15 +519,6 @@ public static string EnterComment { } } - /// - /// Looks up a localized string similar to Complete the fields to send a message. - /// - public static string ErrorMassage_EmptyField { - get { - return ResourceManager.GetString("ErrorMassage_EmptyField", resourceCulture); - } - } - /// /// Looks up a localized string similar to You cannot upload a folder or an empty file. /// @@ -969,15 +960,6 @@ public static string InfoFolderMoveError { } } - /// - /// Looks up a localized string similar to Mails successfully sended. - /// - public static string InfoMailsSended { - get { - return ResourceManager.GetString("InfoMailsSended", resourceCulture); - } - } - /// /// Looks up a localized string similar to You do not have access rights to move some file(s). /// @@ -1195,20 +1177,20 @@ public static string RevisionCurrent { } /// - /// Looks up a localized string similar to Enter the recipient email address. + /// Looks up a localized string similar to You have been granted access to the {0} document. Click the link below to open the document right now: {1}. /// - public static string shareLinkMail { + public static string shareLinkMailBody { get { - return ResourceManager.GetString("shareLinkMail", resourceCulture); + return ResourceManager.GetString("shareLinkMailBody", resourceCulture); } } /// - /// Looks up a localized string similar to Message. + /// Looks up a localized string similar to You have been granted access to the {0} document. /// - public static string shareLinkMailMessage { + public static string shareLinkMailSubject { get { - return ResourceManager.GetString("shareLinkMailMessage", resourceCulture); + return ResourceManager.GetString("shareLinkMailSubject", resourceCulture); } } diff --git a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.resx b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.resx index 2f5f5d502..7760d79b1 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.resx +++ b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.resx @@ -270,9 +270,6 @@ Enter a comment - - Complete the fields to send a message - You cannot upload a folder or an empty file @@ -414,9 +411,6 @@ You cannot move the folder to its subfolder - - Mails successfully sended - You do not have access rights to move some file(s) @@ -495,11 +489,11 @@ current - - Enter the recipient email address + + You have been granted access to the {0} document. Click the link below to open the document right now: {1} - - Message + + You have been granted access to the {0} document elements: {0} diff --git a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.Designer.cs b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.Designer.cs index 1fc7104d9..695384ae8 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.Designer.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.Designer.cs @@ -1509,15 +1509,6 @@ public static string LinkViaMail { } } - /// - /// Looks up a localized string similar to Send. - /// - public static string LinkViaMailSend { - get { - return ResourceManager.GetString("LinkViaMailSend", resourceCulture); - } - } - /// /// Looks up a localized string similar to Login. /// @@ -1851,33 +1842,6 @@ public static string SharedForMe { } } - /// - /// Looks up a localized string similar to Message. - /// - public static string ShareLinkMailMessage { - get { - return ResourceManager.GetString("ShareLinkMailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add a comment. - /// - public static string ShareLinkMailMessageTitle { - get { - return ResourceManager.GetString("ShareLinkMailMessageTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Send a link to the following addresses:. - /// - public static string ShareLinkMailTo { - get { - return ResourceManager.GetString("ShareLinkMailTo", resourceCulture); - } - } - /// /// Looks up a localized string similar to Set up the access right for the link. /// diff --git a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.resx b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.resx index 5fabe9f04..82864ba4b 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.resx +++ b/web/studio/ASC.Web.Studio/Products/Files/Resources/FilesUCResource.resx @@ -585,9 +585,6 @@ via email - - Send - Login @@ -690,15 +687,6 @@ Shared with Me - - Send a link to the following addresses: - - - Message - - - Add a comment - Set up the access right for the link diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.Designer.cs b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.Designer.cs index 83a9d18e7..3d2701ea2 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.Designer.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.Designer.cs @@ -86,19 +86,6 @@ public static string pattern_DocuSignStatus { } } - /// - /// Looks up a localized string similar to h1. Access granted to document: "$DocumentTitle":"$DocumentURL" - /// - ///$__DateTime $__AuthorName ("$UserEmail":"mailto:$UserEmail") granted you the access to the "$DocumentTitle":"$DocumentURL" document with the following access rights: "$AccessRights". - /// - ///$Message. - /// - public static string pattern_LinkToEmail { - get { - return ResourceManager.GetString("pattern_LinkToEmail", resourceCulture); - } - } - /// /// Looks up a localized string similar to h1. Mailing completed /// @@ -178,15 +165,6 @@ public static string subject_DocuSignStatus { } } - /// - /// Looks up a localized string similar to Documents. You are granted access to $DocumentTitle. - /// - public static string subject_LinkToEmail { - get { - return ResourceManager.GetString("subject_LinkToEmail", resourceCulture); - } - } - /// /// Looks up a localized string similar to Documents. Mailing is complete.. /// diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.resx b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.resx index 29fa48653..ac8363c29 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.resx +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/FilesPatternResource.resx @@ -117,13 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - h1. Access granted to document: "$DocumentTitle":"$DocumentURL" - -$__DateTime $__AuthorName ("$UserEmail":"mailto:$UserEmail") granted you the access to the "$DocumentTitle":"$DocumentURL" document with the following access rights: "$AccessRights". - -$Message - h1. All signers completed $DocumentTitle @@ -165,9 +158,6 @@ $Message ^You receive this email because you are a registered user of the "${__VirtualRootPath}":"${__VirtualRootPath}" portal. If you do not want to receive the notifications about the shared folders, please manage your "subscription settings":"$RecipientSubscriptionConfigURL".^ - - Documents. You are granted access to $DocumentTitle - Documents. All signers completed $DocumentTitle diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyClient.cs b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyClient.cs index 8152b403d..bb1ec91fd 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyClient.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyClient.cs @@ -93,32 +93,6 @@ public static void SendMailMergeEnd(Guid userId, int countMails, int countError) ); } - public static void SendLinkToEmail(File file, String url, String message, List addressRecipients) - { - if (file == null || String.IsNullOrEmpty(url)) - throw new ArgumentException(); - - foreach (var recipients in addressRecipients - .Select(addressRecipient => (IRecipient) (new DirectRecipient(SecurityContext.CurrentAccount.ID.ToString(), String.Empty, new[] {addressRecipient}, false)))) - { - Instance.SendNoticeToAsync( - NotifyConstants.Event_LinkToEmail, - null, - new[] {recipients}, - new[] {ASC.Core.Configuration.Constants.NotifyEMailSenderSysName}, - null, - new TagValue(NotifyConstants.Tag_DocumentTitle, file.Title), - new TagValue(NotifyConstants.Tag_DocumentUrl, CommonLinkUtility.GetFullAbsolutePath(url)), - new TagValue(NotifyConstants.Tag_AccessRights, GetAccessString(file.Access, CultureInfo.CurrentUICulture)), - new TagValue(NotifyConstants.Tag_Message, message.HtmlEncode()), - new TagValue(NotifyConstants.Tag_UserEmail, CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).Email), - new TagValue(CommonTags.WithPhoto, CoreContext.Configuration.Personal ? "personal" : ""), - new TagValue(CommonTags.IsPromoLetter, CoreContext.Configuration.Personal ? "true" : "false"), - new TagValue("noUnsubscribeLink", "true") - ); - } - } - public static void SendShareNotice(FileEntry fileEntry, Dictionary recipients, string message) { if (fileEntry == null || recipients.Count == 0) return; diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyConstants.cs b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyConstants.cs index 7e3798f09..7170f960e 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyConstants.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyConstants.cs @@ -37,7 +37,6 @@ public static class NotifyConstants public static readonly INotifyAction Event_MailMergeEnd = new NotifyAction("MailMergeEnd", "mail merge end"); public static readonly INotifyAction Event_ShareDocument = new NotifyAction("ShareDocument", "share document"); public static readonly INotifyAction Event_ShareFolder = new NotifyAction("ShareFolder", "share folder"); - public static readonly INotifyAction Event_LinkToEmail = new NotifyAction("LinkToEmail", "link to email"); #endregion @@ -48,7 +47,6 @@ public static class NotifyConstants public static readonly string Tag_DocumentUrl = "DocumentURL"; public static readonly string Tag_AccessRights = "AccessRights"; public static readonly string Tag_Message = "Message"; - public static readonly string Tag_UserEmail = "UserEmail"; public static readonly string Tag_MailsCount = "MailsCount"; #endregion diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifySource.cs b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifySource.cs index 3321f9abc..15ea8efff 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifySource.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifySource.cs @@ -49,8 +49,7 @@ protected override IActionProvider CreateActionProvider() { return new ConstActionProvider( NotifyConstants.Event_ShareFolder, - NotifyConstants.Event_ShareDocument, - NotifyConstants.Event_LinkToEmail); + NotifyConstants.Event_ShareDocument); } protected override IPatternProvider CreatePatternsProvider() diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/patterns.xml b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/patterns.xml index 62a5ddc05..c39fcafa2 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/patterns.xml +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/patterns.xml @@ -62,20 +62,4 @@ $Message $__VirtualRootPath/products/files/#$FolderID - - - - - - - - $__AuthorName - -$AccessRights - -$Message - -$DocumentURL - - \ No newline at end of file diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileStorageServiceController.cs b/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileStorageServiceController.cs index 2fc60bd9e..2b5483ddc 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileStorageServiceController.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileStorageServiceController.cs @@ -1493,45 +1493,6 @@ public String GetShortenLink(String fileId) } } - [ActionName("sendlinktoemail"), HttpPost] - public void SendLinkToEmail(String fileId, [FromBody] MessageParams messageAddresses) - { - ErrorIf(messageAddresses == null, FilesCommonResource.ErrorMassage_BadRequest); - - ErrorIf(messageAddresses.Address.Count > Global.MaxEmailCount, FilesCommonResource.ErrorMassage_ManyEmailAddresses); - - using (var fileDao = GetFileDao()) - { - var file = fileDao.GetFile(fileId); - ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - - ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException); - - var shareRecord = FileSecurity.GetShares(file).FirstOrDefault(r => r.Subject == FileConstant.ShareLinkId); - ErrorIf(shareRecord == null, FilesCommonResource.ErrorMassage_SecurityException); - - file.Access = shareRecord.Share; - - var shareLink = FileShareLink.GetLink(file); - - if (BitlyLoginProvider.Enabled) - { - try - { - shareLink = BitlyLoginProvider.GetShortenLink(shareLink); - } - catch (Exception ex) - { - Global.Logger.Error("Get shorten link", ex); - } - } - - NotifyClient.SendLinkToEmail(file, shareLink, messageAddresses.Message, messageAddresses.Address); - - FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileSendAccessLink, new[] { file.Title, string.Join(" ", messageAddresses.Address) }); - } - } - [ActionName("setacelink"), HttpGet] public bool SetAceLink(String fileId, FileShare share) { diff --git a/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/IFileStorageService.cs b/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/IFileStorageService.cs index 1b89be82b..ed3e7db65 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/IFileStorageService.cs +++ b/web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/IFileStorageService.cs @@ -115,8 +115,6 @@ public interface IFileStorageService String GetShortenLink(String fileId); - void SendLinkToEmail(String fileId, MessageParams messageAddresses); - bool StoreOriginal(bool store); bool UpdateIfExist(bool update); diff --git a/web/studio/ASC.Web.Studio/Products/Files/js/servicemanager.js b/web/studio/ASC.Web.Studio/Products/Files/js/servicemanager.js index fb1a9f1e5..93e62768f 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/js/servicemanager.js +++ b/web/studio/ASC.Web.Studio/Products/Files/js/servicemanager.js @@ -416,7 +416,6 @@ window.ASC.Files.ServiceManager = (function () { SetAceObject: "setaceobject", UnSubscribeMe: "unsubscribeme", GetShortenLink: "getshortenlink", - SendLinkToEmail: "sendlinktoemail", MarkAsRead: "markasread", GetNews: "getnews", @@ -601,10 +600,6 @@ window.ASC.Files.ServiceManager = (function () { request("get", "json", eventType, params, "shorten?fileId=" + encodeURIComponent(params.fileId)); }; - var sendLinkToEmail = function (eventType, params, data) { - request("post", "json", eventType, params, data, "sendlinktoemail?fileId=" + encodeURIComponent(params.fileId)); - }; - var checkConversion = function (eventType, params, data) { request("post", "json", eventType, params, data, "checkconversion"); }; @@ -724,7 +719,6 @@ window.ASC.Files.ServiceManager = (function () { setAceObject: setAceObject, unSubscribeMe: unSubscribeMe, getShortenLink: getShortenLink, - sendLinkToEmail: sendLinkToEmail, checkConversion: checkConversion, storeOriginalFiles: storeOriginalFiles, diff --git a/web/studio/ASC.Web.Studio/Products/Files/js/ui.js b/web/studio/ASC.Web.Studio/Products/Files/js/ui.js index 13ec57894..bf485b85c 100644 --- a/web/studio/ASC.Web.Studio/Products/Files/js/ui.js +++ b/web/studio/ASC.Web.Studio/Products/Files/js/ui.js @@ -532,6 +532,9 @@ window.ASC.Files.UI = (function () { ASC.Files.UI.selectRow(jq(this), !jq(this).hasClass("row-selected")); }); } else if (!target.is(".checkbox")) { + if (jq(".row-selected").length > 1) { + select = true; + } ASC.Files.UI.checkSelectAll(false); } @@ -1133,7 +1136,7 @@ window.ASC.Files.UI = (function () { jq("#filesMainContent").on("click", ".file-row", ASC.Files.UI.clickRow); jq("#filesMainContent").on("dblclick", ".file-row", function (event) { - if (jq(event.srcElement || event.target).is("input, #contentVersions, #contentVersions *")) { + if (jq(event.srcElement || event.target).is("input, .checkbox, #contentVersions, #contentVersions *")) { return; } jq(this).closest(".file-row").find(".entry-title .name a").trigger("click"); diff --git a/web/studio/ASC.Web.Studio/Products/People/ASC.Web.People.csproj b/web/studio/ASC.Web.Studio/Products/People/ASC.Web.People.csproj index 000cc5e85..27bafd959 100644 --- a/web/studio/ASC.Web.Studio/Products/People/ASC.Web.People.csproj +++ b/web/studio/ASC.Web.Studio/Products/People/ASC.Web.People.csproj @@ -166,11 +166,11 @@ - - diff --git a/web/studio/ASC.Web.Studio/Products/Projects/ProjectsTemplates/ListTasksTemplates.html b/web/studio/ASC.Web.Studio/Products/Projects/ProjectsTemplates/ListTasksTemplates.html index 810d413f5..548b5b6c4 100644 --- a/web/studio/ASC.Web.Studio/Products/Projects/ProjectsTemplates/ListTasksTemplates.html +++ b/web/studio/ASC.Web.Studio/Products/Projects/ProjectsTemplates/ListTasksTemplates.html @@ -42,18 +42,18 @@ {{if $item.data.responsible == null}} ${ASC.Projects.Resources.TasksResource.NoResponsible} {{else}} - ${responsible.displayName} - {{/if}} -
+ ${responsible.displayName} + {{/if}} + {{/if}} {{if $item.data.displayDateDeadline.length}}
- ${displayDateDeadline} + ${displayDateDeadline}
{{else}} - {{if $item.data.milestone != null}} + {{if $item.data.milestone != null}}
- ${milestone.displayDateDeadline} + ${milestone.displayDateDeadline}
{{/if}} {{/if}} @@ -63,9 +63,9 @@ {{if $item.data.canEdit || $item.data.canCreateSubtask}} - {{/if}} -
+ + {{/if}} +
@@ -84,12 +84,12 @@ - \ No newline at end of file diff --git a/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/authorizedocs.js b/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/authorizedocs.js index 1dbba579b..20d5f15f8 100644 --- a/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/authorizedocs.js +++ b/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/authorizedocs.js @@ -156,7 +156,7 @@ jq(function () { } }); - shuffle(reviews); + //shuffle(reviews); reviews.forEach(function (review) { review.stars = new Array(parseInt(review.rating)); if (review.photo) { diff --git a/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/reviews.json b/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/reviews.json index 993725d61..6274faebe 100644 --- a/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/reviews.json +++ b/web/studio/ASC.Web.Studio/UserControls/Common/AuthorizeDocs/js/reviews.json @@ -2,136 +2,20 @@ "en": { "reviews": [ { - "value": "Best office compatible chrome app out there. Retains formatting. Works great as a file manager that allows you to move between onedrive, google drive, and onebox. With offline access this would be the killer app.", - "author": "Jay Borok", - "date": "October 18, 2014", - "rating": "5" - }, - { - "value": "Just tried it and it's the next best thing to MS Word. The popular editing functionality works really well especially the copy/paste functionality when pasting into a .gdoc. Opening/converting .docx files is smooth, converted tables are a dream! Far superior than Google docs.", - "author": "Linda Stansfield", - "date": "October 17, 2014", - "rating": "5", - "photo": "Linda-Stansfield.png" - }, - { - "value": "This app works as explained and works much better than having to use docs and convert files over to Word. Everything is formatted just right and all the tools required for editing are there as well. This is a must have if you are a student and need to use Word docx files.", - "author": "Carlos Navarrete", - "date": "October 8, 2014", - "rating": "5" - }, - { - "value": "Seems to easily have the best fidelity for presenting and editing MS Word docs, including complex tables.", - "author": "Ben Low", - "date": "September 18, 2014", - "rating": "4", - "photo": "Ben_Low.png" - }, - { - "value": "Everything I ever expected from an app like this .... Only started a few days ago but for now is just WOW!", - "author": "Ciprian Ungureanu", - "date": "September 10, 2014", - "rating": "5", - "photo": "Ciprian_Ungureanu.png" - }, - { - "value": "Absolutely the best office-like product out there and I've tried a lot. Kept a lot of complicated formatting in place and is tremendously usable. Thanks for this!", - "author": "Kasey Esposito", - "date": "September 9, 2014", - "rating": "5", - "photo": "Kasey_Esposito.png" - }, - { - "value": "Well executed and simple. The same two reason I also love google docs. This just fills in all the gaps google drive leaves out with MS Office files . It's also much better than quickoffice. Seriously, quickoffice is a joke next to this.", - "author": "Jacob Meyer", - "date": "August 6, 2014", - "rating": "5", - "photo": "Jacob_Meyer.png" - }, - { - "value": "Just started using this, but it looks amazing! It even allows comments in Word documents. Great stuff.", - "author": "David Williamson", - "date": "May 23, 2014", - "rating": "5", - "photo": "David_Williamson.png" - }, - { - "value": "Fantastic print quality. As good as Microsoft Office Online. Highly recommended!", - "author": "Daniel Kueh", - "date": "May 8, 2014", - "rating": "5", - "photo": "Daniel_Kueh.png" - }, - { - "value": "As good as Microsoft Office. But inside Google Drive!", - "author": "Andrey Sidorenko", - "date": "April 10, 2014", - "rating": "5", - "photo": "Andrey_Sidorenko.png" - }, - { - "value": "Better than MS Online office suite.", - "author": "Kabeer Ahmed", - "date": "April 23, 2014", - "rating": "5", - "photo": "Kabeer_Ahmed.png" - }, - { - "value": "Seems to be everything as advertised. Looks good to me. I wonder if the new Google Docs/Slides/Sheets apps functionality will match it. Either way, the user is the winner. Great work!!", - "author": "Peter Pavlovic", - "date": "June 26, 2014", - "rating": "5", - "photo": "Peter_Pavlovic.png" - }, - { - "value": "I am not a Microsoft fan, and I can't believe my good fortune in finding this program. I am a personal user, and so far the program meets and exceeds all my needs- Great job!", - "author": "Frederick Prince", - "date": "Oct 23, 2014", - "rating": "5", - "photo": "Frederick_Prince.png" - }, - { - "value": "This is by far the best alternative to MS Office that I have used on Chrome.", - "author": "Benjamin Coate", - "date": "Oct 25, 2014", - "rating": "4", - "photo": "Benjamin_Coate.png" - }, - { - "value": "Best Web editor for Office-Open-XML documents yet.", - "author": "Sebastian Reuter", - "date": "Oct 30, 2014", - "rating": "5", - "photo": "Sebastian_Reuter.png" - }, - { - "value": "First impression is that I don't need any other office-type application and this will do all that I want.", - "author": "Tony Harvey", - "date": "Nov 13, 2014", - "rating": "4", - "photo": "Tony_Harvey.png" - }, - { - "value": "This is an outstanding Word processor. It works very well and has many features that large competitors offer. The UI is very easy to navigate. Everything does take a bit to load, but in the end, it's all worth it.", - "author": "andrewjcole Scratch", - "date": "Nov 15, 2014", + "value": "Great MS compatibility.", + "author": "Kev M", + "date": "April 27, 2017", "rating": "5", - "photo": "andrewjcole_Scratch.png" + "photo": "Kev_M.png" }, { - "value": "Excellent!", - "author": "Olga Kaczmarczyk", - "date": "Nov 19, 2014", + "value": "It is the best!", + "author": "Сергей Матвеев", + "date": "April 13, 2017", "rating": "5", - "photo": "Olga_Kaczmarczyk.png" + "photo": "sergey_matveev.png" }, { - "value": "As others have pointed out, it matches the settings of the original document well (something Word Online fails to do) and includes lots of settings that make this operate much more like a real version than a stripped-down web version.", - "author": "Tim Byers", - "date": "Nov 24, 2014", - "rating": "4", - "photo": "Tim_Byers.png" - }, { "value": "The best ever editor i have seen.... i was struggling to get an online editor and you saved me BATMAN", "author": "Srikar Teratipally", "date": "January 26, 2017", @@ -144,9 +28,16 @@ "rating": "5" }, { - "value": "I love the product and its support very much! Every time I have a question or problem i can contact them in different ways (email, talk or even call) and they do their best to find a solution for me!Happy customer.", - "author": "Марина Фирсова", - "date": "January 12, 2017", + "value": "Incredible! The best online office editor. Design fantastic. When you intend display pivot table funcitons?", + "author": "Mario Alencar", + "date": "December 29, 2016", + "rating": "5", + "photo": "Mario_Alencar.png" + }, + { + "value": "20/20 no comment best software online for doc etc", + "author": "Rex Imperial", + "date": "July 25, 2016", "rating": "5" }, { @@ -171,11 +62,10 @@ "photo": "Jigar_Jadav.png" }, { - "value": "This is the best app ever for Chromebook. It has saved me a countless amount of time trying to do things with Google docs and Google sheets only to find out they can't be done. BEST APP EVER for Chromebook!", - "author": "Barb Barrett", - "date": "December 18, 2015", - "rating": "5", - "photo": "Barb_Barrett.png" + "value": "Best online office", + "author": "Dzianis Koshkin", + "date": "January 22, 2016", + "rating": "5" }, { "value": "It is not a fake, it is 100% compatible with microsoft office!", @@ -185,80 +75,55 @@ "photo": "Josh_Miller.png" }, { - "value": "20/20 no comment best software online for doc etc", - "author": "Rex Imperial", - "date": "July 25, 2016", - "rating": "5" - }, - { - "value": "Great MS compatibility.", - "author": "Kev M", - "date": "April 27, 2017", + "value": "This is an outstanding Word processor. It works very well and has many features that large competitors offer. The UI is very easy to navigate. Everything does take a bit to load, but in the end, it's all worth it.", + "author": "andrewjcole Scratch", + "date": "Nov 15, 2014", "rating": "5", - "photo": "Kev_M.png" + "photo": "andrewjcole_Scratch.png" }, { - "value": "It is the best!", - "author": "Сергей Матвеев", - "date": "April 13, 2017", + "value": "Just tried it and it's the next best thing to MS Word. The popular editing functionality works really well especially the copy/paste functionality when pasting into a .gdoc. Opening/converting .docx files is smooth, converted tables are a dream! Far superior than Google docs.", + "author": "Linda Stansfield", + "date": "October 17, 2014", "rating": "5", - "photo": "sergey_matveev.png" + "photo": "Linda-Stansfield.png" }, { - "value": "Best online office", - "author": "Dzianis Koshkin", - "date": "January 22, 2016", + "value": "This app works as explained and works much better than having to use docs and convert files over to Word. Everything is formatted just right and all the tools required for editing are there as well. This is a must have if you are a student and need to use Word docx files.", + "author": "Carlos Navarrete", + "date": "October 8, 2014", "rating": "5" - }, - { - "value": "Incredible! The best online office editor. Design fantastic. When you intend display pivot table funcitons?", - "author": "Mario Alencar", - "date": "December 29, 2016", - "rating": "5", - "photo": "Mario_Alencar.png" } ] }, "ru": { "reviews": [ { - "value": "Отличное приложение, 100% замена мелкомягкому офису!", - "author": "Станислав Савельев", - "date": "7 Июня 2014", + "value": "Всё хорошо. Во время учебы пришлось искать облачный офис и выбор пал на OOP. За пару лет работы с ним сильных нареканий не возникало. Функциями и работой доволен. Порадовало так же, что в подключенных аккаунтах появился яндекс диск.", + "author": "Анатолий Ашулин", + "date": "27 Апреля 2017", "rating": "5" }, { - "value": "То, что доктор прописал)", - "author": "Виталий Плитенко", - "date": "12 Апреля 2014", + "value": "Помимо того, что сервис отличный, он помог мне спасти человека с курсачом :) Сервис пофиксил документ с расширением .docm (стандартная ошибка в макросах Word 2010, не открывает после редактирования) и восстановил пользовательские стили. Всё круто, буду пользоваться в связке с облаком! Спасибо разработчику Андрею за \"рекламу\" сайта у нас в ДФ ННГУ)", + "author": "Карина Верба", + "date": "26 Марта 2017", "rating": "5", - "photo": "Vitaliy_Plitenko.png" - }, - { - "value": "Пожалуй лучший онлайн-редактор", - "author": "Denis Ozdemir", - "date": "24 Апреля 2014", - "rating": "5" + "photo": "karina_verba.png" }, { - "value": "Отличный сервис. Из всех опробованных сервисов и программ обладает максимальной совместимостью с продуктами Microsoft Office.", - "author": "Александр Слюсарев", - "date": "14 Сентября 2014", + "value": "Понравилось. Твердая 5+", + "author": "Sergey Strelnikov", + "date": "14 Октября 2016", "rating": "5", - "photo": "Alexsandr_Slusarev.png" + "photo": "Sergey_Strelnikov.png" }, { - "value": "Помимо того, что сервис отличный, он помог мне спасти человека с курсачом :) Сервис пофиксил документ с расширением .docm (стандартная ошибка в макросах Word 2010, не открывает после редактирования) и восстановил пользовательские стили. Всё круто, буду пользоваться в связке с облаком! Спасибо разработчику Андрею за \"рекламу\" сайта у нас в ДФ ННГУ)", - "author": "Карина Верба", - "date": "26 Марта 2017", + "value": "Отлично!", + "author": "Виталий Койструб", + "date": "18 Августа 2016", "rating": "5", - "photo": "karina_verba.png" - }, - { - "value": "Всё хорошо. Во время учебы пришлось искать облачный офис и выбор пал на OOP. За пару лет работы с ним сильных нареканий не возникало. Функциями и работой доволен. Порадовало так же, что в подключенных аккаунтах появился яндекс диск.", - "author": "Анатолий Ашулин", - "date": "27 Апреля 2017", - "rating": "5" + "photo": "vitali_koistrub.png" }, { "value": "Лучший \"облачный офис\", что мне когда-либо попадался. Но вот личное пожелание, добавьте возможность добавлять автособираемое оглавление.", @@ -275,93 +140,22 @@ "photo": "dmitri_malikov.png" }, { - "value": "Отлично!", - "author": "Виталий Койструб", - "date": "18 Августа 2016", + "value": "Отличный сервис. Из всех опробованных сервисов и программ обладает максимальной совместимостью с продуктами Microsoft Office.", + "author": "Александр Слюсарев", + "date": "14 Сентября 2014", "rating": "5", - "photo": "vitali_koistrub.png" + "photo": "Alexsandr_Slusarev.png" }, { - "value": "Понравилось. Твердая 5+", - "author": "Sergey Strelnikov", - "date": "14 Октября 2016", - "rating": "5", - "photo": "Sergey_Strelnikov.png" + "value": "Пожалуй лучший онлайн-редактор", + "author": "Denis Ozdemir", + "date": "24 Апреля 2014", + "rating": "5" } ] }, "es": { "reviews": [ - { - "value": "Es la mejor webapp para editar texto mejor que Documents de Drive y mucho mejor que Word de Web office. Un saludo y espero sigan mucho tiempo así", - "author": "SaJu CeLo", - "date": "6 de agosto 2014", - "rating": "5", - "photo": "SaJu_CeLo.png" - }, - { - "value": "Excelente aplicación. Sincroniza a la perfección con mi dropbox", - "author": "Emanuel Rodriguez", - "date": "10 de junio 2014", - "rating": "5", - "photo": "Emanuel_Rodriguez.png" - }, - { - "value": "Excelente aplicación, fácil de usar y gran compatibilidad !!!", - "author": "Samuel Valderrama Martínez", - "date": "17 de septiembre 2014", - "rating": "5", - "photo": "Samuel_Valderrama_Martinez.png" - }, - { - "value": "Al fin encontré una buena app para abrir mis documentos en linea.. :) .. Gracias!!", - "author": "Angie Benitez Serofani", - "date": "6 de mayo 2014", - "rating": "5", - "photo": "Angie_Benitez_Serofani.png" - }, - { - "value": "Es buenisimo para las cromebook 5 estrellas", - "author": "Luis chuta", - "date": "4 de mayo 2014", - "rating": "5", - "photo": "Luis_chuta.png" - }, - { - "value": "es buenísima...lo recomiendo...", - "author": "Omar Gallardo", - "date": "25 de septiembre 2014", - "rating": "5", - "photo": "Omar_Gallardo.png" - }, - { - "value": "Funciona muy bien!!", - "author": "Alonso Cardona Pereira", - "date": "14 de octubre 2014", - "rating": "5", - "photo": "Alonso_Cardona_Pereira.png" - }, - { - "value": "Una maravilla... Lo recomiendo!!!", - "author": "Jon Cortes", - "date": "29 de octubre 2014", - "rating": "5", - "photo": "Jon_Cortes.png" - }, - { - "value": "Me encanta! Excelente!", - "author": "Mauricio Oscar Alberto Piaggi", - "date": "10 de noviembre 2014", - "rating": "5", - "photo": "Mauricio_Oscar_Alberto_Piaggi.png" - }, - { - "value": "Excelente aplicación en la nube. La mejor para editar archivos de office.", - "author": "Pedro Vilanova", - "date": "18 de noviembre 2014", - "rating": "4", - "photo": "Pedro_Vilanova.png" - }, { "value": "Excelente aplicación, es lo mas parecido a la suite de ofimatica de Microsoft que he podido encontrar", "author": "Alexis Ascui", @@ -395,37 +189,31 @@ "date": "17 de mayo 2016", "rating": "5", "photo": "Carlos_Alberto.png" - } - ] - }, - "fr": { - "reviews": [ - { - "value": "Très bonne application. A utiliser sans réserve. Un plus, la connexion avec vos autres applications (dropbox...)", - "author": "Jean-Luc Plavis", - "date": "13 avril 2014", - "rating": "5" }, { - "value": "Très bonne application pour traiter ses fichiers en ligne.", - "author": "Franck Emile Kouassi", - "date": "6 mai 2014", + "value": "Es la mejor webapp para editar texto mejor que Documents de Drive y mucho mejor que Word de Web office. Un saludo y espero sigan mucho tiempo así", + "author": "SaJu CeLo", + "date": "6 de agosto 2014", "rating": "5", - "photo": "Franck_Emile_Kouassi.png" + "photo": "SaJu_CeLo.png" }, { - "value": "Bien pensée, bien faite, très intéressante la connexion avec les autres plateformes (Google Drive, Dropbox, OneDrive ...). En espérant des améliorations notables dans l'avenir.", - "author": "Eric Genestine", - "date": "16 avril 2014", - "rating": "3", - "photo": "Eric_Genestine.png" - }, + "value": "Excelente aplicación. Sincroniza a la perfección con mi dropbox", + "author": "Emanuel Rodriguez", + "date": "10 de junio 2014", + "rating": "5", + "photo": "Emanuel_Rodriguez.png" + } + ] + }, + "fr": { + "reviews": [ { - "value": "Accessibilité aux fonctions vraiment très simple mais l'interface n'est pas très jolie mais ca fait l'affaire", - "author": "kenneth nitcheu", - "date": "24 avr. 2014", + "value": "C'est pour ma part le meilleur ... 5 étoiles le jour ou cette application fonctionnera hors ligne ! Trés bien ... Merci", + "author": "Hervé COURTOIS", + "date": "24 septembre 2016", "rating": "4", - "photo": "kenneth_nitcheu.png" + "photo": "Herve_COURTOIS.png" }, { "value": "Utile pour ma part et bonne appréciation Continuez ....", @@ -435,16 +223,29 @@ "photo": "Arnaud_D.png" }, { - "value": "C'est pour ma part le meilleur ... 5 étoiles le jour ou cette application fonctionnera hors ligne ! Trés bien ... Merci", - "author": "Hervé COURTOIS", - "date": "24 septembre 2016", - "rating": "4", - "photo": "Herve_COURTOIS.png" + "value": "Très bonne application pour traiter ses fichiers en ligne.", + "author": "Franck Emile Kouassi", + "date": "6 mai 2014", + "rating": "5", + "photo": "Franck_Emile_Kouassi.png" + }, + { + "value": "Très bonne application. A utiliser sans réserve. Un plus, la connexion avec vos autres applications (dropbox...)", + "author": "Jean-Luc Plavis", + "date": "13 avril 2014", + "rating": "5" } ] }, "de": { "reviews": [ + { + "value": "SEHR BRAUCHBAR", + "author": "R. S.", + "date": "3. April 2017", + "rating": "4", + "photo": "r_s.png" + }, { "value": "Vorher bin ich Nutzer eines Notebooks mit Windows gewesen und bin auf ein Chromebook umgestiegen und die App ist so ziemlich die beste Alternative gegenüber Microsoft Office und man kann sogar seine Sprache auswählen.", "author": "Clemens Torno", @@ -458,13 +259,6 @@ "date": "27. Aug. 2014", "rating": "4", "photo": "Bert_Beck.png" - }, - { - "value": "SEHR BRAUCHBAR", - "author": "R. S.", - "date": "3. April 2017", - "rating": "4", - "photo": "r_s.png" } ] }, diff --git a/web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/css/images/flags.png b/web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/css/images/flags.png index a506a34450b0dc6dbf4366b2b284254a2296e394..785408f5d52d2fee2f8c36ad23463147cf2428ff 100644 GIT binary patch literal 6770 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 literal 4026 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 diff --git a/web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/css/userlanguages.less b/web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/css/userlanguages.less index 93df12650..7632230c4 100644 --- a/web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/css/userlanguages.less +++ b/web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/css/userlanguages.less @@ -92,5 +92,6 @@ .usrLang.ko-KR, .languageMenu ul.options li.option.ko-KR a{background-image:url("images/flags.png"); background-position: left -435px;} .usrLang.ja-JP, .languageMenu ul.options li.option.ja-JP a{background-image:url("images/flags.png"); background-position: left -457px;} .usrLang.sl-SI, .languageMenu ul.options li.option.sl-SI a{background-image:url("images/flags.png"); background-position: left -479px;} +.usrLang.sk-SK, .languageMenu ul.options li.option.sk-SK a{background-image:url("images/flags.png"); background-position: left -501px;} .languageMenu ul.options li.option.selected a{color:#116d9d;} diff --git a/web/studio/ASC.Web.Studio/Web.consumers.config b/web/studio/ASC.Web.Studio/Web.consumers.config index 3e9d97c8f..e81aafbe3 100644 --- a/web/studio/ASC.Web.Studio/Web.consumers.config +++ b/web/studio/ASC.Web.Studio/Web.consumers.config @@ -19,6 +19,10 @@ + + + + diff --git a/web/studio/ASC.Web.Studio/addons/calendar/ASC.Web.Calendar.csproj b/web/studio/ASC.Web.Studio/addons/calendar/ASC.Web.Calendar.csproj index cce5a1a39..6cdff0224 100644 --- a/web/studio/ASC.Web.Studio/addons/calendar/ASC.Web.Calendar.csproj +++ b/web/studio/ASC.Web.Studio/addons/calendar/ASC.Web.Calendar.csproj @@ -209,12 +209,12 @@
- diff --git a/web/studio/ASC.Web.Studio/addons/mail/ASC.Web.Mail.csproj b/web/studio/ASC.Web.Studio/addons/mail/ASC.Web.Mail.csproj index b580d8b5a..8ebd07f1a 100644 --- a/web/studio/ASC.Web.Studio/addons/mail/ASC.Web.Mail.csproj +++ b/web/studio/ASC.Web.Studio/addons/mail/ASC.Web.Mail.csproj @@ -442,12 +442,12 @@ - diff --git a/web/studio/ASC.Web.Studio/addons/talk/Default.aspx b/web/studio/ASC.Web.Studio/addons/talk/Default.aspx index 65c4329e5..86a8b7a5b 100644 --- a/web/studio/ASC.Web.Studio/addons/talk/Default.aspx +++ b/web/studio/ASC.Web.Studio/addons/talk/Default.aspx @@ -72,7 +72,7 @@
<%=string.Format(TalkOverviewResource.IntegrationWith3rdPartyAppsSectionContent, - "" + "here" + "") + "" + TalkOverviewResource.Here + "") %>
diff --git a/web/studio/ASC.Web.Studio/addons/talk/UserControls/ContactsContainer.ascx b/web/studio/ASC.Web.Studio/addons/talk/UserControls/ContactsContainer.ascx index 79fa457a3..cd2d5f565 100644 --- a/web/studio/ASC.Web.Studio/addons/talk/UserControls/ContactsContainer.ascx +++ b/web/studio/ASC.Web.Studio/addons/talk/UserControls/ContactsContainer.ascx @@ -32,6 +32,7 @@
  • +
    (/)
    diff --git a/web/studio/ASC.Web.Studio/addons/talk/UserControls/RoomsContainer.ascx b/web/studio/ASC.Web.Studio/addons/talk/UserControls/RoomsContainer.ascx index f3386ee48..0cfb6efed 100644 --- a/web/studio/ASC.Web.Studio/addons/talk/UserControls/RoomsContainer.ascx +++ b/web/studio/ASC.Web.Studio/addons/talk/UserControls/RoomsContainer.ascx @@ -102,16 +102,21 @@
      -
    • - -
      - -
      - +
    • + +
      +
      + +
      +
      +
      +
      +
      +
      + +
      -
      -
    -
  • +
    diff --git a/web/studio/ASC.Web.Studio/addons/talk/UserControls/TabsContainerPart.ascx b/web/studio/ASC.Web.Studio/addons/talk/UserControls/TabsContainerPart.ascx index 52adecd2b..3d1ab0c47 100644 --- a/web/studio/ASC.Web.Studio/addons/talk/UserControls/TabsContainerPart.ascx +++ b/web/studio/ASC.Web.Studio/addons/talk/UserControls/TabsContainerPart.ascx @@ -5,9 +5,11 @@