Skip to content

Feature: Publish Collective as Static Website - #2769

Draft
code4candy wants to merge 10 commits into
mainfrom
feature/collectives-publish
Draft

code4candy wants to merge 10 commits into
mainfrom
feature/collectives-publish

Conversation

@code4candy

@code4candy code4candy commented Sep 10, 2026 •

Copy link
Copy Markdown

📝 Summary

This is the first step towards the publishing feature, that we implement as part of the funding program Prototype Fund (get more information here: https://github.com/nextcloud-publish). This is not going to be merged after a first review, but works as intermediate working tree for the feature.

This PR contains the following Issues:

(Check off once the review has been completed and all feedback has been incorporated.)

IMPORTANT:

publish_enabled was changed from string to a boolean value.
If you have testet the branch before and if you run into an error you need to delete the value and set it again as boolean.
To fix the error you can use the following commands:

docker exec -u www-data master-nextcloud-1 php /var/www/html/occ config:app:delete collectives publish_enabled                                                                                                                                                                                                    
docker exec -u www-data master-nextcloud-1 php /var/www/html/occ config:app:set collectives publish_enabled --value true --type boolean                                                                                                                                                                           
docker exec -u www-data master-nextcloud-1 php /var/www/html/occ config:app:get collectives publish_enabled --details   

@mejo- mejo- left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great 😊 I have some comments on the backend part, the frontend looks fine from reading the code.

Comment thread lib/AppInfo/Application.php Resolved
Comment thread lib/Service/PublishSettings.php Resolved
@kjoscha
kjoscha force-pushed the feature/collectives-publish branch 2 times, most recently from 7cebf56 to 63fc23e Compare September 22, 2026 08:55
@kjoscha

kjoscha commented Sep 22, 2026 •

Copy link
Copy Markdown
image

Since the settings area is not in the Collectives scope, we should prefix the header with collective or BETTER move both settings under a "Collectives" heading

@kjoscha
kjoscha force-pushed the feature/collectives-publish branch 2 times, most recently from 13eabe3 to 20f507c Compare September 22, 2026 12:40
@github-actions

Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@mejo- mejo- left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this PR look good now. Ideally you could merge the three commits into one and then it would be ready to be used as the base for future PRs to be merged into it from my side 😊

@code4candy
code4candy force-pushed the feature/collectives-publish branch from 9ca1098 to 37ee4ef Compare October 7, 2026 21:03
@kjoscha

kjoscha commented Oct 13, 2026

Copy link
Copy Markdown

Important

  • 9fd6602 Stable35 setting in workflow file must be reverted before merge!

@mejo-

mejo- commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Fixed in fix review findings - #2890

I asked Claude to do a review and here's the most important findings. From a quick code walkthrough, at least the security/permission problems seem true.

Security and permissions

  • 1. Archive ignores the page selection (lib/Service/StaticSiteService.php:164). buildArchive() calls contentCollector->collect($collectiveId), which collects every file in the collective folder. The pageIds are stored but never used to filter the archive. A page the user unticked, such as "HR/Salaries", still ends up in the tar.gz along with all attachments. Commit e285da7 says it builds "an archive containing selected pages and assets", which isn't what the code does.
    --> yes, this is an intermediate state --> will be addressed in the following issue, page selection is currently ignored. Only the whole collective gets published)

  • 2. The backend allows any editor, but the UI treats publishing as admin-only (StaticSiteService.php:271). The service checks canEdit(), while the frontend and the e2e test use isCollectiveAdmin. With default permissions, a regular member can call POST or DELETE /static-sites directly, publishing the collective or deleting an admin's site. It should check getLevel() >= Member::LEVEL_ADMIN, or whatever permission is intended.
    --> true - there is already a specific issue regarding this and the general persmission handling

  • 3. The publish_enabled setting is only checked in the frontend (lib/Controller/StaticSiteController.php:87). No controller or service checks it. Even with the feature disabled (the default), editors can call the API and build archives of up to 100 MB in appdata.
    --> feature enabled check added to service

Correctness

  • 4. The page list can be empty (src/components/Nav/CollectivePublishModal.vue:153). created() reads allPageIds once from the pages store and never loads pages itself. If you open the modal for a collective that isn't the current one, or before its pages have loaded, the tree is empty. Publish then only fails with "select at least one page".
    --> add page refresh when publish modal is opened

  • 5. Ticking a subpage doesn't select its parents (CollectivePublishModal.vue:173). Toggling a page only affects its subtree. You can untick the root, tick one deep subpage, and the backend accepts a site whose pages have no parent and no landing page.
    --> will be decided on and handled in another issue

  • 6. A failed retry restarts the 15-minute lock (StaticSiteService.php:126). If an update takes over a timed-out "pending" site and the build then fails, restoreStatus() writes "pending" back through updateStatus(), which sets updated_at to now. Every retry is then refused as "already in progress" for another 15 minutes, although nothing is running.
    --> fixed

  • 7. The feature defaults to enabled in the frontend (src/CollectivesApp.vue:152). loadState(..., 'publish_enabled', true) should default to false, and the === 'true' check is unnecessary. On the backend, getValueBool('collectives', 'publish_enabled') should replace the copied getValueString(...) === 'true' checks in BeforeTemplateRenderedListener and Settings/Admin.
    --> changed default to FALSE
    --> now using BOOL instead of STRING (using loadState)

Design

  • 8. The build runs synchronously in the request (StaticSiteService.php:105). The service copies, tars and gzips up to 100 MB inside the OCS request. The PENDING_TIMEOUT and optimistic-lock logic only exists to work around request timeouts. A queued background job (IJobList) would make that logic unnecessary and avoid timeouts on object storage.
    --> decided to test synchronous building with large content up to 100MB < 60s in new Issue

@code4candy
code4candy force-pushed the feature/collectives-publish branch 2 times, most recently from 090efb9 to 6ac7363 Compare October 15, 2026 15:11
@kjoscha
kjoscha force-pushed the feature/collectives-publish branch 2 times, most recently from effdaaf to 1818384 Compare October 22, 2026 13:46
@code4candy
code4candy force-pushed the feature/collectives-publish branch from b011a83 to 5e4f965 Compare October 26, 2026 12:46
Melpo and others added 9 commits October 26, 2026 13:47
Signed-off-by: kayoshi <jo5cha@web.de>
Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-sonnet-5
- create and save static site metadata to db
- add update and delete route, add state lock on publish
- add symfony/uid and symfony/polyfill-uuid to composer.json
- add title and slug input fields to modal

Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-sonnet-5
- create and save static site metadata to db
- add archiver to store static sites as tar.gz in appdata
- build archive containing selected pages and assets

Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-sonnet-5
- add static site generator settings and connection test
- add public download endpoint to stream the archive to the external ssg service
- notify static site generator when the provided archive is ready
- regenerate OpenAPI specs (adds administration scope)

Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-opus-5-5
…tus + delete archive after successful deployment message

Signed-off-by: kayoshi <jo5cha@web.de>
Assisted-by: ClaudeCode:claude-sonnet-5
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: kayoshi <jo5cha@web.de>
Signed-off-by: kayoshi <jo5cha@web.de>
Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-opus-5-5
@code4candy
code4candy force-pushed the feature/collectives-publish branch from 5e4f965 to 3a9aa28 Compare October 26, 2026 12:50
Signed-off-by: Melpo <melpomene@posteo.net>
Assisted-by: ClaudeCode:claude-opus-5-5
@code4candy
code4candy requested a review from mejo- October 26, 2026 14:27

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants