Merge branch 'develop' into feature/integration-system
This commit is contained in:
commit
b22e3da0dc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
12
ASC.Web.sln
12
ASC.Web.sln
@ -79,8 +79,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.CRM", "products\ASC.CRM
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Mail", "products\ASC.Mail\Server\ASC.Mail.csproj", "{137CA67B-D0F5-4746-B8BC-1888D2859B90}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Radicale", "common\services\ASC.Radicale\ASC.Radicale.csproj", "{74998718-3C9A-4A89-B834-14453762C60F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Web.HealthChecks.UI", "web\ASC.Web.HealthChecks.UI\ASC.Web.HealthChecks.UI.csproj", "{0C1A387E-0CD0-4BE8-82FC-9FCAD05BF289}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ClearEvents", "common\services\ASC.ClearEvents\ASC.ClearEvents.csproj", "{448221A8-EABA-4200-9192-E08BF241A487}"
|
||||
@ -103,6 +101,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.EventBus.RabbitMQ", "co
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.EventBus.Extensions.Logger", "common\ASC.EventBus.Extensions.Logger\ASC.EventBus.Extensions.Logger.csproj", "{ED8CEB38-7C95-43A8-B208-9C9828654AC1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Migration", "common\ASC.Migration\ASC.Migration.csproj", "{05B8FF27-446B-49BF-B508-4A4C096D2BB2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -245,10 +245,6 @@ Global
|
||||
{137CA67B-D0F5-4746-B8BC-1888D2859B90}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{137CA67B-D0F5-4746-B8BC-1888D2859B90}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{137CA67B-D0F5-4746-B8BC-1888D2859B90}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{74998718-3C9A-4A89-B834-14453762C60F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{74998718-3C9A-4A89-B834-14453762C60F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{74998718-3C9A-4A89-B834-14453762C60F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{74998718-3C9A-4A89-B834-14453762C60F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C1A387E-0CD0-4BE8-82FC-9FCAD05BF289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C1A387E-0CD0-4BE8-82FC-9FCAD05BF289}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C1A387E-0CD0-4BE8-82FC-9FCAD05BF289}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -293,6 +289,10 @@ Global
|
||||
{ED8CEB38-7C95-43A8-B208-9C9828654AC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED8CEB38-7C95-43A8-B208-9C9828654AC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED8CEB38-7C95-43A8-B208-9C9828654AC1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -16,6 +16,7 @@
|
||||
"common\\ASC.Feed\\ASC.Feed.csproj",
|
||||
"common\\ASC.IPSecurity\\ASC.IPSecurity.csproj",
|
||||
"common\\ASC.MessagingSystem\\ASC.MessagingSystem.csproj",
|
||||
"common\\ASC.Migration\\ASC.Migration.csproj",
|
||||
"common\\ASC.Notify.Textile\\ASC.Notify.Textile.csproj",
|
||||
"common\\ASC.Textile\\ASC.Textile.csproj",
|
||||
"common\\ASC.VoipService\\ASC.VoipService.csproj",
|
||||
|
@ -1,3 +1,5 @@
|
||||
@echo off
|
||||
|
||||
echo "##########################################################"
|
||||
echo "######### Start build and deploy Personal ##############"
|
||||
echo "##########################################################"
|
||||
@ -6,6 +8,7 @@ echo.
|
||||
|
||||
PUSHD %~dp0
|
||||
call runasadmin.bat "%~dpnx0"
|
||||
|
||||
if %errorlevel% == 0 (
|
||||
|
||||
call start\stop.bat nopause
|
||||
@ -18,7 +21,11 @@ call build\build.static.bat nopause personal
|
||||
echo "BACK-END"
|
||||
call build\build.backend.bat nopause
|
||||
|
||||
start /b call build\start\start.bat nopause
|
||||
PUSHD %~dp0
|
||||
|
||||
call start\start.bat nopause
|
||||
|
||||
echo.
|
||||
|
||||
pause
|
||||
)
|
@ -42,7 +42,7 @@ curl https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add -
|
||||
echo "deb https://artifacts.elastic.co/packages/${ELASTIC_DIST}.x/apt stable main" | tee /etc/apt/sources.list.d/elastic-${ELASTIC_DIST}.x.list
|
||||
|
||||
# add nodejs repo
|
||||
curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||
curl -sL https://deb.nodesource.com/setup_14.x | bash -
|
||||
|
||||
#add yarn repo
|
||||
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
@ -56,16 +56,16 @@ rm packages-microsoft-prod.deb
|
||||
#install kafka
|
||||
PRODUCT_DIR="/var/www/${product}"
|
||||
if [ "$(ls "$PRODUCT_DIR/services/kafka" 2> /dev/null)" == "" ]; then
|
||||
mkdir -p ${PRODUCT_DIR}/services/
|
||||
if ! cat /etc/passwd | grep -q "kafka"; then
|
||||
adduser --quiet --home ${PRODUCT_DIR}/services/kafka --system kafka
|
||||
mkdir -p ${PRODUCT_DIR}/services/kafka/
|
||||
if ! cat /etc/passwd | grep -q "onlyoffice"; then
|
||||
adduser --quiet --home ${PRODUCT_DIR} --system --group onlyoffice
|
||||
fi
|
||||
cd ${PRODUCT_DIR}/services/kafka
|
||||
KAFKA_VERSION=$(curl https://downloads.apache.org/kafka/ | grep -Eo '3.1.[0-9]' | tail -1)
|
||||
KAFKA_ARCHIVE=$(curl https://downloads.apache.org/kafka/$KAFKA_VERSION/ | grep -Eo "kafka_2.[0-9][0-9]-$KAFKA_VERSION.tgz" | tail -1)
|
||||
curl https://downloads.apache.org/kafka/$KAFKA_VERSION/$KAFKA_ARCHIVE -O
|
||||
tar xzf $KAFKA_ARCHIVE --strip 1 && rm -rf $KAFKA_ARCHIVE
|
||||
chown -R kafka ${PRODUCT_DIR}/services/kafka/
|
||||
chown -R onlyoffice ${PRODUCT_DIR}/services/kafka/
|
||||
cd -
|
||||
fi
|
||||
|
||||
@ -76,14 +76,13 @@ Requires=network.target remote-fs.target
|
||||
After=network.target remote-fs.target
|
||||
[Service]
|
||||
Type=simple
|
||||
User=kafka
|
||||
User=onlyoffice
|
||||
ExecStart=/bin/sh -c '${PRODUCT_DIR}/services/kafka/bin/zookeeper-server-start.sh ${PRODUCT_DIR}/services/kafka/config/zookeeper.properties > ${PRODUCT_DIR}/services/kafka/zookeeper.log 2>&1'
|
||||
ExecStop=${PRODUCT_DIR}/services/kafka/bin/zookeeper-server-stop.sh
|
||||
Restart=on-abnormal
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
systemctl start zookeeper
|
||||
fi
|
||||
|
||||
if [ ! -e /lib/systemd/system/kafka.service ]; then
|
||||
@ -93,14 +92,13 @@ Requires=zookeeper.service
|
||||
After=zookeeper.service
|
||||
[Service]
|
||||
Type=simple
|
||||
User=kafka
|
||||
User=onlyoffice
|
||||
ExecStart=/bin/sh -c '${PRODUCT_DIR}/services/kafka/bin/kafka-server-start.sh ${PRODUCT_DIR}/services/kafka/config/server.properties > ${PRODUCT_DIR}/services/kafka/kafka.log 2>&1'
|
||||
ExecStop=${PRODUCT_DIR}/services/kafka/bin/kafka-server-stop.sh
|
||||
Restart=on-abnormal
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
systemctl start kafka
|
||||
fi
|
||||
|
||||
if ! dpkg -l | grep -q "mysql-server"; then
|
||||
@ -154,7 +152,7 @@ apt-get install -o DPkg::options::="--force-confnew" -yq \
|
||||
g++ \
|
||||
make \
|
||||
yarn \
|
||||
dotnet-sdk-5.0 \
|
||||
dotnet-sdk-6.0 \
|
||||
mysql-server \
|
||||
mysql-client \
|
||||
postgresql \
|
||||
|
@ -63,6 +63,7 @@ MYSQL_USER=""
|
||||
MYSQL_PASSWORD=""
|
||||
MYSQL_ROOT_PASSWORD=""
|
||||
MYSQL_HOST=""
|
||||
DATABASE_MIGRATION="true"
|
||||
|
||||
ZOO_PORT=""
|
||||
ZOO_HOST=""
|
||||
@ -291,6 +292,13 @@ while [ "$1" != "" ]; do
|
||||
fi
|
||||
;;
|
||||
|
||||
-dbm | --databasemigration )
|
||||
if [ "$2" != "" ]; then
|
||||
DATABASE_MIGRATION=$2
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
|
||||
-? | -h | --help )
|
||||
echo " Usage: bash $HELP_TARGET [PARAMETER] [[PARAMETER], ...]"
|
||||
echo
|
||||
@ -320,6 +328,7 @@ while [ "$1" != "" ]; do
|
||||
echo " -ep, --externalport external appserver port (default value 8092)"
|
||||
echo " -mk, --machinekey setting for core.machinekey"
|
||||
echo " -ls, --local_scripts run the installation from local scripts"
|
||||
echo " -dbm, --databasemigration database migration (true|false)"
|
||||
echo " -?, -h, --help this help"
|
||||
echo
|
||||
echo " Install all the components without document server:"
|
||||
@ -538,6 +547,7 @@ install_docker_compose () {
|
||||
rm get-pip.py
|
||||
fi
|
||||
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install docker-compose
|
||||
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
|
||||
|
||||
@ -790,7 +800,6 @@ download_files () {
|
||||
fi
|
||||
|
||||
svn export --force https://github.com/ONLYOFFICE/${PRODUCT}/branches/${GIT_BRANCH}/build/install/docker/ ${BASE_DIR}
|
||||
svn export --force https://github.com/ONLYOFFICE/CommunityServer/branches/master/build/sql/ ${BASE_DIR}/config/ #Download SQL scripts
|
||||
|
||||
reconfigure STATUS ${STATUS}
|
||||
}
|
||||
@ -822,6 +831,7 @@ install_mysql_server () {
|
||||
reconfigure MYSQL_PASSWORD ${MYSQL_PASSWORD}
|
||||
reconfigure MYSQL_ROOT_PASSWORD ${MYSQL_ROOT_PASSWORD}
|
||||
reconfigure MYSQL_HOST ${MYSQL_HOST}
|
||||
reconfigure DATABASE_MIGRATION ${DATABASE_MIGRATION}
|
||||
|
||||
docker-compose -f $BASE_DIR/db.yml up -d
|
||||
}
|
||||
|
@ -140,13 +140,14 @@ if rpm -q "firewalld"; then
|
||||
fi
|
||||
|
||||
{ ${package_manager} check-update ${package_sysname}-${product}; APPSERVER_CHECK_UPDATE=$?; } || true
|
||||
if [[ $APPSERVER_CHECK_UPDATE -eq $UPDATE_AVAILABLE_CODE ]]; then
|
||||
APPSERVER_NEED_UPDATE="true"
|
||||
fi
|
||||
|
||||
if [ "$APPSERVER_INSTALLED" = "false" ]; then
|
||||
${package_manager} install -y ${package_sysname}-${product}
|
||||
elif [ "$APPSERVER_NEED_UPDATE" = "true" ]; then
|
||||
${product}-configuration.sh \
|
||||
-mysqlh ${MYSQL_SERVER_HOST} \
|
||||
-mysqld ${MYSQL_SERVER_DB_NAME} \
|
||||
-mysqlu ${MYSQL_SERVER_USER} \
|
||||
-mysqlp ${MYSQL_ROOT_PASS}
|
||||
elif [[ $APPSERVER_CHECK_UPDATE -eq $UPDATE_AVAILABLE_CODE ]]; then
|
||||
ENVIRONMENT="$(cat /lib/systemd/system/${product}-api.service | grep -oP 'ENVIRONMENT=\K.*')"
|
||||
USER_CONNECTIONSTRING=$(json -f /etc/onlyoffice/${product}/appsettings.$ENVIRONMENT.json ConnectionStrings.default.connectionString)
|
||||
MYSQL_SERVER_HOST=$(echo $USER_CONNECTIONSTRING | grep -oP 'Server=\K.*' | grep -o '^[^;]*')
|
||||
@ -156,34 +157,12 @@ elif [ "$APPSERVER_NEED_UPDATE" = "true" ]; then
|
||||
MYSQL_ROOT_PASS=$(echo $USER_CONNECTIONSTRING | grep -oP 'Password=\K.*' | grep -o '^[^;]*')
|
||||
|
||||
${package_manager} -y update ${package_sysname}-${product}
|
||||
fi
|
||||
|
||||
if [ "${APPSERVER_INSTALLED}" = "false" ] || [ "$APPSERVER_NEED_UPDATE" = "true" ]; then
|
||||
expect << EOF
|
||||
set timeout -1
|
||||
log_user 1
|
||||
|
||||
if { "${UPDATE}" == "true" } {
|
||||
spawn ${product}-configuration.sh -e ${ENVIRONMENT}
|
||||
} else {
|
||||
spawn ${product}-configuration.sh
|
||||
}
|
||||
|
||||
expect -re "Database host:"
|
||||
send "\025$MYSQL_SERVER_HOST\r"
|
||||
|
||||
expect -re "Database name:"
|
||||
send "\025$MYSQL_SERVER_DB_NAME\r"
|
||||
|
||||
expect -re "Database user:"
|
||||
send "\025$MYSQL_SERVER_USER\r"
|
||||
|
||||
expect -re "Database password:"
|
||||
send "\025$MYSQL_ROOT_PASS\r"
|
||||
|
||||
expect eof
|
||||
EOF
|
||||
APPSERVER_INSTALLED="true";
|
||||
${product}-configuration.sh \
|
||||
-e ${ENVIRONMENT} \
|
||||
-mysqlh ${MYSQL_SERVER_HOST} \
|
||||
-mysqld ${MYSQL_SERVER_DB_NAME} \
|
||||
-mysqlu ${MYSQL_SERVER_USER} \
|
||||
-mysqlp ${MYSQL_ROOT_PASS}
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
@ -62,7 +62,7 @@ rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-$REV.noarch.r
|
||||
rpm -ivh https://rpms.remirepo.net/enterprise/remi-release-$REV.rpm || true
|
||||
|
||||
#add nodejs repo
|
||||
curl -sL https://rpm.nodesource.com/setup_12.x | bash - || true
|
||||
curl -sL https://rpm.nodesource.com/setup_14.x | bash - || true
|
||||
|
||||
#add yarn
|
||||
curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | tee /etc/yum.repos.d/yarn.repo || true
|
||||
@ -183,7 +183,7 @@ ${package_manager} -y install epel-release \
|
||||
gcc-c++ \
|
||||
make \
|
||||
yarn \
|
||||
dotnet-sdk-5.0 \
|
||||
dotnet-sdk-6.0 \
|
||||
elasticsearch-${ELASTIC_VERSION} --enablerepo=elasticsearch \
|
||||
mysql-server \
|
||||
nginx \
|
||||
@ -207,4 +207,4 @@ if [ ! -e /usr/bin/json ]; then
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
package_services="rabbitmq-server postgresql redis supervisord nginx kafka mysqld"
|
||||
package_services="rabbitmq-server postgresql redis supervisord nginx mysqld"
|
||||
|
@ -0,0 +1,132 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import base64
|
||||
import sys
|
||||
import os
|
||||
import http.client
|
||||
|
||||
from radicale.auth import BaseAuth
|
||||
from radicale.log import logger
|
||||
import platform
|
||||
from urllib.parse import urlparse
|
||||
|
||||
if platform.system() == "Linux":
|
||||
sys.path.insert(0,'/usr/lib/python3/site-packages')
|
||||
import requests
|
||||
from urllib import request
|
||||
from urllib.parse import urlsplit
|
||||
from datetime import datetime, date, time
|
||||
|
||||
PLUGIN_CONFIG_SCHEMA = {
|
||||
"auth": {
|
||||
"portal_url": {"value": "", "type": str},
|
||||
"machine_key": {"value": "", "type": str}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Auth(BaseAuth):
|
||||
def __init__(self, configuration):
|
||||
super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA))
|
||||
|
||||
def create_auth_token(self, pkey, machine_key):
|
||||
|
||||
machine_key = bytes(machine_key, 'UTF-8')
|
||||
now = datetime.strftime(datetime.utcnow(), "%Y%m%d%H%M%S")
|
||||
|
||||
message = bytes('{0}\n{1}'.format(now, pkey), 'UTF-8')
|
||||
|
||||
_hmac = hmac.new(machine_key, message, hashlib.sha1)
|
||||
|
||||
signature = str(base64.urlsafe_b64encode(_hmac.digest()), 'UTF-8')
|
||||
signature = signature.replace('-', '+')
|
||||
signature = signature.replace('_', '/')
|
||||
token = 'ASC {0}:{1}:{2}'.format(pkey, now, signature)
|
||||
|
||||
logger.info('Auth token: %r', token)
|
||||
return token
|
||||
|
||||
def get_external_login(self, environ):
|
||||
self._environ = environ
|
||||
portal = ""
|
||||
if self._environ.get("PATH_INFO"):
|
||||
if len(self._environ.get("PATH_INFO").split('/')) >= 2:
|
||||
userName = self._environ.get("PATH_INFO").split('/')[1]
|
||||
if userName.find('@')!=-1:
|
||||
portal = userName.split('@')[2]
|
||||
if self._environ.get("HTTP_X_REWRITER_URL"):
|
||||
os.environ[portal + 'HTTP_X_REWRITER_URL'] = self._environ["HTTP_X_REWRITER_URL"] # hack: common value for all modules
|
||||
else:
|
||||
urlScheme = ""
|
||||
try:
|
||||
c = http.client.HTTPSConnection(portal)
|
||||
c.request("GET", "/")
|
||||
response = c.getresponse()
|
||||
urlScheme = "https"
|
||||
os.environ[portal + 'HTTP_X_REWRITER_URL'] = self._environ["HTTP_X_REWRITER_URL"]
|
||||
except:
|
||||
urlScheme = "http"
|
||||
os.environ[portal + 'HTTP_X_REWRITER_URL'] = urlScheme + "://" + portal
|
||||
|
||||
return()
|
||||
def login(self, login, password):
|
||||
portal_url = ""
|
||||
machine_key = self.configuration.get("auth", "machine_key")
|
||||
auth_token = self.create_auth_token("radicale", machine_key)
|
||||
|
||||
portal = ""
|
||||
if self._environ.get("PATH_INFO"):
|
||||
if len(self._environ.get("PATH_INFO").split('/')) >= 2:
|
||||
userName = self._environ.get("PATH_INFO").split('/')[1]
|
||||
if userName.find('@')!=-1:
|
||||
portal = userName.split('@')[2]
|
||||
|
||||
remote_host = ""
|
||||
rewriter_url = ""
|
||||
if os.environ[portal + 'HTTP_X_REWRITER_URL']:
|
||||
rewriter_url = os.environ[portal + 'HTTP_X_REWRITER_URL']
|
||||
parsed_uri = urlparse(rewriter_url)
|
||||
if parsed_uri.netloc != '':
|
||||
remote_host = parsed_uri.netloc.replace("'", "").split(':')[0]
|
||||
elif parsed_uri.path != '':
|
||||
remote_host = parsed_uri.path.replace("'", "").split(':')[0]
|
||||
else:
|
||||
logger.error("Authenticated error. Parse REWRITER_URL")
|
||||
return ""
|
||||
else:
|
||||
logger.error("Authenticated error. not exist HTTP_X_REWRITER_URL")
|
||||
return ""
|
||||
|
||||
try:
|
||||
logger.info('Remote host: %r', remote_host)
|
||||
portal_url = self.configuration.get("auth", "portal_url")
|
||||
url = portal_url+"/is_caldav_authenticated"
|
||||
payload = {'User': login+"@"+remote_host, 'Password': password}
|
||||
headers = {'Content-type': 'application/json', 'Authorization': auth_token, 'HTTP_X_REWRITER_URL': rewriter_url}
|
||||
res = requests.post(url, data=json.dumps(payload), headers=headers)
|
||||
|
||||
except:
|
||||
logger.error("Authenticated error. API system")
|
||||
res = False
|
||||
|
||||
try:
|
||||
response = res.json()
|
||||
except:
|
||||
logger.error("Authenticated error.")
|
||||
return ""
|
||||
|
||||
if res.status_code != 200:
|
||||
logger.error("Error login response: %r", response)
|
||||
return ""
|
||||
if 'error' in response:
|
||||
logger.error("Error login response: %r", response)
|
||||
return ""
|
||||
else:
|
||||
if 'value' in response:
|
||||
if response['value'] != "true":
|
||||
logger.error("Error login response: %r", response)
|
||||
return ""
|
||||
else:
|
||||
return login+"@"+remote_host
|
5
build/install/RadicalePlugins/app_auth_plugin/setup.py
Normal file
5
build/install/RadicalePlugins/app_auth_plugin/setup.py
Normal file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(name="app_auth_plugin", version='1.0.0', packages=["app_auth_plugin"])
|
@ -0,0 +1,67 @@
|
||||
import configparser
|
||||
import re
|
||||
|
||||
from radicale import pathutils, rights
|
||||
from radicale.log import logger
|
||||
from radicale import pathutils
|
||||
|
||||
|
||||
class Rights(rights.BaseRights):
|
||||
def __init__(self, configuration):
|
||||
super().__init__(configuration)
|
||||
self._filename = configuration.get("rights", "file")
|
||||
self.full_write_file_path = ""
|
||||
|
||||
def authorization(self, user, path):
|
||||
user = user or ""
|
||||
sane_path = pathutils.strip_path(path)
|
||||
# Prevent "regex injection"
|
||||
escaped_user = re.escape(user)
|
||||
rights_config = configparser.ConfigParser()
|
||||
try:
|
||||
if not rights_config.read(self._filename):
|
||||
raise RuntimeError("No such file: %r" %
|
||||
self._filename)
|
||||
except Exception as e:
|
||||
raise RuntimeError("Failed to load rights file %r: %s" %
|
||||
(self._filename, e)) from e
|
||||
if path=="/" or path=='':
|
||||
return rights_config.get("owner-write", "permissions")
|
||||
|
||||
if path.find("_write.ics") != -1:
|
||||
self.full_write_file_path = path
|
||||
elif path.find(".ics") != -1 and path.find("_write.ics") == -1:
|
||||
self.full_write_file_path = ""
|
||||
|
||||
for section in rights_config.sections():
|
||||
try:
|
||||
user_pattern = rights_config.get(section, "user")
|
||||
collection_pattern = rights_config.get(section, "collection")
|
||||
# Use empty format() for harmonized handling of curly braces
|
||||
user_match = re.fullmatch(user_pattern.format(), user)
|
||||
collection_match = user_match and re.fullmatch(
|
||||
collection_pattern.format(
|
||||
*map(re.escape, user_match.groups()),
|
||||
user=escaped_user), sane_path)
|
||||
file_match = True if self.full_write_file_path.find(path) != -1 and self.full_write_file_path != "" else False
|
||||
|
||||
except Exception as e:
|
||||
raise RuntimeError("Error in section %r of rights file %r: "
|
||||
"%s" % (section, self._filename, e)) from e
|
||||
if user_match and collection_match:
|
||||
if file_match and section == "allow-readonly":
|
||||
logger.debug("Rule %r:%r matches %r:%r from section %r Full Access",
|
||||
user, sane_path, user_pattern,
|
||||
collection_pattern, section)
|
||||
self.full_write_file_path = ""
|
||||
return rights_config.get("admin", "permissions")
|
||||
else:
|
||||
logger.debug("Rule %r:%r matches %r:%r from section %r",
|
||||
user, sane_path, user_pattern,
|
||||
collection_pattern, section)
|
||||
return rights_config.get(section, "permissions")
|
||||
logger.debug("Rule %r:%r doesn't match %r:%r from section %r",
|
||||
user, sane_path, user_pattern, collection_pattern,
|
||||
section)
|
||||
logger.info("Rights: %r:%r doesn't match any section", user, sane_path)
|
||||
return ""
|
5
build/install/RadicalePlugins/app_rights_plugin/setup.py
Normal file
5
build/install/RadicalePlugins/app_rights_plugin/setup.py
Normal file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(name="app_rights_plugin", version='1.0.0', packages=["app_rights_plugin"])
|
@ -0,0 +1,177 @@
|
||||
# This file is part of Radicale Server - Calendar Server
|
||||
# Copyright © 2014 Jean-Marc Martins
|
||||
# Copyright © 2012-2017 Guillaume Ayoub
|
||||
# Copyright © 2017-2019 Unrud <unrud@outlook.com>
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Storage backend that stores data in the file system.
|
||||
|
||||
Uses one folder per collection and one file per collection entry.
|
||||
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import platform
|
||||
from itertools import chain
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
from radicale import pathutils, storage
|
||||
from radicale.storage.multifilesystem.cache import CollectionCacheMixin
|
||||
from radicale.storage.multifilesystem.create_collection import \
|
||||
StorageCreateCollectionMixin
|
||||
from app_store_plugin.delete import CollectionDeleteMixin
|
||||
from radicale.storage.multifilesystem.discover import StorageDiscoverMixin
|
||||
from radicale.storage.multifilesystem.get import CollectionGetMixin
|
||||
from app_store_plugin.history import CollectionHistoryMixin
|
||||
from radicale.storage.multifilesystem.lock import (CollectionLockMixin,
|
||||
StorageLockMixin)
|
||||
from radicale.storage.multifilesystem.meta import CollectionMetaMixin
|
||||
from radicale.storage.multifilesystem.move import StorageMoveMixin
|
||||
from app_store_plugin.sync import CollectionSyncMixin
|
||||
from app_store_plugin.upload import CollectionUploadMixin
|
||||
from app_store_plugin.cache import CollectionCacheMixin
|
||||
from app_store_plugin import log
|
||||
from radicale.storage.multifilesystem.verify import StorageVerifyMixin
|
||||
|
||||
|
||||
PLUGIN_CONFIG_SCHEMA = {
|
||||
"storage": {
|
||||
"portal_url": {"value": "", "type": str}
|
||||
}
|
||||
}
|
||||
|
||||
class Collection(
|
||||
CollectionCacheMixin, CollectionDeleteMixin, CollectionGetMixin,
|
||||
CollectionHistoryMixin, CollectionLockMixin, CollectionMetaMixin,
|
||||
CollectionSyncMixin, CollectionUploadMixin, storage.BaseCollection):
|
||||
|
||||
def __init__(self, storage_, path, filesystem_path=None):
|
||||
self._storage = storage_
|
||||
folder = self._storage._get_collection_root_folder()
|
||||
# Path should already be sanitized
|
||||
self._path = pathutils.strip_path(path)
|
||||
self._encoding = self._storage.configuration.get("encoding", "stock")
|
||||
if filesystem_path is None:
|
||||
filesystem_path = pathutils.path_to_filesystem(folder, self.path)
|
||||
self._filesystem_path = filesystem_path
|
||||
self._etag_cache = None
|
||||
# Start logging
|
||||
filename = os.path.expanduser("radicale.log.config")
|
||||
try:
|
||||
log.start("radicale", filename)
|
||||
except Exception as e:
|
||||
print("ERROR: Failed to start logger: %s" % e, file=sys.stderr)
|
||||
|
||||
super().__init__()
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._path
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _atomic_write(self, path, mode="w", newline=None):
|
||||
parent_dir, name = os.path.split(path)
|
||||
prefix = ''
|
||||
# Do not use mkstemp because it creates with permissions 0o600
|
||||
with TemporaryDirectory(
|
||||
prefix=".Radicale.tmp-", dir=parent_dir) as tmp_dir:
|
||||
with open(prefix+os.path.join(tmp_dir, name), mode, newline=newline,
|
||||
encoding=None if "b" in mode else self._encoding) as tmp:
|
||||
yield tmp
|
||||
tmp.flush()
|
||||
self._storage._fsync(tmp)
|
||||
os.replace(prefix+os.path.join(tmp_dir, name), path)
|
||||
self._storage._sync_directory(parent_dir)
|
||||
|
||||
@property
|
||||
def last_modified(self):
|
||||
relevant_files = chain(
|
||||
(self._filesystem_path,),
|
||||
(self._props_path,) if os.path.exists(self._props_path) else (),
|
||||
(os.path.join(self._filesystem_path, h) for h in self._list()))
|
||||
last = max(map(os.path.getmtime, relevant_files))
|
||||
return time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(last))
|
||||
|
||||
@property
|
||||
def etag(self):
|
||||
# reuse cached value if the storage is read-only
|
||||
if self._storage._lock.locked == "w" or self._etag_cache is None:
|
||||
self._etag_cache = super().etag
|
||||
return self._etag_cache
|
||||
|
||||
|
||||
class Storage(
|
||||
StorageCreateCollectionMixin, StorageDiscoverMixin, StorageLockMixin,
|
||||
StorageMoveMixin, StorageVerifyMixin, storage.BaseStorage):
|
||||
|
||||
_collection_class = Collection
|
||||
|
||||
def __init__(self, configuration):
|
||||
super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA))
|
||||
folder = configuration.get("storage", "filesystem_folder")
|
||||
self._makedirs_synced(folder)
|
||||
|
||||
def _get_collection_root_folder(self):
|
||||
filesystem_folder = self.configuration.get(
|
||||
"storage", "filesystem_folder")
|
||||
return os.path.join(filesystem_folder, "collection-root")
|
||||
|
||||
def _fsync(self, f):
|
||||
if self.configuration.get("storage", "_filesystem_fsync"):
|
||||
try:
|
||||
pathutils.fsync(f.fileno())
|
||||
except OSError as e:
|
||||
raise RuntimeError("Fsync'ing file %r failed: %s" %
|
||||
(f.name, e)) from e
|
||||
|
||||
def _sync_directory(self, path):
|
||||
"""Sync directory to disk.
|
||||
|
||||
This only works on POSIX and does nothing on other systems.
|
||||
|
||||
"""
|
||||
if not self.configuration.get("storage", "_filesystem_fsync"):
|
||||
return
|
||||
if os.name == "posix":
|
||||
try:
|
||||
fd = os.open(path, 0)
|
||||
try:
|
||||
pathutils.fsync(fd)
|
||||
finally:
|
||||
os.close(fd)
|
||||
except OSError as e:
|
||||
raise RuntimeError("Fsync'ing directory %r failed: %s" %
|
||||
(path, e)) from e
|
||||
|
||||
def _makedirs_synced(self, filesystem_path):
|
||||
"""Recursively create a directory and its parents in a sync'ed way.
|
||||
|
||||
This method acts silently when the folder already exists.
|
||||
|
||||
"""
|
||||
if os.path.isdir(filesystem_path):
|
||||
return
|
||||
parent_filesystem_path = os.path.dirname(filesystem_path)
|
||||
# Prevent infinite loop
|
||||
if filesystem_path != parent_filesystem_path:
|
||||
# Create parent dirs recursively
|
||||
self._makedirs_synced(parent_filesystem_path)
|
||||
# Possible race!
|
||||
os.makedirs(filesystem_path, exist_ok=True)
|
||||
self._sync_directory(parent_filesystem_path)
|
@ -0,0 +1,98 @@
|
||||
import os
|
||||
import pickle
|
||||
import time
|
||||
import platform
|
||||
from hashlib import sha256
|
||||
|
||||
from radicale import pathutils, storage
|
||||
from radicale.log import logger
|
||||
|
||||
|
||||
class CollectionCacheMixin:
|
||||
def _clean_cache(self, folder, names, max_age=None):
|
||||
"""Delete all ``names`` in ``folder`` that are older than ``max_age``.
|
||||
"""
|
||||
age_limit = time.time() - max_age if max_age is not None else None
|
||||
modified = False
|
||||
for name in names:
|
||||
if not pathutils.is_safe_filesystem_path_component(name):
|
||||
continue
|
||||
if age_limit is not None:
|
||||
try:
|
||||
# Race: Another process might have deleted the file.
|
||||
mtime = os.path.getmtime(os.path.join(folder, name))
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
if mtime > age_limit:
|
||||
continue
|
||||
logger.debug("Found expired item in cache: %r", name)
|
||||
# Race: Another process might have deleted or locked the
|
||||
# file.
|
||||
try:
|
||||
os.remove(os.path.join(folder, name))
|
||||
except (FileNotFoundError, PermissionError):
|
||||
continue
|
||||
modified = True
|
||||
if modified:
|
||||
self._storage._sync_directory(folder)
|
||||
|
||||
@staticmethod
|
||||
def _item_cache_hash(raw_text):
|
||||
_hash = sha256()
|
||||
_hash.update(storage.CACHE_VERSION)
|
||||
_hash.update(raw_text)
|
||||
return _hash.hexdigest()
|
||||
|
||||
def _item_cache_content(self, item, cache_hash=None):
|
||||
text = item.serialize()
|
||||
if cache_hash is None:
|
||||
cache_hash = self._item_cache_hash(text.encode(self._encoding))
|
||||
return (cache_hash, item.uid, item.etag, text, item.name,
|
||||
item.component_name, *item.time_range)
|
||||
|
||||
def _store_item_cache(self, href, item, cache_hash=None):
|
||||
prefix = ''
|
||||
if platform.system() == 'Windows':
|
||||
prefix = '\\\\?\\'
|
||||
cache_folder = os.path.join(prefix+self._filesystem_path, ".Radicale.cache",
|
||||
"item")
|
||||
content = self._item_cache_content(item, cache_hash)
|
||||
self._storage._makedirs_synced(cache_folder)
|
||||
try:
|
||||
# Race: Other processes might have created and locked the
|
||||
# file.
|
||||
with self._atomic_write(os.path.join(cache_folder, href),
|
||||
"wb") as f:
|
||||
pickle.dump(content, f)
|
||||
except PermissionError:
|
||||
pass
|
||||
return content
|
||||
|
||||
def _load_item_cache(self, href, input_hash):
|
||||
prefix = ''
|
||||
if platform.system() == 'Windows':
|
||||
prefix = '\\\\?\\'
|
||||
cache_folder = os.path.join(prefix+self._filesystem_path, ".Radicale.cache",
|
||||
"item")
|
||||
cache_hash = uid = etag = text = name = tag = start = end = None
|
||||
try:
|
||||
with open(os.path.join(cache_folder, href), "rb") as f:
|
||||
cache_hash, *content = pickle.load(f)
|
||||
if cache_hash == input_hash:
|
||||
uid, etag, text, name, tag, start, end = content
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except (pickle.UnpicklingError, ValueError) as e:
|
||||
logger.warning("Failed to load item cache entry %r in %r: %s",
|
||||
href, self.path, e, exc_info=True)
|
||||
return cache_hash, uid, etag, text, name, tag, start, end
|
||||
|
||||
def _clean_item_cache(self):
|
||||
prefix = ''
|
||||
if platform.system() == 'Windows':
|
||||
prefix = '\\\\?\\'
|
||||
cache_folder = os.path.join(prefix+self._filesystem_path, ".Radicale.cache",
|
||||
"item")
|
||||
self._clean_cache(cache_folder, (
|
||||
e.name for e in os.scandir(cache_folder) if not
|
||||
os.path.isfile(os.path.join(self._filesystem_path, e.name))))
|
@ -0,0 +1,52 @@
|
||||
import os
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
from radicale import pathutils, storage
|
||||
import requests
|
||||
from urllib import request
|
||||
|
||||
class CollectionDeleteMixin:
|
||||
def delete(self, href=None):
|
||||
if href != None:
|
||||
user = self.path.split("/")[0]
|
||||
domain = user.split("@")[2]
|
||||
self.delete_event_portals(self.path+"/"+href, domain)
|
||||
if href is None:
|
||||
# Delete the collection
|
||||
parent_dir = os.path.dirname(self._filesystem_path)
|
||||
try:
|
||||
os.rmdir(self._filesystem_path)
|
||||
except OSError:
|
||||
with TemporaryDirectory(
|
||||
prefix=".Radicale.tmp-", dir=parent_dir) as tmp:
|
||||
os.rename(self._filesystem_path, os.path.join(
|
||||
tmp, os.path.basename(self._filesystem_path)))
|
||||
self._storage._sync_directory(parent_dir)
|
||||
else:
|
||||
self._storage._sync_directory(parent_dir)
|
||||
else:
|
||||
# Delete an item
|
||||
if not pathutils.is_safe_filesystem_path_component(href):
|
||||
raise pathutils.UnsafePathError(href)
|
||||
path = pathutils.path_to_filesystem(self._filesystem_path, href)
|
||||
if not os.path.isfile(path):
|
||||
raise storage.ComponentNotFoundError(href)
|
||||
os.remove(path)
|
||||
self._storage._sync_directory(os.path.dirname(path))
|
||||
# Track the change
|
||||
self._update_history_etag(href, None)
|
||||
self._clean_history()
|
||||
|
||||
def delete_event_portals(self, path, domain):
|
||||
portal = ""
|
||||
userName = path.split('/')[0]
|
||||
portal = userName.split('@')[2]
|
||||
|
||||
rewriter_url = os.environ.get(portal + 'HTTP_X_REWRITER_URL', '')
|
||||
portal_url = self._storage.configuration.get("storage", "portal_url")
|
||||
machine_key = self._storage.configuration.get("auth", "machine_key")
|
||||
auth_token = self.create_auth_token("radicale", machine_key)
|
||||
|
||||
headers = {'Authorization': auth_token, 'HTTP_X_REWRITER_URL': rewriter_url if rewriter_url.find(domain) != -1 else ""}
|
||||
url = portal_url+"/caldav_delete_event?eventInfo={}".format (path)
|
||||
resp = requests.get(url, headers=headers)
|
@ -0,0 +1,73 @@
|
||||
import binascii
|
||||
import os
|
||||
import pickle
|
||||
import platform
|
||||
|
||||
from radicale import item as radicale_item
|
||||
from radicale import pathutils
|
||||
from radicale.log import logger
|
||||
|
||||
|
||||
class CollectionHistoryMixin:
|
||||
def _update_history_etag(self, href, item):
|
||||
"""Updates and retrieves the history etag from the history cache.
|
||||
|
||||
The history cache contains a file for each current and deleted item
|
||||
of the collection. These files contain the etag of the item (empty
|
||||
string for deleted items) and a history etag, which is a hash over
|
||||
the previous history etag and the etag separated by "/".
|
||||
"""
|
||||
prefix = ''
|
||||
if platform.system() == 'Windows':
|
||||
prefix = '\\\\?\\'
|
||||
history_folder = os.path.join(prefix+self._filesystem_path,
|
||||
".Radicale.cache", "history")
|
||||
try:
|
||||
with open(os.path.join(history_folder, href), "rb") as f:
|
||||
cache_etag, history_etag = pickle.load(f)
|
||||
except (FileNotFoundError, pickle.UnpicklingError, ValueError) as e:
|
||||
if isinstance(e, (pickle.UnpicklingError, ValueError)):
|
||||
logger.warning(
|
||||
"Failed to load history cache entry %r in %r: %s",
|
||||
href, self.path, e, exc_info=True)
|
||||
cache_etag = ""
|
||||
# Initialize with random data to prevent collisions with cleaned
|
||||
# expired items.
|
||||
history_etag = binascii.hexlify(os.urandom(16)).decode("ascii")
|
||||
etag = item.etag if item else ""
|
||||
if etag != cache_etag:
|
||||
self._storage._makedirs_synced(history_folder)
|
||||
history_etag = radicale_item.get_etag(
|
||||
history_etag + "/" + etag).strip("\"")
|
||||
try:
|
||||
# Race: Other processes might have created and locked the file.
|
||||
with self._atomic_write(os.path.join(history_folder, href),
|
||||
"wb") as f:
|
||||
pickle.dump([etag, history_etag], f)
|
||||
except PermissionError:
|
||||
pass
|
||||
return history_etag
|
||||
|
||||
def _get_deleted_history_hrefs(self):
|
||||
"""Returns the hrefs of all deleted items that are still in the
|
||||
history cache."""
|
||||
history_folder = os.path.join(self._filesystem_path,
|
||||
".Radicale.cache", "history")
|
||||
try:
|
||||
for entry in os.scandir(history_folder):
|
||||
href = entry.name
|
||||
if not pathutils.is_safe_filesystem_path_component(href):
|
||||
continue
|
||||
if os.path.isfile(os.path.join(self._filesystem_path, href)):
|
||||
continue
|
||||
yield href
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def _clean_history(self):
|
||||
# Delete all expired history entries of deleted items.
|
||||
history_folder = os.path.join(self._filesystem_path,
|
||||
".Radicale.cache", "history")
|
||||
self._clean_cache(history_folder, self._get_deleted_history_hrefs(),
|
||||
max_age=self._storage.configuration.get(
|
||||
"storage", "max_sync_token_age"))
|
@ -0,0 +1,51 @@
|
||||
import logging
|
||||
import logging.config
|
||||
import signal
|
||||
import sys
|
||||
|
||||
|
||||
def configure_from_file(logger, filename, debug):
|
||||
logging.config.fileConfig(filename, disable_existing_loggers=False)
|
||||
if debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
for handler in logger.handlers:
|
||||
handler.setLevel(logging.DEBUG)
|
||||
return logger
|
||||
|
||||
|
||||
class RemoveTracebackFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
record.exc_info = None
|
||||
return True
|
||||
|
||||
|
||||
def start(name="radicale", filename=None, debug=False):
|
||||
"""Start the logging according to the configuration."""
|
||||
logger = logging.getLogger(name)
|
||||
if debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
logger.addFilter(RemoveTracebackFilter())
|
||||
if filename:
|
||||
# Configuration taken from file
|
||||
try:
|
||||
configure_from_file(logger, filename, debug)
|
||||
except Exception as e:
|
||||
raise RuntimeError("Failed to load logging configuration file %r: "
|
||||
"%s" % (filename, e)) from e
|
||||
# Reload config on SIGHUP (UNIX only)
|
||||
if hasattr(signal, "SIGHUP"):
|
||||
def handler(signum, frame):
|
||||
try:
|
||||
configure_from_file(logger, filename, debug)
|
||||
except Exception as e:
|
||||
logger.error("Failed to reload logging configuration file "
|
||||
"%r: %s", filename, e, exc_info=True)
|
||||
signal.signal(signal.SIGHUP, handler)
|
||||
else:
|
||||
# Default configuration, standard output
|
||||
handler = logging.StreamHandler(sys.stderr)
|
||||
handler.setFormatter(
|
||||
logging.Formatter("[%(thread)x] %(levelname)s: %(message)s"))
|
||||
logger.addHandler(handler)
|
||||
return logger
|
@ -0,0 +1,106 @@
|
||||
import itertools
|
||||
import os
|
||||
import pickle
|
||||
import platform
|
||||
|
||||
from hashlib import sha256
|
||||
|
||||
from radicale.log import logger
|
||||
|
||||
|
||||
class CollectionSyncMixin:
|
||||
def sync(self, old_token=None):
|
||||
# The sync token has the form http://radicale.org/ns/sync/TOKEN_NAME
|
||||
# where TOKEN_NAME is the sha256 hash of all history etags of present
|
||||
# and past items of the collection.
|
||||
def check_token_name(token_name):
|
||||
if len(token_name) != 64:
|
||||
return False
|
||||
for c in token_name:
|
||||
if c not in "0123456789abcdef":
|
||||
return False
|
||||
return True
|
||||
|
||||
old_token_name = None
|
||||
if old_token:
|
||||
# Extract the token name from the sync token
|
||||
if not old_token.startswith("http://radicale.org/ns/sync/"):
|
||||
raise ValueError("Malformed token: %r" % old_token)
|
||||
old_token_name = old_token[len("http://radicale.org/ns/sync/"):]
|
||||
if not check_token_name(old_token_name):
|
||||
raise ValueError("Malformed token: %r" % old_token)
|
||||
# Get the current state and sync-token of the collection.
|
||||
state = {}
|
||||
token_name_hash = sha256()
|
||||
# Find the history of all existing and deleted items
|
||||
for href, item in itertools.chain(
|
||||
((item.href, item) for item in self.get_all()),
|
||||
((href, None) for href in self._get_deleted_history_hrefs())):
|
||||
history_etag = self._update_history_etag(href, item)
|
||||
state[href] = history_etag
|
||||
token_name_hash.update((href + "/" + history_etag).encode())
|
||||
token_name = token_name_hash.hexdigest()
|
||||
token = "http://radicale.org/ns/sync/%s" % token_name
|
||||
if token_name == old_token_name:
|
||||
# Nothing changed
|
||||
return token, ()
|
||||
token_folder = os.path.join(self._filesystem_path,
|
||||
".Radicale.cache", "sync-token")
|
||||
token_path = os.path.join(token_folder, token_name)
|
||||
old_state = {}
|
||||
if old_token_name:
|
||||
# load the old token state
|
||||
old_token_path = os.path.join(token_folder, old_token_name)
|
||||
try:
|
||||
# Race: Another process might have deleted the file.
|
||||
with open(old_token_path, "rb") as f:
|
||||
old_state = pickle.load(f)
|
||||
except (FileNotFoundError, pickle.UnpicklingError,
|
||||
ValueError) as e:
|
||||
if isinstance(e, (pickle.UnpicklingError, ValueError)):
|
||||
logger.warning(
|
||||
"Failed to load stored sync token %r in %r: %s",
|
||||
old_token_name, self.path, e, exc_info=True)
|
||||
# Delete the damaged file
|
||||
try:
|
||||
os.remove(old_token_path)
|
||||
except (FileNotFoundError, PermissionError):
|
||||
pass
|
||||
raise ValueError("Token not found: %r" % old_token)
|
||||
# write the new token state or update the modification time of
|
||||
# existing token state
|
||||
if not os.path.exists(token_path):
|
||||
self._storage._makedirs_synced(token_folder)
|
||||
try:
|
||||
# Race: Other processes might have created and locked the file.
|
||||
prefix = ''
|
||||
if platform.system() == 'Windows':
|
||||
prefix = '\\\\?\\'
|
||||
with self._atomic_write(prefix+token_path, "wb") as f:
|
||||
pickle.dump(state, f)
|
||||
except PermissionError:
|
||||
pass
|
||||
else:
|
||||
# clean up old sync tokens and item cache
|
||||
self._clean_cache(token_folder, os.listdir(token_folder),
|
||||
max_age=self._storage.configuration.get(
|
||||
"storage", "max_sync_token_age"))
|
||||
self._clean_history()
|
||||
else:
|
||||
# Try to update the modification time
|
||||
try:
|
||||
# Race: Another process might have deleted the file.
|
||||
os.utime(token_path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
changes = []
|
||||
# Find all new, changed and deleted (that are still in the item cache)
|
||||
# items
|
||||
for href, history_etag in state.items():
|
||||
if history_etag != old_state.get(href):
|
||||
changes.append(href)
|
||||
# Find all deleted items that are no longer in the item cache
|
||||
for href, history_etag in old_state.items():
|
||||
if href not in state:
|
||||
changes.append(href)
|
||||
return token, changes
|
@ -0,0 +1,151 @@
|
||||
# This file is part of Radicale Server - Calendar Server
|
||||
# Copyright © 2014 Jean-Marc Martins
|
||||
# Copyright © 2012-2017 Guillaume Ayoub
|
||||
# Copyright © 2017-2018 Unrud <unrud@outlook.com>
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import pickle
|
||||
|
||||
from radicale import item as radicale_item
|
||||
from radicale import pathutils
|
||||
from radicale import logger
|
||||
from datetime import datetime, date, time
|
||||
import time
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import requests
|
||||
from urllib import request
|
||||
from threading import Thread
|
||||
from configparser import RawConfigParser
|
||||
class CollectionUploadMixin:
|
||||
def upload(self, href, item):
|
||||
if not pathutils.is_safe_filesystem_path_component(href):
|
||||
raise pathutils.UnsafePathError(href)
|
||||
try:
|
||||
self._store_item_cache(href, item)
|
||||
except Exception as e:
|
||||
raise ValueError("Failed to store item %r in collection %r: %s" %
|
||||
(href, self.path, e)) from e
|
||||
path = pathutils.path_to_filesystem(self._filesystem_path, href)
|
||||
with self._atomic_write(path, newline="") as fd:
|
||||
fd.write(item.serialize())
|
||||
# Clean the cache after the actual item is stored, or the cache entry
|
||||
# will be removed again.
|
||||
self._clean_item_cache()
|
||||
# Track the change
|
||||
user = self.path.split("/")[0]
|
||||
domain = user.split("@")[2]
|
||||
try:
|
||||
if item.serialize().find("PRODID:-//Office//Portal//EN") == -1:
|
||||
th = Thread(target=self.set_to_portals, args=(self.path + "/" + href,domain))
|
||||
th.start()
|
||||
|
||||
except:
|
||||
logger.error("Portal sending error.")
|
||||
|
||||
self._update_history_etag(href, item)
|
||||
self._clean_history()
|
||||
return self._get(href, verify_href=False)
|
||||
def create_auth_token(self, pkey, machine_key):
|
||||
|
||||
machine_key = bytes(machine_key, 'UTF-8')
|
||||
now = datetime.strftime(datetime.utcnow(), "%Y%m%d%H%M%S")
|
||||
|
||||
message = bytes('{0}\n{1}'.format(now, pkey), 'UTF-8')
|
||||
|
||||
_hmac = hmac.new(machine_key, message, hashlib.sha1)
|
||||
|
||||
signature = str(base64.urlsafe_b64encode(_hmac.digest()), 'UTF-8')
|
||||
signature = signature.replace('-', '+')
|
||||
signature = signature.replace('_', '/')
|
||||
token = 'ASC {0}:{1}:{2}'.format(pkey, now, signature)
|
||||
|
||||
logger.debug('Auth token: %r', token)
|
||||
return token
|
||||
|
||||
def set_to_portals(self, path, domain):
|
||||
portal = ""
|
||||
userName = path.split('/')[0]
|
||||
portal = userName.split('@')[2]
|
||||
|
||||
rewriter_url = os.environ.get("localhost" + 'HTTP_X_REWRITER_URL', '')
|
||||
portal_url = self._storage.configuration.get("storage", "portal_url")
|
||||
machine_key = self._storage.configuration.get("auth", "machine_key")
|
||||
auth_token = self.create_auth_token("radicale", machine_key)
|
||||
headers = {'Authorization': auth_token, 'HTTP_X_REWRITER_URL': rewriter_url if rewriter_url.find(domain) != -1 else "" }
|
||||
url = portal_url+"/change_to_storage?change={}".format (path)
|
||||
resp = requests.get(url, headers=headers)
|
||||
|
||||
def _upload_all_nonatomic(self, items, suffix=""):
|
||||
"""Upload a new set of items.
|
||||
|
||||
This takes a list of vobject items and
|
||||
uploads them nonatomic and without existence checks.
|
||||
|
||||
"""
|
||||
cache_folder = os.path.join(self._filesystem_path,
|
||||
".Radicale.cache", "item")
|
||||
self._storage._makedirs_synced(cache_folder)
|
||||
hrefs = set()
|
||||
for item in items:
|
||||
uid = item.uid
|
||||
try:
|
||||
cache_content = self._item_cache_content(item)
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
"Failed to store item %r in temporary collection %r: %s" %
|
||||
(uid, self.path, e)) from e
|
||||
href_candidate_funtions = []
|
||||
if os.name in ("nt", "posix"):
|
||||
href_candidate_funtions.append(
|
||||
lambda: uid if uid.lower().endswith(suffix.lower())
|
||||
else uid + suffix)
|
||||
href_candidate_funtions.extend((
|
||||
lambda: radicale_item.get_etag(uid).strip('"') + suffix,
|
||||
lambda: radicale_item.find_available_uid(hrefs.__contains__,
|
||||
suffix)))
|
||||
href = f = None
|
||||
while href_candidate_funtions:
|
||||
href = href_candidate_funtions.pop(0)()
|
||||
if href in hrefs:
|
||||
continue
|
||||
if not pathutils.is_safe_filesystem_path_component(href):
|
||||
if not href_candidate_funtions:
|
||||
raise pathutils.UnsafePathError(href)
|
||||
continue
|
||||
try:
|
||||
f = open(pathutils.path_to_filesystem(
|
||||
self._filesystem_path, href),
|
||||
"w", newline="", encoding=self._encoding)
|
||||
break
|
||||
except OSError as e:
|
||||
if href_candidate_funtions and (
|
||||
os.name == "posix" and e.errno == 22 or
|
||||
os.name == "nt" and e.errno == 123):
|
||||
continue
|
||||
raise
|
||||
with f:
|
||||
f.write(item.serialize())
|
||||
f.flush()
|
||||
self._storage._fsync(f)
|
||||
hrefs.add(href)
|
||||
with open(os.path.join(cache_folder, href), "wb") as f:
|
||||
pickle.dump(cache_content, f)
|
||||
f.flush()
|
||||
self._storage._fsync(f)
|
||||
self._storage._sync_directory(cache_folder)
|
||||
self._storage._sync_directory(self._filesystem_path)
|
3
build/install/RadicalePlugins/app_store_plugin/setup.py
Normal file
3
build/install/RadicalePlugins/app_store_plugin/setup.py
Normal file
@ -0,0 +1,3 @@
|
||||
from distutils.core import setup
|
||||
|
||||
setup(name="app_store_plugin", version='1.0.0', packages=["app_store_plugin"])
|
13
build/install/RadicalePlugins/dependences.txt
Normal file
13
build/install/RadicalePlugins/dependences.txt
Normal file
@ -0,0 +1,13 @@
|
||||
./app_store_plugin
|
||||
./app_auth_plugin
|
||||
./app_rights_plugin
|
||||
pytz
|
||||
vobject
|
||||
certifi
|
||||
chardet
|
||||
idna
|
||||
python_dateutil
|
||||
six
|
||||
urllib3
|
||||
requests
|
||||
radicale==3.0.5
|
@ -92,7 +92,7 @@ while [ "$1" != "" ]; do
|
||||
|
||||
-zkp | --zookeeperport )
|
||||
if [ "$2" != "" ]; then
|
||||
ZOOKEEPER_HOST=$2
|
||||
ZOOKEEPER_PORT=$2
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
@ -208,30 +208,26 @@ install_json() {
|
||||
chown onlyoffice:onlyoffice $USER_CONF
|
||||
|
||||
set_core_machinekey
|
||||
$JSON_USERCONF "this.core={'base-domain': \"$APP_HOST\", 'machinekey': \"$CORE_MACHINEKEY\" }" \
|
||||
$JSON_USERCONF "this.core={'base-domain': \"$APP_HOST\", 'machinekey': \"$CORE_MACHINEKEY\", \
|
||||
'products': { 'folder': '/var/www/appserver/products', 'subfolder': 'server'} }" \
|
||||
-e "this.urlshortener={ 'path': '../ASC.UrlShortener/index.js' }" -e "this.thumb={ 'path': '../ASC.Thumbnails/' }" \
|
||||
-e "this.socket={ 'path': '../ASC.Socket.IO/' }" -e "this.ssoauth={ 'path': '../ASC.SsoAuth/' }" >/dev/null 2>&1
|
||||
$JSON $APP_DIR/appsettings.json -e "this.core.products.subfolder='server'" >/dev/null 2>&1
|
||||
$JSON $APP_DIR/appsettings.services.json -e "this.core={ 'products': { 'folder': '../../products', 'subfolder': 'server'} }" >/dev/null 2>&1
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
restart_services() {
|
||||
echo -n "Restarting services... "
|
||||
|
||||
sed -i "s/Type=.*/Type=simple/" $SYSTEMD_DIR/${PRODUCT}-calendar.service >/dev/null 2>&1 #Fix non-start of service
|
||||
sed -i "s/ENVIRONMENT=.*/ENVIRONMENT=$ENVIRONMENT/" $SYSTEMD_DIR/${PRODUCT}*.service >/dev/null 2>&1
|
||||
systemctl daemon-reload
|
||||
|
||||
for SVC in nginx ${MYSQL_PACKAGE} ${PRODUCT}-api ${PRODUCT}-api-system ${PRODUCT}-urlshortener ${PRODUCT}-thumbnails \
|
||||
${PRODUCT}-socket ${PRODUCT}-studio-notify ${PRODUCT}-notify ${PRODUCT}-people-server ${PRODUCT}-files \
|
||||
${PRODUCT}-files-services ${PRODUCT}-studio ${PRODUCT}-backup ${PRODUCT}-storage-encryption \
|
||||
${PRODUCT}-storage-migration ${PRODUCT}-projects-server ${PRODUCT}-telegram-service ${PRODUCT}-crm \
|
||||
${PRODUCT}-calendar ${PRODUCT}-mail elasticsearch kafka zookeeper
|
||||
${PRODUCT}-storage-migration ${PRODUCT}-telegram-service elasticsearch $KAFKA_SERVICE $ZOOKEEPER_SERVICE
|
||||
do
|
||||
systemctl enable $SVC.service >/dev/null 2>&1
|
||||
systemctl restart $SVC.service
|
||||
systemctl enable $SVC >/dev/null 2>&1
|
||||
systemctl restart $SVC
|
||||
done
|
||||
echo "OK"
|
||||
}
|
||||
@ -242,10 +238,27 @@ input_db_params(){
|
||||
local def_DB_NAME=$(echo $user_connectionString | grep -oP 'Database=\K.*' | grep -o '^[^;]*')
|
||||
local def_DB_USER=$(echo $user_connectionString | grep -oP 'User ID=\K.*' | grep -o '^[^;]*')
|
||||
|
||||
if [ -z $def_DB_HOST ] && [ -z $DB_HOST ]; then read -e -p "Database host: " -i "$DB_HOST" DB_HOST; fi
|
||||
if [ -z $def_DB_NAME ] && [ -z $DB_NAME ]; then read -e -p "Database name: " -i "$DB_NAME" DB_NAME; fi
|
||||
if [ -z $def_DB_USER ] && [ -z $DB_USER ]; then read -e -p "Database user: " -i "$DB_USER" DB_USER; fi
|
||||
if [ -z $DB_PWD ]; then read -e -p "Database password: " -i "$DB_PWD" DB_PWD; fi
|
||||
if [ -z $def_DB_HOST ] && [ -z $DB_HOST ]; then
|
||||
read -e -p "Database host: " -i "$DB_HOST" DB_HOST;
|
||||
else
|
||||
DB_HOST=${DB_HOST:-$def_DB_HOST}
|
||||
fi
|
||||
|
||||
if [ -z $def_DB_NAME ] && [ -z $DB_NAME ]; then
|
||||
read -e -p "Database name: " -i "$DB_NAME" DB_NAME;
|
||||
else
|
||||
DB_NAME=${DB_NAME:-$def_DB_NAME}
|
||||
fi
|
||||
|
||||
if [ -z $def_DB_USER ] && [ -z $DB_USER ]; then
|
||||
read -e -p "Database user: " -i "$DB_USER" DB_USER;
|
||||
else
|
||||
DB_USER=${DB_USER:-$def_DB_USER}
|
||||
fi
|
||||
|
||||
if [ -z $DB_PWD ]; then
|
||||
read -e -p "Database password: " -i "$DB_PWD" -s DB_PWD;
|
||||
fi
|
||||
}
|
||||
|
||||
establish_mysql_conn(){
|
||||
@ -267,8 +280,16 @@ establish_mysql_conn(){
|
||||
|
||||
#Save db settings in .json
|
||||
$JSON_USERCONF "this.ConnectionStrings={'default': {'connectionString': \
|
||||
\"Server=$DB_HOST;Port=$DB_PORT;Database=$DB_NAME;User ID=$DB_USER;Password=$DB_PWD;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none\"}}" >/dev/null 2>&1
|
||||
\"Server=$DB_HOST;Port=$DB_PORT;Database=$DB_NAME;User ID=$DB_USER;Password=$DB_PWD;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=true;Connection Timeout=30;Maximum Pool Size=300\"}}" >/dev/null 2>&1
|
||||
|
||||
change_mysql_config
|
||||
|
||||
#Enable database migration
|
||||
$JSON_USERCONF "this.migration={'enabled': \"true\"}" >/dev/null 2>&1
|
||||
|
||||
#Fixing appserver-backup startup error \ Adding backup_backup and backup_schedule tables
|
||||
$MYSQL -D "$DB_NAME" -e 'CREATE TABLE IF NOT EXISTS `backup_backup` ( `id` char(38) NOT NULL, `tenant_id` int(11) NOT NULL, `is_scheduled` int(1) NOT NULL, `name` varchar(255) NOT NULL, `storage_type` int(11) NOT NULL, `storage_base_path` varchar(255) DEFAULT NULL, `storage_path` varchar(255) NOT NULL, `created_on` datetime NOT NULL, `expires_on` datetime NOT NULL DEFAULT "0001-01-01 00:00:00", `storage_params` TEXT NULL, `hash` char(64) NOT NULL, PRIMARY KEY (`id`), KEY `tenant_id` (`tenant_id`), KEY `expires_on` (`expires_on`), KEY `is_scheduled` (`is_scheduled`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;' >/dev/null 2>&1
|
||||
$MYSQL -D "$DB_NAME" -e 'CREATE TABLE IF NOT EXISTS `backup_schedule` ( `tenant_id` int(11) NOT NULL, `backup_mail` int(11) NOT NULL DEFAULT "0", `cron` varchar(255) NOT NULL, `backups_stored` int(11) NOT NULL, `storage_type` int(11) NOT NULL, `storage_base_path` varchar(255) DEFAULT NULL, `last_backup_time` datetime NOT NULL, `storage_params` TEXT NULL, PRIMARY KEY (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;' >/dev/null 2>&1
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
@ -376,47 +397,6 @@ change_mysql_config(){
|
||||
systemctl restart ${MYSQL_PACKAGE} >/dev/null 2>&1
|
||||
}
|
||||
|
||||
execute_mysql_script(){
|
||||
|
||||
change_mysql_config
|
||||
|
||||
while ! $MYSQL -e ";" >/dev/null 2>&1; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ "$DB_USER" = "root" ] && [ ! "$(mysql -V | grep ' 5.5.')" ]; then
|
||||
# allow connect via mysql_native_password with root and empty password
|
||||
$MYSQL -D "mysql" -e "update user set plugin='mysql_native_password' where user='root';ALTER USER '${DB_USER}'@'localhost' IDENTIFIED WITH mysql_native_password BY '${DB_PWD}';" >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
#Checking the quantity of the tables created in the db
|
||||
DB_TABLES_COUNT=$($MYSQL --silent --skip-column-names -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${DB_NAME}'");
|
||||
|
||||
local SQL_DIR="/var/www/${PRODUCT}/sql"
|
||||
if [ "${DB_TABLES_COUNT}" -eq "0" ]; then
|
||||
|
||||
echo -n "Installing MYSQL database... "
|
||||
|
||||
#Adding data to the db
|
||||
sed -i -e '1 s/^/SET SQL_MODE='ALLOW_INVALID_DATES';\n/;' $SQL_DIR/onlyoffice.sql #Fix a bug related to an incorrect date
|
||||
$MYSQL -e "CREATE DATABASE IF NOT EXISTS $DB_NAME CHARACTER SET utf8 COLLATE 'utf8_general_ci';" >/dev/null 2>&1
|
||||
echo 'CREATE TABLE IF NOT EXISTS `Tenants` ( `id` varchar(200) NOT NULL, `Status` varchar(200) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;' >> $SQL_DIR/onlyoffice.sql #Fix non-existent tables Tenants
|
||||
$MYSQL "$DB_NAME" < "$SQL_DIR/createdb.sql" >/dev/null 2>&1
|
||||
$MYSQL "$DB_NAME" < "$SQL_DIR/onlyoffice.sql" >/dev/null 2>&1
|
||||
$MYSQL "$DB_NAME" < "$SQL_DIR/onlyoffice.data.sql" >/dev/null 2>&1
|
||||
$MYSQL "$DB_NAME" < "$SQL_DIR/onlyoffice.resources.sql" >/dev/null 2>&1
|
||||
for i in $(ls $SQL_DIR/*upgrade*.sql); do
|
||||
$MYSQL "$DB_NAME" < ${i} >/dev/null 2>&1
|
||||
done
|
||||
else
|
||||
echo -n "Upgrading MySQL database... "
|
||||
for i in $(ls $SQL_DIR/*upgrade*.sql); do
|
||||
$MYSQL "$DB_NAME" < ${i} >/dev/null 2>&1
|
||||
done
|
||||
fi
|
||||
echo "OK"
|
||||
}
|
||||
|
||||
setup_nginx(){
|
||||
echo -n "Configuring nginx... "
|
||||
|
||||
@ -443,7 +423,6 @@ setup_nginx(){
|
||||
PORTS+=('5002') #ASC.People
|
||||
PORTS+=('5008') #ASC.Files/client
|
||||
PORTS+=('5013') #ASC.Files/editor
|
||||
PORTS+=('5014') #ASC.CRM
|
||||
setsebool -P httpd_can_network_connect on
|
||||
;;
|
||||
disabled)
|
||||
@ -549,8 +528,6 @@ change_elasticsearch_config(){
|
||||
if [ -d /etc/elasticsearch/ ]; then
|
||||
chmod g+ws /etc/elasticsearch/
|
||||
fi
|
||||
|
||||
systemctl start elasticsearch
|
||||
}
|
||||
|
||||
setup_elasticsearch() {
|
||||
@ -566,7 +543,8 @@ setup_elasticsearch() {
|
||||
|
||||
setup_kafka() {
|
||||
|
||||
KAFKA_SERVICE=$(systemctl list-units --no-legend "*kafka*" | cut -f1 -d' ')
|
||||
KAFKA_SERVICE=$(systemctl list-unit-files --no-legend "*kafka*" | grep -oE '[^ ]+.service')
|
||||
ZOOKEEPER_SERVICE=$(systemctl list-unit-files --no-legend "*zookeeper*" | grep -oE '[^ ]+.service')
|
||||
|
||||
if [ -n ${KAFKA_SERVICE} ]; then
|
||||
|
||||
@ -582,7 +560,9 @@ setup_kafka() {
|
||||
sed -i "s/bootstrap.servers=.*/bootstrap.servers=${KAFKA_HOST}:${KAFKA_PORT}/g" $KAFKA_CONF/connect-standalone.properties
|
||||
sed -i "s/logger.kafka.controller=.*,/logger.kafka.controller=INFO,/g" $KAFKA_CONF/log4j.properties
|
||||
sed -i "s/logger.state.change.logger=.*,/logger.state.change.logger=INFO,/g" $KAFKA_CONF/log4j.properties
|
||||
if ! grep -q "DefaultEventHandler" $KAFKA_CONF/log4j.properties; then
|
||||
echo "log4j.logger.kafka.producer.async.DefaultEventHandler=INFO, kafkaAppender" >> $KAFKA_CONF/log4j.properties
|
||||
fi
|
||||
|
||||
#Save kafka parameters in .json
|
||||
$JSON_USERCONF "this.kafka={'BootstrapServers': \"${KAFKA_HOST}:${KAFKA_PORT}\"}" >/dev/null 2>&1
|
||||
@ -607,7 +587,6 @@ install_json
|
||||
if $PACKAGE_MANAGER mysql-client >/dev/null 2>&1 || $PACKAGE_MANAGER mysql-community-client >/dev/null 2>&1; then
|
||||
input_db_params
|
||||
establish_mysql_conn || exit $?
|
||||
execute_mysql_script || exit $?
|
||||
fi
|
||||
|
||||
if $PACKAGE_MANAGER nginx >/dev/null 2>&1; then
|
||||
|
@ -39,6 +39,7 @@ LOG_DIR="/var/log/onlyoffice/${PRODUCT}"
|
||||
DOTNET_RUN="/usr/share/dotnet/dotnet"
|
||||
APP_URLS="http://0.0.0.0"
|
||||
ENVIRONMENT=" --ENVIRONMENT=production"
|
||||
CORE=" --core:products:folder=${BASE_DIR}/products --core:products:subfolder=server"
|
||||
|
||||
SERVICE_NAME=(
|
||||
api
|
||||
@ -55,11 +56,7 @@ SERVICE_NAME=(
|
||||
backup
|
||||
storage-encryption
|
||||
storage-migration
|
||||
projects-server
|
||||
telegram-service
|
||||
crm
|
||||
calendar
|
||||
mail
|
||||
ssoauth
|
||||
)
|
||||
|
||||
@ -94,13 +91,11 @@ reassign_values (){
|
||||
SERVICE_PORT="5006"
|
||||
WORK_DIR="${BASE_DIR}/services/ASC.Studio.Notify/"
|
||||
EXEC_FILE="ASC.Studio.Notify.dll"
|
||||
CORE=" --core:products:folder=${BASE_DIR}/products --core:products:subfolder=server "
|
||||
;;
|
||||
notify )
|
||||
SERVICE_PORT="5005"
|
||||
WORK_DIR="${BASE_DIR}/services/ASC.Notify/"
|
||||
EXEC_FILE="ASC.Notify.dll"
|
||||
CORE=" --core:products:folder=${BASE_DIR}/products --core:products:subfolder=server "
|
||||
;;
|
||||
people-server )
|
||||
SERVICE_PORT="5004"
|
||||
@ -116,7 +111,6 @@ reassign_values (){
|
||||
SERVICE_PORT="5009"
|
||||
WORK_DIR="${BASE_DIR}/products/ASC.Files/service/"
|
||||
EXEC_FILE="ASC.Files.Service.dll"
|
||||
CORE=" --core:products:folder=${BASE_DIR}/products --core:products:subfolder=server"
|
||||
;;
|
||||
studio )
|
||||
SERVICE_PORT="5003"
|
||||
@ -127,7 +121,6 @@ reassign_values (){
|
||||
SERVICE_PORT="5012"
|
||||
WORK_DIR="${BASE_DIR}/services/ASC.Data.Backup/"
|
||||
EXEC_FILE="ASC.Data.Backup.dll"
|
||||
CORE=" --core:products:folder=${BASE_DIR}/products --core:products:subfolder=server"
|
||||
;;
|
||||
storage-migration )
|
||||
SERVICE_PORT="5018"
|
||||
@ -139,31 +132,11 @@ reassign_values (){
|
||||
WORK_DIR="${BASE_DIR}/services/ASC.Data.Storage.Encryption/"
|
||||
EXEC_FILE="ASC.Data.Storage.Encryption.dll"
|
||||
;;
|
||||
projects-server )
|
||||
SERVICE_PORT="5020"
|
||||
WORK_DIR="${BASE_DIR}/products/ASC.Projects/server/"
|
||||
EXEC_FILE="ASC.Projects.dll"
|
||||
;;
|
||||
telegram-service )
|
||||
SERVICE_PORT="51702"
|
||||
WORK_DIR="${BASE_DIR}/services/ASC.TelegramService/"
|
||||
EXEC_FILE="ASC.TelegramService.dll"
|
||||
;;
|
||||
crm )
|
||||
SERVICE_PORT="5021"
|
||||
WORK_DIR="${BASE_DIR}/products/ASC.CRM/server/"
|
||||
EXEC_FILE="ASC.CRM.dll"
|
||||
;;
|
||||
calendar )
|
||||
SERVICE_PORT="5023"
|
||||
WORK_DIR="${BASE_DIR}/products/ASC.Calendar/server/"
|
||||
EXEC_FILE="ASC.Calendar.dll"
|
||||
;;
|
||||
mail )
|
||||
SERVICE_PORT="5022"
|
||||
WORK_DIR="${BASE_DIR}/products/ASC.Mail/server/"
|
||||
EXEC_FILE="ASC.Mail.dll"
|
||||
;;
|
||||
ssoauth )
|
||||
SERVICE_PORT="9833"
|
||||
WORK_DIR="${BASE_DIR}/services/ASC.SsoAuth.Svc/"
|
||||
@ -173,7 +146,6 @@ reassign_values (){
|
||||
SERVICE_NAME="$1"
|
||||
EXEC_START="${DOTNET_RUN} ${WORK_DIR}${EXEC_FILE} --urls=${APP_URLS}:${SERVICE_PORT} --pathToConf=${PATH_TO_CONF} \
|
||||
--'\$STORAGE_ROOT'=${STORAGE_ROOT} --log:dir=${LOG_DIR} --log:name=${SERVICE_NAME}${CORE}${ENVIRONMENT}"
|
||||
CORE=""
|
||||
}
|
||||
|
||||
write_to_file () {
|
||||
|
@ -1,3 +1,2 @@
|
||||
../../../config/*.json etc/onlyoffice/appserver
|
||||
../../../config/*.config etc/onlyoffice/appserver
|
||||
../docker/config/*.sql var/www/appserver/sql
|
||||
|
@ -18,4 +18,4 @@ if ! cat /etc/passwd | grep -q "nginx:"; then
|
||||
fi
|
||||
|
||||
usermod -aG onlyoffice,nginx onlyoffice
|
||||
chown onlyoffice:onlyoffice /var/log/onlyoffice/appserver /var/www/appserver /etc/onlyoffice/appserver
|
||||
chown -R onlyoffice:onlyoffice /var/log/onlyoffice/appserver /var/www/appserver /etc/onlyoffice/appserver
|
||||
|
@ -1,17 +1,9 @@
|
||||
## COPY PUBLIC ##
|
||||
../../../config/nginx/onlyoffice*.conf etc/nginx/conf.d
|
||||
../../../config/nginx/includes/onlyoffice*.conf etc/nginx/includes
|
||||
../../../public/* var/www/appserver/public
|
||||
../../../public/images/* var/www/appserver/public/images
|
||||
../../../public/offline/* var/www/appserver/public/offline
|
||||
../../../public/thirdparty/* var/www/appserver/public/thirdparty
|
||||
../../../products/ASC.Calendar/Client/dist/* var/www/appserver/products/ASC.Calendar/client
|
||||
../../../products/ASC.CRM/Client/dist/* var/www/appserver/products/ASC.CRM/client
|
||||
../../../products/ASC.Projects/Client/dist/* var/www/appserver/products/ASC.Projects/client
|
||||
../../../products/ASC.Calendar/Client/dist/* var/www/appserver/products/ASC.Calendar/client
|
||||
../../../products/ASC.People/Client/dist/* var/www/appserver/products/ASC.People/client
|
||||
../../../products/ASC.Mail/Client/dist/* var/www/appserver/products/ASC.Mail/client
|
||||
../../../products/ASC.Files/Client/dist/* var/www/appserver/products/ASC.Files/client
|
||||
../../../web/ASC.Web.Editor/dist/* var/www/appserver/products/ASC.Files/editor
|
||||
../../../web/ASC.Web.Client/dist/* var/www/appserver/studio/client
|
||||
../../../web/ASC.Web.Login/dist/* var/www/appserver/studio/login
|
||||
../../../build/deploy/public/* var/www/appserver/public
|
||||
../../../build/deploy/products/ASC.People/client/* var/www/appserver/products/ASC.People/client
|
||||
../../../build/deploy/products/ASC.Files/client/* var/www/appserver/products/ASC.Files/client
|
||||
../../../build/deploy/products/ASC.Files/editor/* var/www/appserver/products/ASC.Files/editor
|
||||
../../../build/deploy/studio/client/* var/www/appserver/studio/client
|
||||
../../../build/deploy/studio/login/* var/www/appserver/studio/login
|
||||
|
@ -1,4 +1,4 @@
|
||||
appserver (0.1-10) unstable; urgency=medium
|
||||
appserver ({{package_header_tag_version}}) unstable; urgency=medium
|
||||
|
||||
* Initial Release.
|
||||
|
||||
|
@ -2,34 +2,30 @@ Source: appserver
|
||||
Section: web
|
||||
Priority: optional
|
||||
Maintainer: onlyoffice
|
||||
Build-Depends: debhelper (>= 10), nodejs (>=10), dotnet-sdk-5.0, yarn
|
||||
Standards-Version: 0.1-10
|
||||
Build-Depends: debhelper (>= 10), nodejs (>=14), dotnet-sdk-6.0, yarn
|
||||
Standards-Version: {{package_header_tag_version}}
|
||||
Homepage: https://www.onlyoffice.com/
|
||||
Architecture: any
|
||||
|
||||
Package: appserver
|
||||
Architecture: any
|
||||
Depends: appserver-api-system,
|
||||
appserver-backup,
|
||||
appserver-calendar,
|
||||
appserver-crm,
|
||||
appserver-storage-encryption,
|
||||
appserver-files,
|
||||
appserver-files-services,
|
||||
appserver-mail,
|
||||
appserver-storage-migration,
|
||||
appserver-notify,
|
||||
appserver-people-server,
|
||||
appserver-projects-server,
|
||||
appserver-socket,
|
||||
appserver-ssoauth,
|
||||
appserver-studio-notify,
|
||||
appserver-telegram-service,
|
||||
appserver-thumbnails,
|
||||
appserver-urlshortener,
|
||||
appserver-api,
|
||||
appserver-studio,
|
||||
appserver-proxy
|
||||
Depends: appserver-api-system (= {{package_header_tag_version}}),
|
||||
appserver-backup (= {{package_header_tag_version}}),
|
||||
appserver-storage-encryption (= {{package_header_tag_version}}),
|
||||
appserver-files (= {{package_header_tag_version}}),
|
||||
appserver-files-services (= {{package_header_tag_version}}),
|
||||
appserver-storage-migration (= {{package_header_tag_version}}),
|
||||
appserver-notify (= {{package_header_tag_version}}),
|
||||
appserver-people-server (= {{package_header_tag_version}}),
|
||||
appserver-socket (= {{package_header_tag_version}}),
|
||||
appserver-ssoauth (= {{package_header_tag_version}}),
|
||||
appserver-studio-notify (= {{package_header_tag_version}}),
|
||||
appserver-telegram-service (= {{package_header_tag_version}}),
|
||||
appserver-thumbnails (= {{package_header_tag_version}}),
|
||||
appserver-urlshortener (= {{package_header_tag_version}}),
|
||||
appserver-api (= {{package_header_tag_version}}),
|
||||
appserver-studio (= {{package_header_tag_version}}),
|
||||
appserver-proxy (= {{package_header_tag_version}})
|
||||
Description: Description
|
||||
|
||||
Package: appserver-common
|
||||
@ -44,174 +40,138 @@ Description: Description
|
||||
|
||||
Package: appserver-api-system
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-backup
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-calendar
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-crm
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-storage-encryption
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-files
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-files-services
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-mail
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-storage-migration
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-notify
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-people-server
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-projects-server
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-socket
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
nodejs (>=10),
|
||||
dotnet-sdk-6.0,
|
||||
nodejs (>=14),
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-studio-notify
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-telegram-service
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-thumbnails
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
nodejs (>=10),
|
||||
dotnet-sdk-6.0,
|
||||
nodejs (>=14),
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-urlshortener
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
nodejs (>=10),
|
||||
dotnet-sdk-6.0,
|
||||
nodejs (>=14),
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-api
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
||||
Package: appserver-studio
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
dotnet-sdk-6.0,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
@ -223,10 +183,10 @@ Description: Description
|
||||
|
||||
Package: appserver-ssoauth
|
||||
Architecture: any
|
||||
Depends: appserver-common,
|
||||
Depends: appserver-common (= {{package_header_tag_version}}),
|
||||
appserver-configuration,
|
||||
dotnet-sdk-5.0,
|
||||
nodejs (>=10),
|
||||
dotnet-sdk-6.0,
|
||||
nodejs (>=14),
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Description
|
||||
|
@ -42,8 +42,8 @@ override_dh_fixperms:
|
||||
dh_fixperms
|
||||
|
||||
override_dh_auto_install:
|
||||
dh_installinit
|
||||
dh_systemd_enable
|
||||
dh_installinit --no-start
|
||||
dh_systemd_enable --no-enable
|
||||
dh_systemd_start --no-start
|
||||
|
||||
override_dh_strip:
|
||||
|
@ -74,4 +74,6 @@ sed -i "s!\"Threads\".*!\"Threads\": \"${ELK_THREADS}\"!g" ${PATH_TO_CONF}/elast
|
||||
sed -i "s!\"subfolder\".*!\"subfolder\": \"server\",!g" ${PATH_TO_CONF}/appsettings.services.json
|
||||
sed -i "s!\"BootstrapServers\".*!\"BootstrapServers\": \"${KAFKA_HOST}\"!g" ${PATH_TO_CONF}/kafka.${APP_DOTNET_ENV}.json
|
||||
|
||||
sed -i "s!\"path\".*!\"path\": \"../../ASC.Socket.IO\"!g" ${PATH_TO_CONF}/socket.${APP_DOTNET_ENV}.json
|
||||
|
||||
dotnet ${DOTNET_RUN} --urls=${URLS} --ENVIRONMENT=${APP_DOTNET_ENV} --'$STORAGE_ROOT'=${APP_STORAGE_ROOT} --pathToConf=${PATH_TO_CONF} --log:dir=${LOG_DIR} --log:name=${DOTNET_LOG_NAME} ${PARAMETERS}
|
||||
|
@ -18,33 +18,28 @@ License: AGPLv3
|
||||
Source0: https://github.com/ONLYOFFICE/%{product}/archive/%GIT_BRANCH.tar.gz#/%{sourcename}.tar.gz
|
||||
Source1: https://github.com/ONLYOFFICE/document-templates/archive/main/community-server.tar.gz#/document-templates-main-community-server.tar.gz
|
||||
Source2: https://github.com/ONLYOFFICE/dictionaries/archive/master.tar.gz#/dictionaries-master.tar.gz
|
||||
Source3: https://github.com/ONLYOFFICE/CommunityServer/archive/master.tar.gz#/CommunityServer-master.tar.gz
|
||||
|
||||
BuildRequires: nodejs >= 12.0
|
||||
BuildRequires: nodejs >= 14.0
|
||||
BuildRequires: yarn
|
||||
BuildRequires: dotnet-sdk-5.0
|
||||
BuildRequires: dotnet-sdk-6.0
|
||||
|
||||
Requires: %name-api-system
|
||||
Requires: %name-calendar
|
||||
Requires: %name-crm
|
||||
Requires: %name-backup
|
||||
Requires: %name-storage-encryption
|
||||
Requires: %name-storage-migration
|
||||
Requires: %name-files
|
||||
Requires: %name-files-services
|
||||
Requires: %name-mail
|
||||
Requires: %name-notify
|
||||
Requires: %name-people-server
|
||||
Requires: %name-projects-server
|
||||
Requires: %name-socket
|
||||
Requires: %name-ssoauth
|
||||
Requires: %name-studio-notify
|
||||
Requires: %name-telegram-service
|
||||
Requires: %name-thumbnails
|
||||
Requires: %name-urlshortener
|
||||
Requires: %name-api
|
||||
Requires: %name-studio
|
||||
Requires: %name-proxy
|
||||
Requires: %name-api-system = %version-%release
|
||||
Requires: %name-backup = %version-%release
|
||||
Requires: %name-storage-encryption = %version-%release
|
||||
Requires: %name-storage-migration = %version-%release
|
||||
Requires: %name-files = %version-%release
|
||||
Requires: %name-files-services = %version-%release
|
||||
Requires: %name-notify = %version-%release
|
||||
Requires: %name-people-server = %version-%release
|
||||
Requires: %name-socket = %version-%release
|
||||
Requires: %name-ssoauth = %version-%release
|
||||
Requires: %name-studio-notify = %version-%release
|
||||
Requires: %name-telegram-service = %version-%release
|
||||
Requires: %name-thumbnails = %version-%release
|
||||
Requires: %name-urlshortener = %version-%release
|
||||
Requires: %name-api = %version-%release
|
||||
Requires: %name-studio = %version-%release
|
||||
Requires: %name-proxy = %version-%release
|
||||
|
||||
%description
|
||||
App Server is a platform for building your own online office by connecting ONLYOFFICE modules packed as separate apps.
|
||||
@ -54,10 +49,9 @@ App Server is a platform for building your own online office by connecting ONLYO
|
||||
%prep
|
||||
|
||||
rm -rf %{_rpmdir}/%{_arch}/%{name}-*
|
||||
%setup -b1 -b2 -b3 -n %{sourcename}
|
||||
%setup -b1 -b2 -n %{sourcename}
|
||||
mv -f %{_builddir}/document-templates-main-community-server/* %{_builddir}/%{sourcename}/products/ASC.Files/Server/DocStore/
|
||||
mv -f %{_builddir}/dictionaries-master/* %{_builddir}/%{sourcename}/common/Tests/Frontend.Translations.Tests/dictionaries/
|
||||
mv -f %{_builddir}/CommunityServer-master/build/sql/* %{_builddir}/%{sourcename}/build/install/docker/config/
|
||||
|
||||
%include build.spec
|
||||
|
||||
|
@ -6,26 +6,18 @@
|
||||
%{buildpath}/studio/api/
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-api.service
|
||||
%dir %{buildpath}/studio/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files backup
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/services/ASC.Data.Backup/
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-backup.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
@ -33,16 +25,11 @@
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files common
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%config %{_sysconfdir}/onlyoffice/%{product}/
|
||||
%{_var}/log/onlyoffice/%{product}/
|
||||
%{buildpath}/sql/
|
||||
%dir %{_sysconfdir}/onlyoffice/
|
||||
%dir %{_var}/log/onlyoffice/
|
||||
|
||||
@ -51,26 +38,18 @@
|
||||
%{buildpath}/products/ASC.Files/service/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-files-services.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.People/server
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files notify
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/services/ASC.Notify/
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-notify.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
@ -78,26 +57,16 @@
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files files
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/products/ASC.Files/server/
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-files.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files api-system
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
@ -115,26 +84,16 @@
|
||||
%{buildpath}/products/ASC.People/client/
|
||||
%{buildpath}/products/ASC.Files/client/
|
||||
%{buildpath}/products/ASC.Files/editor/
|
||||
%{buildpath}/products/ASC.CRM/client/
|
||||
%{buildpath}/products/ASC.Projects/client/
|
||||
%{buildpath}/products/ASC.Calendar/client/
|
||||
%{buildpath}/products/ASC.Mail/client/
|
||||
%dir %{buildpath}/studio/
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Calendar/
|
||||
%dir %{buildpath}/products/ASC.Mail/
|
||||
|
||||
%files studio-notify
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/services/ASC.Studio.Notify/
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-studio-notify.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
@ -142,26 +101,16 @@
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files people-server
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/products/ASC.People/server/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-people-server.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files urlshortener
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
@ -183,23 +132,17 @@
|
||||
%{buildpath}/services/ASC.Socket.IO.Svc/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-socket.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
|
||||
%files studio
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/studio/server/
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-studio.service
|
||||
%dir %{buildpath}/studio/
|
||||
%dir %{buildpath}/products/
|
||||
@ -207,18 +150,12 @@
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files storage-encryption
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/services/ASC.Data.Storage.Encryption/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-storage-encryption.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
@ -226,49 +163,23 @@
|
||||
%dir %{buildpath}/products/ASC.Files/server
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.People/server
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server
|
||||
|
||||
%files storage-migration
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/services/ASC.Data.Storage.Migration/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-storage-migration.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
|
||||
%files projects-server
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/products/ASC.Projects/server/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
/lib/systemd/system/%{product}-projects-server.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
|
||||
%files telegram-service
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/services/ASC.TelegramService/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.CRM/server/ASC.CRM*.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-telegram-service.service
|
||||
%dir %{buildpath}/services/
|
||||
%dir %{buildpath}/products/
|
||||
@ -276,38 +187,6 @@
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.People/
|
||||
%dir %{buildpath}/products/ASC.People/server/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.CRM/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files crm
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/products/ASC.CRM/server/
|
||||
%{buildpath}/products/ASC.Files/server/ASC.Files*.dll
|
||||
%{buildpath}/products/ASC.People/server/ASC.People.dll
|
||||
%{buildpath}/products/ASC.Projects/server/ASC.Projects*.dll
|
||||
/lib/systemd/system/%{product}-crm.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.CRM/
|
||||
%dir %{buildpath}/products/ASC.Files/
|
||||
%dir %{buildpath}/products/ASC.Files/server/
|
||||
%dir %{buildpath}/products/ASC.Projects/
|
||||
%dir %{buildpath}/products/ASC.Projects/server/
|
||||
|
||||
%files calendar
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/products/ASC.Calendar/server/
|
||||
/lib/systemd/system/%{product}-calendar.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.Calendar/
|
||||
|
||||
%files mail
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
%{buildpath}/products/ASC.Mail/server/
|
||||
/lib/systemd/system/%{product}-mail.service
|
||||
%dir %{buildpath}/products/
|
||||
%dir %{buildpath}/products/ASC.Mail/
|
||||
|
||||
%files ssoauth
|
||||
%defattr(-, onlyoffice, onlyoffice, -)
|
||||
|
@ -7,20 +7,12 @@ mkdir -p "%{buildroot}%{_sysconfdir}/onlyoffice/%{product}/.private/"
|
||||
mkdir -p "%{buildroot}%{_sysconfdir}/onlyoffice/%{product}/data/"
|
||||
mkdir -p "%{buildroot}%{_var}/log/onlyoffice/%{product}/"
|
||||
mkdir -p "%{buildroot}/lib/systemd/system/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Calendar/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Calendar/server/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.CRM/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.CRM/server/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Files/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Files/editor/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Files/server/DocStore/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Files/service/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Mail/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Mail/server/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.People/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.People/server/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Projects/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/products/ASC.Projects/server/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/public/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/services/ASC.Socket.IO/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/services/ASC.Socket.IO.Svc/"
|
||||
@ -37,18 +29,13 @@ mkdir -p "%{buildroot}%{buildpath}/services/ASC.Thumbnails/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/services/ASC.UrlShortener/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/services/ASC.UrlShortener.Svc/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/services/ASC.Thumbnails.Svc/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/sql/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/studio/api/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/studio/client/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/studio/login/"
|
||||
mkdir -p "%{buildroot}%{buildpath}/studio/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/products/ASC.Calendar/server/* "%{buildroot}%{buildpath}/products/ASC.Calendar/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/products/ASC.Mail/server/* "%{buildroot}%{buildpath}/products/ASC.Mail/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/products/ASC.CRM/server/* "%{buildroot}%{buildpath}/products/ASC.CRM/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/products/ASC.Files/server/* "%{buildroot}%{buildpath}/products/ASC.Files/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Files.Service/service/* "%{buildroot}%{buildpath}/products/ASC.Files/service/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/products/ASC.People/server/* "%{buildroot}%{buildpath}/products/ASC.People/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/products/ASC.Projects/server/* "%{buildroot}%{buildpath}/products/ASC.Projects/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.ApiSystem/service/* "%{buildroot}%{buildpath}/services/ASC.ApiSystem/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Data.Backup/service/* "%{buildroot}%{buildpath}/services/ASC.Data.Backup/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Notify/service/* "%{buildroot}%{buildpath}/services/ASC.Notify/"
|
||||
@ -67,19 +54,14 @@ cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.UrlShortener.Svc/service/
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Web.Api/service/* "%{buildroot}%{buildpath}/studio/api/"
|
||||
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Web.Studio/service/* "%{buildroot}%{buildpath}/studio/server/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/install/common/systemd/modules/* "%{buildroot}/lib/systemd/system/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/install/docker/config/*.sql "%{buildroot}%{buildpath}/sql/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/install/common/%{product}-configuration.sh "%{buildroot}%{_bindir}/"
|
||||
cp -rf %{_builddir}/%{sourcename}/config/* "%{buildroot}%{_sysconfdir}/onlyoffice/%{product}/"
|
||||
cp -rf %{_builddir}/%{sourcename}/config/nginx/includes/onlyoffice*.conf "%{buildroot}%{_sysconfdir}/nginx/includes/"
|
||||
cp -rf %{_builddir}/%{sourcename}/config/nginx/onlyoffice*.conf "%{buildroot}%{_sysconfdir}/nginx/conf.d/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.CRM/Client/dist/* "%{buildroot}%{buildpath}/products/ASC.CRM/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.Files/Client/dist/* "%{buildroot}%{buildpath}/products/ASC.Files/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/deploy/products/ASC.Files/client/* "%{buildroot}%{buildpath}/products/ASC.Files/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.Files/Server/DocStore/* "%{buildroot}%{buildpath}/products/ASC.Files/server/DocStore/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.People/Client/dist/* "%{buildroot}%{buildpath}/products/ASC.People/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.Projects/Client/dist/* "%{buildroot}%{buildpath}/products/ASC.Projects/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.Calendar/Client/dist/* "%{buildroot}%{buildpath}/products/ASC.Calendar/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/products/ASC.Mail/Client/dist/* "%{buildroot}%{buildpath}/products/ASC.Mail/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/public/* "%{buildroot}%{buildpath}/public/"
|
||||
cp -rf %{_builddir}/%{sourcename}/web/ASC.Web.Client/dist/* "%{buildroot}%{buildpath}/studio/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/web/ASC.Web.Editor/dist/* "%{buildroot}%{buildpath}/products/ASC.Files/editor/"
|
||||
cp -rf %{_builddir}/%{sourcename}/web/ASC.Web.Login/dist/* "%{buildroot}%{buildpath}/studio/login/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/deploy/products/ASC.People/client/* "%{buildroot}%{buildpath}/products/ASC.People/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/deploy/public/* "%{buildroot}%{buildpath}/public/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/deploy/studio/client/* "%{buildroot}%{buildpath}/studio/client/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/deploy/products/ASC.Files/editor/* "%{buildroot}%{buildpath}/products/ASC.Files/editor/"
|
||||
cp -rf %{_builddir}/%{sourcename}/build/deploy/studio/login/* "%{buildroot}%{buildpath}/studio/login/"
|
@ -1,8 +1,8 @@
|
||||
%package backup
|
||||
Summary: backup
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description backup
|
||||
|
||||
@ -14,39 +14,39 @@ Group: Applications/Internet
|
||||
%package files-services
|
||||
Summary: files-services
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description files-services
|
||||
|
||||
%package notify
|
||||
Summary: notify
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description notify
|
||||
|
||||
%package files
|
||||
Summary: files
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description files
|
||||
|
||||
%package api-system
|
||||
Summary: api-system
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description api-system
|
||||
|
||||
%package proxy
|
||||
Summary: proxy
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: nginx >= 1.9.5
|
||||
Requires: mysql-community-client >= 5.7.0
|
||||
AutoReqProv: no
|
||||
@ -55,24 +55,24 @@ AutoReqProv: no
|
||||
%package studio-notify
|
||||
Summary: studio-notify
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description studio-notify
|
||||
|
||||
%package people-server
|
||||
Summary: people-server
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description people-server
|
||||
|
||||
%package urlshortener
|
||||
Summary: urlshortener
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
Requires: nodejs >= 12.0
|
||||
AutoReqProv: no
|
||||
%description urlshortener
|
||||
@ -80,8 +80,8 @@ AutoReqProv: no
|
||||
%package socket
|
||||
Summary: socket
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
Requires: nodejs >= 12.0
|
||||
AutoReqProv: no
|
||||
%description socket
|
||||
@ -89,8 +89,8 @@ AutoReqProv: no
|
||||
%package thumbnails
|
||||
Summary: thumbnails
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
Requires: nodejs >= 12.0
|
||||
AutoReqProv: no
|
||||
%description thumbnails
|
||||
@ -98,80 +98,48 @@ AutoReqProv: no
|
||||
%package studio
|
||||
Summary: studio
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description studio
|
||||
|
||||
%package crm
|
||||
Summary: crm
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
AutoReqProv: no
|
||||
%description crm
|
||||
|
||||
%package api
|
||||
Summary: api
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description api
|
||||
|
||||
%package storage-encryption
|
||||
Summary: storage-encryption
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description storage-encryption
|
||||
|
||||
%package storage-migration
|
||||
Summary: storage-migration
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description storage-migration
|
||||
|
||||
%package projects-server
|
||||
Summary: projects-server
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
AutoReqProv: no
|
||||
%description projects-server
|
||||
|
||||
%package telegram-service
|
||||
Summary: telegram-service
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
AutoReqProv: no
|
||||
%description telegram-service
|
||||
|
||||
%package calendar
|
||||
Summary: calendar
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
AutoReqProv: no
|
||||
%description calendar
|
||||
|
||||
%package mail
|
||||
Summary: mail
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
AutoReqProv: no
|
||||
%description mail
|
||||
|
||||
%package ssoauth
|
||||
Summary: ssoauth
|
||||
Group: Applications/Internet
|
||||
Requires: %name-common
|
||||
Requires: dotnet-sdk-5.0
|
||||
Requires: %name-common = %version-%release
|
||||
Requires: dotnet-sdk-6.0
|
||||
Requires: nodejs >= 12.0
|
||||
AutoReqProv: no
|
||||
%description ssoauth
|
||||
|
@ -27,14 +27,10 @@ powershell -Command "(gc build\deploy\nginx\onlyoffice.conf) -replace '#', '' |
|
||||
xcopy config\nginx\sites-enabled\* build\deploy\nginx\sites-enabled\ /E /R /Y
|
||||
|
||||
REM fix paths
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-calendar.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Calendar\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-calendar.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-crm.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.CRM\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-crm.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-editor.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Files\editor' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-editor.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-files.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Files\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-files.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-login.conf) -replace 'ROOTPATH', '%~dp0deploy\studio\login' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-login.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-mail.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Mail\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-mail.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-people.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.People\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-people.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-projects.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Projects\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-projects.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-studio.conf) -replace 'ROOTPATH', '%~dp0deploy\studio\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-studio.conf"
|
||||
|
||||
REM restart nginx
|
||||
|
67
build/run.e2e.translations.tests.personal.bat
Normal file
67
build/run.e2e.translations.tests.personal.bat
Normal file
@ -0,0 +1,67 @@
|
||||
@echo off
|
||||
|
||||
PUSHD %~dp0
|
||||
call runasadmin.bat "%~dpnx0"
|
||||
|
||||
if %errorlevel% == 0 (
|
||||
PUSHD %~dp0..
|
||||
|
||||
|
||||
echo "mode="
|
||||
|
||||
|
||||
REM call yarn wipe
|
||||
call yarn install
|
||||
|
||||
call yarn build:test.translation:personal
|
||||
|
||||
REM call yarn wipe
|
||||
call yarn deploy:personal
|
||||
|
||||
|
||||
|
||||
REM copy nginx configurations to deploy folder
|
||||
xcopy config\nginx\onlyoffice.conf build\deploy\nginx\ /E /R /Y
|
||||
powershell -Command "(gc build\deploy\nginx\onlyoffice.conf) -replace '#', '' | Out-File -encoding ASCII build\deploy\nginx\onlyoffice.conf"
|
||||
|
||||
xcopy config\nginx\sites-enabled\* build\deploy\nginx\sites-enabled\ /E /R /Y
|
||||
|
||||
REM fix paths
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-editor.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Files\editor' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-editor.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-files.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.Files\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-files.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-login.conf) -replace 'ROOTPATH', '%~dp0deploy\studio\login' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-login.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-people.conf) -replace 'ROOTPATH', '%~dp0deploy\products\ASC.People\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-people.conf"
|
||||
powershell -Command "(gc build\deploy\nginx\sites-enabled\onlyoffice-studio.conf) -replace 'ROOTPATH', '%~dp0deploy\studio\client' -replace '\\', '/' | Out-File -encoding ASCII build\deploy\nginx\sites-enabled\onlyoffice-studio.conf"
|
||||
|
||||
REM restart nginx
|
||||
echo service nginx stop
|
||||
call sc stop nginx > nul
|
||||
|
||||
REM sleep 5 seconds
|
||||
call ping 127.0.0.1 -n 6 > nul
|
||||
|
||||
echo service nginx start
|
||||
call sc start nginx > nul
|
||||
|
||||
REM sleep 5 seconds
|
||||
call ping 127.0.0.1 -n 6 > nul
|
||||
|
||||
call yarn e2e.test:translation:personal
|
||||
|
||||
exit
|
||||
|
||||
|
||||
|
||||
if NOT %errorlevel% == 0 (
|
||||
echo Couldn't restarte Onlyoffice%%~nf service
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
POPD
|
||||
|
||||
if "%1"=="nopause" goto start
|
||||
pause
|
||||
:start
|
4
build/run/MigrationService.bat
Normal file
4
build/run/MigrationService.bat
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
|
||||
PUSHD %~dp0..\..
|
||||
set servicepath=%cd%\common\ASC.Migration\bin\Debug\ASC.Migration.exe urls=http://0.0.0.0:5034 $STORAGE_ROOT=%cd%\Data pathToConf=%cd%\config log:dir=%cd%\Logs log:name=migration core:products:folder=%cd%\products
|
10
build/run/Radicale.xml
Normal file
10
build/run/Radicale.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<service>
|
||||
<id>OnlyofficeRadicale</id>
|
||||
<name>ONLYOFFICE Radicale</name>
|
||||
<startmode>manual</startmode>
|
||||
<executable>python</executable>
|
||||
<arguments>-m radicale --config %BASE%/../../config/radicale.config</arguments>
|
||||
<log mode="none"/>
|
||||
<delayedAutoStart>true</delayedAutoStart>
|
||||
<onfailure action="restart" delay="5 sec" />
|
||||
</service>
|
10
build/run/WebDav.xml
Normal file
10
build/run/WebDav.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<service>
|
||||
<id>OnlyofficeWebDav</id>
|
||||
<name>ONLYOFFICE WebDav Server</name>
|
||||
<startmode>manual</startmode>
|
||||
<executable>node</executable>
|
||||
<arguments>../../common/ASC.WebDav/server/webDavServer.js</arguments>
|
||||
<log mode="none"/>
|
||||
<delayedAutoStart>true</delayedAutoStart>
|
||||
<onfailure action="restart" delay="5 sec" />
|
||||
</service>
|
1
build/scripts/webdav.bat
Normal file
1
build/scripts/webdav.bat
Normal file
@ -0,0 +1 @@
|
||||
yarn install --cwd %~dp0../../common/ASC.WebDav/ --frozen-lockfile
|
@ -121,5 +121,4 @@ global using RabbitMQ.Client;
|
||||
global using StackExchange.Redis.Extensions.Core.Configuration;
|
||||
global using StackExchange.Redis.Extensions.Newtonsoft;
|
||||
|
||||
global using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
global using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
@ -30,6 +30,9 @@ public static partial class CommonLogger
|
||||
[LoggerMessage(Level = LogLevel.Error)]
|
||||
public static partial void ErrorWithException(this ILogger logger, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error)]
|
||||
public static partial void ErrorWithException(this ILogger logger, string message, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error)]
|
||||
public static partial void Error(this ILogger logger, string message);
|
||||
|
||||
@ -44,4 +47,7 @@ public static partial class CommonLogger
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning)]
|
||||
public static partial void WarningWithException(this ILogger logger, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning)]
|
||||
public static partial void WarningWithException(this ILogger logger, string message, Exception exception);
|
||||
}
|
||||
|
@ -174,6 +174,11 @@ public static class HttpRequestExtensions
|
||||
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
|
||||
}
|
||||
|
||||
public static bool MobileApp(this HttpRequest request)
|
||||
{
|
||||
return !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && (request.Headers[HeaderNames.UserAgent].Contains("iOS") || request.Headers[HeaderNames.UserAgent].Contains("Android"));
|
||||
}
|
||||
|
||||
public static string GetUserHostAddress(this HttpRequest request)
|
||||
{
|
||||
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
|
||||
|
@ -439,6 +439,7 @@ public static class MimeMapping
|
||||
AddMimeMapping(".otp", "application/vnd.oasis.opendocument.presentation-template");
|
||||
AddMimeMapping(".ots", "application/vnd.oasis.opendocument.spreadsheet-template");
|
||||
AddMimeMapping(".ott", "application/vnd.oasis.opendocument.text-template");
|
||||
AddMimeMapping(".oxps", "application/oxps");
|
||||
AddMimeMapping(".p", "text/x-pascal");
|
||||
AddMimeMapping(".p10", "application/pkcs10");
|
||||
AddMimeMapping(".p10", "application/x-pkcs10");
|
||||
|
@ -152,7 +152,7 @@ public class BaseCommonLinkUtility
|
||||
var mapped = tenant.MappedDomain.ToLowerInvariant();
|
||||
if (!mapped.Contains(Uri.SchemeDelimiter))
|
||||
{
|
||||
mapped = Uri.UriSchemeHttp + Uri.SchemeDelimiter + mapped;
|
||||
mapped = result.Scheme + Uri.SchemeDelimiter + mapped;
|
||||
}
|
||||
result = new UriBuilder(mapped);
|
||||
}
|
||||
|
@ -84,9 +84,9 @@ public class BillingClient
|
||||
return payments;
|
||||
}
|
||||
|
||||
public IDictionary<string, Tuple<Uri, Uri>> GetPaymentUrls(string portalId, string[] products, string affiliateId = null, string campaign = null, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
public IDictionary<string, Uri> GetPaymentUrls(string portalId, string[] products, string affiliateId = null, string campaign = null, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
var urls = new Dictionary<string, Tuple<Uri, Uri>>();
|
||||
var urls = new Dictionary<string, Uri>();
|
||||
|
||||
var additionalParameters = new List<Tuple<string, string>>() { Tuple.Create("PaymentSystemId", AvangatePaymentSystemId.ToString()) };
|
||||
if (!string.IsNullOrEmpty(affiliateId))
|
||||
@ -124,49 +124,60 @@ public class BillingClient
|
||||
var result = Request("GetPaymentUrl", portalId, parameters);
|
||||
var paymentUrls = JsonSerializer.Deserialize<Dictionary<string, string>>(result);
|
||||
|
||||
var upgradeUrls = new Dictionary<string, string>();
|
||||
if (!string.IsNullOrEmpty(portalId)
|
||||
//TODO: remove
|
||||
&& false)
|
||||
{
|
||||
try
|
||||
{
|
||||
//max 100 products
|
||||
result = Request("GetPaymentUpgradeUrl", portalId, parameters);
|
||||
upgradeUrls = JsonSerializer.Deserialize<Dictionary<string, string>>(result);
|
||||
}
|
||||
catch (BillingNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var p in products)
|
||||
{
|
||||
string url;
|
||||
var paymentUrl = (Uri)null;
|
||||
var upgradeUrl = (Uri)null;
|
||||
if (paymentUrls.TryGetValue(p, out url))
|
||||
{
|
||||
url = ToUrl(url);
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
if (paymentUrls.TryGetValue(p, out url) && !string.IsNullOrEmpty(url = ToUrl(url)))
|
||||
{
|
||||
paymentUrl = new Uri(url);
|
||||
}
|
||||
}
|
||||
if (upgradeUrls.TryGetValue(p, out url))
|
||||
{
|
||||
url = ToUrl(url);
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
upgradeUrl = new Uri(url);
|
||||
}
|
||||
}
|
||||
urls[p] = Tuple.Create(paymentUrl, upgradeUrl);
|
||||
urls[p] = paymentUrl;
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
public string GetPaymentUrl(string portalId, string[] products, string affiliateId = null, string campaign = null, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
var additionalParameters = new List<Tuple<string, string>>() { Tuple.Create("PaymentSystemId", AvangatePaymentSystemId.ToString()) };
|
||||
if (!string.IsNullOrEmpty(affiliateId))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("AffiliateId", affiliateId));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(campaign))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("campaign", campaign));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(currency))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Currency", currency));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(language))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Language", language));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(customerId))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("CustomerID", customerId));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(quantity))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Quantity", quantity));
|
||||
}
|
||||
|
||||
var parameters = products
|
||||
.Distinct()
|
||||
.Select(p => Tuple.Create("ProductId", p))
|
||||
.Concat(additionalParameters)
|
||||
.ToArray();
|
||||
|
||||
var result = Request("GetSinglePaymentUrl", portalId, parameters);
|
||||
var paymentUrl = JsonConvert.DeserializeObject<string>(result);
|
||||
|
||||
return paymentUrl;
|
||||
}
|
||||
|
||||
public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(productIds);
|
||||
|
@ -1,331 +0,0 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using ConfigurationManager = System.Configuration.ConfigurationManager;
|
||||
using ConfigurationSection = System.Configuration.ConfigurationSection;
|
||||
|
||||
namespace ASC.Core.Common.Billing;
|
||||
|
||||
[Singletone]
|
||||
public class CouponManager : IDisposable
|
||||
{
|
||||
private IEnumerable<AvangateProduct> _products;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
private readonly IEnumerable<string> _groups;
|
||||
private readonly int _percent;
|
||||
private readonly int _schedule;
|
||||
private readonly string _vendorCode;
|
||||
private readonly byte[] _secret;
|
||||
private readonly Uri _baseAddress;
|
||||
private readonly string _apiVersion;
|
||||
private readonly SemaphoreSlim _semaphoreSlim;
|
||||
private readonly ILogger<CouponManager> _logger;
|
||||
|
||||
public CouponManager(ILogger<CouponManager> logger, IHttpClientFactory clientFactory)
|
||||
{
|
||||
_semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
_logger = logger;
|
||||
_clientFactory = clientFactory;
|
||||
|
||||
try
|
||||
{
|
||||
var cfg = (AvangateCfgSectionHandler)ConfigurationManager.GetSection("avangate");
|
||||
_secret = Encoding.UTF8.GetBytes(cfg.Secret);
|
||||
_vendorCode = cfg.Vendor;
|
||||
_percent = cfg.Percent;
|
||||
_schedule = cfg.Schedule;
|
||||
_baseAddress = new Uri(cfg.BaseAddress);
|
||||
_apiVersion = "/rest/" + cfg.ApiVersion.TrimStart('/');
|
||||
_groups = (cfg.Groups ?? "").Split(',', '|', ' ');
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_secret = Encoding.UTF8.GetBytes("");
|
||||
_vendorCode = "";
|
||||
_percent = AvangateCfgSectionHandler.DefaultPercent;
|
||||
_schedule = AvangateCfgSectionHandler.DefaultShedule;
|
||||
_baseAddress = new Uri(AvangateCfgSectionHandler.DefaultAdress);
|
||||
_apiVersion = AvangateCfgSectionHandler.DefaultApiVersion;
|
||||
_groups = new List<string>();
|
||||
_logger.CriticalCouponManager(e);
|
||||
}
|
||||
}
|
||||
|
||||
public string CreateCoupon(TenantManager tenantManager)
|
||||
{
|
||||
return CreatePromotionAsync(tenantManager).Result;
|
||||
}
|
||||
|
||||
private async Task<string> CreatePromotionAsync(TenantManager tenantManager)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var httpClient = PrepaireClient();
|
||||
using var content = new StringContent(await Promotion.GeneratePromotion(_logger, this, tenantManager, _percent, _schedule), Encoding.Default, "application/json");
|
||||
using var response = await httpClient.PostAsync($"{_apiVersion}/promotions/", content);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception(response.ReasonPhrase);
|
||||
}
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
await Task.Delay(1000 - DateTime.UtcNow.Millisecond); // otherwise authorize exception
|
||||
var createdPromotion = JsonConvert.DeserializeObject<Promotion>(result);
|
||||
return createdPromotion.Coupon.Code;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorWithException(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<IEnumerable<AvangateProduct>> GetProducts()
|
||||
{
|
||||
return _products != null ? Task.FromResult(_products) : InternalGetProducts();
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<AvangateProduct>> InternalGetProducts()
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
|
||||
if (_products != null)
|
||||
{
|
||||
_semaphoreSlim.Release();
|
||||
|
||||
return _products;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var httpClient = PrepaireClient();
|
||||
using var response = await httpClient.GetAsync($"{_apiVersion}/products/?Limit=1000&Enabled=true");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception(response.ReasonPhrase);
|
||||
}
|
||||
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
_logger.Debug(result);
|
||||
|
||||
var products = JsonConvert.DeserializeObject<List<AvangateProduct>>(result);
|
||||
products = products.Where(r => r.ProductGroup != null && _groups.Contains(r.ProductGroup.Code)).ToList();
|
||||
|
||||
return _products = products;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorWithException(ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private HttpClient PrepaireClient()
|
||||
{
|
||||
const string applicationJson = "application/json";
|
||||
|
||||
var httpClient = _clientFactory.CreateClient();
|
||||
httpClient.BaseAddress = _baseAddress;
|
||||
httpClient.Timeout = TimeSpan.FromMinutes(3);
|
||||
|
||||
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("accept", applicationJson);
|
||||
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", applicationJson);
|
||||
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Avangate-Authentication", CreateAuthHeader());
|
||||
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
private string CreateAuthHeader()
|
||||
{
|
||||
using var hmac = new HMACMD5(_secret);
|
||||
var date = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
var hash = _vendorCode.Length + _vendorCode + date.Length + date;
|
||||
var data = hmac.ComputeHash(Encoding.UTF8.GetBytes(hash));
|
||||
|
||||
var sBuilder = new StringBuilder();
|
||||
foreach (var t in data)
|
||||
{
|
||||
sBuilder.Append(t.ToString("x2"));
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append($"code='{_vendorCode}' ");
|
||||
stringBuilder.Append($"date='{date}' ");
|
||||
stringBuilder.Append($"hash='{sBuilder}'");
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_semaphoreSlim != null)
|
||||
{
|
||||
_semaphoreSlim.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Promotion
|
||||
{
|
||||
public string Code { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string StartDate { get; set; }
|
||||
public string EndDate { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public int MaximumOrdersNumber { get; set; }
|
||||
public bool InstantDiscount { get; set; }
|
||||
public string ChannelType { get; set; }
|
||||
public string ApplyRecurring { get; set; }
|
||||
public Coupon Coupon { get; set; }
|
||||
public Discount Discount { get; set; }
|
||||
public IEnumerable<CouponProduct> Products { get; set; }
|
||||
public int PublishToAffiliatesNetwork { get; set; }
|
||||
public int AutoApply { get; set; }
|
||||
|
||||
public static async Task<string> GeneratePromotion(ILogger log, CouponManager couponManager, TenantManager tenantManager, int percent, int schedule)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tenant = tenantManager.GetCurrentTenant();
|
||||
var startDate = DateTime.UtcNow.Date;
|
||||
var endDate = startDate.AddDays(schedule);
|
||||
var code = tenant.Alias;
|
||||
|
||||
var promotion = new Promotion
|
||||
{
|
||||
Type = "REGULAR",
|
||||
Enabled = true,
|
||||
MaximumOrdersNumber = 1,
|
||||
InstantDiscount = false,
|
||||
ChannelType = "ECOMMERCE",
|
||||
ApplyRecurring = "NONE",
|
||||
PublishToAffiliatesNetwork = 0,
|
||||
AutoApply = 0,
|
||||
|
||||
StartDate = startDate.ToString("yyyy-MM-dd"),
|
||||
EndDate = endDate.ToString("yyyy-MM-dd"),
|
||||
Name = string.Format("{0} {1}% off", code, percent),
|
||||
Coupon = new Coupon { Type = "SINGLE", Code = code },
|
||||
Discount = new Discount { Type = "PERCENT", Value = percent },
|
||||
Products = (await couponManager.GetProducts()).Select(r => new CouponProduct { Code = r.ProductCode })
|
||||
|
||||
};
|
||||
|
||||
return JsonConvert.SerializeObject(promotion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.ErrorWithException(ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Coupon
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
class Discount
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public int Value { get; set; }
|
||||
}
|
||||
|
||||
class AvangateProduct
|
||||
{
|
||||
public string ProductCode { get; set; }
|
||||
public string ProductName { get; set; }
|
||||
public AvangateProductGroup ProductGroup { get; set; }
|
||||
}
|
||||
|
||||
class AvangateProductGroup
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
class CouponProduct
|
||||
{
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
class AvangateCfgSectionHandler : ConfigurationSection
|
||||
{
|
||||
public const string DefaultAdress = "https://api.avangate.com/";
|
||||
public const string DefaultApiVersion = "4.0";
|
||||
public const int DefaultPercent = 5;
|
||||
public const int DefaultShedule = 10;
|
||||
|
||||
[ConfigurationProperty("secret")]
|
||||
public string Secret => (string)this["secret"];
|
||||
|
||||
[ConfigurationProperty("vendor")]
|
||||
public string Vendor
|
||||
{
|
||||
get => (string)this["vendor"];
|
||||
set => this["vendor"] = value;
|
||||
}
|
||||
|
||||
[ConfigurationProperty("percent", DefaultValue = DefaultPercent)]
|
||||
public int Percent
|
||||
{
|
||||
get => Convert.ToInt32(this["percent"]);
|
||||
set => this["percent"] = value;
|
||||
}
|
||||
|
||||
[ConfigurationProperty("schedule", DefaultValue = DefaultShedule)]
|
||||
public int Schedule
|
||||
{
|
||||
get => Convert.ToInt32(this["schedule"]);
|
||||
set => this["schedule"] = value;
|
||||
}
|
||||
|
||||
[ConfigurationProperty("groups")]
|
||||
public string Groups => (string)this["groups"];
|
||||
|
||||
[ConfigurationProperty("address", DefaultValue = DefaultAdress)]
|
||||
public string BaseAddress
|
||||
{
|
||||
get => (string)this["address"];
|
||||
set => this["address"] = value;
|
||||
}
|
||||
|
||||
[ConfigurationProperty("apiVersion", DefaultValue = DefaultApiVersion)]
|
||||
public string ApiVersion
|
||||
{
|
||||
get => (string)this["apiVersion"];
|
||||
set => this["apiVersion"] = value;
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ public interface ITariffService
|
||||
string GetButton(int tariffId, string partnerId);
|
||||
Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true);
|
||||
Uri GetShoppingUri(int? tenant, int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null, string quantity = null);
|
||||
Uri GetShoppingUri(string[] productIds, string affiliateId = null, string currency = null, string language = null, string customerId = null, string quantity = null);
|
||||
void ClearCache(int tenantId);
|
||||
void DeleteDefaultBillingInfo();
|
||||
void SaveButton(int tariffId, string partnerId, string buttonUrl);
|
||||
|
@ -33,30 +33,14 @@ namespace ASC.Core.Billing;
|
||||
public class License
|
||||
{
|
||||
public string OriginalLicense { get; set; }
|
||||
|
||||
[JsonPropertyName("affiliate_id")]
|
||||
public string AffiliateId { get; set; }
|
||||
|
||||
//[Obsolete]
|
||||
public bool WhiteLabel { get; set; }
|
||||
public bool Customization { get; set; }
|
||||
public bool Branding { get; set; }
|
||||
public bool SSBranding { get; set; }
|
||||
|
||||
[JsonPropertyName("end_date")]
|
||||
public DateTime DueDate { get; set; }
|
||||
|
||||
[JsonPropertyName("portal_count")]
|
||||
public int PortalCount { get; set; }
|
||||
public bool Trial { get; set; }
|
||||
|
||||
[JsonPropertyName("user_quota")]
|
||||
public int ActiveUsers { get; set; }
|
||||
|
||||
[JsonPropertyName("customer_id")]
|
||||
public string CustomerId { get; set; }
|
||||
public string Signature { get; set; }
|
||||
public bool? DiscEncryption { get; set; }
|
||||
|
||||
[JsonPropertyName("users_count")]
|
||||
public int DSUsersCount { get; set; }
|
||||
@ -67,6 +51,9 @@ public class License
|
||||
[JsonPropertyName("connections")]
|
||||
public int DSConnections { get; set; }
|
||||
|
||||
[JsonPropertyName("signature")]
|
||||
public string Signature { get; set; }
|
||||
|
||||
public static License Parse(string licenseString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(licenseString))
|
||||
|
@ -44,11 +44,11 @@ public class LicenseReader
|
||||
private readonly PaymentManager _paymentManager;
|
||||
private readonly CoreSettings _coreSettings;
|
||||
private readonly ILogger<LicenseReader> _logger;
|
||||
private readonly Users.Constants _constants;
|
||||
public readonly string LicensePath;
|
||||
private readonly string _licensePathTemp;
|
||||
|
||||
public const string CustomerIdKey = "CustomerId";
|
||||
public const int MaxUserCount = 10000;
|
||||
|
||||
public LicenseReader(
|
||||
UserManager userManager,
|
||||
@ -56,7 +56,8 @@ public class LicenseReader
|
||||
PaymentManager paymentManager,
|
||||
CoreSettings coreSettings,
|
||||
LicenseReaderConfig licenseReaderConfig,
|
||||
ILogger<LicenseReader> logger)
|
||||
ILogger<LicenseReader> logger,
|
||||
Users.Constants constants)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_tenantManager = tenantManager;
|
||||
@ -65,6 +66,7 @@ public class LicenseReader
|
||||
LicensePath = licenseReaderConfig.LicensePath;
|
||||
_licensePathTemp = LicensePath + ".tmp";
|
||||
_logger = logger;
|
||||
_constants = constants;
|
||||
}
|
||||
|
||||
public string CustomerId
|
||||
@ -186,31 +188,6 @@ public class LicenseReader
|
||||
throw new BillingNotConfiguredException("License not correct", license.OriginalLicense);
|
||||
}
|
||||
|
||||
if (license.DueDate.Date < VersionReleaseDate)
|
||||
{
|
||||
throw new LicenseExpiredException("License expired", license.OriginalLicense);
|
||||
}
|
||||
|
||||
if (license.ActiveUsers.Equals(default) || license.ActiveUsers < 1)
|
||||
{
|
||||
license.ActiveUsers = MaxUserCount;
|
||||
}
|
||||
|
||||
if (license.ActiveUsers < _userManager.GetUsers(EmployeeStatus.Default, EmployeeType.User).Length)
|
||||
{
|
||||
throw new LicenseQuotaException("License quota", license.OriginalLicense);
|
||||
}
|
||||
|
||||
if (license.PortalCount <= 0)
|
||||
{
|
||||
license.PortalCount = _tenantManager.GetTenantQuota(Tenant.DefaultTenant).CountPortals;
|
||||
}
|
||||
var activePortals = _tenantManager.GetTenants().Count;
|
||||
if (activePortals > 1 && license.PortalCount < activePortals)
|
||||
{
|
||||
throw new LicensePortalException("License portal count", license.OriginalLicense);
|
||||
}
|
||||
|
||||
return license.DueDate.Date;
|
||||
}
|
||||
|
||||
@ -224,40 +201,16 @@ public class LicenseReader
|
||||
|
||||
var quota = new TenantQuota(-1000)
|
||||
{
|
||||
ActiveUsers = license.ActiveUsers,
|
||||
ActiveUsers = _constants.MaxEveryoneCount,
|
||||
MaxFileSize = defaultQuota.MaxFileSize,
|
||||
MaxTotalSize = defaultQuota.MaxTotalSize,
|
||||
Name = "license",
|
||||
DocsEdition = true,
|
||||
HasDomain = true,
|
||||
Audit = true,
|
||||
ControlPanel = true,
|
||||
HealthCheck = true,
|
||||
Ldap = true,
|
||||
Sso = true,
|
||||
Customization = license.Customization,
|
||||
WhiteLabel = license.WhiteLabel || license.Customization,
|
||||
Branding = license.Branding,
|
||||
SSBranding = license.SSBranding,
|
||||
Update = true,
|
||||
Support = true,
|
||||
Trial = license.Trial,
|
||||
CountPortals = license.PortalCount,
|
||||
DiscEncryption = true,
|
||||
PrivacyRoom = true,
|
||||
Restore = true,
|
||||
ContentSearch = true
|
||||
Trial = license.Trial
|
||||
};
|
||||
|
||||
if (defaultQuota.Name != "overdue" && !defaultQuota.Trial)
|
||||
{
|
||||
quota.WhiteLabel |= defaultQuota.WhiteLabel;
|
||||
quota.Branding |= defaultQuota.Branding;
|
||||
quota.SSBranding |= defaultQuota.SSBranding;
|
||||
|
||||
quota.CountPortals = Math.Max(defaultQuota.CountPortals, quota.CountPortals);
|
||||
}
|
||||
|
||||
_tenantManager.SaveTenantQuota(quota);
|
||||
|
||||
var tariff = new Tariff
|
||||
@ -267,13 +220,6 @@ public class LicenseReader
|
||||
};
|
||||
|
||||
_paymentManager.SetTariff(-1, tariff);
|
||||
|
||||
if (!string.IsNullOrEmpty(license.AffiliateId))
|
||||
{
|
||||
var tenant = _tenantManager.GetCurrentTenant();
|
||||
tenant.AffiliateId = license.AffiliateId;
|
||||
_tenantManager.SaveTenant(tenant);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogError(Exception error)
|
||||
@ -294,61 +240,4 @@ public class LicenseReader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly DateTime _date = DateTime.MinValue;
|
||||
|
||||
public DateTime VersionReleaseDate
|
||||
{
|
||||
get
|
||||
{
|
||||
// release sign is not longer requered
|
||||
return _date;
|
||||
|
||||
//if (_date != DateTime.MinValue) return _date;
|
||||
|
||||
//_date = DateTime.MaxValue;
|
||||
//try
|
||||
//{
|
||||
// var versionDate = Configuration["version:release:date"];
|
||||
// var sign = Configuration["version:release:sign"];
|
||||
|
||||
// if (!sign.StartsWith("ASC "))
|
||||
// {
|
||||
// throw new Exception("sign without ASC");
|
||||
// }
|
||||
|
||||
// var splitted = sign.Substring(4).Split(':');
|
||||
// var pkey = splitted[0];
|
||||
// if (pkey != versionDate)
|
||||
// {
|
||||
// throw new Exception("sign with different date");
|
||||
// }
|
||||
|
||||
// var date = splitted[1];
|
||||
// var orighash = splitted[2];
|
||||
|
||||
//var skey = MachinePseudoKeys.GetMachineConstant();
|
||||
|
||||
//using (var hasher = new HMACSHA1(skey))
|
||||
// {
|
||||
// var data = string.Join("\n", date, pkey);
|
||||
// var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
// if (WebEncoders.Base64UrlEncode(hash) != orighash && Convert.ToBase64String(hash) != orighash)
|
||||
// {
|
||||
// throw new Exception("incorrect hash");
|
||||
// }
|
||||
// }
|
||||
|
||||
// var year = int.Parse(versionDate.Substring(0, 4));
|
||||
// var month = int.Parse(versionDate.Substring(4, 2));
|
||||
// var day = int.Parse(versionDate.Substring(6, 2));
|
||||
// _date = new DateTime(year, month, day);
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Log.Error("VersionReleaseDate", ex);
|
||||
//}
|
||||
//return _date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ public class PaymentInfo
|
||||
public string LName { get; set; }
|
||||
public string Email { get; set; }
|
||||
public DateTime PaymentDate { get; set; }
|
||||
public Decimal Price { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public int Qty { get; set; }
|
||||
public string PaymentCurrency { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
public int QuotaId { get; set; }
|
||||
|
@ -246,6 +246,28 @@ public class TariffService : ITariffService
|
||||
}
|
||||
catch (BillingNotFoundException)
|
||||
{
|
||||
var q = QuotaService.GetTenantQuota(tariff.QuotaId);
|
||||
|
||||
if (q != null
|
||||
&& !q.Trial
|
||||
&& !q.Free
|
||||
&& !q.NonProfit
|
||||
&& !q.Open
|
||||
&& !q.Custom)
|
||||
{
|
||||
var asynctariff = Tariff.CreateDefault();
|
||||
asynctariff.DueDate = DateTime.Today.AddDays(-1);
|
||||
asynctariff.Prolongable = false;
|
||||
asynctariff.Autorenewal = false;
|
||||
asynctariff.State = TariffState.NotPaid;
|
||||
|
||||
if (SaveBillingInfo(tenantId, asynctariff))
|
||||
{
|
||||
asynctariff = CalculateTariff(tenantId, asynctariff);
|
||||
ClearCache(tenantId);
|
||||
Cache.Insert(key, asynctariff, DateTime.UtcNow.Add(GetCacheExpiration()));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
@ -351,9 +373,9 @@ public class TariffService : ITariffService
|
||||
? GetBillingUrlCacheKey(tenant.Value)
|
||||
: string.Format($"notenant{(!string.IsNullOrEmpty(affiliateId) ? "_" + affiliateId : "")}");
|
||||
key += quota.Visible ? "" : "0";
|
||||
if (Cache.Get<Dictionary<string, Tuple<Uri, Uri>>>(key) is not IDictionary<string, Tuple<Uri, Uri>> urls)
|
||||
if (Cache.Get<Dictionary<string, Uri>>(key) is not IDictionary<string, Uri> urls)
|
||||
{
|
||||
urls = new Dictionary<string, Tuple<Uri, Uri>>();
|
||||
urls = new Dictionary<string, Uri>();
|
||||
if (_billingClient.Configured)
|
||||
{
|
||||
try
|
||||
@ -386,29 +408,64 @@ public class TariffService : ITariffService
|
||||
|
||||
ResetCacheExpiration();
|
||||
|
||||
if (!string.IsNullOrEmpty(quota.AvangateId) && urls.TryGetValue(quota.AvangateId, out var tuple))
|
||||
if (!string.IsNullOrEmpty(quota.AvangateId) && urls.TryGetValue(quota.AvangateId, out var url))
|
||||
{
|
||||
var result = tuple.Item2;
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
result = tuple.Item1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tariff = tenant.HasValue ? GetTariff(tenant.Value) : null;
|
||||
if (tariff == null || tariff.QuotaId == quotaId || tariff.State >= TariffState.Delay)
|
||||
{
|
||||
result = tuple.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
if (url == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
result = new Uri(result.ToString()
|
||||
url = new Uri(url.ToString()
|
||||
.Replace("__Currency__", HttpUtility.UrlEncode(currency ?? ""))
|
||||
.Replace("__Language__", HttpUtility.UrlEncode((language ?? "").ToLower()))
|
||||
.Replace("__CustomerID__", HttpUtility.UrlEncode(customerId ?? ""))
|
||||
.Replace("__Quantity__", HttpUtility.UrlEncode(quantity ?? "")));
|
||||
return url;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(string[] productIds, string affiliateId = null, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
var key = "shopingurl" + string.Join("_", productIds) + (!string.IsNullOrEmpty(affiliateId) ? "_" + affiliateId : "");
|
||||
var url = Cache.Get<string>(key);
|
||||
if (url == null)
|
||||
{
|
||||
url = string.Empty;
|
||||
if (_billingClient.Configured)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = GetBillingClient();
|
||||
url =
|
||||
client.GetPaymentUrl(
|
||||
null,
|
||||
productIds,
|
||||
affiliateId,
|
||||
null,
|
||||
!string.IsNullOrEmpty(currency) ? "__Currency__" : null,
|
||||
!string.IsNullOrEmpty(language) ? "__Language__" : null,
|
||||
!string.IsNullOrEmpty(customerId) ? "__CustomerID__" : null,
|
||||
!string.IsNullOrEmpty(quantity) ? "__Quantity__" : null
|
||||
);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
Logger.ErrorWithException(error);
|
||||
}
|
||||
}
|
||||
Cache.Insert(key, url, DateTime.UtcNow.Add(TimeSpan.FromMinutes(10)));
|
||||
}
|
||||
|
||||
ResetCacheExpiration();
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = new Uri(url.ToString()
|
||||
.Replace("__Currency__", HttpUtility.UrlEncode(currency ?? ""))
|
||||
.Replace("__Language__", HttpUtility.UrlEncode((language ?? "").ToLower()))
|
||||
.Replace("__CustomerID__", HttpUtility.UrlEncode(customerId ?? ""))
|
||||
@ -416,9 +473,6 @@ public class TariffService : ITariffService
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(productIds);
|
||||
@ -617,7 +671,6 @@ public class TariffService : ITariffService
|
||||
defaultQuota.Name = "overdue";
|
||||
|
||||
defaultQuota.Features = q.Features;
|
||||
defaultQuota.Support = false;
|
||||
|
||||
QuotaService.SaveTenantQuota(defaultQuota);
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ class CachedAzService : IAzService
|
||||
public AzRecord SaveAce(int tenant, AzRecord r)
|
||||
{
|
||||
r = _service.SaveAce(tenant, r);
|
||||
_cacheNotify.Publish(r, CacheNotifyAction.InsertOrUpdate);
|
||||
_cacheNotify.Publish((AzRecordCache)r, CacheNotifyAction.InsertOrUpdate);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -107,6 +107,6 @@ class CachedAzService : IAzService
|
||||
public void RemoveAce(int tenant, AzRecord r)
|
||||
{
|
||||
_service.RemoveAce(tenant, r);
|
||||
_cacheNotify.Publish(r, CacheNotifyAction.Remove);
|
||||
_cacheNotify.Publish((AzRecordCache)r, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
@ -430,4 +430,9 @@ public class CachedUserService : IUserService, ICachedService
|
||||
|
||||
return Service.GetUser(tenant, id, exp);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetDavUserEmails(int tenant)
|
||||
{
|
||||
return Service.GetDavUserEmails(tenant);
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,17 @@ public class PaymentManager
|
||||
return _tariffService.GetShoppingUri(null, quotaId, affiliateId, currency, language, customerId, quantity);
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(string productId, string currency = null, string language = null, string customerId = null, string quantity = null, string affiliateId = null)
|
||||
{
|
||||
return _tariffService.GetShoppingUri(new[] { productId }, affiliateId, currency, language, customerId, quantity);
|
||||
}
|
||||
|
||||
// used in www
|
||||
public Uri GetShoppingUri(string[] productIds, string currency = null, string language = null, string customerId = null, string quantity = null, string affiliateId = null)
|
||||
{
|
||||
return _tariffService.GetShoppingUri(productIds, affiliateId, currency, language, customerId, quantity);
|
||||
}
|
||||
|
||||
public void ActivateKey(string key)
|
||||
{
|
||||
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(key);
|
||||
|
@ -328,6 +328,7 @@ public class TenantManager
|
||||
{
|
||||
currentQuota.ActiveUsers = tariff.Quantity;
|
||||
currentQuota.MaxTotalSize *= currentQuota.ActiveUsers;
|
||||
currentQuota.Price *= currentQuota.ActiveUsers;
|
||||
}
|
||||
|
||||
return currentQuota;
|
||||
|
@ -55,6 +55,12 @@ public class UserManager
|
||||
private readonly PermissionContext _permissionContext;
|
||||
private readonly UserManagerConstants _userManagerConstants;
|
||||
private readonly CoreBaseSettings _coreBaseSettings;
|
||||
private readonly CoreSettings _coreSettings;
|
||||
private readonly InstanceCrypto _instanceCrypto;
|
||||
private readonly RadicaleClient _radicaleClient;
|
||||
private readonly CardDavAddressbook _cardDavAddressbook;
|
||||
private readonly ILogger<UserManager> _log;
|
||||
private readonly ICache _cache;
|
||||
private readonly Constants _constants;
|
||||
|
||||
private Tenant _tenant;
|
||||
@ -70,13 +76,25 @@ public class UserManager
|
||||
TenantManager tenantManager,
|
||||
PermissionContext permissionContext,
|
||||
UserManagerConstants userManagerConstants,
|
||||
CoreBaseSettings coreBaseSettings)
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings,
|
||||
InstanceCrypto instanceCrypto,
|
||||
RadicaleClient radicaleClient,
|
||||
CardDavAddressbook cardDavAddressbook,
|
||||
ILogger<UserManager> log,
|
||||
ICache cache)
|
||||
{
|
||||
_userService = service;
|
||||
_tenantManager = tenantManager;
|
||||
_permissionContext = permissionContext;
|
||||
_userManagerConstants = userManagerConstants;
|
||||
_coreBaseSettings = coreBaseSettings;
|
||||
_coreSettings = coreSettings;
|
||||
_instanceCrypto = instanceCrypto;
|
||||
_radicaleClient = radicaleClient;
|
||||
_cardDavAddressbook = cardDavAddressbook;
|
||||
_log = log;
|
||||
_cache = cache;
|
||||
_constants = _userManagerConstants.Constants;
|
||||
}
|
||||
|
||||
@ -86,8 +104,14 @@ public class UserManager
|
||||
PermissionContext permissionContext,
|
||||
UserManagerConstants userManagerConstants,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings,
|
||||
InstanceCrypto instanceCrypto,
|
||||
RadicaleClient radicaleClient,
|
||||
CardDavAddressbook cardDavAddressbook,
|
||||
ILogger<UserManager> log,
|
||||
ICache cache,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings)
|
||||
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings, coreSettings, instanceCrypto, radicaleClient, cardDavAddressbook, log, cache)
|
||||
{
|
||||
_accessor = httpContextAccessor;
|
||||
}
|
||||
@ -279,7 +303,7 @@ public class UserManager
|
||||
return findUsers.ToArray();
|
||||
}
|
||||
|
||||
public UserInfo SaveUserInfo(UserInfo u, bool isVisitor = false)
|
||||
public UserInfo SaveUserInfo(UserInfo u, bool isVisitor = false, bool syncCardDav = false)
|
||||
{
|
||||
if (IsSystemUser(u.Id))
|
||||
{
|
||||
@ -329,10 +353,77 @@ public class UserManager
|
||||
throw new InvalidOperationException("Can not disable tenant owner.");
|
||||
}
|
||||
|
||||
var oldUserData = _userService.GetUserByUserName(_tenantManager.GetCurrentTenant().Id, u.UserName);
|
||||
var newUser = _userService.SaveUser(_tenantManager.GetCurrentTenant().Id, u);
|
||||
|
||||
if (syncCardDav)
|
||||
{
|
||||
var tenant = _tenantManager.GetCurrentTenant();
|
||||
var myUri = (_accessor?.HttpContext != null) ? _accessor.HttpContext.Request.GetUrlRewriter().ToString() :
|
||||
(_cache.Get<string>("REWRITE_URL" + tenant.Id) != null) ?
|
||||
new Uri(_cache.Get<string>("REWRITE_URL" + tenant.Id)).ToString() : tenant.GetTenantDomain(_coreSettings);
|
||||
|
||||
var rootAuthorization = _cardDavAddressbook.GetSystemAuthorization();
|
||||
var allUserEmails = GetDavUserEmails().ToList();
|
||||
|
||||
if (oldUserData != null && oldUserData.Status != newUser.Status && newUser.Status == EmployeeStatus.Terminated)
|
||||
{
|
||||
var userAuthorization = oldUserData.Email.ToLower() + ":" + _instanceCrypto.Encrypt(oldUserData.Email);
|
||||
var requestUrlBook = _cardDavAddressbook.GetRadicaleUrl(myUri, newUser.Email.ToLower(), true, true);
|
||||
var collection = _cardDavAddressbook.GetCollection(requestUrlBook, userAuthorization, myUri.ToString()).Result;
|
||||
if (collection.Completed && collection.StatusCode != 404)
|
||||
{
|
||||
_cardDavAddressbook.Delete(myUri, newUser.Id, newUser.Email, tenant.Id).Wait();//TODO
|
||||
}
|
||||
foreach (var email in allUserEmails)
|
||||
{
|
||||
var requestUrlItem = _cardDavAddressbook.GetRadicaleUrl(myUri.ToString(), email.ToLower(), true, true, itemID: newUser.Id.ToString());
|
||||
try
|
||||
{
|
||||
var davItemRequest = new DavRequest()
|
||||
{
|
||||
Url = requestUrlItem,
|
||||
Authorization = rootAuthorization,
|
||||
Header = myUri
|
||||
};
|
||||
_radicaleClient.RemoveAsync(davItemRequest).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.ErrorWithException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var cardDavUser = new CardDavItem(u.Id, u.FirstName, u.LastName, u.UserName, u.BirthDate, u.Sex, u.Title, u.Email, u.ContactsList, u.MobilePhone);
|
||||
|
||||
try
|
||||
{
|
||||
_cardDavAddressbook.UpdateItemForAllAddBooks(allUserEmails, myUri, cardDavUser, _tenantManager.GetCurrentTenant().Id, oldUserData != null && oldUserData.Email != newUser.Email ? oldUserData.Email : null).Wait(); // todo
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.ErrorWithException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.ErrorWithException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return newUser;
|
||||
}
|
||||
public IEnumerable<string> GetDavUserEmails()
|
||||
{
|
||||
return _userService.GetDavUserEmails(_tenantManager.GetCurrentTenant().Id);
|
||||
}
|
||||
|
||||
public void DeleteUser(Guid id)
|
||||
{
|
||||
@ -347,7 +438,59 @@ public class UserManager
|
||||
throw new InvalidOperationException("Can not remove tenant owner.");
|
||||
}
|
||||
|
||||
var delUser = GetUsers(id);
|
||||
_userService.RemoveUser(Tenant.Id, id);
|
||||
var tenant = _tenantManager.GetCurrentTenant();
|
||||
|
||||
try
|
||||
{
|
||||
var curreMail = delUser.Email.ToLower();
|
||||
var currentAccountPaswd = _instanceCrypto.Encrypt(curreMail);
|
||||
var userAuthorization = curreMail + ":" + currentAccountPaswd;
|
||||
var rootAuthorization = _cardDavAddressbook.GetSystemAuthorization();
|
||||
var myUri = (_accessor?.HttpContext != null) ? _accessor.HttpContext.Request.GetUrlRewriter().ToString() :
|
||||
(_cache.Get<string>("REWRITE_URL" + tenant.Id) != null) ?
|
||||
new Uri(_cache.Get<string>("REWRITE_URL" + tenant.Id)).ToString() : tenant.GetTenantDomain(_coreSettings);
|
||||
var davUsersEmails = GetDavUserEmails();
|
||||
var requestUrlBook = _cardDavAddressbook.GetRadicaleUrl(myUri, delUser.Email.ToLower(), true, true);
|
||||
var addBookCollection = _cardDavAddressbook.GetCollection(requestUrlBook, userAuthorization, myUri.ToString()).Result;
|
||||
|
||||
|
||||
if (addBookCollection.Completed && addBookCollection.StatusCode != 404)
|
||||
{
|
||||
var davbookRequest = new DavRequest()
|
||||
{
|
||||
Url = requestUrlBook,
|
||||
Authorization = rootAuthorization,
|
||||
Header = myUri
|
||||
};
|
||||
_radicaleClient.RemoveAsync(davbookRequest).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
foreach (var email in davUsersEmails)
|
||||
{
|
||||
var requestUrlItem = _cardDavAddressbook.GetRadicaleUrl(myUri.ToString(), email.ToLower(), true, true, itemID: delUser.Id.ToString());
|
||||
try
|
||||
{
|
||||
var davItemRequest = new DavRequest()
|
||||
{
|
||||
Url = requestUrlItem,
|
||||
Authorization = rootAuthorization,
|
||||
Header = myUri
|
||||
};
|
||||
_radicaleClient.RemoveAsync(davItemRequest).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.ErrorWithException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.ErrorWithException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveUserPhoto(Guid id, byte[] photo)
|
||||
@ -467,6 +610,15 @@ public class UserManager
|
||||
_userService.SaveUserGroupRef(Tenant.Id, new UserGroupRef(userId, groupId, UserGroupRefType.Contains));
|
||||
|
||||
ResetGroupCache(userId);
|
||||
var user = GetUsers(userId);
|
||||
if (groupId == Constants.GroupVisitor.ID)
|
||||
{
|
||||
var tenant = _tenantManager.GetCurrentTenant();
|
||||
var myUri = (_accessor?.HttpContext != null) ? _accessor.HttpContext.Request.GetUrlRewriter().ToString() :
|
||||
(_cache.Get<string>("REWRITE_URL" + tenant.Id) != null) ?
|
||||
new Uri(_cache.Get<string>("REWRITE_URL" + tenant.Id)).ToString() : tenant.GetTenantDomain(_coreSettings);
|
||||
_cardDavAddressbook.Delete(myUri, user.Id, user.Email, tenant.Id).Wait(); //todo
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveUserFromGroup(Guid userId, Guid groupId)
|
||||
@ -563,7 +715,7 @@ public class UserManager
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
group = ToGroup(Constants.BuildinGroups.FirstOrDefault(r => r.ID == groupID));
|
||||
group = ToGroup(Constants.BuildinGroups.FirstOrDefault(r => r.ID == groupID) ?? Constants.LostGroupInfo);
|
||||
}
|
||||
|
||||
return new GroupInfo
|
||||
|
@ -30,6 +30,8 @@ namespace ASC.Core;
|
||||
public class SecurityContext
|
||||
{
|
||||
private readonly ILogger<SecurityContext> _logger;
|
||||
private readonly DbLoginEventsManager _dbLoginEventsManager;
|
||||
|
||||
public IAccount CurrentAccount => _authContext.CurrentAccount;
|
||||
public bool IsAuthenticated => _authContext.IsAuthenticated;
|
||||
|
||||
@ -50,10 +52,12 @@ public class SecurityContext
|
||||
UserFormatter userFormatter,
|
||||
CookieStorage cookieStorage,
|
||||
TenantCookieSettingsHelper tenantCookieSettingsHelper,
|
||||
ILogger<SecurityContext> logger
|
||||
ILogger<SecurityContext> logger,
|
||||
DbLoginEventsManager dbLoginEventsManager
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_dbLoginEventsManager = dbLoginEventsManager;
|
||||
_userManager = userManager;
|
||||
_authentication = authentication;
|
||||
_authContext = authContext;
|
||||
@ -72,14 +76,15 @@ public class SecurityContext
|
||||
UserFormatter userFormatter,
|
||||
CookieStorage cookieStorage,
|
||||
TenantCookieSettingsHelper tenantCookieSettingsHelper,
|
||||
ILogger<SecurityContext> logger
|
||||
) : this(userManager, authentication, authContext, tenantManager, userFormatter, cookieStorage, tenantCookieSettingsHelper, logger)
|
||||
ILogger<SecurityContext> logger,
|
||||
DbLoginEventsManager dbLoginEventsManager
|
||||
) : this(userManager, authentication, authContext, tenantManager, userFormatter, cookieStorage, tenantCookieSettingsHelper, logger, dbLoginEventsManager)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
|
||||
public string AuthenticateMe(string login, string passwordHash)
|
||||
public string AuthenticateMe(string login, string passwordHash, Func<int> funcLoginEvent = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(login);
|
||||
ArgumentNullException.ThrowIfNull(passwordHash);
|
||||
@ -87,7 +92,7 @@ public class SecurityContext
|
||||
var tenantid = _tenantManager.GetCurrentTenant().Id;
|
||||
var u = _userManager.GetUsersByPasswordHash(tenantid, login, passwordHash);
|
||||
|
||||
return AuthenticateMe(new UserAccount(u, tenantid, _userFormatter));
|
||||
return AuthenticateMe(new UserAccount(u, tenantid, _userFormatter), funcLoginEvent);
|
||||
}
|
||||
|
||||
public bool AuthenticateMe(string cookie)
|
||||
@ -110,7 +115,7 @@ public class SecurityContext
|
||||
}
|
||||
_logger.InformationEmptyBearer(ipFrom, address);
|
||||
}
|
||||
else if (_cookieStorage.DecryptCookie(cookie, out var tenant, out var userid, out var indexTenant, out var expire, out var indexUser))
|
||||
else if (_cookieStorage.DecryptCookie(cookie, out var tenant, out var userid, out var indexTenant, out var expire, out var indexUser, out var loginEventId))
|
||||
{
|
||||
if (tenant != _tenantManager.GetCurrentTenant().Id)
|
||||
{
|
||||
@ -136,8 +141,13 @@ public class SecurityContext
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthenticateMeWithoutCookie(new UserAccount(new UserInfo { Id = userid }, tenant, _userFormatter));
|
||||
var settingLoginEvents = _dbLoginEventsManager.GetLoginEventIds(tenant, userid).Result; // remove Result
|
||||
if (loginEventId != 0 && !settingLoginEvents.Contains(loginEventId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthenticateMeWithoutCookie(new UserAccount(new UserInfo { Id = userid }, tenant, _userFormatter));
|
||||
return true;
|
||||
}
|
||||
catch (InvalidCredentialException ice)
|
||||
@ -174,7 +184,13 @@ public class SecurityContext
|
||||
return false;
|
||||
}
|
||||
|
||||
public string AuthenticateMe(IAccount account, List<Claim> additionalClaims = null)
|
||||
public string AuthenticateMe(Guid userId, Func<int> funcLoginEvent = null, List<Claim> additionalClaims = null)
|
||||
{
|
||||
var account = _authentication.GetAccountByID(_tenantManager.GetCurrentTenant().Id, userId);
|
||||
return AuthenticateMe(account, funcLoginEvent, additionalClaims);
|
||||
}
|
||||
|
||||
public string AuthenticateMe(IAccount account, Func<int> funcLoginEvent = null, List<Claim> additionalClaims = null)
|
||||
{
|
||||
AuthenticateMeWithoutCookie(account, additionalClaims);
|
||||
|
||||
@ -182,7 +198,13 @@ public class SecurityContext
|
||||
|
||||
if (account is IUserAccount)
|
||||
{
|
||||
cookie = _cookieStorage.EncryptCookie(_tenantManager.GetCurrentTenant().Id, account.ID);
|
||||
var loginEventId = 0;
|
||||
if (funcLoginEvent != null)
|
||||
{
|
||||
loginEventId = funcLoginEvent();
|
||||
}
|
||||
|
||||
cookie = _cookieStorage.EncryptCookie(_tenantManager.GetCurrentTenant().Id, account.ID, loginEventId);
|
||||
}
|
||||
|
||||
return cookie;
|
||||
@ -251,13 +273,6 @@ public class SecurityContext
|
||||
_authContext.Principal = new CustomClaimsPrincipal(new ClaimsIdentity(account, claims), account);
|
||||
}
|
||||
|
||||
public string AuthenticateMe(Guid userId, List<Claim> additionalClaims = null)
|
||||
{
|
||||
var account = _authentication.GetAccountByID(_tenantManager.GetCurrentTenant().Id, userId);
|
||||
|
||||
return AuthenticateMe(account, additionalClaims);
|
||||
}
|
||||
|
||||
public void AuthenticateMeWithoutCookie(Guid userId, List<Claim> additionalClaims = null)
|
||||
{
|
||||
var account = _authentication.GetAccountByID(_tenantManager.GetCurrentTenant().Id, userId);
|
||||
|
@ -59,6 +59,7 @@ public interface IUserService
|
||||
UserInfo SaveUser(int tenant, UserInfo user);
|
||||
void RemoveGroup(int tenant, Guid id);
|
||||
void RemoveUser(int tenant, Guid id);
|
||||
IEnumerable<string> GetDavUserEmails(int tenant);
|
||||
void RemoveUserGroupRef(int tenant, Guid userId, Guid groupId, UserGroupRefType refType);
|
||||
void SetUserPasswordHash(int tenant, Guid id, string passwordHash);
|
||||
void SetUserPhoto(int tenant, Guid id, byte[] photo);
|
||||
|
@ -24,8 +24,6 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using AutoMapper.QueryableExtensions;
|
||||
|
||||
namespace ASC.Core.Data;
|
||||
|
||||
[Scope]
|
||||
|
184
common/ASC.Core.Common/Data/DbLoginEventsManager.cs
Normal file
184
common/ASC.Core.Common/Data/DbLoginEventsManager.cs
Normal file
@ -0,0 +1,184 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Core.Data;
|
||||
|
||||
[Scope]
|
||||
public class DbLoginEventsManager
|
||||
{
|
||||
private const string GuidLoginEvent = "F4D8BBF6-EB63-4781-B55E-5885EAB3D759";
|
||||
private static readonly TimeSpan _expirationTimeout = TimeSpan.FromMinutes(5);
|
||||
private static readonly List<int> _loginActions = new List<int>
|
||||
{
|
||||
(int)MessageAction.LoginSuccess,
|
||||
(int)MessageAction.LoginSuccessViaSocialAccount,
|
||||
(int)MessageAction.LoginSuccessViaSms,
|
||||
(int)MessageAction.LoginSuccessViaApi,
|
||||
(int)MessageAction.LoginSuccessViaSocialApp,
|
||||
(int)MessageAction.LoginSuccessViaApiSms,
|
||||
(int)MessageAction.LoginSuccessViaSSO,
|
||||
(int)MessageAction.LoginSuccessViaApiSocialAccount,
|
||||
(int)MessageAction.LoginSuccesViaTfaApp,
|
||||
(int)MessageAction.LoginSuccessViaApiTfa
|
||||
};
|
||||
|
||||
private readonly ICache _cache;
|
||||
private readonly TenantManager _tenantManager;
|
||||
private readonly AuthContext _authContext;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
private MessagesContext LoginEventContext => _lazyLoginEventContext.Value;
|
||||
private readonly Lazy<MessagesContext> _lazyLoginEventContext;
|
||||
|
||||
public DbLoginEventsManager(
|
||||
ICache cache,
|
||||
TenantManager tenantManager,
|
||||
AuthContext authContext,
|
||||
DbContextManager<MessagesContext> dbContextManager,
|
||||
TenantUtil tenantUtil,
|
||||
IMapper mapper)
|
||||
{
|
||||
_cache = cache;
|
||||
_tenantManager = tenantManager;
|
||||
_authContext = authContext;
|
||||
_mapper = mapper;
|
||||
_lazyLoginEventContext = new Lazy<MessagesContext>(() => dbContextManager.Value);
|
||||
}
|
||||
|
||||
public async Task<List<int>> GetLoginEventIds(int tenantId, Guid userId)
|
||||
{
|
||||
var commonKey = GetCacheKey(tenantId, userId);
|
||||
var cacheKeys = _cache.Get<List<int>>(commonKey);
|
||||
if (cacheKeys != null)
|
||||
{
|
||||
return cacheKeys;
|
||||
}
|
||||
|
||||
var date = DateTime.UtcNow.AddYears(-1);
|
||||
var resultList = await LoginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && _loginActions.Contains(r.Action) && r.Date >= date && r.Active)
|
||||
.Select(r => r.Id)
|
||||
.ToListAsync();
|
||||
|
||||
if (resultList != null)
|
||||
{
|
||||
_cache.Insert(commonKey, resultList, _expirationTimeout);
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public async Task<List<BaseEvent>> GetLoginEvents(int tenantId, Guid userId)
|
||||
{
|
||||
var date = DateTime.UtcNow.AddYears(-1);
|
||||
var loginInfo = await LoginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && _loginActions.Contains(r.Action) && r.Date >= date && r.Active)
|
||||
.OrderByDescending(r => r.Id)
|
||||
.ToListAsync();
|
||||
|
||||
return _mapper.Map<List<LoginEvent>, List<BaseEvent>>(loginInfo);
|
||||
}
|
||||
|
||||
public async Task LogOutEvent(int loginEventId)
|
||||
{
|
||||
var events = await LoginEventContext.LoginEvents
|
||||
.Where(r => r.Id == loginEventId)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await LoginEventContext.SaveChangesAsync();
|
||||
|
||||
ResetCache();
|
||||
}
|
||||
|
||||
public async Task LogOutAllActiveConnections(int tenantId, Guid userId)
|
||||
{
|
||||
var events = await LoginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && r.Active)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await LoginEventContext.SaveChangesAsync();
|
||||
|
||||
ResetCache(tenantId, userId);
|
||||
}
|
||||
|
||||
public async Task LogOutAllActiveConnectionsForTenant(int tenantId)
|
||||
{
|
||||
var events = await LoginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.Active)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await LoginEventContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task LogOutAllActiveConnectionsExceptThis(int loginEventId, int tenantId, Guid userId)
|
||||
{
|
||||
var events = await LoginEventContext.LoginEvents
|
||||
.Where(r => r.TenantId == tenantId && r.UserId == userId && r.Id != loginEventId && r.Active)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var e in events)
|
||||
{
|
||||
e.Active = false;
|
||||
}
|
||||
|
||||
await LoginEventContext.SaveChangesAsync();
|
||||
|
||||
ResetCache(tenantId, userId);
|
||||
}
|
||||
|
||||
public void ResetCache()
|
||||
{
|
||||
var tenantId = _tenantManager.GetCurrentTenant().Id;
|
||||
var userId = _authContext.CurrentAccount.ID;
|
||||
ResetCache(tenantId, userId);
|
||||
}
|
||||
|
||||
public void ResetCache(int tenantId, Guid userId)
|
||||
{
|
||||
var key = GetCacheKey(tenantId, userId);
|
||||
_cache.Remove(key);
|
||||
}
|
||||
|
||||
private string GetCacheKey(int tenantId, Guid userId)
|
||||
{
|
||||
return string.Join("", GuidLoginEvent, tenantId, userId);
|
||||
}
|
||||
}
|
@ -24,8 +24,6 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using AutoMapper.QueryableExtensions;
|
||||
|
||||
namespace ASC.Core.Data;
|
||||
|
||||
[Scope]
|
||||
|
@ -24,8 +24,6 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using AutoMapper.QueryableExtensions;
|
||||
|
||||
namespace ASC.Core.Data;
|
||||
|
||||
[Scope]
|
||||
@ -147,34 +145,15 @@ public class DbTenantService : ITenantService
|
||||
if (Guid.TryParse(login, out var userId))
|
||||
{
|
||||
var pwdHash = GetPasswordHash(userId, passwordHash);
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
var q = query()
|
||||
.Where(r => r.User.Id == userId)
|
||||
.Where(r => r.UserSecurity.PwdHash == pwdHash || r.UserSecurity.PwdHash == oldHash) //todo: remove old scheme
|
||||
.Where(r => r.UserSecurity.PwdHash == pwdHash)
|
||||
;
|
||||
|
||||
return q.ProjectTo<Tenant>(_mapper.ConfigurationProvider).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
|
||||
var q =
|
||||
query()
|
||||
.Where(r => r.UserSecurity.PwdHash == oldHash);
|
||||
|
||||
if (login.Contains('@'))
|
||||
{
|
||||
q = q.Where(r => r.User.Email == login);
|
||||
}
|
||||
else if (Guid.TryParse(login, out var uId))
|
||||
{
|
||||
q = q.Where(r => r.User.Id == uId);
|
||||
}
|
||||
|
||||
//old password
|
||||
var result = q.ProjectTo<Tenant>(_mapper.ConfigurationProvider).ToList();
|
||||
|
||||
var usersQuery = UserDbContext.Users
|
||||
.Where(r => r.Email == login)
|
||||
.Where(r => r.Status == EmployeeStatus.Active)
|
||||
@ -184,13 +163,10 @@ public class DbTenantService : ITenantService
|
||||
|
||||
var passwordHashs = usersQuery.Select(r => GetPasswordHash(r, passwordHash)).ToList();
|
||||
|
||||
q = query()
|
||||
var q = query()
|
||||
.Where(r => passwordHashs.Any(p => r.UserSecurity.PwdHash == p) && r.DbTenant.Status == TenantStatus.Active);
|
||||
|
||||
//new password
|
||||
result = result.Concat(q.ProjectTo<Tenant>(_mapper.ConfigurationProvider)).ToList();
|
||||
|
||||
return result.Distinct();
|
||||
return q.ProjectTo<Tenant>(_mapper.ConfigurationProvider).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,7 +435,7 @@ public class DbTenantService : ITenantService
|
||||
// cut number suffix
|
||||
while (true)
|
||||
{
|
||||
if (6 < domain.Length && char.IsNumber(domain, domain.Length - 1))
|
||||
if (TenantDomainValidator.MinLength < domain.Length && char.IsNumber(domain, domain.Length - 1))
|
||||
{
|
||||
domain = domain[0..^1];
|
||||
}
|
||||
|
@ -24,8 +24,6 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using AutoMapper.QueryableExtensions;
|
||||
|
||||
namespace ASC.Core.Data;
|
||||
|
||||
[Scope]
|
||||
@ -119,10 +117,7 @@ public class EFUserService : IUserService
|
||||
|
||||
if (Guid.TryParse(login, out var userId))
|
||||
{
|
||||
RegeneratePassword(tenant, userId);
|
||||
|
||||
var pwdHash = GetPasswordHash(userId, passwordHash);
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
|
||||
var q = GetUserQuery(tenant)
|
||||
.Where(r => !r.Removed)
|
||||
@ -132,7 +127,7 @@ public class EFUserService : IUserService
|
||||
User = user,
|
||||
UserSecurity = security
|
||||
})
|
||||
.Where(r => r.UserSecurity.PwdHash == pwdHash || r.UserSecurity.PwdHash == oldHash) //todo: remove old scheme
|
||||
.Where(r => r.UserSecurity.PwdHash == pwdHash)
|
||||
;
|
||||
|
||||
if (tenant != Tenant.DefaultTenant)
|
||||
@ -151,31 +146,20 @@ public class EFUserService : IUserService
|
||||
.Where(r => r.Email == login);
|
||||
|
||||
var users = q.ProjectTo<UserInfo>(_mapper.ConfigurationProvider).ToList();
|
||||
UserInfo result = null;
|
||||
foreach (var user in users)
|
||||
{
|
||||
RegeneratePassword(tenant, user.Id);
|
||||
|
||||
var pwdHash = GetPasswordHash(user.Id, passwordHash);
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
|
||||
var any = UserDbContext.UserSecurity
|
||||
.Any(r => r.UserId == user.Id && (r.PwdHash == pwdHash || r.PwdHash == oldHash));//todo: remove old scheme
|
||||
.Any(r => r.UserId == user.Id && (r.PwdHash == pwdHash));
|
||||
|
||||
if (any)
|
||||
{
|
||||
if (tenant != Tenant.DefaultTenant)
|
||||
{
|
||||
return user;
|
||||
}
|
||||
|
||||
//need for regenerate all passwords only
|
||||
//todo: remove with old scheme
|
||||
result = user;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,31 +172,6 @@ public class EFUserService : IUserService
|
||||
return q.ProjectTo<UserInfo>(_mapper.ConfigurationProvider).ToList();
|
||||
}
|
||||
|
||||
//todo: remove
|
||||
private void RegeneratePassword(int tenant, Guid userId)
|
||||
{
|
||||
var q = UserDbContext.UserSecurity
|
||||
.Where(r => r.UserId == userId);
|
||||
|
||||
if (tenant != Tenant.DefaultTenant)
|
||||
{
|
||||
q = q.Where(r => r.Tenant == tenant);
|
||||
}
|
||||
|
||||
var h2 = q.Select(r => new { r.Tenant, r.PwdHashSha512 })
|
||||
.Take(1)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (h2 == null || string.IsNullOrEmpty(h2.PwdHashSha512))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var password = Crypto.GetV(h2.PwdHashSha512, 1, false);
|
||||
var passwordHash = _passwordHasher.GetClientPassword(password);
|
||||
SetUserPasswordHash(h2.Tenant, userId, passwordHash);
|
||||
}
|
||||
|
||||
public UserGroupRef GetUserGroupRef(int tenant, Guid groupId, UserGroupRefType refType)
|
||||
{
|
||||
IQueryable<UserGroup> q = UserDbContext.UserGroups;
|
||||
@ -550,7 +509,6 @@ public class EFUserService : IUserService
|
||||
Tenant = tenant,
|
||||
UserId = id,
|
||||
PwdHash = h1,
|
||||
PwdHashSha512 = null,//todo: remove
|
||||
LastModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
@ -745,6 +703,16 @@ public class EFUserService : IUserService
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetDavUserEmails(int tenant)
|
||||
{
|
||||
return (from usersDav in UserDbContext.UsersDav
|
||||
join users in UserDbContext.Users on new { tenant = usersDav.TenantId, userId = usersDav.UserId } equals new { tenant = users.Tenant, userId = users.Id }
|
||||
where usersDav.TenantId == tenant
|
||||
select users.Email)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
protected string GetPasswordHash(Guid userId, string password)
|
||||
{
|
||||
return Hasher.Base64Hash(password + userId + Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()), HashAlg.SHA512);
|
||||
|
@ -39,6 +39,7 @@ public class UserDbContext : BaseDbContext
|
||||
public DbSet<UserGroup> UserGroups { get; set; }
|
||||
public DbSet<Subscription> Subscriptions { get; set; }
|
||||
public DbSet<DbSubscriptionMethod> SubscriptionMethods { get; set; }
|
||||
public DbSet<UserDav> UsersDav { get; set; }
|
||||
|
||||
protected override Dictionary<Provider, Func<BaseDbContext>> ProviderContext
|
||||
{
|
||||
@ -63,7 +64,8 @@ public class UserDbContext : BaseDbContext
|
||||
.AddUserPhoto()
|
||||
.AddDbGroup()
|
||||
.AddUserGroup()
|
||||
.AddSubscription();
|
||||
.AddSubscription()
|
||||
.AddUserDav();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ public class MySqlWebstudioDbContext : WebstudioDbContext { }
|
||||
public class PostgreSqlWebstudioDbContext : WebstudioDbContext { }
|
||||
public class WebstudioDbContext : BaseDbContext
|
||||
{
|
||||
public DbSet<DbTenant> Tenants { get; set; }
|
||||
public DbSet<DbWebstudioSettings> WebstudioSettings { get; set; }
|
||||
public DbSet<DbWebstudioUserVisit> WebstudioUserVisit { get; set; }
|
||||
public DbSet<DbWebstudioIndex> WebstudioIndex { get; set; }
|
||||
@ -52,7 +53,9 @@ public class WebstudioDbContext : BaseDbContext
|
||||
.From(modelBuilder, _provider)
|
||||
.AddWebstudioSettings()
|
||||
.AddWebstudioUserVisit()
|
||||
.AddDbWebstudioIndex();
|
||||
.AddDbWebstudioIndex()
|
||||
.AddDbTenant()
|
||||
.AddDbFunction();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,17 +103,18 @@ public static class AclExtension
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|1e04460243b54d7982f3fd6208a11960", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|6743007c6f954d208c88a8601ce5e76d", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|e67be73df9ae4ce18fec1880cb518cb4", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|ea942538e68e49079394035336ee0ba8", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|ea942538e68e49079394035336ee0ba8", AceType = AceType.Deny },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|32d24cb57ece46069c9419216ba42086", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|bf88953e3c434850a3fbb1e43ad53a3e", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|2a9230378b2d487b9a225ac0918acf3f", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|f4d98afdd336433287783c6945c81ea0", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|28b10049dd204f54b986873bc14ccfc7", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|3cfd481b46f24a4ab55cb8c0c9def02c", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|6a598c7491ae437da5f4ad339bd11bb2", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|742cf945cbbc4a5782d61600a12cf8ca", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|853b6eb973ee438d9b098ffeedf36234", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|46cfa73af32046cf8d5bcd82e1d67f26", AceType = 0 }
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|28b10049dd204f54b986873bc14ccfc7", AceType = AceType.Deny },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|3cfd481b46f24a4ab55cb8c0c9def02c", AceType = AceType.Deny },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|6a598c7491ae437da5f4ad339bd11bb2", AceType = AceType.Deny },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|742cf945cbbc4a5782d61600a12cf8ca", AceType = AceType.Deny },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|853b6eb973ee438d9b098ffeedf36234", AceType = AceType.Deny },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|46cfa73af32046cf8d5bcd82e1d67f26", AceType = 0 },
|
||||
new Acl { Tenant = -1, Subject = Guid.Parse("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), Action = Guid.Parse("77777777-32ae-425f-99b5-83176061d1ae"), Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|37620ae5c40b45ce855a39dd7d76a1fa", AceType = 0 }
|
||||
);
|
||||
|
||||
return modelBuilder;
|
||||
|
86
common/ASC.Core.Common/EF/Model/User/UserDav.cs
Normal file
86
common/ASC.Core.Common/EF/Model/User/UserDav.cs
Normal file
@ -0,0 +1,86 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Core.Common.EF;
|
||||
public class UserDav : BaseEntity
|
||||
{
|
||||
public int TenantId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
return new object[] { TenantId, UserId };
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserDavExtension
|
||||
{
|
||||
public static ModelBuilderWrapper AddUserDav(this ModelBuilderWrapper modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.Add(MySqlAddUserDav, Provider.MySql)
|
||||
.Add(PgSqlAddUserDav, Provider.PostgreSql);
|
||||
|
||||
return modelBuilder;
|
||||
}
|
||||
|
||||
public static void MySqlAddUserDav(this ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<UserDav>(entity =>
|
||||
{
|
||||
entity.HasKey(e => new { e.TenantId, e.UserId })
|
||||
.HasName("PRIMARY");
|
||||
|
||||
entity.ToTable("core_userdav");
|
||||
|
||||
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
|
||||
|
||||
entity.Property(e => e.UserId)
|
||||
.HasColumnName("userid")
|
||||
.HasColumnType("varchar(38)")
|
||||
.HasCharSet("utf8")
|
||||
.UseCollation("utf8_general_ci");
|
||||
});
|
||||
}
|
||||
|
||||
public static void PgSqlAddUserDav(this ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<UserDav>(entity =>
|
||||
{
|
||||
entity.HasKey(e => new { e.TenantId, e.UserId })
|
||||
.HasName("core_userdav_pkey");
|
||||
|
||||
entity.ToTable("core_userdav", "onlyoffice");
|
||||
|
||||
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
|
||||
|
||||
entity.Property(e => e.UserId)
|
||||
.HasColumnName("userid")
|
||||
.HasMaxLength(38);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -31,7 +31,6 @@ public class UserSecurity : BaseEntity
|
||||
public int Tenant { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public string PwdHash { get; set; }
|
||||
public string PwdHashSha512 { get; set; }
|
||||
public DateTime? LastModified { get; set; }
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
@ -90,12 +89,6 @@ public static class UserSecurityExtension
|
||||
.HasCharSet("utf8")
|
||||
.UseCollation("utf8_general_ci");
|
||||
|
||||
entity.Property(e => e.PwdHashSha512)
|
||||
.HasColumnName("pwdhashsha512")
|
||||
.HasColumnType("varchar(512)")
|
||||
.HasCharSet("utf8")
|
||||
.UseCollation("utf8_general_ci");
|
||||
|
||||
entity.Property(e => e.Tenant).HasColumnName("tenant");
|
||||
});
|
||||
}
|
||||
@ -125,11 +118,6 @@ public static class UserSecurityExtension
|
||||
.HasMaxLength(512)
|
||||
.HasDefaultValueSql("NULL");
|
||||
|
||||
entity.Property(e => e.PwdHashSha512)
|
||||
.HasColumnName("pwdhashsha512")
|
||||
.HasMaxLength(512)
|
||||
.HasDefaultValueSql("NULL");
|
||||
|
||||
entity.Property(e => e.Tenant).HasColumnName("tenant");
|
||||
});
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ global using System.Globalization;
|
||||
global using System.Linq;
|
||||
global using System.Linq.Expressions;
|
||||
global using System.Net;
|
||||
global using System.Net.Http.Headers;
|
||||
global using System.Reflection;
|
||||
global using System.Resources;
|
||||
global using System.Runtime.Serialization;
|
||||
@ -56,15 +57,19 @@ global using Amazon.Runtime;
|
||||
global using Amazon.SimpleEmail;
|
||||
global using Amazon.SimpleEmail.Model;
|
||||
|
||||
global using ASC.AuditTrail.Models;
|
||||
global using ASC.Collections;
|
||||
global using ASC.Common;
|
||||
global using ASC.Common.Caching;
|
||||
global using ASC.Common.Data;
|
||||
global using ASC.Common.Log;
|
||||
global using ASC.Common.Logging;
|
||||
global using ASC.Common.Mapping;
|
||||
global using ASC.Common.Module;
|
||||
global using ASC.Common.Notify.Engine;
|
||||
global using ASC.Common.Notify.Patterns;
|
||||
global using ASC.Common.Radicale;
|
||||
global using ASC.Common.Radicale.Core;
|
||||
global using ASC.Common.Security;
|
||||
global using ASC.Common.Security.Authentication;
|
||||
global using ASC.Common.Security.Authorizing;
|
||||
@ -74,7 +79,6 @@ global using ASC.Core;
|
||||
global using ASC.Core.Billing;
|
||||
global using ASC.Core.Caching;
|
||||
global using ASC.Core.Common;
|
||||
global using ASC.Core.Common.Billing;
|
||||
global using ASC.Core.Common.Configuration;
|
||||
global using ASC.Core.Common.EF;
|
||||
global using ASC.Core.Common.EF.Context;
|
||||
@ -104,6 +108,10 @@ global using ASC.Core.Users;
|
||||
global using ASC.EventBus.Abstractions;
|
||||
global using ASC.EventBus.Events;
|
||||
global using ASC.Geolocation;
|
||||
global using ASC.MessagingSystem.Core;
|
||||
global using ASC.MessagingSystem.Data;
|
||||
global using ASC.MessagingSystem.Mapping;
|
||||
global using ASC.MessagingSystem.Models;
|
||||
global using ASC.Notify;
|
||||
global using ASC.Notify.Channels;
|
||||
global using ASC.Notify.Cron;
|
||||
@ -119,6 +127,7 @@ global using ASC.Web.Studio.Utility;
|
||||
global using Autofac;
|
||||
|
||||
global using AutoMapper;
|
||||
global using AutoMapper.QueryableExtensions;
|
||||
|
||||
global using MailKit.Security;
|
||||
|
||||
@ -149,4 +158,3 @@ global using ProtoBuf;
|
||||
global using Telegram.Bot;
|
||||
|
||||
global using static ASC.Security.Cryptography.EmailValidationKeyProvider;
|
||||
global using ASC.Common.Data;
|
@ -242,7 +242,7 @@ public class HostedSolution
|
||||
var expires = tenantSettings.IsDefault() ? DateTime.UtcNow.AddYears(1) : DateTime.UtcNow.AddMinutes(tenantSettings.LifeTime);
|
||||
var userSettings = SettingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, user.Id);
|
||||
|
||||
return cookieStorage.EncryptCookie(tenantId, user.Id, tenantSettings.Index, expires, userSettings.Index);
|
||||
return cookieStorage.EncryptCookie(tenantId, user.Id, tenantSettings.Index, expires, userSettings.Index, 0);
|
||||
}
|
||||
|
||||
public Tariff GetTariff(int tenant, bool withRequestToPaymentSystem = true)
|
||||
|
@ -27,6 +27,9 @@
|
||||
namespace ASC.Core.Common.Log;
|
||||
internal static partial class CookieStorageLogger
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "Authenticate error: cookie {cookie}, tenant {tenant}, userid {userid}, indexTenant {indexTenant}, expire {expire}")]
|
||||
public static partial void AuthenticateError(this ILogger<CookieStorage> logger, string cookie, int tenant, Guid userId, int indexTenant, string expire, Exception exception);
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "Authenticate error: cookie {cookie}, tenant {tenant}, userid {userid}, indexTenant {indexTenant}, expire {expire}, loginEvent {loginEvent}")]
|
||||
public static partial void AuthenticateError(this ILogger<CookieStorage> logger, string cookie, int tenant, Guid userId, int indexTenant, string expire, int loginEvent, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to get login event ID from cookie: cookie {cookie}, loginEvent {loginEventId}")]
|
||||
public static partial void ErrorLoginEvent(this ILogger<CookieStorage> logger, string cookie, int loginEventId, Exception exception);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
namespace ASC.AuditTrail.Models;
|
||||
|
||||
public class BaseEvent
|
||||
public class BaseEvent : IMapFrom<LoginEvent>
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int TenantId { get; set; }
|
||||
@ -35,7 +35,7 @@ public class BaseEvent
|
||||
public IList<string> Description { get; set; }
|
||||
|
||||
[Event("IpCol")]
|
||||
public string Ip { get; set; }
|
||||
public string IP { get; set; }
|
||||
|
||||
[Event("BrowserCol")]
|
||||
public string Browser { get; set; }
|
||||
@ -54,22 +54,11 @@ public class BaseEvent
|
||||
|
||||
[Event("ActionCol")]
|
||||
public string ActionText { get; set; }
|
||||
}
|
||||
|
||||
internal class BaseEventMap<T> : ClassMap<T> where T : BaseEvent
|
||||
{
|
||||
public BaseEventMap()
|
||||
public virtual void Mapping(Profile profile)
|
||||
{
|
||||
var eventType = typeof(T);
|
||||
var eventProps = eventType
|
||||
.GetProperties()
|
||||
.Where(r => r.GetCustomAttribute<EventAttribute>() != null)
|
||||
.OrderBy(r => r.GetCustomAttribute<EventAttribute>().Order);
|
||||
|
||||
foreach (var prop in eventProps)
|
||||
{
|
||||
var attr = prop.GetCustomAttribute<EventAttribute>().Resource;
|
||||
Map(eventType, prop).Name(AuditReportResource.ResourceManager.GetString(attr));
|
||||
}
|
||||
profile.CreateMap<LoginEvent, BaseEvent>()
|
||||
.ConvertUsing<BaseEventTypeConverter>();
|
||||
}
|
||||
}
|
||||
|
46
common/ASC.Core.Common/Messaging/BaseEventTypeConverter.cs
Normal file
46
common/ASC.Core.Common/Messaging/BaseEventTypeConverter.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.MessagingSystem.Mapping;
|
||||
|
||||
[Scope]
|
||||
public class BaseEventTypeConverter : ITypeConverter<LoginEvent, BaseEvent>
|
||||
{
|
||||
private readonly TenantUtil _tenantUtil;
|
||||
|
||||
public BaseEventTypeConverter(TenantUtil tenantUtil)
|
||||
{
|
||||
_tenantUtil = tenantUtil;
|
||||
}
|
||||
|
||||
public BaseEvent Convert(LoginEvent source, BaseEvent destination, ResolutionContext context)
|
||||
{
|
||||
var baseEvent = context.Mapper.Map<LoginEvent, BaseEvent>(source);
|
||||
baseEvent.IP = source.Ip.Split(':').Length > 1 ? source.Ip.Split(':')[0] : source.Ip;
|
||||
baseEvent.Date = _tenantUtil.DateTimeFromUtc(source.Date);
|
||||
return baseEvent;
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.AuditTrail.Attributes;
|
||||
namespace ASC.AuditTrail;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class EventAttribute : Attribute
|
@ -24,6 +24,7 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
|
||||
namespace ASC.MessagingSystem.Models;
|
||||
|
||||
public class EventMessage
|
||||
@ -41,4 +42,5 @@ public class EventMessage
|
||||
public IList<string> Description { get; set; }
|
||||
public MessageTarget Target { get; set; }
|
||||
public string UAHeader { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
@ -24,11 +24,14 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
|
||||
|
||||
namespace ASC.MessagingSystem.Models;
|
||||
|
||||
public class LoginEvent : MessageEvent, IMapFrom<EventMessage>
|
||||
{
|
||||
public string Login { get; set; }
|
||||
public bool Active { get; set; }
|
||||
|
||||
public void Mapping(Profile profile)
|
||||
{
|
||||
@ -104,7 +107,11 @@ public static class LoginEventsExtension
|
||||
.HasCharSet("utf8")
|
||||
.UseCollation("utf8_general_ci");
|
||||
|
||||
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
|
||||
entity.Property(e => e.TenantId)
|
||||
.HasColumnName("tenant_id");
|
||||
|
||||
entity.Property(e => e.Active)
|
||||
.HasColumnName("active");
|
||||
|
||||
entity.Property(e => e.UserId)
|
||||
.IsRequired()
|
||||
@ -164,6 +171,8 @@ public static class LoginEventsExtension
|
||||
|
||||
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
|
||||
|
||||
entity.Property(e => e.Active).HasColumnName("active");
|
||||
|
||||
entity.Property(e => e.UserId)
|
||||
.IsRequired()
|
||||
.HasColumnName("user_id")
|
@ -1,4 +1,4 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
@ -24,6 +24,23 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2021
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace ASC.MessagingSystem.Core;
|
||||
|
||||
public enum MessageAction
|
||||
@ -109,6 +126,7 @@ public enum MessageAction
|
||||
SubtaskUpdated = 2035,
|
||||
SubtaskUpdatedStatus = 2036,
|
||||
SubtaskDeleted = 2037,
|
||||
SubtaskMoved = 2058,
|
||||
|
||||
DiscussionCreated = 2038,
|
||||
DiscussionUpdated = 2039,
|
||||
@ -379,6 +397,10 @@ public enum MessageAction
|
||||
UserDataReassigns = 4030,
|
||||
UserDataRemoving = 4031,
|
||||
|
||||
UserLogoutActiveConnections = 4034,
|
||||
UserLogoutActiveConnection = 4035,
|
||||
UserLogoutActiveConnectionsForUser = 4036,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Documents
|
||||
@ -394,10 +416,15 @@ public enum MessageAction
|
||||
FileLocked = 5006,
|
||||
FileUnlocked = 5007,
|
||||
FileUpdatedAccess = 5008,
|
||||
FileUpdatedAccessFor = 5068,
|
||||
FileSendAccessLink = 5036, // not used
|
||||
FileOpenedForChange = 5054,
|
||||
FileRemovedFromList = 5058,
|
||||
FileExternalLinkAccessUpdated = 5060,
|
||||
|
||||
FileDownloaded = 5009,
|
||||
FileDownloadedAs = 5010,
|
||||
FileRevisionDownloaded = 5062,
|
||||
|
||||
FileUploaded = 5011,
|
||||
FileImported = 5012,
|
||||
@ -407,18 +434,23 @@ public enum MessageAction
|
||||
FileMoved = 5015,
|
||||
FileMovedWithOverwriting = 5016,
|
||||
FileMovedToTrash = 5017,
|
||||
FileDeleted = 5018, // not used
|
||||
FileDeleted = 5018,
|
||||
|
||||
FolderCreated = 5019,
|
||||
FolderRenamed = 5020,
|
||||
FolderUpdatedAccess = 5021,
|
||||
FolderUpdatedAccessFor = 5066,
|
||||
|
||||
FolderCopied = 5022,
|
||||
FolderCopiedWithOverwriting = 5023,
|
||||
FolderMoved = 5024,
|
||||
FolderMovedFrom = 5067,
|
||||
FolderMovedWithOverwriting = 5025,
|
||||
FolderMovedToTrash = 5026,
|
||||
FolderDeleted = 5027, // not used
|
||||
FolderDeleted = 5027,
|
||||
FolderRemovedFromList = 5059,
|
||||
|
||||
FolderDownloaded = 5057,
|
||||
|
||||
ThirdPartyCreated = 5028,
|
||||
ThirdPartyUpdated = 5029,
|
||||
@ -426,9 +458,10 @@ public enum MessageAction
|
||||
|
||||
DocumentsThirdPartySettingsUpdated = 5031,
|
||||
DocumentsOverwritingSettingsUpdated = 5032,
|
||||
DocumentsForcesave = 5049, // last
|
||||
DocumentsForcesave = 5049,
|
||||
DocumentsStoreForcesave = 5048,
|
||||
DocumentsUploadingFormatsSettingsUpdated = 5033,
|
||||
DocumentsExternalShareSettingsUpdated = 5069, // last
|
||||
|
||||
FileConverted = 5035,
|
||||
|
||||
@ -437,6 +470,15 @@ public enum MessageAction
|
||||
DocumentSignComplete = 5046,
|
||||
DocumentSendToSign = 5045,
|
||||
|
||||
FileMarkedAsFavorite = 5055,
|
||||
FileRemovedFromFavorite = 5056,
|
||||
FileMarkedAsRead = 5063,
|
||||
FileReaded = 5064,
|
||||
|
||||
TrashEmptied = 5061,
|
||||
|
||||
FolderMarkedAsRead = 5065,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Settings
|
@ -41,48 +41,31 @@ public class MessageTarget
|
||||
|
||||
public MessageTarget Create<T>(T value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = new List<string>();
|
||||
|
||||
if (value is System.Collections.IEnumerable ids)
|
||||
{
|
||||
res.AddRange(from object id in ids select id.ToString());
|
||||
}
|
||||
else
|
||||
var res = new List<string>(1);
|
||||
if (value != null)
|
||||
{
|
||||
res.Add(value.ToString());
|
||||
}
|
||||
|
||||
return new MessageTarget(_option)
|
||||
{
|
||||
_items = res.Distinct()
|
||||
_items = res
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorEventMessageTarget(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MessageTarget Create(IEnumerable<string> value)
|
||||
{
|
||||
try
|
||||
var res = new MessageTarget(_option)
|
||||
{
|
||||
return new MessageTarget(_option)
|
||||
{
|
||||
_items = value.Distinct()
|
||||
_items = new List<string>()
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorEventMessageTarget(e);
|
||||
|
||||
return null;
|
||||
if (value != null)
|
||||
{
|
||||
res._items = value.Select(r => r.ToString()).ToList();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public MessageTarget Parse(string value)
|
||||
@ -104,7 +87,7 @@ public class MessageTarget
|
||||
_items = items
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetItems() { return _items.ToList(); }
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(",", _items);
|
@ -100,7 +100,7 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
Tenant = -1,
|
||||
ActiveUsers = 10000,
|
||||
AvangateId = "0",
|
||||
Features = "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore",
|
||||
Features = "update",
|
||||
MaxFileSize = 102400L,
|
||||
MaxTotalSize = 10995116277760L,
|
||||
Name = "default",
|
||||
|
@ -116,7 +116,7 @@ public partial class CoreDbContextMySql : Migration
|
||||
migrationBuilder.InsertData(
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "active_users", "avangate_id", "description", "features", "max_file_size", "max_total_size", "name", "price", "visible" },
|
||||
values: new object[] { -1, 10000, "0", null, "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore", 102400L, 10995116277760L, "default", 0.00m, false });
|
||||
values: new object[] { -1, 10000, "0", null, "update", 102400L, 10995116277760L, "default", 0.00m, false });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "last_modified",
|
||||
|
@ -99,7 +99,7 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
Tenant = -1,
|
||||
ActiveUsers = 10000,
|
||||
AvangateId = "0",
|
||||
Features = "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore",
|
||||
Features = "update",
|
||||
MaxFileSize = 102400L,
|
||||
MaxTotalSize = 10995116277760L,
|
||||
Name = "default",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -53,166 +53,354 @@ public partial class FilesDbContextMySql : Migration
|
||||
columns: new[] { "input", "output" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ ".csv", ".ods" },
|
||||
{ ".pps", ".odp" },
|
||||
{ ".pps", ".pdf" },
|
||||
{ ".pps", ".pptx" },
|
||||
{ ".ppsm", ".odp" },
|
||||
{ ".ppsm", ".pdf" },
|
||||
{ ".ppsm", ".pptx" },
|
||||
{ ".potx", ".pptx" },
|
||||
{ ".ppsx", ".odp" },
|
||||
{ ".ppsx", ".pptx" },
|
||||
{ ".ppt", ".odp" },
|
||||
{ ".ppt", ".pdf" },
|
||||
{ ".ppt", ".pptx" },
|
||||
{ ".pptm", ".odp" },
|
||||
{ ".pptm", ".pdf" },
|
||||
{ ".ppsx", ".pdf" },
|
||||
{ ".potx", ".pdf" },
|
||||
{ ".potx", ".odp" },
|
||||
{ ".potm", ".pptx" },
|
||||
{ ".ots", ".xlsx" },
|
||||
{ ".odt", ".docx" },
|
||||
{ ".odt", ".pdf" },
|
||||
{ ".odt", ".rtf" },
|
||||
{ ".odt", ".txt" },
|
||||
{ ".ott", ".docx" },
|
||||
{ ".ott", ".odt" },
|
||||
{ ".ott", ".pdf" },
|
||||
{ ".ott", ".rtf" },
|
||||
{ ".ott", ".txt" },
|
||||
{ ".pot", ".odp" },
|
||||
{ ".pot", ".pdf" },
|
||||
{ ".pot", ".pptx" },
|
||||
{ ".potm", ".odp" },
|
||||
{ ".potm", ".pdf" },
|
||||
{ ".pptm", ".pptx" },
|
||||
{ ".ots", ".pdf" },
|
||||
{ ".pptt", ".odp" },
|
||||
{ ".pptt", ".pptx" },
|
||||
{ ".xlst", ".xlsx" },
|
||||
{ ".xlst", ".csv" },
|
||||
{ ".xlst", ".ods" },
|
||||
{ ".xlt", ".csv" },
|
||||
{ ".xlt", ".ods" },
|
||||
{ ".xlt", ".pdf" },
|
||||
{ ".xlst", ".pdf" },
|
||||
{ ".xlt", ".xlsx" },
|
||||
{ ".xltm", ".ods" },
|
||||
{ ".xltm", ".pdf" },
|
||||
{ ".xltm", ".xlsx" },
|
||||
{ ".xltx", ".pdf" },
|
||||
{ ".xltx", ".csv" },
|
||||
{ ".xltx", ".ods" },
|
||||
{ ".xltm", ".csv" },
|
||||
{ ".xlsm", ".xlsx" },
|
||||
{ ".xlsm", ".ods" },
|
||||
{ ".xlsm", ".pdf" },
|
||||
{ ".pptx", ".odp" },
|
||||
{ ".pptx", ".pdf" },
|
||||
{ ".rtf", ".odp" },
|
||||
{ ".rtf", ".pdf" },
|
||||
{ ".rtf", ".docx" },
|
||||
{ ".rtf", ".txt" },
|
||||
{ ".txt", ".pdf" },
|
||||
{ ".txt", ".docx" },
|
||||
{ ".txt", ".odp" },
|
||||
{ ".txt", ".rtx" },
|
||||
{ ".xls", ".csv" },
|
||||
{ ".xls", ".ods" },
|
||||
{ ".xls", ".pdf" },
|
||||
{ ".xls", ".xlsx" },
|
||||
{ ".xlsm", ".csv" },
|
||||
{ ".pptt", ".pdf" },
|
||||
{ ".ots", ".ods" },
|
||||
{ ".ots", ".csv" },
|
||||
{ ".ods", ".xlsx" },
|
||||
{ ".dot", ".pdf" },
|
||||
{ ".dot", ".rtf" },
|
||||
{ ".dot", ".txt" },
|
||||
{ ".dotm", ".docx" },
|
||||
{ ".dotm", ".odt" },
|
||||
{ ".dotm", ".pdf" },
|
||||
{ ".dot", ".odt" },
|
||||
{ ".dotm", ".rtf" },
|
||||
{ ".dotx", ".docx" },
|
||||
{ ".dotx", ".odt" },
|
||||
{ ".dotx", ".pdf" },
|
||||
{ ".dotx", ".rtf" },
|
||||
{ ".dotx", ".txt" },
|
||||
{ ".epub", ".docx" },
|
||||
{ ".dotm", ".txt" },
|
||||
{ ".dot", ".docx" },
|
||||
{ ".docx", ".txt" },
|
||||
{ ".docx", ".rtf" },
|
||||
{ ".docx", ".docxf" },
|
||||
{ ".docxf",".docx" },
|
||||
{ ".docxf",".dotx" },
|
||||
{ ".docxf",".epub" },
|
||||
{ ".docxf",".fb2" },
|
||||
{ ".docxf",".html" },
|
||||
{ ".docxf",".odt" },
|
||||
{ ".docxf",".oform" },
|
||||
{ ".docxf",".ott" },
|
||||
{ ".docxf",".pdf" },
|
||||
{ ".docxf",".rtf" },
|
||||
{ ".docxf",".txt" },
|
||||
{ ".csv", ".pdf" },
|
||||
{ ".csv", ".xlsx" },
|
||||
{ ".doc", ".docx" },
|
||||
{ ".doc", ".odt" },
|
||||
{ ".doc", ".pdf" },
|
||||
{ ".doc", ".rtf" },
|
||||
{ ".doc", ".txt" },
|
||||
{ ".docm", ".docx" },
|
||||
{ ".docm", ".odt" },
|
||||
{ ".docm", ".pdf" },
|
||||
{ ".docm", ".rtf" },
|
||||
{ ".docm", ".txt" },
|
||||
{ ".doct", ".docx" },
|
||||
{ ".docx", ".odt" },
|
||||
{ ".docx", ".pdf" },
|
||||
{ ".epub", ".odt" },
|
||||
{ ".epub", ".pdf" },
|
||||
{ ".epub", ".rtf" },
|
||||
{ ".epub", ".txt" },
|
||||
{ ".html", ".pdf" },
|
||||
{ ".html", ".rtf" },
|
||||
{ ".html", ".txt" },
|
||||
{ ".mht", ".docx" },
|
||||
{ ".mht", ".odt" },
|
||||
{ ".mht", ".pdf" },
|
||||
{ ".mht", ".rtf" },
|
||||
{ ".mht", ".txt" },
|
||||
{ ".odp", ".pdf" },
|
||||
{ ".odp", ".pptx" },
|
||||
{ ".otp", ".odp" },
|
||||
{ ".otp", ".pdf" },
|
||||
{ ".otp", ".pptx" },
|
||||
{ ".ods", ".csv" },
|
||||
{ ".ods", ".pdf" },
|
||||
{ ".html", ".odt" },
|
||||
{ ".xltx", ".xlsx" },
|
||||
{ ".html", ".docx" },
|
||||
{ ".fodt", ".rtf" },
|
||||
{ ".fb2", ".docx" },
|
||||
{ ".fb2", ".odt" },
|
||||
{ ".fb2", ".pdf" },
|
||||
{ ".fb2", ".rtf" },
|
||||
{ ".fb2", ".txt" },
|
||||
{ ".fodp", ".odp" },
|
||||
{ ".fodp", ".pdf" },
|
||||
{ ".fodp", ".pptx" },
|
||||
{ ".fods", ".csv" },
|
||||
{ ".fods", ".ods" },
|
||||
{ ".fods", ".pdf" },
|
||||
{ ".fods", ".xlsx" },
|
||||
{ ".fodt", ".docx" },
|
||||
{ ".fodt", ".odt" },
|
||||
{ ".fodt", ".pdf" },
|
||||
{ ".fodt", ".txt" },
|
||||
{ ".xps", ".pdf" }
|
||||
{".csv", ".ods"},
|
||||
{".csv", ".ots"},
|
||||
{".csv", ".pdf"},
|
||||
{".csv", ".xlsm"},
|
||||
{".csv", ".xlsx"},
|
||||
{".csv", ".xltm"},
|
||||
{".csv", ".xltx"},
|
||||
{".doc", ".docm"},
|
||||
{".doc", ".docx"},
|
||||
{".doc", ".dotm"},
|
||||
{".doc", ".dotx"},
|
||||
{".doc", ".epub"},
|
||||
{".doc", ".fb2"},
|
||||
{".doc", ".html"},
|
||||
{".doc", ".odt"},
|
||||
{".doc", ".ott"},
|
||||
{".doc", ".pdf"},
|
||||
{".doc", ".rtf"},
|
||||
{".doc", ".txt"},
|
||||
{".docm", ".docx"},
|
||||
{".docm", ".dotm"},
|
||||
{".docm", ".dotx"},
|
||||
{".docm", ".epub"},
|
||||
{".docm", ".fb2"},
|
||||
{".docm", ".html"},
|
||||
{".docm", ".odt"},
|
||||
{".docm", ".ott"},
|
||||
{".docm", ".pdf"},
|
||||
{".docm", ".rtf"},
|
||||
{".docm", ".txt"},
|
||||
{".doct", ".docx"},
|
||||
{".docx", ".docm"},
|
||||
{".docx", ".docxf"},
|
||||
{".docx", ".dotm"},
|
||||
{".docx", ".dotx"},
|
||||
{".docx", ".epub"},
|
||||
{".docx", ".fb2"},
|
||||
{".docx", ".html"},
|
||||
{".docx", ".odt"},
|
||||
{".docx", ".ott"},
|
||||
{".docx", ".pdf"},
|
||||
{".docx", ".rtf"},
|
||||
{".docx", ".txt"},
|
||||
{".docxf", ".docx"},
|
||||
{".docxf", ".dotx"},
|
||||
{".docxf", ".epub"},
|
||||
{".docxf", ".fb2"},
|
||||
{".docxf", ".html"},
|
||||
{".docxf", ".odt"},
|
||||
{".docxf", ".oform"},
|
||||
{".docxf", ".ott"},
|
||||
{".docxf", ".pdf"},
|
||||
{".docxf", ".rtf"},
|
||||
{".docxf", ".txt"},
|
||||
{".dot", ".docm"},
|
||||
{".dot", ".docx"},
|
||||
{".dot", ".dotm"},
|
||||
{".dot", ".dotx"},
|
||||
{".dot", ".epub"},
|
||||
{".dot", ".fb2"},
|
||||
{".dot", ".html"},
|
||||
{".dot", ".odt"},
|
||||
{".dot", ".ott"},
|
||||
{".dot", ".pdf"},
|
||||
{".dot", ".rtf"},
|
||||
{".dot", ".txt"},
|
||||
{".dotm", ".docm"},
|
||||
{".dotm", ".docx"},
|
||||
{".dotm", ".dotx"},
|
||||
{".dotm", ".epub"},
|
||||
{".dotm", ".fb2"},
|
||||
{".dotm", ".html"},
|
||||
{".dotm", ".odt"},
|
||||
{".dotm", ".ott"},
|
||||
{".dotm", ".pdf"},
|
||||
{".dotm", ".rtf"},
|
||||
{".dotm", ".txt"},
|
||||
{".dotx", ".docm"},
|
||||
{".dotx", ".docx"},
|
||||
{".dotx", ".dotm"},
|
||||
{".dotx", ".epub"},
|
||||
{".dotx", ".fb2"},
|
||||
{".dotx", ".html"},
|
||||
{".dotx", ".odt"},
|
||||
{".dotx", ".ott"},
|
||||
{".dotx", ".pdf"},
|
||||
{".dotx", ".rtf"},
|
||||
{".dotx", ".txt"},
|
||||
{".epub", ".docm"},
|
||||
{".epub", ".docx"},
|
||||
{".epub", ".dotm"},
|
||||
{".epub", ".dotx"},
|
||||
{".epub", ".fb2"},
|
||||
{".epub", ".html"},
|
||||
{".epub", ".odt"},
|
||||
{".epub", ".ott"},
|
||||
{".epub", ".pdf"},
|
||||
{".epub", ".rtf"},
|
||||
{".epub", ".txt"},
|
||||
{".fb2", ".docm"},
|
||||
{".fb2", ".docx"},
|
||||
{".fb2", ".dotm"},
|
||||
{".fb2", ".dotx"},
|
||||
{".fb2", ".epub"},
|
||||
{".fb2", ".html"},
|
||||
{".fb2", ".odt"},
|
||||
{".fb2", ".ott"},
|
||||
{".fb2", ".pdf"},
|
||||
{".fb2", ".rtf"},
|
||||
{".fb2", ".txt"},
|
||||
{".fodp", ".odp"},
|
||||
{".fodp", ".otp"},
|
||||
{".fodp", ".pdf"},
|
||||
{".fodp", ".potm"},
|
||||
{".fodp", ".potx"},
|
||||
{".fodp", ".pptm"},
|
||||
{".fodp", ".pptx"},
|
||||
{".fods", ".csv"},
|
||||
{".fods", ".ods"},
|
||||
{".fods", ".ots"},
|
||||
{".fods", ".pdf"},
|
||||
{".fods", ".xlsm"},
|
||||
{".fods", ".xlsx"},
|
||||
{".fods", ".xltm"},
|
||||
{".fods", ".xltx"},
|
||||
{".fodt", ".docm"},
|
||||
{".fodt", ".docx"},
|
||||
{".fodt", ".dotm"},
|
||||
{".fodt", ".dotx"},
|
||||
{".fodt", ".epub"},
|
||||
{".fodt", ".fb2"},
|
||||
{".fodt", ".html"},
|
||||
{".fodt", ".odt"},
|
||||
{".fodt", ".ott"},
|
||||
{".fodt", ".pdf"},
|
||||
{".fodt", ".rtf"},
|
||||
{".fodt", ".txt"},
|
||||
{".html", ".docm"},
|
||||
{".html", ".docx"},
|
||||
{".html", ".dotm"},
|
||||
{".html", ".dotx"},
|
||||
{".html", ".epub"},
|
||||
{".html", ".fb2"},
|
||||
{".html", ".odt"},
|
||||
{".html", ".ott"},
|
||||
{".html", ".pdf"},
|
||||
{".html", ".rtf"},
|
||||
{".html", ".txt"},
|
||||
{".mht", ".docm"},
|
||||
{".mht", ".docx"},
|
||||
{".mht", ".dotm"},
|
||||
{".mht", ".dotx"},
|
||||
{".mht", ".epub"},
|
||||
{".mht", ".fb2"},
|
||||
{".mht", ".odt"},
|
||||
{".mht", ".ott"},
|
||||
{".mht", ".pdf"},
|
||||
{".mht", ".rtf"},
|
||||
{".mht", ".txt"},
|
||||
{".odp", ".otp"},
|
||||
{".odp", ".pdf"},
|
||||
{".odp", ".potm"},
|
||||
{".odp", ".potx"},
|
||||
{".odp", ".pptm"},
|
||||
{".odp", ".pptx"},
|
||||
{".otp", ".odp"},
|
||||
{".otp", ".pdf"},
|
||||
{".otp", ".potm"},
|
||||
{".otp", ".potx"},
|
||||
{".otp", ".pptm"},
|
||||
{".otp", ".pptx"},
|
||||
{".ods", ".csv"},
|
||||
{".ods", ".ots"},
|
||||
{".ods", ".pdf"},
|
||||
{".ods", ".xlsm"},
|
||||
{".ods", ".xlsx"},
|
||||
{".ods", ".xltm"},
|
||||
{".ods", ".xltx"},
|
||||
{".ots", ".csv"},
|
||||
{".ots", ".ods"},
|
||||
{".ots", ".pdf"},
|
||||
{".ots", ".xlsm"},
|
||||
{".ots", ".xlsx"},
|
||||
{".ots", ".xltm"},
|
||||
{".ots", ".xltx"},
|
||||
{".odt", ".docm"},
|
||||
{".odt", ".docx"},
|
||||
{".odt", ".dotm"},
|
||||
{".odt", ".dotx"},
|
||||
{".odt", ".epub"},
|
||||
{".odt", ".fb2"},
|
||||
{".odt", ".html"},
|
||||
{".odt", ".ott"},
|
||||
{".odt", ".pdf"},
|
||||
{".odt", ".rtf"},
|
||||
{".odt", ".txt"},
|
||||
{".ott", ".docm"},
|
||||
{".ott", ".docx"},
|
||||
{".ott", ".dotm"},
|
||||
{".ott", ".dotx"},
|
||||
{".ott", ".epub"},
|
||||
{".ott", ".fb2"},
|
||||
{".ott", ".html"},
|
||||
{".ott", ".odt"},
|
||||
{".ott", ".pdf"},
|
||||
{".ott", ".rtf"},
|
||||
{".ott", ".txt"},
|
||||
{".oxps", ".pdf"},
|
||||
{".pot", ".odp"},
|
||||
{".pot", ".otp"},
|
||||
{".pot", ".pdf"},
|
||||
{".pot", ".pptm"},
|
||||
{".pot", ".pptx"},
|
||||
{".pot", ".potm"},
|
||||
{".pot", ".potx"},
|
||||
{".potm", ".odp"},
|
||||
{".potm", ".otp"},
|
||||
{".potm", ".pdf"},
|
||||
{".potm", ".potx"},
|
||||
{".potm", ".pptm"},
|
||||
{".potm", ".pptx"},
|
||||
{".potx", ".odp"},
|
||||
{".potx", ".otp"},
|
||||
{".potx", ".pdf"},
|
||||
{".potx", ".potm"},
|
||||
{".potx", ".pptm"},
|
||||
{".potx", ".pptx"},
|
||||
{".pps", ".odp"},
|
||||
{".pps", ".otp"},
|
||||
{".pps", ".pdf"},
|
||||
{".pps", ".potm"},
|
||||
{".pps", ".potx"},
|
||||
{".pps", ".pptm"},
|
||||
{".pps", ".pptx"},
|
||||
{".ppsm", ".odp"},
|
||||
{".ppsm", ".otp"},
|
||||
{".ppsm", ".pdf"},
|
||||
{".ppsm", ".potm"},
|
||||
{".ppsm", ".potx"},
|
||||
{".ppsm", ".pptm"},
|
||||
{".ppsm", ".pptx"},
|
||||
{".ppsx", ".odp"},
|
||||
{".ppsx", ".otp"},
|
||||
{".ppsx", ".pdf"},
|
||||
{".ppsx", ".potm"},
|
||||
{".ppsx", ".potx"},
|
||||
{".ppsx", ".pptm"},
|
||||
{".ppsx", ".pptx"},
|
||||
{".ppt", ".odp"},
|
||||
{".ppt", ".otp"},
|
||||
{".ppt", ".pdf"},
|
||||
{".ppt", ".potm"},
|
||||
{".ppt", ".potx"},
|
||||
{".ppt", ".pptm"},
|
||||
{".ppt", ".pptx"},
|
||||
{".pptm", ".odp"},
|
||||
{".pptm", ".otp"},
|
||||
{".pptm", ".pdf"},
|
||||
{".pptm", ".potm"},
|
||||
{".pptm", ".potx"},
|
||||
{".pptm", ".pptx"},
|
||||
{".pptt", ".pptx"},
|
||||
{".pptx", ".odp"},
|
||||
{".pptx", ".otp"},
|
||||
{".pptx", ".pdf"},
|
||||
{".pptx", ".potm"},
|
||||
{".pptx", ".potx"},
|
||||
{".pptx", ".pptm"},
|
||||
{".rtf", ".docm"},
|
||||
{".rtf", ".docx"},
|
||||
{".rtf", ".dotm"},
|
||||
{".rtf", ".dotx"},
|
||||
{".rtf", ".epub"},
|
||||
{".rtf", ".fb2"},
|
||||
{".rtf", ".html"},
|
||||
{".rtf", ".odt"},
|
||||
{".rtf", ".ott"},
|
||||
{".rtf", ".pdf"},
|
||||
{".rtf", ".txt"},
|
||||
{".txt", ".docm"},
|
||||
{".txt", ".docx"},
|
||||
{".txt", ".dotm"},
|
||||
{".txt", ".dotx"},
|
||||
{".txt", ".epub"},
|
||||
{".txt", ".fb2"},
|
||||
{".txt", ".html"},
|
||||
{".txt", ".odt"},
|
||||
{".txt", ".ott"},
|
||||
{".txt", ".pdf"},
|
||||
{".txt", ".rtf"},
|
||||
{".xls", ".csv"},
|
||||
{".xls", ".ods"},
|
||||
{".xls", ".ots"},
|
||||
{".xls", ".pdf"},
|
||||
{".xls", ".xlsm"},
|
||||
{".xls", ".xlsx"},
|
||||
{".xls", ".xltm"},
|
||||
{".xls", ".xltx"},
|
||||
{".xlsm", ".csv"},
|
||||
{".xlsm", ".ods"},
|
||||
{".xlsm", ".ots"},
|
||||
{".xlsm", ".pdf"},
|
||||
{".xlsm", ".xlsx"},
|
||||
{".xlsm", ".xltm"},
|
||||
{".xlsm", ".xltx"},
|
||||
{".xlst", ".xlsx"},
|
||||
{".xlsx", ".csv"},
|
||||
{".xlsx", ".ods"},
|
||||
{".xlsx", ".ots"},
|
||||
{".xlsx", ".pdf"},
|
||||
{".xlsx", ".xlsm"},
|
||||
{".xlsx", ".xltm"},
|
||||
{".xlsx", ".xltx"},
|
||||
{".xlt", ".csv"},
|
||||
{".xlt", ".ods"},
|
||||
{".xlt", ".ots"},
|
||||
{".xlt", ".pdf"},
|
||||
{".xlt", ".xlsm"},
|
||||
{".xlt", ".xlsx"},
|
||||
{".xlt", ".xltm"},
|
||||
{".xlt", ".xltx"},
|
||||
{".xltm", ".csv"},
|
||||
{".xltm", ".ods"},
|
||||
{".xltm", ".ots"},
|
||||
{".xltm", ".pdf"},
|
||||
{".xltm", ".xlsm"},
|
||||
{".xltm", ".xlsx"},
|
||||
{".xltm", ".xltx"},
|
||||
{".xltx", ".csv"},
|
||||
{".xltx", ".ods"},
|
||||
{".xltx", ".ots"},
|
||||
{".xltx", ".pdf"},
|
||||
{".xltx", ".xlsm"},
|
||||
{".xltx", ".xlsx"},
|
||||
{".xltx", ".xltm"},
|
||||
{".xml", ".docm"},
|
||||
{".xml", ".docx"},
|
||||
{".xml", ".dotm"},
|
||||
{".xml", ".dotx"},
|
||||
{".xml", ".epub"},
|
||||
{".xml", ".fb2"},
|
||||
{".xml", ".html"},
|
||||
{".xml", ".odt"},
|
||||
{".xml", ".ott"},
|
||||
{".xml", ".pdf"},
|
||||
{".xml", ".rtf"},
|
||||
{".xml", ".txt"},
|
||||
{".xps", ".pdf"}
|
||||
});
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -327,6 +327,10 @@ namespace ASC.MessagingSystem.Migrations.MySql.MessagesContextMySql
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("tenant_id");
|
||||
|
||||
b.Property<int>("Active")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("active");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("char(38)")
|
@ -81,6 +81,7 @@ public partial class MessagesContextMySql : Migration
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
date = table.Column<DateTime>(type: "datetime", nullable: false),
|
||||
tenant_id = table.Column<int>(type: "int", nullable: false),
|
||||
active = table.Column<int>(type: "int", nullable: false),
|
||||
user_id = table.Column<string>(type: "char(38)", nullable: false, collation: "utf8_general_ci")
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
page = table.Column<string>(type: "varchar(300)", nullable: true, collation: "utf8_general_ci")
|
@ -67,6 +67,10 @@ namespace ASC.MessagingSystem.Migrations.MySql.MessagesContextMySql
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("tenant_id");
|
||||
|
||||
b.Property<int>("Active")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("active");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("char(38)")
|
@ -495,7 +495,7 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|ea942538e68e49079394035336ee0ba8",
|
||||
AceType = 0
|
||||
AceType = AceType.Deny
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -535,7 +535,7 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|28b10049dd204f54b986873bc14ccfc7",
|
||||
AceType = 0
|
||||
AceType = AceType.Deny
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -543,7 +543,7 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|3cfd481b46f24a4ab55cb8c0c9def02c",
|
||||
AceType = 0
|
||||
AceType = AceType.Deny
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -551,7 +551,7 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|6a598c7491ae437da5f4ad339bd11bb2",
|
||||
AceType = 0
|
||||
AceType = AceType.Deny
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -559,7 +559,7 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|742cf945cbbc4a5782d61600a12cf8ca",
|
||||
AceType = 0
|
||||
AceType = AceType.Deny
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -567,7 +567,7 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|853b6eb973ee438d9b098ffeedf36234",
|
||||
AceType = 0
|
||||
AceType = AceType.Deny
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -576,6 +576,14 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|46cfa73af32046cf8d5bcd82e1d67f26",
|
||||
AceType = 0
|
||||
},
|
||||
new
|
||||
{
|
||||
Tenant = -1,
|
||||
Subject = "c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e",
|
||||
Action = "77777777-32ae-425f-99b5-83176061d1ae",
|
||||
Object = "ASC.Web.Core.WebItemSecurity+WebItemSecurityObject|37620ae5c40b45ce855a39dd7d76a1fa",
|
||||
AceType = 0
|
||||
});
|
||||
});
|
||||
|
||||
@ -1425,12 +1433,6 @@ namespace ASC.Core.Common.Migrations.MySql.UserDbContextMySql
|
||||
.UseCollation("utf8_general_ci")
|
||||
.HasAnnotation("MySql:CharSet", "utf8");
|
||||
|
||||
b.Property<string>("PwdHashSha512")
|
||||
.HasColumnType("varchar(512)")
|
||||
.HasColumnName("pwdhashsha512")
|
||||
.UseCollation("utf8_general_ci")
|
||||
.HasAnnotation("MySql:CharSet", "utf8");
|
||||
|
||||
b.Property<int>("Tenant")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("tenant");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user