Merge branch 'master' into enh/speech-to-text-provider-with-userid

pull/42761/head
Alexander Piskun 4 months ago committed by GitHub
commit be260d2171
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

File diff suppressed because it is too large Load Diff

10
.github/CODEOWNERS vendored

@ -28,7 +28,15 @@
/apps/weather_status/appinfo/info.xml @julien-nc @juliushaertl
/apps/workflowengine/appinfo/info.xml @blizzz @juliushaertl
# Frontend expertise
/apps/files/src @skjnldsv
/apps/files_external/src @skjnldsv
/apps/files_reminders/src @skjnldsv
/apps/files_sharing/src/actions @skjnldsv
/apps/files_trashbin/src @skjnldsv
# Security team
/resources/codesigning @mgallien @miaulalala @nickvergessen
/resources/config/ca-bundle.crt @ChristophWurst @miaulalala @nickvergessen
/.drone.yml @nickvergessen
@ -43,7 +51,7 @@
/core/routes.php @Altahrim
# OpenAPI
openapi.json @provokateurin
openapi*.json @provokateurin
ResponseDefinitions.php @provokateurin
# Talk team

@ -20,7 +20,7 @@ jobs:
# Only run on stableXX branches
if: startsWith( github.base_ref, 'stable')
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
steps:
- name: Download updater config

@ -22,7 +22,7 @@ jobs:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
steps:
- name: Download version.php from ${{ github.base_ref }}

@ -15,15 +15,16 @@ jobs:
arg1: ${{ steps.command.outputs.arg1 }}
arg2: ${{ steps.command.outputs.arg2 }}
head_ref: ${{ steps.comment-branch.outputs.head_ref }}
base_ref: ${{ steps.comment-branch.outputs.base_ref }}
steps:
- name: Check actor permission
uses: skjnldsv/check-actor-permission@e591dbfe838300c007028e1219ca82cc26e8d7c5 # v2
uses: skjnldsv/check-actor-permission@69e92a3c4711150929bca9fcf34448c5bf5526e7 # v2
with:
require: write
- name: Add reaction on start
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.1.0
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }}
@ -31,7 +32,7 @@ jobs:
reactions: "+1"
- name: Parse command
uses: skjnldsv/parse-command-comment@7cef1df370a99dfd5bf896d50121390c96785db8 # v2
uses: skjnldsv/parse-command-comment@d8c0034c481b791dd6348fcacd9c510dc3a4cb4f # v2
id: command
# Init path depending on which command is run
@ -39,9 +40,9 @@ jobs:
id: git-path
run: |
if ${{ startsWith(steps.command.outputs.arg1, '/') }}; then
echo "path=${{ github.workspace }}${{steps.command.outputs.arg1}}" >> $GITHUB_OUTPUT
echo "path=${{steps.command.outputs.arg1}}" >> $GITHUB_OUTPUT
else
echo "path=${{ github.workspace }}${{steps.command.outputs.arg2}}" >> $GITHUB_OUTPUT
echo "path=${{steps.command.outputs.arg2}}" >> $GITHUB_OUTPUT
fi
- name: Init branch
@ -54,13 +55,13 @@ jobs:
steps:
- name: Restore cached git repository
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: buildjet/cache@e376f15c6ec6dc595375c78633174c7e5f92dc0e # v3
with:
path: .git
key: git-repo
- name: Checkout ${{ needs.init.outputs.head_ref }}
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3.6.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
fetch-depth: 0
@ -76,16 +77,22 @@ jobs:
id: package-engines-versions
with:
fallbackNode: '^20'
fallbackNpm: '^9'
fallbackNpm: '^10'
- name: Set up node ${{ steps.package-engines-versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v3
with:
node-version: ${{ steps.package-engines-versions.outputs.nodeVersion }}
cache: npm
- name: Set up npm ${{ steps.package-engines-versions.outputs.npmVersion }}
run: npm i -g npm@"${{ steps.package-engines-versions.outputs.npmVersion }}"
- name: Rebase to ${{ needs.init.outputs.base_ref }}
if: ${{ contains(needs.init.outputs.arg1, 'rebase') }}
run: |
git fetch origin ${{ needs.init.outputs.base_ref }}:${{ needs.init.outputs.base_ref }}
git rebase origin/${{ needs.init.outputs.base_ref }}
- name: Install dependencies & build
env:
@ -95,29 +102,36 @@ jobs:
npm ci
npm run build --if-present
- name: Commit and push default
if: ${{ needs.init.outputs.arg1 != 'fixup' && needs.init.outputs.arg1 != 'amend' }}
- name: Commit default
if: ${{ !contains(needs.init.outputs.arg1, 'fixup') && !contains(needs.init.outputs.arg1, 'amend') }}
run: |
git add ${{ needs.init.outputs.git_path }}
git add ${{ github.workspace }}${{ needs.init.outputs.git_path }}
git commit --signoff -m 'chore(assets): Recompile assets'
git push origin ${{ needs.init.outputs.head_ref }}
- name: Commit and push fixup
if: ${{ needs.init.outputs.arg1 == 'fixup' }}
- name: Commit fixup
if: ${{ contains(needs.init.outputs.arg1, 'fixup') }}
run: |
git add ${{ needs.init.outputs.git_path }}
git add ${{ github.workspace }}${{ needs.init.outputs.git_path }}
git commit --fixup=HEAD --signoff
git push origin ${{ needs.init.outputs.head_ref }}
- name: Commit and push amend
if: ${{ needs.init.outputs.arg1 == 'amend' }}
- name: Commit amend
if: ${{ contains(needs.init.outputs.arg1, 'amend') }}
run: |
git add ${{ needs.init.outputs.git_path }}
git add ${{ github.workspace }}${{ needs.init.outputs.git_path }}
git commit --amend --no-edit --signoff
git push --force origin ${{ needs.init.outputs.head_ref }}
# Remove any [skip ci] from the amended commit
git commit --amend -m "$(git log -1 --format='%B' | sed '/\[skip ci\]/d')"
- name: Push normally
if: ${{ !contains(needs.init.outputs.arg1, 'rebase') && !contains(needs.init.outputs.arg1, 'amend') }}
run: git push origin ${{ needs.init.outputs.head_ref }}
- name: Force push
if: ${{ contains(needs.init.outputs.arg1, 'rebase') || contains(needs.init.outputs.arg1, 'amend') }}
run: git push --force origin ${{ needs.init.outputs.head_ref }}
- name: Add reaction on failure
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.1.0
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: failure()
with:
token: ${{ secrets.COMMAND_BOT_PAT }}

@ -18,7 +18,7 @@ jobs:
steps:
- name: Add reaction on start
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }}
@ -51,7 +51,7 @@ jobs:
git push
- name: Add reaction on failure
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
if: failure()
with:
token: ${{ secrets.COMMAND_BOT_PAT }}

@ -23,7 +23,7 @@ jobs:
steps:
- name: Add reaction on start
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }}
@ -42,7 +42,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}
- name: Add reaction on failure
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
if: failure()
with:
token: ${{ secrets.COMMAND_BOT_PAT }}

@ -47,7 +47,7 @@ jobs:
fallbackNpm: "^9"
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -77,10 +77,10 @@ jobs:
matrix:
# Run multiple copies of the current job in parallel
# Please increase the number or runners as your tests suite grows (0 based index for e2e tests)
containers: ["component", 0, 1, 2]
containers: ["component", 0, 1, 2, 3, 4, 5]
# Hack as strategy.job-total includes the component and GitHub does not allow math expressions
# Always aling this number with the total of e2e runners (max. index + 1)
total-containers: [3]
total-containers: [6]
name: runner ${{ matrix.containers }}
@ -93,7 +93,7 @@ jobs:
path: ./
- name: Set up node ${{ needs.init.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: ${{ needs.init.outputs.nodeVersion }}
@ -121,7 +121,7 @@ jobs:
SPLIT_INDEX: ${{ matrix.containers == 'component' && 0 || matrix.containers }}
- name: Upload snapshots
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: always()
with:
name: snapshots_${{ matrix.containers }}
@ -132,7 +132,7 @@ jobs:
run: docker logs nextcloud-cypress-tests-${{ env.APP_NAME }} > nextcloud.log
- name: Upload NC logs
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: failure() && matrix.containers != 'component'
with:
name: nc_logs_${{ matrix.containers }}
@ -143,14 +143,14 @@ jobs:
run: docker exec nextcloud-cypress-tests-server tar -cvjf - data > data.tar
- name: Upload data dir archive
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: failure() && matrix.containers != 'component'
with:
name: nc_data_${{ matrix.containers }}
path: data.tar
summary:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [init, cypress]
if: always()

@ -22,7 +22,7 @@ concurrency:
jobs:
auto-approve-merge:
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
permissions:
# for hmarr/auto-approve-action to approve PRs
pull-requests: write

@ -1,29 +1,51 @@
name: FTP unit tests
name: PHPUnit files_external FTP
on:
pull_request:
paths:
- '.github/**'
- 'apps/files_external/**'
schedule:
- cron: "5 2 * * *"
concurrency:
group: ftp-${{ github.head_ref || github.run_id }}
group: files-external-ftp-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
APP_NAME: files_external
jobs:
ftp-tests:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-ftp:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
php-versions: ['8.0', '8.3']
ftpd: ['proftpd', 'vsftpd', 'pure-ftpd']
include:
- php-versions: '8.0'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-${{ matrix.ftpd }}
@ -42,11 +64,14 @@ jobs:
if [[ "${{ matrix.ftpd }}" == 'proftpd' ]]; then docker run --name ftp -d --net host -e PASV_ADDRESS=127.0.0.1 -e FTPUSER_NAME=test -v /tmp/secret.txt:/run/secrets/ftp-user-password-secret -v /tmp/ftp:/home/test instantlinux/proftpd; fi
if [[ "${{ matrix.ftpd }}" == 'vsftpd' ]]; then docker run --name ftp -d --net host -e FTP_USER=test -e FTP_PASS=test -e PASV_ADDRESS=127.0.0.1 -v /tmp/ftp:/home/vsftpd/test fauria/vsftpd; fi
if [[ "${{ matrix.ftpd }}" == 'pure-ftpd' ]]; then docker run --name ftp -d --net host -e "PUBLICHOST=localhost" -e FTP_USER_NAME=test -e FTP_USER_PASS=test -e FTP_USER_HOME=/home/test -v /tmp/ftp:/home/test -v /tmp/ftp:/etc/pure-ftpd/passwd stilliard/pure-ftpd; fi
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -55,8 +80,9 @@ jobs:
composer install
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
./occ app:enable --force files_external
echo "<?php return ['run' => true,'host' => 'localhost','user' => 'test','password' => 'test', 'root' => '${{ env.FTP_ROOT }}'];" > apps/files_external/tests/config.ftp.php
- name: smoketest ftp
run: |
php -r 'var_dump(file_put_contents("ftp://test:test@localhost${{ env.FTP_ROOT }}/ftp.txt", "asd"));'
@ -64,21 +90,30 @@ jobs:
php -r 'var_dump(mkdir("ftp://test:test@localhost${{ env.FTP_ROOT }}/asdads"));'
ls -l /tmp/ftp
[ -f /tmp/ftp/ftp.txt ]
- name: PHPUnit
run: |
echo "<?php return ['run' => true,'host' => 'localhost','user' => 'test','password' => 'test', 'root' => '${{ env.FTP_ROOT }}'];" > apps/${{ env.APP_NAME }}/tests/config.ftp.php
composer run test:files_external apps/files_external/tests/Storage/FtpTest.php
run: composer run test:files_external -- \
apps/files_external/tests/Storage/FtpTest.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-files-external-ftp
- name: ftpd logs
if: always()
run: |
docker logs ftp
ftp-summary:
runs-on: ubuntu-latest
needs: ftp-tests
runs-on: ubuntu-latest-low
needs: [changes, files-external-ftp]
if: always()
steps:
- name: Summary status
run: if ${{ needs.ftp-tests.result != 'success' }}; then exit 1; fi
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-ftp.result != 'success' }}; then exit 1; fi

