Compare commits

..

No commits in common. "main" and "helm-chart-12.5.0" have entirely different histories.

90 changed files with 1110 additions and 1326 deletions

View file

@ -1,5 +0,0 @@
<!--
- 🚨 SECURITY INFO
-
- Before sending a pull request that fixes a security issue please report it via our HackerOne page (https://hackerone.com/nextcloud) following our security policy (https://nextcloud.com/security/). This allows us to coordinate the fix and release without potentially exposing all Nextcloud servers and users in the meantime.
-->

View file

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: Check spelling - name: Check spelling
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2 uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2
with: with:

View file

@ -10,7 +10,7 @@ jobs:
name: update collabora name: update collabora
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Run collabora-profile-update - name: Run collabora-profile-update
run: | run: |
rm -f php/cool-seccomp-profile.json rm -f php/cool-seccomp-profile.json
@ -18,7 +18,7 @@ jobs:
mv cool-seccomp-profile.json php/ mv cool-seccomp-profile.json php/
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: collabora-seccomp-update automated change commit-message: collabora-seccomp-update automated change
signoff: true signoff: true

View file

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: Validate structure - name: Validate structure
run: | run: |
CONTAINERS="$(find ./community-containers -mindepth 1 -maxdepth 1 -type d)" CONTAINERS="$(find ./community-containers -mindepth 1 -maxdepth 1 -type d)"

View file

@ -10,7 +10,7 @@ jobs:
name: Run dependency update script name: Run dependency update script
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2 - uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with: with:
php-version: 8.4 php-version: 8.4
@ -44,7 +44,7 @@ jobs:
)" )"
sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile sed -i "s|pecl install APCu.*\;|pecl install APCu-$apcu_version\;|" ./Containers/mastercontainer/Dockerfile
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: php dependency updates commit-message: php dependency updates
signoff: true signoff: true

View file

@ -25,7 +25,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: Install hadolint - name: Install hadolint
run: | run: |

View file

@ -1,50 +0,0 @@
name: Block if prerelease is present
on:
pull_request:
permissions:
contents: read
jobs:
check-latest-release:
runs-on: ubuntu-latest
steps:
- name: "Check latest published release isn't a prerelease"
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v6
with:
script: |
const tags = await github.rest.repos.listTags({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 1
});
if (!tags.data || tags.data.length === 0) {
core.info('No tags found for this repository; skipping prerelease check.');
return;
}
const latestTag = tags.data[0].name;
core.info(`Latest tag found: ${latestTag}`);
try {
const { data } = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: latestTag
});
if (data.prerelease) {
core.setFailed(`Release for tag ${latestTag} (${data.tag_name}) is a prerelease. Blocking merges to main as we need to wait for the prerelease to become stable.`);
} else {
core.info(`Release for tag ${latestTag} (${data.tag_name}) is not a prerelease.`);
}
} catch (err) {
if (err.status === 404) {
core.info(`No release found for tag ${latestTag}; skipping prerelease check.`);
} else {
throw err;
}
}

View file

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: Turnstyle - name: Turnstyle
uses: softprops/turnstyle@e565d2d86403c5d23533937e95980570545e5586 # v2 uses: softprops/turnstyle@e565d2d86403c5d23533937e95980570545e5586 # v2

View file

@ -10,7 +10,7 @@ jobs:
name: update to latest imaginary commit on master branch name: update to latest imaginary commit on master branch
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Run imaginary-update - name: Run imaginary-update
run: | run: |
# Imaginary # Imaginary
@ -22,7 +22,7 @@ jobs:
sed -i "s|^ENV IMAGINARY_HASH.*$|ENV IMAGINARY_HASH=$imaginary_version|" ./Containers/imaginary/Dockerfile sed -i "s|^ENV IMAGINARY_HASH.*$|ENV IMAGINARY_HASH=$imaginary_version|" ./Containers/imaginary/Dockerfile
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: imaginary-update automated change commit-message: imaginary-update automated change
signoff: true signoff: true

View file

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: Validate Json - name: Validate Json
run: | run: |
sudo apt-get update sudo apt-get update

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
with: with:
fetch-depth: 0 fetch-depth: 0

View file

@ -36,7 +36,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5.0.1
with: with:
persist-credentials: false persist-credentials: false

View file

