Merge branch 'develop' into bugfix/storybook-fixes

This commit is contained in:
Alexey Safronov 2023-04-20 13:23:32 +04:00
commit 0f23ead295
1552 changed files with 41797 additions and 23926 deletions

40
.github/workflows/build-ffvideo.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: ffvideo build
on:
push:
branches:
- release/v1.0.0
paths:
- 'build/install/docker/**.ffvideo'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [linux/amd64]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./build/install/docker/Dockerfile.ffvideo
push: true
tags: onlyoffice/ffvideo:6.0

1
.gitignore vendored
View File

@ -50,3 +50,4 @@ TestsResults/
**/.yarn/cache
**/.yarn/install-state.gz
licenses.csv

File diff suppressed because one or more lines are too long

View File

@ -7,5 +7,7 @@ plugins:
spec: "@yarnpkg/plugin-interactive-tools"
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"
- path: .yarn/plugins/@yarnpkg/plugin-licenses-audit.cjs
spec: "https://raw.githubusercontent.com/tophat/yarn-plugin-licenses/master/bundles/@yarnpkg/plugin-licenses-audit.js"
yarnPath: .yarn/releases/yarn-3.2.4.cjs

View File

@ -41,26 +41,6 @@ elif [ "$UPDATE" = "true" ] && [ "$DOCUMENT_SERVER_INSTALLED" = "true" ]; then
apt-get install -y --only-upgrade ${package_sysname}-documentserver
fi
NGINX_ROOT_DIR="/etc/nginx"
NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-$(grep processor /proc/cpuinfo | wc -l)};
NGINX_WORKER_CONNECTIONS=${NGINX_WORKER_CONNECTIONS:-$(ulimit -n)};
sed 's/^worker_processes.*/'"worker_processes ${NGINX_WORKER_PROCESSES};"'/' -i ${NGINX_ROOT_DIR}/nginx.conf
sed 's/worker_connections.*/'"worker_connections ${NGINX_WORKER_CONNECTIONS};"'/' -i ${NGINX_ROOT_DIR}/nginx.conf
if ! id "nginx" &>/dev/null; then
systemctl stop nginx
rm -dfr /var/log/nginx/*
rm -dfr /var/cache/nginx/*
useradd -s /bin/false nginx
systemctl start nginx
else
systemctl reload nginx
fi
if [ "$PRODUCT_INSTALLED" = "false" ]; then
echo ${product} ${product}/db-pwd select $MYSQL_SERVER_PASS | sudo debconf-set-selections
echo ${product} ${product}/db-user select $MYSQL_SERVER_USER | sudo debconf-set-selections

View File

@ -118,14 +118,8 @@ apt-get install -o DPkg::options::="--force-confnew" -yq \
postgresql \
redis-server \
rabbitmq-server \
nginx-extras
if [ -e /etc/redis/redis.conf ]; then
sed -i "s/bind .*/bind 127.0.0.1/g" /etc/redis/redis.conf
sed -r "/^save\s[0-9]+/d" -i /etc/redis/redis.conf
service redis-server restart
fi
nginx-extras \
ffmpeg
if [ ! -e /usr/bin/json ]; then
npm i json -g >/dev/null 2>&1

View File

@ -10,13 +10,6 @@ cat<<EOF
EOF
if [ -e /etc/redis.conf ]; then
sed -i "s/bind .*/bind 127.0.0.1/g" /etc/redis.conf
sed -r "/^save\s[0-9]+/d" -i /etc/redis.conf
systemctl restart redis
fi
sed "/host\s*all\s*all\s*127\.0\.0\.1\/32\s*ident$/s|ident$|trust|" -i /var/lib/pgsql/data/pg_hba.conf
sed "/host\s*all\s*all\s*::1\/128\s*ident$/s|ident$|trust|" -i /var/lib/pgsql/data/pg_hba.conf
@ -148,22 +141,6 @@ elif [[ $PRODUCT_CHECK_UPDATE -eq $UPDATE_AVAILABLE_CODE ]]; then
-mysqlp ${MYSQL_ROOT_PASS}
fi
NGINX_ROOT_DIR="/etc/nginx"
NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-$(grep processor /proc/cpuinfo | wc -l)};
NGINX_WORKER_CONNECTIONS=${NGINX_WORKER_CONNECTIONS:-$(ulimit -n)};
sed 's/^worker_processes.*/'"worker_processes ${NGINX_WORKER_PROCESSES};"'/' -i ${NGINX_ROOT_DIR}/nginx.conf
sed 's/worker_connections.*/'"worker_connections ${NGINX_WORKER_CONNECTIONS};"'/' -i ${NGINX_ROOT_DIR}/nginx.conf
if rpm -q "firewalld"; then
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
systemctl restart firewalld.service
fi
systemctl restart nginx
echo ""
echo "$RES_INSTALL_SUCCESS"
echo "$RES_QUESTIONS"

View File

@ -50,7 +50,6 @@ yum localinstall -y --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusi
MONOREV=$REV
if [ "$REV" = "9" ]; then
MONOREV="8"
yum localinstall -y --nogpgcheck https://vault.centos.org/centos/8/AppStream/x86_64/os/Packages/xorg-x11-font-utils-7.5-41.el8.x86_64.rpm
elif [ "$REV" = "8" ]; then
POWERTOOLS_REPO="--enablerepo=powertools"
fi
@ -61,6 +60,7 @@ curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.
#add nodejs repo
curl -sL https://rpm.nodesource.com/setup_16.x | sed 's/centos|/'$DIST'|/g' | sudo bash - || true
rpm --import http://rpm.nodesource.com/pub/el/NODESOURCE-GPG-SIGNING-KEY-EL
#add dotnet repo
if [ $REV = "7" ] || [[ $DIST != "redhat" && $REV = "8" ]]; then
@ -104,9 +104,6 @@ gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
END
${package_manager} -y install python3-dnf-plugin-versionlock || ${package_manager} -y install yum-plugin-versionlock
${package_manager} versionlock clear
${package_manager} -y install epel-release \
python3 \
nodejs \
@ -119,7 +116,8 @@ ${package_manager} -y install epel-release \
rabbitmq-server$rabbitmq_version \
redis --enablerepo=remi \
SDL2 $POWERTOOLS_REPO \
expect
expect \
ffmpeg
py3_version=$(python3 -c 'import sys; print(sys.version_info.minor)')
if [[ $py3_version -lt 6 ]]; then

View File