@ -0,0 +1,185 @@
name: PHPUnit files_external S3
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-s3-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-s3-minio:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-s3
services:
minio:
image: bitnami/minio
env:
MINIO_ROOT_USER: nextcloud
MINIO_ROOT_PASSWORD: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
MINIO_DEFAULT_BUCKETS: nextcloud
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: |
composer install
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force files_external
echo "<?php return ['run' => true, 'secret' => 'actually-not-secret', 'passwordsalt' => 'actually-not-secret', 'hostname' => 'localhost','key' => '$OBJECT_STORE_KEY','secret' => '$OBJECT_STORE_SECRET', 'bucket' => 'bucket', 'port' => 9000, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/files_external/tests/config.amazons3.php
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: PHPUnit
run: composer run test:files_external -- \
apps/files_external/tests/Storage/Amazons3Test.php \
apps/files_external/tests/Storage/VersionedAmazonS3Test.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-files-external-s3
- name: S3 logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
files-external-s3-localstack:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-s3
services:
localstack:
env:
SERVICES: s3
DEBUG: 1
image: localstack/localstack
ports:
- "4566:4566"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force files_external
echo "<?php return ['run' => true,'hostname' => 'localhost','key' => 'ignored','secret' => 'ignored', 'bucket' => 'bucket', 'port' => 4566, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/files_external/tests/config.amazons3.php
- name: PHPUnit
run: composer run test:files_external -- \
apps/files_external/tests/Storage/Amazons3Test.php \
apps/files_external/tests/Storage/VersionedAmazonS3Test.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-files-external-s3
- name: S3 logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-external-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-s3-minio, files-external-s3-localstack]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-s3-minio.result != 'success' && needs.files-external-s3-localstack.result != 'success' }}; then exit 1; fi

@ -0,0 +1,109 @@
name: PHPUnit files_external sFTP
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-sftp-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-sftp:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0', '8.3']
sftpd: ['openssh']
include:
- php-versions: '8.0'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-${{ matrix.sftpd }}
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up sftpd
run: |
sudo mkdir /tmp/sftp
sudo chown -R 0777 /tmp/sftp
if [[ "${{ matrix.sftpd }}" == 'openssh' ]]; then docker run -p 2222:22 --name sftp -d -v /tmp/sftp:/home/test atmoz/sftp "test:test:::data"; fi
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force files_external
echo "<?php return ['run' => true, 'host' => 'localhost:2222','user' => 'test','password' => 'test', 'root' => 'data'];" > apps/files_external/tests/config.sftp.php
- name: PHPUnit
run: composer run test:files_external -- \
apps/files_external/tests/Storage/SftpTest.php \
apps/files_external/tests/Storage/SFTP_KeyTest.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-files-external-sftp
- name: sftpd logs
if: always()
run: |
ls -l /tmp/sftp
docker logs sftp
sftp-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-sftp]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-sftp.result != 'success' }}; then exit 1; fi

@ -1,19 +1,41 @@
name: Samba Kerberos SSO
on:
pull_request:
paths:
- 'apps/files_external/**'
- '.github/workflows/smb-kerberos.yml'
schedule:
- cron: "5 2 * * *"
concurrency:
group: smb-kerberos-${{ github.head_ref || github.run_id }}
group: files-external-smb-kerberos-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
smb-kerberos-tests:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-smb-kerberos:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
name: smb-kerberos-sso
@ -22,11 +44,13 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Checkout user_saml
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: nextcloud/user_saml
path: apps/user_saml
- name: Pull images
run: |
docker pull ghcr.io/icewind1991/samba-krb-test-dc
@ -35,21 +59,35 @@ jobs:
docker tag ghcr.io/icewind1991/samba-krb-test-dc icewind1991/samba-krb-test-dc
docker tag ghcr.io/icewind1991/samba-krb-test-apache icewind1991/samba-krb-test-apache
docker tag ghcr.io/icewind1991/samba-krb-test-client icewind1991/samba-krb-test-client
- name: Setup AD-DC
run: |
DC_IP=$(apps/files_external/tests/sso-setup/start-dc.sh)
sleep 1
apps/files_external/tests/sso-setup/start-apache.sh $DC_IP $PWD
echo "DC_IP=$DC_IP" >> $GITHUB_ENV
- name: Set up Nextcloud
run: |
apps/files_external/tests/sso-setup/setup-sso-nc.sh
- name: Test SSO
run: |
apps/files_external/tests/sso-setup/test-sso-smb.sh ${{ env.DC_IP }}
- name: Show logs
if: failure()
if: always()
run: |
FILEPATH=$(docker exec --user 33 apache ./occ log:file | grep "Log file:" | cut -d' ' -f3)
echo "$FILEPATH:"
docker exec --user 33 apache cat $FILEPATH
sftp-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-smb-kerberos]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-smb-kerberos.result != 'success' }}; then exit 1; fi

@ -0,0 +1,105 @@
name: PHPUnit files_external WebDAV
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-webdav-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-webdav-apache:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-webdav
services:
apache:
image: ghcr.io/nextcloud/continuous-integration-webdav-apache:latest
ports:
- 8081:80
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ config:system:set --value true --type boolean allow_local_remote_servers
./occ app:enable --force files_external
echo "<?php return ['run' => true, 'host' => 'localhost:8081/webdav/', 'user' => 'test', 'password'=>'pass', 'root' => '', 'wait' => 0];" > apps/files_external/tests/config.webdav.php
- name: Wait for WebDAV
run: |
sleep 5
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://test:pass@localhost:8081/webdav/
- name: PHPUnit
run: composer run test:files_external -- --verbose \
apps/files_external/tests/Storage/WebdavTest.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@4fe8c5f003fae66aa5ebb77cfd3e7bfbbda0b6b0 # v3.1.5
with:
files: ./clover.xml
flags: phpunit-files-external-webdav
files-external-webdav-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-webdav-apache]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-webdav-apache.result != 'success' }}; then exit 1; fi

@ -24,7 +24,7 @@ jobs:
pull-requests: write
name: Block fixup and squash commits
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
steps:
- name: Run check

@ -0,0 +1,117 @@
name: S3 primary storage integration tests
on:
pull_request:
concurrency:
group: integration-s3-primary-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- 'build/integration/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
integration-s3-primary:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false' && github.repository_owner != 'nextcloud-gmbh'
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
redis:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
ports:
- 6379:6379/tcp
minio:
image: bitnami/minio
env:
MINIO_ROOT_USER: nextcloud
MINIO_ROOT_PASSWORD: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
MINIO_DEFAULT_BUCKETS: nextcloud
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: 'none'
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: Set up Nextcloud
run: |
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "nextcloud", "secret" => "bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
echo '<?php $CONFIG=["redis" => ["host" => "localhost", "port" => 6379], "memcache.local" => "\OC\Memcache\Redis", "memcache.distributed" => "\OC\Memcache\Redis"];' > config/redis.config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f index.php
- name: Integration
run: |
cd build/integration
bash run.sh --tags "~@failure-s3" dav_features/webdav-related.feature
- name: S3 logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-integration-summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, integration-s3-primary]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.integration-s3-primary.result != 'success' }}; then exit 1; fi

@ -0,0 +1,166 @@
name: Integration sqlite
on:
pull_request:
push:
branches:
- main
- master
- stable*
permissions:
contents: read
concurrency:
group: integration-sqlite-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- 'build/integration/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
integration-sqlite:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
fail-fast: false
matrix:
test-suite:
- 'capabilities_features'
- 'collaboration_features'
- 'comments_features'
- 'dav_features'
- 'features'
- 'federation_features'
- '--tags ~@large files_features'
- 'filesdrop_features'
- 'openldap_features'
- 'openldap_numerical_features'
- 'ldap_features'
- 'remoteapi_features'
- 'setup_features'
- 'sharees_features'
- 'sharing_features'
- 'videoverification_features'
php-versions: ['8.2']
spreed-versions: ['main']
services:
redis:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
ports:
- 6379:6379/tcp
openldap:
image: ghcr.io/nextcloud/continuous-integration-openldap:openldap-7
ports:
- 389:389
env:
SLAPD_DOMAIN: nextcloud.ci
SLAPD_ORGANIZATION: Nextcloud
SLAPD_PASSWORD: admin
SLAPD_ADDITIONAL_MODULES: memberof
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: true
- name: Checkout Talk app
if: ${{ matrix.test-suite == 'videoverification_features' }}
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
repository: nextcloud/spreed
path: apps/spreed
ref: ${{ matrix.spreed-versions }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, imagick, intl, json, ldap, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: none
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up production dependencies
run: composer i --no-dev
- name: Set up behat dependencies
working-directory: build/integration
run: composer i
- name: Set up Talk dependencies
if: ${{ matrix.test-suite == 'videoverification_features' }}
working-directory: apps/spreed
run: composer i --no-dev
- name: Set up Nextcloud
run: |
mkdir data
./occ maintenance:install --verbose ${{ contains(matrix.test-suite,'ldap') && '--data-dir=/dev/shm/nc_int' || '' }} --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
./occ config:system:set hashing_default_password --value=true --type=boolean
- name: Configure caching
if: ${{ contains(matrix.test-suite,'ldap') }}
run: |
./occ config:system:set redis host --value=localhost
./occ config:system:set redis port --value=6379 --type=integer
./occ config:system:set redis timeout --value=0 --type=integer
./occ config:system:set memcache.local --value='\OC\Memcache\Redis'
./occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
- name: Run integration
working-directory: build/integration
env:
LDAP_HOST: localhost
run: bash run.sh ${{ matrix.test-suite }} no-tail-log
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, integration-sqlite]
if: always()
name: integration-sqlite-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.integration-sqlite.result != 'success' }}; then exit 1; fi

@ -20,13 +20,13 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
@ -64,7 +64,7 @@ jobs:
fallbackNpm: '^9'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -83,7 +83,7 @@ jobs:
summary:
permissions:
contents: none
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [changes, lint]
if: always()

@ -16,13 +16,13 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
@ -65,7 +65,7 @@ jobs:
summary:
permissions:
contents: none
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [changes, lint]
if: always()

@ -17,13 +17,13 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
@ -70,7 +70,7 @@ jobs:
summary:
permissions:
contents: none
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [changes, lint]
if: always()

@ -11,13 +11,13 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
@ -72,7 +72,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with:
node-version: ${{ needs.versions.outputs.nodeVersion }}
@ -107,7 +107,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with:
node-version: ${{ needs.versions.outputs.nodeVersion }}
@ -138,7 +138,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with:
node-version: ${{ needs.versions.outputs.nodeVersion }}
@ -157,7 +157,7 @@ jobs:
summary:
permissions:
contents: none
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [changes, test, jsunit, handlebars]
if: always()

@ -17,13 +17,13 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
@ -58,7 +58,7 @@ jobs:
fallbackNpm: '^9'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -87,7 +87,7 @@ jobs:
summary:
permissions:
contents: none
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [changes, build]
if: always()

@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
branches: ["main", "master", "stable28", "stable27", "stable26", "stable25", "stable24"]
branches: ["main", "master", "stable28", "stable27", "stable26"]
name: npm-audit-fix-${{ matrix.branches }}
@ -36,7 +36,7 @@ jobs:
fallbackNpm: '^9'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}

@ -0,0 +1,125 @@
name: Object storage azure
on:
pull_request:
schedule:
- cron: "15 2 * * *"
concurrency:
group: object-storage-azure-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
azure-primary-tests:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-azure
services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
env:
AZURITE_ACCOUNTS: nextcloud:bmV4dGNsb3Vk
ports:
- 10000:10000
options: --health-cmd="nc 127.0.0.1 10000 -z" --health-interval=1s --health-retries=30
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE: azure
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bmV4dGNsb3Vk
run: |
composer install
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
env:
OBJECT_STORE: azure
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bmV4dGNsb3Vk
run: composer run test -- --group PRIMARY-azure ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-azure
- name: Azurite logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
azure-primary-summary:
runs-on: ubuntu-latest-low
needs: [changes, azure-primary-tests]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.azure-primary-tests.result != 'success' }}; then exit 1; fi

@ -0,0 +1,131 @@
name: Object storage S3
on:
pull_request:
schedule:
- cron: "15 2 * * *"
concurrency:
group: object-storage-s3-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
s3-primary-tests-minio:
runs-on: ubuntu-22.04
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-s3
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
minio:
image: bitnami/minio
env:
MINIO_ROOT_USER: nextcloud
MINIO_ROOT_PASSWORD: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
MINIO_DEFAULT_BUCKETS: nextcloud
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE: s3
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: |
composer install
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: PHPUnit
env:
OBJECT_STORE: s3
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: composer run test -- --group PRIMARY-s3 ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-s3
- name: S3 logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-summary:
runs-on: ubuntu-latest-low
needs: [changes,s3-primary-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.s3-primary-tests-minio.result != 'success' }}; then exit 1; fi

@ -0,0 +1,121 @@
name: Object storage Swift
on:
pull_request:
schedule:
- cron: "15 2 * * *"
concurrency:
group: object-storage-swift-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
swift-primary-tests:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-swift
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
swift:
image: ghcr.io/cscfi/docker-keystone-swift
ports:
- 5000:5000
- 8080:8080
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE: swift
OBJECT_STORE_SECRET: veryfast
run: |
composer install
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
env:
OBJECT_STORE: swift
OBJECT_STORE_SECRET: veryfast
run: composer run test -- --group PRIMARY-swift ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-swift
- name: Swift logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
swift-primary-summary:
runs-on: ubuntu-latest-low
needs: [changes,swift-primary-tests]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.swift-primary-tests.result != 'success' }}; then exit 1; fi

@ -82,7 +82,7 @@ jobs:
- name: Upload profiles
if: always()
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8
with:
name: profiles
path: |