@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.1 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with: with:
persist-credentials: false persist-credentials: false
@ -36,7 +36,7 @@ jobs:
line-length: warning line-length: warning
- name: Install the latest version of uv - name: Install the latest version of uv
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
- name: Check GitHub actions - name: Check GitHub actions
run: uvx zizmor --min-severity medium .github/workflows/*.yml run: uvx zizmor --min-severity medium .github/workflows/*.yml

View file

@ -11,7 +11,7 @@ jobs:
name: Run nextcloud-update script name: Run nextcloud-update script
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Run nextcloud-update script - name: Run nextcloud-update script
run: | run: |
# Inspired by https://github.com/nextcloud/docker/blob/master/update.sh # Inspired by https://github.com/nextcloud/docker/blob/master/update.sh
@ -79,7 +79,7 @@ jobs:
fi fi
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: nextcloud-update automated change commit-message: nextcloud-update automated change
signoff: true signoff: true

View file

@ -16,7 +16,7 @@ jobs:
name: PHP Deprecation Detector name: PHP Deprecation Detector
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Set up php - name: Set up php
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2 uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
with: with:

View file

@ -24,9 +24,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - uses: actions/setup-node@v6
with: with:
node-version: lts/* node-version: lts/*
@ -114,7 +114,7 @@ jobs:
exit 1 exit 1
fi fi
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - uses: actions/upload-artifact@v6
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
name: playwright-report name: playwright-report

View file

@ -13,9 +13,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - uses: actions/setup-node@v6
with: with:
node-version: lts/* node-version: lts/*
@ -82,7 +82,7 @@ jobs:
exit 1 exit 1
fi fi
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - uses: actions/upload-artifact@v6
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
name: playwright-report name: playwright-report

View file

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Set up php - name: Set up php
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2 uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2
@ -30,7 +30,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: Update psalm baseline commit-message: Update psalm baseline

View file

@ -32,7 +32,7 @@ jobs:
name: static-psalm-analysis name: static-psalm-analysis
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5.0.1
with: with:
persist-credentials: false persist-credentials: false

View file

@ -15,7 +15,7 @@ jobs:
name: Check Shell name: Check Shell
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Run Shellcheck - name: Run Shellcheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0
with: with:

View file

@ -10,7 +10,7 @@ jobs:
name: update talk name: update talk
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Run talk-container-update - name: Run talk-container-update
run: | run: |
# Recording # Recording
@ -45,7 +45,7 @@ jobs:
sed -i "s|^ARG JANUS_VERSION=.*$|ARG JANUS_VERSION=$janus_version|" ./Containers/talk/Dockerfile sed -i "s|^ARG JANUS_VERSION=.*$|ARG JANUS_VERSION=$janus_version|" ./Containers/talk/Dockerfile
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: talk-update automated change commit-message: talk-update automated change
signoff: true signoff: true

View file

@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: Set up php ${{ matrix.php-versions }} - name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2 uses: shivammathur/setup-php@7bf05c6b704e0b9bfee22300130a31b5ea68d593 # v2

View file

@ -8,4 +8,4 @@ jobs:
name: update copyright name: update copyright
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: update helm chart - name: update helm chart
run: | run: |
set -x set -x
@ -23,7 +23,7 @@ jobs:
sudo bash nextcloud-aio-helm-chart/update-helm.sh "$DOCKER_TAG" sudo bash nextcloud-aio-helm-chart/update-helm.sh "$DOCKER_TAG"
fi fi
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: Helm Chart updates commit-message: Helm Chart updates
signoff: true signoff: true

View file

@ -11,12 +11,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v6.0.1
- name: update yaml files - name: update yaml files
run: | run: |
sudo bash manual-install/update-yaml.sh sudo bash manual-install/update-yaml.sh
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: Yaml updates commit-message: Yaml updates
signoff: true signoff: true

View file

@ -10,7 +10,7 @@ jobs:
name: update watchtower name: update watchtower
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@v6.0.1
- name: Run watchtower-container-update - name: Run watchtower-container-update
run: | run: |
# Watchtower # Watchtower
@ -26,7 +26,7 @@ jobs:
sed -i "s|\$WATCHTOWER_COMMIT_HASH.*$|\$WATCHTOWER_COMMIT_HASH # $watchtower_version|" ./Containers/watchtower/Dockerfile sed -i "s|\$WATCHTOWER_COMMIT_HASH.*$|\$WATCHTOWER_COMMIT_HASH # $watchtower_version|" ./Containers/watchtower/Dockerfile
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7 uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with: with:
commit-message: watchtower-update automated change commit-message: watchtower-update automated change
signoff: true signoff: true

View file

@ -1,13 +0,0 @@
<!--
- SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
In the Nextcloud community, participants from all over the world come together to create Free Software for a free internet. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use Nextcloud software.
Our code of conduct offers some guidance to ensure Nextcloud participants can cooperate effectively in a positive and inspiring atmosphere, and to explain how together we can strengthen and support each other.
The Code of Conduct is shared by all contributors and users who engage with the Nextcloud team and its community services. It presents a summary of the shared values and “common sense” thinking in our community.
You can find our full code of conduct on our website: https://nextcloud.com/code-of-conduct/
Please, keep our CoC in mind when you contribute! That way, everyone can be a part of our community in a productive, positive, creative and fun way.

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM alpine:3.23.3 FROM alpine:3.23.2
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a apk upgrade --no-cache -a

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM alpine:3.23.3 FROM alpine:3.23.2
RUN set -ex; \ RUN set -ex; \
\ \

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM alpine:3.23.3 FROM alpine:3.23.2
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \

View file

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
# From a file located probably somewhere here: https://github.com/CollaboraOnline/online/blob/master/docker/from-packages/Dockerfile # From a file located probably somewhere here: https://github.com/CollaboraOnline/online/blob/master/docker/from-packages/Dockerfile
FROM collabora/code:25.04.8.3.1 FROM collabora/code:25.04.8.1.1
USER root USER root
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM haproxy:3.3.2-alpine FROM haproxy:3.3.1-alpine
# hadolint ignore=DL3002 # hadolint ignore=DL3002
USER root USER root

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM alpine:3.23.3 FROM alpine:3.23.2
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \
apk add --no-cache bash lighttpd netcat-openbsd; \ apk add --no-cache bash lighttpd netcat-openbsd; \

View file

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
# Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile # Probably from here https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/Dockerfile
FROM elasticsearch:8.19.11 FROM elasticsearch:8.19.10
USER root USER root

View file

@ -1,7 +1,7 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM golang:1.26.0-alpine3.23 AS go FROM golang:1.25.6-alpine3.23 AS go
ENV IMAGINARY_HASH=6a274b488759a896aff02f52afee6e50b5e3a3ee ENV IMAGINARY_HASH=6a274b488759a896aff02f52afee6e50b5e3a3ee
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \
@ -14,7 +14,7 @@ RUN set -ex; \
build-base; \ build-base; \
go install github.com/h2non/imaginary@"$IMAGINARY_HASH"; go install github.com/h2non/imaginary@"$IMAGINARY_HASH";
FROM alpine:3.23.3 FROM alpine:3.23.2
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \
apk add --no-cache \ apk add --no-cache \

View file

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
# Docker CLI is a requirement # Docker CLI is a requirement
FROM docker:29.2.1-cli AS docker FROM docker:29.1.5-cli AS docker
# Caddy is a requirement # Caddy is a requirement
FROM caddy:2.10.2-alpine AS caddy FROM caddy:2.10.2-alpine AS caddy

View file

@ -4,7 +4,7 @@ echo "Daily backup script has started"
# Check if initial configuration has been done, otherwise this script should do nothing. # Check if initial configuration has been done, otherwise this script should do nothing.
CONFIG_FILE=/mnt/docker-aio-config/data/configuration.json CONFIG_FILE=/mnt/docker-aio-config/data/configuration.json
if ! [ -f "$CONFIG_FILE" ] || (! grep -q "wasStartButtonClicked.*1" "$CONFIG_FILE" && ! grep -q "wasStartButtonClicked.*true" "$CONFIG_FILE"); then if ! [ -f "$CONFIG_FILE" ] || ! grep -q "wasStartButtonClicked.*1" "$CONFIG_FILE"; then
echo "Initial configuration via AIO interface not done yet. Exiting..." echo "Initial configuration via AIO interface not done yet. Exiting..."
exit 0 exit 0
fi fi

View file

@ -166,7 +166,7 @@ elif ! sudo -E -u www-data docker volume ls --format "{{.Name}}" | grep -q "^nex
print_red "It seems like you did not give the mastercontainer volume the correct name? (The 'nextcloud_aio_mastercontainer' volume was not found.) print_red "It seems like you did not give the mastercontainer volume the correct name? (The 'nextcloud_aio_mastercontainer' volume was not found.)
Using a different name is not supported since the built-in backup solution will not work in that case!" Using a different name is not supported since the built-in backup solution will not work in that case!"
exit 1 exit 1
elif ! sudo -E -u www-data docker inspect nextcloud-aio-mastercontainer --format '{{.Mounts}}' | grep -q " nextcloud_aio_mastercontainer "; then elif ! sudo -E -u www-data docker inspect nextcloud-aio-mastercontainer | grep -q "nextcloud_aio_mastercontainer"; then
print_red "It seems like you did not attach the 'nextcloud_aio_mastercontainer' volume to the mastercontainer? print_red "It seems like you did not attach the 'nextcloud_aio_mastercontainer' volume to the mastercontainer?
This is not supported since the built-in backup solution will not work in that case!" This is not supported since the built-in backup solution will not work in that case!"
exit 1 exit 1

View file

@ -182,11 +182,8 @@ if ! [ -f "$NEXTCLOUD_DATA_DIR/skip.update" ]; then
curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2.asc" curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/latest-${NEXT_MAJOR}.tar.bz2.asc"
GNUPGHOME="$(mktemp -d)" GNUPGHOME="$(mktemp -d)"
export GNUPGHOME export GNUPGHOME
if ! gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A; then # gpg key from https://nextcloud.com/nextcloud.asc
if ! gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 28806A878AE423A28372792ED75899B9A724937A; then gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 28806A878AE423A28372792ED75899B9A724937A
curl -sSL https://nextcloud.com/nextcloud.asc | gpg --import
fi
fi
gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2 gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2
mkdir -p /usr/src/tmp mkdir -p /usr/src/tmp
tar -xjf nextcloud.tar.bz2 -C /usr/src/tmp/ tar -xjf nextcloud.tar.bz2 -C /usr/src/tmp/

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM alpine:3.23.3 FROM alpine:3.23.2
COPY --chmod=775 start.sh /start.sh COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh COPY --chmod=775 healthcheck.sh /healthcheck.sh

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM python:3.14.3-alpine3.23 FROM python:3.14.2-alpine3.23
COPY --chmod=775 start.sh /start.sh COPY --chmod=775 start.sh /start.sh
COPY --chmod=775 healthcheck.sh /healthcheck.sh COPY --chmod=775 healthcheck.sh /healthcheck.sh

View file

@ -1,10 +1,10 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM nats:2.12.4-scratch AS nats FROM nats:2.12.3-scratch AS nats
FROM eturnal/eturnal:1.12.2-alpine AS eturnal FROM eturnal/eturnal:1.12.2-alpine AS eturnal
FROM strukturag/nextcloud-spreed-signaling:2.1.0 AS signaling FROM strukturag/nextcloud-spreed-signaling:2.0.4 AS signaling
FROM alpine:3.23.3 AS janus FROM alpine:3.23.2 AS janus
ARG JANUS_VERSION=v1.4.0 ARG JANUS_VERSION=v1.3.3
WORKDIR /src WORKDIR /src
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \
@ -35,7 +35,7 @@ RUN set -ex; \
make configs; \ make configs; \
rename -v ".jcfg.sample" ".jcfg" /usr/local/etc/janus/*.jcfg.sample rename -v ".jcfg.sample" ".jcfg" /usr/local/etc/janus/*.jcfg.sample
FROM alpine:3.23.3 FROM alpine:3.23.2
ENV ETURNAL_ETC_DIR="/conf" ENV ETURNAL_ETC_DIR="/conf"
ENV SKIP_CERT_VERIFY=false ENV SKIP_CERT_VERIFY=false
COPY --from=janus --chmod=777 --chown=1000:1000 /usr/local /usr/local COPY --from=janus --chmod=777 --chown=1000:1000 /usr/local /usr/local

View file

@ -25,9 +25,7 @@ certificate = /etc/nginx/ssl/server.crt
key = /etc/nginx/ssl/server.key key = /etc/nginx/ssl/server.key
[app] [app]
# Set to "true" to install pprof debug handlers. Access will only be possible # Set to "true" to install pprof debug handlers.
# from IPs allowed through the "allowed_ips" option below.
#
# See "https://golang.org/pkg/net/http/pprof/" for further information. # See "https://golang.org/pkg/net/http/pprof/" for further information.
debug = false debug = false
@ -272,9 +270,8 @@ connectionsperhost = 8
#SA = NA #SA = NA
[stats] [stats]
# Comma-separated list of IP addresses that are allowed to access the debug, # Comma-separated list of IP addresses that are allowed to access the stats
# stats and metrics endpoints. # endpoint. Leave empty (or commented) to only allow access from "127.0.0.1".
# Leave empty (or commented) to only allow access from localhost.
#allowed_ips = #allowed_ips =
[etcd] [etcd]

View file

@ -1,15 +1,15 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
FROM golang:1.26.0-alpine3.23 AS go FROM golang:1.25.6-alpine3.23 AS go
ENV WATCHTOWER_COMMIT_HASH=b09b3a5c5e1094b746575a19a7fc0135c8908c9d ENV WATCHTOWER_COMMIT_HASH=f522ce27e1fbe4618da54833025a95be62aa838a
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \
apk add --no-cache \ apk add --no-cache \
build-base; \ build-base; \
go install github.com/nicholas-fedor/watchtower@$WATCHTOWER_COMMIT_HASH # v1.14.1 go install github.com/nicholas-fedor/watchtower@$WATCHTOWER_COMMIT_HASH # v1.14.0
FROM alpine:3.23.3 FROM alpine:3.23.2
RUN set -ex; \ RUN set -ex; \
apk upgrade --no-cache -a; \ apk upgrade --no-cache -a; \

View file

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:latest # syntax=docker/dockerfile:latest
# Probably from this file: https://github.com/nextcloud/whiteboard/blob/main/Dockerfile # Probably from this file: https://github.com/nextcloud/whiteboard/blob/main/Dockerfile
FROM ghcr.io/nextcloud-releases/whiteboard:v1.5.6 FROM ghcr.io/nextcloud-releases/whiteboard:v1.5.3
USER root USER root
RUN set -ex; \ RUN set -ex; \

View file

@ -1,5 +1,5 @@
## Caddy with geoblocking ## Caddy with geoblocking
This container bundles caddy and auto-configures it for you. It also covers [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden) by listening on `bw.$NC_DOMAIN`, if installed. It also covers [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart) by listening on `mail.$NC_DOMAIN`, if installed. It also covers [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) by listening on `media.$NC_DOMAIN`, if installed. It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap) by listening on `ldap.$NC_DOMAIN`, if installed. It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed. It also covers [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter) by listening on `metrics.$NC_DOMAIN`, if installed. It also covers [LocalAI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai) by listening on `ai.$NC_DOMAIN`, if installed. This container bundles caddy and auto-configures it for you. It also covers [vaultwarden](https://github.com/nextcloud/all-in-one/tree/main/community-containers/vaultwarden) by listening on `bw.$NC_DOMAIN`, if installed. It also covers [stalwart](https://github.com/nextcloud/all-in-one/tree/main/community-containers/stalwart) by listening on `mail.$NC_DOMAIN`, if installed. It also covers [jellyfin](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyfin) by listening on `media.$NC_DOMAIN`, if installed. It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/community-containers/lldap) by listening on `ldap.$NC_DOMAIN`, if installed. It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed. It also covers [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter) by listening on `metrics.$NC_DOMAIN`, if installed.
### Notes ### Notes
- This container is incompatible with the [npmplus](https://github.com/nextcloud/all-in-one/tree/main/community-containers/npmplus) community container. So make sure that you do not enable both at the same time! - This container is incompatible with the [npmplus](https://github.com/nextcloud/all-in-one/tree/main/community-containers/npmplus) community container. So make sure that you do not enable both at the same time!
@ -14,7 +14,6 @@ This container bundles caddy and auto-configures it for you. It also covers [vau
- If you want to use this with [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb), make sure that you point `tables.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nocodb. - If you want to use this with [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb), make sure that you point `tables.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nocodb.
- If you want to use this with [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr), make sure that you point `requests.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for jellyseerr. - If you want to use this with [jellyseerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr), make sure that you point `requests.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for jellyseerr.
- If you want to use this with [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter), make sure that you point `metrics.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nextcloud-exporter. - If you want to use this with [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter), make sure that you point `metrics.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nextcloud-exporter.
- If you want to use this with [local AI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai), make sure that you point `ai.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for local AI.
- After the container was started the first time, you should see a new `nextcloud-aio-caddy` folder and inside there an `allowed-countries.txt` file when you open the files app with the default `admin` user. In there you can adjust the allowed country codes for caddy by adding them to the first line, e.g. `IT FR` would allow access from italy and france. Private ip-ranges are always allowed. Additionally, in order to activate this config, you need to get an account at https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and download the `GeoLite2-Country.mmdb` and upload it with this exact name into the `nextcloud-aio-caddy` folder. Afterwards restart all containers from the AIO interface and your new config should be active! - After the container was started the first time, you should see a new `nextcloud-aio-caddy` folder and inside there an `allowed-countries.txt` file when you open the files app with the default `admin` user. In there you can adjust the allowed country codes for caddy by adding them to the first line, e.g. `IT FR` would allow access from italy and france. Private ip-ranges are always allowed. Additionally, in order to activate this config, you need to get an account at https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and download the `GeoLite2-Country.mmdb` and upload it with this exact name into the `nextcloud-aio-caddy` folder. Afterwards restart all containers from the AIO interface and your new config should be active!
- You can add your own Caddy configurations in `/data/caddy-imports/` inside the Caddy container (`sudo docker exec -it nextcloud-aio-caddy bash`). These will be imported on container startup. **Please note:** If you do not have CLI access to the server, you can now run docker commands via a web session by using this community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/container-management - You can add your own Caddy configurations in `/data/caddy-imports/` inside the Caddy container (`sudo docker exec -it nextcloud-aio-caddy bash`). These will be imported on container startup. **Please note:** If you do not have CLI access to the server, you can now run docker commands via a web session by using this community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/container-management
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack - See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack

View file

@ -4,59 +4,42 @@
"container_name": "nextcloud-aio-local-ai", "container_name": "nextcloud-aio-local-ai",
"display_name": "Local AI", "display_name": "Local AI",
"documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai", "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai",
"image": "ghcr.io/docjyj/aio-local-ai-vulkan", "image": "ghcr.io/szaimen/aio-local-ai",
"image_tag": "v1", "image_tag": "v2",
"internal_port": "10078", "internal_port": "8080",
"restart": "unless-stopped", "restart": "unless-stopped",
"environment": [ "environment": [
"TZ=%TIMEZONE%", "TZ=%TIMEZONE%",
"LOCALAI_API_KEY=%LOCALAI_API_KEY%", "MODELS_PATH=/models"
"LOCALAI_ADDRESS=:10078",
"LOCALAI_CONFIG_DIR=/configuration",
"LOCALAI_MODEL_PATH=/models",
"LOCALAI_BACKEND_PATH=/backends"
],
"ports": [
{
"ip_binding": "%APACHE_IP_BINDING%",
"port_number": "10078",
"protocol": "tcp"
}
], ],
"volumes": [ "volumes": [
{
"source": "nextcloud_aio_localai_configuration",
"destination": "/configuration",
"writeable": true
},
{ {
"source": "nextcloud_aio_localai_models", "source": "nextcloud_aio_localai_models",
"destination": "/models", "destination": "/models",
"writeable": true "writeable": true
}, },
{ {
"source": "nextcloud_aio_localai_backends", "source": "nextcloud_aio_localai_images",
"destination": "/backends", "destination": "/tmp/generated/images/",
"writeable": true "writeable": true
},
{
"source": "%NEXTCLOUD_DATADIR%",
"destination": "/nextcloud",
"writeable": false
} }
], ],
"secrets": [ "enable_nvidia_gpu": false,
"LOCALAI_API_KEY"
],
"ui_secret": "LOCALAI_API_KEY",
"devices": [
"/dev/dri"
],
"nextcloud_exec_commands": [ "nextcloud_exec_commands": [
"mkdir '/mnt/ncdata/admin/files/nextcloud-aio-local-ai'",
"touch '/mnt/ncdata/admin/files/nextcloud-aio-local-ai/models.yaml'",
"echo 'Scanning nextcloud-aio-local-ai folder for admin user...'",
"php /var/www/html/occ files:scan --path='/admin/files/nextcloud-aio-local-ai'",
"php /var/www/html/occ app:install integration_openai", "php /var/www/html/occ app:install integration_openai",
"php /var/www/html/occ app:enable integration_openai", "php /var/www/html/occ app:enable integration_openai",
"php /var/www/html/occ config:app:set integration_openai url --value http://nextcloud-aio-local-ai:10078", "php /var/www/html/occ config:app:set integration_openai url --value http://nextcloud-aio-local-ai:8080",
"php /var/www/html/occ config:app:set integration_openai api_key --value %LOCALAI_API_KEY%",
"php /var/www/html/occ app:install assistant", "php /var/www/html/occ app:install assistant",
"php /var/www/html/occ app:enable assistant" "php /var/www/html/occ app:enable assistant"
],
"backup_volumes": [
"nextcloud_aio_localai_configuration"
] ]
} }
] ]

View file

@ -1,16 +1,21 @@
## Local AI ## Local AI
This container bundles Local AI and auto-configures it for you. It support hardware acceleration with Vulkan. This container bundles Local AI and auto-configures it for you.
### Notes ### Notes
Documentation is available on the container repository. This documentation is regularly updated and is intended to be as simple and detailed as possible. Thanks for all your feedback! - Make sure to have enough storage space available. This container alone needs ~7GB storage. Every model that you add to `models.yaml` will of course use additional space which adds up quite fast.
- After the container was started the first time, you should see a new `nextcloud-aio-local-ai` folder when you open the files app with the default `admin` user. In there you should see a `models.yaml` config file. You can now add models in there. Please refer [here](https://github.com/mudler/LocalAI/blob/master/gallery/index.yaml) where you can get further urls that you can put in there. Afterwards restart all containers from the AIO interface and the models should automatically get downloaded by the local-ai container and activated.
- See https://github.com/docjyJ/aio-local-ai-vulkan#getting-started for getting start with this container. - Example for content of `models.yaml` (if you add all of them, it takes around 10GB additional space):
```yaml
# Stable Diffusion in NCNN with c++, supported txt2img and img2img
- url: github:mudler/LocalAI/blob/master/gallery/stablediffusion.yaml
name: Stable_diffusion
```
- To make it work, you first need to browse `https://your-nc-domain.com/settings/admin/ai` and enable or disable specific features for your models in the openAI settings. Afterwards using the Nextcloud Assistant should work.
- See [this guide](https://github.com/nextcloud/all-in-one/discussions/5430) for how to improve AI task pickup speed - See [this guide](https://github.com/nextcloud/all-in-one/discussions/5430) for how to improve AI task pickup speed
- Note that Nextcloud supports only one server for AI queries, so this container cannot be used at the same time as other AI containers.
- See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack - See https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers how to add it to the AIO stack
### Repository ### Repository
https://github.com/docjyJ/aio-local-ai-vulkan https://github.com/szaimen/aio-local-ai
### Maintainer ### Maintainer
https://github.com/docjyJ https://github.com/szaimen

View file

@ -2,7 +2,7 @@
"aio_services_v1": [ "aio_services_v1": [
{ {
"container_name": "nextcloud-aio-nocodb", "container_name": "nextcloud-aio-nocodb",
"display_name": "NocoDB (deprecated)", "display_name": "NocoDB",
"documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb", "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb",
"image": "nocodb/nocodb", "image": "nocodb/nocodb",
"image_tag": "latest", "image_tag": "latest",

View file

@ -1,8 +1,3 @@
> [!CAUTION]
> NocoDB is licensed under a non-free license.
>
> And is no longer maintained.
> [!NOTE] > [!NOTE]
> This container is there to compensate for the lack of functionality in Nextcloud Tables. > This container is there to compensate for the lack of functionality in Nextcloud Tables.
> >

View file

@ -47,7 +47,6 @@ sed -i '/AIO_URL/d' containers.yml
sed -i '/DOCKER_SOCKET_PROXY_ENABLED/d' containers.yml sed -i '/DOCKER_SOCKET_PROXY_ENABLED/d' containers.yml
sed -i '/ADDITIONAL_TRUSTED_PROXY/d' containers.yml sed -i '/ADDITIONAL_TRUSTED_PROXY/d' containers.yml
sed -i '/TURN_DOMAIN/d' containers.yml sed -i '/TURN_DOMAIN/d' containers.yml
sed -i '/NC_AIO_VERSION/d' containers.yml
TCP="$(grep -oP '[%A-Z0-9_]+/tcp' containers.yml | sort -u)" TCP="$(grep -oP '[%A-Z0-9_]+/tcp' containers.yml | sort -u)"
mapfile -t TCP <<< "$TCP" mapfile -t TCP <<< "$TCP"

View file

@ -1,6 +1,6 @@
name: nextcloud-aio-helm-chart name: nextcloud-aio-helm-chart
description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose
version: 12.6.1 version: 12.5.0
apiVersion: v2 apiVersion: v2
keywords: keywords:
- latest - latest

View file

@ -61,7 +61,7 @@ spec:
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
- name: WHITEBOARD_HOST - name: WHITEBOARD_HOST
value: nextcloud-aio-whiteboard value: nextcloud-aio-whiteboard
image: ghcr.io/nextcloud-releases/aio-apache:20260211_141900 image: ghcr.io/nextcloud-releases/aio-apache:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -36,7 +36,7 @@ spec:
{{- end }} {{- end }}
initContainers: initContainers:
- name: init-subpath - name: init-subpath
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900 image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command: command:
- mkdir - mkdir
- "-p" - "-p"
@ -59,7 +59,7 @@ spec:
value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}" value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-clamav:20260211_141900 image: ghcr.io/nextcloud-releases/aio-clamav:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -36,9 +36,9 @@ spec:
- name: server_name - name: server_name
value: "{{ .Values.NC_DOMAIN }}" value: "{{ .Values.NC_DOMAIN }}"
{{- if contains "--o:support_key=" (join " " (.Values.ADDITIONAL_COLLABORA_OPTIONS | default list)) }} {{- if contains "--o:support_key=" (join " " (.Values.ADDITIONAL_COLLABORA_OPTIONS | default list)) }}
image: ghcr.io/nextcloud-releases/aio-collabora-online:20260211_141900 image: ghcr.io/nextcloud-releases/aio-collabora-online:20260122_105751
{{- else }} {{- else }}
image: ghcr.io/nextcloud-releases/aio-collabora:20260211_141900 image: ghcr.io/nextcloud-releases/aio-collabora:20260122_105751
{{- end }} {{- end }}
readinessProbe: readinessProbe:
exec: exec:

View file

@ -35,7 +35,7 @@ spec:
{{- end }} {{- end }}
initContainers: initContainers:
- name: init-subpath - name: init-subpath
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900 image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command: command:
- mkdir - mkdir
- "-p" - "-p"
@ -64,7 +64,7 @@ spec:
value: nextcloud value: nextcloud
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-postgresql:20260211_141900 image: ghcr.io/nextcloud-releases/aio-postgresql:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -24,7 +24,7 @@ spec:
spec: spec:
initContainers: initContainers:
- name: init-volumes - name: init-volumes
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900 image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command: command:
- chmod - chmod
- "777" - "777"
@ -54,7 +54,7 @@ spec:
value: basic value: basic
- name: xpack.security.enabled - name: xpack.security.enabled
value: "false" value: "false"
image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260211_141900 image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -38,7 +38,7 @@ spec:
value: "{{ .Values.IMAGINARY_SECRET }}" value: "{{ .Values.IMAGINARY_SECRET }}"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-imaginary:20260211_141900 image: ghcr.io/nextcloud-releases/aio-imaginary:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -38,7 +38,7 @@ spec:
# AIO settings start # Do not remove or change this line! # AIO settings start # Do not remove or change this line!
initContainers: initContainers:
- name: init-volumes - name: init-volumes
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900 image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command: command:
- chmod - chmod
- "777" - "777"
@ -190,7 +190,7 @@ spec:
value: "{{ .Values.WHITEBOARD_ENABLED }}" value: "{{ .Values.WHITEBOARD_ENABLED }}"
- name: WHITEBOARD_SECRET - name: WHITEBOARD_SECRET
value: "{{ .Values.WHITEBOARD_SECRET }}" value: "{{ .Values.WHITEBOARD_SECRET }}"
image: ghcr.io/nextcloud-releases/aio-nextcloud:20260211_141900 image: ghcr.io/nextcloud-releases/aio-nextcloud:20260122_105751
{{- if eq (.Values.RPSS_ENABLED | default "no") "yes" }} # AIO-config - do not change this comment! {{- if eq (.Values.RPSS_ENABLED | default "no") "yes" }} # AIO-config - do not change this comment!
securityContext: securityContext:
# The items below only work in container context # The items below only work in container context

View file

@ -57,7 +57,7 @@ spec:
value: "6379" value: "6379"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-notify-push:20260211_141900 image: ghcr.io/nextcloud-releases/aio-notify-push:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -24,7 +24,7 @@ spec:
spec: spec:
initContainers: initContainers:
- name: init-volumes - name: init-volumes
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900 image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
command: command:
- chmod - chmod
- "777" - "777"
@ -42,7 +42,7 @@ spec:
value: "{{ .Values.ONLYOFFICE_SECRET }}" value: "{{ .Values.ONLYOFFICE_SECRET }}"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260211_141900 image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -39,7 +39,7 @@ spec:
value: "{{ .Values.REDIS_PASSWORD }}" value: "{{ .Values.REDIS_PASSWORD }}"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-redis:20260211_141900 image: ghcr.io/nextcloud-releases/aio-redis:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -52,7 +52,7 @@ spec:
value: "{{ .Values.TURN_SECRET }}" value: "{{ .Values.TURN_SECRET }}"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-talk:20260211_141900 image: ghcr.io/nextcloud-releases/aio-talk:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -44,7 +44,7 @@ spec:
value: "{{ .Values.RECORDING_SECRET }}" value: "{{ .Values.RECORDING_SECRET }}"
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-talk-recording:20260211_141900 image: ghcr.io/nextcloud-releases/aio-talk-recording:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -50,7 +50,7 @@ spec:
value: redis value: redis
- name: TZ - name: TZ
value: "{{ .Values.TIMEZONE }}" value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-whiteboard:20260211_141900 image: ghcr.io/nextcloud-releases/aio-whiteboard:20260122_105751
readinessProbe: readinessProbe:
exec: exec:
command: command:

View file

@ -407,7 +407,7 @@ rm latest.yml
mv latest.yml.backup latest.yml mv latest.yml.backup latest.yml
# Get version of AIO # Get version of AIO
AIO_VERSION="$(grep -oP '[0-9]+.[0-9]+.[0-9]+' ../php/templates/includes/aio-version.twig)" AIO_VERSION="$(grep 'Nextcloud AIO ' ../php/templates/includes/aio-version.twig | grep -oP '[0-9]+.[0-9]+.[0-9]+')"
sed -i "s|^version:.*|version: $AIO_VERSION|" ../helm-chart/Chart.yaml sed -i "s|^version:.*|version: $AIO_VERSION|" ../helm-chart/Chart.yaml
# Conversion of sample.conf # Conversion of sample.conf

136
php/composer.lock generated
View file

@ -391,27 +391,27 @@
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v2.0.9", "version": "v2.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/serializable-closure.git", "url": "https://github.com/laravel/serializable-closure.git",
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e" "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e", "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b",
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e", "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^8.1" "php": "^8.1"
}, },
"require-dev": { "require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0|^13.0", "illuminate/support": "^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.67|^3.0", "nesbot/carbon": "^2.67|^3.0",
"pestphp/pest": "^2.36|^3.0|^4.0", "pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0", "phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" "symfony/var-dumper": "^6.2.0|^7.0.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -448,7 +448,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues", "issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure" "source": "https://github.com/laravel/serializable-closure"
}, },
"time": "2026-02-03T06:55:34+00:00" "time": "2026-01-08T16:22:46+00:00"
}, },
{ {
"name": "nikic/fast-route", "name": "nikic/fast-route",
@ -1644,16 +1644,16 @@
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.23.0", "version": "v3.22.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9" "reference": "946ddeafa3c9f4ce279d1f34051af041db0e16f2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", "url": "https://api.github.com/repos/twigphp/Twig/zipball/946ddeafa3c9f4ce279d1f34051af041db0e16f2",
"reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", "reference": "946ddeafa3c9f4ce279d1f34051af041db0e16f2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1707,7 +1707,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.23.0" "source": "https://github.com/twigphp/Twig/tree/v3.22.2"
}, },
"funding": [ "funding": [
{ {
@ -1719,7 +1719,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-01-23T21:00:41+00:00" "time": "2025-12-14T11:28:47+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -2888,29 +2888,29 @@
}, },
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
"version": "1.1.6", "version": "1.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/deprecations.git", "url": "https://github.com/doctrine/deprecations.git",
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.1 || ^8.0" "php": "^7.1 || ^8.0"
}, },
"conflict": { "conflict": {
"phpunit/phpunit": "<=7.5 || >=14" "phpunit/phpunit": "<=7.5 || >=13"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9 || ^12 || ^14", "doctrine/coding-standard": "^9 || ^12 || ^13",
"phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan": "1.4.10 || 2.1.11",
"phpstan/phpstan-phpunit": "^1.0 || ^2", "phpstan/phpstan-phpunit": "^1.0 || ^2",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
"psr/log": "^1 || ^2 || ^3" "psr/log": "^1 || ^2 || ^3"
}, },
"suggest": { "suggest": {
@ -2930,9 +2930,9 @@
"homepage": "https://www.doctrine-project.org/", "homepage": "https://www.doctrine-project.org/",
"support": { "support": {
"issues": "https://github.com/doctrine/deprecations/issues", "issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.6" "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
}, },
"time": "2026-02-07T07:09:04+00:00" "time": "2025-04-07T20:06:18+00:00"
}, },
{ {
"name": "felixfbecker/language-server-protocol", "name": "felixfbecker/language-server-protocol",
@ -3578,16 +3578,16 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "2.3.2", "version": "2.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/16dbf9937da8d4528ceb2145c9c7c0bd29e26374",
"reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3619,9 +3619,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.1"
}, },
"time": "2026-01-25T14:56:51+00:00" "time": "2026-01-12T11:33:04+00:00"
}, },
{ {
"name": "revolt/event-loop", "name": "revolt/event-loop",
@ -3697,29 +3697,29 @@
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
"version": "8.0.0", "version": "7.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/diff.git", "url": "https://github.com/sebastianbergmann/diff.git",
"reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3" "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a2b6d09d7729ee87d605a439469f9dcc39be5ea3", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
"reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3", "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.4" "php": ">=8.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^13.0", "phpunit/phpunit": "^12.0",
"symfony/process": "^7.2" "symfony/process": "^7.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "8.0-dev" "dev-main": "7.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -3752,27 +3752,15 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/diff/issues", "issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy", "security": "https://github.com/sebastianbergmann/diff/security/policy",
"source": "https://github.com/sebastianbergmann/diff/tree/8.0.0" "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
}, },
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
"type": "github" "type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/diff",
"type": "tidelift"
} }
], ],
"time": "2026-02-06T04:42:27+00:00" "time": "2025-02-07T04:55:46+00:00"
}, },
{ {
"name": "spatie/array-to-xml", "name": "spatie/array-to-xml",
@ -3902,16 +3890,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.4.32", "version": "v6.4.31",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" "reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", "url": "https://api.github.com/repos/symfony/console/zipball/f9f8a889f54c264f9abac3fc0f7a371ffca51997",
"reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", "reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3976,7 +3964,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.4.32" "source": "https://github.com/symfony/console/tree/v6.4.31"
}, },
"funding": [ "funding": [
{ {
@ -3996,7 +3984,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-01-13T08:45:59+00:00" "time": "2025-12-22T08:30:34+00:00"
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
@ -4070,16 +4058,16 @@
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v6.4.33", "version": "v6.4.31",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "24965ca011dac87431729640feef8bcf7b5523e0" "reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/24965ca011dac87431729640feef8bcf7b5523e0", "url": "https://api.github.com/repos/symfony/finder/zipball/5547f2e1f0ca8e2e7abe490156b62da778cfbe2b",
"reference": "24965ca011dac87431729640feef8bcf7b5523e0", "reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4114,7 +4102,7 @@
"description": "Finds files and directories via an intuitive fluent interface", "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/finder/tree/v6.4.33" "source": "https://github.com/symfony/finder/tree/v6.4.31"
}, },
"funding": [ "funding": [
{ {
@ -4134,7 +4122,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-01-26T13:03:48+00:00" "time": "2025-12-11T14:52:17+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-grapheme", "name": "symfony/polyfill-intl-grapheme",
@ -4472,16 +4460,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v7.4.4", "version": "v7.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003",
"reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4539,7 +4527,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v7.4.4" "source": "https://github.com/symfony/string/tree/v7.4.0"
}, },
"funding": [ "funding": [
{ {
@ -4559,20 +4547,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-01-12T10:54:30+00:00" "time": "2025-11-27T13:27:24+00:00"
}, },
{ {
"name": "vimeo/psalm", "name": "vimeo/psalm",
"version": "6.15.1", "version": "6.14.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vimeo/psalm.git", "url": "https://github.com/vimeo/psalm.git",
"reference": "28dc127af1b5aecd52314f6f645bafc10d0e11f9" "reference": "d0b040a91f280f071c1abcb1b77ce3822058725a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/28dc127af1b5aecd52314f6f645bafc10d0e11f9", "url": "https://api.github.com/repos/vimeo/psalm/zipball/d0b040a91f280f071c1abcb1b77ce3822058725a",
"reference": "28dc127af1b5aecd52314f6f645bafc10d0e11f9", "reference": "d0b040a91f280f071c1abcb1b77ce3822058725a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4596,7 +4584,7 @@
"netresearch/jsonmapper": "^5.0", "netresearch/jsonmapper": "^5.0",
"nikic/php-parser": "^5.0.0", "nikic/php-parser": "^5.0.0",
"php": "~8.1.31 || ~8.2.27 || ~8.3.16 || ~8.4.3 || ~8.5.0", "php": "~8.1.31 || ~8.2.27 || ~8.3.16 || ~8.4.3 || ~8.5.0",
"sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0",
"spatie/array-to-xml": "^2.17.0 || ^3.0", "spatie/array-to-xml": "^2.17.0 || ^3.0",
"symfony/console": "^6.0 || ^7.0 || ^8.0", "symfony/console": "^6.0 || ^7.0 || ^8.0",
"symfony/filesystem": "~6.3.12 || ~6.4.3 || ^7.0.3 || ^8.0", "symfony/filesystem": "~6.3.12 || ~6.4.3 || ^7.0.3 || ^8.0",
@ -4677,7 +4665,7 @@
"issues": "https://github.com/vimeo/psalm/issues", "issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm" "source": "https://github.com/vimeo/psalm"
}, },
"time": "2026-02-07T19:27:16+00:00" "time": "2025-12-23T15:36:48+00:00"
}, },
{ {
"name": "wapmorgan/php-deprecation-detector", "name": "wapmorgan/php-deprecation-detector",

View file

@ -219,7 +219,6 @@
"SIGNALING_SECRET=%SIGNALING_SECRET%", "SIGNALING_SECRET=%SIGNALING_SECRET%",
"ONLYOFFICE_SECRET=%ONLYOFFICE_SECRET%", "ONLYOFFICE_SECRET=%ONLYOFFICE_SECRET%",
"AIO_URL=%AIO_URL%", "AIO_URL=%AIO_URL%",
"NC_AIO_VERSION=v%AIO_VERSION%",
"NEXTCLOUD_MOUNT=%NEXTCLOUD_MOUNT%", "NEXTCLOUD_MOUNT=%NEXTCLOUD_MOUNT%",
"CLAMAV_ENABLED=%CLAMAV_ENABLED%", "CLAMAV_ENABLED=%CLAMAV_ENABLED%",
"CLAMAV_HOST=nextcloud-aio-clamav", "CLAMAV_HOST=nextcloud-aio-clamav",

View file

@ -1,3 +0,0 @@
#!/usr/bin/env bash
awk '/^ public [^f][^u][^n]/ { sub(/\$/, "", $3); print $3 }' src/Data/ConfigurationManager.php | sort

View file

@ -20,10 +20,5 @@
</extraFiles> </extraFiles>
<issueHandlers> <issueHandlers>
<ClassMustBeFinal errorLevel="suppress" /> <ClassMustBeFinal errorLevel="suppress" />
<MissingConstructor>
<errorLevel type="suppress">
<file name="src/Data/ConfigurationManager.php" /> <!-- We're using property hooks with virtual properties in that file, which Psalm wrongly complains about. See <https://github.com/vimeo/psalm/issues/11435>. -->
</errorLevel>
</MissingConstructor>
</issueHandlers> </issueHandlers>
</psalm> </psalm>

View file

@ -1,9 +1,7 @@
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
// Hide submit button initially // Hide submit button initially
const optionsFormSubmit = document.querySelectorAll(".options-form-submit"); const optionsFormSubmit = document.getElementById("options-form-submit");
optionsFormSubmit.forEach(element => { optionsFormSubmit.style.display = 'none';
element.style.display = 'none';
});
const communityFormSubmit = document.getElementById("community-form-submit"); const communityFormSubmit = document.getElementById("community-form-submit");
communityFormSubmit.style.display = 'none'; communityFormSubmit.style.display = 'none';
@ -14,14 +12,6 @@ document.addEventListener("DOMContentLoaded", function () {
const optionsContainersCheckboxes = document.querySelectorAll("#options-form input[type='checkbox']"); const optionsContainersCheckboxes = document.querySelectorAll("#options-form input[type='checkbox']");
const communityContainersCheckboxes = document.querySelectorAll("#community-form input[type='checkbox']"); const communityContainersCheckboxes = document.querySelectorAll("#community-form input[type='checkbox']");
// Office suite radio buttons
const collaboraRadio = document.getElementById('office-collabora');
const onlyofficeRadio = document.getElementById('office-onlyoffice');
const noneRadio = document.getElementById('office-none');
const collaboraHidden = document.getElementById('collabora');
const onlyofficeHidden = document.getElementById('onlyoffice');
let initialOfficeSelection = null;
optionsContainersCheckboxes.forEach(checkbox => { optionsContainersCheckboxes.forEach(checkbox => {
initialStateOptionsContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state initialStateOptionsContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state
}); });
@ -30,17 +20,6 @@ document.addEventListener("DOMContentLoaded", function () {
initialStateCommunityContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state initialStateCommunityContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state
}); });
// Store initial office suite selection
if (collaboraRadio && onlyofficeRadio && noneRadio) {
if (collaboraRadio.checked) {
initialOfficeSelection = 'collabora';
} else if (onlyofficeRadio.checked) {
initialOfficeSelection = 'onlyoffice';
} else {
initialOfficeSelection = 'none';
}
}
// Function to compare current states to initial states // Function to compare current states to initial states
function checkForOptionContainerChanges() { function checkForOptionContainerChanges() {
let hasChanges = false; let hasChanges = false;
@ -51,32 +30,8 @@ document.addEventListener("DOMContentLoaded", function () {
} }
}); });
// Check office suite changes and sync to hidden inputs
if (collaboraRadio && onlyofficeRadio && noneRadio && collaboraHidden && onlyofficeHidden) {
let currentOfficeSelection = null;
if (collaboraRadio.checked) {
currentOfficeSelection = 'collabora';
collaboraHidden.value = 'on';
onlyofficeHidden.value = '';
} else if (onlyofficeRadio.checked) {
currentOfficeSelection = 'onlyoffice';
collaboraHidden.value = '';
onlyofficeHidden.value = 'on';
} else {
currentOfficeSelection = 'none';
collaboraHidden.value = '';
onlyofficeHidden.value = '';
}
if (currentOfficeSelection !== initialOfficeSelection) {
hasChanges = true;
}
}
// Show or hide submit button based on changes // Show or hide submit button based on changes
optionsFormSubmit.forEach(element => { optionsFormSubmit.style.display = hasChanges ? 'block' : 'none';
element.style.display = hasChanges ? 'block' : 'none';
});
} }
// Function to compare current states to initial states // Function to compare current states to initial states
@ -127,13 +82,6 @@ document.addEventListener("DOMContentLoaded", function () {
// Initialize talk-recording visibility on page load // Initialize talk-recording visibility on page load
handleTalkVisibility(); // Ensure talk-recording is correctly initialized handleTalkVisibility(); // Ensure talk-recording is correctly initialized
// Add event listeners for office suite radio buttons
if (collaboraRadio && onlyofficeRadio && noneRadio) {
collaboraRadio.addEventListener('change', checkForOptionContainerChanges);
onlyofficeRadio.addEventListener('change', checkForOptionContainerChanges);
noneRadio.addEventListener('change', checkForOptionContainerChanges);
}
// Initial call to check for changes // Initial call to check for changes
checkForOptionContainerChanges(); checkForOptionContainerChanges();
checkForCommunityContainerChanges(); checkForCommunityContainerChanges();

View file

@ -1,5 +1,5 @@
document.addEventListener("DOMContentLoaded", function(event) { document.addEventListener("DOMContentLoaded", function(event) {
// Collabora // Collabora
const collabora = document.getElementById("office-collabora"); let collabora = document.getElementById("collabora");
collabora.disabled = true; collabora.disabled = true;
}); });

View file

@ -1,5 +1,7 @@
document.addEventListener("DOMContentLoaded", function(event) { document.addEventListener("DOMContentLoaded", function(event) {
// OnlyOffice // OnlyOffice
const onlyoffice = document.getElementById("office-onlyoffice"); let onlyoffice = document.getElementById("onlyoffice");
onlyoffice.disabled = true; if (onlyoffice) {
onlyoffice.disabled = true;
}
}); });

View file

@ -91,54 +91,54 @@ $app->get('/containers', function (Request $request, Response $response, array $
$skip_domain_validation = isset($params['skip_domain_validation']); $skip_domain_validation = isset($params['skip_domain_validation']);
return $view->render($response, 'containers.twig', [ return $view->render($response, 'containers.twig', [
'domain' => $configurationManager->domain, 'domain' => $configurationManager->GetDomain(),
'apache_port' => $configurationManager->apachePort, 'apache_port' => $configurationManager->GetApachePort(),
'borg_backup_host_location' => $configurationManager->borgBackupHostLocation, 'borg_backup_host_location' => $configurationManager->GetBorgBackupHostLocation(),
'borg_remote_repo' => $configurationManager->borgRemoteRepo, 'borg_remote_repo' => $configurationManager->GetBorgRemoteRepo(),
'borg_public_key' => $configurationManager->getBorgPublicKey(), 'borg_public_key' => $configurationManager->GetBorgPublicKey(),
'nextcloud_password' => $configurationManager->getAndGenerateSecret('NEXTCLOUD_PASSWORD'), 'nextcloud_password' => $configurationManager->GetAndGenerateSecret('NEXTCLOUD_PASSWORD'),
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(), 'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
'borgbackup_password' => $configurationManager->getAndGenerateSecret('BORGBACKUP_PASSWORD'), 'borgbackup_password' => $configurationManager->GetAndGenerateSecret('BORGBACKUP_PASSWORD'),
'is_mastercontainer_update_available' => ( $bypass_mastercontainer_update ? false : $dockerActionManager->IsMastercontainerUpdateAvailable() ), 'is_mastercontainer_update_available' => ( $bypass_mastercontainer_update ? false : $dockerActionManager->IsMastercontainerUpdateAvailable() ),
'has_backup_run_once' => $configurationManager->hasBackupRunOnce(), 'has_backup_run_once' => $configurationManager->hasBackupRunOnce(),
'is_backup_container_running' => $dockerActionManager->isBackupContainerRunning(), 'is_backup_container_running' => $dockerActionManager->isBackupContainerRunning(),
'backup_exit_code' => $dockerActionManager->GetBackupcontainerExitCode(), 'backup_exit_code' => $dockerActionManager->GetBackupcontainerExitCode(),
'is_instance_restore_attempt' => $configurationManager->instanceRestoreAttempt, 'is_instance_restore_attempt' => $configurationManager->isInstanceRestoreAttempt(),
'borg_backup_mode' => $configurationManager->backupMode, 'borg_backup_mode' => $configurationManager->GetBackupMode(),
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked, 'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
'has_update_available' => $dockerActionManager->isAnyUpdateAvailable(), 'has_update_available' => $dockerActionManager->isAnyUpdateAvailable(),
'last_backup_time' => $configurationManager->getLastBackupTime(), 'last_backup_time' => $configurationManager->GetLastBackupTime(),
'backup_times' => $configurationManager->getBackupTimes(), 'backup_times' => $configurationManager->GetBackupTimes(),
'current_channel' => $dockerActionManager->GetCurrentChannel(), 'current_channel' => $dockerActionManager->GetCurrentChannel(),
'is_clamav_enabled' => $configurationManager->isClamavEnabled, 'is_clamav_enabled' => $configurationManager->isClamavEnabled(),
'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled, 'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled(),
'is_collabora_enabled' => $configurationManager->isCollaboraEnabled, 'is_collabora_enabled' => $configurationManager->isCollaboraEnabled(),
'is_talk_enabled' => $configurationManager->isTalkEnabled, 'is_talk_enabled' => $configurationManager->isTalkEnabled(),
'borg_restore_password' => $configurationManager->borgRestorePassword, 'borg_restore_password' => $configurationManager->GetBorgRestorePassword(),
'daily_backup_time' => $configurationManager->getDailyBackupTime(), 'daily_backup_time' => $configurationManager->GetDailyBackupTime(),
'is_daily_backup_running' => $configurationManager->isDailyBackupRunning(), 'is_daily_backup_running' => $configurationManager->isDailyBackupRunning(),
'timezone' => $configurationManager->timezone, 'timezone' => $configurationManager->GetTimezone(),
'skip_domain_validation' => $configurationManager->shouldDomainValidationBeSkipped($skip_domain_validation), 'skip_domain_validation' => $configurationManager->shouldDomainValidationBeSkipped($skip_domain_validation),
'talk_port' => $configurationManager->talkPort, 'talk_port' => $configurationManager->GetTalkPort(),
'collabora_dictionaries' => $configurationManager->collaboraDictionaries, 'collabora_dictionaries' => $configurationManager->GetCollaboraDictionaries(),
'collabora_additional_options' => $configurationManager->collaboraAdditionalOptions, 'collabora_additional_options' => $configurationManager->GetAdditionalCollaboraOptions(),
'automatic_updates' => $configurationManager->areAutomaticUpdatesEnabled(), 'automatic_updates' => $configurationManager->areAutomaticUpdatesEnabled(),
'is_backup_section_enabled' => !$configurationManager->disableBackupSection, 'is_backup_section_enabled' => $configurationManager->isBackupSectionEnabled(),
'is_imaginary_enabled' => $configurationManager->isImaginaryEnabled, 'is_imaginary_enabled' => $configurationManager->isImaginaryEnabled(),
'is_fulltextsearch_enabled' => $configurationManager->isFulltextsearchEnabled, 'is_fulltextsearch_enabled' => $configurationManager->isFulltextsearchEnabled(),
'additional_backup_directories' => $configurationManager->getAdditionalBackupDirectoriesString(), 'additional_backup_directories' => $configurationManager->GetAdditionalBackupDirectoriesString(),
'nextcloud_datadir' => $configurationManager->nextcloudDatadirMount, 'nextcloud_datadir' => $configurationManager->GetNextcloudDatadirMount(),
'nextcloud_mount' => $configurationManager->nextcloudMount, 'nextcloud_mount' => $configurationManager->GetNextcloudMount(),
'nextcloud_upload_limit' => $configurationManager->nextcloudUploadLimit, 'nextcloud_upload_limit' => $configurationManager->GetNextcloudUploadLimit(),
'nextcloud_max_time' => $configurationManager->nextcloudMaxTime, 'nextcloud_max_time' => $configurationManager->GetNextcloudMaxTime(),
'nextcloud_memory_limit' => $configurationManager->nextcloudMemoryLimit, 'nextcloud_memory_limit' => $configurationManager->GetNextcloudMemoryLimit(),
'is_dri_device_enabled' => $configurationManager->nextcloudEnableDriDevice, 'is_dri_device_enabled' => $configurationManager->isDriDeviceEnabled(),
'is_nvidia_gpu_enabled' => $configurationManager->enableNvidiaGpu, 'is_nvidia_gpu_enabled' => $configurationManager->isNvidiaGpuEnabled(),
'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled, 'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled(),
'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled, 'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled(),
'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled, 'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled(),
'community_containers' => $configurationManager->listAvailableCommunityContainers(), 'community_containers' => $configurationManager->listAvailableCommunityContainers(),
'community_containers_enabled' => $configurationManager->aioCommunityContainers, 'community_containers_enabled' => $configurationManager->GetEnabledCommunityContainers(),
'bypass_container_update' => $bypass_container_update, 'bypass_container_update' => $bypass_container_update,
]); ]);
})->setName('profile'); })->setName('profile');

View file

@ -28,7 +28,7 @@
--border-radius-large: 12px; --border-radius-large: 12px;
--default-font-size: 13px; --default-font-size: 13px;
--checkbox-size: 16px; --checkbox-size: 16px;
--max-width: 580px; --max-width: 500px;
--container-top-margin: 20px; --container-top-margin: 20px;
--container-bottom-margin: 20px; --container-bottom-margin: 20px;
--container-padding: 2px; --container-padding: 2px;
@ -37,9 +37,9 @@
--main-padding: 50px; --main-padding: 50px;
} }
/* Breakpoint calculation: 580px (max-width) + 100px (main-padding * 2) + 200px (additional space) = 880px /* Breakpoint calculation: 500px (max-width) + 100px (main-padding * 2) + 200px (additional space) = 800px
Note: Unfortunately, it's not possible to calculate this dynamically using CSS variables in media queries */ Note: Unfortunately, it's not possible to calculate this dynamically using CSS variables in media queries */
@media only screen and (max-width: 880px) { @media only screen and (max-width: 800px) {
:root { :root {
--container-top-margin: 50px; --container-top-margin: 50px;
--container-bottom-margin: 0px; --container-bottom-margin: 0px;
@ -549,160 +549,3 @@ input[type="checkbox"]:disabled:not(:checked) + label {
#theme-toggle:not(:hover) #theme-icon { #theme-toggle:not(:hover) #theme-icon {
opacity: 0.6; /* Slightly transparent */ opacity: 0.6; /* Slightly transparent */
} }
/* Office Suite Feature Cards */
.office-suite-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin: 20px 0;
align-items: stretch;
}
.office-radio {
display: none;
}
.office-card {
position: relative;
border: 2px solid var(--color-border-maxcontrast);
border-radius: var(--border-radius-large);
padding: 20px;
cursor: pointer;
transition: all 0.3s ease;
background-color: var(--color-main-background);
display: flex;
flex-direction: column;
}
.office-card-disabled {
opacity: 50%;
pointer-events: none;
}
.office-card:hover {
border-color: var(--color-primary-element);
box-shadow: 0 4px 12px rgba(0, 130, 201, 0.15);
transform: translateY(-2px);
}
#office-collabora:checked + .office-card,
#office-onlyoffice:checked + .office-card {
border-color: var(--color-nextcloud-blue);
background: linear-gradient(135deg, rgba(0, 130, 201, 0.08) 0%, rgba(0, 130, 201, 0.02) 100%);
}
[data-theme="dark"] #office-collabora:checked + .office-card,
[data-theme="dark"] #office-onlyoffice:checked + .office-card {
background: linear-gradient(135deg, rgba(0, 145, 242, 0.15) 0%, rgba(0, 145, 242, 0.03) 100%);
}
.office-card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.office-card h4 {
margin: 0;
height: 24px;
font-size: 18px;
font-weight: 600;
color: var(--color-main-text);
}
.office-checkmark {
flex-shrink: 0;
display: none;
}
#office-collabora:checked + .office-card .office-checkmark,
#office-onlyoffice:checked + .office-card .office-checkmark {
display: block;
}
.office-features {
list-style: none;
padding: 0;
margin: 0;
}
.office-features li {
position: relative;
padding-left: 20px;
margin-bottom: 4px;
font-size: var(--default-font-size);
line-height: 1.5;
color: var(--color-main-text);
}
.office-features li::before {
content: '•';
position: absolute;
left: 6px;
color: var(--color-nextcloud-blue);
font-weight: bold;
}
.office-checkbox {
position: absolute;
opacity: 0;
pointer-events: none;
}
.office-learn-more {
display: inline-flex;
align-items: center;
margin-top: 12px;
color: var(--color-primary-element);
text-decoration: none;
font-size: var(--default-font-size);
font-weight: 500;
transition: color 0.2s ease;
}
.office-learn-more:hover {
color: var(--color-primary-element-hover);
}
.office-learn-more svg {
transition: transform 0.2s ease;
}
.office-learn-more:hover svg {
transform: translateX(3px);
}
.office-none-card {
text-align: center;
margin: 12px 0 20px 0;
}
.office-none-label {
display: inline-flex;
align-items: center;
font-size: 13px;
color: var(--color-primary-element);
cursor: pointer;
opacity: 0.7;
transition: opacity 0.2s ease;
padding: 8px 12px;
border-radius: var(--border-radius);
}
.office-none-label:hover {
opacity: 1;
background-color: var(--color-primary-element-light);
}
#office-none:checked + .office-none-label {
opacity: 1;
font-weight: 600;
}
/* Responsive adjustments for mobile */
@media only screen and (max-width: 800px) {
.office-suite-cards {
grid-template-columns: 1fr;
}
}

