diff --git a/.github/workflows/build_packages.yml b/.github/workflows/build_packages.yml new file mode 100644 index 0000000000..03b8abe5f8 --- /dev/null +++ b/.github/workflows/build_packages.yml @@ -0,0 +1,161 @@ +name: Build packages + +on: + push: + branches: + - release/* + - develop + - hotfix/* + paths: + - build/install/deb** + - build/install/rpm** + workflow_dispatch: + +env: + BRANCH_NAME: $(echo ${GITHUB_REF#refs/heads/}) + PRODUCT_LOW: $(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]' ) + PRODUCT: "${{ github.event.repository.name }}" + BUILD_NUMBER: "${{ github.run_number }}" + + +jobs: + build_deb: + name: DEB packages + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Import GPG + uses: crazy-max/ghaction-import-gpg@v5 + id: gpg_step + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PRIVATE_KEY_PASS }} + + - name: Get files from repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Prepare build + id: get_vars + run: | + wget -O - https://dl.yarnpkg.com/debian/pubkey.gpg | \ + sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/yarnkey.gpg --import + sudo chmod 644 /usr/share/keyrings/yarnkey.gpg + echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian/ stable main" | \ + sudo tee /etc/apt/sources.list.d/yarn.list + wget https://packages.microsoft.com/config/$(lsb_release -is | \ + tr [:upper:] [:lower:])/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb + sudo dpkg -i packages-microsoft-prod.deb + wget -O - https://deb.nodesource.com/setup_18.x | sudo -E bash - + sudo apt install -y dotnet-sdk-7.0 yarn nodejs dh-make rename dpkg-sig lintian + sudo npm install -g json + echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_OUTPUT + echo "VERSION=$(echo "${{ github.ref }}" | grep -oP '\d+\.\d+\.\d+' || echo "1.0.0")" >> $GITHUB_OUTPUT + + - name: Build + shell: bash + run: | + cd build/install/deb/ + rename -f -v "s/product([^\/]*)$/${{ env.PRODUCT_LOW }}\$1/g" debian/* ../common/* ../common/logrotate/* + find ../ -type f -exec sed -i "s/{{product}}/${{ env.PRODUCT_LOW }}/g" {} ';' + sed -i "s/{{package_header_tag_version}}/${{ steps.get_vars.outputs.VERSION }}.$BUILD_NUMBER/g" \ + debian/changelog debian/control + dpkg-buildpackage -uc -k${{ steps.gpg_step.outputs.fingerprint }} + + - name: Upload to Nexus + run: | + for file in /home/runner/work/${{ env.PRODUCT }}/${{ env.PRODUCT }}/build/install/*.deb; do + echo $file + curl --verbose --user ${{ secrets.REPO_LOGIN }}:${{ secrets.REPO_PASS }} -H "Content-Type: multipart/form-data" \ + --data-binary "@$file" ${{ secrets.REPO_URL_4TESTING_DEB }} + done + + - name: Lint + run: | + lintian --suppress-tags=mismatched-override --profile debian /home/runner/work/${{ env.PRODUCT }}/${{ env.PRODUCT }}/build/install/*.deb \ + | tee -a file + if grep -qE '^(W:|E:)' file; then echo \ + "::warning Noticedeb=lintian::$(cat file | awk '/^W:/ { ws += 1 } /^E:/ { es += 1 } END { print "Warnings:", ws, "Errors:", es }')"; fi + + build_rpm: + name: RPM packages + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Import GPG + uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PRIVATE_KEY_PASS }} + + - name: Get files from repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Prepare build + id: get_vars + run: | + wget -O - https://dl.yarnpkg.com/debian/pubkey.gpg | sudo gpg --no-default-keyring --keyring \ + gnupg-ring:/usr/share/keyrings/yarnkey.gpg --import + sudo chmod 644 /usr/share/keyrings/yarnkey.gpg + echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian/ stable main" | \ + sudo tee /etc/apt/sources.list.d/yarn.list + wget https://packages.microsoft.com/config/$(lsb_release -is | \ + tr [:upper:] [:lower:])/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb + sudo dpkg -i packages-microsoft-prod.deb + wget -O - https://deb.nodesource.com/setup_18.x | sudo -E bash - + sudo apt install -y dotnet-sdk-7.0 yarn nodejs dh-make rename python3-pip python3-rpm + sudo npm install -g json + sudo pip install rpmlint + echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_OUTPUT + echo "VERSION=$(echo "${ GITHUB_REF##*/ }" | grep -oP '\d+\.\d+\.\d+' || echo "1.0.0")" >> $GITHUB_OUTPUT + + - name: Build + run: | + cd build/install/rpm/SPECS + mv ./SOURCES/product.rpmlintrc ./SOURCES/${{ env.PRODUCT_LOW }}.rpmlintrc + wget https://github.com/ONLYOFFICE/${{ env.PRODUCT }}/archive/${{ env.BRANCH_NAME }}.tar.gz \ + -O ./SOURCES/${{ env.PRODUCT }}-$(echo ${{ env.BRANCH_NAME }} | tr '/' '-').tar.gz + wget https://github.com/ONLYOFFICE/document-templates/archive/main/community-server.tar.gz \ + -O ./SOURCES/document-templates-main-community-server.tar.gz + wget https://github.com/ONLYOFFICE/dictionaries/archive/master.tar.gz \ + -O ./SOURCES/dictionaries-master.tar.gz + sed -i -e '/BuildRequires/d' product.spec + rpmbuild -D "packager Ascensio System SIA " -D "GIT_BRANCH $(echo ${{ env.BRANCH_NAME }} \ + | tr '/' '-')" -D "_topdir $(pwd)" -D "version ${{ steps.get_vars.outputs.VERSION }}" \ + -D "release ${{ env.BUILD_NUMBER }}" -ba product.spec + + - name: Sign + run: | + cat << EOF >> $HOME/.rpmmacros + %_signature gpg + %_gpg_name ${{ secrets.GPG_KEY_NAME }} + %_gpg_path $HOME/.gnupg + %__gpg /usr/bin/gpg + EOF + gpg --export --armor --output onlyoffice-gpgkey.pub + rpm --import onlyoffice-gpgkey.pub + rpm --addsign /home/runner/work/${{ env.PRODUCT }}/${{ env.PRODUCT }}/build/install/rpm/SPECS/RPMS/x86_64/*.rpm + + - name: Upload + run: | + for file in /home/runner/work/${{ env.PRODUCT }}/${{ env.PRODUCT }}/build/install/rpm/SPECS/RPMS/x86_64/*.rpm; do + curl --verbose --user ${{ secrets.REPO_LOGIN }}:${{ secrets.REPO_PASS }} \ + --upload-file "$file" ${{ secrets.REPO_URL_4TESTING_RPM }} + done + + - name: Rpmlint + run: | + for package in /home/runner/work/${{ env.PRODUCT }}/${{ env.PRODUCT }}/build/install/rpm/SPECS/RPMS/x86_64/*.rpm + do rpmlint --ignore-unused-rpmlintrc --rpmlintrc \ + /home/runner/work/${{ env.PRODUCT }}/${{ env.PRODUCT }}/build/install/rpm/SPECS/SOURCES/${{ env.PRODUCT_LOW }}.rpmlintrc $package \ + | tee -a file2 + done + if grep -qE '^(W:|E:)' file2; then echo \ + "::warning NoticeRpm=rpmLint::$(cat file2 | awk '/W:/ { ws += 1 } /E:/ { es += 1 } END { print "Warnings:", ws, "Errors:", es }')" ; fi diff --git a/build/install/OneClickInstall/install-Docker.sh b/build/install/OneClickInstall/install-Docker.sh index 33f078ba98..637a03daa8 100644 --- a/build/install/OneClickInstall/install-Docker.sh +++ b/build/install/OneClickInstall/install-Docker.sh @@ -552,14 +552,14 @@ install_docker_compose () { install_service python3 fi - if command_exists apt-get; then - apt-get -y update -qq - apt-get -y -q install python3-pip - elif command_exists yum; then + py3_version=$(python3 -c 'import sys; print(sys.version_info.minor)') + if [[ $py3_version -lt 6 ]]; then + curl -O https://bootstrap.pypa.io/pip/3.$py3_version/get-pip.py + else curl -O https://bootstrap.pypa.io/get-pip.py - python3 get-pip.py || true - rm get-pip.py - fi + fi + python3 get-pip.py + rm get-pip.py python3 -m pip install --upgrade pip python3 -m pip install docker-compose @@ -571,21 +571,6 @@ install_docker_compose () { fi } -install_jq () { - if command_exists apt-get; then - apt-get -y update - apt-get -y -q install jq - elif command_exists yum; then - rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-$REV.noarch.rpm || true - yum -y install jq - fi - - if ! command_exists jq; then - echo "command jq not found" - exit 1; - fi -} - check_ports () { RESERVED_PORTS=(3306 8092); ARRAY_PORTS=(); @@ -779,10 +764,6 @@ get_available_version () { install_curl; fi - if ! command_exists jq ; then - install_jq - fi - CREDENTIALS=""; AUTH_HEADER=""; TAGS_RESP=""; @@ -953,6 +934,13 @@ download_files () { install_service svn subversion fi + if ! command_exists jq ; then + if command_exists yum; then + rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-$REV.noarch.rpm + fi + install_service jq + fi + svn export --force https://github.com/${PACKAGE_SYSNAME}/${PRODUCT}/branches/${GIT_BRANCH}/build/install/docker/ ${BASE_DIR} reconfigure STATUS ${STATUS} @@ -965,8 +953,8 @@ download_files () { } reconfigure () { - local VARIABLE_NAME=$1 - local VARIABLE_VALUE=$2 + local VARIABLE_NAME="$1" + local VARIABLE_VALUE="$2" if [[ -n ${VARIABLE_VALUE} ]]; then sed -i "s~${VARIABLE_NAME}=.*~${VARIABLE_NAME}=${VARIABLE_VALUE}~g" $BASE_DIR/.env diff --git a/build/install/deb/debian/source/lintian-overrides b/build/install/deb/debian/source/lintian-overrides index f2a6362cf2..8fdb0f12da 100644 --- a/build/install/deb/debian/source/lintian-overrides +++ b/build/install/deb/debian/source/lintian-overrides @@ -7,7 +7,7 @@ privacy-breach-generic var/www/{{product}}/services/*/node_modules/* # Ignoring node_modules errors due to lack of ability to influence them script-not-executable var/www/{{product}}/services/*/node_modules/* # Ignoring node_modules errors due to lack of ability to influence them -unusual-interpreter var/www/{{product}}/services/*/node_modules/* +unusual-interpreter */node_modules/* # The use of the /var/www directory is caused by its past history as the default document root dir-or-file-in-var-www @@ -44,3 +44,12 @@ untranslatable-debconf-templates # We use this to protect sensitive information (ie passwords) in the config file non-standard-file-perm + +# There are instances where temporary or future code sections need to be retained for documentation or future development purposes +no-code-sections + +# Ignoring errors due to lack of ability to influence them +library-not-linked-against-libc + +# Some file triggers a privacy concern, specifically references an image files .png +privacy-breach-generic diff --git a/build/install/rpm/SPECS/SOURCES/product.rpmlintrc b/build/install/rpm/SPECS/SOURCES/product.rpmlintrc index 6285c55e82..af41bdc289 100644 --- a/build/install/rpm/SPECS/SOURCES/product.rpmlintrc +++ b/build/install/rpm/SPECS/SOURCES/product.rpmlintrc @@ -7,9 +7,6 @@ addFilter(r' W: non-standard-(uid|gid)') # This is necessary to ensure that all child packages are updated correctly addFilter(r'W: requires-on-release') -# The signature of packages occurs in further stages -addFilter(r'E: no-signature') - # The basic documentation comes with the common package addFilter(r'W: no-documentation') @@ -45,3 +42,18 @@ addFilter(r'non-standard-executable-perm') # We use this to protect sensitive information (ie passwords) in the config file addFilter(r'non-readable') + +# No one license from allowed pull AGPLv3, AGPLv3+ worked +addFilter(r'W: invalid-license AGPLv3') + +# Сertain services require write access to the log directory. These services are launched under a user account that is different from the root user. +addFilter(r'logrotate-user-writable-log-dir') + +# The use of the /var/www directory is caused by its past history as the default document root +addFilter(r'W: non-standard-dir-in-var www') + +# Shared libraries centos7-librdkafka.so, libgrpc_csharp_ext.x64.so location of which is hardcoded +addFilter(r'W: binary-or-shlib-calls-gethostbyname') + +# There are the same files, however on a different languages +addFilter(r'files-duplicate') diff --git a/build/install/rpm/SPECS/package.spec b/build/install/rpm/SPECS/package.spec index a937357d43..f69cccc5e6 100644 --- a/build/install/rpm/SPECS/package.spec +++ b/build/install/rpm/SPECS/package.spec @@ -1,4 +1,5 @@ %package backup +Packager: %{packager} Summary: Backup Group: Applications/Internet Requires: %name-common = %version-%release @@ -8,6 +9,7 @@ AutoReqProv: no Backup %package common +Packager: %{packager} Summary: Common Group: Applications/Internet Requires: logrotate @@ -15,6 +17,7 @@ Requires: logrotate Common %package files-services +Packager: %{packager} Summary: Files-services Group: Applications/Internet Requires: %name-common = %version-%release @@ -25,6 +28,7 @@ AutoReqProv: no Files-services %package notify +Packager: %{packager} Summary: Notify Group: Applications/Internet Requires: %name-common = %version-%release @@ -34,6 +38,7 @@ AutoReqProv: no Notify %package files +Packager: %{packager} Summary: Files Group: Applications/Internet Requires: %name-common = %version-%release @@ -43,6 +48,7 @@ AutoReqProv: no Files %package proxy +Packager: %{packager} Summary: Proxy Group: Applications/Internet Requires: %name-common = %version-%release @@ -53,6 +59,7 @@ AutoReqProv: no Proxy %package studio-notify +Packager: %{packager} Summary: Studio-notify Group: Applications/Internet Requires: %name-common = %version-%release @@ -62,6 +69,7 @@ AutoReqProv: no Studio-notify %package people-server +Packager: %{packager} Summary: People-server Group: Applications/Internet Requires: %name-common = %version-%release @@ -71,6 +79,7 @@ AutoReqProv: no People-server %package socket +Packager: %{packager} Summary: Socket Group: Applications/Internet Requires: %name-common = %version-%release @@ -80,6 +89,7 @@ AutoReqProv: no Socket %package studio +Packager: %{packager} Summary: Studio Group: Applications/Internet Requires: %name-common = %version-%release @@ -89,6 +99,7 @@ AutoReqProv: no Studio %package api +Packager: %{packager} Summary: Api Group: Applications/Internet Requires: %name-common = %version-%release @@ -98,6 +109,7 @@ AutoReqProv: no Api %package api-system +Packager: %{packager} Summary: Api-system Group: Applications/Internet Requires: %name-common = %version-%release @@ -107,6 +119,7 @@ AutoReqProv: no Api-system %package ssoauth +Packager: %{packager} Summary: Ssoauth Group: Applications/Internet Requires: %name-common = %version-%release @@ -116,6 +129,7 @@ AutoReqProv: no Ssoauth %package clear-events +Packager: %{packager} Summary: Clear-events Group: Applications/Internet Requires: %name-common = %version-%release @@ -125,6 +139,7 @@ AutoReqProv: no Clear-events %package backup-background +Packager: %{packager} Summary: Backup-background Group: Applications/Internet Requires: %name-common = %version-%release @@ -134,6 +149,7 @@ AutoReqProv: no Backup-background %package radicale +Packager: %{packager} Summary: Radicale Group: Applications/Internet Requires: %name-common = %version-%release @@ -143,6 +159,7 @@ AutoReqProv: no Radicale %package doceditor +Packager: %{packager} Summary: Doceditor Group: Applications/Internet Requires: %name-common = %version-%release @@ -152,6 +169,7 @@ AutoReqProv: no Doceditor %package migration-runner +Packager: %{packager} Summary: Migration-runner Group: Applications/Internet Requires: %name-common = %version-%release @@ -161,6 +179,7 @@ AutoReqProv: no Migration-runner %package login +Packager: %{packager} Summary: Login Group: Applications/Internet Requires: %name-common = %version-%release @@ -170,6 +189,7 @@ AutoReqProv: no Login %package healthchecks +Packager: %{packager} Summary: Healthchecks Group: Applications/Internet Requires: %name-common = %version-%release diff --git a/build/install/rpm/SPECS/product.spec b/build/install/rpm/SPECS/product.spec index e8ff8529ab..0fc9f9b11a 100644 --- a/build/install/rpm/SPECS/product.spec +++ b/build/install/rpm/SPECS/product.spec @@ -14,6 +14,7 @@ AutoReqProv: no URL: http://onlyoffice.com Vendor: Ascensio System SIA +Packager: %{packager} License: AGPLv3 Source0: https://github.com/ONLYOFFICE/%{product}/archive/%GIT_BRANCH.tar.gz#/%{sourcename}.tar.gz diff --git a/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs b/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs index 6983e1e2e8..540f594606 100644 --- a/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs +++ b/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs @@ -434,7 +434,15 @@ public class DiscDataStore : BaseStorage } var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.AllDirectories); - var size = entries.Select(entry => _crypt.GetFileSize(entry)).Sum(); + var size = entries.Where(r => + { + if (QuotaController == null || string.IsNullOrEmpty(QuotaController.ExcludePattern)) + { + return true; + } + return !Path.GetFileName(r).StartsWith(QuotaController.ExcludePattern); + } + ).Select(_crypt.GetFileSize).Sum(); var subDirs = Directory.GetDirectories(targetDir, "*", SearchOption.AllDirectories).ToList(); subDirs.Reverse(); diff --git a/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs b/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs index c842ed2428..199078a621 100644 --- a/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs +++ b/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs @@ -457,7 +457,15 @@ public class GoogleCloudStorage : BaseStorage await foreach (var obj in objToDel) { await storage.DeleteObjectAsync(_bucket, obj.Name); - await QuotaUsedDelete(domain, Convert.ToInt64(obj.Size)); + + if (QuotaController != null) + { + if (string.IsNullOrEmpty(QuotaController.ExcludePattern) || + !Path.GetFileName(obj.Name).StartsWith(QuotaController.ExcludePattern)) + { + await QuotaUsedDelete(domain, Convert.ToInt64(obj.Size)); + } + } } } diff --git a/common/ASC.Data.Storage/IQuotaController.cs b/common/ASC.Data.Storage/IQuotaController.cs index 5858f5d43d..e514021228 100644 --- a/common/ASC.Data.Storage/IQuotaController.cs +++ b/common/ASC.Data.Storage/IQuotaController.cs @@ -36,4 +36,6 @@ public interface IQuotaController void QuotaUsedSet(string module, string domain, string dataTag, long size); void QuotaUsedCheck(long size); + + string ExcludePattern { get; set; } } diff --git a/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs b/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs index 03212024e8..3f23df0075 100644 --- a/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs +++ b/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs @@ -189,10 +189,10 @@ public class RackspaceCloudStorage : BaseStorage return SaveAsync(domain, path, stream, string.Empty, string.Empty, ACL.Auto, contentEncoding, cacheDays); } - private bool EnableQuotaCheck(string domain) - { - return (QuotaController != null) && !domain.EndsWith("_temp"); - } + private bool EnableQuotaCheck(string domain) + { + return (QuotaController != null) && !domain.EndsWith("_temp"); + } public async Task SaveAsync(string domain, string path, Stream stream, string contentType, string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5, @@ -200,7 +200,7 @@ public class RackspaceCloudStorage : BaseStorage { var buffered = _tempStream.GetBuffered(stream); - if (EnableQuotaCheck(domain)) + if (EnableQuotaCheck(domain)) { QuotaController.QuotaUsedCheck(buffered.Length); } @@ -482,7 +482,15 @@ public class RackspaceCloudStorage : BaseStorage foreach (var obj in objToDel) { client.DeleteObject(_private_container, obj.Name); - await QuotaUsedDelete(domain, obj.Bytes); + + if (QuotaController != null) + { + if (string.IsNullOrEmpty(QuotaController.ExcludePattern) || + !Path.GetFileName(obj.Name).StartsWith(QuotaController.ExcludePattern)) + { + await QuotaUsedDelete(domain, obj.Bytes); + } + } } } @@ -755,7 +763,7 @@ public class RackspaceCloudStorage : BaseStorage var obj = client.ListObjects(_private_container, null, null, null, prefix, _region).FirstOrDefault(); - var lastModificationDate = obj == null ? throw new FileNotFoundException("File not found" + prefix) : obj.LastModified.UtcDateTime; + var lastModificationDate = obj == null ? throw new FileNotFoundException("File not found" + prefix) : obj.LastModified.UtcDateTime; var etag = '"' + lastModificationDate.Ticks.ToString("X8", CultureInfo.InvariantCulture) + '"'; diff --git a/common/ASC.Data.Storage/S3/S3Storage.cs b/common/ASC.Data.Storage/S3/S3Storage.cs index b5037b457b..0874816339 100644 --- a/common/ASC.Data.Storage/S3/S3Storage.cs +++ b/common/ASC.Data.Storage/S3/S3Storage.cs @@ -495,7 +495,14 @@ public class S3Storage : BaseStorage await client.DeleteObjectAsync(deleteRequest); - await QuotaUsedDelete(domain, s3Object.Size); + if (QuotaController != null) + { + if (string.IsNullOrEmpty(QuotaController.ExcludePattern) || + !Path.GetFileName(s3Object.Key).StartsWith(QuotaController.ExcludePattern)) + { + await QuotaUsedDelete(domain, s3Object.Size); + } + } } } diff --git a/common/ASC.Data.Storage/TenantQuotaController.cs b/common/ASC.Data.Storage/TenantQuotaController.cs index 7d7531170f..048a9c9009 100644 --- a/common/ASC.Data.Storage/TenantQuotaController.cs +++ b/common/ASC.Data.Storage/TenantQuotaController.cs @@ -50,6 +50,7 @@ public class TenantQuotaController : IQuotaController private readonly TenantQuotaFeatureChecker _maxTotalSizeChecker; private Lazy _lazyCurrentSize; private long _currentSize; + public string ExcludePattern { get; set; } public TenantQuotaController(TenantManager tenantManager, AuthContext authContext, TenantQuotaFeatureChecker maxFileSizeChecker, TenantQuotaFeatureChecker maxTotalSizeChecker) { @@ -58,13 +59,14 @@ public class TenantQuotaController : IQuotaController _maxTotalSizeChecker = maxTotalSizeChecker; _authContext = authContext; } - - public void Init(int tenant) + + public void Init(int tenant, string excludePattern = null) { _tenant = tenant; _lazyCurrentSize = new Lazy(() => _tenantManager.FindTenantQuotaRows(tenant) .Where(r => UsedInQuota(r.Tag)) .Sum(r => r.Counter)); + ExcludePattern = excludePattern; } public void QuotaUsedAdd(string module, string domain, string dataTag, long size, bool quotaCheckFileSize = true) diff --git a/common/services/ASC.ElasticSearch/Engine/FactoryIndexer.cs b/common/services/ASC.ElasticSearch/Engine/FactoryIndexer.cs index 8dbaad6998..10a30e24f7 100644 --- a/common/services/ASC.ElasticSearch/Engine/FactoryIndexer.cs +++ b/common/services/ASC.ElasticSearch/Engine/FactoryIndexer.cs @@ -394,6 +394,15 @@ public class FactoryIndexer : IFactoryIndexer where T : class, ISearchItem Logger.ErrorUpdate(e); } } + public Task UpdateAsync(T data, UpdateAction action, Expression> field, bool immediately = true) + { + var t = _serviceProvider.GetService(); + + return !Support(t) + ? Task.FromResult(false) + : Queue(() => _indexer.Update(data, action, field, immediately)); + } + public void Update(T data, Expression, Selector>> expression, bool immediately = true, params Expression>[] fields) { diff --git a/config/appsettings.json b/config/appsettings.json index 0030128f0f..f2a8ba416d 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -47,7 +47,7 @@ "oidc": { "authority": "" }, - "server-root": "" + "server-root": "" }, "license": { "file": { @@ -296,7 +296,8 @@ "book-training-email": "training@onlyoffice.com", "documentation-email": "documentation@onlyoffice.com", "max-upload-size": 5242880, - "zendesk-key": "" + "zendesk-key": "", + "samesite": "" }, "ConnectionStrings": { "default": { @@ -342,7 +343,8 @@ "storageBucket": "", "messagingSenderId": "", "appId": "", - "measurementId": "" + "measurementId": "", + "databaseURL": "" }, "debug-info": { "enabled": "true" diff --git a/package.json b/package.json index ac62e878d8..999637466b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docspace", - "version": "1.0.1", + "version": "1.1.0", "private": true, "workspaces": { "packages": [ diff --git a/packages/client/package.json b/packages/client/package.json index 7930ce0e46..8b50f191e2 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@docspace/client", - "version": "1.0.1", + "version": "1.1.0", "private": true, "homepage": "", "scripts": { diff --git a/packages/client/src/Shell.jsx b/packages/client/src/Shell.jsx index 7c302b002f..5875931cfe 100644 --- a/packages/client/src/Shell.jsx +++ b/packages/client/src/Shell.jsx @@ -487,6 +487,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => { "/files/trash/filter", "/accounts", + "/accounts/changeOwner", "/accounts/filter", "/accounts/create/:type", diff --git a/packages/client/src/components/dialogs/ReportDialog/index.js b/packages/client/src/components/dialogs/ReportDialog/index.js new file mode 100644 index 0000000000..baf799ecf4 --- /dev/null +++ b/packages/client/src/components/dialogs/ReportDialog/index.js @@ -0,0 +1,165 @@ +import FileReactSvgUrl from "PUBLIC_DIR/images/icons/24/file.svg?url"; +import DownloadReactSvgUrl from "PUBLIC_DIR/images/download.react.svg?url"; + +import React, { useEffect, useState } from "react"; +import styled from "styled-components"; +import { useTranslation } from "react-i18next"; +import { inject, observer } from "mobx-react"; +import { isMobileOnly } from "react-device-detect"; + +import ModalDialog from "@docspace/components/modal-dialog"; +import Text from "@docspace/components/text"; +import Button from "@docspace/components/button"; +import Textarea from "@docspace/components/textarea"; +import IconButton from "@docspace/components/icon-button"; +import toastr from "@docspace/components/toast/toastr"; + +import { + getCrashReport, + downloadJson, + getCurrentDate, +} from "SRC_DIR/helpers/crashReport"; + +const ModalDialogContainer = styled(ModalDialog)` + #modal-dialog { + width: auto; + max-width: 520px; + max-height: 560px; + } + + .report-description { + margin-bottom: 16px; + } + + .report-wrapper { + margin-top: 8px; + height: 48px; + display: flex; + gap: 16px; + align-items: center; + + .report-filename { + display: flex; + } + + .file-icon { + width: 24px; + user-select: none; + } + + .icon-button { + cursor: pointer; + } + } +`; + +const ReportDialog = (props) => { + const { t, ready } = useTranslation(["Common"]); + const { visible, onClose, error, user, version, FirebaseHelper } = props; + const [report, setReport] = useState({}); + const [description, setDescription] = useState(""); + + useEffect(() => { + const report = getCrashReport(user.id, version, user.cultureName, error); + setReport(report); + console.log(report); + }, []); + + const onChangeTextareaValue = (e) => { + setDescription(e.target.value); + }; + + const onClickDownload = () => { + downloadJson(report, fileTitle); + }; + + const onClickSend = async () => { + try { + const reportWithDescription = Object.assign(report, { + description: description, + }); + await FirebaseHelper.sendCrashReport(reportWithDescription); + toastr.success(t("ErrorReportSuccess")); + onCloseAction(); + } catch (e) { + console.error(e); + toastr.error(e); + } + }; + + const onCloseAction = () => { + setDescription(""); + onClose(); + }; + + const fileTitle = t("ErrorReport") + " " + getCurrentDate(); + + return ( + + {t("ErrorReport")} + + + {t("ErrorReportDescription")} + +