@ -0,0 +1,144 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit mariadb
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-mariadb-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-mariadb:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0']
mariadb-versions: ['10.3', '10.4', '10.5', '10.6', '10.11']
include:
- php-versions: '8.3'
mariadb-versions: '10.6'
coverage: ${{ github.event_name != 'pull_request' }}
name: MariaDB ${{ matrix.mariadb-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
mariadb:
image: mariadb:${{ matrix.mariadb-versions }}
ports:
- 4444:3306/tcp
env:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_USER: oc_autotest
MYSQL_PASSWORD: nextcloud
MYSQL_DATABASE: oc_autotest
options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 5
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, mysql, pdo_mysql
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Enable ONLY_FULL_GROUP_BY MySQL option
run: |
echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
echo "SELECT @@sql_mode;" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.db.xml
flags: phpunit-mariadb
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-mariadb]
if: always()
name: phpunit-mariadb-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-mariadb.result != 'success' }}; then exit 1; fi

@ -0,0 +1,123 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit memcached
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-memcached-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-memcached:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: Memcached (PHP ${{ matrix.php-versions }})
services:
memcached:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 11212:11212/tcp
- 11212:11212/udp
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, memcached, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
run: |
mkdir data
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit memcached tests
run: composer run test -- --group Memcache,Memcached ${{ matrix.coverage && '--coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.xml
flags: phpunit-memcached
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-memcached]
if: always()
name: phpunit-memcached-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-memcached.result != 'success' }}; then exit 1; fi

@ -0,0 +1,144 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit mysql
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-mysql-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-mysql:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0']
mysql-versions: ['8.0', '8.3']
include:
- mysql-versions: '8.0'
php-versions: '8.3'
coverage: ${{ github.event_name != 'pull_request' }}
name: MySQL ${{ matrix.mysql-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
mysql:
image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest
ports:
- 4444:3306/tcp
env:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_USER: oc_autotest
MYSQL_PASSWORD: nextcloud
MYSQL_DATABASE: oc_autotest
options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 5
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, mysql, pdo_mysql
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Enable ONLY_FULL_GROUP_BY MySQL option
run: |
echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
echo "SELECT @@sql_mode;" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.db.xml
flags: phpunit-mysql
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-mysql]
if: always()
name: phpunit-mysql-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-mysql.result != 'success' }}; then exit 1; fi

@ -0,0 +1,127 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
# This is the testsuite running all non-database agnostic unit tests
name: PHPUnit nodb
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-nodb-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-nodb:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: No DB unit tests (PHP ${{ matrix.php-versions }})
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, imagick, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
# Required for tests that use pcntl
ini-values: disable_functions=""
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit nodb testsuite
run: composer run test -- --exclude-group DB,SLOWDB ${{ matrix.coverage && ' --coverage-clover ./clover.nodb.xml' || '' }}
- name: Upload nodb code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.nodb.xml
flags: phpunit-nodb
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-nodb]
if: always()
name: phpunit-nodb-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-nodb.result != 'success' }}; then exit 1; fi

@ -2,6 +2,8 @@ name: PHPUnit oci
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
@ -12,13 +14,13 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
@ -26,36 +28,51 @@ jobs:
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- '**/vendor-bin/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-oci:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
if: needs.changes.outputs.src != 'false' && ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2']
oracle-versions: ['11']
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: ${{ github.event_name != 'pull_request' }}
name: Oracle ${{ matrix.oracle-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
oracle:
image: ghcr.io/gvenzl/oracle-xe:11
image: ghcr.io/gvenzl/oracle-xe:${{ matrix.oracle-versions }}
# Provide passwords and other environment variables to container
env:
ORACLE_RANDOM_PASSWORD: true
APP_USER: autotest
APP_USER_PASSWORD: owncloud
APP_USER: oc_autotest
APP_USER_PASSWORD: nextcloud
# Forward Oracle port
ports:
- 1521:1521/tcp
- 4444:1521/tcp
# Provide healthcheck script options for startup
options: >-
@ -71,24 +88,38 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
extensions: ctype, curl, dom, fileinfo, gd, imagick, intl, json, mbstring, oci8, openssl, pcntl, pdo_sqlite, posix, sqlite, xml, zip
coverage: none
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, oci8
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
composer install
mkdir data
./occ maintenance:install --verbose --database=oci --database-name=XE --database-host=127.0.0.1 --database-port=1521 --database-user=autotest --database-pass=owncloud --admin-user admin --admin-pass admin
php -f index.php
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=oci --database-name=XE --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=oc_autotest --database-pass=nextcloud --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
run: composer run test:db
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.db.xml
flags: phpunit-oci
- name: Run repair steps
run: |
@ -97,7 +128,7 @@ jobs:
summary:
permissions:
contents: none
runs-on: ubuntu-latest
runs-on: ubuntu-latest-low
needs: [changes, phpunit-oci]
if: always()

@ -0,0 +1,143 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit pgsql
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-pgsql-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-pgsql:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0']
# To keep the matrix smaller we ignore PostgreSQL '11', '13', '14' as we already test 10 and 15 as lower and upper bound
postgres-versions: ['10', '15', '16']
include:
- php-versions: '8.3'
postgres-versions: '15'
coverage: ${{ github.event_name != 'pull_request' }}
name: PostgreSQL ${{ matrix.postgres-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
postgres:
image: ghcr.io/nextcloud/continuous-integration-postgres-${{ matrix.postgres-versions }}:latest
ports:
- 4444:5432/tcp
env:
POSTGRES_USER: root
POSTGRES_PASSWORD: rootpassword
POSTGRES_DB: nextcloud
options: --mount type=tmpfs,destination=/var/lib/postgresql/data --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit database tests
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.db.xml
flags: phpunit-postgres
- name: Run repair steps
run: |
./occ maintenance:repair --include-expensive
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-pgsql]
if: always()
name: phpunit-pgsql-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-pgsql.result != 'success' }}; then exit 1; fi

@ -0,0 +1,127 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit sqlite
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-sqlite-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-sqlite:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.1'
coverage: ${{ github.event_name != 'pull_request' }}
name: SQLite (PHP ${{ matrix.php-versions }})
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: Nextcloud debug information
run: ./occ app:list && echo "======= System config =======" && ./occ config:list system
- name: PHPUnit database tests
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v3
with:
files: ./clover.db.xml
flags: phpunit-sqlite
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-sqlite]
if: always()
name: phpunit-sqlite-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-sqlite.result != 'success' }}; then exit 1; fi

@ -1,130 +0,0 @@
name: S3 External storage
on:
pull_request:
paths:
- 'apps/files_external/**'
concurrency:
group: s3-external-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
APP_NAME: files_external
jobs:
s3-external-tests-minio:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0', '8.1']
name: php${{ matrix.php-versions }}-minio
services:
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.10.6
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
- name: PHPUnit
run: |
echo "<?php return ['run' => true, 'secret' => 'actually-not-secret', 'passwordsalt' => 'actually-not-secret', 'hostname' => 'localhost','key' => 'minio','secret' => 'minio123', 'bucket' => 'bucket', 'port' => 9000, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/${{ env.APP_NAME }}/tests/config.amazons3.php
composer run test:files_external apps/files_external/tests/Storage/Amazons3Test.php
composer run test:files_external apps/files_external/tests/Storage/VersionedAmazonS3Test.php
- name: S3 logs
if: always()
run: |
docker ps -a
docker logs $(docker ps -aq)
s3-external-tests-localstack:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0', '8.1']
name: php${{ matrix.php-versions }}-localstack
services:
minio:
env:
SERVICES: s3
DEBUG: 1
image: localstack/localstack:0.12.7
ports:
- "4566:4566"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
- name: PHPUnit
run: |
echo "<?php return ['run' => true,'hostname' => 'localhost','key' => 'ignored','secret' => 'ignored', 'bucket' => 'bucket', 'port' => 4566, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/${{ env.APP_NAME }}/tests/config.amazons3.php
composer run test:files_external apps/files_external/tests/Storage/Amazons3Test.php
composer run test:files_external apps/files_external/tests/Storage/VersionedAmazonS3Test.php
- name: S3 logs
if: always()
run: |
docker ps -a
docker logs $(docker ps -aq)
s3-external-summary:
runs-on: ubuntu-latest
needs: [s3-external-tests-minio, s3-external-tests-localstack]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-external-tests-minio.result != 'success' }} || ${{ needs.s3-external-tests-localstack.result != 'success' }}; then exit 1; fi

@ -1,95 +0,0 @@
name: S3 primary storage integration tests
on:
pull_request:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
concurrency:
group: s3-external-integration-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
s3-primary-integration-tests-minio:
runs-on: ubuntu-20.04
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
redis:
image: redis
ports:
- "6379:6379"
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.12.29
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, redis
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: Set up Nextcloud
run: |
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "minio", "secret" => "minio123", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
echo '<?php $CONFIG=["redis" => ["host" => "localhost", "port" => 6379], "memcache.local" => "\OC\Memcache\Redis", "memcache.distributed" => "\OC\Memcache\Redis"];' > config/redis.config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f index.php
- name: Integration
run: |
cd build/integration
bash run.sh --tags "~@failure-s3" features/webdav-related.feature
- name: S3 logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-integration-summary:
runs-on: ubuntu-latest
needs: [s3-primary-integration-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-primary-integration-tests-minio.result != 'success' }}; then exit 1; fi

@ -1,87 +0,0 @@
name: S3 primary storage
on:
pull_request:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
concurrency:
group: s3-primary-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
s3-primary-tests-minio:
runs-on: ubuntu-20.04
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.12.29
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "minio", "secret" => "minio123", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
php -f index.php
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: PHPUnit
run: composer run test:db
- name: S3 logs
if: always()
run: |
docker ps -a
docker logs $(docker ps -aq)
s3-primary-summary:
runs-on: ubuntu-latest
needs: [s3-primary-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-primary-tests-minio.result != 'success' }}; then exit 1; fi

@ -1,73 +0,0 @@
name: SFTP unit tests
on:
pull_request:
paths:
- 'apps/files_external/**'
env:
APP_NAME: files_external
concurrency:
group: sftp-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
sftp-tests:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
sftpd: ['openssh']
name: php${{ matrix.php-versions }}-${{ matrix.sftpd }}
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up sftpd
run: |
sudo mkdir /tmp/sftp
sudo chown -R 0777 /tmp/sftp
if [[ "${{ matrix.sftpd }}" == 'openssh' ]]; then docker run -p 2222:22 --name sftp -d -v /tmp/sftp:/home/test atmoz/sftp "test:test:::data"; fi
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
- name: PHPUnit
run: |
echo "<?php return ['run' => true, 'host' => 'localhost:2222','user' => 'test','password' => 'test', 'root' => 'data'];" > apps/${{ env.APP_NAME }}/tests/config.sftp.php
composer run test:files_external apps/files_external/tests/Storage/SftpTest.php
- name: sftpd logs
if: always()
run: |
ls -l /tmp/sftp
docker logs sftp
sftp-summary:
runs-on: ubuntu-latest
needs: sftp-tests
if: always()
steps:
- name: Summary status
run: if ${{ needs.sftp-tests.result != 'success' }}; then exit 1; fi

@ -40,3 +40,4 @@ jobs:
labels: |
dependencies
3. to review
reviewers: ChristophWurst, miaulalala, nickvergessen