@ -219,18 +219,11 @@ set_core_machinekey () {
}
install_json() {
if [ ! -e /usr/bin/json ]; then
echo -n "Install json package... "
npm i json -g >/dev/null 2>&1
echo "OK"
fi
#Creating a user-defined .json
if [ ! -e $USER_CONF ]; then
echo "{}" >> $USER_CONF
chown ${PACKAGE_SYSNAME}:${PACKAGE_SYSNAME} $USER_CONF
fi
}
restart_services() {
@ -427,6 +420,12 @@ setup_nginx(){
rm -f $NGINX_CONF/default.conf >/dev/null 2>&1 || rm -f $NGINX_DIR/sites-enabled/default >/dev/null 2>&1
sed -i "s/listen.*;/listen $APP_PORT;/" $NGINX_CONF/${PACKAGE_SYSNAME}.conf
NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-$(grep processor /proc/cpuinfo | wc -l)};
NGINX_WORKER_CONNECTIONS=${NGINX_WORKER_CONNECTIONS:-$(ulimit -n)};
sed "s!\(^worker_processes\).*;!\1 ${NGINX_WORKER_PROCESSES};!" -i ${NGINX_ROOT_DIR}/nginx.conf
sed "s!\(worker_connections\).*;!\1 ${NGINX_WORKER_CONNECTIONS};!" -i ${NGINX_ROOT_DIR}/nginx.conf
if [ "$DIST" = "RedHat" ]; then
# Remove default nginx settings
DELETION_LINE=$(sed -n '/server {/=' /etc/nginx/nginx.conf | head -n 1)
@ -472,7 +471,26 @@ setup_nginx(){
true
done
fi
if rpm -q "firewalld"; then
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
systemctl restart firewalld.service
fi
elif [ "$DIST" = "Debian" ]; then
if ! id "nginx" &>/dev/null; then
systemctl stop nginx
rm -dfr /var/log/nginx/*
rm -dfr /var/cache/nginx/*
useradd -s /bin/false nginx
systemctl start nginx
else
systemctl reload nginx
fi
fi
chown nginx:nginx /etc/nginx/* -R
systemctl enable nginx >/dev/null 2>&1
systemctl restart nginx
@ -485,7 +503,7 @@ setup_docs() {
local JSON_DSCONF="$JSON $DS_CONF -e"
#Changing the Docs port in nginx conf
sed 's/\(listen .*:\)\([0-9]\{2,5\}\b\)\( default_server\)\?\(;\)/\1'${DS_PORT}'\3\4/' -i $NGINX_CONF/ds.conf
sed 's/\(listen .*:\)\([0-9]\{2,5\}\b\)\( default_server\)\?\(;\)/\1'${DOCUMENT_SERVER_PORT}'\3\4/' -i $NGINX_CONF/ds.conf
sed "0,/proxy_pass .*;/{s/proxy_pass .*;/proxy_pass http:\/\/${DOCUMENT_SERVER_HOST}:${DOCUMENT_SERVER_PORT};/}" -i $NGINX_CONF/${PACKAGE_SYSNAME}.conf
#Enable JWT validation for Docs
@ -581,6 +599,11 @@ setup_redis() {
sed "s_\(\"Host\":\).*_\1 \"${REDIS_HOST}\",_" -i $APP_DIR/redis.json
sed "s_\(\"Port\":\).*_\1 \"${REDIS_PORT}\"_" -i $APP_DIR/redis.json
if [ -e /etc/redis/redis.conf ]; then
sed "s_\(^bind\).*_\1 ${REDIS_HOST}_" -i /etc/redis/redis.conf
sed -r "/^save\s[0-9]+/d" -i /etc/redis/redis.conf
fi
systemctl enable $REDIS_PACKAGE >/dev/null 2>&1
systemctl restart $REDIS_PACKAGE
@ -601,6 +624,17 @@ setup_rabbitmq() {
product_configuration(){
echo -n "Configuring ${PRODUCT}... "
#Creating environment configuration files
enviromentFiles=("appsettings.$ENVIRONMENT.json" "apisystem.$ENVIRONMENT.json" "elastic.$ENVIRONMENT.json" "rabbitmq.$ENVIRONMENT.json")
for i in "${!enviromentFiles[@]}";
do
if [ ! -e "$APP_DIR/${enviromentFiles[$i]}" ]; then
echo "{}" >> "$APP_DIR/${enviromentFiles[$i]}"
chown ${PACKAGE_SYSNAME}:${PACKAGE_SYSNAME} "$APP_DIR/${enviromentFiles[$i]}"
fi
done
$JSON $APP_DIR/plugins.json -e "this.pluginsConf={'path': \"$PRODUCT_DIR/Tools/radicale/plugins/\" }" >/dev/null 2>&1
set_core_machinekey

View File

@ -63,6 +63,7 @@ Package: {{product}}-files-services
Architecture: any
Depends: {{product}}-common (= {{package_header_tag_version}}),
dotnet-sdk-7.0,
ffmpeg,
${misc:Depends},
${shlibs:Depends}
Description: {{product}}-files-services

View File

@ -227,14 +227,12 @@ CMD ["ASC.Files.dll", "ASC.Files"]
## ASC.Files.Service ##
FROM dotnetrun AS files_services
RUN apt-get -y update && \
apt-get install -yq ffmpeg &&\
rm -rf /var/lib/apt/lists/*
ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Files.Service/service/ .
COPY --from=onlyoffice/ffvideo:6.0 --chown=onlyoffice:onlyoffice /usr/local /usr/local/
CMD ["ASC.Files.Service.dll", "ASC.Files.Service", "core:eventBus:subscriptionClientName=asc_event_bus_files_service_queue"]

View File

@ -225,7 +225,6 @@ CMD ["ASC.Files.dll", "ASC.Files"]
FROM dotnetrun AS files_services
RUN apt-get -y update && \
apt-get install -yq ffmpeg
WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
@ -261,13 +260,13 @@ COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Socket
CMD ["server.js", "ASC.Socket.IO"]
## ASC.SsoAuth ##
# FROM noderun AS ssoauth
# WORKDIR ${BUILD_PATH}/services/ASC.SsoAuth/
FROM noderun AS ssoauth
WORKDIR ${BUILD_PATH}/services/ASC.SsoAuth/
# COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
# COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.SsoAuth/service/ .
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.SsoAuth/service/ .
# CMD ["app.js", "ASC.SsoAuth"]
CMD ["app.js", "ASC.SsoAuth"]
## ASC.Studio.Notify ##
FROM dotnetrun AS studio_notify

View File

@ -0,0 +1,585 @@
FROM ubuntu:20.04 AS base
ENV DEBIAN_FRONTEND="noninteractive"
ENV TZ="Etc/UTC"
RUN apt-get -yqq update && \
apt-get install -yq --no-install-recommends ca-certificates expat libgomp1 && \
apt-get autoremove -y && \
apt-get clean -y
FROM base as build
ENV FFMPEG_VERSION=6.0 \
AOM_VERSION=v1.0.0 \
CHROMAPRINT_VERSION=1.5.0 \
FDKAAC_VERSION=0.1.5 \
FONTCONFIG_VERSION=2.12.4 \
FREETYPE_VERSION=2.10.4 \
FRIBIDI_VERSION=0.19.7 \
KVAZAAR_VERSION=2.0.0 \
LAME_VERSION=3.100 \
LIBASS_VERSION=0.13.7 \
LIBPTHREAD_STUBS_VERSION=0.4 \
LIBVIDSTAB_VERSION=1.1.0 \
LIBXCB_VERSION=1.13.1 \
XCBPROTO_VERSION=1.13 \
OGG_VERSION=1.3.2 \
OPENCOREAMR_VERSION=0.1.5 \
OPUS_VERSION=1.2 \
OPENJPEG_VERSION=2.1.2 \
THEORA_VERSION=1.1.1 \
VORBIS_VERSION=1.3.5 \
VPX_VERSION=1.8.0 \
WEBP_VERSION=1.0.2 \
X264_VERSION=20170226-2245-stable \
X265_VERSION=3.4 \
XAU_VERSION=1.0.9 \
XORG_MACROS_VERSION=1.19.2 \
XPROTO_VERSION=7.0.31 \
XVID_VERSION=1.3.4 \
LIBXML2_VERSION=2.9.12 \
LIBBLURAY_VERSION=1.1.2 \
LIBZMQ_VERSION=4.3.2 \
LIBSRT_VERSION=1.4.1 \
LIBARIBB24_VERSION=1.0.3 \
LIBPNG_VERSION=1.6.9 \
LIBVMAF_VERSION=2.1.1 \
SRC=/usr/local
ARG FREETYPE_SHA256SUM="5eab795ebb23ac77001cfb68b7d4d50b5d6c7469247b0b01b2c953269f658dac freetype-2.10.4.tar.gz"
ARG FRIBIDI_SHA256SUM="3fc96fa9473bd31dcb5500bdf1aa78b337ba13eb8c301e7c28923fea982453a8 0.19.7.tar.gz"
ARG LIBASS_SHA256SUM="8fadf294bf701300d4605e6f1d92929304187fca4b8d8a47889315526adbafd7 0.13.7.tar.gz"
ARG LIBVIDSTAB_SHA256SUM="14d2a053e56edad4f397be0cb3ef8eb1ec3150404ce99a426c4eb641861dc0bb v1.1.0.tar.gz"
ARG OGG_SHA256SUM="e19ee34711d7af328cb26287f4137e70630e7261b17cbe3cd41011d73a654692 libogg-1.3.2.tar.gz"
ARG OPUS_SHA256SUM="77db45a87b51578fbc49555ef1b10926179861d854eb2613207dc79d9ec0a9a9 opus-1.2.tar.gz"
ARG THEORA_SHA256SUM="40952956c47811928d1e7922cda3bc1f427eb75680c3c37249c91e949054916b libtheora-1.1.1.tar.gz"
ARG VORBIS_SHA256SUM="6efbcecdd3e5dfbf090341b485da9d176eb250d893e3eb378c428a2db38301ce libvorbis-1.3.5.tar.gz"
ARG XVID_SHA256SUM="4e9fd62728885855bc5007fe1be58df42e5e274497591fec37249e1052ae316f xvidcore-1.3.4.tar.gz"
ARG LIBBLURAY_SHA256SUM="a3dd452239b100dc9da0d01b30e1692693e2a332a7d29917bf84bb10ea7c0b42 libbluray-1.1.2.tar.bz2"
ARG LIBZMQ_SHA256SUM="02ecc88466ae38cf2c8d79f09cfd2675ba299a439680b64ade733e26a349edeb v4.3.2.tar.gz"
ARG LIBARIBB24_SHA256SUM="f61560738926e57f9173510389634d8c06cabedfa857db4b28fb7704707ff128 v1.0.3.tar.gz"
ARG LD_LIBRARY_PATH=/opt/ffmpeg/lib
ARG MAKEFLAGS="-j2"
ARG PKG_CONFIG_PATH="/opt/ffmpeg/share/pkgconfig:/opt/ffmpeg/lib/pkgconfig:/opt/ffmpeg/lib64/pkgconfig"
ARG PREFIX=/opt/ffmpeg
ARG LD_LIBRARY_PATH="/opt/ffmpeg/lib:/opt/ffmpeg/lib64"
ARG DEBIAN_FRONTEND=noninteractive
RUN buildDeps="autoconf \
automake \
cmake \
curl \
bzip2 \
libexpat1-dev \
g++ \
gcc \
git \
gperf \
libtool \
make \
meson \
nasm \
perl \
pkg-config \
python \
libssl-dev \
yasm \
zlib1g-dev" && \
apt-get -yqq update && \
apt-get install -yq --no-install-recommends ${buildDeps}
## libvmaf https://github.com/Netflix/vmaf
RUN \
if which meson || false; then \
echo "Building VMAF." && \
DIR=/tmp/vmaf && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/Netflix/vmaf/archive/v${LIBVMAF_VERSION}.tar.gz && \
tar -xz --strip-components=1 -f v${LIBVMAF_VERSION}.tar.gz && \
cd /tmp/vmaf/libvmaf && \
meson build --buildtype release --prefix=${PREFIX} && \
ninja -vC build && \
ninja -vC build install && \
mkdir -p ${PREFIX}/share/model/ && \
cp -r /tmp/vmaf/model/* ${PREFIX}/share/model/ && \
rm -rf ${DIR}; \
else \
echo "VMAF skipped."; \
fi
## opencore-amr https://sourceforge.net/projects/opencore-amr/
RUN \
DIR=/tmp/opencore-amr && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-${OPENCOREAMR_VERSION}.tar.gz/download | \
tar -zx --strip-components=1 && \
./configure --prefix="${PREFIX}" --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
## x264 http://www.videolan.org/developers/x264.html
RUN \
DIR=/tmp/x264 && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-${X264_VERSION}.tar.bz2 | \
tar -jx --strip-components=1 && \
./configure --prefix="${PREFIX}" --enable-shared --enable-pic --disable-cli && \
make && \
make install && \
rm -rf ${DIR}
### x265 http://x265.org/
RUN \
DIR=/tmp/x265 && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://github.com/videolan/x265/archive/refs/tags/${X265_VERSION}.tar.gz | \
tar -zx && \
cd x265-${X265_VERSION}/build/linux && \
sed -i "/-DEXTRA_LIB/ s/$/ -DCMAKE_INSTALL_PREFIX=\${PREFIX}/" multilib.sh && \
sed -i "/^cmake/ s/$/ -DENABLE_CLI=OFF/" multilib.sh && \
./multilib.sh && \
make -C 8bit install && \
rm -rf ${DIR}
### libogg https://www.xiph.org/ogg/
RUN \
DIR=/tmp/ogg && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz && \
echo ${OGG_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f libogg-${OGG_VERSION}.tar.gz && \
./configure --prefix="${PREFIX}" --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
### libopus https://www.opus-codec.org/
RUN \
DIR=/tmp/opus && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz && \
echo ${OPUS_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f opus-${OPUS_VERSION}.tar.gz && \
autoreconf -fiv && \
./configure --prefix="${PREFIX}" --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
### libvorbis https://xiph.org/vorbis/
RUN \
DIR=/tmp/vorbis && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERSION}.tar.gz && \
echo ${VORBIS_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f libvorbis-${VORBIS_VERSION}.tar.gz && \
./configure --prefix="${PREFIX}" --with-ogg="${PREFIX}" --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
### libtheora http://www.theora.org/
RUN \
DIR=/tmp/theora && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.gz && \
echo ${THEORA_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f libtheora-${THEORA_VERSION}.tar.gz && \
./configure --prefix="${PREFIX}" --with-ogg="${PREFIX}" --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
### libvpx https://www.webmproject.org/code/
RUN \
DIR=/tmp/vpx && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://codeload.github.com/webmproject/libvpx/tar.gz/v${VPX_VERSION} | \
tar -zx --strip-components=1 && \
./configure --prefix="${PREFIX}" --enable-vp8 --enable-vp9 --enable-vp9-highbitdepth --enable-pic --enable-shared \
--disable-debug --disable-examples --disable-docs --disable-install-bins && \
make && \
make install && \
rm -rf ${DIR}
### libwebp https://developers.google.com/speed/webp/
RUN \
DIR=/tmp/vebp && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz | \
tar -zx --strip-components=1 && \
./configure --prefix="${PREFIX}" --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
### libmp3lame http://lame.sourceforge.net/
RUN \
DIR=/tmp/lame && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://sourceforge.net/projects/lame/files/lame/${LAME_VERSION}/lame-${LAME_VERSION}.tar.gz/download | \
tar -zx --strip-components=1 && \
./configure --prefix="${PREFIX}" --bindir="${PREFIX}/bin" --enable-shared --enable-nasm --disable-frontend && \
make && \
make install && \
rm -rf ${DIR}
### xvid https://www.xvid.com/
RUN \
DIR=/tmp/xvid && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO http://downloads.xvid.org/downloads/xvidcore-${XVID_VERSION}.tar.gz && \
echo ${XVID_SHA256SUM} | sha256sum --check && \
tar -zx -f xvidcore-${XVID_VERSION}.tar.gz && \
cd xvidcore/build/generic && \
./configure --prefix="${PREFIX}" --bindir="${PREFIX}/bin" && \
make && \
make install && \
rm -rf ${DIR}
### fdk-aac https://github.com/mstorsjo/fdk-aac
RUN \
DIR=/tmp/fdk-aac && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://github.com/mstorsjo/fdk-aac/archive/v${FDKAAC_VERSION}.tar.gz | \
tar -zx --strip-components=1 && \
autoreconf -fiv && \
./configure --prefix="${PREFIX}" --enable-shared --datadir="${DIR}" && \
make && \
make install && \
rm -rf ${DIR}
## openjpeg https://github.com/uclouvain/openjpeg
RUN \
DIR=/tmp/openjpeg && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz | \
tar -zx --strip-components=1 && \
cmake -DBUILD_THIRDPARTY:BOOL=ON -DCMAKE_INSTALL_PREFIX="${PREFIX}" . && \
make && \
make install && \
rm -rf ${DIR}
## freetype https://www.freetype.org/
RUN \
DIR=/tmp/freetype && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://download.savannah.gnu.org/releases/freetype/freetype-${FREETYPE_VERSION}.tar.gz && \
echo ${FREETYPE_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f freetype-${FREETYPE_VERSION}.tar.gz && \
./configure --prefix="${PREFIX}" --disable-static --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
## libvstab https://github.com/georgmartius/vid.stab
RUN \
DIR=/tmp/vid.stab && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/georgmartius/vid.stab/archive/v${LIBVIDSTAB_VERSION}.tar.gz && \
echo ${LIBVIDSTAB_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f v${LIBVIDSTAB_VERSION}.tar.gz && \
cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" . && \
make && \
make install && \
rm -rf ${DIR}
## fridibi https://www.fribidi.org/
RUN \
DIR=/tmp/fribidi && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/fribidi/fribidi/archive/${FRIBIDI_VERSION}.tar.gz && \
echo ${FRIBIDI_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f ${FRIBIDI_VERSION}.tar.gz && \
sed -i 's/^SUBDIRS =.*/SUBDIRS=gen.tab charset lib bin/' Makefile.am && \
./bootstrap --no-config --auto && \
./configure --prefix="${PREFIX}" --disable-static --enable-shared && \
make -j1 && \
make install && \
rm -rf ${DIR}
## fontconfig https://www.freedesktop.org/wiki/Software/fontconfig/
RUN \
DIR=/tmp/fontconfig && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://www.freedesktop.org/software/fontconfig/release/fontconfig-${FONTCONFIG_VERSION}.tar.bz2 && \
tar -jx --strip-components=1 -f fontconfig-${FONTCONFIG_VERSION}.tar.bz2 && \
./configure --prefix="${PREFIX}" --disable-static --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
## libass https://github.com/libass/libass
RUN \
DIR=/tmp/libass && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/libass/libass/archive/${LIBASS_VERSION}.tar.gz && \
echo ${LIBASS_SHA256SUM} | sha256sum --check && \
tar -zx --strip-components=1 -f ${LIBASS_VERSION}.tar.gz && \
./autogen.sh && \
./configure --prefix="${PREFIX}" --disable-static --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
## kvazaar https://github.com/ultravideo/kvazaar
RUN \
DIR=/tmp/kvazaar && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/ultravideo/kvazaar/archive/v${KVAZAAR_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f v${KVAZAAR_VERSION}.tar.gz && \
./autogen.sh && \
./configure --prefix="${PREFIX}" --disable-static --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
RUN \
DIR=/tmp/aom && \
git clone --branch ${AOM_VERSION} --depth 1 https://aomedia.googlesource.com/aom ${DIR} ; \
cd ${DIR} ; \
rm -rf CMakeCache.txt CMakeFiles ; \
mkdir -p ./aom_build ; \
cd ./aom_build ; \
cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DBUILD_SHARED_LIBS=1 ..; \
make ; \
make install ; \
rm -rf ${DIR}
## libxcb (and supporting libraries) for screen capture https://xcb.freedesktop.org/
RUN \
DIR=/tmp/xorg-macros && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://www.x.org/archive//individual/util/util-macros-${XORG_MACROS_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f util-macros-${XORG_MACROS_VERSION}.tar.gz && \
./configure --srcdir=${DIR} --prefix="${PREFIX}" && \
make && \
make install && \
rm -rf ${DIR}
RUN \
DIR=/tmp/xproto && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://www.x.org/archive/individual/proto/xproto-${XPROTO_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f xproto-${XPROTO_VERSION}.tar.gz && \
./configure --srcdir=${DIR} --prefix="${PREFIX}" && \
make && \
make install && \
rm -rf ${DIR}
RUN \
DIR=/tmp/libXau && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://www.x.org/archive/individual/lib/libXau-${XAU_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f libXau-${XAU_VERSION}.tar.gz && \
./configure --srcdir=${DIR} --prefix="${PREFIX}" && \
make && \
make install && \
rm -rf ${DIR}
RUN \
DIR=/tmp/libpthread-stubs && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://xcb.freedesktop.org/dist/libpthread-stubs-${LIBPTHREAD_STUBS_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f libpthread-stubs-${LIBPTHREAD_STUBS_VERSION}.tar.gz && \
./configure --prefix="${PREFIX}" && \
make && \
make install && \
rm -rf ${DIR}
RUN \
DIR=/tmp/libxcb-proto && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://xcb.freedesktop.org/dist/xcb-proto-${XCBPROTO_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f xcb-proto-${XCBPROTO_VERSION}.tar.gz && \
ACLOCAL_PATH="${PREFIX}/share/aclocal" ./autogen.sh && \
./configure --prefix="${PREFIX}" && \
make && \
make install && \
rm -rf ${DIR}
RUN \
DIR=/tmp/libxcb && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://xcb.freedesktop.org/dist/libxcb-${LIBXCB_VERSION}.tar.gz && \
tar -zx --strip-components=1 -f libxcb-${LIBXCB_VERSION}.tar.gz && \
ACLOCAL_PATH="${PREFIX}/share/aclocal" ./autogen.sh && \
./configure --prefix="${PREFIX}" --disable-static --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
## libxml2 - for libbluray
RUN \
DIR=/tmp/libxml2 && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sL https://github.com/GNOME/libxml2/archive/refs/tags/v${LIBXML2_VERSION}.tar.gz | \
tar -xz --strip-components=1 && \
./autogen.sh --prefix="${PREFIX}" --with-ftp=no --with-http=no --with-python=no && \
make && \
make install && \
rm -rf ${DIR}
## libbluray - Requires libxml, freetype, and fontconfig
RUN \
DIR=/tmp/libbluray && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://download.videolan.org/pub/videolan/libbluray/${LIBBLURAY_VERSION}/libbluray-${LIBBLURAY_VERSION}.tar.bz2 && \
echo ${LIBBLURAY_SHA256SUM} | sha256sum --check && \
tar -jx --strip-components=1 -f libbluray-${LIBBLURAY_VERSION}.tar.bz2 && \
./configure --prefix="${PREFIX}" --disable-examples --disable-bdjava-jar --disable-static --enable-shared && \
make && \
make install && \
rm -rf ${DIR}
## libzmq https://github.com/zeromq/libzmq/
RUN \
DIR=/tmp/libzmq && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/zeromq/libzmq/archive/v${LIBZMQ_VERSION}.tar.gz && \
echo ${LIBZMQ_SHA256SUM} | sha256sum --check && \
tar -xz --strip-components=1 -f v${LIBZMQ_VERSION}.tar.gz && \
./autogen.sh && \
./configure --prefix="${PREFIX}" && \
make && \
make check && \
make install && \
rm -rf ${DIR}
## libsrt https://github.com/Haivision/srt
RUN \
DIR=/tmp/srt && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/Haivision/srt/archive/v${LIBSRT_VERSION}.tar.gz && \
tar -xz --strip-components=1 -f v${LIBSRT_VERSION}.tar.gz && \
cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" . && \
make && \
make install && \
rm -rf ${DIR}
## libpng
RUN \
DIR=/tmp/png && \
mkdir -p ${DIR} && \
cd ${DIR} && \
git clone https://git.code.sf.net/p/libpng/code ${DIR} -b v${LIBPNG_VERSION} --depth 1 && \
./autogen.sh && \
./configure --prefix="${PREFIX}" && \
make check && \
make install && \
rm -rf ${DIR}
## libaribb24
RUN \
DIR=/tmp/b24 && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLO https://github.com/nkoriyama/aribb24/archive/v${LIBARIBB24_VERSION}.tar.gz && \
echo ${LIBARIBB24_SHA256SUM} | sha256sum --check && \
tar -xz --strip-components=1 -f v${LIBARIBB24_VERSION}.tar.gz && \
autoreconf -fiv && \
./configure CFLAGS="-I${PREFIX}/include -fPIC" --prefix="${PREFIX}" && \
make && \
make install && \
rm -rf ${DIR}
## Download ffmpeg https://ffmpeg.org/
RUN \
DIR=/tmp/ffmpeg && mkdir -p ${DIR} && cd ${DIR} && \
curl -sLO https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2 && \
tar -jx --strip-components=1 -f ffmpeg-${FFMPEG_VERSION}.tar.bz2 && \
./configure --disable-debug --disable-doc --disable-ffplay --enable-shared --enable-gpl --extra-libs=-ldl && \
make ; make install
## Build ffmpeg https://ffmpeg.org/
RUN \
DIR=/tmp/ffmpeg && cd ${DIR} && \
./configure \
--disable-debug \
--disable-doc \
--disable-ffplay \
--enable-fontconfig \
--enable-gpl \
--enable-libaom \
--enable-libaribb24 \
--enable-libass \
--enable-libbluray \
--enable-libfdk_aac \
--enable-libfreetype \
--enable-libkvazaar \
--enable-libmp3lame \
--enable-libopencore-amrnb \
--enable-libopencore-amrwb \
--enable-libopenjpeg \
--enable-libopus \
--enable-libsrt \
--enable-libtheora \
--enable-libvidstab \
--enable-libvmaf \
--enable-libvorbis \
--enable-libvpx \
--enable-libwebp \
--enable-libx264 \
--enable-libx265 \
--enable-libxcb \
--enable-libxvid \
--enable-libzmq \
--enable-nonfree \
--enable-openssl \
--enable-postproc \
--enable-shared \
--enable-small \
--enable-version3 \
--extra-cflags="-I${PREFIX}/include" \
--extra-ldflags="-L${PREFIX}/lib" \
--extra-libs=-ldl \
--extra-libs=-lpthread \
--prefix="${PREFIX}" && \
make clean && \
make && \
make install && \
make tools/zmqsend && cp tools/zmqsend ${PREFIX}/bin/ && \
make distclean && \
hash -r && \
cd tools && \
make qt-faststart && cp qt-faststart ${PREFIX}/bin/
## cleanup
RUN \
ldd ${PREFIX}/bin/ffmpeg | grep opt/ffmpeg | cut -d ' ' -f 3 | xargs -i cp {} /usr/local/lib/ && \
for lib in /usr/local/lib/*.so.*; do ln -s "${lib##*/}" "${lib%%.so.*}".so; done && \
cp ${PREFIX}/bin/* /usr/local/bin/ && \
cp -r ${PREFIX}/share/ffmpeg /usr/local/share/ && \
LD_LIBRARY_PATH=/usr/local/lib ffmpeg -buildconf && \
cp -r ${PREFIX}/include/libav* ${PREFIX}/include/libpostproc ${PREFIX}/include/libsw* /usr/local/include && \
mkdir -p /usr/local/lib/pkgconfig && \
for pc in ${PREFIX}/lib/pkgconfig/libav*.pc ${PREFIX}/lib/pkgconfig/libpostproc.pc ${PREFIX}/lib/pkgconfig/libsw*.pc; do \
sed "s:${PREFIX}:/usr/local:g" <"$pc" >/usr/local/lib/pkgconfig/"${pc##*/}"; \
done
FROM base AS release
ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
COPY --from=build /usr/local /usr/local/
ENTRYPOINT ["bash"]

View File

@ -106,12 +106,12 @@ services:
target: studio
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
# onlyoffice-ssoauth:
# build:
# context: ./
# dockerfile: "${DOCKERFILE}"
# target: ssoauth
# image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
onlyoffice-ssoauth:
build:
context: ./
dockerfile: "${DOCKERFILE}"
target: ssoauth
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
# onlyoffice-webhooks-service:
# build:

View File

@ -129,13 +129,13 @@ services:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
container_name: ${STUDIO_HOST}
# onlyoffice-ssoauth:
# <<: *x-service-base
# image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
# container_name: ${SSOAUTH_HOST}
# expose:
# - ${SERVICE_PORT}
# - "9834"
onlyoffice-ssoauth:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-ssoauth:${DOCKER_TAG}"
container_name: ${SSOAUTH_HOST}
expose:
- ${SERVICE_PORT}
- "9834"
# onlyoffice-webhooks-service:
# <<: *x-service-base
@ -168,7 +168,7 @@ services:
- onlyoffice-api
# - onlyoffice-api-system
- onlyoffice-studio
# - onlyoffice-ssoauth
- onlyoffice-ssoauth
environment:
- SERVICE_BACKUP=${SERVICE_BACKUP}
- SERVICE_FILES=${SERVICE_FILES}

View File

@ -1,4 +1,12 @@
version: "3.8"
x-healthcheck:
&x-healthcheck
test: curl --fail http://127.0.0.1 || exit 1
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
x-service: &x-service-base
container_name: base
restart: always
@ -54,31 +62,49 @@ services:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup-background:${DOCKER_TAG}"
container_name: ${BACKUP_BACKGRUOND_TASKS_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_BACKUP_BACKGRUOND_TASKS}/health/ || exit 1
onlyoffice-backup:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup:${DOCKER_TAG}"
container_name: ${BACKUP_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_BACKUP}/health/ || exit 1
onlyoffice-clear-events:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-clear-events:${DOCKER_TAG}"
container_name: ${CLEAR_EVENTS_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_CLEAR_EVENTS}/health/ || exit 1
onlyoffice-files:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files:${DOCKER_TAG}"
container_name: ${FILES_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_FILES}/health/ || exit 1
onlyoffice-files-services:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files-services:${DOCKER_TAG}"
container_name: ${FILES_SERVICES_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_FILES_SERVICES}/health/ || exit 1
onlyoffice-people-server:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-people-server:${DOCKER_TAG}"
container_name: ${PEOPLE_SERVER_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_PEOPLE_SERVER}/health/ || exit 1
onlyoffice-socket:
<<: *x-service-base
@ -91,21 +117,33 @@ services:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio-notify:${DOCKER_TAG}"
container_name: ${STUDIO_NOTIFY_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_STUDIO_NOTIFY}/health/ || exit 1
onlyoffice-api:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api:${DOCKER_TAG}"
container_name: ${API_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_API}/health/ || exit 1
onlyoffice-api-system:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
container_name: ${API_SYSTEM_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_API_SYSTEM}/health/ || exit 1
onlyoffice-studio:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
container_name: ${STUDIO_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_STUDIO}/health/ || exit 1
onlyoffice-ssoauth:
<<: *x-service-base
@ -135,6 +173,9 @@ services:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-proxy:${DOCKER_TAG}"
container_name: ${PROXY_HOST}
restart: always
healthcheck:
<<: *x-healthcheck
test: nginx -t || exit 1
expose:
- "8081"
- "8099"

View File

@ -1,4 +1,12 @@
version: "3.8"
x-healthcheck:
&x-healthcheck
test: curl --fail http://127.0.0.1 || exit 1
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
x-service:
&x-service-base
container_name: base
@ -33,6 +41,9 @@ services:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-notify:${DOCKER_TAG}"
container_name: ${NOTIFY_HOST}
healthcheck:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_NOTIFY}/health/ || exit 1
networks:
default:

View File

@ -18,7 +18,7 @@ Common
Summary: Files-services
Group: Applications/Internet
Requires: %name-common = %version-%release
Requires: dotnet-sdk-7.0
Requires: dotnet-sdk-7.0, ffmpeg
AutoReqProv: no
%description files-services
Files-services

View File

@ -2,4 +2,9 @@ PUSHD %~dp0..
set dir=%~dp0..
echo %dir%
dotnet test common\Tests\Frontend.Translations.Tests\Frontend.Translations.Tests.csproj --filter Name~SpellCheckTest -l:html --environment "BASE_DIR=%dir%" --results-directory "%dir%/TestsResults"
set save=false
if /I "%1" == "-s" set save=%2 & shift
shift
dotnet test common\Tests\Frontend.Translations.Tests\Frontend.Translations.Tests.csproj --filter Name~SpellCheckTest -l:html --environment "BASE_DIR=%dir%" --environment "SAVE=%save%" --results-directory "%dir%/TestsResults"

View File

@ -3,6 +3,15 @@ echo "Run script directory:" $dir
dir=$(builtin cd $rd/../; pwd)
save=false
while getopts s: flag
do
case "${flag}" in
s) save=${OPTARG};;
esac
done
echo "Root directory:" $dir
dotnet test $dir/common/Tests/Frontend.Translations.Tests/Frontend.Translations.Tests.csproj --filter Name~SpellCheckTest -l:html --results-directory "$dir/TestsResults" --environment "BASE_DIR=$dir"
dotnet test $dir/common/Tests/Frontend.Translations.Tests/Frontend.Translations.Tests.csproj --filter Name~SpellCheckTest -l:html --results-directory "$dir/TestsResults" --environment "BASE_DIR=$dir" --environment "SAVE=$save"

View File

@ -71,7 +71,7 @@ public class Criteria : ICloneable
/// Add nested Criteria
/// </summary>
/// <param name="nested"></param>
/// <returns>себя</returns>
/// <returns>Self</returns>
public Criteria Add(Criteria nested)
{
_nestedCriteras.Add(nested);

View File

@ -417,7 +417,7 @@ public class LdapUserImporter : IDisposable
if (!actualPortalLdapGroups.Contains(portalUserLdapGroup))
{
_logger.DebugTrySyncUserGroupMembershipRemovingUserFromGroup(userInfo.UserName, ldapUser.Sid, portalUserLdapGroup.Name, portalUserLdapGroup.Sid);
UserManager.RemoveUserFromGroup(userInfo.Id, portalUserLdapGroup.ID);
await UserManager.RemoveUserFromGroup(userInfo.Id, portalUserLdapGroup.ID);
}
}

View File

@ -299,13 +299,13 @@ public class LdapOperationJob : DistributedTaskProgress
{
_logger.DebugTurnOffLDAP();
TurnOffLDAP();
await TurnOffLDAP();
var ldapCurrentUserPhotos = _settingsManager.Load<LdapCurrentUserPhotos>().GetDefault();
_settingsManager.Save(ldapCurrentUserPhotos);
var ldapCurrentAcccessSettings = _settingsManager.Load<LdapCurrentAcccessSettings>().GetDefault();
_settingsManager.Save(ldapCurrentAcccessSettings);
//не снимать права при выключении
// don't remove permissions on shutdown
//var rights = new List<LdapSettings.AccessRight>();
//TakeUsersRights(rights);
@ -349,7 +349,7 @@ public class LdapOperationJob : DistributedTaskProgress
: "", "");
}
private void TurnOffLDAP()
private async Task TurnOffLDAP()
{
const double percents = 48;
@ -380,7 +380,7 @@ public class LdapOperationJob : DistributedTaskProgress
_logger.DebugSaveUserInfo(existingLDAPUser.GetUserInfoString());
_userManager.UpdateUserInfo(existingLDAPUser);
await _userManager.UpdateUserInfo(existingLDAPUser);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
@ -667,7 +667,7 @@ public class LdapOperationJob : DistributedTaskProgress
SetProgress(20, Resource.LdapSettingsStatusRemovingOldUsers, "");
ldapUsers = RemoveOldDbUsers(ldapUsers);
ldapUsers = await RemoveOldDbUsers(ldapUsers);
SetProgress(30,
OperationType == LdapOperationType.Save || OperationType == LdapOperationType.SaveTest
@ -729,7 +729,7 @@ public class LdapOperationJob : DistributedTaskProgress
SetProgress(90, Resource.LdapSettingsStatusRemovingOldUsers, "");
RemoveOldDbUsers(newUniqueLdapGroupUsers);
await RemoveOldDbUsers(newUniqueLdapGroupUsers);
}
private async Task SyncDbGroups(Dictionary<GroupInfo, List<UserInfo>> ldapGroupsWithUsers)
@ -895,7 +895,7 @@ public class LdapOperationJob : DistributedTaskProgress
++index, count,
_userFormatter.GetUserName(dbUser, DisplayUserNameFormat.Default)));
_userManager.RemoveUserFromGroup(dbUser.Id, dbLdapGroup.ID);
await _userManager.RemoveUserFromGroup(dbUser.Id, dbLdapGroup.ID);
}
index = 0;
@ -1012,7 +1012,7 @@ public class LdapOperationJob : DistributedTaskProgress
/// </summary>
/// <param name="ldapUsers">list of actual LDAP users</param>
/// <returns>New list of actual LDAP users</returns>
private List<UserInfo> RemoveOldDbUsers(List<UserInfo> ldapUsers)
private async Task<List<UserInfo>> RemoveOldDbUsers(List<UserInfo> ldapUsers)
{
var dbLdapUsers = _userManager.GetUsers(EmployeeStatus.All).Where(u => u.Sid != null).ToList();
@ -1064,7 +1064,7 @@ public class LdapOperationJob : DistributedTaskProgress
_logger.DebugSaveUserInfo(removedUser.GetUserInfoString());
_userManager.UpdateUserInfo(removedUser);
await _userManager.UpdateUserInfo(removedUser);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:

View File

@ -126,7 +126,7 @@ public class LdapUserManager
return portalUserInfo;
}
if (!TryChangeExistingUserName(ldapUserInfo.UserName, onlyGetChanges))
if (!await TryChangeExistingUserName(ldapUserInfo.UserName, onlyGetChanges))
{
_logger.DebugUserAlredyExistsForUserName(ldapUserInfo.Sid, ldapUserInfo.UserName);
@ -177,7 +177,7 @@ public class LdapUserManager
return portalUserInfo;
}
private bool TryChangeExistingUserName(string ldapUserName, bool onlyGetChanges)
private async Task<bool> TryChangeExistingUserName(string ldapUserName, bool onlyGetChanges)
{
try
{
@ -209,7 +209,7 @@ public class LdapUserManager
_logger.DebugSaveUserInfo(otherUser.GetUserInfoString());
_userManager.UpdateUserInfo(otherUser);
await _userManager.UpdateUserInfo(otherUser);
return true;
}
@ -343,9 +343,11 @@ public class LdapUserManager
return wrapper;
}
_logger.DebugSyncUserLdapUpdaiting(ldapUserInfo.Sid, ldapUserInfo.UserName);
UserInfo uf;
if (!TryUpdateUserWithLDAPInfo(userToUpdate, ldapUserInfo, onlyGetChanges, out uf))
_logger.DebugSyncUserLdapUpdaiting(ldapUserInfo.Sid, ldapUserInfo.UserName);
var (updated, uf) = await TryUpdateUserWithLDAPInfo(userToUpdate, ldapUserInfo, onlyGetChanges);
if (!updated)
{
if (onlyGetChanges)
{
@ -379,7 +381,7 @@ public class LdapUserManager
var newContacts = new List<string>(ldapUser.ContactsList);
for (int i = 0; i < portalUserContacts.Count; i += 2)
for (var i = 0; i < portalUserContacts.Count; i += 2)
{
if (portalUserContacts[i] == EXT_MOB_PHONE || portalUserContacts[i] == EXT_MAIL
|| portalUserContacts[i] == EXT_PHONE || portalUserContacts[i] == EXT_SKYPE)
@ -516,9 +518,9 @@ public class LdapUserManager
return needUpdate;
}
private bool TryUpdateUserWithLDAPInfo(UserInfo userToUpdate, UserInfo updateInfo, bool onlyGetChanges, out UserInfo portlaUserInfo)
private async Task<(bool, UserInfo)> TryUpdateUserWithLDAPInfo(UserInfo userToUpdate, UserInfo updateInfo, bool onlyGetChanges)
{
portlaUserInfo = Constants.LostUser;
var portlaUserInfo = Constants.LostUser;
try
{
@ -527,11 +529,11 @@ public class LdapUserManager
var settings = _settingsManager.Load<LdapSettings>();
if (!userToUpdate.UserName.Equals(updateInfo.UserName, StringComparison.InvariantCultureIgnoreCase)
&& !TryChangeExistingUserName(updateInfo.UserName, onlyGetChanges))
&& !await TryChangeExistingUserName(updateInfo.UserName, onlyGetChanges))
{
_logger.DebugUpdateUserUserNameAlredyExists(userToUpdate.Id, userToUpdate.UserName, updateInfo.UserName);
return false;
return (false, portlaUserInfo);
}
if (!userToUpdate.Email.Equals(updateInfo.Email, StringComparison.InvariantCultureIgnoreCase)
@ -539,7 +541,7 @@ public class LdapUserManager
{
_logger.DebugUpdateUserEmailAlreadyExists(userToUpdate.Id, userToUpdate.Email, updateInfo.Email);
return false;
return (false, portlaUserInfo);
}
if (userToUpdate.Email != updateInfo.Email && !(updateInfo.ActivationStatus == EmployeeActivationStatus.AutoGenerated &&
@ -589,10 +591,10 @@ public class LdapUserManager
{
_logger.DebugSaveUserInfo(userToUpdate.GetUserInfoString());
portlaUserInfo = _userManager.UpdateUserInfo(userToUpdate);
portlaUserInfo = await _userManager.UpdateUserInfo(userToUpdate);
}
return true;
return (true, portlaUserInfo);
}
catch (Exception ex)
{
@ -600,7 +602,7 @@ public class LdapUserManager
userToUpdate.Sid, ex);
}
return false;
return (false, portlaUserInfo);
}
public async Task<UserInfo> TryGetAndSyncLdapUserInfo(string login, string password)
@ -678,7 +680,7 @@ public class LdapUserManager
log.DebugTryGetAndSyncLdapUserInfoDisablingUser(login, uInfo);
uInfo.Status = EmployeeStatus.Terminated;
uInfo.Sid = null;
userManager.UpdateUserInfo(uInfo);
await userManager.UpdateUserInfo(uInfo);
await cookiesManager.ResetUserCookie(uInfo.Id);
}
}
@ -730,7 +732,7 @@ public class LdapUserManager
{
userInfo.Sid = null;
userInfo.Status = EmployeeStatus.Terminated;
_userManager.UpdateUserInfo(userInfo);
await _userManager.UpdateUserInfo(userInfo);
throw new Exception("The user did not pass the configuration check by ldap group settings");
}

View File

@ -40,7 +40,7 @@ public class WarmupServicesStartupTask : IStartupTask
}
public Task ExecuteAsync(CancellationToken cancellationToken)
{
{
var processedFailed = 0;
var processedSuccessed = 0;
var startTime = DateTime.UtcNow;
@ -52,13 +52,13 @@ public class WarmupServicesStartupTask : IStartupTask
logger.TraceWarmupStarted();
tenantManager.SetCurrentTenant("localhost");
tenantManager.SetCurrentTenant("localhost");
foreach (var service in GetServices(_services))
{
try
{
scope.ServiceProvider.GetServices(service);
{
scope.ServiceProvider.GetService(service);
processedSuccessed++;
}
@ -72,9 +72,9 @@ public class WarmupServicesStartupTask : IStartupTask
var processed = processedSuccessed + processedFailed;
logger.TraceWarmupFinished(processed,
processedSuccessed,
processedFailed,
logger.TraceWarmupFinished(processed,
processedSuccessed,
processedFailed,
(DateTime.UtcNow - startTime).TotalMilliseconds);
}
@ -86,7 +86,7 @@ public class WarmupServicesStartupTask : IStartupTask
return services
.Where(descriptor => descriptor.ImplementationType != typeof(WarmupServicesStartupTask))
.Where(descriptor => descriptor.ServiceType.ContainsGenericParameters == false)
.Select(descriptor => descriptor.ServiceType)
.Select(descriptor => descriptor.ServiceType)
.Distinct();
}
}

View File

@ -146,7 +146,7 @@ public static class ServiceCollectionExtension
var logger = sp.GetRequiredService<ILogger<DefaultActiveMQPersistentConnection>>();
var factory = new Apache.NMS.NMSConnectionFactory(activeMQConfiguration.Uri);
var retryCount = 5;
if (!string.IsNullOrEmpty(cfg["core:eventBus:connectRetryCount"]))
@ -195,10 +195,8 @@ public static class ServiceCollectionExtension
/// Add a IHostedService for given type.
/// Only one copy of this instance type will active in multi process architecture.
/// </remarks>
public static void AddActivePassiveHostedService<T>(this IServiceCollection services) where T : class, IHostedService
public static void AddActivePassiveHostedService<T>(this IServiceCollection services, DIHelper diHelper) where T : class, IHostedService
{
var diHelper = new DIHelper(services);
diHelper.TryAdd<IRegisterInstanceDao<T>, RegisterInstanceDao<T>>();
diHelper.TryAdd<IRegisterInstanceManager<T>, RegisterInstanceManager<T>>();

View File

@ -70,7 +70,7 @@ public class RedisCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
private string GetChannelName(CacheNotifyAction action)
{
return $"asc:channel:{action}:{typeof(T).FullName}".ToLower();
return $"asc:channel:{action}:{typeof(T).FullName}".ToLower(CultureInfo.InvariantCulture);
}
class RedisCachePubSubItem<T0>

View File

@ -26,13 +26,6 @@
namespace ASC.Core.Common;
[Scope]
public class CommonLinkUtilitySettings
{
public string ServerUri { get; set; }
}
[Scope]
public class BaseCommonLinkUtility
{
@ -43,14 +36,22 @@ public class BaseCommonLinkUtility
private string _vpath;
protected IHttpContextAccessor _httpContextAccessor;
public string ServerUri
{
set
{
var uri = new Uri(value.Replace('*', 'x').Replace('+', 'x'));
_serverRoot = new UriBuilder(uri.Scheme, uri.Host != "x" ? uri.Host : LocalHost, uri.Port);
_vpath = "/" + uri.AbsolutePath.Trim('/');
}
}
public BaseCommonLinkUtility(
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
TenantManager tenantManager,
ILoggerProvider options,
CommonLinkUtilitySettings settings)
: this(null, coreBaseSettings, coreSettings, tenantManager, options, settings)
ILoggerProvider options)
: this(null, coreBaseSettings, coreSettings, tenantManager, options)
{
}
@ -59,37 +60,29 @@ public class BaseCommonLinkUtility
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
TenantManager tenantManager,
ILoggerProvider options,
CommonLinkUtilitySettings settings)
ILoggerProvider options)
{
var serverUri = settings.ServerUri;
if (!string.IsNullOrEmpty(serverUri))
try
{
var uri = new Uri(serverUri.Replace('*', 'x').Replace('+', 'x'));
_serverRoot = new UriBuilder(uri.Scheme, uri.Host != "x" ? uri.Host : LocalHost, uri.Port);
_vpath = "/" + uri.AbsolutePath.Trim('/');
_httpContextAccessor = httpContextAccessor;
if (_httpContextAccessor?.HttpContext?.Request != null)
{
var u = _httpContextAccessor?.HttpContext.Request.GetUrlRewriter();
ArgumentNullException.ThrowIfNull(u);
_serverRoot = new UriBuilder(u.Scheme, LocalHost, u.Port);
}
else if (_serverRoot == null)
{
_serverRoot = new UriBuilder(Uri.UriSchemeHttp, LocalHost);
}
}
else
catch (Exception error)
{
try
{
_httpContextAccessor = httpContextAccessor;
var uriBuilder = new UriBuilder(Uri.UriSchemeHttp, LocalHost);
if (_httpContextAccessor?.HttpContext?.Request != null)
{
var u = _httpContextAccessor?.HttpContext.Request.GetUrlRewriter();
ArgumentNullException.ThrowIfNull(u);
uriBuilder = new UriBuilder(u.Scheme, LocalHost, u.Port);
}
_serverRoot = uriBuilder;
}
catch (Exception error)
{
options.CreateLogger("ASC.Web").ErrorWithException(error);
}
options.CreateLogger("ASC.Web").ErrorWithException(error);
}
_coreBaseSettings = coreBaseSettings;
@ -103,16 +96,10 @@ public class BaseCommonLinkUtility
private readonly CoreSettings _coreSettings;
protected TenantManager _tenantManager;
private string _serverRootPath;
public string ServerRootPath
{
get
{
if (!string.IsNullOrEmpty(_serverRootPath))
{
return _serverRootPath;
}
UriBuilder result;
// first, take from current request
if (_httpContextAccessor?.HttpContext?.Request != null)
@ -160,7 +147,7 @@ public class BaseCommonLinkUtility
}
}
return _serverRootPath = result.Uri.ToString().TrimEnd('/');
return result.Uri.ToString().TrimEnd('/');
}
}