View file

@ -15,11 +15,11 @@ readonly class AuthManager {
} }
public function CheckCredentials(string $password) : bool { public function CheckCredentials(string $password) : bool {
return hash_equals($this->configurationManager->password, $password); return hash_equals($this->configurationManager->GetPassword(), $password);
} }
public function CheckToken(string $token) : bool { public function CheckToken(string $token) : bool {
return hash_equals($this->configurationManager->aioToken, $token); return hash_equals($this->configurationManager->GetToken(), $token);
} }
public function SetAuthState(bool $isLoggedIn) : void { public function SetAuthState(bool $isLoggedIn) : void {

View file

@ -41,7 +41,7 @@ readonly class ContainerDefinitionFetcher {
$data = json_decode((string)file_get_contents(DataConst::GetContainersDefinitionPath()), true, 512, JSON_THROW_ON_ERROR); $data = json_decode((string)file_get_contents(DataConst::GetContainersDefinitionPath()), true, 512, JSON_THROW_ON_ERROR);
$additionalContainerNames = []; $additionalContainerNames = [];
foreach ($this->configurationManager->aioCommunityContainers as $communityContainer) { foreach ($this->configurationManager->GetEnabledCommunityContainers() as $communityContainer) {
if ($communityContainer !== '') { if ($communityContainer !== '') {
$path = DataConst::GetCommunityContainersDirectory() . '/' . $communityContainer . '/' . $communityContainer . '.json'; $path = DataConst::GetCommunityContainersDirectory() . '/' . $communityContainer . '/' . $communityContainer . '.json';
$additionalData = json_decode((string)file_get_contents($path), true, 512, JSON_THROW_ON_ERROR); $additionalData = json_decode((string)file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
@ -56,42 +56,42 @@ readonly class ContainerDefinitionFetcher {
$containers = []; $containers = [];
foreach ($data['aio_services_v1'] as $entry) { foreach ($data['aio_services_v1'] as $entry) {
if ($entry['container_name'] === 'nextcloud-aio-clamav') { if ($entry['container_name'] === 'nextcloud-aio-clamav') {
if (!$this->configurationManager->isClamavEnabled) { if (!$this->configurationManager->isClamavEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-onlyoffice') { } elseif ($entry['container_name'] === 'nextcloud-aio-onlyoffice') {
if (!$this->configurationManager->isOnlyofficeEnabled) { if (!$this->configurationManager->isOnlyofficeEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-collabora') { } elseif ($entry['container_name'] === 'nextcloud-aio-collabora') {
if (!$this->configurationManager->isCollaboraEnabled) { if (!$this->configurationManager->isCollaboraEnabled()) {
continue; continue;
} }
if ($this->configurationManager->isCollaboraSubscriptionEnabled()) { if ($this->configurationManager->isCollaboraSubscriptionEnabled()) {
$entry['image'] = 'ghcr.io/nextcloud-releases/aio-collabora-online'; $entry['image'] = 'ghcr.io/nextcloud-releases/aio-collabora-online';
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-talk') { } elseif ($entry['container_name'] === 'nextcloud-aio-talk') {
if (!$this->configurationManager->isTalkEnabled) { if (!$this->configurationManager->isTalkEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-talk-recording') { } elseif ($entry['container_name'] === 'nextcloud-aio-talk-recording') {
if (!$this->configurationManager->isTalkRecordingEnabled) { if (!$this->configurationManager->isTalkRecordingEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-imaginary') { } elseif ($entry['container_name'] === 'nextcloud-aio-imaginary') {
if (!$this->configurationManager->isImaginaryEnabled) { if (!$this->configurationManager->isImaginaryEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-fulltextsearch') { } elseif ($entry['container_name'] === 'nextcloud-aio-fulltextsearch') {
if (!$this->configurationManager->isFulltextsearchEnabled) { if (!$this->configurationManager->isFulltextsearchEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-docker-socket-proxy') { } elseif ($entry['container_name'] === 'nextcloud-aio-docker-socket-proxy') {
if (!$this->configurationManager->isDockerSocketProxyEnabled) { if (!$this->configurationManager->isDockerSocketProxyEnabled()) {
continue; continue;
} }
} elseif ($entry['container_name'] === 'nextcloud-aio-whiteboard') { } elseif ($entry['container_name'] === 'nextcloud-aio-whiteboard') {
if (!$this->configurationManager->isWhiteboardEnabled) { if (!$this->configurationManager->isWhiteboardEnabled()) {
continue; continue;
} }
} }
@ -113,34 +113,34 @@ readonly class ContainerDefinitionFetcher {
if (isset($entry['volumes'])) { if (isset($entry['volumes'])) {
foreach ($entry['volumes'] as $value) { foreach ($entry['volumes'] as $value) {
if($value['source'] === '%BORGBACKUP_HOST_LOCATION%') { if($value['source'] === '%BORGBACKUP_HOST_LOCATION%') {
$value['source'] = $this->configurationManager->borgBackupHostLocation; $value['source'] = $this->configurationManager->GetBorgBackupHostLocation();
if($value['source'] === '') { if($value['source'] === '') {
continue; continue;
} }
} }
if($value['source'] === '%NEXTCLOUD_MOUNT%') { if($value['source'] === '%NEXTCLOUD_MOUNT%') {
$value['source'] = $this->configurationManager->nextcloudMount; $value['source'] = $this->configurationManager->GetNextcloudMount();
if($value['source'] === '') { if($value['source'] === '') {
continue; continue;
} }
} elseif ($value['source'] === '%NEXTCLOUD_DATADIR%') { } elseif ($value['source'] === '%NEXTCLOUD_DATADIR%') {
$value['source'] = $this->configurationManager->nextcloudDatadirMount; $value['source'] = $this->configurationManager->GetNextcloudDatadirMount();
if ($value['source'] === '') { if ($value['source'] === '') {
continue; continue;
} }
} elseif ($value['source'] === '%WATCHTOWER_DOCKER_SOCKET_PATH%') { } elseif ($value['source'] === '%WATCHTOWER_DOCKER_SOCKET_PATH%') {
$value['source'] = $this->configurationManager->dockerSocketPath; $value['source'] = $this->configurationManager->GetDockerSocketPath();
if($value['source'] === '') { if($value['source'] === '') {
continue; continue;
} }
} elseif ($value['source'] === '%NEXTCLOUD_TRUSTED_CACERTS_DIR%') { } elseif ($value['source'] === '%NEXTCLOUD_TRUSTED_CACERTS_DIR%') {
$value['source'] = $this->configurationManager->trustedCacertsDir; $value['source'] = $this->configurationManager->GetTrustedCacertsDir();
if($value['source'] === '') { if($value['source'] === '') {
continue; continue;
} }
} }
if ($value['destination'] === '%NEXTCLOUD_MOUNT%') { if ($value['destination'] === '%NEXTCLOUD_MOUNT%') {
$value['destination'] = $this->configurationManager->nextcloudMount; $value['destination'] = $this->configurationManager->GetNextcloudMount();
if($value['destination'] === '') { if($value['destination'] === '') {
continue; continue;
} }
@ -168,39 +168,39 @@ readonly class ContainerDefinitionFetcher {
} }
foreach ($valueDependsOn as $value) { foreach ($valueDependsOn as $value) {
if ($value === 'nextcloud-aio-clamav') { if ($value === 'nextcloud-aio-clamav') {
if (!$this->configurationManager->isClamavEnabled) { if (!$this->configurationManager->isClamavEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-onlyoffice') { } elseif ($value === 'nextcloud-aio-onlyoffice') {
if (!$this->configurationManager->isOnlyofficeEnabled) { if (!$this->configurationManager->isOnlyofficeEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-collabora') { } elseif ($value === 'nextcloud-aio-collabora') {
if (!$this->configurationManager->isCollaboraEnabled) { if (!$this->configurationManager->isCollaboraEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-talk') { } elseif ($value === 'nextcloud-aio-talk') {
if (!$this->configurationManager->isTalkEnabled) { if (!$this->configurationManager->isTalkEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-talk-recording') { } elseif ($value === 'nextcloud-aio-talk-recording') {
if (!$this->configurationManager->isTalkRecordingEnabled) { if (!$this->configurationManager->isTalkRecordingEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-imaginary') { } elseif ($value === 'nextcloud-aio-imaginary') {
if (!$this->configurationManager->isImaginaryEnabled) { if (!$this->configurationManager->isImaginaryEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-fulltextsearch') { } elseif ($value === 'nextcloud-aio-fulltextsearch') {
if (!$this->configurationManager->isFulltextsearchEnabled) { if (!$this->configurationManager->isFulltextsearchEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-docker-socket-proxy') { } elseif ($value === 'nextcloud-aio-docker-socket-proxy') {
if (!$this->configurationManager->isDockerSocketProxyEnabled) { if (!$this->configurationManager->isDockerSocketProxyEnabled()) {
continue; continue;
} }
} elseif ($value === 'nextcloud-aio-whiteboard') { } elseif ($value === 'nextcloud-aio-whiteboard') {
if (!$this->configurationManager->isWhiteboardEnabled) { if (!$this->configurationManager->isWhiteboardEnabled()) {
continue; continue;
} }
} }
@ -246,7 +246,7 @@ readonly class ContainerDefinitionFetcher {
// All secrets are registered with the configuration when they // All secrets are registered with the configuration when they
// are discovered so they can be later generated at time-of-use. // are discovered so they can be later generated at time-of-use.
foreach ($entry['secrets'] as $secret) { foreach ($entry['secrets'] as $secret) {
$this->configurationManager->registerSecret($secret); $this->configurationManager->RegisterSecret($secret);
} }
} }

View file

@ -17,30 +17,29 @@ readonly class ConfigurationController {
public function SetConfig(Request $request, Response $response, array $args): Response { public function SetConfig(Request $request, Response $response, array $args): Response {
try { try {
$this->configurationManager->startTransaction();
if (isset($request->getParsedBody()['domain'])) { if (isset($request->getParsedBody()['domain'])) {
$domain = $request->getParsedBody()['domain'] ?? ''; $domain = $request->getParsedBody()['domain'] ?? '';
$skipDomainValidation = isset($request->getParsedBody()['skip_domain_validation']); $skipDomainValidation = isset($request->getParsedBody()['skip_domain_validation']);
$this->configurationManager->setDomain($domain, $skipDomainValidation); $this->configurationManager->SetDomain($domain, $skipDomainValidation);
} }
if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) { if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
$currentMasterPassword = $request->getParsedBody()['current-master-password'] ?? ''; $currentMasterPassword = $request->getParsedBody()['current-master-password'] ?? '';
$newMasterPassword = $request->getParsedBody()['new-master-password'] ?? ''; $newMasterPassword = $request->getParsedBody()['new-master-password'] ?? '';
$this->configurationManager->changeMasterPassword($currentMasterPassword, $newMasterPassword); $this->configurationManager->ChangeMasterPassword($currentMasterPassword, $newMasterPassword);
} }
if (isset($request->getParsedBody()['borg_backup_host_location']) || isset($request->getParsedBody()['borg_remote_repo'])) { if (isset($request->getParsedBody()['borg_backup_host_location']) || isset($request->getParsedBody()['borg_remote_repo'])) {
$location = $request->getParsedBody()['borg_backup_host_location'] ?? ''; $location = $request->getParsedBody()['borg_backup_host_location'] ?? '';
$borgRemoteRepo = $request->getParsedBody()['borg_remote_repo'] ?? ''; $borgRemoteRepo = $request->getParsedBody()['borg_remote_repo'] ?? '';
$this->configurationManager->setBorgLocationVars($location, $borgRemoteRepo); $this->configurationManager->SetBorgLocationVars($location, $borgRemoteRepo);
} }
if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_remote_repo']) || isset($request->getParsedBody()['borg_restore_password'])) { if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_remote_repo']) || isset($request->getParsedBody()['borg_restore_password'])) {
$restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? ''; $restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? '';
$borgRemoteRepo = $request->getParsedBody()['borg_restore_remote_repo'] ?? ''; $borgRemoteRepo = $request->getParsedBody()['borg_restore_remote_repo'] ?? '';
$borgPassword = $request->getParsedBody()['borg_restore_password'] ?? ''; $borgPassword = $request->getParsedBody()['borg_restore_password'] ?? '';
$this->configurationManager->setBorgRestoreLocationVarsAndPassword($restoreLocation, $borgRemoteRepo, $borgPassword); $this->configurationManager->SetBorgRestoreLocationVarsAndPassword($restoreLocation, $borgRemoteRepo, $borgPassword);
} }
if (isset($request->getParsedBody()['daily_backup_time'])) { if (isset($request->getParsedBody()['daily_backup_time'])) {
@ -55,47 +54,76 @@ readonly class ConfigurationController {
$successNotification = false; $successNotification = false;
} }
$dailyBackupTime = $request->getParsedBody()['daily_backup_time'] ?? ''; $dailyBackupTime = $request->getParsedBody()['daily_backup_time'] ?? '';
$this->configurationManager->setDailyBackupTime($dailyBackupTime, $enableAutomaticUpdates, $successNotification); $this->configurationManager->SetDailyBackupTime($dailyBackupTime, $enableAutomaticUpdates, $successNotification);
} }
if (isset($request->getParsedBody()['delete_daily_backup_time'])) { if (isset($request->getParsedBody()['delete_daily_backup_time'])) {
$this->configurationManager->deleteDailyBackupTime(); $this->configurationManager->DeleteDailyBackupTime();
} }
if (isset($request->getParsedBody()['additional_backup_directories'])) { if (isset($request->getParsedBody()['additional_backup_directories'])) {
$additionalBackupDirectories = $request->getParsedBody()['additional_backup_directories'] ?? ''; $additionalBackupDirectories = $request->getParsedBody()['additional_backup_directories'] ?? '';
$this->configurationManager->setAdditionalBackupDirectories($additionalBackupDirectories); $this->configurationManager->SetAdditionalBackupDirectories($additionalBackupDirectories);
} }
if (isset($request->getParsedBody()['delete_timezone'])) { if (isset($request->getParsedBody()['delete_timezone'])) {
$this->configurationManager->deleteTimezone(); $this->configurationManager->DeleteTimezone();
} }
if (isset($request->getParsedBody()['timezone'])) { if (isset($request->getParsedBody()['timezone'])) {
$timezone = $request->getParsedBody()['timezone'] ?? ''; $timezone = $request->getParsedBody()['timezone'] ?? '';
$this->configurationManager->timezone = $timezone; $this->configurationManager->SetTimezone($timezone);
} }
if (isset($request->getParsedBody()['options-form'])) { if (isset($request->getParsedBody()['options-form'])) {
$officeSuiteChoice = $request->getParsedBody()['office_suite_choice'] ?? ''; if (isset($request->getParsedBody()['collabora']) && isset($request->getParsedBody()['onlyoffice'])) {
throw new InvalidSettingConfigurationException("Collabora and Onlyoffice are not allowed to be enabled at the same time!");
if ($officeSuiteChoice === 'collabora') { }
$this->configurationManager->isCollaboraEnabled = true; if (isset($request->getParsedBody()['clamav'])) {
$this->configurationManager->isOnlyofficeEnabled = false; $this->configurationManager->SetClamavEnabledState(1);
} elseif ($officeSuiteChoice === 'onlyoffice') { } else {
$this->configurationManager->isCollaboraEnabled = false; $this->configurationManager->SetClamavEnabledState(0);
$this->configurationManager->isOnlyofficeEnabled = true; }
} else { if (isset($request->getParsedBody()['onlyoffice'])) {
$this->configurationManager->isCollaboraEnabled = false; $this->configurationManager->SetOnlyofficeEnabledState(1);
$this->configurationManager->isOnlyofficeEnabled = false; } else {
$this->configurationManager->SetOnlyofficeEnabledState(0);
}
if (isset($request->getParsedBody()['collabora'])) {
$this->configurationManager->SetCollaboraEnabledState(1);
} else {
$this->configurationManager->SetCollaboraEnabledState(0);
}
if (isset($request->getParsedBody()['talk'])) {
$this->configurationManager->SetTalkEnabledState(1);
} else {
$this->configurationManager->SetTalkEnabledState(0);
}
if (isset($request->getParsedBody()['talk-recording'])) {
$this->configurationManager->SetTalkRecordingEnabledState(1);
} else {
$this->configurationManager->SetTalkRecordingEnabledState(0);
}
if (isset($request->getParsedBody()['imaginary'])) {
$this->configurationManager->SetImaginaryEnabledState(1);
} else {
$this->configurationManager->SetImaginaryEnabledState(0);
}
if (isset($request->getParsedBody()['fulltextsearch'])) {
$this->configurationManager->SetFulltextsearchEnabledState(1);
} else {
$this->configurationManager->SetFulltextsearchEnabledState(0);
}
if (isset($request->getParsedBody()['docker-socket-proxy'])) {
$this->configurationManager->SetDockerSocketProxyEnabledState(1);
} else {
$this->configurationManager->SetDockerSocketProxyEnabledState(0);
}
if (isset($request->getParsedBody()['whiteboard'])) {
$this->configurationManager->SetWhiteboardEnabledState(1);
} else {
$this->configurationManager->SetWhiteboardEnabledState(0);
} }
$this->configurationManager->isClamavEnabled = isset($request->getParsedBody()['clamav']);
$this->configurationManager->isTalkEnabled = isset($request->getParsedBody()['talk']);
$this->configurationManager->isTalkRecordingEnabled = isset($request->getParsedBody()['talk-recording']);
$this->configurationManager->isImaginaryEnabled = isset($request->getParsedBody()['imaginary']);
$this->configurationManager->isFulltextsearchEnabled = isset($request->getParsedBody()['fulltextsearch']);
$this->configurationManager->isDockerSocketProxyEnabled = isset($request->getParsedBody()['docker-socket-proxy']);
$this->configurationManager->isWhiteboardEnabled = isset($request->getParsedBody()['whiteboard']);
} }
if (isset($request->getParsedBody()['community-form'])) { if (isset($request->getParsedBody()['community-form'])) {
@ -109,37 +137,35 @@ readonly class ConfigurationController {
$enabledCC[] = $item; $enabledCC[] = $item;
} }
} }
$this->configurationManager->aioCommunityContainers = $enabledCC; $this->configurationManager->SetEnabledCommunityContainers($enabledCC);
} }
if (isset($request->getParsedBody()['delete_collabora_dictionaries'])) { if (isset($request->getParsedBody()['delete_collabora_dictionaries'])) {
$this->configurationManager->deleteCollaboraDictionaries(); $this->configurationManager->DeleteCollaboraDictionaries();
} }
if (isset($request->getParsedBody()['collabora_dictionaries'])) { if (isset($request->getParsedBody()['collabora_dictionaries'])) {
$collaboraDictionaries = $request->getParsedBody()['collabora_dictionaries'] ?? ''; $collaboraDictionaries = $request->getParsedBody()['collabora_dictionaries'] ?? '';
$this->configurationManager->collaboraDictionaries = $collaboraDictionaries; $this->configurationManager->SetCollaboraDictionaries($collaboraDictionaries);
} }
if (isset($request->getParsedBody()['delete_collabora_additional_options'])) { if (isset($request->getParsedBody()['delete_collabora_additional_options'])) {
$this->configurationManager->deleteAdditionalCollaboraOptions(); $this->configurationManager->DeleteAdditionalCollaboraOptions();
} }
if (isset($request->getParsedBody()['collabora_additional_options'])) { if (isset($request->getParsedBody()['collabora_additional_options'])) {
$additionalCollaboraOptions = $request->getParsedBody()['collabora_additional_options'] ?? ''; $additionalCollaboraOptions = $request->getParsedBody()['collabora_additional_options'] ?? '';
$this->configurationManager->collaboraAdditionalOptions = $additionalCollaboraOptions; $this->configurationManager->SetAdditionalCollaboraOptions($additionalCollaboraOptions);
} }
if (isset($request->getParsedBody()['delete_borg_backup_location_vars'])) { if (isset($request->getParsedBody()['delete_borg_backup_location_vars'])) {
$this->configurationManager->deleteBorgBackupLocationItems(); $this->configurationManager->DeleteBorgBackupLocationItems();
} }
return $response->withStatus(201)->withHeader('Location', '.'); return $response->withStatus(201)->withHeader('Location', '.');
} catch (InvalidSettingConfigurationException $ex) { } catch (InvalidSettingConfigurationException $ex) {
$response->getBody()->write($ex->getMessage()); $response->getBody()->write($ex->getMessage());
return $response->withStatus(422); return $response->withStatus(422);
} finally {
$this->configurationManager->commitTransaction();
} }
} }
} }

View file

@ -89,7 +89,7 @@ readonly class DockerController {
} }
public function startBackup(bool $forceStopNextcloud = false) : void { public function startBackup(bool $forceStopNextcloud = false) : void {
$this->configurationManager->backupMode = 'backup'; $this->configurationManager->SetBackupMode('backup');
$id = self::TOP_CONTAINER; $id = self::TOP_CONTAINER;
$this->PerformRecursiveContainerStop($id, $forceStopNextcloud); $this->PerformRecursiveContainerStop($id, $forceStopNextcloud);
@ -109,25 +109,29 @@ readonly class DockerController {
} }
public function checkBackup() : void { public function checkBackup() : void {
$this->configurationManager->backupMode = 'check'; $this->configurationManager->SetBackupMode('check');
$id = 'nextcloud-aio-borgbackup'; $id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id); $this->PerformRecursiveContainerStart($id);
} }
private function listBackup() : void { private function listBackup() : void {
$this->configurationManager->backupMode = 'list'; $this->configurationManager->SetBackupMode('list');
$id = 'nextcloud-aio-borgbackup'; $id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id); $this->PerformRecursiveContainerStart($id);
} }
public function StartBackupContainerRestore(Request $request, Response $response, array $args) : Response { public function StartBackupContainerRestore(Request $request, Response $response, array $args) : Response {
$this->configurationManager->startTransaction(); $this->configurationManager->SetBackupMode('restore');
$this->configurationManager->backupMode = 'restore'; $config = $this->configurationManager->GetConfig();
$this->configurationManager->selectedRestoreTime = $request->getParsedBody()['selected_restore_time'] ?? ''; $config['selected-restore-time'] = $request->getParsedBody()['selected_restore_time'] ?? '';
$this->configurationManager->restoreExcludePreviews = isset($request->getParsedBody()['restore-exclude-previews']); if (isset($request->getParsedBody()['restore-exclude-previews'])) {
$this->configurationManager->commitTransaction(); $config['restore-exclude-previews'] = 1;
} else {
$config['restore-exclude-previews'] = '';
}
$this->configurationManager->WriteConfig($config);
$id = self::TOP_CONTAINER; $id = self::TOP_CONTAINER;
$forceStopNextcloud = true; $forceStopNextcloud = true;
@ -140,22 +144,22 @@ readonly class DockerController {
} }
public function StartBackupContainerCheckRepair(Request $request, Response $response, array $args) : Response { public function StartBackupContainerCheckRepair(Request $request, Response $response, array $args) : Response {
$this->configurationManager->backupMode = 'check-repair'; $this->configurationManager->SetBackupMode('check-repair');
$id = 'nextcloud-aio-borgbackup'; $id = 'nextcloud-aio-borgbackup';
$this->PerformRecursiveContainerStart($id); $this->PerformRecursiveContainerStart($id);
// Restore to backup check which is needed to make the UI logic work correctly // Restore to backup check which is needed to make the UI logic work correctly
$this->configurationManager->backupMode = 'check'; $this->configurationManager->SetBackupMode('check');
return $response->withStatus(201)->withHeader('Location', '.'); return $response->withStatus(201)->withHeader('Location', '.');
} }
public function StartBackupContainerTest(Request $request, Response $response, array $args) : Response { public function StartBackupContainerTest(Request $request, Response $response, array $args) : Response {
$this->configurationManager->startTransaction(); $this->configurationManager->SetBackupMode('test');
$this->configurationManager->backupMode = 'test'; $config = $this->configurationManager->GetConfig();
$this->configurationManager->instanceRestoreAttempt = false; $config['instance_restore_attempt'] = 0;
$this->configurationManager->commitTransaction(); $this->configurationManager->WriteConfig($config);
$id = self::TOP_CONTAINER; $id = self::TOP_CONTAINER;
$this->PerformRecursiveContainerStop($id); $this->PerformRecursiveContainerStop($id);
@ -178,19 +182,20 @@ readonly class DockerController {
} }
if (isset($request->getParsedBody()['install_latest_major'])) { if (isset($request->getParsedBody()['install_latest_major'])) {
$installLatestMajor = '32'; $installLatestMajor = 32;
} else { } else {
$installLatestMajor = ''; $installLatestMajor = "";
} }
$this->configurationManager->startTransaction(); $config = $this->configurationManager->GetConfig();
$this->configurationManager->installLatestMajor = $installLatestMajor;
// set AIO_URL // set AIO_URL
$this->configurationManager->aioUrl = $host . ':' . (string)$port . $path; $config['AIO_URL'] = $host . ':' . (string)$port . $path;
// set wasStartButtonClicked // set wasStartButtonClicked
$this->configurationManager->wasStartButtonClicked = true; $config['wasStartButtonClicked'] = 1;
$this->configurationManager->commitTransaction(); // set install_latest_major
$config['install_latest_major'] = $installLatestMajor;
$this->configurationManager->WriteConfig($config);
// Do not pull container images in case 'bypass_container_update' is set via url params // Do not pull container images in case 'bypass_container_update' is set via url params
// Needed for local testing // Needed for local testing
$pullImage = !isset($request->getParsedBody()['bypass_container_update']); $pullImage = !isset($request->getParsedBody()['bypass_container_update']);
@ -208,7 +213,10 @@ readonly class DockerController {
} }
public function startTopContainer(bool $pullImage) : void { public function startTopContainer(bool $pullImage) : void {
$this->configurationManager->aioToken = bin2hex(random_bytes(24)); $config = $this->configurationManager->GetConfig();
// set AIO_TOKEN
$config['AIO_TOKEN'] = bin2hex(random_bytes(24));
$this->configurationManager->WriteConfig($config);
// Stop domaincheck since apache would not be able to start otherwise // Stop domaincheck since apache would not be able to start otherwise
$this->StopDomaincheckContainer(); $this->StopDomaincheckContainer();
@ -236,7 +244,7 @@ readonly class DockerController {
// This is a hack but no better solution was found for the meantime // This is a hack but no better solution was found for the meantime
// Stop Collabora first to make sure it force-saves // Stop Collabora first to make sure it force-saves
// See https://github.com/nextcloud/richdocuments/issues/3799 // See https://github.com/nextcloud/richdocuments/issues/3799
if ($id === self::TOP_CONTAINER && $this->configurationManager->isCollaboraEnabled) { if ($id === self::TOP_CONTAINER && $this->configurationManager->isCollaboraEnabled()) {
$this->PerformRecursiveContainerStop('nextcloud-aio-collabora'); $this->PerformRecursiveContainerStop('nextcloud-aio-collabora');
} }
@ -269,7 +277,7 @@ readonly class DockerController {
public function StartDomaincheckContainer() : void public function StartDomaincheckContainer() : void
{ {
# Don't start if domain is already set # Don't start if domain is already set
if ($this->configurationManager->domain !== '' || $this->configurationManager->wasStartButtonClicked) { if ($this->configurationManager->GetDomain() !== '' || $this->configurationManager->wasStartButtonClicked()) {
return; return;
} }

File diff suppressed because it is too large Load diff

View file

@ -66,8 +66,4 @@ class DataConst {
public static function GetContainersDefinitionPath() : string { public static function GetContainersDefinitionPath() : string {
return (string)realpath(__DIR__ . '/../../containers.json'); return (string)realpath(__DIR__ . '/../../containers.json');
} }
public static function GetAioVersionFile() : string {
return (string)realpath(__DIR__ . '/../../templates/includes/aio-version.twig');
}
} }

View file

@ -17,7 +17,7 @@ readonly class Setup {
} }
$password = $this->passwordGenerator->GeneratePassword(8); $password = $this->passwordGenerator->GeneratePassword(8);
$this->configurationManager->password = $password; $this->configurationManager->SetPassword($password);
return $password; return $password;
} }

View file

@ -115,9 +115,9 @@ readonly class DockerActionManager {
$containerName = $container->identifier; $containerName = $container->identifier;
$internalPort = $container->internalPorts; $internalPort = $container->internalPorts;
if ($internalPort === '%APACHE_PORT%') { if ($internalPort === '%APACHE_PORT%') {
$internalPort = $this->configurationManager->apachePort; $internalPort = $this->configurationManager->GetApachePort();
} elseif ($internalPort === '%TALK_PORT%') { } elseif ($internalPort === '%TALK_PORT%') {
$internalPort = $this->configurationManager->talkPort; $internalPort = $this->configurationManager->GetTalkPort();
} }
if ($internalPort !== "" && $internalPort !== 'host') { if ($internalPort !== "" && $internalPort !== 'host') {
@ -205,7 +205,7 @@ readonly class DockerActionManager {
foreach ($container->volumes->GetVolumes() as $volume) { foreach ($container->volumes->GetVolumes() as $volume) {
// // NEXTCLOUD_MOUNT gets added via bind-mount later on // // NEXTCLOUD_MOUNT gets added via bind-mount later on
// if ($container->identifier === 'nextcloud-aio-nextcloud') { // if ($container->identifier === 'nextcloud-aio-nextcloud') {
// if ($volume->name === $this->configurationManager->nextcloudMount) { // if ($volume->name === $this->configurationManager->GetNextcloudMount()) {
// continue; // continue;
// } // }
// } // }
@ -228,7 +228,15 @@ readonly class DockerActionManager {
$requestBody['HostConfig']['Binds'] = $volumes; $requestBody['HostConfig']['Binds'] = $volumes;
} }
$this->configurationManager->setAioVariables($container->aioVariables->GetVariables()); $aioVariables = $container->aioVariables->GetVariables();
foreach ($aioVariables as $variable) {
$config = $this->configurationManager->GetConfig();
$variable = $this->replaceEnvPlaceholders($variable);
$variableArray = explode('=', $variable);
$config[$variableArray[0]] = $variableArray[1];
$this->configurationManager->WriteConfig($config);
sleep(1);
}
$envs = $container->containerEnvironmentVariables->GetVariables(); $envs = $container->containerEnvironmentVariables->GetVariables();
// Special thing for the nextcloud container // Special thing for the nextcloud container
@ -236,7 +244,7 @@ readonly class DockerActionManager {
$envs[] = $this->GetAllNextcloudExecCommands(); $envs[] = $this->GetAllNextcloudExecCommands();
} }
foreach ($envs as $key => $env) { foreach ($envs as $key => $env) {
$envs[$key] = $this->configurationManager->replaceEnvPlaceholders($env); $envs[$key] = $this->replaceEnvPlaceholders($env);
} }
if (count($envs) > 0) { if (count($envs) > 0) {
@ -253,13 +261,13 @@ readonly class DockerActionManager {
$port = $value->port; $port = $value->port;
$protocol = $value->protocol; $protocol = $value->protocol;
if ($port === '%APACHE_PORT%') { if ($port === '%APACHE_PORT%') {
$port = $this->configurationManager->apachePort; $port = $this->configurationManager->GetApachePort();
// Do not expose udp if AIO is in reverse proxy mode // Do not expose udp if AIO is in reverse proxy mode
if ($port !== '443' && $protocol === 'udp') { if ($port !== '443' && $protocol === 'udp') {
continue; continue;
} }
} else if ($port === '%TALK_PORT%') { } else if ($port === '%TALK_PORT%') {
$port = $this->configurationManager->talkPort; $port = $this->configurationManager->GetTalkPort();
} }
$portWithProtocol = $port . '/' . $protocol; $portWithProtocol = $port . '/' . $protocol;
$exposedPorts[$portWithProtocol] = null; $exposedPorts[$portWithProtocol] = null;
@ -275,13 +283,13 @@ readonly class DockerActionManager {
$port = $value->port; $port = $value->port;
$protocol = $value->protocol; $protocol = $value->protocol;
if ($port === '%APACHE_PORT%') { if ($port === '%APACHE_PORT%') {
$port = $this->configurationManager->apachePort; $port = $this->configurationManager->GetApachePort();
// Do not expose udp if AIO is in reverse proxy mode // Do not expose udp if AIO is in reverse proxy mode
if ($port !== '443' && $protocol === 'udp') { if ($port !== '443' && $protocol === 'udp') {
continue; continue;
} }
} else if ($port === '%TALK_PORT%') { } else if ($port === '%TALK_PORT%') {
$port = $this->configurationManager->talkPort; $port = $this->configurationManager->GetTalkPort();
// Skip publishing talk tcp port if it is set to 443 // Skip publishing talk tcp port if it is set to 443
if ($port === '443' && $protocol === 'tcp') { if ($port === '443' && $protocol === 'tcp') {
continue; continue;
@ -289,7 +297,7 @@ readonly class DockerActionManager {
} }
$ipBinding = $value->ipBinding; $ipBinding = $value->ipBinding;
if ($ipBinding === '%APACHE_IP_BINDING%') { if ($ipBinding === '%APACHE_IP_BINDING%') {
$ipBinding = $this->configurationManager->apacheIpBinding; $ipBinding = $this->configurationManager->GetApacheIPBinding();
// Do not expose if AIO is in internal network mode // Do not expose if AIO is in internal network mode
if ($ipBinding === '@INTERNAL') { if ($ipBinding === '@INTERNAL') {
continue; continue;
@ -307,7 +315,7 @@ readonly class DockerActionManager {
$devices = []; $devices = [];
foreach ($container->devices as $device) { foreach ($container->devices as $device) {
if ($device === '/dev/dri' && !$this->configurationManager->nextcloudEnableDriDevice) { if ($device === '/dev/dri' && !$this->configurationManager->isDriDeviceEnabled()) {
continue; continue;
} }
$devices[] = ["PathOnHost" => $device, "PathInContainer" => $device, "CgroupPermissions" => "rwm"]; $devices[] = ["PathOnHost" => $device, "PathInContainer" => $device, "CgroupPermissions" => "rwm"];
@ -317,7 +325,7 @@ readonly class DockerActionManager {
$requestBody['HostConfig']['Devices'] = $devices; $requestBody['HostConfig']['Devices'] = $devices;
} }
if ($container->enableNvidiaGpu && $this->configurationManager->enableNvidiaGpu) { if ($container->enableNvidiaGpu && $this->configurationManager->isNvidiaGpuEnabled()) {
$requestBody['HostConfig']['Runtime'] = 'nvidia'; $requestBody['HostConfig']['Runtime'] = 'nvidia';
$requestBody['HostConfig']['DeviceRequests'] = [ $requestBody['HostConfig']['DeviceRequests'] = [
[ [
@ -348,11 +356,6 @@ readonly class DockerActionManager {
$requestBody['HostConfig']['Init'] = $container->init; $requestBody['HostConfig']['Init'] = $container->init;
$maxShutDownTime = $container->maxShutdownTime;
if ($maxShutDownTime > 0) {
$requestBody['StopTimeout'] = $maxShutDownTime;
}
$capAdds = $container->capAdd; $capAdds = $container->capAdd;
if (count($capAdds) > 0) { if (count($capAdds) > 0) {
$requestBody['HostConfig']['CapAdd'] = $capAdds; $requestBody['HostConfig']['CapAdd'] = $capAdds;
@ -383,7 +386,7 @@ readonly class DockerActionManager {
// Make volumes read only in case of borgbackup container. The viewer makes them writeable // Make volumes read only in case of borgbackup container. The viewer makes them writeable
$isReadOnly = $container->identifier === 'nextcloud-aio-borgbackup'; $isReadOnly = $container->identifier === 'nextcloud-aio-borgbackup';
foreach ($this->configurationManager->getAdditionalBackupDirectoriesArray() as $additionalBackupDirectories) { foreach ($this->configurationManager->GetAdditionalBackupDirectoriesArray() as $additionalBackupDirectories) {
if ($additionalBackupDirectories !== '') { if ($additionalBackupDirectories !== '') {
if (!str_starts_with($additionalBackupDirectories, '/')) { if (!str_starts_with($additionalBackupDirectories, '/')) {
$mounts[] = ["Type" => "volume", "Source" => $additionalBackupDirectories, "Target" => "/docker_volumes/" . $additionalBackupDirectories, "ReadOnly" => $isReadOnly]; $mounts[] = ["Type" => "volume", "Source" => $additionalBackupDirectories, "Target" => "/docker_volumes/" . $additionalBackupDirectories, "ReadOnly" => $isReadOnly];
@ -400,7 +403,7 @@ readonly class DockerActionManager {
// // Special things for the nextcloud container which should not be exposed in the containers.json // // Special things for the nextcloud container which should not be exposed in the containers.json
// } elseif ($container->identifier === 'nextcloud-aio-nextcloud') { // } elseif ($container->identifier === 'nextcloud-aio-nextcloud') {
// foreach ($container->volumes->GetVolumes() as $volume) { // foreach ($container->volumes->GetVolumes() as $volume) {
// if ($volume->name !== $this->configurationManager->nextcloudMount) { // if ($volume->name !== $this->configurationManager->GetNextcloudMount()) {
// continue; // continue;
// } // }
// $mounts[] = ["Type" => "bind", "Source" => $volume->name, "Target" => $volume->mountPoint, "ReadOnly" => !$volume->isWritable, "BindOptions" => [ "Propagation" => "rshared"]]; // $mounts[] = ["Type" => "bind", "Source" => $volume->name, "Target" => $volume->mountPoint, "ReadOnly" => !$volume->isWritable, "BindOptions" => [ "Propagation" => "rshared"]];
@ -412,21 +415,15 @@ readonly class DockerActionManager {
// Special things for the collabora container which should not be exposed in the containers.json // Special things for the collabora container which should not be exposed in the containers.json
} elseif ($container->identifier === 'nextcloud-aio-collabora') { } elseif ($container->identifier === 'nextcloud-aio-collabora') {
if (!$this->configurationManager->collaboraSeccompDisabled) { if (!$this->configurationManager->isSeccompDisabled()) {
// Load reference seccomp profile for collabora // Load reference seccomp profile for collabora
$seccompProfile = (string)file_get_contents(DataConst::GetCollaboraSeccompProfilePath()); $seccompProfile = (string)file_get_contents(DataConst::GetCollaboraSeccompProfilePath());
$requestBody['HostConfig']['SecurityOpt'] = ["label:disable", "seccomp=$seccompProfile"]; $requestBody['HostConfig']['SecurityOpt'] = ["label:disable", "seccomp=$seccompProfile"];
} }
// Additional Collabora options // Additional Collabora options
if ($this->configurationManager->collaboraAdditionalOptions !== '') { if ($this->configurationManager->GetAdditionalCollaboraOptions() !== '') {
// Split the list of Collabora options, which are stored as a string but must be assigned as an array. $requestBody['Cmd'] = [$this->configurationManager->GetAdditionalCollaboraOptions()];
// To avoid problems with whitespace or dashes in option arguments we use a regular expression
// that splits the string at every position where a whitespace is followed by '--o:'.
// The leading whitespace is removed in the split but the following characters are not.
// Example: "--o:example_config1='some thing' --o:example_config2=something-else" -> ["--o:example_config1='some thing'", "--o:example_config2=something-else"]
$regEx = '/\s+(?=--o:)/';
$requestBody['Cmd'] = preg_split($regEx, rtrim($this->configurationManager->collaboraAdditionalOptions));
} }
} }
@ -528,6 +525,82 @@ readonly class DockerActionManager {
} }
} }
// Replaces placeholders in $envValue with their values.
// E.g. "%NC_DOMAIN%:%APACHE_PORT" becomes "my.nextcloud.com:11000"
private function replaceEnvPlaceholders(string $envValue): string {
// $pattern breaks down as:
// % - matches a literal percent sign
// ([^%]+) - capture group that matches one or more characters that are NOT percent signs
// % - matches the closing percent sign
//
// Assumes literal percent signs are always matched and there is no
// escaping.
$pattern = '/%([^%]+)%/';
$matchCount = preg_match_all($pattern, $envValue, $matches);
if ($matchCount === 0) {
return $envValue;
}
$placeholders = $matches[0]; // ["%PLACEHOLDER1%", "%PLACEHOLDER2%", ...]
$placeholderNames = $matches[1]; // ["PLACEHOLDER1", "PLACEHOLDER2", ...]
$placeholderPatterns = array_map(static fn(string $p) => '/' . preg_quote($p) . '/', $placeholders); // ["/%PLACEHOLDER1%/", ...]
$placeholderValues = array_map($this->getPlaceholderValue(...), $placeholderNames); // ["val1", "val2"]
// Guaranteed to be non-null because we found the placeholders in the preg_match_all.
return (string) preg_replace($placeholderPatterns, $placeholderValues, $envValue);
}
private function getPlaceholderValue(string $placeholder) : string {
return match ($placeholder) {
'NC_DOMAIN' => $this->configurationManager->GetDomain(),
'NC_BASE_DN' => $this->configurationManager->GetBaseDN(),
'AIO_TOKEN' => $this->configurationManager->GetToken(),
'BORGBACKUP_REMOTE_REPO' => $this->configurationManager->GetBorgRemoteRepo(),
'BORGBACKUP_MODE' => $this->configurationManager->GetBackupMode(),
'AIO_URL' => $this->configurationManager->GetAIOURL(),
'SELECTED_RESTORE_TIME' => $this->configurationManager->GetSelectedRestoreTime(),
'RESTORE_EXCLUDE_PREVIEWS' => $this->configurationManager->GetRestoreExcludePreviews(),
'APACHE_PORT' => $this->configurationManager->GetApachePort(),
'APACHE_IP_BINDING' => $this->configurationManager->GetApacheIPBinding(),
'TALK_PORT' => $this->configurationManager->GetTalkPort(),
'TURN_DOMAIN' => $this->configurationManager->GetTurnDomain(),
'NEXTCLOUD_MOUNT' => $this->configurationManager->GetNextcloudMount(),
'BACKUP_RESTORE_PASSWORD' => $this->configurationManager->GetBorgRestorePassword(),
'CLAMAV_ENABLED' => $this->configurationManager->isClamavEnabled() ? 'yes' : '',
'TALK_RECORDING_ENABLED' => $this->configurationManager->isTalkRecordingEnabled() ? 'yes' : '',
'ONLYOFFICE_ENABLED' => $this->configurationManager->isOnlyofficeEnabled() ? 'yes' : '',
'COLLABORA_ENABLED' => $this->configurationManager->isCollaboraEnabled() ? 'yes' : '',
'TALK_ENABLED' => $this->configurationManager->isTalkEnabled() ? 'yes' : '',
'UPDATE_NEXTCLOUD_APPS' => ($this->configurationManager->isDailyBackupRunning() && $this->configurationManager->areAutomaticUpdatesEnabled()) ? 'yes' : '',
'TIMEZONE' => $this->configurationManager->GetTimezone() === '' ? 'Etc/UTC' : $this->configurationManager->GetTimezone(),
'COLLABORA_DICTIONARIES' => $this->configurationManager->GetCollaboraDictionaries() === '' ? 'de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru' : $this->configurationManager->GetCollaboraDictionaries(),
'IMAGINARY_ENABLED' => $this->configurationManager->isImaginaryEnabled() ? 'yes' : '',
'FULLTEXTSEARCH_ENABLED' => $this->configurationManager->isFulltextsearchEnabled() ? 'yes' : '',
'DOCKER_SOCKET_PROXY_ENABLED' => $this->configurationManager->isDockerSocketProxyEnabled() ? 'yes' : '',
'NEXTCLOUD_UPLOAD_LIMIT' => $this->configurationManager->GetNextcloudUploadLimit(),
'NEXTCLOUD_MEMORY_LIMIT' => $this->configurationManager->GetNextcloudMemoryLimit(),
'NEXTCLOUD_MAX_TIME' => $this->configurationManager->GetNextcloudMaxTime(),
'BORG_RETENTION_POLICY' => $this->configurationManager->GetBorgRetentionPolicy(),
'FULLTEXTSEARCH_JAVA_OPTIONS' => $this->configurationManager->GetFulltextsearchJavaOptions(),
'NEXTCLOUD_TRUSTED_CACERTS_DIR' => $this->configurationManager->GetTrustedCacertsDir(),
'ADDITIONAL_DIRECTORIES_BACKUP' => $this->configurationManager->GetAdditionalBackupDirectoriesString() !== '' ? 'yes' : '',
'BORGBACKUP_HOST_LOCATION' => $this->configurationManager->GetBorgBackupHostLocation(),
'APACHE_MAX_SIZE' => (string)($this->configurationManager->GetApacheMaxSize()),
'COLLABORA_SECCOMP_POLICY' => $this->configurationManager->GetCollaboraSeccompPolicy(),
'NEXTCLOUD_STARTUP_APPS' => $this->configurationManager->GetNextcloudStartupApps(),
'NEXTCLOUD_ADDITIONAL_APKS' => $this->configurationManager->GetNextcloudAdditionalApks(),
'NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS' => $this->configurationManager->GetNextcloudAdditionalPhpExtensions(),
'INSTALL_LATEST_MAJOR' => $this->configurationManager->shouldLatestMajorGetInstalled() ? 'yes' : '',
'REMOVE_DISABLED_APPS' => $this->configurationManager->shouldDisabledAppsGetRemoved() ? 'yes' : '',
// Allow to get local ip-address of database container which allows to talk to it even in host mode (the container that requires this needs to be started first then)
'AIO_DATABASE_HOST' => gethostbyname('nextcloud-aio-database'),
// Allow to get local ip-address of caddy container and add it to trusted proxies automatically
'CADDY_IP_ADDRESS' => in_array('caddy', $this->configurationManager->GetEnabledCommunityContainers(), true) ? gethostbyname('nextcloud-aio-caddy') : '',
'WHITEBOARD_ENABLED' => $this->configurationManager->isWhiteboardEnabled() ? 'yes' : '',
default => $this->configurationManager->GetRegisteredSecret($placeholder),
};
}
private function isContainerUpdateAvailable(string $id): string { private function isContainerUpdateAvailable(string $id): string {
$container = $this->containerDefinitionFetcher->GetContainerById($id); $container = $this->containerDefinitionFetcher->GetContainerById($id);
@ -543,7 +616,7 @@ readonly class DockerActionManager {
public function isAnyUpdateAvailable(): bool { public function isAnyUpdateAvailable(): bool {
// return early if instance is not installed // return early if instance is not installed
if (!$this->configurationManager->wasStartButtonClicked) { if (!$this->configurationManager->wasStartButtonClicked()) {
return false; return false;
} }
$id = 'nextcloud-aio-apache'; $id = 'nextcloud-aio-apache';
@ -843,7 +916,7 @@ readonly class DockerActionManager {
$this->ConnectContainerIdToNetwork($container->identifier, $container->internalPorts, alias: $alias); $this->ConnectContainerIdToNetwork($container->identifier, $container->internalPorts, alias: $alias);
if ($container->identifier === 'nextcloud-aio-apache' || $container->identifier === 'nextcloud-aio-domaincheck') { if ($container->identifier === 'nextcloud-aio-apache' || $container->identifier === 'nextcloud-aio-domaincheck') {
$apacheAdditionalNetwork = $this->configurationManager->getApacheAdditionalNetwork(); $apacheAdditionalNetwork = $this->configurationManager->GetApacheAdditionalNetwork();
if ($apacheAdditionalNetwork !== '') { if ($apacheAdditionalNetwork !== '') {
$this->ConnectContainerIdToNetwork($container->identifier, $container->internalPorts, $apacheAdditionalNetwork, false, $alias); $this->ConnectContainerIdToNetwork($container->identifier, $container->internalPorts, $apacheAdditionalNetwork, false, $alias);
} }
@ -946,7 +1019,7 @@ readonly class DockerActionManager {
} }
public function GetAndGenerateSecretWrapper(string $secretId): string { public function GetAndGenerateSecretWrapper(string $secretId): string {
return $this->configurationManager->getAndGenerateSecret($secretId); return $this->configurationManager->GetAndGenerateSecret($secretId);
} }
public function isNextcloudImageOutdated(): bool { public function isNextcloudImageOutdated(): bool {

View file

@ -27,7 +27,7 @@
<script type="text/javascript" src="timezone.js"></script> <script type="text/javascript" src="timezone.js"></script>
{# js for optional containers and additional containers forms #} {# js for optional containers and additional containers forms #}
<script type="text/javascript" src="containers-form-submit.js?v5"></script> <script type="text/javascript" src="containers-form-submit.js?v4"></script>
{% set hasBackupLocation = borg_backup_host_location or borg_remote_repo %} {% set hasBackupLocation = borg_backup_host_location or borg_remote_repo %}
{% set isAnyRunning = false %} {% set isAnyRunning = false %}

View file

@ -1 +1 @@
12.6.1 12.5.0

View file

@ -9,105 +9,6 @@
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}"> <input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}"> <input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
<input type="hidden" name="options-form" value="options-form"> <input type="hidden" name="options-form" value="options-form">
<h3>Office Suite</h3>
{% if isAnyRunning == false %}
<p>Choose your preferred office suite. Only one can be enabled at a time.</p>
{% endif %}
<div class="office-suite-cards">
<input
type="radio"
id="office-collabora"
name="office_suite_choice"
value="collabora"
class="office-radio"
{% if is_collabora_enabled == true %}
checked="checked"
{% endif %}
>
<label class="office-card{{ isAnyRunning ? ' office-card-disabled' : '' }}" for="office-collabora">
<div class="office-card-header">
<h4>Nextcloud Office</h4>
<svg class="office-checkmark" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" fill="var(--color-nextcloud-blue)"/>
<path d="M7 12L10.5 15.5L17 9" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<ul class="office-features">
<li>Best Nextcloud integration</li>
<li>Open source</li>
<li>Good performance</li>
<li>Best security: documents never leave your server</li>
<li>Best ODF compatibility</li>
<li>Best support for legacy files</li>
</ul>
{% if isAnyRunning == false %}
<a href="https://www.collaboraoffice.com/code/" target="_blank" class="office-learn-more" onclick="event.stopPropagation();">
Learn more
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-left: 4px;">
<path d="M6 12L10 8L6 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
{% endif %}
</label>
<input type="hidden" id="collabora" name="collabora" value="" data-initial-state="{% if is_collabora_enabled == true %}true{% else %}false{% endif %}">
<input
type="radio"
id="office-onlyoffice"
name="office_suite_choice"
value="onlyoffice"
class="office-radio"
{% if is_onlyoffice_enabled == true %}
checked="checked"
{% endif %}
>
<label class="office-card{{ isAnyRunning ? ' office-card-disabled' : '' }}" for="office-onlyoffice">
<div class="office-card-header">
<h4>OnlyOffice</h4>
<svg class="office-checkmark" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" fill="var(--color-nextcloud-blue)"/>
<path d="M7 12L10.5 15.5L17 9" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<ul class="office-features">
<li>Good Nextcloud integration</li>
<li>Open core</li>
<li>Best performance</li>
<li>Limited ODF compatibility</li>
<li>Best Microsoft compatibility</li>
</ul>
{% if isAnyRunning == false %}
<a href="https://www.onlyoffice.com/" target="_blank" class="office-learn-more" onclick="event.stopPropagation();">
Learn more
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-left: 4px;">
<path d="M6 12L10 8L6 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
{% endif %}
</label>
<input type="hidden" id="onlyoffice" name="onlyoffice" value="" data-initial-state="{% if is_onlyoffice_enabled == true %}true{% else %}false{% endif %}">
</div>
{% if isAnyRunning == false %}
<div class="office-none-card">
<input
type="radio"
id="office-none"
name="office_suite_choice"
value=""
class="office-radio"
{% if is_collabora_enabled == false and is_onlyoffice_enabled == false %}
checked="checked"
{% endif %}
>
<label class="office-none-label" for="office-none">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-right: 6px;">
<path d="M2 2L14 14M2 14L14 2" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Disable office suite
</label>
</div>
{% endif %}
<input class="options-form-submit" type="submit" value="Save changes" />
<h3>Additional Optional Containers</h3>
<p> <p>
<input <input
type="checkbox" type="checkbox"
@ -122,6 +23,20 @@
> >
<label for="clamav">ClamAV (Antivirus backend for Nextcloud, needs ~1GB additional RAM)</label> <label for="clamav">ClamAV (Antivirus backend for Nextcloud, needs ~1GB additional RAM)</label>
</p> </p>
<p>
<input
type="checkbox"
id="collabora"
name="collabora"
{% if is_collabora_enabled == true %}
checked="checked"
data-initial-state="true"
{% else %}
data-initial-state="false"
{% endif %}
>
<label for="collabora">Collabora (Nextcloud Office)</label>
</p>
<p> <p>
<input <input
type="checkbox" type="checkbox"
@ -183,7 +98,20 @@
> >
<label for="talk-recording">Nextcloud Talk Recording-server (needs Nextcloud Talk being enabled and ~1GB additional RAM and ~2 additional vCPUs)</label> <label for="talk-recording">Nextcloud Talk Recording-server (needs Nextcloud Talk being enabled and ~1GB additional RAM and ~2 additional vCPUs)</label>
</p> </p>
<p>
<input
type="checkbox"
id="onlyoffice"
name="onlyoffice"
{% if is_onlyoffice_enabled == true %}
checked="checked"
data-initial-state="true"
{% else %}
data-initial-state="false"
{% endif %}
>
<label for="onlyoffice">OnlyOffice</label>
</p>
<p> <p>
<input <input
type="checkbox" type="checkbox"
@ -212,15 +140,15 @@
> >
<label for="whiteboard">Whiteboard</label> <label for="whiteboard">Whiteboard</label>
</p> </p>
<input class="options-form-submit" type="submit" value="Save changes" /> <input id="options-form-submit" type="submit" value="Save changes" />
</form> </form>
<p><strong>Minimal system requirements:</strong> When any optional container is enabled, at least 2GB RAM, a dual-core CPU and 40GB system storage are required. When enabling ClamAV, Nextcloud Talk Recording-server or Fulltextsearch, at least 3GB RAM are required. For Talk Recording-server additional 2 vCPUs are required. When enabling everything, at least 5GB RAM and a quad-core CPU are required. Recommended are at least 1GB more RAM than the minimal requirement. For further advice and recommendations see <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/1335">this documentation</a></strong></p> <p><strong>Minimal system requirements:</strong> When any optional container is enabled, at least 2GB RAM, a dual-core CPU and 40GB system storage are required. When enabling ClamAV, Nextcloud Talk Recording-server or Fulltextsearch, at least 3GB RAM are required. For Talk Recording-server additional 2 vCPUs are required. When enabling everything, at least 5GB RAM and a quad-core CPU are required. Recommended are at least 1GB more RAM than the minimal requirement. For further advice and recommendations see <strong><a target="_blank" href="https://github.com/nextcloud/all-in-one/discussions/1335">this documentation</a></strong></p>
{% if isAnyRunning == true %} {% if isAnyRunning == true %}
<script type="text/javascript" src="disable-clamav.js"></script> <script type="text/javascript" src="disable-clamav.js"></script>
<script type="text/javascript" src="disable-docker-socket-proxy.js"></script> <script type="text/javascript" src="disable-docker-socket-proxy.js"></script>
<script type="text/javascript" src="disable-talk.js"></script> <script type="text/javascript" src="disable-talk.js"></script>
<script type="text/javascript" src="disable-collabora.js?v2"></script> <script type="text/javascript" src="disable-collabora.js"></script>
<script type="text/javascript" src="disable-onlyoffice.js?v2"></script> <script type="text/javascript" src="disable-onlyoffice.js"></script>
<script type="text/javascript" src="disable-imaginary.js"></script> <script type="text/javascript" src="disable-imaginary.js"></script>
<script type="text/javascript" src="disable-fulltextsearch.js"></script> <script type="text/javascript" src="disable-fulltextsearch.js"></script>
<script type="text/javascript" src="disable-talk-recording.js"></script> <script type="text/javascript" src="disable-talk-recording.js"></script>
@ -228,46 +156,46 @@
{% endif %} {% endif %}
{% if is_collabora_enabled == true and isAnyRunning == false and was_start_button_clicked == true %} {% if is_collabora_enabled == true and isAnyRunning == false and was_start_button_clicked == true %}
<h3>Nextcloud Office dictionaries</h3> <h3>Collabora dictionaries</h3>
{% if collabora_dictionaries == "" %} {% if collabora_dictionaries == "" %}
<p>In order to get the correct dictionaries in Nextcloud Office, you may configure the dictionaries below:</p> <p>In order to get the correct dictionaries in Collabora, you may configure the dictionaries below:</p>
<form method="POST" action="api/configuration" class="xhr"> <form method="POST" action="api/configuration" class="xhr">
<input type="text" name="collabora_dictionaries" placeholder="de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru" /> <input type="text" name="collabora_dictionaries" placeholder="de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru" />
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}"> <input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}"> <input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
<input type="submit" value="Submit Nextcloud Office dictionaries" /> <input type="submit" value="Submit collabora dictionaries" />
</form> </form>
<p>You need to make sure that the dictionaries that you enter are valid. An example is <strong>de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru</strong>.</p> <p>You need to make sure that the dictionaries that you enter are valid. An example is <strong>de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru</strong>.</p>
{% else %} {% else %}
<p>The dictionaries for Nextcloud Office are currently set to <strong>{{ collabora_dictionaries }}</strong>. You can reset them again by clicking on the button below.</p> <p>The dictionaries for Collabora are currently set to <strong>{{ collabora_dictionaries }}</strong>. You can reset them again by clicking on the button below.</p>
<form method="POST" action="api/configuration" class="xhr"> <form method="POST" action="api/configuration" class="xhr">
<input type="hidden" name="delete_collabora_dictionaries" value="yes"/> <input type="hidden" name="delete_collabora_dictionaries" value="yes"/>
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}"> <input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}"> <input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
<input type="submit" value="Reset Nextcloud Office dictionaries" /> <input type="submit" value="Reset collabora dictionaries" />
</form> </form>
{% endif %} {% endif %}
<h3>Additional Nextcloud Office options</h3> <h3>Additional Collabora options</h3>
{% if collabora_additional_options == "" %} {% if collabora_additional_options == "" %}
<p>You can configure additional options for Nextcloud Office below.</p> <p>You can configure additional options for collabora below.</p>
<p>(This can be used for configuring the net.content_security_policy and more. Make sure to submit the value!)</p> <p>(This can be used for configuring the net.content_security_policy and more. Make sure to submit the value!)</p>
<form method="POST" action="api/configuration" class="xhr"> <form method="POST" action="api/configuration" class="xhr">
<input type="text" name="collabora_additional_options" /> <input type="text" name="collabora_additional_options" />
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}"> <input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}"> <input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
<input type="submit" value="Submit additional Nextcloud Office options" /> <input type="submit" value="Submit additional collabora options" />
</form> </form>
<p>You need to make sure that the options that you enter are valid. An example is <strong>--o:net.content_security_policy=frame-ancestors *.example.com:*;</strong>.</p> <p>You need to make sure that the options that you enter are valid. An example is <strong>--o:net.content_security_policy=frame-ancestors *.example.com:*;</strong>.</p>
{% else %} {% else %}
<p>The additioinal options for Nextcloud Office are currently set to <strong>{{ collabora_additional_options }}</strong>. You can reset them again by clicking on the button below.</p> <p>The additioinal options for Collabora are currently set to <strong>{{ collabora_additional_options }}</strong>. You can reset them again by clicking on the button below.</p>
<form method="POST" action="api/configuration" class="xhr"> <form method="POST" action="api/configuration" class="xhr">
<input type="hidden" name="delete_collabora_additional_options" value="yes"/> <input type="hidden" name="delete_collabora_additional_options" value="yes"/>
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}"> <input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}"> <input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">
<input type="submit" value="Reset additional Nextcloud Office options" /> <input type="submit" value="Reset additional collabora options" />
</form> </form>
{% endif %} {% endif %}
{% endif %} {% endif %}

View file

@ -1,7 +1,7 @@
<html> <html>
<head> <head>
<title>AIO</title> <title>AIO</title>
<link rel="stylesheet" href="style.css?v7" media="all" /> <link rel="stylesheet" href="style.css?v6" media="all" />
<link rel="icon" href="img/favicon.png"> <link rel="icon" href="img/favicon.png">
<script type="text/javascript" src="forms.js"></script> <script type="text/javascript" src="forms.js"></script>
<script type="text/javascript" src="toggle-dark-mode.js"></script> <script type="text/javascript" src="toggle-dark-mode.js"></script>

View file

@ -32,12 +32,12 @@ test('Initial setup', async ({ page: setupPage }) => {
await containersPage.locator('#talk').uncheck(); await containersPage.locator('#talk').uncheck();
await containersPage.getByRole('checkbox', { name: 'Whiteboard' }).uncheck(); await containersPage.getByRole('checkbox', { name: 'Whiteboard' }).uncheck();
await containersPage.getByRole('checkbox', { name: 'Imaginary' }).uncheck(); await containersPage.getByRole('checkbox', { name: 'Imaginary' }).uncheck();
await containersPage.getByText('Disable office suite').click(); await containersPage.getByRole('checkbox', { name: 'Collabora' }).uncheck();
await containersPage.getByRole('button', { name: 'Save changes' }).last().click(); await containersPage.getByRole('button', { name: 'Save changes' }).click();
await expect(containersPage.locator('#talk')).not.toBeChecked() await expect(containersPage.locator('#talk')).not.toBeChecked()
await expect(containersPage.getByRole('checkbox', { name: 'Whiteboard' })).not.toBeChecked() await expect(containersPage.getByRole('checkbox', { name: 'Whiteboard' })).not.toBeChecked()
await expect(containersPage.getByRole('checkbox', { name: 'Imaginary' })).not.toBeChecked() await expect(containersPage.getByRole('checkbox', { name: 'Imaginary' })).not.toBeChecked()
await expect(containersPage.locator('#office-none')).toBeChecked() await expect(containersPage.getByRole('checkbox', { name: 'Collabora' })).not.toBeChecked()
// Reject invalid time zones // Reject invalid time zones
await containersPage.locator('#timezone').click(); await containersPage.locator('#timezone').click();

View file

@ -74,7 +74,7 @@ test('Restore instance', async ({ page: setupPage }) => {
dialog.accept() dialog.accept()
}); });
await containersPage.getByRole('button', { name: 'Start and update containers' }).click(); await containersPage.getByRole('button', { name: 'Start and update containers' }).click();
await expect(containersPage.getByRole('link', { name: 'Open your Nextcloud ↗' })).toBeVisible({ timeout: 8 * 60 * 1000 }); await expect(containersPage.getByRole('link', { name: 'Open your Nextcloud ↗' })).toBeVisible({ timeout: 5 * 60 * 1000 });
await expect(containersPage.getByRole('main')).toContainText(initialNextcloudPassword); await expect(containersPage.getByRole('main')).toContainText(initialNextcloudPassword);
// Verify that containers are all stopped // Verify that containers are all stopped

View file

@ -4,5 +4,7 @@ rules:
dangerous-triggers: dangerous-triggers:
ignore: ignore:
- build_images.yml - build_images.yml
artipacked: unpinned-uses:
disable: true config:
policies:
actions/*: ref-pin