@ -0,0 +1,46 @@
name: Update code signing revocation list
on:
workflow_dispatch:
schedule:
- cron: "5 2 * * *"
jobs:
update-code-signing-crl:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
branches: ["master", "stable28", "stable27", "stable26", "stable25", "stable24", "stable23", "stable22"]
name: update-code-signing-crl-${{ matrix.branches }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ matrix.branches }}
submodules: true
- name: Download CRL file from Appstore repository
run: curl --output resources/codesigning/root.crl https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/certificate/nextcloud.crl
- name: Verify CRL is from CRT
run: openssl crl -verify -in resources/codesigning/root.crl -CAfile resources/codesigning/root.crt -noout
- name: Create Pull Request
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: "fix(security): Update code signing revocation list"
committer: GitHub <noreply@github.com>
author: nextcloud-command <nextcloud-command@users.noreply.github.com>
signoff: true
branch: automated/noid/${{ matrix.branches }}-update-code-signing-crl
title: "[${{ matrix.branches }}] fix(security): Update code signing revocation list"
body: |
Auto-generated update of code signing revocation list from [Appstore](https://github.com/nextcloud/appstore/commits/master/nextcloudappstore/certificate/nextcloud.crl)
labels: |
dependencies
3. to review
reviewers: mgallien, miaulalala, nickvergessen

@ -28,7 +28,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
extensions: ctype,curl,dom,fileinfo,gd,intl,json,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip
extensions: apcu,ctype,curl,dom,fileinfo,ftp,gd,intl,json,ldap,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip
coverage: none
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -37,11 +37,11 @@ jobs:
run: composer install
- name: Psalm
run: composer run psalm -- --monochrome --no-progress --output-format=text --update-baseline
run: composer run psalm:ci -- --monochrome --no-progress --output-format=text --update-baseline
continue-on-error: true
- name: Psalm OCP
run: composer run psalm -- -c psalm-ocp.xml --monochrome --no-progress --output-format=github --update-baseline
run: composer run psalm:ci -- -c psalm-ocp.xml --monochrome --no-progress --output-format=github --update-baseline
continue-on-error: true
- name: Reset composer

2
.gitignore vendored

@ -129,6 +129,8 @@ nbproject
/build/bin
/build/lib/
/build/jsdocs/
/build/integration/output/
/build/integration/phpserver.log
/npm-debug.log
/PhantomJS_*

@ -94,5 +94,19 @@
RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule>
# Clients like xDavv5 on Android, or Cyberduck, use chunked requests.
# When FastCGI or FPM is used with apache, requests arrive to Nextcloud without any content.
# This leads to the creation of empty files.
# The following directive will force the problematic requests to be buffered before being forwarded to Nextcloud.
# This way, the "Transfer-Encoding" header is removed, the "Content-Length" header is set, and the request content is proxied to Nextcloud.
# Here are more information about the issue:
# - https://docs.cyberduck.io/mountainduck/issues/fastcgi/
# - https://docs.nextcloud.com/server/latest/admin_manual/issues/general_troubleshooting.html#troubleshooting-webdav
<IfModule setenvif.c>
<Location "/remote.php">
SetEnvIf Transfer-Encoding "chunked" proxy-sendcl=1
</Location>
</IfModule>
AddDefaultCharset utf-8
Options -Indexes

@ -1 +1 @@
Subproject commit a71bd8af76fdcfad78c865d1c60f6dde6e24f1dd
Subproject commit 77db3ca48a21013824dde3c932cdcc462d52984f

@ -1,14 +1,14 @@
# Security Policy
[Security](https://nextcloud.com/security/) is very important to us.
[Security](https://nextcloud.com/security/) is very important to us.
If you believe you have found a security vulnerability that meets our definition of a security
If you believe you have found a security vulnerability that meets our definition of a security
vulnerability, please report is as described below.
## Context
Please review our [threat model and accepted risks](https://nextcloud.com/security/threat-model) to learn what
is currently considered a security vulnerability versus expected behavior. And review what is considered
Please review our [threat model and accepted risks](https://nextcloud.com/security/threat-model) to learn what
is currently considered a security vulnerability versus expected behavior. And review what is considered
[in scope or bounty eligible](https://hackerone.com/nextcloud/policy_scopes).
@ -31,13 +31,17 @@ Your report should include:
You should receive an initial acknowledgement within 24 hours in most cases.
A member of the security team will confirm the vulnerability, determine its impact, follow-up with any questions,
A member of the security team will confirm the vulnerability, determine its impact, follow-up with any questions,
and coordinate the fix and publication.
The fix will be applied to all applicable and still supported stable branches, tested, and packaged in the next security release.
The vulnerability will be publicly announced after the release. Finally, your name will be added
to the [hall of fame](https://hackerone.com/nextcloud/thanks) as a thank you from the entire Nextcloud
community.
to the [hall of fame](https://hackerone.com/nextcloud/thanks) as a thank you from the entire Nextcloud
community.
If the vulnerability involves an app that is not maintained by Nextcloud (i.e. hosted by the
Nextcloud project but community maintained, or hosted elsewhere), the security team will try to coordinate with the
current maintainer and help to get the issue fixed in similar fashion.
### Bug Bounties
@ -47,8 +51,7 @@ on past bounty ranges can be found at [hackerone.com/nextcloud](https://hackeron
## Existing Security Advisories
Published security advisories for the Nextcloud Server, Clients and Apps can be viewed at
[https://github.com/nextcloud/security-advisories/security/advisories](https://github.com/nextcloud/security-advisories/security/advisories
).
[https://github.com/nextcloud/security-advisories/security/advisories](https://github.com/nextcloud/security-advisories/security/advisories).
## Supported Versions

@ -30,6 +30,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Log\Audit\CriticalActionPerformedEvent;
/** @template-implements IEventListener<CriticalActionPerformedEvent> */
class CriticalActionPerformedEventListener extends Action implements IEventListener {
public function handle(Event $event): void {
if (!($event instanceof CriticalActionPerformedEvent)) {

@ -0,0 +1,8 @@
OC.L10N.register(
"cloud_federation_api",
{
"Cloud Federation API" : "API de Federación en la Nube",
"Enable clouds to communicate with each other and exchange data" : "Permitir que las nubes se comuniquen entre sí e intercambien datos",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de Federación de Nubes permite que varias instancias de Nextcloud se comuniquen entre sí y intercambien datos."
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");

@ -0,0 +1,6 @@
{ "translations": {
"Cloud Federation API" : "API de Federación en la Nube",
"Enable clouds to communicate with each other and exchange data" : "Permitir que las nubes se comuniquen entre sí e intercambien datos",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de Federación de Nubes permite que varias instancias de Nextcloud se comuniquen entre sí y intercambien datos."
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}

@ -30,6 +30,7 @@ use OCA\CloudFederationAPI\Config;
use OCA\CloudFederationAPI\ResponseDefinitions;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
@ -55,6 +56,7 @@ use Psr\Log\LoggerInterface;
* @psalm-import-type CloudFederationAPIValidationError from ResponseDefinitions
* @psalm-import-type CloudFederationAPIError from ResponseDefinitions
*/
#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)]
class RequestHandlerController extends Controller {
public function __construct(
string $appName,

@ -7,8 +7,22 @@ OC.L10N.register(
"You commented on %1$s" : "Comentesti en: %1$s",
"You commented on {file}" : "Comentesti en: {file}",
"%1$s commented on %2$s" : "%1$s comentó en: %2$s",
"{author} commented on {file}" : "{author} comentó en {file}",
"{author} commented on {file}" : "{author} comentó en: {file}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Un usuariu que ta desaniciáu mentóte nun comentariu de: {file}",
"{user} mentioned you in a comment on \"{file}\"" : "{user} mentóte nun comentariu de: «{file}»",
"Edit comment" : "Editar el comentariu",
"Delete comment" : "Desaniciar el comentariu",
"Cancel edit" : "Anular la edición",
"New comment" : "Comentariu nuevu",
"Write a comment …" : "Escribi un comentariu…",
"Post comment" : "Espublizar el comentariu",
"@ for mentions, : for emoji, / for smart picker" : "@ pa les menciones, : pa los fustaxes, / pal selector intelixente",
"Could not reload comments" : "Nun se pudieron recargar los comentarios",
"No comments yet, start the conversation!" : "Nun hai comentarios, ¡anicia una conversación!",
"No more messages" : "Nun hai más mensaxes",
"Retry" : "Retentar",
"Unable to load the comments list" : "Nun ye posible cargar la llista de comentarios",
"_1 new comment_::_{unread} new comments_" : ["1 comentariu nuevu","{unread} comentarios nuevos"],
"Comment" : "Comentariu",
"An error occurred while trying to edit the comment" : "Prodúxose un error mentanto se tentaba d'editar el comentariu",

@ -5,8 +5,22 @@
"You commented on %1$s" : "Comentesti en: %1$s",
"You commented on {file}" : "Comentesti en: {file}",
"%1$s commented on %2$s" : "%1$s comentó en: %2$s",
"{author} commented on {file}" : "{author} comentó en {file}",
"{author} commented on {file}" : "{author} comentó en: {file}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Un usuariu que ta desaniciáu mentóte nun comentariu de: {file}",
"{user} mentioned you in a comment on \"{file}\"" : "{user} mentóte nun comentariu de: «{file}»",
"Edit comment" : "Editar el comentariu",
"Delete comment" : "Desaniciar el comentariu",
"Cancel edit" : "Anular la edición",
"New comment" : "Comentariu nuevu",
"Write a comment …" : "Escribi un comentariu…",
"Post comment" : "Espublizar el comentariu",
"@ for mentions, : for emoji, / for smart picker" : "@ pa les menciones, : pa los fustaxes, / pal selector intelixente",
"Could not reload comments" : "Nun se pudieron recargar los comentarios",
"No comments yet, start the conversation!" : "Nun hai comentarios, ¡anicia una conversación!",
"No more messages" : "Nun hai más mensaxes",
"Retry" : "Retentar",
"Unable to load the comments list" : "Nun ye posible cargar la llista de comentarios",
"_1 new comment_::_{unread} new comments_" : ["1 comentariu nuevu","{unread} comentarios nuevos"],
"Comment" : "Comentariu",
"An error occurred while trying to edit the comment" : "Prodúxose un error mentanto se tentaba d'editar el comentariu",

@ -16,6 +16,7 @@ OC.L10N.register(
"Delete comment" : "Smazat komentář",
"Cancel edit" : "Zrušit úpravu",
"New comment" : "Nový komentář",
"Write a comment …" : "Napsat komentář…",
"Post comment" : "Odeslat komentář",
"@ for mentions, : for emoji, / for smart picker" : "@ pro zmínění, : pro emotikony, / pro inteligentní výběr",
"Could not reload comments" : "Znovunačtení komentářů se nezdařilo",

@ -14,6 +14,7 @@
"Delete comment" : "Smazat komentář",
"Cancel edit" : "Zrušit úpravu",
"New comment" : "Nový komentář",
"Write a comment …" : "Napsat komentář…",
"Post comment" : "Odeslat komentář",
"@ for mentions, : for emoji, / for smart picker" : "@ pro zmínění, : pro emotikony, / pro inteligentní výběr",
"Could not reload comments" : "Znovunačtení komentářů se nezdařilo",

@ -16,6 +16,7 @@ OC.L10N.register(
"Delete comment" : "Borrar comentario",
"Cancel edit" : "Cacelar edición",
"New comment" : "Comentario nuevo",
"Write a comment …" : "Escribir un comentario …",
"Post comment" : "Publicar comentario",
"@ for mentions, : for emoji, / for smart picker" : "@ para menciones, : para emoji, / para selector inteligente",
"Could not reload comments" : "No se pudieron recargar los comentarios",

@ -14,6 +14,7 @@
"Delete comment" : "Borrar comentario",
"Cancel edit" : "Cacelar edición",
"New comment" : "Comentario nuevo",
"Write a comment …" : "Escribir un comentario …",
"Post comment" : "Publicar comentario",
"@ for mentions, : for emoji, / for smart picker" : "@ para menciones, : para emoji, / para selector inteligente",
"Could not reload comments" : "No se pudieron recargar los comentarios",

@ -16,6 +16,7 @@ OC.L10N.register(
"Delete comment" : "Elimina commento",
"Cancel edit" : "Annulla modifica",
"New comment" : "Nuovo commento",
"Write a comment …" : "Scrivi un commento...",
"Post comment" : "Pubblica commento",
"@ for mentions, : for emoji, / for smart picker" : "@ per menzioni, : per emoji, / per selettore intelligente",
"Could not reload comments" : "Impossibile ricaricare i commenti",

@ -14,6 +14,7 @@
"Delete comment" : "Elimina commento",
"Cancel edit" : "Annulla modifica",
"New comment" : "Nuovo commento",
"Write a comment …" : "Scrivi un commento...",
"Post comment" : "Pubblica commento",
"@ for mentions, : for emoji, / for smart picker" : "@ per menzioni, : per emoji, / per selettore intelligente",
"Could not reload comments" : "Impossibile ricaricare i commenti",

@ -15,6 +15,8 @@ OC.L10N.register(
"Edit comment" : "コメントを編集",
"Delete comment" : "コメントを削除",
"Cancel edit" : "編集をキャンセル",
"New comment" : "新しいコメント",
"Write a comment …" : "コメントを書く...",
"Post comment" : "コメントを投稿",
"@ for mentions, : for emoji, / for smart picker" : "メンションには@、絵文字には:、スマートピッカーには/",
"Could not reload comments" : "コメントをリロードできませんでした",

@ -13,6 +13,8 @@
"Edit comment" : "コメントを編集",
"Delete comment" : "コメントを削除",
"Cancel edit" : "編集をキャンセル",
"New comment" : "新しいコメント",
"Write a comment …" : "コメントを書く...",
"Post comment" : "コメントを投稿",
"@ for mentions, : for emoji, / for smart picker" : "メンションには@、絵文字には:、スマートピッカーには/",
"Could not reload comments" : "コメントをリロードできませんでした",

@ -9,13 +9,28 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%2$s에 %1$s 님이 댓글 남김",
"{author} commented on {file}" : "{author} 님이 {file}에 댓글 남김",
"<strong>Comments</strong> for files" : "파일의 <strong>댓글</strong>",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "삭제된 사용자가 남긴 “{file}”의 댓글에서 나를 언급함",
"{user} mentioned you in a comment on \"{file}\"" : "{user} 님이 “{file}”에 남긴 댓글에서 나를 언급함",
"Files app plugin to add comments to files" : "파일에 댓글을 남기는 파일 앱 플러그인",
"Edit comment" : "댓글 편집",
"Delete comment" : "댓글 삭제",
"Cancel edit" : "편집 취소",
"New comment" : "새로운 댓글",
"Write a comment …" : "댓글 쓰기 ...",
"Post comment" : "댓글 게시",
"@ for mentions, : for emoji, / for smart picker" : "@을 입력해 언급, :을 입력해 이모지 추가, /을 입력해 스마트 피커를 사용하십시오.",
"Could not reload comments" : "댓글을 다시 불러올 수 없음",
"No comments yet, start the conversation!" : "아직 댓글이 없습니다. 대화를 시작하십시오!",
"No more messages" : "메시지 더 이상 없음",
"Retry" : "다시 시도",
"Failed to mark comments as read" : "댓글을 읽음 표시할 수 없음",
"Unable to load the comments list" : "댓글 목록을 불러올 수 없음",
"_1 new comment_::_{unread} new comments_" : ["새 댓글 {unread}개"],
"Comment" : "설명",
"An error occurred while trying to edit the comment" : "댓글을 편집하는 중 오류 발생",
"Comment deleted" : "댓글이 삭제됨",
"An error occurred while trying to delete the comment" : "댓글을 삭제하는 중 오류 발생",
"An error occurred while trying to create the comment" : "댓글을 작성하는 중 오류 발생",
"_%n unread comment_::_%n unread comments_" : ["읽지 않은 댓글 %n개"]
},
"nplurals=1; plural=0;");

@ -7,13 +7,28 @@
"%1$s commented on %2$s" : "%2$s에 %1$s 님이 댓글 남김",
"{author} commented on {file}" : "{author} 님이 {file}에 댓글 남김",
"<strong>Comments</strong> for files" : "파일의 <strong>댓글</strong>",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "삭제된 사용자가 남긴 “{file}”의 댓글에서 나를 언급함",
"{user} mentioned you in a comment on \"{file}\"" : "{user} 님이 “{file}”에 남긴 댓글에서 나를 언급함",
"Files app plugin to add comments to files" : "파일에 댓글을 남기는 파일 앱 플러그인",
"Edit comment" : "댓글 편집",
"Delete comment" : "댓글 삭제",
"Cancel edit" : "편집 취소",
"New comment" : "새로운 댓글",
"Write a comment …" : "댓글 쓰기 ...",
"Post comment" : "댓글 게시",
"@ for mentions, : for emoji, / for smart picker" : "@을 입력해 언급, :을 입력해 이모지 추가, /을 입력해 스마트 피커를 사용하십시오.",
"Could not reload comments" : "댓글을 다시 불러올 수 없음",
"No comments yet, start the conversation!" : "아직 댓글이 없습니다. 대화를 시작하십시오!",
"No more messages" : "메시지 더 이상 없음",
"Retry" : "다시 시도",
"Failed to mark comments as read" : "댓글을 읽음 표시할 수 없음",
"Unable to load the comments list" : "댓글 목록을 불러올 수 없음",
"_1 new comment_::_{unread} new comments_" : ["새 댓글 {unread}개"],
"Comment" : "설명",
"An error occurred while trying to edit the comment" : "댓글을 편집하는 중 오류 발생",
"Comment deleted" : "댓글이 삭제됨",
"An error occurred while trying to delete the comment" : "댓글을 삭제하는 중 오류 발생",
"An error occurred while trying to create the comment" : "댓글을 작성하는 중 오류 발생",
"_%n unread comment_::_%n unread comments_" : ["읽지 않은 댓글 %n개"]
},"pluralForm" :"nplurals=1; plural=0;"
}

@ -15,6 +15,8 @@ OC.L10N.register(
"Edit comment" : "Измени коментар",
"Delete comment" : "Обриши коментар",
"Cancel edit" : "Поништи измену",
"New comment" : "Нови коментар",
"Write a comment …" : "Напишите коментар…",
"Post comment" : "Објави коментар",
"@ for mentions, : for emoji, / for smart picker" : "@ за помињања, : за емођи, / за паметни бирач",
"Could not reload comments" : "Коментари не могу поново да се учитају",

@ -13,6 +13,8 @@
"Edit comment" : "Измени коментар",
"Delete comment" : "Обриши коментар",
"Cancel edit" : "Поништи измену",
"New comment" : "Нови коментар",
"Write a comment …" : "Напишите коментар…",
"Post comment" : "Објави коментар",
"@ for mentions, : for emoji, / for smart picker" : "@ за помињања, : за емођи, / за паметни бирач",
"Could not reload comments" : "Коментари не могу поново да се учитају",

@ -15,7 +15,8 @@ OC.L10N.register(
"Edit comment" : "Yorumu düzenle",
"Delete comment" : "Yorumu sil",
"Cancel edit" : "Düzenlemeyi iptal et",
"New comment" : "Yorum kle",
"New comment" : "Yorum ekle",
"Write a comment …" : "Bir yorum yazın…",
"Post comment" : "Yorum gönder",
"@ for mentions, : for emoji, / for smart picker" : "Anmalar için @, emojiler için :, akıllı seçici için /",
"Could not reload comments" : "Yorumlar yeniden yüklenemedi",

@ -13,7 +13,8 @@
"Edit comment" : "Yorumu düzenle",
"Delete comment" : "Yorumu sil",
"Cancel edit" : "Düzenlemeyi iptal et",
"New comment" : "Yorum kle",
"New comment" : "Yorum ekle",
"Write a comment …" : "Bir yorum yazın…",
"Post comment" : "Yorum gönder",
"@ for mentions, : for emoji, / for smart picker" : "Anmalar için @, emojiler için :, akıllı seçici için /",
"Could not reload comments" : "Yorumlar yeniden yüklenemedi",

@ -15,6 +15,8 @@ OC.L10N.register(
"Edit comment" : "Редагувати коментар",
"Delete comment" : "Вилучити коментар",
"Cancel edit" : "Скасувати редагування",
"New comment" : "Новий коментар",
"Write a comment …" : "Додати коментар ...",
"Post comment" : "Опублікувати коментар",
"@ for mentions, : for emoji, / for smart picker" : "@ for згадування, : для емоційок, / для асистента з вибору",
"Could not reload comments" : "Не вдалося перезавантажити коментарі",

@ -13,6 +13,8 @@
"Edit comment" : "Редагувати коментар",
"Delete comment" : "Вилучити коментар",
"Cancel edit" : "Скасувати редагування",
"New comment" : "Новий коментар",
"Write a comment …" : "Додати коментар ...",
"Post comment" : "Опублікувати коментар",
"@ for mentions, : for emoji, / for smart picker" : "@ for згадування, : для емоційок, / для асистента з вибору",
"Could not reload comments" : "Не вдалося перезавантажити коментарі",

@ -15,6 +15,8 @@ OC.L10N.register(
"Edit comment" : "編輯留言",
"Delete comment" : "刪除留言",
"Cancel edit" : "取消編輯",
"New comment" : "新留言",
"Write a comment …" : "編寫留言……",
"Post comment" : "張貼留言",
"@ for mentions, : for emoji, / for smart picker" : "@ 表示提及、: 表示表情符號、/ 表示智慧型選取程式",
"Could not reload comments" : "無法重新載入留言",

@ -13,6 +13,8 @@
"Edit comment" : "編輯留言",
"Delete comment" : "刪除留言",
"Cancel edit" : "取消編輯",
"New comment" : "新留言",
"Write a comment …" : "編寫留言……",
"Post comment" : "張貼留言",
"@ for mentions, : for emoji, / for smart picker" : "@ 表示提及、: 表示表情符號、/ 表示智慧型選取程式",
"Could not reload comments" : "無法重新載入留言",

@ -26,7 +26,7 @@ namespace OCA\Comments\Controller;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\IgnoreOpenAPI;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\Comments\IComment;
@ -41,7 +41,7 @@ use OCP\Notification\IManager;
/**
* @package OCA\Comments\Controller
*/
#[IgnoreOpenAPI]
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class NotificationsController extends Controller {
public function __construct(
string $appName,

@ -30,6 +30,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\IRootFolder;
/** @template-implements IEventListener<CommentsEntityEvent> */
class CommentsEntityEventListener implements IEventListener {
public function __construct(
private IRootFolder $rootFolder,

@ -33,6 +33,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Util;
/** @template-implements IEventListener<LoadAdditionalScriptsEvent> */
class LoadAdditionalScripts implements IEventListener {
public function handle(Event $event): void {
if (!($event instanceof LoadAdditionalScriptsEvent)) {

@ -35,6 +35,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Util;
/** @template-implements IEventListener<LoadSidebar> */
class LoadSidebarScripts implements IEventListener {
public function __construct(
private ICommentsManager $commentsManager,

@ -1,9 +1,9 @@
OC.L10N.register(
"contactsinteraction",
{
"Recently contacted" : "Нещодавно спілкувався",
"Recently contacted" : "Нещодавно спілкувалися",
"Contacts Interaction" : "Взаємодія з контактами",
"Manages interaction between users and contacts" : "Керує взаємодією між користувачами та контактами",
"Collect data about user and contacts interactions and provide an address book for the data" : "Збирайте дані про взаємодію користувачів і контактів і створюйте адресну книгу для цих даних"
"Collect data about user and contacts interactions and provide an address book for the data" : "Збирайте дані про взаємодію користувачів і контактів та створюйте адресну книгу на основі цих даних"
},
"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);");

@ -1,7 +1,7 @@
{ "translations": {
"Recently contacted" : "Нещодавно спілкувався",
"Recently contacted" : "Нещодавно спілкувалися",
"Contacts Interaction" : "Взаємодія з контактами",
"Manages interaction between users and contacts" : "Керує взаємодією між користувачами та контактами",
"Collect data about user and contacts interactions and provide an address book for the data" : "Збирайте дані про взаємодію користувачів і контактів і створюйте адресну книгу для цих даних"
"Collect data about user and contacts interactions and provide an address book for the data" : "Збирайте дані про взаємодію користувачів і контактів та створюйте адресну книгу на основі цих даних"
},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"
}

@ -40,6 +40,7 @@ use Psr\Log\LoggerInterface;
use Sabre\VObject\Component\VCard;
use Sabre\VObject\UUIDUtil;
/** @template-implements IEventListener<ContactInteractedWithEvent> */
class ContactInteractionListener implements IEventListener {
use TTransactional;
@ -74,7 +75,7 @@ class ContactInteractionListener implements IEventListener {
$uid = $event->getUid();
$email = $event->getEmail();
$federatedCloudId = $event->getFederatedCloudId();
$existingContact = $this->cardSearchDao->findExisting(
$event->getActor(),
$uid,

@ -3,6 +3,8 @@ OC.L10N.register(
{
"Dashboard" : "Instrumentpanel",
"Dashboard app" : "Instrumentpanel app",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an overview of your upcoming appointments, urgent emails, chat messages, incoming tickets, latest tweets and much more! Users can add the widgets they like and change the background to their liking." : "Start dagen din informert\n\nNextcloud-kontrollpanel er ditt utgangspunkt for dagen, og gir deg en oversikt over dine kommende avtaler, presserende e-poster, chatmeldinger, innkommende billetter, siste tvitringer og mye mer! Brukere kan legge til widgetene de liker og endre bakgrunnen etter eget ønske.",
"\"{title} icon\"" : "\"{title} ikon\"",
"Customize" : "Tilpass",
"Edit widgets" : "Rediger widgets",
"Get more widgets from the App Store" : "Få flere widgets fra app-butikken",

@ -1,6 +1,8 @@
{ "translations": {
"Dashboard" : "Instrumentpanel",
"Dashboard app" : "Instrumentpanel app",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an overview of your upcoming appointments, urgent emails, chat messages, incoming tickets, latest tweets and much more! Users can add the widgets they like and change the background to their liking." : "Start dagen din informert\n\nNextcloud-kontrollpanel er ditt utgangspunkt for dagen, og gir deg en oversikt over dine kommende avtaler, presserende e-poster, chatmeldinger, innkommende billetter, siste tvitringer og mye mer! Brukere kan legge til widgetene de liker og endre bakgrunnen etter eget ønske.",
"\"{title} icon\"" : "\"{title} ikon\"",
"Customize" : "Tilpass",
"Edit widgets" : "Rediger widgets",
"Get more widgets from the App Store" : "Få flere widgets fra app-butikken",

@ -30,23 +30,20 @@ declare(strict_types=1);
*/
namespace OCA\Dashboard\Controller;
use OCA\Files\Event\LoadSidebar;
use OCA\Viewer\Event\LoadViewer;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\IgnoreOpenAPI;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Dashboard\IManager;
use OCP\Dashboard\IWidget;
use OCP\Dashboard\RegisterWidgetEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
#[IgnoreOpenAPI]
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class DashboardController extends Controller {
/** @var IInitialState */
@ -91,13 +88,6 @@ class DashboardController extends Controller {
\OCP\Util::addStyle('dashboard', 'dashboard');
\OCP\Util::addScript('dashboard', 'main', 'theming');
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
if (class_exists(LoadViewer::class)) {
$this->eventDispatcher->dispatchTyped(new LoadViewer());
}
$this->eventDispatcher->dispatchTyped(new RegisterWidgetEvent($this->dashboardManager));
$systemDefault = $this->config->getAppValue('dashboard', 'layout', 'recommendations,spreed,mail,calendar');
$userLayout = explode(',', $this->config->getUserValue($this->userId, 'dashboard', 'layout', $systemDefault));
$widgets = array_map(function (IWidget $widget) {

@ -74,7 +74,8 @@
:checked="isStatusActive(status)"
@input="updateStatusCheckbox(status, $event.target.checked)">
<label :for="'status-checkbox-' + status">
<span :class="statusInfo[status].icon" aria-hidden="true" />
<NcUserStatusIcon v-if="status === 'status'" status="online" aria-hidden="true" />
<span v-else :class="statusInfo[status].icon" aria-hidden="true" />
{{ statusInfo[status].text }}
</label>
</li>
@ -124,6 +125,7 @@ import axios from '@nextcloud/axios'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import Draggable from 'vuedraggable'
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
import NcUserStatusIcon from '@nextcloud/vue/dist/Components/NcUserStatusIcon.js'
import Pencil from 'vue-material-design-icons/Pencil.vue'
import Vue from 'vue'
@ -140,7 +142,6 @@ const statusInfo = {
},
status: {
text: t('dashboard', 'Status'),
icon: 'icon-user-status-online',
},
}
@ -152,6 +153,7 @@ export default {
Draggable,
NcModal,
Pencil,
NcUserStatusIcon,
},
mixins: [
isMobile,

@ -33,13 +33,6 @@ Vue.directive('Tooltip', VTooltip)
Vue.prototype.t = t
// FIXME workaround to make the sidebar work
if (!window.OCA.Files) {
window.OCA.Files = {}
}
Object.assign(window.OCA.Files, { App: { fileList: { filesClient: OC.Files.getClient() } } }, window.OCA.Files)
const Dashboard = Vue.extend(DashboardApp)
const Instance = new Dashboard({}).$mount('#app-content-vue')

@ -73,7 +73,7 @@ $linkCheckPlugin = new \OCA\DAV\Files\Sharing\PublicLinkCheckPlugin();
$filesDropPlugin = new \OCA\DAV\Files\Sharing\FilesDropPlugin();
$server = $serverFactory->createServer($baseuri, $requestUri, $authPlugin, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin, $filesDropPlugin) {
$isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
$isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? ''));
/** @var \OCA\FederatedFileSharing\FederatedShareProvider $shareProvider */
$federatedShareProvider = \OC::$server->query(\OCA\FederatedFileSharing\FederatedShareProvider::class);
if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && !$isAjax) {

@ -96,7 +96,7 @@ preg_match('/(^files\/\w+)/i', substr($requestUri, strlen($baseuri)), $match);
$baseuri = $baseuri . $match[0];
$server = $serverFactory->createServer($baseuri, $requestUri, $authPlugin, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin, $filesDropPlugin) {
$isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
$isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? ''));
$federatedShareProvider = \OCP\Server::get(FederatedShareProvider::class);
if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && !$isAjax) {
// this is what is thrown when trying to access a non-existing share

@ -1 +1 @@
<svg width="16" height="16" version="1.1" viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1c-0.5 0-1 0.5-1 1v2c0 0.5 0.5 1 1 1s1-0.5 1-1v-2c0-0.5-0.5-1-1-1zm8 0c-0.5 0-1 0.5-1 1v2c0 0.5 0.5 1 1 1s1-0.5 1-1v-2c0-0.5-0.5-1-1-1zm-6.5 2v1c0 0.831-0.5 1.5-1.5 1.5s-1.5-0.5-1.5-1.5v-0.9375c-0.8841 0.227-1.5 1.0247-1.5 1.9375v8c0 1.108 0.892 2 2 2h10c1.108 0 2-0.892 2-2v-8c0-0.9128-0.61588-1.7105-1.5-1.9375v0.9375c0 0.831-0.5 1.5-1.5 1.5s-1.5-0.5-1.5-1.5v-1zm7.5 5v5h-10v-5z"/></svg>
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1c-0.5 0-1 0.5-1 1v2c0 0.5 0.5 1 1 1s1-0.5 1-1v-2c0-0.5-0.5-1-1-1zm8 0c-0.5 0-1 0.5-1 1v2c0 0.5 0.5 1 1 1s1-0.5 1-1v-2c0-0.5-0.5-1-1-1zm-6.5 2v1c0 0.831-0.5 1.5-1.5 1.5s-1.5-0.5-1.5-1.5v-0.9375c-0.8841 0.227-1.5 1.0247-1.5 1.9375v8c0 1.108 0.892 2 2 2h10c1.108 0 2-0.892 2-2v-8c0-0.9128-0.61588-1.7105-1.5-1.9375v0.9375c0 0.831-0.5 1.5-1.5 1.5s-1.5-0.5-1.5-1.5v-1zm7.5 5v5h-10v-5z"/></svg>

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

@ -178,8 +178,8 @@ OC.L10N.register(
"Friday" : "Viernes",
"Saturday" : "Sábado",
"Sunday" : "Domingo",
"Pick a start time for {dayName}" : "Elige una hora de inicio para {dayName}",
"Pick a end time for {dayName}" : "Elige una hora de fin para {dayName}",
"Pick a start time for {dayName}" : "Elija una hora de inicio para {dayName}",
"Pick a end time for {dayName}" : "Elija una hora fin para {dayName}",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "Cambiar automáticamente el estado del usuario a \"No molestar\" cuando no esté disponible para silenciar todas las notificaciones.",
"Failed to load availability" : "No se ha podido cargar la disponibilidad",
"Saved availability" : "Disponibilidad guardada",
@ -194,12 +194,12 @@ OC.L10N.register(
"Birthday calendars will be generated by a background job." : "Los calendarios de cumpleaños se generarán mediante un trabajo en segundo plano.",
"Hence they will not be available immediately after enabling but will show up after some time." : "Por ello, no estarán disponibles inmediatamente tras activarlos, sino que aparecerán después de cierto tiempo.",
"Send notifications for events" : "Enviar notificaciones de los eventos",
"Notifications are sent via background jobs, so these must occur often enough." : "Las notificaciones son enviadas a través de trabajos en segundo plano, por lo que estos deben ocurrir con la suficiente frecuencia.",
"Notifications are sent via background jobs, so these must occur often enough." : "Las notificaciones son enviadas a través de trabajos en segundo plano, por lo que estos deben ocurrir con suficiente frecuencia.",
"Send reminder notifications to calendar sharees as well" : "Enviar recordatorio también a los usuarios con los que se comparte el calendario",
"Reminders are always sent to organizers and attendees." : "Los recordatorios siempre se envía a los organizadores y asistentes.",
"Reminders are always sent to organizers and attendees." : "Los recordatorios siempre se envían a los organizadores y asistentes.",
"Enable notifications for events via push" : "Activar notificaciones push para eventos",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Instala también la {calendarappstoreopen}app de Calendario{linkclose} o {calendardocopen}conecta tu escritorio y móvil para sincronizar ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Por favor, asegúrate de configurar correctamente {emailopen}el servidor web{linkclose}",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Instale también la {calendarappstoreopen}app de Calendario{linkclose} o {calendardocopen}conecte su escritorio y móvil para sincronizar ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Por favor, asegúrese de configurar correctamente {emailopen}el servidor web{linkclose}",
"There was an error updating your attendance status." : "Ha habido un error al actualizar tu estado de asistencia.",
"Please contact the organizer directly." : "Por favor, contacta directamente con el organizador.",
"Are you accepting the invitation?" : "¿Aceptas la invitación?",

@ -176,8 +176,8 @@
"Friday" : "Viernes",
"Saturday" : "Sábado",
"Sunday" : "Domingo",
"Pick a start time for {dayName}" : "Elige una hora de inicio para {dayName}",
"Pick a end time for {dayName}" : "Elige una hora de fin para {dayName}",
"Pick a start time for {dayName}" : "Elija una hora de inicio para {dayName}",
"Pick a end time for {dayName}" : "Elija una hora fin para {dayName}",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "Cambiar automáticamente el estado del usuario a \"No molestar\" cuando no esté disponible para silenciar todas las notificaciones.",
"Failed to load availability" : "No se ha podido cargar la disponibilidad",
"Saved availability" : "Disponibilidad guardada",
@ -192,12 +192,12 @@
"Birthday calendars will be generated by a background job." : "Los calendarios de cumpleaños se generarán mediante un trabajo en segundo plano.",
"Hence they will not be available immediately after enabling but will show up after some time." : "Por ello, no estarán disponibles inmediatamente tras activarlos, sino que aparecerán después de cierto tiempo.",
"Send notifications for events" : "Enviar notificaciones de los eventos",
"Notifications are sent via background jobs, so these must occur often enough." : "Las notificaciones son enviadas a través de trabajos en segundo plano, por lo que estos deben ocurrir con la suficiente frecuencia.",
"Notifications are sent via background jobs, so these must occur often enough." : "Las notificaciones son enviadas a través de trabajos en segundo plano, por lo que estos deben ocurrir con suficiente frecuencia.",
"Send reminder notifications to calendar sharees as well" : "Enviar recordatorio también a los usuarios con los que se comparte el calendario",
"Reminders are always sent to organizers and attendees." : "Los recordatorios siempre se envía a los organizadores y asistentes.",
"Reminders are always sent to organizers and attendees." : "Los recordatorios siempre se envían a los organizadores y asistentes.",
"Enable notifications for events via push" : "Activar notificaciones push para eventos",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Instala también la {calendarappstoreopen}app de Calendario{linkclose} o {calendardocopen}conecta tu escritorio y móvil para sincronizar ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Por favor, asegúrate de configurar correctamente {emailopen}el servidor web{linkclose}",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Instale también la {calendarappstoreopen}app de Calendario{linkclose} o {calendardocopen}conecte su escritorio y móvil para sincronizar ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Por favor, asegúrese de configurar correctamente {emailopen}el servidor web{linkclose}",
"There was an error updating your attendance status." : "Ha habido un error al actualizar tu estado de asistencia.",
"Please contact the organizer directly." : "Por favor, contacta directamente con el organizador.",
"Are you accepting the invitation?" : "¿Aceptas la invitación?",

@ -113,8 +113,8 @@ OC.L10N.register(
"{actor} unshared address book {addressbook} from group {group}" : "{actor} ha eliminato la condivisone della rubrica {addressbook} con il gruppo {group}",
"{actor} created contact {card} in address book {addressbook}" : "{actor} ha creato il contatto {card} nella rubrica {addressbook}",
"You created contact {card} in address book {addressbook}" : "Hai creato il contatto {card} nella rubrica {addressbook}",
"{actor} deleted contact {card} from address book {addressbook}" : "{actor} ha cancellato il contatto {card} nella rubrica {addressbook}",
"You deleted contact {card} from address book {addressbook}" : "Hai cancellato il contatto {card} nella rubrica {addressbook}",
"{actor} deleted contact {card} from address book {addressbook}" : "{actor} ha eliminato il contatto {card} nella rubrica {addressbook}",
"You deleted contact {card} from address book {addressbook}" : "Hai eliminato il contatto {card} nella rubrica {addressbook}",
"{actor} updated contact {card} in address book {addressbook}" : "{actor} ha aggiornato il contatto {card} nella rubrica {addressbook}",
"You updated contact {card} in address book {addressbook}" : "Hai aggiornato il contatto {card} nella rubrica {addressbook}",
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "Un <strong>contatto</strong> o <strong>rubrica</strong> sono stati modificati ",
@ -123,16 +123,16 @@ OC.L10N.register(
"File is not updatable: %1$s" : "Il file non è aggiornabile: %1$s",
"Could not write to final file, canceled by hook" : "Impossibile scrivere nel file finale, annullato da hook",
"Could not write file contents" : "Impossibile scrivere il contenuto del file",
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes","%n bytes"],
"_%n byte_::_%n bytes_" : ["%n byte","%n byte","%n byte"],
"Error while copying file to target location (copied: %1$s, expected filesize: %2$s)" : "Errore durante la copia del file nella destinazione (copiato: %1$s, dimensione prevista del file: %2$s)",
"Expected filesize of %1$s but read (from Nextcloud client) and wrote (to Nextcloud storage) %2$s. Could either be a network problem on the sending side or a problem writing to the storage on the server side." : "Dimensione prevista del file %1$s, letto (dal client Nextcloud) e scritto (nell'archivio Nextcloud) %2$s. Potrebbe trattarsi di un problema di rete sul lato d'invio o di un problema di scrittura nell'archivio sul lato server.",
"Could not rename part file to final file, canceled by hook" : "Impossibile rinominare il file di parte in file finale, annullato da hook",
"Could not rename part file to final file" : "Impossibile rinominare il file di parte in file finale",
"Failed to check file size: %1$s" : "Verifica della dimensione del file non riuscito: %1$s",
"Could not open file" : "Impossibile aprire il file",
"Encryption not ready: %1$s" : "Crittografia non pronta: %1$s",
"Encryption not ready: %1$s" : "Cifratura non pronta: %1$s",
"Failed to open file: %1$s" : "Apertura del file non riuscito: %1$s",
"Failed to unlink: %1$s" : "Scollegamento fallito: %1$s",
"Failed to unlink: %1$s" : "Scollegamento non riuscito: %1$s",
"Invalid chunk name" : "Nome non valido per lo spezzone",
"Could not rename part file assembled from chunks" : "Non è possibile rinominare il file assemblato da più spezzoni",
"Failed to write file contents: %1$s" : "Scrittura del contenuto del file non riuscita: %1$s",

@ -111,8 +111,8 @@
"{actor} unshared address book {addressbook} from group {group}" : "{actor} ha eliminato la condivisone della rubrica {addressbook} con il gruppo {group}",
"{actor} created contact {card} in address book {addressbook}" : "{actor} ha creato il contatto {card} nella rubrica {addressbook}",
"You created contact {card} in address book {addressbook}" : "Hai creato il contatto {card} nella rubrica {addressbook}",
"{actor} deleted contact {card} from address book {addressbook}" : "{actor} ha cancellato il contatto {card} nella rubrica {addressbook}",
"You deleted contact {card} from address book {addressbook}" : "Hai cancellato il contatto {card} nella rubrica {addressbook}",
"{actor} deleted contact {card} from address book {addressbook}" : "{actor} ha eliminato il contatto {card} nella rubrica {addressbook}",
"You deleted contact {card} from address book {addressbook}" : "Hai eliminato il contatto {card} nella rubrica {addressbook}",
"{actor} updated contact {card} in address book {addressbook}" : "{actor} ha aggiornato il contatto {card} nella rubrica {addressbook}",
"You updated contact {card} in address book {addressbook}" : "Hai aggiornato il contatto {card} nella rubrica {addressbook}",
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "Un <strong>contatto</strong> o <strong>rubrica</strong> sono stati modificati ",
@ -121,16 +121,16 @@
"File is not updatable: %1$s" : "Il file non è aggiornabile: %1$s",
"Could not write to final file, canceled by hook" : "Impossibile scrivere nel file finale, annullato da hook",
"Could not write file contents" : "Impossibile scrivere il contenuto del file",
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes","%n bytes"],
"_%n byte_::_%n bytes_" : ["%n byte","%n byte","%n byte"],
"Error while copying file to target location (copied: %1$s, expected filesize: %2$s)" : "Errore durante la copia del file nella destinazione (copiato: %1$s, dimensione prevista del file: %2$s)",
"Expected filesize of %1$s but read (from Nextcloud client) and wrote (to Nextcloud storage) %2$s. Could either be a network problem on the sending side or a problem writing to the storage on the server side." : "Dimensione prevista del file %1$s, letto (dal client Nextcloud) e scritto (nell'archivio Nextcloud) %2$s. Potrebbe trattarsi di un problema di rete sul lato d'invio o di un problema di scrittura nell'archivio sul lato server.",
"Could not rename part file to final file, canceled by hook" : "Impossibile rinominare il file di parte in file finale, annullato da hook",
"Could not rename part file to final file" : "Impossibile rinominare il file di parte in file finale",
"Failed to check file size: %1$s" : "Verifica della dimensione del file non riuscito: %1$s",
"Could not open file" : "Impossibile aprire il file",
"Encryption not ready: %1$s" : "Crittografia non pronta: %1$s",
"Encryption not ready: %1$s" : "Cifratura non pronta: %1$s",
"Failed to open file: %1$s" : "Apertura del file non riuscito: %1$s",
"Failed to unlink: %1$s" : "Scollegamento fallito: %1$s",
"Failed to unlink: %1$s" : "Scollegamento non riuscito: %1$s",
"Invalid chunk name" : "Nome non valido per lo spezzone",
"Could not rename part file assembled from chunks" : "Non è possibile rinominare il file assemblato da più spezzoni",
"Failed to write file contents: %1$s" : "Scrittura del contenuto del file non riuscita: %1$s",

@ -73,8 +73,16 @@ OC.L10N.register(
"Where: %s" : "장소: %s",
"%1$s via %2$s" : "%1$s(%2$s 경유)",
"Cancelled: %1$s" : "취소됨: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\"이(가) 취소되었습니다",
"Re: %1$s" : "Re: %1$s",
"%1$s has accepted your invitation" : "%1$s이(가) 초대를 수락했습니다",
"%1$s has tentatively accepted your invitation" : "%1$s이(기) 초대를 잠정 수락했습니다",
"%1$s has declined your invitation" : "%1$s이(가) 초대를 거절했습니다",
"%1$s has responded to your invitation" : "%1$s이(가) 초대에 응답했습니다",
"Invitation updated: %1$s" : "초대 갱신됨: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s님이 일정 \"%2$s\"을(를) 갱신했습니다",
"Invitation: %1$s" : "초대: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s님이 나를 \"%2$s\"에 초대했습니다",
"Organizer:" : "주최자:",
"Attendees:" : "참석자:",
"Title:" : "제목:",
@ -110,6 +118,7 @@ OC.L10N.register(
"{actor} updated contact {card} in address book {addressbook}" : "{actor}님이 주소록 {addressbook}의 연락처 {card}을(를) 갱신함",
"You updated contact {card} in address book {addressbook}" : "주소록 {addressbook}의 연락처 {card}을(를) 갱신함",
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "<strong>연락처</strong> 또는 <strong>주소록</strong>이 변경됨",
"System address book which holds all accounts" : "시스템 주소록이 모든 계정 정보를 보유합니다",
"File is not updatable: %1$s" : "파일을 갱신할 수 없습니다: %1$s",
"Could not write to final file, canceled by hook" : "후크에 의해 취소되어 최종 파일에 쓸 수 없음",
"Could not write file contents" : "파일 내용을 쓸 수 없음",
@ -127,7 +136,7 @@ OC.L10N.register(
"Could not rename part file assembled from chunks" : "청크에서 조합 된 부분 파일의 이름을 바꿀 수 없음",
"Failed to write file contents: %1$s" : "파일 내용을 쓸 수 없음: %1$s",
"File not found: %1$s" : "파일을 찾을 수 없음: %1$s",
"System is in maintenance mode." : "시스템이 유지 관리 모드입니다.",
"System is in maintenance mode." : "시스템이 유지 보수 모드입니다.",
"Upgrade needed" : "업그레이드 필요",
"Your %s needs to be configured to use HTTPS in order to use CalDAV and CardDAV with iOS/macOS." : "iOS/macOS에서 CalDAV 및 CardDAV를 사용하려면 %s에서 HTTPS를 사용하도록 설정해야 합니다.",
"Configures a CalDAV account" : "CalDAV 계정 설정",
@ -138,12 +147,23 @@ OC.L10N.register(
"Completed on %s" : "%s에 완료됨",
"Due on %s by %s" : "%s일 %s에 만료됨",
"Due on %s" : "%s에 만료됨",
"DAV system address book" : "DAV 시스템 주소록",
"The DAV system address book sync has not run yet as your instance has more than 1000 users or because an error occurred. Please run it manually by calling \"occ dav:sync-system-addressbook\"." : "DAV 시스템 주소록 동기화가 아직 작동하지 않았습니다. 이는 인스턴스의 사용자가 1000명을 초과하거나 오류가 발생했기 때문입니다. occ dav:sync-system-addressbook 명령어를 통해 수동으로 이를 수행하십시오.",
"Migrated calendar (%1$s)" : "가져온 달력 (%1$s)",
"Calendars including events, details and attendees" : "일정, 세부 정보 및 참석자를 포함한 캘린더",
"Contacts and groups" : "연락처 및 그룹",
"WebDAV" : "WebDAV",
"WebDAV endpoint" : "WebDAV 종단점",
"First day" : "시작일",
"Last day (inclusive)" : "종료일 (이 날짜까지 포함됨)",
"Short absence status" : "부재 상태 개요",
"Long absence Message" : "부재 상태 상세 설명",
"Save" : "저장",
"Disable absence" : "부재 상태 비활성화",
"Absence saved" : "부재 상태 저장됨",
"Failed to save your absence settings" : "부재 상태 설정 저장 실패",
"Absence cleared" : "부재 상태 비워짐",
"Failed to clear your absence settings" : "부재 설정 비우기 실패",
"Time zone:" : "시간대:",
"to" : "에서",
"Delete slot" : "시간대 삭제",
@ -156,12 +176,16 @@ OC.L10N.register(
"Friday" : "금요일",
"Saturday" : "토요일",
"Sunday" : "일요일",
"Pick a start time for {dayName}" : "{dayName} 시작 시각을 지정하십시오",
"Pick a end time for {dayName}" : "{dayName} 종료 시각을 지정하십시오",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "다른 용무 중일 때 자동으로 사용자를 '방해 금지' 모드로 설정해 모든 알림을 음소거합니다.",
"Failed to load availability" : "가용성 불러오기 실패",
"Saved availability" : "가용성을 저장함",
"Failed to save availability" : "가용성 저장 실패",
"Availability" : "가용성",
"Failed to load availability" : "시간 조율 설정 불러오기 실패",
"Saved availability" : "시간 조율 설정 저장함",
"Failed to save availability" : "시간 조율 설정 저장 실패",
"Availability" : "시간 조율",
"If you configure your working hours, other users will see when you are out of office when they book a meeting." : "업무 시간을 설정하면, 회의를 예약할 때 다른 사용자가 부재 중 시간을 볼 수 있습니다.",
"Absence" : "부재",
"Configure your next absence period." : "다음 부재 기간을 설정하십시오.",
"Calendar server" : "달력 서버",
"Send invitations to attendees" : "참석자에게 초대장 보내기",
"Automatically generate a birthday calendar" : "자동으로 생일 달력 생성",

@ -71,8 +71,16 @@
"Where: %s" : "장소: %s",
"%1$s via %2$s" : "%1$s(%2$s 경유)",
"Cancelled: %1$s" : "취소됨: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\"이(가) 취소되었습니다",
"Re: %1$s" : "Re: %1$s",
"%1$s has accepted your invitation" : "%1$s이(가) 초대를 수락했습니다",
"%1$s has tentatively accepted your invitation" : "%1$s이(기) 초대를 잠정 수락했습니다",
"%1$s has declined your invitation" : "%1$s이(가) 초대를 거절했습니다",
"%1$s has responded to your invitation" : "%1$s이(가) 초대에 응답했습니다",
"Invitation updated: %1$s" : "초대 갱신됨: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s님이 일정 \"%2$s\"을(를) 갱신했습니다",
"Invitation: %1$s" : "초대: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s님이 나를 \"%2$s\"에 초대했습니다",
"Organizer:" : "주최자:",
"Attendees:" : "참석자:",
"Title:" : "제목:",
@ -108,6 +116,7 @@
"{actor} updated contact {card} in address book {addressbook}" : "{actor}님이 주소록 {addressbook}의 연락처 {card}을(를) 갱신함",
"You updated contact {card} in address book {addressbook}" : "주소록 {addressbook}의 연락처 {card}을(를) 갱신함",
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "<strong>연락처</strong> 또는 <strong>주소록</strong>이 변경됨",
"System address book which holds all accounts" : "시스템 주소록이 모든 계정 정보를 보유합니다",
"File is not updatable: %1$s" : "파일을 갱신할 수 없습니다: %1$s",
"Could not write to final file, canceled by hook" : "후크에 의해 취소되어 최종 파일에 쓸 수 없음",
"Could not write file contents" : "파일 내용을 쓸 수 없음",
@ -125,7 +134,7 @@
"Could not rename part file assembled from chunks" : "청크에서 조합 된 부분 파일의 이름을 바꿀 수 없음",
"Failed to write file contents: %1$s" : "파일 내용을 쓸 수 없음: %1$s",
"File not found: %1$s" : "파일을 찾을 수 없음: %1$s",
"System is in maintenance mode." : "시스템이 유지 관리 모드입니다.",
"System is in maintenance mode." : "시스템이 유지 보수 모드입니다.",
"Upgrade needed" : "업그레이드 필요",
"Your %s needs to be configured to use HTTPS in order to use CalDAV and CardDAV with iOS/macOS." : "iOS/macOS에서 CalDAV 및 CardDAV를 사용하려면 %s에서 HTTPS를 사용하도록 설정해야 합니다.",
"Configures a CalDAV account" : "CalDAV 계정 설정",
@ -136,12 +145,23 @@
"Completed on %s" : "%s에 완료됨",
"Due on %s by %s" : "%s일 %s에 만료됨",
"Due on %s" : "%s에 만료됨",
"DAV system address book" : "DAV 시스템 주소록",
"The DAV system address book sync has not run yet as your instance has more than 1000 users or because an error occurred. Please run it manually by calling \"occ dav:sync-system-addressbook\"." : "DAV 시스템 주소록 동기화가 아직 작동하지 않았습니다. 이는 인스턴스의 사용자가 1000명을 초과하거나 오류가 발생했기 때문입니다. occ dav:sync-system-addressbook 명령어를 통해 수동으로 이를 수행하십시오.",
"Migrated calendar (%1$s)" : "가져온 달력 (%1$s)",
"Calendars including events, details and attendees" : "일정, 세부 정보 및 참석자를 포함한 캘린더",
"Contacts and groups" : "연락처 및 그룹",
"WebDAV" : "WebDAV",
"WebDAV endpoint" : "WebDAV 종단점",
"First day" : "시작일",
"Last day (inclusive)" : "종료일 (이 날짜까지 포함됨)",
"Short absence status" : "부재 상태 개요",
"Long absence Message" : "부재 상태 상세 설명",
"Save" : "저장",
"Disable absence" : "부재 상태 비활성화",
"Absence saved" : "부재 상태 저장됨",
"Failed to save your absence settings" : "부재 상태 설정 저장 실패",
"Absence cleared" : "부재 상태 비워짐",
"Failed to clear your absence settings" : "부재 설정 비우기 실패",
"Time zone:" : "시간대:",
"to" : "에서",
"Delete slot" : "시간대 삭제",
@ -154,12 +174,16 @@
"Friday" : "금요일",
"Saturday" : "토요일",
"Sunday" : "일요일",
"Pick a start time for {dayName}" : "{dayName} 시작 시각을 지정하십시오",
"Pick a end time for {dayName}" : "{dayName} 종료 시각을 지정하십시오",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "다른 용무 중일 때 자동으로 사용자를 '방해 금지' 모드로 설정해 모든 알림을 음소거합니다.",
"Failed to load availability" : "가용성 불러오기 실패",
"Saved availability" : "가용성을 저장함",
"Failed to save availability" : "가용성 저장 실패",
"Availability" : "가용성",
"Failed to load availability" : "시간 조율 설정 불러오기 실패",
"Saved availability" : "시간 조율 설정 저장함",
"Failed to save availability" : "시간 조율 설정 저장 실패",
"Availability" : "시간 조율",
"If you configure your working hours, other users will see when you are out of office when they book a meeting." : "업무 시간을 설정하면, 회의를 예약할 때 다른 사용자가 부재 중 시간을 볼 수 있습니다.",
"Absence" : "부재",
"Configure your next absence period." : "다음 부재 기간을 설정하십시오.",
"Calendar server" : "달력 서버",
"Send invitations to attendees" : "참석자에게 초대장 보내기",
"Automatically generate a birthday calendar" : "자동으로 생일 달력 생성",

@ -146,6 +146,7 @@ OC.L10N.register(
"Contacts and groups" : "Kontakter og grupper",
"WebDAV" : "WebDAV",
"WebDAV endpoint" : "WebDAV endepunkt",
"First day" : "Første dag",
"Save" : "Lagre",
"Time zone:" : "Tidssone:",
"to" : "til",

@ -144,6 +144,7 @@
"Contacts and groups" : "Kontakter og grupper",
"WebDAV" : "WebDAV",
"WebDAV endpoint" : "WebDAV endepunkt",
"First day" : "Første dag",
"Save" : "Lagre",
"Time zone:" : "Tidssone:",
"to" : "til",

@ -162,7 +162,9 @@ OC.L10N.register(
"Long absence Message" : "长期离开信息",
"Save" : "保存",
"Disable absence" : "禁用离开状态",
"Absence saved" : "缺席已保存",
"Failed to save your absence settings" : "未能保存您的离开状态设置",
"Absence cleared" : "缺席已清除",
"Failed to clear your absence settings" : "未能清除您的离开状态设置",
"Time zone:" : "时区:",
"to" : "到",

@ -160,7 +160,9 @@
"Long absence Message" : "长期离开信息",
"Save" : "保存",
"Disable absence" : "禁用离开状态",
"Absence saved" : "缺席已保存",
"Failed to save your absence settings" : "未能保存您的离开状态设置",
"Absence cleared" : "缺席已清除",
"Failed to clear your absence settings" : "未能清除您的离开状态设置",
"Time zone:" : "时区:",
"to" : "到",

@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2018 Georg Ehrke <oc.list@georgehrke.com>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Côme Chilliet <come.chilliet@nextcloud.com>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Citharel <nextcloud@tcit.fr>
@ -34,42 +35,18 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\BackgroundJob\Job;
use OCP\IConfig;
use OCP\ILogger;
use Psr\Log\LoggerInterface;
use Sabre\VObject\DateTimeParser;
use Sabre\VObject\InvalidDataException;
class RefreshWebcalJob extends Job {
/**
* @var RefreshWebcalService
*/
private $refreshWebcalService;
/**
* @var IConfig
*/
private $config;
/** @var ILogger */
private $logger;
/** @var ITimeFactory */
private $timeFactory;
/**
* RefreshWebcalJob constructor.
*
* @param RefreshWebcalService $refreshWebcalService
* @param IConfig $config
* @param ILogger $logger
* @param ITimeFactory $timeFactory
*/
public function __construct(RefreshWebcalService $refreshWebcalService, IConfig $config, ILogger $logger, ITimeFactory $timeFactory) {
public function __construct(
private RefreshWebcalService $refreshWebcalService,
private IConfig $config,
private LoggerInterface $logger,
ITimeFactory $timeFactory,
) {
parent::__construct($timeFactory);
$this->refreshWebcalService = $refreshWebcalService;
$this->config = $config;
$this->logger = $logger;
$this->timeFactory = $timeFactory;
}
/**
@ -77,7 +54,7 @@ class RefreshWebcalJob extends Job {
*
* @inheritdoc
*/
public function execute(IJobList $jobList, ILogger $logger = null) {
public function start(IJobList $jobList): void {
$subscription = $this->refreshWebcalService->getSubscription($this->argument['principaluri'], $this->argument['uri']);
if (!$subscription) {
return;
@ -95,17 +72,19 @@ class RefreshWebcalJob extends Job {
/** @var DateInterval $dateInterval */
$dateInterval = DateTimeParser::parseDuration($refreshRate);
} catch (InvalidDataException $ex) {
$this->logger->logException($ex);
$this->logger->warning("Subscription $subscriptionId could not be refreshed, refreshrate in database is invalid");
$this->logger->error(
"Subscription $subscriptionId could not be refreshed, refreshrate in database is invalid",
['exception' => $ex]
);
return;
}
$interval = $this->getIntervalFromDateInterval($dateInterval);
if (($this->timeFactory->getTime() - $this->lastRun) <= $interval) {
if (($this->time->getTime() - $this->lastRun) <= $interval) {
return;
}
parent::execute($jobList, $logger);
parent::start($jobList);
}
/**

@ -77,12 +77,13 @@ class StatusService {
return;
}
$userStatusTimestamp = null;
$currentStatus = null;
try {
$currentStatus = $this->userStatusService->findByUserId($userId);
$userStatusTimestamp = $currentStatus->getIsUserDefined() ? $currentStatus->getStatusTimestamp() : null;
// Was the status set by anything other than the calendar automation?
$userStatusTimestamp = $currentStatus->getIsUserDefined() && $currentStatus->getMessageId() !== IUserStatus::MESSAGE_CALENDAR_BUSY ? $currentStatus->getStatusTimestamp() : null;
} catch (DoesNotExistException) {
$userStatusTimestamp = null;
$currentStatus = null;
}
if($currentStatus !== null && $currentStatus->getMessageId() === IUserStatus::MESSAGE_CALL
@ -94,21 +95,23 @@ class StatusService {
}
// Filter events to see if we have any that apply to the calendar status
$applicableEvents = array_filter($calendarEvents, function (array $calendarEvent) use ($userStatusTimestamp) {
$applicableEvents = array_filter($calendarEvents, static function (array $calendarEvent) use ($userStatusTimestamp): bool {
if (empty($calendarEvent['objects'])) {
return false;
}
$component = $calendarEvent['objects'][0];
if(isset($component['X-NEXTCLOUD-OUT-OF-OFFICE'])) {
if (isset($component['X-NEXTCLOUD-OUT-OF-OFFICE'])) {
return false;
}
if(isset($component['DTSTART']) && $userStatusTimestamp !== null) {
if (isset($component['DTSTART']) && $userStatusTimestamp !== null) {
/** @var DateTimeImmutable $dateTime */
$dateTime = $component['DTSTART'][0];
$timestamp = $dateTime->getTimestamp();
if($userStatusTimestamp > $timestamp) {
if($dateTime instanceof DateTimeImmutable && $userStatusTimestamp > $dateTime->getTimestamp()) {
return false;
}
}
// Ignore events that are transparent
if(isset($component['TRANSP']) && strcasecmp($component['TRANSP'][0], 'TRANSPARENT') === 0) {
if (isset($component['TRANSP']) && strcasecmp($component['TRANSP'][0], 'TRANSPARENT') === 0) {
return false;
}
return true;
@ -120,19 +123,21 @@ class StatusService {
return;
}
// One event that fulfills all status conditions is enough
// 1. Not an OOO event
// 2. Current user status was not set after the start of this event
// 3. Event is not set to be transparent
$count = count($applicableEvents);
$this->logger->debug("Found $count applicable event(s), changing user status", ['user' => $userId]);
$this->userStatusService->setUserStatus(
$userId,
IUserStatus::AWAY,
IUserStatus::MESSAGE_CALENDAR_BUSY,
true
);
// Only update the status if it's neccesary otherwise we mess up the timestamp
if($currentStatus === null || $currentStatus->getMessageId() !== IUserStatus::MESSAGE_CALENDAR_BUSY) {
// One event that fulfills all status conditions is enough
// 1. Not an OOO event
// 2. Current user status (that is not a calendar status) was not set after the start of this event
// 3. Event is not set to be transparent
$count = count($applicableEvents);
$this->logger->debug("Found $count applicable event(s), changing user status", ['user' => $userId]);
$this->userStatusService->setUserStatus(
$userId,
IUserStatus::AWAY,
IUserStatus::MESSAGE_CALENDAR_BUSY,
true
);
}
}
private function getCalendarEvents(User $user): array {

@ -31,11 +31,15 @@ use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\Exception\NotImplemented;
use Sabre\DAVACL\ACLTrait;
use Sabre\DAVACL\IACL;
use function array_map;
use function implode;
use function preg_match;
class DeletedCalendarObjectsCollection implements ICalendarObjectContainer {
class DeletedCalendarObjectsCollection implements ICalendarObjectContainer, IACL {
use ACLTrait;
public const NAME = 'objects';
/** @var CalDavBackend */
@ -129,4 +133,23 @@ class DeletedCalendarObjectsCollection implements ICalendarObjectContainer {
[$calendarInfo['id'], 'ics'],
);
}
public function getOwner() {
return $this->principalInfo['uri'];
}
public function getACL(): array {
return [
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner(),
'protected' => true,
],
[
'privilege' => '{DAV:}unbind',
'principal' => '{DAV:}owner',
'protected' => true,
]
];
}
}

@ -79,6 +79,7 @@ class FilesPlugin extends ServerPlugin {
public const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
public const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
public const MOUNT_TYPE_PROPERTYNAME = '{http://nextcloud.org/ns}mount-type';
public const MOUNT_ROOT_PROPERTYNAME = '{http://nextcloud.org/ns}is-mount-root';
public const IS_ENCRYPTED_PROPERTYNAME = '{http://nextcloud.org/ns}is-encrypted';
public const METADATA_ETAG_PROPERTYNAME = '{http://nextcloud.org/ns}metadata_etag';
public const UPLOAD_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}upload_time';
@ -361,6 +362,16 @@ class FilesPlugin extends ServerPlugin {
return $node->getFileInfo()->getMountPoint()->getMountType();
});
/**
* This is a special property which is used to determine if a node
* is a mount root or not, e.g. a shared folder.
* If so, then the node can only be unshared and not deleted.
* @see https://github.com/nextcloud/server/blob/cc75294eb6b16b916a342e69998935f89222619d/lib/private/Files/View.php#L696-L698
*/
$propFind->handle(self::MOUNT_ROOT_PROPERTYNAME, function () use ($node) {
return $node->getNode()->getInternalPath() === '' ? 'true' : 'false';
});
$propFind->handle(self::SHARE_NOTE, function () use ($node, $httpRequest): ?string {
$user = $this->userSession->getUser();
if ($user === null) {

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

Loading…
Cancel
Save