View File

@ -31,7 +31,7 @@ public interface ITariffService
{
IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds);
IEnumerable<PaymentInfo> GetPayments(int tenantId);
Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true);
Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true, bool refresh = false);
Task<Uri> GetShoppingUri(int tenant, string currency = null, string language = null, string customerEmail = null, Dictionary<string, int> quantity = null, string backUrl = null);
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);

View File

@ -53,7 +53,7 @@ public class Tariff
return t != null
&& t.DueDate == DueDate
&& t.Quotas.Count == Quotas.Count
&& t.Quotas.Any(q => Quotas.Contains(q))
&& t.Quotas.Any(Quotas.Contains)
&& t.CustomerId == CustomerId;
}
}

View File

@ -23,7 +23,7 @@
// 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.Billing;
[Singletone]
@ -145,18 +145,9 @@ public class TariffService : ITariffService
_cache = _tariffServiceStorage.Cache;
_notify = _tariffServiceStorage.Notify;
_dbContextFactory = coreDbContextManager;
//var range = (_configuration["core.payment-user-range"] ?? "").Split('-');
//if (!int.TryParse(range[0], out _activeUsersMin))
//{
// _activeUsersMin = 0;
//}
//if (range.Length < 2 || !int.TryParse(range[1], out _activeUsersMax))
//{
// _activeUsersMax = constants.MaxEveryoneCount;
//}
}
public Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true)
public Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true, bool refresh = false)
{
//single tariff for all portals
if (_coreBaseSettings.Standalone)
@ -164,8 +155,7 @@ public class TariffService : ITariffService
tenantId = -1;
}
var tariff = GetTariffFromCache(tenantId);
int? tariffId = null;
var tariff = refresh ? null : GetTariffFromCache(tenantId);
if (tariff == null)
{
@ -174,11 +164,12 @@ public class TariffService : ITariffService
if (string.IsNullOrEmpty(_cache.Get<string>(GetTariffNeedToUpdateCacheKey(tenantId))))
{
tariffId = tariff.Id;
UpdateCache(tariff.Id);
}
if (_billingClient.Configured && withRequestToPaymentSystem)
{
var paymentFound = false;
try
{
@ -190,10 +181,11 @@ public class TariffService : ITariffService
var asynctariff = CreateDefault(true);
string email = null;
var tenantQuotas = _quotaService.GetTenantQuotas();
foreach (var currentPayment in currentPayments)
foreach (var currentPayment in currentPayments.OrderBy(r => r.EndDate))
{
var quota = _quotaService.GetTenantQuotas().SingleOrDefault(q => q.ProductId == currentPayment.ProductId.ToString());
var quota = tenantQuotas.SingleOrDefault(q => q.ProductId == currentPayment.ProductId.ToString());
if (quota == null)
{
throw new InvalidOperationException($"Quota with id {currentPayment.ProductId} not found for portal {GetPortalId(tenantId)}.");
@ -204,10 +196,23 @@ public class TariffService : ITariffService
var paymentEndDate = 9999 <= currentPayment.EndDate.Year ? DateTime.MaxValue : currentPayment.EndDate;
asynctariff.DueDate = DateTime.Compare(asynctariff.DueDate, paymentEndDate) < 0 ? asynctariff.DueDate : paymentEndDate;
asynctariff.Quotas = asynctariff.Quotas.Where(r => r.Id != quota.Tenant).ToList();
asynctariff.Quotas.Add(new Quota(quota.Tenant, currentPayment.Quantity));
email = currentPayment.PaymentEmail;
}
TenantQuota updatedQuota = null;
foreach (var quota in asynctariff.Quotas)
{
var tenantQuota = tenantQuotas.SingleOrDefault(q => q.Tenant == quota.Id);
tenantQuota *= quota.Quantity;
updatedQuota += tenantQuota;
}
updatedQuota.Check(_serviceProvider).Wait();
if (!string.IsNullOrEmpty(email))
{
asynctariff.CustomerId = email;
@ -217,10 +222,21 @@ public class TariffService : ITariffService
{
asynctariff = CalculateTariff(tenantId, asynctariff);
tariff = asynctariff;
tariffId = asynctariff.Id;
}
UpdateCache(tariff.Id);
paymentFound = true;
}
catch (Exception error)
{
if (error is not BillingNotFoundException)
{
LogError(error, tenantId.ToString());
}
}
catch (BillingNotFoundException)
if (!paymentFound)
{
var freeTariff = tariff.Quotas.FirstOrDefault(tariffRow =>
{
@ -244,22 +260,23 @@ public class TariffService : ITariffService
{
asynctariff = CalculateTariff(tenantId, asynctariff);
tariff = asynctariff;
tariffId = asynctariff.Id;
}
}
catch (Exception error)
{
LogError(error, tenantId.ToString());
UpdateCache(tariff.Id);
}
}
}
if (tariffId.HasValue && tariffId.Value != 0)
else
{
_notify.Publish(new TariffCacheItem { TenantId = tenantId, TariffId = tariffId.Value }, CacheNotifyAction.Insert);
tariff = CalculateTariff(tenantId, tariff);
}
return tariff;
void UpdateCache(int tariffId)
{
_notify.Publish(new TariffCacheItem { TenantId = tenantId, TariffId = tariffId }, CacheNotifyAction.Insert);
}
}
public async Task<bool> PaymentChange(int tenantId, Dictionary<string, int> quantity)
@ -430,6 +447,27 @@ public class TariffService : ITariffService
public async Task<Uri> GetShoppingUri(int tenant, string currency = null, string language = null, string customerEmail = null, Dictionary<string, int> quantity = null, string backUrl = null)
{
List<TenantQuota> newQuotas = new();
if (_billingClient.Configured)
{
var allQuotas = _quotaService.GetTenantQuotas().Where(q => !string.IsNullOrEmpty(q.ProductId) && q.Visible).ToList();
newQuotas = quantity.Select(item => allQuotas.FirstOrDefault(q => q.Name == item.Key)).ToList();
TenantQuota updatedQuota = null;
foreach (var addedQuota in newQuotas)
{
var qty = quantity[addedQuota.Name];
var quota = addedQuota;
quota *= qty;
updatedQuota += quota;
}
await updatedQuota.Check(_serviceProvider);
}
var hasQuantity = quantity != null && quantity.Any();
var key = "shopingurl_" + (hasQuantity ? string.Join('_', quantity.Keys.ToArray()) : "all");
var url = _cache.Get<string>(key);
@ -438,22 +476,6 @@ public class TariffService : ITariffService
url = string.Empty;
if (_billingClient.Configured)
{
var allQuotas = _quotaService.GetTenantQuotas().Where(q => !string.IsNullOrEmpty(q.ProductId) && q.Visible);
var newQuotas = quantity.Select(item => allQuotas.FirstOrDefault(q => q.Name == item.Key));
TenantQuota updatedQuota = null;
foreach (var addedQuota in newQuotas)
{
var qty = quantity[addedQuota.Name];
var quota = addedQuota;
quota *= qty;
updatedQuota += quota;
}
await updatedQuota.Check(_serviceProvider);
var productIds = newQuotas.Select(q => q.ProductId);
try
@ -682,6 +704,7 @@ public class TariffService : ITariffService
}
var tariff = CreateDefault(true);
tariff.Id = r.Id;
tariff.DueDate = r.Stamp.Year < 9999 ? r.Stamp : DateTime.MaxValue;
tariff.CustomerId = r.CustomerId;
@ -727,6 +750,7 @@ public class TariffService : ITariffService
if (efTariff.Id == default)
{
efTariff.Id = (-tenant);
tariffInfo.Id = efTariff.Id;
}
if (efTariff.CustomerId == default)
@ -769,8 +793,9 @@ public class TariffService : ITariffService
// update tenant.LastModified to flush cache in documents
_tenantService.SaveTenant(_coreSettings, t);
}
ClearCache(tenant);
NotifyWebSocket(currentTariff, tariffInfo);
}
return inserted;
@ -941,6 +966,57 @@ public class TariffService : ITariffService
}
}
private void NotifyWebSocket(Tariff currenTariff, Tariff newTariff)
{
var quotaSocketManager = _serviceProvider.GetRequiredService<QuotaSocketManager>();
var updatedQuota = GetTenantQuotaFromTariff(newTariff);
var maxTotalSize = updatedQuota.MaxTotalSize;
var maxTotalSizeFeatureName = updatedQuota.GetFeature<MaxTotalSizeFeature>().Name;
_ = quotaSocketManager.ChangeQuotaFeatureValue(maxTotalSizeFeatureName, maxTotalSize);
var maxPaidUsers = updatedQuota.CountRoomAdmin;
var maxPaidUsersFeatureName = updatedQuota.GetFeature<CountPaidUserFeature>().Name;
_ = quotaSocketManager.ChangeQuotaFeatureValue(maxPaidUsersFeatureName, maxPaidUsers);
var maxRoomCount = updatedQuota.CountRoom == int.MaxValue ? -1 : updatedQuota.CountRoom;
var maxRoomCountFeatureName = updatedQuota.GetFeature<CountRoomFeature>().Name;
_ = quotaSocketManager.ChangeQuotaFeatureValue(maxRoomCountFeatureName, maxRoomCount);
if (currenTariff != null)
{
var currentQuota = GetTenantQuotaFromTariff(currenTariff);
var free = updatedQuota.Free;
if (currentQuota.Free != free)
{
var freeFeatureName = updatedQuota.GetFeature<FreeFeature>().Name;
_ = quotaSocketManager.ChangeQuotaFeatureValue(freeFeatureName, free);
}
}
}
private TenantQuota GetTenantQuotaFromTariff(Tariff tariff)
{
TenantQuota result = null;
foreach (var tariffRow in tariff.Quotas)
{
var qty = tariffRow.Quantity;
var quota = _quotaService.GetTenantQuota(tariffRow.Id);
quota *= qty;
result += quota;
}
return result;
}
public int GetPaymentDelay()
{
return _paymentDelay;

View File

@ -271,6 +271,7 @@ public class CachedUserService : IUserService, ICachedService
{
Service.SetUserPhoto(tenant, id, photo);
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, CacheNotifyAction.Remove);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Id = id.ToString(), Tenant = tenant }, CacheNotifyAction.Any);
}
public DateTime GetUserPasswordStamp(int tenant, Guid id)

View File

@ -45,7 +45,7 @@ public class TenantManager
internal CoreBaseSettings CoreBaseSettings { get; set; }
internal CoreSettings CoreSettings { get; set; }
private readonly static object _lock = new object();
private static readonly object _lock = new object();
static TenantManager()
{
@ -283,17 +283,17 @@ public class TenantManager
return QuotaService.GetTenantQuotas().Where(q => q.Tenant < 0 && (all || q.Visible)).OrderByDescending(q => q.Tenant).ToList();
}
public TenantQuota GetCurrentTenantQuota()
public TenantQuota GetCurrentTenantQuota(bool refresh = false)
{
return GetTenantQuota(GetCurrentTenant().Id);
return GetTenantQuota(GetCurrentTenant().Id, refresh);
}
public TenantQuota GetTenantQuota(int tenant)
public TenantQuota GetTenantQuota(int tenant, bool refresh = false)
{
var defaultQuota = QuotaService.GetTenantQuota(tenant) ?? QuotaService.GetTenantQuota(Tenant.DefaultTenant) ?? TenantQuota.Default;
if (defaultQuota.Tenant != tenant && TariffService != null)
{
var tariff = TariffService.GetTariff(tenant);
var tariff = TariffService.GetTariff(tenant, refresh: refresh);
TenantQuota currentQuota = null;
foreach (var tariffRow in tariff.Quotas)

View File

@ -65,9 +65,9 @@ public class UserManager
private readonly TenantQuotaFeatureCheckerCount<CountUserFeature> _activeUsersFeatureChecker;
private readonly Constants _constants;
private readonly UserFormatter _userFormatter;
private Tenant _tenant;
private Tenant Tenant => _tenant ??= _tenantManager.GetCurrentTenant();
private readonly QuotaSocketManager _quotaSocketManager;
private readonly TenantQuotaFeatureStatHelper _tenantQuotaFeatureStatHelper;
private Tenant Tenant => _tenantManager.GetCurrentTenant();
public UserManager()
{
@ -88,7 +88,9 @@ public class UserManager
ICache cache,
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> countPaidUserChecker,
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
UserFormatter userFormatter
UserFormatter userFormatter,
QuotaSocketManager quotaSocketManager,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper
)
{
_userService = service;
@ -106,6 +108,8 @@ public class UserManager
_activeUsersFeatureChecker = activeUsersFeatureChecker;
_constants = _userManagerConstants.Constants;
_userFormatter = userFormatter;
_quotaSocketManager = quotaSocketManager;
_tenantQuotaFeatureStatHelper = tenantQuotaFeatureStatHelper;
}
public UserManager(
@ -123,8 +127,10 @@ public class UserManager
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> tenantQuotaFeatureChecker,
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
IHttpContextAccessor httpContextAccessor,
UserFormatter userFormatter)
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings, coreSettings, instanceCrypto, radicaleClient, cardDavAddressbook, log, cache, tenantQuotaFeatureChecker, activeUsersFeatureChecker, userFormatter)
UserFormatter userFormatter,
QuotaSocketManager quotaSocketManager,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper)
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings, coreSettings, instanceCrypto, radicaleClient, cardDavAddressbook, log, cache, tenantQuotaFeatureChecker, activeUsersFeatureChecker, userFormatter, quotaSocketManager, tenantQuotaFeatureStatHelper)
{
_accessor = httpContextAccessor;
}
@ -322,7 +328,7 @@ public class UserManager
return findUsers.ToArray();
}
public UserInfo UpdateUserInfo(UserInfo u)
public async Task<UserInfo> UpdateUserInfo(UserInfo u)
{
if (IsSystemUser(u.Id))
{
@ -343,15 +349,31 @@ public class UserManager
throw new InvalidOperationException("User not found.");
}
return _userService.SaveUser(_tenantManager.GetCurrentTenant().Id, u);
var (name, value) = ("", -1);
if (!IsUserInGroup(oldUserData.Id, Constants.GroupUser.ID) &&
oldUserData.Status != u.Status)
{
(name, value) = await _tenantQuotaFeatureStatHelper.GetStat<CountPaidUserFeature, int>();
value = oldUserData.Status > u.Status ? ++value : --value;//crutch: data race
}
var newUserData = _userService.SaveUser(_tenantManager.GetCurrentTenant().Id, u);
if (value > 0)
{
_ = _quotaSocketManager.ChangeQuotaUsedValue(name, value);
}
return newUserData;
}
public async Task<UserInfo> UpdateUserInfoWithSyncCardDavAsync(UserInfo u)
{
var oldUserData = _userService.GetUserByUserName(_tenantManager.GetCurrentTenant().Id, u.UserName);
var newUser = UpdateUserInfo(u);
var newUser = await UpdateUserInfo(u);
if (_coreBaseSettings.DisableDocSpace)
{
await SyncCardDavAsync(u, oldUserData, newUser);
@ -644,7 +666,7 @@ public class UserManager
return GetUsers(employeeStatus).Where(u => IsUserInGroupInternal(u.Id, groupId, refs)).ToArray();
}
public async Task AddUserIntoGroup(Guid userId, Guid groupId, bool dontClearAddressBook = false)
public async Task AddUserIntoGroup(Guid userId, Guid groupId, bool dontClearAddressBook = false, bool notifyWebSocket = true)
{
if (Constants.LostUser.Id == userId || Constants.LostGroupInfo.ID == groupId)
{
@ -652,6 +674,8 @@ public class UserManager
}
var user = GetUsers(userId);
var isUser = this.IsUser(user);
var isPaidUser = IsPaidUser(user);
_permissionContext.DemandPermissions(new UserGroupObject(new UserAccount(user, _tenantManager.GetCurrentTenant().Id, _userFormatter), groupId),
Constants.Action_EditGroups);
@ -659,6 +683,7 @@ public class UserManager
_userService.SaveUserGroupRef(Tenant.Id, new UserGroupRef(userId, groupId, UserGroupRefType.Contains));
ResetGroupCache(userId);
if (groupId == Constants.GroupUser.ID)
{
var tenant = _tenantManager.GetCurrentTenant();
@ -671,9 +696,21 @@ public class UserManager
await _cardDavAddressbook.Delete(myUri, user.Id, user.Email, tenant.Id);
}
}
if (!notifyWebSocket)
{
return;
}
if (isUser && groupId != Constants.GroupUser.ID ||
!isUser && !isPaidUser && groupId != Constants.GroupUser.ID)
{
var (name, value) = await _tenantQuotaFeatureStatHelper.GetStat<CountPaidUserFeature, int>();
_ = _quotaSocketManager.ChangeQuotaUsedValue(name, value);
}
}
public void RemoveUserFromGroup(Guid userId, Guid groupId)
public async Task RemoveUserFromGroup(Guid userId, Guid groupId)
{
if (Constants.LostUser.Id == userId || Constants.LostGroupInfo.ID == groupId)
{
@ -681,6 +718,8 @@ public class UserManager
}
var user = GetUsers(userId);
var isUserBefore = this.IsUser(user);
var isPaidUserBefore = IsPaidUser(user);
_permissionContext.DemandPermissions(new UserGroupObject(new UserAccount(user, _tenantManager.GetCurrentTenant().Id, _userFormatter), groupId),
Constants.Action_EditGroups);
@ -688,6 +727,16 @@ public class UserManager
_userService.RemoveUserGroupRef(Tenant.Id, userId, groupId, UserGroupRefType.Contains);
ResetGroupCache(userId);
var isUserAfter = this.IsUser(user);
var isPaidUserAfter = IsPaidUser(user);
if (isPaidUserBefore && !isPaidUserAfter && isUserAfter ||
isUserBefore && !isUserAfter)
{
var (name, value) = await _tenantQuotaFeatureStatHelper.GetStat<CountPaidUserFeature, int>();
_ = _quotaSocketManager.ChangeQuotaUsedValue(name, value);
}
}
internal void ResetGroupCache(Guid userID)
@ -904,7 +953,7 @@ public class UserManager
{
return isCollaborator;
}
if (groupId == Constants.GroupManager.ID)
{
return !isUser && !isCollaborator;
@ -930,4 +979,9 @@ public class UserManager
Sid = g.Sid
};
}
private bool IsPaidUser(UserInfo userInfo)
{
return this.IsCollaborator(userInfo) || this.IsDocSpaceAdmin(userInfo);
}
}

View File

@ -123,7 +123,7 @@ public class WorkContext
INotifySender emailSender = _notifyServiceSender;
INotifySender telegramSender = _telegramSender;
INotifySender pushSender = _pushSender;
var postman = _configuration["core:notify:postman"];
@ -161,6 +161,11 @@ public class WorkContext
}
}
public void RegisterSendMethod(Func<DateTime, Task> method, string cron)
{
NotifyEngine.RegisterSendMethod(method, cron);
}
public void RegisterSendMethod(Action<DateTime> method, string cron)
{
NotifyEngine.RegisterSendMethod(method, cron);

View File

@ -24,6 +24,10 @@
// 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 ASC.Core.Common.EF;
using Microsoft.EntityFrameworkCore;
namespace ASC.Core.Data;
[Scope]
@ -227,7 +231,7 @@ public class EFUserService : IUserService
if (sortBy == "type")
{
var q1 = from user in q
join userGroup in userDbContext.UserGroups.Where(g => !g.Removed && (g.UserGroupId == Users.Constants.GroupAdmin.ID || g.UserGroupId == Users.Constants.GroupUser.ID
join userGroup in userDbContext.UserGroups.Where(g => !g.Removed && (g.UserGroupId == Users.Constants.GroupAdmin.ID || g.UserGroupId == Users.Constants.GroupUser.ID
|| g.UserGroupId == Users.Constants.GroupCollaborator.ID))
on user.Id equals userGroup.Userid into joinedGroup
from @group in joinedGroup.DefaultIfEmpty()
@ -317,8 +321,8 @@ public class EFUserService : IUserService
if (immediate)
{
await userGroups.ExecuteDeleteAsync();
await groups.ExecuteDeleteAsync();
await userGroups.ExecuteDeleteAsync();
await groups.ExecuteDeleteAsync();
}
else
{
@ -372,15 +376,15 @@ public class EFUserService : IUserService
.SetProperty(p => p.Removed, true)
.SetProperty(p => p.LastModified, DateTime.UtcNow));
await users.ExecuteUpdateAsync(ug => ug
.SetProperty(p => p.Removed, true)
.SetProperty(p => p.LastModified, DateTime.UtcNow)
.SetProperty(p => p.TerminatedDate, DateTime.UtcNow)
.SetProperty(p => p.Status, EmployeeStatus.Terminated)
);
await users.ExecuteUpdateAsync(ug => ug
.SetProperty(p => p.Removed, true)
.SetProperty(p => p.LastModified, DateTime.UtcNow)
.SetProperty(p => p.TerminatedDate, DateTime.UtcNow)
.SetProperty(p => p.Status, EmployeeStatus.Terminated)
);
}
await tr.CommitAsync();
await tr.CommitAsync();
}).GetAwaiter()
.GetResult();
}
@ -403,7 +407,7 @@ public class EFUserService : IUserService
var userGroups = userDbContext.UserGroups.Where(r => r.Tenant == tenant && r.Userid == userId && r.UserGroupId == groupId && r.RefType == refType);
if (immediate)
{
await userGroups.ExecuteDeleteAsync();
await userGroups.ExecuteDeleteAsync();
}
else
{
@ -517,7 +521,7 @@ public class EFUserService : IUserService
if (user != null)
{
user.LastModified = userGroupRef.LastModified;
await userDbContext.AddOrUpdateAsync(r => userDbContext.UserGroups, _mapper.Map<UserGroupRef, UserGroup>(userGroupRef));
await userDbContext.AddOrUpdateAsync(r => userDbContext.UserGroups, _mapper.Map<UserGroupRef, UserGroup>(userGroupRef));
}
await userDbContext.SaveChangesAsync();
@ -548,42 +552,45 @@ public class EFUserService : IUserService
public void SetUserPhoto(int tenant, Guid id, byte[] photo)
{
using var userDbContext = _dbContextFactory.CreateDbContext();
var strategy = userDbContext.Database.CreateExecutionStrategy();
strategy.Execute(async () =>
var userPhoto = userDbContext.Photos.FirstOrDefault(r => r.UserId == id && r.Tenant == tenant);
if (photo != null && photo.Length != 0)
{
using var userDbContext = _dbContextFactory.CreateDbContext();
using var tr = await userDbContext.Database.BeginTransactionAsync();
var userPhoto = await userDbContext.Photos.FirstOrDefaultAsync(r => r.UserId == id && r.Tenant == tenant);
if (photo != null && photo.Length != 0)
if (userPhoto == null)
{
if (userPhoto == null)
userPhoto = new UserPhoto
{
userPhoto = new UserPhoto
{
Tenant = tenant,
UserId = id,
Photo = photo
};
}
else
{
userPhoto.Photo = photo;
}
await userDbContext.AddOrUpdateAsync(r => userDbContext.Photos, userPhoto);
Tenant = tenant,
UserId = id,
Photo = photo
};
}
else if (userPhoto != null)
else
{
userDbContext.Photos.Remove(userPhoto);
userPhoto.Photo = photo;
}
await userDbContext.SaveChangesAsync();
await tr.CommitAsync();
}).GetAwaiter()
.GetResult();
userDbContext.AddOrUpdate(userDbContext.Photos, userPhoto);
var userEntity = new User
{
Id = id,
LastModified = DateTime.UtcNow,
Tenant = tenant
};
userDbContext.Users.Attach(userEntity);
userDbContext.Entry(userEntity).Property(x => x.LastModified).IsModified = true;
}
else if (userPhoto != null)
{
userDbContext.Photos.Remove(userPhoto);
}
userDbContext.SaveChanges();
}
private IQueryable<User> GetUserQuery(UserDbContext userDbContext, int tenant)

View File

