Merge branch 'develop' into branch feature/image-thumbnail
This commit is contained in:
commit
d2f4748d79
40
.github/workflows/build-ffvideo.yml
vendored
Normal file
40
.github/workflows/build-ffvideo.yml
vendored
Normal 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
|
||||||
|
|
43
.github/workflows/storybook-publish.yml
vendored
Normal file
43
.github/workflows/storybook-publish.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
name: storybook build/publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
paths:
|
||||||
|
- 'public/**'
|
||||||
|
- 'packages/components/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform: [linux/amd64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18.x'
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn storybook-build
|
||||||
|
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v2
|
||||||
|
with:
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
|
|
||||||
|
- name: Upload storybook files
|
||||||
|
run: |
|
||||||
|
aws s3 cp ./packages/components/storybook-static/ ${{ secrets.AWS_BUCKER_URL }}/ \
|
||||||
|
--recursive
|
||||||
|
|
||||||
|
- name: Invalidate AWS CLOUDFRONT cache
|
||||||
|
run: |
|
||||||
|
aws cloudfront create-invalidation \
|
||||||
|
-- --paths "/*" \
|
||||||
|
--distribution-id ${{ secrets.AWS_DISTRIBUTION_ID }}
|
@ -219,18 +219,11 @@ set_core_machinekey () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_json() {
|
install_json() {
|
||||||
|
|
||||||
if [ ! -e /usr/bin/json ]; then
|
if [ ! -e /usr/bin/json ]; then
|
||||||
echo -n "Install json package... "
|
echo -n "Install json package... "
|
||||||
npm i json -g >/dev/null 2>&1
|
npm i json -g >/dev/null 2>&1
|
||||||
echo "OK"
|
echo "OK"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#Creating a user-defined .json
|
|
||||||
if [ ! -e $USER_CONF ]; then
|
|
||||||
echo "{}" >> $USER_CONF
|
|
||||||
chown ${PACKAGE_SYSNAME}:${PACKAGE_SYSNAME} $USER_CONF
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_services() {
|
restart_services() {
|
||||||
@ -485,7 +478,7 @@ setup_docs() {
|
|||||||
local JSON_DSCONF="$JSON $DS_CONF -e"
|
local JSON_DSCONF="$JSON $DS_CONF -e"
|
||||||
|
|
||||||
#Changing the Docs port in nginx conf
|
#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
|
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
|
#Enable JWT validation for Docs
|
||||||
@ -601,6 +594,17 @@ setup_rabbitmq() {
|
|||||||
product_configuration(){
|
product_configuration(){
|
||||||
echo -n "Configuring ${PRODUCT}... "
|
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
|
$JSON $APP_DIR/plugins.json -e "this.pluginsConf={'path': \"$PRODUCT_DIR/Tools/radicale/plugins/\" }" >/dev/null 2>&1
|
||||||
set_core_machinekey
|
set_core_machinekey
|
||||||
|
|
||||||
|
@ -227,14 +227,12 @@ CMD ["ASC.Files.dll", "ASC.Files"]
|
|||||||
|
|
||||||
## ASC.Files.Service ##
|
## ASC.Files.Service ##
|
||||||
FROM dotnetrun AS files_services
|
FROM dotnetrun AS files_services
|
||||||
RUN apt-get -y update && \
|
ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
|
||||||
apt-get install -yq ffmpeg &&\
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
|
WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
|
||||||
|
|
||||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
|
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=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"]
|
CMD ["ASC.Files.Service.dll", "ASC.Files.Service", "core:eventBus:subscriptionClientName=asc_event_bus_files_service_queue"]
|
||||||
|
|
||||||
|
@ -225,7 +225,6 @@ CMD ["ASC.Files.dll", "ASC.Files"]
|
|||||||
FROM dotnetrun AS files_services
|
FROM dotnetrun AS files_services
|
||||||
RUN apt-get -y update && \
|
RUN apt-get -y update && \
|
||||||
apt-get install -yq ffmpeg
|
apt-get install -yq ffmpeg
|
||||||
|
|
||||||
WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
|
WORKDIR ${BUILD_PATH}/products/ASC.Files/service/
|
||||||
|
|
||||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
|
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
|
||||||
|
585
build/install/docker/Dockerfile.ffvideo
Normal file
585
build/install/docker/Dockerfile.ffvideo
Normal 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"]
|
@ -1,4 +1,12 @@
|
|||||||
version: "3.8"
|
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
|
x-service: &x-service-base
|
||||||
container_name: base
|
container_name: base
|
||||||
restart: always
|
restart: always
|
||||||
@ -54,31 +62,49 @@ services:
|
|||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup-background:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup-background:${DOCKER_TAG}"
|
||||||
container_name: ${BACKUP_BACKGRUOND_TASKS_HOST}
|
container_name: ${BACKUP_BACKGRUOND_TASKS_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_BACKUP_BACKGRUOND_TASKS}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-backup:
|
onlyoffice-backup:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup:${DOCKER_TAG}"
|
||||||
container_name: ${BACKUP_HOST}
|
container_name: ${BACKUP_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_BACKUP}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-clear-events:
|
onlyoffice-clear-events:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-clear-events:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-clear-events:${DOCKER_TAG}"
|
||||||
container_name: ${CLEAR_EVENTS_HOST}
|
container_name: ${CLEAR_EVENTS_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_CLEAR_EVENTS}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-files:
|
onlyoffice-files:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files:${DOCKER_TAG}"
|
||||||
container_name: ${FILES_HOST}
|
container_name: ${FILES_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_FILES}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-files-services:
|
onlyoffice-files-services:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files-services:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files-services:${DOCKER_TAG}"
|
||||||
container_name: ${FILES_SERVICES_HOST}
|
container_name: ${FILES_SERVICES_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_FILES_SERVICES}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-people-server:
|
onlyoffice-people-server:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-people-server:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-people-server:${DOCKER_TAG}"
|
||||||
container_name: ${PEOPLE_SERVER_HOST}
|
container_name: ${PEOPLE_SERVER_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_PEOPLE_SERVER}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-socket:
|
onlyoffice-socket:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
@ -91,21 +117,33 @@ services:
|
|||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio-notify:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio-notify:${DOCKER_TAG}"
|
||||||
container_name: ${STUDIO_NOTIFY_HOST}
|
container_name: ${STUDIO_NOTIFY_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_STUDIO_NOTIFY}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-api:
|
onlyoffice-api:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api:${DOCKER_TAG}"
|
||||||
container_name: ${API_HOST}
|
container_name: ${API_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_API}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-api-system:
|
onlyoffice-api-system:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
|
||||||
container_name: ${API_SYSTEM_HOST}
|
container_name: ${API_SYSTEM_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_API_SYSTEM}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-studio:
|
onlyoffice-studio:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}"
|
||||||
container_name: ${STUDIO_HOST}
|
container_name: ${STUDIO_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_STUDIO}/health/ || exit 1
|
||||||
|
|
||||||
onlyoffice-ssoauth:
|
onlyoffice-ssoauth:
|
||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
@ -135,6 +173,9 @@ services:
|
|||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-proxy:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-proxy:${DOCKER_TAG}"
|
||||||
container_name: ${PROXY_HOST}
|
container_name: ${PROXY_HOST}
|
||||||
restart: always
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: nginx -t || exit 1
|
||||||
expose:
|
expose:
|
||||||
- "8081"
|
- "8081"
|
||||||
- "8099"
|
- "8099"
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
version: "3.8"
|
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:
|
||||||
&x-service-base
|
&x-service-base
|
||||||
container_name: base
|
container_name: base
|
||||||
@ -33,6 +41,9 @@ services:
|
|||||||
<<: *x-service-base
|
<<: *x-service-base
|
||||||
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-notify:${DOCKER_TAG}"
|
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-notify:${DOCKER_TAG}"
|
||||||
container_name: ${NOTIFY_HOST}
|
container_name: ${NOTIFY_HOST}
|
||||||
|
healthcheck:
|
||||||
|
<<: *x-healthcheck
|
||||||
|
test: curl --fail http://${SERVICE_NOTIFY}/health/ || exit 1
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
default:
|
default:
|
||||||
|
@ -2,4 +2,9 @@ PUSHD %~dp0..
|
|||||||
set dir=%~dp0..
|
set dir=%~dp0..
|
||||||
echo %dir%
|
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"
|
@ -3,6 +3,15 @@ echo "Run script directory:" $dir
|
|||||||
|
|
||||||
dir=$(builtin cd $rd/../; pwd)
|
dir=$(builtin cd $rd/../; pwd)
|
||||||
|
|
||||||
|
save=false
|
||||||
|
|
||||||
|
while getopts s: flag
|
||||||
|
do
|
||||||
|
case "${flag}" in
|
||||||
|
s) save=${OPTARG};;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
echo "Root directory:" $dir
|
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"
|
@ -417,7 +417,7 @@ public class LdapUserImporter : IDisposable
|
|||||||
if (!actualPortalLdapGroups.Contains(portalUserLdapGroup))
|
if (!actualPortalLdapGroups.Contains(portalUserLdapGroup))
|
||||||
{
|
{
|
||||||
_logger.DebugTrySyncUserGroupMembershipRemovingUserFromGroup(userInfo.UserName, ldapUser.Sid, portalUserLdapGroup.Name, portalUserLdapGroup.Sid);
|
_logger.DebugTrySyncUserGroupMembershipRemovingUserFromGroup(userInfo.UserName, ldapUser.Sid, portalUserLdapGroup.Name, portalUserLdapGroup.Sid);
|
||||||
UserManager.RemoveUserFromGroup(userInfo.Id, portalUserLdapGroup.ID);
|
await UserManager.RemoveUserFromGroup(userInfo.Id, portalUserLdapGroup.ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
{
|
{
|
||||||
_logger.DebugTurnOffLDAP();
|
_logger.DebugTurnOffLDAP();
|
||||||
|
|
||||||
TurnOffLDAP();
|
await TurnOffLDAP();
|
||||||
var ldapCurrentUserPhotos = _settingsManager.Load<LdapCurrentUserPhotos>().GetDefault();
|
var ldapCurrentUserPhotos = _settingsManager.Load<LdapCurrentUserPhotos>().GetDefault();
|
||||||
_settingsManager.Save(ldapCurrentUserPhotos);
|
_settingsManager.Save(ldapCurrentUserPhotos);
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
: "", "");
|
: "", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TurnOffLDAP()
|
private async Task TurnOffLDAP()
|
||||||
{
|
{
|
||||||
const double percents = 48;
|
const double percents = 48;
|
||||||
|
|
||||||
@ -380,7 +380,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
|
|
||||||
_logger.DebugSaveUserInfo(existingLDAPUser.GetUserInfoString());
|
_logger.DebugSaveUserInfo(existingLDAPUser.GetUserInfoString());
|
||||||
|
|
||||||
_userManager.UpdateUserInfo(existingLDAPUser);
|
await _userManager.UpdateUserInfo(existingLDAPUser);
|
||||||
break;
|
break;
|
||||||
case LdapOperationType.SaveTest:
|
case LdapOperationType.SaveTest:
|
||||||
case LdapOperationType.SyncTest:
|
case LdapOperationType.SyncTest:
|
||||||
@ -667,7 +667,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
|
|
||||||
SetProgress(20, Resource.LdapSettingsStatusRemovingOldUsers, "");
|
SetProgress(20, Resource.LdapSettingsStatusRemovingOldUsers, "");
|
||||||
|
|
||||||
ldapUsers = RemoveOldDbUsers(ldapUsers);
|
ldapUsers = await RemoveOldDbUsers(ldapUsers);
|
||||||
|
|
||||||
SetProgress(30,
|
SetProgress(30,
|
||||||
OperationType == LdapOperationType.Save || OperationType == LdapOperationType.SaveTest
|
OperationType == LdapOperationType.Save || OperationType == LdapOperationType.SaveTest
|
||||||
@ -729,7 +729,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
|
|
||||||
SetProgress(90, Resource.LdapSettingsStatusRemovingOldUsers, "");
|
SetProgress(90, Resource.LdapSettingsStatusRemovingOldUsers, "");
|
||||||
|
|
||||||
RemoveOldDbUsers(newUniqueLdapGroupUsers);
|
await RemoveOldDbUsers(newUniqueLdapGroupUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SyncDbGroups(Dictionary<GroupInfo, List<UserInfo>> ldapGroupsWithUsers)
|
private async Task SyncDbGroups(Dictionary<GroupInfo, List<UserInfo>> ldapGroupsWithUsers)
|
||||||
@ -895,7 +895,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
++index, count,
|
++index, count,
|
||||||
_userFormatter.GetUserName(dbUser, DisplayUserNameFormat.Default)));
|
_userFormatter.GetUserName(dbUser, DisplayUserNameFormat.Default)));
|
||||||
|
|
||||||
_userManager.RemoveUserFromGroup(dbUser.Id, dbLdapGroup.ID);
|
await _userManager.RemoveUserFromGroup(dbUser.Id, dbLdapGroup.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
@ -1012,7 +1012,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ldapUsers">list of actual LDAP users</param>
|
/// <param name="ldapUsers">list of actual LDAP users</param>
|
||||||
/// <returns>New list of actual LDAP users</returns>
|
/// <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();
|
var dbLdapUsers = _userManager.GetUsers(EmployeeStatus.All).Where(u => u.Sid != null).ToList();
|
||||||
|
|
||||||
@ -1064,7 +1064,7 @@ public class LdapOperationJob : DistributedTaskProgress
|
|||||||
|
|
||||||
_logger.DebugSaveUserInfo(removedUser.GetUserInfoString());
|
_logger.DebugSaveUserInfo(removedUser.GetUserInfoString());
|
||||||
|
|
||||||
_userManager.UpdateUserInfo(removedUser);
|
await _userManager.UpdateUserInfo(removedUser);
|
||||||
break;
|
break;
|
||||||
case LdapOperationType.SaveTest:
|
case LdapOperationType.SaveTest:
|
||||||
case LdapOperationType.SyncTest:
|
case LdapOperationType.SyncTest:
|
||||||
|
@ -126,7 +126,7 @@ public class LdapUserManager
|
|||||||
return portalUserInfo;
|
return portalUserInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryChangeExistingUserName(ldapUserInfo.UserName, onlyGetChanges))
|
if (!await TryChangeExistingUserName(ldapUserInfo.UserName, onlyGetChanges))
|
||||||
{
|
{
|
||||||
_logger.DebugUserAlredyExistsForUserName(ldapUserInfo.Sid, ldapUserInfo.UserName);
|
_logger.DebugUserAlredyExistsForUserName(ldapUserInfo.Sid, ldapUserInfo.UserName);
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ public class LdapUserManager
|
|||||||
return portalUserInfo;
|
return portalUserInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryChangeExistingUserName(string ldapUserName, bool onlyGetChanges)
|
private async Task<bool> TryChangeExistingUserName(string ldapUserName, bool onlyGetChanges)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -209,7 +209,7 @@ public class LdapUserManager
|
|||||||
|
|
||||||
_logger.DebugSaveUserInfo(otherUser.GetUserInfoString());
|
_logger.DebugSaveUserInfo(otherUser.GetUserInfoString());
|
||||||
|
|
||||||
_userManager.UpdateUserInfo(otherUser);
|
await _userManager.UpdateUserInfo(otherUser);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -343,9 +343,11 @@ public class LdapUserManager
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.DebugSyncUserLdapUpdaiting(ldapUserInfo.Sid, ldapUserInfo.UserName);
|
_logger.DebugSyncUserLdapUpdaiting(ldapUserInfo.Sid, ldapUserInfo.UserName);
|
||||||
UserInfo uf;
|
|
||||||
if (!TryUpdateUserWithLDAPInfo(userToUpdate, ldapUserInfo, onlyGetChanges, out uf))
|
var (updated, uf) = await TryUpdateUserWithLDAPInfo(userToUpdate, ldapUserInfo, onlyGetChanges);
|
||||||
|
|
||||||
|
if (!updated)
|
||||||
{
|
{
|
||||||
if (onlyGetChanges)
|
if (onlyGetChanges)
|
||||||
{
|
{
|
||||||
@ -379,7 +381,7 @@ public class LdapUserManager
|
|||||||
|
|
||||||
var newContacts = new List<string>(ldapUser.ContactsList);
|
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
|
if (portalUserContacts[i] == EXT_MOB_PHONE || portalUserContacts[i] == EXT_MAIL
|
||||||
|| portalUserContacts[i] == EXT_PHONE || portalUserContacts[i] == EXT_SKYPE)
|
|| portalUserContacts[i] == EXT_PHONE || portalUserContacts[i] == EXT_SKYPE)
|
||||||
@ -516,9 +518,9 @@ public class LdapUserManager
|
|||||||
return needUpdate;
|
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
|
try
|
||||||
{
|
{
|
||||||
@ -527,11 +529,11 @@ public class LdapUserManager
|
|||||||
var settings = _settingsManager.Load<LdapSettings>();
|
var settings = _settingsManager.Load<LdapSettings>();
|
||||||
|
|
||||||
if (!userToUpdate.UserName.Equals(updateInfo.UserName, StringComparison.InvariantCultureIgnoreCase)
|
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);
|
_logger.DebugUpdateUserUserNameAlredyExists(userToUpdate.Id, userToUpdate.UserName, updateInfo.UserName);
|
||||||
|
|
||||||
return false;
|
return (false, portlaUserInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userToUpdate.Email.Equals(updateInfo.Email, StringComparison.InvariantCultureIgnoreCase)
|
if (!userToUpdate.Email.Equals(updateInfo.Email, StringComparison.InvariantCultureIgnoreCase)
|
||||||
@ -539,7 +541,7 @@ public class LdapUserManager
|
|||||||
{
|
{
|
||||||
_logger.DebugUpdateUserEmailAlreadyExists(userToUpdate.Id, userToUpdate.Email, updateInfo.Email);
|
_logger.DebugUpdateUserEmailAlreadyExists(userToUpdate.Id, userToUpdate.Email, updateInfo.Email);
|
||||||
|
|
||||||
return false;
|
return (false, portlaUserInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userToUpdate.Email != updateInfo.Email && !(updateInfo.ActivationStatus == EmployeeActivationStatus.AutoGenerated &&
|
if (userToUpdate.Email != updateInfo.Email && !(updateInfo.ActivationStatus == EmployeeActivationStatus.AutoGenerated &&
|
||||||
@ -589,10 +591,10 @@ public class LdapUserManager
|
|||||||
{
|
{
|
||||||
_logger.DebugSaveUserInfo(userToUpdate.GetUserInfoString());
|
_logger.DebugSaveUserInfo(userToUpdate.GetUserInfoString());
|
||||||
|
|
||||||
portlaUserInfo = _userManager.UpdateUserInfo(userToUpdate);
|
portlaUserInfo = await _userManager.UpdateUserInfo(userToUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return (true, portlaUserInfo);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -600,7 +602,7 @@ public class LdapUserManager
|
|||||||
userToUpdate.Sid, ex);
|
userToUpdate.Sid, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return (false, portlaUserInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserInfo> TryGetAndSyncLdapUserInfo(string login, string password)
|
public async Task<UserInfo> TryGetAndSyncLdapUserInfo(string login, string password)
|
||||||
@ -678,7 +680,7 @@ public class LdapUserManager
|
|||||||
log.DebugTryGetAndSyncLdapUserInfoDisablingUser(login, uInfo);
|
log.DebugTryGetAndSyncLdapUserInfoDisablingUser(login, uInfo);
|
||||||
uInfo.Status = EmployeeStatus.Terminated;
|
uInfo.Status = EmployeeStatus.Terminated;
|
||||||
uInfo.Sid = null;
|
uInfo.Sid = null;
|
||||||
userManager.UpdateUserInfo(uInfo);
|
await userManager.UpdateUserInfo(uInfo);
|
||||||
await cookiesManager.ResetUserCookie(uInfo.Id);
|
await cookiesManager.ResetUserCookie(uInfo.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -730,7 +732,7 @@ public class LdapUserManager
|
|||||||
{
|
{
|
||||||
userInfo.Sid = null;
|
userInfo.Sid = null;
|
||||||
userInfo.Status = EmployeeStatus.Terminated;
|
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");
|
throw new Exception("The user did not pass the configuration check by ldap group settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ public class WarmupServicesStartupTask : IStartupTask
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Task ExecuteAsync(CancellationToken cancellationToken)
|
public Task ExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var processedFailed = 0;
|
var processedFailed = 0;
|
||||||
var processedSuccessed = 0;
|
var processedSuccessed = 0;
|
||||||
var startTime = DateTime.UtcNow;
|
var startTime = DateTime.UtcNow;
|
||||||
@ -52,13 +52,13 @@ public class WarmupServicesStartupTask : IStartupTask
|
|||||||
|
|
||||||
logger.TraceWarmupStarted();
|
logger.TraceWarmupStarted();
|
||||||
|
|
||||||
tenantManager.SetCurrentTenant("localhost");
|
tenantManager.SetCurrentTenant("localhost");
|
||||||
|
|
||||||
foreach (var service in GetServices(_services))
|
foreach (var service in GetServices(_services))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
scope.ServiceProvider.GetServices(service);
|
scope.ServiceProvider.GetService(service);
|
||||||
|
|
||||||
processedSuccessed++;
|
processedSuccessed++;
|
||||||
}
|
}
|
||||||
@ -72,9 +72,9 @@ public class WarmupServicesStartupTask : IStartupTask
|
|||||||
|
|
||||||
var processed = processedSuccessed + processedFailed;
|
var processed = processedSuccessed + processedFailed;
|
||||||
|
|
||||||
logger.TraceWarmupFinished(processed,
|
logger.TraceWarmupFinished(processed,
|
||||||
processedSuccessed,
|
processedSuccessed,
|
||||||
processedFailed,
|
processedFailed,
|
||||||
(DateTime.UtcNow - startTime).TotalMilliseconds);
|
(DateTime.UtcNow - startTime).TotalMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ public class WarmupServicesStartupTask : IStartupTask
|
|||||||
return services
|
return services
|
||||||
.Where(descriptor => descriptor.ImplementationType != typeof(WarmupServicesStartupTask))
|
.Where(descriptor => descriptor.ImplementationType != typeof(WarmupServicesStartupTask))
|
||||||
.Where(descriptor => descriptor.ServiceType.ContainsGenericParameters == false)
|
.Where(descriptor => descriptor.ServiceType.ContainsGenericParameters == false)
|
||||||
.Select(descriptor => descriptor.ServiceType)
|
.Select(descriptor => descriptor.ServiceType)
|
||||||
.Distinct();
|
.Distinct();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -146,7 +146,7 @@ public static class ServiceCollectionExtension
|
|||||||
var logger = sp.GetRequiredService<ILogger<DefaultActiveMQPersistentConnection>>();
|
var logger = sp.GetRequiredService<ILogger<DefaultActiveMQPersistentConnection>>();
|
||||||
|
|
||||||
var factory = new Apache.NMS.NMSConnectionFactory(activeMQConfiguration.Uri);
|
var factory = new Apache.NMS.NMSConnectionFactory(activeMQConfiguration.Uri);
|
||||||
|
|
||||||
var retryCount = 5;
|
var retryCount = 5;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(cfg["core:eventBus:connectRetryCount"]))
|
if (!string.IsNullOrEmpty(cfg["core:eventBus:connectRetryCount"]))
|
||||||
@ -195,10 +195,8 @@ public static class ServiceCollectionExtension
|
|||||||
/// Add a IHostedService for given type.
|
/// Add a IHostedService for given type.
|
||||||
/// Only one copy of this instance type will active in multi process architecture.
|
/// Only one copy of this instance type will active in multi process architecture.
|
||||||
/// </remarks>
|
/// </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<IRegisterInstanceDao<T>, RegisterInstanceDao<T>>();
|
||||||
diHelper.TryAdd<IRegisterInstanceManager<T>, RegisterInstanceManager<T>>();
|
diHelper.TryAdd<IRegisterInstanceManager<T>, RegisterInstanceManager<T>>();
|
||||||
|
|
||||||
|
@ -160,6 +160,8 @@ public static class MimeMapping
|
|||||||
AddMimeMapping(".dotm", "application/vnd.ms-word.template.macroEnabled.12");
|
AddMimeMapping(".dotm", "application/vnd.ms-word.template.macroEnabled.12");
|
||||||
AddMimeMapping(".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template");
|
AddMimeMapping(".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template");
|
||||||
AddMimeMapping(".dp", "application/commonground");
|
AddMimeMapping(".dp", "application/commonground");
|
||||||
|
AddMimeMapping(".dps", "application/presentation");
|
||||||
|
AddMimeMapping(".dpt", "application/presentation");
|
||||||
AddMimeMapping(".drw", "application/drafting");
|
AddMimeMapping(".drw", "application/drafting");
|
||||||
AddMimeMapping(".dump", "application/octet-stream");
|
AddMimeMapping(".dump", "application/octet-stream");
|
||||||
AddMimeMapping(".dv", "video/x-dv");
|
AddMimeMapping(".dv", "video/x-dv");
|
||||||
@ -181,6 +183,8 @@ public static class MimeMapping
|
|||||||
AddMimeMapping(".eps", "application/postscript");
|
AddMimeMapping(".eps", "application/postscript");
|
||||||
AddMimeMapping(".epub", "application/epub+zip");
|
AddMimeMapping(".epub", "application/epub+zip");
|
||||||
AddMimeMapping(".es", "application/x-esrehber");
|
AddMimeMapping(".es", "application/x-esrehber");
|
||||||
|
AddMimeMapping(".et", "application/spreadsheet");
|
||||||
|
AddMimeMapping(".ett", "application/spreadsheet");
|
||||||
AddMimeMapping(".etx", "text/x-setext");
|
AddMimeMapping(".etx", "text/x-setext");
|
||||||
AddMimeMapping(".evy", "application/envoy");
|
AddMimeMapping(".evy", "application/envoy");
|
||||||
AddMimeMapping(".evy", "application/x-envoy");
|
AddMimeMapping(".evy", "application/x-envoy");
|
||||||
@ -616,6 +620,7 @@ public static class MimeMapping
|
|||||||
AddMimeMapping(".stl", "application/vndms-pkistl");
|
AddMimeMapping(".stl", "application/vndms-pkistl");
|
||||||
AddMimeMapping(".stm", "text/html");
|
AddMimeMapping(".stm", "text/html");
|
||||||
AddMimeMapping(".stp", "application/step");
|
AddMimeMapping(".stp", "application/step");
|
||||||
|
AddMimeMapping(".stw", "application/vnd.sun.xml.writer.template");
|
||||||
AddMimeMapping(".sv4cpio", "application/x-sv4cpio");
|
AddMimeMapping(".sv4cpio", "application/x-sv4cpio");
|
||||||
AddMimeMapping(".sv4crc", "application/x-sv4crc");
|
AddMimeMapping(".sv4crc", "application/x-sv4crc");
|
||||||
AddMimeMapping(".svf", "image/vnd.dwg");
|
AddMimeMapping(".svf", "image/vnd.dwg");
|
||||||
@ -625,6 +630,9 @@ public static class MimeMapping
|
|||||||
AddMimeMapping(".svg", "image/svg+xml");
|
AddMimeMapping(".svg", "image/svg+xml");
|
||||||
AddMimeMapping(".svgt", "image/svg+xml");
|
AddMimeMapping(".svgt", "image/svg+xml");
|
||||||
AddMimeMapping(".swf", "application/x-shockwave-flash");
|
AddMimeMapping(".swf", "application/x-shockwave-flash");
|
||||||
|
AddMimeMapping(".sxi", "application/presentation");
|
||||||
|
AddMimeMapping(".sxc", "application/vnd.sun.xml.calc");
|
||||||
|
AddMimeMapping(".sxw", "application/vnd.sun.xml.writer");
|
||||||
AddMimeMapping(".t", "application/x-troff");
|
AddMimeMapping(".t", "application/x-troff");
|
||||||
AddMimeMapping(".talk", "text/x-speech");
|
AddMimeMapping(".talk", "text/x-speech");
|
||||||
AddMimeMapping(".tar", "application/x-tar");
|
AddMimeMapping(".tar", "application/x-tar");
|
||||||
@ -719,7 +727,8 @@ public static class MimeMapping
|
|||||||
AddMimeMapping(".wp6", "application/wordperfect");
|
AddMimeMapping(".wp6", "application/wordperfect");
|
||||||
AddMimeMapping(".wpd", "application/wordperfect");
|
AddMimeMapping(".wpd", "application/wordperfect");
|
||||||
AddMimeMapping(".wpd", "application/x-wpwin");
|
AddMimeMapping(".wpd", "application/x-wpwin");
|
||||||
AddMimeMapping(".wps", "application/vnd.ms-works");
|
AddMimeMapping(".wps", "application/document");
|
||||||
|
AddMimeMapping(".wpt", "application/document");
|
||||||
AddMimeMapping(".wq1", "application/x-lotus");
|
AddMimeMapping(".wq1", "application/x-lotus");
|
||||||
AddMimeMapping(".wri", "application/mswrite");
|
AddMimeMapping(".wri", "application/mswrite");
|
||||||
AddMimeMapping(".wri", "application/x-wri");
|
AddMimeMapping(".wri", "application/x-wri");
|
||||||
|
@ -26,13 +26,6 @@
|
|||||||
|
|
||||||
namespace ASC.Core.Common;
|
namespace ASC.Core.Common;
|
||||||
|
|
||||||
[Scope]
|
|
||||||
public class CommonLinkUtilitySettings
|
|
||||||
{
|
|
||||||
public string ServerUri { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Scope]
|
[Scope]
|
||||||
public class BaseCommonLinkUtility
|
public class BaseCommonLinkUtility
|
||||||
{
|
{
|
||||||
@ -43,14 +36,22 @@ public class BaseCommonLinkUtility
|
|||||||
private string _vpath;
|
private string _vpath;
|
||||||
|
|
||||||
protected IHttpContextAccessor _httpContextAccessor;
|
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(
|
public BaseCommonLinkUtility(
|
||||||
CoreBaseSettings coreBaseSettings,
|
CoreBaseSettings coreBaseSettings,
|
||||||
CoreSettings coreSettings,
|
CoreSettings coreSettings,
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
ILoggerProvider options,
|
ILoggerProvider options)
|
||||||
CommonLinkUtilitySettings settings)
|
: this(null, coreBaseSettings, coreSettings, tenantManager, options)
|
||||||
: this(null, coreBaseSettings, coreSettings, tenantManager, options, settings)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,37 +60,29 @@ public class BaseCommonLinkUtility
|
|||||||
CoreBaseSettings coreBaseSettings,
|
CoreBaseSettings coreBaseSettings,
|
||||||
CoreSettings coreSettings,
|
CoreSettings coreSettings,
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
ILoggerProvider options,
|
ILoggerProvider options)
|
||||||
CommonLinkUtilitySettings settings)
|
|
||||||
{
|
{
|
||||||
var serverUri = settings.ServerUri;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(serverUri))
|
try
|
||||||
{
|
{
|
||||||
var uri = new Uri(serverUri.Replace('*', 'x').Replace('+', 'x'));
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_serverRoot = new UriBuilder(uri.Scheme, uri.Host != "x" ? uri.Host : LocalHost, uri.Port);
|
|
||||||
_vpath = "/" + uri.AbsolutePath.Trim('/');
|
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
|
options.CreateLogger("ASC.Web").ErrorWithException(error);
|
||||||
{
|
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_coreBaseSettings = coreBaseSettings;
|
_coreBaseSettings = coreBaseSettings;
|
||||||
|
@ -31,7 +31,7 @@ public interface ITariffService
|
|||||||
{
|
{
|
||||||
IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds);
|
IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds);
|
||||||
IEnumerable<PaymentInfo> GetPayments(int tenantId);
|
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);
|
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(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);
|
Uri GetShoppingUri(string[] productIds, string affiliateId = null, string currency = null, string language = null, string customerId = null, string quantity = null);
|
||||||
|
@ -53,7 +53,7 @@ public class Tariff
|
|||||||
return t != null
|
return t != null
|
||||||
&& t.DueDate == DueDate
|
&& t.DueDate == DueDate
|
||||||
&& t.Quotas.Count == Quotas.Count
|
&& t.Quotas.Count == Quotas.Count
|
||||||
&& t.Quotas.Any(q => Quotas.Contains(q))
|
&& t.Quotas.Any(Quotas.Contains)
|
||||||
&& t.CustomerId == CustomerId;
|
&& t.CustomerId == CustomerId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
// 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
|
// 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
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
namespace ASC.Core.Billing;
|
namespace ASC.Core.Billing;
|
||||||
|
|
||||||
[Singletone]
|
[Singletone]
|
||||||
@ -145,18 +145,9 @@ public class TariffService : ITariffService
|
|||||||
_cache = _tariffServiceStorage.Cache;
|
_cache = _tariffServiceStorage.Cache;
|
||||||
_notify = _tariffServiceStorage.Notify;
|
_notify = _tariffServiceStorage.Notify;
|
||||||
_dbContextFactory = coreDbContextManager;
|
_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
|
//single tariff for all portals
|
||||||
if (_coreBaseSettings.Standalone)
|
if (_coreBaseSettings.Standalone)
|
||||||
@ -164,8 +155,7 @@ public class TariffService : ITariffService
|
|||||||
tenantId = -1;
|
tenantId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tariff = GetTariffFromCache(tenantId);
|
var tariff = refresh ? null : GetTariffFromCache(tenantId);
|
||||||
int? tariffId = null;
|
|
||||||
|
|
||||||
if (tariff == null)
|
if (tariff == null)
|
||||||
{
|
{
|
||||||
@ -174,11 +164,12 @@ public class TariffService : ITariffService
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(_cache.Get<string>(GetTariffNeedToUpdateCacheKey(tenantId))))
|
if (string.IsNullOrEmpty(_cache.Get<string>(GetTariffNeedToUpdateCacheKey(tenantId))))
|
||||||
{
|
{
|
||||||
tariffId = tariff.Id;
|
UpdateCache(tariff.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_billingClient.Configured && withRequestToPaymentSystem)
|
if (_billingClient.Configured && withRequestToPaymentSystem)
|
||||||
{
|
{
|
||||||
|
var paymentFound = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -190,10 +181,11 @@ public class TariffService : ITariffService
|
|||||||
|
|
||||||
var asynctariff = CreateDefault(true);
|
var asynctariff = CreateDefault(true);
|
||||||
string email = null;
|
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)
|
if (quota == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Quota with id {currentPayment.ProductId} not found for portal {GetPortalId(tenantId)}.");
|
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;
|
var paymentEndDate = 9999 <= currentPayment.EndDate.Year ? DateTime.MaxValue : currentPayment.EndDate;
|
||||||
asynctariff.DueDate = DateTime.Compare(asynctariff.DueDate, paymentEndDate) < 0 ? asynctariff.DueDate : paymentEndDate;
|
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));
|
asynctariff.Quotas.Add(new Quota(quota.Tenant, currentPayment.Quantity));
|
||||||
email = currentPayment.PaymentEmail;
|
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))
|
if (!string.IsNullOrEmpty(email))
|
||||||
{
|
{
|
||||||
asynctariff.CustomerId = email;
|
asynctariff.CustomerId = email;
|
||||||
@ -217,10 +222,21 @@ public class TariffService : ITariffService
|
|||||||
{
|
{
|
||||||
asynctariff = CalculateTariff(tenantId, asynctariff);
|
asynctariff = CalculateTariff(tenantId, asynctariff);
|
||||||
tariff = 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 =>
|
var freeTariff = tariff.Quotas.FirstOrDefault(tariffRow =>
|
||||||
{
|
{
|
||||||
@ -244,22 +260,23 @@ public class TariffService : ITariffService
|
|||||||
{
|
{
|
||||||
asynctariff = CalculateTariff(tenantId, asynctariff);
|
asynctariff = CalculateTariff(tenantId, asynctariff);
|
||||||
tariff = asynctariff;
|
tariff = asynctariff;
|
||||||
tariffId = asynctariff.Id;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception error)
|
UpdateCache(tariff.Id);
|
||||||
{
|
|
||||||
LogError(error, tenantId.ToString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (tariffId.HasValue && tariffId.Value != 0)
|
|
||||||
{
|
{
|
||||||
_notify.Publish(new TariffCacheItem { TenantId = tenantId, TariffId = tariffId.Value }, CacheNotifyAction.Insert);
|
tariff = CalculateTariff(tenantId, tariff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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)
|
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)
|
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 hasQuantity = quantity != null && quantity.Any();
|
||||||
var key = "shopingurl_" + (hasQuantity ? string.Join('_', quantity.Keys.ToArray()) : "all");
|
var key = "shopingurl_" + (hasQuantity ? string.Join('_', quantity.Keys.ToArray()) : "all");
|
||||||
var url = _cache.Get<string>(key);
|
var url = _cache.Get<string>(key);
|
||||||
@ -438,22 +476,6 @@ public class TariffService : ITariffService
|
|||||||
url = string.Empty;
|
url = string.Empty;
|
||||||
if (_billingClient.Configured)
|
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);
|
var productIds = newQuotas.Select(q => q.ProductId);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -682,6 +704,7 @@ public class TariffService : ITariffService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tariff = CreateDefault(true);
|
var tariff = CreateDefault(true);
|
||||||
|
tariff.Id = r.Id;
|
||||||
tariff.DueDate = r.Stamp.Year < 9999 ? r.Stamp : DateTime.MaxValue;
|
tariff.DueDate = r.Stamp.Year < 9999 ? r.Stamp : DateTime.MaxValue;
|
||||||
tariff.CustomerId = r.CustomerId;
|
tariff.CustomerId = r.CustomerId;
|
||||||
|
|
||||||
@ -727,6 +750,7 @@ public class TariffService : ITariffService
|
|||||||
if (efTariff.Id == default)
|
if (efTariff.Id == default)
|
||||||
{
|
{
|
||||||
efTariff.Id = (-tenant);
|
efTariff.Id = (-tenant);
|
||||||
|
tariffInfo.Id = efTariff.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (efTariff.CustomerId == default)
|
if (efTariff.CustomerId == default)
|
||||||
@ -769,8 +793,9 @@ public class TariffService : ITariffService
|
|||||||
// update tenant.LastModified to flush cache in documents
|
// update tenant.LastModified to flush cache in documents
|
||||||
_tenantService.SaveTenant(_coreSettings, t);
|
_tenantService.SaveTenant(_coreSettings, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearCache(tenant);
|
ClearCache(tenant);
|
||||||
|
|
||||||
|
NotifyWebSocket(currentTariff, tariffInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inserted;
|
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()
|
public int GetPaymentDelay()
|
||||||
{
|
{
|
||||||
return _paymentDelay;
|
return _paymentDelay;
|
||||||
|
@ -271,6 +271,7 @@ public class CachedUserService : IUserService, ICachedService
|
|||||||
{
|
{
|
||||||
Service.SetUserPhoto(tenant, id, photo);
|
Service.SetUserPhoto(tenant, id, photo);
|
||||||
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, CacheNotifyAction.Remove);
|
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)
|
public DateTime GetUserPasswordStamp(int tenant, Guid id)
|
||||||
|
@ -45,7 +45,7 @@ public class TenantManager
|
|||||||
internal CoreBaseSettings CoreBaseSettings { get; set; }
|
internal CoreBaseSettings CoreBaseSettings { get; set; }
|
||||||
internal CoreSettings CoreSettings { get; set; }
|
internal CoreSettings CoreSettings { get; set; }
|
||||||
|
|
||||||
private readonly static object _lock = new object();
|
private static readonly object _lock = new object();
|
||||||
|
|
||||||
static TenantManager()
|
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();
|
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;
|
var defaultQuota = QuotaService.GetTenantQuota(tenant) ?? QuotaService.GetTenantQuota(Tenant.DefaultTenant) ?? TenantQuota.Default;
|
||||||
if (defaultQuota.Tenant != tenant && TariffService != null)
|
if (defaultQuota.Tenant != tenant && TariffService != null)
|
||||||
{
|
{
|
||||||
var tariff = TariffService.GetTariff(tenant);
|
var tariff = TariffService.GetTariff(tenant, refresh: refresh);
|
||||||
|
|
||||||
TenantQuota currentQuota = null;
|
TenantQuota currentQuota = null;
|
||||||
foreach (var tariffRow in tariff.Quotas)
|
foreach (var tariffRow in tariff.Quotas)
|
||||||
|
@ -65,9 +65,9 @@ public class UserManager
|
|||||||
private readonly TenantQuotaFeatureCheckerCount<CountUserFeature> _activeUsersFeatureChecker;
|
private readonly TenantQuotaFeatureCheckerCount<CountUserFeature> _activeUsersFeatureChecker;
|
||||||
private readonly Constants _constants;
|
private readonly Constants _constants;
|
||||||
private readonly UserFormatter _userFormatter;
|
private readonly UserFormatter _userFormatter;
|
||||||
|
private readonly QuotaSocketManager _quotaSocketManager;
|
||||||
private Tenant _tenant;
|
private readonly TenantQuotaFeatureStatHelper _tenantQuotaFeatureStatHelper;
|
||||||
private Tenant Tenant => _tenant ??= _tenantManager.GetCurrentTenant();
|
private Tenant Tenant => _tenantManager.GetCurrentTenant();
|
||||||
|
|
||||||
public UserManager()
|
public UserManager()
|
||||||
{
|
{
|
||||||
@ -88,7 +88,9 @@ public class UserManager
|
|||||||
ICache cache,
|
ICache cache,
|
||||||
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> countPaidUserChecker,
|
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> countPaidUserChecker,
|
||||||
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
|
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
|
||||||
UserFormatter userFormatter
|
UserFormatter userFormatter,
|
||||||
|
QuotaSocketManager quotaSocketManager,
|
||||||
|
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_userService = service;
|
_userService = service;
|
||||||
@ -106,6 +108,8 @@ public class UserManager
|
|||||||
_activeUsersFeatureChecker = activeUsersFeatureChecker;
|
_activeUsersFeatureChecker = activeUsersFeatureChecker;
|
||||||
_constants = _userManagerConstants.Constants;
|
_constants = _userManagerConstants.Constants;
|
||||||
_userFormatter = userFormatter;
|
_userFormatter = userFormatter;
|
||||||
|
_quotaSocketManager = quotaSocketManager;
|
||||||
|
_tenantQuotaFeatureStatHelper = tenantQuotaFeatureStatHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserManager(
|
public UserManager(
|
||||||
@ -123,8 +127,10 @@ public class UserManager
|
|||||||
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> tenantQuotaFeatureChecker,
|
TenantQuotaFeatureCheckerCount<CountPaidUserFeature> tenantQuotaFeatureChecker,
|
||||||
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
|
TenantQuotaFeatureCheckerCount<CountUserFeature> activeUsersFeatureChecker,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
UserFormatter userFormatter)
|
UserFormatter userFormatter,
|
||||||
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings, coreSettings, instanceCrypto, radicaleClient, cardDavAddressbook, log, cache, tenantQuotaFeatureChecker, activeUsersFeatureChecker, userFormatter)
|
QuotaSocketManager quotaSocketManager,
|
||||||
|
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper)
|
||||||
|
: this(service, tenantManager, permissionContext, userManagerConstants, coreBaseSettings, coreSettings, instanceCrypto, radicaleClient, cardDavAddressbook, log, cache, tenantQuotaFeatureChecker, activeUsersFeatureChecker, userFormatter, quotaSocketManager, tenantQuotaFeatureStatHelper)
|
||||||
{
|
{
|
||||||
_accessor = httpContextAccessor;
|
_accessor = httpContextAccessor;
|
||||||
}
|
}
|
||||||
@ -322,7 +328,7 @@ public class UserManager
|
|||||||
return findUsers.ToArray();
|
return findUsers.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserInfo UpdateUserInfo(UserInfo u)
|
public async Task<UserInfo> UpdateUserInfo(UserInfo u)
|
||||||
{
|
{
|
||||||
if (IsSystemUser(u.Id))
|
if (IsSystemUser(u.Id))
|
||||||
{
|
{
|
||||||
@ -343,15 +349,31 @@ public class UserManager
|
|||||||
throw new InvalidOperationException("User not found.");
|
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)
|
public async Task<UserInfo> UpdateUserInfoWithSyncCardDavAsync(UserInfo u)
|
||||||
{
|
{
|
||||||
var oldUserData = _userService.GetUserByUserName(_tenantManager.GetCurrentTenant().Id, u.UserName);
|
var oldUserData = _userService.GetUserByUserName(_tenantManager.GetCurrentTenant().Id, u.UserName);
|
||||||
|
|
||||||
var newUser = UpdateUserInfo(u);
|
var newUser = await UpdateUserInfo(u);
|
||||||
|
|
||||||
if (_coreBaseSettings.DisableDocSpace)
|
if (_coreBaseSettings.DisableDocSpace)
|
||||||
{
|
{
|
||||||
await SyncCardDavAsync(u, oldUserData, newUser);
|
await SyncCardDavAsync(u, oldUserData, newUser);
|
||||||
@ -644,7 +666,7 @@ public class UserManager
|
|||||||
return GetUsers(employeeStatus).Where(u => IsUserInGroupInternal(u.Id, groupId, refs)).ToArray();
|
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)
|
if (Constants.LostUser.Id == userId || Constants.LostGroupInfo.ID == groupId)
|
||||||
{
|
{
|
||||||
@ -652,6 +674,8 @@ public class UserManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
var user = GetUsers(userId);
|
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),
|
_permissionContext.DemandPermissions(new UserGroupObject(new UserAccount(user, _tenantManager.GetCurrentTenant().Id, _userFormatter), groupId),
|
||||||
Constants.Action_EditGroups);
|
Constants.Action_EditGroups);
|
||||||
@ -659,6 +683,7 @@ public class UserManager
|
|||||||
_userService.SaveUserGroupRef(Tenant.Id, new UserGroupRef(userId, groupId, UserGroupRefType.Contains));
|
_userService.SaveUserGroupRef(Tenant.Id, new UserGroupRef(userId, groupId, UserGroupRefType.Contains));
|
||||||
|
|
||||||
ResetGroupCache(userId);
|
ResetGroupCache(userId);
|
||||||
|
|
||||||
if (groupId == Constants.GroupUser.ID)
|
if (groupId == Constants.GroupUser.ID)
|
||||||
{
|
{
|
||||||
var tenant = _tenantManager.GetCurrentTenant();
|
var tenant = _tenantManager.GetCurrentTenant();
|
||||||
@ -671,9 +696,21 @@ public class UserManager
|
|||||||
await _cardDavAddressbook.Delete(myUri, user.Id, user.Email, tenant.Id);
|
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)
|
if (Constants.LostUser.Id == userId || Constants.LostGroupInfo.ID == groupId)
|
||||||
{
|
{
|
||||||
@ -681,6 +718,8 @@ public class UserManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
var user = GetUsers(userId);
|
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),
|
_permissionContext.DemandPermissions(new UserGroupObject(new UserAccount(user, _tenantManager.GetCurrentTenant().Id, _userFormatter), groupId),
|
||||||
Constants.Action_EditGroups);
|
Constants.Action_EditGroups);
|
||||||
@ -688,6 +727,16 @@ public class UserManager
|
|||||||
_userService.RemoveUserGroupRef(Tenant.Id, userId, groupId, UserGroupRefType.Contains);
|
_userService.RemoveUserGroupRef(Tenant.Id, userId, groupId, UserGroupRefType.Contains);
|
||||||
|
|
||||||
ResetGroupCache(userId);
|
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)
|
internal void ResetGroupCache(Guid userID)
|
||||||
@ -904,7 +953,7 @@ public class UserManager
|
|||||||
{
|
{
|
||||||
return isCollaborator;
|
return isCollaborator;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupId == Constants.GroupManager.ID)
|
if (groupId == Constants.GroupManager.ID)
|
||||||
{
|
{
|
||||||
return !isUser && !isCollaborator;
|
return !isUser && !isCollaborator;
|
||||||
@ -930,4 +979,9 @@ public class UserManager
|
|||||||
Sid = g.Sid
|
Sid = g.Sid
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsPaidUser(UserInfo userInfo)
|
||||||
|
{
|
||||||
|
return this.IsCollaborator(userInfo) || this.IsDocSpaceAdmin(userInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ public class WorkContext
|
|||||||
INotifySender emailSender = _notifyServiceSender;
|
INotifySender emailSender = _notifyServiceSender;
|
||||||
INotifySender telegramSender = _telegramSender;
|
INotifySender telegramSender = _telegramSender;
|
||||||
INotifySender pushSender = _pushSender;
|
INotifySender pushSender = _pushSender;
|
||||||
|
|
||||||
|
|
||||||
var postman = _configuration["core:notify:postman"];
|
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)
|
public void RegisterSendMethod(Action<DateTime> method, string cron)
|
||||||
{
|
{
|
||||||
NotifyEngine.RegisterSendMethod(method, cron);
|
NotifyEngine.RegisterSendMethod(method, cron);
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// 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
|
// 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;
|
namespace ASC.Core.Data;
|
||||||
|
|
||||||
[Scope]
|
[Scope]
|
||||||
@ -227,7 +231,7 @@ public class EFUserService : IUserService
|
|||||||
if (sortBy == "type")
|
if (sortBy == "type")
|
||||||
{
|
{
|
||||||
var q1 = from user in q
|
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))
|
|| g.UserGroupId == Users.Constants.GroupCollaborator.ID))
|
||||||
on user.Id equals userGroup.Userid into joinedGroup
|
on user.Id equals userGroup.Userid into joinedGroup
|
||||||
from @group in joinedGroup.DefaultIfEmpty()
|
from @group in joinedGroup.DefaultIfEmpty()
|
||||||
@ -317,8 +321,8 @@ public class EFUserService : IUserService
|
|||||||
|
|
||||||
if (immediate)
|
if (immediate)
|
||||||
{
|
{
|
||||||
await userGroups.ExecuteDeleteAsync();
|
await userGroups.ExecuteDeleteAsync();
|
||||||
await groups.ExecuteDeleteAsync();
|
await groups.ExecuteDeleteAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -372,15 +376,15 @@ public class EFUserService : IUserService
|
|||||||
.SetProperty(p => p.Removed, true)
|
.SetProperty(p => p.Removed, true)
|
||||||
.SetProperty(p => p.LastModified, DateTime.UtcNow));
|
.SetProperty(p => p.LastModified, DateTime.UtcNow));
|
||||||
|
|
||||||
await users.ExecuteUpdateAsync(ug => ug
|
await users.ExecuteUpdateAsync(ug => ug
|
||||||
.SetProperty(p => p.Removed, true)
|
.SetProperty(p => p.Removed, true)
|
||||||
.SetProperty(p => p.LastModified, DateTime.UtcNow)
|
.SetProperty(p => p.LastModified, DateTime.UtcNow)
|
||||||
.SetProperty(p => p.TerminatedDate, DateTime.UtcNow)
|
.SetProperty(p => p.TerminatedDate, DateTime.UtcNow)
|
||||||
.SetProperty(p => p.Status, EmployeeStatus.Terminated)
|
.SetProperty(p => p.Status, EmployeeStatus.Terminated)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await tr.CommitAsync();
|
await tr.CommitAsync();
|
||||||
}).GetAwaiter()
|
}).GetAwaiter()
|
||||||
.GetResult();
|
.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);
|
var userGroups = userDbContext.UserGroups.Where(r => r.Tenant == tenant && r.Userid == userId && r.UserGroupId == groupId && r.RefType == refType);
|
||||||
if (immediate)
|
if (immediate)
|
||||||
{
|
{
|
||||||
await userGroups.ExecuteDeleteAsync();
|
await userGroups.ExecuteDeleteAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -517,7 +521,7 @@ public class EFUserService : IUserService
|
|||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
user.LastModified = userGroupRef.LastModified;
|
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();
|
await userDbContext.SaveChangesAsync();
|
||||||
@ -548,42 +552,45 @@ public class EFUserService : IUserService
|
|||||||
public void SetUserPhoto(int tenant, Guid id, byte[] photo)
|
public void SetUserPhoto(int tenant, Guid id, byte[] photo)
|
||||||
{
|
{
|
||||||
using var userDbContext = _dbContextFactory.CreateDbContext();
|
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();
|
if (userPhoto == null)
|
||||||
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)
|
userPhoto = new UserPhoto
|
||||||
{
|
{
|
||||||
userPhoto = new UserPhoto
|
Tenant = tenant,
|
||||||
{
|
UserId = id,
|
||||||
Tenant = tenant,
|
Photo = photo
|
||||||
UserId = id,
|
};
|
||||||
Photo = photo
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
userPhoto.Photo = photo;
|
|
||||||
}
|
|
||||||
|
|
||||||
await userDbContext.AddOrUpdateAsync(r => userDbContext.Photos, userPhoto);
|
|
||||||
}
|
}
|
||||||
else if (userPhoto != null)
|
else
|
||||||
{
|
{
|
||||||
userDbContext.Photos.Remove(userPhoto);
|
userPhoto.Photo = photo;
|
||||||
}
|
}
|
||||||
|
|
||||||
await userDbContext.SaveChangesAsync();
|
|
||||||
await tr.CommitAsync();
|
userDbContext.AddOrUpdate(userDbContext.Photos, userPhoto);
|
||||||
}).GetAwaiter()
|
|
||||||
.GetResult();
|
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)
|
private IQueryable<User> GetUserQuery(UserDbContext userDbContext, int tenant)
|
||||||
|
@ -59,7 +59,7 @@ public static class DbQuotaExtension
|
|||||||
Tenant = -1,
|
Tenant = -1,
|
||||||
Name = "trial",
|
Name = "trial",
|
||||||
Description = null,
|
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,
|
Price = 0,
|
||||||
ProductId = null,
|
ProductId = null,
|
||||||
Visible = false
|
Visible = false
|
||||||
@ -69,7 +69,7 @@ public static class DbQuotaExtension
|
|||||||
Tenant = -2,
|
Tenant = -2,
|
||||||
Name = "admin",
|
Name = "admin",
|
||||||
Description = null,
|
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,
|
Price = 30,
|
||||||
ProductId = "1002",
|
ProductId = "1002",
|
||||||
Visible = true
|
Visible = true
|
||||||
@ -79,7 +79,7 @@ public static class DbQuotaExtension
|
|||||||
Tenant = -3,
|
Tenant = -3,
|
||||||
Name = "startup",
|
Name = "startup",
|
||||||
Description = null,
|
Description = null,
|
||||||
Features = "free,total_size:2147483648,manager:5,room:5",
|
Features = "free,total_size:2147483648,manager:3,room:12",
|
||||||
Price = 0,
|
Price = 0,
|
||||||
ProductId = null,
|
ProductId = null,
|
||||||
Visible = false
|
Visible = false
|
||||||
|
@ -100,6 +100,25 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
|||||||
_methodsEvent.Set();
|
_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)
|
internal void UnregisterSendMethod(Action<DateTime> method)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(method);
|
ArgumentNullException.ThrowIfNull(method);
|
||||||
@ -124,7 +143,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
|||||||
copy = _sendMethods.ToList();
|
copy = _sendMethods.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(var w in copy)
|
foreach (var w in copy)
|
||||||
{
|
{
|
||||||
if (!w.ScheduleDate.HasValue)
|
if (!w.ScheduleDate.HasValue)
|
||||||
{
|
{
|
||||||
@ -590,6 +609,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
|||||||
private readonly SemaphoreSlim _semaphore;
|
private readonly SemaphoreSlim _semaphore;
|
||||||
private readonly CronExpression _cronExpression;
|
private readonly CronExpression _cronExpression;
|
||||||
private readonly Action<DateTime> _method;
|
private readonly Action<DateTime> _method;
|
||||||
|
private readonly Func<DateTime, Task> _asyncMethod;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public DateTime? ScheduleDate { get; private set; }
|
public DateTime? ScheduleDate { get; private set; }
|
||||||
@ -608,6 +628,11 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
|||||||
UpdateScheduleDate(DateTime.UtcNow);
|
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)
|
public void UpdateScheduleDate(DateTime d)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -626,11 +651,18 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
|||||||
public async Task InvokeSendMethod(DateTime d)
|
public async Task InvokeSendMethod(DateTime d)
|
||||||
{
|
{
|
||||||
await _semaphore.WaitAsync();
|
await _semaphore.WaitAsync();
|
||||||
await Task.Run(() =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_method(d);
|
if (_method != null)
|
||||||
|
{
|
||||||
|
_method(d);
|
||||||
|
}
|
||||||
|
else if (_asyncMethod != null)
|
||||||
|
{
|
||||||
|
await _asyncMethod(d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -642,7 +674,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
|||||||
|
|
||||||
public override bool Equals(object obj)
|
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()
|
public override int GetHashCode()
|
||||||
|
@ -1,45 +1,34 @@
|
|||||||
// (c) Copyright Ascensio System SIA 2010-2022
|
// (c) Copyright Ascensio System SIA 2010-2022
|
||||||
//
|
//
|
||||||
// This program is a free software product.
|
// This program is a free software product.
|
||||||
// You can redistribute it and/or modify it under the terms
|
// 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
|
// 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
|
// 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
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||||
// any third-party rights.
|
// any third-party rights.
|
||||||
//
|
//
|
||||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
// 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.
|
// 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
|
// 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.
|
// 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
|
// 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
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||||
// trademark law for use of our trademarks.
|
// trademark law for use of our trademarks.
|
||||||
//
|
//
|
||||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
// 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
|
// 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
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
namespace ASC.Files.Thirdparty.Box;
|
namespace ASC.Core.Common.Quota.Features;
|
||||||
|
public class FreeFeature : TenantQuotaFeatureFlag
|
||||||
[Scope]
|
{
|
||||||
internal class BoxTagDao : BoxDaoBase, ITagDao<string>
|
public override string Name { get => "free"; }
|
||||||
{
|
public FreeFeature(TenantQuota tenantQuota) : base(tenantQuota)
|
||||||
public BoxTagDao(
|
{
|
||||||
IServiceProvider serviceProvider,
|
}
|
||||||
UserManager userManager,
|
}
|
||||||
TenantManager tenantManager,
|
|
||||||
TenantUtil tenantUtil,
|
|
||||||
IDbContextFactory<FilesDbContext> dbContextManager,
|
|
||||||
SetupInfo setupInfo,
|
|
||||||
ILogger<BoxTagDao> monitor,
|
|
||||||
FileUtility fileUtility,
|
|
||||||
TempPath tempPath,
|
|
||||||
AuthContext authContext) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility, tempPath, authContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
64
common/ASC.Core.Common/Quota/QuotaSocketManager.cs
Normal file
64
common/ASC.Core.Common/Quota/QuotaSocketManager.cs
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
@ -67,7 +67,7 @@ public class TenantQuotaFeature<T> : TenantQuotaFeature
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual T Default { get; }
|
public virtual T Default { get; }
|
||||||
|
|
||||||
public TenantQuotaFeature(TenantQuota tenantQuota)
|
public TenantQuotaFeature(TenantQuota tenantQuota)
|
||||||
{
|
{
|
||||||
@ -83,7 +83,7 @@ public class TenantQuotaFeature<T> : TenantQuotaFeature
|
|||||||
|
|
||||||
public class TenantQuotaFeatureCount : TenantQuotaFeature<int>
|
public class TenantQuotaFeatureCount : TenantQuotaFeature<int>
|
||||||
{
|
{
|
||||||
protected override int Default => int.MaxValue;
|
public override int Default => int.MaxValue;
|
||||||
|
|
||||||
public TenantQuotaFeatureCount(TenantQuota tenantQuota) : base(tenantQuota)
|
public TenantQuotaFeatureCount(TenantQuota tenantQuota) : base(tenantQuota)
|
||||||
{
|
{
|
||||||
@ -105,7 +105,7 @@ public class TenantQuotaFeatureCount : TenantQuotaFeature<int>
|
|||||||
|
|
||||||
public class TenantQuotaFeatureSize : TenantQuotaFeature<long>
|
public class TenantQuotaFeatureSize : TenantQuotaFeature<long>
|
||||||
{
|
{
|
||||||
protected override long Default => long.MaxValue;
|
public override long Default => long.MaxValue;
|
||||||
|
|
||||||
public TenantQuotaFeatureSize(TenantQuota tenantQuota) : base(tenantQuota)
|
public TenantQuotaFeatureSize(TenantQuota tenantQuota) : base(tenantQuota)
|
||||||
{
|
{
|
||||||
|
@ -1,46 +1,50 @@
|
|||||||
// (c) Copyright Ascensio System SIA 2010-2022
|
// (c) Copyright Ascensio System SIA 2010-2022
|
||||||
//
|
//
|
||||||
// This program is a free software product.
|
// This program is a free software product.
|
||||||
// You can redistribute it and/or modify it under the terms
|
// 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
|
// 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
|
// 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
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||||
// any third-party rights.
|
// any third-party rights.
|
||||||
//
|
//
|
||||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
// 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.
|
// 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
|
// 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.
|
// 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
|
// 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
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||||
// trademark law for use of our trademarks.
|
// trademark law for use of our trademarks.
|
||||||
//
|
//
|
||||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
// 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
|
// 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
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
namespace ASC.Files.Thirdparty.OneDrive;
|
namespace ASC.Core.Common.Quota;
|
||||||
|
[Scope]
|
||||||
[Scope]
|
public class TenantQuotaFeatureStatHelper
|
||||||
internal class OneDriveTagDao : OneDriveDaoBase, ITagDao<string>
|
{
|
||||||
{
|
private readonly IServiceProvider _serviceProvider;
|
||||||
public OneDriveTagDao(
|
public TenantQuotaFeatureStatHelper(IServiceProvider serviceProvider)
|
||||||
IServiceProvider serviceProvider,
|
{
|
||||||
UserManager userManager,
|
_serviceProvider = serviceProvider;
|
||||||
TenantManager tenantManager,
|
}
|
||||||
TenantUtil tenantUtil,
|
public async Task<(string Name, T1 Value)> GetStat<T, T1>() where T : TenantQuotaFeature
|
||||||
IDbContextFactory<FilesDbContext> dbContextManager,
|
{
|
||||||
SetupInfo setupInfo,
|
var statisticProvider = (ITenantQuotaFeatureStat<T1>)_serviceProvider.GetService(typeof(ITenantQuotaFeatureStat<,>).MakeGenericType(typeof(T), typeof(T1)));
|
||||||
ILogger<OneDriveTagDao> monitor,
|
|
||||||
FileUtility fileUtility,
|
var quota = new TenantQuota();
|
||||||
TempPath tempPath,
|
var name = quota.GetFeature<T>().Name;
|
||||||
AuthContext authContext)
|
|
||||||
: base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility, tempPath, authContext)
|
if (statisticProvider != null)
|
||||||
{
|
{
|
||||||
}
|
return (name, await statisticProvider.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (name, default(T1));
|
||||||
|
}
|
||||||
|
}
|
@ -222,13 +222,13 @@ public class TenantQuota : IMapFrom<DbQuota>
|
|||||||
|
|
||||||
_countUserFeature = new CountUserFeature(this) { Order = 1 };
|
_countUserFeature = new CountUserFeature(this) { Order = 1 };
|
||||||
_countPaidUserFeature = new CountPaidUserFeature(this);
|
_countPaidUserFeature = new CountPaidUserFeature(this);
|
||||||
_usersInRoomFeature = new UsersInRoomFeature(this) { Order = 8 };
|
_usersInRoomFeature = new UsersInRoomFeature(this) { Order = 8, Visible = false };
|
||||||
_countRoomFeature = new CountRoomFeature(this) { Order = 2 };
|
_countRoomFeature = new CountRoomFeature(this) { Order = 2 };
|
||||||
_maxTotalSizeFeature = new MaxTotalSizeFeature(this);
|
_maxTotalSizeFeature = new MaxTotalSizeFeature(this);
|
||||||
_maxFileSizeFeature = new MaxFileSizeFeature(this);
|
_maxFileSizeFeature = new MaxFileSizeFeature(this);
|
||||||
_nonProfitFeature = new TenantQuotaFeatureFlag(this) { Name = "non-profit", Visible = false };
|
_nonProfitFeature = new TenantQuotaFeatureFlag(this) { Name = "non-profit", Visible = false };
|
||||||
_trialFeature = new TenantQuotaFeatureFlag(this) { Name = "trial", 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 };
|
_updateFeature = new TenantQuotaFeatureFlag(this) { Name = "update", Visible = false };
|
||||||
_auditFeature = new TenantQuotaFeatureFlag(this) { Name = "audit", Order = 7 };
|
_auditFeature = new TenantQuotaFeatureFlag(this) { Name = "audit", Order = 7 };
|
||||||
_docsEditionFeature = new TenantQuotaFeatureFlag(this) { Name = "docs", Visible = false };
|
_docsEditionFeature = new TenantQuotaFeatureFlag(this) { Name = "docs", Visible = false };
|
||||||
@ -323,7 +323,7 @@ public class TenantQuota : IMapFrom<DbQuota>
|
|||||||
return quota;
|
return quota;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newQuota = new TenantQuota(quota);
|
var newQuota = new TenantQuota(old);
|
||||||
newQuota.Price += quota.Price;
|
newQuota.Price += quota.Price;
|
||||||
newQuota.Visible &= quota.Visible;
|
newQuota.Visible &= quota.Visible;
|
||||||
newQuota.ProductId = "";
|
newQuota.ProductId = "";
|
||||||
@ -336,11 +336,31 @@ public class TenantQuota : IMapFrom<DbQuota>
|
|||||||
}
|
}
|
||||||
else if (f is TenantQuotaFeatureCount count)
|
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)
|
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)
|
else if (f is TenantQuotaFeatureFlag flag)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ public class BackupRepository : IBackupRepository
|
|||||||
public List<BackupRecord> GetExpiredBackupRecords()
|
public List<BackupRecord> GetExpiredBackupRecords()
|
||||||
{
|
{
|
||||||
using var backupContext = _dbContextFactory.CreateDbContext();
|
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()
|
public List<BackupRecord> GetScheduledBackupRecords()
|
||||||
|
@ -709,14 +709,18 @@ public class BackupPortalTask : PortalTaskBase
|
|||||||
foreach (var file in group)
|
foreach (var file in group)
|
||||||
{
|
{
|
||||||
var storage = StorageFactory.GetStorage(TenantId, group.Key);
|
var storage = StorageFactory.GetStorage(TenantId, group.Key);
|
||||||
var file1 = file;
|
var file1 = file;
|
||||||
|
Stream fileStream = null;
|
||||||
await ActionInvoker.Try(async state =>
|
await ActionInvoker.Try(async state =>
|
||||||
{
|
{
|
||||||
var f = (BackupFileInfo)state;
|
var f = (BackupFileInfo)state;
|
||||||
using var fileStream = await storage.GetReadStreamAsync(f.Domain, f.Path);
|
fileStream = await storage.GetReadStreamAsync(f.Domain, f.Path);
|
||||||
await writer.WriteEntryAsync(file1.GetZipKey(), fileStream);
|
|
||||||
}, file, 5, error => _logger.WarningCanNotBackupFile(file1.Module, file1.Path, error));
|
}, 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));
|
SetCurrentStepProgress((int)(++filesProcessed * 100 / (double)filesCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// 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
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using ASC.Files.Core.Core.Thirdparty.ProviderDao;
|
||||||
|
|
||||||
namespace ASC.Data.Backup.Tasks.Modules;
|
namespace ASC.Data.Backup.Tasks.Modules;
|
||||||
|
|
||||||
public class FilesModuleSpecifics : ModuleSpecificsBase
|
public class FilesModuleSpecifics : ModuleSpecificsBase
|
||||||
@ -172,8 +176,8 @@ public class FilesModuleSpecifics : ModuleSpecificsBase
|
|||||||
preparedRow = new Dictionary<string, object>();
|
preparedRow = new Dictionary<string, object>();
|
||||||
|
|
||||||
object folderId = null;
|
object folderId = null;
|
||||||
|
var ids = string.Join("-|", Selectors.All.Select(s => s.Id));
|
||||||
var sboxId = Regex.Replace(row[1].ToString(), @"(?<=(?:sbox-|box-|dropbox-|spoint-|drive-|onedrive-))\d+", match =>
|
var sboxId = Regex.Replace(row[1].ToString(), @"(?<=(?:" + $"{ids}-" + @"))\d+", match =>
|
||||||
{
|
{
|
||||||
folderId = columnMapper.GetMapping("files_thirdparty_account", "id", match.Value);
|
folderId = columnMapper.GetMapping("files_thirdparty_account", "id", match.Value);
|
||||||
|
|
||||||
|
@ -48,6 +48,9 @@ public abstract class BaseStorage : IDataStore
|
|||||||
protected readonly ILoggerProvider _options;
|
protected readonly ILoggerProvider _options;
|
||||||
protected readonly IHttpClientFactory _clientFactory;
|
protected readonly IHttpClientFactory _clientFactory;
|
||||||
|
|
||||||
|
private readonly TenantQuotaFeatureStatHelper _tenantQuotaFeatureStatHelper;
|
||||||
|
private readonly QuotaSocketManager _quotaSocketManager;
|
||||||
|
|
||||||
public BaseStorage(
|
public BaseStorage(
|
||||||
TempStream tempStream,
|
TempStream tempStream,
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
@ -56,7 +59,9 @@ public abstract class BaseStorage : IDataStore
|
|||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
ILoggerProvider options,
|
ILoggerProvider options,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IHttpClientFactory clientFactory)
|
IHttpClientFactory clientFactory,
|
||||||
|
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
|
||||||
|
QuotaSocketManager quotaSocketManager)
|
||||||
{
|
{
|
||||||
|
|
||||||
_tempStream = tempStream;
|
_tempStream = tempStream;
|
||||||
@ -67,6 +72,8 @@ public abstract class BaseStorage : IDataStore
|
|||||||
_clientFactory = clientFactory;
|
_clientFactory = clientFactory;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
_tenantQuotaFeatureStatHelper = tenantQuotaFeatureStatHelper;
|
||||||
|
_quotaSocketManager = quotaSocketManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan GetExpire(string domain)
|
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,
|
public abstract string GetPostParams(string domain, string directoryPath, long maxUploadSize, string contentType,
|
||||||
string contentDisposition);
|
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)
|
if (QuotaController != null)
|
||||||
{
|
{
|
||||||
QuotaController.QuotaUsedAdd(Modulename, domain, DataList.GetData(domain), size, quotaCheckFileSize);
|
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)
|
if (QuotaController != null)
|
||||||
{
|
{
|
||||||
QuotaController.QuotaUsedDelete(Modulename, domain, DataList.GetData(domain), size);
|
QuotaController.QuotaUsedDelete(Modulename, domain, DataList.GetData(domain), size);
|
||||||
|
var (name, value) = await _tenantQuotaFeatureStatHelper.GetStat<MaxTotalSizeFeature, long>();
|
||||||
|
_ = _quotaSocketManager.ChangeQuotaUsedValue(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +75,10 @@ public class DiscDataStore : BaseStorage
|
|||||||
ILogger<DiscDataStore> logger,
|
ILogger<DiscDataStore> logger,
|
||||||
EncryptionSettingsHelper encryptionSettingsHelper,
|
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||||
EncryptionFactory encryptionFactory,
|
EncryptionFactory encryptionFactory,
|
||||||
IHttpClientFactory clientFactory)
|
IHttpClientFactory clientFactory,
|
||||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, clientFactory)
|
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
|
||||||
|
QuotaSocketManager quotaSocketManager)
|
||||||
|
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, clientFactory, tenantQuotaFeatureStatHelper, quotaSocketManager)
|
||||||
{
|
{
|
||||||
_encryptionSettingsHelper = encryptionSettingsHelper;
|
_encryptionSettingsHelper = encryptionSettingsHelper;
|
||||||
_encryptionFactory = encryptionFactory;
|
_encryptionFactory = encryptionFactory;
|
||||||
@ -143,18 +145,18 @@ public class DiscDataStore : BaseStorage
|
|||||||
{
|
{
|
||||||
return SaveAsync(domain, path, stream);
|
return SaveAsync(domain, path, stream);
|
||||||
}
|
}
|
||||||
private bool EnableQuotaCheck(string domain)
|
private bool EnableQuotaCheck(string domain)
|
||||||
{
|
{
|
||||||
return (QuotaController != null) && !domain.EndsWith("_temp");
|
return (QuotaController != null) && !domain.EndsWith("_temp");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<Uri> SaveAsync(string domain, string path, Stream stream)
|
public override Task<Uri> SaveAsync(string domain, string path, Stream stream)
|
||||||
{
|
{
|
||||||
Logger.DebugSavePath(path);
|
Logger.DebugSavePath(path);
|
||||||
|
|
||||||
var buffered = _tempStream.GetBuffered(stream);
|
var buffered = _tempStream.GetBuffered(stream);
|
||||||
|
|
||||||
if (EnableQuotaCheck(domain))
|
if (EnableQuotaCheck(domain))
|
||||||
{
|
{
|
||||||
QuotaController.QuotaUsedCheck(buffered.Length);
|
QuotaController.QuotaUsedCheck(buffered.Length);
|
||||||
}
|
}
|
||||||
@ -193,7 +195,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
fslen = fs.Length;
|
fslen = fs.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuotaUsedAdd(domain, fslen);
|
await QuotaUsedAdd(domain, fslen);
|
||||||
|
|
||||||
_crypt.EncryptFile(target);
|
_crypt.EncryptFile(target);
|
||||||
|
|
||||||
@ -226,7 +228,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
return string.Format("{0}_{1}", chunkNumber, uploadId);
|
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);
|
var target = GetTarget(domain, path);
|
||||||
|
|
||||||
@ -238,12 +240,12 @@ public class DiscDataStore : BaseStorage
|
|||||||
}
|
}
|
||||||
|
|
||||||
var size = _crypt.GetFileSize(target);
|
var size = _crypt.GetFileSize(target);
|
||||||
QuotaUsedAdd(domain, size);
|
await QuotaUsedAdd(domain, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
_crypt.EncryptFile(target);
|
_crypt.EncryptFile(target);
|
||||||
|
|
||||||
return GetUriAsync(domain, path);
|
return await GetUriAsync(domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task AbortChunkedUploadAsync(string domain, string path, string uploadId)
|
public override Task AbortChunkedUploadAsync(string domain, string path, string uploadId)
|
||||||
@ -258,7 +260,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public override Task DeleteAsync(string domain, string path)
|
public override async Task DeleteAsync(string domain, string path)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(path);
|
ArgumentNullException.ThrowIfNull(path);
|
||||||
|
|
||||||
@ -269,8 +271,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
var size = _crypt.GetFileSize(target);
|
var size = _crypt.GetFileSize(target);
|
||||||
File.Delete(target);
|
File.Delete(target);
|
||||||
|
|
||||||
QuotaUsedDelete(domain, size);
|
await QuotaUsedDelete(domain, size);
|
||||||
return Task.CompletedTask; ;
|
|
||||||
}
|
}
|
||||||
else
|
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);
|
ArgumentNullException.ThrowIfNull(paths);
|
||||||
|
|
||||||
@ -294,13 +295,11 @@ public class DiscDataStore : BaseStorage
|
|||||||
var size = _crypt.GetFileSize(target);
|
var size = _crypt.GetFileSize(target);
|
||||||
File.Delete(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);
|
ArgumentNullException.ThrowIfNull(folderPath);
|
||||||
|
|
||||||
@ -313,9 +312,8 @@ public class DiscDataStore : BaseStorage
|
|||||||
{
|
{
|
||||||
var size = _crypt.GetFileSize(entry);
|
var size = _crypt.GetFileSize(entry);
|
||||||
File.Delete(entry);
|
File.Delete(entry);
|
||||||
QuotaUsedDelete(domain, size);
|
await QuotaUsedDelete(domain, size);
|
||||||
}
|
}
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
else
|
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);
|
ArgumentNullException.ThrowIfNull(folderPath);
|
||||||
|
|
||||||
@ -339,7 +337,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
{
|
{
|
||||||
var size = _crypt.GetFileSize(entry);
|
var size = _crypt.GetFileSize(entry);
|
||||||
File.Delete(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");
|
throw new DirectoryNotFoundException($"Directory '{targetDir}' not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task MoveDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
|
public override Task MoveDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
|
||||||
@ -367,7 +363,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
return Task.CompletedTask;
|
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(srcpath);
|
||||||
ArgumentNullException.ThrowIfNull(newpath);
|
ArgumentNullException.ThrowIfNull(newpath);
|
||||||
@ -392,14 +388,14 @@ public class DiscDataStore : BaseStorage
|
|||||||
|
|
||||||
File.Move(target, newtarget);
|
File.Move(target, newtarget);
|
||||||
|
|
||||||
QuotaUsedDelete(srcdomain, flength);
|
await QuotaUsedDelete(srcdomain, flength);
|
||||||
QuotaUsedAdd(newdomain, flength, quotaCheckFileSize);
|
await QuotaUsedAdd(newdomain, flength, quotaCheckFileSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
|
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)
|
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));
|
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);
|
ArgumentNullException.ThrowIfNull(path);
|
||||||
|
|
||||||
@ -434,7 +430,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
|
|
||||||
if (!Directory.Exists(targetDir))
|
if (!Directory.Exists(targetDir))
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.AllDirectories);
|
var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.AllDirectories);
|
||||||
@ -446,8 +442,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
|
|
||||||
Directory.Delete(targetDir, true);
|
Directory.Delete(targetDir, true);
|
||||||
|
|
||||||
QuotaUsedDelete(domain, size);
|
await QuotaUsedDelete(domain, size);
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<long> GetFileSizeAsync(string domain, string path)
|
public override Task<long> GetFileSizeAsync(string domain, string path)
|
||||||
@ -488,7 +483,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
return result.ToString();
|
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);
|
ArgumentNullException.ThrowIfNull(folderPath);
|
||||||
|
|
||||||
@ -496,7 +491,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
var targetDir = GetTarget(domain, folderPath);
|
var targetDir = GetTarget(domain, folderPath);
|
||||||
if (!Directory.Exists(targetDir))
|
if (!Directory.Exists(targetDir))
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.TopDirectoryOnly);
|
var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.TopDirectoryOnly);
|
||||||
@ -508,11 +503,9 @@ public class DiscDataStore : BaseStorage
|
|||||||
var size = _crypt.GetFileSize(entry);
|
var size = _crypt.GetFileSize(entry);
|
||||||
File.Delete(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)
|
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);
|
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(srcpath);
|
||||||
ArgumentNullException.ThrowIfNull(newpath);
|
ArgumentNullException.ThrowIfNull(newpath);
|
||||||
@ -626,16 +619,16 @@ public class DiscDataStore : BaseStorage
|
|||||||
File.Copy(target, newtarget, true);
|
File.Copy(target, newtarget, true);
|
||||||
|
|
||||||
var flength = _crypt.GetFileSize(target);
|
var flength = _crypt.GetFileSize(target);
|
||||||
QuotaUsedAdd(newdomain, flength);
|
await QuotaUsedAdd(newdomain, flength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
|
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 target = GetTarget(srcdomain, srcdir);
|
||||||
var newtarget = GetTarget(newdomain, newdir);
|
var newtarget = GetTarget(newdomain, newdir);
|
||||||
@ -643,8 +636,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
var diSource = new DirectoryInfo(target);
|
var diSource = new DirectoryInfo(target);
|
||||||
var diTarget = new DirectoryInfo(newtarget);
|
var diTarget = new DirectoryInfo(newtarget);
|
||||||
|
|
||||||
CopyAll(diSource, diTarget, newdomain);
|
await CopyAll(diSource, diTarget, newdomain);
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -684,7 +676,7 @@ public class DiscDataStore : BaseStorage
|
|||||||
return SaveAsync(domain, path, stream);
|
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.
|
// Check if the target directory exists, if not, create it.
|
||||||
if (!Directory.Exists(target.FullName))
|
if (!Directory.Exists(target.FullName))
|
||||||
@ -698,14 +690,14 @@ public class DiscDataStore : BaseStorage
|
|||||||
var fp = CrossPlatform.PathCombine(target.ToString(), fi.Name);
|
var fp = CrossPlatform.PathCombine(target.ToString(), fi.Name);
|
||||||
fi.CopyTo(fp, true);
|
fi.CopyTo(fp, true);
|
||||||
var size = _crypt.GetFileSize(fp);
|
var size = _crypt.GetFileSize(fp);
|
||||||
QuotaUsedAdd(newdomain, size);
|
await QuotaUsedAdd(newdomain, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy each subdirectory using recursion.
|
// Copy each subdirectory using recursion.
|
||||||
foreach (var diSourceSubDir in source.GetDirectories())
|
foreach (var diSourceSubDir in source.GetDirectories())
|
||||||
{
|
{
|
||||||
var nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
|
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);
|
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 lastModificationDate = File.Exists(target) ? File.GetLastWriteTimeUtc(target) : throw new FileNotFoundException("File not found" + target);
|
||||||
var etag = '"' + lastModificationDate.Ticks.ToString("X8", CultureInfo.InvariantCulture) + '"';
|
var etag = '"' + lastModificationDate.Ticks.ToString("X8", CultureInfo.InvariantCulture) + '"';
|
||||||
|
|
||||||
|
@ -48,8 +48,10 @@ public class GoogleCloudStorage : BaseStorage
|
|||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
ILoggerProvider factory,
|
ILoggerProvider factory,
|
||||||
ILogger<GoogleCloudStorage> options,
|
ILogger<GoogleCloudStorage> options,
|
||||||
IHttpClientFactory clientFactory)
|
IHttpClientFactory clientFactory,
|
||||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, 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));
|
// InvalidateCloudFront(MakePath(domain, path));
|
||||||
|
|
||||||
QuotaUsedAdd(domain, buffered.Length);
|
await QuotaUsedAdd(domain, buffered.Length);
|
||||||
|
|
||||||
return await GetUriAsync(domain, path);
|
return await GetUriAsync(domain, path);
|
||||||
}
|
}
|
||||||
@ -248,7 +250,7 @@ public class GoogleCloudStorage : BaseStorage
|
|||||||
|
|
||||||
await storage.DeleteObjectAsync(_bucket, key);
|
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)
|
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 foreach (var obj in objToDel)
|
||||||
{
|
{
|
||||||
await storage.DeleteObjectAsync(_bucket, obj.Name);
|
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)
|
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 foreach (var obj in objToDel)
|
||||||
{
|
{
|
||||||
await storage.DeleteObjectAsync(_bucket, obj.Name);
|
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);
|
await DeleteAsync(srcdomain, srcpath);
|
||||||
|
|
||||||
QuotaUsedDelete(srcdomain, size);
|
await QuotaUsedDelete(srcdomain, size);
|
||||||
QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
|
await QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
|
||||||
|
|
||||||
return await GetUriAsync(newdomain, newpath);
|
return await GetUriAsync(newdomain, newpath);
|
||||||
}
|
}
|
||||||
@ -455,7 +457,7 @@ public class GoogleCloudStorage : BaseStorage
|
|||||||
await foreach (var obj in objToDel)
|
await foreach (var obj in objToDel)
|
||||||
{
|
{
|
||||||
await storage.DeleteObjectAsync(_bucket, obj.Name);
|
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);
|
await storage.CopyObjectAsync(_bucket, MakePath(srcdomain, srcpath), _bucket, MakePath(newdomain, newpath), options);
|
||||||
|
|
||||||
QuotaUsedAdd(newdomain, size);
|
await QuotaUsedAdd(newdomain, size);
|
||||||
|
|
||||||
return await GetUriAsync(newdomain, newpath);
|
return await GetUriAsync(newdomain, newpath);
|
||||||
}
|
}
|
||||||
@ -571,7 +573,7 @@ public class GoogleCloudStorage : BaseStorage
|
|||||||
DestinationPredefinedAcl = GetDomainACL(newdomain)
|
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)
|
if (QuotaController != null)
|
||||||
{
|
{
|
||||||
var size = await GetFileSizeAsync(domain, path);
|
var size = await GetFileSizeAsync(domain, path);
|
||||||
QuotaUsedAdd(domain, size);
|
await QuotaUsedAdd(domain, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await GetUriAsync(domain, path);
|
return await GetUriAsync(domain, path);
|
||||||
|
@ -55,8 +55,10 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
ILoggerProvider options,
|
ILoggerProvider options,
|
||||||
ILogger<RackspaceCloudStorage> logger,
|
ILogger<RackspaceCloudStorage> logger,
|
||||||
IHttpClientFactory httpClient)
|
IHttpClientFactory httpClient,
|
||||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, httpClient)
|
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
|
||||||
|
QuotaSocketManager quotaSocketManager)
|
||||||
|
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options, logger, httpClient, tenantQuotaFeatureStatHelper, quotaSocketManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
TempPath = tempPath;
|
TempPath = tempPath;
|
||||||
@ -192,7 +194,7 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
return (QuotaController != null) && !domain.EndsWith("_temp");
|
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,
|
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5,
|
||||||
DateTime? deleteAt = null, long? deleteAfter = null)
|
DateTime? deleteAt = null, long? deleteAfter = null)
|
||||||
{
|
{
|
||||||
@ -282,9 +284,9 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
_region
|
_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));
|
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();
|
var client = GetClient();
|
||||||
|
|
||||||
@ -309,7 +311,7 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
|
|
||||||
if (!files.Any())
|
if (!files.Any())
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
@ -319,10 +321,8 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
|
|
||||||
if (QuotaController != null)
|
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)
|
public override Task DeleteFilesAsync(string domain, List<string> paths)
|
||||||
@ -371,11 +371,11 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
|
|
||||||
if (quotaUsed > 0)
|
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();
|
var client = GetClient();
|
||||||
|
|
||||||
@ -384,7 +384,7 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
|
|
||||||
if (!files.Any())
|
if (!files.Any())
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
@ -394,10 +394,8 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
|
|
||||||
if (QuotaController != null)
|
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)
|
public override Task MoveDirectoryAsync(string srcdomain, string srcdir, string newdomain, string newdir)
|
||||||
@ -429,8 +427,8 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
|
|
||||||
await DeleteAsync(srcdomain, srcpath);
|
await DeleteAsync(srcdomain, srcpath);
|
||||||
|
|
||||||
QuotaUsedDelete(srcdomain, size);
|
await QuotaUsedDelete(srcdomain, size);
|
||||||
QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
|
await QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
|
||||||
|
|
||||||
return await GetUriAsync(newdomain, newpath);
|
return await GetUriAsync(newdomain, newpath);
|
||||||
}
|
}
|
||||||
@ -475,7 +473,7 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
return IsFileAsync(domain, path);
|
return IsFileAsync(domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task DeleteDirectoryAsync(string domain, string path)
|
public override async Task DeleteDirectoryAsync(string domain, string path)
|
||||||
{
|
{
|
||||||
var client = GetClient();
|
var client = GetClient();
|
||||||
|
|
||||||
@ -484,9 +482,8 @@ public class RackspaceCloudStorage : BaseStorage
|
|||||||
foreach (var obj in objToDel)
|
foreach (var obj in objToDel)
|
||||||
{
|
{
|
||||||
client.DeleteObject(_private_container, obj.Name);
|
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)
|
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);
|
client.CopyObject(_private_container, srcKey, _private_container, dstKey);
|
||||||
|
|
||||||
QuotaUsedAdd(newdomain, size);
|
await QuotaUsedAdd(newdomain, size);
|
||||||
|
|
||||||
return await GetUriAsync(newdomain, newpath);
|
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 srckey = MakePath(srcdomain, dir);
|
||||||
var dstkey = MakePath(newdomain, newdir);
|
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));
|
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)
|
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);
|
var size = await GetFileSizeAsync(domain, path);
|
||||||
|
|
||||||
QuotaUsedAdd(domain, size);
|
await QuotaUsedAdd(domain, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await GetUriAsync(domain, path);
|
return await GetUriAsync(domain, path);
|
||||||
|
@ -67,8 +67,10 @@ public class S3Storage : BaseStorage
|
|||||||
ILoggerProvider factory,
|
ILoggerProvider factory,
|
||||||
ILogger<S3Storage> options,
|
ILogger<S3Storage> options,
|
||||||
IHttpClientFactory clientFactory,
|
IHttpClientFactory clientFactory,
|
||||||
IConfiguration configuration)
|
IConfiguration configuration,
|
||||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, clientFactory)
|
TenantQuotaFeatureStatHelper tenantQuotaFeatureStatHelper,
|
||||||
|
QuotaSocketManager quotaSocketManager)
|
||||||
|
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, factory, options, clientFactory, tenantQuotaFeatureStatHelper, quotaSocketManager)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
@ -259,7 +261,7 @@ public class S3Storage : BaseStorage
|
|||||||
|
|
||||||
await InvalidateCloudFrontAsync(MakePath(domain, path));
|
await InvalidateCloudFrontAsync(MakePath(domain, path));
|
||||||
|
|
||||||
QuotaUsedAdd(domain, buffered.Length);
|
await QuotaUsedAdd(domain, buffered.Length);
|
||||||
|
|
||||||
return await GetUriAsync(domain, path);
|
return await GetUriAsync(domain, path);
|
||||||
}
|
}
|
||||||
@ -352,7 +354,7 @@ public class S3Storage : BaseStorage
|
|||||||
if (QuotaController != null)
|
if (QuotaController != null)
|
||||||
{
|
{
|
||||||
var size = await GetFileSizeAsync(domain, path);
|
var size = await GetFileSizeAsync(domain, path);
|
||||||
QuotaUsedAdd(domain, size);
|
await QuotaUsedAdd(domain, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await GetUriAsync(domain, path);
|
return await GetUriAsync(domain, path);
|
||||||
@ -407,7 +409,7 @@ public class S3Storage : BaseStorage
|
|||||||
|
|
||||||
await client.DeleteObjectAsync(request);
|
await client.DeleteObjectAsync(request);
|
||||||
|
|
||||||
QuotaUsedDelete(domain, size);
|
await QuotaUsedDelete(domain, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task DeleteFilesAsync(string domain, List<string> paths)
|
public override Task DeleteFilesAsync(string domain, List<string> paths)
|
||||||
@ -467,7 +469,7 @@ public class S3Storage : BaseStorage
|
|||||||
|
|
||||||
if (quotaUsed > 0)
|
if (quotaUsed > 0)
|
||||||
{
|
{
|
||||||
QuotaUsedDelete(domain, quotaUsed);
|
await QuotaUsedDelete(domain, quotaUsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +495,7 @@ public class S3Storage : BaseStorage
|
|||||||
|
|
||||||
await client.DeleteObjectAsync(deleteRequest);
|
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);
|
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 CopyFileAsync(client, srcKey, dstKey, newdomain, S3MetadataDirective.REPLACE);
|
||||||
await DeleteAsync(srcdomain, srcpath);
|
await DeleteAsync(srcdomain, srcpath);
|
||||||
|
|
||||||
QuotaUsedDelete(srcdomain, size);
|
await QuotaUsedDelete(srcdomain, size);
|
||||||
QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
|
await QuotaUsedAdd(newdomain, size, quotaCheckFileSize);
|
||||||
|
|
||||||
return await GetUriAsync(newdomain, newpath);
|
return await GetUriAsync(newdomain, newpath);
|
||||||
}
|
}
|
||||||
@ -848,7 +850,7 @@ public class S3Storage : BaseStorage
|
|||||||
using var client = GetClient();
|
using var client = GetClient();
|
||||||
await CopyFileAsync(client, srcKey, dstKey, newdomain, S3MetadataDirective.REPLACE);
|
await CopyFileAsync(client, srcKey, dstKey, newdomain, S3MetadataDirective.REPLACE);
|
||||||
|
|
||||||
QuotaUsedAdd(newdomain, size);
|
await QuotaUsedAdd(newdomain, size);
|
||||||
|
|
||||||
return await GetUriAsync(newdomain, newpath);
|
return await GetUriAsync(newdomain, newpath);
|
||||||
}
|
}
|
||||||
@ -866,7 +868,7 @@ public class S3Storage : BaseStorage
|
|||||||
{
|
{
|
||||||
await CopyFileAsync(client, s3Object.Key, s3Object.Key.Replace(srckey, dstkey), newdomain);
|
await CopyFileAsync(client, s3Object.Key, s3Object.Key.Replace(srckey, dstkey), newdomain);
|
||||||
|
|
||||||
QuotaUsedAdd(newdomain, s3Object.Size);
|
await QuotaUsedAdd(newdomain, s3Object.Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ public class ChunkZipWriteOperator : IDataWriteOperator
|
|||||||
theMemStream.Position = 0;
|
theMemStream.Position = 0;
|
||||||
if (bytesRead == chunkUploadSize || last)
|
if (bytesRead == chunkUploadSize || last)
|
||||||
{
|
{
|
||||||
if (_fileStream.Position == _fileStream.Length)
|
if (_fileStream.Position == _fileStream.Length && last)
|
||||||
{
|
{
|
||||||
_chunkedUploadSession.LastChunk = true;
|
_chunkedUploadSession.LastChunk = true;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,5 @@ public class FeedApiFilter
|
|||||||
public Guid Author { get; set; }
|
public Guid Author { get; set; }
|
||||||
public string[] SearchKeys { get; set; }
|
public string[] SearchKeys { get; set; }
|
||||||
public bool OnlyNew { get; set; }
|
public bool OnlyNew { get; set; }
|
||||||
public bool WithoutMe { get; set; }
|
public bool History { get; set; }
|
||||||
public bool WithRelated { get; set; }
|
|
||||||
}
|
}
|
@ -202,23 +202,58 @@ public class FeedAggregateDataProvider
|
|||||||
var q = feedDbContext.FeedAggregates.AsNoTracking()
|
var q = feedDbContext.FeedAggregates.AsNoTracking()
|
||||||
.Where(r => r.Tenant == _tenantManager.GetCurrentTenant().Id);
|
.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)
|
.OrderByDescending(r => r.aggregates.ModifiedDate)
|
||||||
.Skip(filter.Offset)
|
.Skip(filter.Offset)
|
||||||
.Take(filter.Max);
|
.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)
|
if (filter.OnlyNew)
|
||||||
{
|
{
|
||||||
@ -249,16 +284,14 @@ public class FeedAggregateDataProvider
|
|||||||
if (filter.SearchKeys != null && filter.SearchKeys.Length > 0)
|
if (filter.SearchKeys != null && filter.SearchKeys.Length > 0)
|
||||||
{
|
{
|
||||||
var keys = filter.SearchKeys
|
var keys = filter.SearchKeys
|
||||||
.Where(s => !string.IsNullOrEmpty(s))
|
.Where(s => !string.IsNullOrEmpty(s))
|
||||||
.Select(s => s.Replace("\\", "\\\\").Replace("%", "\\%").Replace("_", "\\_"))
|
.Select(s => s.Replace("\\", "\\\\").Replace("%", "\\%").Replace("_", "\\_"))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
q1 = q1.Where(r => keys.Any(k => r.aggregates.Keywords.StartsWith(k)));
|
q1 = q1.Where(r => keys.Any(k => r.aggregates.Keywords.StartsWith(k)));
|
||||||
}
|
}
|
||||||
|
|
||||||
var news = q1.Select(r => r.aggregates).Distinct().AsEnumerable();
|
return q1.Select(r => r.aggregates).Distinct();
|
||||||
|
|
||||||
return _mapper.Map<IEnumerable<FeedAggregate>, List<FeedResultItem>>(news);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetNewFeedsCount(DateTime lastReadedTime)
|
public int GetNewFeedsCount(DateTime lastReadedTime)
|
||||||
@ -323,30 +356,30 @@ public class FeedAggregateDataProvider
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(module))
|
if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(module))
|
||||||
{
|
{
|
||||||
return exp;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module == Constants.RoomsModule)
|
switch (module)
|
||||||
{
|
{
|
||||||
var roomId = $"{Constants.RoomItem}_{id}";
|
case Constants.RoomsModule:
|
||||||
var sharedRoomId = $"{Constants.SharedRoomItem}_{id}";
|
{
|
||||||
|
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)
|
if (withRelated)
|
||||||
{
|
{
|
||||||
exp = f => f.Id == roomId || f.Id.StartsWith(sharedRoomId) || f.ContextId == roomId;
|
exp = f => f.Id == roomId || f.ContextId == roomId;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (module == Constants.FilesModule)
|
break;
|
||||||
{
|
}
|
||||||
exp = f => f.Id.StartsWith($"{Constants.FileItem}_{id}") || f.Id.StartsWith($"{Constants.SharedFileItem}_{id}");
|
case Constants.FilesModule:
|
||||||
}
|
exp = f => f.Id.StartsWith($"{Constants.FileItem}_{id}") || f.Id.StartsWith($"{Constants.SharedFileItem}_{id}");
|
||||||
|
break;
|
||||||
if (module == Constants.FoldersModule)
|
case Constants.FoldersModule:
|
||||||
{
|
exp = f => f.Id == $"{Constants.FolderItem}_{id}" || f.Id.StartsWith($"{Constants.SharedFolderItem}_{id}");
|
||||||
exp = f => f.Id == $"{Constants.FolderItem}_{id}" || f.Id.StartsWith($"{Constants.SharedFolderItem}_{id}");
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exp;
|
return exp;
|
||||||
|
@ -46,7 +46,7 @@ public class GwsMigratingFiles : MigratingFiles
|
|||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileSecurity _fileSecurity;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly string _rootFolder;
|
private readonly string _rootFolder;
|
||||||
private int _foldersCount;
|
private int _foldersCount;
|
||||||
private int _filesCount;
|
private int _filesCount;
|
||||||
@ -109,7 +109,7 @@ public class GwsMigratingFiles : MigratingFiles
|
|||||||
_groups = groups.ToDictionary(group => group.GroupName, group => group);
|
_groups = groups.ToDictionary(group => group.GroupName, group => group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GwsMigratingFiles(GlobalFolderHelper globalFolderHelper, IDaoFactory daoFactory, FileSecurity fileSecurity, FileStorageService<int> fileStorageService, string rootFolder, GwsMigratingUser user, Action<string, Exception> log) : base(log)
|
public GwsMigratingFiles(GlobalFolderHelper globalFolderHelper, IDaoFactory daoFactory, FileSecurity fileSecurity, FileStorageService fileStorageService, string rootFolder, GwsMigratingUser user, Action<string, Exception> log) : base(log)
|
||||||
{
|
{
|
||||||
_globalFolderHelper = globalFolderHelper;
|
_globalFolderHelper = globalFolderHelper;
|
||||||
_daoFactory = daoFactory;
|
_daoFactory = daoFactory;
|
||||||
|
@ -38,14 +38,14 @@ public class GwsMigratingUser : MigratingUser<GwsMigratingContacts, GwsMigrating
|
|||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileSecurity _fileSecurity;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly UserManager _userManager;
|
private readonly UserManager _userManager;
|
||||||
|
|
||||||
public GwsMigratingUser(
|
public GwsMigratingUser(
|
||||||
GlobalFolderHelper globalFolderHelper,
|
GlobalFolderHelper globalFolderHelper,
|
||||||
IDaoFactory daoFactory,
|
IDaoFactory daoFactory,
|
||||||
FileSecurity fileSecurity,
|
FileSecurity fileSecurity,
|
||||||
FileStorageService<int> fileStorageService,
|
FileStorageService fileStorageService,
|
||||||
UserManager userManager)
|
UserManager userManager)
|
||||||
{
|
{
|
||||||
_globalFolderHelper = globalFolderHelper;
|
_globalFolderHelper = globalFolderHelper;
|
||||||
|
@ -42,7 +42,7 @@ public class NCMigratingFiles : MigratingFiles
|
|||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileSecurity _fileSecurity;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly NCMigratingUser _user;
|
private readonly NCMigratingUser _user;
|
||||||
private readonly string _rootFolder;
|
private readonly string _rootFolder;
|
||||||
private List<NCFileCache> _files;
|
private List<NCFileCache> _files;
|
||||||
@ -55,7 +55,7 @@ public class NCMigratingFiles : MigratingFiles
|
|||||||
private Dictionary<string, NCMigratingGroups> _groups;
|
private Dictionary<string, NCMigratingGroups> _groups;
|
||||||
private Dictionary<object, int> _matchingFileId;
|
private Dictionary<object, int> _matchingFileId;
|
||||||
private string _folderCreation;
|
private string _folderCreation;
|
||||||
public NCMigratingFiles(GlobalFolderHelper globalFolderHelper, IDaoFactory daoFactory, FileSecurity fileSecurity, FileStorageService<int> fileStorageService, NCMigratingUser user, NCStorages storages, string rootFolder, Action<string, Exception> log) : base(log)
|
public NCMigratingFiles(GlobalFolderHelper globalFolderHelper, IDaoFactory daoFactory, FileSecurity fileSecurity, FileStorageService fileStorageService, NCMigratingUser user, NCStorages storages, string rootFolder, Action<string, Exception> log) : base(log)
|
||||||
{
|
{
|
||||||
_globalFolderHelper = globalFolderHelper;
|
_globalFolderHelper = globalFolderHelper;
|
||||||
_daoFactory = daoFactory;
|
_daoFactory = daoFactory;
|
||||||
|
@ -46,7 +46,7 @@ public class NCMigratingUser : MigratingUser<NCMigratingContacts, NCMigratingCal
|
|||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileSecurity _fileSecurity;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly TenantManager _tenantManager;
|
private readonly TenantManager _tenantManager;
|
||||||
private readonly UserManager _userManager;
|
private readonly UserManager _userManager;
|
||||||
private readonly NCUser _user;
|
private readonly NCUser _user;
|
||||||
@ -57,7 +57,7 @@ public class NCMigratingUser : MigratingUser<NCMigratingContacts, NCMigratingCal
|
|||||||
GlobalFolderHelper globalFolderHelper,
|
GlobalFolderHelper globalFolderHelper,
|
||||||
IDaoFactory daoFactory,
|
IDaoFactory daoFactory,
|
||||||
FileSecurity fileSecurity,
|
FileSecurity fileSecurity,
|
||||||
FileStorageService<int> fileStorageService,
|
FileStorageService fileStorageService,
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
UserManager userManager,
|
UserManager userManager,
|
||||||
string key,
|
string key,
|
||||||
|
@ -38,7 +38,7 @@ public class NextcloudWorkspaceMigration : AbstractMigration<NCMigrationInfo, NC
|
|||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileSecurity _fileSecurity;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly SecurityContext _securityContext;
|
private readonly SecurityContext _securityContext;
|
||||||
private readonly UserManager _userManager;
|
private readonly UserManager _userManager;
|
||||||
private readonly TenantManager _tenantManager;
|
private readonly TenantManager _tenantManager;
|
||||||
@ -47,7 +47,7 @@ public class NextcloudWorkspaceMigration : AbstractMigration<NCMigrationInfo, NC
|
|||||||
GlobalFolderHelper globalFolderHelper,
|
GlobalFolderHelper globalFolderHelper,
|
||||||
IDaoFactory daoFactory,
|
IDaoFactory daoFactory,
|
||||||
FileSecurity fileSecurity,
|
FileSecurity fileSecurity,
|
||||||
FileStorageService<int> fileStorageService,
|
FileStorageService fileStorageService,
|
||||||
SecurityContext securityContext,
|
SecurityContext securityContext,
|
||||||
UserManager userManager,
|
UserManager userManager,
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
|
@ -41,8 +41,7 @@ public class OCMigratingFiles : MigratingFiles
|
|||||||
|
|
||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
|
||||||
private readonly OCMigratingUser _user;
|
private readonly OCMigratingUser _user;
|
||||||
private readonly string _rootFolder;
|
private readonly string _rootFolder;
|
||||||
private List<OCFileCache> _files;
|
private List<OCFileCache> _files;
|
||||||
@ -55,11 +54,10 @@ public class OCMigratingFiles : MigratingFiles
|
|||||||
private Dictionary<string, OCMigratingGroups> _groups;
|
private Dictionary<string, OCMigratingGroups> _groups;
|
||||||
private Dictionary<object, int> _matchingFileId;
|
private Dictionary<object, int> _matchingFileId;
|
||||||
private string _folderCreation;
|
private string _folderCreation;
|
||||||
public OCMigratingFiles(GlobalFolderHelper globalFolderHelper, IDaoFactory daoFactory, FileSecurity fileSecurity, FileStorageService<int> fileStorageService, OCMigratingUser user, OCStorages storages, string rootFolder, Action<string, Exception> log) : base(log)
|
public OCMigratingFiles(GlobalFolderHelper globalFolderHelper, IDaoFactory daoFactory, FileStorageService fileStorageService, OCMigratingUser user, OCStorages storages, string rootFolder, Action<string, Exception> log) : base(log)
|
||||||
{
|
{
|
||||||
_globalFolderHelper = globalFolderHelper;
|
_globalFolderHelper = globalFolderHelper;
|
||||||
_daoFactory = daoFactory;
|
_daoFactory = daoFactory;
|
||||||
_fileSecurity = fileSecurity;
|
|
||||||
_fileStorageService = fileStorageService;
|
_fileStorageService = fileStorageService;
|
||||||
_user = user;
|
_user = user;
|
||||||
_rootFolder = rootFolder;
|
_rootFolder = rootFolder;
|
||||||
|
@ -45,8 +45,7 @@ public class OCMigratingUser : MigratingUser<OCMigratingContacts, OCMigratingCal
|
|||||||
private UserInfo _userInfo;
|
private UserInfo _userInfo;
|
||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
|
||||||
private readonly TenantManager _tenantManager;
|
private readonly TenantManager _tenantManager;
|
||||||
private readonly UserManager _userManager;
|
private readonly UserManager _userManager;
|
||||||
private readonly OCUser _user;
|
private readonly OCUser _user;
|
||||||
@ -55,8 +54,7 @@ public class OCMigratingUser : MigratingUser<OCMigratingContacts, OCMigratingCal
|
|||||||
public OCMigratingUser(
|
public OCMigratingUser(
|
||||||
GlobalFolderHelper globalFolderHelper,
|
GlobalFolderHelper globalFolderHelper,
|
||||||
IDaoFactory daoFactory,
|
IDaoFactory daoFactory,
|
||||||
FileSecurity fileSecurity,
|
FileStorageService fileStorageService,
|
||||||
FileStorageService<int> fileStorageService,
|
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
UserManager userManager,
|
UserManager userManager,
|
||||||
string key,
|
string key,
|
||||||
@ -67,7 +65,6 @@ public class OCMigratingUser : MigratingUser<OCMigratingContacts, OCMigratingCal
|
|||||||
Key = key;
|
Key = key;
|
||||||
_globalFolderHelper = globalFolderHelper;
|
_globalFolderHelper = globalFolderHelper;
|
||||||
_daoFactory = daoFactory;
|
_daoFactory = daoFactory;
|
||||||
_fileSecurity = fileSecurity;
|
|
||||||
_fileStorageService = fileStorageService;
|
_fileStorageService = fileStorageService;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
@ -126,7 +123,7 @@ public class OCMigratingUser : MigratingUser<OCMigratingContacts, OCMigratingCal
|
|||||||
ModulesList.Add(new MigrationModules(MigratingCalendar.ModuleName, MigrationResource.OnlyofficeModuleNameCalendar));
|
ModulesList.Add(new MigrationModules(MigratingCalendar.ModuleName, MigrationResource.OnlyofficeModuleNameCalendar));
|
||||||
}
|
}
|
||||||
|
|
||||||
MigratingFiles = new OCMigratingFiles(_globalFolderHelper, _daoFactory, _fileSecurity, _fileStorageService, this, _user.Storages, _rootFolder, log);
|
MigratingFiles = new OCMigratingFiles(_globalFolderHelper, _daoFactory, _fileStorageService, this, _user.Storages, _rootFolder, log);
|
||||||
MigratingFiles.Parse();
|
MigratingFiles.Parse();
|
||||||
if (MigratingFiles.FoldersCount != 0 || MigratingFiles.FilesCount != 0)
|
if (MigratingFiles.FoldersCount != 0 || MigratingFiles.FilesCount != 0)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ public class OwnCloudMigration : AbstractMigration<OCMigrationInfo, OCMigratingU
|
|||||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||||
private readonly IDaoFactory _daoFactory;
|
private readonly IDaoFactory _daoFactory;
|
||||||
private readonly FileSecurity _fileSecurity;
|
private readonly FileSecurity _fileSecurity;
|
||||||
private readonly FileStorageService<int> _fileStorageService;
|
private readonly FileStorageService _fileStorageService;
|
||||||
private readonly SecurityContext _securityContext;
|
private readonly SecurityContext _securityContext;
|
||||||
private readonly TenantManager _tenantManager;
|
private readonly TenantManager _tenantManager;
|
||||||
private readonly UserManager _userManager;
|
private readonly UserManager _userManager;
|
||||||
@ -46,7 +46,7 @@ public class OwnCloudMigration : AbstractMigration<OCMigrationInfo, OCMigratingU
|
|||||||
GlobalFolderHelper globalFolderHelper,
|
GlobalFolderHelper globalFolderHelper,
|
||||||
IDaoFactory daoFactory,
|
IDaoFactory daoFactory,
|
||||||
FileSecurity fileSecurity,
|
FileSecurity fileSecurity,
|
||||||
FileStorageService<int> fileStorageService,
|
FileStorageService fileStorageService,
|
||||||
SecurityContext securityContext,
|
SecurityContext securityContext,
|
||||||
TenantManager tenantManager,
|
TenantManager tenantManager,
|
||||||
UserManager userManager,
|
UserManager userManager,
|
||||||
|
@ -45,11 +45,21 @@
|
|||||||
files.markAsNewFile(req.body);
|
files.markAsNewFile(req.body);
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/markasnew-folder", (req, res) => {
|
router.post("/markasnew-folder", (req, res) => {
|
||||||
files.markAsNewFolder(req.body);
|
files.markAsNewFolder(req.body);
|
||||||
res.end();
|
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;
|
return router;
|
||||||
};
|
};
|
||||||
|
@ -55,11 +55,11 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("subscribe", ({roomParts, individual}) => {
|
socket.on("subscribe", ({ roomParts, individual }) => {
|
||||||
changeSubscription(roomParts, individual, subscribe);
|
changeSubscription(roomParts, individual, subscribe);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("unsubscribe", ({roomParts, individual}) => {
|
socket.on("unsubscribe", ({ roomParts, individual }) => {
|
||||||
changeSubscription(roomParts, individual, unsubscribe);
|
changeSubscription(roomParts, individual, unsubscribe);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
changeFunc(roomParts);
|
changeFunc(roomParts);
|
||||||
|
|
||||||
if(individual){
|
if (individual) {
|
||||||
if (Array.isArray(roomParts)) {
|
if (Array.isArray(roomParts)) {
|
||||||
changeFunc(roomParts.map((p) => `${p}-${userId}`));
|
changeFunc(roomParts.map((p) => `${p}-${userId}`));
|
||||||
} else {
|
} else {
|
||||||
@ -116,7 +116,6 @@
|
|||||||
socket.leave(room);
|
socket.leave(room);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function startEdit({ fileId, room } = {}) {
|
function startEdit({ fileId, room } = {}) {
|
||||||
@ -167,11 +166,34 @@
|
|||||||
logger.info(`markAsNewFile ${fileId} in room ${room}:${count}`);
|
logger.info(`markAsNewFile ${fileId} in room ${room}:${count}`);
|
||||||
filesIO.to(room).emit("s:markasnew-file", { fileId, count });
|
filesIO.to(room).emit("s:markasnew-file", { fileId, count });
|
||||||
}
|
}
|
||||||
|
|
||||||
function markAsNewFolder({ folderId, count, room } = {}) {
|
function markAsNewFolder({ folderId, count, room } = {}) {
|
||||||
logger.info(`markAsNewFolder ${folderId} in room ${room}:${count}`);
|
logger.info(`markAsNewFolder ${folderId} in room ${room}:${count}`);
|
||||||
filesIO.to(room).emit("s:markasnew-folder", { folderId, 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,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,10 @@ const accessKeyId = aws.accessKeyId;
|
|||||||
const secretAccessKey = aws.secretAccessKey;
|
const secretAccessKey = aws.secretAccessKey;
|
||||||
const awsRegion = aws.region;
|
const awsRegion = aws.region;
|
||||||
const logGroupName = aws.logGroupName;
|
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)) {
|
if (!fs.existsSync(dirName)) {
|
||||||
fs.mkdirSync(dirName);
|
fs.mkdirSync(dirName);
|
||||||
@ -54,17 +57,7 @@ var options = {
|
|||||||
cloudWatch: {
|
cloudWatch: {
|
||||||
name: 'aws',
|
name: 'aws',
|
||||||
level: "debug",
|
level: "debug",
|
||||||
logStreamName: () => {
|
logStreamName: 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);
|
|
||||||
},
|
|
||||||
logGroupName: logGroupName,
|
logGroupName: logGroupName,
|
||||||
awsRegion: awsRegion,
|
awsRegion: awsRegion,
|
||||||
jsonMessage: true,
|
jsonMessage: true,
|
||||||
|
@ -58,7 +58,10 @@ const accessKeyId = aws.accessKeyId;
|
|||||||
const secretAccessKey = aws.secretAccessKey;
|
const secretAccessKey = aws.secretAccessKey;
|
||||||
const awsRegion = aws.region;
|
const awsRegion = aws.region;
|
||||||
const logGroupName = aws.logGroupName;
|
const logGroupName = aws.logGroupName;
|
||||||
const logStreamName = aws.logStreamName;
|
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'));
|
||||||
|
|
||||||
let transports = [];
|
let transports = [];
|
||||||
|
|
||||||
@ -77,17 +80,7 @@ if (aws != null && aws.accessKeyId !== '')
|
|||||||
transports.push(new WinstonCloudWatch({
|
transports.push(new WinstonCloudWatch({
|
||||||
name: 'aws',
|
name: 'aws',
|
||||||
level: "debug",
|
level: "debug",
|
||||||
logStreamName: () => {
|
logStreamName: 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,
|
logGroupName: logGroupName,
|
||||||
awsRegion: awsRegion,
|
awsRegion: awsRegion,
|
||||||
jsonMessage: true,
|
jsonMessage: true,
|
||||||
|
@ -72,7 +72,10 @@ const accessKeyId = aws.accessKeyId;
|
|||||||
const secretAccessKey = aws.secretAccessKey;
|
const secretAccessKey = aws.secretAccessKey;
|
||||||
const awsRegion = aws.region;
|
const awsRegion = aws.region;
|
||||||
const logGroupName = aws.logGroupName;
|
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 = [
|
let transports = [
|
||||||
new (winston.transports.Console)(),
|
new (winston.transports.Console)(),
|
||||||
@ -85,17 +88,7 @@ if (aws != null && aws.accessKeyId !== '')
|
|||||||
transports.push(new WinstonCloudWatch({
|
transports.push(new WinstonCloudWatch({
|
||||||
name: 'aws',
|
name: 'aws',
|
||||||
level: "debug",
|
level: "debug",
|
||||||
logStreamName: () => {
|
logStreamName: 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);
|
|
||||||
},
|
|
||||||
logGroupName: logGroupName,
|
logGroupName: logGroupName,
|
||||||
awsRegion: awsRegion,
|
awsRegion: awsRegion,
|
||||||
jsonMessage: true,
|
jsonMessage: true,
|
||||||
|
@ -32,7 +32,10 @@ const accessKeyId = aws.accessKeyId;
|
|||||||
const secretAccessKey = aws.secretAccessKey;
|
const secretAccessKey = aws.secretAccessKey;
|
||||||
const awsRegion = aws.region;
|
const awsRegion = aws.region;
|
||||||
const logGroupName = aws.logGroupName;
|
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 = {
|
const options = {
|
||||||
file: {
|
file: {
|
||||||
@ -54,18 +57,8 @@ const options = {
|
|||||||
cloudWatch: {
|
cloudWatch: {
|
||||||
name: 'aws',
|
name: 'aws',
|
||||||
level: "debug",
|
level: "debug",
|
||||||
logStreamName: () => {
|
logStreamName: logStreamName,
|
||||||
const hostname = os.hostname();
|
logGroupName: logGroupName,
|
||||||
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,
|
|
||||||
awsRegion: awsRegion,
|
awsRegion: awsRegion,
|
||||||
jsonMessage: true,
|
jsonMessage: true,
|
||||||
awsOptions: {
|
awsOptions: {
|
||||||
|
@ -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<string> Workspaces { get; set; }
|
||||||
public List<TranslationFile> TranslationFiles { get; set; }
|
public List<TranslationFile> TranslationFiles { get; set; }
|
||||||
public List<JavaScriptFile> JavaScriptFiles { get; set; }
|
public List<JavaScriptFile> JavaScriptFiles { get; set; }
|
||||||
public List<ModuleFolder> ModuleFolders { get; set; }
|
public List<ModuleFolder> ModuleFolders { get; set; }
|
||||||
public List<KeyValuePair<string, string>> NotTranslatedToasts { 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<LanguageItem> CommonTranslations { get; set; }
|
||||||
public List<ParseJsonError> ParseJsonErrors { get; set; }
|
public List<ParseJsonError> ParseJsonErrors { get; set; }
|
||||||
public static string ConvertPathToOS { get; private set; }
|
public static string ConvertPathToOS { get; private set; }
|
||||||
@ -68,13 +83,19 @@ public class LocalesTest
|
|||||||
//public List<JsonEncodingError> WrongEncodingJsonErrors { get; set; }
|
//public List<JsonEncodingError> WrongEncodingJsonErrors { get; set; }
|
||||||
|
|
||||||
private static readonly string _md5ExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../md5-excludes.json"));
|
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 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))
|
? JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(_md5ExcludesPath))
|
||||||
: new List<string>();
|
: 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)
|
//private static List<string> encodingExcludes = File.Exists(_encodingExcludesPath)
|
||||||
// ? JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(_encodingExcludesPath))
|
// ? JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(_encodingExcludesPath))
|
||||||
// : new List<string>();
|
// : new List<string>();
|
||||||
@ -201,7 +222,10 @@ public class LocalesTest
|
|||||||
"|(?<=toastr.success\\([\"`\'])(.*)(?=[\"\'`])" +
|
"|(?<=toastr.success\\([\"`\'])(.*)(?=[\"\'`])" +
|
||||||
"|(?<=toastr.warn\\([\"`\'])(.*)(?=[\"\'`])", RegexOptions.Multiline | RegexOptions.ECMAScript);
|
"|(?<=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>>();
|
NotTranslatedToasts = new List<KeyValuePair<string, string>>();
|
||||||
|
NotTranslatedProps = new List<KeyValuePair<string, string>>();
|
||||||
|
|
||||||
foreach (var path in javascriptFiles)
|
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 matches = regexp.Matches(jsFileText);
|
||||||
|
|
||||||
var translationKeys = matches
|
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 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 errorsCount = 0;
|
||||||
var message = $"Next keys have spell check issues:\r\n\r\n";
|
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
|
var groupByLng = TranslationFiles
|
||||||
.GroupBy(t => t.Language)
|
.GroupBy(t => t.Language)
|
||||||
@ -376,7 +416,7 @@ public class LocalesTest
|
|||||||
{
|
{
|
||||||
var dicPaths = SpellCheck.GetDictionaryPaths(group.Language);
|
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 dictionaryStream = File.OpenRead(dicPaths.DictionaryPath))
|
||||||
using (var affixStream = File.OpenRead(dicPaths.AffixPath))
|
using (var affixStream = File.OpenRead(dicPaths.AffixPath))
|
||||||
@ -391,27 +431,44 @@ public class LocalesTest
|
|||||||
|
|
||||||
if (result.HasProblems)
|
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++;
|
errorsCount++;
|
||||||
|
|
||||||
|
if (Save)
|
||||||
/*foreach (var word in result.SpellIssues
|
{
|
||||||
|
foreach (var word in result.SpellIssues
|
||||||
.Where(issue => issue.Suggestions.Any())
|
.Where(issue => issue.Suggestions.Any())
|
||||||
.Select(issue => issue.Word))
|
.Select(issue => issue.Word))
|
||||||
{
|
{
|
||||||
if (!spellCheckExclude.Excludes.Contains(word))
|
if (!spellCheckExclude.Excludes.Contains(word))
|
||||||
{
|
{
|
||||||
spellCheckExclude.Excludes.Add(word);
|
spellCheckExclude.Excludes.Add(word);
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//spellCheckExclude.Excludes.Sort();
|
if (Save)
|
||||||
|
{
|
||||||
//list.Add(spellCheckExclude);
|
spellCheckExclude.Excludes.Sort();
|
||||||
|
|
||||||
|
list.Add(spellCheckExclude);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (NotSupportedException)
|
catch (NotSupportedException)
|
||||||
{
|
{
|
||||||
@ -420,8 +477,12 @@ public class LocalesTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//string json = JsonConvert.SerializeObject(list, Formatting.Indented);
|
if (Save)
|
||||||
//File.WriteAllText("../../../spellcheck-excludes.json", json, Encoding.UTF8);
|
{
|
||||||
|
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);
|
Assert.AreEqual(0, errorsCount, message);
|
||||||
}
|
}
|
||||||
@ -443,7 +504,7 @@ public class LocalesTest
|
|||||||
{
|
{
|
||||||
var duplicatesByMD5 = TranslationFiles
|
var duplicatesByMD5 = TranslationFiles
|
||||||
.Where(t => t.Language != "pt-BR")
|
.Where(t => t.Language != "pt-BR")
|
||||||
.Where(t => !_md5Excludes.Contains(t.Md5Hash))
|
.Where(t => !Md5Excludes.Contains(t.Md5Hash))
|
||||||
.GroupBy(t => t.Md5Hash)
|
.GroupBy(t => t.Md5Hash)
|
||||||
.Where(grp => grp.Count() > 1)
|
.Where(grp => grp.Count() > 1)
|
||||||
.Select(grp => new { Key = grp.Key, Count = grp.Count(), Paths = grp.ToList().Select(f => f.FilePath) })
|
.Select(grp => new { Key = grp.Key, Count = grp.Count(), Paths = grp.ToList().Select(f => f.FilePath) })
|
||||||
@ -747,7 +808,10 @@ public class LocalesTest
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exepts = new List<string> { "Error", "Done", "Warning", "Alert", "Info" };
|
||||||
|
|
||||||
var notCommonKeys = module.AppliedJsTranslationKeys
|
var notCommonKeys = module.AppliedJsTranslationKeys
|
||||||
|
.Except(exepts)
|
||||||
.Where(k => !k.StartsWith("Common:"))
|
.Where(k => !k.StartsWith("Common:"))
|
||||||
.OrderBy(t => t)
|
.OrderBy(t => t)
|
||||||
.ToList();
|
.ToList();
|
||||||
@ -1079,11 +1143,34 @@ public class LocalesTest
|
|||||||
Assert.AreEqual(0, NotTranslatedToasts.Count, message);
|
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]
|
[Test]
|
||||||
[Category("Locales")]
|
[Category("Locales")]
|
||||||
public void WrongTranslationVariablesTest()
|
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 regVariables = new Regex("\\{\\{([^\\{].?[^\\}]+)\\}\\}", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||||
|
|
||||||
var groupedByLng = TranslationFiles
|
var groupedByLng = TranslationFiles
|
||||||
@ -1092,8 +1179,8 @@ public class LocalesTest
|
|||||||
{
|
{
|
||||||
Language = g.Key,
|
Language = g.Key,
|
||||||
TranslationsWithVariables = g.ToList()
|
TranslationsWithVariables = g.ToList()
|
||||||
.SelectMany(t => t.Translations)
|
.SelectMany(t => t.Translations)
|
||||||
.Where(k => k.Value.IndexOf("{{") != -1)
|
//.Where(k => k.Value.IndexOf("{{") != -1)
|
||||||
.Select(t => new
|
.Select(t => new
|
||||||
{
|
{
|
||||||
t.Key,
|
t.Key,
|
||||||
@ -1109,6 +1196,7 @@ public class LocalesTest
|
|||||||
var enWithVariables = groupedByLng
|
var enWithVariables = groupedByLng
|
||||||
.Where(t => t.Language == "en")
|
.Where(t => t.Language == "en")
|
||||||
.SelectMany(t => t.TranslationsWithVariables)
|
.SelectMany(t => t.TranslationsWithVariables)
|
||||||
|
.Where(t => t.Variables.Count > 0)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var otherLanguagesWithVariables = groupedByLng
|
var otherLanguagesWithVariables = groupedByLng
|
||||||
@ -1118,11 +1206,129 @@ public class LocalesTest
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
var errorsCount = 0;
|
var errorsCount = 0;
|
||||||
|
|
||||||
foreach (var lng in otherLanguagesWithVariables)
|
foreach (var enKeyWithVariables in enWithVariables)
|
||||||
{
|
{
|
||||||
foreach (var t in lng.TranslationsWithVariables)
|
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)
|
.Where(en => en.Key == t.Key)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
@ -1134,25 +1340,25 @@ public class LocalesTest
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enKey.Variables.Count != t.Variables.Count)
|
if (enKey.Tags.Count != t.Tags.Count)
|
||||||
{
|
{
|
||||||
// wrong
|
// wrong
|
||||||
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has less variables then 'en' language have " +
|
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has less tags then 'en' language have " +
|
||||||
$"(en={enKey.Variables.Count}|{lng.Language}={t.Variables.Count})\r\n" +
|
$"(en={enKey.Tags.Count}|{lng.Language}={t.Tags.Count})\r\n" +
|
||||||
$"'en': '{enKey.Value}'\r\n'{lng.Language}': '{t.Value}'\r\n\r\n";
|
$"'en': '{enKey.Value}'\r\n'{lng.Language}': '{t.Value}'\r\n\r\n";
|
||||||
errorsCount++;
|
errorsCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!t.Variables.All(v => enKey.Variables.Contains(v)))
|
if (!t.Tags.All(v => enKey.Tags.Contains(v)))
|
||||||
{
|
{
|
||||||
// wrong
|
// wrong
|
||||||
errorsCount++;
|
errorsCount++;
|
||||||
message += $"{++i}. lng='{lng.Language}' key='{t.Key}' has not equals variables of 'en' language have\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.Variables)}\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.Variables)} \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);
|
Assert.AreEqual(0, errorsCount, message);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
"Amazon",
|
||||||
|
"AWS",
|
||||||
|
"DocSpace",
|
||||||
|
"ONLYOFFICE",
|
||||||
|
"ID",
|
||||||
|
"IP",
|
||||||
|
"IPv4",
|
||||||
|
"IPv",
|
||||||
|
"DNS",
|
||||||
|
"SVG",
|
||||||
|
"PNG",
|
||||||
|
"NameId",
|
||||||
|
"IdP",
|
||||||
|
"Sp",
|
||||||
|
"macOS",
|
||||||
|
"SAML",
|
||||||
|
"Stripe",
|
||||||
|
"SDK"
|
||||||
|
]
|
@ -102,15 +102,15 @@ public class PortalController : ControllerBase
|
|||||||
[HttpPost("register")]
|
[HttpPost("register")]
|
||||||
[AllowCrossSiteJson]
|
[AllowCrossSiteJson]
|
||||||
[Authorize(AuthenticationSchemes = "auth:allowskip:registerportal")]
|
[Authorize(AuthenticationSchemes = "auth:allowskip:registerportal")]
|
||||||
public Task<IActionResult> RegisterAsync(TenantModel model)
|
public async Task<IActionResult> RegisterAsync(TenantModel model)
|
||||||
{
|
{
|
||||||
if (model == null)
|
if (model == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IActionResult>(BadRequest(new
|
return BadRequest(new
|
||||||
{
|
{
|
||||||
error = "portalNameEmpty",
|
error = "portalNameEmpty",
|
||||||
message = "PortalName is required"
|
message = "PortalName is required"
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
@ -122,11 +122,11 @@ public class PortalController : ControllerBase
|
|||||||
message.Add(ModelState[k].Errors.FirstOrDefault().ErrorMessage);
|
message.Add(ModelState[k].Errors.FirstOrDefault().ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult<IActionResult>(BadRequest(new
|
return BadRequest(new
|
||||||
{
|
{
|
||||||
error = "params",
|
error = "params",
|
||||||
message
|
message
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
@ -136,7 +136,7 @@ public class PortalController : ControllerBase
|
|||||||
if (!CheckPasswordPolicy(model.Password, out var error1))
|
if (!CheckPasswordPolicy(model.Password, out var error1))
|
||||||
{
|
{
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
return Task.FromResult<IActionResult>(BadRequest(error1));
|
return BadRequest(error1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.Password))
|
if (!string.IsNullOrEmpty(model.Password))
|
||||||
@ -152,16 +152,11 @@ public class PortalController : ControllerBase
|
|||||||
{
|
{
|
||||||
sw.Stop();
|
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();
|
model.PortalName = (model.PortalName ?? "").Trim();
|
||||||
var (exists, _) = await CheckExistingNamePortalAsync(model.PortalName);
|
(var exists, error) = await CheckExistingNamePortalAsync(model.PortalName);
|
||||||
|
|
||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
|
@ -66,8 +66,8 @@ public class Startup : BaseStartup
|
|||||||
services.AddHostedService<BackupCleanerTempFileService>();
|
services.AddHostedService<BackupCleanerTempFileService>();
|
||||||
|
|
||||||
services.AddHostedService<BackupWorkerService>();
|
services.AddHostedService<BackupWorkerService>();
|
||||||
services.AddActivePassiveHostedService<BackupCleanerService>();
|
services.AddActivePassiveHostedService<BackupCleanerService>(DIHelper);
|
||||||
services.AddActivePassiveHostedService<BackupSchedulerService>();
|
services.AddActivePassiveHostedService<BackupSchedulerService>(DIHelper);
|
||||||
|
|
||||||
services.AddBaseDbContextPool<BackupsContext>();
|
services.AddBaseDbContextPool<BackupsContext>();
|
||||||
services.AddBaseDbContextPool<FilesDbContext>();
|
services.AddBaseDbContextPool<FilesDbContext>();
|
||||||
|
@ -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 time = date.ToString("g");
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
var hours = now.Hour;
|
|
||||||
var groupIdHours = hours - (hours % interval);
|
|
||||||
|
|
||||||
if (rootId == null)
|
if (rootId == null)
|
||||||
{
|
{
|
||||||
// groupId = {item}_{author}_{date}
|
return $"{item}_{author}_{time}";
|
||||||
return string.Format("{0}_{1}_{2}",
|
|
||||||
item,
|
|
||||||
author,
|
|
||||||
now.ToString("yyyy.MM.dd.") + groupIdHours);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == -1)
|
if (action == -1)
|
||||||
{
|
{
|
||||||
// groupId = {item}_{author}_{date}_{rootId}_{action}
|
return $"{item}_{author}_{time}_{rootId}";
|
||||||
return string.Format("{0}_{1}_{2}_{3}",
|
|
||||||
item,
|
|
||||||
author,
|
|
||||||
now.ToString("yyyy.MM.dd.") + groupIdHours,
|
|
||||||
rootId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// groupId = {item}_{author}_{date}_{rootId}_{action}
|
return $"{item}_{author}_{time}_{rootId}_{action}";
|
||||||
return string.Format("{0}_{1}_{2}_{3}_{4}",
|
|
||||||
item,
|
|
||||||
author,
|
|
||||||
now.ToString("yyyy.MM.dd.") + groupIdHours,
|
|
||||||
rootId,
|
|
||||||
action);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ public class Startup : BaseWorkerStartup
|
|||||||
DIHelper.TryAdd<NotifyInvokeSendMethodRequestedIntegrationEventHandler>();
|
DIHelper.TryAdd<NotifyInvokeSendMethodRequestedIntegrationEventHandler>();
|
||||||
DIHelper.TryAdd<NotifySendMessageRequestedIntegrationEventHandler>();
|
DIHelper.TryAdd<NotifySendMessageRequestedIntegrationEventHandler>();
|
||||||
|
|
||||||
services.AddActivePassiveHostedService<NotifySenderService>();
|
services.AddActivePassiveHostedService<NotifySenderService>(DIHelper);
|
||||||
services.AddActivePassiveHostedService<NotifyCleanerService>();
|
services.AddActivePassiveHostedService<NotifyCleanerService>(DIHelper);
|
||||||
|
|
||||||
services.AddBaseDbContextPool<NotifyDbContext>();
|
services.AddBaseDbContextPool<NotifyDbContext>();
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,13 @@
|
|||||||
"docservice": {
|
"docservice": {
|
||||||
"coauthor-docs": [ ".pptx", ".ppsx", ".xlsx", ".csv", ".docx", ".docxf", ".oform", ".txt" ],
|
"coauthor-docs": [ ".pptx", ".ppsx", ".xlsx", ".csv", ".docx", ".docxf", ".oform", ".txt" ],
|
||||||
"commented-docs": [ ".docx", ".docxf", ".xlsx", ".pptx" ],
|
"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" ],
|
"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" ],
|
"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" ],
|
"encrypted-docs": [ ".docx", ".docxf", ".xlsx", ".pptx", ".oform" ],
|
||||||
"formfilling-docs": [ ".oform" ],
|
"formfilling-docs": [ ".oform" ],
|
||||||
"customfilter-docs": [ ".xlsx" ],
|
"customfilter-docs": [ ".xlsx" ],
|
||||||
"reviewed-docs": [ ".docx", ".docxf" ],
|
"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", ".epub", ".pdf", ".djvu", ".xps" ],
|
"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": {
|
"secret": {
|
||||||
"value": "secret",
|
"value": "secret",
|
||||||
"header": "AuthorizationJwt"
|
"header": "AuthorizationJwt"
|
||||||
@ -110,6 +110,8 @@
|
|||||||
"min": 3,
|
"min": 3,
|
||||||
"max": 50
|
"max": 50
|
||||||
},
|
},
|
||||||
|
"api-system":"",
|
||||||
|
"api-cache":"",
|
||||||
"images": "static/images",
|
"images": "static/images",
|
||||||
"hide-settings": "Monitoring,LdapSettings,DocService,MailService,PublicPortal,ProxyHttpContent,SpamSubscription,FullTextSearch",
|
"hide-settings": "Monitoring,LdapSettings,DocService,MailService,PublicPortal,ProxyHttpContent,SpamSubscription,FullTextSearch",
|
||||||
"hub": {
|
"hub": {
|
||||||
@ -120,10 +122,14 @@
|
|||||||
"controlpanel": {
|
"controlpanel": {
|
||||||
"url": ""
|
"url": ""
|
||||||
},
|
},
|
||||||
|
"legalterms": "https://www.onlyoffice.com/legalterms.aspx",
|
||||||
"support-feedback": "https://helpdesk.onlyoffice.com",
|
"support-feedback": "https://helpdesk.onlyoffice.com",
|
||||||
"teamlab-site": "http://www.onlyoffice.com",
|
"teamlab-site": "http://www.onlyoffice.com",
|
||||||
"help-center": "https://helpcenter.onlyoffice.com/{ru|de|fr|es|it}",
|
"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": {
|
"ConnectionStrings": {
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -150,38 +150,6 @@
|
|||||||
"clickatellapiKey": ""
|
"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",
|
"type": "ASC.FederatedLogin.LoginProviders.DropboxLoginProvider, ASC.FederatedLogin",
|
||||||
@ -338,37 +306,6 @@
|
|||||||
"linkedInRedirectUrl" : "https://service.teamlab.info/oauth2.aspx"
|
"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",
|
"type": "ASC.FederatedLogin.LoginProviders.OneDriveLoginProvider, ASC.FederatedLogin",
|
||||||
|
3957
i18next/client.babel
3957
i18next/client.babel
File diff suppressed because it is too large
Load Diff
1652
i18next/common.babel
1652
i18next/common.babel
File diff suppressed because it is too large
Load Diff
@ -73,7 +73,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -1,
|
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",
|
Name = "trial",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
@ -81,7 +81,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -2,
|
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",
|
Name = "admin",
|
||||||
Price = 30m,
|
Price = 30m,
|
||||||
ProductId = "1002",
|
ProductId = "1002",
|
||||||
@ -90,7 +90,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -3,
|
Tenant = -3,
|
||||||
Features = "free,total_size:2147483648,manager:5,room:5",
|
Features = "free,total_size:2147483648,manager:3,room:12",
|
||||||
Name = "startup",
|
Name = "startup",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
|
@ -120,17 +120,17 @@ public partial class CoreDbContextMigrate : Migration
|
|||||||
migrationBuilder.InsertData(
|
migrationBuilder.InsertData(
|
||||||
table: "tenants_quota",
|
table: "tenants_quota",
|
||||||
columns: new[] { "tenant", "description", "features", "name", "product_id" },
|
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(
|
migrationBuilder.InsertData(
|
||||||
table: "tenants_quota",
|
table: "tenants_quota",
|
||||||
columns: new[] { "tenant", "description", "features", "name", "price", "product_id", "visible" },
|
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(
|
migrationBuilder.InsertData(
|
||||||
table: "tenants_quota",
|
table: "tenants_quota",
|
||||||
columns: new[] { "tenant", "description", "features", "name", "product_id" },
|
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(
|
migrationBuilder.CreateIndex(
|
||||||
name: "last_modified",
|
name: "last_modified",
|
||||||
|
@ -70,7 +70,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -1,
|
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",
|
Name = "trial",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
@ -78,7 +78,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -2,
|
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",
|
Name = "admin",
|
||||||
Price = 30m,
|
Price = 30m,
|
||||||
ProductId = "1002",
|
ProductId = "1002",
|
||||||
@ -87,7 +87,7 @@ namespace ASC.Migrations.MySql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -3,
|
Tenant = -3,
|
||||||
Features = "free,total_size:2147483648,manager:5,room:5",
|
Features = "free,total_size:2147483648,manager:3,room:12",
|
||||||
Name = "startup",
|
Name = "startup",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
|
@ -68,7 +68,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -1,
|
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",
|
Name = "trial",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
@ -76,7 +76,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -2,
|
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",
|
Name = "admin",
|
||||||
Price = 30m,
|
Price = 30m,
|
||||||
ProductId = "1002",
|
ProductId = "1002",
|
||||||
@ -85,7 +85,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -3,
|
Tenant = -3,
|
||||||
Features = "free,total_size:2147483648,manager:5,room:5",
|
Features = "free,total_size:2147483648,manager:3,room:12",
|
||||||
Name = "startup",
|
Name = "startup",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
|
@ -113,19 +113,19 @@ public partial class CoreDbContextMigrate : Migration
|
|||||||
schema: "onlyoffice",
|
schema: "onlyoffice",
|
||||||
table: "tenants_quota",
|
table: "tenants_quota",
|
||||||
columns: new[] { "tenant", "description", "features", "name", "visible" },
|
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(
|
migrationBuilder.InsertData(
|
||||||
schema: "onlyoffice",
|
schema: "onlyoffice",
|
||||||
table: "tenants_quota",
|
table: "tenants_quota",
|
||||||
columns: new[] { "tenant", "description", "features", "name", "price", "product_id", "visible" },
|
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(
|
migrationBuilder.InsertData(
|
||||||
schema: "onlyoffice",
|
schema: "onlyoffice",
|
||||||
table: "tenants_quota",
|
table: "tenants_quota",
|
||||||
columns: new[] { "tenant", "description", "features", "name", "visible" },
|
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(
|
migrationBuilder.CreateIndex(
|
||||||
name: "last_modified_tenants_quotarow",
|
name: "last_modified_tenants_quotarow",
|
||||||
|
@ -82,7 +82,7 @@ namespace ASC.Migrations.PostgreSql.Migrations.CoreDb
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Tenant = -3,
|
Tenant = -3,
|
||||||
Features = "free,total_size:2147483648,manager:5,room:5",
|
Features = "free,total_size:2147483648,manager:3,room:12",
|
||||||
Name = "startup",
|
Name = "startup",
|
||||||
Price = 0m,
|
Price = 0m,
|
||||||
Visible = false
|
Visible = false
|
||||||
|
@ -36,8 +36,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"auto-changelog": "file:./packages/auto-changelog-2.3.1.tgz",
|
"auto-changelog": "file:./packages/auto-changelog-2.3.1.tgz",
|
||||||
"he": "^1.2.0",
|
"he": "^1.2.0",
|
||||||
"shx": "^0.3.3",
|
"shx": "^0.3.4",
|
||||||
"terser": "^5.8.0"
|
"terser": "^5.16.6"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.2.4"
|
"packageManager": "yarn@3.2.4"
|
||||||
}
|
}
|
||||||
|
@ -41,49 +41,50 @@
|
|||||||
"test:ui:mobile": "cross-env DEVICE_TYPE=mobile npx codecept-ui"
|
"test:ui:mobile": "cross-env DEVICE_TYPE=mobile npx codecept-ui"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"copy-to-clipboard": "^3.3.1",
|
"copy-to-clipboard": "^3.3.3",
|
||||||
"element-resize-detector": "^1.2.4",
|
"element-resize-detector": "^1.2.4",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"firebase": "^8.10.0",
|
"firebase": "^8.10.1",
|
||||||
"hex-to-rgba": "^2.0.1",
|
"hex-to-rgba": "^2.0.1",
|
||||||
"react-avatar-editor": "^13.0.0",
|
"react-avatar-editor": "^13.0.0",
|
||||||
"react-colorful": "^5.5.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-hotkeys-hook": "^3.4.4",
|
"react-hotkeys-hook": "^3.4.7",
|
||||||
"react-markdown": "^7.0.1",
|
"react-markdown": "^7.1.2",
|
||||||
"react-smartbanner": "^5.1.4",
|
"react-smartbanner": "^5.1.4",
|
||||||
"react-string-format": "^0.1.4",
|
"react-string-format": "^0.1.4",
|
||||||
"windows-iana": "^5.1.0"
|
"windows-iana": "^5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.15.5",
|
"@babel/core": "^7.21.3",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||||
"@babel/plugin-proposal-export-default-from": "^7.14.5",
|
"@babel/plugin-proposal-export-default-from": "^7.18.10",
|
||||||
"@babel/plugin-transform-runtime": "^7.15.0",
|
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||||
"@babel/preset-env": "^7.15.6",
|
"@babel/preset-env": "^7.20.2",
|
||||||
"@babel/preset-react": "^7.14.5",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"@babel/preset-typescript": "^7.18.6",
|
"@babel/preset-typescript": "^7.21.0",
|
||||||
"@svgr/webpack": "^5.5.0",
|
"@svgr/webpack": "^5.5.0",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.3.0",
|
||||||
"clean-webpack-plugin": "^4.0.0",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^9.1.0",
|
||||||
"css-loader": "^6.2.0",
|
"css-loader": "^6.7.3",
|
||||||
"external-remotes-plugin": "^1.0.0",
|
"external-remotes-plugin": "^1.0.0",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-loader": "^4.2.0",
|
"html-loader": "^4.2.0",
|
||||||
"html-webpack-plugin": "5.3.2",
|
"html-webpack-plugin": "5.5.0",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"playwright": "^1.18.1",
|
"playwright": "^1.32.0",
|
||||||
"sass": "^1.39.2",
|
"sass": "^1.59.3",
|
||||||
"sass-loader": "^12.1.0",
|
"sass-loader": "^12.6.0",
|
||||||
"serve": "14.1.1",
|
"serve": "14.2.0",
|
||||||
"shx": "^0.3.3",
|
"shx": "^0.3.4",
|
||||||
"source-map-loader": "^3.0.0",
|
"source-map-loader": "^3.0.2",
|
||||||
"style-loader": "3.2.1",
|
"style-loader": "3.3.2",
|
||||||
"terser-webpack-plugin": "^5.2.4",
|
"terser-webpack-plugin": "^5.3.7",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.9.5",
|
||||||
"webpack": "5.52.1",
|
"use-resize-observer": "^9.1.0",
|
||||||
|
"webpack": "5.76.3",
|
||||||
"webpack-cli": "4.10.0",
|
"webpack-cli": "4.10.0",
|
||||||
"webpack-dev-server": "4.3.1"
|
"webpack-dev-server": "4.13.1"
|
||||||
},
|
},
|
||||||
"title": "ONLYOFFICE"
|
"title": "ONLYOFFICE"
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"AboutCompanyAddressTitle": "Ünvan",
|
|
||||||
"AboutCompanyEmailTitle": "e-poçt",
|
"AboutCompanyEmailTitle": "e-poçt",
|
||||||
"AboutHeader": "Bu proqram haqqında",
|
"AboutHeader": "Bu proqram haqqında",
|
||||||
"DocumentManagement": "Sənədlərin idarə edilməsi",
|
"DocumentManagement": "Sənədlərin idarə edilməsi",
|
||||||
"OnlineEditors": "Onlayn redaktorlar",
|
"OnlineEditors": "Onlayn redaktorlar",
|
||||||
|
"Site": "Sayt",
|
||||||
"SoftwareLicense": "Proqram təminatı lisenziyası"
|
"SoftwareLicense": "Proqram təminatı lisenziyası"
|
||||||
}
|
}
|
||||||
|
@ -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?"
|
||||||
|
}
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
"AppointAdmin": "Administratorları təyin edin",
|
||||||
"BackupPortal": "DocSpace məlumatlarını yedəkləyin",
|
"BackupPortal": "DocSpace məlumatlarını yedəkləyin",
|
||||||
"ManagePortal": " DocSpace konfiqurasiyasını idarə edin",
|
"ChangeInstruction": "DocSpace sahibini dəyişmək üçün lütfən, aşağıda yeni sahibin adını seçin.",
|
||||||
"ManageUser": "İstifadəçi hesablarını idarə edin"
|
"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"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"ChangeUserStatusDialog": "{{ userStatus }} olan istifadəçilər {{ status }} olacaqlar.",
|
"ChangeUserStatusDialog": "{{ userStatus }} olan istifadəçilər {{ status }} olacaqlar.",
|
||||||
"ChangeUserStatusDialogHeader": "İstifadəçi statusunun dəyişdirilməsi",
|
"ChangeUserStatusDialogHeader": "İstifadəçi statusunun dəyişdirilməsi",
|
||||||
|
"ChangeUserStatusDialogMessage": "DocSpace-in sahibi və özünüz üçün vəziyyəti dəyişdirə bilməzsiniz.",
|
||||||
"ChangeUsersActiveStatus": "iz ver",
|
"ChangeUsersActiveStatus": "iz ver",
|
||||||
"ChangeUsersDisableStatus": "söndürülüb"
|
"ChangeUsersDisableStatus": "söndürülüb"
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"ChangeUserTypeButton": "Növün dəyişdirilməsi",
|
"ChangeUserTypeButton": "Növün dəyişdirilməsi",
|
||||||
"ChangeUserTypeHeader": "İstifadəçi növünün dəyişdirilməsi",
|
"ChangeUserTypeHeader": "İstifadəçi növünün dəyişdirilməsi",
|
||||||
"ChangeUserTypeMessage": "'{{ firstType }}' tipinə malik olan istifadəçilər '{{ secondType }}' istifadəçi tipinə dəyişdirildi.",
|
"ChangeUserTypeMessage": "'{{ firstType }}' tipinə malik olan istifadəçilər '{{ secondType }}' istifadəçi tipinə dəyişdirildi.",
|
||||||
|
"ChangeUserTypeMessageMulti": "Seçilmiş istifadəçilər '{{ secondType }}' növünə köçürüləcək.",
|
||||||
"ChangeUserTypeMessageWarning": "DocSpace inzibatçının və özüvüzün istifadəçi tipini dəyişdirə bilməzsiniz.",
|
"ChangeUserTypeMessageWarning": "DocSpace inzibatçının və özüvüzün istifadəçi tipini dəyişdirə bilməzsiniz.",
|
||||||
"SuccessChangeUserType": "İstifadəçi tipi müvəffəqiyyətlə dəyişdirildi"
|
"SuccessChangeUserType": "İstifadəçi tipi müvəffəqiyyətlə dəyişdirildi"
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
"CurrentNumber": "Cari mobil telefon nömrəniz",
|
"CurrentNumber": "Cari mobil telefon nömrəniz",
|
||||||
"DeleteProfileBtn": "Hesabımı silin",
|
"DeleteProfileBtn": "Hesabımı silin",
|
||||||
"DeleteProfileConfirmation": "Diqqət! Hesabınızı silmək üzrəsiniz.",
|
"DeleteProfileConfirmation": "Diqqət! Hesabınızı silmək üzrəsiniz.",
|
||||||
"DeleteProfileConfirmationInfo": "\"Hesabımı silin\" seçiminə klikləməklə bizim Məxfilik siyasətimizlə razılaşırsınız.",
|
"DeleteProfileConfirmationInfo": "\"Hesabımı silin\" seçiminə klikləməklə bizim <1>Məxfilik siyasətimizlə razılaşırsınız.</1>",
|
||||||
"DeleteProfileSuccessMessage": "Hesabınız uğurla silinmişdir.",
|
"DeleteProfileSuccessMessage": "Hesabınız uğurla silinmişdir.",
|
||||||
"DeleteProfileSuccessMessageInfo": "Hesabınızın və onunla bağlı məlumatların silinməsi haqqında daha ətraflı öyrənmək üçün bizim Məxfilik Siyasətimizə nəzər yetirin.",
|
"DeleteProfileSuccessMessageInfo": "Hesabınızın və onunla bağlı məlumatların silinməsi haqqında daha ətraflı öyrənmək üçün bizim <1>Məxfilik Siyasətimizə</1> nəzər yetirin.",
|
||||||
"EmailAndPasswordCopiedToClipboard": "E-poçt ünvanı və şifrə mübadilə buferinə kopyalandı.",
|
"EmailAndPasswordCopiedToClipboard": "E-poçt ünvanı və şifrə mübadilə buferinə kopyalandı.",
|
||||||
"EnterAppCodeDescription": "Öz tətbiqinizdən əldə etdiyiniz 6 rəqəmli kodu daxil edin. Əgər telefonunuz əlçatan deyilsə, o zaman ehtiyat kodlarından istifadə edin.",
|
"EnterAppCodeDescription": "Öz tətbiqinizdən əldə etdiyiniz 6 rəqəmli kodu daxil edin. Əgər telefonunuz əlçatan deyilsə, o zaman ehtiyat kodlarından istifadə edin.",
|
||||||
"EnterAppCodeTitle": "Doğrulama tətbiqindən kodu daxil edin",
|
"EnterAppCodeTitle": "Doğrulama tətbiqindən kodu daxil edin",
|
||||||
@ -18,9 +18,16 @@
|
|||||||
"LoginRegistryButton": "Qoşulun",
|
"LoginRegistryButton": "Qoşulun",
|
||||||
"PassworResetTitle": "İndi yeni şifrə yarada bilərsiniz.",
|
"PassworResetTitle": "İndi yeni şifrə yarada bilərsiniz.",
|
||||||
"PhoneSubtitle": "Əlavə təhlükəsizliyini təmin etmək üçün iki faktorlu autentifikasiya işə salınıb. DocSpace işə davam etmək üçün mobil telefon nömrənizi daxil edin. Mobil telefon nömrəsi ölkə kodu ilə beynəlxalq formatda daxil edilməlidir.",
|
"PhoneSubtitle": "Əlavə təhlükəsizliyini təmin etmək üçün iki faktorlu autentifikasiya işə salınıb. DocSpace işə davam etmək üçün mobil telefon nömrənizi daxil edin. Mobil telefon nömrəsi ölkə kodu ilə beynəlxalq formatda daxil edilməlidir.",
|
||||||
|
"PortalContinueTitle": "Lütfən, DocSpace-i yenidən aktivləşdirmək istədiyinizi təsdiqləyin.",
|
||||||
|
"PortalDeactivateTitle": "Lütfən, DocSpace-i deaktiv etmək istədiyinizi təsdiqləyin.",
|
||||||
|
"PortalRemoveTitle": "Lütfən, DocSpace-i silmək istədiyinizi təsdiqləyin.",
|
||||||
|
"Reactivate": "Yenidən aktivləşdirin",
|
||||||
"SetAppButton": "Tətbiqə qoşulun",
|
"SetAppButton": "Tətbiqə qoşulun",
|
||||||
"SetAppDescription": "İki faktorlu avtorizasiya kodu aktivləşdirildi. DocSpace-də işləməyə davam etmək üçün doğrulama tətbiqini quraşdırın. Doğrulama tətbiqini <1>Android</1> və <4>iOS</4> və ya <8>Windows Phone</8> üçün istifadə edə bilərsiniz.",
|
"SetAppDescription": "İki faktorlu avtorizasiya kodu aktivləşdirildi. DocSpace-də işləməyə davam etmək üçün doğrulama tətbiqini quraşdırın. Doğrulama tətbiqini <1>Android</1> və <4>iOS</4> və ya <8>Windows Phone</8> üçün istifadə edə bilərsiniz.",
|
||||||
"SetAppInstallDescription": "Tətbiqə qoşulmaq üçün QR kodu skan edin və ya manual olaraq öz gizli açarınızı <1>{{ secretKey }}</1>, daha sonra isə aşağıdakı xanada tətbiqdən əldə etdiyiz 6 rəqəmli kodu daxil edin.",
|
"SetAppInstallDescription": "Tətbiqə qoşulmaq üçün QR kodu skan edin və ya manual olaraq öz gizli açarınızı <1>{{ secretKey }}</1>, daha sonra isə aşağıdakı xanada tətbiqdən əldə etdiyiz 6 rəqəmli kodu daxil edin.",
|
||||||
"SetAppTitle": "Doğrulama tətbiqini quraşdırın",
|
"SetAppTitle": "Doğrulama tətbiqini quraşdırın",
|
||||||
|
"SuccessDeactivate": "Hesabınız uğurla deaktiv edildi. 10 saniyə ərzində <1>sayt</1>a yönləndiriləcəksiniz.",
|
||||||
|
"SuccessReactivate": "Hesabınız uğurla yenidən aktivləşdirildi. 10 saniyəyə <1>portala</1> yönləndiriləcəksiniz.",
|
||||||
|
"SuccessRemoved": "Hesabınız uğurla silindi. 10 saniyə ərzində <1>sayt</1>a yönləndiriləcəksiniz.",
|
||||||
"WelcomeUser": "DocSpace-ə xoş gəlmisiniz!\nBaşlamaq üçün qeydiyyatdan keçin və ya sosial şəbəkə vasitəsilə giriş edin."
|
"WelcomeUser": "DocSpace-ə xoş gəlmisiniz!\nBaşlamaq üçün qeydiyyatdan keçin və ya sosial şəbəkə vasitəsilə giriş edin."
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ConflictResolveDescription": "<1>{{file}}</1> adlı fayl artıq <1>{{folder}}</1> qovluğunda mövcuddur. ",
|
"ConflictResolveDescription": "<1>{{file}}</1> adlı fayl artıq <1>{{folder}}</1> qovluğunda mövcuddur. ",
|
||||||
"ConflictResolveDescriptionFiles": "{{filesCount}} sənəd sayı artıq <1>{{folder}}<1> qovluğunda mövcuddur.",
|
"ConflictResolveDescriptionFiles": "{{filesCount}} sənəd sayı artıq <1>{{folder}}</1> qovluğunda mövcuddur.",
|
||||||
"ConflictResolveSelectAction": "Xahiş edirik əməliyyatı seçin:",
|
"ConflictResolveSelectAction": "Xahiş edirik əməliyyatı seçin:",
|
||||||
"ConflictResolveTitle": "Üzərinə yazmanın təsdiqlənməsi",
|
"ConflictResolveTitle": "Üzərinə yazmanın təsdiqlənməsi",
|
||||||
"CreateDescription": "Qovluqda iki fərqli fayl olacaq. ",
|
"CreateDescription": "Qovluqda iki fərqli fayl olacaq. ",
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
"ConnectFolderTitle": "Qovluq başlığı",
|
"ConnectFolderTitle": "Qovluq başlığı",
|
||||||
"ConnectionUrl": "Qoşulma üçün URL",
|
"ConnectionUrl": "Qoşulma üçün URL",
|
||||||
"Login": "Giriş edin",
|
"Login": "Giriş edin",
|
||||||
"Reconnect": "Yenidən qoşul"
|
"Reconnect": "Yenidən qoşul",
|
||||||
|
"SuccessfulConnectionOfAThirdParty": "Üçüncü tərəf xidməti uğurla qoşuldu."
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
"ConversionMessage": "Bütün yüklənilmiş sənədlər sürətli redaktə etmək üçün Office Open XML formatına (docx, xlsx və ya pptx) konvertasiya olunur.",
|
"ConversionMessage": "Bütün yüklənilmiş sənədlər sürətli redaktə etmək üçün Office Open XML formatına (docx, xlsx və ya pptx) konvertasiya olunur.",
|
||||||
"ConvertedFileDestination": "Faylın nüsxəsi <strong>{{folderTitle}}</strong> qovluğunda yaradılacaq.",
|
"ConvertedFileDestination": "Faylın nüsxəsi <strong>{{folderTitle}}</strong> qovluğunda yaradılacaq.",
|
||||||
|
"DocumentConversionTitle": "Sənədin çevrilməsi",
|
||||||
|
"FailedToConvert": "Çevrilmə uğursuz oldu",
|
||||||
|
"FileUploadTitle": "Fayl yükləndi",
|
||||||
"HideMessage": "Bu bildirişi bir daha göstərmə",
|
"HideMessage": "Bu bildirişi bir daha göstərmə",
|
||||||
"InfoCreateFileIn": "Yeni fayl '{{fileTitle}}' '{{folderTitle}}' qovluğunda yaradıldı",
|
"InfoCreateFileIn": "Yeni fayl '{{fileTitle}}' '{{folderTitle}}' qovluğunda yaradıldı",
|
||||||
|
"OpenFileMessage": "Açdığınız sənəd faylı tez baxmaq və redaktə etmək üçün Office Open XML formatına çevriləcək.",
|
||||||
"SaveOriginalFormatMessage": "Faylın nüsxəsini orijinal formatda yadda saxla"
|
"SaveOriginalFormatMessage": "Faylın nüsxəsini orijinal formatda yadda saxla"
|
||||||
}
|
}
|
||||||
|
@ -1 +1,27 @@
|
|||||||
{}
|
{
|
||||||
|
"ChooseRoomType": "Otaq növünü seçin",
|
||||||
|
"CollaborationRoomDescription": "Komandanızla bir və ya bir neçə sənəd üzərində əməkdaşlıq edin",
|
||||||
|
"CollaborationRoomTitle": "Əməkdaşlıq otağı",
|
||||||
|
"CreateRoomConfirmation": "Yaddaşa qoşulmadan davam edilsin?\nSiz hələ qoşulmamış üçüncü tərəfin yaddaş seçimini etmisiniz. Xidmətə qoşulmadan davam etsəniz, bu seçim əlavə edilməyəcək.",
|
||||||
|
"CreateTagOption": "Teq yaradın",
|
||||||
|
"CustomRoomDescription": "Bu otaqdan istənilən xüsusi məqsəd üçün istifadə etmək üçün öz parametrlərinizi tətbiq edin.",
|
||||||
|
"CustomRoomTitle": "Fərdi otaq",
|
||||||
|
"FillingFormsRoomDescription": "İstənilən sənəd növünü cəld yaratmaq üçün sənəd şablonlarını yaradın, paylaşın və doldurun və ya əvvəlcədən təyin edilmiş parametrlərlə işləyin.",
|
||||||
|
"FillingFormsRoomTitle": "Formaların doldurulması otağı",
|
||||||
|
"Icon": "Simvol",
|
||||||
|
"MakeRoomPrivateDescription": "Bu otaqdakı bütün fayllar şifrələnəcək.",
|
||||||
|
"MakeRoomPrivateLimitationsWarningDescription": "Bu funksiya ilə siz yalnız mövcud DocSpace istifadəçilərini dəvət edə bilərsiniz. Otaq yaratdıqdan sonra istifadəçi siyahısını dəyişə bilməzsiniz.",
|
||||||
|
"MakeRoomPrivateTitle": "Otağı Şəxsi edin",
|
||||||
|
"ReviewRoomDescription": "Sənədlərə baxış və ya şərh tələb edin",
|
||||||
|
"ReviewRoomTitle": "Baxış otağı",
|
||||||
|
"RoomEditing": "Otaq təşkili",
|
||||||
|
"RootLabel": "Mənbə",
|
||||||
|
"TagsPlaceholder": "Teq əlavə edin",
|
||||||
|
"ThirdPartyStorageComboBoxPlaceholder": "Yaddaş seçin",
|
||||||
|
"ThirdPartyStorageDescription": "Bu otaq üçün məlumat yaddaşı kimi üçüncü tərəf xidmətlərindən istifadə edin. Bu otağın məlumatlarını saxlamaq üçün əlaqələndirilmiş yaddaşda yeni qovluq yaradılacaq.",
|
||||||
|
"ThirdPartyStorageNoStorageAlert": "Əvvəllər \"İnteqrasiya\" bölməsində müvafiq xidməti birləşdirməlisiniz. Əks halda bağlantı mümkün olmayacaq.",
|
||||||
|
"ThirdPartyStoragePermanentSettingDescription": "Fayllar {{thirdpartyTitle}} qovluğunda üçüncü tərəf \"{{thirdpartyFolderName}}\" deposunda saxlanılır.\n<strong>{{thirdpartyPath}}</strong>",
|
||||||
|
"ThirdPartyStorageRoomAdminNoStorageAlert": "Üçüncü tərəfin yaddaşına qoşulmaq üçün DocSpace parametrlərinin İnteqrasiya bölməsində müvafiq xidməti əlavə etməlisiniz. İnteqrasiyanı aktivləşdirmək üçün DocSpace sahibi və ya administratorla əlaqə saxlayın.",
|
||||||
|
"ViewOnlyRoomDescription": "Hazır sənədlərə, hesabatlara, sənədləşməyə və digər fayllara baxmaq üçün paylaşın.",
|
||||||
|
"ViewOnlyRoomTitle": "Yalnız baxış otağı"
|
||||||
|
}
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
{
|
{
|
||||||
|
"DeleteFile": "Bu faylı silmək üzrəsiniz. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"DeleteFolder": "Bu qovluğu silmək üzrəsiniz. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"DeleteItems": "Bu elementləri silmək üzrəsiniz. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"DeleteRoom": "Siz bu otağı silmək üzrəsiniz. Siz onu bərpa edə bilməzsiniz.",
|
||||||
|
"DeleteRooms": "Bu otaqları silmək üzrəsiniz. Onları bərpa edə bilməzsiniz.",
|
||||||
"MoveToTrashButton": "Zibil qutusuna yerləşdir",
|
"MoveToTrashButton": "Zibil qutusuna yerləşdir",
|
||||||
|
"MoveToTrashFile": "Bu faylı silmək üzrəsiniz. Nəzərə alın ki, fayl kimsə ilə paylaşılıbsa, əlçatan olmayacaq. Fayl 30 gün ərzində həmişəlik silinəcək. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"MoveToTrashFolder": "Siz bu qovluğu silmək üzrəsiniz. Nəzərə alın ki, bunu kimsə ilə paylaşmısınızsa, istifadə edilə bilməz. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"MoveToTrashFolderFromPersonal": "Bu qovluğu silmək üzrəsiniz. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"MoveToTrashItems": "Bu elementləri silmək üzrəsiniz. Nəzərə alın ki, elementləri kimsə ilə paylaşmısınızsa, onlar əlçatan olmayacaq. Davam etmək istədiyinizə əminsiniz?",
|
||||||
|
"MoveToTrashTitle": "Zibil qutusuna atılsın?",
|
||||||
"UnsubscribeButton": "Abunəlikdən çıx",
|
"UnsubscribeButton": "Abunəlikdən çıx",
|
||||||
"UnsubscribeNote": "Siyahıda göstərilən elementlərdən abunəliyi dayandırmağı əminsinizmi?",
|
"UnsubscribeNote": "Siyahıda göstərilən elementlərdən abunəliyi dayandırmağı əminsinizmi?",
|
||||||
"UnsubscribeTitle": "Abunəlikdən çıxma təsdiqi"
|
"UnsubscribeTitle": "Abunəlikdən çıxma təsdiqi"
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"DeleteUser": "İstifadəçini sil",
|
"DeleteUser": "İstifadəçini sil",
|
||||||
|
"DeleteUserMessage": "{{userCaption}} <strong>{{user}}</strong> silinəcək. Başqalarına açıq olan istifadəçinin şəxsi sənədləri silinəcək. Davam etmək istədiyinizə əminsiniz?",
|
||||||
"SuccessfullyDeleteUserInfoMessage": "İstifadəçi müvəffəqiyyətlə silinmişdir"
|
"SuccessfullyDeleteUserInfoMessage": "İstifadəçi müvəffəqiyyətlə silinmişdir"
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"DisconnectCloudMessage": "{{service}} hizmetini kaldırmak istediğinizden emin misiniz? Bu, {{account}} hesabınızı hiçbir şekilde etkilemeyecektir.",
|
||||||
|
"DisconnectCloudTitle": "Buludla bağlantını dayandırın",
|
||||||
"SuccessDeleteThirdParty": "Üçüncü tərəf {{service}} silinir "
|
"SuccessDeleteThirdParty": "Üçüncü tərəf {{service}} silinir "
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
{
|
{
|
||||||
"DeleteGroupUsersSuccessMessage": "İstifadəçilər müvəffəqiyyətlə silinmişdir."
|
"DeleteGroupUsersSuccessMessage": "İstifadəçilər müvəffəqiyyətlə silinmişdir.",
|
||||||
|
"DeleteUsers": "İstifadəçiləri silin",
|
||||||
|
"DeleteUsersMessage": "Seçilmiş əngəllənmiş istifadəçilər DocSpace-dən silinəcək. Bu istifadəçilərin başqaları üçün əlçatan olan şəxsi sənədləri silinəcək."
|
||||||
}
|
}
|
||||||
|
@ -1 +1,3 @@
|
|||||||
{}
|
{
|
||||||
|
"SaveOrChange": "Tələb olunan parametri azaldın və ya cari qiymət planınızı saxlayın."
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"ChooseFormatText": "Yüklənəcək hər bir faylın formatını seçin ",
|
"ChooseFormatText": "Yüklənəcək hər bir faylın formatını seçin ",
|
||||||
"ConvertMessage": "Əgər faylın konvertasiyasını seçsəz, bəzi məlumatlar itə bilər.",
|
"ConvertMessage": "Əgər faylın konvertasiyasını seçsəz, bəzi məlumatlar itə bilər.",
|
||||||
"ConvertToZip": "Fayllar .zip formatına sıxlaşdırılacaq",
|
"ConvertToZip": "<strong>Fayllar .zip</strong> formatına sıxlaşdırılacaq",
|
||||||
"CustomFormat": "Fərdi format",
|
"CustomFormat": "Fərdi format",
|
||||||
"OriginalFormat": "Orijinal format"
|
"OriginalFormat": "Orijinal format"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"DeleteForeverButton": "Həmişəlik sil",
|
"DeleteForeverButton": "Həmişəlik sil",
|
||||||
"DeleteForeverNote": "Zibil qutusundan elementlər həmişəlik silinəcək. Siz onları bərpa edə bilməyəcəksiniz.",
|
"DeleteForeverNote": "Zibil qutusundan elementlər həmişəlik silinəcək. Siz onları bərpa edə bilməyəcəksiniz.",
|
||||||
|
"DeleteForeverNoteArchive": "Arxivlənmiş bütün elementlər həmişəlik silinəcək. Onları bərpa edə bilməyəcəksiniz.",
|
||||||
"DeleteForeverTitle": "Həmişəlik silinsin?",
|
"DeleteForeverTitle": "Həmişəlik silinsin?",
|
||||||
|
"SuccessEmptyArchived": "Arxivi boşaldıldı",
|
||||||
"SuccessEmptyTrash": "Zibil qutusu təmizləndi"
|
"SuccessEmptyTrash": "Zibil qutusu təmizləndi"
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
"Error403Text": "Təəssüf ki, giriş rədd edilmişdir.",
|
"Error403Text": "Təəssüf ki, giriş rədd edilmişdir.",
|
||||||
"Error404Text": "Təəssüf ki, resurs tapıla bilmir.",
|
"Error404Text": "Təəssüf ki, resurs tapıla bilmir.",
|
||||||
"ErrorEmptyResponse": "Boş cavab",
|
"ErrorEmptyResponse": "Boş cavab",
|
||||||
"ErrorOfflineText": "İnternet bağlantısı tapılmadı"
|
"ErrorOfflineText": "İnternet bağlantısı tapılmadı",
|
||||||
|
"ErrorUnavailableText": "DocSpace əlçatan deyil"
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,58 @@
|
|||||||
{
|
{
|
||||||
|
"AddMembersDescription": "Yeni komanda üzvlərini əl ilə əlavə edə və ya onları keçid vasitəsilə dəvət edə bilərsiniz.",
|
||||||
"All": "Bütün",
|
"All": "Bütün",
|
||||||
"AllFiles": "Bütün fayllar",
|
"AllFiles": "Bütün fayllar",
|
||||||
|
"ArchiveAction": "Boş arxiv",
|
||||||
|
"ArchiveEmptyScreen": "Siz DocSpace-də istifadə etmədiyiniz otaqları arxivləşdirə və bərpa edə və ya istənilən vaxt onları həmişəlik silə bilərsiniz. Bu otaqlar burada görünəcək.",
|
||||||
|
"ArchiveEmptyScreenHeader": "Burada hələ arxivləşdirilmiş otaqlar yoxdur",
|
||||||
|
"ArchiveEmptyScreenUser": "Arxivlənmiş otaqlar burada görünəcək.",
|
||||||
|
"ArchivedRoomAction": "'{{name}}' otağı arxivləşdirildi",
|
||||||
|
"ArchivedRoomsAction": "Otaqlar arxivləşdirildi",
|
||||||
"Archives": "Arxivlər",
|
"Archives": "Arxivlər",
|
||||||
"BackToParentFolderButton": "Ana qovluğa qayıt",
|
"BackToParentFolderButton": "Ana qovluğa qayıt",
|
||||||
"ByAuthor": "Müəllif",
|
"ByAuthor": "Müəllif",
|
||||||
"ByCreation": "Yaradıldı",
|
"ByCreation": "Yaradıldı",
|
||||||
|
"ByErasure": "Təmizləmə",
|
||||||
"ByLastModified": "Dəyişdirilib",
|
"ByLastModified": "Dəyişdirilib",
|
||||||
|
"CollaborationRooms": "Əməkdaşlıq",
|
||||||
"ContainsSpecCharacter": "Başlıqda aşağıdakı simvollardan heç biri ola bilməz: *+: \"<>? |/ ",
|
"ContainsSpecCharacter": "Başlıqda aşağıdakı simvollardan heç biri ola bilməz: *+: \"<>? |/ ",
|
||||||
"Convert": "Konvertasiya",
|
"Convert": "Konvertasiya",
|
||||||
"CopyItem": "<strong>{{title}}</strong> köçürüldü",
|
"CopyItem": "<strong>{{title}}</strong> köçürüldü",
|
||||||
"CopyItems": "<strong>{{qty}}</strong> elementlər köçürüldü",
|
"CopyItems": "<strong>{{qty}}</strong> elementlər köçürüldü",
|
||||||
|
"CreateRoom": "Otaq yaradın",
|
||||||
|
"CustomRooms": "Fərdi",
|
||||||
|
"DaysRemaining": "Qalan günlər: {{daysRemaining}}",
|
||||||
|
"DisableNotifications": "Bildirişləri söndürün",
|
||||||
"Document": "Sənəd",
|
"Document": "Sənəd",
|
||||||
|
"EditRoom": "Otağı redaktə edin",
|
||||||
"EmptyFile": "Boş fayl",
|
"EmptyFile": "Boş fayl",
|
||||||
"EmptyFilterDescriptionText": "Heç bir fayl və ya qovluq bu süzgəcə uyğun deyil. Xahiş edirik digər süzgəc parametrindən istifadə edin və ya bütün faylların göstərilməsi üçün süzgəci sıfırlayın.",
|
"EmptyFilterDescriptionText": "Heç bir fayl və ya qovluq bu süzgəcə uyğun deyil. Xahiş edirik digər süzgəc parametrindən istifadə edin və ya bütün faylların göstərilməsi üçün süzgəci sıfırlayın.",
|
||||||
"EmptyFilterSubheadingText": "Bu süzgəc üçün heç bir fayl tapılmadı",
|
"EmptyFilterSubheadingText": "Bu süzgəc üçün heç bir fayl tapılmadı",
|
||||||
"EmptyFolderDecription": "Faylları buraya çəkin və ya yenilərini yaradın",
|
"EmptyFolderDecription": "Faylları buraya çəkin və ya yenilərini yaradın",
|
||||||
|
"EmptyFolderDescriptionUser": "Adminlər tərəfindən yüklənmiş fayl və qovluqlar burada görünəcək.",
|
||||||
"EmptyFolderHeader": "Bu qovluqda heç bir fayl yoxdur",
|
"EmptyFolderHeader": "Bu qovluqda heç bir fayl yoxdur",
|
||||||
"EmptyRecycleBin": "Boş zibil qutusu",
|
"EmptyRecycleBin": "Boş zibil qutusu",
|
||||||
"EmptyScreenFolder": "Burada hələ ki, heç bir sənəd yoxdur",
|
"EmptyScreenFolder": "Burada hələ ki, heç bir sənəd yoxdur",
|
||||||
|
"EnableNotifications": "Bildirişləri aktivləşdirin",
|
||||||
|
"ExcludeSubfolders": "Alt qovluqları istisna edin",
|
||||||
"FavoritesEmptyContainerDescription": "Faylları favorit kimi qeyd etmək və ya bu siyahıdan çıxarmaq üçün kontekst menyusundan istifadə edin. ",
|
"FavoritesEmptyContainerDescription": "Faylları favorit kimi qeyd etmək və ya bu siyahıdan çıxarmaq üçün kontekst menyusundan istifadə edin. ",
|
||||||
|
"FileContents": "Fayl məzmunları",
|
||||||
"FileRemoved": "Fayl zibil qutusuna göndərildi",
|
"FileRemoved": "Fayl zibil qutusuna göndərildi",
|
||||||
"FileRenamed": "'{{oldTitle}}' sənəd adı '{{newTitle}}'adına dəyişdirildi",
|
"FileRenamed": "'{{oldTitle}}' sənəd adı '{{newTitle}}'adına dəyişdirildi",
|
||||||
|
"FillingFormRooms": "Anket doldurmaq",
|
||||||
"Filter": "Süzgəc",
|
"Filter": "Süzgəc",
|
||||||
"FinalizeVersion": "Versiyanı formalaşdır",
|
"FinalizeVersion": "Versiyanı formalaşdır",
|
||||||
"Folder": "Qovluq",
|
"Folder": "Qovluq",
|
||||||
"FolderRemoved": "Qovluq zibil qutusuna göndərildi",
|
"FolderRemoved": "Qovluq zibil qutusuna göndərildi",
|
||||||
"FolderRenamed": "'{{folderTitle}}' qovluğunun adı '{{newFoldedTitle}}' olaraq dəyişdirildi ",
|
"FolderRenamed": "'{{folderTitle}}' qovluğunun adı '{{newFoldedTitle}}' olaraq dəyişdirildi ",
|
||||||
|
"Forms": "Anketlər",
|
||||||
|
"FormsTemplates": "Anket şablonları",
|
||||||
|
"GoToMyRooms": "Otaqlarım bölməsinə keçin",
|
||||||
|
"GoToPersonal": "Sənədlərim bölməsinə keçin",
|
||||||
"Images": "Şəkillər",
|
"Images": "Şəkillər",
|
||||||
|
"InviteUsersInRoom": "İstifadəçiləri otağa dəvət edin",
|
||||||
"LinkForPortalUsers": "Portal istifadəçiləri üçün link",
|
"LinkForPortalUsers": "Portal istifadəçiləri üçün link",
|
||||||
|
"LinkForRoomMembers": "Otaq üzvləri üçün keçid",
|
||||||
"MarkAsFavorite": "Favorit kimi işarələ",
|
"MarkAsFavorite": "Favorit kimi işarələ",
|
||||||
"MarkRead": "Oxunmuş kimi işarələ",
|
"MarkRead": "Oxunmuş kimi işarələ",
|
||||||
"MarkedAsFavorite": "Çox istifadə olunan siyahısına əlavə olundu",
|
"MarkedAsFavorite": "Çox istifadə olunan siyahısına əlavə olundu",
|
||||||
@ -36,10 +61,17 @@
|
|||||||
"MoveItems": "<strong>{{qty}}</strong> elementlərin yeri dəyişdirildi",
|
"MoveItems": "<strong>{{qty}}</strong> elementlərin yeri dəyişdirildi",
|
||||||
"MoveOrCopy": "Köçür və ya Kopyala",
|
"MoveOrCopy": "Köçür və ya Kopyala",
|
||||||
"MoveTo": "Yerini dəyiş",
|
"MoveTo": "Yerini dəyiş",
|
||||||
|
"MoveToArchive": "Arxivə köçürün",
|
||||||
"MoveToFolderMessage": "Qovluğu alt qovluğuna köçürə bilməzsiniz ",
|
"MoveToFolderMessage": "Qovluğu alt qovluğuna köçürə bilməzsiniz ",
|
||||||
"New": "Yeni",
|
"New": "Yeni",
|
||||||
|
"NewRoom": "Yeni otaq",
|
||||||
|
"NoAccessRoomDescription": "5 saniyə ərzində avtomatik olaraq Otaqlarım bölməsinə yönləndiriləcəksiniz.",
|
||||||
|
"NoAccessRoomTitle": "Təəssüf ki, bu otağa girişiniz yoxdur.",
|
||||||
|
"NoFilesHereYet": "Burada hələ heç bir fayl yoxdur",
|
||||||
"Open": "Açmaq",
|
"Open": "Açmaq",
|
||||||
"OpenLocation": "Qovluğu açmaq",
|
"OpenLocation": "Qovluğu açmaq",
|
||||||
|
"Pin": "Sabitləyin",
|
||||||
|
"PinToTop": "Yuxarıya sabitləyin",
|
||||||
"Presentation": "Təqdimat",
|
"Presentation": "Təqdimat",
|
||||||
"PrivateRoomDescriptionEncrypted": "Şifrlənmiş redaktə və real zaman rejimində kollektiv iş.",
|
"PrivateRoomDescriptionEncrypted": "Şifrlənmiş redaktə və real zaman rejimində kollektiv iş.",
|
||||||
"PrivateRoomDescriptionSafest": "Docx, xlsx və pptx üçün ən təhlükəsiz saxlama.",
|
"PrivateRoomDescriptionSafest": "Docx, xlsx və pptx üçün ən təhlükəsiz saxlama.",
|
||||||
@ -47,10 +79,23 @@
|
|||||||
"PrivateRoomDescriptionUnbreakable": "Sındırılmamış AES-256 alqoritmi.",
|
"PrivateRoomDescriptionUnbreakable": "Sındırılmamış AES-256 alqoritmi.",
|
||||||
"PrivateRoomHeader": "Yazdığınız hər bir simvolun şifrələndiyi ONLYOFFICE şəxsi otağına xoş gəldiniz",
|
"PrivateRoomHeader": "Yazdığınız hər bir simvolun şifrələndiyi ONLYOFFICE şəxsi otağına xoş gəldiniz",
|
||||||
"PrivateRoomSupport": "Şəxsi Otaqda işləmək {{organizationName}} masa üstü tətbiqi ilə mümkündür. <3> Təlimatlar </3> ",
|
"PrivateRoomSupport": "Şəxsi Otaqda işləmək {{organizationName}} masa üstü tətbiqi ilə mümkündür. <3> Təlimatlar </3> ",
|
||||||
|
"RecentEmptyContainerDescription": "Bu bölmədə bu yaxınlarda baxdığınız və ya redaktə etdiyiniz sənədlər göstəriləcək.",
|
||||||
|
"RecycleBinAction": "Boş zibil qutusu",
|
||||||
"RemoveFromFavorites": "Favoritlərdən sil",
|
"RemoveFromFavorites": "Favoritlərdən sil",
|
||||||
"RemoveFromList": "Siyahıdan sil",
|
"RemoveFromList": "Siyahıdan sil",
|
||||||
"RemovedFromFavorites": "Favoritlərdən sil",
|
"RemovedFromFavorites": "Favoritlərdən sil",
|
||||||
"Rename": "Adını dəyiş",
|
"Rename": "Adını dəyiş",
|
||||||
|
"RestoreAll": "Hər şeyi bərpa edin",
|
||||||
|
"RoomCreated": "Otaq yaradıldı",
|
||||||
|
"RoomEmptyContainerDescription": "Lütfən, ilk otağı yaradın.",
|
||||||
|
"RoomEmptyContainerDescriptionUser": "Sizinlə paylaşılan otaqlar burada görünəcək",
|
||||||
|
"RoomNotificationsDisabled": "Otaq bildirişləri deaktiv edildi",
|
||||||
|
"RoomNotificationsEnabled": "Otaq bildirişləri aktiv edildi",
|
||||||
|
"RoomPinned": "Otaq sabitləndi",
|
||||||
|
"RoomRemoved": "Otaq silindi",
|
||||||
|
"RoomUnpinned": "Otaq sabitləmədən çıxarıldı",
|
||||||
|
"RoomsRemoved": "Otaqlar silindi",
|
||||||
|
"SearchByContent": "Fayl məzmununa görə axtarın",
|
||||||
"SendByEmail": "Elektron poçt vasitəsi ilə göndər",
|
"SendByEmail": "Elektron poçt vasitəsi ilə göndər",
|
||||||
"Share": "Paylaş",
|
"Share": "Paylaş",
|
||||||
"ShowVersionHistory": "Versiya tarixçəsinə bax",
|
"ShowVersionHistory": "Versiya tarixçəsinə bax",
|
||||||
@ -59,9 +104,15 @@
|
|||||||
"TooltipElementsCopyMessage": "{{element}} elementlərini köçürmək",
|
"TooltipElementsCopyMessage": "{{element}} elementlərini köçürmək",
|
||||||
"TooltipElementsMoveMessage": "{{element}} elementinin yerdəyişməsi",
|
"TooltipElementsMoveMessage": "{{element}} elementinin yerdəyişməsi",
|
||||||
"TrashEmptyDescription": "'Səbət' bölməsinə bütün silinmiş fayllar yerləşdirilirlər. Əgər onlar səhvən siliniblərsə, Siz onları bərpa edə bilərsiniz, və ya onları ömürlük silə bilərsiniz. Lütfən, nəzərə alın ki, 'Səbətdən' silinən fayllar bir də bərpa oluna bilməyəcəklər.",
|
"TrashEmptyDescription": "'Səbət' bölməsinə bütün silinmiş fayllar yerləşdirilirlər. Əgər onlar səhvən siliniblərsə, Siz onları bərpa edə bilərsiniz, və ya onları ömürlük silə bilərsiniz. Lütfən, nəzərə alın ki, 'Səbətdən' silinən fayllar bir də bərpa oluna bilməyəcəklər.",
|
||||||
|
"TrashErasureWarning": "Zibil qutusundakı elementlər 30 gündən sonra avtomatik silinir.",
|
||||||
|
"UnarchivedRoomAction": "'{{name}}' otağı arxivdən çıxarıldı.",
|
||||||
|
"UnarchivedRoomsAction": "Otaqlar arxivdən çıxarıldı.",
|
||||||
"UnblockVersion": "Blokdan çıxar",
|
"UnblockVersion": "Blokdan çıxar",
|
||||||
|
"Unpin": "Sabitləmədən çıxarın",
|
||||||
"VersionBadge": "V.{{version}}",
|
"VersionBadge": "V.{{version}}",
|
||||||
"VersionHistory": "Versiya tarixçəsi",
|
"VersionHistory": "Versiya tarixçəsi",
|
||||||
"ViewList": "Siyahı",
|
"ViewList": "Siyahı",
|
||||||
"ViewTiles": "Plitkalar"
|
"ViewOnlyRooms": "Yalnız baxın",
|
||||||
|
"ViewTiles": "Plitkalar",
|
||||||
|
"WithSubfolders": "Alt qovluqlarla"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"AdditionalSections": "Əlavə bölmələr",
|
||||||
"ConnectEmpty": "Burada heç nə yoxdur",
|
"ConnectEmpty": "Burada heç nə yoxdur",
|
||||||
"DisplayFavorites": "Ən çox istifadə olunanları göstər",
|
"DisplayFavorites": "Ən çox istifadə olunanları göstər",
|
||||||
"DisplayNotification": "Zibil qutusuna atılan zaman bildirişi göstər",
|
"DisplayNotification": "Zibil qutusuna atılan zaman bildirişi göstər",
|
||||||
@ -8,5 +9,8 @@
|
|||||||
"KeepIntermediateVersion": "Aralıq versiyaları redaktə edəndə yadda saxla",
|
"KeepIntermediateVersion": "Aralıq versiyaları redaktə edəndə yadda saxla",
|
||||||
"OriginalCopy": "Faylın nüsxəsini orijinal formatda da yadda saxla",
|
"OriginalCopy": "Faylın nüsxəsini orijinal formatda da yadda saxla",
|
||||||
"StoringFileVersion": "Fayl versiyaları saxla",
|
"StoringFileVersion": "Fayl versiyaları saxla",
|
||||||
"UpdateOrCreate": "Eyni adı olan mövcud faylın fayl versiyasını yeniləyin. Əks halda, faylın bir nüsxəsi yaradılacaq. "
|
"ThirdPartyAccounts": "Üçüncü tərəf hesabları",
|
||||||
|
"ThirdPartyBtn": "Üçüncü tərəf yaddaşının quraşdırılmasına icazə verin",
|
||||||
|
"UpdateOrCreate": "Eyni adı olan mövcud faylın fayl versiyasını yeniləyin. Əks halda, faylın bir nüsxəsi yaradılacaq. ",
|
||||||
|
"UploadPluginsHere": "Pluginləri buradan yükləyin"
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,41 @@
|
|||||||
{
|
{
|
||||||
|
"AccountsEmptyScreenText": "İstifadəçi detallarına burada baxın",
|
||||||
|
"AndMoreLabel": "və <strong>{{count}} daha çox</strong>",
|
||||||
|
"CreationDate": "Yaradılma tarixi",
|
||||||
|
"Data": "Məlumat",
|
||||||
|
"DateModified": "Değiştirilme tarihi",
|
||||||
|
"FeedCreateFileSeveral": "Fayllar əlavə edildi",
|
||||||
|
"FeedCreateFileSingle": "Fayl yaradıldı",
|
||||||
|
"FeedCreateFolderSeveral": "Qovluqlar əlavə edildi",
|
||||||
|
"FeedCreateFolderSingle": "Qovluq yaradıldı",
|
||||||
|
"FeedCreateRoom": "<strong>«{{roomTitle}}»</strong> otaq yaradıldı",
|
||||||
|
"FeedCreateRoomTag": "Teqlər əlavə edildi",
|
||||||
|
"FeedCreateUser": "İstifadəçilər əlavə edildi",
|
||||||
|
"FeedDeleteFile": "Fayllar silindi",
|
||||||
|
"FeedDeleteFolder": "Qovluqlar silindi",
|
||||||
|
"FeedDeleteRoomTag": "Teqlər silindi",
|
||||||
|
"FeedDeleteUser": "İstifadəçi silindi",
|
||||||
|
"FeedLocationLabel": "Qovluq «{{folderTitle}}»",
|
||||||
|
"FeedMoveFile": "Fayllar köçürüldü",
|
||||||
|
"FeedMoveFolder": "Qovluqlar köçürüldü",
|
||||||
|
"FeedRenameFile": "Faylın adı dəyişdirildi",
|
||||||
|
"FeedRenameFolder": "Qovluğun adı dəyişdirildi",
|
||||||
|
"FeedRenameRoom": "<strong>{{oldRoomTitle}}»</strong> olan otağın adı <strong>«{{roomTitle}}»</strong> olaraq dəyişdirildi.",
|
||||||
|
"FeedUpdateFile": "Fayl yeniləndi",
|
||||||
|
"FeedUpdateRoom": "Simvol dəyişdirildi",
|
||||||
|
"FeedUpdateUser": "{{role}} rolu təyin edildi",
|
||||||
"FileExtension": "Fayl uzantısı",
|
"FileExtension": "Fayl uzantısı",
|
||||||
"FilesEmptyScreenText": "Fayl və qovluq detallarına burada baxın",
|
"FilesEmptyScreenText": "Fayl və qovluq detallarına burada baxın",
|
||||||
"ItemsSelected": "Seçilmiş elementlər",
|
"ItemsSelected": "Seçilmiş elementlər",
|
||||||
"LastModifiedBy": "tərəfindən Son Dəyişiklik",
|
"LastModifiedBy": "tərəfindən Son Dəyişiklik",
|
||||||
|
"PendingInvitations": "Gözləyən dəvətlər",
|
||||||
|
"Properties": "Xüsusiyyətlər",
|
||||||
|
"RoomsEmptyScreenTent": "Otaq detallarına burada baxın",
|
||||||
|
"SelectedUsers": "Seçilmiş hesablar",
|
||||||
|
"StorageType": "Yaddaş növü",
|
||||||
|
"SubmenuDetails": "Detallar",
|
||||||
|
"SubmenuHistory": "Tarixçə",
|
||||||
"SystemProperties": "Sistem xüsusiyyətləri",
|
"SystemProperties": "Sistem xüsusiyyətləri",
|
||||||
|
"UsersInRoom": "Otaqdakı istifadəçilər",
|
||||||
"Versions": "Versiyalar"
|
"Versions": "Versiyalar"
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
{
|
{
|
||||||
"LinkCopySuccess": "Link köçürüldü"
|
"AddManually": "Əl ilə əlavə edin",
|
||||||
|
"AddManuallyDescriptionAccounts": "Yeni istifadəçiləri e-poçt vasitəsilə şəxsən DocSpace-ə dəvət edin",
|
||||||
|
"AddManuallyDescriptionRoom": "Mövcud DocSpace istifadəçilərini adlardan istifadə edərək otağa əlavə edin və ya yeni istifadəçiləri e-poçt vasitəsilə şəxsən dəvət edin",
|
||||||
|
"EmailErrorMessage": "E-poçt ünvanı etibarlı deyil. Siz e-poçtu klikləməklə redaktə edə bilərsiniz.",
|
||||||
|
"InviteAccountSearchPlaceholder": "İnsanları e-məktubla dəvət edin",
|
||||||
|
"InviteRoomSearchPlaceholder": "İnsanları ad və ya e-məktubla dəvət edin",
|
||||||
|
"InviteViaLink": "Keçidlə dəvət edin",
|
||||||
|
"InviteViaLinkDescriptionAccounts": "DocSpace-də avtorizasiya üçün universal keçid yaradın",
|
||||||
|
"InviteViaLinkDescriptionRoom": "Otağın avtorizasiyası üçün universal keçid yaradın",
|
||||||
|
"Invited": "Dəvət edildi",
|
||||||
|
"LinkCopySuccess": "Link köçürüldü",
|
||||||
|
"SendInvitation": "Dəvət göndərin"
|
||||||
}
|
}
|
||||||
|
22
packages/client/public/locales/az/JavascriptSdk.json
Normal file
22
packages/client/public/locales/az/JavascriptSdk.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"Ascending": "Artan",
|
||||||
|
"CopyWindowCode": "Pəncərə yerləşdirmə kodunu kopyalayın",
|
||||||
|
"DataDisplay": "Məlumatların göstərilməsi parametrləri",
|
||||||
|
"Descending": "Azalan",
|
||||||
|
"Destroy": "Məhv etmək",
|
||||||
|
"EnterCount": "Sayını daxil edin",
|
||||||
|
"EnterHeight": "Hündürlüyü daxil edin",
|
||||||
|
"EnterId": "ID daxil edin",
|
||||||
|
"EnterPage": "Nömrə səhifəsini daxil edin",
|
||||||
|
"EnterWidth": "Genişliyi daxil edin",
|
||||||
|
"FolderId": "Qovluq id",
|
||||||
|
"FrameId": "Çərçivə id",
|
||||||
|
"Header": "Başlıq",
|
||||||
|
"ItemsCount": "Maddələr sayılır",
|
||||||
|
"JavascriptSdk": "Javascript SDK",
|
||||||
|
"Menu": "Menyu",
|
||||||
|
"Page": "Səhifə",
|
||||||
|
"SearchTerm": "Axtarış termini",
|
||||||
|
"SortOrder": "Sırala",
|
||||||
|
"WindowParameters": "Pəncərə parametrləri"
|
||||||
|
}
|
@ -1 +1,14 @@
|
|||||||
{}
|
{
|
||||||
|
"ClickHere": "Buraya klikləyin",
|
||||||
|
"ConfirmEmailDescription": "Aktivləşdirmə e-məktubunda göndərilən keçiddən istifadə edin. Aktivləşdirmə linki olan e-məktub almamısınız?",
|
||||||
|
"ConfirmEmailHeader": "Lütfən, DocSpace xüsusiyyətlərinə daxil olmaq üçün e-poçtunuzu ({{ email }}) aktiv edin.",
|
||||||
|
"RequestActivation": "Yenidən aktivləşdirmə tələb edin",
|
||||||
|
"RoomQuotaDescription": "DocSpace üçün daha uyğun qiymət planı tapmaq üçün lazımsız otaqları arxivləşdirə və ya <1>{{clickHere}}</1> edə bilərsiniz.",
|
||||||
|
"RoomQuotaHeader": "Otaqlar keçmək üzrədir: {{currentValue}} / {{maxValue}}",
|
||||||
|
"StorageAndRoomHeader": "Yaddaş və otaq limitləri aşmaq üzrədir.",
|
||||||
|
"StorageAndUserHeader": "Yaddaş və administratorlar/ekspert istifadəçilər limitləri aşmaq üzrədir.",
|
||||||
|
"StorageQuotaDescription": "Siz lazımsız faylları silə və ya DocSpace üçün daha uyğun qiymət planı tapmaq üçün <1>{{clickHere}}</1> edə bilərsiniz.",
|
||||||
|
"StorageQuotaHeader": "Yaddaş sahəsinin həcmi keçmək üzrədir : {{currentValue}} / {{maxValue}}",
|
||||||
|
"UserQuotaDescription": "Portalınız üçün daha yaxşı qiymət planı tapmaq üçün <1>{{clickHere}}</1>.",
|
||||||
|
"UserQuotaHeader": "Admin/ekspert istifadəçilərin sayı keçmək üzrədir: {{currentValue}} / {{maxValue}}."
|
||||||
|
}
|
||||||
|
@ -1 +1,13 @@
|
|||||||
{}
|
{
|
||||||
|
"ActionsWithFilesDescription": "Nişanlar sizə fayl yükləmələri, yeni yaradılanlar və dəyişikliklər haqqında məlumat verir.",
|
||||||
|
"Badges": "Beyclər",
|
||||||
|
"DailyFeed": "Gündəlik DocSpace axını",
|
||||||
|
"DailyFeedDescription": "DocSpace-dəki xəbərləri və hadisələri gündəlik xülasədə oxuyun.",
|
||||||
|
"ManageNotifications": "İdarə etmək",
|
||||||
|
"Notifications": "Bildirişlər",
|
||||||
|
"RoomsActions": "Otaqlarda fayllarla əməliyyatlar",
|
||||||
|
"RoomsActivity": "Otaqların fəaliyyəti",
|
||||||
|
"RoomsActivityDescription": "Saatlıq bildirişlər. Otaqlarınızdakı bütün hərəkətlərdən xəbərdar olun",
|
||||||
|
"UsefulTips": "Faydalı DocSpace məsləhətləri",
|
||||||
|
"UsefulTipsDescription": "DocSpace-də faydalı təlimatlar əldə edin"
|
||||||
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user