From 1162dcf5483a0aa37c7c0093b7985d9c39af464d Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" Date: Mon, 9 Feb 2026 15:23:24 +0100 Subject: [PATCH 01/22] IONOS(build): update build artifact pipeline to restore apps from cache and JFrog Signed-off-by: Misha M.-Kupriyanov --- .github/workflows/build-artifact.yml | 198 ++++++++++++++------------- 1 file changed, 105 insertions(+), 93 deletions(-) diff --git a/.github/workflows/build-artifact.yml b/.github/workflows/build-artifact.yml index ae9148c3ffc06..39f8496ae7ec7 100644 --- a/.github/workflows/build-artifact.yml +++ b/.github/workflows/build-artifact.yml @@ -478,7 +478,6 @@ jobs: fetch-depth: 1 - name: Setup JFrog CLI - if: needs.prepare-matrix.outputs.has_apps_to_restore == 'true' uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.4.1 env: JF_URL: ${{ secrets.JF_ARTIFACTORY_URL }} @@ -490,29 +489,111 @@ jobs: # Ping the server jf rt ping - - name: Restore cached apps - if: needs.prepare-matrix.outputs.has_apps_to_restore == 'true' + - name: Restore all apps from cache and JFrog run: | set -e - echo "📦 Restoring cached apps..." - APPS_TO_RESTORE='${{ needs.prepare-matrix.outputs.apps_to_restore }}' + # Restore apps that are in cache (from apps_to_restore) + if [ "${{ needs.prepare-matrix.outputs.has_apps_to_restore }}" == "true" ]; then + echo "📦 Restoring cached apps..." + APPS_TO_RESTORE='${{ needs.prepare-matrix.outputs.apps_to_restore }}' - # Process each app in the restore list - echo "$APPS_TO_RESTORE" | jq -c '.[]' | while read -r app_json; do - APP_NAME=$(echo "$app_json" | jq -r '.name') - APP_SHA=$(echo "$app_json" | jq -r '.sha') - APP_PATH=$(echo "$app_json" | jq -r '.path') - SOURCE=$(echo "$app_json" | jq -r '.source') + # Process each app in the restore list + echo "$APPS_TO_RESTORE" | jq -c '.[]' | while read -r app_json; do + APP_NAME=$(echo "$app_json" | jq -r '.name') + APP_SHA=$(echo "$app_json" | jq -r '.sha') + APP_PATH=$(echo "$app_json" | jq -r '.path') + SOURCE=$(echo "$app_json" | jq -r '.source') + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Restoring: $APP_NAME (source: $SOURCE)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + if [ "$SOURCE" == "jfrog" ]; then + # Restore from JFrog + JFROG_PATH=$(echo "$app_json" | jq -r '.jfrog_path') + ARCHIVE_NAME="${APP_NAME}-${APP_SHA}.tar.gz" + + echo "📥 Downloading from JFrog: $JFROG_PATH" + + if jf rt download "$JFROG_PATH" "$ARCHIVE_NAME" --flat=true; then + echo "✅ Downloaded successfully" + echo "Extracting to $APP_PATH..." + mkdir -p "$(dirname "$APP_PATH")" + tar -xzf "$ARCHIVE_NAME" -C "$(dirname "$APP_PATH")" + + if [ -d "$APP_PATH" ] && [ -f "$APP_PATH/appinfo/info.xml" ]; then + echo "✅ Restored $APP_NAME from JFrog" + else + echo "❌ Failed to extract or validate $APP_NAME" + exit 1 + fi + + rm -f "$ARCHIVE_NAME" + else + echo "❌ Failed to download from JFrog" + exit 1 + fi + + elif [ "$SOURCE" == "github-cache" ]; then + # Restore from GitHub cache + CACHE_KEY=$(echo "$app_json" | jq -r '.cache_key') + + echo "💾 Restoring from GitHub cache: $CACHE_KEY" + + # Use actions/cache/restore in a way that works in a script context + # We need to use gh CLI to restore the cache + if gh cache restore "$CACHE_KEY" --key "$CACHE_KEY"; then + echo "✅ Restored $APP_NAME from GitHub cache" + + # Validate restoration + if [ ! -d "$APP_PATH" ] || [ ! -f "$APP_PATH/appinfo/info.xml" ]; then + echo "❌ Validation failed for $APP_NAME" + exit 1 + fi + else + echo "❌ Failed to restore from GitHub cache" + exit 1 + fi + else + echo "❌ Unknown source: $SOURCE" + exit 1 + fi + done + + echo "" + echo "✅ All cached apps restored successfully" + fi + + # Also restore newly built apps from JFrog (from apps_to_build) + if [ "${{ needs.prepare-matrix.outputs.has_apps_to_build }}" == "true" ]; then echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "Restoring: $APP_NAME (source: $SOURCE)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📦 Restoring newly built apps from JFrog..." + APPS_TO_BUILD='${{ needs.prepare-matrix.outputs.apps_to_build }}' + FULL_MATRIX='${{ needs.prepare-matrix.outputs.external_apps_matrix }}' + EFFECTIVE_CACHE_VERSION="${{ needs.prepare-matrix.outputs.effective_cache_version }}" + + # Process each app in the build list + echo "$APPS_TO_BUILD" | jq -c '.[]' | while read -r app_json; do + APP_NAME=$(echo "$app_json" | jq -r '.name') + APP_SHA=$(echo "$app_json" | jq -r '.sha') + + # Get app path from full matrix + APP_PATH=$(echo "$FULL_MATRIX" | jq -r --arg name "$APP_NAME" '.[] | select(.name == $name) | .path') + + if [ -z "$APP_PATH" ] || [ "$APP_PATH" == "null" ]; then + echo "❌ Could not find path for $APP_NAME in matrix" + exit 1 + fi + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Restoring newly built: $APP_NAME" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - if [ "$SOURCE" == "jfrog" ]; then - # Restore from JFrog - JFROG_PATH=$(echo "$app_json" | jq -r '.jfrog_path') + # Construct JFrog path matching what build-external-apps uploaded + JFROG_PATH="${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/apps/${EFFECTIVE_CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${APP_SHA}.tar.gz" ARCHIVE_NAME="${APP_NAME}-${APP_SHA}.tar.gz" echo "📥 Downloading from JFrog: $JFROG_PATH" @@ -535,88 +616,19 @@ jobs: echo "❌ Failed to download from JFrog" exit 1 fi + done - elif [ "$SOURCE" == "github-cache" ]; then - # Restore from GitHub cache - CACHE_KEY=$(echo "$app_json" | jq -r '.cache_key') - - echo "💾 Restoring from GitHub cache: $CACHE_KEY" - - # Use actions/cache/restore in a way that works in a script context - # We need to use gh CLI to restore the cache - if gh cache restore "$CACHE_KEY" --key "$CACHE_KEY"; then - echo "✅ Restored $APP_NAME from GitHub cache" - - # Validate restoration - if [ ! -d "$APP_PATH" ] || [ ! -f "$APP_PATH/appinfo/info.xml" ]; then - echo "❌ Validation failed for $APP_NAME" - exit 1 - fi - else - echo "❌ Failed to restore from GitHub cache" - exit 1 - fi - else - echo "❌ Unknown source: $SOURCE" - exit 1 - fi - done + echo "" + echo "✅ All newly built apps restored from JFrog successfully" + fi echo "" - echo "✅ All cached apps restored successfully" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "✅ All apps restored successfully" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" env: GH_TOKEN: ${{ github.token }} - - name: Download build external apps - uses: actions/download-artifact@v5 - with: - pattern: external-app-build-* - path: apps-external/ - - - name: Reorganize downloaded apps-external artifacts - run: | - cd apps-external/ - - echo "Initial structure:" - ls -la - - # Move contents from external-app-build-* directories to their target directories - for artifact_dir in external-app-build-*; do - if [ -d "$artifact_dir" ]; then - # Extract app name from artifact directory name - app_name=${artifact_dir#external-app-build-} - - echo "Processing artifact: $artifact_dir -> $app_name" - - # If target directory exists, merge the contents from the artifact directory containing build artifacts - if [ -d "$app_name" ]; then - echo "Target directory $app_name exists, merging contents from $artifact_dir" - # Copy contents from artifact directory to target directory - cp -r "$artifact_dir"/* "$app_name"/ - # Remove the now-empty artifact directory - rm -rf "$artifact_dir" - else - # Move the artifact directory to the proper app name - echo "Moving $artifact_dir to $app_name" - mv "$artifact_dir" "$app_name" - fi - fi - done - - echo "Reorganization complete. Final structure:" - ls -la - - - name: Verify downloaded artifacts structure - run: | - echo "External apps structure:" - ls -la apps-external/ - for app_dir in apps-external/*/; do - if [ -d "$app_dir" ]; then - echo "Contents of $app_dir:" - ls -la "$app_dir" - fi - done - - name: Set up node with version from package.json's engines uses: actions/setup-node@v6 with: From ba522821b2615921235cc6b9d4ea7f06fe5fc776 Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" Date: Mon, 9 Feb 2026 17:19:00 +0100 Subject: [PATCH 02/22] IONOS(build): update upload condition to include manual workflow_dispatch for artifact uploads --- .github/workflows/build-artifact.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-artifact.yml b/.github/workflows/build-artifact.yml index 39f8496ae7ec7..45f53ba1b1bed 100644 --- a/.github/workflows/build-artifact.yml +++ b/.github/workflows/build-artifact.yml @@ -710,10 +710,10 @@ jobs: upload-to-artifactory: runs-on: self-hosted - # Upload the artifact to the Artifactory repository on PR *OR* on "ionos-dev|ionos-stable|rc/*" branch push defined in the on:push:branches + # Upload the artifact to the Artifactory repository on PR *OR* on "ionos-dev|ionos-stable|rc/*" branch push defined in the on:push:branches *OR* on manual workflow_dispatch if: | always() && - (github.event_name == 'pull_request' || github.ref_name == 'ionos-dev' || github.ref_name == 'ionos-stable' || startsWith(github.ref_name, 'rc/')) && + (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' || github.ref_name == 'ionos-dev' || github.ref_name == 'ionos-stable' || startsWith(github.ref_name, 'rc/')) && needs.prepare-matrix.result == 'success' && (needs.build-external-apps.result == 'success' || needs.build-external-apps.result == 'skipped') && needs.build-artifact.result == 'success' From f2fb683e6abe40395b72c3d323cc5c0ed4f70954 Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" <145785698+printminion-co@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:11:27 +0100 Subject: [PATCH 03/22] Update .github/workflows/build-artifact.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Misha M.-Kupriyanov <145785698+printminion-co@users.noreply.github.com> --- .github/workflows/build-artifact.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-artifact.yml b/.github/workflows/build-artifact.yml index 45f53ba1b1bed..f2f0d2a36dd77 100644 --- a/.github/workflows/build-artifact.yml +++ b/.github/workflows/build-artifact.yml @@ -491,7 +491,7 @@ jobs: - name: Restore all apps from cache and JFrog run: | - set -e + set -euo pipefail # Restore apps that are in cache (from apps_to_restore) if [ "${{ needs.prepare-matrix.outputs.has_apps_to_restore }}" == "true" ]; then From 265cdac3624fb8fad7e9cb896e6eb3618cfefad1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 09:18:48 +0000 Subject: [PATCH 04/22] IONOS(config): update submodule bacda90 (feat(update-user-email): add script to update Nextcloud user email) https://github.com/IONOS-Productivity/ncw-config/releases/tag/bacda90 Signed-off-by: github-actions[bot] --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index 66c2a3ad8087a..bacda907219ef 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit 66c2a3ad8087a35b4f276990bd53aa66c948c969 +Subproject commit bacda907219ef50d09e60f9cd9d1667708135606 From 43e439b5306fee15fdc015cfba0d99f5b6b5fe4f Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Thu, 5 Feb 2026 16:07:32 +0100 Subject: [PATCH 05/22] IONOS(activity): Switch activity app to IONOS fork To update your local repo cd ncw-server rm -rf .git/modules/apps-external/activity git submodule deinit -f apps-external/activity git pull git submodule update --init --recursive apps-external/activity git submodule sync apps-external/activity Verify the change: cd apps-external/activity git remote -v Signed-off-by: Kai Henseler --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index a7c0d60e7e858..37edeacb61d4e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -24,7 +24,7 @@ url = git@github.com:nextcloud/notify_push.git [submodule "apps-external/activity"] path = apps-external/activity - url = git@github.com:nextcloud/activity.git + url = git@github.com:IONOS-Productivity/nc-activity.git [submodule "apps-external/tasks"] path = apps-external/tasks url = git@github.com:nextcloud/tasks.git From 2604d51660102b23a5e5c3668d06910b416615ca Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Fri, 6 Feb 2026 09:18:23 +0100 Subject: [PATCH 06/22] IONOS(copilot): eductate copilot on recurring workflow docs Signed-off-by: Kai Henseler --- .github/copilot-instructions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 9e39697a38799..a4b5255e3257a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -166,6 +166,7 @@ The development container provides several convenience features for development: * Pay attention to the IONOS-specific scripts and configurations when working on related features. * Use the `IONOS/configure.sh` script for most configuration tasks rather than manual OCC commands. * Before committing any changes, make sure to run the relevant tests and linters. +* **Recurring Tasks Documentation:** For common development tasks (e.g., delegating settings to admin, adding apps, etc.), check `..//docs/recurring-tasks/` for step-by-step guides. ## Code Organization & Structure From 915737a767257d4ae0570cdd7c2a15123a1283d0 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Fri, 6 Feb 2026 09:18:57 +0100 Subject: [PATCH 07/22] IONOS(activity): update submodule (delegate settings) Signed-off-by: Kai Henseler --- apps-external/activity | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps-external/activity b/apps-external/activity index d5a969a1c52a7..ca3cd2e5e5883 160000 --- a/apps-external/activity +++ b/apps-external/activity @@ -1 +1 @@ -Subproject commit d5a969a1c52a7fbc42431df0949f383933419576 +Subproject commit ca3cd2e5e58839d62e5ec3e6afbac0b58d52f8a0 From ae62a61a454c75deeba8aa2b2c1b50b720275cda Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Fri, 6 Feb 2026 09:19:40 +0100 Subject: [PATCH 08/22] IONOS(config): update submodule (add delegated activity settings) Signed-off-by: Kai Henseler --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index bacda907219ef..c6b270f0fced4 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit bacda907219ef50d09e60f9cd9d1667708135606 +Subproject commit c6b270f0fced4f741442cab01b5cb68df70c46bb From f93f0ad286fe5d8d540b4e923721100909828507 Mon Sep 17 00:00:00 2001 From: Arsalan Ul Haq Sohni Date: Wed, 11 Feb 2026 14:11:00 +0100 Subject: [PATCH 09/22] IONOS(files_pdfviewer): add submodule v31.0.13 (21125af) Signed-off-by: Arsalan Ul Haq Sohni --- .gitmodules | 3 +++ apps-external/files_pdfviewer | 1 + 2 files changed, 4 insertions(+) create mode 160000 apps-external/files_pdfviewer diff --git a/.gitmodules b/.gitmodules index 37edeacb61d4e..6592e74a508ff 100644 --- a/.gitmodules +++ b/.gitmodules @@ -91,3 +91,6 @@ [submodule "apps-external/ncw_tools"] path = apps-external/ncw_tools url = git@github.com:IONOS-Productivity/ncw-tools.git +[submodule "apps-external/files_pdfviewer"] + path = apps-external/files_pdfviewer + url = git@github.com:nextcloud/files_pdfviewer.git diff --git a/apps-external/files_pdfviewer b/apps-external/files_pdfviewer new file mode 160000 index 0000000000000..21125af4ab4a8 --- /dev/null +++ b/apps-external/files_pdfviewer @@ -0,0 +1 @@ +Subproject commit 21125af4ab4a8c2f9784fc4cd66cdae85a41ed4e From b83bec1898cb59e415e0505a2196cfd23491a4bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 11:35:06 +0000 Subject: [PATCH 10/22] IONOS(config): update submodule bdfd74f (build: enable files_pdfviewer app in configuration and Makefile) https://github.com/IONOS-Productivity/ncw-config/releases/tag/bdfd74f Signed-off-by: github-actions[bot] --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index c6b270f0fced4..bdfd74fa9f566 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit c6b270f0fced4f741442cab01b5cb68df70c46bb +Subproject commit bdfd74fa9f566f10d455ff90c039286fb73ad7ac From f392cc91b9d4c2283deb787ac1430051b391a3cb Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Wed, 11 Feb 2026 15:53:19 +0100 Subject: [PATCH 11/22] IONOS(config): update submodule (add flag to hide dev notice) Signed-off-by: Kai Henseler Signed-off-by: Arsalan Ul Haq Sohni --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index bdfd74fa9f566..4192e9c9b70de 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit bdfd74fa9f566f10d455ff90c039286fb73ad7ac +Subproject commit 4192e9c9b70debc433fe1365827f683592e00e41 From c8cb7486e98257d3df5f5e9eec1510eb33390387 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Wed, 11 Feb 2026 15:54:06 +0100 Subject: [PATCH 12/22] IONOS(Settings): hide footer depending on config flag Signed-off-by: Kai Henseler --- apps/settings/lib/Settings/Personal/ServerDevNotice.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/settings/lib/Settings/Personal/ServerDevNotice.php b/apps/settings/lib/Settings/Personal/ServerDevNotice.php index 71c83740b9291..916d69e97d1da 100644 --- a/apps/settings/lib/Settings/Personal/ServerDevNotice.php +++ b/apps/settings/lib/Settings/Personal/ServerDevNotice.php @@ -15,6 +15,7 @@ use OCP\Settings\ISettings; use OCP\Support\Subscription\IRegistry; use OCP\Util; +use OCP\IConfig; class ServerDevNotice implements ISettings { @@ -25,6 +26,7 @@ public function __construct( private IUserSession $userSession, private IInitialState $initialState, private IURLGenerator $urlGenerator, + private IConfig $config, ) { } @@ -62,6 +64,10 @@ public function getSection(): ?string { return null; } + if ($this->config->getSystemValueBool('settings.hide-dev-notice')) { + return null; + } + return 'personal-info'; } From 637cd74e69e1f0cf7e24846cfd2487bf51820a12 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Wed, 11 Feb 2026 11:01:15 +0100 Subject: [PATCH 13/22] IONOS(bruteforcesettings): add new submodule Signed-off-by: Kai Henseler --- .gitmodules | 3 +++ apps-external/bruteforcesettings | 1 + 2 files changed, 4 insertions(+) create mode 160000 apps-external/bruteforcesettings diff --git a/.gitmodules b/.gitmodules index 6592e74a508ff..fab07b1b89865 100644 --- a/.gitmodules +++ b/.gitmodules @@ -94,3 +94,6 @@ [submodule "apps-external/files_pdfviewer"] path = apps-external/files_pdfviewer url = git@github.com:nextcloud/files_pdfviewer.git +[submodule "apps-external/bruteforcesettings"] + path = apps-external/bruteforcesettings + url = git@github.com:IONOS-Productivity/nc-bruteforcesettings.git diff --git a/apps-external/bruteforcesettings b/apps-external/bruteforcesettings new file mode 160000 index 0000000000000..dc12df63f91cc --- /dev/null +++ b/apps-external/bruteforcesettings @@ -0,0 +1 @@ +Subproject commit dc12df63f91cc5f5636f5519bac39838abd66455 From 30b0f94480be7748c5571d146be0dcaf124b5300 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Wed, 11 Feb 2026 11:01:56 +0100 Subject: [PATCH 14/22] IONOS(bruteforcesettings): update submodule (delegate settings) Signed-off-by: Kai Henseler --- apps-external/bruteforcesettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps-external/bruteforcesettings b/apps-external/bruteforcesettings index dc12df63f91cc..423a1065c682b 160000 --- a/apps-external/bruteforcesettings +++ b/apps-external/bruteforcesettings @@ -1 +1 @@ -Subproject commit dc12df63f91cc5f5636f5519bac39838abd66455 +Subproject commit 423a1065c682be3cb065bdc91c78353fee36c798 From 1cbfcff5164230840cf5de90b0c628e4c74b8b5e Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Wed, 11 Feb 2026 11:04:47 +0100 Subject: [PATCH 15/22] IONOS(config): update submodule (delegate bruteforcesettings) Signed-off-by: Kai Henseler --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index 4192e9c9b70de..bb7db058d334f 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit 4192e9c9b70debc433fe1365827f683592e00e41 +Subproject commit bb7db058d334f99d9ec148d6b9cd7462aa80db8e From b7b0d26153a0e3d0786003f39fd2e4c3eb3d4183 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Fri, 6 Feb 2026 13:20:38 +0100 Subject: [PATCH 16/22] IONOS(user_oidc): change submodule repo Signed-off-by: Kai Henseler --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index fab07b1b89865..a612546b88da1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -81,7 +81,7 @@ url = git@github.com:IONOS-Productivity/nc-notifications.git [submodule "apps-external/user_oidc"] path = apps-external/user_oidc - url = git@github.com:nextcloud/user_oidc.git + url = git@github.com:IONOS-Productivity/nc-user_oidc.git [submodule "apps-external/end_to_end_encryption"] path = apps-external/end_to_end_encryption url = git@github.com:nextcloud/end_to_end_encryption.git From 24a82beeb394ca89aef2fab67f37b8aa905e9801 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Fri, 6 Feb 2026 13:35:28 +0100 Subject: [PATCH 17/22] IONOS(user_oidc): update submodule (delegate settings) Signed-off-by: Kai Henseler Signed-off-by: Arsalan Ul Haq Sohni --- apps-external/user_oidc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps-external/user_oidc b/apps-external/user_oidc index 192826636cc8b..085f98727f738 160000 --- a/apps-external/user_oidc +++ b/apps-external/user_oidc @@ -1 +1 @@ -Subproject commit 192826636cc8b25acfb43a56617db0758869f808 +Subproject commit 085f98727f73886e3144cf0b65e6580aebd17d87 From 2cc4e2aea2f59080a6d027d91cf3f15db3d7b9c8 Mon Sep 17 00:00:00 2001 From: Kai Henseler Date: Fri, 6 Feb 2026 13:36:14 +0100 Subject: [PATCH 18/22] IONOS(config): update submodule (add user oidc setting delegation) Signed-off-by: Kai Henseler Signed-off-by: Arsalan Ul Haq Sohni --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index bb7db058d334f..30be7051586fa 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit bb7db058d334f99d9ec148d6b9cd7462aa80db8e +Subproject commit 30be7051586faae63a143d061925045dd800dba5 From 2a3b4074b52cbf9ff758150b1cbe5f49d9c1e05a Mon Sep 17 00:00:00 2001 From: Arsalan Ul Haq Sohni Date: Tue, 17 Feb 2026 12:51:52 +0100 Subject: [PATCH 19/22] Revert "IONOS(appsettings): conditionally display developer documentation link based on configuration" This reverts commit 8217b8a4e4acd4a6d24634abfb21daf71b7ea4aa. --- .../lib/Controller/AppSettingsController.php | 9 +- .../settings/src/views/AppStoreNavigation.vue | 3 +- .../Controller/AppSettingsControllerTest.php | 99 ------------------- 3 files changed, 2 insertions(+), 109 deletions(-) diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php index d76408010da79..c0ba0b556291b 100644 --- a/apps/settings/lib/Controller/AppSettingsController.php +++ b/apps/settings/lib/Controller/AppSettingsController.php @@ -35,7 +35,6 @@ use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFolder; use OCP\Http\Client\IClientService; -use OCP\IAppConfig; use OCP\IConfig; use OCP\IGroup; use OCP\IL10N; @@ -75,7 +74,6 @@ public function __construct( private IInitialState $initialState, private AppDiscoverFetcher $discoverFetcher, private IClientService $clientService, - private IAppConfig $appConfig, ) { parent::__construct($appName, $request); $this->appData = $appDataFactory->get('appstore'); @@ -92,12 +90,7 @@ public function viewApps(): TemplateResponse { $this->initialState->provideInitialState('appstoreEnabled', $this->config->getSystemValueBool('appstoreenabled', true)); $this->initialState->provideInitialState('appstoreBundles', $this->getBundles()); - - // Conditionally set developer docs link based on configuration - $displayDocumentationLink = $this->appConfig->getValueBool('settings', 'display_documentation_link', true); - $developerDocsUrl = $displayDocumentationLink ? $this->urlGenerator->linkToDocs('developer-manual') : ''; - $this->initialState->provideInitialState('appstoreDeveloperDocs', $developerDocsUrl); - + $this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual')); $this->initialState->provideInitialState('appstoreUpdateCount', count($this->getAppsWithUpdates())); if ($this->appManager->isInstalled('app_api')) { diff --git a/apps/settings/src/views/AppStoreNavigation.vue b/apps/settings/src/views/AppStoreNavigation.vue index 3507006c47d5b..a35cd94da95fb 100644 --- a/apps/settings/src/views/AppStoreNavigation.vue +++ b/apps/settings/src/views/AppStoreNavigation.vue @@ -91,8 +91,7 @@ - diff --git a/apps/settings/tests/Controller/AppSettingsControllerTest.php b/apps/settings/tests/Controller/AppSettingsControllerTest.php index 3c0df4532d79f..8adba2083296e 100644 --- a/apps/settings/tests/Controller/AppSettingsControllerTest.php +++ b/apps/settings/tests/Controller/AppSettingsControllerTest.php @@ -19,7 +19,6 @@ use OCP\AppFramework\Services\IInitialState; use OCP\Files\AppData\IAppDataFactory; use OCP\Http\Client\IClientService; -use OCP\IAppConfig; use OCP\IConfig; use OCP\IL10N; use OCP\INavigationManager; @@ -46,8 +45,6 @@ class AppSettingsControllerTest extends TestCase { private $l10n; /** @var IConfig|MockObject */ private $config; - /** @var IAppConfig|MockObject */ - private $appConfig; /** @var INavigationManager|MockObject */ private $navigationManager; private AppManager&MockObject $appManager; @@ -84,7 +81,6 @@ protected function setUp(): void { ->method('t') ->willReturnArgument(0); $this->config = $this->createMock(IConfig::class); - $this->appConfig = $this->createMock(IAppConfig::class); $this->navigationManager = $this->createMock(INavigationManager::class); $this->appManager = $this->createMock(AppManager::class); $this->categoryFetcher = $this->createMock(CategoryFetcher::class); @@ -116,7 +112,6 @@ protected function setUp(): void { $this->initialState, $this->discoverFetcher, $this->clientService, - $this->appConfig, ); } @@ -185,11 +180,6 @@ public function testViewApps(): void { ->method('getSystemValueBool') ->with('appstoreenabled', true) ->willReturn(true); - $this->appConfig - ->expects($this->once()) - ->method('getValueBool') - ->with('settings', 'display_documentation_link', true) - ->willReturn(true); $this->navigationManager ->expects($this->once()) ->method('setActiveEntry') @@ -235,11 +225,6 @@ public function testViewAppsAppstoreNotEnabled(): void { ->method('getSystemValueBool') ->with('appstoreenabled', true) ->willReturn(false); - $this->appConfig - ->expects($this->once()) - ->method('getValueBool') - ->with('settings', 'display_documentation_link', true) - ->willReturn(true); $this->navigationManager ->expects($this->once()) ->method('setActiveEntry') @@ -274,88 +259,4 @@ public function testViewAppsAppstoreNotEnabled(): void { $this->assertEquals($expected, $this->appSettingsController->viewApps()); } - - public function testDeveloperDocumentationLinkHiddenWhenConfigured(): void { - $this->installer->expects($this->any()) - ->method('isUpdateAvailable') - ->willReturn(false); - $this->bundleFetcher->expects($this->once())->method('getBundles')->willReturn([]); - $this->config - ->expects($this->once()) - ->method('getSystemValueBool') - ->with('appstoreenabled', true) - ->willReturn(true); - $this->appConfig - ->expects($this->once()) - ->method('getValueBool') - ->with('settings', 'display_documentation_link', true) - ->willReturn(false); - $this->navigationManager - ->expects($this->once()) - ->method('setActiveEntry') - ->with('core_apps'); - - // When display_documentation_link is false, linkToDocs should not be called - $this->urlGenerator - ->expects($this->never()) - ->method('linkToDocs'); - - $providedStates = []; - $this->initialState - ->expects($this->exactly(4)) - ->method('provideInitialState') - ->willReturnCallback(function ($key, $value) use (&$providedStates) { - $providedStates[$key] = $value; - }); - - $this->appSettingsController->viewApps(); - - // Assert that the developer docs state was provided with an empty string - $this->assertArrayHasKey('appstoreDeveloperDocs', $providedStates); - $this->assertEquals('', $providedStates['appstoreDeveloperDocs']); - } - - public function testDeveloperDocumentationLinkShownByDefault(): void { - $this->installer->expects($this->any()) - ->method('isUpdateAvailable') - ->willReturn(false); - $this->bundleFetcher->expects($this->once())->method('getBundles')->willReturn([]); - $this->config - ->expects($this->once()) - ->method('getSystemValueBool') - ->with('appstoreenabled', true) - ->willReturn(true); - $this->appConfig - ->expects($this->once()) - ->method('getValueBool') - ->with('settings', 'display_documentation_link', true) - ->willReturn(true); - $this->navigationManager - ->expects($this->once()) - ->method('setActiveEntry') - ->with('core_apps'); - - $developerDocsUrl = 'https://docs.nextcloud.com/server/latest/developer_manual/'; - - // When display_documentation_link is true (default), linkToDocs should be called - $this->urlGenerator - ->expects($this->once()) - ->method('linkToDocs') - ->with('developer-manual') - ->willReturn($developerDocsUrl); - - $providedStates = []; - $this->initialState - ->expects($this->exactly(4)) - ->method('provideInitialState') - ->willReturnCallback(function ($key, $value) use (&$providedStates) { - $providedStates[$key] = $value; - }); - - $this->appSettingsController->viewApps(); - - // Assert that the developer docs state was provided with the correct URL - $this->assertArrayHasKey('appstoreDeveloperDocs', $providedStates); - $this->assertEquals($developerDocsUrl, $providedStates['appstoreDeveloperDocs']); - } } From 5eb344583a60c01cd602c02782ecd3fd3c299515 Mon Sep 17 00:00:00 2001 From: Arsalan Ul Haq Sohni Date: Tue, 17 Feb 2026 12:53:11 +0100 Subject: [PATCH 20/22] Revert "IONOS(tests): add tests for developer documentation link generation" This reverts commit a79215ce2e4d3d3f8ccc3283d6ae085579e61352. --- .../Controller/AppSettingsControllerTest.php | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/apps/settings/tests/Controller/AppSettingsControllerTest.php b/apps/settings/tests/Controller/AppSettingsControllerTest.php index 8adba2083296e..f72bd45a3d234 100644 --- a/apps/settings/tests/Controller/AppSettingsControllerTest.php +++ b/apps/settings/tests/Controller/AppSettingsControllerTest.php @@ -185,21 +185,9 @@ public function testViewApps(): void { ->method('setActiveEntry') ->with('core_apps'); - // Test that developer docs link is generated correctly - $this->urlGenerator - ->expects($this->once()) - ->method('linkToDocs') - ->with('developer-manual') - ->willReturn('https://docs.nextcloud.com/server/latest/developer_manual/'); - $this->initialState ->expects($this->exactly(4)) - ->method('provideInitialState') - ->willReturnCallback(function ($key, $value) { - if ($key === 'appstoreDeveloperDocs') { - $this->assertEquals('https://docs.nextcloud.com/server/latest/developer_manual/', $value); - } - }); + ->method('provideInitialState'); $policy = new ContentSecurityPolicy(); $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); @@ -230,21 +218,9 @@ public function testViewAppsAppstoreNotEnabled(): void { ->method('setActiveEntry') ->with('core_apps'); - // Test that developer docs link is still generated even when appstore is disabled - $this->urlGenerator - ->expects($this->once()) - ->method('linkToDocs') - ->with('developer-manual') - ->willReturn('https://docs.nextcloud.com/server/latest/developer_manual/'); - $this->initialState ->expects($this->exactly(4)) - ->method('provideInitialState') - ->willReturnCallback(function ($key, $value) { - if ($key === 'appstoreDeveloperDocs') { - $this->assertEquals('https://docs.nextcloud.com/server/latest/developer_manual/', $value); - } - }); + ->method('provideInitialState'); $policy = new ContentSecurityPolicy(); $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); From 60636398d8b404eb640643c7810bb3c915e851ed Mon Sep 17 00:00:00 2001 From: Arsalan Ul Haq Sohni Date: Tue, 2 Dec 2025 11:49:30 +0100 Subject: [PATCH 21/22] docs: remove developer documentation link Signed-off-by: Arsalan Ul Haq Sohni --- apps/settings/lib/Controller/AppSettingsController.php | 1 - apps/settings/src/views/AppStoreNavigation.vue | 4 ---- 2 files changed, 5 deletions(-) diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php index c0ba0b556291b..370ff883a769f 100644 --- a/apps/settings/lib/Controller/AppSettingsController.php +++ b/apps/settings/lib/Controller/AppSettingsController.php @@ -90,7 +90,6 @@ public function viewApps(): TemplateResponse { $this->initialState->provideInitialState('appstoreEnabled', $this->config->getSystemValueBool('appstoreenabled', true)); $this->initialState->provideInitialState('appstoreBundles', $this->getBundles()); - $this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual')); $this->initialState->provideInitialState('appstoreUpdateCount', count($this->getAppsWithUpdates())); if ($this->appManager->isInstalled('app_api')) { diff --git a/apps/settings/src/views/AppStoreNavigation.vue b/apps/settings/src/views/AppStoreNavigation.vue index a35cd94da95fb..4d8a2b3e48ce1 100644 --- a/apps/settings/src/views/AppStoreNavigation.vue +++ b/apps/settings/src/views/AppStoreNavigation.vue @@ -91,9 +91,6 @@ - @@ -115,7 +112,6 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import APPSTORE_CATEGORY_ICONS from '../constants/AppstoreCategoryIcons.ts' const appstoreEnabled = loadState('settings', 'appstoreEnabled', true) -const developerDocsUrl = loadState('settings', 'appstoreDeveloperDocs', '') const store = useAppsStore() const categories = computed(() => store.categories) From 01f08b856780a6399e10a64f8e0a4e4757e55e52 Mon Sep 17 00:00:00 2001 From: Arsalan Ul Haq Sohni Date: Tue, 17 Feb 2026 14:39:23 +0100 Subject: [PATCH 22/22] Revert "IONOS(config): add developer_documentation_url boolean and build ncw core config" Signed-off-by: Arsalan Ul Haq Sohni --- IONOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONOS b/IONOS index 30be7051586fa..7d2d1bb7bbfee 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit 30be7051586faae63a143d061925045dd800dba5 +Subproject commit 7d2d1bb7bbfee8e7fd0e3443a18bf4c303d53095