@ -39,7 +39,7 @@ public static class FilesConvertsExtension
modelBuilder
.Add(MySqlAddFilesConverts, Provider.MySql)
.Add(PgSqlAddFilesConverts, Provider.PostgreSql)
.HasData(
.HasData(
new FilesConverts { Input = ".csv", Output = ".ods" },
new FilesConverts { Input = ".csv", Output = ".pdf" },
new FilesConverts { Input = ".csv", Output = ".ots" },
@ -47,6 +47,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".csv", Output = ".xlsm" },
new FilesConverts { Input = ".csv", Output = ".xltm" },
new FilesConverts { Input = ".csv", Output = ".xltx" },
new FilesConverts { Input = ".doc", Output = ".docx" },
new FilesConverts { Input = ".doc", Output = ".docm" },
new FilesConverts { Input = ".doc", Output = ".dotm" },
@ -59,6 +60,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".doc", Output = ".pdf" },
new FilesConverts { Input = ".doc", Output = ".rtf" },
new FilesConverts { Input = ".doc", Output = ".txt" },
new FilesConverts { Input = ".docm", Output = ".docx" },
new FilesConverts { Input = ".docm", Output = ".dotm" },
new FilesConverts { Input = ".docm", Output = ".html" },
@ -70,6 +72,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".docm", Output = ".pdf" },
new FilesConverts { Input = ".docm", Output = ".rtf" },
new FilesConverts { Input = ".docm", Output = ".txt" },
new FilesConverts { Input = ".doct", Output = ".docx" },
new FilesConverts { Input = ".docx", Output = ".odt" },
new FilesConverts { Input = ".docx", Output = ".pdf" },
@ -82,9 +85,11 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".docx", Output = ".fb2" },
new FilesConverts { Input = ".docx", Output = ".ott" },
new FilesConverts { Input = ".docx", Output = ".docm" },
new FilesConverts { Input = ".docx", Output = ".docxf" },
new FilesConverts { Input = ".docxf", Output = ".docm" },
new FilesConverts { Input = ".docxf", Output = ".docx" },
new FilesConverts { Input = ".docxf", Output = ".dotm" },
new FilesConverts { Input = ".docxf", Output = ".odt" },
new FilesConverts { Input = ".docxf", Output = ".oform" },
new FilesConverts { Input = ".docxf", Output = ".pdf" },
@ -108,6 +113,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".dot", Output = ".fb2" },
new FilesConverts { Input = ".dot", Output = ".html" },
new FilesConverts { Input = ".dot", Output = ".ott" },
new FilesConverts { Input = ".dotm", Output = ".docx" },
new FilesConverts { Input = ".dotm", Output = ".odt" },
new FilesConverts { Input = ".dotm", Output = ".pdf" },
@ -119,6 +125,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".dotm", Output = ".fb2" },
new FilesConverts { Input = ".dotm", Output = ".html" },
new FilesConverts { Input = ".dotm", Output = ".ott" },
new FilesConverts { Input = ".dotx", Output = ".docx" },
new FilesConverts { Input = ".dotx", Output = ".odt" },
new FilesConverts { Input = ".dotx", Output = ".pdf" },
@ -130,6 +137,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".dotx", Output = ".fb2" },
new FilesConverts { Input = ".dotx", Output = ".html" },
new FilesConverts { Input = ".dotx", Output = ".ott" },
new FilesConverts { Input = ".epub", Output = ".docx" },
new FilesConverts { Input = ".epub", Output = ".odt" },
new FilesConverts { Input = ".epub", Output = ".pdf" },
@ -141,6 +149,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".epub", Output = ".fb2" },
new FilesConverts { Input = ".epub", Output = ".html" },
new FilesConverts { Input = ".epub", Output = ".ott" },
new FilesConverts { Input = ".fb2", Output = ".docx" },
new FilesConverts { Input = ".fb2", Output = ".odt" },
new FilesConverts { Input = ".fb2", Output = ".pdf" },
@ -152,12 +161,15 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".fb2", Output = ".epub" },
new FilesConverts { Input = ".fb2", Output = ".html" },
new FilesConverts { Input = ".fb2", Output = ".ott" },
new FilesConverts { Input = ".fodp", Output = ".odp" },
new FilesConverts { Input = ".fodp", Output = ".pdf" },
new FilesConverts { Input = ".fodp", Output = ".pptx" },
new FilesConverts { Input = ".fodp", Output = ".otp" },
new FilesConverts { Input = ".fodp", Output = ".potm" },
new FilesConverts { Input = ".fodp", Output = ".potx" },
new FilesConverts { Input = ".fodp", Output = ".ppsm" },
new FilesConverts { Input = ".fodp", Output = ".ppsx" },
new FilesConverts { Input = ".fodp", Output = ".pptm" },
new FilesConverts { Input = ".fods", Output = ".csv" },
new FilesConverts { Input = ".fods", Output = ".ods" },
@ -179,6 +191,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".fodt", Output = ".fb2" },
new FilesConverts { Input = ".fodt", Output = ".html" },
new FilesConverts { Input = ".fodt", Output = ".ott" },
new FilesConverts { Input = ".html", Output = ".docx" },
new FilesConverts { Input = ".html", Output = ".odt" },
new FilesConverts { Input = ".html", Output = ".pdf" },
@ -190,6 +203,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".html", Output = ".epub" },
new FilesConverts { Input = ".html", Output = ".fb2" },
new FilesConverts { Input = ".html", Output = ".ott" },
new FilesConverts { Input = ".mht", Output = ".docx" },
new FilesConverts { Input = ".mht", Output = ".odt" },
new FilesConverts { Input = ".mht", Output = ".pdf" },
@ -201,18 +215,25 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".mht", Output = ".epub" },
new FilesConverts { Input = ".mht", Output = ".fb2" },
new FilesConverts { Input = ".mht", Output = ".ott" },
new FilesConverts { Input = ".odp", Output = ".pdf" },
new FilesConverts { Input = ".odp", Output = ".pptx" },
new FilesConverts { Input = ".odp", Output = ".otp" },
new FilesConverts { Input = ".odp", Output = ".potm" },
new FilesConverts { Input = ".odp", Output = ".potx" },
new FilesConverts { Input = ".odp", Output = ".ppsm" },
new FilesConverts { Input = ".odp", Output = ".ppsx" },
new FilesConverts { Input = ".odp", Output = ".pptm" },
new FilesConverts { Input = ".otp", Output = ".odp" },
new FilesConverts { Input = ".otp", Output = ".pdf" },
new FilesConverts { Input = ".otp", Output = ".potm" },
new FilesConverts { Input = ".otp", Output = ".potx" },
new FilesConverts { Input = ".otp", Output = ".pptm" },
new FilesConverts { Input = ".otp", Output = ".ppsm" },
new FilesConverts { Input = ".otp", Output = ".ppsx" },
new FilesConverts { Input = ".otp", Output = ".pptx" },
new FilesConverts { Input = ".ods", Output = ".csv" },
new FilesConverts { Input = ".ods", Output = ".pdf" },
new FilesConverts { Input = ".ods", Output = ".xlsx" },
@ -220,6 +241,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".ods", Output = ".xlsm" },
new FilesConverts { Input = ".ods", Output = ".xltm" },
new FilesConverts { Input = ".ods", Output = ".xltx" },
new FilesConverts { Input = ".ots", Output = ".csv" },
new FilesConverts { Input = ".ots", Output = ".ods" },
new FilesConverts { Input = ".ots", Output = ".pdf" },
@ -227,7 +249,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".ots", Output = ".xltm" },
new FilesConverts { Input = ".ots", Output = ".xltx" },
new FilesConverts { Input = ".ots", Output = ".xlsx" },
new FilesConverts { Input = ".oxps", Output = ".pdf" },
new FilesConverts { Input = ".odt", Output = ".docx" },
new FilesConverts { Input = ".odt", Output = ".pdf" },
new FilesConverts { Input = ".odt", Output = ".rtf" },
@ -239,6 +261,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".odt", Output = ".fb2" },
new FilesConverts { Input = ".odt", Output = ".html" },
new FilesConverts { Input = ".odt", Output = ".ott" },
new FilesConverts { Input = ".ott", Output = ".docx" },
new FilesConverts { Input = ".ott", Output = ".odt" },
new FilesConverts { Input = ".ott", Output = ".pdf" },
@ -250,6 +273,32 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".ott", Output = ".epub" },
new FilesConverts { Input = ".ott", Output = ".fb2" },
new FilesConverts { Input = ".ott", Output = ".html" },
new FilesConverts { Input = ".oxps", Output = ".docm" },
new FilesConverts { Input = ".oxps", Output = ".docx" },
new FilesConverts { Input = ".oxps", Output = ".dotm" },
new FilesConverts { Input = ".oxps", Output = ".dotx" },
new FilesConverts { Input = ".oxps", Output = ".epub" },
new FilesConverts { Input = ".oxps", Output = ".fb2" },
new FilesConverts { Input = ".oxps", Output = ".html" },
new FilesConverts { Input = ".oxps", Output = ".odt" },
new FilesConverts { Input = ".oxps", Output = ".ott" },
new FilesConverts { Input = ".oxps", Output = ".pdf" },
new FilesConverts { Input = ".oxps", Output = ".rtf" },
new FilesConverts { Input = ".oxps", Output = ".txt" },
new FilesConverts { Input = ".pdf", Output = ".docm" },
new FilesConverts { Input = ".pdf", Output = ".docx" },
new FilesConverts { Input = ".pdf", Output = ".dotm" },
new FilesConverts { Input = ".pdf", Output = ".dotx" },
new FilesConverts { Input = ".pdf", Output = ".epub" },
new FilesConverts { Input = ".pdf", Output = ".fb2" },
new FilesConverts { Input = ".pdf", Output = ".html" },
new FilesConverts { Input = ".pdf", Output = ".odt" },
new FilesConverts { Input = ".pdf", Output = ".ott" },
new FilesConverts { Input = ".pdf", Output = ".rtf" },
new FilesConverts { Input = ".pdf", Output = ".txt" },
new FilesConverts { Input = ".pot", Output = ".odp" },
new FilesConverts { Input = ".pot", Output = ".pdf" },
new FilesConverts { Input = ".pot", Output = ".pptx" },
@ -257,18 +306,28 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".pot", Output = ".potm" },
new FilesConverts { Input = ".pot", Output = ".potx" },
new FilesConverts { Input = ".pot", Output = ".pptm" },
new FilesConverts { Input = ".pot", Output = ".ppsm" },
new FilesConverts { Input = ".pot", Output = ".ppsx" },
new FilesConverts { Input = ".potm", Output = ".odp" },
new FilesConverts { Input = ".potm", Output = ".pdf" },
new FilesConverts { Input = ".potm", Output = ".pptx" },
new FilesConverts { Input = ".potm", Output = ".otp" },
new FilesConverts { Input = ".potm", Output = ".potx" },
new FilesConverts { Input = ".potm", Output = ".pptm" },
new FilesConverts { Input = ".potm", Output = ".ppsm" },
new FilesConverts { Input = ".potm", Output = ".ppsx" },
new FilesConverts { Input = ".potx", Output = ".odp" },
new FilesConverts { Input = ".potx", Output = ".pdf" },
new FilesConverts { Input = ".potx", Output = ".pptx" },
new FilesConverts { Input = ".potx", Output = ".otp" },
new FilesConverts { Input = ".potx", Output = ".potm" },
new FilesConverts { Input = ".potx", Output = ".pptm" },
new FilesConverts { Input = ".potx", Output = ".ppsm" },
new FilesConverts { Input = ".potx", Output = ".ppsx" },
new FilesConverts { Input = ".pps", Output = ".odp" },
new FilesConverts { Input = ".pps", Output = ".pdf" },
new FilesConverts { Input = ".pps", Output = ".pptx" },
@ -276,6 +335,9 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".pps", Output = ".potm" },
new FilesConverts { Input = ".pps", Output = ".potx" },
new FilesConverts { Input = ".pps", Output = ".pptm" },
new FilesConverts { Input = ".pps", Output = ".ppsm" },
new FilesConverts { Input = ".pps", Output = ".ppsx" },
new FilesConverts { Input = ".ppsm", Output = ".odp" },
new FilesConverts { Input = ".ppsm", Output = ".pdf" },
new FilesConverts { Input = ".ppsm", Output = ".pptx" },
@ -283,13 +345,17 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".ppsm", Output = ".potm" },
new FilesConverts { Input = ".ppsm", Output = ".potx" },
new FilesConverts { Input = ".ppsm", Output = ".pptm" },
new FilesConverts { Input = ".ppsm", Output = ".ppsx" },
new FilesConverts { Input = ".ppsx", Output = ".odp" },
new FilesConverts { Input = ".ppsx", Output = ".pdf" },
new FilesConverts { Input = ".ppsx", Output = ".pptx" },
new FilesConverts { Input = ".ppsx", Output = ".otp" },
new FilesConverts { Input = ".ppsx", Output = ".potm" },
new FilesConverts { Input = ".ppsx", Output = ".potx" },
new FilesConverts { Input = ".ppsx", Output = ".ppsm" },
new FilesConverts { Input = ".ppsx", Output = ".pptm" },
new FilesConverts { Input = ".ppt", Output = ".odp" },
new FilesConverts { Input = ".ppt", Output = ".pdf" },
new FilesConverts { Input = ".ppt", Output = ".pptx" },
@ -297,12 +363,18 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".ppt", Output = ".potm" },
new FilesConverts { Input = ".ppt", Output = ".potx" },
new FilesConverts { Input = ".ppt", Output = ".pptm" },
new FilesConverts { Input = ".ppt", Output = ".ppsm" },
new FilesConverts { Input = ".ppt", Output = ".ppsx" },
new FilesConverts { Input = ".pptm", Output = ".odp" },
new FilesConverts { Input = ".pptm", Output = ".pdf" },
new FilesConverts { Input = ".pptm", Output = ".pptx" },
new FilesConverts { Input = ".pptm", Output = ".otp" },
new FilesConverts { Input = ".pptm", Output = ".potm" },
new FilesConverts { Input = ".pptm", Output = ".potx" },
new FilesConverts { Input = ".pptm", Output = ".ppsm" },
new FilesConverts { Input = ".pptm", Output = ".ppsx" },
new FilesConverts { Input = ".pptt", Output = ".pptx" },
new FilesConverts { Input = ".pptx", Output = ".odp" },
new FilesConverts { Input = ".pptx", Output = ".pdf" },
@ -310,6 +382,9 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".pptx", Output = ".potm" },
new FilesConverts { Input = ".pptx", Output = ".potx" },
new FilesConverts { Input = ".pptx", Output = ".pptm" },
new FilesConverts { Input = ".pptx", Output = ".ppsm" },
new FilesConverts { Input = ".pptx", Output = ".ppsx" },
new FilesConverts { Input = ".rtf", Output = ".odt" },
new FilesConverts { Input = ".rtf", Output = ".pdf" },
new FilesConverts { Input = ".rtf", Output = ".docx" },
@ -321,6 +396,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".rtf", Output = ".fb2" },
new FilesConverts { Input = ".rtf", Output = ".html" },
new FilesConverts { Input = ".rtf", Output = ".ott" },
new FilesConverts { Input = ".txt", Output = ".pdf" },
new FilesConverts { Input = ".txt", Output = ".docx" },
new FilesConverts { Input = ".txt", Output = ".odt" },
@ -332,6 +408,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".txt", Output = ".fb2" },
new FilesConverts { Input = ".txt", Output = ".html" },
new FilesConverts { Input = ".txt", Output = ".ott" },
new FilesConverts { Input = ".xls", Output = ".csv" },
new FilesConverts { Input = ".xls", Output = ".ods" },
new FilesConverts { Input = ".xls", Output = ".pdf" },
@ -340,6 +417,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".xls", Output = ".xlsm" },
new FilesConverts { Input = ".xls", Output = ".xltm" },
new FilesConverts { Input = ".xls", Output = ".xltx" },
new FilesConverts { Input = ".xlsm", Output = ".csv" },
new FilesConverts { Input = ".xlsm", Output = ".xltm" },
new FilesConverts { Input = ".xlsm", Output = ".xltx" },
@ -347,6 +425,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".xlsm", Output = ".pdf" },
new FilesConverts { Input = ".xlsm", Output = ".ods" },
new FilesConverts { Input = ".xlsm", Output = ".xlsx" },
new FilesConverts { Input = ".xlsx", Output = ".csv" },
new FilesConverts { Input = ".xlsx", Output = ".ods" },
new FilesConverts { Input = ".xlsx", Output = ".ots" },
@ -355,6 +434,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".xlsx", Output = ".xltm" },
new FilesConverts { Input = ".xlsx", Output = ".xltx" },
new FilesConverts { Input = ".xlst", Output = ".xlsx" },
new FilesConverts { Input = ".xlt", Output = ".csv" },
new FilesConverts { Input = ".xlt", Output = ".ods" },
new FilesConverts { Input = ".xlt", Output = ".pdf" },
@ -363,6 +443,7 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".xlt", Output = ".xlsm" },
new FilesConverts { Input = ".xlt", Output = ".xltm" },
new FilesConverts { Input = ".xlt", Output = ".xltx" },
new FilesConverts { Input = ".xltm", Output = ".csv" },
new FilesConverts { Input = ".xltm", Output = ".ods" },
new FilesConverts { Input = ".xltm", Output = ".pdf" },
@ -377,7 +458,6 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".xltx", Output = ".xlsm" },
new FilesConverts { Input = ".xltx", Output = ".xltm" },
new FilesConverts { Input = ".xltx", Output = ".xlsx" },
new FilesConverts { Input = ".xps", Output = ".pdf" },
new FilesConverts { Input = ".xml", Output = ".docm" },
new FilesConverts { Input = ".xml", Output = ".docx" },
new FilesConverts { Input = ".xml", Output = ".dotm" },
@ -389,7 +469,20 @@ public static class FilesConvertsExtension
new FilesConverts { Input = ".xml", Output = ".ott" },
new FilesConverts { Input = ".xml", Output = ".pdf" },
new FilesConverts { Input = ".xml", Output = ".rtf" },
new FilesConverts { Input = ".xml", Output = ".txt" }
new FilesConverts { Input = ".xml", Output = ".txt" },
new FilesConverts { Input = ".xps", Output = ".docm" },
new FilesConverts { Input = ".xps", Output = ".docx" },
new FilesConverts { Input = ".xps", Output = ".dotm" },
new FilesConverts { Input = ".xps", Output = ".dotx" },
new FilesConverts { Input = ".xps", Output = ".epub" },
new FilesConverts { Input = ".xps", Output = ".fb2" },
new FilesConverts { Input = ".xps", Output = ".html" },
new FilesConverts { Input = ".xps", Output = ".odt" },
new FilesConverts { Input = ".xps", Output = ".ott" },
new FilesConverts { Input = ".xps", Output = ".pdf" },
new FilesConverts { Input = ".xps", Output = ".rtf" },
new FilesConverts { Input = ".xps", Output = ".txt" }
);
return modelBuilder;

View File

@ -59,7 +59,7 @@ public static class DbQuotaExtension
Tenant = -1,
Name = "trial",
Description = null,
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1",
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,oauth,total_size:107374182400,file_size:100,manager:1",
Price = 0,
ProductId = null,
Visible = false
@ -69,7 +69,7 @@ public static class DbQuotaExtension
Tenant = -2,
Name = "admin",
Description = null,
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,oauth,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Price = 30,
ProductId = "1002",
Visible = true
@ -79,7 +79,7 @@ public static class DbQuotaExtension
Tenant = -3,
Name = "startup",
Description = null,
Features = "free,total_size:2147483648,manager:5,room:5",
Features = "free,total_size:2147483648,manager:3,room:12",
Price = 0,
ProductId = null,
Visible = false

View File

@ -29,16 +29,16 @@ namespace ASC.Geolocation;
[Scope]
public class GeolocationHelper
{
private readonly IDbContextFactory<CustomDbContext> _dbContextFactory;
private readonly CreatorDbContext _creatorDbContext;
private readonly ILogger<GeolocationHelper> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
public GeolocationHelper(
IDbContextFactory<CustomDbContext> dbContextFactory,
CreatorDbContext creatorDbContext,
ILogger<GeolocationHelper> logger,
IHttpContextAccessor httpContextAccessor)
{
_dbContextFactory = dbContextFactory;
_creatorDbContext = creatorDbContext;
_logger = logger;
_httpContextAccessor = httpContextAccessor;
}
@ -47,7 +47,7 @@ public class GeolocationHelper
{
try
{
using var dbContext = _dbContextFactory.CreateDbContext();
using var dbContext = _creatorDbContext.CreateDbContext<CustomDbContext>(nameConnectionString: "teamlabsite");
var ipformatted = FormatIP(ip);
var q = dbContext.DbipLocation
.Where(r => r.IPStart.CompareTo(ipformatted) <= 0)

View File

@ -100,6 +100,25 @@ public class NotifyEngine : INotifyEngine, IDisposable
_methodsEvent.Set();
}
internal void RegisterSendMethod(Func<DateTime, Task> method, string cron)
{
ArgumentNullException.ThrowIfNull(method);
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(cron);
var w = new SendMethodWrapper(method, cron, _logger);
lock (_sendMethods)
{
if (!_notifyScheduler.IsAlive)
{
_notifyScheduler.Start();
}
_sendMethods.Remove(w);
_sendMethods.Add(w);
}
_methodsEvent.Set();
}
internal void UnregisterSendMethod(Action<DateTime> method)
{
ArgumentNullException.ThrowIfNull(method);
@ -124,7 +143,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
copy = _sendMethods.ToList();
}
foreach(var w in copy)
foreach (var w in copy)
{
if (!w.ScheduleDate.HasValue)
{
@ -590,6 +609,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
private readonly SemaphoreSlim _semaphore;
private readonly CronExpression _cronExpression;
private readonly Action<DateTime> _method;
private readonly Func<DateTime, Task> _asyncMethod;
private readonly ILogger _logger;
public DateTime? ScheduleDate { get; private set; }
@ -608,6 +628,11 @@ public class NotifyEngine : INotifyEngine, IDisposable
UpdateScheduleDate(DateTime.UtcNow);
}
public SendMethodWrapper(Func<DateTime, Task> method, string cron, ILogger log) : this((Action<DateTime>)null, cron, log)
{
_asyncMethod = method;
}
public void UpdateScheduleDate(DateTime d)
{
try
@ -626,11 +651,18 @@ public class NotifyEngine : INotifyEngine, IDisposable
public async Task InvokeSendMethod(DateTime d)
{
await _semaphore.WaitAsync();
await Task.Run(() =>
await Task.Run(async () =>
{
try
{
_method(d);
if (_method != null)
{
_method(d);
}
else if (_asyncMethod != null)
{
await _asyncMethod(d);
}
}
catch (Exception e)
{
@ -642,7 +674,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
public override bool Equals(object obj)
{
return obj is SendMethodWrapper w && _method.Equals(w._method);
return obj is SendMethodWrapper w && ((_method != null && _method.Equals(w._method)) || (_asyncMethod != null && _asyncMethod.Equals(w._asyncMethod)));
}
public override int GetHashCode()

View File

@ -0,0 +1,34 @@
// (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.Quota.Features;
public class FreeFeature : TenantQuotaFeatureFlag
{
public override string Name { get => "free"; }
public FreeFeature(TenantQuota tenantQuota) : base(tenantQuota)
{
}
}

View File

@ -0,0 +1,64 @@
// (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.Quota;
public class QuotaSocketManager : SocketServiceClient
{
private readonly TenantManager _tenantManager;
public override string Hub => "files";
public QuotaSocketManager(
ILogger<SocketServiceClient> logger,
IHttpClientFactory clientFactory,
MachinePseudoKeys mashinePseudoKeys,
TenantManager tenantManager,
IConfiguration configuration) : base(logger, clientFactory, mashinePseudoKeys, configuration)
{
_tenantManager = tenantManager;
}
public async Task ChangeQuotaUsedValue(string featureId, object value)
{
var room = GetQuotaRoom();
await MakeRequest("change-quota-used-value", new { room, featureId, value });
}
public async Task ChangeQuotaFeatureValue(string featureId, object value)
{
var room = GetQuotaRoom();
await MakeRequest("change-quota-feature-value", new { room, featureId, value });
}
private string GetQuotaRoom()
{
var tenantId = _tenantManager.GetCurrentTenant().Id;
return $"{tenantId}-quota";
}
}

View File

@ -67,7 +67,7 @@ public class TenantQuotaFeature<T> : TenantQuotaFeature
}
}
protected virtual T Default { get; }
public virtual T Default { get; }
public TenantQuotaFeature(TenantQuota tenantQuota)
{
@ -83,7 +83,7 @@ public class TenantQuotaFeature<T> : TenantQuotaFeature
public class TenantQuotaFeatureCount : TenantQuotaFeature<int>
{
protected override int Default => int.MaxValue;
public override int Default => int.MaxValue;
public TenantQuotaFeatureCount(TenantQuota tenantQuota) : base(tenantQuota)
{
@ -105,7 +105,7 @@ public class TenantQuotaFeatureCount : TenantQuotaFeature<int>
public class TenantQuotaFeatureSize : TenantQuotaFeature<long>
{
protected override long Default => long.MaxValue;
public override long Default => long.MaxValue;
public TenantQuotaFeatureSize(TenantQuota tenantQuota) : base(tenantQuota)
{

View File

@ -0,0 +1,50 @@
// (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.Quota;
[Scope]
public class TenantQuotaFeatureStatHelper
{
private readonly IServiceProvider _serviceProvider;
public TenantQuotaFeatureStatHelper(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task<(string Name, T1 Value)> GetStat<T, T1>() where T : TenantQuotaFeature
{
var statisticProvider = (ITenantQuotaFeatureStat<T1>)_serviceProvider.GetService(typeof(ITenantQuotaFeatureStat<,>).MakeGenericType(typeof(T), typeof(T1)));
var quota = new TenantQuota();
var name = quota.GetFeature<T>().Name;
if (statisticProvider != null)
{
return (name, await statisticProvider.GetValue());
}
return (name, default(T1));
}
}

View File

@ -222,13 +222,13 @@ public class TenantQuota : IMapFrom<DbQuota>
_countUserFeature = new CountUserFeature(this) { Order = 1 };
_countPaidUserFeature = new CountPaidUserFeature(this);
_usersInRoomFeature = new UsersInRoomFeature(this) { Order = 8 };
_usersInRoomFeature = new UsersInRoomFeature(this) { Order = 8, Visible = false };
_countRoomFeature = new CountRoomFeature(this) { Order = 2 };
_maxTotalSizeFeature = new MaxTotalSizeFeature(this);
_maxFileSizeFeature = new MaxFileSizeFeature(this);
_nonProfitFeature = new TenantQuotaFeatureFlag(this) { Name = "non-profit", Visible = false };
_trialFeature = new TenantQuotaFeatureFlag(this) { Name = "trial", Visible = false };
_freeFeature = new TenantQuotaFeatureFlag(this) { Name = "free", Visible = false };
_freeFeature = new FreeFeature(this) { Visible = false };
_updateFeature = new TenantQuotaFeatureFlag(this) { Name = "update", Visible = false };
_auditFeature = new TenantQuotaFeatureFlag(this) { Name = "audit", Order = 7 };
_docsEditionFeature = new TenantQuotaFeatureFlag(this) { Name = "docs", Visible = false };
@ -323,7 +323,7 @@ public class TenantQuota : IMapFrom<DbQuota>
return quota;
}
var newQuota = new TenantQuota(quota);
var newQuota = new TenantQuota(old);
newQuota.Price += quota.Price;
newQuota.Visible &= quota.Visible;
newQuota.ProductId = "";
@ -336,11 +336,31 @@ public class TenantQuota : IMapFrom<DbQuota>
}
else if (f is TenantQuotaFeatureCount count)
{
count.Value += quota.GetFeature<int>(f.Name).Value;
var currentValue = count.Value;
var newValue = quota.GetFeature<int>(f.Name).Value;
if (currentValue == count.Default && newValue != currentValue)
{
count.Value = newValue;
}
else if (currentValue != count.Default && newValue != count.Default)
{
count.Value += newValue;
}
}
else if (f is TenantQuotaFeatureSize length)
{
length.Value += quota.GetFeature<long>(f.Name).Value;
var currentValue = length.Value;
var newValue = quota.GetFeature<long>(f.Name).Value;
if (currentValue == length.Default && newValue != currentValue)
{
length.Value = newValue;
}
else
{
length.Value += newValue;
}
}
else if (f is TenantQuotaFeatureFlag flag)
{

View File

@ -60,7 +60,7 @@ public class BackupRepository : IBackupRepository
public List<BackupRecord> GetExpiredBackupRecords()
{
using var backupContext = _dbContextFactory.CreateDbContext();
return backupContext.Backups.AsNoTracking().Where(b => b.ExpiresOn != DateTime.MinValue && b.ExpiresOn <= DateTime.UtcNow).ToList();
return backupContext.Backups.AsNoTracking().Where(b => b.ExpiresOn != DateTime.MinValue && b.ExpiresOn <= DateTime.UtcNow && b.Removed == false).ToList();
}
public List<BackupRecord> GetScheduledBackupRecords()

View File

@ -709,14 +709,18 @@ public class BackupPortalTask : PortalTaskBase
foreach (var file in group)
{
var storage = StorageFactory.GetStorage(TenantId, group.Key);
var file1 = file;
var file1 = file;
Stream fileStream = null;
await ActionInvoker.Try(async state =>
{
var f = (BackupFileInfo)state;
using var fileStream = await storage.GetReadStreamAsync(f.Domain, f.Path);
await writer.WriteEntryAsync(file1.GetZipKey(), fileStream);
fileStream = await storage.GetReadStreamAsync(f.Domain, f.Path);
}, file, 5, error => _logger.WarningCanNotBackupFile(file1.Module, file1.Path, error));
if(fileStream != null)
{
await writer.WriteEntryAsync(file1.GetZipKey(), fileStream);
fileStream.Dispose();
}
SetCurrentStepProgress((int)(++filesProcessed * 100 / (double)filesCount));
}
}

View File

@ -48,6 +48,9 @@ public abstract class BaseStorage : IDataStore
protected readonly ILoggerProvider _options;
protected readonly IHttpClientFactory _clientFactory;
private readonly TenantQuotaFeatureStatHelper _tenantQuotaFeatureStatHelper;
private readonly QuotaSocketManager _quotaSocketManager;
public BaseStorage(
TempStream tempStream,
TenantManager tenantManager,
@ -56,7 +59,9 @@ public abstract class BaseStorage : IDataStore
IHttpContextAccessor httpContextAccessor,
ILoggerProvider options,
ILogger logger,
IHttpClientFactory clientFactory)
IHttpClientFactory clientFactory,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
QuotaSocketManager quotaSocketManager)
{
_tempStream = tempStream;
@ -67,6 +72,8 @@ public abstract class BaseStorage : IDataStore
_clientFactory = clientFactory;
Logger = logger;
_httpContextAccessor = httpContextAccessor;
_tenantQuotaFeatureStatHelper = tenantQuotaFeatureStatHelper;
_quotaSocketManager = quotaSocketManager;
}
public TimeSpan GetExpire(string domain)
@ -334,19 +341,23 @@ public abstract class BaseStorage : IDataStore
public abstract string GetPostParams(string domain, string directoryPath, long maxUploadSize, string contentType,
string contentDisposition);
internal void QuotaUsedAdd(string domain, long size, bool quotaCheckFileSize = true)
internal async Task QuotaUsedAdd(string domain, long size, bool quotaCheckFileSize = true)
{
if (QuotaController != null)
{
QuotaController.QuotaUsedAdd(Modulename, domain, DataList.GetData(domain), size, quotaCheckFileSize);
var(name, value) = await _tenantQuotaFeatureStatHelper.GetStat<MaxTotalSizeFeature, long>();
_ = _quotaSocketManager.ChangeQuotaUsedValue(name, value);
}
}
internal void QuotaUsedDelete(string domain, long size)
internal async Task QuotaUsedDelete(string domain, long size)
{
if (QuotaController != null)
{
QuotaController.QuotaUsedDelete(Modulename, domain, DataList.GetData(domain), size);
var (name, value) = await _tenantQuotaFeatureStatHelper.GetStat<MaxTotalSizeFeature, long>();
_ = _quotaSocketManager.ChangeQuotaUsedValue(name, value);
}
}

View File

@ -75,8 +75,10 @@ public class DiscDataStore : BaseStorage
ILogger<DiscDataStore> logger,
EncryptionSettingsHelper encryptionSettingsHelper,
EncryptionFactory encryptionFactory,
IHttpClientFactory clientFactory)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, clientFactory)
IHttpClientFactory clientFactory,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
QuotaSocketManager quotaSocketManager)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, clientFactory, tenantQuotaFeatureStatHelper, quotaSocketManager)
{
_encryptionSettingsHelper = encryptionSettingsHelper;
_encryptionFactory = encryptionFactory;
@ -143,18 +145,18 @@ public class DiscDataStore : BaseStorage
{
return SaveAsync(domain, path, stream);
}
private bool EnableQuotaCheck(string domain)
{
return (QuotaController != null) && !domain.EndsWith("_temp");
}
private bool EnableQuotaCheck(string domain)
{
return (QuotaController != null) && !domain.EndsWith("_temp");
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream)
{
Logger.DebugSavePath(path);
var buffered = _tempStream.GetBuffered(stream);
if (EnableQuotaCheck(domain))
if (EnableQuotaCheck(domain))
{
QuotaController.QuotaUsedCheck(buffered.Length);
}
@ -193,7 +195,7 @@ public class DiscDataStore : BaseStorage
fslen = fs.Length;
}
QuotaUsedAdd(domain, fslen);
await QuotaUsedAdd(domain, fslen);
_crypt.EncryptFile(target);
@ -226,7 +228,7 @@ public class DiscDataStore : BaseStorage
return string.Format("{0}_{1}", chunkNumber, uploadId);
}
public override Task<Uri> FinalizeChunkedUploadAsync(string domain, string path, string uploadId, Dictionary<int, string> eTags)
public override async Task<Uri> FinalizeChunkedUploadAsync(string domain, string path, string uploadId, Dictionary<int, string> eTags)
{
var target = GetTarget(domain, path);
@ -238,12 +240,12 @@ public class DiscDataStore : BaseStorage
}
var size = _crypt.GetFileSize(target);
QuotaUsedAdd(domain, size);
await QuotaUsedAdd(domain, size);
}
_crypt.EncryptFile(target);
return GetUriAsync(domain, path);
return await GetUriAsync(domain, path);
}
public override Task AbortChunkedUploadAsync(string domain, string path, string uploadId)
@ -258,7 +260,7 @@ public class DiscDataStore : BaseStorage
#endregion
public override Task DeleteAsync(string domain, string path)
public override async Task DeleteAsync(string domain, string path)
{
ArgumentNullException.ThrowIfNull(path);
@ -269,8 +271,7 @@ public class DiscDataStore : BaseStorage
var size = _crypt.GetFileSize(target);
File.Delete(target);
QuotaUsedDelete(domain, size);
return Task.CompletedTask; ;
await QuotaUsedDelete(domain, size);
}
else
{
@ -278,7 +279,7 @@ public class DiscDataStore : BaseStorage
}
}
public override Task DeleteFilesAsync(string domain, List<string> paths)
public override async Task DeleteFilesAsync(string domain, List<string> paths)
{
ArgumentNullException.ThrowIfNull(paths);
@ -294,13 +295,11 @@ public class DiscDataStore : BaseStorage
var size = _crypt.GetFileSize(target);
File.Delete(target);
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
return Task.CompletedTask;
}
public override Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
{
ArgumentNullException.ThrowIfNull(folderPath);
@ -313,9 +312,8 @@ public class DiscDataStore : BaseStorage
{
var size = _crypt.GetFileSize(entry);
File.Delete(entry);
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
return Task.CompletedTask;
}
else
{
@ -323,7 +321,7 @@ public class DiscDataStore : BaseStorage
}
}
public override Task DeleteFilesAsync(string domain, string folderPath, DateTime fromDate, DateTime toDate)
public override async Task DeleteFilesAsync(string domain, string folderPath, DateTime fromDate, DateTime toDate)
{
ArgumentNullException.ThrowIfNull(folderPath);
@ -339,7 +337,7 @@ public class DiscDataStore : BaseStorage
{
var size = _crypt.GetFileSize(entry);
File.Delete(entry);
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
}
}
@ -347,8 +345,6 @@ public class DiscDataStore : BaseStorage
{
throw new DirectoryNotFoundException($"Directory '{targetDir}' not found");
}
return Task.CompletedTask;
}
public override Task MoveDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
@ -367,7 +363,7 @@ public class DiscDataStore : BaseStorage
return Task.CompletedTask;
}
public override Task<Uri> MoveAsync(string srcdomain, string srcpath, string newdomain, string newpath, bool quotaCheckFileSize = true)
public override async Task<Uri> MoveAsync(string srcdomain, string srcpath, string newdomain, string newpath, bool quotaCheckFileSize = true)
{
ArgumentNullException.ThrowIfNull(srcpath);
ArgumentNullException.ThrowIfNull(newpath);
@ -392,14 +388,14 @@ public class DiscDataStore : BaseStorage
File.Move(target, newtarget);
QuotaUsedDelete(srcdomain, flength);
QuotaUsedAdd(newdomain, flength, quotaCheckFileSize);
await QuotaUsedDelete(srcdomain, flength);
await QuotaUsedAdd(newdomain, flength, quotaCheckFileSize);
}
else
{
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
}
return GetUriAsync(newdomain, newpath);
return await GetUriAsync(newdomain, newpath);
}
public override Task<bool> IsDirectoryAsync(string domain, string path)
@ -415,7 +411,7 @@ public class DiscDataStore : BaseStorage
return Task.FromResult(!string.IsNullOrEmpty(targetDir) && Directory.Exists(targetDir));
}
public override Task DeleteDirectoryAsync(string domain, string path)
public override async Task DeleteDirectoryAsync(string domain, string path)
{
ArgumentNullException.ThrowIfNull(path);
@ -434,7 +430,7 @@ public class DiscDataStore : BaseStorage
if (!Directory.Exists(targetDir))
{
return Task.CompletedTask;
return;
}
var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.AllDirectories);
@ -446,8 +442,7 @@ public class DiscDataStore : BaseStorage
Directory.Delete(targetDir, true);
QuotaUsedDelete(domain, size);
return Task.CompletedTask;
await QuotaUsedDelete(domain, size);
}
public override Task<long> GetFileSizeAsync(string domain, string path)
@ -488,7 +483,7 @@ public class DiscDataStore : BaseStorage
return result.ToString();
}
public override Task DeleteExpiredAsync(string domain, string folderPath, TimeSpan oldThreshold)
public override async Task DeleteExpiredAsync(string domain, string folderPath, TimeSpan oldThreshold)
{
ArgumentNullException.ThrowIfNull(folderPath);
@ -496,7 +491,7 @@ public class DiscDataStore : BaseStorage
var targetDir = GetTarget(domain, folderPath);
if (!Directory.Exists(targetDir))
{
return Task.CompletedTask;
return;
}
var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.TopDirectoryOnly);
@ -508,11 +503,9 @@ public class DiscDataStore : BaseStorage
var size = _crypt.GetFileSize(entry);
File.Delete(entry);
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
}
return Task.CompletedTask;
}
public override string GetUploadForm(string domain, string directoryPath, string redirectTo, long maxUploadSize, string contentType, string contentDisposition, string submitLabel)
@ -608,7 +601,7 @@ public class DiscDataStore : BaseStorage
return Task.FromResult(size);
}
public override Task<Uri> CopyAsync(string srcdomain, string srcpath, string newdomain, string newpath)
public override async Task<Uri> CopyAsync(string srcdomain, string srcpath, string newdomain, string newpath)
{
ArgumentNullException.ThrowIfNull(srcpath);
ArgumentNullException.ThrowIfNull(newpath);
@ -626,16 +619,16 @@ public class DiscDataStore : BaseStorage
File.Copy(target, newtarget, true);
var flength = _crypt.GetFileSize(target);
QuotaUsedAdd(newdomain, flength);
await QuotaUsedAdd(newdomain, flength);
}
else
{
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
}
return GetUriAsync(newdomain, newpath);
return await GetUriAsync(newdomain, newpath);
}
public override Task CopyDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
public override async Task CopyDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
{
var target = GetTarget(srcdomain, srcdir);
var newtarget = GetTarget(newdomain, newdir);
@ -643,8 +636,7 @@ public class DiscDataStore : BaseStorage
var diSource = new DirectoryInfo(target);
var diTarget = new DirectoryInfo(newtarget);
CopyAll(diSource, diTarget, newdomain);
return Task.CompletedTask;
await CopyAll(diSource, diTarget, newdomain);
}
@ -684,7 +676,7 @@ public class DiscDataStore : BaseStorage
return SaveAsync(domain, path, stream);
}
private void CopyAll(DirectoryInfo source, DirectoryInfo target, string newdomain)
private async Task CopyAll(DirectoryInfo source, DirectoryInfo target, string newdomain)
{
// Check if the target directory exists, if not, create it.
if (!Directory.Exists(target.FullName))
@ -698,14 +690,14 @@ public class DiscDataStore : BaseStorage
var fp = CrossPlatform.PathCombine(target.ToString(), fi.Name);
fi.CopyTo(fp, true);
var size = _crypt.GetFileSize(fp);
QuotaUsedAdd(newdomain, size);
await QuotaUsedAdd(newdomain, size);
}
// Copy each subdirectory using recursion.
foreach (var diSourceSubDir in source.GetDirectories())
{
var nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir, newdomain);
await CopyAll(diSourceSubDir, nextTargetSubDir, newdomain);
}
}
@ -768,7 +760,7 @@ public class DiscDataStore : BaseStorage
{
ArgumentNullException.ThrowIfNull(path);
var target = GetTarget(domain, path);
var target = GetTarget(domain, path);
var lastModificationDate = File.Exists(target) ? File.GetLastWriteTimeUtc(target) : throw new FileNotFoundException("File not found" + target);
var etag = '"' + lastModificationDate.Ticks.ToString("X8", CultureInfo.InvariantCulture) + '"';

View File

@ -48,8 +48,10 @@ public class GoogleCloudStorage : BaseStorage
IHttpContextAccessor httpContextAccessor,
ILoggerProvider factory,
ILogger<GoogleCloudStorage> options,
IHttpClientFactory clientFactory)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, clientFactory)
IHttpClientFactory clientFactory,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
QuotaSocketManager quotaSocketManager)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, clientFactory, tenantQuotaFeatureStatHelper, quotaSocketManager)
{
}
@ -234,7 +236,7 @@ public class GoogleCloudStorage : BaseStorage
// InvalidateCloudFront(MakePath(domain, path));
QuotaUsedAdd(domain, buffered.Length);
await QuotaUsedAdd(domain, buffered.Length);
return await GetUriAsync(domain, path);
}
@ -248,7 +250,7 @@ public class GoogleCloudStorage : BaseStorage
await storage.DeleteObjectAsync(_bucket, key);
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
@ -271,7 +273,7 @@ public class GoogleCloudStorage : BaseStorage
await foreach (var obj in objToDel)
{
await storage.DeleteObjectAsync(_bucket, obj.Name);
QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
await QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
}
}
@ -325,7 +327,7 @@ public class GoogleCloudStorage : BaseStorage
if (quotaUsed > 0)
{
QuotaUsedDelete(domain, quotaUsed);
await QuotaUsedDelete(domain, quotaUsed);
}
}
@ -339,7 +341,7 @@ public class GoogleCloudStorage : BaseStorage
await foreach (var obj in objToDel)
{
await storage.DeleteObjectAsync(_bucket, obj.Name);
QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
await QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
}
}
@ -378,8 +380,8 @@ public class GoogleCloudStorage : BaseStorage
await DeleteAsync(srcdomain, srcpath);
QuotaUsedDelete(srcdomain, size);
QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
await QuotaUsedDelete(srcdomain, size);
await QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
return await GetUriAsync(newdomain, newpath);
}
@ -455,7 +457,7 @@ public class GoogleCloudStorage : BaseStorage
await foreach (var obj in objToDel)
{
await storage.DeleteObjectAsync(_bucket, obj.Name);
QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
await QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
}
}
@ -549,7 +551,7 @@ public class GoogleCloudStorage : BaseStorage
await storage.CopyObjectAsync(_bucket, MakePath(srcdomain, srcpath), _bucket, MakePath(newdomain, newpath), options);
QuotaUsedAdd(newdomain, size);
await QuotaUsedAdd(newdomain, size);
return await GetUriAsync(newdomain, newpath);
}
@ -571,7 +573,7 @@ public class GoogleCloudStorage : BaseStorage
DestinationPredefinedAcl = GetDomainACL(newdomain)
});
QuotaUsedAdd(newdomain, Convert.ToInt64(obj.Size));
await QuotaUsedAdd(newdomain, Convert.ToInt64(obj.Size));
}
}
@ -734,7 +736,7 @@ public class GoogleCloudStorage : BaseStorage
if (QuotaController != null)
{
var size = await GetFileSizeAsync(domain, path);
QuotaUsedAdd(domain, size);
await QuotaUsedAdd(domain, size);
}
return await GetUriAsync(domain, path);

View File

@ -55,8 +55,10 @@ public class RackspaceCloudStorage : BaseStorage
IHttpContextAccessor httpContextAccessor,
ILoggerProvider options,
ILogger<RackspaceCloudStorage> logger,
IHttpClientFactory httpClient)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, httpClient)
IHttpClientFactory httpClient,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
QuotaSocketManager quotaSocketManager)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, httpClient, tenantQuotaFeatureStatHelper, quotaSocketManager)
{
_logger = logger;
TempPath = tempPath;
@ -192,7 +194,7 @@ public class RackspaceCloudStorage : BaseStorage
return (QuotaController != null) && !domain.EndsWith("_temp");
}
public Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
public async Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5,
DateTime? deleteAt = null, long? deleteAfter = null)
{
@ -282,9 +284,9 @@ public class RackspaceCloudStorage : BaseStorage
_region
);
QuotaUsedAdd(domain, buffered.Length);
await QuotaUsedAdd(domain, buffered.Length);
return GetUriAsync(domain, path);
return await GetUriAsync(domain, path);
}
@ -296,11 +298,11 @@ public class RackspaceCloudStorage : BaseStorage
client.DeleteObject(_private_container, MakePath(domain, path));
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
public override Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
{
var client = GetClient();
@ -309,7 +311,7 @@ public class RackspaceCloudStorage : BaseStorage
if (!files.Any())
{
return Task.CompletedTask;
return;
}
foreach (var file in files)
@ -319,10 +321,8 @@ public class RackspaceCloudStorage : BaseStorage
if (QuotaController != null)
{
QuotaUsedDelete(domain, files.Select(x => x.Bytes).Sum());
await QuotaUsedDelete(domain, files.Select(x => x.Bytes).Sum());
}
return Task.CompletedTask;
}
public override Task DeleteFilesAsync(string domain, List<string> paths)
@ -371,11 +371,11 @@ public class RackspaceCloudStorage : BaseStorage
if (quotaUsed > 0)
{
QuotaUsedDelete(domain, quotaUsed);
await QuotaUsedDelete(domain, quotaUsed);
}
}
public override Task DeleteFilesAsync(string domain, string folderPath, DateTime fromDate, DateTime toDate)
public override async Task DeleteFilesAsync(string domain, string folderPath, DateTime fromDate, DateTime toDate)
{
var client = GetClient();
@ -384,7 +384,7 @@ public class RackspaceCloudStorage : BaseStorage
if (!files.Any())
{
return Task.CompletedTask;
return;
}
foreach (var file in files)
@ -394,10 +394,8 @@ public class RackspaceCloudStorage : BaseStorage
if (QuotaController != null)
{
QuotaUsedDelete(domain, files.Select(x => x.Bytes).Sum());
await QuotaUsedDelete(domain, files.Select(x => x.Bytes).Sum());
}
return Task.CompletedTask;
}
public override Task MoveDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
@ -429,8 +427,8 @@ public class RackspaceCloudStorage : BaseStorage
await DeleteAsync(srcdomain, srcpath);
QuotaUsedDelete(srcdomain, size);
QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
await QuotaUsedDelete(srcdomain, size);
await QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
return await GetUriAsync(newdomain, newpath);
}
@ -475,7 +473,7 @@ public class RackspaceCloudStorage : BaseStorage
return IsFileAsync(domain, path);
}
public override Task DeleteDirectoryAsync(string domain, string path)
public override async Task DeleteDirectoryAsync(string domain, string path)
{
var client = GetClient();
@ -484,9 +482,8 @@ public class RackspaceCloudStorage : BaseStorage
foreach (var obj in objToDel)
{
client.DeleteObject(_private_container, obj.Name);
QuotaUsedDelete(domain, obj.Bytes);
await QuotaUsedDelete(domain, obj.Bytes);
}
return Task.CompletedTask;
}
public override Task<long> GetFileSizeAsync(string domain, string path)
@ -571,12 +568,12 @@ public class RackspaceCloudStorage : BaseStorage
client.CopyObject(_private_container, srcKey, _private_container, dstKey);
QuotaUsedAdd(newdomain, size);
await QuotaUsedAdd(newdomain, size);
return await GetUriAsync(newdomain, newpath);
}
public override Task CopyDirectoryAsync(string srcdomain, string dir, string newdomain, string newdir)
public override async Task CopyDirectoryAsync(string srcdomain, string dir, string newdomain, string newdir)
{
var srckey = MakePath(srcdomain, dir);
var dstkey = MakePath(newdomain, newdir);
@ -588,9 +585,8 @@ public class RackspaceCloudStorage : BaseStorage
{
client.CopyObject(_private_container, file.Name, _private_container, file.Name.Replace(srckey, dstkey));
QuotaUsedAdd(newdomain, file.Bytes);
await QuotaUsedAdd(newdomain, file.Bytes);
}
return Task.CompletedTask;
}
public override async Task<string> SavePrivateAsync(string domain, string path, Stream stream, DateTime expires)
@ -671,7 +667,7 @@ public class RackspaceCloudStorage : BaseStorage
{
var size = await GetFileSizeAsync(domain, path);
QuotaUsedAdd(domain, size);
await QuotaUsedAdd(domain, size);
}
return await GetUriAsync(domain, path);

View File

@ -67,8 +67,10 @@ public class S3Storage : BaseStorage
ILoggerProvider factory,
ILogger<S3Storage> options,
IHttpClientFactory clientFactory,
IConfiguration configuration)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, clientFactory)
IConfiguration configuration,
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
QuotaSocketManager quotaSocketManager)
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, clientFactory, tenantQuotaFeatureStatHelper, quotaSocketManager)
{
_configuration = configuration;
}
@ -259,7 +261,7 @@ public class S3Storage : BaseStorage
await InvalidateCloudFrontAsync(MakePath(domain, path));
QuotaUsedAdd(domain, buffered.Length);
await QuotaUsedAdd(domain, buffered.Length);
return await GetUriAsync(domain, path);
}
@ -352,7 +354,7 @@ public class S3Storage : BaseStorage
if (QuotaController != null)
{
var size = await GetFileSizeAsync(domain, path);
QuotaUsedAdd(domain, size);
await QuotaUsedAdd(domain, size);
}
return await GetUriAsync(domain, path);
@ -407,7 +409,7 @@ public class S3Storage : BaseStorage
await client.DeleteObjectAsync(request);
QuotaUsedDelete(domain, size);
await QuotaUsedDelete(domain, size);
}
public override Task DeleteFilesAsync(string domain, List<string> paths)
@ -467,7 +469,7 @@ public class S3Storage : BaseStorage
if (quotaUsed > 0)
{
QuotaUsedDelete(domain, quotaUsed);
await QuotaUsedDelete(domain, quotaUsed);
}
}
@ -493,7 +495,7 @@ public class S3Storage : BaseStorage
await client.DeleteObjectAsync(deleteRequest);
QuotaUsedDelete(domain, s3Object.Size);
await QuotaUsedDelete(domain, s3Object.Size);
}
}
@ -515,7 +517,7 @@ public class S3Storage : BaseStorage
await client.DeleteObjectAsync(deleteRequest);
QuotaUsedDelete(domain, s3Object.Size);
await QuotaUsedDelete(domain, s3Object.Size);
}
}
@ -554,8 +556,8 @@ public class S3Storage : BaseStorage
await CopyFileAsync(client, srcKey, dstKey, newdomain, S3MetadataDirective.REPLACE);
await DeleteAsync(srcdomain, srcpath);
QuotaUsedDelete(srcdomain, size);
QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
await QuotaUsedDelete(srcdomain, size);
await QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
return await GetUriAsync(newdomain, newpath);
}
@ -848,7 +850,7 @@ public class S3Storage : BaseStorage
using var client = GetClient();
await CopyFileAsync(client, srcKey, dstKey, newdomain, S3MetadataDirective.REPLACE);
QuotaUsedAdd(newdomain, size);
await QuotaUsedAdd(newdomain, size);
return await GetUriAsync(newdomain, newpath);
}
@ -866,7 +868,7 @@ public class S3Storage : BaseStorage
{
await CopyFileAsync(client, s3Object.Key, s3Object.Key.Replace(srckey, dstkey), newdomain);
QuotaUsedAdd(newdomain, s3Object.Size);
await QuotaUsedAdd(newdomain, s3Object.Size);
}
}

View File

@ -102,7 +102,7 @@ public class ChunkZipWriteOperator : IDataWriteOperator
theMemStream.Position = 0;
if (bytesRead == chunkUploadSize || last)
{
if (_fileStream.Position == _fileStream.Length)
if (_fileStream.Position == _fileStream.Length && last)
{
_chunkedUploadSession.LastChunk = true;
}

View File

@ -89,12 +89,47 @@ public class S3ZipWriteOperator : IDataWriteOperator
{
var fs = _fileStream;
_fileStream = null;
Computehash(fs, false);
Upload(fs);
SplitAndUpload(fs);
}
}
private void Computehash(Stream stream, bool last)
private void SplitAndUpload(Stream stream, bool last = false)
{
stream.Position = 0;
var buffer = new byte[_sessionHolder.MaxChunkUploadSize];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, (int)_sessionHolder.MaxChunkUploadSize)) > 0)
{
var tempStream = _tempStream.Create();
tempStream.Write(buffer, 0, bytesRead);
if (tempStream.Length == _sessionHolder.MaxChunkUploadSize)
{
tempStream.Position = 0;
ComputeHash(tempStream, false);
Upload(tempStream);
}
else
{
if (last)
{
ComputeHash(tempStream, last);
Upload(tempStream);
}
else
{
tempStream.Position = tempStream.Length;
_fileStream = tempStream;
_gZipOutputStream.baseOutputStream_ = _fileStream;
}
}
}
stream.Dispose();
}
private void ComputeHash(Stream stream, bool last)
{
stream.Position = 0;
var buffer = new byte[_sessionHolder.MaxChunkUploadSize];
@ -134,8 +169,7 @@ public class S3ZipWriteOperator : IDataWriteOperator
_tarOutputStream.Close();
_tarOutputStream.Dispose();
Computehash(_fileStream, true);
Upload(_fileStream);
SplitAndUpload(_fileStream, true);
Task.WaitAll(_tasks.ToArray());

View File

@ -57,8 +57,8 @@ public class Feed
public string ContextId { get; set; }
public bool IsAllDayEvent { get; set; }
// это значит, что новость может обновляться (пр. добавление комментариев);
// следовательно и права доступа могут устаревать
// this means that the news can be updated (eg adding comments);
// hence permissions may be outdated
public bool Variate { get; private set; }
public Feed() { }

View File

@ -38,6 +38,5 @@ public class FeedApiFilter
public Guid Author { get; set; }
public string[] SearchKeys { get; set; }
public bool OnlyNew { get; set; }
public bool WithoutMe { get; set; }
public bool WithRelated { get; set; }
public bool History { get; set; }
}

View File

@ -202,23 +202,58 @@ public class FeedAggregateDataProvider
var q = feedDbContext.FeedAggregates.AsNoTracking()
.Where(r => r.Tenant == _tenantManager.GetCurrentTenant().Id);
var exp = GetIdSearchExpression(filter.Id, filter.Module, filter.WithRelated);
var feeds = filter.History ? GetFeedsAsHistoryQuery(q, filter) : GetFeedsDefaultQuery(feedDbContext, q, filter);
if (exp != null)
return _mapper.Map<IEnumerable<FeedAggregate>, List<FeedResultItem>>(feeds);
}
private static IQueryable<FeedAggregate> GetFeedsAsHistoryQuery(IQueryable<FeedAggregate> query, FeedApiFilter filter)
{
Expression<Func<FeedAggregate, bool>> exp = null;
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(filter.Id);
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(filter.Module);
switch (filter.Module)
{
q = q.Where(exp);
case Constants.RoomsModule:
{
var roomId = $"{Constants.RoomItem}_{filter.Id}";
exp = f => f.Id == roomId || (f.Id.StartsWith(Constants.SharedRoomItem) && f.ContextId == roomId);
if (filter.History)
{
exp = f => f.Id == roomId || f.ContextId == roomId;
}
break;
}
case Constants.FilesModule:
exp = f => f.Id.StartsWith($"{Constants.FileItem}_{filter.Id}") || f.Id.StartsWith($"{Constants.SharedFileItem}_{filter.Id}");
break;
case Constants.FoldersModule:
exp = f => f.Id == $"{Constants.FolderItem}_{filter.Id}" || f.Id.StartsWith($"{Constants.SharedFolderItem}_{filter.Id}");
break;
}
var q1 = q.Join(feedDbContext.FeedUsers, a => a.Id, b => b.FeedId, (aggregates, users) => new { aggregates, users })
if (exp == null)
{
throw new InvalidOperationException();
}
return query.Where(exp);
}
private IQueryable<FeedAggregate> GetFeedsDefaultQuery(FeedDbContext feedDbContext, IQueryable<FeedAggregate> query, FeedApiFilter filter)
{
var q1 = query.Join(feedDbContext.FeedUsers, a => a.Id, b => b.FeedId, (aggregates, users) => new { aggregates, users })
.OrderByDescending(r => r.aggregates.ModifiedDate)
.Skip(filter.Offset)
.Take(filter.Max);
if (exp == null)
{
q1 = q1.Where(r => r.aggregates.ModifiedBy != _authContext.CurrentAccount.ID).
Where(r => r.users.UserId == _authContext.CurrentAccount.ID);
}
q1 = q1.Where(r => r.aggregates.ModifiedBy != _authContext.CurrentAccount.ID).
Where(r => r.users.UserId == _authContext.CurrentAccount.ID);
if (filter.OnlyNew)
{
@ -249,16 +284,14 @@ public class FeedAggregateDataProvider
if (filter.SearchKeys != null && filter.SearchKeys.Length > 0)
{
var keys = filter.SearchKeys
.Where(s => !string.IsNullOrEmpty(s))
.Select(s => s.Replace("\\", "\\\\").Replace("%", "\\%").Replace("_", "\\_"))
.ToList();
.Where(s => !string.IsNullOrEmpty(s))
.Select(s => s.Replace("\\", "\\\\").Replace("%", "\\%").Replace("_", "\\_"))
.ToList();
q1 = q1.Where(r => keys.Any(k => r.aggregates.Keywords.StartsWith(k)));
}
var news = q1.Select(r => r.aggregates).Distinct().AsEnumerable();
return _mapper.Map<IEnumerable<FeedAggregate>, List<FeedResultItem>>(news);
return q1.Select(r => r.aggregates).Distinct();
}
public int GetNewFeedsCount(DateTime lastReadedTime)
@ -323,30 +356,30 @@ public class FeedAggregateDataProvider
if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(module))
{
return exp;
return null;
}
if (module == Constants.RoomsModule)
switch (module)
{
var roomId = $"{Constants.RoomItem}_{id}";
var sharedRoomId = $"{Constants.SharedRoomItem}_{id}";
case Constants.RoomsModule:
{
var roomId = $"{Constants.RoomItem}_{id}";
exp = f => f.Id == roomId || f.Id.StartsWith(sharedRoomId);
exp = f => f.Id == roomId || (f.Id.StartsWith(Constants.SharedRoomItem) && f.ContextId == roomId);
if (withRelated)
{
exp = f => f.Id == roomId || f.Id.StartsWith(sharedRoomId) || f.ContextId == roomId;
}
}
if (withRelated)
{
exp = f => f.Id == roomId || f.ContextId == roomId;
}
if (module == Constants.FilesModule)
{
exp = f => f.Id.StartsWith($"{Constants.FileItem}_{id}") || f.Id.StartsWith($"{Constants.SharedFileItem}_{id}");
}
if (module == Constants.FoldersModule)
{
exp = f => f.Id == $"{Constants.FolderItem}_{id}" || f.Id.StartsWith($"{Constants.SharedFolderItem}_{id}");
break;
}
case Constants.FilesModule:
exp = f => f.Id.StartsWith($"{Constants.FileItem}_{id}") || f.Id.StartsWith($"{Constants.SharedFileItem}_{id}");
break;
case Constants.FoldersModule:
exp = f => f.Id == $"{Constants.FolderItem}_{id}" || f.Id.StartsWith($"{Constants.SharedFolderItem}_{id}");
break;
}
return exp;

View File

@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
@ -13,12 +13,12 @@ namespace ASC.Migration.Resources {
/// <summary>
/// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д.
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// Этот класс создан автоматически классом StronglyTypedResourceBuilder
// с помощью такого средства, как ResGen или Visual Studio.
// Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen
// с параметром /str или перестройте свой проект VS.
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
@ -33,7 +33,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом.
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
@ -47,8 +47,8 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Перезаписывает свойство CurrentUICulture текущего потока для всех
/// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией.
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
@ -61,7 +61,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Clearing temporary data.
/// Looks up a localized string similar to Clearing temporary data.
/// </summary>
internal static string ClearingTemporaryData {
get {
@ -70,7 +70,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Data processing....
/// Looks up a localized string similar to Data processing....
/// </summary>
internal static string DataProcessing {
get {
@ -79,7 +79,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Data processing completed.
/// Looks up a localized string similar to Data processing completed.
/// </summary>
internal static string DataProcessingCompleted {
get {
@ -88,7 +88,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Database parsing.
/// Looks up a localized string similar to Database parsing.
/// </summary>
internal static string DumpParse {
get {
@ -97,7 +97,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Mail`s Contacts.
/// Looks up a localized string similar to Mail`s Contacts.
/// </summary>
internal static string GoogleModuleNameContacts {
get {
@ -106,7 +106,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Google Drive`s Files.
/// Looks up a localized string similar to Google Drive`s Files.
/// </summary>
internal static string GoogleModuleNameDocuments {
get {
@ -115,7 +115,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Group migration {0} ({1}/{2}).
/// Looks up a localized string similar to Group migration {0} ({1}/{2}).
/// </summary>
internal static string GroupMigration {
get {
@ -124,7 +124,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Migrating user contacts {0} ({1}/{2}).
/// Looks up a localized string similar to Migrating user contacts {0} ({1}/{2}).
/// </summary>
internal static string MigratingUserContacts {
get {
@ -133,7 +133,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Migrating user files {0} ({1}/{2}).
/// Looks up a localized string similar to Migrating user files {0} ({1}/{2}).
/// </summary>
internal static string MigratingUserFiles {
get {
@ -142,7 +142,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Migration canceled.
/// Looks up a localized string similar to Migration canceled.
/// </summary>
internal static string MigrationCanceled {
get {
@ -151,7 +151,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Migration completed.
/// Looks up a localized string similar to Migration completed.
/// </summary>
internal static string MigrationCompleted {
get {
@ -160,7 +160,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Calendar.
/// Looks up a localized string similar to Calendar.
/// </summary>
internal static string ModuleNameCalendar {
get {
@ -169,7 +169,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Groups.
/// Looks up a localized string similar to Groups.
/// </summary>
internal static string ModuleNameGroups {
get {
@ -178,7 +178,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Mail.
/// Looks up a localized string similar to Mail.
/// </summary>
internal static string ModuleNameMail {
get {
@ -187,7 +187,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Users.
/// Looks up a localized string similar to Users.
/// </summary>
internal static string ModuleNameUsers {
get {
@ -196,7 +196,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Contacts.
/// Looks up a localized string similar to Contacts.
/// </summary>
internal static string NextcloudModuleNameContacts {
get {
@ -205,7 +205,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на User`s Files.
/// Looks up a localized string similar to User`s Files.
/// </summary>
internal static string NextcloudModuleNameDocuments {
get {
@ -214,7 +214,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Calendar.
/// Looks up a localized string similar to Calendar.
/// </summary>
internal static string OnlyofficeModuleNameCalendar {
get {
@ -223,7 +223,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Documents.
/// Looks up a localized string similar to Documents.
/// </summary>
internal static string OnlyofficeModuleNameDocuments {
get {
@ -232,7 +232,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Mail.
/// Looks up a localized string similar to Mail.
/// </summary>
internal static string OnlyofficeModuleNameMail {
get {
@ -241,7 +241,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на People.
/// Looks up a localized string similar to People.
/// </summary>
internal static string OnlyofficeModuleNamePeople {
get {
@ -250,7 +250,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Preparing for migration.
/// Looks up a localized string similar to Preparing for migration.
/// </summary>
internal static string PreparingForMigration {
get {
@ -259,7 +259,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Starting data processing....
/// Looks up a localized string similar to Starting data processing....
/// </summary>
internal static string StartOfDataProcessing {
get {
@ -268,7 +268,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Unzipping....
/// Looks up a localized string similar to Unzipping....
/// </summary>
internal static string Unzipping {
get {
@ -277,7 +277,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Unzipping completed....
/// Looks up a localized string similar to Unzipping completed....
/// </summary>
internal static string UnzippingFinished {
get {
@ -286,7 +286,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на User calendar migration {0} ({1}/{2}).
/// Looks up a localized string similar to User calendar migration {0} ({1}/{2}).
/// </summary>
internal static string UserCalendarMigration {
get {
@ -295,7 +295,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на User migration {0} ({1}/{2}).
/// Looks up a localized string similar to User migration {0} ({1}/{2}).
/// </summary>
internal static string UserMigration {
get {
@ -304,7 +304,7 @@ namespace ASC.Migration.Resources {
}
/// <summary>
/// Ищет локализованную строку, похожую на Failed to import user: {0} ({1}/{2}).
/// Looks up a localized string similar to Failed to import user: {0} ({1}/{2}).
/// </summary>
internal static string UserSkipped {
get {

View File

@ -45,11 +45,21 @@
files.markAsNewFile(req.body);
res.end();
});
router.post("/markasnew-folder", (req, res) => {
files.markAsNewFolder(req.body);
res.end();
});
router.post("/change-quota-used-value", (req, res) => {
files.changeQuotaUsedValue(req.body);
res.end();
});
router.post("/change-quota-feature-value", (req, res) => {
files.changeQuotaFeatureValue(req.body);
res.end();
});
return router;
};

View File

@ -55,11 +55,11 @@
);
});
socket.on("subscribe", ({roomParts, individual}) => {
socket.on("subscribe", ({ roomParts, individual }) => {
changeSubscription(roomParts, individual, subscribe);
});
socket.on("unsubscribe", ({roomParts, individual}) => {
socket.on("unsubscribe", ({ roomParts, individual }) => {
changeSubscription(roomParts, individual, unsubscribe);
});
@ -80,7 +80,7 @@
changeFunc(roomParts);
if(individual){
if (individual) {
if (Array.isArray(roomParts)) {
changeFunc(roomParts.map((p) => `${p}-${userId}`));
} else {
@ -116,7 +116,6 @@
socket.leave(room);
}
}
});
function startEdit({ fileId, room } = {}) {
@ -167,11 +166,34 @@
logger.info(`markAsNewFile ${fileId} in room ${room}:${count}`);
filesIO.to(room).emit("s:markasnew-file", { fileId, count });
}
function markAsNewFolder({ folderId, count, room } = {}) {
logger.info(`markAsNewFolder ${folderId} in room ${room}:${count}`);
filesIO.to(room).emit("s:markasnew-folder", { folderId, count });
}
return { startEdit, stopEdit, createFile, createFolder, deleteFile, deleteFolder, updateFile, updateFolder, markAsNewFile, markAsNewFolder };
function changeQuotaUsedValue({ featureId, value, room } = {}) {
logger.info(`changeQuotaUsedValue in room ${room}`, { featureId, value });
filesIO.to(room).emit("s:change-quota-used-value", { featureId, value });
}
function changeQuotaFeatureValue({ featureId, value, room } = {}) {
logger.info(`changeQuotaFeatureValue in room ${room}`, { featureId, value });
filesIO.to(room).emit("s:change-quota-feature-value", { featureId, value });
}
return {
startEdit,
stopEdit,
createFile,
createFolder,
deleteFile,
deleteFolder,
updateFile,
updateFolder,
markAsNewFile,
markAsNewFolder,
changeQuotaUsedValue,
changeQuotaFeatureValue,
};
};

View File

@ -28,7 +28,10 @@ const accessKeyId = aws.accessKeyId;
const secretAccessKey = aws.secretAccessKey;
const awsRegion = aws.region;
const logGroupName = aws.logGroupName;
const logStreamName = aws.logStreamName;
const logStreamName = aws.logStreamName.replace("${hostname}", os.hostname())
.replace("${applicationContext}", "SocketIO")
.replace("${guid}", randomUUID())
.replace("${date}", date.format(new Date(), 'YYYY/MM/DDTHH.mm.ss'));
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName);
@ -54,17 +57,7 @@ var options = {
cloudWatch: {
name: 'aws',
level: "debug",
logStreamName: () => {
const hostname = os.hostname();
const now = new Date();
const guid = randomUUID();
const dateAsString = date.format(now, 'YYYY/MM/DDTHH.mm.ss');
return logStreamName.replace("${hostname}", hostname)
.replace("${applicationContext}", "SocketIO")
.replace("${guid}", guid)
.replace("${date}", dateAsString);
},
logStreamName: logStreamName,
logGroupName: logGroupName,
awsRegion: awsRegion,
jsonMessage: true,

View File

@ -1,7 +1,7 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2021
*
* (c) Copyright Ascensio System Limited 2010-2023
*
* 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
@ -12,148 +12,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
*/
"use strict";
process.env.NODE_ENV = process.env.NODE_ENV || "development";
const fs = require("fs"),
http = require("http"),
express = require("express"),
morgan = require("morgan"),
cookieParser = require("cookie-parser"),
bodyParser = require("body-parser"),
session = require("express-session"),
winston = require("winston"),
WinstonCloudWatch = require('winston-cloudwatch'),
config = require("./config").get(),
path = require("path"),
exphbs = require("express-handlebars"),
favicon = require("serve-favicon"),
cors = require("cors"),
{ randomUUID } = require('crypto'),
date = require('date-and-time'),
os = require("os");
const http = require("http"),
express = require("express"),
morgan = require("morgan"),
cookieParser = require("cookie-parser"),
bodyParser = require("body-parser"),
session = require("express-session"),
winston = require("./app/log.js"),
config = require("./config").get(),
path = require("path"),
exphbs = require("express-handlebars"),
favicon = require("serve-favicon"),
cors = require("cors");
require('winston-daily-rotate-file');
winston.stream = {
write: (message) => winston.info(message),
};
const app = express();
let logpath = config["logPath"];
if(logpath != null)
{
if(!path.isAbsolute(logpath))
{
logpath = path.join(__dirname, logpath);
}
// ensure log directory exists
fs.existsSync(logpath) || fs.mkdirSync(logpath);
}
const aws = config["aws"].cloudWatch;
const accessKeyId = aws.accessKeyId;
const secretAccessKey = aws.secretAccessKey;
const awsRegion = aws.region;
const logGroupName = aws.logGroupName;
const logStreamName = aws.logStreamName;
let transports = [];
if (config.logger.file) {
let logDir = logpath ? logpath : (config.app.logDir[0] === "." ? path.join(__dirname, config.app.logDir) : config.app.logDir);
config.logger.file.filename = path.join(logDir, config.app.logName);
transports.push(new (winston.transports.DailyRotateFile)(config.logger.file));
}
if (config.logger.console) {
transports.push(new (winston.transports.Console)(config.logger.console));
}
if (aws != null && aws.accessKeyId !== '')
{
transports.push(new WinstonCloudWatch({
name: 'aws',
level: "debug",
logStreamName: () => {
const hostname = os.hostname();
const now = new Date();
const guid = randomUUID();
const dateAsString = date.format(now, 'YYYY/MM/DDTHH.mm.ss');
return logStreamName.replace("${hostname}", hostname)
.replace("${applicationContext}", "SsoAuth")
.replace("${guid}", guid)
.replace("${date}", dateAsString);
},
logGroupName: logGroupName,
awsRegion: awsRegion,
jsonMessage: true,
awsOptions: {
credentials: {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey
}
}
}));
}
const customFormat = winston.format(info => {
const now = new Date();
info.date = date.format(now, 'YYYY-MM-DD HH:mm:ss');
info.applicationContext = "SsoAuth";
info.level = info.level.toUpperCase();
const hostname = os.hostname();
info["instance-id"] = hostname;
return info;
})();
let logger = winston.createLogger({
format: winston.format.combine(
customFormat,
winston.format.json()
),
transports: transports,
exitOnError: false
});
logger.stream = {
write: function(message) {
logger.info(message.trim());
}
};
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.engine("handlebars", exphbs({ defaultLayout: "main" }));
app.set("view engine", "handlebars");
app.use(favicon(path.join(__dirname, "public", "favicon.ico")))
.use(morgan("combined", { "stream": logger.stream }))
.use(cookieParser())
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: false }))
.use(session(
{
resave: true,
saveUninitialized: true,
secret: config["core"].machinekey ? config["core"].machinekey : config.app.machinekey
}))
.use(cors());
const machineKey = config["core"].machinekey
? config["core"].machinekey
: config.app.machinekey;
require("./app/middleware/saml")(app, config, logger);
require("./app/routes")(app, config, logger);
app
.use(favicon(path.join(__dirname, "public", "favicon.ico")))
.use(morgan("combined", { stream: winston.stream }))
.use(cookieParser())
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: false }))
.use(
session({
resave: true,
saveUninitialized: true,
secret: machineKey,
})
)
.use(cors());
require("./app/middleware/saml")(app, config);
require("./app/routes")(app, config);
const httpServer = http.createServer(app);
httpServer.listen(config.app.port,
function () {
logger.info(`Start SSO Service Provider listening on port ${config.app.port} for http`);
});
httpServer.listen(config.app.port, function () {
winston.info(
`Start SSO Service Provider listening on port ${config.app.port} ` +
`machineKey='${machineKey}' ` +
`appsettings path='${config.app.appsettings}'`
);
});

View File

@ -0,0 +1,101 @@
const winston = require("winston"),
WinstonCloudWatch = require("winston-cloudwatch");
require("winston-daily-rotate-file");
const path = require("path");
const config = require("../config");
const fs = require("fs");
const os = require("os");
const { randomUUID } = require("crypto");
const date = require("date-and-time");
let logpath = config.get("logPath");
if (logpath != null) {
if (!path.isAbsolute(logpath)) {
logpath = path.join(__dirname, "..", logpath);
}
}
const fileName = logpath
? path.join(logpath, "web.sso.%DATE%.log")
: path.join(__dirname, "..", "..", "..", "Logs", "web.sso.%DATE%.log");
const dirName = path.dirname(fileName);
const aws = config.get("aws").cloudWatch;
const accessKeyId = aws.accessKeyId;
const secretAccessKey = aws.secretAccessKey;
const awsRegion = aws.region;
const logGroupName = aws.logGroupName;
const logStreamName = aws.logStreamName
.replace("${hostname}", os.hostname())
.replace("${applicationContext}", "SsoAuth")
.replace("${guid}", randomUUID())
.replace("${date}", date.format(new Date(), "YYYY/MM/DDTHH.mm.ss"));
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName);
}
var options = {
file: {
filename: fileName,
datePattern: "MM-DD",
handleExceptions: true,
humanReadableUnhandledException: true,
zippedArchive: true,
maxSize: "50m",
maxFiles: "30d",
json: true,
},
console: {
level: "debug",
handleExceptions: true,
json: false,
colorize: true,
},
cloudWatch: {
name: "aws",
level: "debug",
logStreamName: logStreamName,
logGroupName: logGroupName,
awsRegion: awsRegion,
jsonMessage: true,
awsOptions: {
credentials: {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
},
},
},
};
let transports = [
new winston.transports.Console(options.console),
new winston.transports.DailyRotateFile(options.file),
];
if (aws != null && aws.accessKeyId !== "") {
transports.push(new WinstonCloudWatch(options.cloudWatch));
}
const customFormat = winston.format((info) => {
const now = new Date();
info.date = date.format(now, "YYYY-MM-DD HH:mm:ss");
info.applicationContext = "SsoAuth";
info.level = info.level.toUpperCase();
const hostname = os.hostname();
info["instance-id"] = hostname;
return info;
})();
module.exports = new winston.createLogger({
format: winston.format.combine(customFormat, winston.format.json()),
transports: transports,
exitOnError: false,
});

View File

@ -1,7 +1,7 @@
/*
*
* (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
@ -12,18 +12,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
*/
"use strict";
module.exports = (app, config, logger) => {
const urlResolver = require("../utils/resolver")(logger);
module.exports = (app, config) => {
const logger = require("../log.js");
const urlResolver = require("../utils/resolver")();
const coder = require("../utils/coder");
const converter = require("../utils/converter")(logger);
const converter = require("../utils/converter")();
const _ = require("lodash");
const fetch = require("node-fetch");
const routes = _.values(config.routes);
const machineKey = config["core"].machinekey
? config["core"].machinekey
: config.app.machinekey;
const fetchConfig = async (req, res, next) => {
const foundRoutes =
@ -33,9 +36,9 @@ module.exports = (app, config, logger) => {
})
: [];
if(req.originalUrl =="/isLife") {
res.sendStatus(200);
return;
if (req.originalUrl == "/isLife") {
res.sendStatus(200);
return;
}
if (!foundRoutes.length) {
@ -63,7 +66,7 @@ module.exports = (app, config, logger) => {
const text = await response.text();
const ssoConfig = coder.decodeData(text);
const ssoConfig = coder.decodeData(text, machineKey);
const idp = converter.toIdp(ssoConfig);

View File

@ -17,10 +17,11 @@
"use strict";
module.exports = function (app, config, logger) {
module.exports = function (app, config) {
const saml = require("samlify");
const { SamlLib: libsaml } = saml;
const urlResolver = require("./utils/resolver")(logger);
const logger = require("./log.js");
const urlResolver = require("./utils/resolver")();
const coder = require("./utils/coder");
const urn = require("samlify/build/src/urn");
const fetch = require("node-fetch");
@ -32,8 +33,10 @@ module.exports = function (app, config, logger) {
const UserModel = require("./model/user");
const LogoutModel = require("./model/logout");
const fs = require('fs');
let uploadDir = "";
const selfSignedDomain = "myselfsigned.crt";
const machineKey = config["core"].machinekey ? config["core"].machinekey : config.app.machinekey;
function verifySetting(req) {
if (!req.providersInfo.settings.EnableSso) {
@ -396,13 +399,14 @@ module.exports = function (app, config, logger) {
req.providersInfo.mapping
);
logger.info(`SSO User ${JSON.stringify(user)}`);
logger.info(`SSO User ${JSON.stringify(user)} machineKey=${machineKey}`);
// Use the parseResult can do customized action
const data = coder.encodeData(user);
const data = coder.encodeData(user, machineKey);
if (!data) {
logger.error("coder.encodeData", user);
logger.error("EncodeData response is EMPTY", user, machineKey);
return res.redirect(
urlResolver.getPortalAuthErrorUrl(
req,
@ -511,10 +515,14 @@ module.exports = function (app, config, logger) {
const relayState = urlResolver.getPortalAuthUrl(req);
const userData = coder.decodeData(req.query["data"]);
const queryData = req.query["data"];
logger.info(`sendLogoutRequest: data: ${queryData} machineKey=${machineKey}`);
const userData = coder.decodeData(queryData, machineKey);
if (!userData) {
logger.error(`coder.decodeData ${req.query["data"]}`);
logger.error("DecodeData response is EMPTY", queryData, machineKey);
return res.redirect(urlResolver.getPortal500Url(req));
}
@ -599,11 +607,12 @@ module.exports = function (app, config, logger) {
const sendPortalLogout = async (user, req) => {
try {
const data = coder.encodeData(user);
logger.info(`sendPortalLogout: SSO User ${JSON.stringify(user)} machineKey=${machineKey}`);
const data = coder.encodeData(user, machineKey);
if (!data) {
const errorMessage = `EncodeData is EMPTY`;
throw new Error(errorMessage);
throw new Error("EncodeData response is EMPTY", user, machineKey);
//return res.redirect(urlResolver.getPortal500Url(req));
}

View File

@ -17,26 +17,25 @@
"use strict";
const config = require("../../config").get(),
hash = require("./hash");
const hash = require("./hash");
var Coder = function() {
return {
encodeData: function(data) {
encodeData: function(data, machinekey) {
if (!data && typeof (data) !== "object")
return undefined;
const jsonStr = JSON.stringify(data);
const dataEncoded = hash.encode(jsonStr, config["machinekey"] ? config["core"].machinekey : config.app.machinekey);
const dataEncoded = hash.encode(jsonStr, machinekey);
return dataEncoded;
},
decodeData: function(data) {
decodeData: function(data, machinekey) {
if (!data && typeof (data) !== "string")
return undefined;
const jsonStr = hash.decode(data, config["core"].machinekey ? config["core"].machinekey : config.app.machinekey);
const jsonStr = hash.decode(data, machinekey);
const dataDecoded = JSON.parse(jsonStr);
return dataDecoded;

View File

@ -25,6 +25,7 @@ const _ = require("lodash");
const fs = require("fs");
const path = require("path");
const minifyXML = require("minify-xml").minify;
const logger = require("../log.js");
saml.setSchemaValidator(validator);
@ -33,7 +34,7 @@ const IdentityProvider = saml.IdentityProvider;
const templDir = path.join(process.cwd(),"../../common/ASC.SsoAuth", "/app/templates/");
module.exports = function (logger) {
module.exports = function () {
function removeCertHead(cert) {
var newCert = cert;
if (cert && cert[0] === "-") {
@ -283,5 +284,3 @@ module.exports = function (logger) {
},
};
};
//module.exports = Converter(logger);

View File

@ -1,7 +1,7 @@
/*
*
* (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
@ -12,73 +12,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
*/
"use strict";
const logger = require("../log.js");
var Hash = function () {
var getHashBase64 = function (str) {
const crypto = require("crypto");
const sha256 = crypto.createHash("sha256");
sha256.update(str, "utf8");
const result = sha256.digest("base64");
return result;
};
var getHashBase64 = function (str) {
const crypto = require("crypto");
const sha256 = crypto.createHash("sha256");
sha256.update(str, "utf8");
const result = sha256.digest("base64");
return result;
};
return {
encode: function(str, secret) {
try {
const strHash = getHashBase64(str + secret) + "?" + str;
return {
encode: function (str, secret) {
try {
const strHash = getHashBase64(str + secret) + "?" + str;
let data = new Buffer(strHash).toString("base64");
let data = Buffer.from(strHash).toString("base64");
let cnt = 0;
while (data.indexOf("=") !== -1) {
cnt++;
data = data.replace("=", "");
}
data = data.replace(/\+/g, "-").replace(/\//g, "_");
data = (data + cnt).replace(/\+/g, "-").replace(/\//g, "_");
return data;
} catch (ex) {
logger?.error("hash.encode", str, secret, ex);
return null;
}
},
decode: function (str, secret) {
try {
let strDecoded = Buffer.from(unescape(str), "base64").toString();
return data;
const lastIndex = strDecoded.lastIndexOf("}");
} catch (ex) {
return null;
}
},
decode: function(str, secret) {
try {
let strDecoded = Buffer.from(unescape(str), "base64").toString();
const lastIndex = strDecoded.lastIndexOf("}");
if (lastIndex + 1 < strDecoded.length) {
strDecoded = strDecoded.substring(0, lastIndex + 1);
}
const index = strDecoded.indexOf("?");
if (index > 0 && strDecoded[index + 1] == '{') {
let hash = strDecoded.substring(0, index);
let data = strDecoded.substring(index + 1);
if(getHashBase64(data + secret) === hash)
{
return data;
}
}
// Sig incorrect
return null;
} catch (ex) {
console.error("hash.decode", str, secret, ex);
return null;
}
if (lastIndex + 1 < strDecoded.length) {
strDecoded = strDecoded.substring(0, lastIndex + 1);
}
};
const index = strDecoded.indexOf("?");
if (index > 0 && strDecoded[index + 1] == "{") {
let hash = strDecoded.substring(0, index);
let data = strDecoded.substring(index + 1);
if (getHashBase64(data + secret) === hash) {
return data;
}
}
// Sig incorrect
return null;
} catch (ex) {
logger?.error("hash.decode", str, secret, ex);
return null;
}
},
};
};
module.exports = Hash();

View File

@ -18,11 +18,11 @@
"use strict";
const config = require("../../config").get(),
// ReSharper disable once InconsistentNaming
URL = require("url");
logger = require("../log.js");
URL = require("url");
// ReSharper disable once InconsistentNaming
module.exports = function (logger) {
module.exports = function () {
function getBaseUrl(req) {
const url = req.headers["x-rewriter-url"] || req.protocol + "://" + req.get("host");

View File

@ -72,7 +72,10 @@ const accessKeyId = aws.accessKeyId;
const secretAccessKey = aws.secretAccessKey;
const awsRegion = aws.region;
const logGroupName = aws.logGroupName;
const logStreamName = aws.logStreamName;
const logStreamName = aws.logStreamName.replace("${hostname}", os.hostname())
.replace("${applicationContext}", "WebDav")
.replace("${guid}", randomUUID())
.replace("${date}", date.format(new Date(), 'YYYY/MM/DDTHH.mm.ss'));
let transports = [
new (winston.transports.Console)(),
@ -85,17 +88,7 @@ if (aws != null && aws.accessKeyId !== '')
transports.push(new WinstonCloudWatch({
name: 'aws',
level: "debug",
logStreamName: () => {
const hostname = os.hostname();
const now = new Date();
const guid = randomUUID();
const dateAsString = date.format(now, 'YYYY/MM/DDTHH.mm.ss');
return logStreamName.replace("${hostname}", hostname)
.replace("${applicationContext}", "WebDav")
.replace("${guid}", guid)
.replace("${date}", dateAsString);
},
logStreamName: logStreamName,
logGroupName: logGroupName,
awsRegion: awsRegion,
jsonMessage: true,

View File

@ -32,7 +32,10 @@ const accessKeyId = aws.accessKeyId;
const secretAccessKey = aws.secretAccessKey;
const awsRegion = aws.region;
const logGroupName = aws.logGroupName;
const logStreamName = aws.logStreamName;
const logStreamName = aws.logStreamName.replace("${hostname}", os.hostname())
.replace("${applicationContext}", "WebPlugins")
.replace("${guid}", randomUUID())
.replace("${date}", date.format(new Date(), 'YYYY/MM/DDTHH.mm.ss'));
const options = {
file: {
@ -54,18 +57,8 @@ const options = {
cloudWatch: {
name: 'aws',
level: "debug",
logStreamName: () => {
const hostname = os.hostname();
const now = new Date();
const guid = randomUUID();
const dateAsString = date.format(now, 'YYYY/MM/DDTHH.mm.ss');
return logStreamName.replace("${hostname}", hostname)
.replace("${applicationContext}", "WebPlugins")
.replace("${guid}", guid)
.replace("${date}", dateAsString);
},
logGroupName:logGroupName,
logStreamName: logStreamName,
logGroupName: logGroupName,
awsRegion: awsRegion,
jsonMessage: true,
awsOptions: {

View File

@ -56,11 +56,26 @@ public class LocalesTest
}
}
public static bool Save
{
get
{
bool save;
if (bool.TryParse(Environment.GetEnvironmentVariable("SAVE"), out save))
{
return save;
}
return false;
}
}
public List<string> Workspaces { get; set; }
public List<TranslationFile> TranslationFiles { get; set; }
public List<JavaScriptFile> JavaScriptFiles { get; set; }
public List<ModuleFolder> ModuleFolders { get; set; }
public List<KeyValuePair<string, string>> NotTranslatedToasts { get; set; }
public List<KeyValuePair<string, string>> NotTranslatedProps { get; set; }
public List<LanguageItem> CommonTranslations { get; set; }
public List<ParseJsonError> ParseJsonErrors { get; set; }
public static string ConvertPathToOS { get; private set; }
@ -68,13 +83,19 @@ public class LocalesTest
//public List<JsonEncodingError> WrongEncodingJsonErrors { get; set; }
private static readonly string _md5ExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../md5-excludes.json"));
private static readonly string _spellCheckCommonExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../spellcheck-excludes-common.json"));
private static readonly string _spellCheckExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../spellcheck-excludes.json"));
//private static string _encodingExcludesPath = "../../../encoding-excludes.json";
private static readonly List<string> _md5Excludes = File.Exists(_md5ExcludesPath)
private static readonly List<string> Md5Excludes = File.Exists(_md5ExcludesPath)
? JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(_md5ExcludesPath))
: new List<string>();
private static readonly List<string> SpellCheckCommonExcludes = File.Exists(_spellCheckCommonExcludesPath)
? JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(_spellCheckCommonExcludesPath))
: new List<string>();
//private static List<string> encodingExcludes = File.Exists(_encodingExcludesPath)
// ? JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(_encodingExcludesPath))
// : new List<string>();
@ -201,7 +222,10 @@ public class LocalesTest
"|(?<=toastr.success\\([\"`\'])(.*)(?=[\"\'`])" +
"|(?<=toastr.warn\\([\"`\'])(.*)(?=[\"\'`])", RegexOptions.Multiline | RegexOptions.ECMAScript);
var notTranslatedPropsRegex = new Regex("<[\\w\\n][^>]* (title|placeholder|label|text)={?[\\\"\\'](.*)[\\\"\\']}?", RegexOptions.Multiline | RegexOptions.ECMAScript);
NotTranslatedToasts = new List<KeyValuePair<string, string>>();
NotTranslatedProps = new List<KeyValuePair<string, string>>();
foreach (var path in javascriptFiles)
{
@ -219,6 +243,18 @@ public class LocalesTest
}
}
var propsMatches = notTranslatedPropsRegex.Matches(jsFileText).ToList();
if (propsMatches.Any())
{
foreach (var propsMatch in propsMatches)
{
var found = propsMatch.Value;
if (!string.IsNullOrEmpty(found) && !NotTranslatedProps.Exists(t => t.Value == found))
NotTranslatedProps.Add(new KeyValuePair<string, string>(path, found));
}
}
var matches = regexp.Matches(jsFileText);
var translationKeys = matches
@ -318,7 +354,11 @@ public class LocalesTest
TestContext.Progress.WriteLine($"Found CommonTranslations = {CommonTranslations.Count()}. First path is '{CommonTranslations.FirstOrDefault()?.Path}'");
TestContext.Progress.WriteLine($"Found _md5Excludes = {_md5Excludes.Count()} Path to file '{_md5ExcludesPath}'");
TestContext.Progress.WriteLine($"Found Md5Excludes = {Md5Excludes.Count} Path to file '{_md5ExcludesPath}'");
TestContext.Progress.WriteLine($"Found SpellCheckCommonExcludes = {SpellCheckCommonExcludes.Count} Path to file '{_spellCheckCommonExcludesPath}'");
TestContext.Progress.WriteLine($"Save spell check excludes = {Save} Path to file '{_spellCheckExcludesPath}'");
}
@ -359,7 +399,7 @@ public class LocalesTest
var errorsCount = 0;
var message = $"Next keys have spell check issues:\r\n\r\n";
//var list = new List<SpellCheckExclude>();
var list = new List<SpellCheckExclude>();
var groupByLng = TranslationFiles
.GroupBy(t => t.Language)
@ -376,7 +416,7 @@ public class LocalesTest
{
var dicPaths = SpellCheck.GetDictionaryPaths(group.Language);
//var spellCheckExclude = new SpellCheckExclude(group.Language);
var spellCheckExclude = new SpellCheckExclude(group.Language);
using (var dictionaryStream = File.OpenRead(dicPaths.DictionaryPath))
using (var affixStream = File.OpenRead(dicPaths.AffixPath))
@ -391,27 +431,44 @@ public class LocalesTest
if (result.HasProblems)
{
message += $"{++i}. lng='{group.Language}' file='{g.FilePath}'\r\nkey='{item.Key}' value='{item.Value}'\r\nIncorrect words:\r\n{string.Join("\r\n", result.SpellIssues.Select(issue => $"'{issue.Word}' Suggestion: '{issue.Suggestions.FirstOrDefault()}'"))}\r\n\r\n";
var incorrectWords = result.SpellIssues
.Where(t => !SpellCheckCommonExcludes
.Exists(e => e.Equals(t.Word, StringComparison.InvariantCultureIgnoreCase)))
.Select(issue => $"'{issue.Word}' " +
$"Suggestion: '{issue.Suggestions.FirstOrDefault()}'")
.ToList();
if (!incorrectWords.Any())
continue;
message += $"{++i}. lng='{group.Language}' file='{g.FilePath}'\r\nkey='{item.Key}' " +
$"value='{item.Value}'\r\nIncorrect words:\r\n" +
$"{string.Join("\r\n", incorrectWords)}\r\n\r\n";
errorsCount++;
/*foreach (var word in result.SpellIssues
if (Save)
{
foreach (var word in result.SpellIssues
.Where(issue => issue.Suggestions.Any())
.Select(issue => issue.Word))
{
if (!spellCheckExclude.Excludes.Contains(word))
{
spellCheckExclude.Excludes.Add(word);
}
}*/
.Select(issue => issue.Word))
{
if (!spellCheckExclude.Excludes.Contains(word))
{
spellCheckExclude.Excludes.Add(word);
}
}
}
}
}
}
}
//spellCheckExclude.Excludes.Sort();
//list.Add(spellCheckExclude);
if (Save)
{
spellCheckExclude.Excludes.Sort();
list.Add(spellCheckExclude);
}
}
catch (NotSupportedException)
{
@ -420,8 +477,12 @@ public class LocalesTest
}
}
//string json = JsonConvert.SerializeObject(list, Formatting.Indented);
//File.WriteAllText("../../../spellcheck-excludes.json", json, Encoding.UTF8);
if (Save)
{
string json = JsonConvert.SerializeObject(list, Formatting.Indented);
File.WriteAllText(_spellCheckExcludesPath, json, Encoding.UTF8);
TestContext.Progress.WriteLine($"File spellcheck-excludes.json has been saved to '{_spellCheckExcludesPath}'");
}
Assert.AreEqual(0, errorsCount, message);
}
@ -443,7 +504,7 @@ public class LocalesTest
{
var duplicatesByMD5 = TranslationFiles
.Where(t => t.Language != "pt-BR")
.Where(t => !_md5Excludes.Contains(t.Md5Hash))
.Where(t => !Md5Excludes.Contains(t.Md5Hash))
.GroupBy(t => t.Md5Hash)
.Where(grp => grp.Count() > 1)
.Select(grp => new { Key = grp.Key, Count = grp.Count(), Paths = grp.ToList().Select(f => f.FilePath) })
@ -747,7 +808,10 @@ public class LocalesTest
continue;
}
var exepts = new List<string> { "Error", "Done", "Warning", "Alert", "Info" };
var notCommonKeys = module.AppliedJsTranslationKeys
.Except(exepts)
.Where(k => !k.StartsWith("Common:"))
.OrderBy(t => t)
.ToList();
@ -1079,11 +1143,34 @@ public class LocalesTest
Assert.AreEqual(0, NotTranslatedToasts.Count, message);
}
[Test]
[Category("Locales")]
public void NotTranslatedPropsTest()
{
var message = $"Next text not translated props (title, placeholder, label, text):\r\n\r\n";
var i = 0;
NotTranslatedProps.GroupBy(t => t.Key)
.Select(g => new
{
FilePath = g.Key,
Values = g.ToList()
})
.ToList()
.ForEach(t =>
{
message += $"{++i}. Path='{t.FilePath}'\r\n\r\n{string.Join("\r\n", t.Values.Select(v => v.Value))}\r\n\r\n";
});
Assert.AreEqual(0, NotTranslatedProps.Count, message);
}
[Test]
[Category("Locales")]
public void WrongTranslationVariablesTest()
{
var message = $"Next keys have wrong variables:\r\n\r\n";
var message = $"Next keys have wrong or empty variables:\r\n\r\n";
var regVariables = new Regex("\\{\\{([^\\{].?[^\\}]+)\\}\\}", RegexOptions.Compiled | RegexOptions.Multiline);
var groupedByLng = TranslationFiles
@ -1092,8 +1179,8 @@ public class LocalesTest
{
Language = g.Key,
TranslationsWithVariables = g.ToList()
.SelectMany(t => t.Translations)
.Where(k => k.Value.IndexOf("{{") != -1)
.SelectMany(t => t.Translations)
//.Where(k => k.Value.IndexOf("{{") != -1)
.Select(t => new
{
t.Key,
@ -1109,6 +1196,7 @@ public class LocalesTest
var enWithVariables = groupedByLng
.Where(t => t.Language == "en")
.SelectMany(t => t.TranslationsWithVariables)
.Where(t => t.Variables.Count > 0)
.ToList();
var otherLanguagesWithVariables = groupedByLng
@ -1118,11 +1206,129 @@ public class LocalesTest
var i = 0;
var errorsCount = 0;
foreach (var lng in otherLanguagesWithVariables)
{
foreach (var t in lng.TranslationsWithVariables)
foreach (var enKeyWithVariables in enWithVariables)
{
foreach (var lng in otherLanguagesWithVariables)
{
var lngKey = lng.TranslationsWithVariables
.Where(t => t.Key == enKeyWithVariables.Key)
.FirstOrDefault();
if (lngKey == null)
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{enKeyWithVariables.Key}' not found\r\n\r\n";
errorsCount++;
continue;
}
if (enKeyWithVariables.Variables.Count != lngKey.Variables.Count)
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has less variables then 'en' language have " +
$"(en={enKeyWithVariables.Variables.Count}|{lng.Language}={lngKey.Variables.Count})\r\n" +
$"'en': '{enKeyWithVariables.Value}'\r\n'{lng.Language}': '{lngKey.Value}'\r\n\r\n";
errorsCount++;
}
if (!lngKey.Variables.All(v => enKeyWithVariables.Variables.Contains(v)))
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has not equals variables of 'en' language have \r\n" +
$"'{enKeyWithVariables.Value}' Variables=[{string.Join(",", enKeyWithVariables.Variables)}]\r\n" +
$"'{lngKey.Value}' Variables=[{string.Join(",", lngKey.Variables)}]\r\n\r\n";
errorsCount++;
}
}
}
Assert.AreEqual(0, errorsCount, message);
}
[Test]
[Category("Locales")]
public void WrongTranslationTagsTest()
{
var message = $"Next keys have wrong or empty translation's html tags:\r\n\r\n";
var regString = "<([^>]*)>(\\s*(.+?)\\s*)</([^>/]*)>";
var regTags = new Regex(regString, RegexOptions.Compiled | RegexOptions.Multiline);
var groupedByLng = TranslationFiles
.GroupBy(t => t.Language)
.Select(g => new
{
var enKey = enWithVariables
Language = g.Key,
TranslationsWithTags = g.ToList()
.SelectMany(t => t.Translations)
//.Where(k => k.Value.IndexOf("<") != -1)
.Select(t => new
{
t.Key,
t.Value,
Tags = regTags.Matches(t.Value)
.Select(m => m.Groups[1]?.Value?.Trim())
.ToList()
})
.ToList()
})
.ToList();
var enWithTags = groupedByLng
.Where(t => t.Language == "en")
.SelectMany(t => t.TranslationsWithTags)
.Where(t => t.Tags.Count > 0)
.ToList();
var otherLanguagesWithTags = groupedByLng
.Where(t => t.Language != "en")
.ToList();
var i = 0;
var errorsCount = 0;
foreach (var enKeyWithTags in enWithTags)
{
foreach (var lng in otherLanguagesWithTags)
{
var lngKey = lng.TranslationsWithTags
.Where(t => t.Key == enKeyWithTags.Key)
.FirstOrDefault();
if (lngKey == null)
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{enKeyWithTags.Key}' not found\r\n\r\n";
errorsCount++;
continue;
}
if (enKeyWithTags.Tags.Count != lngKey.Tags.Count)
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has less tags then 'en' language have " +
$"(en={enKeyWithTags.Tags.Count}|{lng.Language}={lngKey.Tags.Count})\r\n" +
$"'en': '{enKeyWithTags.Value}'\r\n'{lng.Language}': '{lngKey.Value}'\r\n\r\n";
errorsCount++;
}
if (!lngKey.Tags.All(v => enKeyWithTags.Tags.Contains(v)))
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has not equals tags of 'en' language have \r\n" +
$"'{enKeyWithTags.Value}' Tags=[{string.Join(",", enKeyWithTags.Tags)}]\r\n" +
$"'{lngKey.Value}' Tags=[{string.Join(",", lngKey.Tags)}]\r\n\r\n";
errorsCount++;
}
}
}
/*foreach (var lng in otherLanguagesWithTags)
{
foreach (var t in lng.TranslationsWithTags)
{
var enKey = enWithTags
.Where(en => en.Key == t.Key)
.FirstOrDefault();
@ -1134,25 +1340,25 @@ public class LocalesTest
continue;
}
if (enKey.Variables.Count != t.Variables.Count)
if (enKey.Tags.Count != t.Tags.Count)
{
// wrong
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has less variables then 'en' language have " +
$"(en={enKey.Variables.Count}|{lng.Language}={t.Variables.Count})\r\n" +
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has less tags then 'en' language have " +
$"(en={enKey.Tags.Count}|{lng.Language}={t.Tags.Count})\r\n" +
$"'en': '{enKey.Value}'\r\n'{lng.Language}': '{t.Value}'\r\n\r\n";
errorsCount++;
}
if (!t.Variables.All(v => enKey.Variables.Contains(v)))
if (!t.Tags.All(v => enKey.Tags.Contains(v)))
{
// wrong
errorsCount++;
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has not equals variables of 'en' language have\r\n\r\n" +
$"Have to be:\r\n'{enKey.Value}'\r\n\r\n{string.Join("\r\n", enKey.Variables)}\r\n\r\n" +
$"But in real:\r\n'{t.Value}'\r\n\r\n{string.Join("\r\n", t.Variables)} \r\n\r\n";
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has not equals tags of 'en' language have\r\n\r\n" +
$"Have to be:\r\n'{enKey.Value}'\r\n\r\n{string.Join("\r\n", enKey.Tags)}\r\n\r\n" +
$"But in real:\r\n'{t.Value}'\r\n\r\n{string.Join("\r\n", t.Tags)} \r\n\r\n";
}
}
}
}*/
Assert.AreEqual(0, errorsCount, message);
}

View File

@ -0,0 +1,20 @@
[
"Amazon",
"AWS",
"DocSpace",
"ONLYOFFICE",
"ID",
"IP",
"IPv4",
"IPv",
"DNS",
"SVG",
"PNG",
"NameId",
"IdP",
"Sp",
"macOS",
"SAML",
"Stripe",
"SDK"
]

View File

@ -102,15 +102,15 @@ public class PortalController : ControllerBase
[HttpPost("register")]
[AllowCrossSiteJson]
[Authorize(AuthenticationSchemes = "auth:allowskip:registerportal")]
public Task<IActionResult> RegisterAsync(TenantModel model)
public async Task<IActionResult> RegisterAsync(TenantModel model)
{
if (model == null)
{
return Task.FromResult<IActionResult>(BadRequest(new
return BadRequest(new
{
error = "portalNameEmpty",
message = "PortalName is required"
}));
});
}
if (!ModelState.IsValid)
@ -122,11 +122,11 @@ public class PortalController : ControllerBase
message.Add(ModelState[k].Errors.FirstOrDefault().ErrorMessage);
}
return Task.FromResult<IActionResult>(BadRequest(new
return BadRequest(new
{
error = "params",
message
}));
});
}
var sw = Stopwatch.StartNew();
@ -136,7 +136,7 @@ public class PortalController : ControllerBase
if (!CheckPasswordPolicy(model.Password, out var error1))
{
sw.Stop();
return Task.FromResult<IActionResult>(BadRequest(error1));
return BadRequest(error1);
}
if (!string.IsNullOrEmpty(model.Password))
@ -152,16 +152,11 @@ public class PortalController : ControllerBase
{
sw.Stop();
return Task.FromResult<IActionResult>(BadRequest(error));
return BadRequest(error);
}
return InternalRegisterAsync(model, error, sw);
}
private async Task<IActionResult> InternalRegisterAsync(TenantModel model, object error, Stopwatch sw)
{
model.PortalName = (model.PortalName ?? "").Trim();
var (exists, _) = await CheckExistingNamePortalAsync(model.PortalName);
(var exists, error) = await CheckExistingNamePortalAsync(model.PortalName);
if (!exists)
{

View File

@ -66,8 +66,8 @@ public class Startup : BaseStartup
services.AddHostedService<BackupCleanerTempFileService>();
services.AddHostedService<BackupWorkerService>();
services.AddActivePassiveHostedService<BackupCleanerService>();
services.AddActivePassiveHostedService<BackupSchedulerService>();
services.AddActivePassiveHostedService<BackupCleanerService>(DIHelper);
services.AddActivePassiveHostedService<BackupSchedulerService>(DIHelper);
services.AddBaseDbContextPool<BackupsContext>();
services.AddBaseDbContextPool<FilesDbContext>();

View File

@ -82,38 +82,20 @@ public abstract class FeedModule : IFeedModule
}
}
protected string GetGroupId(string item, Guid author, string rootId = null, int action = -1)
protected string GetGroupId(string item, Guid author, DateTime date, string rootId = null, int action = -1)
{
const int interval = 2;
var now = DateTime.UtcNow;
var hours = now.Hour;
var groupIdHours = hours - (hours % interval);
var time = date.ToString("g");
if (rootId == null)
{
// groupId = {item}_{author}_{date}
return string.Format("{0}_{1}_{2}",
item,
author,
now.ToString("yyyy.MM.dd.") + groupIdHours);
return $"{item}_{author}_{time}";
}
if (action == -1)
{
// groupId = {item}_{author}_{date}_{rootId}_{action}
return string.Format("{0}_{1}_{2}_{3}",
item,
author,
now.ToString("yyyy.MM.dd.") + groupIdHours,
rootId);
return $"{item}_{author}_{time}_{rootId}";
}
// groupId = {item}_{author}_{date}_{rootId}_{action}
return string.Format("{0}_{1}_{2}_{3}_{4}",
item,
author,
now.ToString("yyyy.MM.dd.") + groupIdHours,
rootId,
action);
return $"{item}_{author}_{time}_{rootId}_{action}";
}
}

View File

@ -53,8 +53,8 @@ public class Startup : BaseWorkerStartup
DIHelper.TryAdd<NotifyInvokeSendMethodRequestedIntegrationEventHandler>();
DIHelper.TryAdd<NotifySendMessageRequestedIntegrationEventHandler>();
services.AddActivePassiveHostedService<NotifySenderService>();
services.AddActivePassiveHostedService<NotifyCleanerService>();
services.AddActivePassiveHostedService<NotifySenderService>(DIHelper);
services.AddActivePassiveHostedService<NotifyCleanerService>(DIHelper);
services.AddBaseDbContextPool<NotifyDbContext>();
}

View File

@ -69,15 +69,15 @@
"enable": [ "box", "dropboxv2", "docusign", "google", "onedrive", "sharepoint", "nextcloud", "owncloud", "webdav", "kdrive" ]
},
"docservice": {
"coauthor-docs": [ ".csv", ".docm", ".docx", ".docxf", ".dotm", ".dotx", ".oform", ".potm", ".potx", ".ppsm", ".pptm", ".ppsx", ".pptx", ".txt", ".xlsm", ".xlsx", ".xltm", ".xltx" ],
"commented-docs": [ ".docm", ".docx", ".docxf", ".dotm", ".dotx", ".potm", ".potx", ".ppsm", ".pptm", ".ppsx", ".pptx", ".xlsm", ".xlsx", ".xltm", ".xltx" ],
"convert-docs": [ ".doc", ".dot", ".dps", ".dpt", ".epub", ".et", ".ett", ".fb2", ".fodp", ".fods", ".fodt", ".htm", ".html", ".mht", ".mhtml", ".odp", ".ods", ".odt", ".otp", ".ots", ".ott", ".pot", ".pps", ".ppt", ".rtf", ".stw", ".sxc", "sxi", ".sxw", ".wps", ".wpt", ".xls", ".xlsb", ".xlt", ".xml" ],
"edited-docs": [ "csv", ".doc", ".docm", ".docx", ".docxf", ".dot", ".dotm", ".dotx", ".dps", ".dpt", ".epub", ".et", ".ett", ".fb2", ".fodp", ".fods", ".fodt", ".htm", ".html", ".mht", ".mhtml", ".odp", ".ods", ".odt", ".oform", ".otp", ".ots", ".ott", ".pot", ".potm", ".potx", ".pps", ".ppsm", ".ppsx", ".ppt", ".pptm", ".pptx", ".rtf", ".stw", ".sxc", "sxi", ".sxw", ".txt", ".wps", ".wpt", ".xls", ".xlsb", ".xlsm", ".xlsx", ".xlt", ".xltm", ".xltx", ".xml" ],
"encrypted-docs": [ ".docm", ".docx", ".docxf", ".dotm", ".dotx", ".oform", ".potm", ".potx", ".ppsm", ".pptm", ".ppsx", ".pptx", ".xlsm", ".xlsx", ".xltm", ".xltx" ],
"coauthor-docs": [ ".pptx", ".ppsx", ".xlsx", ".csv", ".docx", ".docxf", ".oform", ".txt" ],
"commented-docs": [ ".docx", ".docxf", ".xlsx", ".pptx" ],
"convert-docs": [ ".pptm", ".ppt", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".rtf", ".xml" ],
"edited-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".csv", ".docx", ".docxf", ".oform", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".txt", ".rtf", ".mht", ".html", ".htm" ],
"encrypted-docs": [ ".docx", ".docxf", ".xlsx", ".pptx", ".oform" ],
"formfilling-docs": [ ".oform" ],
"customfilter-docs": [ ".xlsm", ".xlsx", ".xltm", ".xltx" ],
"reviewed-docs": [ ".docm", ".docx", ".docxf", ".dotm", ".dotx" ],
"viewed-docs": [ ".csv", ".djvu", ".doc", ".docm", ".docx", ".docxf", ".dot", ".dotm", ".dotx", ".dps", ".dpt", ".epub", ".et", ".ett", ".fb2", ".fodp", ".fods", ".fodt", ".gdoc", ".gsheet", ".gslides", ".htm", ".html", ".mht", ".mhtml", ".odp", ".ods", ".odt", ".oform", ".otp", ".ots", ".ott", ".oxps", ".pdf", ".pot", ".potm", ".potx", ".pps", ".ppsm", ".ppsx", ".ppt", ".pptm", ".pptx", ".rtf", ".stw", ".sxc", "sxi", ".sxw", ".txt", ".wps", ".wpt", ".xls", ".xlsb", ".xlsm", ".xlsx", ".xlt", ".xltm", ".xltx", ".xml", ".xps" ],
"customfilter-docs": [ ".xlsx" ],
"reviewed-docs": [ ".docx", ".docxf" ],
"viewed-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".gslides", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".gsheet", ".csv", ".docx", ".docxf", ".oform", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".gdoc", ".txt", ".rtf", ".mht", ".html", ".htm", ".xml", ".fb2", ".epub", ".pdf", ".djvu", ".xps", ".oxps" ],
"secret": {
"value": "secret",
"header": "AuthorizationJwt"
@ -110,6 +110,8 @@
"min": 3,
"max": 50
},
"api-system":"",
"api-cache":"",
"images": "static/images",
"hide-settings": "Monitoring,LdapSettings,DocService,MailService,PublicPortal,ProxyHttpContent,SpamSubscription,FullTextSearch",
"hub": {
@ -120,30 +122,24 @@
"controlpanel": {
"url": ""
},
"legalterms": "https://www.onlyoffice.com/legalterms.aspx",
"support-feedback": "https://helpdesk.onlyoffice.com",
"teamlab-site": "http://www.onlyoffice.com",
"help-center": "https://helpcenter.onlyoffice.com/{ru|de|fr|es|it}",
"max-upload-size" : 5242880
"book-training-email": "training@onlyoffice.com",
"documentation-email": "documentation@onlyoffice.com",
"max-upload-size" : 5242880,
"zendesk-key" : ""
},
"ConnectionStrings": {
"default": {
"name": "default",
"connectionString": "Server=localhost;Database=docspace;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
},
"postgre": {
"name": "postgre",
"connectionString": "Host=localhost;Port=5432;Database=docspace;Username=postgres;Password=dev;",
"providerName": "Npgsql"
},
"mysql": {
"name": "mysql",
"connectionString": "Server=localhost;Database=docspace;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
},
"teamlabsite": {
"name": "docspacesite",
"connectionString": "Server=localhost;Database=docspacesite;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"name": "teamlabsite",
"connectionString": "Server=localhost;Database=teamlabsite;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
}
},

View File

@ -150,38 +150,6 @@
"clickatellapiKey": ""
}
}
},
{
"type": "ASC.FederatedLogin.LoginProviders.DocuSignLoginProvider, ASC.FederatedLogin",
"services": [
{
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
},
{
"type": "ASC.FederatedLogin.LoginProviders.DocuSignLoginProvider, ASC.FederatedLogin"
},
{
"key": "docuSign",
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
},
{
"key": "docuSign",
"type": "ASC.FederatedLogin.LoginProviders.DocuSignLoginProvider, ASC.FederatedLogin"
}
],
"instanceScope": "perlifetimescope",
"parameters": {
"name": "docuSign",
"order": "1",
"props": {
"docuSignClientId": "",
"docuSignClientSecret": "",
"docuSignHost": ""
},
"additional": {
"docuSignRedirectUrl" : "https://service.teamlab.info/oauth2.aspx"
}
}
},
{
"type": "ASC.FederatedLogin.LoginProviders.DropboxLoginProvider, ASC.FederatedLogin",
@ -338,37 +306,6 @@
"linkedInRedirectUrl" : "https://service.teamlab.info/oauth2.aspx"
}
}
},
{
"type": "ASC.FederatedLogin.LoginProviders.MailRuLoginProvider, ASC.FederatedLogin",
"services": [
{
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
},
{
"type": "ASC.FederatedLogin.LoginProviders.MailRuLoginProvider, ASC.FederatedLogin"
},
{
"key": "mailru",
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
},
{
"key": "mailru",
"type": "ASC.FederatedLogin.LoginProviders.MailRuLoginProvider, ASC.FederatedLogin"
}
],
"instanceScope": "perlifetimescope",
"parameters": {
"name": "mailru",
"order": "4",
"props": {
"mailRuClientId": "",
"mailRuClientSecret": ""
},
"additional": {
"mailRuRedirectUrl" : "https://service.teamlab.info/oauth2.aspx"
}
}
},
{
"type": "ASC.FederatedLogin.LoginProviders.OneDriveLoginProvider, ASC.FederatedLogin",

View File

@ -191,7 +191,9 @@ server {
location ~* /(authentication|modules|portal|security|settings|smtpsettings|capabilities|thirdparty|encryption|feed) {
proxy_pass http://127.0.0.1:5000;
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location ~* portal/(.*)(backup|restore)(.*) {
rewrite (.*)/portal/(.*) $1/backup/$2 break;
proxy_redirect off;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6
licenses.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
isValidLicense: (license) => {
const valid = new RegExp("\\b(mit|apache\\b.*2|bsd|isc|unlicense)\\b", "i");
return valid.test(license);
},
};

View File

@ -73,7 +73,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -1,
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1",
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,oauth,total_size:107374182400,file_size:100,manager:1",
Name = "trial",
Price = 0m,
Visible = false
@ -81,7 +81,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -2,
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,oauth,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Name = "admin",
Price = 30m,
ProductId = "1002",
@ -90,7 +90,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -3,
Features = "free,total_size:2147483648,manager:5,room:5",
Features = "free,total_size:2147483648,manager:3,room:12",
Name = "startup",
Price = 0m,
Visible = false

View File

@ -120,17 +120,17 @@ public partial class CoreDbContextMigrate : Migration
migrationBuilder.InsertData(
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "product_id" },
values: new object[] { -3, null, "free,total_size:2147483648,manager:5,room:5", "startup", null });
values: new object[] { -3, null, "free,total_size:2147483648,manager:3,room:12", "startup", null });
migrationBuilder.InsertData(
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "price", "product_id", "visible" },
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,thirdparty,restore,contentsearch,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,thirdparty,restore,oauth,contentsearch,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
migrationBuilder.InsertData(
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "product_id" },
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1", "trial", null });
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,thirdparty,restore,oauth,total_size:107374182400,file_size:100,manager:1", "trial", null });
migrationBuilder.CreateIndex(
name: "last_modified",

View File

@ -70,7 +70,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -1,
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1",
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,oauth,total_size:107374182400,file_size:100,manager:1",
Name = "trial",
Price = 0m,
Visible = false
@ -78,7 +78,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -2,
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,oauth,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Name = "admin",
Price = 30m,
ProductId = "1002",
@ -87,7 +87,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
new
{
Tenant = -3,
Features = "free,total_size:2147483648,manager:5,room:5",
Features = "free,total_size:2147483648,manager:3,room:12",
Name = "startup",
Price = 0m,
Visible = false

View File

@ -362,355 +362,412 @@ public partial class FilesDbContextMigrate : Migration
table: "files_converts",
columns: new[] { "input", "output" },
values: new object[,]
{
{ ".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" },
{ ".ods", ".csv" },
{ ".ods", ".ots" },
{ ".ods", ".pdf" },
{ ".ods", ".xlsm" },
{ ".ods", ".xlsx" },
{ ".ods", ".xltm" },
{ ".ods", ".xltx" },
{ ".odt", ".docm" },
{ ".odt", ".docx" },
{ ".odt", ".dotm" },
{ ".odt", ".dotx" },
{ ".odt", ".epub" },
{ ".odt", ".fb2" },
{ ".odt", ".html" },
{ ".odt", ".ott" },
{ ".odt", ".pdf" },
{ ".odt", ".rtf" },
{ ".odt", ".txt" },
{ ".otp", ".odp" },
{ ".otp", ".pdf" },
{ ".otp", ".potm" },
{ ".otp", ".potx" },
{ ".otp", ".pptm" },
{ ".otp", ".pptx" },
{ ".ots", ".csv" },
{ ".ots", ".ods" },
{ ".ots", ".pdf" },
{ ".ots", ".xlsm" },
{ ".ots", ".xlsx" },
{ ".ots", ".xltm" },
{ ".ots", ".xltx" },
{ ".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", ".potm" },
{ ".pot", ".potx" },
{ ".pot", ".pptm" },
{ ".pot", ".pptx" },
{ ".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" }
{
{ ".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", ".docm "},
{ ".docxf", ".docx "},
{ ".docxf", ".dotm "},
{ ".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", ".ppsm "},
{ ".fodp", ".ppsx "},
{ ".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", ".ppsm "},
{ ".odp", ".ppsx "},
{ ".odp", ".pptm "},
{ ".odp", ".pptx "},
{ ".ods", ".csv "},
{ ".ods", ".ots "},
{ ".ods", ".pdf "},
{ ".ods", ".xlsm "},
{ ".ods", ".xlsx "},
{ ".ods", ".xltm "},
{ ".ods", ".xltx "},
{ ".odt", ".docm "},
{ ".odt", ".docx "},
{ ".odt", ".dotm "},
{ ".odt", ".dotx "},
{ ".odt", ".epub "},
{ ".odt", ".fb2 "},
{ ".odt", ".html "},
{ ".odt", ".ott "},
{ ".odt", ".pdf "},
{ ".odt", ".rtf "},
{ ".odt", ".txt "},
{ ".otp", ".odp "},
{ ".otp", ".pdf "},
{ ".otp", ".potm "},
{ ".otp", ".potx "},
{ ".otp", ".ppsm "},
{ ".otp", ".ppsx "},
{ ".otp", ".pptm "},
{ ".otp", ".pptx "},
{ ".ots", ".csv "},
{ ".ots", ".ods "},
{ ".ots", ".pdf "},
{ ".ots", ".xlsm "},
{ ".ots", ".xlsx "},
{ ".ots", ".xltm "},
{ ".ots", ".xltx "},
{ ".ott", ".docm "},
{ ".ott", ".docx "},
{ ".ott", ".dotm "},
{ ".ott", ".dotx "},
{ ".ott", ".epub "},
{ ".ott", ".fb2 "},
{ ".ott", ".html "},
{ ".ott", ".odt "},
{ ".ott", ".pdf "},
{ ".ott", ".rtf "},
{ ".ott", ".txt "},
{ ".oxps", ".docm "},
{ ".oxps", ".docx "},
{ ".oxps", ".dotm "},
{ ".oxps", ".dotx "},
{ ".oxps", ".epub "},
{ ".oxps", ".fb2 "},
{ ".oxps", ".html "},
{ ".oxps", ".odt "},
{ ".oxps", ".ott "},
{ ".oxps", ".pdf "},
{ ".oxps", ".rtf "},
{ ".oxps", ".txt "},
{ ".pdf", ".docm "},
{ ".pdf", ".docx "},
{ ".pdf", ".dotm "},
{ ".pdf", ".dotx "},
{ ".pdf", ".epub "},
{ ".pdf", ".fb2 "},
{ ".pdf", ".html "},
{ ".pdf", ".odt "},
{ ".pdf", ".ott "},
{ ".pdf", ".rtf "},
{ ".pdf", ".txt "},
{ ".pot", ".odp "},
{ ".pot", ".otp "},
{ ".pot", ".pdf "},
{ ".pot", ".potm "},
{ ".pot", ".potx "},
{ ".pot", ".ppsm "},
{ ".pot", ".ppsx "},
{ ".pot", ".pptm "},
{ ".pot", ".pptx "},
{ ".potm", ".odp "},
{ ".potm", ".otp "},
{ ".potm", ".pdf "},
{ ".potm", ".potx "},
{ ".potm", ".ppsm "},
{ ".potm", ".ppsx "},
{ ".potm", ".pptm "},
{ ".potm", ".pptx "},
{ ".potx", ".odp "},
{ ".potx", ".otp "},
{ ".potx", ".pdf "},
{ ".potx", ".potm "},
{ ".potx", ".ppsm "},
{ ".potx", ".ppsx "},
{ ".potx", ".pptm "},
{ ".potx", ".pptx "},
{ ".pps", ".odp "},
{ ".pps", ".otp "},
{ ".pps", ".pdf "},
{ ".pps", ".potm "},
{ ".pps", ".potx "},
{ ".pps", ".ppsm "},
{ ".pps", ".ppsx "},
{ ".pps", ".pptm "},
{ ".pps", ".pptx "},
{ ".ppsm", ".odp "},
{ ".ppsm", ".otp "},
{ ".ppsm", ".pdf "},
{ ".ppsm", ".potm "},
{ ".ppsm", ".potx "},
{ ".ppsm", ".ppsx "},
{ ".ppsm", ".pptm "},
{ ".ppsm", ".pptx "},
{ ".ppsx", ".odp "},
{ ".ppsx", ".otp "},
{ ".ppsx", ".pdf "},
{ ".ppsx", ".potm "},
{ ".ppsx", ".potx "},
{ ".ppsx", ".ppsm "},
{ ".ppsx", ".pptm "},
{ ".ppsx", ".pptx "},
{ ".ppt", ".odp "},
{ ".ppt", ".otp "},
{ ".ppt", ".pdf "},
{ ".ppt", ".potm "},
{ ".ppt", ".potx "},
{ ".ppt", ".ppsm "},
{ ".ppt", ".ppsx "},
{ ".ppt", ".pptm "},
{ ".ppt", ".pptx "},
{ ".pptm", ".odp "},
{ ".pptm", ".otp "},
{ ".pptm", ".pdf "},
{ ".pptm", ".potm "},
{ ".pptm", ".potx "},
{ ".pptm", ".ppsm "},
{ ".pptm", ".ppsx "},
{ ".pptm", ".pptx "},
{ ".pptt", ".pptx "},
{ ".pptx", ".odp "},
{ ".pptx", ".otp "},
{ ".pptx", ".pdf "},
{ ".pptx", ".potm "},
{ ".pptx", ".potx "},
{ ".pptx", ".ppsm "},
{ ".pptx", ".ppsx "},
{ ".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", ".docm "},
{ ".xps", ".docx "},
{ ".xps", ".dotm "},
{ ".xps", ".dotx "},
{ ".xps", ".epub "},
{ ".xps", ".fb2 "},
{ ".xps", ".html "},
{ ".xps", ".odt "},
{ ".xps", ".ott "},
{ ".xps", ".pdf "},
{ ".xps", ".rtf "},
{ ".xps", ".txt" }
});
migrationBuilder.InsertData(

File diff suppressed because it is too large Load Diff

View File

@ -68,7 +68,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
new
{
Tenant = -1,
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1",
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,oauth,total_size:107374182400,file_size:100,manager:1",
Name = "trial",
Price = 0m,
Visible = false
@ -76,7 +76,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
new
{
Tenant = -2,
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,oauth,contentsearch,total_size:107374182400,file_size:1024,manager:1",
Name = "admin",
Price = 30m,
ProductId = "1002",
@ -85,7 +85,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
new
{
Tenant = -3,
Features = "free,total_size:2147483648,manager:5,room:5",
Features = "free,total_size:2147483648,manager:3,room:12",
Name = "startup",
Price = 0m,
Visible = false

View File

@ -113,19 +113,19 @@ public partial class CoreDbContextMigrate : Migration
schema: "onlyoffice",
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "visible" },
values: new object[] { -3, null, "free,total_size:2147483648,manager:5,room:5", "startup", false });
values: new object[] { -3, null, "free,total_size:2147483648,manager:3,room:12", "startup", false });
migrationBuilder.InsertData(
schema: "onlyoffice",
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "price", "product_id", "visible" },
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,thirdparty,restore,contentsearch,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,thirdparty,restore,oauth,contentsearch,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
migrationBuilder.InsertData(
schema: "onlyoffice",
table: "tenants_quota",
columns: new[] { "tenant", "description", "features", "name", "visible" },
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1", "trial", false });
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,thirdparty,restore,oauth,total_size:107374182400,file_size:100,manager:1", "trial", false });
migrationBuilder.CreateIndex(
name: "last_modified_tenants_quotarow",

View File

@ -82,7 +82,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
new
{
Tenant = -3,
Features = "free,total_size:2147483648,manager:5,room:5",
Features = "free,total_size:2147483648,manager:3,room:12",
Name = "startup",
Price = 0m,
Visible = false

View File

@ -318,354 +318,411 @@ public partial class FilesDbContextMigrate : Migration
columns: new[] { "input", "output" },
values: new object[,]
{
{ ".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" },
{ ".ods", ".csv" },
{ ".ods", ".ots" },
{ ".ods", ".pdf" },
{ ".ods", ".xlsm" },
{ ".ods", ".xlsx" },
{ ".ods", ".xltm" },
{ ".ods", ".xltx" },
{ ".odt", ".docm" },
{ ".odt", ".docx" },
{ ".odt", ".dotm" },
{ ".odt", ".dotx" },
{ ".odt", ".epub" },
{ ".odt", ".fb2" },
{ ".odt", ".html" },
{ ".odt", ".ott" },
{ ".odt", ".pdf" },
{ ".odt", ".rtf" },
{ ".odt", ".txt" },
{ ".otp", ".odp" },
{ ".otp", ".pdf" },
{ ".otp", ".potm" },
{ ".otp", ".potx" },
{ ".otp", ".pptm" },
{ ".otp", ".pptx" },
{ ".ots", ".csv" },
{ ".ots", ".ods" },
{ ".ots", ".pdf" },
{ ".ots", ".xlsm" },
{ ".ots", ".xlsx" },
{ ".ots", ".xltm" },
{ ".ots", ".xltx" },
{ ".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", ".potm" },
{ ".pot", ".potx" },
{ ".pot", ".pptm" },
{ ".pot", ".pptx" },
{ ".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" }
{ ".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", ".docm "},
{ ".docxf", ".docx "},
{ ".docxf", ".dotm "},
{ ".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", ".ppsm "},
{ ".fodp", ".ppsx "},
{ ".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", ".ppsm "},
{ ".odp", ".ppsx "},
{ ".odp", ".pptm "},
{ ".odp", ".pptx "},
{ ".ods", ".csv "},
{ ".ods", ".ots "},
{ ".ods", ".pdf "},
{ ".ods", ".xlsm "},
{ ".ods", ".xlsx "},
{ ".ods", ".xltm "},
{ ".ods", ".xltx "},
{ ".odt", ".docm "},
{ ".odt", ".docx "},
{ ".odt", ".dotm "},
{ ".odt", ".dotx "},
{ ".odt", ".epub "},
{ ".odt", ".fb2 "},
{ ".odt", ".html "},
{ ".odt", ".ott "},
{ ".odt", ".pdf "},
{ ".odt", ".rtf "},
{ ".odt", ".txt "},
{ ".otp", ".odp "},
{ ".otp", ".pdf "},
{ ".otp", ".potm "},
{ ".otp", ".potx "},
{ ".otp", ".ppsm "},
{ ".otp", ".ppsx "},
{ ".otp", ".pptm "},
{ ".otp", ".pptx "},
{ ".ots", ".csv "},
{ ".ots", ".ods "},
{ ".ots", ".pdf "},
{ ".ots", ".xlsm "},
{ ".ots", ".xlsx "},
{ ".ots", ".xltm "},
{ ".ots", ".xltx "},
{ ".ott", ".docm "},
{ ".ott", ".docx "},
{ ".ott", ".dotm "},
{ ".ott", ".dotx "},
{ ".ott", ".epub "},
{ ".ott", ".fb2 "},
{ ".ott", ".html "},
{ ".ott", ".odt "},
{ ".ott", ".pdf "},
{ ".ott", ".rtf "},
{ ".ott", ".txt "},
{ ".oxps", ".docm "},
{ ".oxps", ".docx "},
{ ".oxps", ".dotm "},
{ ".oxps", ".dotx "},
{ ".oxps", ".epub "},
{ ".oxps", ".fb2 "},
{ ".oxps", ".html "},
{ ".oxps", ".odt "},
{ ".oxps", ".ott "},
{ ".oxps", ".pdf "},
{ ".oxps", ".rtf "},
{ ".oxps", ".txt "},
{ ".pdf", ".docm "},
{ ".pdf", ".docx "},
{ ".pdf", ".dotm "},
{ ".pdf", ".dotx "},
{ ".pdf", ".epub "},
{ ".pdf", ".fb2 "},
{ ".pdf", ".html "},
{ ".pdf", ".odt "},
{ ".pdf", ".ott "},
{ ".pdf", ".rtf "},
{ ".pdf", ".txt "},
{ ".pot", ".odp "},
{ ".pot", ".otp "},
{ ".pot", ".pdf "},
{ ".pot", ".potm "},
{ ".pot", ".potx "},
{ ".pot", ".ppsm "},
{ ".pot", ".ppsx "},
{ ".pot", ".pptm "},
{ ".pot", ".pptx "},
{ ".potm", ".odp "},
{ ".potm", ".otp "},
{ ".potm", ".pdf "},
{ ".potm", ".potx "},
{ ".potm", ".ppsm "},
{ ".potm", ".ppsx "},
{ ".potm", ".pptm "},
{ ".potm", ".pptx "},
{ ".potx", ".odp "},
{ ".potx", ".otp "},
{ ".potx", ".pdf "},
{ ".potx", ".potm "},
{ ".potx", ".ppsm "},
{ ".potx", ".ppsx "},
{ ".potx", ".pptm "},
{ ".potx", ".pptx "},
{ ".pps", ".odp "},
{ ".pps", ".otp "},
{ ".pps", ".pdf "},
{ ".pps", ".potm "},
{ ".pps", ".potx "},
{ ".pps", ".ppsm "},
{ ".pps", ".ppsx "},
{ ".pps", ".pptm "},
{ ".pps", ".pptx "},
{ ".ppsm", ".odp "},
{ ".ppsm", ".otp "},
{ ".ppsm", ".pdf "},
{ ".ppsm", ".potm "},
{ ".ppsm", ".potx "},
{ ".ppsm", ".ppsx "},
{ ".ppsm", ".pptm "},
{ ".ppsm", ".pptx "},
{ ".ppsx", ".odp "},
{ ".ppsx", ".otp "},
{ ".ppsx", ".pdf "},
{ ".ppsx", ".potm "},
{ ".ppsx", ".potx "},
{ ".ppsx", ".ppsm "},
{ ".ppsx", ".pptm "},
{ ".ppsx", ".pptx "},
{ ".ppt", ".odp "},
{ ".ppt", ".otp "},
{ ".ppt", ".pdf "},
{ ".ppt", ".potm "},
{ ".ppt", ".potx "},
{ ".ppt", ".ppsm "},
{ ".ppt", ".ppsx "},
{ ".ppt", ".pptm "},
{ ".ppt", ".pptx "},
{ ".pptm", ".odp "},
{ ".pptm", ".otp "},
{ ".pptm", ".pdf "},
{ ".pptm", ".potm "},
{ ".pptm", ".potx "},
{ ".pptm", ".ppsm "},
{ ".pptm", ".ppsx "},
{ ".pptm", ".pptx "},
{ ".pptt", ".pptx "},
{ ".pptx", ".odp "},
{ ".pptx", ".otp "},
{ ".pptx", ".pdf "},
{ ".pptx", ".potm "},
{ ".pptx", ".potx "},
{ ".pptx", ".ppsm "},
{ ".pptx", ".ppsx "},
{ ".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", ".docm "},
{ ".xps", ".docx "},
{ ".xps", ".dotm "},
{ ".xps", ".dotx "},
{ ".xps", ".epub "},
{ ".xps", ".fb2 "},
{ ".xps", ".html "},
{ ".xps", ".odt "},
{ ".xps", ".ott "},
{ ".xps", ".pdf "},
{ ".xps", ".rtf "},
{ ".xps", ".txt" }
});
migrationBuilder.InsertData(

View File

@ -23,7 +23,8 @@
"storybook-serve": "yarn workspace @docspace/components run storybook-serve",
"test": "yarn workspace @docspace/components test",
"wipe": "shx rm -rf node_modules yarn.lock packages/**/node_modules",
"debug-info": "auto-changelog --unreleased-only --template debuginfo --output public/debuginfo.md"
"debug-info": "auto-changelog --unreleased-only --template debuginfo --output public/debuginfo.md",
"licenses-audit": "yarn licenses audit --output-csv=licenses.csv --config=licenses.config.js --summary"
},
"old-scripts": {
"build:test": "yarn workspaces foreach -vptiR --from '{@docspace/client,@docspace/login,@docspace/editor}' run build:test",

View File

@ -81,6 +81,7 @@
"style-loader": "3.3.2",
"terser-webpack-plugin": "^5.3.7",
"typescript": "^4.9.5",
"use-resize-observer": "^9.1.0",
"webpack": "5.76.3",
"webpack-cli": "4.10.0",
"webpack-dev-server": "4.13.1"

View File

@ -1,8 +1,8 @@
{
"AboutCompanyAddressTitle": "Ünvan",
"AboutCompanyEmailTitle": "e-poçt",
"AboutHeader": "Bu proqram haqqında",
"DocumentManagement": "Sənədlərin idarə edilməsi",
"OnlineEditors": "Onlayn redaktorlar",
"Site": "Sayt",
"SoftwareLicense": "Proqram təminatı lisenziyası"
}

View File

@ -1 +1,8 @@
{}
{
"ArchiveHeader": "Arxivə köçürülsün?",
"ArchiveRoom": "Otağı arxivləşdirmək üzrəsiniz.",
"ArchiveRooms": "Otaqları arxivləşdirmək üzrəsiniz.",
"RestoreAllRooms": "Bütün otaqları bərpa etmək istədiyinizə əminsiniz?",
"RestoreRoom": "Otağı bərpa etmək istədiyinizə əminsiniz?",
"RestoreRooms": "Otaqları bərpa etmək istədiyinizə əminsiniz?"
}

View File

@ -1,5 +1,14 @@
{
"AppointAdmin": "Administratorları təyin edin",
"BackupPortal": "DocSpace məlumatlarını yedəkləyin",
"ManagePortal": " DocSpace konfiqurasiyasını idarə edin",
"ManageUser": "İstifadəçi hesablarını idarə edin"
"ChangeInstruction": "DocSpace sahibini dəyişmək üçün lütfən, aşağıda yeni sahibin adını seçin.",
"ChangeOwner": "DocSpace sahibini dəyişdirin",
"ChangeUser": "İstifadəçini dəyişdirin",
"DeactivateOrDeletePortal": "DocSpace-i deaktiv edin və ya silin",
"DoTheSame": "Administratorlarla da eyni şeyi edin",
"ManagePortal": "DocSpace konfiqurasiyasını idarə edin",
"ManageUser": "İstifadəçi hesablarını idarə edin",
"NewPortalOwner": "Yeni DocSpace sahibi",
"PortalOwnerCan": "DocSpace sahibi edə bilər:",
"SetAccessRights": "Giriş hüquqlarını təyin edin"
}

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