Skip to main content

IntraVox - Releases

← App details

Nextcloud 34

IntraVox 1.9.7
Release Details
UpdatedAug. 7, 2026, 8:25 p.m.
Changelog

Fixed

  • Uploading a photo failed with "Upload failed: page not found", on a page that was open in front of you. Adding a Photo widget and choosing an image appeared to work, and then saving the page reported that the page did not exist. Images placed in the resource folder through Files showed up in the Shared Library as a filename and a size with no preview, and stayed blank when selected. Saving the page first made no difference. (#92)

This is the same read/write split that #90 fixed for pages in 1.9.6, in the one place that fix did not reach: media. A page's images live next to the page, but IntraVox looked for them in a language folder chosen for you — your Nextcloud display language when uploading, the language you are shown when listing. Whenever those differed from the language the page itself is written in, every media operation searched the wrong folder: uploads reported the page missing, the Shared Library came back empty so previews had nothing to load, and thumbnails answered 404.

The permission check on the very same request had already found the page correctly, which is why the failure looked so contradictory — permission granted, then "page not found" for the upload that followed.

Media now resolves through the page it belongs to, so an upload lands beside its own page whichever language that page is in, and the Shared Library lists the library that page actually uses. Uploading to a page that genuinely does not exist answers a plain 404 and writes a log line, instead of the silent 500 that left this issue with no Nextcloud log entries to go on.

This affected every media widget — Photo, Photo Story, File Story and Gallery — not only the Photo widget.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQGR2+MVQYJYo1mg8qjMMBHAHr+V92aHAmEz08lqTMIYlzT05mbJqKeXtFan18+jUHp54/u5nyRHY0Hrc0AjJ2jfdq2oHyTvgKGtm6jHiswmM6dB/AkSglQ87ZRXmeeZzjfweWCmVayBnjqUCYRYuzvxXiu9qkmItu1I3vX2wvh2SyzC7YsWii3RvvHhuo00UAOEETwn3PrAD7vx/J4O4IiDMruq7fULsq2F+0Qb+XhlLVVTtvJPQHyYgStZGoP9hHYC+4fE1ugGgv1GQ4Rntae3MqKG+R3STVHDuXpNn9wMeIM3/24u8NyKPWosTSjgTnkoflb/Z73poiZaCfD3cApenQiEhjeM7rTjVARsOZtft6knovG1Wug4URzha1Onqvc2zqWkfDn5SCRQFJxpXjPojFiNETlEJXGoF5rG3s9Agn8/5l2lNDyhKqT7+8JCM8Da0P43fwDQn9rH1dVJH27P0D02HEvM4Ash/kV0SAdU6QBMUvEWtfcfTsVfJTonul71Z4NaA3v7LoK8nDAOVrUx8WYrssS7ZQrvV8HUxhsg4ymtMk/muUS4MJJAp3g2yALMvs49A+SI8fq44FL1opIKUjGlGvN2dJ0BHA0FUlxeX/aqb6/CmDTGhOQyFJ4UjZhxKuhLCTQk0RfG+6Fd1jBapWZehF2IsaJBNlmL/hEI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.6
Release Details
UpdatedAug. 7, 2026, 8:17 a.m.
Changelog

Added

  • Editors are told when a page is not in their own language. A badge next to the page title appears when the page you are on belongs to a different language than your own — in both view and edit mode. It names the language of the page, not of your interface: a German editor opening an English page sees "English", and knows that editing it saves back into English.

It shows up only when the two differ, so it never becomes a permanent label you stop reading; on a page in your own language, and on any single-language intranet, there is no badge at all. Like the Draft badge it is only shown to people who can edit the page.

It is an indicator, not a switcher: to work in another language, navigate to that language's pages.

Fixed

  • Editing a page failed with "Saving failed: Request failed with status code 400" and "Unable to save the page: Page not found". The page was on screen, it opened in the editor, and the save then insisted it did not exist. (#90)

Reading a page and saving one looked in different places. Opening a page searched the language you are shown — your own language, and failing that the recommended language or English — and then looked through every other language folder besides. Saving searched only the folder matching your own Nextcloud display language, and gave up there. Any page written in one language and opened by someone using another was therefore readable but impossible to save, along with its version history, its metadata and its delete action.

Nothing was wrong with the page or with the Team Folder holding it. Editing an existing page now writes back to wherever that page actually lives, so anything you can open, you can also save. Creating a new page is unchanged: it still lands in your own language folder. Permissions are unchanged too — a read-only member still gets a clear "not allowed" rather than a save that appears to work.

A page that genuinely does not exist now answers with a plain 404 instead of the contradictory "400 / not found" pair that made this so puzzling to report.

  • A sub-page created under a parent in another language ended up detached from it. Adding a sub-page to a German parent while your own Nextcloud language was English filed it under English instead — and built an empty de/departments/… mirror of the folder structure on the way, whose parent pages did not exist there. The new page disappeared from the very structure it was created in.

Page creation now follows the structure you are working in rather than your personal language setting. A sub-page joins its parent's language; a top-level page is created in the language you are currently viewing; and only when there is nothing to derive it from does IntraVox fall back to your own language, as before.

Together with the save fix above, the rule for editors is now a single sentence: you write where you are looking. Which language your Nextcloud interface is in no longer decides which content you can work on, and the admin panel's recommended language remains what it always was — a viewing fallback, never a write target.

  • Links to a page in another language resolved inconsistently. A link carrying a page's unique id found the page wherever it lived, but an older-style link built from the page name only searched your own language folder — so the same page could open, show a different language's page, or fail, depending on which kind of link you happened to follow. Both kinds now resolve the same way.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureMAygWy2LuZA4GrDZTIZjUtB0CSP60pbrfZdeVRb8Rg5ZOjGg9e4hrAMPbJ7GnT00NbDnP7GVkeaa0MdQT4n0pPtMrykmuJHY98uBTbNilcDUE80iYcKVnojntSffQtLClBXde5Sv4Gd2o9G5L5FWqlEI9nHfoz6C7qpiLgZGZlmQYzvNWBdCC49gYJUAxxGfxCtALhczS0Q+LjME1YnuPsSlxFCQW3Q7DhgpyAlbO+WS7VZ6FQhAZCKv3B0PVox1ouac3l2YZ1DuR0fZJuEnX5/3NQpIRqtSyZOfRYuNKA/dopXKs4T4SJzDUsdJtBH+aCHDdUEG+Jx3hQcb7XRe2C2SJnrsT7Azqm350pS9vDsz5Rspt26M9S95zHXJYQoL7EH/TnlIKZpJPF6qgB+zwen6rCz50FoJAPKdiWG0+0nBZT8ImwT2sAG3vCfJrs5pCbcueeFWUqGv2I0wdZNkE2pWDSPHAot9AGnu4DAUL8Qv1CFAG4QjIFbtQN/ayyt1Kf1tEGx23+kVNhDH8qSbwl1lQTTQVLzJsRh/XuL562O3Tdz63BUicjQTXiZsedFNqTpssz1vONJjlQN82a6jRT4zJyySBPelOd0k4uKtV+Em5FbarUvs2EuebW/zsR1+MdvFxTDNwHH9weTLd/4dqMWrkvl2enYKy35KpwBa/jw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.5
Release Details
UpdatedAug. 5, 2026, 9:02 p.m.
Changelog

Fixed

  • The filter panel lost all its options a few minutes after the page was loaded. The groups still appeared with their headings, but every one of them read No matching options — and then filled back in by itself some minutes later, without anyone changing a thing.

The widget's configuration was never the problem. The background job that refreshes People data every ten minutes runs without a logged-in session, and it rebuilt each widget's data as though an anonymous visitor had asked for it. That strips every field marked Local — including role and organisation — and skips IntraVox custom fields entirely, which is where fields like Werking, Thema and Gebouw live. The stripped result was then written over the copy meant for logged-in readers. With no values left to count, every group had nothing left to show.

This only affected instances that had switched on Visitor filters, and only from 1.9.4, where both the filter panel and that background job were introduced. The refresh now rebuilds each set of data for the audience it belongs to. Anonymous visitors are unaffected: they still see only what each field's visibility scope allows, so the fix does not widen what a public share can reach.

No action is needed on upgrade — the affected data is a cache and is rebuilt automatically.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJa1s+EtGix95c7jHfQz6ZUxx8YYfPLYzBPEsz9pc0A1GHIokKC3JSZbyGr8TD+1HNjO7WXoyXo7hSBV6wlIrqznQSj676/Cl+zp1GsYedg/EZnyG3lnGq3LRfMLMBnadAAZ+CB8yMxuo/09bQkrWo3pJ9mmq1ClIRjRl/0lNVBjOxTONaBEhJ8Bjt+nsVjLZb+bobmAvbR48peA2j1XOZtqQoCLU56V5WnZQNTWFHnLQ4K4pRcBb37n/OHPAaLIudWtoU8yiFAnNPjajq63e9TAeyxxIdJl+8MqOb6bKBrCKSk88LDDvBXeG8pfiqYYbfdfR1vT115+H8VMhDVUEa/D4D522aTTsEhrBkj4rpkC1/h04hjPTq+xyRCs/XiBAlWNLAs5Gy8KP8dtdXM8hOLKBgJrLk+lxb8HCE4Bu2oT3vq12exQ9DpZ88VJ4dUrPsbAkQ1E77Clka+imEZI946X7UuAqx0+Kq1UtfgmYgBm9gww/cFeCnSdd34FpQxG2saMkgsAe//+osGEX0H3nuI+eotxUdEjvKQTkpzz5nGUHTrmXQrAcwriI7dNufweaGbxVw3W33fgziJmzxeW6lxY1qjGDNmj4NiNsq+jRxO4VqbPhYkdPTDw6zn4w+eM0W3BzNaeGPO2JHrGsV+ezh0n/Cng5IdFn/z2ED3JuuUU=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.4
Release Details
UpdatedAug. 5, 2026, 6:04 p.m.
Changelog

Added

  • People widgets can now be filtered by the people reading them. Until now only the editor could decide who a widget showed; a reader got a fixed list. Switch on Visitor filters in the widget editor and the widget grows a filter panel: one group per field you choose, each value with a live count, plus an optional search box and removable chips for what is currently selected.

The counts are the point. They are calculated over the actual result set, and they narrow as you choose — pick a department and the building list immediately shows only buildings where that department sits, with real numbers. Picking a value never empties its own group, so "Noord or Zuid" is expressible; that is what makes it a filter panel rather than a series of dropdowns. Whatever a count promises, clicking it delivers exactly that many people.

A visitor can only ever narrow what the widget already shows. If you scoped a widget to one department, no filter combination reaches outside it — the restriction is built into how the results are assembled, not bolted on afterwards.

Selections live in the page URL, so a filtered view can be shared or bookmarked and opens filtered. On a phone the panel folds into a Filters (3) button. Filters do not appear on public share links: the values would amount to a browsable directory of your organisation for anyone holding the URL.

  • occ intravox:people:scope-report — prints which profile fields will become invisible under the visibility fix below, and for how many accounts. Run it before upgrading; --all scans every account instead of sampling.

Security

  • People widgets no longer appear on public share links. A public share is normally created to hand someone a set of documents. If the page also carried a People widget, the act of sharing those documents published a staff directory — names, photos and profile fields — to anyone holding the URL, without the people on that list having agreed to it or the person sharing necessarily realising the widget was there.

People widgets are now withheld from public share links by default. The rest of the page is shared exactly as before. Administrators who have a genuine reason — an external project page with a named contact, say — can allow it under Settings → Administration → IntraVox → Publication, but it is now a decision someone takes rather than a side effect of sharing a folder. The /api/share/{token}/people endpoint refuses as well, so the widget cannot be reached by calling the API directly.

  • People widgets now respect each field's visibility setting. IntraVox never consulted the visibility scope Nextcloud stores per account property, so every field the account manager returned was handed to whoever loaded a People widget — including the extra fields your directory syncs (LDAP/OIDC), and including anonymous visitors following a public share link. A phone number or birthdate a colleague deliberately marked Private was published anyway.

From this release the scope is honoured: Private fields reach nobody, Local fields reach logged-in users only, Federated and Published fields also reach public shares. The email address was a second route to the same leak — it was read straight from the user account rather than from the scoped property — and now follows the same rule. IntraVox custom fields (set through user preferences rather than Personal info) carry no scope of their own and are treated as Local: visible when logged in, never on a public share.

This is a visible change, not only a fix. Fields your users marked private will disappear from existing People widgets. Nothing needs to be run for the upgrade itself, but if you want to know in advance which fields are affected and for how many accounts, occ intravox:people:scope-report will tell you. The field most likely to surprise you is email: it defaults to Federated, but plenty of instances set it to Local, which removes it from public-share People widgets. Users change this themselves under Settings → Personal → Personal info, with the visibility picker beside each field.

The cached filter results were also shared between users regardless of what each was allowed to see. The cache key now includes both the audience and the viewer's group membership, and the old entries are abandoned rather than reused — otherwise the fix would not have taken effect until they expired.

Performance

  • People widgets read account data in one query instead of one per user. Profile data now comes from a single database read rather than a separate call for every account. Measured cold on a 106-account instance, the widget's scan drops from 35–45 ms to around 14 ms; the account read itself falls from 20.4 ms to 1.4 ms per hundred accounts. The remaining time is Nextcloud's own account enumeration, which an app cannot bypass. Instances with tens of thousands of users benefit proportionally.

  • Concurrent visitors no longer each trigger their own rebuild. When a widget's cached data expired, every visitor arriving at that moment started a full scan of their own. On an LDAP-backed instance, where reading a large group can take half a minute, fifty simultaneous readers meant fifty simultaneous scans. Now one request refreshes while the others are served the previous data, which is at most a few minutes old.

  • A background job refreshes recently-used People widgets every ten minutes, so in normal use no visitor waits for a rebuild at all. It only touches data that has actually expired, so an idle instance costs nothing.

Fixed

  • The People widget on a public share always failed. /api/share/{token}/people called a method that does not exist on the share service, so every request died and returned a server error. Anyone with a People widget on a shared page saw an empty widget. It now resolves the share token correctly.

  • The People widget's pagination setting was discarded on every save. The "show pagination" option was read when rendering but never stored, so it silently reverted each time the page was saved.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureI102notxijb2rG68TSr3XvT8Rh7/HOyPn1hIcu9DYcXWz0Fs3hSt0WBJzwj4rx3VOzL1kYcuganvYD9Sphfxe2qyIwlR/K9Oqd37KM9bg+v/IFqXvWCP6HMV97wazJdizbEaSEoohPran03F05inYQNrY+4SqpC2o7O1TJ3go4c3w5FwoL83uWxvF1MKto4eG6jozbM/oUkPEFQ1KUBa2ySbMIcZYrPO/Yh8eKPoD/YwMqDl1uqCejeRGKPMWh4XWkIjKlviKhVlfQ97QMsUh3rX/NppD0QKJMka08mOqDKpw+8xRU496qDZa0Z1LwKdapT1xa2A62oWR+e2dZr3mBCm/FzMI/cA55IeHw+SxXaRA+hyyuevtW+epvRl1FZecEeIII0CM66Kn/bBbWYfHTpsyBJba0Ev1bchFrqlba74TCniTu4FZvvm806ogf5yGHL5+2RQ9QwJrd2AHS1nF5XEr9FaPDI3gldzzGFGfWcNFStyz/jVEIHTbhG7OzQDZmDHdbh/lYHoa4Fs+KVtdr+qgsxfjxQ0DJD3W9ZpDgQwzpgVB/4NUG8iTCpDVsd7R8VL+EbXbCbOV+TOx0iiySuaOyCHDkhdkR0ilOOrUUfYkxUDuKo6vqutKOBa+qe8cW5c8seVVEB9HbVvJ/U7OPkmMFClHrmdFN4dLXJGPNM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.3
Release Details
UpdatedAug. 5, 2026, 11:35 a.m.
Changelog

Added

  • Search now finds pages by their MetaVox metadata. A page tagged City: Liège or Primary driver: HENK was invisible to IntraVox search unless the term also appeared in its title or content — the metadata lives beside the file, not inside the page. Those pages now show up under IntraVox pages, with a subline in MetaVox's own format (Label: value, joined with , matching field first, up to three fields) so the same document reads identically in both providers' results. Fields the user may not view are left out, so a restricted metadata field cannot surface here.

Changed

  • Search results no longer stop at the title index. The title index was consulted first and returned immediately on a hit, which silently suppressed pages that matched only on content or metadata whenever some other page happened to match on title. Index hits still render first (they are the fastest path); full-text and metadata matches are now appended after them, with duplicates removed.

  • The minimum search length follows the server setting instead of the app. IntraVox enforced its own two-character minimum, overriding the admin's unified-search.min-search-length (Nextcloud's default is 1). Nextcloud already rejects too-short terms centrally, before a provider is ever called, so the app-side check only served to make short but meaningful terms — HR, IT, CJK characters — unfindable regardless of how the instance was configured. No bundled Nextcloud app defines its own minimum.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDW78m+c4qRGRDYMcIhwYpytCtMO3guijSNnbzFEIXppXHYzSCHGAsrSllWOlPckQLasMUn+S1dpXLwk8uIKLXZYm+tfi+hfkmkrwN0SnCfTb+zGwiSOMdIvbMO/l0NnMEAglJf4/0fHsDxVX34/duPgvI+aOEk9yAr5qJeSu2J/T5DW4PvISOHKkY94p5z+QkOR2lOa6vO5iH3MtzaotNvgBRJd+VKy2riIO0O/Sfx5VSQL8CV0JY1mXBk1qbotIDNbYsfew7wr5iR2sEKNjUoocZAhxBAqzmSWYRvEy9tL5wx0miEeE4RIdeTNx7ItTSyzXocZm+JsVSG9iZKDiGg5dGd2VWtT+3Wg3ZAzHYGhHFMshlO9nEeWzR3e5Y87FIW1PasyRl2+8ZOS+hevaqR2s9aYc3mKSXZUqrmAC1TEn72V1kSgrUMrukBbqTjaBLNnhJZtnMqyLZ68yiPExcSCg0/DE8ul0ZPWLiTM+kznXuyTuKncDGXwqi0XFGiYKr0pHnJbR00C4KD3VLwIIIXbf+SReOSFMwaIE5xiBk2Fjc0vrmq1GZZZoLV46s3jTZdeB0JJzWjpNDczl4O2/jO8xEbAfY+Khhp4B/oMMA3nOl9WARJj1aezBHnNnxy+HEGJAxd72XuvuahjLXEa1OCec1vOPif1e1ac5zKXsRMc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.2
Release Details
UpdatedAug. 5, 2026, 7:49 a.m.
Changelog

Added

  • A page's "Publish on" / "Expire on" date now controls visibility everywhere. Previously the publication-date MetaVox fields only filtered the News widget's list; a page with a future publish date was still reachable directly, via the menu, the page tree and public shares. Now a page that is not yet published (future publish date) or has expired is hidden from readers and anonymous visitors — exactly like a draft — and automatically becomes visible the moment its publish time passes (evaluated live, no cron). Editors still see these pages, with a Scheduled / Expired badge next to the title.

  • Copy a link to any section of a page. Every heading — both stand-alone heading widgets and headings inside a text block — now gets a stable anchor. Hover a heading to reveal a small link icon; clicking it copies a deep link (e.g. …?page=…#h-creating-a-new-form) to the clipboard. Opening that link loads the page and scrolls straight to the section. Works in both the logged-in view and anonymous public shares. Page navigation (?page= / #page-…) is unaffected — section anchors use a distinct #h-… fragment so the two never collide.

Changed

  • A publish date takes precedence over the manual Draft flag. Following the WordPress/Drupal model, a page is in exactly one effective state: Draft (no date, held back manually), Scheduled (a future publish date) or Published (publish date has passed, or published with no date). This removes the confusing case where a page showed a Draft badge even though its publish date had already passed. In edit mode the manual toggle is then replaced by a read-only chip showing the effective state, with the explanation "Publication is controlled by the Publish on date. Clear the date to switch manually."

  • Draft no longer promises more than it delivers. The status keeps the name Draft (consistent with the rest of the industry and with how it is stored), but the wording now states plainly that it is a visibility filter, not a permission: the page is hidden from readers everywhere in IntraVox, while the page file itself keeps the folder's normal Nextcloud rights. Editing a draft page shows this as a standard Nextcloud info note card; the status badges carry a short, state-specific tooltip.

  • The editor documentation spells out where a draft page is still reachable. It previously claimed a draft was "completely invisible to readers", which was only true inside IntraVox. The guide (EN + NL) now lists the routes that bypass the filter — Files/WebDAV, Unified and full-text search, the activity stream and notifications, versions and trash, Collabora, sync clients and MetaVox metadata — and advises restricting the folder with Team folder permissions for genuinely confidential content.

  • The details sidebar (ⓘ) is now reachable while editing. It was hidden in edit mode, so setting a page's Publish on date — which lives in the sidebar's MetaVox tab — meant leaving the editor first.

  • The status updates immediately after saving a publish date. MetaVox stores those dates itself, outside IntraVox's own save flow, so a page you had just scheduled kept showing its old Draft badge until you reloaded. IntraVox now picks up the save and re-reads the page's publication state straight away. While editing, an info note explains the current state — including what Scheduled means and that the publish date overrides the Draft/Published button.

Fixed

  • Public link shares on a page folder now render for anonymous visitors. Opening the anonymous URL of a shared folder (e.g. a whole-language or sub-tree share) returned "This page is not available or the share link has expired" for every page under it — the share tree loaded, but each individual page 404'd. The page-scope check compared a per-user mount path (/Sam/files/IntraVox/en/docs/…) against the GroupFolder storage path (files/en/docs), so nothing ever matched. Pages are now resolved by their fileid in the GroupFolder storage — the same robust lookup already used for the share path — so folder-level public sharing works.

  • Internal links inside a shared page now navigate. In the public (anonymous) share view, clicking an internal page link in a Link or News widget did nothing — the shared view's navigation handler only understood the Navigation bar's object payload and silently ignored the bare page-id string that widgets emit. Both payload shapes are now handled, so sub-page tiles/links inside a folder share work.

  • The breadcrumb inside a public folder share shows the full path. On a nested page in a shared folder (e.g. Docs → FormVox → User → Creating Forms), the anonymous breadcrumb collapsed to just the share root, because the builder was fed a per-user mount path that could not be normalised against the share scope. It now uses the canonical GroupFolder-storage path, so all levels between the share root and the current page appear and are clickable.

  • Draft and scheduled pages no longer leak into a public share's menu or page tree. The share navigation and tree now apply the same visibility rules as the page content (which already returned "not available").

  • The News widget's "show only published pages" option now really hides drafts. News items were assembled without their publication status, so the filter saw every item as published and removed nothing. It also gave up when no publication date fields were configured or MetaVox was absent, and the caller only ran it when MetaVox was installed — in each of those cases drafts still showed. The status now travels with each item and is always honoured. A News widget inside a public share had no filter at all and could list drafts to anonymous visitors; it does now.

  • News cards meet WCAG 2.1 AA contrast, including on hover. On a coloured (dark) row, cards are drawn on a light tint but their text used the white "on primary" colour — measured 1.17:1 for titles and 1.12:1 for date and excerpt, where 4.5:1 is the minimum for body text. Titles now use Nextcloud's matching light-surface colour (12.96:1) and the date and excerpt use the full text colour instead of an opacity fade. Hovering previously flipped the card to a dark blue while the text stayed dark (1.75:1); the card now keeps its light tint (11.59:1). The carousel's secondary text (3.80:1) was corrected as well.

  • Publication dates are time-aware and use the instance timezone. The check compared dates only, so a page scheduled for later today counted as already published; and a time entered as local time (e.g. 15:57 in Amsterdam) was compared against a UTC clock, so a page could read "Scheduled" for hours after it was live. Dates now respect the time of day and are read in the instance timezone (the logtimezone system setting → the viewer's Nextcloud timezone → the server default); dates with an explicit offset keep their own zone. Administrators on a UTC server should set logtimezone, otherwise anonymous share visitors — who have no personal timezone — see scheduled pages appear at the wrong local time. See the editor guide for the command.

  • Blank items in the text widget's "Paragraph" dropdown. The heading options (H1–H4) below "Paragraph" rendered empty because their labels were passed to the translation function with the level as the app id. The markers now show correctly.

  • Several untranslated interface strings are now translatable. The page tree's "Show N more…" button and its expand/collapse labels, the navigation editor's focus-trap label, and the admin video-recommendation risk badges, category names and People-widget fallback field labels were hard-coded (or passed a variable the extractor never saw), so they stayed English in every language. They now go through the translation system.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureUBb4nMn8TJ3eLofW2Cb2kKLzsBx4OSswqMmfxydA3Uzv4+0qdn0F8h7zqPxwnbtQ6Zxo4oNtNkk7iqANQx7U34c85fWLpv7nrMYi7tJScTIcN2P47p44cyUmxgoj0IOAzWveB9d5OPd1zJUH48xf19Wfv46bVzmPdRKq6kpvnxlm4cofAc+eZLy1oMRrLQt1acRb1ZDMV5nefIp+i6z7NqUDVgxgdbCE0d/PpsjMU+dVzg33A+4RJMw7SJBMaNJyxBipn4mhNRzBw75Crs6UZeEVFbu+eP/CHhFRSdr8sR9uTHa8LrizFX1G+kvLUGO63izEZz61LsO56ntB7orQCSlwkpWfjWtu6v+IPTbF0DZhZn9JGCz40NQET5pg7UT9/ZUj29qyVuBn+HcQtFvxQ/cSYbNw9cMZ+cq+egWjqXBCz5SaXmP48GdPXQJVILhie61DL5hoSbFHGqwGfX458wBWZ860hxRywFF59+kDd0JhJ173qXDLAe0lbH2puSe0yvdRSQZXJhz8EHOrt4ix5Yh0t7xw8LUM73flZNeMqlqF9KMRr7RxPoSuPD7o4PAadC79TtHJS1WpnNYhvZpiKlxZcblk15skt3YH3b7++Xg2WVMBG+hVYa44ldeP/9Iegd/hpsS2vpXuxT3PiDBBSc8nzBntNvAAzOVG6aeGVdA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.1
Release Details
UpdatedAug. 3, 2026, 5:26 p.m.
Changelog

Changed

  • The page actions (⋯) menu is now grouped. As the menu grew it had become a flat, interleaved list. Its items are now organised into logical groups — page actions (Rename, Page settings, Copy, Save as template), site (New page, Edit navigation), utility (RSS feed) and the destructive Delete on its own — separated by thin dividers. The dividers adapt to your permissions, so you never see a stray or doubled line: a read-only visitor sees a clean short menu, the homepage hides Delete, and so on. No actions changed — only their order and grouping.

  • The help text in the Page structure and Edit navigation dialogs is collapsible. The multi-line explanation that filled the top of those dialogs every time is now a single collapsed line ("About the page structure" / "About editing navigation") that expands on click — the guidance is still there, but no longer in the way once you know it.

Fixed

  • Copy, and the navigation editor, now respect per-user permissions correctly in Team folders (#86 follow-up, thanks @kma-cloud). Three remaining gaps after 1.9.0: (1) the page tree's Copy button appeared where the user couldn't actually create, then failed — it now copies a page as a sibling into its own parent and is shown only where the backend will allow it (root-level items are gated on create-permission at the language root). (2) Trying to save the navigation without write permission returned a 500 error instead of a clean refusal — it now returns 403. (3) Edit navigation is gated strictly on write access to the root, so a read-only user no longer sees a button whose save would be refused.

Security

  • Dependency updates. Patched bundled front-end dependencies to clear all known npm advisories (axios, postcss, dompurify, fast-uri, linkify-it, brace-expansion) — non-breaking patch/minor bumps, no functional change.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureqGA3vDWGE6zTcCgb+VIfpjRMzk/kGoFf2p5HKz8bzQ8dq8ghNzvClqaWGiDuQjzld07fq3ETLpMzglrGjYcNI3tvg6WJr7Sv78OOI19Vdl3j6v1HTPBe4lqbq3DhLRHcNeNaPxMJ2QOeXfQqsm9Re8USkLCG99/IbsQpcd1KLWbhutLCFe4eu1In60nRxT6Ix7KUuKuLGFjBJ79Sk3SkRFgzc0NwUF4KVisPt01lVDt4QX6AeDOkrVD5tzgJqM1Bso82wDkqlMp5CmK6ANMD/7eZ26Df/D4HQjuT9AmcbwCIF4iRRdJwRZa98swOQw25KFGoeonB49ErxrT5ghQr9pTd/EsGy2s+sS15OS+ux8YKunPrRnhhdbe+g3i3+gRLWhGItisMBkEbGWNfYf4bW0RKgbaRuTokDuagszGTA9d52aCROwk3h/Kipqk3n0mLgwkxcdtA8G5/NclWRZ1XjR1kNPjEkeAdv4nWXc6Wo/wmompOlrSU7hxjEys5pnWWDBfT231b3+ymzLQwfGRoVWFsYY0LGiDRI8Q17+pWv1Wo5rLwx5+1acIJm/PrtU0Jl8456k9Ou13kQAFyy8u+khavNT1hprl9PcnxOnkDSzrOiNUWZrCJ0noRmJjTr6BqWqfUDAxrxygP/Hn8f/EopXQwArHc2xfh6RJ+UaaQvPk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.0
Release Details
UpdatedAug. 3, 2026, 6:07 a.m.
Changelog

Added

  • Rename a page directly from the UI (#84, thanks @kma-cloud). A page's title could only be changed from the Details sidebar, which nobody found — so it looked like pages couldn't be renamed at all. There is now a Rename page entry in the page actions menu (the ⋯ menu on the page you're viewing) and a rename button in the page tree's manage mode, both available to anyone with edit rights. Renaming only changes the page's title — the page's address (folder) and all links to it stay exactly the same, so nothing breaks. When the navigation menu label still matched the old title, it's updated to the new one automatically; a menu label you'd deliberately set to something different is left untouched.

  • Page buttons for the File Story and Photo Story widgets (#78, thanks @kma-cloud). Setting a maximum number of documents used to hide everything past that count, with no way to reach older files. Both widgets now have a Long lists choice: keep the existing Infinite scroll, or switch to Page buttons with a Documents/Photos per page size and Previous/Next buttons that page through the rest, so everything stays reachable and the widget keeps a predictable height. Maximum documents/photos stays a separate, optional total cap that applies in both modes. Page buttons apply where the widget already paginates — File Story's List and Tiles, Photo Story's single-folder Timeline and Grid; the other layouts always use infinite scroll. Existing widgets are unchanged (they default to infinite scroll).

Fixed

  • The filter operator dropdown in the People and News widgets was blank. When filtering people or news by attribute, the operator selector (equals / contains / is not empty / …) rendered empty options — only a checkmark, no text — so you could not tell which condition you were choosing. The template translated the labels with a single-argument t(op.label) call, which @nextcloud/l10n read as the app id and returned undefined (the same bug class as #79). The labels are now translated correctly and, as a bonus, are actual translatable strings (they were previously hardcoded English that no language could translate).

  • Special characters in page titles work correctly. A title like Collega's was stored HTML-encoded (Collega&apos;s) and shown with the literal entity in the title, breadcrumb and heading; A & B, quotes and <> were mangled the same way. Plain-text fields (page and widget titles, alt text, link labels) are no longer HTML-encoded at storage — the frontend and the RSS/export sinks already escape at output, so there is no security regression. An occ intravox:repair-entities command (with --dry-run and --user) decodes titles/text already corrupted by the old behaviour. Two related fixes: accented and non-Latin letters in a title are now transliterated into the folder name (Müllermuller, Cafécafe) instead of being dropped (mller, caf); and creating a page whose title collides with an existing one now opens the newly created page instead of failing to save with "Page not found" (the new page is selected by its stable id, not the derived slug).

  • Page-structure and per-page management now follow per-user permissions in Team folders (#86, thanks @kma-cloud). With GroupFolder Advanced Permissions (ACLs), a user who could write in only one section either saw structure/management controls that then failed with a 403, or did not see them at all. Two causes: (1) the page tree was cached per group, so a per-user ACL grant was not reflected in the tree's permissions — it is now recomputed live for each user (the same per-user approach already used when opening a page); and (2) the "Manage structure" toolbar and the per-page manage actions (reorder, move, rename, copy, set-as-homepage) were shown based on write access to the root, not to the actual page. The toolbar now appears whenever the user can manage any page, and each action is shown only where the backend will actually allow it, so the UI no longer offers actions that 403. Note: this addresses the UI/permission mismatch only — a per-folder "Read + Write" ACL still requires the user's group to have write at the base level (an ACL cannot grant above a read-only base; see the authorization docs).

  • The "From template" picker went blank as soon as one template existed (#79, thanks @quarterstaff-tech for the thorough diagnosis). With zero templates the picker correctly showed "No templates found", but any template at all made the panel render completely empty — no error, no list. The template preview card tried to look up a per-template translation via this.t('template_<id>_title'), calling the t(app, text) wrapper with a single argument: the key landed in the app slot and the text was undefined, so @nextcloud/l10n's translate() crashed on undefined.replace(…) (TypeError: can't access property "replace", f is undefined), taking the whole panel down during render. Those template_<id>_title / template_<id>_description keys never existed in the translation catalog, so the lookup was dead code that only ever crashed; the card now uses the template's own title/description directly.

  • Drag-and-drop upload did nothing but open the file in a new browser tab (#85, thanks @kma-cloud). The image/video widget's media picker invited you to "drag and drop", but the drop zone never handled the drag events, so the browser fell back to its default behaviour and navigated to the dropped file instead of uploading it. The drop zone now accepts dropped files into the same upload flow as the file browser, with a highlight while dragging and a type check (native drop ignores the accept filter, so an image widget rejects non-image drops, and video rejects non-video). The same missing-handler bug in the admin Confluence HTML import drop zone is fixed the same way (validated on the .zip extension).

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureqrQoDs284d1e7hHhvExpV85DY/hEp2pQ5lZn5WaBYxJfBxVpT1bdcatKbRjwdHGcnxbjzTh79qsEP8Zdm23RCEblKiyPbJMkSR3KwSka4ZsyrKjI3tYNm4sKalKfF32nyYt8lMlNpduALWkJCVb3CsydyuGeIsMXa0GL7Dg3JBsP1fPknHo3MkKRt/G3zr8LyrrKp6fYAy4r43MVSfYaLH1C7osKCG3zsrfO5VYb2CP0kSsIld77IV4FX23PRqawMJoAYNQ4ULqF7BlmllXOpUD1YsPoIJc8RODyLTBsY4jwXHGQJ5BBCrN71zDuPW1/Xdqpw0ey2XvJISuzKKvYOeZXMEpr0IzCwQ9grMFbZUfcz0sHr3oSG8WKxGRnmEKpP8yTHsnnadhESSX+Acli6S+gunpnmgHM9V9iJ7LtG5qBV95gBBY0mUJU1Ekdv6uIIvzSRB0H3f2lFc7x1jhxFREsSgws74O6DkIP0wF2iEO2Iq74Xark7/z+hjeBGE17aznK6Y/pdaWG+jXS+jazezBHeVjxHnsFvEJqgNsxzV4ZLMFFiMraJab9muUfeIuMxfmLrTJOTK2MuNU890a6B5YIuawDVF4uHtzwDbAMm5DP/gkNipxbXbPh2QK1uAl7grazK84X3vQ+QiQUgd3H+qFrTH6DrngYbEVEBI0TZWE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.4
Release Details
UpdatedJuly 10, 2026, 6:15 p.m.
Changelog

Fixed

  • Every button and label in several dialogs read "intravox" (#77). Four modals used a translation wrapper that put the app id in the wrong argument, so the "Create new page" and "Save as template" dialogs, the page-tree selector, and the "All pages" list rendered the literal string "intravox" for every tab, label, and button — making them unusable. The wrapper is now aligned with the rest of the app (t(app, text, vars)), so the real labels show again ("Blank page", "From template", "Page title", "Cancel", "Create", …). Pre-existing bug, unrelated to recent translation changes.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTe1odfxiiohPjc11AuhYvlSV+RfrbFqpMxueWeTS8IMhi4V9DQQeMegMU+opEACytWuY2smPcEmvApaOBFQHFBhcpE9EUIF0A/yoW1HK7IoZXwTWmaeTW01XqNBgm01NIEV/k677kzSCmCe03a53nEJpn517hScNan9nUZxr0d3VDfHxB/MuDBKq2gCBS1eEV4AsyLfrUo9x2AfYI/Lh4UZcnGFxN4Zd/9DD3slBOg3G8A5MUixjArUKLGAD33x+qrTXL96IX/TM1CQdwhycP+82OVTdEtQiFB2PCWq17Z2GVncv5xec+eRddw78gOFnyad2ykWshSfPSTAAuQlZ/+AM0pYMyTEcEHBQTMOxOMoZjQpMjEyB159TZzoxynlkDEuV5/RE3iP5i5lcrOXuARStcp2BZLyhBAkjAQ+/7diVM8urYIw4tqvA1b9T3WeLlQUC+kJtgg5WEb2F206yBN/Thd9aT/c4LlhMBtUW7KLfY3PnWvxNfMpDULuQvjnPsXJOuzFa871O/IuiYPyJeYtf4pdBCJ9ihc5Zxqu7ZL/mv6LmQMuNFdtSCYd443UAFrl3hpWUx6ox7fupKVq+D57VRMd2jmJeOHIZJ2Ii3qYH5jwq3qIw95OwDK9YTEYDN0IR8aDkMfhzasSEIH9mgr6Tn19OjxVHKI4+KD9aFq8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.3
Release Details
UpdatedJuly 10, 2026, 1:51 p.m.
Changelog

Added

  • mave.io as an allowed video service (EU-hosted, cookieless, GDPR-compliant). Because mave.io serves each space from its own subdomain (space-{hash}.video-dns.com), a fixed allowlist entry can't match every space, so this adds a wildcard-base-domain mechanism: a whitelisted base domain also matches its subdomains. Matching is boundary-safe (the host must equal the base or end with .+base, over HTTPS), so look-alike domains like evilvideo-dns.com are rejected. Enforced identically on the backend (PageService) and the frontend Save-gate (WidgetEditor).

Changed

  • Translation polish from reviewer feedback (thanks @rakekniven and the Nextcloud translators). Added TRANSLATORS: context hints for the Photo Story layout-style names (Magazine / Apple / Travelogue) so they're not translated literally; renamed the admin heading "Video embed domains" → "Domains for embedding videos"; fixed "Popup blocked. Please allow popups…" → "Pop-up blocked. Please allow pop-ups…"; and updated the app description to say "Team folders" (the current Nextcloud user-facing name) instead of "GroupFolders". The feed-URL example placeholder is no longer a translatable string. Ships with refreshed community translations (de, de_DE, et_EE, pt_BR, and others).
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureALXXa8zgPsReRyfFakJc3pmk5fyZ/f3XJhbWvdWmiSs/GGoh6k4bpHLg7eV5CC0A3Fpdkf2w1K9T0/84NaoI65mkuLQazVnI9OBRqdGfJdkJOcToh8FMGRr06oJH7KEYnZhphBbdjKvaq2/Jhe7gZkUdOpqoNYlWGWqmIAngpYpaWjdglJLHTSWK86nwckDAEB6mTnUlfEfyzAF6i5SbIcYWaIL0VFy7dYqtnSgkEyrRFc/bb+iwOvWp+TwqCLWy1RMT/mmK3VcTeIgwzPsW+X8gxgJHYWCmY0ZDTEpjoHR9xM5hA/jtW791bAIdBbwOnLxH2g8es83H8DRX4RFwFBaDQKNCCMQLVVVePaM9YaWuIVUImJ3wRcJqX51MYA9BH7LH/lp/muUaR94uzxIlOb/TnCPaeOL2x7haSD681R7/pELc8OUuxtpiFkb+wmenZryjE9MK9n2hGrCU+lwXD9hVeFs/8PD6Q6vNc4erEUegrxuvA2BjO8nF3jtHrFXSmdjuR5IKoXiiUa7oueJQjTLaS4OKf5R3sfZ/bIy3jE4VlQua+C1B267c7qswulmkHNyWEaL3mAPmY101OXS4yOeaKnIYLbtcuL+/BguNgD2N4Q4OZVpdnkw+qiVe0DjgT1KwkwoZSPsYcNp1SJZ2HYIhUV2SFsTjSoZuhyspdt8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.2
Release Details
UpdatedJuly 8, 2026, 11:01 a.m.
Changelog

Changed

  • Faster group lookups. Permission checks now use Nextcloud's getUserGroupIds() instead of loading full group objects, avoiding unnecessary object hydration on the hot permission path (#74, thanks @carlschwan).

Fixed

  • Users whose language has no content are shown the recommended language instead of a blocking notice (#75). The admin settings promise "if there is none, they are shown the recommended language below", but the landing page ignored the recommended (primary) language entirely and only ever fell back to English — and since 1.7.0 it showed a full-screen "No content in your language yet" notice even when English (or any recommended language) had content. The page now resolves the language to show as: the user's own language (if it has content) → the admin-configured recommended language (if it has content) → English → and only when nothing can be served does the notice appear. Authoring is unaffected: an editor still creates and saves pages in their own language, never the fallback. Also fixed the notice's "Manage intranet languages" button, which deep-linked to the old Demo data tab instead of the new Languages tab.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureL1CilQMaUR50sVUvKQgjThVmYhacoxZ/0IU6asyD7jwLv81NCDoeEqbIaYd92How8BoPGPg/OPQM6wTgn0lYvOb2/a3Yr+CrLF0Cf/2KNFZrRmXguv9qoLXIHDahbelQfSrl9GyuyDw0i1v1s7KvC3dYyTrAh5/VA8ZoXe3raKRAP3T6+II2UNN/NHOE3K6f+zPkKYDk5Ne+qHWIQqxmdm3k6nZaqZ7AZbNF9hNePrvBu7MF81Pshh2MCXsDD5+R9Wrq+W5zWijhLWvsUYlXYMLbL2pjF7xKl2U8TcnED3O7hLI1GI1DoZTqaRGlQs2cye/rw2zyds2UW2a99r+BUbVStKmJcoJfm2iQ+mFZMqRJNoC1pONvmImAm6iRFfDT5F6rTfUCXZnEsQKbyGfn+1pI+FGqMBcIE7HRvg7Zvo5VYC9VYBTtaUYPEXo/mv/+1gAPT6S9vohBOsK8yhDTxaBuTXUxXvHnEK9xkLK6YnOcAcGa4rRUQoDS3mUd7T2A0GLUSr6jqwkc0aGKFSozDJElR6iFZX5/y1BXzIQorkFWNTL7ZWrKXyHgsWL/WToiDe4StSKAk9u5gggebJ1O4O54yzgSHjSAwzijv8TN4gy76YO2d6GUNYr5caSCLBQwKpWvzchKlZt8VOA0XvbL/TV2RNiEsFOdlKbjAP2OqlQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.1
Release Details
UpdatedJuly 7, 2026, 4:03 p.m.
Changelog

Changed

  • Intranet languages now have their own admin settings tab. Choosing which languages the intranet holds content in — the "languages with content" list, the recommended (fallback) language, and add/remove language — was buried under the Demo data tab, where nobody looked for it. It is now a dedicated Languages tab, sitting alongside Video services / Engagement / Publication as a peer "how the intranet behaves" setting. The old tab is renamed Demo content and now holds only the demo-install table, so its name is honest. To avoid growing the tab bar, the rarely-visited Maintenance tab (orphaned Team folder data) becomes a sub-tab under Support — both are infrequent operator tasks. Old #maintenance deep-links and the orphaned-data banner still work: they now open Support → Maintenance.

Fixed

  • The recommended language can only be one that has content (#73). The recommended (fallback) language picker previously listed every language, so an admin could point the fallback at a language with no pages — leaving users whose own language has no content staring at an empty intranet. The picker now offers only languages that have content (plus English, the universal source/fallback), and the backend rejects setting the recommended language to one without content (POST /api/languages/primary returns 400).
  • The "Edit page" button now hides for read-only Team Folder members (#70). Even after the 1.8.0 permission hardening, a read-only member (e.g. an "IntraVox User" group with view-only access) still saw the Edit button and only hit a 403 on save. Two causes: (1) a page's canWrite was derived from the page folder, which a read-only Team Folder can report as writable, while the actual save preflights the page file — so the button and the save disagreed. canWrite/canEdit are now gated on the file the write path targets, matching reality. (2) A page's per-user permissions were baked into a distributed cache shared across users, so an editor's canWrite could be served to a read-only user (and vice-versa) for up to an hour; permissions are now recomputed per request and never cached, while the expensive page content stays cached. canCreate/canDelete remain folder-level as before.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBYA7jrD9xK8H4nt4f/dxUKG5VVqr8boApvEJgZiEfQYlmFRhA1ukRyzwClJ1ioAe3sHUKySuW+fOUgqD6ICcV/N7douwFXqb7UIHdsG3z3pAOsjifmfW2/6SLLCrWYnonC6W+eZdr9sQj2hjPBYRZuiK4MJCNSxrrnZE3eEt2kQFeFsK6GLOdhF+UkPVQNqtKdsZDKOCZsTAq2LyPBefse4R4pHk4/no/4sOisfEvxxln0cVIpESr5KfVPFASbvgzMLjktSAN0/A3Xx4l/q9RYe9ulaIJPZ5HfKOrB7cqUQ350n88LFk1SV9g3qXdo8o7kgnLA04vaSMXa2QngupJpYIFB8VsOZl9QDZSeGB8yU0PF1VZm9z8dCohCZ1/JWSY9bc6kYZ2nq2maC0AP0g3sAMGioJ6ta3ZYCBUHcGmWSpagAnvyAQC6gfIPsMI6zIbm6ALX88YKjiyF4hYCWIgN51xOUpgsTAIKelsEyqlKcvxfAJeuTbq9gxpeSajQw8d4o2IcMl2hx6g5w92KzsXDV+Rx7FrQStYZrC3nDdQr2aVWlmJTXYNYMMV6glVZsrO/UX2ENqGA+GdKA8duaRQMuQ6uB4tcfMxE88Ozx6nFH+mYrv7plcQrFppuHlKmmVWyF7TyHRSaRsYbC9LIbNQrkh/riql891SebcOIIjprs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.0
Release Details
UpdatedJuly 7, 2026, 7:07 a.m.
Changelog

Editors can now manage the page structure directly from the IntraVox UI, without touching the underlying folders. This release also hardens IntraVox on Team Folders: read-only members are handled correctly, and setup/demo-import now work on installations with primary object storage.

Added

  • Reorder and move pages from the structure view (#69). The page-structure modal gains a Manage structure mode with per-row controls: move up / move down to reorder a page among its siblings, move to another page to relocate a page (with its whole subtree) under a different parent, and delete (with the existing confirmation). The home page stays pinned — it cannot be moved, reordered or deleted. All controls respect Nextcloud permissions: you only see them where you have write access, and cross-department moves obey GroupFolder ACLs.
  • Sibling order is persisted in a new per-page order field. Installations that have never reordered keep their existing order untouched (a stable comparator leaves pages without an explicit order in filesystem sequence), so this is a no-op until an editor first reorders.
  • New endpoint POST /api/pages/reorder; cross-parent moves use the existing POST /api/bulk/move (admin-only for now). Moving keeps the page's uniqueId, so internal links and URLs by id stay valid; a folder-name collision at the destination gets a -2/-3 suffix.
  • Configurable homepage. Any root-level page can be made the homepage from the page-structure manage mode ("Set as homepage"), and the current homepage is marked with a Home badge. The homepage is now a per-language pointer (homepage.json) rather than a hardcoded home.json, so no page needs to be renamed. The homepage cannot be deleted or moved until another page is assigned (returns HOMEPAGE_PROTECTED, surfaced as a clear notice). Fully back-compatible: installs without a pointer keep using the legacy home.json; the old homepage is lazily normalized into a regular folder page (keeping its uniqueId, so links survive) the first time a different page is set as home. New endpoint POST /api/homepage.
  • Copy page. Duplicate a page as a new draft from the top-right "⋯" menu (copies the current page) or per-row in the page structure. The copy gets a fresh uniqueId, keeps the layout and media, is titled "… (copy)", and never inherits the homepage role. New endpoint POST /api/pages/copy.
  • Delete page in the "⋯" menu. The top-right page menu now has a "Delete page" action (with confirmation), hidden on the homepage and shown only where you have delete permission — matching SharePoint's page menu.

Changed

  • Clearer separation of "Edit navigation" vs "Page structure". The navigation editor now states up front that it only changes the links in the navigation bar and their order (not the actual pages), and the page-structure modal explains that its manage actions move the real pages and folders. Both modals lead with the same info banner and cross-reference each other, and the word "menu" (ambiguous) is gone in favour of "navigation bar". The "⋯" menu also closes when an item opens a modal. The page-structure modal also notes that only top-level pages can be set as the homepage (move a sub-page to the top level first).
  • Faster page-structure operations at scale. Reordering siblings is now O(N) instead of O(N²) (it reads a parent's direct children in a single cached pass rather than walking the whole subtree per child), and bulk delete/move/update clear the distributed cache once per batch instead of once per item — noticeably quicker on large, deeply nested intranets. No behaviour change.

Fixed

  • File Story widget now shows Whiteboard and FormVox files (#68). The widget filtered files through a hardcoded document-mimetype allowlist that omitted Nextcloud Whiteboard (application/vnd.excalidraw+json) and FormVox forms (application/x-fvform), so those files were silently dropped from a picked folder. Both are now included — FormVox forms render with their real preview, whiteboards fall back to the mime-icon placeholder — and each groups under its own "Whiteboards" / "Forms" category. Also added .odg drawings (application/vnd.oasis.opendocument.graphics, grouped as "Drawings") and the text/x-markdown alias so .md files aren't dropped on installs that register markdown that way.
  • Page-structure modal labels now translate. The tree modal and its rows used a wrapper that passed the app id as the translation key, so strings like "Collapse", "Expand" and "Current" rendered as literal "intravox". The wrapper now matches the rest of the app (translate(app, text, vars)), so those labels localize correctly.
  • Deleting a page by uniqueId now works. PageService::deletePage resolved only legacy folder-name ids, so a delete request keyed on a page-… uniqueId (how the UI deletes) failed with "Page not found". It now resolves uniqueId first, then falls back to the folder id.
  • Read-only Team Folder members are handled correctly (#70). On a Team Folder shared read-only to a group (no Advanced Permissions/ACLs), such users could open the editor and the Save then failed with a confusing HTTP 400. IntraVox now reports write/create/delete permission accurately (it combines Nextcloud's permission bits with the node's own isUpdateable()/isCreatable()/isDeletable(), which reflect the mount's writability), so the Edit button is hidden for read-only users and a write attempt returns a clean 403 instead of a 400. This also removes the follow-on Nextcloud core ShareHelper error. Reading navigation/homepage no longer tries to create the language folder for read-only users (which explained the intermittent "navigation not visible until permissions were adjusted").
  • Setup and demo-data import work with primary object storage (#71). intravox:setup and the demo import resolved the Team Folder via the internal /__groupfolders storage path, which does not exist as a node when object storage is the primary backend, so setup failed with "Failed to access groupfolder". IntraVox now resolves the folder through a member's mounted view — the same storage-agnostic mechanism the rest of the app uses — with the legacy path kept only as a fallback for local storage.
  • The "Add widget" picker opens again (#72). The widget picker crashed on open with TypeError: this.t is not a function because the component was missing the translation wrapper the rest of the app uses, so clicking "Add widget" appeared to do nothing. Adding the wrapper restores the picker.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturesf/demh4nISYFiTA4SLXu8F8cZOd40DZL/psxAoptr6CjZBliXnhmzsvL/x+LPUU+AwAROwBBi4XyXalNjWTiTUz06Y9XjmUwwTcRzOuniF+E9oddyOYbsCy6Ea/LgVIVDHymPQbaB/JSfjgm+5khswNyuuLyQumOSdK6RZQYRopMg0u0LfUJJmhAwl1LXZI/+YF8p/uIISKkgUf3JfeyY6JseZ/IIe/Z6EXjmt+nrOZY6ZCTRgYzjOS95uYsaky7+T0hKRdIVaBiOUn9HkEsHAnAfEajkZ6+lui2dyP7ztzjgYBUklWrnfV14PISVJF1V6MTJl5ZLg9IoC6KA4iIj0itvjzoVX1KgJhgN2JbQMw8fOEUmG/iY44mpDqL849rQp8qmw/t1EngVUQbXC3BYWgNip3b/FxDHO3wK61ysvCVjUaVblYHMcCq4O1Ei1aytM+akxbyAOAD5YTgRKEGKr9o2l4g2tHS2umG5vPT3kNQhXkgnIuFysaT16Z3P5V7+rpWiI387kfUR6Seb35qe+a+jdS0f4MWW+JU4g2psQ/2cKt9V1b/7paJbHC+meXl31GNMJaqAJBquUiPISCGaCSiszcQ76PIn5OUuU3PdHEbFGKTEt3RX4f4pC9pVJiiFu9bkDBAwwrPxoY5jjVeQCfo0txD6d7eeFjzfnf4Gk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.7.0
Release Details
UpdatedJuly 3, 2026, 12:48 p.m.
Changelog

When an editor maintained content only in one language (e.g. Dutch) and a user's Nextcloud language was set to another (e.g. English), the user silently saw a generic placeholder homepage — the editor's real work was invisible and there was no hint that this was a fallback. This release replaces that silent placeholder with a clear notice, gives admins full control over which languages the intranet holds content in, aligns the language handling with the wider VoxCloud model, and brings all source strings in line with the Nextcloud translation guidelines so the Transifex resource could be unlocked for translators.

Added

  • Language fallback notice on the landing page. If the user's own language has no real (editor-authored) homepage but another language does, IntraVox shows a clear LanguageFallbackNotice instead of the generic placeholder: it states the intranet has no pages in the user's language yet, lists the languages that do have content, and links to the user's Nextcloud personal settings so they can change their own language. New endpoint GET /api/languages/content-status.
  • Full content-language management in admin settings. Admins can pick from every Nextcloud-known language (not only the subset IntraVox ships a translation file for), choose a recommended (primary) language used as the fallback suggestion, add a language (creates an empty homepage so editors can fill it), and remove a language with a confirmation dialog that warns how many pages will be deleted (the folder goes to the trash, restorable from Files). The fallback language (English) and the current recommended language are protected from removal. New endpoints POST /api/languages/primary, POST /api/languages/{code}/add, DELETE /api/languages/{code}.
  • UI translation-coverage indicator next to each "Languages with content" chip, showing what share of the IntraVox interface is translated into that language (e.g. "UI 8%"), with a tooltip. LanguageService::getTranslationCoverage() computes it per base code (largest regional variant wins, e.g. dede_DE.json); scripts/extract-en-json.js writes a committed l10n/.source-count.json so the denominator is available at runtime.
  • Deep-linkable admin settings tabs. Each admin settings tab is addressable via the URL hash (e.g. …/settings/admin/intravox#demo), and the tab updates the hash as you navigate.
  • l10n/en.json extractor (scripts/extract-en-json.js, run via npm run l10n:extract / npm run pot). It scans src/ and lib/ for every t()/n()/$t()/$n() call and regenerates the English source for the POT, replacing the previous hand-maintained/restore-from-git workflow.

Changed

  • "Active" languages are now derived from content, not an opt-in list. A language is active once it has a homepage; the enabled_languages opt-in checkbox grid is replaced by a "languages with content" view plus add/remove controls. Real (editor-authored) content is told apart from auto-generated placeholders via a _generated marker, dropped automatically the first time an editor saves the page. The admin chip list shows active languages (any homepage, including a freshly added placeholder), while the fallback notice keeps the stricter "real content" rule so a placeholder never masks "no content in your language".
  • Demo content table now lists exactly the languages IntraVox ships bundled demo content for (Dutch, English, German, French), independent of the deprecated enabled-list (German was previously missing). Hint reworded accordingly.
  • Source strings aligned with the Nextcloud translation guidelines (#63): sentence-case for headings/labels/buttons (e.g. "Demo Data" → "Demo data", "API Token" → "API token"), a non-breaking space before every ellipsis, "GroupFolder"/"Team Folder" → "Team folder" wording, real gettext plurals for relative-time and file-count strings, URL/placeholder values removed from t(), and the redundant translated language-name helper dropped (the picker uses Nextcloud's own localized names).
  • Complete Dutch, German and French UI translations bundled (all ~1220 interface strings, including plurals). After the source-string cleanup the Transifex resource was re-provisioned without the earlier translation memory, so these are shipped in l10n/ and also serve as translation memory for the next Transifex sync — the community can refine them online from a fully-translated baseline instead of from scratch.

Fixed

  • "Add language" actually creates the content folder now. It silently failed before: LanguageHomepageService wrote to getUserFolder('intravox'), but there is no intravox system user ("Backends provided no user object"), so nothing was written — while the UI optimistically showed "Language added". It now writes via SetupService::getSharedFolder() (the same GroupFolder path demo-data uses), and the frontend reads the real server state instead of guessing, surfacing an error if the write fails. Adding and removing a language now triggers a synchronous groupfolders:scan so the change shows up immediately in every user's view and the Files app — without it, an added folder stayed invisible and a removed one lingered as a stale entry until the next background scan.
  • 3-letter language codes are no longer truncated. Language codes were clipped to two letters (substr($code, 0, 2) / [a-z]{2} matching), so Asturianu (ast) became an invalid as folder that didn't match its real code. Base codes are now treated as 2–3 letters throughout (ast, kab, …), so adding/removing such a language creates and deletes the correct ast/ folder.
  • Bumped vulnerable dependencies (dompurify, form-data, markdown-it, ws); npm audit reports no vulnerabilities.

Deprecated

  • enabled_languages app-config and the language#setEnabled / language#createEmptyHomepage endpoints are deprecated. The config key is no longer written by the admin UI but is kept in the database for downgrade safety (it is simply ignored by 1.7.0 code).
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLGu99gGuBgb/dL9oReX7t3liWl+nUdx6xXacAH71VZ567hyQ95XSVRziAGTirgeMXo5p/FRSvX7lXfIYdCO71UTDt5evJug1NuDcR77ARGdb59wstOQg5NceDiN+kvKB8ET08m/zqG5F6iDtyaIOFdZuIuKqwQR9QPdX4+UunJhReAQRk699Ssqb/PR1AWjv88MG8JBUSfpa0ZiV2iVsvIkLn6xuPFgzdqvedssa/fQFcGrg9yyHHmgnUe0QBk38D5hDan4SNNGNg003jcK/tUEOTINKUQQoWp3FYFDrb11X4PzwUewDOvBiA0uE/dtiE3NPsap8M9ClE+81wolGu5flksqjvRndHbc2qV4jdbmeevGA18mTRNqb5s1BT4e4q3rWEljFCO9epg5o+UzEV31OefkvCoIYnZIe1nU/d4yl6xGCi/YgtP1f0ayff421vqD0Kda7xu1g0L+OV0vxmvV1oU+3wgwdEfX7Z49k22mUwleeArCOjuluQIuPwC8vNxkyiv+uwhwXyju4f4MqJfNbMDAYjSHNCrYqO+rQBkKQFUZ8qMOtYY0LYQTEmltlLgZA210c+YuBqbeZknBxtJKWf5IeOkMwGttZVUkDhgu+4rufsxs+I8ZbAhxDfBWxyRUyIOYa4cgyZOmuaN71Y0KBP28VSYIxJfkaAXKB/E4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.6.1
Release Details
UpdatedJune 14, 2026, 3:36 p.m.
Changelog

Bugfix release. IntraVox 1.6.0 declared Nextcloud 34 support but crashed on occ app:enable intravox:

Error: Call to undefined method OC\Server::getAppManager()

Nextcloud 34 removed the legacy \OC::$server->getXxx() getter shortcuts on OC\Server. The 1.6.0 NC34 audit only checked the public OCP\* API surface and missed these internal OC\ getters, which were still called in lib/. During install the repair step (SetupDemoData) hits SetupService::isGroupFoldersAppEnabled(), so the crash aborted app:enable entirely.

Fixed

  • App can be enabled on Nextcloud 34 again (#58). Replaced every removed \OC::$server->getXxx() getter with dependency injection of the stable OCP\* interfaces across 11 files (SetupService, PermissionService, ApiController, PageService, PhotoStoryController, PreviewController, LicenseService, DemoDataService, OrphanedDataService, ImportDemoDataCommand, ImportPagesCommand). Getters migrated: getAppManagerOCP\App\IAppManager, getUserManagerOCP\IUserManager, getDatabaseConnectionOCP\IDBConnection, getURLGeneratorOCP\IURLGenerator, getMimeTypeDetectorOCP\Files\IMimeTypeDetector, getConfig → injected OCP\IConfig. These interfaces are unchanged across NC 32/33/34, so a single codebase keeps working on all three.

Removed

  • Dead $nextcloudPath = '/var/www/nextcloud' field in SetupService (unused, and wrong for non-default install layouts).
  • Redundant \OC::$SERVERROOT-based demo-data path fallback in DemoDataService::getBundledDemoDataPath(); IAppManager::getAppPath('intravox') already resolves both apps/ and custom_apps/ layouts.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWy0T0lmM8uWfR36zg8kC6FuQgij2PPpmHKD773BWRd8ARdh56W6m9tw6QQNBgUWIQ5cNahUZINEJPVCUmHVBbFA3e/DSndhZ2BBCXHSnAF5JyJu+LAzII3RYpPI8FQi8dW4YM0vqatnbYi+jeJwq9029rjJ7fq8Rgansx4vsi9sIxzszrDtBTzPSNeXEUxDzHMIhX8urvA71wdHUjhCKQDStFMgn4UR0ts+pr7vpl+GcbbEI5g4ySvBehKGYsSSWBea8oGQXR7EuIDmaAqk7PRp3PUdh91afXWQTNaDnx1e0yinXD5MURzxa91k8cfik+g9bsmSU2wbxcuKFOXKxujpPJTM4Qm0Rm48QLkDeoSHyZPzSDUtAcFvfP020hW64jfeXgMFEIF0OIm20z6WnxjimJa7Nbr3v+3RZMiCxJa7EzpK4chKlX2MHVGXm16/tUOwU1VUf2OEm+99AfGQqwImcKKbLS8Y9Ysk+pm9BmzF7y4nCpTbiBZmBF0K6Cuwk0QAj2ThQnjW3rDxOJ4oAkiuaIXC+4E3z67pWeSzkMiIC6B5zRpsSHu7jteX9PBxMQJOEG1prE13sLJaX48KzLA6iYcxx2gCwF29wgpwsAujHwNQu82JQWPSHjnvPmm+yfxHbDPDvuxG/2BaGgsQzHOorqdZbIcUPTuJyyOLeWww=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.6.0
Release Details
UpdatedJune 13, 2026, 11:59 a.m.
Changelog

Major release with three themes: Nextcloud 34 compatibility, community translations via Transifex, and admin-curated language activation. Plus PhotoStory lightbox fullscreen + "Open in Files" originally drafted for 1.5.6 are folded into this release. No data loss on upgrade — existing installs keep their four configured languages enabled by default.

Upgrade safety contract

This release respects seven rules so existing installs cannot break:

  1. No language folder is ever deleted automatically — not on toggle-off, not on upgrade, not by cleanup.
  2. Default for installs upgrading from 1.5.x is ["nl","en","de","fr"] — exactly the previous hardcoded set.
  3. The Version10600 migration only seeds the config key; it never creates or removes content folders.
  4. English cannot be disabled — it is the guaranteed fallback for every code path.
  5. License page-counts stay per-language and are not reset when a language is toggled.
  6. Cache invalidation runs automatically when the admin changes the enabled set.
  7. occ upgrade from 1.5.x → 1.6.0 produces zero user-visible changes (until the admin acts).

Added

  • Nextcloud 34 compatibility declaredinfo.xml now ships <nextcloud min-version="32" max-version="34"/>. Audit results: zero removed-in-NC34 OCP PHP APIs referenced in lib/; all five OC.* JS globals IntraVox uses (OC.dialogs.filepicker, OC.MimeType.getIconUrl, OC.L10N.translate, OC.requestToken, OC.webroot) remain functional in NC34 stable (deprecated, scheduled for migration in 1.7); bundled @nextcloud/vue (9.8.1) and Vue (3.5.22) match NC34's ship versions; PHP >=8.2 matches NC34's >=8.2 <8.6 requirement.
  • Transifex-ready translation pipeline — IntraVox is now packaged for community translations via Nextcloud's Transifex pool (o:nextcloud:p:nextcloud:r:intravox). New .tx/config + .l10nignore + l10n/.gitkeep + committed POT template enable the Nextcloud l10n sync-bot to open pull requests with new translations as they land. Resource provisioning requested via docker-ci#951. The four existing languages (NL/EN/DE/FR) continue to ship in l10n/*.json until the resource is online.
  • Admin-curated language list — new "Available languages" section at the top of the Demo Data tab in admin settings. Each language IntraVox ships a translation for appears as a checkbox; the admin ticks which ones should be active in the intranet. Disabled languages disappear from IntraVox menus, navigation, and the demo-data table, but all their content stays on disk and reappears the moment the language is re-enabled. English is always enabled and cannot be unticked.
  • Empty homepage on language activation — when an admin enables a new language (one without bundled full-intranet demo data), IntraVox creates an empty homepage in the content folder so the language is immediately usable. Idempotent: never overwrites existing content.
  • New LanguageService, LanguageController, LanguageHomepageService under OCA\IntraVox\Service\* and OCA\IntraVox\Controller\* — the single source of truth for "what languages are shipped" (auto-discovered from l10n/*.json) versus "what languages are active" (admin-controlled, persisted in oc_appconfig.intravox.enabled_languages).
  • PhotoStory lightbox: "Open in Files" button in the lightbox topbar, plus a clickable filename in the details panel. Both open the photo's parent folder in the Files app in a new tab. A new server-side endpoint /api/photo-story/open-in-files?file_id=N resolves the user-relative parent path (including federated/GroupFolder mountpoints) and 302-redirects to the Files view — the API's path field is storage-internal, so building the URL client-side would 404 on those mounts.
  • PhotoStory lightbox: swipe-down-to-close on mobile — vertical swipe over 100px closes the lightbox, alongside the existing horizontal swipe for prev/next.

Changed

  • All hardcoded SUPPORTED_LANGUAGES constants replaced — 12 services that each defined their own copy of ['nl','en','de','fr'] (PageService, DemoDataService, LicenseService, NavigationService, SetupService, FooterService, SystemFileService, FeedService, OrphanedDataService, ExportService, PagePathHelper, plus 2 OCC commands) now read from the central LanguageService. License page-counts only enumerate enabled languages; RSS feeds only include enabled languages; the orphaned-data scan recognises any language that's ever been shipped or enabled so it can never accidentally flag legitimate content as orphaned.
  • Navigation fallback unified on EnglishNavigationService::getCurrentLanguage() used to fall back to 'nl' for unknown user-locales. It now falls back to the universal English default, matching the rest of the codebase and the Transifex source-of-truth.
  • SetupService upgrade migrations now language-awaremigrateResourcesFolders(), migrateTemplatesFolders(), and migrateVersioningFolders() now iterate over admin-enabled languages and skip language folders that don't already exist on disk. The result: occ upgrade from 1.5.x → 1.6.0 touches exactly the four folders the install already had, never creates phantom folders for new Transifex-discovered languages.
  • Demo Data tab filters by enabled languages — only ticked languages appear in the install-status table. The "Full intranet" content option remains bundled for NL+EN only; other enabled languages show "Homepage only" and use the empty-homepage flow.
  • POT generation uses Nextcloud's official translationtool.pharscripts/generate-pot.js is now a thin Node wrapper around the same binary the sync-bot runs (create-pot-files task). Zero drift between local extraction and what Transifex sees. Replaces a custom en.json-based extractor that produced inflated POTs containing ~820 stale msgids the bot would have stripped anyway.
  • Plural-form overrides for JA/KO/ZH/TH/VI/ID (1 form), FR/PT (n > 1), PL/RU/UK/CS/SK (3 Slavic forms), SL (4 forms), AR (6 forms) — ported from IntroVox's regenerate_js_translations.py so non-Germanic languages render correctly when their pluralForm field is absent. Without these overrides Asian and Slavic translations rendered with the wrong plural rule.

Fixed

  • PhotoStory lightbox: Nextcloud header overlapped the topbar — the lightbox sat at z-index: 100000 but the NC header (z-index 2000) stayed visible because parent containers create stacking contexts (transforms/filters) that trap position: fixed children. Wrapping the template in <Teleport to="body"> escapes the trapped context; the lightbox now genuinely covers the full viewport.
  • PhotoStory lightbox: date/location pill unreadable against light photos — the translucent pill background disappeared against bright photos (white walls, snow, paper). Darker background, stronger backdrop-blur with saturation, subtle border, heavier drop-shadow, plus a text-shadow fallback for browsers without backdrop-filter.
  • PhotoStory lightbox: body scroll-lock on open — the page underneath could be scrolled with the trackpad while the lightbox was open. body.style.overflow = 'hidden' is now applied on open and restored on close.
  • PhotoStory lightbox: iOS notch / Android status bar in fullscreen — topbar now uses env(safe-area-inset-*) padding so the close button doesn't hide behind the notch.

Removed

  • Stray l10n/*.po files — replaced by the canonical Transifex output path translationfiles/<lang>/intravox.po. The PO files in l10n/ were never used by the Nextcloud runtime (which reads .js + .json) and only created dual-source confusion. Bundled translations remain in l10n/{nl,en,de,fr}.json until Transifex onboarding completes.
  • PageService::SUPPORTED_LANGUAGES constant — and 11 sibling constants across the service layer. All logic now routes through LanguageService.

Internal

  • New migration Version001600Date20260609000000 — pure config-init, seeds intravox.enabled_languages with the legacy default on first upgrade. Idempotent.
  • PagePathHelper stays a pure helper — its language-code set is static-class state synchronised once per request from Application::boot(). Avoids piping LanguageService through every caller of a previously side-effect-free helper.
  • AdminSettings initial state expanded — admin UI receives availableLanguages, enabledLanguageCodes, and defaultLanguage server-side, no separate fetch needed on tab open.
  • RELEASE_CHECKLIST.md rewritten with the full Transifex pipeline diagram and two adopted IntroVox v1.7.1 gotchas (GitHub-bot divergence, near-empty-language conflict resolution) so the next release doesn't repeat IntroVox's mistakes.
  • scripts/generate-pot.js rewritten as wrapper around translationtool.phar (downloaded + cached under scripts/.cache/ for 7 days).

Notes

  • The first Transifex sync PR will land only after a Nextcloud team member provisions o:nextcloud:p:nextcloud:r:intravox on the Transifex server. A GitHub issue on nextcloud/docker-ci requests this. Until then, translation files remain manually maintained for NL/EN/DE/FR.
  • Disabled-language pages don't count toward the free-tier 50-pages-per-language limit. This is the intended behaviour: organisations get back unused-language capacity once they curate the list. Re-enabling a language re-counts.
  • The bundled LANGUAGE_META map in DemoDataService still hardcodes display names and the "has full intranet demo" flag for NL/EN/DE/FR. New Transifex-shipped languages will appear in the admin UI with their base code as the name (e.g. "es") until they're added to the meta map. Cosmetic-only; activation and content management work either way.
  • Cosmetic legacy still in code: five OC.* JavaScript globals (deprecated since NC 26-30) — migration to @nextcloud/* equivalents is planned for 1.7. Works on NC32-34 today, may break on NC35 if Nextcloud removes them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTf7ZtlGWgI9TvkiQXT6xXf2fHFVS7KIq4LEB/evxDo4c/+mV4vL14flkwjF+dH6wtwnwbgjdFXGW3YPGcpWb5EU/ulDXwplwsPL3M+JxJGOgUtVR3DpMufuel27aggb9QKJeV1MGmlqyZivWUn9PgHtHciWghT1F2Xab3ui7YSFtC0UYlZm94f1J54payg2/5eQWZBr2odtZ0yIUc8IlIlYaYApDWcMr0NX52EX9DRFE33G0SqpB9L06WDu2BRxbesistv1KNp0IN6CDajkrs9dNPe0O6IIPW+9Ryo4oO2xjAzKKfwu+84egH611IkMhheumimFL7zeQZ3GE2VDQC26A/fE0S8Xo+uoHF63NliWIZvtvKPCDecHsVozYGoLm9Tdu3R+V1vNRgy8OeNg6VF1qNAup+YN6WFOxw+ftpKe526KCNHETQOdwp7JqEU4I0miYRJdo8GT6nEOC/MD4eBNsMLUxubt4iH1emd/PzvGPmUppF+iCudLzUCPYHG2xMyTDQprnW0hoBlb/9BCD3csE6lQwqwFsbzX+ITzd5PoMWbHX7Cy7AKQ6Izc3F2ZfAUrCVcoqFwAEiH3c/7RGRCXPxvQ2H50m9vKk8pn7gW8Lo5zu4E+66QaHUjUueLzeQd0AmHfCDdgbicqev0xrWwhk6wQsCLilRmLrpVdy7sw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0

Nextcloud 33

IntraVox 1.9.7
Release Details
UpdatedAug. 7, 2026, 8:25 p.m.
Changelog

Fixed

  • Uploading a photo failed with "Upload failed: page not found", on a page that was open in front of you. Adding a Photo widget and choosing an image appeared to work, and then saving the page reported that the page did not exist. Images placed in the resource folder through Files showed up in the Shared Library as a filename and a size with no preview, and stayed blank when selected. Saving the page first made no difference. (#92)

This is the same read/write split that #90 fixed for pages in 1.9.6, in the one place that fix did not reach: media. A page's images live next to the page, but IntraVox looked for them in a language folder chosen for you — your Nextcloud display language when uploading, the language you are shown when listing. Whenever those differed from the language the page itself is written in, every media operation searched the wrong folder: uploads reported the page missing, the Shared Library came back empty so previews had nothing to load, and thumbnails answered 404.

The permission check on the very same request had already found the page correctly, which is why the failure looked so contradictory — permission granted, then "page not found" for the upload that followed.

Media now resolves through the page it belongs to, so an upload lands beside its own page whichever language that page is in, and the Shared Library lists the library that page actually uses. Uploading to a page that genuinely does not exist answers a plain 404 and writes a log line, instead of the silent 500 that left this issue with no Nextcloud log entries to go on.

This affected every media widget — Photo, Photo Story, File Story and Gallery — not only the Photo widget.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQGR2+MVQYJYo1mg8qjMMBHAHr+V92aHAmEz08lqTMIYlzT05mbJqKeXtFan18+jUHp54/u5nyRHY0Hrc0AjJ2jfdq2oHyTvgKGtm6jHiswmM6dB/AkSglQ87ZRXmeeZzjfweWCmVayBnjqUCYRYuzvxXiu9qkmItu1I3vX2wvh2SyzC7YsWii3RvvHhuo00UAOEETwn3PrAD7vx/J4O4IiDMruq7fULsq2F+0Qb+XhlLVVTtvJPQHyYgStZGoP9hHYC+4fE1ugGgv1GQ4Rntae3MqKG+R3STVHDuXpNn9wMeIM3/24u8NyKPWosTSjgTnkoflb/Z73poiZaCfD3cApenQiEhjeM7rTjVARsOZtft6knovG1Wug4URzha1Onqvc2zqWkfDn5SCRQFJxpXjPojFiNETlEJXGoF5rG3s9Agn8/5l2lNDyhKqT7+8JCM8Da0P43fwDQn9rH1dVJH27P0D02HEvM4Ash/kV0SAdU6QBMUvEWtfcfTsVfJTonul71Z4NaA3v7LoK8nDAOVrUx8WYrssS7ZQrvV8HUxhsg4ymtMk/muUS4MJJAp3g2yALMvs49A+SI8fq44FL1opIKUjGlGvN2dJ0BHA0FUlxeX/aqb6/CmDTGhOQyFJ4UjZhxKuhLCTQk0RfG+6Fd1jBapWZehF2IsaJBNlmL/hEI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.6
Release Details
UpdatedAug. 7, 2026, 8:17 a.m.
Changelog

Added

  • Editors are told when a page is not in their own language. A badge next to the page title appears when the page you are on belongs to a different language than your own — in both view and edit mode. It names the language of the page, not of your interface: a German editor opening an English page sees "English", and knows that editing it saves back into English.

It shows up only when the two differ, so it never becomes a permanent label you stop reading; on a page in your own language, and on any single-language intranet, there is no badge at all. Like the Draft badge it is only shown to people who can edit the page.

It is an indicator, not a switcher: to work in another language, navigate to that language's pages.

Fixed

  • Editing a page failed with "Saving failed: Request failed with status code 400" and "Unable to save the page: Page not found". The page was on screen, it opened in the editor, and the save then insisted it did not exist. (#90)

Reading a page and saving one looked in different places. Opening a page searched the language you are shown — your own language, and failing that the recommended language or English — and then looked through every other language folder besides. Saving searched only the folder matching your own Nextcloud display language, and gave up there. Any page written in one language and opened by someone using another was therefore readable but impossible to save, along with its version history, its metadata and its delete action.

Nothing was wrong with the page or with the Team Folder holding it. Editing an existing page now writes back to wherever that page actually lives, so anything you can open, you can also save. Creating a new page is unchanged: it still lands in your own language folder. Permissions are unchanged too — a read-only member still gets a clear "not allowed" rather than a save that appears to work.

A page that genuinely does not exist now answers with a plain 404 instead of the contradictory "400 / not found" pair that made this so puzzling to report.

  • A sub-page created under a parent in another language ended up detached from it. Adding a sub-page to a German parent while your own Nextcloud language was English filed it under English instead — and built an empty de/departments/… mirror of the folder structure on the way, whose parent pages did not exist there. The new page disappeared from the very structure it was created in.

Page creation now follows the structure you are working in rather than your personal language setting. A sub-page joins its parent's language; a top-level page is created in the language you are currently viewing; and only when there is nothing to derive it from does IntraVox fall back to your own language, as before.

Together with the save fix above, the rule for editors is now a single sentence: you write where you are looking. Which language your Nextcloud interface is in no longer decides which content you can work on, and the admin panel's recommended language remains what it always was — a viewing fallback, never a write target.

  • Links to a page in another language resolved inconsistently. A link carrying a page's unique id found the page wherever it lived, but an older-style link built from the page name only searched your own language folder — so the same page could open, show a different language's page, or fail, depending on which kind of link you happened to follow. Both kinds now resolve the same way.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureMAygWy2LuZA4GrDZTIZjUtB0CSP60pbrfZdeVRb8Rg5ZOjGg9e4hrAMPbJ7GnT00NbDnP7GVkeaa0MdQT4n0pPtMrykmuJHY98uBTbNilcDUE80iYcKVnojntSffQtLClBXde5Sv4Gd2o9G5L5FWqlEI9nHfoz6C7qpiLgZGZlmQYzvNWBdCC49gYJUAxxGfxCtALhczS0Q+LjME1YnuPsSlxFCQW3Q7DhgpyAlbO+WS7VZ6FQhAZCKv3B0PVox1ouac3l2YZ1DuR0fZJuEnX5/3NQpIRqtSyZOfRYuNKA/dopXKs4T4SJzDUsdJtBH+aCHDdUEG+Jx3hQcb7XRe2C2SJnrsT7Azqm350pS9vDsz5Rspt26M9S95zHXJYQoL7EH/TnlIKZpJPF6qgB+zwen6rCz50FoJAPKdiWG0+0nBZT8ImwT2sAG3vCfJrs5pCbcueeFWUqGv2I0wdZNkE2pWDSPHAot9AGnu4DAUL8Qv1CFAG4QjIFbtQN/ayyt1Kf1tEGx23+kVNhDH8qSbwl1lQTTQVLzJsRh/XuL562O3Tdz63BUicjQTXiZsedFNqTpssz1vONJjlQN82a6jRT4zJyySBPelOd0k4uKtV+Em5FbarUvs2EuebW/zsR1+MdvFxTDNwHH9weTLd/4dqMWrkvl2enYKy35KpwBa/jw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.5
Release Details
UpdatedAug. 5, 2026, 9:02 p.m.
Changelog

Fixed

  • The filter panel lost all its options a few minutes after the page was loaded. The groups still appeared with their headings, but every one of them read No matching options — and then filled back in by itself some minutes later, without anyone changing a thing.

The widget's configuration was never the problem. The background job that refreshes People data every ten minutes runs without a logged-in session, and it rebuilt each widget's data as though an anonymous visitor had asked for it. That strips every field marked Local — including role and organisation — and skips IntraVox custom fields entirely, which is where fields like Werking, Thema and Gebouw live. The stripped result was then written over the copy meant for logged-in readers. With no values left to count, every group had nothing left to show.

This only affected instances that had switched on Visitor filters, and only from 1.9.4, where both the filter panel and that background job were introduced. The refresh now rebuilds each set of data for the audience it belongs to. Anonymous visitors are unaffected: they still see only what each field's visibility scope allows, so the fix does not widen what a public share can reach.

No action is needed on upgrade — the affected data is a cache and is rebuilt automatically.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJa1s+EtGix95c7jHfQz6ZUxx8YYfPLYzBPEsz9pc0A1GHIokKC3JSZbyGr8TD+1HNjO7WXoyXo7hSBV6wlIrqznQSj676/Cl+zp1GsYedg/EZnyG3lnGq3LRfMLMBnadAAZ+CB8yMxuo/09bQkrWo3pJ9mmq1ClIRjRl/0lNVBjOxTONaBEhJ8Bjt+nsVjLZb+bobmAvbR48peA2j1XOZtqQoCLU56V5WnZQNTWFHnLQ4K4pRcBb37n/OHPAaLIudWtoU8yiFAnNPjajq63e9TAeyxxIdJl+8MqOb6bKBrCKSk88LDDvBXeG8pfiqYYbfdfR1vT115+H8VMhDVUEa/D4D522aTTsEhrBkj4rpkC1/h04hjPTq+xyRCs/XiBAlWNLAs5Gy8KP8dtdXM8hOLKBgJrLk+lxb8HCE4Bu2oT3vq12exQ9DpZ88VJ4dUrPsbAkQ1E77Clka+imEZI946X7UuAqx0+Kq1UtfgmYgBm9gww/cFeCnSdd34FpQxG2saMkgsAe//+osGEX0H3nuI+eotxUdEjvKQTkpzz5nGUHTrmXQrAcwriI7dNufweaGbxVw3W33fgziJmzxeW6lxY1qjGDNmj4NiNsq+jRxO4VqbPhYkdPTDw6zn4w+eM0W3BzNaeGPO2JHrGsV+ezh0n/Cng5IdFn/z2ED3JuuUU=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.4
Release Details
UpdatedAug. 5, 2026, 6:04 p.m.
Changelog

Added

  • People widgets can now be filtered by the people reading them. Until now only the editor could decide who a widget showed; a reader got a fixed list. Switch on Visitor filters in the widget editor and the widget grows a filter panel: one group per field you choose, each value with a live count, plus an optional search box and removable chips for what is currently selected.

The counts are the point. They are calculated over the actual result set, and they narrow as you choose — pick a department and the building list immediately shows only buildings where that department sits, with real numbers. Picking a value never empties its own group, so "Noord or Zuid" is expressible; that is what makes it a filter panel rather than a series of dropdowns. Whatever a count promises, clicking it delivers exactly that many people.

A visitor can only ever narrow what the widget already shows. If you scoped a widget to one department, no filter combination reaches outside it — the restriction is built into how the results are assembled, not bolted on afterwards.

Selections live in the page URL, so a filtered view can be shared or bookmarked and opens filtered. On a phone the panel folds into a Filters (3) button. Filters do not appear on public share links: the values would amount to a browsable directory of your organisation for anyone holding the URL.

  • occ intravox:people:scope-report — prints which profile fields will become invisible under the visibility fix below, and for how many accounts. Run it before upgrading; --all scans every account instead of sampling.

Security

  • People widgets no longer appear on public share links. A public share is normally created to hand someone a set of documents. If the page also carried a People widget, the act of sharing those documents published a staff directory — names, photos and profile fields — to anyone holding the URL, without the people on that list having agreed to it or the person sharing necessarily realising the widget was there.

People widgets are now withheld from public share links by default. The rest of the page is shared exactly as before. Administrators who have a genuine reason — an external project page with a named contact, say — can allow it under Settings → Administration → IntraVox → Publication, but it is now a decision someone takes rather than a side effect of sharing a folder. The /api/share/{token}/people endpoint refuses as well, so the widget cannot be reached by calling the API directly.

  • People widgets now respect each field's visibility setting. IntraVox never consulted the visibility scope Nextcloud stores per account property, so every field the account manager returned was handed to whoever loaded a People widget — including the extra fields your directory syncs (LDAP/OIDC), and including anonymous visitors following a public share link. A phone number or birthdate a colleague deliberately marked Private was published anyway.

From this release the scope is honoured: Private fields reach nobody, Local fields reach logged-in users only, Federated and Published fields also reach public shares. The email address was a second route to the same leak — it was read straight from the user account rather than from the scoped property — and now follows the same rule. IntraVox custom fields (set through user preferences rather than Personal info) carry no scope of their own and are treated as Local: visible when logged in, never on a public share.

This is a visible change, not only a fix. Fields your users marked private will disappear from existing People widgets. Nothing needs to be run for the upgrade itself, but if you want to know in advance which fields are affected and for how many accounts, occ intravox:people:scope-report will tell you. The field most likely to surprise you is email: it defaults to Federated, but plenty of instances set it to Local, which removes it from public-share People widgets. Users change this themselves under Settings → Personal → Personal info, with the visibility picker beside each field.

The cached filter results were also shared between users regardless of what each was allowed to see. The cache key now includes both the audience and the viewer's group membership, and the old entries are abandoned rather than reused — otherwise the fix would not have taken effect until they expired.

Performance

  • People widgets read account data in one query instead of one per user. Profile data now comes from a single database read rather than a separate call for every account. Measured cold on a 106-account instance, the widget's scan drops from 35–45 ms to around 14 ms; the account read itself falls from 20.4 ms to 1.4 ms per hundred accounts. The remaining time is Nextcloud's own account enumeration, which an app cannot bypass. Instances with tens of thousands of users benefit proportionally.

  • Concurrent visitors no longer each trigger their own rebuild. When a widget's cached data expired, every visitor arriving at that moment started a full scan of their own. On an LDAP-backed instance, where reading a large group can take half a minute, fifty simultaneous readers meant fifty simultaneous scans. Now one request refreshes while the others are served the previous data, which is at most a few minutes old.

  • A background job refreshes recently-used People widgets every ten minutes, so in normal use no visitor waits for a rebuild at all. It only touches data that has actually expired, so an idle instance costs nothing.

Fixed

  • The People widget on a public share always failed. /api/share/{token}/people called a method that does not exist on the share service, so every request died and returned a server error. Anyone with a People widget on a shared page saw an empty widget. It now resolves the share token correctly.

  • The People widget's pagination setting was discarded on every save. The "show pagination" option was read when rendering but never stored, so it silently reverted each time the page was saved.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureI102notxijb2rG68TSr3XvT8Rh7/HOyPn1hIcu9DYcXWz0Fs3hSt0WBJzwj4rx3VOzL1kYcuganvYD9Sphfxe2qyIwlR/K9Oqd37KM9bg+v/IFqXvWCP6HMV97wazJdizbEaSEoohPran03F05inYQNrY+4SqpC2o7O1TJ3go4c3w5FwoL83uWxvF1MKto4eG6jozbM/oUkPEFQ1KUBa2ySbMIcZYrPO/Yh8eKPoD/YwMqDl1uqCejeRGKPMWh4XWkIjKlviKhVlfQ97QMsUh3rX/NppD0QKJMka08mOqDKpw+8xRU496qDZa0Z1LwKdapT1xa2A62oWR+e2dZr3mBCm/FzMI/cA55IeHw+SxXaRA+hyyuevtW+epvRl1FZecEeIII0CM66Kn/bBbWYfHTpsyBJba0Ev1bchFrqlba74TCniTu4FZvvm806ogf5yGHL5+2RQ9QwJrd2AHS1nF5XEr9FaPDI3gldzzGFGfWcNFStyz/jVEIHTbhG7OzQDZmDHdbh/lYHoa4Fs+KVtdr+qgsxfjxQ0DJD3W9ZpDgQwzpgVB/4NUG8iTCpDVsd7R8VL+EbXbCbOV+TOx0iiySuaOyCHDkhdkR0ilOOrUUfYkxUDuKo6vqutKOBa+qe8cW5c8seVVEB9HbVvJ/U7OPkmMFClHrmdFN4dLXJGPNM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.3
Release Details
UpdatedAug. 5, 2026, 11:35 a.m.
Changelog

Added

  • Search now finds pages by their MetaVox metadata. A page tagged City: Liège or Primary driver: HENK was invisible to IntraVox search unless the term also appeared in its title or content — the metadata lives beside the file, not inside the page. Those pages now show up under IntraVox pages, with a subline in MetaVox's own format (Label: value, joined with , matching field first, up to three fields) so the same document reads identically in both providers' results. Fields the user may not view are left out, so a restricted metadata field cannot surface here.

Changed

  • Search results no longer stop at the title index. The title index was consulted first and returned immediately on a hit, which silently suppressed pages that matched only on content or metadata whenever some other page happened to match on title. Index hits still render first (they are the fastest path); full-text and metadata matches are now appended after them, with duplicates removed.

  • The minimum search length follows the server setting instead of the app. IntraVox enforced its own two-character minimum, overriding the admin's unified-search.min-search-length (Nextcloud's default is 1). Nextcloud already rejects too-short terms centrally, before a provider is ever called, so the app-side check only served to make short but meaningful terms — HR, IT, CJK characters — unfindable regardless of how the instance was configured. No bundled Nextcloud app defines its own minimum.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDW78m+c4qRGRDYMcIhwYpytCtMO3guijSNnbzFEIXppXHYzSCHGAsrSllWOlPckQLasMUn+S1dpXLwk8uIKLXZYm+tfi+hfkmkrwN0SnCfTb+zGwiSOMdIvbMO/l0NnMEAglJf4/0fHsDxVX34/duPgvI+aOEk9yAr5qJeSu2J/T5DW4PvISOHKkY94p5z+QkOR2lOa6vO5iH3MtzaotNvgBRJd+VKy2riIO0O/Sfx5VSQL8CV0JY1mXBk1qbotIDNbYsfew7wr5iR2sEKNjUoocZAhxBAqzmSWYRvEy9tL5wx0miEeE4RIdeTNx7ItTSyzXocZm+JsVSG9iZKDiGg5dGd2VWtT+3Wg3ZAzHYGhHFMshlO9nEeWzR3e5Y87FIW1PasyRl2+8ZOS+hevaqR2s9aYc3mKSXZUqrmAC1TEn72V1kSgrUMrukBbqTjaBLNnhJZtnMqyLZ68yiPExcSCg0/DE8ul0ZPWLiTM+kznXuyTuKncDGXwqi0XFGiYKr0pHnJbR00C4KD3VLwIIIXbf+SReOSFMwaIE5xiBk2Fjc0vrmq1GZZZoLV46s3jTZdeB0JJzWjpNDczl4O2/jO8xEbAfY+Khhp4B/oMMA3nOl9WARJj1aezBHnNnxy+HEGJAxd72XuvuahjLXEa1OCec1vOPif1e1ac5zKXsRMc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.2
Release Details
UpdatedAug. 5, 2026, 7:49 a.m.
Changelog

Added

  • A page's "Publish on" / "Expire on" date now controls visibility everywhere. Previously the publication-date MetaVox fields only filtered the News widget's list; a page with a future publish date was still reachable directly, via the menu, the page tree and public shares. Now a page that is not yet published (future publish date) or has expired is hidden from readers and anonymous visitors — exactly like a draft — and automatically becomes visible the moment its publish time passes (evaluated live, no cron). Editors still see these pages, with a Scheduled / Expired badge next to the title.

  • Copy a link to any section of a page. Every heading — both stand-alone heading widgets and headings inside a text block — now gets a stable anchor. Hover a heading to reveal a small link icon; clicking it copies a deep link (e.g. …?page=…#h-creating-a-new-form) to the clipboard. Opening that link loads the page and scrolls straight to the section. Works in both the logged-in view and anonymous public shares. Page navigation (?page= / #page-…) is unaffected — section anchors use a distinct #h-… fragment so the two never collide.

Changed

  • A publish date takes precedence over the manual Draft flag. Following the WordPress/Drupal model, a page is in exactly one effective state: Draft (no date, held back manually), Scheduled (a future publish date) or Published (publish date has passed, or published with no date). This removes the confusing case where a page showed a Draft badge even though its publish date had already passed. In edit mode the manual toggle is then replaced by a read-only chip showing the effective state, with the explanation "Publication is controlled by the Publish on date. Clear the date to switch manually."

  • Draft no longer promises more than it delivers. The status keeps the name Draft (consistent with the rest of the industry and with how it is stored), but the wording now states plainly that it is a visibility filter, not a permission: the page is hidden from readers everywhere in IntraVox, while the page file itself keeps the folder's normal Nextcloud rights. Editing a draft page shows this as a standard Nextcloud info note card; the status badges carry a short, state-specific tooltip.

  • The editor documentation spells out where a draft page is still reachable. It previously claimed a draft was "completely invisible to readers", which was only true inside IntraVox. The guide (EN + NL) now lists the routes that bypass the filter — Files/WebDAV, Unified and full-text search, the activity stream and notifications, versions and trash, Collabora, sync clients and MetaVox metadata — and advises restricting the folder with Team folder permissions for genuinely confidential content.

  • The details sidebar (ⓘ) is now reachable while editing. It was hidden in edit mode, so setting a page's Publish on date — which lives in the sidebar's MetaVox tab — meant leaving the editor first.

  • The status updates immediately after saving a publish date. MetaVox stores those dates itself, outside IntraVox's own save flow, so a page you had just scheduled kept showing its old Draft badge until you reloaded. IntraVox now picks up the save and re-reads the page's publication state straight away. While editing, an info note explains the current state — including what Scheduled means and that the publish date overrides the Draft/Published button.

Fixed

  • Public link shares on a page folder now render for anonymous visitors. Opening the anonymous URL of a shared folder (e.g. a whole-language or sub-tree share) returned "This page is not available or the share link has expired" for every page under it — the share tree loaded, but each individual page 404'd. The page-scope check compared a per-user mount path (/Sam/files/IntraVox/en/docs/…) against the GroupFolder storage path (files/en/docs), so nothing ever matched. Pages are now resolved by their fileid in the GroupFolder storage — the same robust lookup already used for the share path — so folder-level public sharing works.

  • Internal links inside a shared page now navigate. In the public (anonymous) share view, clicking an internal page link in a Link or News widget did nothing — the shared view's navigation handler only understood the Navigation bar's object payload and silently ignored the bare page-id string that widgets emit. Both payload shapes are now handled, so sub-page tiles/links inside a folder share work.

  • The breadcrumb inside a public folder share shows the full path. On a nested page in a shared folder (e.g. Docs → FormVox → User → Creating Forms), the anonymous breadcrumb collapsed to just the share root, because the builder was fed a per-user mount path that could not be normalised against the share scope. It now uses the canonical GroupFolder-storage path, so all levels between the share root and the current page appear and are clickable.

  • Draft and scheduled pages no longer leak into a public share's menu or page tree. The share navigation and tree now apply the same visibility rules as the page content (which already returned "not available").

  • The News widget's "show only published pages" option now really hides drafts. News items were assembled without their publication status, so the filter saw every item as published and removed nothing. It also gave up when no publication date fields were configured or MetaVox was absent, and the caller only ran it when MetaVox was installed — in each of those cases drafts still showed. The status now travels with each item and is always honoured. A News widget inside a public share had no filter at all and could list drafts to anonymous visitors; it does now.

  • News cards meet WCAG 2.1 AA contrast, including on hover. On a coloured (dark) row, cards are drawn on a light tint but their text used the white "on primary" colour — measured 1.17:1 for titles and 1.12:1 for date and excerpt, where 4.5:1 is the minimum for body text. Titles now use Nextcloud's matching light-surface colour (12.96:1) and the date and excerpt use the full text colour instead of an opacity fade. Hovering previously flipped the card to a dark blue while the text stayed dark (1.75:1); the card now keeps its light tint (11.59:1). The carousel's secondary text (3.80:1) was corrected as well.

  • Publication dates are time-aware and use the instance timezone. The check compared dates only, so a page scheduled for later today counted as already published; and a time entered as local time (e.g. 15:57 in Amsterdam) was compared against a UTC clock, so a page could read "Scheduled" for hours after it was live. Dates now respect the time of day and are read in the instance timezone (the logtimezone system setting → the viewer's Nextcloud timezone → the server default); dates with an explicit offset keep their own zone. Administrators on a UTC server should set logtimezone, otherwise anonymous share visitors — who have no personal timezone — see scheduled pages appear at the wrong local time. See the editor guide for the command.

  • Blank items in the text widget's "Paragraph" dropdown. The heading options (H1–H4) below "Paragraph" rendered empty because their labels were passed to the translation function with the level as the app id. The markers now show correctly.

  • Several untranslated interface strings are now translatable. The page tree's "Show N more…" button and its expand/collapse labels, the navigation editor's focus-trap label, and the admin video-recommendation risk badges, category names and People-widget fallback field labels were hard-coded (or passed a variable the extractor never saw), so they stayed English in every language. They now go through the translation system.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureUBb4nMn8TJ3eLofW2Cb2kKLzsBx4OSswqMmfxydA3Uzv4+0qdn0F8h7zqPxwnbtQ6Zxo4oNtNkk7iqANQx7U34c85fWLpv7nrMYi7tJScTIcN2P47p44cyUmxgoj0IOAzWveB9d5OPd1zJUH48xf19Wfv46bVzmPdRKq6kpvnxlm4cofAc+eZLy1oMRrLQt1acRb1ZDMV5nefIp+i6z7NqUDVgxgdbCE0d/PpsjMU+dVzg33A+4RJMw7SJBMaNJyxBipn4mhNRzBw75Crs6UZeEVFbu+eP/CHhFRSdr8sR9uTHa8LrizFX1G+kvLUGO63izEZz61LsO56ntB7orQCSlwkpWfjWtu6v+IPTbF0DZhZn9JGCz40NQET5pg7UT9/ZUj29qyVuBn+HcQtFvxQ/cSYbNw9cMZ+cq+egWjqXBCz5SaXmP48GdPXQJVILhie61DL5hoSbFHGqwGfX458wBWZ860hxRywFF59+kDd0JhJ173qXDLAe0lbH2puSe0yvdRSQZXJhz8EHOrt4ix5Yh0t7xw8LUM73flZNeMqlqF9KMRr7RxPoSuPD7o4PAadC79TtHJS1WpnNYhvZpiKlxZcblk15skt3YH3b7++Xg2WVMBG+hVYa44ldeP/9Iegd/hpsS2vpXuxT3PiDBBSc8nzBntNvAAzOVG6aeGVdA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.1
Release Details
UpdatedAug. 3, 2026, 5:26 p.m.
Changelog

Changed

  • The page actions (⋯) menu is now grouped. As the menu grew it had become a flat, interleaved list. Its items are now organised into logical groups — page actions (Rename, Page settings, Copy, Save as template), site (New page, Edit navigation), utility (RSS feed) and the destructive Delete on its own — separated by thin dividers. The dividers adapt to your permissions, so you never see a stray or doubled line: a read-only visitor sees a clean short menu, the homepage hides Delete, and so on. No actions changed — only their order and grouping.

  • The help text in the Page structure and Edit navigation dialogs is collapsible. The multi-line explanation that filled the top of those dialogs every time is now a single collapsed line ("About the page structure" / "About editing navigation") that expands on click — the guidance is still there, but no longer in the way once you know it.

Fixed

  • Copy, and the navigation editor, now respect per-user permissions correctly in Team folders (#86 follow-up, thanks @kma-cloud). Three remaining gaps after 1.9.0: (1) the page tree's Copy button appeared where the user couldn't actually create, then failed — it now copies a page as a sibling into its own parent and is shown only where the backend will allow it (root-level items are gated on create-permission at the language root). (2) Trying to save the navigation without write permission returned a 500 error instead of a clean refusal — it now returns 403. (3) Edit navigation is gated strictly on write access to the root, so a read-only user no longer sees a button whose save would be refused.

Security

  • Dependency updates. Patched bundled front-end dependencies to clear all known npm advisories (axios, postcss, dompurify, fast-uri, linkify-it, brace-expansion) — non-breaking patch/minor bumps, no functional change.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureqGA3vDWGE6zTcCgb+VIfpjRMzk/kGoFf2p5HKz8bzQ8dq8ghNzvClqaWGiDuQjzld07fq3ETLpMzglrGjYcNI3tvg6WJr7Sv78OOI19Vdl3j6v1HTPBe4lqbq3DhLRHcNeNaPxMJ2QOeXfQqsm9Re8USkLCG99/IbsQpcd1KLWbhutLCFe4eu1In60nRxT6Ix7KUuKuLGFjBJ79Sk3SkRFgzc0NwUF4KVisPt01lVDt4QX6AeDOkrVD5tzgJqM1Bso82wDkqlMp5CmK6ANMD/7eZ26Df/D4HQjuT9AmcbwCIF4iRRdJwRZa98swOQw25KFGoeonB49ErxrT5ghQr9pTd/EsGy2s+sS15OS+ux8YKunPrRnhhdbe+g3i3+gRLWhGItisMBkEbGWNfYf4bW0RKgbaRuTokDuagszGTA9d52aCROwk3h/Kipqk3n0mLgwkxcdtA8G5/NclWRZ1XjR1kNPjEkeAdv4nWXc6Wo/wmompOlrSU7hxjEys5pnWWDBfT231b3+ymzLQwfGRoVWFsYY0LGiDRI8Q17+pWv1Wo5rLwx5+1acIJm/PrtU0Jl8456k9Ou13kQAFyy8u+khavNT1hprl9PcnxOnkDSzrOiNUWZrCJ0noRmJjTr6BqWqfUDAxrxygP/Hn8f/EopXQwArHc2xfh6RJ+UaaQvPk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.0
Release Details
UpdatedAug. 3, 2026, 6:07 a.m.
Changelog

Added

  • Rename a page directly from the UI (#84, thanks @kma-cloud). A page's title could only be changed from the Details sidebar, which nobody found — so it looked like pages couldn't be renamed at all. There is now a Rename page entry in the page actions menu (the ⋯ menu on the page you're viewing) and a rename button in the page tree's manage mode, both available to anyone with edit rights. Renaming only changes the page's title — the page's address (folder) and all links to it stay exactly the same, so nothing breaks. When the navigation menu label still matched the old title, it's updated to the new one automatically; a menu label you'd deliberately set to something different is left untouched.

  • Page buttons for the File Story and Photo Story widgets (#78, thanks @kma-cloud). Setting a maximum number of documents used to hide everything past that count, with no way to reach older files. Both widgets now have a Long lists choice: keep the existing Infinite scroll, or switch to Page buttons with a Documents/Photos per page size and Previous/Next buttons that page through the rest, so everything stays reachable and the widget keeps a predictable height. Maximum documents/photos stays a separate, optional total cap that applies in both modes. Page buttons apply where the widget already paginates — File Story's List and Tiles, Photo Story's single-folder Timeline and Grid; the other layouts always use infinite scroll. Existing widgets are unchanged (they default to infinite scroll).

Fixed

  • The filter operator dropdown in the People and News widgets was blank. When filtering people or news by attribute, the operator selector (equals / contains / is not empty / …) rendered empty options — only a checkmark, no text — so you could not tell which condition you were choosing. The template translated the labels with a single-argument t(op.label) call, which @nextcloud/l10n read as the app id and returned undefined (the same bug class as #79). The labels are now translated correctly and, as a bonus, are actual translatable strings (they were previously hardcoded English that no language could translate).

  • Special characters in page titles work correctly. A title like Collega's was stored HTML-encoded (Collega&apos;s) and shown with the literal entity in the title, breadcrumb and heading; A & B, quotes and <> were mangled the same way. Plain-text fields (page and widget titles, alt text, link labels) are no longer HTML-encoded at storage — the frontend and the RSS/export sinks already escape at output, so there is no security regression. An occ intravox:repair-entities command (with --dry-run and --user) decodes titles/text already corrupted by the old behaviour. Two related fixes: accented and non-Latin letters in a title are now transliterated into the folder name (Müllermuller, Cafécafe) instead of being dropped (mller, caf); and creating a page whose title collides with an existing one now opens the newly created page instead of failing to save with "Page not found" (the new page is selected by its stable id, not the derived slug).

  • Page-structure and per-page management now follow per-user permissions in Team folders (#86, thanks @kma-cloud). With GroupFolder Advanced Permissions (ACLs), a user who could write in only one section either saw structure/management controls that then failed with a 403, or did not see them at all. Two causes: (1) the page tree was cached per group, so a per-user ACL grant was not reflected in the tree's permissions — it is now recomputed live for each user (the same per-user approach already used when opening a page); and (2) the "Manage structure" toolbar and the per-page manage actions (reorder, move, rename, copy, set-as-homepage) were shown based on write access to the root, not to the actual page. The toolbar now appears whenever the user can manage any page, and each action is shown only where the backend will actually allow it, so the UI no longer offers actions that 403. Note: this addresses the UI/permission mismatch only — a per-folder "Read + Write" ACL still requires the user's group to have write at the base level (an ACL cannot grant above a read-only base; see the authorization docs).

  • The "From template" picker went blank as soon as one template existed (#79, thanks @quarterstaff-tech for the thorough diagnosis). With zero templates the picker correctly showed "No templates found", but any template at all made the panel render completely empty — no error, no list. The template preview card tried to look up a per-template translation via this.t('template_<id>_title'), calling the t(app, text) wrapper with a single argument: the key landed in the app slot and the text was undefined, so @nextcloud/l10n's translate() crashed on undefined.replace(…) (TypeError: can't access property "replace", f is undefined), taking the whole panel down during render. Those template_<id>_title / template_<id>_description keys never existed in the translation catalog, so the lookup was dead code that only ever crashed; the card now uses the template's own title/description directly.

  • Drag-and-drop upload did nothing but open the file in a new browser tab (#85, thanks @kma-cloud). The image/video widget's media picker invited you to "drag and drop", but the drop zone never handled the drag events, so the browser fell back to its default behaviour and navigated to the dropped file instead of uploading it. The drop zone now accepts dropped files into the same upload flow as the file browser, with a highlight while dragging and a type check (native drop ignores the accept filter, so an image widget rejects non-image drops, and video rejects non-video). The same missing-handler bug in the admin Confluence HTML import drop zone is fixed the same way (validated on the .zip extension).

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureqrQoDs284d1e7hHhvExpV85DY/hEp2pQ5lZn5WaBYxJfBxVpT1bdcatKbRjwdHGcnxbjzTh79qsEP8Zdm23RCEblKiyPbJMkSR3KwSka4ZsyrKjI3tYNm4sKalKfF32nyYt8lMlNpduALWkJCVb3CsydyuGeIsMXa0GL7Dg3JBsP1fPknHo3MkKRt/G3zr8LyrrKp6fYAy4r43MVSfYaLH1C7osKCG3zsrfO5VYb2CP0kSsIld77IV4FX23PRqawMJoAYNQ4ULqF7BlmllXOpUD1YsPoIJc8RODyLTBsY4jwXHGQJ5BBCrN71zDuPW1/Xdqpw0ey2XvJISuzKKvYOeZXMEpr0IzCwQ9grMFbZUfcz0sHr3oSG8WKxGRnmEKpP8yTHsnnadhESSX+Acli6S+gunpnmgHM9V9iJ7LtG5qBV95gBBY0mUJU1Ekdv6uIIvzSRB0H3f2lFc7x1jhxFREsSgws74O6DkIP0wF2iEO2Iq74Xark7/z+hjeBGE17aznK6Y/pdaWG+jXS+jazezBHeVjxHnsFvEJqgNsxzV4ZLMFFiMraJab9muUfeIuMxfmLrTJOTK2MuNU890a6B5YIuawDVF4uHtzwDbAMm5DP/gkNipxbXbPh2QK1uAl7grazK84X3vQ+QiQUgd3H+qFrTH6DrngYbEVEBI0TZWE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.4
Release Details
UpdatedJuly 10, 2026, 6:15 p.m.
Changelog

Fixed

  • Every button and label in several dialogs read "intravox" (#77). Four modals used a translation wrapper that put the app id in the wrong argument, so the "Create new page" and "Save as template" dialogs, the page-tree selector, and the "All pages" list rendered the literal string "intravox" for every tab, label, and button — making them unusable. The wrapper is now aligned with the rest of the app (t(app, text, vars)), so the real labels show again ("Blank page", "From template", "Page title", "Cancel", "Create", …). Pre-existing bug, unrelated to recent translation changes.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTe1odfxiiohPjc11AuhYvlSV+RfrbFqpMxueWeTS8IMhi4V9DQQeMegMU+opEACytWuY2smPcEmvApaOBFQHFBhcpE9EUIF0A/yoW1HK7IoZXwTWmaeTW01XqNBgm01NIEV/k677kzSCmCe03a53nEJpn517hScNan9nUZxr0d3VDfHxB/MuDBKq2gCBS1eEV4AsyLfrUo9x2AfYI/Lh4UZcnGFxN4Zd/9DD3slBOg3G8A5MUixjArUKLGAD33x+qrTXL96IX/TM1CQdwhycP+82OVTdEtQiFB2PCWq17Z2GVncv5xec+eRddw78gOFnyad2ykWshSfPSTAAuQlZ/+AM0pYMyTEcEHBQTMOxOMoZjQpMjEyB159TZzoxynlkDEuV5/RE3iP5i5lcrOXuARStcp2BZLyhBAkjAQ+/7diVM8urYIw4tqvA1b9T3WeLlQUC+kJtgg5WEb2F206yBN/Thd9aT/c4LlhMBtUW7KLfY3PnWvxNfMpDULuQvjnPsXJOuzFa871O/IuiYPyJeYtf4pdBCJ9ihc5Zxqu7ZL/mv6LmQMuNFdtSCYd443UAFrl3hpWUx6ox7fupKVq+D57VRMd2jmJeOHIZJ2Ii3qYH5jwq3qIw95OwDK9YTEYDN0IR8aDkMfhzasSEIH9mgr6Tn19OjxVHKI4+KD9aFq8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.3
Release Details
UpdatedJuly 10, 2026, 1:51 p.m.
Changelog

Added

  • mave.io as an allowed video service (EU-hosted, cookieless, GDPR-compliant). Because mave.io serves each space from its own subdomain (space-{hash}.video-dns.com), a fixed allowlist entry can't match every space, so this adds a wildcard-base-domain mechanism: a whitelisted base domain also matches its subdomains. Matching is boundary-safe (the host must equal the base or end with .+base, over HTTPS), so look-alike domains like evilvideo-dns.com are rejected. Enforced identically on the backend (PageService) and the frontend Save-gate (WidgetEditor).

Changed

  • Translation polish from reviewer feedback (thanks @rakekniven and the Nextcloud translators). Added TRANSLATORS: context hints for the Photo Story layout-style names (Magazine / Apple / Travelogue) so they're not translated literally; renamed the admin heading "Video embed domains" → "Domains for embedding videos"; fixed "Popup blocked. Please allow popups…" → "Pop-up blocked. Please allow pop-ups…"; and updated the app description to say "Team folders" (the current Nextcloud user-facing name) instead of "GroupFolders". The feed-URL example placeholder is no longer a translatable string. Ships with refreshed community translations (de, de_DE, et_EE, pt_BR, and others).
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureALXXa8zgPsReRyfFakJc3pmk5fyZ/f3XJhbWvdWmiSs/GGoh6k4bpHLg7eV5CC0A3Fpdkf2w1K9T0/84NaoI65mkuLQazVnI9OBRqdGfJdkJOcToh8FMGRr06oJH7KEYnZhphBbdjKvaq2/Jhe7gZkUdOpqoNYlWGWqmIAngpYpaWjdglJLHTSWK86nwckDAEB6mTnUlfEfyzAF6i5SbIcYWaIL0VFy7dYqtnSgkEyrRFc/bb+iwOvWp+TwqCLWy1RMT/mmK3VcTeIgwzPsW+X8gxgJHYWCmY0ZDTEpjoHR9xM5hA/jtW791bAIdBbwOnLxH2g8es83H8DRX4RFwFBaDQKNCCMQLVVVePaM9YaWuIVUImJ3wRcJqX51MYA9BH7LH/lp/muUaR94uzxIlOb/TnCPaeOL2x7haSD681R7/pELc8OUuxtpiFkb+wmenZryjE9MK9n2hGrCU+lwXD9hVeFs/8PD6Q6vNc4erEUegrxuvA2BjO8nF3jtHrFXSmdjuR5IKoXiiUa7oueJQjTLaS4OKf5R3sfZ/bIy3jE4VlQua+C1B267c7qswulmkHNyWEaL3mAPmY101OXS4yOeaKnIYLbtcuL+/BguNgD2N4Q4OZVpdnkw+qiVe0DjgT1KwkwoZSPsYcNp1SJZ2HYIhUV2SFsTjSoZuhyspdt8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.2
Release Details
UpdatedJuly 8, 2026, 11:01 a.m.
Changelog

Changed

  • Faster group lookups. Permission checks now use Nextcloud's getUserGroupIds() instead of loading full group objects, avoiding unnecessary object hydration on the hot permission path (#74, thanks @carlschwan).

Fixed

  • Users whose language has no content are shown the recommended language instead of a blocking notice (#75). The admin settings promise "if there is none, they are shown the recommended language below", but the landing page ignored the recommended (primary) language entirely and only ever fell back to English — and since 1.7.0 it showed a full-screen "No content in your language yet" notice even when English (or any recommended language) had content. The page now resolves the language to show as: the user's own language (if it has content) → the admin-configured recommended language (if it has content) → English → and only when nothing can be served does the notice appear. Authoring is unaffected: an editor still creates and saves pages in their own language, never the fallback. Also fixed the notice's "Manage intranet languages" button, which deep-linked to the old Demo data tab instead of the new Languages tab.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureL1CilQMaUR50sVUvKQgjThVmYhacoxZ/0IU6asyD7jwLv81NCDoeEqbIaYd92How8BoPGPg/OPQM6wTgn0lYvOb2/a3Yr+CrLF0Cf/2KNFZrRmXguv9qoLXIHDahbelQfSrl9GyuyDw0i1v1s7KvC3dYyTrAh5/VA8ZoXe3raKRAP3T6+II2UNN/NHOE3K6f+zPkKYDk5Ne+qHWIQqxmdm3k6nZaqZ7AZbNF9hNePrvBu7MF81Pshh2MCXsDD5+R9Wrq+W5zWijhLWvsUYlXYMLbL2pjF7xKl2U8TcnED3O7hLI1GI1DoZTqaRGlQs2cye/rw2zyds2UW2a99r+BUbVStKmJcoJfm2iQ+mFZMqRJNoC1pONvmImAm6iRFfDT5F6rTfUCXZnEsQKbyGfn+1pI+FGqMBcIE7HRvg7Zvo5VYC9VYBTtaUYPEXo/mv/+1gAPT6S9vohBOsK8yhDTxaBuTXUxXvHnEK9xkLK6YnOcAcGa4rRUQoDS3mUd7T2A0GLUSr6jqwkc0aGKFSozDJElR6iFZX5/y1BXzIQorkFWNTL7ZWrKXyHgsWL/WToiDe4StSKAk9u5gggebJ1O4O54yzgSHjSAwzijv8TN4gy76YO2d6GUNYr5caSCLBQwKpWvzchKlZt8VOA0XvbL/TV2RNiEsFOdlKbjAP2OqlQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.1
Release Details
UpdatedJuly 7, 2026, 4:03 p.m.
Changelog

Changed

  • Intranet languages now have their own admin settings tab. Choosing which languages the intranet holds content in — the "languages with content" list, the recommended (fallback) language, and add/remove language — was buried under the Demo data tab, where nobody looked for it. It is now a dedicated Languages tab, sitting alongside Video services / Engagement / Publication as a peer "how the intranet behaves" setting. The old tab is renamed Demo content and now holds only the demo-install table, so its name is honest. To avoid growing the tab bar, the rarely-visited Maintenance tab (orphaned Team folder data) becomes a sub-tab under Support — both are infrequent operator tasks. Old #maintenance deep-links and the orphaned-data banner still work: they now open Support → Maintenance.

Fixed

  • The recommended language can only be one that has content (#73). The recommended (fallback) language picker previously listed every language, so an admin could point the fallback at a language with no pages — leaving users whose own language has no content staring at an empty intranet. The picker now offers only languages that have content (plus English, the universal source/fallback), and the backend rejects setting the recommended language to one without content (POST /api/languages/primary returns 400).
  • The "Edit page" button now hides for read-only Team Folder members (#70). Even after the 1.8.0 permission hardening, a read-only member (e.g. an "IntraVox User" group with view-only access) still saw the Edit button and only hit a 403 on save. Two causes: (1) a page's canWrite was derived from the page folder, which a read-only Team Folder can report as writable, while the actual save preflights the page file — so the button and the save disagreed. canWrite/canEdit are now gated on the file the write path targets, matching reality. (2) A page's per-user permissions were baked into a distributed cache shared across users, so an editor's canWrite could be served to a read-only user (and vice-versa) for up to an hour; permissions are now recomputed per request and never cached, while the expensive page content stays cached. canCreate/canDelete remain folder-level as before.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBYA7jrD9xK8H4nt4f/dxUKG5VVqr8boApvEJgZiEfQYlmFRhA1ukRyzwClJ1ioAe3sHUKySuW+fOUgqD6ICcV/N7douwFXqb7UIHdsG3z3pAOsjifmfW2/6SLLCrWYnonC6W+eZdr9sQj2hjPBYRZuiK4MJCNSxrrnZE3eEt2kQFeFsK6GLOdhF+UkPVQNqtKdsZDKOCZsTAq2LyPBefse4R4pHk4/no/4sOisfEvxxln0cVIpESr5KfVPFASbvgzMLjktSAN0/A3Xx4l/q9RYe9ulaIJPZ5HfKOrB7cqUQ350n88LFk1SV9g3qXdo8o7kgnLA04vaSMXa2QngupJpYIFB8VsOZl9QDZSeGB8yU0PF1VZm9z8dCohCZ1/JWSY9bc6kYZ2nq2maC0AP0g3sAMGioJ6ta3ZYCBUHcGmWSpagAnvyAQC6gfIPsMI6zIbm6ALX88YKjiyF4hYCWIgN51xOUpgsTAIKelsEyqlKcvxfAJeuTbq9gxpeSajQw8d4o2IcMl2hx6g5w92KzsXDV+Rx7FrQStYZrC3nDdQr2aVWlmJTXYNYMMV6glVZsrO/UX2ENqGA+GdKA8duaRQMuQ6uB4tcfMxE88Ozx6nFH+mYrv7plcQrFppuHlKmmVWyF7TyHRSaRsYbC9LIbNQrkh/riql891SebcOIIjprs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.0
Release Details
UpdatedJuly 7, 2026, 7:07 a.m.
Changelog

Editors can now manage the page structure directly from the IntraVox UI, without touching the underlying folders. This release also hardens IntraVox on Team Folders: read-only members are handled correctly, and setup/demo-import now work on installations with primary object storage.

Added

  • Reorder and move pages from the structure view (#69). The page-structure modal gains a Manage structure mode with per-row controls: move up / move down to reorder a page among its siblings, move to another page to relocate a page (with its whole subtree) under a different parent, and delete (with the existing confirmation). The home page stays pinned — it cannot be moved, reordered or deleted. All controls respect Nextcloud permissions: you only see them where you have write access, and cross-department moves obey GroupFolder ACLs.
  • Sibling order is persisted in a new per-page order field. Installations that have never reordered keep their existing order untouched (a stable comparator leaves pages without an explicit order in filesystem sequence), so this is a no-op until an editor first reorders.
  • New endpoint POST /api/pages/reorder; cross-parent moves use the existing POST /api/bulk/move (admin-only for now). Moving keeps the page's uniqueId, so internal links and URLs by id stay valid; a folder-name collision at the destination gets a -2/-3 suffix.
  • Configurable homepage. Any root-level page can be made the homepage from the page-structure manage mode ("Set as homepage"), and the current homepage is marked with a Home badge. The homepage is now a per-language pointer (homepage.json) rather than a hardcoded home.json, so no page needs to be renamed. The homepage cannot be deleted or moved until another page is assigned (returns HOMEPAGE_PROTECTED, surfaced as a clear notice). Fully back-compatible: installs without a pointer keep using the legacy home.json; the old homepage is lazily normalized into a regular folder page (keeping its uniqueId, so links survive) the first time a different page is set as home. New endpoint POST /api/homepage.
  • Copy page. Duplicate a page as a new draft from the top-right "⋯" menu (copies the current page) or per-row in the page structure. The copy gets a fresh uniqueId, keeps the layout and media, is titled "… (copy)", and never inherits the homepage role. New endpoint POST /api/pages/copy.
  • Delete page in the "⋯" menu. The top-right page menu now has a "Delete page" action (with confirmation), hidden on the homepage and shown only where you have delete permission — matching SharePoint's page menu.

Changed

  • Clearer separation of "Edit navigation" vs "Page structure". The navigation editor now states up front that it only changes the links in the navigation bar and their order (not the actual pages), and the page-structure modal explains that its manage actions move the real pages and folders. Both modals lead with the same info banner and cross-reference each other, and the word "menu" (ambiguous) is gone in favour of "navigation bar". The "⋯" menu also closes when an item opens a modal. The page-structure modal also notes that only top-level pages can be set as the homepage (move a sub-page to the top level first).
  • Faster page-structure operations at scale. Reordering siblings is now O(N) instead of O(N²) (it reads a parent's direct children in a single cached pass rather than walking the whole subtree per child), and bulk delete/move/update clear the distributed cache once per batch instead of once per item — noticeably quicker on large, deeply nested intranets. No behaviour change.

Fixed

  • File Story widget now shows Whiteboard and FormVox files (#68). The widget filtered files through a hardcoded document-mimetype allowlist that omitted Nextcloud Whiteboard (application/vnd.excalidraw+json) and FormVox forms (application/x-fvform), so those files were silently dropped from a picked folder. Both are now included — FormVox forms render with their real preview, whiteboards fall back to the mime-icon placeholder — and each groups under its own "Whiteboards" / "Forms" category. Also added .odg drawings (application/vnd.oasis.opendocument.graphics, grouped as "Drawings") and the text/x-markdown alias so .md files aren't dropped on installs that register markdown that way.
  • Page-structure modal labels now translate. The tree modal and its rows used a wrapper that passed the app id as the translation key, so strings like "Collapse", "Expand" and "Current" rendered as literal "intravox". The wrapper now matches the rest of the app (translate(app, text, vars)), so those labels localize correctly.
  • Deleting a page by uniqueId now works. PageService::deletePage resolved only legacy folder-name ids, so a delete request keyed on a page-… uniqueId (how the UI deletes) failed with "Page not found". It now resolves uniqueId first, then falls back to the folder id.
  • Read-only Team Folder members are handled correctly (#70). On a Team Folder shared read-only to a group (no Advanced Permissions/ACLs), such users could open the editor and the Save then failed with a confusing HTTP 400. IntraVox now reports write/create/delete permission accurately (it combines Nextcloud's permission bits with the node's own isUpdateable()/isCreatable()/isDeletable(), which reflect the mount's writability), so the Edit button is hidden for read-only users and a write attempt returns a clean 403 instead of a 400. This also removes the follow-on Nextcloud core ShareHelper error. Reading navigation/homepage no longer tries to create the language folder for read-only users (which explained the intermittent "navigation not visible until permissions were adjusted").
  • Setup and demo-data import work with primary object storage (#71). intravox:setup and the demo import resolved the Team Folder via the internal /__groupfolders storage path, which does not exist as a node when object storage is the primary backend, so setup failed with "Failed to access groupfolder". IntraVox now resolves the folder through a member's mounted view — the same storage-agnostic mechanism the rest of the app uses — with the legacy path kept only as a fallback for local storage.
  • The "Add widget" picker opens again (#72). The widget picker crashed on open with TypeError: this.t is not a function because the component was missing the translation wrapper the rest of the app uses, so clicking "Add widget" appeared to do nothing. Adding the wrapper restores the picker.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturesf/demh4nISYFiTA4SLXu8F8cZOd40DZL/psxAoptr6CjZBliXnhmzsvL/x+LPUU+AwAROwBBi4XyXalNjWTiTUz06Y9XjmUwwTcRzOuniF+E9oddyOYbsCy6Ea/LgVIVDHymPQbaB/JSfjgm+5khswNyuuLyQumOSdK6RZQYRopMg0u0LfUJJmhAwl1LXZI/+YF8p/uIISKkgUf3JfeyY6JseZ/IIe/Z6EXjmt+nrOZY6ZCTRgYzjOS95uYsaky7+T0hKRdIVaBiOUn9HkEsHAnAfEajkZ6+lui2dyP7ztzjgYBUklWrnfV14PISVJF1V6MTJl5ZLg9IoC6KA4iIj0itvjzoVX1KgJhgN2JbQMw8fOEUmG/iY44mpDqL849rQp8qmw/t1EngVUQbXC3BYWgNip3b/FxDHO3wK61ysvCVjUaVblYHMcCq4O1Ei1aytM+akxbyAOAD5YTgRKEGKr9o2l4g2tHS2umG5vPT3kNQhXkgnIuFysaT16Z3P5V7+rpWiI387kfUR6Seb35qe+a+jdS0f4MWW+JU4g2psQ/2cKt9V1b/7paJbHC+meXl31GNMJaqAJBquUiPISCGaCSiszcQ76PIn5OUuU3PdHEbFGKTEt3RX4f4pC9pVJiiFu9bkDBAwwrPxoY5jjVeQCfo0txD6d7eeFjzfnf4Gk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.7.0
Release Details
UpdatedJuly 3, 2026, 12:48 p.m.
Changelog

When an editor maintained content only in one language (e.g. Dutch) and a user's Nextcloud language was set to another (e.g. English), the user silently saw a generic placeholder homepage — the editor's real work was invisible and there was no hint that this was a fallback. This release replaces that silent placeholder with a clear notice, gives admins full control over which languages the intranet holds content in, aligns the language handling with the wider VoxCloud model, and brings all source strings in line with the Nextcloud translation guidelines so the Transifex resource could be unlocked for translators.

Added

  • Language fallback notice on the landing page. If the user's own language has no real (editor-authored) homepage but another language does, IntraVox shows a clear LanguageFallbackNotice instead of the generic placeholder: it states the intranet has no pages in the user's language yet, lists the languages that do have content, and links to the user's Nextcloud personal settings so they can change their own language. New endpoint GET /api/languages/content-status.
  • Full content-language management in admin settings. Admins can pick from every Nextcloud-known language (not only the subset IntraVox ships a translation file for), choose a recommended (primary) language used as the fallback suggestion, add a language (creates an empty homepage so editors can fill it), and remove a language with a confirmation dialog that warns how many pages will be deleted (the folder goes to the trash, restorable from Files). The fallback language (English) and the current recommended language are protected from removal. New endpoints POST /api/languages/primary, POST /api/languages/{code}/add, DELETE /api/languages/{code}.
  • UI translation-coverage indicator next to each "Languages with content" chip, showing what share of the IntraVox interface is translated into that language (e.g. "UI 8%"), with a tooltip. LanguageService::getTranslationCoverage() computes it per base code (largest regional variant wins, e.g. dede_DE.json); scripts/extract-en-json.js writes a committed l10n/.source-count.json so the denominator is available at runtime.
  • Deep-linkable admin settings tabs. Each admin settings tab is addressable via the URL hash (e.g. …/settings/admin/intravox#demo), and the tab updates the hash as you navigate.
  • l10n/en.json extractor (scripts/extract-en-json.js, run via npm run l10n:extract / npm run pot). It scans src/ and lib/ for every t()/n()/$t()/$n() call and regenerates the English source for the POT, replacing the previous hand-maintained/restore-from-git workflow.

Changed

  • "Active" languages are now derived from content, not an opt-in list. A language is active once it has a homepage; the enabled_languages opt-in checkbox grid is replaced by a "languages with content" view plus add/remove controls. Real (editor-authored) content is told apart from auto-generated placeholders via a _generated marker, dropped automatically the first time an editor saves the page. The admin chip list shows active languages (any homepage, including a freshly added placeholder), while the fallback notice keeps the stricter "real content" rule so a placeholder never masks "no content in your language".
  • Demo content table now lists exactly the languages IntraVox ships bundled demo content for (Dutch, English, German, French), independent of the deprecated enabled-list (German was previously missing). Hint reworded accordingly.
  • Source strings aligned with the Nextcloud translation guidelines (#63): sentence-case for headings/labels/buttons (e.g. "Demo Data" → "Demo data", "API Token" → "API token"), a non-breaking space before every ellipsis, "GroupFolder"/"Team Folder" → "Team folder" wording, real gettext plurals for relative-time and file-count strings, URL/placeholder values removed from t(), and the redundant translated language-name helper dropped (the picker uses Nextcloud's own localized names).
  • Complete Dutch, German and French UI translations bundled (all ~1220 interface strings, including plurals). After the source-string cleanup the Transifex resource was re-provisioned without the earlier translation memory, so these are shipped in l10n/ and also serve as translation memory for the next Transifex sync — the community can refine them online from a fully-translated baseline instead of from scratch.

Fixed

  • "Add language" actually creates the content folder now. It silently failed before: LanguageHomepageService wrote to getUserFolder('intravox'), but there is no intravox system user ("Backends provided no user object"), so nothing was written — while the UI optimistically showed "Language added". It now writes via SetupService::getSharedFolder() (the same GroupFolder path demo-data uses), and the frontend reads the real server state instead of guessing, surfacing an error if the write fails. Adding and removing a language now triggers a synchronous groupfolders:scan so the change shows up immediately in every user's view and the Files app — without it, an added folder stayed invisible and a removed one lingered as a stale entry until the next background scan.
  • 3-letter language codes are no longer truncated. Language codes were clipped to two letters (substr($code, 0, 2) / [a-z]{2} matching), so Asturianu (ast) became an invalid as folder that didn't match its real code. Base codes are now treated as 2–3 letters throughout (ast, kab, …), so adding/removing such a language creates and deletes the correct ast/ folder.
  • Bumped vulnerable dependencies (dompurify, form-data, markdown-it, ws); npm audit reports no vulnerabilities.

Deprecated

  • enabled_languages app-config and the language#setEnabled / language#createEmptyHomepage endpoints are deprecated. The config key is no longer written by the admin UI but is kept in the database for downgrade safety (it is simply ignored by 1.7.0 code).
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLGu99gGuBgb/dL9oReX7t3liWl+nUdx6xXacAH71VZ567hyQ95XSVRziAGTirgeMXo5p/FRSvX7lXfIYdCO71UTDt5evJug1NuDcR77ARGdb59wstOQg5NceDiN+kvKB8ET08m/zqG5F6iDtyaIOFdZuIuKqwQR9QPdX4+UunJhReAQRk699Ssqb/PR1AWjv88MG8JBUSfpa0ZiV2iVsvIkLn6xuPFgzdqvedssa/fQFcGrg9yyHHmgnUe0QBk38D5hDan4SNNGNg003jcK/tUEOTINKUQQoWp3FYFDrb11X4PzwUewDOvBiA0uE/dtiE3NPsap8M9ClE+81wolGu5flksqjvRndHbc2qV4jdbmeevGA18mTRNqb5s1BT4e4q3rWEljFCO9epg5o+UzEV31OefkvCoIYnZIe1nU/d4yl6xGCi/YgtP1f0ayff421vqD0Kda7xu1g0L+OV0vxmvV1oU+3wgwdEfX7Z49k22mUwleeArCOjuluQIuPwC8vNxkyiv+uwhwXyju4f4MqJfNbMDAYjSHNCrYqO+rQBkKQFUZ8qMOtYY0LYQTEmltlLgZA210c+YuBqbeZknBxtJKWf5IeOkMwGttZVUkDhgu+4rufsxs+I8ZbAhxDfBWxyRUyIOYa4cgyZOmuaN71Y0KBP28VSYIxJfkaAXKB/E4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.6.1
Release Details
UpdatedJune 14, 2026, 3:36 p.m.
Changelog

Bugfix release. IntraVox 1.6.0 declared Nextcloud 34 support but crashed on occ app:enable intravox:

Error: Call to undefined method OC\Server::getAppManager()

Nextcloud 34 removed the legacy \OC::$server->getXxx() getter shortcuts on OC\Server. The 1.6.0 NC34 audit only checked the public OCP\* API surface and missed these internal OC\ getters, which were still called in lib/. During install the repair step (SetupDemoData) hits SetupService::isGroupFoldersAppEnabled(), so the crash aborted app:enable entirely.

Fixed

  • App can be enabled on Nextcloud 34 again (#58). Replaced every removed \OC::$server->getXxx() getter with dependency injection of the stable OCP\* interfaces across 11 files (SetupService, PermissionService, ApiController, PageService, PhotoStoryController, PreviewController, LicenseService, DemoDataService, OrphanedDataService, ImportDemoDataCommand, ImportPagesCommand). Getters migrated: getAppManagerOCP\App\IAppManager, getUserManagerOCP\IUserManager, getDatabaseConnectionOCP\IDBConnection, getURLGeneratorOCP\IURLGenerator, getMimeTypeDetectorOCP\Files\IMimeTypeDetector, getConfig → injected OCP\IConfig. These interfaces are unchanged across NC 32/33/34, so a single codebase keeps working on all three.

Removed

  • Dead $nextcloudPath = '/var/www/nextcloud' field in SetupService (unused, and wrong for non-default install layouts).
  • Redundant \OC::$SERVERROOT-based demo-data path fallback in DemoDataService::getBundledDemoDataPath(); IAppManager::getAppPath('intravox') already resolves both apps/ and custom_apps/ layouts.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWy0T0lmM8uWfR36zg8kC6FuQgij2PPpmHKD773BWRd8ARdh56W6m9tw6QQNBgUWIQ5cNahUZINEJPVCUmHVBbFA3e/DSndhZ2BBCXHSnAF5JyJu+LAzII3RYpPI8FQi8dW4YM0vqatnbYi+jeJwq9029rjJ7fq8Rgansx4vsi9sIxzszrDtBTzPSNeXEUxDzHMIhX8urvA71wdHUjhCKQDStFMgn4UR0ts+pr7vpl+GcbbEI5g4ySvBehKGYsSSWBea8oGQXR7EuIDmaAqk7PRp3PUdh91afXWQTNaDnx1e0yinXD5MURzxa91k8cfik+g9bsmSU2wbxcuKFOXKxujpPJTM4Qm0Rm48QLkDeoSHyZPzSDUtAcFvfP020hW64jfeXgMFEIF0OIm20z6WnxjimJa7Nbr3v+3RZMiCxJa7EzpK4chKlX2MHVGXm16/tUOwU1VUf2OEm+99AfGQqwImcKKbLS8Y9Ysk+pm9BmzF7y4nCpTbiBZmBF0K6Cuwk0QAj2ThQnjW3rDxOJ4oAkiuaIXC+4E3z67pWeSzkMiIC6B5zRpsSHu7jteX9PBxMQJOEG1prE13sLJaX48KzLA6iYcxx2gCwF29wgpwsAujHwNQu82JQWPSHjnvPmm+yfxHbDPDvuxG/2BaGgsQzHOorqdZbIcUPTuJyyOLeWww=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.6.0
Release Details
UpdatedJune 13, 2026, 11:59 a.m.
Changelog

Major release with three themes: Nextcloud 34 compatibility, community translations via Transifex, and admin-curated language activation. Plus PhotoStory lightbox fullscreen + "Open in Files" originally drafted for 1.5.6 are folded into this release. No data loss on upgrade — existing installs keep their four configured languages enabled by default.

Upgrade safety contract

This release respects seven rules so existing installs cannot break:

  1. No language folder is ever deleted automatically — not on toggle-off, not on upgrade, not by cleanup.
  2. Default for installs upgrading from 1.5.x is ["nl","en","de","fr"] — exactly the previous hardcoded set.
  3. The Version10600 migration only seeds the config key; it never creates or removes content folders.
  4. English cannot be disabled — it is the guaranteed fallback for every code path.
  5. License page-counts stay per-language and are not reset when a language is toggled.
  6. Cache invalidation runs automatically when the admin changes the enabled set.
  7. occ upgrade from 1.5.x → 1.6.0 produces zero user-visible changes (until the admin acts).

Added

  • Nextcloud 34 compatibility declaredinfo.xml now ships <nextcloud min-version="32" max-version="34"/>. Audit results: zero removed-in-NC34 OCP PHP APIs referenced in lib/; all five OC.* JS globals IntraVox uses (OC.dialogs.filepicker, OC.MimeType.getIconUrl, OC.L10N.translate, OC.requestToken, OC.webroot) remain functional in NC34 stable (deprecated, scheduled for migration in 1.7); bundled @nextcloud/vue (9.8.1) and Vue (3.5.22) match NC34's ship versions; PHP >=8.2 matches NC34's >=8.2 <8.6 requirement.
  • Transifex-ready translation pipeline — IntraVox is now packaged for community translations via Nextcloud's Transifex pool (o:nextcloud:p:nextcloud:r:intravox). New .tx/config + .l10nignore + l10n/.gitkeep + committed POT template enable the Nextcloud l10n sync-bot to open pull requests with new translations as they land. Resource provisioning requested via docker-ci#951. The four existing languages (NL/EN/DE/FR) continue to ship in l10n/*.json until the resource is online.
  • Admin-curated language list — new "Available languages" section at the top of the Demo Data tab in admin settings. Each language IntraVox ships a translation for appears as a checkbox; the admin ticks which ones should be active in the intranet. Disabled languages disappear from IntraVox menus, navigation, and the demo-data table, but all their content stays on disk and reappears the moment the language is re-enabled. English is always enabled and cannot be unticked.
  • Empty homepage on language activation — when an admin enables a new language (one without bundled full-intranet demo data), IntraVox creates an empty homepage in the content folder so the language is immediately usable. Idempotent: never overwrites existing content.
  • New LanguageService, LanguageController, LanguageHomepageService under OCA\IntraVox\Service\* and OCA\IntraVox\Controller\* — the single source of truth for "what languages are shipped" (auto-discovered from l10n/*.json) versus "what languages are active" (admin-controlled, persisted in oc_appconfig.intravox.enabled_languages).
  • PhotoStory lightbox: "Open in Files" button in the lightbox topbar, plus a clickable filename in the details panel. Both open the photo's parent folder in the Files app in a new tab. A new server-side endpoint /api/photo-story/open-in-files?file_id=N resolves the user-relative parent path (including federated/GroupFolder mountpoints) and 302-redirects to the Files view — the API's path field is storage-internal, so building the URL client-side would 404 on those mounts.
  • PhotoStory lightbox: swipe-down-to-close on mobile — vertical swipe over 100px closes the lightbox, alongside the existing horizontal swipe for prev/next.

Changed

  • All hardcoded SUPPORTED_LANGUAGES constants replaced — 12 services that each defined their own copy of ['nl','en','de','fr'] (PageService, DemoDataService, LicenseService, NavigationService, SetupService, FooterService, SystemFileService, FeedService, OrphanedDataService, ExportService, PagePathHelper, plus 2 OCC commands) now read from the central LanguageService. License page-counts only enumerate enabled languages; RSS feeds only include enabled languages; the orphaned-data scan recognises any language that's ever been shipped or enabled so it can never accidentally flag legitimate content as orphaned.
  • Navigation fallback unified on EnglishNavigationService::getCurrentLanguage() used to fall back to 'nl' for unknown user-locales. It now falls back to the universal English default, matching the rest of the codebase and the Transifex source-of-truth.
  • SetupService upgrade migrations now language-awaremigrateResourcesFolders(), migrateTemplatesFolders(), and migrateVersioningFolders() now iterate over admin-enabled languages and skip language folders that don't already exist on disk. The result: occ upgrade from 1.5.x → 1.6.0 touches exactly the four folders the install already had, never creates phantom folders for new Transifex-discovered languages.
  • Demo Data tab filters by enabled languages — only ticked languages appear in the install-status table. The "Full intranet" content option remains bundled for NL+EN only; other enabled languages show "Homepage only" and use the empty-homepage flow.
  • POT generation uses Nextcloud's official translationtool.pharscripts/generate-pot.js is now a thin Node wrapper around the same binary the sync-bot runs (create-pot-files task). Zero drift between local extraction and what Transifex sees. Replaces a custom en.json-based extractor that produced inflated POTs containing ~820 stale msgids the bot would have stripped anyway.
  • Plural-form overrides for JA/KO/ZH/TH/VI/ID (1 form), FR/PT (n > 1), PL/RU/UK/CS/SK (3 Slavic forms), SL (4 forms), AR (6 forms) — ported from IntroVox's regenerate_js_translations.py so non-Germanic languages render correctly when their pluralForm field is absent. Without these overrides Asian and Slavic translations rendered with the wrong plural rule.

Fixed

  • PhotoStory lightbox: Nextcloud header overlapped the topbar — the lightbox sat at z-index: 100000 but the NC header (z-index 2000) stayed visible because parent containers create stacking contexts (transforms/filters) that trap position: fixed children. Wrapping the template in <Teleport to="body"> escapes the trapped context; the lightbox now genuinely covers the full viewport.
  • PhotoStory lightbox: date/location pill unreadable against light photos — the translucent pill background disappeared against bright photos (white walls, snow, paper). Darker background, stronger backdrop-blur with saturation, subtle border, heavier drop-shadow, plus a text-shadow fallback for browsers without backdrop-filter.
  • PhotoStory lightbox: body scroll-lock on open — the page underneath could be scrolled with the trackpad while the lightbox was open. body.style.overflow = 'hidden' is now applied on open and restored on close.
  • PhotoStory lightbox: iOS notch / Android status bar in fullscreen — topbar now uses env(safe-area-inset-*) padding so the close button doesn't hide behind the notch.

Removed

  • Stray l10n/*.po files — replaced by the canonical Transifex output path translationfiles/<lang>/intravox.po. The PO files in l10n/ were never used by the Nextcloud runtime (which reads .js + .json) and only created dual-source confusion. Bundled translations remain in l10n/{nl,en,de,fr}.json until Transifex onboarding completes.
  • PageService::SUPPORTED_LANGUAGES constant — and 11 sibling constants across the service layer. All logic now routes through LanguageService.

Internal

  • New migration Version001600Date20260609000000 — pure config-init, seeds intravox.enabled_languages with the legacy default on first upgrade. Idempotent.
  • PagePathHelper stays a pure helper — its language-code set is static-class state synchronised once per request from Application::boot(). Avoids piping LanguageService through every caller of a previously side-effect-free helper.
  • AdminSettings initial state expanded — admin UI receives availableLanguages, enabledLanguageCodes, and defaultLanguage server-side, no separate fetch needed on tab open.
  • RELEASE_CHECKLIST.md rewritten with the full Transifex pipeline diagram and two adopted IntroVox v1.7.1 gotchas (GitHub-bot divergence, near-empty-language conflict resolution) so the next release doesn't repeat IntroVox's mistakes.
  • scripts/generate-pot.js rewritten as wrapper around translationtool.phar (downloaded + cached under scripts/.cache/ for 7 days).

Notes

  • The first Transifex sync PR will land only after a Nextcloud team member provisions o:nextcloud:p:nextcloud:r:intravox on the Transifex server. A GitHub issue on nextcloud/docker-ci requests this. Until then, translation files remain manually maintained for NL/EN/DE/FR.
  • Disabled-language pages don't count toward the free-tier 50-pages-per-language limit. This is the intended behaviour: organisations get back unused-language capacity once they curate the list. Re-enabling a language re-counts.
  • The bundled LANGUAGE_META map in DemoDataService still hardcodes display names and the "has full intranet demo" flag for NL/EN/DE/FR. New Transifex-shipped languages will appear in the admin UI with their base code as the name (e.g. "es") until they're added to the meta map. Cosmetic-only; activation and content management work either way.
  • Cosmetic legacy still in code: five OC.* JavaScript globals (deprecated since NC 26-30) — migration to @nextcloud/* equivalents is planned for 1.7. Works on NC32-34 today, may break on NC35 if Nextcloud removes them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTf7ZtlGWgI9TvkiQXT6xXf2fHFVS7KIq4LEB/evxDo4c/+mV4vL14flkwjF+dH6wtwnwbgjdFXGW3YPGcpWb5EU/ulDXwplwsPL3M+JxJGOgUtVR3DpMufuel27aggb9QKJeV1MGmlqyZivWUn9PgHtHciWghT1F2Xab3ui7YSFtC0UYlZm94f1J54payg2/5eQWZBr2odtZ0yIUc8IlIlYaYApDWcMr0NX52EX9DRFE33G0SqpB9L06WDu2BRxbesistv1KNp0IN6CDajkrs9dNPe0O6IIPW+9Ryo4oO2xjAzKKfwu+84egH611IkMhheumimFL7zeQZ3GE2VDQC26A/fE0S8Xo+uoHF63NliWIZvtvKPCDecHsVozYGoLm9Tdu3R+V1vNRgy8OeNg6VF1qNAup+YN6WFOxw+ftpKe526KCNHETQOdwp7JqEU4I0miYRJdo8GT6nEOC/MD4eBNsMLUxubt4iH1emd/PzvGPmUppF+iCudLzUCPYHG2xMyTDQprnW0hoBlb/9BCD3csE6lQwqwFsbzX+ITzd5PoMWbHX7Cy7AKQ6Izc3F2ZfAUrCVcoqFwAEiH3c/7RGRCXPxvQ2H50m9vKk8pn7gW8Lo5zu4E+66QaHUjUueLzeQd0AmHfCDdgbicqev0xrWwhk6wQsCLilRmLrpVdy7sw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.5
Release Details
UpdatedMay 30, 2026, 8:59 p.m.
Changelog

Patch release that fixes #57: clicking-save on a Link widget item whose URL is mailto:, tel:, or sms: would silently empty the URL on save. After page refresh the link rendered as #. No DB migration, no API breaking changes.

Fixed

  • Link widget: mailto:, tel:, and sms: URLs were stripped on save (#57) — Service\Sanitize\UrlSanitizer::sanitize() only allowed http(s)://, root-relative paths, and # anchors. Any other scheme — including the universally-accepted communication shortcuts mailto/tel/sms — was rewritten to an empty string at save time. The widget then rendered href="#" after a page refresh, even though the in-memory edit showed the correct URL until then. The Navigation editor used a different sanitization path (FILTER_SANITIZE_URL without the scheme allowlist) which is why mailto links worked there but not in Link widgets. Allowlist extended to include mailto:, tel:, sms: — three schemes with no JavaScript execution path, part of the default allowlist of DOMPurify and HTMLPurifier. javascript:, data:, file:, xmpp:, matrix:, and bare domains remain blocked. New unit tests cover both the accept and the continued-reject cases.

Notes

  • Existing Link widgets that lost their mailto/tel/sms URL still need to be re-edited and saved once — the empty value is persisted on disk. There is no automatic migration; once saved with 1.5.5 the URLs stick.
  • xmpp: and matrix: remain blocked. They are safe in principle (no JS execution) but unlikely to be intentional in most intranets; add per-need with an explicit code review if you want them. Open an issue if your installation needs them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCh/CmZ8aQnDr2XuBCui2CiOFzzX9RnHEHBISRDwUZISNfh8j+W8l9zbtlV5dsZ2tjgpT9EfMQCcK0O7Rms0xrEl7tGFWeGB4+3Nr6RlfhR59CFDtiXB1eg/mHhFR5uJBOB8CMhhhCTnN/dkD1np0PCRFJjDbn3lmij92xMOLMwFsaPAvhvRFA1wHn0cy+hUl5ZQyFDHivA7OLdadsh+eMth/Z0WaZJXvHuoWqbUFpGOMGzRmeeIYubZj5NsVslZg6gL93XSul9y5Jllh6IsMCcEwMLdhA3N+G9rLF9QzKUjev3aV1OzH+vVyY6LAhRYTN7k3bAZLOEt7HhuwA5f2bgEPbbjzNgW867foQA8HpAHeczfKSjbWiCOPCFhJ7q0OCIsAf9RJzCXHLUsBbSIDuxQyH35rd0sRL1qmg7hSikMBCs4G2d4/ajzZo34WA5k+R4WFmqhsJiMAm0By5ENBs9dVkAS+E6hxJruM9W/BevyftUjV/guD8YfLy1yByTuUICpA13pnJjo0rxFZmv6Iyo2uwDFZUVzag4RfLok80mXSY6icuKLWsH6mdX+7WaoT1n0v5NqFT38v7dVGG/DWZpF/edJSW5koAJMcr0gHTJ6h0wJzXFf+vx+1XOkJ/1184HStnxv9W9CabTkxRybcwHPwH7AtdH/GytDDG4qVi0k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.4
Release Details
UpdatedMay 30, 2026, 1:53 p.m.
Changelog

Patch release that closes an information disclosure issue introduced by 1.5.3.1, fixes a Leaflet/sticky-topbar layering bug, and brings the bundled @nextcloud/vue in line with what Nextcloud 33 itself ships so IntraVox widgets visually match NC's own apps again. No DB migration, no API breaking changes.

Security

  • FileStory / PhotoStory: source folder path leaked to users without access — 1.5.3.1 added a "You do not have access to this folder" empty-state that showed the configured folder path (e.g. Shalution/Administratie/2026) as context. For a user who is deliberately excluded from that folder, this disclosed the existence and naming of paths they shouldn't be aware of — path names can carry sensitive context (client names, project codes, person names, dated boundaries). The empty-state now renders a minimal lock icon + "You do not have access to this widget" with no folder name and no scan hint. The folder path remains visible only for users who do have access but happen to see an empty result (legitimate context).

Fixed

  • PhotoStory: Leaflet map overlapped the sticky IntraVox topbar on scrollPhotoStoryMap.vue and PhotoStoryDayMap.vue had position: relative with no z-index, so Leaflet's internal panes (default z-index 200–700) rendered over .intravox-topbar (z-index 100) when the page scrolled past the map. Both map containers now establish their own stacking context with position: relative; z-index: 0; isolation: isolate;, capping the Leaflet panes below the topbar without touching Leaflet's own z-index conventions.
  • PageDetailsSidebar tabs visually diverged from NC Files — IntraVox bundled @nextcloud/vue 9.5, while NC 33 ships 9.6+ with a refreshed sidebar-tab look. The result was a different (often "double-underline" feeling) active-tab rendering versus what users see in NC's own Files sidebar. Bumped the bundled @nextcloud/vue to ^9.6.0 (resolved to 9.8.1) so PageDetailsSidebar now renders identically to NC's own sidebar tabs.

Changed

  • Bundled @nextcloud/vue upgraded from 9.5.0 → 9.8.1 (within ^9.6.0 range, matching the version NC 33 itself bundles). No public IntraVox API changes; some Nc* components may have minor visual refinements that come along with the upgrade.

Removed

  • Obsolete .app-sidebar-tabs__nav border-bottom override — the 1.5.1-era CSS workaround in css/main.css was meant to fix a double-underline on NcAppSidebarTabs in NC 32+. With the @nextcloud/vue 9.6+ refresh that override became counter-productive (it removed the hairline that NC's new active-tab rendering visually anchors against, producing the misaligned look reported on 1.5.4-rc). The override has been removed; the look is now exactly what NC Files renders.

Internal

  • RELEASE_CHECKLIST: new section 1b "Dependency parity with Nextcloud core" — codifies the lesson from this release. Before tagging, check node_modules/@nextcloud/vue/package.json against the version NC ships for the target NC min-version (table maintained in the checklist). Visual canary: PageDetailsSidebar tabs vs. NC Files sidebar.

Notes

  • The defensive backend guard PhotoStoryService::assertNotResolvedToUserRoot() added in 1.5.3.1 stays in place. It already returns reason: 'folder_not_accessible' on the 404 response which the new empty-state branches on.
  • Known follow-up: News widget's empty-state still shows Source: {path} for unauthorised users. Same pattern, lower severity (source is usually a page-id, not a filesystem path); tracked separately.
  • Future direction: SharePoint-style audience targeting per widget will eventually let admins hide widgets entirely from users who shouldn't see them. The lock-state introduced here is the fallback for the edge-case where audience-target users lose folder permissions after configuration.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturebdeRHVR20/nH1R+zH2h19G2oU3imUS1G7ErSfoE76L06c1ZdJWAxX3IRoU0uXXw6g1riRPttaiwpkXuype8kPK/9mDqdXZT0WKUtYqSV+dkBjdpe1ODKCrXZhR4WZsDfGpuvzA68HeCYLTk5Zb9LgSwZIcwBfLDaAKK+DzgBuosLV/WepscTkKBAtjb0jOGyfYRQQRXScO4ywNS4Ke9kzTkvqpqlSgStQ8yMVer6cwb7/ToxjGhMSeUy7w0IKS69K2usogY79m28XVmLpaUp/5ky0BxA1+ggtv8Z9tdLCxy+G3S59ndDIXqgCXT6G1eShRFP7PuoQg3rJZK2rhM6hn2oOFX3ZUHDVE9hxpA2Iv67B3u1alq5ZYdmbtppwCFyFmUuOl5juZLHAZc5MG4T0USxIdgorxh2A2rBmuGAdrQk3vJlby8G+apL/hhFaZoUeBi1i7wFS1f62ucSJUKO6IAfAYJUxBDkIVFNboaZeRI30hPAa2yJGbYgAq2vuDuj1eGpewDQ65SNvaitI0LBjj0IQiPYs3DdnLVXDOqpva+VhaiQnA8Iq8TFK55tMyQiCn6QFNWCfTApT6L3W7X1j1GsiMutzjSS3GLLt27SeB/8948hXeR1JqcCLmiqaYt9C5KsbFH/UiMq6AGTungHCm4mxz1jSaGEAXBpsPlAqb4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.3
Release Details
UpdatedMay 30, 2026, 11:35 a.m.
Changelog

Patch release that fixes a "file no longer exists" toast when clicking documents in FileStory, and makes click-to-open behaviour consistent across all mount types. No DB migration, no API breaking changes.

Fixed

  • FileStory: "file no longer exists" toast on click for legacy shared-storage GroupFoldersFileStoryWidget.openFile() preferred OCA.Viewer.open({path}) for inline preview, deriving the path from file.path by stripping a leading files/. That works for personal storage and per-folder jail GroupFolders, but in legacy shared-storage GroupFolders the cache row stores __groupfolders/<id>/... and the user-visible mount-point name (e.g. Shalution) isn't carried on the row. The Viewer received /__groupfolders/4/Administratie/2026/Boekhouding.xlsx, couldn't resolve it against the user's tree, and NC raised the "file no longer exists" toast. Federated shares hit a similar dead-end via a different code path.
  • FileStory click behaviour now consistent across mount types — documents always open in a new tab via NC's /f/<id> handler, which resolves the right mount server-side for personal storage, both GroupFolders mount strategies, internal shares and federated shares. Removed the path-derivation entirely (resolveDisplayPath() deleted).

Notes

  • Behaviour change: clicking a document in FileStory no longer opens the inline NC Viewer overlay — every click now opens a new tab at the file's NC Files location. This trades inline-preview ergonomics for "actually works on every mount type" reliability.
  • PhotoStory is unaffected; its widget uses an internal Lightbox component and never touched OCA.Viewer.open().
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureAJvUlLcI5LNjLuz5DDx6QDyCAMh6j7PTBvzanLh5i26TsW2mHudGF/mCkxku08w9eJvE8ZY0VKFEzkLbbBc0v16RHQ1YO0slEGvbTv6QdrECl8JdmGwU0oDHpWAKlrGOeKRO0b9oDSu7D+Z1mVGlhxxMexJAnpugWDkevjeI1aznx0Di8FNa5KMxT9apIvceQfuHPbBOBPnE2BgjJMQTBWwR0sel8DYmdcd4y5FVKwY/3TlcTqzNLKwujDpqPt4Ihu4GVjS/dltaJqhSVlKJCiyh/w+kmB/RujnoEwLVru+GNhfgggvtr+YbQrwxoCqsoP1xiHeNoIA60/VCINwB0NkZHxXkrjGuTG7lInhzhEgwbl5sDg1JpG3BfQv1Z4R9VIHDXhCxyJT6oH7WbrssaUI0RlZQ2amYMu7a+FBe4+wHau4vD/KkvfOj62YZ6jPksvS140seB7IMYw9gxsw45bjjFS0COXGeIado8437PU17MBvwVGshcQHwdkwSyGTl3HWvXeQ5i4Gt9TiYTjjfmU4KFk83X8PcwB4qYho0yHLsMTZpdEApYTmLMkCrIKkJSk/mKnUQdiLkNnCjCTvZI1YvajTqzZxlNFy7IudFrvP6lyGosRum7OSdCACTQGSauuRMw7bB+J5x6aME6islckUuqmc9vxce92r6/brSurs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.2
Release Details
UpdatedMay 28, 2026, 5:52 p.m.
Changelog

Patch release with two production-blocking PhotoStory fixes (groupfolder albums and federated-file thumbnails), three UX improvements requested from real use, and one admin-tool clarification. No DB migration, no API breaking changes.

Fixed

  • PhotoStory shows "No photos found" for every groupfolder albumPhotoStoryService::extractStorageAndPath() returned the jailed Node path (e.g. Albums/Doris Synchroonzwemmen) while oc_filecache.path stores the unjailed form (__groupfolders/7/Albums/Doris Synchroonzwemmen or files/Albums/Doris Synchroonzwemmen, depending on which mount strategy the groupfolder uses). The SQL path LIKE predicate matched zero rows, the widget rendered its empty state, and the hint text misleadingly pointed admins at occ files:scan — even though the files were already indexed. The path is now reconstructed by walking the cache wrapper chain for the first CacheJail::getGetUnjailedRoot(), which covers both groupfolder mount layouts as well as any other jailed mount (federated, encryption-wrapped). Root-mode / enumeration also benefits — separate groupfolder mounts no longer collapse into the personal-storage scope.
  • PhotoStory/FileStory tile previews missing for federated files — NC's /core/preview returns 404 for any file on a Files_Sharing\External\Storage mount: the preview providers (Image, Office, PDF) need a local file path or a Collabora/LibreOffice render, and federated files only exist on the remote NC's disk. Result: PDFs, docx, xlsx and even jpg tiles from an OCM share rendered as a generic mime-icon instead of a thumbnail. New shared PreviewController at GET /api/preview?file_id=N&x=400&y=400 closes the gap: local files 302-redirect to /core/preview (no overhead, NC's own preview cache stays hot); federated files are handled by the new FederatedPreviewService which calls the owner instance's /index.php/apps/files_sharing/publicpreview/{token} endpoint and caches the result in appdata/intravox/federated-preview/ keyed by {fileId}-{etag}-{x}-{y}. Cold response ~250–400 ms (~5–15 KB transfer per file, not the file body), warm ~180 ms.

    Three protection layers stack to keep this scalable and friendly to the remote: a per-user rate throttle (UserRateThrottle(600/min)) bounds individual misuse; in-flight deduplication via NC's distributed cache ensures that 50 users opening the same uncached tile at once produce a single outbound HTTPS call (49 wait for the cache to materialise, then read); a per-remote concurrency semaphore (default 8 simultaneous outbound calls per remote host) prevents an IntraVox-server from saturating one owner instance and tripping its IP-throttle. When the cap is hit the request degrades gracefully to the mime-icon fallback. A companion POST /api/preview/warmup endpoint pre-warms up to 16 federated tiles per call; PhotoStoryWidget and FileStoryWidget call it fire-and-forget after every paged fetch so most tiles are already warm by the time the user scrolls into view. Bandwidth scales with viewed files, not with corpus size — fine on 1M-file federated mounts.

Added

  • PhotoStory: hide RAW sidecars when a JPG/HEIC variant exists — DSLRs and mirrorless cameras in "RAW + JPG" mode write two files per shot (IMG_5432.CR2 + IMG_5432.JPG) that show up as visual duplicates in any folder view. New hideRawDuplicates widget option (default on) groups files by (parent_dir, basename-without-extension) and prefers the browser-displayable variant over the RAW. Covers Canon (CR2/CR3), Nikon (NEF/NRW), Sony (ARW), Adobe (DNG), Fujifilm (RAF), Olympus (ORF), Panasonic (RW2), Pentax (PEF), Samsung (SRW) and Sigma (X3F). Implemented as over-fetch + dedup + slice so paginated infinite scroll stays correct; total continues to count physical files (honest source-of-truth for storage cost).
  • Sticky page navigation — header (title + Save/Edit) and navigation bar are now wrapped in a position: sticky; top: 0 topbar so they stay reachable on long pages. Previously a 300-photo Photo Story timeline forced you to scroll all the way back up to reach another page. Dropdowns/megamenus continue to position via getBoundingClientRect(), so their placement is unaffected.
  • Orphaned GroupFolder admin: show what's actually in the folder — the "Content" column used to render the literal "Unknown data" for non-IntraVox orphans, leaving admins to delete blind. OrphanedDataService::analyzeOrphanedFolder() now returns a sampleContents field with the first 8 top-level entries (name, type, size) sorted alphabetically, and the admin UI renders them as a small listing under the badge. The empty-state label also changes from "Unknown data" to "Non-IntraVox data" for accuracy (#56).

Notes

  • The PhotoStory groupfolder fix activates on every groupfolder-hosted album with zero config — existing widgets pointing at a groupfolder path will start returning their photos immediately after upgrade.
  • The federated preview proxy degrades gracefully: if the owner instance can't produce a thumbnail (no Collabora/LibreOffice on their side, or the file format is unsupported there), the endpoint serves a 302 redirect to the matching mime-icon SVG. No broken-image placeholders.
  • hideRawDuplicates defaults to enabled also for existing widgets (the param is absent → backend reads its default). Users with RAW-only albums can untick the new editor checkbox.
  • No DB migration; widget configs are read back through the new optional field transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturemyEi+pL/zo6IBucOaSFT5mI0lcpEe1D/O6I6fF/yEeHWYWnAeylyogGH5pDKz1TFn0b5mhCXPr2bwZDXRq4gkW8dpXkLVDPC9ox3kX/7jwULrvSzXbn7okB18UC0eGDvG3O0VXrVPl0XMveQCjlZ3GYvSi3p2mukoN6vKYXJazEwnioFhh18W39wUZ+/rxQz5MnQKfaWnOBisrv1Js1z4TAOITDII1gSnMcJFFWKepzSaUQbXNjsAjieaV0qshjTM9JAPZiAOGIQEJH6mGM60LgvV9czXdd5g5StTDinr2zK7O/kHe0qia5Z2GjmN50KrLAsmff7nFS4P2qDTov4H8p7Kw+qEClC+Wm0F6p/E3yZ7XWc3KkwU8vk96gXuYJ8yF4zCswLx4YAwSS1QvuACxQBnC+fF42jh/wXJpPylbMrJqeKKY3Ql24TTzUkSX+ZMweoQ4qkb3BQRQPQY/9pyiQrxc/OvpMdicJkl2IGIIYPG/5pLhTEZEZCXtlVRMpcO9LKzLzU1e+Otddyz3DsyXBwcTawwWknmZPhhD7fvSYpQb6dp0pgjWjBnoI7+YCcMI4sKONQUYrTzwA6eCjYRCiAcW30bTsUG27xHGvHT2cTg/JnNfaeYPIEVvWE+qCXKPON39QL/SMPfSJPrCMOptTuW35mpF4A/w4AF+BCq8k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.1
Release Details
UpdatedMay 28, 2026, 10:58 a.m.
Changelog

Patch release that fixes legibility on themed page rows and tightens a handful of widget rough-edges that surfaced in production after 1.5.0. No new features, no API changes.

Fixed

  • PhotoStory/FileStory contrast on dark row backgrounds — filenames, day-headers and meta lines used --color-main-text (dark) regardless of the row's background colour. On Primary (--color-primary-element) rows that produced unreadable dark-on-dark text. Both widgets now accept rowBackgroundColor from the parent Widget.vue (closing a gap with the existing widgets that already consume it) and switch internal text + tile surfaces to a WCAG-paired colour set via two CSS variables (--fs-text/--ps-text + their muted siblings). Tile bodies become a tinted-glass card on dark rows instead of cutting a hard white rectangle through the coloured backdrop.
  • FileStory tile filenames invisible on dark rows — regression from the same root cause: tile bodies kept their --color-main-background (white) while inheriting the now-white filename colour. Tile surfaces, hover state, preview-fallback bg and mime-icon placeholder all lift to translucent white on fs--on-dark.
  • Folder-path "/" silently collapses to empty after savePageService::sanitizePath strips leading/trailing slashes, so a configured PhotoStory/FileStory folderPath = "/" (root) was persisted as "" and rendered as "no folder selected" after reload. New sanitizeFolderPath() wrapper preserves / (and \) as a meaningful "whole drive" marker before delegating to the generic sanitizer.
  • 502/503 during page save — entering edit mode after a FileStory widget existed triggered four expensive folder=/ queries within ~250 ms (the legacy debounce). Apache workers saturated on large libraries. FetchKey watcher debounce raised from 250 ms to 700 ms in both widgets.
  • NcAppSidebarTabs double underline (NC 32 regression)@nextcloud/vue 8.x renders both a 1 px hairline on the tab-strip wrapper and a 4 px coloured indicator on the active tab, producing a stacked double underline in the PageDetailsSidebar. Global override in css/main.css removes the redundant hairline; scoped Vue CSS couldn't reach the data-v--tagged third-party selector.
  • Photo previews missing for common web formatsPhotoStoryService::MEDIA_MIMES was narrower than what users actually drop into their photo folders. Now also includes webp, gif, svg+xml, bmp and video/webm.
  • Empty folder picker returning "" instead of / — NC's OC.dialogs.filepicker returns an empty string when the user picks the root; both editors now normalise that to "/" so the configured value matches the sanitizer's accepted shape.

Notes

  • Default-themed rows (transparent / --color-background-hover / --color-primary-element-light) are visually unchanged; the new contrast logic only activates on saturated row colours.
  • No DB migration. Existing PhotoStory/FileStory widget configs are read back through the new sanitizer transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJUDu14MZav9zDCdwASLwOt9QfZFE4mkGdJjWn05l54CySpeTxrouul/CjST66UGcUmHOIM4gNXCBgrEkSACF0vpv1XWOWu6/PWHUmTsoZWretFLxxA/OXlcO6h3/Q0gHqS9TnIAxFCk1fnHbHHD3hGgYAnISLj6gL6s4axrs+h0/JpIon1ZMloUFxt3759D8Oc+LAgV5kNtYIndBkwb1BM89kb3Ri8NfCzZo3+5wo688lAty1cWjjqkOhzoxw6ERPWxRlek4XXB+4V/9a3wY0/gPWXdHb7YlSOgQpS2KB2m+F/YW64NUfCGOdTE8m/jAvw4Mz/ZDWVhtEk8vFgI3P3Sn1n4WxjArYYE5bChuDHa3A+G2sHZAWQ+/FRUHqExcaoK+mRXQGavoih9WkwVS2Bk9bJ6lKAVFwZgkvgD8YuKwiT9xe3tIhaFceYx1OZq90s6xqijZ6Upm6uoNZO8zwY28LwMJpxlOxqy0lyXVbhKQMb5cU9M80S2kmXbWCHJ1Tech4ZMpTdfZTP/MyoDtdqN9AczNCaMoxMRbW42x2FgNMDwBxszBV4q2mWa0LODiqo3X3AubXvJScBL62d3cWbHhGiEoiB4OJP99YlahBMOw8HoOebDrDYYCUnznz3Hh4GZoNFgWk+wtzrbR3Lu/TBimWHEkkYYQZAHr5mIWjsc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.0
Release Details
UpdatedMay 27, 2026, 8:57 p.m.
Changelog

Major release. Introduces two new widgets — Photo Story for photo galleries with EXIF, location maps and an Apple-style lightbox; File Story for document libraries with multi-mode layouts, MetaVox-aware filtering and federated-share awareness. Adds a fresh wave of perf, security, accessibility and l10n polish across the photo + file widget surface.

Added — Photo Story Widget

  • Four layout modes: Timeline (Magazine, Apple or Travelogue style), Highlights (auto-curated top photos), Grid (masonry), and On-this-day (year-over-year retrospective).
  • Lightbox with keyboard navigation (Arrow/Home/End/Esc/Space), slideshow mode with adjustable speed, focus-trap and focus-restore for screen readers, semi-transparent date/location pill that toggles a mini-map for geo-tagged photos.
  • OpenStreetMap integration via Leaflet: optional overview map per widget, per-day mini-maps in Timeline mode, and a cross-folder cluster endpoint for browsable map-driven storytelling. Admin-config aware (NC admin can disable all map features instance-wide).
  • EXIF metadata rendered into a details flyout (people, subjects, camera, location). Reads from NC core oc_files_metadata when populated; falls back to the bundled lsolesen/pel reader as a last resort with a per-request eager-EXIF cap.
  • MetaVox-driven filtering, grouping and sorting when the MetaVox app is installed. Supports cross-folder discovery mode (empty folder + ≥1 filter) for "all my photos tagged X across the instance".
  • Geocoding cache with periodic warmup job for fast country/location lookup on GPS-bearing photos.

Added — File Story Widget

  • Four layout modes: Timeline (per-day / per-month / per-year granularity), List (flat sortable), Tiles (visual grid with first-page previews and three configurable sizes: Small/Medium/Large), and Grouped (by file-type or MetaVox field).
  • Federated-share awareness — incoming OCM shares are detected per-file via a single indexed SQL join (oc_storages × oc_share_external). Federated rows render with a subtle cloud-badge and silently skip MetaVox-fetch since the remote NC has its own metadata database we cannot reach cross-instance. Mixed sources (local + federated under one root) keep full controls; pure-federated sources hide the MetaVox UI with an explanatory banner.
  • Configurable visible columns: Date, File size, Folder path. Date column can render either filesystem mtime or EXIF/MetaVox taken_at. Filename + file-type icon are always present.
  • MetaVox filter-builder, sort, group-by identical to Photo Story but adapted to document use-cases (e.g. group-by archief_categorie for compliance views).
  • Open-in-Files-viewer click target on every row/tile with role="button", Enter+Space keyboard activation and aria-label per item.

Added — Page editor & widget plumbing

  • Widget registration for Photo Story and File Story in the picker, with iconography and descriptive copy.
  • Editors for both widgets with folder picker (NC FilePicker dialog), live capability detection (MetaVox available?, source-federated?), sortable filter builder with type-aware operators (equals, contains, in, year_equals), and persisted widget config validated by PageService::sanitizeWidget.
  • REST API under /api/photo-story/* and /api/file-story/* covering paged listing, capabilities, MetaVox field discovery, location clusters, EXIF detail and range-aware video streaming (Photo Story only).

Performance

  • Paged enumeration via oc_filecache for all primary widget modes — no more full-tree getDirectoryListing() on large libraries. Hard caps (5000 cross-folder, 20k filtered, 200k count) prevent OOM on massive folders.
  • Federated detection is one preloaded SQL query per request, O(1) lookups per file. The previous IMountManager::findIn('/') per-file approach (cause of the 2026-05-27 saturation incident on nc-dev) is gone.
  • clusters, highlights and on-this-day endpoints now go through listPhotosPaged with sane caps instead of the unpaged legacy path that risked the same blast radius as the federated-detect outage.
  • filterFileIdsByScope collapsed from chunks × scopes SQL roundtrips to one ORed WHERE per chunk — at filtered-MetaVox-page scale this drops ~400 queries per page to ~40.
  • extractGroupfolderId memoised per node within a request.
  • Frontend AbortController on every fetch + fetchMore: rapid config changes no longer race stale responses overwriting fresh data, and pending requests cancel on widget unmount.

Security

  • Per-file ACL guard on the slice in MetaVox cross-folder hydration (buildPagedResponseViaMetaVox) using $userFolder->getById(). Bounded to ≤page-size lookups, so sub-folder ACLs inside groupfolders are honored.
  • Filter payload caps: 16 KB JSON pre-decode rejection on both controllers, value-length cap of 200 chars per filter, max 32 filters and 64 array values per filter — prevents pathological-input DoS.
  • Generic 500 messages on both controllers (no $e->getMessage() reaching client); folder-not-found mapped to clean 404 with empty-state payload instead of generic 500.

Accessibility (WCAG 2.1 AA)

  • Tiles, rows and hero elements: role="button", tabindex="0", Enter + Space activation, meaningful aria-label derived from caption/location.
  • Lightbox: focus-trap (Tab cycles within modal, no escape to background), focus-restore on close, counter announced via aria-live="polite", icon-only buttons get descriptive aria-label + aria-pressed where appropriate.
  • Editors: orphan <label> without for= converted to <div class="editor-label"> to avoid mis-association; form controls properly labelled.
  • Reduced motion: @media (prefers-reduced-motion: reduce) honored for Ken-Burns animation, pulse skeletons, and pill transitions.
  • Status regions: role="status" / role="alert" on loading, empty and error states; map-cluster list items keyboard-reachable; federated cloud-badge gets role="img" + aria-label.
  • Alt-text: meaningful (caption / location / numbered fallback) instead of filename for photos; decorative alt="" for tile previews where the parent already labels the action.

Internationalisation

  • Backend month/category labels now route through IL10N::t() (PhotoStoryService::localizedMonth, FileStoryController::extractGroupKey). No more hardcoded Dutch in API payloads.
  • Frontend date formatters use getCanonicalLocale() from @nextcloud/l10n everywhere — toLocaleDateString / toLocaleString / Intl.DateTimeFormat calls in PhotoStoryWidget, FileStoryWidget and PhotoLightbox no longer pin nl-NL.

UX polish

  • Retry button in the error-state of both widgets. Users recover from transient API failures without reloading the page.
  • Context-aware empty messages: distinguishes "no folder selected" / "no documents match current filters" / "folder is empty".
  • Transparent date headers in FileStoryWidget Timeline mode — replaces the opaque white sticky bar that clashed with themed/coloured rows. Count-badge uses color-mix(in srgb, var(--color-primary-element) 14%, transparent) for a subtle tinted chip that adapts to the active theme.

Developer-side hardening

  • scripts/check-import-consistency.js runs in prebuild: detects mixed sync/async imports of the same .vue component (the root cause of a runtime TypeError we hit on 2026-05-27) and fails the build before it ships.
  • scripts/auto-bump-dev.js auto-bumps the patch level on dev deploys so NC's md5(appVersion) cache-buster always changes — browsers never serve a stale bundle after a deploy.
  • Translation files (en/nl/de/fr) synced for all 122 new UI strings added by Photo Story + File Story.

Notes

  • No DB migrations required for the widget functionality itself; existing pages keep working.
  • PhotoStory federated-share awareness is on the roadmap but not yet implemented (single-storage photo libraries are the typical case). FileStory has the full federated-aware code path.
  • MetaVox cross-instance sync remains out of scope: NC core exposes no federation tokens or remote-file-id mapping. Roadmap item.

New Vue components: src/components/PhotoStoryWidget.vue, src/components/PhotoStoryWidgetEditor.vue, src/components/PhotoLightbox.vue, src/components/PhotoStoryMap.vue, src/components/PhotoStoryDayMap.vue, src/components/PhotoStoryFilterBuilder.vue, src/components/FileStoryWidget.vue, src/components/FileStoryWidgetEditor.vue.

Composer: lsolesen/pel added for the optional in-process EXIF reader.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureFLZvFbovK9mQvZvpGHVOIIcY1Wkokfi3grl/FTH48JoSlk35yZ49frh91/2T0Bda+dcFMO1aCpsNd694iEd26hCMp66F+QA8nqYMB0+WCiEUwlDSVT1x7S9MdLch+7LGPrm2A6h1MWsTQGV9pOIOjWtP4rPGv1+Mw+LFEva+CmFep5Kh/w/RaEqvn9LwcDzxx5JEzzme+nYZurAgV6146olp+xl0rCtxM/IPvL5JlZ7NchtiEc0udMvLroBfdOHKRU0aIJY7ZzVdjJJB46a911krwyn9jfcJmqGVrHZtNlp6uwpFKKlXo1fZDdnMsu/YxnVH5XTJOEflsQTB8GWntZa//R5zRRGXX0jj4o/dWNxvRMPD9jvCTO7Wq5oEvyorRcHVCJ70QatCHKNhOqXtq/vvywVZODt3BZk9gtQ5ssv9FFe7JB7zZWS69ZhHcTS9HqzV0UJ3SpSZfjXN0gsCdTlSi6hknGP9X4wvShSjV+DeHeBJoM4EZHVLSZiRjBWBYpqg0ffwj5X5U8VrXIFtIUHwUMXUJzl7Ta3Uwo4liP77h5AA2xInz+IxLAcpAP/ncaLtlrqCvm0PN1QRz3zq9IBaxE0VI7UDIn6S6ojzXQDWHTPaTPfS/e9v7WqPUB4t/o+6PyEulzq8TXq2jpmXcMsEDHQaRAJl5XT4W3h7TMM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.1
Release Details
UpdatedMay 20, 2026, 6:01 a.m.
Changelog

Patch release that resolves all open frontend security advisories flagged by GitHub Dependabot shortly after the v1.4.0 push. No functional or API changes — npm audit fix lifted eight vulnerable transitive packages to patched versions within their declared semver ranges, no package.json edits required. Build, PHPUnit (258/413) and dev-server smoke tests all green.

Fixed

  • axios → 1.16.1 — resolves 11 advisories (prototype pollution gadgets, CRLF injection, header injection, NO_PROXY/SSRF bypasses, DoS via deep toFormData recursion, streamed upload/response body-size bypasses, null-byte injection in URLSearchParams, XSRF token cross-origin leak)
  • dompurify → 3.4.5 — resolves four XSS bypasses (SAFE_FOR_TEMPLATES/RETURN_DOM, ADD_TAGS/FORBID_TAGS short-circuit and function-form, prototype-pollution via CUSTOM_ELEMENT_HANDLING)
  • fast-uri → 3.1.2 — path-traversal via percent-encoded dot segments + host-confusion via percent-encoded authority delimiters
  • fast-xml-builder / fast-xml-parser — XML comment/CDATA injection and attribute-value quote-bypass
  • brace-expansion → 5.0.6 — DoS via numeric range that defeated documented max protection
  • follow-redirects → 1.16.1 — custom auth-header leak on cross-domain redirects
  • postcss → 8.5.15 — XSS via unescaped </style> in CSS stringify output

After the bump npm audit reports zero vulnerabilities.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDc0e6XrFG/+dkBa2rqaitf3dwAEkyMJA/wqM2F2ZDIp+L9644GrNvZpexYR5xe/IEL4TR6gu1JHpUs2nqxnQ/Wgm8miJwi8+/9Jgg1bjc93k11siFiM8ca+ljWMlJ9Ai1UofzB8tdX2UqOPc1jzPMJwttj1+vYNBIrmD8Ypdubmnw6U3VDP/vSVwwR7I9O08D0DT/f6YGPRa4reXbqHRRllXRUgKXCXL0EWITQ1uwV/XoipV2U35G/BjFwOsQV370teRvY9aMarNl1j86d9N2O+cFMRokMVD/feZNeDXJ1jKh6UxOGPSuJZiQFEVdwMmyyH1MXYy3xh52ZI01G+je1GvGPwzpouTvZzDMYYdsNFepGZtNl1nDBH8THuNnEnMCyBxCPabrlNfBPH9GFdDSPjFptQjZ+ec3/UJHCIqAQHV2no41W5KEBCJTHGf/ex4tU3LIUGGZeTPGmdYCHvH4VNqqqHffL88FqFCKHNO6kWrqnHaFGNwfxsM5uNeYKlZttEzinZzg0Y+ka+e6p0Ko6YNlzG98rpngbyWFM/CVEliEoVYnOsPGHhoV2/GLxMc9JjjRJEBSrRCU7WXCqVQNr8hOLy/qlfvkCnKv2E9YHv4lTKKMayDmJWE0iFCF8DfoA2eHyfLt/6bWSsMzEGERpu4Z/N6EDeoEAws+tfk3No=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.0
Release Details
UpdatedMay 19, 2026, 8:39 p.m.
Changelog

This release lays down the foundation IntraVox needs to scale cleanly to Nextcloud Enterprise customers with thousands of users on multi-node deployments. Two themes: PageService gets split into focused, testable services, and the caching layer gains group-aware keys + a content-addressable distributed cache + a frontend prefetch pipeline.

User-visible: pages and navigation are noticeably faster on warm caches, especially for groups of users that share the same permission profile. Cold-cache latency is bounded by a new background warmup job. No breaking changes; every public API is unchanged.

Added

  • Subtree support on GET /api/pages/tree — Optional rootPageId query parameter narrows the response to the subtree rooted at the page with that uniqueId. Resolves #45 from JustinDoek (teamhub app builder) who previously had to combine listPages + getBreadcrumb to list pages under one anchor. Backward compatible — without the parameter the full tree is returned as before. The same parameter is available on the <PageTreeSelect> Vue component (rootPageId prop) for in-app subtree pickers (lib/Service/Path/PagePathHelper.php::findSubtree, lib/Service/PageService.php, lib/Controller/ApiController.php, src/components/PageTreeSelect.vue)
  • ETag / 304 conditional responses on GET /api/pages/{id} — Browser revalidation now returns a 304 with zero body when the cached page is still current. Per-user group hash is included in the ETag so a permission change automatically invalidates the cached entry without leaking content across users (lib/Http/EtagBuilder.php, lib/Controller/HasConditionalResponse.php, lib/Controller/ApiController.php)
  • Group-hash cache key for page tree + permission map — Tree and navigation caches are now keyed by a hash of the user's group memberships instead of their user-id. At enterprise scale (1000+ users in ~10 groups) this turns thousands of cache entries into dozens — same correctness, two orders of magnitude less memory. Permission path-maps are cached per-language (one entry per supported language, shared across all users) (lib/Service/GroupContextService.php, lib/Service/PageService.php, lib/Service/PermissionService.php)
  • Event-based cache invalidation on group changes — Adding or removing a user from a group flushes the affected distributed caches via UserAddedEvent / UserRemovedEvent listeners. Group permission updates propagate within one request cycle instead of waiting for TTL expiry (lib/Listener/GroupMembershipChangedListener.php)
  • Page-content distributed cache with mtime-indexed keys — Sanitized page output is cached under content_{uniqueId}_{mtime}; a write bumps mtime, the next reader misses cache and rebuilds. The expensive sanitize-pipeline (~500 lines of widget processing) only runs on cache miss (lib/Service/PageService.php)
  • News widget result cache with version countergetNewsPages() results are cached per {lang}_{groupHash}_v{counter}_{paramHash}. Mutations clear the cache; subsequent reads rebuild from a fresh counter state (lib/Service/PageService.php)
  • Frontend prefetch servicesrc/services/PrefetchService.js speculatively loads pages on hover (desktop, 100ms delay) and IntersectionObserver entry (mobile, 200px rootMargin). Respects navigator.connection.saveData so users on metered connections aren't surprised by extra requests; max 3 concurrent in-flight requests. Writes through the existing CacheService so real navigations pick up the prefetched data instantly
  • LRU eviction on localStorage quotaCacheService.set() now catches QuotaExceededError, drops the persistent entry with the earliest expiry, and retries once. Prevents silent cache-write failures on heavy intranets
  • Background cache-warmup job — Runs every 15 minutes (TIME_INSENSITIVE) and pre-warms the path-map + tree + navigation caches for each supported language. Prevents the cold-cache thundering herd after a deploy or after a page mutation (lib/BackgroundJob/CacheWarmupJob.php)
  • RequestTimer infrastructure — Light static utility for measuring p50/p95 latency of expensive operations. Used internally for ad-hoc profiling; not yet wired into TelemetryService (lib/Performance/RequestTimer.php)

Changed

  • PageService.php is 615 lines smaller — From 6135 to ~5520 lines. Ten pure helpers extracted into focused, individually-testable services. PageService remains the orchestrator for filesystem + cache + permissions, but the sanitize, format, search, path and template logic now live in dedicated modules:
  • lib/Service/Sanitize/HtmlSanitizer.php (strip_tags + style-property whitelist + entity decode)
  • lib/Service/Sanitize/UrlSanitizer.php (schema-whitelist for link URLs)
  • lib/Service/Sanitize/ColorSanitizer.php (NC theme-vars + hex + rgb/rgba)
  • lib/Service/Sanitize/MediaSanitizer.php (filename + SVG + image-header validation)
  • lib/Service/Version/PageVersionFormatter.php (NC-style "X sec/min/hour/day ago" + metadata accessors)
  • lib/Service/Template/TemplateMetadataExtractor.php (preview summary: column count, widget mix, complexity bucket)
  • lib/Service/News/NewsContentExtractor.php (excerpt, first-image, markdown strip)
  • lib/Service/Search/PageSearchHelper.php (snippet extraction, per-widget-type scoring)
  • lib/Service/Path/PagePathHelper.php (depth, page-type, department slug, current-page marking)
  • lib/Service/Util/PageIdUtils.php (sanitizeId, RFC 4122 v4 UUID, php.ini size parsing, formatBytes)
  • Test suite grew from 78 (with 36 errors) to 252 / 401 assertions, all green — Existing Controller tests were updated to match the current constructor signatures; a fresh unit-test layer covers every extracted service

Fixed

  • Cache-invalidation gaps closed across page/nav/media/import flows — Discovered during dev verification of the new caching layer: several mutation paths wrote to disk without flushing the distributed caches introduced by PR-3 / PR-12 / PR-13, so changes were invisible for up to 5 minutes after a save. Now resolved:
  • PageService::createPage flushes after writing — without this, the new page sat behind the 5-minute tree-cache TTL (visible on "Create from template" — page appeared in the breadcrumb but the editor mounted blank until reload).
  • PageService::createPageFromTemplate re-fetches through getPage() so the response includes enrichWithPathData + the sanitize pipeline. Previously the API returned half-populated page data and the editor rendered blank until a manual save round-tripped through the real read path.
  • App.vue::handleCreatePageFromTemplate uses the enriched backend response directly instead of doing a second selectPage() round-trip that occasionally 404'd against a freshly-created folder and bounced the user back to the home page. URL hash, local pages array and frontend CacheService are all warmed in one synchronous block before the editor mounts.
  • ImportService::importFromZip flushes all PageService caches after a bulk import — without this, 50+ imported pages were invisible in tree, navigation and news widgets for the next 5 minutes.
  • NavigationService::saveNavigation flushes intravox-pages + intravox-permissions after writing — previously a menu edit landed on disk but the path-map cache (PR-3) served the old menu for 5 minutes.
  • PageService::uploadMedia + uploadMediaWithOriginalName flush the per-page content cache so the next page-render reflects the just-uploaded asset (important for image overwrites where users otherwise got the cached old version back).
  • Public PageService::invalidateAllCaches() introduced as the cross-service hook for the import path (kept internal clearCache() private; only the audit-driven external use case opens it up).
  • Actionable error messages on failed ZIP imports — Resolves #52 from @apesorguk, who saw only "Import failed. Please check the ZIP file format and try again" when uploading a cloudron Nextcloud backup. The five validation errors in ImportService (invalid ZIP, missing export.json, invalid JSON, unsupported version, incomplete export) now bubble through a typed InvalidImportException and reach the user with copy that tells them what went wrong and how to fix it ("Make sure you uploaded an IntraVox export, not a Nextcloud Files backup..."). HTTP status is now 400 for these instead of 500. Generic failures still hide behind an errorId so server paths don't leak. A NcNoteCard above the import form spells out the supported format up front. Error messages translated to NL/DE/FR via a stable errorCode (INVALID_ZIP, MISSING_EXPORT_JSON, INVALID_JSON, UNSUPPORTED_VERSION, INCOMPLETE_EXPORT) the frontend maps to localized strings (lib/Exception/InvalidImportException.php, lib/Service/ImportService.php, lib/Controller/ApiController.php, lib/Controller/ImportController.php, src/components/AdminSettings.vue)
  • Broken Controller test suiteApiControllerTest, BulkControllerTest, AnalyticsControllerTest now compile against the current Controller constructor signatures. The OCP stub gained ISession, ICache, ICacheFactory, IGroup, group-membership events and Files_Versions\IVersion to keep unit tests runnable without a full Nextcloud install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturer9Dvf1Sv0MUqG5zMrZC7vrTGxJ/b/FMFLIQaX9apeRGFYpfb4hH4Zsbt+aKCbyoRj3zOGtdytKpqUDEXZ9jFexiNrkKjfWOvW8XSH1dlFHc6Vo/z+h7Ms+02xgNdSxajfN0yJK0WnDDfhEUn1j9VaByfKuF9VaMVwHL0u4A+k2LwCW0izMkZVjLtiJk/1VyA7pc4Olz+6eWyF0QaKkTXyMmbibugQNrRjRCAylR8up/tSlgi4aTobGMZKkoeZg+HK5KfQXiZHoC4B3GiP3Vf/CfzU0WYyhq7sOZ4LM7PUtgZwcJyUMk5i12oS56Nf+4Umubrn6OaupdmOmgSbCbN3G1K7HWgRpYGqmdDdqzIajzm/lt2vV5gtW4PUyY1ESAh5F1Cch/h/+HWndtyQZDkKgX0jgXtKttltXJbC4/+LQWPIDmffP8ve12tSpCYcENQdvV8rtGkS4aAH0Mf3jiqa8oNtpr7VgwslCHEhrSXxMz1mprSO+x+R3wqWmo+JCo9QmPnwT9nhf81CtvazMkZ2zmzrGX4EegRNpILLPbR3BwrV214CHpu6lnE9zZlCqU9/pXyJoutDUrGtk8gqD3tl2heAy4EcEOIgnHOYx72Q14HXk227XA61Qvq02dp/+lQKLtiEBByL5ZkT/FYQsgyZsEM4p9YBMXr9/ZzmTDrG1k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.4
Release Details
UpdatedMay 8, 2026, 8:11 a.m.
Changelog

Identical content to 1.3.1 (released earlier today). The version number is bumped to 1.3.4 because an internal 1.3.3 build was published to the App Store on 2026-05-06; instances that picked up that build would not see 1.3.1 as an upgrade. 1.3.4 ensures every existing install gets the editor/table improvements and the privacy cleanup of [1.3.1] below.

No code changes vs. 1.3.1.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBQtsgQvlSPO/vsSYvRbB2PBuBbivwcUewzg126b/lwuFwdLoS/6+o9m1Kahs/ZxLur3f6fBRJEw2fZOh85ofBGQbd6o3KFJtLkUzZZ3/zsfiwbxlUCaNiO3hnuF5UHqpumyiL2bQO2BzaYHCn0G+82UonzYOsvbhMMwVIJeL3oCis3B9Z0+lB6KkCtAuE0mGLybehJ0Sa1KG326gf69OopoE94ikLowwxOPFmFJx6944rmk7axG92CtAV4x68WI8imrKPY59lAt3VI4+YiAXWdjyGKrG08yPi30AjnMwW5raab78hiySW1mIKcpMd8UaDVfKz19oG3MnRz7TpVSzADxuxx5ueuP1sV58e+5UU/Uv2OcghdnFSdyiSCHGQokUqUi63q0QV74517WQgdnmygJRXR+YwYfOn/AhhhKXSeyb/KFIlHoTTdM+gNysJldCBktY49ZEKGhi5AJkGW2jzZ3+hVW1PZylTqV9HRq/ZgFVukYJdPYsWV5UQ8XzN+vYcLuYsPMBWxfKeuecfdzjChZ6sxseqIYyqk2WzN/hBZLbzuQODvroGmb7nPzQsJHolgv7YcCLk0EexuyI2FdYUpI3UKSes9jqAIdLsRylBsgtnVNV6pe53IX3NjWgYubA2VQWgzMM5hFjiM9Q2PyebaXDb7n/LTl73D/qy/0guHw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.1
Release Details
UpdatedMay 8, 2026, 6:34 a.m.
Changelog

Added

  • Text alignment — New alignment dropdown in the text editor toolbar (left, center, right). Alignment persists through save/reload using CSS classes in markdown storage. Supports paragraphs and headings. Keyboard shortcuts: Ctrl+Shift+L/E/R. Custom TipTap extension uses CSS classes instead of inline styles for DOMPurify compatibility (textAlignExtension.js, InlineTextEditor.vue, markdownSerializer.js)
  • Blockquote button — New blockquote toggle button in the text editor toolbar. Uses the existing StarterKit blockquote extension — only the toolbar button and read-only styling were missing (InlineTextEditor.vue, Widget.vue, Footer.vue)
  • Nextcloud Extended Support telemetry — Telemetry payload now includes hasExtendedSupport (boolean), sourced from Nextcloud's public OCP\Util::hasExtendedSupport() API. Helps us understand which share of IntraVox installations runs on Nextcloud Enterprise / Extended Support — relevant for compatibility prioritization and the Nextcloud ISV partnership. Falls under the existing telemetry opt-out (no separate consent), and is listed in the admin "What we collect" overview for transparency. No personal data, just a single yes/no per instance (TelemetryService.php, SupportSettings.vue)
  • Persistent column widths in tables — Column widths an editor sets by dragging the TipTap resize handles now survive save/reload. A post-render hydrator in markdownSerializer.js builds a <colgroup> from data-colwidth (modern) or colwidth (legacy) cell attributes and any pre-existing <col style="width: Xpx">, then converts pixel widths to percentages so the table always fits its container — even when the saved widths sum higher than a narrow page-row column. Tables without explicit widths keep the previous auto-layout behaviour (markdownSerializer.js)
  • Table width presets — New "Width" row in the table toolbar dropdown with presets Auto, 25%, 50%, 75%, 100%. Stored as data-table-width on the <table> (InlineTextEditor.vue)
  • Table alignment — New "Alignment" row in the same dropdown with Left/Center/Right buttons. Stored as data-table-align; rendered as margin-left: auto / margin-right: auto so a 50%-wide table can sit left, centered, or right with surrounding text (InlineTextEditor.vue)
  • Free-form table width drag handle — A custom ProseMirror plugin adds an 8px-wide drag area on the right edge of the active table. Click+drag to set any pixel width between 80px and the widget container's width; the resulting style survives save/reload via the same hydrator. Coexists with the column-resize handles inside the table — different hit zones (tableResizeHandle.js, InlineTextEditor.vue)
  • Horizontal scroll wrapper for wide tables — Tables wider than their page-column scroll horizontally inside a .tableWrapper div instead of pushing the page layout sideways. Read-mode wraps every table via the hydrator; edit-mode reuses TipTap's built-in .tableWrapper element with the same styling, so what the editor sees matches what readers get (markdownSerializer.js, Widget.vue, InlineTextEditor.vue)

Changed

  • Toolbar reordered — Text editor toolbar reorganized into logical groups based on analysis of 10 popular editors: (1) Inline formatting: B, I, U, S (2) Block structure: Heading, Lists, Blockquote (3) Alignment dropdown (4) Insert actions: Link, Table. Compact mode follows the same grouping in the "More" dropdown (InlineTextEditor.vue)
  • Alignment as dropdown — Text alignment uses a single dropdown button (like the heading dropdown) instead of 3 separate buttons. The button icon dynamically reflects the active alignment. Keeps the toolbar compact on all screen sizes (InlineTextEditor.vue)
  • Telemetry includes license key for Enterprise claim verificationTelemetryService::collectData() now adds the configured license key (or empty string for community instances). The license server uses it to verify hasExtendedSupport claims against the bound license_usage row before honoring them; without this binding the boolean would be anonymously spoofable. The key is the same value the app already sends to license validation/usage endpoints, so this introduces no new disclosure (TelemetryService.php)
  • Table cell text wrap policy — Cells use overflow-wrap: anywhere (CSS Text Module Level 3) so long unbreakable tokens (URLs, hashes) wrap mid-word when needed. Edit-mode and read-mode use the same rules so what the editor sees is what readers get. Replaces the deprecated word-break: break-word combo with the modern one-line equivalent (InlineTextEditor.vue, Widget.vue)
  • Page rows allow narrow content.page-row, .row-content, .page-grid got min-width: 0 and max-width: 100% so a wide table inside a multi-column row no longer forces the row beyond its viewport. The grid columns now use repeat(N, minmax(0, 1fr)) instead of repeat(N, 1fr) so a 1fr track can shrink below its content's min-content (PageViewer.vue, PageEditor.vue)

Fixed

  • Aligned text not surviving save/reload — Content with text alignment was escaped to raw HTML after saving and reloading. Root cause: markdownToHtml() had a validation check (html === preservedMarkdown) that incorrectly treated HTML blocks passed through by marked as a parse failure, triggering escapeHtml(). Fixed by skipping this check when content starts with < (markdownSerializer.js)
  • Table widths and alignment getting stripped on savedata-table-width and data-table-align were not in the DOMPurify allowlist, so user-set widths and alignment from the table dropdown silently disappeared after saving. Added to the allowlist together with the <div> tag we now use for the scroll wrapper (markdownSerializer.js)
  • Text overflowing table cells — In fixed-layout tables, long text in a cell could push past the cell border into the next column or beyond the table edge. Multi-cause fix: paragraphs and headings inside cells get min-width: 0; max-width: 100%, cells get white-space: normal (overrides a Nextcloud core rule that set nowrap on <p>), and the entire page-row chain was given proper min-width: 0 so a wide table can no longer push its ancestors sideways (InlineTextEditor.vue, Widget.vue, PageViewer.vue, PageEditor.vue)
  • TipTap auto-generated table widths preventing fit-to-container — TipTap writes <table style="width: 422px"> based on summed colwidths; in narrow page-row columns this pinned the table beyond its container even with table-layout: fixed. The hydrator now strips that auto-style and rebuilds only from user-set data-table-width (markdownSerializer.js)

Removed

  • Organization name & contact email from telemetryorganizationName and contactEmail fields are no longer included in the telemetry payload sent to licenses.voxcloud.nl/api/telemetry/report. These were the only direct identifiers in an otherwise pseudonymous payload, so removing them brings telemetry closer to true anonymity. The fields had no functional purpose for telemetry — the license server doesn't use them — and no direct identifiers remain (TelemetryService.php)
  • "Your organization (optional)" admin settings section — Removed the corresponding UI section, Vue state, and GET/POST /api/settings endpoints from LicenseController. Pre-existing organization_name / contact_email config values remain in oc_appconfig on upgraded instances but are no longer read or transmitted; they can be cleaned up in a future migration (SupportSettings.vue, LicenseController.php, routes.php)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDR0XAuKJCLgbWV58zbVn9unXzIqAifDSrOYOGR04PcRtLR9ZDkgt/FbrI0HctxpnWmXD2zcV5pjYAu4Xc+m5OyWl+o9aMgKao4LZqyVkLiE6KeagdVonIEHbDd5wvNfSG9KXBWjcVu31jH831sBhodRmJ/ovY795C3q5cOFNYoLIGVHi278qa4r/wSqbsvULzu1vPEUpY3hukQn6XjzkRyh+gahUDmcU76xKeNL6f2pEdKkDKqFUN3TgBOJDaZYwJpy3tCwLRZNwFkLLoLy2XihULJxIlc800+zuIFlI3e1EfbhYtdBJXc449sJo7pIBHaHhF1vPU6eFgVmk+J8sPj1RoXiC7CRYNje41NOy0Bvkdx7QeB2O4ElH3huRnsS66oCrzcr+FJ1zRe8USai20NO8zfQifO0W5JR8Y1aWl/aKrzWIKtkZAYRptfMb4T+c0Sc9h1XPgfm5wK5D2eAJfnDgXJ3sUSfg8bf66tFQbvEmrbtG1n5C0X7j3i8jCL/7CqyWHpFbfCTsh4hmm6jnGSHVQvFoFwTcnbiLAamCMbkcRQ5DnaLMIXY/B5r2I2xzy8wEDhl4CJI8imIkjMTsFjrj8/UcTjQ1fL9bO5q8M4wfupSpPE62BIQcyvsKhfD+vfjRKegu3C60e52A9XtErd9sPUGFZNpXvz+DHGk6VHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.0
Release Details
UpdatedApril 21, 2026, 9:26 a.m.
Changelog

Added

  • Feed widget — New widget type for displaying external content on intranet pages. Supports RSS/Atom feeds and admin-configured connections to external systems (Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, and custom REST APIs). Features include: list and grid layouts (2-4 columns), configurable display options (image, date, excerpt, source, author), per-user OAuth2 personalization for LMS content, OIDC auto-connect for zero-click SSO, manual token fallback, 15-minute server-side caching, and public share support (FeedWidget.vue, FeedWidgetEditor.vue, FeedReaderService.php, FeedItem.vue)
  • Feed widget: connection presets — Administrators configure connections in Admin Settings using platform presets that auto-fill endpoint paths, auth methods, and response field mapping. Presets available for Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, and Custom REST API. Each preset supports platform-specific content types (e.g. News/Courses/Deadlines for LMS, Pages/Documents/Lists for SharePoint, Bugs/Recent/Created for Jira)
  • Feed widget: content type selection — Widget editors choose what content to display per connection type. LMS connections offer News/Announcements, My Courses, and Upcoming Deadlines. SharePoint offers Pages/News, Documents, and List items (with library/list selector). Jira offers project filtering and content types (bugs, recent, created). Content type selection happens in the widget editor, not admin settings
  • Feed widget: SharePoint integration — Full Microsoft Graph API integration via OAuth2 client_credentials flow. Automatic token acquisition and caching using tenant ID, client ID, and client secret. Supports SharePoint site ID resolution (hostname:/path: format), page/news listing, document libraries, and list items. Admin configures site URL + Entra ID credentials; editors choose content type and library in the widget
  • Feed widget: image proxy — Secure HMAC-signed image proxy bypasses Nextcloud CSP restrictions for feed images. Supports JPEG, PNG, GIF, WebP, AVIF, SVG (with sanitization via enshrined/svg-sanitize), and ICO. Daily signature rotation with yesterday grace window. All feed images (RSS, LMS, SharePoint, Jira) are proxied automatically (FeedReaderController.php, FeedReaderService.php)
  • Feed widget: OAuth2 account linking — Users can connect their personal LMS account via OAuth2 popup flow (Canvas, Moodle with local_oauth2 plugin, Brightspace). Connected users see personalized content from their own courses. Token refresh is automatic (LmsOAuthService.php, LmsOAuthController.php, LmsTokenService.php, OidcTokenBridge.php)
  • Feed widget: sort and filter — Feed items can be sorted by date or title (ascending/descending) and filtered by keyword. Filter searches in title, excerpt, and author (case-insensitive). Applied server-side after caching for instant response
  • Feed widget: custom request headers — REST API connections support configurable HTTP headers (key-value pairs). Enables Nextcloud OCS API integration (OCS-APIRequest: true) and other systems requiring custom headers
  • Feed widget: design principle — IntraVox focuses on organizational content (news, team updates, external feeds). Personal Nextcloud data (activities, notifications, recent files, Talk, Deck, Mail) belongs on the Nextcloud Dashboard. IntraVox does not duplicate Dashboard functionality. For organizational Nextcloud data from remote instances, use the REST API (custom) source type with OCS API endpoints
  • Calendar widget: external ICS feeds — Editors can add external ICS calendar URLs (e.g. from Moodle, Canvas, Brightspace) directly in the calendar widget. Events from these feeds are visible to all page visitors, including public share viewers. No Nextcloud Calendar subscription required per user. Supports up to 5 ICS feeds per widget with 30-minute caching (ExternalIcsService.php, CalendarWidgetEditor.vue)
  • Calendar widget: LMS event deep links — Clicking an external calendar event opens the event in the source LMS. Supports Canvas (native URL field), Brightspace (URL constructed from UID), and Moodle (URL constructed from UID). Unknown sources link to the feed domain
  • Feed widget: singleflight lock — Prevents thundering herd on cache expiry. When the feed cache expires, only the first request fetches from the external source; concurrent requests wait and read from the freshly populated cache. Uses a distributed lock with unique request ID verification (FeedReaderService.php)
  • Feed widget: circuit breaker — After 3 consecutive failures for a feed source, the circuit breaker opens and returns immediately with "temporarily unavailable". Resets automatically after 5 minutes or on first successful fetch. Prevents cascade failures from unstable external sources
  • Feed widget: background refresh — New FeedRefreshJob background job proactively refreshes configured feed connections every 10 minutes, before cache expiry. Users almost never trigger a cold fetch. Includes its own circuit breaker to skip failing sources
  • Feed widget: rate limitingUserRateThrottle(30/min) on authenticated feed endpoints, AnonRateThrottle(30/min) on public share feed endpoint (FeedReaderController.php)
  • Page metadata database index — New intravox_page_index table stores pre-indexed page metadata (title, uniqueId, path, language, status, modification time). Eliminates O(N) filesystem traversals for page listing, tree, and search operations. Updated automatically on page create/update/delete (PageIndexService.php, Version001300Date20260420000000.php)
  • Nextcloud search: index-first — The unified search provider (Ctrl+K) now queries the page metadata index for fast title-based results (~1ms), with fallback to full-text filesystem search for content matches (PageSearchProvider.php)
  • Distributed page tree cache — Page tree is cached in Redis/APCu (distributed) in addition to the existing in-process static cache. Shared across PHP processes/requests for ~70% reduction in tree response time. Invalidated automatically on page create/update/delete (PageService.php)
  • People widget: scalability guardrails — Hard cap of 5,000 users on the unscoped filter path to prevent OOM/timeout on large Nextcloud instances. Filter results cached in Redis/APCu for 1 hour. Batch status prefetching reduces API calls from N to 1 (UserService.php)
  • Rate limiting on mutating endpointsUserRateThrottle added to page create/delete (10/min), bulk operations (5/min), comments (20/min), reactions (30/min), and analytics tracking (60/min). Covers ApiController, BulkController, CommentController, AnalyticsController
  • GDPR user deletion handlerUserDeletedListener automatically cleans up analytics records, page locks, feed tokens, and LMS OAuth tokens when a Nextcloud user is deleted (UserDeletedListener.php, Application.php)
  • Audit logging — Administrative operations logged with IntraVox Audit: prefix for SIEM integration: bulk delete/move/update (with page IDs and user), license key changes, organization settings, engagement settings (BulkController.php, LicenseController.php, ApiController.php)
  • Health check endpointGET /apps/intravox/api/health returns app status and version for monitoring and orchestration (Kubernetes, uptime monitoring)
  • Scalability documentation — New SCALABILITY.md documenting all performance, caching, resilience, rate limiting, and enterprise features
  • Admin: connection test button — "Test connection" button on each feed connection card verifies credentials and endpoint by fetching a preview from the external API
  • Admin: connection export/import — Export all feed connections as JSON (without tokens/secrets). Import on another instance with duplicate detection and preview dialog
  • Admin: connection active/inactive toggle — Each connection has an NcCheckboxRadioSwitch toggle to temporarily disable it without deleting. Inactive connections show a specific message in widgets ("This connection is currently disabled by an administrator.") and are excluded from the widget editor dropdown. Re-enabling restores all widgets automatically — no reconfiguration needed. Toggle saves immediately
  • Admin: connection status badges — Connection cards show configuration status as text badges: "Configured" (green), "Not configured" (orange), "Token missing" (orange), "Credentials missing" (orange). Replaces the previous green/grey dots for better visibility
  • Admin: connection remove confirmation — Removing a feed connection shows a Nextcloud-style confirmation dialog instead of a browser prompt
  • Admin: Clean Start DELETE confirmation — Destructive "Clean Start" action now requires typing DELETE to confirm
  • Admin: orphaned data banner — Automatically detects orphaned data on admin panel load and shows a warning banner with link to Maintenance tab
  • Admin: advanced options collapse — Endpoint path, response mapping, and custom headers for custom REST API connections are behind an "Advanced options" toggle
  • Admin: column width warning — Shows a warning when the configured number of page columns may be too narrow for the available width, with a recommendation for fewer columns
  • Feed widget: error messages — Specific error messages for inactive connections, 404 (connection not found), 401 (authentication required), 403 (access denied), and 429 (rate limited) instead of generic "Could not load feed"

Changed

  • Feed widget: HTTP timeout reduced — Outbound HTTP timeout reduced from 10s to 5s to prevent PHP worker blocking when external sources are slow (FeedReaderService.php)
  • Bundle splitting — Enabled webpack splitChunks to separate vendor code (~2.9 MB) from application code (~220 KB). Main bundle reduced from 3.7 MB to 220 KB. Vendor chunk is shared between main and admin entry points and cached separately by browsers (webpack.config.js)
  • TipTap lazy-loaded — TipTap editor and all 8 extensions (~240 KB) are loaded dynamically via import() on first editor mount. Pages viewed in read-only mode never download the editor code (InlineTextEditor.vue)
  • Widget components lazy-loaded — All widget components (News, People, Calendar, Feed, Links, InlineTextEditor) loaded via defineAsyncComponent. Pages only download the widget types they actually use (Widget.vue)
  • Widget watchers debounced — Deep watchers on News, People, and Feed widgets debounced with 300ms delay to prevent API call bursts during editor configuration changes (NewsWidget.vue, PeopleWidget.vue, FeedWidget.vue)
  • Widget initial fetch deferred — News and Feed widgets use requestIdleCallback for initial data fetch, improving perceived page load performance
  • Page + lock fetch parallelized — Page content and lock status are now fetched in parallel via Promise.all instead of sequentially, eliminating ~100ms waterfall (App.vue)
  • Engagement settings cached — Engagement settings now use CacheService with 5-minute TTL, consistent with navigation and footer caching (App.vue)
  • News widget: collection limit — Recursive folder scan stops after collecting enough items (default: max(limit * 4, 200)) instead of scanning all folders before applying array_slice (PageService.php)
  • Tree components: progressive rendering — PageTreeItem and PageTreeSelectItem render max 50 children per node initially with a "Show more" button for additional items. Prevents DOM bloat with large page hierarchies (PageTreeItem.vue, PageTreeSelectItem.vue)
  • Navigation/footer HTTP caching — Added Cache-Control: private, max-age=300, must-revalidate and ETag headers to navigation and footer API responses, consistent with the existing feed API pattern (NavigationController.php, FooterController.php)
  • Feed widget: unified connection architecture — Replaced separate source types (Moodle, Canvas, Brightspace, REST API custom) with a single "Connection" concept. Editors choose RSS or Connection; the admin configures connections with presets (Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, Custom, plus LMS types). Presets auto-fill endpoint, auth method, and response mapping. LMS-specific logic (Moodle POST body auth, Canvas context_codes, Brightspace org unit) is preserved internally but hidden from the user. Backwards-compatible with existing connections
  • Calendar widget: IManager refactor — Replaced CalDavBackend with OCP\Calendar\IManager for fetching calendars. This properly handles both regular calendars and ICS subscriptions. Calendar identifiers changed from numeric IDs to string keys (CalendarService.php, CalendarController.php, PageService.php)
  • Calendar widget: hide ICS subscriptions from selector — Nextcloud ICS subscriptions are no longer shown in the calendar selector since external feeds are now managed via the dedicated ICS URL field
  • CSS theming compliance — Replaced non-standard --color-text-light with --color-text-maxcontrast in Feed and News widgets. Replaced hardcoded #fff/white with var(--color-primary-element-text). Replaced hardcoded border-radius values with NC variables. Standardized font-weight to 600 (NC convention). Dark theme backgrounds now use var(--color-primary-element-light) instead of hardcoded rgba values. Affects: FeedItem.vue, NewsItem.vue, CalendarWidget.vue, FeedWidgetEditor.vue

Fixed

  • Calendar widget wrong events shown — When an ICS subscription had the same numeric ID as a regular calendar, the widget showed events from the wrong calendar. Fixed by switching to unique string keys via IManager
  • REST API SSRF hardening — Connection base URL is now re-validated on every fetch request, not just at save time. Prevents SSRF if an admin account is compromised and a malicious URL is injected into stored connection config
  • Version restore not persisting — Restoring a page version appeared to work but reverted after a hard refresh. Root cause: the backend reused a stale file node after IVersionManager::rollback(), and the frontend masked the issue by showing a version preview instead of the actual restored page. Fixed by re-obtaining a fresh file node after rollback and clearing the version preview after restore
  • SSRF hardening: LMS connectors — Added validateUrl() with private IP range blocking to Moodle, Canvas, and Brightspace fetch methods. Previously only the generic REST API connector validated URLs at fetch time
  • SSRF hardening: ICS calendar feeds — Added private/reserved IP range blocking to ExternalIcsService::validateUrl(). Previously only enforced HTTPS without checking for internal network addresses
  • SSRF hardening: SharePoint & Jira — Added validateUrl() to resolveSharePointSiteId() and getJiraProjects() to block requests to private IP ranges
  • SSRF hardening: Confluence API importer — Added URL validation with private IP range blocking to the Confluence REST API importer's base URL
  • XXE hardening: Confluence importer — Added LIBXML_NONET flag to DOMDocument::loadXML() and loadHTML() in the Confluence Storage Format parser to prevent external entity resolution
  • Token handling: Jira project listing — Replaced direct admin token decryption with resolveToken() for consistent token resolution across all connector methods

Security

  • CSP hardened — Removed unsafe-eval from Content Security Policy. The Vue 3 runtime-only build and TipTap editor do not require eval(). This was a historical precaution that is no longer needed (PageController.php)
  • HMAC key hardened — Image proxy signature key now uses hash('sha256', ...) for proper 256-bit key derivation instead of string concatenation (FeedReaderService.php)
  • API response size limit — External API responses larger than 10 MB are rejected before JSON parsing to prevent out-of-memory conditions (FeedReaderService.php)

Accessibility

  • Feed widget aria-live — Loading and content states announced to screen readers via aria-live="polite" and role="status" (FeedWidget.vue)
  • Feed item semantics — Removed conflicting role="article" from feed item <a> tags. Added focus-visible outline for keyboard navigation (FeedItem.vue)
  • Admin loading spinners — All loading spinners in admin settings now have role="status" and aria-label="Loading" for screen reader users (AdminSettings.vue)
  • Connection card keyboard nav — Feed connection expand/collapse headers are keyboard-accessible with tabindex, role="button", aria-expanded, and Enter/Space handlers (AdminSettings.vue)
  • Status dot contrast — Disconnected connection status indicator has a visible border for better contrast on light backgrounds (AdminSettings.vue)

Documentation

  • New SCALABILITY.md — Comprehensive guide to performance, caching, resilience, rate limiting, GDPR, and enterprise features
  • Updated ARCHITECTURE.md with scalability section
  • Updated SECURITY.md with CSP, rate limiting, GDPR, audit logging, and feed widget security sections
  • Updated ADMIN_GUIDE.md with health check and audit log sections
  • Updated ADMIN_SETTINGS.md with connection testing, export/import, enabling/disabling connections, Clean Start confirmation, and advanced options collapse
  • Updated FEED_WIDGET.md with RSS example screenshot, SharePoint setup guide (Entra ID app registration), content type selection, error messages table, and screenshots for all connection types
  • Updated ACCESSIBILITY.md with feed widget and admin panel accessibility improvements
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLc6iFEUpymkn2oOpihHrtxmTjKYFZWKcuvfBrf1Xr3us6SzOBhArJpj7t5GHUekRY6sJiuf47lqIDbjzf9fby51vse5bF+n1/QHXdApMDmsxo6EhtM5e3VRWje9A+ZuT2W+Xspdu1owszLqJfQw3TMBFmtAF2QNLAxTU6X8BOwc2Px6MUJnD+aNrOaE4117bBqSv27JihzvyHoz21ey+kZK+vrXaZoXrLzKkf69mPYKMEiVuyKaueTLhuRcihJPZAuVC+ClgZVTueZGDmNQA39xfL9Puy5JpbQx6+7MSL6FKhoN4bXD3ve3DloPsIC35KF+gpH/T8hY6f3vWQgX5mGh5mQSJLHTTkYulKiDcXRq82cDg/o2tpw7D6Uu3R/wVafqGrndtl8A5/okhCHGJnwh7FdG3vzoMFMLdEM03Zlk4W5hiVio5fd1Wy0LVM6SaGM81S9+TrOV0S35vuONStfe56e17wDC9DVaznDTQJW7E7qj4eihX/r0sVD0qQzYoIQ7PvnJ5XNAobWh28TA0eXwOnTwlOSsFhHxBLyt/DJE2CYoEz8YYBNnBgTGthYVKPp/grlWfFGNrRygNOYYMbMSmVqZQ/8liz1OrMcFwC0DoW/IVtmaB8PIGYs7XO8D8IBYRVpklTlQpgFrEf8PpD/8rfnp04VGlWCb/E9tR9x4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.2.0
Release Details
UpdatedApril 16, 2026, 10:48 a.m.
Changelog

Fixed

  • People widget filter persistence — Filters using the "does not contain" operator were silently converted to "equals" on save because not_contains was missing from the backend operator whitelist. After a page refresh the filter showed different results. The operator is now correctly preserved
  • People widget filter value encoding — Filter values containing special characters (&, <, >, quotes) were HTML-encoded on save via htmlspecialchars(), causing them to no longer match user profile data (e.g., "R&D" became "R&D"). Filter values now use a dedicated sanitizeFilterValue() that strips tags and control characters without HTML-encoding. Existing corrupted values are automatically decoded on read
  • Editor contrast on colored rows — Column labels, placeholder text ("Enter text..."), column borders, and "Add Widget" buttons now adapt to dark row backgrounds (Primary color). Previously these elements were nearly invisible on dark backgrounds

Added

  • Skip-to-content link — Keyboard users can skip past the navigation to reach the main content directly (App.vue, PublicPageView.vue)
  • Semantic landmarks<header>, <main> elements replace generic <div> wrappers for better screen reader navigation
  • ARIA tab patterns — Proper role="tablist/tab/tabpanel" with aria-selected on NewPageModal and MediaPicker tab interfaces
  • ARIA combobox pattern — PageTreeSelect now announces as a combobox with aria-expanded and role="listbox" on the dropdown
  • Carousel accessibility — News carousel has role="region", aria-roledescription, aria-label, aria-live="polite" for slide announcements, and respects prefers-reduced-motion
  • Live regions — Loading states use role="status" with aria-live="polite", error states use role="alert" (App.vue, PublicPageView.vue, CalendarWidget.vue)
  • Focus-visible styles — Global *:focus-visible outline for keyboard navigation visibility
  • Reduced motion support — Global prefers-reduced-motion media query disables all CSS animations and transitions. Carousel autoplay is skipped when the user prefers reduced motion
  • Visually-hidden utility class.visually-hidden CSS class for screen reader-only content
  • Breadcrumb current pagearia-current="page" marks the active page in breadcrumb navigation
  • Accessibility documentation — New ACCESSIBILITY.md documenting WCAG 2.1 AA compliance status, legal framework (Wet Digitale Overheid), and implemented measures

Changed

  • Form labels associated with inputs — All form inputs across 15+ components now have programmatically associated labels via for/id pairs or aria-label attributes (WidgetEditor, NewPageModal, PageTreeSelect, CommentSection, MediaPicker, AdminSettings, PageEditor, NewsWidgetEditor, PeopleWidgetEditor, CalendarWidgetEditor, LinksEditor, NavigationEditor, PublicPageView)
  • Icon buttons accessible — All icon-only buttons in InlineTextEditor toolbar, carousel navigation, MediaPicker, and AdminSettings now have aria-label attributes
  • Draft badge contrast improved — Fallback text color darkened from #856404 to #6d5003 for a 5.5:1 contrast ratio (WCAG AA requires 4.5:1)
  • Dropdown accessibility — Navigation dropdowns have aria-haspopup and aria-expanded attributes
  • WelcomeScreen heading — Changed from <h1> to <h2> to prevent duplicate h1 on the page
  • Password error announced — Public page password error message has role="alert" for screen reader announcement
  • MediaPicker strings translated — All hardcoded English strings wrapped in t() translation function

Fixed

  • Focus anti-pattern removed — Removed event.target.blur() in Navigation.vue that was stripping keyboard focus after clicking the page structure button

Documentation

  • Added ACCESSIBILITY.md with full WCAG 2.1 AA compliance matrix
  • Added accessibility link to README documentation section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWi2Kezb67KRxkFi/zRvjUrCCpNNRc2DBOWtuhOITpNScggVnaSiP+zLGO3s+/fPnKmgGrFoPeSuTSQifpEA37aQrwWx1comrLRq6k9SG+4+VhgAxVjvYdha0fqhah0HDjsgfC1cLhOBExqudxnijKEf+NCGgZqf1tHFnLtUbM1Z+x5o0CjAjv47c8Qrz/LD5NTvDcmU2vkkePA4nNjMheGuxC70rmwceaXaoA2CRf9BZ2XQsI8AgE9yoTEFvdWVdpN/BR+DKoAQya6XBZitrAp1jvH3okVMMap+XDBJrhD8mfBC/9eEn4Q/UW1Xc/m3WnCMVy5MiuY3Jv0b9pl+BghH8elxTjsZZRQJ7riGX1k9e/I3hjl4GZKO96USxGi5tDoWWtq/dKLddmrzy00o0cBMuKaAJ/sFal+OyZg++OWO7Zi0sxeL12T2OaojmJ4u22sZmgaZi+Tl5naidjOE9cz3Tv41C7IIAKpW4j1Xrj7L2D9vA5C7rKH/7vIbY/iLWnIY0df5BDs7NsccnftNNLXGA24PjtN7C21SoLbSHA2hDk81Lq3QohMyCod13UkcCO4/OjKFH523IEmLnzxujA+YXNxnfEvaEW66AQn56pDKgBN0tmLKjMBd8hIAEBzpBP67buSytYIj3XjoRtR9rMHq1W125eljViPQlVVd0vTM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.2
Release Details
UpdatedApril 10, 2026, 10:41 a.m.
Changelog

Fixed

  • Telemetry error feedback: The "Send report now" button now shows the actual server error message (e.g., rate limit, connectivity issue) instead of silently failing
  • MetaVox icon dynamic loaded — MetaVox sidebar tab icon is no longer a hardcoded SVG copy. Now loads dynamically from the MetaVox app via imagePath('metavox', 'app.svg'), so logo changes in MetaVox are automatically reflected in IntraVox. Dark mode handled by Nextcloud's automatic app-dark.svg serving

Changed

  • App Store description rewritten — Expanded from ~150 to ~250 words, structured in 6 sections: page editor, widgets, collaboration, content management, enterprise, and requirements
  • App Store summary — Changed to "SharePoint-style intranet pages for Nextcloud — no code required"
  • Author updated to VoxCloud — Author name, email (info@voxcloud.nl), and homepage (voxcloud.nl) now reflect VoxCloud branding
  • Screenshots expanded from 3 to 7 — Added calendar widget, people widget, news carousel, templates, and engagement screenshots
  • Category social added — Reflects engagement features (reactions, comments, people widget)

Added

  • Documentation links in App Store — Editor Guide, Admin Guide, and API Development Guide now linked from the app listing

Security

  • axios upgraded to 1.15.0+ — Fixes critical SSRF vulnerability via NO_PROXY hostname normalization bypass (GHSA-3p68-rc4w-qgx5)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturedEPa13irIrVkzszfHig0ZkpEhHIKNvbSxRdMHeALc3YGKW3H/pXgEyzlSiOgTRlYG9JwD6bAo8ANVhK9tBaIMr5nzOO0JrgExrnHniBe4LtGgJ2xbE1TeVVKEnlgcmwi8SG60ueKvIJU/x/Vy2yIJJGe/ShTntep5qiwGJBe8QksUTojfPiDaqDXzcgVRyYhbvIuT44/TF5oohBzbLLHvXm5bhcbUP6WyWz2KsTF7sgMtkKmClOiY/vZYVG2QaK87+QbwBwnW5icirect8ZzPzxSHqsg3LJdP4InayQhs21ZSm6rdrmBhT8Z36OJv9Mu2Dzdvl5cbqalUJbLs5ILHh/i4LKcIgt5fd9yvPHrtH7DNKQHeYMdH6x9saOq6zDC/g71N2zb1klXypSNpnkb/Ki9ZniJd0AQq2vxj4i0rguZZSM2HyMgnQnmAUU/HHbZGExGVQ6qqZl2xdVp3PZMZiQKJvIoVFqev4CbHr1Mite0cy2aYcb8iGnAdGYBL8Q2YahPyL3+dgHmi6/ywY3pmo9w+4O+JDggH3O7Mt2rlgbEQAaR0qLafrRU0yTB54Xyk7CNQE4kV1oGzl+wIO0LBBpDnuQAqenvuh7ac4W3kil3fbjVs9lk3JiH9q0Wb9gQ50ZE9T00RM/VhSDacfnmghY1udXhgAThMrNXeOjQ3m0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.1
Release Details
UpdatedApril 8, 2026, 11:53 a.m.
Changelog

Added

  • Support contact settings — New admin settings section for configuring organization name and support contact details. Contact information is included in telemetry for easier support identification
  • App Store screenshots — Added calendar widget screenshots (layout, editor, primary, sidebar) and updated admin demo data and edit mode screenshots

Changed

  • Contact info updated — Author email changed to info@voxcloud.nl and website URL to voxcloud.nl
  • Admin settings refactored — Extracted support/contact settings into dedicated SupportSettings component for cleaner code organization

Security

  • serialize-javascript upgraded to 7.0.5 — Fixes excessive CPU usage vulnerability in array-like object serialization during webpack build process (#42)
  • brace-expansion upgraded to 5.0.5 — Fixes bracket handling vulnerability (#40)

Fixed

  • Demo data imports all languages — Demo data setup now detects the single active language and imports only that language's content, instead of importing all available languages regardless of configuration
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureaKR0xRRjvews2FOdXJ446XMnOvUrRh3oPx3N7dR/TGujbDnjFFXwF8qC7wXo9CrwLD164arXII26lxxH509xmimeAfARht3+m5iFU8X2UdeWfszCJtuf2TilPEp+3ZDcgKOpN3o9dkcas6hV7rYfsqVJTkLAPqvAhOA3lRQOM70SKV8P5Jo3wSKHiXocbdsk094u2jd640LIR3EFfkdCrzxQJ9KetiH3w+h135bz1qwU8/eceKTH+O9aHYtphsbfFqRvZzMqnZ3qEABfWzSdOMgkvSIrpYZDWy20aPi1vagdi9VtLBzuzVNvmzjLKcCu3HNdJ2mrITGFykR1JM+EKG5AmdoIovqjunLgwpoCQCmLYnvhLegYfsIz1MbG0mgfJ1ZeHwW/DI/9usLGtlNOwRqJjaL9WIgT2zk4wPkG0P0N8f+i/S4limsWXHilNlqj7nZJWQftBm+UoecxZ4hewwGbQZZIGdBDIFkbKV3JPsnN8y6OXohEIAWXfgy66SXM5n2KdYVlFAiMyAcIPWkab+ZjB/o+jrpkGuC/9+eJ0fTd8LAwSKzupt4hTCqmmru5t2Or/6YSEZxl3LlghWtC3ivSefxvqLuKy95vPVmT+ylOPohgmzUxPzlOHHcOp/N9YIP3YSWwMZ2cDbvAI4PeZD3UjHpnhm3t9q8lHOrygyk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.0
Release Details
UpdatedMarch 29, 2026, 7:49 a.m.
Changelog

Added

  • Calendar widget — New widget that displays upcoming events from shared Nextcloud calendars. Supports multi-calendar selection (merged view), configurable date range, event limit, and show/hide time and location. Events are shown with colored date badges matching the calendar color. Recurring events (RRULE) are correctly expanded into individual occurrences
  • Responsive calendar layout — Calendar widget automatically adapts to available space: 1 column in side columns, 2 columns in medium containers, 3 columns in wide content areas (via CSS container queries)

Fixed

  • People widget users lost on reload — User IDs containing dots, @ signs, or spaces (common in LDAP/SAML/OIDC environments) were silently stripped during save, causing selected users to disappear after page reload (#41)
  • Deploy script OPcache — Added Apache/PHP-FPM restart to deploy script to clear OPcache after deploying new PHP controllers

Security

  • Rate limiting on public People API — Added AnonRateThrottle to the public share endpoint for the People widget to prevent user enumeration

Documentation

  • Language & demo data — Added guidance that Nextcloud language setting must match the imported demo data language. Added troubleshooting entry for "Admin sees empty Welcome page after demo import" (#37)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureZBIZ5aIC0Jf+cgyuNd3xYfy7lZbE7fbg38Xem2/zEuWkI5PWOSY/WmCebThcm9NHRdFJIL74zHRIUbfE2XaicmcqwgSZozNcUeUG8kpK5elRhLYJXPdPZMAN1LpKiPlrz3951koLc2f0LNpTvOBvsXgk0Fjlsj/NRmYcn6Oy224uzlYrkwpwBn8UDRA6CBC8qJLG+TYF4/VnIfJLEomG01HV9Ar2TGb+dDUobWPWAgfXfkdNtrc7gfLPipGlAs8enaBWbEhLQi/qRVfU2W1azSTYzFgl1rwBMnFG5V9g8ymkZpakbioOnL074u9JUYwBIcXGSq+7w9oKo5LFmzidPmSALp8B12aM+lAElH/vBKlHBYSoDv3A/KoqWfXW5BZvXQXmtFa043vK0kHD5M0PARFfvPN7xkVXUYoQX5o9Ptre/I+UkINXO6FX7X4KepWM57WFVidCOMwwCl9e6b5UQdt6aeYSl1qoAnBNQgAxtYm2QgRJa9FyDEl4+yup+bBwrYU8URBCQJk6GTbAFaA5397wE12N3OLpwoiIx3g7ZBP+ppRmO1eb1SDGN9tJWa5AKgEg7CBnBaV5YNtWRlmoUfsgfCt1b039Dca7fEVcL523m5zgmxqkiCbO70fwlTdhoe00hQpcZomfmEP6wB7FftWIqMR63Ndw+7WmoGIouhM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.1
Release Details
UpdatedMarch 9, 2026, 3:12 p.m.
Changelog

Added

  • IntraVox Editors group — A third permission group (IntraVox Editors) is now automatically created during setup with Read + Write + Create permissions. This provides a three-tier permission model out of the box: Users (read), Editors (read/write/create), Admins (full access)
  • Scenarios documentation — New SCENARIOS.md guide with step-by-step recipes for content approval workflows (using the Nextcloud Approval app and MetaVox) and department-based intranets

Documentation

  • Updated ADMIN_GUIDE, AUTHORIZATION, EDITOR_GUIDE, and README to reflect the new three-group permission model
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQuql4/Qdcw6lDxelq5UHCLVmlFf7+6YjcNPpfIDS+ynsrL+9QbyGsGQyx8fZdisovKtKJODYvfEou6EmcdD8l14mvBc4P6v6PZwzRmgP3qGMG4fYX0lFfniULGs8YGtKVGtgqilJ1gLnHQrO4qIxQqvvNGtTKmr8N3GehbHprT/tTzgPTlhmIHPIjKrw6q5m380WyUBhq9Hw9o16MekCX5obAshT2pwQuQvkmEYuprV4wr3dFOqKC5vM04yd1x6s2y72ZLcCC4YDPRoMP75vClpQaaScIYwVoulnFlLqOZUw/qlywWttwMAalDJkRPmC3E08xlOup4RwZkGSdu9jv5ESDemPoxvtV4alDMkf/qECW8KZkjTEX89MuYfFLK7POiH68qJllpAooquc71PAdN/YmTtKPplKBKqiJwWReAgDK4dZdls1komf17vcn+usYsJhzVT5Jarp8jjT0aQpBFAUDIuEJmeF0nzI/Q0xV1bMeCs/j2yjDdSIJPLHr27uk68Tb+gBQbhYdpPR6sYxLT2DT3xbbvq9z3RPlowcO3/kvN71ojGEx6xPGOsISJbRDpg4v3ixzVaKa9nUurb44Hsp7E1GsF19ARAlEquCuJxkCXONHc4jjW0pPGUxyBAt5V4kvWqRhS9Whl1JjSWOd7X30GvShRSWwWu59BiaTpI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.0
Release Details
UpdatedMarch 8, 2026, 10:37 a.m.
Changelog

IntraVox 1.0 marks the first stable release. After 19 iterative releases, the app offers a complete intranet platform: a full page builder with 10+ widget types, page versioning, templates, public sharing, RSS feeds, engagement (reactions & comments), draft/published workflow, concurrent edit protection, and multi-language support. The JSON page format and REST API are considered stable from this version onward.

Added

  • Page locking — Pessimistic locking prevents concurrent edits. When a user starts editing a page, other users see who is editing and the Edit button is disabled. Locks auto-expire after 15 minutes of inactivity, with a 60-second heartbeat to keep active sessions alive. Locks are released on save, cancel, navigation, and tab close
  • Lock safety net in API — Backend updatePage() rejects saves with HTTP 409 if the page is locked by another user, preventing data loss even if the frontend check is bypassed
  • Force unlock for admins — IntraVox Admins can force-release a page lock held by another user (e.g. after a browser crash). Includes confirmation dialog to warn about potential unsaved changes
  • Draft pages (#32) — Pages can be saved as "Draft" or "Published". Draft pages are only visible to users with write permission and are hidden from read-only users, public shares, search results, RSS feeds, and the page tree. Editors see a clickable status badge in edit mode to toggle between Draft and Published, and a "Draft" indicator in view mode. Backward compatible: existing pages without a status field default to Published
  • Duplicate row (#32) — Editors can duplicate a complete row (including all columns and widgets) with a single click. The duplicate button appears in the row controls next to the delete button
  • Sticky edit toolbar (#32) — The header toolbar with Save/Cancel buttons stays fixed at the top of the viewport when scrolling, making it accessible on long pages

Changed

  • Page lock translations — Lock-related UI strings translated to English, Dutch, German, and French
  • Draft/duplicate translations — Draft, Published, and Duplicate row strings translated to English, Dutch, German, and French
  • New pages default to Draft — Newly created pages (both blank and from template) start as Draft and automatically open in edit mode so editors can begin working immediately

Fixed

  • Links widget tile overflow — Tiles in narrow containers (sidebar, small columns) no longer shrink to unreadable vertical text. Tiles auto-wrap to the next row when there isn't enough horizontal space, while respecting the configured column count when space allows

Documentation

  • Editor guide — Added sections for sticky toolbar, page locking, draft/published status with visibility table, duplicate rows, and updated creating new pages workflow
  • Admin guide — Added page locking and draft pages sections, updated security considerations
  • README — Added page editor features (duplicate rows, sticky toolbar, page locking, draft/published), new feature sections with screenshots, updated security section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureiNaCstuvlWhKDNWHxOI3UH2urSyZ8OZCmlMAvQHWW8FDbfo3gBmHCD7ofk/6G78se/+9K8bLaSPMd0f3n3enR62K0ZG0jj5TP4eVvIsVYpVlLdzZlV64fJRcFSUotMFaluWlflLPKhuJbPJTCLivaYwzxX8QhfG7f9SUgZcsb/YZrCU0exRzekrFevLtHNsVE5aj7UWGg3lQh/zYZ28tlpsoWUPCJ2dT4qQ56kFO6IYvc4Wmf2diEzLLye1XaVpLaBbldRfDt2b4siu3uUMPePJHij6EDYL1dQAPuYAa12slvrh9TTRlffbtU1ny3b+1t9yLAVBiE6NEFccX7S/P5pmEPNmoeCECIv8lTyw8GJUeRNT+VdmlOZporvVXn4CWhW4aaQW+qVMLUrKrQ4Ond/ZYmVyVR4TjKiGZr04hr/xIdj0FDPffqe3SiLS5DJ4g3P+q3CCI7vktKlIdOrgpyHFavOfTq9IT2MT94UfJFob8L34g+yDsfdyQdYC2hQTXZsQUJ9TS72pzUC4c52Y4gomtLyUh4E7xOv8hAiGiKvaCDlcQJD7jE95LKw+EEwMvXrDMfhgn8hHMg9JxzSapRggu59B5Butz83jVNRnTWht9gaGu3nlpvMnNoE0YdFyU2c1yj0w5DoB7VmKd+4+1S32aO97qba7DCBpqrdQYc8o=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.18
Release Details
UpdatedMarch 7, 2026, 11:51 a.m.
Changelog

Added

  • Spacer widget rendering - Spacer widget now renders correctly in view mode with configurable height (10-200px). Previously fell through to "Unknown Widget Type" error display
  • Links widget tiles layout - Links widget now supports a tiles layout alongside the existing list layout. Tiles display a larger icon (36px) with a separate title and subtitle on two lines, creating a card-style presentation. Editors can switch between layouts and set title/subtitle per link in tile mode
  • 30+ extra link icons - Added icons for common intranet use cases: folders, chat, dashboard, contacts, forms, code, support, security, organization, news, and more
  • 5 unique demo showcases with rich, diverse layouts demonstrating all widget types:
  • de-linden (Universiteit) — 4 photos, 1/2/3/4-column rows, video, people grid, SURF services, right sidebar
  • van-der-berg (Advocatenkantoor) — 3 photos, header row, news grid, file widgets, no sidebars
  • gemeente-duin (Gemeente) — 3 photos, 1/2/3/5-column rows, left sidebar, news list
  • de-bron (Zorggroep) — 3 photos, 4-column department overview, people cards, video, file widgets, right sidebar
  • horizon-labs (Tech startup) — 2 photos, news carousel, culture row, right sidebar

Documentation

  • Showcases guide (SHOWCASES.md) — Complete documentation of all 5 showcases: widget coverage matrix, technical structure, background color guidelines, image handling, and people widget portability
  • Editor guide updated — Added documentation for file, spacer, news, and people widgets; updated column support from 1-3 to 1-5; documented collapsible rows, header rows, and side columns
  • Export/import updated — Widget types list expanded from 6 to 10 (added links, file, news, people)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCnOojEkcaYY3IrqfW3cj9gDhgOnlVkTd+sZpTFow4jh1pH+IrZ1NgXRjGgIKZiQtdvlh3AqgHdEE7kWidNvVTps4SL79TTLcQlO+aT223Sf9OOMC+GQsGkxUVKVY1d456mupVrZyslUCopbxr4Rf2aYxfsm3GFdMxPFGByXWE4VkJztuo8UI4krp2rfVRcBbv2m8RWd2w+1mAlkOiRK7176eS+d4jHn0h6Kslde5E/E4DfGML8uUyyu5yACJ/MMkUcJ+wxLvu2esOM5oPkbMrAHpWCa5TRzqVtbpoplcmDq4pYVw84AXc/+V91HduZOVLHgzWXhkV6O0qXjsWgsDfAPiZ1t9EWFuUMuV0EY2WbIxdo5eBSQsDaG4R60JKVlUvbx07OXecWG80VRslsngbXbTtvWV/AwHGWN60MufTQbEU8+cw3tIBD5RAlXwcnIVDHawBvasxQ7wlWU5/B8BZZkEDGdQMBlXTQE45+FVEbwXOaaQPD8s7cde2zCGk7Ze4MfIqZDyD5cBuszuVf5ljCpm8BQvt4oBGRPX9C0K8TB+l3vp6XzuMOvxixdIES9E20e9LYn1Yve0tTf3PzBQgUvPM4eYjXHD3U24w/0PNPNrBtLzg0uePqmm01dHBkVTqQC4CdmLD/cRG7GIH8bVBey+9XsftagMXH2LGuz8NS8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.16
Release Details
UpdatedFeb. 25, 2026, 1:50 p.m.
Changelog

Added

  • RSS feed - Personal RSS feed for each user with token-based authentication, feed media endpoint, conditional requests (ETag/Last-Modified), and brute force protection
  • RSS feed settings UI - Generate, regenerate, and revoke feed tokens with configurable scope (my language / all languages) and item limit
  • RSS feed sharing policy - Feed respects Nextcloud's "Allow users to share via link" admin setting; shows clear error when disabled
  • RSS feed cross-language links - Feed items link via #page-{uniqueId} format, automatically resolving pages across language folders

Changed

  • Dummy text generator - Removed =dad() alias, only =dadjokes() and =lorem() are now supported
  • =lorem() rich formatting - Now generates richly formatted content showcasing all text widget capabilities: headings, blockquotes, bullet lists, tables, ordered lists, and mixed inline marks (bold, italic, code, underline, strikethrough)
  • Dummy text multilingual labels - =lorem() section headings, table columns, and status labels are now localized for EN, NL, DE, and FR
  • Documentation - Added RSS feed admin setup guide with GroupFolder permission requirements (Read + Share), ACL examples, and troubleshooting

Fixed

  • People widget "Invalid Date" - Birthdate now correctly displayed regardless of Nextcloud locale settings. Added backend normalization of locale-specific date formats (DD-MM-YYYY, DD/MM/YYYY, DD.MM.YYYY) to ISO 8601 before sending to frontend, with additional frontend fallback for edge cases
  • RSS feed empty for ACL users - Documented that GroupFolders requires both Read and Share permissions for public feed endpoints; updated all permission tables and recommendations
  • Webpack build failure - Added string_decoder and buffer to webpack resolve.fallback to fix build error caused by @nextcloud/dialogs 7.3.0 pulling in Node.js core modules via sax/is-svg
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLkqXT+TE7U884io7bEDmL/gZLvaShUTg97nU7qIjNMBXEkd4nqo9nooA8+Y8qLUQEIjP1wFkw2p/TMduDHbWgZcPe+SIDuvfyQhqSlO5aeD8Q+pW+KmGAy0XbbQlVX6neiqaNGhD8TpCdnIStIHuPkjRngBSOuXf4JjeV3DNM2QKlck2at1svnElJOWujwLerTqWVGWQEaXSBvn0YGAHiLorgKXVitgZRMOxviUeSTxdWtwNsJ3vVIZ+mr+4UllElQh1jLgnePi2xa3DXs3b+r9CqebhIIQ2Brt8r0U2l3W5LIsjZJtf+/PHf9ytfAag51+XHLb/xMEZx9NDxakeGZlDPdQ652np7z7jgUxwE/wASSpVJ4LePTzwoBrdg4EDocI114Gtz0vqJGoTOJBHxZEovydDEXjOZSJcnLvzpfs1nkQBQYUvQGzSVti+0W64vSCh/I53o/U7GRYmCL03pYbNYZ9S2nk32usjfFizVbpGvKFrA5crLqxBns5Yb6bYY5QNtZtqHJiobkijwP19esHX6eCNLIKvI6aozaMtpawOQ/IDCDdJFI7N1+QFcoMgUsbbpfBXhImJ1I3LjWOjbzl+ZQ4d6CrHC1Gmd/KohKuvx5ER7RmgvLIhpgEEAKvdpFxgBc2gnQeVwTLUOBlzjJhS+I+7ggkrmX7+5HarwP0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.15
Release Details
UpdatedFeb. 19, 2026, 6:35 a.m.
Changelog

Fixed

  • MetaVox sidebar on NC33 - MetaVox metadata tab now works in IntraVox on Nextcloud 33, where MetaVox registers via the new scoped globals API instead of the legacy OCA.Files.Sidebar API
  • MetaVox mock Node object now passes correct mountType and mountPoint attributes (camelCase) so groupfolder detection works properly
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signatured13CndlYRWziam4mAOeDoHdjExboNyPiyFqfTRdrqRtcJkWVhRE0vN7wCEpWqUZaAni+r5JOpmwhpD7ePTFB8j77sIMq2K2ahdeGOVhnRrhQ3Qk055iXrnxzm3lvwaaerShVPa9D5fga3auYwpcuJxW4NDj36QvCwybkhwzJx381shlVjGyuZKQFJJWn3d3ZAzC2u1El8OlLIeBEDeszJizpa3EBEGdftZ7sfqkem+UMU9jWOGrXMwkYsauDhp+0mW6TNb7lDV84gZUKoE9lAYYLTPzFU5VWDA2mtvV6h09kwtZrXfkMxoh+S/qAcFkP9gwXFHKZKCDs3Z/HGTqeDxrbW6EM5sboYLOS7+VQapwes/UsGRO3XO9jzo5cfe4+c6fy32mjgwyhskSBm5UYdpYANsRgvOj0D9GQFNLYSuktoHaV0lq7BAtroDDk7B09k/422Eia0taM9PuoTmbMZ97yhgYZpEyJMLVx4nTMu30zXXkw0fkF3KfF0vZMnsOaAgYfQWXzChqpOlvemmz7bx/Ew7Murqz5ytaXfZvQ09WtWEV4l1b4AdCaf1ow/+w+V5BtXM/tCvaUmjQtdK+mf70ptdCr/+crxjhytihIm+NFMZSB/FMNlOKGcM3J0wz/kcBJ6tCLAcCIjzaf9p+42yUo8bgi+WzJTNp0r6EZSLA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.14
Release Details
UpdatedFeb. 18, 2026, 2:07 p.m.
Changelog

Added

  • Nextcloud 33 support - App now supports Nextcloud 32 and 33 (PHP 8.2+ required)
  • Page nesting depth increased from 3 to 5 levels for deeper page hierarchies
  • Dummy text generator (easter egg) - Type =dad(), =dadjokes(3,5), or =lorem(2,4) in a text widget and press Enter to generate dummy content (inspired by MS Word's =rand())
  • Birthdate field support in People widget - display, filter (is_today, within_next_days)
  • Bluesky social link support in People widget
  • Date filter operators for People widget: is today, within next X days

Fixed

  • People widget display options now correctly control rendered fields in grid layout
  • Removed gridShowFields override that forced fields off
  • Removed hardcoded layout !== 'grid' template restrictions
  • Removed CSS rule that hid headline in grid layout
  • showFields is now the single source of truth across all layouts
  • All display option checkboxes now always visible in editor (no longer hidden per layout)
  • showFields whitelist expanded in backend (PageService.php) to support all 15 field types
  • Legacy title field synced with role for backwards compatibility
  • Heading widget bottom spacing increased
  • Comment cascade delete now properly deletes replies and updates count
  • Security: markdown-it updated to 14.1.1 (ReDoS fix in linkify inline rule)
  • Security: ajv updated to 8.18.0 (CVE-2025-69873 ReDoS fix)

Changed

  • Twitter links now point to x.com instead of twitter.com
  • Dependency updates: axios 1.13.5, qs 6.14.2, webpack 5.105.0, ajv 8.18.0
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureKx4wBbCHSaA+wD5HWQ0/arQjdIOdtmxLwRYyh1GhcBKDiUVrfNUoFlOreUrs/FPv6heMXFD8XdJcVn6XXxPZzSOAYVCnKaIGGYea4RfsTlCbrShkasX2TxQ/1Kn1vH2QM+qe0aNdZstYv1QxhFgQyb82tWreFTuhisKgndvWqE5LouHSIDzamgr+iKmEoxf/LvCbPt4UvWc8nQdCc+XdnDa7WzMrjAB1xu5tHXE3coFmEqAWUwdMpp+vR9YanFLjC8CKfJEl+S4qL0DhDviXXUzjlOmIEttrXwRI1nv5rLg+Ucy1fBdZPUmMLXqgh7eUTWCSAlTVsTPYMvdhNQAZMWpioKf7X7pZcbp9JvcmbTZ6+VJVIT8tGGJROwpx/Z8v1fN3e5Gcv+pSq0yHpKM43v2S8LSa+Z5HB7BIV5GeUCmSIGfrWYEJvXYhpHtyHJrdVYfH2YuYbqkAH5bKuURwKQdJ0Y6A9v/gpEdwso44dNpPh0CY2uaGk/FwrJs1IYYmCI59OqF6l1/ffo9l/jR+PA5Jh3nns9lUR+hhfTJ25hF3+xhYdQV818Acbnl24c59rugq7+hX++cVn/b8VXen5WIUdVK4nl8eHNSYYVJoRLoz0PqhEVitwSF9k6zU+6/kSWIe2UiEwiOALXTSS89q+TVRT1J1oX1L//SPTg0b988=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0

Nextcloud 32

IntraVox 1.9.7
Release Details
UpdatedAug. 7, 2026, 8:25 p.m.
Changelog

Fixed

  • Uploading a photo failed with "Upload failed: page not found", on a page that was open in front of you. Adding a Photo widget and choosing an image appeared to work, and then saving the page reported that the page did not exist. Images placed in the resource folder through Files showed up in the Shared Library as a filename and a size with no preview, and stayed blank when selected. Saving the page first made no difference. (#92)

This is the same read/write split that #90 fixed for pages in 1.9.6, in the one place that fix did not reach: media. A page's images live next to the page, but IntraVox looked for them in a language folder chosen for you — your Nextcloud display language when uploading, the language you are shown when listing. Whenever those differed from the language the page itself is written in, every media operation searched the wrong folder: uploads reported the page missing, the Shared Library came back empty so previews had nothing to load, and thumbnails answered 404.

The permission check on the very same request had already found the page correctly, which is why the failure looked so contradictory — permission granted, then "page not found" for the upload that followed.

Media now resolves through the page it belongs to, so an upload lands beside its own page whichever language that page is in, and the Shared Library lists the library that page actually uses. Uploading to a page that genuinely does not exist answers a plain 404 and writes a log line, instead of the silent 500 that left this issue with no Nextcloud log entries to go on.

This affected every media widget — Photo, Photo Story, File Story and Gallery — not only the Photo widget.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQGR2+MVQYJYo1mg8qjMMBHAHr+V92aHAmEz08lqTMIYlzT05mbJqKeXtFan18+jUHp54/u5nyRHY0Hrc0AjJ2jfdq2oHyTvgKGtm6jHiswmM6dB/AkSglQ87ZRXmeeZzjfweWCmVayBnjqUCYRYuzvxXiu9qkmItu1I3vX2wvh2SyzC7YsWii3RvvHhuo00UAOEETwn3PrAD7vx/J4O4IiDMruq7fULsq2F+0Qb+XhlLVVTtvJPQHyYgStZGoP9hHYC+4fE1ugGgv1GQ4Rntae3MqKG+R3STVHDuXpNn9wMeIM3/24u8NyKPWosTSjgTnkoflb/Z73poiZaCfD3cApenQiEhjeM7rTjVARsOZtft6knovG1Wug4URzha1Onqvc2zqWkfDn5SCRQFJxpXjPojFiNETlEJXGoF5rG3s9Agn8/5l2lNDyhKqT7+8JCM8Da0P43fwDQn9rH1dVJH27P0D02HEvM4Ash/kV0SAdU6QBMUvEWtfcfTsVfJTonul71Z4NaA3v7LoK8nDAOVrUx8WYrssS7ZQrvV8HUxhsg4ymtMk/muUS4MJJAp3g2yALMvs49A+SI8fq44FL1opIKUjGlGvN2dJ0BHA0FUlxeX/aqb6/CmDTGhOQyFJ4UjZhxKuhLCTQk0RfG+6Fd1jBapWZehF2IsaJBNlmL/hEI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.6
Release Details
UpdatedAug. 7, 2026, 8:17 a.m.
Changelog

Added

  • Editors are told when a page is not in their own language. A badge next to the page title appears when the page you are on belongs to a different language than your own — in both view and edit mode. It names the language of the page, not of your interface: a German editor opening an English page sees "English", and knows that editing it saves back into English.

It shows up only when the two differ, so it never becomes a permanent label you stop reading; on a page in your own language, and on any single-language intranet, there is no badge at all. Like the Draft badge it is only shown to people who can edit the page.

It is an indicator, not a switcher: to work in another language, navigate to that language's pages.

Fixed

  • Editing a page failed with "Saving failed: Request failed with status code 400" and "Unable to save the page: Page not found". The page was on screen, it opened in the editor, and the save then insisted it did not exist. (#90)

Reading a page and saving one looked in different places. Opening a page searched the language you are shown — your own language, and failing that the recommended language or English — and then looked through every other language folder besides. Saving searched only the folder matching your own Nextcloud display language, and gave up there. Any page written in one language and opened by someone using another was therefore readable but impossible to save, along with its version history, its metadata and its delete action.

Nothing was wrong with the page or with the Team Folder holding it. Editing an existing page now writes back to wherever that page actually lives, so anything you can open, you can also save. Creating a new page is unchanged: it still lands in your own language folder. Permissions are unchanged too — a read-only member still gets a clear "not allowed" rather than a save that appears to work.

A page that genuinely does not exist now answers with a plain 404 instead of the contradictory "400 / not found" pair that made this so puzzling to report.

  • A sub-page created under a parent in another language ended up detached from it. Adding a sub-page to a German parent while your own Nextcloud language was English filed it under English instead — and built an empty de/departments/… mirror of the folder structure on the way, whose parent pages did not exist there. The new page disappeared from the very structure it was created in.

Page creation now follows the structure you are working in rather than your personal language setting. A sub-page joins its parent's language; a top-level page is created in the language you are currently viewing; and only when there is nothing to derive it from does IntraVox fall back to your own language, as before.

Together with the save fix above, the rule for editors is now a single sentence: you write where you are looking. Which language your Nextcloud interface is in no longer decides which content you can work on, and the admin panel's recommended language remains what it always was — a viewing fallback, never a write target.

  • Links to a page in another language resolved inconsistently. A link carrying a page's unique id found the page wherever it lived, but an older-style link built from the page name only searched your own language folder — so the same page could open, show a different language's page, or fail, depending on which kind of link you happened to follow. Both kinds now resolve the same way.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureMAygWy2LuZA4GrDZTIZjUtB0CSP60pbrfZdeVRb8Rg5ZOjGg9e4hrAMPbJ7GnT00NbDnP7GVkeaa0MdQT4n0pPtMrykmuJHY98uBTbNilcDUE80iYcKVnojntSffQtLClBXde5Sv4Gd2o9G5L5FWqlEI9nHfoz6C7qpiLgZGZlmQYzvNWBdCC49gYJUAxxGfxCtALhczS0Q+LjME1YnuPsSlxFCQW3Q7DhgpyAlbO+WS7VZ6FQhAZCKv3B0PVox1ouac3l2YZ1DuR0fZJuEnX5/3NQpIRqtSyZOfRYuNKA/dopXKs4T4SJzDUsdJtBH+aCHDdUEG+Jx3hQcb7XRe2C2SJnrsT7Azqm350pS9vDsz5Rspt26M9S95zHXJYQoL7EH/TnlIKZpJPF6qgB+zwen6rCz50FoJAPKdiWG0+0nBZT8ImwT2sAG3vCfJrs5pCbcueeFWUqGv2I0wdZNkE2pWDSPHAot9AGnu4DAUL8Qv1CFAG4QjIFbtQN/ayyt1Kf1tEGx23+kVNhDH8qSbwl1lQTTQVLzJsRh/XuL562O3Tdz63BUicjQTXiZsedFNqTpssz1vONJjlQN82a6jRT4zJyySBPelOd0k4uKtV+Em5FbarUvs2EuebW/zsR1+MdvFxTDNwHH9weTLd/4dqMWrkvl2enYKy35KpwBa/jw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.5
Release Details
UpdatedAug. 5, 2026, 9:02 p.m.
Changelog

Fixed

  • The filter panel lost all its options a few minutes after the page was loaded. The groups still appeared with their headings, but every one of them read No matching options — and then filled back in by itself some minutes later, without anyone changing a thing.

The widget's configuration was never the problem. The background job that refreshes People data every ten minutes runs without a logged-in session, and it rebuilt each widget's data as though an anonymous visitor had asked for it. That strips every field marked Local — including role and organisation — and skips IntraVox custom fields entirely, which is where fields like Werking, Thema and Gebouw live. The stripped result was then written over the copy meant for logged-in readers. With no values left to count, every group had nothing left to show.

This only affected instances that had switched on Visitor filters, and only from 1.9.4, where both the filter panel and that background job were introduced. The refresh now rebuilds each set of data for the audience it belongs to. Anonymous visitors are unaffected: they still see only what each field's visibility scope allows, so the fix does not widen what a public share can reach.

No action is needed on upgrade — the affected data is a cache and is rebuilt automatically.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJa1s+EtGix95c7jHfQz6ZUxx8YYfPLYzBPEsz9pc0A1GHIokKC3JSZbyGr8TD+1HNjO7WXoyXo7hSBV6wlIrqznQSj676/Cl+zp1GsYedg/EZnyG3lnGq3LRfMLMBnadAAZ+CB8yMxuo/09bQkrWo3pJ9mmq1ClIRjRl/0lNVBjOxTONaBEhJ8Bjt+nsVjLZb+bobmAvbR48peA2j1XOZtqQoCLU56V5WnZQNTWFHnLQ4K4pRcBb37n/OHPAaLIudWtoU8yiFAnNPjajq63e9TAeyxxIdJl+8MqOb6bKBrCKSk88LDDvBXeG8pfiqYYbfdfR1vT115+H8VMhDVUEa/D4D522aTTsEhrBkj4rpkC1/h04hjPTq+xyRCs/XiBAlWNLAs5Gy8KP8dtdXM8hOLKBgJrLk+lxb8HCE4Bu2oT3vq12exQ9DpZ88VJ4dUrPsbAkQ1E77Clka+imEZI946X7UuAqx0+Kq1UtfgmYgBm9gww/cFeCnSdd34FpQxG2saMkgsAe//+osGEX0H3nuI+eotxUdEjvKQTkpzz5nGUHTrmXQrAcwriI7dNufweaGbxVw3W33fgziJmzxeW6lxY1qjGDNmj4NiNsq+jRxO4VqbPhYkdPTDw6zn4w+eM0W3BzNaeGPO2JHrGsV+ezh0n/Cng5IdFn/z2ED3JuuUU=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.4
Release Details
UpdatedAug. 5, 2026, 6:04 p.m.
Changelog

Added

  • People widgets can now be filtered by the people reading them. Until now only the editor could decide who a widget showed; a reader got a fixed list. Switch on Visitor filters in the widget editor and the widget grows a filter panel: one group per field you choose, each value with a live count, plus an optional search box and removable chips for what is currently selected.

The counts are the point. They are calculated over the actual result set, and they narrow as you choose — pick a department and the building list immediately shows only buildings where that department sits, with real numbers. Picking a value never empties its own group, so "Noord or Zuid" is expressible; that is what makes it a filter panel rather than a series of dropdowns. Whatever a count promises, clicking it delivers exactly that many people.

A visitor can only ever narrow what the widget already shows. If you scoped a widget to one department, no filter combination reaches outside it — the restriction is built into how the results are assembled, not bolted on afterwards.

Selections live in the page URL, so a filtered view can be shared or bookmarked and opens filtered. On a phone the panel folds into a Filters (3) button. Filters do not appear on public share links: the values would amount to a browsable directory of your organisation for anyone holding the URL.

  • occ intravox:people:scope-report — prints which profile fields will become invisible under the visibility fix below, and for how many accounts. Run it before upgrading; --all scans every account instead of sampling.

Security

  • People widgets no longer appear on public share links. A public share is normally created to hand someone a set of documents. If the page also carried a People widget, the act of sharing those documents published a staff directory — names, photos and profile fields — to anyone holding the URL, without the people on that list having agreed to it or the person sharing necessarily realising the widget was there.

People widgets are now withheld from public share links by default. The rest of the page is shared exactly as before. Administrators who have a genuine reason — an external project page with a named contact, say — can allow it under Settings → Administration → IntraVox → Publication, but it is now a decision someone takes rather than a side effect of sharing a folder. The /api/share/{token}/people endpoint refuses as well, so the widget cannot be reached by calling the API directly.

  • People widgets now respect each field's visibility setting. IntraVox never consulted the visibility scope Nextcloud stores per account property, so every field the account manager returned was handed to whoever loaded a People widget — including the extra fields your directory syncs (LDAP/OIDC), and including anonymous visitors following a public share link. A phone number or birthdate a colleague deliberately marked Private was published anyway.

From this release the scope is honoured: Private fields reach nobody, Local fields reach logged-in users only, Federated and Published fields also reach public shares. The email address was a second route to the same leak — it was read straight from the user account rather than from the scoped property — and now follows the same rule. IntraVox custom fields (set through user preferences rather than Personal info) carry no scope of their own and are treated as Local: visible when logged in, never on a public share.

This is a visible change, not only a fix. Fields your users marked private will disappear from existing People widgets. Nothing needs to be run for the upgrade itself, but if you want to know in advance which fields are affected and for how many accounts, occ intravox:people:scope-report will tell you. The field most likely to surprise you is email: it defaults to Federated, but plenty of instances set it to Local, which removes it from public-share People widgets. Users change this themselves under Settings → Personal → Personal info, with the visibility picker beside each field.

The cached filter results were also shared between users regardless of what each was allowed to see. The cache key now includes both the audience and the viewer's group membership, and the old entries are abandoned rather than reused — otherwise the fix would not have taken effect until they expired.

Performance

  • People widgets read account data in one query instead of one per user. Profile data now comes from a single database read rather than a separate call for every account. Measured cold on a 106-account instance, the widget's scan drops from 35–45 ms to around 14 ms; the account read itself falls from 20.4 ms to 1.4 ms per hundred accounts. The remaining time is Nextcloud's own account enumeration, which an app cannot bypass. Instances with tens of thousands of users benefit proportionally.

  • Concurrent visitors no longer each trigger their own rebuild. When a widget's cached data expired, every visitor arriving at that moment started a full scan of their own. On an LDAP-backed instance, where reading a large group can take half a minute, fifty simultaneous readers meant fifty simultaneous scans. Now one request refreshes while the others are served the previous data, which is at most a few minutes old.

  • A background job refreshes recently-used People widgets every ten minutes, so in normal use no visitor waits for a rebuild at all. It only touches data that has actually expired, so an idle instance costs nothing.

Fixed

  • The People widget on a public share always failed. /api/share/{token}/people called a method that does not exist on the share service, so every request died and returned a server error. Anyone with a People widget on a shared page saw an empty widget. It now resolves the share token correctly.

  • The People widget's pagination setting was discarded on every save. The "show pagination" option was read when rendering but never stored, so it silently reverted each time the page was saved.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureI102notxijb2rG68TSr3XvT8Rh7/HOyPn1hIcu9DYcXWz0Fs3hSt0WBJzwj4rx3VOzL1kYcuganvYD9Sphfxe2qyIwlR/K9Oqd37KM9bg+v/IFqXvWCP6HMV97wazJdizbEaSEoohPran03F05inYQNrY+4SqpC2o7O1TJ3go4c3w5FwoL83uWxvF1MKto4eG6jozbM/oUkPEFQ1KUBa2ySbMIcZYrPO/Yh8eKPoD/YwMqDl1uqCejeRGKPMWh4XWkIjKlviKhVlfQ97QMsUh3rX/NppD0QKJMka08mOqDKpw+8xRU496qDZa0Z1LwKdapT1xa2A62oWR+e2dZr3mBCm/FzMI/cA55IeHw+SxXaRA+hyyuevtW+epvRl1FZecEeIII0CM66Kn/bBbWYfHTpsyBJba0Ev1bchFrqlba74TCniTu4FZvvm806ogf5yGHL5+2RQ9QwJrd2AHS1nF5XEr9FaPDI3gldzzGFGfWcNFStyz/jVEIHTbhG7OzQDZmDHdbh/lYHoa4Fs+KVtdr+qgsxfjxQ0DJD3W9ZpDgQwzpgVB/4NUG8iTCpDVsd7R8VL+EbXbCbOV+TOx0iiySuaOyCHDkhdkR0ilOOrUUfYkxUDuKo6vqutKOBa+qe8cW5c8seVVEB9HbVvJ/U7OPkmMFClHrmdFN4dLXJGPNM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.3
Release Details
UpdatedAug. 5, 2026, 11:35 a.m.
Changelog

Added

  • Search now finds pages by their MetaVox metadata. A page tagged City: Liège or Primary driver: HENK was invisible to IntraVox search unless the term also appeared in its title or content — the metadata lives beside the file, not inside the page. Those pages now show up under IntraVox pages, with a subline in MetaVox's own format (Label: value, joined with , matching field first, up to three fields) so the same document reads identically in both providers' results. Fields the user may not view are left out, so a restricted metadata field cannot surface here.

Changed

  • Search results no longer stop at the title index. The title index was consulted first and returned immediately on a hit, which silently suppressed pages that matched only on content or metadata whenever some other page happened to match on title. Index hits still render first (they are the fastest path); full-text and metadata matches are now appended after them, with duplicates removed.

  • The minimum search length follows the server setting instead of the app. IntraVox enforced its own two-character minimum, overriding the admin's unified-search.min-search-length (Nextcloud's default is 1). Nextcloud already rejects too-short terms centrally, before a provider is ever called, so the app-side check only served to make short but meaningful terms — HR, IT, CJK characters — unfindable regardless of how the instance was configured. No bundled Nextcloud app defines its own minimum.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDW78m+c4qRGRDYMcIhwYpytCtMO3guijSNnbzFEIXppXHYzSCHGAsrSllWOlPckQLasMUn+S1dpXLwk8uIKLXZYm+tfi+hfkmkrwN0SnCfTb+zGwiSOMdIvbMO/l0NnMEAglJf4/0fHsDxVX34/duPgvI+aOEk9yAr5qJeSu2J/T5DW4PvISOHKkY94p5z+QkOR2lOa6vO5iH3MtzaotNvgBRJd+VKy2riIO0O/Sfx5VSQL8CV0JY1mXBk1qbotIDNbYsfew7wr5iR2sEKNjUoocZAhxBAqzmSWYRvEy9tL5wx0miEeE4RIdeTNx7ItTSyzXocZm+JsVSG9iZKDiGg5dGd2VWtT+3Wg3ZAzHYGhHFMshlO9nEeWzR3e5Y87FIW1PasyRl2+8ZOS+hevaqR2s9aYc3mKSXZUqrmAC1TEn72V1kSgrUMrukBbqTjaBLNnhJZtnMqyLZ68yiPExcSCg0/DE8ul0ZPWLiTM+kznXuyTuKncDGXwqi0XFGiYKr0pHnJbR00C4KD3VLwIIIXbf+SReOSFMwaIE5xiBk2Fjc0vrmq1GZZZoLV46s3jTZdeB0JJzWjpNDczl4O2/jO8xEbAfY+Khhp4B/oMMA3nOl9WARJj1aezBHnNnxy+HEGJAxd72XuvuahjLXEa1OCec1vOPif1e1ac5zKXsRMc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.2
Release Details
UpdatedAug. 5, 2026, 7:49 a.m.
Changelog

Added

  • A page's "Publish on" / "Expire on" date now controls visibility everywhere. Previously the publication-date MetaVox fields only filtered the News widget's list; a page with a future publish date was still reachable directly, via the menu, the page tree and public shares. Now a page that is not yet published (future publish date) or has expired is hidden from readers and anonymous visitors — exactly like a draft — and automatically becomes visible the moment its publish time passes (evaluated live, no cron). Editors still see these pages, with a Scheduled / Expired badge next to the title.

  • Copy a link to any section of a page. Every heading — both stand-alone heading widgets and headings inside a text block — now gets a stable anchor. Hover a heading to reveal a small link icon; clicking it copies a deep link (e.g. …?page=…#h-creating-a-new-form) to the clipboard. Opening that link loads the page and scrolls straight to the section. Works in both the logged-in view and anonymous public shares. Page navigation (?page= / #page-…) is unaffected — section anchors use a distinct #h-… fragment so the two never collide.

Changed

  • A publish date takes precedence over the manual Draft flag. Following the WordPress/Drupal model, a page is in exactly one effective state: Draft (no date, held back manually), Scheduled (a future publish date) or Published (publish date has passed, or published with no date). This removes the confusing case where a page showed a Draft badge even though its publish date had already passed. In edit mode the manual toggle is then replaced by a read-only chip showing the effective state, with the explanation "Publication is controlled by the Publish on date. Clear the date to switch manually."

  • Draft no longer promises more than it delivers. The status keeps the name Draft (consistent with the rest of the industry and with how it is stored), but the wording now states plainly that it is a visibility filter, not a permission: the page is hidden from readers everywhere in IntraVox, while the page file itself keeps the folder's normal Nextcloud rights. Editing a draft page shows this as a standard Nextcloud info note card; the status badges carry a short, state-specific tooltip.

  • The editor documentation spells out where a draft page is still reachable. It previously claimed a draft was "completely invisible to readers", which was only true inside IntraVox. The guide (EN + NL) now lists the routes that bypass the filter — Files/WebDAV, Unified and full-text search, the activity stream and notifications, versions and trash, Collabora, sync clients and MetaVox metadata — and advises restricting the folder with Team folder permissions for genuinely confidential content.

  • The details sidebar (ⓘ) is now reachable while editing. It was hidden in edit mode, so setting a page's Publish on date — which lives in the sidebar's MetaVox tab — meant leaving the editor first.

  • The status updates immediately after saving a publish date. MetaVox stores those dates itself, outside IntraVox's own save flow, so a page you had just scheduled kept showing its old Draft badge until you reloaded. IntraVox now picks up the save and re-reads the page's publication state straight away. While editing, an info note explains the current state — including what Scheduled means and that the publish date overrides the Draft/Published button.

Fixed

  • Public link shares on a page folder now render for anonymous visitors. Opening the anonymous URL of a shared folder (e.g. a whole-language or sub-tree share) returned "This page is not available or the share link has expired" for every page under it — the share tree loaded, but each individual page 404'd. The page-scope check compared a per-user mount path (/Sam/files/IntraVox/en/docs/…) against the GroupFolder storage path (files/en/docs), so nothing ever matched. Pages are now resolved by their fileid in the GroupFolder storage — the same robust lookup already used for the share path — so folder-level public sharing works.

  • Internal links inside a shared page now navigate. In the public (anonymous) share view, clicking an internal page link in a Link or News widget did nothing — the shared view's navigation handler only understood the Navigation bar's object payload and silently ignored the bare page-id string that widgets emit. Both payload shapes are now handled, so sub-page tiles/links inside a folder share work.

  • The breadcrumb inside a public folder share shows the full path. On a nested page in a shared folder (e.g. Docs → FormVox → User → Creating Forms), the anonymous breadcrumb collapsed to just the share root, because the builder was fed a per-user mount path that could not be normalised against the share scope. It now uses the canonical GroupFolder-storage path, so all levels between the share root and the current page appear and are clickable.

  • Draft and scheduled pages no longer leak into a public share's menu or page tree. The share navigation and tree now apply the same visibility rules as the page content (which already returned "not available").

  • The News widget's "show only published pages" option now really hides drafts. News items were assembled without their publication status, so the filter saw every item as published and removed nothing. It also gave up when no publication date fields were configured or MetaVox was absent, and the caller only ran it when MetaVox was installed — in each of those cases drafts still showed. The status now travels with each item and is always honoured. A News widget inside a public share had no filter at all and could list drafts to anonymous visitors; it does now.

  • News cards meet WCAG 2.1 AA contrast, including on hover. On a coloured (dark) row, cards are drawn on a light tint but their text used the white "on primary" colour — measured 1.17:1 for titles and 1.12:1 for date and excerpt, where 4.5:1 is the minimum for body text. Titles now use Nextcloud's matching light-surface colour (12.96:1) and the date and excerpt use the full text colour instead of an opacity fade. Hovering previously flipped the card to a dark blue while the text stayed dark (1.75:1); the card now keeps its light tint (11.59:1). The carousel's secondary text (3.80:1) was corrected as well.

  • Publication dates are time-aware and use the instance timezone. The check compared dates only, so a page scheduled for later today counted as already published; and a time entered as local time (e.g. 15:57 in Amsterdam) was compared against a UTC clock, so a page could read "Scheduled" for hours after it was live. Dates now respect the time of day and are read in the instance timezone (the logtimezone system setting → the viewer's Nextcloud timezone → the server default); dates with an explicit offset keep their own zone. Administrators on a UTC server should set logtimezone, otherwise anonymous share visitors — who have no personal timezone — see scheduled pages appear at the wrong local time. See the editor guide for the command.

  • Blank items in the text widget's "Paragraph" dropdown. The heading options (H1–H4) below "Paragraph" rendered empty because their labels were passed to the translation function with the level as the app id. The markers now show correctly.

  • Several untranslated interface strings are now translatable. The page tree's "Show N more…" button and its expand/collapse labels, the navigation editor's focus-trap label, and the admin video-recommendation risk badges, category names and People-widget fallback field labels were hard-coded (or passed a variable the extractor never saw), so they stayed English in every language. They now go through the translation system.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureUBb4nMn8TJ3eLofW2Cb2kKLzsBx4OSswqMmfxydA3Uzv4+0qdn0F8h7zqPxwnbtQ6Zxo4oNtNkk7iqANQx7U34c85fWLpv7nrMYi7tJScTIcN2P47p44cyUmxgoj0IOAzWveB9d5OPd1zJUH48xf19Wfv46bVzmPdRKq6kpvnxlm4cofAc+eZLy1oMRrLQt1acRb1ZDMV5nefIp+i6z7NqUDVgxgdbCE0d/PpsjMU+dVzg33A+4RJMw7SJBMaNJyxBipn4mhNRzBw75Crs6UZeEVFbu+eP/CHhFRSdr8sR9uTHa8LrizFX1G+kvLUGO63izEZz61LsO56ntB7orQCSlwkpWfjWtu6v+IPTbF0DZhZn9JGCz40NQET5pg7UT9/ZUj29qyVuBn+HcQtFvxQ/cSYbNw9cMZ+cq+egWjqXBCz5SaXmP48GdPXQJVILhie61DL5hoSbFHGqwGfX458wBWZ860hxRywFF59+kDd0JhJ173qXDLAe0lbH2puSe0yvdRSQZXJhz8EHOrt4ix5Yh0t7xw8LUM73flZNeMqlqF9KMRr7RxPoSuPD7o4PAadC79TtHJS1WpnNYhvZpiKlxZcblk15skt3YH3b7++Xg2WVMBG+hVYa44ldeP/9Iegd/hpsS2vpXuxT3PiDBBSc8nzBntNvAAzOVG6aeGVdA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.1
Release Details
UpdatedAug. 3, 2026, 5:26 p.m.
Changelog

Changed

  • The page actions (⋯) menu is now grouped. As the menu grew it had become a flat, interleaved list. Its items are now organised into logical groups — page actions (Rename, Page settings, Copy, Save as template), site (New page, Edit navigation), utility (RSS feed) and the destructive Delete on its own — separated by thin dividers. The dividers adapt to your permissions, so you never see a stray or doubled line: a read-only visitor sees a clean short menu, the homepage hides Delete, and so on. No actions changed — only their order and grouping.

  • The help text in the Page structure and Edit navigation dialogs is collapsible. The multi-line explanation that filled the top of those dialogs every time is now a single collapsed line ("About the page structure" / "About editing navigation") that expands on click — the guidance is still there, but no longer in the way once you know it.

Fixed

  • Copy, and the navigation editor, now respect per-user permissions correctly in Team folders (#86 follow-up, thanks @kma-cloud). Three remaining gaps after 1.9.0: (1) the page tree's Copy button appeared where the user couldn't actually create, then failed — it now copies a page as a sibling into its own parent and is shown only where the backend will allow it (root-level items are gated on create-permission at the language root). (2) Trying to save the navigation without write permission returned a 500 error instead of a clean refusal — it now returns 403. (3) Edit navigation is gated strictly on write access to the root, so a read-only user no longer sees a button whose save would be refused.

Security

  • Dependency updates. Patched bundled front-end dependencies to clear all known npm advisories (axios, postcss, dompurify, fast-uri, linkify-it, brace-expansion) — non-breaking patch/minor bumps, no functional change.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureqGA3vDWGE6zTcCgb+VIfpjRMzk/kGoFf2p5HKz8bzQ8dq8ghNzvClqaWGiDuQjzld07fq3ETLpMzglrGjYcNI3tvg6WJr7Sv78OOI19Vdl3j6v1HTPBe4lqbq3DhLRHcNeNaPxMJ2QOeXfQqsm9Re8USkLCG99/IbsQpcd1KLWbhutLCFe4eu1In60nRxT6Ix7KUuKuLGFjBJ79Sk3SkRFgzc0NwUF4KVisPt01lVDt4QX6AeDOkrVD5tzgJqM1Bso82wDkqlMp5CmK6ANMD/7eZ26Df/D4HQjuT9AmcbwCIF4iRRdJwRZa98swOQw25KFGoeonB49ErxrT5ghQr9pTd/EsGy2s+sS15OS+ux8YKunPrRnhhdbe+g3i3+gRLWhGItisMBkEbGWNfYf4bW0RKgbaRuTokDuagszGTA9d52aCROwk3h/Kipqk3n0mLgwkxcdtA8G5/NclWRZ1XjR1kNPjEkeAdv4nWXc6Wo/wmompOlrSU7hxjEys5pnWWDBfT231b3+ymzLQwfGRoVWFsYY0LGiDRI8Q17+pWv1Wo5rLwx5+1acIJm/PrtU0Jl8456k9Ou13kQAFyy8u+khavNT1hprl9PcnxOnkDSzrOiNUWZrCJ0noRmJjTr6BqWqfUDAxrxygP/Hn8f/EopXQwArHc2xfh6RJ+UaaQvPk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.9.0
Release Details
UpdatedAug. 3, 2026, 6:07 a.m.
Changelog

Added

  • Rename a page directly from the UI (#84, thanks @kma-cloud). A page's title could only be changed from the Details sidebar, which nobody found — so it looked like pages couldn't be renamed at all. There is now a Rename page entry in the page actions menu (the ⋯ menu on the page you're viewing) and a rename button in the page tree's manage mode, both available to anyone with edit rights. Renaming only changes the page's title — the page's address (folder) and all links to it stay exactly the same, so nothing breaks. When the navigation menu label still matched the old title, it's updated to the new one automatically; a menu label you'd deliberately set to something different is left untouched.

  • Page buttons for the File Story and Photo Story widgets (#78, thanks @kma-cloud). Setting a maximum number of documents used to hide everything past that count, with no way to reach older files. Both widgets now have a Long lists choice: keep the existing Infinite scroll, or switch to Page buttons with a Documents/Photos per page size and Previous/Next buttons that page through the rest, so everything stays reachable and the widget keeps a predictable height. Maximum documents/photos stays a separate, optional total cap that applies in both modes. Page buttons apply where the widget already paginates — File Story's List and Tiles, Photo Story's single-folder Timeline and Grid; the other layouts always use infinite scroll. Existing widgets are unchanged (they default to infinite scroll).

Fixed

  • The filter operator dropdown in the People and News widgets was blank. When filtering people or news by attribute, the operator selector (equals / contains / is not empty / …) rendered empty options — only a checkmark, no text — so you could not tell which condition you were choosing. The template translated the labels with a single-argument t(op.label) call, which @nextcloud/l10n read as the app id and returned undefined (the same bug class as #79). The labels are now translated correctly and, as a bonus, are actual translatable strings (they were previously hardcoded English that no language could translate).

  • Special characters in page titles work correctly. A title like Collega's was stored HTML-encoded (Collega&apos;s) and shown with the literal entity in the title, breadcrumb and heading; A & B, quotes and <> were mangled the same way. Plain-text fields (page and widget titles, alt text, link labels) are no longer HTML-encoded at storage — the frontend and the RSS/export sinks already escape at output, so there is no security regression. An occ intravox:repair-entities command (with --dry-run and --user) decodes titles/text already corrupted by the old behaviour. Two related fixes: accented and non-Latin letters in a title are now transliterated into the folder name (Müllermuller, Cafécafe) instead of being dropped (mller, caf); and creating a page whose title collides with an existing one now opens the newly created page instead of failing to save with "Page not found" (the new page is selected by its stable id, not the derived slug).

  • Page-structure and per-page management now follow per-user permissions in Team folders (#86, thanks @kma-cloud). With GroupFolder Advanced Permissions (ACLs), a user who could write in only one section either saw structure/management controls that then failed with a 403, or did not see them at all. Two causes: (1) the page tree was cached per group, so a per-user ACL grant was not reflected in the tree's permissions — it is now recomputed live for each user (the same per-user approach already used when opening a page); and (2) the "Manage structure" toolbar and the per-page manage actions (reorder, move, rename, copy, set-as-homepage) were shown based on write access to the root, not to the actual page. The toolbar now appears whenever the user can manage any page, and each action is shown only where the backend will actually allow it, so the UI no longer offers actions that 403. Note: this addresses the UI/permission mismatch only — a per-folder "Read + Write" ACL still requires the user's group to have write at the base level (an ACL cannot grant above a read-only base; see the authorization docs).

  • The "From template" picker went blank as soon as one template existed (#79, thanks @quarterstaff-tech for the thorough diagnosis). With zero templates the picker correctly showed "No templates found", but any template at all made the panel render completely empty — no error, no list. The template preview card tried to look up a per-template translation via this.t('template_<id>_title'), calling the t(app, text) wrapper with a single argument: the key landed in the app slot and the text was undefined, so @nextcloud/l10n's translate() crashed on undefined.replace(…) (TypeError: can't access property "replace", f is undefined), taking the whole panel down during render. Those template_<id>_title / template_<id>_description keys never existed in the translation catalog, so the lookup was dead code that only ever crashed; the card now uses the template's own title/description directly.

  • Drag-and-drop upload did nothing but open the file in a new browser tab (#85, thanks @kma-cloud). The image/video widget's media picker invited you to "drag and drop", but the drop zone never handled the drag events, so the browser fell back to its default behaviour and navigated to the dropped file instead of uploading it. The drop zone now accepts dropped files into the same upload flow as the file browser, with a highlight while dragging and a type check (native drop ignores the accept filter, so an image widget rejects non-image drops, and video rejects non-video). The same missing-handler bug in the admin Confluence HTML import drop zone is fixed the same way (validated on the .zip extension).

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureqrQoDs284d1e7hHhvExpV85DY/hEp2pQ5lZn5WaBYxJfBxVpT1bdcatKbRjwdHGcnxbjzTh79qsEP8Zdm23RCEblKiyPbJMkSR3KwSka4ZsyrKjI3tYNm4sKalKfF32nyYt8lMlNpduALWkJCVb3CsydyuGeIsMXa0GL7Dg3JBsP1fPknHo3MkKRt/G3zr8LyrrKp6fYAy4r43MVSfYaLH1C7osKCG3zsrfO5VYb2CP0kSsIld77IV4FX23PRqawMJoAYNQ4ULqF7BlmllXOpUD1YsPoIJc8RODyLTBsY4jwXHGQJ5BBCrN71zDuPW1/Xdqpw0ey2XvJISuzKKvYOeZXMEpr0IzCwQ9grMFbZUfcz0sHr3oSG8WKxGRnmEKpP8yTHsnnadhESSX+Acli6S+gunpnmgHM9V9iJ7LtG5qBV95gBBY0mUJU1Ekdv6uIIvzSRB0H3f2lFc7x1jhxFREsSgws74O6DkIP0wF2iEO2Iq74Xark7/z+hjeBGE17aznK6Y/pdaWG+jXS+jazezBHeVjxHnsFvEJqgNsxzV4ZLMFFiMraJab9muUfeIuMxfmLrTJOTK2MuNU890a6B5YIuawDVF4uHtzwDbAMm5DP/gkNipxbXbPh2QK1uAl7grazK84X3vQ+QiQUgd3H+qFrTH6DrngYbEVEBI0TZWE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.4
Release Details
UpdatedJuly 10, 2026, 6:15 p.m.
Changelog

Fixed

  • Every button and label in several dialogs read "intravox" (#77). Four modals used a translation wrapper that put the app id in the wrong argument, so the "Create new page" and "Save as template" dialogs, the page-tree selector, and the "All pages" list rendered the literal string "intravox" for every tab, label, and button — making them unusable. The wrapper is now aligned with the rest of the app (t(app, text, vars)), so the real labels show again ("Blank page", "From template", "Page title", "Cancel", "Create", …). Pre-existing bug, unrelated to recent translation changes.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTe1odfxiiohPjc11AuhYvlSV+RfrbFqpMxueWeTS8IMhi4V9DQQeMegMU+opEACytWuY2smPcEmvApaOBFQHFBhcpE9EUIF0A/yoW1HK7IoZXwTWmaeTW01XqNBgm01NIEV/k677kzSCmCe03a53nEJpn517hScNan9nUZxr0d3VDfHxB/MuDBKq2gCBS1eEV4AsyLfrUo9x2AfYI/Lh4UZcnGFxN4Zd/9DD3slBOg3G8A5MUixjArUKLGAD33x+qrTXL96IX/TM1CQdwhycP+82OVTdEtQiFB2PCWq17Z2GVncv5xec+eRddw78gOFnyad2ykWshSfPSTAAuQlZ/+AM0pYMyTEcEHBQTMOxOMoZjQpMjEyB159TZzoxynlkDEuV5/RE3iP5i5lcrOXuARStcp2BZLyhBAkjAQ+/7diVM8urYIw4tqvA1b9T3WeLlQUC+kJtgg5WEb2F206yBN/Thd9aT/c4LlhMBtUW7KLfY3PnWvxNfMpDULuQvjnPsXJOuzFa871O/IuiYPyJeYtf4pdBCJ9ihc5Zxqu7ZL/mv6LmQMuNFdtSCYd443UAFrl3hpWUx6ox7fupKVq+D57VRMd2jmJeOHIZJ2Ii3qYH5jwq3qIw95OwDK9YTEYDN0IR8aDkMfhzasSEIH9mgr6Tn19OjxVHKI4+KD9aFq8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.3
Release Details
UpdatedJuly 10, 2026, 1:51 p.m.
Changelog

Added

  • mave.io as an allowed video service (EU-hosted, cookieless, GDPR-compliant). Because mave.io serves each space from its own subdomain (space-{hash}.video-dns.com), a fixed allowlist entry can't match every space, so this adds a wildcard-base-domain mechanism: a whitelisted base domain also matches its subdomains. Matching is boundary-safe (the host must equal the base or end with .+base, over HTTPS), so look-alike domains like evilvideo-dns.com are rejected. Enforced identically on the backend (PageService) and the frontend Save-gate (WidgetEditor).

Changed

  • Translation polish from reviewer feedback (thanks @rakekniven and the Nextcloud translators). Added TRANSLATORS: context hints for the Photo Story layout-style names (Magazine / Apple / Travelogue) so they're not translated literally; renamed the admin heading "Video embed domains" → "Domains for embedding videos"; fixed "Popup blocked. Please allow popups…" → "Pop-up blocked. Please allow pop-ups…"; and updated the app description to say "Team folders" (the current Nextcloud user-facing name) instead of "GroupFolders". The feed-URL example placeholder is no longer a translatable string. Ships with refreshed community translations (de, de_DE, et_EE, pt_BR, and others).
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureALXXa8zgPsReRyfFakJc3pmk5fyZ/f3XJhbWvdWmiSs/GGoh6k4bpHLg7eV5CC0A3Fpdkf2w1K9T0/84NaoI65mkuLQazVnI9OBRqdGfJdkJOcToh8FMGRr06oJH7KEYnZhphBbdjKvaq2/Jhe7gZkUdOpqoNYlWGWqmIAngpYpaWjdglJLHTSWK86nwckDAEB6mTnUlfEfyzAF6i5SbIcYWaIL0VFy7dYqtnSgkEyrRFc/bb+iwOvWp+TwqCLWy1RMT/mmK3VcTeIgwzPsW+X8gxgJHYWCmY0ZDTEpjoHR9xM5hA/jtW791bAIdBbwOnLxH2g8es83H8DRX4RFwFBaDQKNCCMQLVVVePaM9YaWuIVUImJ3wRcJqX51MYA9BH7LH/lp/muUaR94uzxIlOb/TnCPaeOL2x7haSD681R7/pELc8OUuxtpiFkb+wmenZryjE9MK9n2hGrCU+lwXD9hVeFs/8PD6Q6vNc4erEUegrxuvA2BjO8nF3jtHrFXSmdjuR5IKoXiiUa7oueJQjTLaS4OKf5R3sfZ/bIy3jE4VlQua+C1B267c7qswulmkHNyWEaL3mAPmY101OXS4yOeaKnIYLbtcuL+/BguNgD2N4Q4OZVpdnkw+qiVe0DjgT1KwkwoZSPsYcNp1SJZ2HYIhUV2SFsTjSoZuhyspdt8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.2
Release Details
UpdatedJuly 8, 2026, 11:01 a.m.
Changelog

Changed

  • Faster group lookups. Permission checks now use Nextcloud's getUserGroupIds() instead of loading full group objects, avoiding unnecessary object hydration on the hot permission path (#74, thanks @carlschwan).

Fixed

  • Users whose language has no content are shown the recommended language instead of a blocking notice (#75). The admin settings promise "if there is none, they are shown the recommended language below", but the landing page ignored the recommended (primary) language entirely and only ever fell back to English — and since 1.7.0 it showed a full-screen "No content in your language yet" notice even when English (or any recommended language) had content. The page now resolves the language to show as: the user's own language (if it has content) → the admin-configured recommended language (if it has content) → English → and only when nothing can be served does the notice appear. Authoring is unaffected: an editor still creates and saves pages in their own language, never the fallback. Also fixed the notice's "Manage intranet languages" button, which deep-linked to the old Demo data tab instead of the new Languages tab.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureL1CilQMaUR50sVUvKQgjThVmYhacoxZ/0IU6asyD7jwLv81NCDoeEqbIaYd92How8BoPGPg/OPQM6wTgn0lYvOb2/a3Yr+CrLF0Cf/2KNFZrRmXguv9qoLXIHDahbelQfSrl9GyuyDw0i1v1s7KvC3dYyTrAh5/VA8ZoXe3raKRAP3T6+II2UNN/NHOE3K6f+zPkKYDk5Ne+qHWIQqxmdm3k6nZaqZ7AZbNF9hNePrvBu7MF81Pshh2MCXsDD5+R9Wrq+W5zWijhLWvsUYlXYMLbL2pjF7xKl2U8TcnED3O7hLI1GI1DoZTqaRGlQs2cye/rw2zyds2UW2a99r+BUbVStKmJcoJfm2iQ+mFZMqRJNoC1pONvmImAm6iRFfDT5F6rTfUCXZnEsQKbyGfn+1pI+FGqMBcIE7HRvg7Zvo5VYC9VYBTtaUYPEXo/mv/+1gAPT6S9vohBOsK8yhDTxaBuTXUxXvHnEK9xkLK6YnOcAcGa4rRUQoDS3mUd7T2A0GLUSr6jqwkc0aGKFSozDJElR6iFZX5/y1BXzIQorkFWNTL7ZWrKXyHgsWL/WToiDe4StSKAk9u5gggebJ1O4O54yzgSHjSAwzijv8TN4gy76YO2d6GUNYr5caSCLBQwKpWvzchKlZt8VOA0XvbL/TV2RNiEsFOdlKbjAP2OqlQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.1
Release Details
UpdatedJuly 7, 2026, 4:03 p.m.
Changelog

Changed

  • Intranet languages now have their own admin settings tab. Choosing which languages the intranet holds content in — the "languages with content" list, the recommended (fallback) language, and add/remove language — was buried under the Demo data tab, where nobody looked for it. It is now a dedicated Languages tab, sitting alongside Video services / Engagement / Publication as a peer "how the intranet behaves" setting. The old tab is renamed Demo content and now holds only the demo-install table, so its name is honest. To avoid growing the tab bar, the rarely-visited Maintenance tab (orphaned Team folder data) becomes a sub-tab under Support — both are infrequent operator tasks. Old #maintenance deep-links and the orphaned-data banner still work: they now open Support → Maintenance.

Fixed

  • The recommended language can only be one that has content (#73). The recommended (fallback) language picker previously listed every language, so an admin could point the fallback at a language with no pages — leaving users whose own language has no content staring at an empty intranet. The picker now offers only languages that have content (plus English, the universal source/fallback), and the backend rejects setting the recommended language to one without content (POST /api/languages/primary returns 400).
  • The "Edit page" button now hides for read-only Team Folder members (#70). Even after the 1.8.0 permission hardening, a read-only member (e.g. an "IntraVox User" group with view-only access) still saw the Edit button and only hit a 403 on save. Two causes: (1) a page's canWrite was derived from the page folder, which a read-only Team Folder can report as writable, while the actual save preflights the page file — so the button and the save disagreed. canWrite/canEdit are now gated on the file the write path targets, matching reality. (2) A page's per-user permissions were baked into a distributed cache shared across users, so an editor's canWrite could be served to a read-only user (and vice-versa) for up to an hour; permissions are now recomputed per request and never cached, while the expensive page content stays cached. canCreate/canDelete remain folder-level as before.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBYA7jrD9xK8H4nt4f/dxUKG5VVqr8boApvEJgZiEfQYlmFRhA1ukRyzwClJ1ioAe3sHUKySuW+fOUgqD6ICcV/N7douwFXqb7UIHdsG3z3pAOsjifmfW2/6SLLCrWYnonC6W+eZdr9sQj2hjPBYRZuiK4MJCNSxrrnZE3eEt2kQFeFsK6GLOdhF+UkPVQNqtKdsZDKOCZsTAq2LyPBefse4R4pHk4/no/4sOisfEvxxln0cVIpESr5KfVPFASbvgzMLjktSAN0/A3Xx4l/q9RYe9ulaIJPZ5HfKOrB7cqUQ350n88LFk1SV9g3qXdo8o7kgnLA04vaSMXa2QngupJpYIFB8VsOZl9QDZSeGB8yU0PF1VZm9z8dCohCZ1/JWSY9bc6kYZ2nq2maC0AP0g3sAMGioJ6ta3ZYCBUHcGmWSpagAnvyAQC6gfIPsMI6zIbm6ALX88YKjiyF4hYCWIgN51xOUpgsTAIKelsEyqlKcvxfAJeuTbq9gxpeSajQw8d4o2IcMl2hx6g5w92KzsXDV+Rx7FrQStYZrC3nDdQr2aVWlmJTXYNYMMV6glVZsrO/UX2ENqGA+GdKA8duaRQMuQ6uB4tcfMxE88Ozx6nFH+mYrv7plcQrFppuHlKmmVWyF7TyHRSaRsYbC9LIbNQrkh/riql891SebcOIIjprs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.8.0
Release Details
UpdatedJuly 7, 2026, 7:07 a.m.
Changelog

Editors can now manage the page structure directly from the IntraVox UI, without touching the underlying folders. This release also hardens IntraVox on Team Folders: read-only members are handled correctly, and setup/demo-import now work on installations with primary object storage.

Added

  • Reorder and move pages from the structure view (#69). The page-structure modal gains a Manage structure mode with per-row controls: move up / move down to reorder a page among its siblings, move to another page to relocate a page (with its whole subtree) under a different parent, and delete (with the existing confirmation). The home page stays pinned — it cannot be moved, reordered or deleted. All controls respect Nextcloud permissions: you only see them where you have write access, and cross-department moves obey GroupFolder ACLs.
  • Sibling order is persisted in a new per-page order field. Installations that have never reordered keep their existing order untouched (a stable comparator leaves pages without an explicit order in filesystem sequence), so this is a no-op until an editor first reorders.
  • New endpoint POST /api/pages/reorder; cross-parent moves use the existing POST /api/bulk/move (admin-only for now). Moving keeps the page's uniqueId, so internal links and URLs by id stay valid; a folder-name collision at the destination gets a -2/-3 suffix.
  • Configurable homepage. Any root-level page can be made the homepage from the page-structure manage mode ("Set as homepage"), and the current homepage is marked with a Home badge. The homepage is now a per-language pointer (homepage.json) rather than a hardcoded home.json, so no page needs to be renamed. The homepage cannot be deleted or moved until another page is assigned (returns HOMEPAGE_PROTECTED, surfaced as a clear notice). Fully back-compatible: installs without a pointer keep using the legacy home.json; the old homepage is lazily normalized into a regular folder page (keeping its uniqueId, so links survive) the first time a different page is set as home. New endpoint POST /api/homepage.
  • Copy page. Duplicate a page as a new draft from the top-right "⋯" menu (copies the current page) or per-row in the page structure. The copy gets a fresh uniqueId, keeps the layout and media, is titled "… (copy)", and never inherits the homepage role. New endpoint POST /api/pages/copy.
  • Delete page in the "⋯" menu. The top-right page menu now has a "Delete page" action (with confirmation), hidden on the homepage and shown only where you have delete permission — matching SharePoint's page menu.

Changed

  • Clearer separation of "Edit navigation" vs "Page structure". The navigation editor now states up front that it only changes the links in the navigation bar and their order (not the actual pages), and the page-structure modal explains that its manage actions move the real pages and folders. Both modals lead with the same info banner and cross-reference each other, and the word "menu" (ambiguous) is gone in favour of "navigation bar". The "⋯" menu also closes when an item opens a modal. The page-structure modal also notes that only top-level pages can be set as the homepage (move a sub-page to the top level first).
  • Faster page-structure operations at scale. Reordering siblings is now O(N) instead of O(N²) (it reads a parent's direct children in a single cached pass rather than walking the whole subtree per child), and bulk delete/move/update clear the distributed cache once per batch instead of once per item — noticeably quicker on large, deeply nested intranets. No behaviour change.

Fixed

  • File Story widget now shows Whiteboard and FormVox files (#68). The widget filtered files through a hardcoded document-mimetype allowlist that omitted Nextcloud Whiteboard (application/vnd.excalidraw+json) and FormVox forms (application/x-fvform), so those files were silently dropped from a picked folder. Both are now included — FormVox forms render with their real preview, whiteboards fall back to the mime-icon placeholder — and each groups under its own "Whiteboards" / "Forms" category. Also added .odg drawings (application/vnd.oasis.opendocument.graphics, grouped as "Drawings") and the text/x-markdown alias so .md files aren't dropped on installs that register markdown that way.
  • Page-structure modal labels now translate. The tree modal and its rows used a wrapper that passed the app id as the translation key, so strings like "Collapse", "Expand" and "Current" rendered as literal "intravox". The wrapper now matches the rest of the app (translate(app, text, vars)), so those labels localize correctly.
  • Deleting a page by uniqueId now works. PageService::deletePage resolved only legacy folder-name ids, so a delete request keyed on a page-… uniqueId (how the UI deletes) failed with "Page not found". It now resolves uniqueId first, then falls back to the folder id.
  • Read-only Team Folder members are handled correctly (#70). On a Team Folder shared read-only to a group (no Advanced Permissions/ACLs), such users could open the editor and the Save then failed with a confusing HTTP 400. IntraVox now reports write/create/delete permission accurately (it combines Nextcloud's permission bits with the node's own isUpdateable()/isCreatable()/isDeletable(), which reflect the mount's writability), so the Edit button is hidden for read-only users and a write attempt returns a clean 403 instead of a 400. This also removes the follow-on Nextcloud core ShareHelper error. Reading navigation/homepage no longer tries to create the language folder for read-only users (which explained the intermittent "navigation not visible until permissions were adjusted").
  • Setup and demo-data import work with primary object storage (#71). intravox:setup and the demo import resolved the Team Folder via the internal /__groupfolders storage path, which does not exist as a node when object storage is the primary backend, so setup failed with "Failed to access groupfolder". IntraVox now resolves the folder through a member's mounted view — the same storage-agnostic mechanism the rest of the app uses — with the legacy path kept only as a fallback for local storage.
  • The "Add widget" picker opens again (#72). The widget picker crashed on open with TypeError: this.t is not a function because the component was missing the translation wrapper the rest of the app uses, so clicking "Add widget" appeared to do nothing. Adding the wrapper restores the picker.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturesf/demh4nISYFiTA4SLXu8F8cZOd40DZL/psxAoptr6CjZBliXnhmzsvL/x+LPUU+AwAROwBBi4XyXalNjWTiTUz06Y9XjmUwwTcRzOuniF+E9oddyOYbsCy6Ea/LgVIVDHymPQbaB/JSfjgm+5khswNyuuLyQumOSdK6RZQYRopMg0u0LfUJJmhAwl1LXZI/+YF8p/uIISKkgUf3JfeyY6JseZ/IIe/Z6EXjmt+nrOZY6ZCTRgYzjOS95uYsaky7+T0hKRdIVaBiOUn9HkEsHAnAfEajkZ6+lui2dyP7ztzjgYBUklWrnfV14PISVJF1V6MTJl5ZLg9IoC6KA4iIj0itvjzoVX1KgJhgN2JbQMw8fOEUmG/iY44mpDqL849rQp8qmw/t1EngVUQbXC3BYWgNip3b/FxDHO3wK61ysvCVjUaVblYHMcCq4O1Ei1aytM+akxbyAOAD5YTgRKEGKr9o2l4g2tHS2umG5vPT3kNQhXkgnIuFysaT16Z3P5V7+rpWiI387kfUR6Seb35qe+a+jdS0f4MWW+JU4g2psQ/2cKt9V1b/7paJbHC+meXl31GNMJaqAJBquUiPISCGaCSiszcQ76PIn5OUuU3PdHEbFGKTEt3RX4f4pC9pVJiiFu9bkDBAwwrPxoY5jjVeQCfo0txD6d7eeFjzfnf4Gk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.7.0
Release Details
UpdatedJuly 3, 2026, 12:48 p.m.
Changelog

When an editor maintained content only in one language (e.g. Dutch) and a user's Nextcloud language was set to another (e.g. English), the user silently saw a generic placeholder homepage — the editor's real work was invisible and there was no hint that this was a fallback. This release replaces that silent placeholder with a clear notice, gives admins full control over which languages the intranet holds content in, aligns the language handling with the wider VoxCloud model, and brings all source strings in line with the Nextcloud translation guidelines so the Transifex resource could be unlocked for translators.

Added

  • Language fallback notice on the landing page. If the user's own language has no real (editor-authored) homepage but another language does, IntraVox shows a clear LanguageFallbackNotice instead of the generic placeholder: it states the intranet has no pages in the user's language yet, lists the languages that do have content, and links to the user's Nextcloud personal settings so they can change their own language. New endpoint GET /api/languages/content-status.
  • Full content-language management in admin settings. Admins can pick from every Nextcloud-known language (not only the subset IntraVox ships a translation file for), choose a recommended (primary) language used as the fallback suggestion, add a language (creates an empty homepage so editors can fill it), and remove a language with a confirmation dialog that warns how many pages will be deleted (the folder goes to the trash, restorable from Files). The fallback language (English) and the current recommended language are protected from removal. New endpoints POST /api/languages/primary, POST /api/languages/{code}/add, DELETE /api/languages/{code}.
  • UI translation-coverage indicator next to each "Languages with content" chip, showing what share of the IntraVox interface is translated into that language (e.g. "UI 8%"), with a tooltip. LanguageService::getTranslationCoverage() computes it per base code (largest regional variant wins, e.g. dede_DE.json); scripts/extract-en-json.js writes a committed l10n/.source-count.json so the denominator is available at runtime.
  • Deep-linkable admin settings tabs. Each admin settings tab is addressable via the URL hash (e.g. …/settings/admin/intravox#demo), and the tab updates the hash as you navigate.
  • l10n/en.json extractor (scripts/extract-en-json.js, run via npm run l10n:extract / npm run pot). It scans src/ and lib/ for every t()/n()/$t()/$n() call and regenerates the English source for the POT, replacing the previous hand-maintained/restore-from-git workflow.

Changed

  • "Active" languages are now derived from content, not an opt-in list. A language is active once it has a homepage; the enabled_languages opt-in checkbox grid is replaced by a "languages with content" view plus add/remove controls. Real (editor-authored) content is told apart from auto-generated placeholders via a _generated marker, dropped automatically the first time an editor saves the page. The admin chip list shows active languages (any homepage, including a freshly added placeholder), while the fallback notice keeps the stricter "real content" rule so a placeholder never masks "no content in your language".
  • Demo content table now lists exactly the languages IntraVox ships bundled demo content for (Dutch, English, German, French), independent of the deprecated enabled-list (German was previously missing). Hint reworded accordingly.
  • Source strings aligned with the Nextcloud translation guidelines (#63): sentence-case for headings/labels/buttons (e.g. "Demo Data" → "Demo data", "API Token" → "API token"), a non-breaking space before every ellipsis, "GroupFolder"/"Team Folder" → "Team folder" wording, real gettext plurals for relative-time and file-count strings, URL/placeholder values removed from t(), and the redundant translated language-name helper dropped (the picker uses Nextcloud's own localized names).
  • Complete Dutch, German and French UI translations bundled (all ~1220 interface strings, including plurals). After the source-string cleanup the Transifex resource was re-provisioned without the earlier translation memory, so these are shipped in l10n/ and also serve as translation memory for the next Transifex sync — the community can refine them online from a fully-translated baseline instead of from scratch.

Fixed

  • "Add language" actually creates the content folder now. It silently failed before: LanguageHomepageService wrote to getUserFolder('intravox'), but there is no intravox system user ("Backends provided no user object"), so nothing was written — while the UI optimistically showed "Language added". It now writes via SetupService::getSharedFolder() (the same GroupFolder path demo-data uses), and the frontend reads the real server state instead of guessing, surfacing an error if the write fails. Adding and removing a language now triggers a synchronous groupfolders:scan so the change shows up immediately in every user's view and the Files app — without it, an added folder stayed invisible and a removed one lingered as a stale entry until the next background scan.
  • 3-letter language codes are no longer truncated. Language codes were clipped to two letters (substr($code, 0, 2) / [a-z]{2} matching), so Asturianu (ast) became an invalid as folder that didn't match its real code. Base codes are now treated as 2–3 letters throughout (ast, kab, …), so adding/removing such a language creates and deletes the correct ast/ folder.
  • Bumped vulnerable dependencies (dompurify, form-data, markdown-it, ws); npm audit reports no vulnerabilities.

Deprecated

  • enabled_languages app-config and the language#setEnabled / language#createEmptyHomepage endpoints are deprecated. The config key is no longer written by the admin UI but is kept in the database for downgrade safety (it is simply ignored by 1.7.0 code).
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLGu99gGuBgb/dL9oReX7t3liWl+nUdx6xXacAH71VZ567hyQ95XSVRziAGTirgeMXo5p/FRSvX7lXfIYdCO71UTDt5evJug1NuDcR77ARGdb59wstOQg5NceDiN+kvKB8ET08m/zqG5F6iDtyaIOFdZuIuKqwQR9QPdX4+UunJhReAQRk699Ssqb/PR1AWjv88MG8JBUSfpa0ZiV2iVsvIkLn6xuPFgzdqvedssa/fQFcGrg9yyHHmgnUe0QBk38D5hDan4SNNGNg003jcK/tUEOTINKUQQoWp3FYFDrb11X4PzwUewDOvBiA0uE/dtiE3NPsap8M9ClE+81wolGu5flksqjvRndHbc2qV4jdbmeevGA18mTRNqb5s1BT4e4q3rWEljFCO9epg5o+UzEV31OefkvCoIYnZIe1nU/d4yl6xGCi/YgtP1f0ayff421vqD0Kda7xu1g0L+OV0vxmvV1oU+3wgwdEfX7Z49k22mUwleeArCOjuluQIuPwC8vNxkyiv+uwhwXyju4f4MqJfNbMDAYjSHNCrYqO+rQBkKQFUZ8qMOtYY0LYQTEmltlLgZA210c+YuBqbeZknBxtJKWf5IeOkMwGttZVUkDhgu+4rufsxs+I8ZbAhxDfBWxyRUyIOYa4cgyZOmuaN71Y0KBP28VSYIxJfkaAXKB/E4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.6.1
Release Details
UpdatedJune 14, 2026, 3:36 p.m.
Changelog

Bugfix release. IntraVox 1.6.0 declared Nextcloud 34 support but crashed on occ app:enable intravox:

Error: Call to undefined method OC\Server::getAppManager()

Nextcloud 34 removed the legacy \OC::$server->getXxx() getter shortcuts on OC\Server. The 1.6.0 NC34 audit only checked the public OCP\* API surface and missed these internal OC\ getters, which were still called in lib/. During install the repair step (SetupDemoData) hits SetupService::isGroupFoldersAppEnabled(), so the crash aborted app:enable entirely.

Fixed

  • App can be enabled on Nextcloud 34 again (#58). Replaced every removed \OC::$server->getXxx() getter with dependency injection of the stable OCP\* interfaces across 11 files (SetupService, PermissionService, ApiController, PageService, PhotoStoryController, PreviewController, LicenseService, DemoDataService, OrphanedDataService, ImportDemoDataCommand, ImportPagesCommand). Getters migrated: getAppManagerOCP\App\IAppManager, getUserManagerOCP\IUserManager, getDatabaseConnectionOCP\IDBConnection, getURLGeneratorOCP\IURLGenerator, getMimeTypeDetectorOCP\Files\IMimeTypeDetector, getConfig → injected OCP\IConfig. These interfaces are unchanged across NC 32/33/34, so a single codebase keeps working on all three.

Removed

  • Dead $nextcloudPath = '/var/www/nextcloud' field in SetupService (unused, and wrong for non-default install layouts).
  • Redundant \OC::$SERVERROOT-based demo-data path fallback in DemoDataService::getBundledDemoDataPath(); IAppManager::getAppPath('intravox') already resolves both apps/ and custom_apps/ layouts.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWy0T0lmM8uWfR36zg8kC6FuQgij2PPpmHKD773BWRd8ARdh56W6m9tw6QQNBgUWIQ5cNahUZINEJPVCUmHVBbFA3e/DSndhZ2BBCXHSnAF5JyJu+LAzII3RYpPI8FQi8dW4YM0vqatnbYi+jeJwq9029rjJ7fq8Rgansx4vsi9sIxzszrDtBTzPSNeXEUxDzHMIhX8urvA71wdHUjhCKQDStFMgn4UR0ts+pr7vpl+GcbbEI5g4ySvBehKGYsSSWBea8oGQXR7EuIDmaAqk7PRp3PUdh91afXWQTNaDnx1e0yinXD5MURzxa91k8cfik+g9bsmSU2wbxcuKFOXKxujpPJTM4Qm0Rm48QLkDeoSHyZPzSDUtAcFvfP020hW64jfeXgMFEIF0OIm20z6WnxjimJa7Nbr3v+3RZMiCxJa7EzpK4chKlX2MHVGXm16/tUOwU1VUf2OEm+99AfGQqwImcKKbLS8Y9Ysk+pm9BmzF7y4nCpTbiBZmBF0K6Cuwk0QAj2ThQnjW3rDxOJ4oAkiuaIXC+4E3z67pWeSzkMiIC6B5zRpsSHu7jteX9PBxMQJOEG1prE13sLJaX48KzLA6iYcxx2gCwF29wgpwsAujHwNQu82JQWPSHjnvPmm+yfxHbDPDvuxG/2BaGgsQzHOorqdZbIcUPTuJyyOLeWww=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.6.0
Release Details
UpdatedJune 13, 2026, 11:59 a.m.
Changelog

Major release with three themes: Nextcloud 34 compatibility, community translations via Transifex, and admin-curated language activation. Plus PhotoStory lightbox fullscreen + "Open in Files" originally drafted for 1.5.6 are folded into this release. No data loss on upgrade — existing installs keep their four configured languages enabled by default.

Upgrade safety contract

This release respects seven rules so existing installs cannot break:

  1. No language folder is ever deleted automatically — not on toggle-off, not on upgrade, not by cleanup.
  2. Default for installs upgrading from 1.5.x is ["nl","en","de","fr"] — exactly the previous hardcoded set.
  3. The Version10600 migration only seeds the config key; it never creates or removes content folders.
  4. English cannot be disabled — it is the guaranteed fallback for every code path.
  5. License page-counts stay per-language and are not reset when a language is toggled.
  6. Cache invalidation runs automatically when the admin changes the enabled set.
  7. occ upgrade from 1.5.x → 1.6.0 produces zero user-visible changes (until the admin acts).

Added

  • Nextcloud 34 compatibility declaredinfo.xml now ships <nextcloud min-version="32" max-version="34"/>. Audit results: zero removed-in-NC34 OCP PHP APIs referenced in lib/; all five OC.* JS globals IntraVox uses (OC.dialogs.filepicker, OC.MimeType.getIconUrl, OC.L10N.translate, OC.requestToken, OC.webroot) remain functional in NC34 stable (deprecated, scheduled for migration in 1.7); bundled @nextcloud/vue (9.8.1) and Vue (3.5.22) match NC34's ship versions; PHP >=8.2 matches NC34's >=8.2 <8.6 requirement.
  • Transifex-ready translation pipeline — IntraVox is now packaged for community translations via Nextcloud's Transifex pool (o:nextcloud:p:nextcloud:r:intravox). New .tx/config + .l10nignore + l10n/.gitkeep + committed POT template enable the Nextcloud l10n sync-bot to open pull requests with new translations as they land. Resource provisioning requested via docker-ci#951. The four existing languages (NL/EN/DE/FR) continue to ship in l10n/*.json until the resource is online.
  • Admin-curated language list — new "Available languages" section at the top of the Demo Data tab in admin settings. Each language IntraVox ships a translation for appears as a checkbox; the admin ticks which ones should be active in the intranet. Disabled languages disappear from IntraVox menus, navigation, and the demo-data table, but all their content stays on disk and reappears the moment the language is re-enabled. English is always enabled and cannot be unticked.
  • Empty homepage on language activation — when an admin enables a new language (one without bundled full-intranet demo data), IntraVox creates an empty homepage in the content folder so the language is immediately usable. Idempotent: never overwrites existing content.
  • New LanguageService, LanguageController, LanguageHomepageService under OCA\IntraVox\Service\* and OCA\IntraVox\Controller\* — the single source of truth for "what languages are shipped" (auto-discovered from l10n/*.json) versus "what languages are active" (admin-controlled, persisted in oc_appconfig.intravox.enabled_languages).
  • PhotoStory lightbox: "Open in Files" button in the lightbox topbar, plus a clickable filename in the details panel. Both open the photo's parent folder in the Files app in a new tab. A new server-side endpoint /api/photo-story/open-in-files?file_id=N resolves the user-relative parent path (including federated/GroupFolder mountpoints) and 302-redirects to the Files view — the API's path field is storage-internal, so building the URL client-side would 404 on those mounts.
  • PhotoStory lightbox: swipe-down-to-close on mobile — vertical swipe over 100px closes the lightbox, alongside the existing horizontal swipe for prev/next.

Changed

  • All hardcoded SUPPORTED_LANGUAGES constants replaced — 12 services that each defined their own copy of ['nl','en','de','fr'] (PageService, DemoDataService, LicenseService, NavigationService, SetupService, FooterService, SystemFileService, FeedService, OrphanedDataService, ExportService, PagePathHelper, plus 2 OCC commands) now read from the central LanguageService. License page-counts only enumerate enabled languages; RSS feeds only include enabled languages; the orphaned-data scan recognises any language that's ever been shipped or enabled so it can never accidentally flag legitimate content as orphaned.
  • Navigation fallback unified on EnglishNavigationService::getCurrentLanguage() used to fall back to 'nl' for unknown user-locales. It now falls back to the universal English default, matching the rest of the codebase and the Transifex source-of-truth.
  • SetupService upgrade migrations now language-awaremigrateResourcesFolders(), migrateTemplatesFolders(), and migrateVersioningFolders() now iterate over admin-enabled languages and skip language folders that don't already exist on disk. The result: occ upgrade from 1.5.x → 1.6.0 touches exactly the four folders the install already had, never creates phantom folders for new Transifex-discovered languages.
  • Demo Data tab filters by enabled languages — only ticked languages appear in the install-status table. The "Full intranet" content option remains bundled for NL+EN only; other enabled languages show "Homepage only" and use the empty-homepage flow.
  • POT generation uses Nextcloud's official translationtool.pharscripts/generate-pot.js is now a thin Node wrapper around the same binary the sync-bot runs (create-pot-files task). Zero drift between local extraction and what Transifex sees. Replaces a custom en.json-based extractor that produced inflated POTs containing ~820 stale msgids the bot would have stripped anyway.
  • Plural-form overrides for JA/KO/ZH/TH/VI/ID (1 form), FR/PT (n > 1), PL/RU/UK/CS/SK (3 Slavic forms), SL (4 forms), AR (6 forms) — ported from IntroVox's regenerate_js_translations.py so non-Germanic languages render correctly when their pluralForm field is absent. Without these overrides Asian and Slavic translations rendered with the wrong plural rule.

Fixed

  • PhotoStory lightbox: Nextcloud header overlapped the topbar — the lightbox sat at z-index: 100000 but the NC header (z-index 2000) stayed visible because parent containers create stacking contexts (transforms/filters) that trap position: fixed children. Wrapping the template in <Teleport to="body"> escapes the trapped context; the lightbox now genuinely covers the full viewport.
  • PhotoStory lightbox: date/location pill unreadable against light photos — the translucent pill background disappeared against bright photos (white walls, snow, paper). Darker background, stronger backdrop-blur with saturation, subtle border, heavier drop-shadow, plus a text-shadow fallback for browsers without backdrop-filter.
  • PhotoStory lightbox: body scroll-lock on open — the page underneath could be scrolled with the trackpad while the lightbox was open. body.style.overflow = 'hidden' is now applied on open and restored on close.
  • PhotoStory lightbox: iOS notch / Android status bar in fullscreen — topbar now uses env(safe-area-inset-*) padding so the close button doesn't hide behind the notch.

Removed

  • Stray l10n/*.po files — replaced by the canonical Transifex output path translationfiles/<lang>/intravox.po. The PO files in l10n/ were never used by the Nextcloud runtime (which reads .js + .json) and only created dual-source confusion. Bundled translations remain in l10n/{nl,en,de,fr}.json until Transifex onboarding completes.
  • PageService::SUPPORTED_LANGUAGES constant — and 11 sibling constants across the service layer. All logic now routes through LanguageService.

Internal

  • New migration Version001600Date20260609000000 — pure config-init, seeds intravox.enabled_languages with the legacy default on first upgrade. Idempotent.
  • PagePathHelper stays a pure helper — its language-code set is static-class state synchronised once per request from Application::boot(). Avoids piping LanguageService through every caller of a previously side-effect-free helper.
  • AdminSettings initial state expanded — admin UI receives availableLanguages, enabledLanguageCodes, and defaultLanguage server-side, no separate fetch needed on tab open.
  • RELEASE_CHECKLIST.md rewritten with the full Transifex pipeline diagram and two adopted IntroVox v1.7.1 gotchas (GitHub-bot divergence, near-empty-language conflict resolution) so the next release doesn't repeat IntroVox's mistakes.
  • scripts/generate-pot.js rewritten as wrapper around translationtool.phar (downloaded + cached under scripts/.cache/ for 7 days).

Notes

  • The first Transifex sync PR will land only after a Nextcloud team member provisions o:nextcloud:p:nextcloud:r:intravox on the Transifex server. A GitHub issue on nextcloud/docker-ci requests this. Until then, translation files remain manually maintained for NL/EN/DE/FR.
  • Disabled-language pages don't count toward the free-tier 50-pages-per-language limit. This is the intended behaviour: organisations get back unused-language capacity once they curate the list. Re-enabling a language re-counts.
  • The bundled LANGUAGE_META map in DemoDataService still hardcodes display names and the "has full intranet demo" flag for NL/EN/DE/FR. New Transifex-shipped languages will appear in the admin UI with their base code as the name (e.g. "es") until they're added to the meta map. Cosmetic-only; activation and content management work either way.
  • Cosmetic legacy still in code: five OC.* JavaScript globals (deprecated since NC 26-30) — migration to @nextcloud/* equivalents is planned for 1.7. Works on NC32-34 today, may break on NC35 if Nextcloud removes them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureTf7ZtlGWgI9TvkiQXT6xXf2fHFVS7KIq4LEB/evxDo4c/+mV4vL14flkwjF+dH6wtwnwbgjdFXGW3YPGcpWb5EU/ulDXwplwsPL3M+JxJGOgUtVR3DpMufuel27aggb9QKJeV1MGmlqyZivWUn9PgHtHciWghT1F2Xab3ui7YSFtC0UYlZm94f1J54payg2/5eQWZBr2odtZ0yIUc8IlIlYaYApDWcMr0NX52EX9DRFE33G0SqpB9L06WDu2BRxbesistv1KNp0IN6CDajkrs9dNPe0O6IIPW+9Ryo4oO2xjAzKKfwu+84egH611IkMhheumimFL7zeQZ3GE2VDQC26A/fE0S8Xo+uoHF63NliWIZvtvKPCDecHsVozYGoLm9Tdu3R+V1vNRgy8OeNg6VF1qNAup+YN6WFOxw+ftpKe526KCNHETQOdwp7JqEU4I0miYRJdo8GT6nEOC/MD4eBNsMLUxubt4iH1emd/PzvGPmUppF+iCudLzUCPYHG2xMyTDQprnW0hoBlb/9BCD3csE6lQwqwFsbzX+ITzd5PoMWbHX7Cy7AKQ6Izc3F2ZfAUrCVcoqFwAEiH3c/7RGRCXPxvQ2H50m9vKk8pn7gW8Lo5zu4E+66QaHUjUueLzeQd0AmHfCDdgbicqev0xrWwhk6wQsCLilRmLrpVdy7sw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<35.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.5
Release Details
UpdatedMay 30, 2026, 8:59 p.m.
Changelog

Patch release that fixes #57: clicking-save on a Link widget item whose URL is mailto:, tel:, or sms: would silently empty the URL on save. After page refresh the link rendered as #. No DB migration, no API breaking changes.

Fixed

  • Link widget: mailto:, tel:, and sms: URLs were stripped on save (#57) — Service\Sanitize\UrlSanitizer::sanitize() only allowed http(s)://, root-relative paths, and # anchors. Any other scheme — including the universally-accepted communication shortcuts mailto/tel/sms — was rewritten to an empty string at save time. The widget then rendered href="#" after a page refresh, even though the in-memory edit showed the correct URL until then. The Navigation editor used a different sanitization path (FILTER_SANITIZE_URL without the scheme allowlist) which is why mailto links worked there but not in Link widgets. Allowlist extended to include mailto:, tel:, sms: — three schemes with no JavaScript execution path, part of the default allowlist of DOMPurify and HTMLPurifier. javascript:, data:, file:, xmpp:, matrix:, and bare domains remain blocked. New unit tests cover both the accept and the continued-reject cases.

Notes

  • Existing Link widgets that lost their mailto/tel/sms URL still need to be re-edited and saved once — the empty value is persisted on disk. There is no automatic migration; once saved with 1.5.5 the URLs stick.
  • xmpp: and matrix: remain blocked. They are safe in principle (no JS execution) but unlikely to be intentional in most intranets; add per-need with an explicit code review if you want them. Open an issue if your installation needs them.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCh/CmZ8aQnDr2XuBCui2CiOFzzX9RnHEHBISRDwUZISNfh8j+W8l9zbtlV5dsZ2tjgpT9EfMQCcK0O7Rms0xrEl7tGFWeGB4+3Nr6RlfhR59CFDtiXB1eg/mHhFR5uJBOB8CMhhhCTnN/dkD1np0PCRFJjDbn3lmij92xMOLMwFsaPAvhvRFA1wHn0cy+hUl5ZQyFDHivA7OLdadsh+eMth/Z0WaZJXvHuoWqbUFpGOMGzRmeeIYubZj5NsVslZg6gL93XSul9y5Jllh6IsMCcEwMLdhA3N+G9rLF9QzKUjev3aV1OzH+vVyY6LAhRYTN7k3bAZLOEt7HhuwA5f2bgEPbbjzNgW867foQA8HpAHeczfKSjbWiCOPCFhJ7q0OCIsAf9RJzCXHLUsBbSIDuxQyH35rd0sRL1qmg7hSikMBCs4G2d4/ajzZo34WA5k+R4WFmqhsJiMAm0By5ENBs9dVkAS+E6hxJruM9W/BevyftUjV/guD8YfLy1yByTuUICpA13pnJjo0rxFZmv6Iyo2uwDFZUVzag4RfLok80mXSY6icuKLWsH6mdX+7WaoT1n0v5NqFT38v7dVGG/DWZpF/edJSW5koAJMcr0gHTJ6h0wJzXFf+vx+1XOkJ/1184HStnxv9W9CabTkxRybcwHPwH7AtdH/GytDDG4qVi0k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.4
Release Details
UpdatedMay 30, 2026, 1:53 p.m.
Changelog

Patch release that closes an information disclosure issue introduced by 1.5.3.1, fixes a Leaflet/sticky-topbar layering bug, and brings the bundled @nextcloud/vue in line with what Nextcloud 33 itself ships so IntraVox widgets visually match NC's own apps again. No DB migration, no API breaking changes.

Security

  • FileStory / PhotoStory: source folder path leaked to users without access — 1.5.3.1 added a "You do not have access to this folder" empty-state that showed the configured folder path (e.g. Shalution/Administratie/2026) as context. For a user who is deliberately excluded from that folder, this disclosed the existence and naming of paths they shouldn't be aware of — path names can carry sensitive context (client names, project codes, person names, dated boundaries). The empty-state now renders a minimal lock icon + "You do not have access to this widget" with no folder name and no scan hint. The folder path remains visible only for users who do have access but happen to see an empty result (legitimate context).

Fixed

  • PhotoStory: Leaflet map overlapped the sticky IntraVox topbar on scrollPhotoStoryMap.vue and PhotoStoryDayMap.vue had position: relative with no z-index, so Leaflet's internal panes (default z-index 200–700) rendered over .intravox-topbar (z-index 100) when the page scrolled past the map. Both map containers now establish their own stacking context with position: relative; z-index: 0; isolation: isolate;, capping the Leaflet panes below the topbar without touching Leaflet's own z-index conventions.
  • PageDetailsSidebar tabs visually diverged from NC Files — IntraVox bundled @nextcloud/vue 9.5, while NC 33 ships 9.6+ with a refreshed sidebar-tab look. The result was a different (often "double-underline" feeling) active-tab rendering versus what users see in NC's own Files sidebar. Bumped the bundled @nextcloud/vue to ^9.6.0 (resolved to 9.8.1) so PageDetailsSidebar now renders identically to NC's own sidebar tabs.

Changed

  • Bundled @nextcloud/vue upgraded from 9.5.0 → 9.8.1 (within ^9.6.0 range, matching the version NC 33 itself bundles). No public IntraVox API changes; some Nc* components may have minor visual refinements that come along with the upgrade.

Removed

  • Obsolete .app-sidebar-tabs__nav border-bottom override — the 1.5.1-era CSS workaround in css/main.css was meant to fix a double-underline on NcAppSidebarTabs in NC 32+. With the @nextcloud/vue 9.6+ refresh that override became counter-productive (it removed the hairline that NC's new active-tab rendering visually anchors against, producing the misaligned look reported on 1.5.4-rc). The override has been removed; the look is now exactly what NC Files renders.

Internal

  • RELEASE_CHECKLIST: new section 1b "Dependency parity with Nextcloud core" — codifies the lesson from this release. Before tagging, check node_modules/@nextcloud/vue/package.json against the version NC ships for the target NC min-version (table maintained in the checklist). Visual canary: PageDetailsSidebar tabs vs. NC Files sidebar.

Notes

  • The defensive backend guard PhotoStoryService::assertNotResolvedToUserRoot() added in 1.5.3.1 stays in place. It already returns reason: 'folder_not_accessible' on the 404 response which the new empty-state branches on.
  • Known follow-up: News widget's empty-state still shows Source: {path} for unauthorised users. Same pattern, lower severity (source is usually a page-id, not a filesystem path); tracked separately.
  • Future direction: SharePoint-style audience targeting per widget will eventually let admins hide widgets entirely from users who shouldn't see them. The lock-state introduced here is the fallback for the edge-case where audience-target users lose folder permissions after configuration.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturebdeRHVR20/nH1R+zH2h19G2oU3imUS1G7ErSfoE76L06c1ZdJWAxX3IRoU0uXXw6g1riRPttaiwpkXuype8kPK/9mDqdXZT0WKUtYqSV+dkBjdpe1ODKCrXZhR4WZsDfGpuvzA68HeCYLTk5Zb9LgSwZIcwBfLDaAKK+DzgBuosLV/WepscTkKBAtjb0jOGyfYRQQRXScO4ywNS4Ke9kzTkvqpqlSgStQ8yMVer6cwb7/ToxjGhMSeUy7w0IKS69K2usogY79m28XVmLpaUp/5ky0BxA1+ggtv8Z9tdLCxy+G3S59ndDIXqgCXT6G1eShRFP7PuoQg3rJZK2rhM6hn2oOFX3ZUHDVE9hxpA2Iv67B3u1alq5ZYdmbtppwCFyFmUuOl5juZLHAZc5MG4T0USxIdgorxh2A2rBmuGAdrQk3vJlby8G+apL/hhFaZoUeBi1i7wFS1f62ucSJUKO6IAfAYJUxBDkIVFNboaZeRI30hPAa2yJGbYgAq2vuDuj1eGpewDQ65SNvaitI0LBjj0IQiPYs3DdnLVXDOqpva+VhaiQnA8Iq8TFK55tMyQiCn6QFNWCfTApT6L3W7X1j1GsiMutzjSS3GLLt27SeB/8948hXeR1JqcCLmiqaYt9C5KsbFH/UiMq6AGTungHCm4mxz1jSaGEAXBpsPlAqb4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.3
Release Details
UpdatedMay 30, 2026, 11:35 a.m.
Changelog

Patch release that fixes a "file no longer exists" toast when clicking documents in FileStory, and makes click-to-open behaviour consistent across all mount types. No DB migration, no API breaking changes.

Fixed

  • FileStory: "file no longer exists" toast on click for legacy shared-storage GroupFoldersFileStoryWidget.openFile() preferred OCA.Viewer.open({path}) for inline preview, deriving the path from file.path by stripping a leading files/. That works for personal storage and per-folder jail GroupFolders, but in legacy shared-storage GroupFolders the cache row stores __groupfolders/<id>/... and the user-visible mount-point name (e.g. Shalution) isn't carried on the row. The Viewer received /__groupfolders/4/Administratie/2026/Boekhouding.xlsx, couldn't resolve it against the user's tree, and NC raised the "file no longer exists" toast. Federated shares hit a similar dead-end via a different code path.
  • FileStory click behaviour now consistent across mount types — documents always open in a new tab via NC's /f/<id> handler, which resolves the right mount server-side for personal storage, both GroupFolders mount strategies, internal shares and federated shares. Removed the path-derivation entirely (resolveDisplayPath() deleted).

Notes

  • Behaviour change: clicking a document in FileStory no longer opens the inline NC Viewer overlay — every click now opens a new tab at the file's NC Files location. This trades inline-preview ergonomics for "actually works on every mount type" reliability.
  • PhotoStory is unaffected; its widget uses an internal Lightbox component and never touched OCA.Viewer.open().
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureAJvUlLcI5LNjLuz5DDx6QDyCAMh6j7PTBvzanLh5i26TsW2mHudGF/mCkxku08w9eJvE8ZY0VKFEzkLbbBc0v16RHQ1YO0slEGvbTv6QdrECl8JdmGwU0oDHpWAKlrGOeKRO0b9oDSu7D+Z1mVGlhxxMexJAnpugWDkevjeI1aznx0Di8FNa5KMxT9apIvceQfuHPbBOBPnE2BgjJMQTBWwR0sel8DYmdcd4y5FVKwY/3TlcTqzNLKwujDpqPt4Ihu4GVjS/dltaJqhSVlKJCiyh/w+kmB/RujnoEwLVru+GNhfgggvtr+YbQrwxoCqsoP1xiHeNoIA60/VCINwB0NkZHxXkrjGuTG7lInhzhEgwbl5sDg1JpG3BfQv1Z4R9VIHDXhCxyJT6oH7WbrssaUI0RlZQ2amYMu7a+FBe4+wHau4vD/KkvfOj62YZ6jPksvS140seB7IMYw9gxsw45bjjFS0COXGeIado8437PU17MBvwVGshcQHwdkwSyGTl3HWvXeQ5i4Gt9TiYTjjfmU4KFk83X8PcwB4qYho0yHLsMTZpdEApYTmLMkCrIKkJSk/mKnUQdiLkNnCjCTvZI1YvajTqzZxlNFy7IudFrvP6lyGosRum7OSdCACTQGSauuRMw7bB+J5x6aME6islckUuqmc9vxce92r6/brSurs=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.2
Release Details
UpdatedMay 28, 2026, 5:52 p.m.
Changelog

Patch release with two production-blocking PhotoStory fixes (groupfolder albums and federated-file thumbnails), three UX improvements requested from real use, and one admin-tool clarification. No DB migration, no API breaking changes.

Fixed

  • PhotoStory shows "No photos found" for every groupfolder albumPhotoStoryService::extractStorageAndPath() returned the jailed Node path (e.g. Albums/Doris Synchroonzwemmen) while oc_filecache.path stores the unjailed form (__groupfolders/7/Albums/Doris Synchroonzwemmen or files/Albums/Doris Synchroonzwemmen, depending on which mount strategy the groupfolder uses). The SQL path LIKE predicate matched zero rows, the widget rendered its empty state, and the hint text misleadingly pointed admins at occ files:scan — even though the files were already indexed. The path is now reconstructed by walking the cache wrapper chain for the first CacheJail::getGetUnjailedRoot(), which covers both groupfolder mount layouts as well as any other jailed mount (federated, encryption-wrapped). Root-mode / enumeration also benefits — separate groupfolder mounts no longer collapse into the personal-storage scope.
  • PhotoStory/FileStory tile previews missing for federated files — NC's /core/preview returns 404 for any file on a Files_Sharing\External\Storage mount: the preview providers (Image, Office, PDF) need a local file path or a Collabora/LibreOffice render, and federated files only exist on the remote NC's disk. Result: PDFs, docx, xlsx and even jpg tiles from an OCM share rendered as a generic mime-icon instead of a thumbnail. New shared PreviewController at GET /api/preview?file_id=N&x=400&y=400 closes the gap: local files 302-redirect to /core/preview (no overhead, NC's own preview cache stays hot); federated files are handled by the new FederatedPreviewService which calls the owner instance's /index.php/apps/files_sharing/publicpreview/{token} endpoint and caches the result in appdata/intravox/federated-preview/ keyed by {fileId}-{etag}-{x}-{y}. Cold response ~250–400 ms (~5–15 KB transfer per file, not the file body), warm ~180 ms.

    Three protection layers stack to keep this scalable and friendly to the remote: a per-user rate throttle (UserRateThrottle(600/min)) bounds individual misuse; in-flight deduplication via NC's distributed cache ensures that 50 users opening the same uncached tile at once produce a single outbound HTTPS call (49 wait for the cache to materialise, then read); a per-remote concurrency semaphore (default 8 simultaneous outbound calls per remote host) prevents an IntraVox-server from saturating one owner instance and tripping its IP-throttle. When the cap is hit the request degrades gracefully to the mime-icon fallback. A companion POST /api/preview/warmup endpoint pre-warms up to 16 federated tiles per call; PhotoStoryWidget and FileStoryWidget call it fire-and-forget after every paged fetch so most tiles are already warm by the time the user scrolls into view. Bandwidth scales with viewed files, not with corpus size — fine on 1M-file federated mounts.

Added

  • PhotoStory: hide RAW sidecars when a JPG/HEIC variant exists — DSLRs and mirrorless cameras in "RAW + JPG" mode write two files per shot (IMG_5432.CR2 + IMG_5432.JPG) that show up as visual duplicates in any folder view. New hideRawDuplicates widget option (default on) groups files by (parent_dir, basename-without-extension) and prefers the browser-displayable variant over the RAW. Covers Canon (CR2/CR3), Nikon (NEF/NRW), Sony (ARW), Adobe (DNG), Fujifilm (RAF), Olympus (ORF), Panasonic (RW2), Pentax (PEF), Samsung (SRW) and Sigma (X3F). Implemented as over-fetch + dedup + slice so paginated infinite scroll stays correct; total continues to count physical files (honest source-of-truth for storage cost).
  • Sticky page navigation — header (title + Save/Edit) and navigation bar are now wrapped in a position: sticky; top: 0 topbar so they stay reachable on long pages. Previously a 300-photo Photo Story timeline forced you to scroll all the way back up to reach another page. Dropdowns/megamenus continue to position via getBoundingClientRect(), so their placement is unaffected.
  • Orphaned GroupFolder admin: show what's actually in the folder — the "Content" column used to render the literal "Unknown data" for non-IntraVox orphans, leaving admins to delete blind. OrphanedDataService::analyzeOrphanedFolder() now returns a sampleContents field with the first 8 top-level entries (name, type, size) sorted alphabetically, and the admin UI renders them as a small listing under the badge. The empty-state label also changes from "Unknown data" to "Non-IntraVox data" for accuracy (#56).

Notes

  • The PhotoStory groupfolder fix activates on every groupfolder-hosted album with zero config — existing widgets pointing at a groupfolder path will start returning their photos immediately after upgrade.
  • The federated preview proxy degrades gracefully: if the owner instance can't produce a thumbnail (no Collabora/LibreOffice on their side, or the file format is unsupported there), the endpoint serves a 302 redirect to the matching mime-icon SVG. No broken-image placeholders.
  • hideRawDuplicates defaults to enabled also for existing widgets (the param is absent → backend reads its default). Users with RAW-only albums can untick the new editor checkbox.
  • No DB migration; widget configs are read back through the new optional field transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturemyEi+pL/zo6IBucOaSFT5mI0lcpEe1D/O6I6fF/yEeHWYWnAeylyogGH5pDKz1TFn0b5mhCXPr2bwZDXRq4gkW8dpXkLVDPC9ox3kX/7jwULrvSzXbn7okB18UC0eGDvG3O0VXrVPl0XMveQCjlZ3GYvSi3p2mukoN6vKYXJazEwnioFhh18W39wUZ+/rxQz5MnQKfaWnOBisrv1Js1z4TAOITDII1gSnMcJFFWKepzSaUQbXNjsAjieaV0qshjTM9JAPZiAOGIQEJH6mGM60LgvV9czXdd5g5StTDinr2zK7O/kHe0qia5Z2GjmN50KrLAsmff7nFS4P2qDTov4H8p7Kw+qEClC+Wm0F6p/E3yZ7XWc3KkwU8vk96gXuYJ8yF4zCswLx4YAwSS1QvuACxQBnC+fF42jh/wXJpPylbMrJqeKKY3Ql24TTzUkSX+ZMweoQ4qkb3BQRQPQY/9pyiQrxc/OvpMdicJkl2IGIIYPG/5pLhTEZEZCXtlVRMpcO9LKzLzU1e+Otddyz3DsyXBwcTawwWknmZPhhD7fvSYpQb6dp0pgjWjBnoI7+YCcMI4sKONQUYrTzwA6eCjYRCiAcW30bTsUG27xHGvHT2cTg/JnNfaeYPIEVvWE+qCXKPON39QL/SMPfSJPrCMOptTuW35mpF4A/w4AF+BCq8k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.1
Release Details
UpdatedMay 28, 2026, 10:58 a.m.
Changelog

Patch release that fixes legibility on themed page rows and tightens a handful of widget rough-edges that surfaced in production after 1.5.0. No new features, no API changes.

Fixed

  • PhotoStory/FileStory contrast on dark row backgrounds — filenames, day-headers and meta lines used --color-main-text (dark) regardless of the row's background colour. On Primary (--color-primary-element) rows that produced unreadable dark-on-dark text. Both widgets now accept rowBackgroundColor from the parent Widget.vue (closing a gap with the existing widgets that already consume it) and switch internal text + tile surfaces to a WCAG-paired colour set via two CSS variables (--fs-text/--ps-text + their muted siblings). Tile bodies become a tinted-glass card on dark rows instead of cutting a hard white rectangle through the coloured backdrop.
  • FileStory tile filenames invisible on dark rows — regression from the same root cause: tile bodies kept their --color-main-background (white) while inheriting the now-white filename colour. Tile surfaces, hover state, preview-fallback bg and mime-icon placeholder all lift to translucent white on fs--on-dark.
  • Folder-path "/" silently collapses to empty after savePageService::sanitizePath strips leading/trailing slashes, so a configured PhotoStory/FileStory folderPath = "/" (root) was persisted as "" and rendered as "no folder selected" after reload. New sanitizeFolderPath() wrapper preserves / (and \) as a meaningful "whole drive" marker before delegating to the generic sanitizer.
  • 502/503 during page save — entering edit mode after a FileStory widget existed triggered four expensive folder=/ queries within ~250 ms (the legacy debounce). Apache workers saturated on large libraries. FetchKey watcher debounce raised from 250 ms to 700 ms in both widgets.
  • NcAppSidebarTabs double underline (NC 32 regression)@nextcloud/vue 8.x renders both a 1 px hairline on the tab-strip wrapper and a 4 px coloured indicator on the active tab, producing a stacked double underline in the PageDetailsSidebar. Global override in css/main.css removes the redundant hairline; scoped Vue CSS couldn't reach the data-v--tagged third-party selector.
  • Photo previews missing for common web formatsPhotoStoryService::MEDIA_MIMES was narrower than what users actually drop into their photo folders. Now also includes webp, gif, svg+xml, bmp and video/webm.
  • Empty folder picker returning "" instead of / — NC's OC.dialogs.filepicker returns an empty string when the user picks the root; both editors now normalise that to "/" so the configured value matches the sanitizer's accepted shape.

Notes

  • Default-themed rows (transparent / --color-background-hover / --color-primary-element-light) are visually unchanged; the new contrast logic only activates on saturated row colours.
  • No DB migration. Existing PhotoStory/FileStory widget configs are read back through the new sanitizer transparently.
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureJUDu14MZav9zDCdwASLwOt9QfZFE4mkGdJjWn05l54CySpeTxrouul/CjST66UGcUmHOIM4gNXCBgrEkSACF0vpv1XWOWu6/PWHUmTsoZWretFLxxA/OXlcO6h3/Q0gHqS9TnIAxFCk1fnHbHHD3hGgYAnISLj6gL6s4axrs+h0/JpIon1ZMloUFxt3759D8Oc+LAgV5kNtYIndBkwb1BM89kb3Ri8NfCzZo3+5wo688lAty1cWjjqkOhzoxw6ERPWxRlek4XXB+4V/9a3wY0/gPWXdHb7YlSOgQpS2KB2m+F/YW64NUfCGOdTE8m/jAvw4Mz/ZDWVhtEk8vFgI3P3Sn1n4WxjArYYE5bChuDHa3A+G2sHZAWQ+/FRUHqExcaoK+mRXQGavoih9WkwVS2Bk9bJ6lKAVFwZgkvgD8YuKwiT9xe3tIhaFceYx1OZq90s6xqijZ6Upm6uoNZO8zwY28LwMJpxlOxqy0lyXVbhKQMb5cU9M80S2kmXbWCHJ1Tech4ZMpTdfZTP/MyoDtdqN9AczNCaMoxMRbW42x2FgNMDwBxszBV4q2mWa0LODiqo3X3AubXvJScBL62d3cWbHhGiEoiB4OJP99YlahBMOw8HoOebDrDYYCUnznz3Hh4GZoNFgWk+wtzrbR3Lu/TBimWHEkkYYQZAHr5mIWjsc=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.5.0
Release Details
UpdatedMay 27, 2026, 8:57 p.m.
Changelog

Major release. Introduces two new widgets — Photo Story for photo galleries with EXIF, location maps and an Apple-style lightbox; File Story for document libraries with multi-mode layouts, MetaVox-aware filtering and federated-share awareness. Adds a fresh wave of perf, security, accessibility and l10n polish across the photo + file widget surface.

Added — Photo Story Widget

  • Four layout modes: Timeline (Magazine, Apple or Travelogue style), Highlights (auto-curated top photos), Grid (masonry), and On-this-day (year-over-year retrospective).
  • Lightbox with keyboard navigation (Arrow/Home/End/Esc/Space), slideshow mode with adjustable speed, focus-trap and focus-restore for screen readers, semi-transparent date/location pill that toggles a mini-map for geo-tagged photos.
  • OpenStreetMap integration via Leaflet: optional overview map per widget, per-day mini-maps in Timeline mode, and a cross-folder cluster endpoint for browsable map-driven storytelling. Admin-config aware (NC admin can disable all map features instance-wide).
  • EXIF metadata rendered into a details flyout (people, subjects, camera, location). Reads from NC core oc_files_metadata when populated; falls back to the bundled lsolesen/pel reader as a last resort with a per-request eager-EXIF cap.
  • MetaVox-driven filtering, grouping and sorting when the MetaVox app is installed. Supports cross-folder discovery mode (empty folder + ≥1 filter) for "all my photos tagged X across the instance".
  • Geocoding cache with periodic warmup job for fast country/location lookup on GPS-bearing photos.

Added — File Story Widget

  • Four layout modes: Timeline (per-day / per-month / per-year granularity), List (flat sortable), Tiles (visual grid with first-page previews and three configurable sizes: Small/Medium/Large), and Grouped (by file-type or MetaVox field).
  • Federated-share awareness — incoming OCM shares are detected per-file via a single indexed SQL join (oc_storages × oc_share_external). Federated rows render with a subtle cloud-badge and silently skip MetaVox-fetch since the remote NC has its own metadata database we cannot reach cross-instance. Mixed sources (local + federated under one root) keep full controls; pure-federated sources hide the MetaVox UI with an explanatory banner.
  • Configurable visible columns: Date, File size, Folder path. Date column can render either filesystem mtime or EXIF/MetaVox taken_at. Filename + file-type icon are always present.
  • MetaVox filter-builder, sort, group-by identical to Photo Story but adapted to document use-cases (e.g. group-by archief_categorie for compliance views).
  • Open-in-Files-viewer click target on every row/tile with role="button", Enter+Space keyboard activation and aria-label per item.

Added — Page editor & widget plumbing

  • Widget registration for Photo Story and File Story in the picker, with iconography and descriptive copy.
  • Editors for both widgets with folder picker (NC FilePicker dialog), live capability detection (MetaVox available?, source-federated?), sortable filter builder with type-aware operators (equals, contains, in, year_equals), and persisted widget config validated by PageService::sanitizeWidget.
  • REST API under /api/photo-story/* and /api/file-story/* covering paged listing, capabilities, MetaVox field discovery, location clusters, EXIF detail and range-aware video streaming (Photo Story only).

Performance

  • Paged enumeration via oc_filecache for all primary widget modes — no more full-tree getDirectoryListing() on large libraries. Hard caps (5000 cross-folder, 20k filtered, 200k count) prevent OOM on massive folders.
  • Federated detection is one preloaded SQL query per request, O(1) lookups per file. The previous IMountManager::findIn('/') per-file approach (cause of the 2026-05-27 saturation incident on nc-dev) is gone.
  • clusters, highlights and on-this-day endpoints now go through listPhotosPaged with sane caps instead of the unpaged legacy path that risked the same blast radius as the federated-detect outage.
  • filterFileIdsByScope collapsed from chunks × scopes SQL roundtrips to one ORed WHERE per chunk — at filtered-MetaVox-page scale this drops ~400 queries per page to ~40.
  • extractGroupfolderId memoised per node within a request.
  • Frontend AbortController on every fetch + fetchMore: rapid config changes no longer race stale responses overwriting fresh data, and pending requests cancel on widget unmount.

Security

  • Per-file ACL guard on the slice in MetaVox cross-folder hydration (buildPagedResponseViaMetaVox) using $userFolder->getById(). Bounded to ≤page-size lookups, so sub-folder ACLs inside groupfolders are honored.
  • Filter payload caps: 16 KB JSON pre-decode rejection on both controllers, value-length cap of 200 chars per filter, max 32 filters and 64 array values per filter — prevents pathological-input DoS.
  • Generic 500 messages on both controllers (no $e->getMessage() reaching client); folder-not-found mapped to clean 404 with empty-state payload instead of generic 500.

Accessibility (WCAG 2.1 AA)

  • Tiles, rows and hero elements: role="button", tabindex="0", Enter + Space activation, meaningful aria-label derived from caption/location.
  • Lightbox: focus-trap (Tab cycles within modal, no escape to background), focus-restore on close, counter announced via aria-live="polite", icon-only buttons get descriptive aria-label + aria-pressed where appropriate.
  • Editors: orphan <label> without for= converted to <div class="editor-label"> to avoid mis-association; form controls properly labelled.
  • Reduced motion: @media (prefers-reduced-motion: reduce) honored for Ken-Burns animation, pulse skeletons, and pill transitions.
  • Status regions: role="status" / role="alert" on loading, empty and error states; map-cluster list items keyboard-reachable; federated cloud-badge gets role="img" + aria-label.
  • Alt-text: meaningful (caption / location / numbered fallback) instead of filename for photos; decorative alt="" for tile previews where the parent already labels the action.

Internationalisation

  • Backend month/category labels now route through IL10N::t() (PhotoStoryService::localizedMonth, FileStoryController::extractGroupKey). No more hardcoded Dutch in API payloads.
  • Frontend date formatters use getCanonicalLocale() from @nextcloud/l10n everywhere — toLocaleDateString / toLocaleString / Intl.DateTimeFormat calls in PhotoStoryWidget, FileStoryWidget and PhotoLightbox no longer pin nl-NL.

UX polish

  • Retry button in the error-state of both widgets. Users recover from transient API failures without reloading the page.
  • Context-aware empty messages: distinguishes "no folder selected" / "no documents match current filters" / "folder is empty".
  • Transparent date headers in FileStoryWidget Timeline mode — replaces the opaque white sticky bar that clashed with themed/coloured rows. Count-badge uses color-mix(in srgb, var(--color-primary-element) 14%, transparent) for a subtle tinted chip that adapts to the active theme.

Developer-side hardening

  • scripts/check-import-consistency.js runs in prebuild: detects mixed sync/async imports of the same .vue component (the root cause of a runtime TypeError we hit on 2026-05-27) and fails the build before it ships.
  • scripts/auto-bump-dev.js auto-bumps the patch level on dev deploys so NC's md5(appVersion) cache-buster always changes — browsers never serve a stale bundle after a deploy.
  • Translation files (en/nl/de/fr) synced for all 122 new UI strings added by Photo Story + File Story.

Notes

  • No DB migrations required for the widget functionality itself; existing pages keep working.
  • PhotoStory federated-share awareness is on the roadmap but not yet implemented (single-storage photo libraries are the typical case). FileStory has the full federated-aware code path.
  • MetaVox cross-instance sync remains out of scope: NC core exposes no federation tokens or remote-file-id mapping. Roadmap item.

New Vue components: src/components/PhotoStoryWidget.vue, src/components/PhotoStoryWidgetEditor.vue, src/components/PhotoLightbox.vue, src/components/PhotoStoryMap.vue, src/components/PhotoStoryDayMap.vue, src/components/PhotoStoryFilterBuilder.vue, src/components/FileStoryWidget.vue, src/components/FileStoryWidgetEditor.vue.

Composer: lsolesen/pel added for the optional in-process EXIF reader.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureFLZvFbovK9mQvZvpGHVOIIcY1Wkokfi3grl/FTH48JoSlk35yZ49frh91/2T0Bda+dcFMO1aCpsNd694iEd26hCMp66F+QA8nqYMB0+WCiEUwlDSVT1x7S9MdLch+7LGPrm2A6h1MWsTQGV9pOIOjWtP4rPGv1+Mw+LFEva+CmFep5Kh/w/RaEqvn9LwcDzxx5JEzzme+nYZurAgV6146olp+xl0rCtxM/IPvL5JlZ7NchtiEc0udMvLroBfdOHKRU0aIJY7ZzVdjJJB46a911krwyn9jfcJmqGVrHZtNlp6uwpFKKlXo1fZDdnMsu/YxnVH5XTJOEflsQTB8GWntZa//R5zRRGXX0jj4o/dWNxvRMPD9jvCTO7Wq5oEvyorRcHVCJ70QatCHKNhOqXtq/vvywVZODt3BZk9gtQ5ssv9FFe7JB7zZWS69ZhHcTS9HqzV0UJ3SpSZfjXN0gsCdTlSi6hknGP9X4wvShSjV+DeHeBJoM4EZHVLSZiRjBWBYpqg0ffwj5X5U8VrXIFtIUHwUMXUJzl7Ta3Uwo4liP77h5AA2xInz+IxLAcpAP/ncaLtlrqCvm0PN1QRz3zq9IBaxE0VI7UDIn6S6ojzXQDWHTPaTPfS/e9v7WqPUB4t/o+6PyEulzq8TXq2jpmXcMsEDHQaRAJl5XT4W3h7TMM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.1
Release Details
UpdatedMay 20, 2026, 6:01 a.m.
Changelog

Patch release that resolves all open frontend security advisories flagged by GitHub Dependabot shortly after the v1.4.0 push. No functional or API changes — npm audit fix lifted eight vulnerable transitive packages to patched versions within their declared semver ranges, no package.json edits required. Build, PHPUnit (258/413) and dev-server smoke tests all green.

Fixed

  • axios → 1.16.1 — resolves 11 advisories (prototype pollution gadgets, CRLF injection, header injection, NO_PROXY/SSRF bypasses, DoS via deep toFormData recursion, streamed upload/response body-size bypasses, null-byte injection in URLSearchParams, XSRF token cross-origin leak)
  • dompurify → 3.4.5 — resolves four XSS bypasses (SAFE_FOR_TEMPLATES/RETURN_DOM, ADD_TAGS/FORBID_TAGS short-circuit and function-form, prototype-pollution via CUSTOM_ELEMENT_HANDLING)
  • fast-uri → 3.1.2 — path-traversal via percent-encoded dot segments + host-confusion via percent-encoded authority delimiters
  • fast-xml-builder / fast-xml-parser — XML comment/CDATA injection and attribute-value quote-bypass
  • brace-expansion → 5.0.6 — DoS via numeric range that defeated documented max protection
  • follow-redirects → 1.16.1 — custom auth-header leak on cross-domain redirects
  • postcss → 8.5.15 — XSS via unescaped </style> in CSS stringify output

After the bump npm audit reports zero vulnerabilities.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDc0e6XrFG/+dkBa2rqaitf3dwAEkyMJA/wqM2F2ZDIp+L9644GrNvZpexYR5xe/IEL4TR6gu1JHpUs2nqxnQ/Wgm8miJwi8+/9Jgg1bjc93k11siFiM8ca+ljWMlJ9Ai1UofzB8tdX2UqOPc1jzPMJwttj1+vYNBIrmD8Ypdubmnw6U3VDP/vSVwwR7I9O08D0DT/f6YGPRa4reXbqHRRllXRUgKXCXL0EWITQ1uwV/XoipV2U35G/BjFwOsQV370teRvY9aMarNl1j86d9N2O+cFMRokMVD/feZNeDXJ1jKh6UxOGPSuJZiQFEVdwMmyyH1MXYy3xh52ZI01G+je1GvGPwzpouTvZzDMYYdsNFepGZtNl1nDBH8THuNnEnMCyBxCPabrlNfBPH9GFdDSPjFptQjZ+ec3/UJHCIqAQHV2no41W5KEBCJTHGf/ex4tU3LIUGGZeTPGmdYCHvH4VNqqqHffL88FqFCKHNO6kWrqnHaFGNwfxsM5uNeYKlZttEzinZzg0Y+ka+e6p0Ko6YNlzG98rpngbyWFM/CVEliEoVYnOsPGHhoV2/GLxMc9JjjRJEBSrRCU7WXCqVQNr8hOLy/qlfvkCnKv2E9YHv4lTKKMayDmJWE0iFCF8DfoA2eHyfLt/6bWSsMzEGERpu4Z/N6EDeoEAws+tfk3No=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.4.0
Release Details
UpdatedMay 19, 2026, 8:39 p.m.
Changelog

This release lays down the foundation IntraVox needs to scale cleanly to Nextcloud Enterprise customers with thousands of users on multi-node deployments. Two themes: PageService gets split into focused, testable services, and the caching layer gains group-aware keys + a content-addressable distributed cache + a frontend prefetch pipeline.

User-visible: pages and navigation are noticeably faster on warm caches, especially for groups of users that share the same permission profile. Cold-cache latency is bounded by a new background warmup job. No breaking changes; every public API is unchanged.

Added

  • Subtree support on GET /api/pages/tree — Optional rootPageId query parameter narrows the response to the subtree rooted at the page with that uniqueId. Resolves #45 from JustinDoek (teamhub app builder) who previously had to combine listPages + getBreadcrumb to list pages under one anchor. Backward compatible — without the parameter the full tree is returned as before. The same parameter is available on the <PageTreeSelect> Vue component (rootPageId prop) for in-app subtree pickers (lib/Service/Path/PagePathHelper.php::findSubtree, lib/Service/PageService.php, lib/Controller/ApiController.php, src/components/PageTreeSelect.vue)
  • ETag / 304 conditional responses on GET /api/pages/{id} — Browser revalidation now returns a 304 with zero body when the cached page is still current. Per-user group hash is included in the ETag so a permission change automatically invalidates the cached entry without leaking content across users (lib/Http/EtagBuilder.php, lib/Controller/HasConditionalResponse.php, lib/Controller/ApiController.php)
  • Group-hash cache key for page tree + permission map — Tree and navigation caches are now keyed by a hash of the user's group memberships instead of their user-id. At enterprise scale (1000+ users in ~10 groups) this turns thousands of cache entries into dozens — same correctness, two orders of magnitude less memory. Permission path-maps are cached per-language (one entry per supported language, shared across all users) (lib/Service/GroupContextService.php, lib/Service/PageService.php, lib/Service/PermissionService.php)
  • Event-based cache invalidation on group changes — Adding or removing a user from a group flushes the affected distributed caches via UserAddedEvent / UserRemovedEvent listeners. Group permission updates propagate within one request cycle instead of waiting for TTL expiry (lib/Listener/GroupMembershipChangedListener.php)
  • Page-content distributed cache with mtime-indexed keys — Sanitized page output is cached under content_{uniqueId}_{mtime}; a write bumps mtime, the next reader misses cache and rebuilds. The expensive sanitize-pipeline (~500 lines of widget processing) only runs on cache miss (lib/Service/PageService.php)
  • News widget result cache with version countergetNewsPages() results are cached per {lang}_{groupHash}_v{counter}_{paramHash}. Mutations clear the cache; subsequent reads rebuild from a fresh counter state (lib/Service/PageService.php)
  • Frontend prefetch servicesrc/services/PrefetchService.js speculatively loads pages on hover (desktop, 100ms delay) and IntersectionObserver entry (mobile, 200px rootMargin). Respects navigator.connection.saveData so users on metered connections aren't surprised by extra requests; max 3 concurrent in-flight requests. Writes through the existing CacheService so real navigations pick up the prefetched data instantly
  • LRU eviction on localStorage quotaCacheService.set() now catches QuotaExceededError, drops the persistent entry with the earliest expiry, and retries once. Prevents silent cache-write failures on heavy intranets
  • Background cache-warmup job — Runs every 15 minutes (TIME_INSENSITIVE) and pre-warms the path-map + tree + navigation caches for each supported language. Prevents the cold-cache thundering herd after a deploy or after a page mutation (lib/BackgroundJob/CacheWarmupJob.php)
  • RequestTimer infrastructure — Light static utility for measuring p50/p95 latency of expensive operations. Used internally for ad-hoc profiling; not yet wired into TelemetryService (lib/Performance/RequestTimer.php)

Changed

  • PageService.php is 615 lines smaller — From 6135 to ~5520 lines. Ten pure helpers extracted into focused, individually-testable services. PageService remains the orchestrator for filesystem + cache + permissions, but the sanitize, format, search, path and template logic now live in dedicated modules:
  • lib/Service/Sanitize/HtmlSanitizer.php (strip_tags + style-property whitelist + entity decode)
  • lib/Service/Sanitize/UrlSanitizer.php (schema-whitelist for link URLs)
  • lib/Service/Sanitize/ColorSanitizer.php (NC theme-vars + hex + rgb/rgba)
  • lib/Service/Sanitize/MediaSanitizer.php (filename + SVG + image-header validation)
  • lib/Service/Version/PageVersionFormatter.php (NC-style "X sec/min/hour/day ago" + metadata accessors)
  • lib/Service/Template/TemplateMetadataExtractor.php (preview summary: column count, widget mix, complexity bucket)
  • lib/Service/News/NewsContentExtractor.php (excerpt, first-image, markdown strip)
  • lib/Service/Search/PageSearchHelper.php (snippet extraction, per-widget-type scoring)
  • lib/Service/Path/PagePathHelper.php (depth, page-type, department slug, current-page marking)
  • lib/Service/Util/PageIdUtils.php (sanitizeId, RFC 4122 v4 UUID, php.ini size parsing, formatBytes)
  • Test suite grew from 78 (with 36 errors) to 252 / 401 assertions, all green — Existing Controller tests were updated to match the current constructor signatures; a fresh unit-test layer covers every extracted service

Fixed

  • Cache-invalidation gaps closed across page/nav/media/import flows — Discovered during dev verification of the new caching layer: several mutation paths wrote to disk without flushing the distributed caches introduced by PR-3 / PR-12 / PR-13, so changes were invisible for up to 5 minutes after a save. Now resolved:
  • PageService::createPage flushes after writing — without this, the new page sat behind the 5-minute tree-cache TTL (visible on "Create from template" — page appeared in the breadcrumb but the editor mounted blank until reload).
  • PageService::createPageFromTemplate re-fetches through getPage() so the response includes enrichWithPathData + the sanitize pipeline. Previously the API returned half-populated page data and the editor rendered blank until a manual save round-tripped through the real read path.
  • App.vue::handleCreatePageFromTemplate uses the enriched backend response directly instead of doing a second selectPage() round-trip that occasionally 404'd against a freshly-created folder and bounced the user back to the home page. URL hash, local pages array and frontend CacheService are all warmed in one synchronous block before the editor mounts.
  • ImportService::importFromZip flushes all PageService caches after a bulk import — without this, 50+ imported pages were invisible in tree, navigation and news widgets for the next 5 minutes.
  • NavigationService::saveNavigation flushes intravox-pages + intravox-permissions after writing — previously a menu edit landed on disk but the path-map cache (PR-3) served the old menu for 5 minutes.
  • PageService::uploadMedia + uploadMediaWithOriginalName flush the per-page content cache so the next page-render reflects the just-uploaded asset (important for image overwrites where users otherwise got the cached old version back).
  • Public PageService::invalidateAllCaches() introduced as the cross-service hook for the import path (kept internal clearCache() private; only the audit-driven external use case opens it up).
  • Actionable error messages on failed ZIP imports — Resolves #52 from @apesorguk, who saw only "Import failed. Please check the ZIP file format and try again" when uploading a cloudron Nextcloud backup. The five validation errors in ImportService (invalid ZIP, missing export.json, invalid JSON, unsupported version, incomplete export) now bubble through a typed InvalidImportException and reach the user with copy that tells them what went wrong and how to fix it ("Make sure you uploaded an IntraVox export, not a Nextcloud Files backup..."). HTTP status is now 400 for these instead of 500. Generic failures still hide behind an errorId so server paths don't leak. A NcNoteCard above the import form spells out the supported format up front. Error messages translated to NL/DE/FR via a stable errorCode (INVALID_ZIP, MISSING_EXPORT_JSON, INVALID_JSON, UNSUPPORTED_VERSION, INCOMPLETE_EXPORT) the frontend maps to localized strings (lib/Exception/InvalidImportException.php, lib/Service/ImportService.php, lib/Controller/ApiController.php, lib/Controller/ImportController.php, src/components/AdminSettings.vue)
  • Broken Controller test suiteApiControllerTest, BulkControllerTest, AnalyticsControllerTest now compile against the current Controller constructor signatures. The OCP stub gained ISession, ICache, ICacheFactory, IGroup, group-membership events and Files_Versions\IVersion to keep unit tests runnable without a full Nextcloud install
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturer9Dvf1Sv0MUqG5zMrZC7vrTGxJ/b/FMFLIQaX9apeRGFYpfb4hH4Zsbt+aKCbyoRj3zOGtdytKpqUDEXZ9jFexiNrkKjfWOvW8XSH1dlFHc6Vo/z+h7Ms+02xgNdSxajfN0yJK0WnDDfhEUn1j9VaByfKuF9VaMVwHL0u4A+k2LwCW0izMkZVjLtiJk/1VyA7pc4Olz+6eWyF0QaKkTXyMmbibugQNrRjRCAylR8up/tSlgi4aTobGMZKkoeZg+HK5KfQXiZHoC4B3GiP3Vf/CfzU0WYyhq7sOZ4LM7PUtgZwcJyUMk5i12oS56Nf+4Umubrn6OaupdmOmgSbCbN3G1K7HWgRpYGqmdDdqzIajzm/lt2vV5gtW4PUyY1ESAh5F1Cch/h/+HWndtyQZDkKgX0jgXtKttltXJbC4/+LQWPIDmffP8ve12tSpCYcENQdvV8rtGkS4aAH0Mf3jiqa8oNtpr7VgwslCHEhrSXxMz1mprSO+x+R3wqWmo+JCo9QmPnwT9nhf81CtvazMkZ2zmzrGX4EegRNpILLPbR3BwrV214CHpu6lnE9zZlCqU9/pXyJoutDUrGtk8gqD3tl2heAy4EcEOIgnHOYx72Q14HXk227XA61Qvq02dp/+lQKLtiEBByL5ZkT/FYQsgyZsEM4p9YBMXr9/ZzmTDrG1k=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.4
Release Details
UpdatedMay 8, 2026, 8:11 a.m.
Changelog

Identical content to 1.3.1 (released earlier today). The version number is bumped to 1.3.4 because an internal 1.3.3 build was published to the App Store on 2026-05-06; instances that picked up that build would not see 1.3.1 as an upgrade. 1.3.4 ensures every existing install gets the editor/table improvements and the privacy cleanup of [1.3.1] below.

No code changes vs. 1.3.1.

Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureBQtsgQvlSPO/vsSYvRbB2PBuBbivwcUewzg126b/lwuFwdLoS/6+o9m1Kahs/ZxLur3f6fBRJEw2fZOh85ofBGQbd6o3KFJtLkUzZZ3/zsfiwbxlUCaNiO3hnuF5UHqpumyiL2bQO2BzaYHCn0G+82UonzYOsvbhMMwVIJeL3oCis3B9Z0+lB6KkCtAuE0mGLybehJ0Sa1KG326gf69OopoE94ikLowwxOPFmFJx6944rmk7axG92CtAV4x68WI8imrKPY59lAt3VI4+YiAXWdjyGKrG08yPi30AjnMwW5raab78hiySW1mIKcpMd8UaDVfKz19oG3MnRz7TpVSzADxuxx5ueuP1sV58e+5UU/Uv2OcghdnFSdyiSCHGQokUqUi63q0QV74517WQgdnmygJRXR+YwYfOn/AhhhKXSeyb/KFIlHoTTdM+gNysJldCBktY49ZEKGhi5AJkGW2jzZ3+hVW1PZylTqV9HRq/ZgFVukYJdPYsWV5UQ8XzN+vYcLuYsPMBWxfKeuecfdzjChZ6sxseqIYyqk2WzN/hBZLbzuQODvroGmb7nPzQsJHolgv7YcCLk0EexuyI2FdYUpI3UKSes9jqAIdLsRylBsgtnVNV6pe53IX3NjWgYubA2VQWgzMM5hFjiM9Q2PyebaXDb7n/LTl73D/qy/0guHw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.1
Release Details
UpdatedMay 8, 2026, 6:34 a.m.
Changelog

Added

  • Text alignment — New alignment dropdown in the text editor toolbar (left, center, right). Alignment persists through save/reload using CSS classes in markdown storage. Supports paragraphs and headings. Keyboard shortcuts: Ctrl+Shift+L/E/R. Custom TipTap extension uses CSS classes instead of inline styles for DOMPurify compatibility (textAlignExtension.js, InlineTextEditor.vue, markdownSerializer.js)
  • Blockquote button — New blockquote toggle button in the text editor toolbar. Uses the existing StarterKit blockquote extension — only the toolbar button and read-only styling were missing (InlineTextEditor.vue, Widget.vue, Footer.vue)
  • Nextcloud Extended Support telemetry — Telemetry payload now includes hasExtendedSupport (boolean), sourced from Nextcloud's public OCP\Util::hasExtendedSupport() API. Helps us understand which share of IntraVox installations runs on Nextcloud Enterprise / Extended Support — relevant for compatibility prioritization and the Nextcloud ISV partnership. Falls under the existing telemetry opt-out (no separate consent), and is listed in the admin "What we collect" overview for transparency. No personal data, just a single yes/no per instance (TelemetryService.php, SupportSettings.vue)
  • Persistent column widths in tables — Column widths an editor sets by dragging the TipTap resize handles now survive save/reload. A post-render hydrator in markdownSerializer.js builds a <colgroup> from data-colwidth (modern) or colwidth (legacy) cell attributes and any pre-existing <col style="width: Xpx">, then converts pixel widths to percentages so the table always fits its container — even when the saved widths sum higher than a narrow page-row column. Tables without explicit widths keep the previous auto-layout behaviour (markdownSerializer.js)
  • Table width presets — New "Width" row in the table toolbar dropdown with presets Auto, 25%, 50%, 75%, 100%. Stored as data-table-width on the <table> (InlineTextEditor.vue)
  • Table alignment — New "Alignment" row in the same dropdown with Left/Center/Right buttons. Stored as data-table-align; rendered as margin-left: auto / margin-right: auto so a 50%-wide table can sit left, centered, or right with surrounding text (InlineTextEditor.vue)
  • Free-form table width drag handle — A custom ProseMirror plugin adds an 8px-wide drag area on the right edge of the active table. Click+drag to set any pixel width between 80px and the widget container's width; the resulting style survives save/reload via the same hydrator. Coexists with the column-resize handles inside the table — different hit zones (tableResizeHandle.js, InlineTextEditor.vue)
  • Horizontal scroll wrapper for wide tables — Tables wider than their page-column scroll horizontally inside a .tableWrapper div instead of pushing the page layout sideways. Read-mode wraps every table via the hydrator; edit-mode reuses TipTap's built-in .tableWrapper element with the same styling, so what the editor sees matches what readers get (markdownSerializer.js, Widget.vue, InlineTextEditor.vue)

Changed

  • Toolbar reordered — Text editor toolbar reorganized into logical groups based on analysis of 10 popular editors: (1) Inline formatting: B, I, U, S (2) Block structure: Heading, Lists, Blockquote (3) Alignment dropdown (4) Insert actions: Link, Table. Compact mode follows the same grouping in the "More" dropdown (InlineTextEditor.vue)
  • Alignment as dropdown — Text alignment uses a single dropdown button (like the heading dropdown) instead of 3 separate buttons. The button icon dynamically reflects the active alignment. Keeps the toolbar compact on all screen sizes (InlineTextEditor.vue)
  • Telemetry includes license key for Enterprise claim verificationTelemetryService::collectData() now adds the configured license key (or empty string for community instances). The license server uses it to verify hasExtendedSupport claims against the bound license_usage row before honoring them; without this binding the boolean would be anonymously spoofable. The key is the same value the app already sends to license validation/usage endpoints, so this introduces no new disclosure (TelemetryService.php)
  • Table cell text wrap policy — Cells use overflow-wrap: anywhere (CSS Text Module Level 3) so long unbreakable tokens (URLs, hashes) wrap mid-word when needed. Edit-mode and read-mode use the same rules so what the editor sees is what readers get. Replaces the deprecated word-break: break-word combo with the modern one-line equivalent (InlineTextEditor.vue, Widget.vue)
  • Page rows allow narrow content.page-row, .row-content, .page-grid got min-width: 0 and max-width: 100% so a wide table inside a multi-column row no longer forces the row beyond its viewport. The grid columns now use repeat(N, minmax(0, 1fr)) instead of repeat(N, 1fr) so a 1fr track can shrink below its content's min-content (PageViewer.vue, PageEditor.vue)

Fixed

  • Aligned text not surviving save/reload — Content with text alignment was escaped to raw HTML after saving and reloading. Root cause: markdownToHtml() had a validation check (html === preservedMarkdown) that incorrectly treated HTML blocks passed through by marked as a parse failure, triggering escapeHtml(). Fixed by skipping this check when content starts with < (markdownSerializer.js)
  • Table widths and alignment getting stripped on savedata-table-width and data-table-align were not in the DOMPurify allowlist, so user-set widths and alignment from the table dropdown silently disappeared after saving. Added to the allowlist together with the <div> tag we now use for the scroll wrapper (markdownSerializer.js)
  • Text overflowing table cells — In fixed-layout tables, long text in a cell could push past the cell border into the next column or beyond the table edge. Multi-cause fix: paragraphs and headings inside cells get min-width: 0; max-width: 100%, cells get white-space: normal (overrides a Nextcloud core rule that set nowrap on <p>), and the entire page-row chain was given proper min-width: 0 so a wide table can no longer push its ancestors sideways (InlineTextEditor.vue, Widget.vue, PageViewer.vue, PageEditor.vue)
  • TipTap auto-generated table widths preventing fit-to-container — TipTap writes <table style="width: 422px"> based on summed colwidths; in narrow page-row columns this pinned the table beyond its container even with table-layout: fixed. The hydrator now strips that auto-style and rebuilds only from user-set data-table-width (markdownSerializer.js)

Removed

  • Organization name & contact email from telemetryorganizationName and contactEmail fields are no longer included in the telemetry payload sent to licenses.voxcloud.nl/api/telemetry/report. These were the only direct identifiers in an otherwise pseudonymous payload, so removing them brings telemetry closer to true anonymity. The fields had no functional purpose for telemetry — the license server doesn't use them — and no direct identifiers remain (TelemetryService.php)
  • "Your organization (optional)" admin settings section — Removed the corresponding UI section, Vue state, and GET/POST /api/settings endpoints from LicenseController. Pre-existing organization_name / contact_email config values remain in oc_appconfig on upgraded instances but are no longer read or transmitted; they can be cleaned up in a future migration (SupportSettings.vue, LicenseController.php, routes.php)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureDR0XAuKJCLgbWV58zbVn9unXzIqAifDSrOYOGR04PcRtLR9ZDkgt/FbrI0HctxpnWmXD2zcV5pjYAu4Xc+m5OyWl+o9aMgKao4LZqyVkLiE6KeagdVonIEHbDd5wvNfSG9KXBWjcVu31jH831sBhodRmJ/ovY795C3q5cOFNYoLIGVHi278qa4r/wSqbsvULzu1vPEUpY3hukQn6XjzkRyh+gahUDmcU76xKeNL6f2pEdKkDKqFUN3TgBOJDaZYwJpy3tCwLRZNwFkLLoLy2XihULJxIlc800+zuIFlI3e1EfbhYtdBJXc449sJo7pIBHaHhF1vPU6eFgVmk+J8sPj1RoXiC7CRYNje41NOy0Bvkdx7QeB2O4ElH3huRnsS66oCrzcr+FJ1zRe8USai20NO8zfQifO0W5JR8Y1aWl/aKrzWIKtkZAYRptfMb4T+c0Sc9h1XPgfm5wK5D2eAJfnDgXJ3sUSfg8bf66tFQbvEmrbtG1n5C0X7j3i8jCL/7CqyWHpFbfCTsh4hmm6jnGSHVQvFoFwTcnbiLAamCMbkcRQ5DnaLMIXY/B5r2I2xzy8wEDhl4CJI8imIkjMTsFjrj8/UcTjQ1fL9bO5q8M4wfupSpPE62BIQcyvsKhfD+vfjRKegu3C60e52A9XtErd9sPUGFZNpXvz+DHGk6VHg=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.3.0
Release Details
UpdatedApril 21, 2026, 9:26 a.m.
Changelog

Added

  • Feed widget — New widget type for displaying external content on intranet pages. Supports RSS/Atom feeds and admin-configured connections to external systems (Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, and custom REST APIs). Features include: list and grid layouts (2-4 columns), configurable display options (image, date, excerpt, source, author), per-user OAuth2 personalization for LMS content, OIDC auto-connect for zero-click SSO, manual token fallback, 15-minute server-side caching, and public share support (FeedWidget.vue, FeedWidgetEditor.vue, FeedReaderService.php, FeedItem.vue)
  • Feed widget: connection presets — Administrators configure connections in Admin Settings using platform presets that auto-fill endpoint paths, auth methods, and response field mapping. Presets available for Canvas, Moodle, Brightspace, Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, and Custom REST API. Each preset supports platform-specific content types (e.g. News/Courses/Deadlines for LMS, Pages/Documents/Lists for SharePoint, Bugs/Recent/Created for Jira)
  • Feed widget: content type selection — Widget editors choose what content to display per connection type. LMS connections offer News/Announcements, My Courses, and Upcoming Deadlines. SharePoint offers Pages/News, Documents, and List items (with library/list selector). Jira offers project filtering and content types (bugs, recent, created). Content type selection happens in the widget editor, not admin settings
  • Feed widget: SharePoint integration — Full Microsoft Graph API integration via OAuth2 client_credentials flow. Automatic token acquisition and caching using tenant ID, client ID, and client secret. Supports SharePoint site ID resolution (hostname:/path: format), page/news listing, document libraries, and list items. Admin configures site URL + Entra ID credentials; editors choose content type and library in the widget
  • Feed widget: image proxy — Secure HMAC-signed image proxy bypasses Nextcloud CSP restrictions for feed images. Supports JPEG, PNG, GIF, WebP, AVIF, SVG (with sanitization via enshrined/svg-sanitize), and ICO. Daily signature rotation with yesterday grace window. All feed images (RSS, LMS, SharePoint, Jira) are proxied automatically (FeedReaderController.php, FeedReaderService.php)
  • Feed widget: OAuth2 account linking — Users can connect their personal LMS account via OAuth2 popup flow (Canvas, Moodle with local_oauth2 plugin, Brightspace). Connected users see personalized content from their own courses. Token refresh is automatic (LmsOAuthService.php, LmsOAuthController.php, LmsTokenService.php, OidcTokenBridge.php)
  • Feed widget: sort and filter — Feed items can be sorted by date or title (ascending/descending) and filtered by keyword. Filter searches in title, excerpt, and author (case-insensitive). Applied server-side after caching for instant response
  • Feed widget: custom request headers — REST API connections support configurable HTTP headers (key-value pairs). Enables Nextcloud OCS API integration (OCS-APIRequest: true) and other systems requiring custom headers
  • Feed widget: design principle — IntraVox focuses on organizational content (news, team updates, external feeds). Personal Nextcloud data (activities, notifications, recent files, Talk, Deck, Mail) belongs on the Nextcloud Dashboard. IntraVox does not duplicate Dashboard functionality. For organizational Nextcloud data from remote instances, use the REST API (custom) source type with OCS API endpoints
  • Calendar widget: external ICS feeds — Editors can add external ICS calendar URLs (e.g. from Moodle, Canvas, Brightspace) directly in the calendar widget. Events from these feeds are visible to all page visitors, including public share viewers. No Nextcloud Calendar subscription required per user. Supports up to 5 ICS feeds per widget with 30-minute caching (ExternalIcsService.php, CalendarWidgetEditor.vue)
  • Calendar widget: LMS event deep links — Clicking an external calendar event opens the event in the source LMS. Supports Canvas (native URL field), Brightspace (URL constructed from UID), and Moodle (URL constructed from UID). Unknown sources link to the feed domain
  • Feed widget: singleflight lock — Prevents thundering herd on cache expiry. When the feed cache expires, only the first request fetches from the external source; concurrent requests wait and read from the freshly populated cache. Uses a distributed lock with unique request ID verification (FeedReaderService.php)
  • Feed widget: circuit breaker — After 3 consecutive failures for a feed source, the circuit breaker opens and returns immediately with "temporarily unavailable". Resets automatically after 5 minutes or on first successful fetch. Prevents cascade failures from unstable external sources
  • Feed widget: background refresh — New FeedRefreshJob background job proactively refreshes configured feed connections every 10 minutes, before cache expiry. Users almost never trigger a cold fetch. Includes its own circuit breaker to skip failing sources
  • Feed widget: rate limitingUserRateThrottle(30/min) on authenticated feed endpoints, AnonRateThrottle(30/min) on public share feed endpoint (FeedReaderController.php)
  • Page metadata database index — New intravox_page_index table stores pre-indexed page metadata (title, uniqueId, path, language, status, modification time). Eliminates O(N) filesystem traversals for page listing, tree, and search operations. Updated automatically on page create/update/delete (PageIndexService.php, Version001300Date20260420000000.php)
  • Nextcloud search: index-first — The unified search provider (Ctrl+K) now queries the page metadata index for fast title-based results (~1ms), with fallback to full-text filesystem search for content matches (PageSearchProvider.php)
  • Distributed page tree cache — Page tree is cached in Redis/APCu (distributed) in addition to the existing in-process static cache. Shared across PHP processes/requests for ~70% reduction in tree response time. Invalidated automatically on page create/update/delete (PageService.php)
  • People widget: scalability guardrails — Hard cap of 5,000 users on the unscoped filter path to prevent OOM/timeout on large Nextcloud instances. Filter results cached in Redis/APCu for 1 hour. Batch status prefetching reduces API calls from N to 1 (UserService.php)
  • Rate limiting on mutating endpointsUserRateThrottle added to page create/delete (10/min), bulk operations (5/min), comments (20/min), reactions (30/min), and analytics tracking (60/min). Covers ApiController, BulkController, CommentController, AnalyticsController
  • GDPR user deletion handlerUserDeletedListener automatically cleans up analytics records, page locks, feed tokens, and LMS OAuth tokens when a Nextcloud user is deleted (UserDeletedListener.php, Application.php)
  • Audit logging — Administrative operations logged with IntraVox Audit: prefix for SIEM integration: bulk delete/move/update (with page IDs and user), license key changes, organization settings, engagement settings (BulkController.php, LicenseController.php, ApiController.php)
  • Health check endpointGET /apps/intravox/api/health returns app status and version for monitoring and orchestration (Kubernetes, uptime monitoring)
  • Scalability documentation — New SCALABILITY.md documenting all performance, caching, resilience, rate limiting, and enterprise features
  • Admin: connection test button — "Test connection" button on each feed connection card verifies credentials and endpoint by fetching a preview from the external API
  • Admin: connection export/import — Export all feed connections as JSON (without tokens/secrets). Import on another instance with duplicate detection and preview dialog
  • Admin: connection active/inactive toggle — Each connection has an NcCheckboxRadioSwitch toggle to temporarily disable it without deleting. Inactive connections show a specific message in widgets ("This connection is currently disabled by an administrator.") and are excluded from the widget editor dropdown. Re-enabling restores all widgets automatically — no reconfiguration needed. Toggle saves immediately
  • Admin: connection status badges — Connection cards show configuration status as text badges: "Configured" (green), "Not configured" (orange), "Token missing" (orange), "Credentials missing" (orange). Replaces the previous green/grey dots for better visibility
  • Admin: connection remove confirmation — Removing a feed connection shows a Nextcloud-style confirmation dialog instead of a browser prompt
  • Admin: Clean Start DELETE confirmation — Destructive "Clean Start" action now requires typing DELETE to confirm
  • Admin: orphaned data banner — Automatically detects orphaned data on admin panel load and shows a warning banner with link to Maintenance tab
  • Admin: advanced options collapse — Endpoint path, response mapping, and custom headers for custom REST API connections are behind an "Advanced options" toggle
  • Admin: column width warning — Shows a warning when the configured number of page columns may be too narrow for the available width, with a recommendation for fewer columns
  • Feed widget: error messages — Specific error messages for inactive connections, 404 (connection not found), 401 (authentication required), 403 (access denied), and 429 (rate limited) instead of generic "Could not load feed"

Changed

  • Feed widget: HTTP timeout reduced — Outbound HTTP timeout reduced from 10s to 5s to prevent PHP worker blocking when external sources are slow (FeedReaderService.php)
  • Bundle splitting — Enabled webpack splitChunks to separate vendor code (~2.9 MB) from application code (~220 KB). Main bundle reduced from 3.7 MB to 220 KB. Vendor chunk is shared between main and admin entry points and cached separately by browsers (webpack.config.js)
  • TipTap lazy-loaded — TipTap editor and all 8 extensions (~240 KB) are loaded dynamically via import() on first editor mount. Pages viewed in read-only mode never download the editor code (InlineTextEditor.vue)
  • Widget components lazy-loaded — All widget components (News, People, Calendar, Feed, Links, InlineTextEditor) loaded via defineAsyncComponent. Pages only download the widget types they actually use (Widget.vue)
  • Widget watchers debounced — Deep watchers on News, People, and Feed widgets debounced with 300ms delay to prevent API call bursts during editor configuration changes (NewsWidget.vue, PeopleWidget.vue, FeedWidget.vue)
  • Widget initial fetch deferred — News and Feed widgets use requestIdleCallback for initial data fetch, improving perceived page load performance
  • Page + lock fetch parallelized — Page content and lock status are now fetched in parallel via Promise.all instead of sequentially, eliminating ~100ms waterfall (App.vue)
  • Engagement settings cached — Engagement settings now use CacheService with 5-minute TTL, consistent with navigation and footer caching (App.vue)
  • News widget: collection limit — Recursive folder scan stops after collecting enough items (default: max(limit * 4, 200)) instead of scanning all folders before applying array_slice (PageService.php)
  • Tree components: progressive rendering — PageTreeItem and PageTreeSelectItem render max 50 children per node initially with a "Show more" button for additional items. Prevents DOM bloat with large page hierarchies (PageTreeItem.vue, PageTreeSelectItem.vue)
  • Navigation/footer HTTP caching — Added Cache-Control: private, max-age=300, must-revalidate and ETag headers to navigation and footer API responses, consistent with the existing feed API pattern (NavigationController.php, FooterController.php)
  • Feed widget: unified connection architecture — Replaced separate source types (Moodle, Canvas, Brightspace, REST API custom) with a single "Connection" concept. Editors choose RSS or Connection; the admin configures connections with presets (Jira, Confluence, SharePoint, OpenProject, AFAS, TOPdesk, Custom, plus LMS types). Presets auto-fill endpoint, auth method, and response mapping. LMS-specific logic (Moodle POST body auth, Canvas context_codes, Brightspace org unit) is preserved internally but hidden from the user. Backwards-compatible with existing connections
  • Calendar widget: IManager refactor — Replaced CalDavBackend with OCP\Calendar\IManager for fetching calendars. This properly handles both regular calendars and ICS subscriptions. Calendar identifiers changed from numeric IDs to string keys (CalendarService.php, CalendarController.php, PageService.php)
  • Calendar widget: hide ICS subscriptions from selector — Nextcloud ICS subscriptions are no longer shown in the calendar selector since external feeds are now managed via the dedicated ICS URL field
  • CSS theming compliance — Replaced non-standard --color-text-light with --color-text-maxcontrast in Feed and News widgets. Replaced hardcoded #fff/white with var(--color-primary-element-text). Replaced hardcoded border-radius values with NC variables. Standardized font-weight to 600 (NC convention). Dark theme backgrounds now use var(--color-primary-element-light) instead of hardcoded rgba values. Affects: FeedItem.vue, NewsItem.vue, CalendarWidget.vue, FeedWidgetEditor.vue

Fixed

  • Calendar widget wrong events shown — When an ICS subscription had the same numeric ID as a regular calendar, the widget showed events from the wrong calendar. Fixed by switching to unique string keys via IManager
  • REST API SSRF hardening — Connection base URL is now re-validated on every fetch request, not just at save time. Prevents SSRF if an admin account is compromised and a malicious URL is injected into stored connection config
  • Version restore not persisting — Restoring a page version appeared to work but reverted after a hard refresh. Root cause: the backend reused a stale file node after IVersionManager::rollback(), and the frontend masked the issue by showing a version preview instead of the actual restored page. Fixed by re-obtaining a fresh file node after rollback and clearing the version preview after restore
  • SSRF hardening: LMS connectors — Added validateUrl() with private IP range blocking to Moodle, Canvas, and Brightspace fetch methods. Previously only the generic REST API connector validated URLs at fetch time
  • SSRF hardening: ICS calendar feeds — Added private/reserved IP range blocking to ExternalIcsService::validateUrl(). Previously only enforced HTTPS without checking for internal network addresses
  • SSRF hardening: SharePoint & Jira — Added validateUrl() to resolveSharePointSiteId() and getJiraProjects() to block requests to private IP ranges
  • SSRF hardening: Confluence API importer — Added URL validation with private IP range blocking to the Confluence REST API importer's base URL
  • XXE hardening: Confluence importer — Added LIBXML_NONET flag to DOMDocument::loadXML() and loadHTML() in the Confluence Storage Format parser to prevent external entity resolution
  • Token handling: Jira project listing — Replaced direct admin token decryption with resolveToken() for consistent token resolution across all connector methods

Security

  • CSP hardened — Removed unsafe-eval from Content Security Policy. The Vue 3 runtime-only build and TipTap editor do not require eval(). This was a historical precaution that is no longer needed (PageController.php)
  • HMAC key hardened — Image proxy signature key now uses hash('sha256', ...) for proper 256-bit key derivation instead of string concatenation (FeedReaderService.php)
  • API response size limit — External API responses larger than 10 MB are rejected before JSON parsing to prevent out-of-memory conditions (FeedReaderService.php)

Accessibility

  • Feed widget aria-live — Loading and content states announced to screen readers via aria-live="polite" and role="status" (FeedWidget.vue)
  • Feed item semantics — Removed conflicting role="article" from feed item <a> tags. Added focus-visible outline for keyboard navigation (FeedItem.vue)
  • Admin loading spinners — All loading spinners in admin settings now have role="status" and aria-label="Loading" for screen reader users (AdminSettings.vue)
  • Connection card keyboard nav — Feed connection expand/collapse headers are keyboard-accessible with tabindex, role="button", aria-expanded, and Enter/Space handlers (AdminSettings.vue)
  • Status dot contrast — Disconnected connection status indicator has a visible border for better contrast on light backgrounds (AdminSettings.vue)

Documentation

  • New SCALABILITY.md — Comprehensive guide to performance, caching, resilience, rate limiting, GDPR, and enterprise features
  • Updated ARCHITECTURE.md with scalability section
  • Updated SECURITY.md with CSP, rate limiting, GDPR, audit logging, and feed widget security sections
  • Updated ADMIN_GUIDE.md with health check and audit log sections
  • Updated ADMIN_SETTINGS.md with connection testing, export/import, enabling/disabling connections, Clean Start confirmation, and advanced options collapse
  • Updated FEED_WIDGET.md with RSS example screenshot, SharePoint setup guide (Entra ID app registration), content type selection, error messages table, and screenshots for all connection types
  • Updated ACCESSIBILITY.md with feed widget and admin panel accessibility improvements
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLc6iFEUpymkn2oOpihHrtxmTjKYFZWKcuvfBrf1Xr3us6SzOBhArJpj7t5GHUekRY6sJiuf47lqIDbjzf9fby51vse5bF+n1/QHXdApMDmsxo6EhtM5e3VRWje9A+ZuT2W+Xspdu1owszLqJfQw3TMBFmtAF2QNLAxTU6X8BOwc2Px6MUJnD+aNrOaE4117bBqSv27JihzvyHoz21ey+kZK+vrXaZoXrLzKkf69mPYKMEiVuyKaueTLhuRcihJPZAuVC+ClgZVTueZGDmNQA39xfL9Puy5JpbQx6+7MSL6FKhoN4bXD3ve3DloPsIC35KF+gpH/T8hY6f3vWQgX5mGh5mQSJLHTTkYulKiDcXRq82cDg/o2tpw7D6Uu3R/wVafqGrndtl8A5/okhCHGJnwh7FdG3vzoMFMLdEM03Zlk4W5hiVio5fd1Wy0LVM6SaGM81S9+TrOV0S35vuONStfe56e17wDC9DVaznDTQJW7E7qj4eihX/r0sVD0qQzYoIQ7PvnJ5XNAobWh28TA0eXwOnTwlOSsFhHxBLyt/DJE2CYoEz8YYBNnBgTGthYVKPp/grlWfFGNrRygNOYYMbMSmVqZQ/8liz1OrMcFwC0DoW/IVtmaB8PIGYs7XO8D8IBYRVpklTlQpgFrEf8PpD/8rfnp04VGlWCb/E9tR9x4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.2.0
Release Details
UpdatedApril 16, 2026, 10:48 a.m.
Changelog

Fixed

  • People widget filter persistence — Filters using the "does not contain" operator were silently converted to "equals" on save because not_contains was missing from the backend operator whitelist. After a page refresh the filter showed different results. The operator is now correctly preserved
  • People widget filter value encoding — Filter values containing special characters (&, <, >, quotes) were HTML-encoded on save via htmlspecialchars(), causing them to no longer match user profile data (e.g., "R&D" became "R&D"). Filter values now use a dedicated sanitizeFilterValue() that strips tags and control characters without HTML-encoding. Existing corrupted values are automatically decoded on read
  • Editor contrast on colored rows — Column labels, placeholder text ("Enter text..."), column borders, and "Add Widget" buttons now adapt to dark row backgrounds (Primary color). Previously these elements were nearly invisible on dark backgrounds

Added

  • Skip-to-content link — Keyboard users can skip past the navigation to reach the main content directly (App.vue, PublicPageView.vue)
  • Semantic landmarks<header>, <main> elements replace generic <div> wrappers for better screen reader navigation
  • ARIA tab patterns — Proper role="tablist/tab/tabpanel" with aria-selected on NewPageModal and MediaPicker tab interfaces
  • ARIA combobox pattern — PageTreeSelect now announces as a combobox with aria-expanded and role="listbox" on the dropdown
  • Carousel accessibility — News carousel has role="region", aria-roledescription, aria-label, aria-live="polite" for slide announcements, and respects prefers-reduced-motion
  • Live regions — Loading states use role="status" with aria-live="polite", error states use role="alert" (App.vue, PublicPageView.vue, CalendarWidget.vue)
  • Focus-visible styles — Global *:focus-visible outline for keyboard navigation visibility
  • Reduced motion support — Global prefers-reduced-motion media query disables all CSS animations and transitions. Carousel autoplay is skipped when the user prefers reduced motion
  • Visually-hidden utility class.visually-hidden CSS class for screen reader-only content
  • Breadcrumb current pagearia-current="page" marks the active page in breadcrumb navigation
  • Accessibility documentation — New ACCESSIBILITY.md documenting WCAG 2.1 AA compliance status, legal framework (Wet Digitale Overheid), and implemented measures

Changed

  • Form labels associated with inputs — All form inputs across 15+ components now have programmatically associated labels via for/id pairs or aria-label attributes (WidgetEditor, NewPageModal, PageTreeSelect, CommentSection, MediaPicker, AdminSettings, PageEditor, NewsWidgetEditor, PeopleWidgetEditor, CalendarWidgetEditor, LinksEditor, NavigationEditor, PublicPageView)
  • Icon buttons accessible — All icon-only buttons in InlineTextEditor toolbar, carousel navigation, MediaPicker, and AdminSettings now have aria-label attributes
  • Draft badge contrast improved — Fallback text color darkened from #856404 to #6d5003 for a 5.5:1 contrast ratio (WCAG AA requires 4.5:1)
  • Dropdown accessibility — Navigation dropdowns have aria-haspopup and aria-expanded attributes
  • WelcomeScreen heading — Changed from <h1> to <h2> to prevent duplicate h1 on the page
  • Password error announced — Public page password error message has role="alert" for screen reader announcement
  • MediaPicker strings translated — All hardcoded English strings wrapped in t() translation function

Fixed

  • Focus anti-pattern removed — Removed event.target.blur() in Navigation.vue that was stripping keyboard focus after clicking the page structure button

Documentation

  • Added ACCESSIBILITY.md with full WCAG 2.1 AA compliance matrix
  • Added accessibility link to README documentation section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureWi2Kezb67KRxkFi/zRvjUrCCpNNRc2DBOWtuhOITpNScggVnaSiP+zLGO3s+/fPnKmgGrFoPeSuTSQifpEA37aQrwWx1comrLRq6k9SG+4+VhgAxVjvYdha0fqhah0HDjsgfC1cLhOBExqudxnijKEf+NCGgZqf1tHFnLtUbM1Z+x5o0CjAjv47c8Qrz/LD5NTvDcmU2vkkePA4nNjMheGuxC70rmwceaXaoA2CRf9BZ2XQsI8AgE9yoTEFvdWVdpN/BR+DKoAQya6XBZitrAp1jvH3okVMMap+XDBJrhD8mfBC/9eEn4Q/UW1Xc/m3WnCMVy5MiuY3Jv0b9pl+BghH8elxTjsZZRQJ7riGX1k9e/I3hjl4GZKO96USxGi5tDoWWtq/dKLddmrzy00o0cBMuKaAJ/sFal+OyZg++OWO7Zi0sxeL12T2OaojmJ4u22sZmgaZi+Tl5naidjOE9cz3Tv41C7IIAKpW4j1Xrj7L2D9vA5C7rKH/7vIbY/iLWnIY0df5BDs7NsccnftNNLXGA24PjtN7C21SoLbSHA2hDk81Lq3QohMyCod13UkcCO4/OjKFH523IEmLnzxujA+YXNxnfEvaEW66AQn56pDKgBN0tmLKjMBd8hIAEBzpBP67buSytYIj3XjoRtR9rMHq1W125eljViPQlVVd0vTM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.2
Release Details
UpdatedApril 10, 2026, 10:41 a.m.
Changelog

Fixed

  • Telemetry error feedback: The "Send report now" button now shows the actual server error message (e.g., rate limit, connectivity issue) instead of silently failing
  • MetaVox icon dynamic loaded — MetaVox sidebar tab icon is no longer a hardcoded SVG copy. Now loads dynamically from the MetaVox app via imagePath('metavox', 'app.svg'), so logo changes in MetaVox are automatically reflected in IntraVox. Dark mode handled by Nextcloud's automatic app-dark.svg serving

Changed

  • App Store description rewritten — Expanded from ~150 to ~250 words, structured in 6 sections: page editor, widgets, collaboration, content management, enterprise, and requirements
  • App Store summary — Changed to "SharePoint-style intranet pages for Nextcloud — no code required"
  • Author updated to VoxCloud — Author name, email (info@voxcloud.nl), and homepage (voxcloud.nl) now reflect VoxCloud branding
  • Screenshots expanded from 3 to 7 — Added calendar widget, people widget, news carousel, templates, and engagement screenshots
  • Category social added — Reflects engagement features (reactions, comments, people widget)

Added

  • Documentation links in App Store — Editor Guide, Admin Guide, and API Development Guide now linked from the app listing

Security

  • axios upgraded to 1.15.0+ — Fixes critical SSRF vulnerability via NO_PROXY hostname normalization bypass (GHSA-3p68-rc4w-qgx5)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturedEPa13irIrVkzszfHig0ZkpEhHIKNvbSxRdMHeALc3YGKW3H/pXgEyzlSiOgTRlYG9JwD6bAo8ANVhK9tBaIMr5nzOO0JrgExrnHniBe4LtGgJ2xbE1TeVVKEnlgcmwi8SG60ueKvIJU/x/Vy2yIJJGe/ShTntep5qiwGJBe8QksUTojfPiDaqDXzcgVRyYhbvIuT44/TF5oohBzbLLHvXm5bhcbUP6WyWz2KsTF7sgMtkKmClOiY/vZYVG2QaK87+QbwBwnW5icirect8ZzPzxSHqsg3LJdP4InayQhs21ZSm6rdrmBhT8Z36OJv9Mu2Dzdvl5cbqalUJbLs5ILHh/i4LKcIgt5fd9yvPHrtH7DNKQHeYMdH6x9saOq6zDC/g71N2zb1klXypSNpnkb/Ki9ZniJd0AQq2vxj4i0rguZZSM2HyMgnQnmAUU/HHbZGExGVQ6qqZl2xdVp3PZMZiQKJvIoVFqev4CbHr1Mite0cy2aYcb8iGnAdGYBL8Q2YahPyL3+dgHmi6/ywY3pmo9w+4O+JDggH3O7Mt2rlgbEQAaR0qLafrRU0yTB54Xyk7CNQE4kV1oGzl+wIO0LBBpDnuQAqenvuh7ac4W3kil3fbjVs9lk3JiH9q0Wb9gQ50ZE9T00RM/VhSDacfnmghY1udXhgAThMrNXeOjQ3m0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.1
Release Details
UpdatedApril 8, 2026, 11:53 a.m.
Changelog

Added

  • Support contact settings — New admin settings section for configuring organization name and support contact details. Contact information is included in telemetry for easier support identification
  • App Store screenshots — Added calendar widget screenshots (layout, editor, primary, sidebar) and updated admin demo data and edit mode screenshots

Changed

  • Contact info updated — Author email changed to info@voxcloud.nl and website URL to voxcloud.nl
  • Admin settings refactored — Extracted support/contact settings into dedicated SupportSettings component for cleaner code organization

Security

  • serialize-javascript upgraded to 7.0.5 — Fixes excessive CPU usage vulnerability in array-like object serialization during webpack build process (#42)
  • brace-expansion upgraded to 5.0.5 — Fixes bracket handling vulnerability (#40)

Fixed

  • Demo data imports all languages — Demo data setup now detects the single active language and imports only that language's content, instead of importing all available languages regardless of configuration
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureaKR0xRRjvews2FOdXJ446XMnOvUrRh3oPx3N7dR/TGujbDnjFFXwF8qC7wXo9CrwLD164arXII26lxxH509xmimeAfARht3+m5iFU8X2UdeWfszCJtuf2TilPEp+3ZDcgKOpN3o9dkcas6hV7rYfsqVJTkLAPqvAhOA3lRQOM70SKV8P5Jo3wSKHiXocbdsk094u2jd640LIR3EFfkdCrzxQJ9KetiH3w+h135bz1qwU8/eceKTH+O9aHYtphsbfFqRvZzMqnZ3qEABfWzSdOMgkvSIrpYZDWy20aPi1vagdi9VtLBzuzVNvmzjLKcCu3HNdJ2mrITGFykR1JM+EKG5AmdoIovqjunLgwpoCQCmLYnvhLegYfsIz1MbG0mgfJ1ZeHwW/DI/9usLGtlNOwRqJjaL9WIgT2zk4wPkG0P0N8f+i/S4limsWXHilNlqj7nZJWQftBm+UoecxZ4hewwGbQZZIGdBDIFkbKV3JPsnN8y6OXohEIAWXfgy66SXM5n2KdYVlFAiMyAcIPWkab+ZjB/o+jrpkGuC/9+eJ0fTd8LAwSKzupt4hTCqmmru5t2Or/6YSEZxl3LlghWtC3ivSefxvqLuKy95vPVmT+ylOPohgmzUxPzlOHHcOp/N9YIP3YSWwMZ2cDbvAI4PeZD3UjHpnhm3t9q8lHOrygyk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.1.0
Release Details
UpdatedMarch 29, 2026, 7:49 a.m.
Changelog

Added

  • Calendar widget — New widget that displays upcoming events from shared Nextcloud calendars. Supports multi-calendar selection (merged view), configurable date range, event limit, and show/hide time and location. Events are shown with colored date badges matching the calendar color. Recurring events (RRULE) are correctly expanded into individual occurrences
  • Responsive calendar layout — Calendar widget automatically adapts to available space: 1 column in side columns, 2 columns in medium containers, 3 columns in wide content areas (via CSS container queries)

Fixed

  • People widget users lost on reload — User IDs containing dots, @ signs, or spaces (common in LDAP/SAML/OIDC environments) were silently stripped during save, causing selected users to disappear after page reload (#41)
  • Deploy script OPcache — Added Apache/PHP-FPM restart to deploy script to clear OPcache after deploying new PHP controllers

Security

  • Rate limiting on public People API — Added AnonRateThrottle to the public share endpoint for the People widget to prevent user enumeration

Documentation

  • Language & demo data — Added guidance that Nextcloud language setting must match the imported demo data language. Added troubleshooting entry for "Admin sees empty Welcome page after demo import" (#37)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureZBIZ5aIC0Jf+cgyuNd3xYfy7lZbE7fbg38Xem2/zEuWkI5PWOSY/WmCebThcm9NHRdFJIL74zHRIUbfE2XaicmcqwgSZozNcUeUG8kpK5elRhLYJXPdPZMAN1LpKiPlrz3951koLc2f0LNpTvOBvsXgk0Fjlsj/NRmYcn6Oy224uzlYrkwpwBn8UDRA6CBC8qJLG+TYF4/VnIfJLEomG01HV9Ar2TGb+dDUobWPWAgfXfkdNtrc7gfLPipGlAs8enaBWbEhLQi/qRVfU2W1azSTYzFgl1rwBMnFG5V9g8ymkZpakbioOnL074u9JUYwBIcXGSq+7w9oKo5LFmzidPmSALp8B12aM+lAElH/vBKlHBYSoDv3A/KoqWfXW5BZvXQXmtFa043vK0kHD5M0PARFfvPN7xkVXUYoQX5o9Ptre/I+UkINXO6FX7X4KepWM57WFVidCOMwwCl9e6b5UQdt6aeYSl1qoAnBNQgAxtYm2QgRJa9FyDEl4+yup+bBwrYU8URBCQJk6GTbAFaA5397wE12N3OLpwoiIx3g7ZBP+ppRmO1eb1SDGN9tJWa5AKgEg7CBnBaV5YNtWRlmoUfsgfCt1b039Dca7fEVcL523m5zgmxqkiCbO70fwlTdhoe00hQpcZomfmEP6wB7FftWIqMR63Ndw+7WmoGIouhM=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.1
Release Details
UpdatedMarch 9, 2026, 3:12 p.m.
Changelog

Added

  • IntraVox Editors group — A third permission group (IntraVox Editors) is now automatically created during setup with Read + Write + Create permissions. This provides a three-tier permission model out of the box: Users (read), Editors (read/write/create), Admins (full access)
  • Scenarios documentation — New SCENARIOS.md guide with step-by-step recipes for content approval workflows (using the Nextcloud Approval app and MetaVox) and department-based intranets

Documentation

  • Updated ADMIN_GUIDE, AUTHORIZATION, EDITOR_GUIDE, and README to reflect the new three-group permission model
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureQuql4/Qdcw6lDxelq5UHCLVmlFf7+6YjcNPpfIDS+ynsrL+9QbyGsGQyx8fZdisovKtKJODYvfEou6EmcdD8l14mvBc4P6v6PZwzRmgP3qGMG4fYX0lFfniULGs8YGtKVGtgqilJ1gLnHQrO4qIxQqvvNGtTKmr8N3GehbHprT/tTzgPTlhmIHPIjKrw6q5m380WyUBhq9Hw9o16MekCX5obAshT2pwQuQvkmEYuprV4wr3dFOqKC5vM04yd1x6s2y72ZLcCC4YDPRoMP75vClpQaaScIYwVoulnFlLqOZUw/qlywWttwMAalDJkRPmC3E08xlOup4RwZkGSdu9jv5ESDemPoxvtV4alDMkf/qECW8KZkjTEX89MuYfFLK7POiH68qJllpAooquc71PAdN/YmTtKPplKBKqiJwWReAgDK4dZdls1komf17vcn+usYsJhzVT5Jarp8jjT0aQpBFAUDIuEJmeF0nzI/Q0xV1bMeCs/j2yjDdSIJPLHr27uk68Tb+gBQbhYdpPR6sYxLT2DT3xbbvq9z3RPlowcO3/kvN71ojGEx6xPGOsISJbRDpg4v3ixzVaKa9nUurb44Hsp7E1GsF19ARAlEquCuJxkCXONHc4jjW0pPGUxyBAt5V4kvWqRhS9Whl1JjSWOd7X30GvShRSWwWu59BiaTpI=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 1.0.0
Release Details
UpdatedMarch 8, 2026, 10:37 a.m.
Changelog

IntraVox 1.0 marks the first stable release. After 19 iterative releases, the app offers a complete intranet platform: a full page builder with 10+ widget types, page versioning, templates, public sharing, RSS feeds, engagement (reactions & comments), draft/published workflow, concurrent edit protection, and multi-language support. The JSON page format and REST API are considered stable from this version onward.

Added

  • Page locking — Pessimistic locking prevents concurrent edits. When a user starts editing a page, other users see who is editing and the Edit button is disabled. Locks auto-expire after 15 minutes of inactivity, with a 60-second heartbeat to keep active sessions alive. Locks are released on save, cancel, navigation, and tab close
  • Lock safety net in API — Backend updatePage() rejects saves with HTTP 409 if the page is locked by another user, preventing data loss even if the frontend check is bypassed
  • Force unlock for admins — IntraVox Admins can force-release a page lock held by another user (e.g. after a browser crash). Includes confirmation dialog to warn about potential unsaved changes
  • Draft pages (#32) — Pages can be saved as "Draft" or "Published". Draft pages are only visible to users with write permission and are hidden from read-only users, public shares, search results, RSS feeds, and the page tree. Editors see a clickable status badge in edit mode to toggle between Draft and Published, and a "Draft" indicator in view mode. Backward compatible: existing pages without a status field default to Published
  • Duplicate row (#32) — Editors can duplicate a complete row (including all columns and widgets) with a single click. The duplicate button appears in the row controls next to the delete button
  • Sticky edit toolbar (#32) — The header toolbar with Save/Cancel buttons stays fixed at the top of the viewport when scrolling, making it accessible on long pages

Changed

  • Page lock translations — Lock-related UI strings translated to English, Dutch, German, and French
  • Draft/duplicate translations — Draft, Published, and Duplicate row strings translated to English, Dutch, German, and French
  • New pages default to Draft — Newly created pages (both blank and from template) start as Draft and automatically open in edit mode so editors can begin working immediately

Fixed

  • Links widget tile overflow — Tiles in narrow containers (sidebar, small columns) no longer shrink to unreadable vertical text. Tiles auto-wrap to the next row when there isn't enough horizontal space, while respecting the configured column count when space allows

Documentation

  • Editor guide — Added sections for sticky toolbar, page locking, draft/published status with visibility table, duplicate rows, and updated creating new pages workflow
  • Admin guide — Added page locking and draft pages sections, updated security considerations
  • README — Added page editor features (duplicate rows, sticky toolbar, page locking, draft/published), new feature sections with screenshots, updated security section
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureiNaCstuvlWhKDNWHxOI3UH2urSyZ8OZCmlMAvQHWW8FDbfo3gBmHCD7ofk/6G78se/+9K8bLaSPMd0f3n3enR62K0ZG0jj5TP4eVvIsVYpVlLdzZlV64fJRcFSUotMFaluWlflLPKhuJbPJTCLivaYwzxX8QhfG7f9SUgZcsb/YZrCU0exRzekrFevLtHNsVE5aj7UWGg3lQh/zYZ28tlpsoWUPCJ2dT4qQ56kFO6IYvc4Wmf2diEzLLye1XaVpLaBbldRfDt2b4siu3uUMPePJHij6EDYL1dQAPuYAa12slvrh9TTRlffbtU1ny3b+1t9yLAVBiE6NEFccX7S/P5pmEPNmoeCECIv8lTyw8GJUeRNT+VdmlOZporvVXn4CWhW4aaQW+qVMLUrKrQ4Ond/ZYmVyVR4TjKiGZr04hr/xIdj0FDPffqe3SiLS5DJ4g3P+q3CCI7vktKlIdOrgpyHFavOfTq9IT2MT94UfJFob8L34g+yDsfdyQdYC2hQTXZsQUJ9TS72pzUC4c52Y4gomtLyUh4E7xOv8hAiGiKvaCDlcQJD7jE95LKw+EEwMvXrDMfhgn8hHMg9JxzSapRggu59B5Butz83jVNRnTWht9gaGu3nlpvMnNoE0YdFyU2c1yj0w5DoB7VmKd+4+1S32aO97qba7DCBpqrdQYc8o=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.18
Release Details
UpdatedMarch 7, 2026, 11:51 a.m.
Changelog

Added

  • Spacer widget rendering - Spacer widget now renders correctly in view mode with configurable height (10-200px). Previously fell through to "Unknown Widget Type" error display
  • Links widget tiles layout - Links widget now supports a tiles layout alongside the existing list layout. Tiles display a larger icon (36px) with a separate title and subtitle on two lines, creating a card-style presentation. Editors can switch between layouts and set title/subtitle per link in tile mode
  • 30+ extra link icons - Added icons for common intranet use cases: folders, chat, dashboard, contacts, forms, code, support, security, organization, news, and more
  • 5 unique demo showcases with rich, diverse layouts demonstrating all widget types:
  • de-linden (Universiteit) — 4 photos, 1/2/3/4-column rows, video, people grid, SURF services, right sidebar
  • van-der-berg (Advocatenkantoor) — 3 photos, header row, news grid, file widgets, no sidebars
  • gemeente-duin (Gemeente) — 3 photos, 1/2/3/5-column rows, left sidebar, news list
  • de-bron (Zorggroep) — 3 photos, 4-column department overview, people cards, video, file widgets, right sidebar
  • horizon-labs (Tech startup) — 2 photos, news carousel, culture row, right sidebar

Documentation

  • Showcases guide (SHOWCASES.md) — Complete documentation of all 5 showcases: widget coverage matrix, technical structure, background color guidelines, image handling, and people widget portability
  • Editor guide updated — Added documentation for file, spacer, news, and people widgets; updated column support from 1-3 to 1-5; documented collapsible rows, header rows, and side columns
  • Export/import updated — Widget types list expanded from 6 to 10 (added links, file, news, people)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCnOojEkcaYY3IrqfW3cj9gDhgOnlVkTd+sZpTFow4jh1pH+IrZ1NgXRjGgIKZiQtdvlh3AqgHdEE7kWidNvVTps4SL79TTLcQlO+aT223Sf9OOMC+GQsGkxUVKVY1d456mupVrZyslUCopbxr4Rf2aYxfsm3GFdMxPFGByXWE4VkJztuo8UI4krp2rfVRcBbv2m8RWd2w+1mAlkOiRK7176eS+d4jHn0h6Kslde5E/E4DfGML8uUyyu5yACJ/MMkUcJ+wxLvu2esOM5oPkbMrAHpWCa5TRzqVtbpoplcmDq4pYVw84AXc/+V91HduZOVLHgzWXhkV6O0qXjsWgsDfAPiZ1t9EWFuUMuV0EY2WbIxdo5eBSQsDaG4R60JKVlUvbx07OXecWG80VRslsngbXbTtvWV/AwHGWN60MufTQbEU8+cw3tIBD5RAlXwcnIVDHawBvasxQ7wlWU5/B8BZZkEDGdQMBlXTQE45+FVEbwXOaaQPD8s7cde2zCGk7Ze4MfIqZDyD5cBuszuVf5ljCpm8BQvt4oBGRPX9C0K8TB+l3vp6XzuMOvxixdIES9E20e9LYn1Yve0tTf3PzBQgUvPM4eYjXHD3U24w/0PNPNrBtLzg0uePqmm01dHBkVTqQC4CdmLD/cRG7GIH8bVBey+9XsftagMXH2LGuz8NS8=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.16
Release Details
UpdatedFeb. 25, 2026, 1:50 p.m.
Changelog

Added

  • RSS feed - Personal RSS feed for each user with token-based authentication, feed media endpoint, conditional requests (ETag/Last-Modified), and brute force protection
  • RSS feed settings UI - Generate, regenerate, and revoke feed tokens with configurable scope (my language / all languages) and item limit
  • RSS feed sharing policy - Feed respects Nextcloud's "Allow users to share via link" admin setting; shows clear error when disabled
  • RSS feed cross-language links - Feed items link via #page-{uniqueId} format, automatically resolving pages across language folders

Changed

  • Dummy text generator - Removed =dad() alias, only =dadjokes() and =lorem() are now supported
  • =lorem() rich formatting - Now generates richly formatted content showcasing all text widget capabilities: headings, blockquotes, bullet lists, tables, ordered lists, and mixed inline marks (bold, italic, code, underline, strikethrough)
  • Dummy text multilingual labels - =lorem() section headings, table columns, and status labels are now localized for EN, NL, DE, and FR
  • Documentation - Added RSS feed admin setup guide with GroupFolder permission requirements (Read + Share), ACL examples, and troubleshooting

Fixed

  • People widget "Invalid Date" - Birthdate now correctly displayed regardless of Nextcloud locale settings. Added backend normalization of locale-specific date formats (DD-MM-YYYY, DD/MM/YYYY, DD.MM.YYYY) to ISO 8601 before sending to frontend, with additional frontend fallback for edge cases
  • RSS feed empty for ACL users - Documented that GroupFolders requires both Read and Share permissions for public feed endpoints; updated all permission tables and recommendations
  • Webpack build failure - Added string_decoder and buffer to webpack resolve.fallback to fix build error caused by @nextcloud/dialogs 7.3.0 pulling in Node.js core modules via sax/is-svg
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureLkqXT+TE7U884io7bEDmL/gZLvaShUTg97nU7qIjNMBXEkd4nqo9nooA8+Y8qLUQEIjP1wFkw2p/TMduDHbWgZcPe+SIDuvfyQhqSlO5aeD8Q+pW+KmGAy0XbbQlVX6neiqaNGhD8TpCdnIStIHuPkjRngBSOuXf4JjeV3DNM2QKlck2at1svnElJOWujwLerTqWVGWQEaXSBvn0YGAHiLorgKXVitgZRMOxviUeSTxdWtwNsJ3vVIZ+mr+4UllElQh1jLgnePi2xa3DXs3b+r9CqebhIIQ2Brt8r0U2l3W5LIsjZJtf+/PHf9ytfAag51+XHLb/xMEZx9NDxakeGZlDPdQ652np7z7jgUxwE/wASSpVJ4LePTzwoBrdg4EDocI114Gtz0vqJGoTOJBHxZEovydDEXjOZSJcnLvzpfs1nkQBQYUvQGzSVti+0W64vSCh/I53o/U7GRYmCL03pYbNYZ9S2nk32usjfFizVbpGvKFrA5crLqxBns5Yb6bYY5QNtZtqHJiobkijwP19esHX6eCNLIKvI6aozaMtpawOQ/IDCDdJFI7N1+QFcoMgUsbbpfBXhImJ1I3LjWOjbzl+ZQ4d6CrHC1Gmd/KohKuvx5ER7RmgvLIhpgEEAKvdpFxgBc2gnQeVwTLUOBlzjJhS+I+7ggkrmX7+5HarwP0=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.15
Release Details
UpdatedFeb. 19, 2026, 6:35 a.m.
Changelog

Fixed

  • MetaVox sidebar on NC33 - MetaVox metadata tab now works in IntraVox on Nextcloud 33, where MetaVox registers via the new scoped globals API instead of the legacy OCA.Files.Sidebar API
  • MetaVox mock Node object now passes correct mountType and mountPoint attributes (camelCase) so groupfolder detection works properly
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signatured13CndlYRWziam4mAOeDoHdjExboNyPiyFqfTRdrqRtcJkWVhRE0vN7wCEpWqUZaAni+r5JOpmwhpD7ePTFB8j77sIMq2K2ahdeGOVhnRrhQ3Qk055iXrnxzm3lvwaaerShVPa9D5fga3auYwpcuJxW4NDj36QvCwybkhwzJx381shlVjGyuZKQFJJWn3d3ZAzC2u1El8OlLIeBEDeszJizpa3EBEGdftZ7sfqkem+UMU9jWOGrXMwkYsauDhp+0mW6TNb7lDV84gZUKoE9lAYYLTPzFU5VWDA2mtvV6h09kwtZrXfkMxoh+S/qAcFkP9gwXFHKZKCDs3Z/HGTqeDxrbW6EM5sboYLOS7+VQapwes/UsGRO3XO9jzo5cfe4+c6fy32mjgwyhskSBm5UYdpYANsRgvOj0D9GQFNLYSuktoHaV0lq7BAtroDDk7B09k/422Eia0taM9PuoTmbMZ97yhgYZpEyJMLVx4nTMu30zXXkw0fkF3KfF0vZMnsOaAgYfQWXzChqpOlvemmz7bx/Ew7Murqz5ytaXfZvQ09WtWEV4l1b4AdCaf1ow/+w+V5BtXM/tCvaUmjQtdK+mf70ptdCr/+crxjhytihIm+NFMZSB/FMNlOKGcM3J0wz/kcBJ6tCLAcCIjzaf9p+42yUo8bgi+WzJTNp0r6EZSLA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.14
Release Details
UpdatedFeb. 18, 2026, 2:07 p.m.
Changelog

Added

  • Nextcloud 33 support - App now supports Nextcloud 32 and 33 (PHP 8.2+ required)
  • Page nesting depth increased from 3 to 5 levels for deeper page hierarchies
  • Dummy text generator (easter egg) - Type =dad(), =dadjokes(3,5), or =lorem(2,4) in a text widget and press Enter to generate dummy content (inspired by MS Word's =rand())
  • Birthdate field support in People widget - display, filter (is_today, within_next_days)
  • Bluesky social link support in People widget
  • Date filter operators for People widget: is today, within next X days

Fixed

  • People widget display options now correctly control rendered fields in grid layout
  • Removed gridShowFields override that forced fields off
  • Removed hardcoded layout !== 'grid' template restrictions
  • Removed CSS rule that hid headline in grid layout
  • showFields is now the single source of truth across all layouts
  • All display option checkboxes now always visible in editor (no longer hidden per layout)
  • showFields whitelist expanded in backend (PageService.php) to support all 15 field types
  • Legacy title field synced with role for backwards compatibility
  • Heading widget bottom spacing increased
  • Comment cascade delete now properly deletes replies and updates count
  • Security: markdown-it updated to 14.1.1 (ReDoS fix in linkify inline rule)
  • Security: ajv updated to 8.18.0 (CVE-2025-69873 ReDoS fix)

Changed

  • Twitter links now point to x.com instead of twitter.com
  • Dependency updates: axios 1.13.5, qs 6.14.2, webpack 5.105.0, ajv 8.18.0
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureKx4wBbCHSaA+wD5HWQ0/arQjdIOdtmxLwRYyh1GhcBKDiUVrfNUoFlOreUrs/FPv6heMXFD8XdJcVn6XXxPZzSOAYVCnKaIGGYea4RfsTlCbrShkasX2TxQ/1Kn1vH2QM+qe0aNdZstYv1QxhFgQyb82tWreFTuhisKgndvWqE5LouHSIDzamgr+iKmEoxf/LvCbPt4UvWc8nQdCc+XdnDa7WzMrjAB1xu5tHXE3coFmEqAWUwdMpp+vR9YanFLjC8CKfJEl+S4qL0DhDviXXUzjlOmIEttrXwRI1nv5rLg+Ucy1fBdZPUmMLXqgh7eUTWCSAlTVsTPYMvdhNQAZMWpioKf7X7pZcbp9JvcmbTZ6+VJVIT8tGGJROwpx/Z8v1fN3e5Gcv+pSq0yHpKM43v2S8LSa+Z5HB7BIV5GeUCmSIGfrWYEJvXYhpHtyHJrdVYfH2YuYbqkAH5bKuURwKQdJ0Y6A9v/gpEdwso44dNpPh0CY2uaGk/FwrJs1IYYmCI59OqF6l1/ffo9l/jR+PA5Jh3nns9lUR+hhfTJ25hF3+xhYdQV818Acbnl24c59rugq7+hX++cVn/b8VXen5WIUdVK4nl8eHNSYYVJoRLoz0PqhEVitwSF9k6zU+6/kSWIe2UiEwiOALXTSS89q+TVRT1J1oX1L//SPTg0b988=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<34.0.0
Minimum Integer bits32
PHP>=8.2.0
IntraVox 0.9.13
Release Details
UpdatedFeb. 12, 2026, 8:31 a.m.
Changelog

Added

  • People Widget: New widget to display Nextcloud user profiles on pages
  • Three layouts: Card (detailed with contact info), List (compact rows), Grid (avatar gallery)
  • Two selection modes: Manual user selection or filter-based (by group, role, department, etc.)
  • Group filtering: Show all users from specific Nextcloud groups automatically
  • Field filtering: Filter users by any profile field with operators (equals, contains, does not contain, is one of, etc.)
  • Customizable display: Toggle which fields to show (avatar, name, email, phone, role, headline, department, biography, social links)
  • Display options grouped: Basic Information, Contact, and Extended categories for easier configuration
  • Role and Headline fields: Separate fields for official job title (Role) and personal tagline (Headline)
  • LDAP/OIDC support: Custom fields from LDAP or OIDC are automatically detected and can be displayed
  • Nextcloud integration: Clicking avatars opens Nextcloud's contact menu (view profile, send email, check availability)
  • Privacy-first defaults: Phone numbers and addresses are hidden by default
  • Sorting options: Sort by name or email, ascending or descending
  • Column configuration: 2, 3, or 4 columns for Card and Grid layouts
  • Pagination: "Show more" button when there are more people than the configured limit
  • Dark background support: Proper text contrast on colored widget backgrounds
  • People Widget Guide: Comprehensive documentation at docs/PEOPLE_WIDGET.md

Changed

  • Filter field order: Filter fields now match the Display Options order (Group, Name, Pronouns, Role, Headline, Organisation, Email, Phone, Address, Website, Biography, Twitter/X, Fediverse)
  • Filter operators: Added "does not contain" operator for text fields
  • Column alignment: Fixed page columns aligning to different heights (now uses align-items: start)

Fixed

  • Dark background text contrast: Pagination footer text now readable on dark widget backgrounds
  • Widget title alignment: Widgets with background color now align with widgets without background
  • profileEnabled filter: Internal Nextcloud field no longer appears as a filter option
  • Avatar filter: Avatar field removed from filter options (not useful as a filter)

Documentation

  • README Updated: Added People widget to features list and documentation links
  • Internal Docs: Updated Additions.md roadmap to reflect People widget completion
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturehV3i13h8ckL9hELKxdaQ8Uyr/kUJCtjteUUgczGkj0i4AUY1qmxOQpr7h3SZSYG/5V7cOWG0VcT6eofmd2tM2zTY21oQjMEs+vlojzYwU0TgjXUQJlwkremsvgKJJsa28o6Np3w43G7RDk3/xVWl8Rcp+McTwCw3jIYGHJLnOTshQgmWIahWCynsLDUVGxidb5kwUoDGMZKii7tS9oM5l/1H5RnNGtlD7fvquDNemQ6wBVJ2u2ijvPXCdFzn20gfwfWk3T2O7Hwjz50fnkrdvd5vO7OzaxjbIhBKy7mZanIEHuRNHA7xjzCvB+Cd6yPk6SRHR/5vY3igFgSTdpF8pJCopnnNr8Tid+lWeprqIl51wwgjb1Gz2Z+OQQ84zVj2bmpV9i36aY/r3TuWw551KhqTFSMnMUQmk2vYw91wP5iPQGX6kxu0h99Qmt9Zs8HjFoikwLWtDb7iAGHa77pC+SBTdrV5fP7BCD//AD5owXapaFJT2NXrGcMoFJBQes6CR9dBVHZ04WU9lMINnqh3G/EzigknzoMwheQ/dqD7mH2PVuIMFNm/FIEWXUPbIwgYvjrX/pkeFVtU4U7O2Tt7jbBYD2kwSMFEM4loiC7wNEzCUJ+UAwBj3ajE5PL3o11UHademWD2HzCTabzlQg0K3seX4M+aig2MzmEugamVGhw=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.12
Release Details
UpdatedFeb. 9, 2026, 5:01 p.m.
Changelog

Changed

  • Automatic Template Installation: Default templates are now automatically installed during app install/update
  • No longer requires manual occ intravox:setup command for templates
  • Existing templates are preserved (idempotent installation)
  • Templates are installed after demo data import completes
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturerVvT4H+yHmCH6KJhXQzLiyYtLlPHVtbrH3egQgcFN1xupxG4LNuGDzHOx097ODYQew0KOYcfb388+/V1Y7XxTiqXUeFRxX6hANfZo3TWoMP2YUW37X8IYiGFbpWsBxSbxP2qgrgsjbegXDNDmXOzPA264ee7O5yIPHyWtm5ZLD49RFOMItOB5phR8h7+4digwmdfAwtg9HR9OkBXJZI0mUmFUuJ/CWpDhFVTi/RUbNQ40D8Vyl8PWgiYN/00SmzFq4IwMRKpaGcSTeD7xU4exMKi06Rn/IO8zdpjSJJXN2gS2YUm9+c+cOxJ4p22QR6oPO7buPS9R5hN3AiwoW3Y7W9mu15NsRIOAHlgSiGpPiqAUfd02iKUHllL/ZH3cWYK39xynRoyqAOz64vKUiGo7O6thbOfrsua501HN6Xu9EkPMjTOeljcu1ZgErJCJr/W+XbvXbj62L8DnxiJW6fwTTUZQiFTpPeBBwgzKjX29qj4f/c+w9RJH8r4etu4YWj+kgVvBVU9tmn1ZOoDO4O8e5LiudB+kG0Rt0+hwxy1xyU/zybjiVtTeIjRIaIqXtbXMRfTO8lDcQjoLdGxkuOLN8f96VmIPSTzPUp9+DC67c7SCAQEO0mmR1iYu5o7UsiCZKg26kFdmU8sJIxJcjM3D2DSIvs1/HRvZqdRjBBAtyQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.11
Release Details
UpdatedFeb. 9, 2026, 4:20 p.m.
Changelog

Added

  • Default Page Templates: 7 professional page templates installed automatically during setup
  • Department: Team info, services, and resources layout
  • Event: Program schedule, speakers, and registration sections
  • Knowledge Base: Documentation hub with categories, FAQ, and popular articles
  • Landing Page: Visual homepage with hero, features, sidebar, and call-to-action
  • News Article: Single article layout with hero image and related links
  • News Hub: Central news page with carousel, featured articles, and categories
  • Project: Project management page with status, milestones, team, and documents
  • Template Preview Cards: Visual layout previews when creating pages from templates
  • SVG-based schematic showing column layout, header rows, sidebars, and collapsible sections
  • Widget type badges showing which components are used (heading, text, image, video, news, links, divider)
  • Complexity indicator (Simple/Medium/Advanced) based on layout structure
  • Column count and widget count statistics
  • Enlarged Template Modal: Larger "Create new page" dialog with improved template gallery
  • Grid layout with 220px minimum card width
  • Scrollable gallery area (450px max height)
  • Template Translations: All template titles and descriptions translated
  • Dutch, English, German, and French translations
  • Automatic fallback to original text for custom user templates
  • Template Stock Images: Professional placeholder images included with each template
  • Hero images, feature images, team photos, speaker portraits
  • Images automatically copied when creating pages from templates

Changed

  • Template installation now runs automatically during occ intravox:setup
  • Templates are installed to {lang}/_templates/ for each language folder
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturef4SDWLwiEFHMcQ9i+1jUrkEJL3RcJA3/36FDPoI6nVf5uS3h8kmnF/tnNLGzj7gr5SKdvn9AglqkSTF9L6a/uz28LTgVq+9QaLPlBUDdjhuIDMIJwPbN1Z+kiWIcCVpz0gjNkhbyCQJ4ZQNv/ViYQHFG74Xk2GCIuRfXeopAyklSJcL2cZHfTQhoJDv42nLS4aJ7Umgx7XXiQgi9aAX5u911NTer++UU32Tu9ywlCx/XmI7IRLB/yv/Lufgzm44PiNpejcnCYsCuXTGemqUZhO44LcNN6299uwiz0X7A72r4KblNo1HDBjCeBTrut0EdguRCOeZuRIrW1xBC5nLK0ETn8C03BAomGvqHVcdxehgZ7V3dstxE82DwQ0/CGok3DiWg3k9xlQItM/Hej/Ztss6YJmgZafrN8yx8hrvu21yCnPUYzBurL4Xz3odQOa3+NqIWx9YPB10nsmHti2mnxm36wKxIl7Lcw53prdUhWrVMateZyOUXHJhIlHOUjAs2IkkSrWAcr6r9gqCasTYADMNGb3SK2q7ne8Xc07A9KHJR+gxen4HYVINqCNZXtEgKc3c6e9yTFoVp05d4NkVHT4eEjzAjr5q6fyzLDYtZnRqznFTtMdlIeutKI+a6s0Np9iMt6XU8E0hvB8x+i6uTsNN4ebCRu7DmJma7GZripmA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.10
Release Details
UpdatedFeb. 5, 2026, 6:29 a.m.
Changelog

Fixed

  • Text Editor Table Spacing: Fixed blank lines between tables doubling on each save cycle
  • TipTap inserts phantom <p> elements between block-level nodes, causing newline growth
  • cleanMarkdown() now caps consecutive newlines at 3 (one visual blank line max)
  • Preserves user-added blank lines while preventing accumulation
  • Text Editor Asterisks: Fixed * and ** appearing in text after saving bold/italic combined with underline
  • Mixed markdown + HTML (**text<u>underlined</u>**) now correctly serialized as pure HTML tags
  • Error fallback now escapes content instead of returning raw markdown
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureRb0bxVoFDn0onuvt08cN9KDhGJKkZ7Ywexlj2Gc1E67YHFQLxeR+6iSbf2/p+vRuIi6rOBpSzlycylZNcgtyMLbD5/Qr5YFTyX+QxVPyu4l8HtySuCpyzBk0roO2gJZMYOC/iBvFVqmRojoURC5x4wwNhmoQtK1l8vM4rDVVX/IA3bn2kj5TD14EzAyG8nWkTogmwmDmNDiRu0Ut+uPOTznHSb3NbeoTQb55q88uljKHc52dqLeR/C/zxyxZdmNJ3jnHkLdqfr01SMFw2cXh8VnVa7fEy0kwvbY/JOXX/5puMGDu61ViuNDhrldm+tw+fPpswuwiSE/fax4JuJHw2Xpt3le47BQ0ulWVXoPABervbAK40QFxAtQAQwa6KB7AgSQS2/mArmBS+lmJWhWxduYnrWLmrmP2os4n/8Z6hS4CCjpqhbUKYJTmyGh3ZILw3ILvuqGXW8q63f6D0uccAwM9hkRYAQtdtJWf0/MoI8q2gzxe6k6n8TH+UOor8GzwqIq2QrR02xBGak+M8QyQ939BeZGzki6ZLX9K3eJ0pPeuf998szkZWDqm0NR40b9CCTepv6VzpwQK99C2YgDDW8TynbZQlz1FKHZouiUDFlct7PC7Jt530foYbSuO+j4gP+5Orz2AaFD/JJjT69UkaZ/NskvxawLKF8ypfXLjCT4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.9
Release Details
UpdatedFeb. 4, 2026, 5:04 p.m.
Changelog

Added

  • Orphaned GroupFolder Data Management: New "Maintenance" tab in admin settings
  • Scan for orphaned groupfolder data (from reinstalled Team Folders app)
  • Recover content by migrating to the active IntraVox groupfolder
  • Delete orphaned data permanently
  • Useful for production environments recovering from Team Folders reinstallation

Improved

  • Team Folders Error Messages: Renamed "GroupFolders" to "Team Folders" to match Nextcloud App Store naming
  • More specific error messages when the Team Folders app is not installed or enabled
  • Separate error messages for different failure scenarios (app not installed, folder creation failed, access denied, unexpected error)
  • Full translations in Dutch, German, and French

Fixed

  • Public Share Page Tree: Fixed current page not being highlighted in page structure popup when viewing via public share link
  • Public Share Page Tree URL: Fixed 404 error on page structure in public share view (was calling /pagetree instead of /tree)
  • Password-Protected Share Navigation: Fixed "page not found" error after entering password on public share links
  • Generic "Could not create IntraVox GroupFolder" error now shows specific guidance based on the actual problem
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCLK9mZDM5DTV0G98PiLFat4vI+clsiUTK4u6rci3QZo3gGoEfdS9scFLnDFufZAX38L1jetr0rM7ox0+DJz4xLXmZ+dTEjPT+ACNuja3PIGIkp/qO2+4E8nZfKU5xmSWT8oIPylplzgJ9xJ3BkbeRmz+V63g7yRa4AD/OSg2j9sXudoSBci2+qmIyKm0WML6erw+rUw4NY7bOLo2GCe1UrVFel92VJ73bm6ASSMPgg1un6880sSu+Hoc+Y/3HXQYUftfkv9fWWLvcIv2lDcsDQqC8+2i+F5DjLgS7EC7u+nLJKCxDyeAinA+oC67q2Q3ztXb66OcvDDe1C73tgp/4K4d1a5hNwzBs26LrkvnTf95hT1IiVWdIIxSMJ9mFCDtzAlyThKm6IQub8De8bcpGocMN5jkNiZgt6eAj4oTbCvB3P1m0oRHa7+FWvTkLC8n81NLQg7JteoR4BzSM7IpmWs6X3AFv6TfHfTmRTOQgwHtLietzq4WFlD927LtTYwHJwuyb8/JAbsDGvzhKO40V+Jw25FuolqF808s64TWjrjz9ejta5yuk1eg44FlrqVXICwUvOZ1Qcx/kIaOUgpG0N1zvPmiU6Z0sB3bCkVyujYFmP7ouL3pOrkh1LsCEGFMxtrnx6x0O/fCfpqr8TLA1p/nSGRddchhwRhc/DKz8DE=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.8
Release Details
UpdatedFeb. 1, 2026, 1:57 p.m.
Changelog

Added

  • Public Share Links: Full anonymous access to IntraVox pages via Nextcloud share links
  • Share any folder scope (language root or subfolder) as a public link
  • Anonymous users see pages, navigation, footer, page tree, and breadcrumbs without login
  • Share scope enforced: only pages within the shared folder are accessible
  • Rate limiting on all public endpoints to prevent abuse
  • Public Page Viewer: Dedicated read-only view for anonymous visitors
  • Full page rendering with all widget types (text, images, video, links, news)
  • Navigation menu with mega-menu support
  • Page tree sidebar for browsing available pages
  • Breadcrumb navigation
  • Footer display
  • Responsive layout for mobile and desktop
  • Password-Protected Shares: Full support for Nextcloud share link passwords
  • Server-side password challenge screen (rendered before JavaScript loads)
  • Session-based authentication — enter password once, navigate freely within scope
  • Brute force protection (10 attempts/min per IP) with random timing delays
  • Password verified via Nextcloud's IHasher (bcrypt) — plain text never stored
  • API endpoints return 401 with passwordRequired flag for expired sessions
  • Vue.js fallback password form for session expiry during navigation
  • Share Dialog: Redesigned public link modal with full share context
  • Scope indicator shows whether link shares a page, folder, or language root
  • "Password protected" badge with lock icon when share has a password
  • Navigation tree showing shared pages structure
  • Clickable "Manage share in Files" link opens Nextcloud Files sharing sidebar
  • Copy public link button
  • Share Button: Always visible in page toolbar with two states
  • Active state (theme color): share link exists — click to open share dialog
  • Inactive state (muted): no share link — click for guidance on creating one
  • Detects existing Nextcloud share links for the current scope
  • Admin Shares Overview: New "Sharing" tab in IntraVox admin settings
  • Lists all active Nextcloud share links on IntraVox content
  • Shows scope, file path, creation date, and expiration
  • Direct link to manage each share in the Files app
  • Useful for auditing public access
  • Sharing Disabled Warning: Clear feedback when NC link sharing is disabled
  • Warning dialog with link to Nextcloud Sharing settings
  • Explains the prerequisite for public sharing
  • Public News Widget: News widget works in anonymous share view
  • New API endpoint /api/share/{token}/news for fetching news without authentication
  • Supports both sourcePageId and legacy sourcePath filtering
  • Share-aware image URLs for media in news items
  • Only shows pages within the share scope
  • Public Media Access: Images and resources accessible via share token
  • Page media: /api/share/{token}/page/{uniqueId}/media/{filename}
  • Shared resources: /api/share/{token}/resources/media/{filename}
  • Resource subfolders: /api/share/{token}/resources/media/{folder}/{filename}
  • Links Widget Color System: Redesigned color options for intuitive background control
  • Container background: 4 options — None, Light, Accent, Primary (with visual color swatches)
  • Individual link background: 3 options — Default, Light, Primary (with visual color swatches)
  • Default links blend transparently into their container/row background
  • Automatic contrast detection: white text/icons on dark backgrounds, dark text on light
  • Telemetry expansion: Added 7 new server configuration fields to anonymous usage statistics
  • Country code, database type, default language, timezone, OS family, web server, Docker detection
  • Send report now button: Manual telemetry report trigger in admin Statistics tab
  • Breadcrumb Home label from navigation.json: Home breadcrumb now reads its label from the first item in navigation.json instead of hardcoded "Home"
  • Public sharing documentation: Comprehensive guide covering setup, scope, password protection, security, and admin overview

Changed

  • SystemFileService: Extended with news page retrieval for public context
  • getNewsPagesForShare() uses system-level GroupFolder access (no user session)
  • Recursive page discovery with share scope filtering
  • Excerpt extraction from first text widget
  • First image detection with share-aware URL rewriting
  • Color Utilities Refactored: Separated DARK_BACKGROUNDS and LIGHT_BACKGROUNDS arrays in colorUtils.js
  • New isLightBackground() function for accurate contrast detection
  • --color-primary-element-light correctly classified as light background (was incorrectly dark)
  • News widget layouts (List, Grid) updated to use new light background detection

Fixed

  • Public Share Page Tree: Fixed page tree only showing homepage when sharing a language root folder
  • extractSubtreeByScope() now correctly returns the full tree for language-root shares
  • All subfolders and pages are visible in the sidebar navigation
  • Links Widget Contrast: Fixed white text/icons on light backgrounds (Accent, Light)
  • Links without explicit background now blend transparently into their container
  • Correct contrast for all container/link background combinations
  • Webpack Chunk Caching: Fixed TypeError: n[e] is undefined when opening page editor after rebuild
  • Added content hash to chunk filenames ([contenthash:8]) to prevent stale cached chunks
  • Telemetry countryCode and timezone: Country code now derived from default_phone_region instead of default_language. Timezone uses smarter fallback: Nextcloud config → php.ini → UTC
  • Telemetry sending to wrong URL: Fixed telemetry using deprecated endpoint. Now correctly uses TelemetryService::sendReport()
  • Homepage breadcrumb label: Fixed breadcrumb showing page title instead of navigation label on the homepage itself
  • Files URL in Share Dialog: Fixed file ID using internal GroupFolder storage ID instead of user-mounted ID, and corrected URL format to include index.php prefix

Removed

  • HMAC token system: Removed unused PublicPageService, PublicPageController, and templates/public.php — dead code from an earlier public sharing approach that was never used

Security

  • All public endpoints use #[PublicPage] and #[NoCSRFRequired] attributes
  • Share token validation before any data access
  • Share scope path enforcement prevents access to pages outside the shared folder
  • Anonymous rate throttling (60 requests/minute) on all public endpoints
  • Password brute force protection (10 attempts/minute per IP) with random delays (100–300ms)
  • Session-based password auth — password never sent to browser or exposed in API responses
  • Nextcloud share link settings respected (shareapi_allow_links)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
Signaturem52gHbT8mXTWqFH4iSNkuu5vB+wlx9soo59UPs31A7tFoHe9ipoUyemUw94tnosKwj12P217nOwEQEFnSr059Bmndx8PbO4OGgALv3MkZppE6KJoglXIt2oLYwh48ALSlGDRkNU3ciWDTruxcO2KF541cglphiykpfqrp0nTBwz9KDiseor0Ts9qE9aXjYmxPQGKTmb1XEYg0L0h01T0+QTS0pyl4mozMspZY6wok7y6hMe7/GAv/tE2EOBlUudKN/l8cG6T8I4p6Qce4ChxHQXrFEOJy4nTnGaL9HAt91iIYl6Pc42qjdzv4gTAYlmHYreAXkxf2duLBapfAhS3mcuoArtf4V0e+IEOji3+yZNR9c9zE0UkeTqBSXSqZ0hyFAUcDMO5VRbHh4CtOYW3yY5skaSNrl6quM881IHN9ipvlFkIimm/gxttYI8Kh+9/kg7QZiEnx59JPkc8jPy7yoeATW/iFLmFNvgGh05j+Gm2EG81SlkgUmkEWxXVOjWKi8g/s0IQlZjzP/0ZwrsbnclXAkzxXR66jx0K9ajZbu9hLkCDDlJ71lYk5WnSYiZgqdllraAhc7kaPRQDIPW/PqH+CxVV+KB68TW/3wUwJvPewuMpTDxXN6uuZC2IymxXib9wn59TiXGpxRJDk6R9K4hqPmnwBV99NW9Oj8J6q1I=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.7
Release Details
UpdatedJan. 26, 2026, 9:51 p.m.
Changelog

Fixed

  • Code Block Rendering: Fixed code blocks corrupting after editing (#15)
  • Backticks no longer accumulate when saving and re-editing code blocks
  • Fixed double-processing of nested <code> tags inside <pre> elements
  • Code block content now correctly preserved through save/load cycles
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturefR/S9LkpLomqMbPE9qRCN51jLKAOMSBBCKWk1nyzwc5cK5N6NGBgTR5N2dcU038O2He96+BawNXePcpw4tUMoKYjLAt6DLr8iGq4+CSfGoFCYaGpoRm9RZS3hd0iVIgGeh81hXnEkWGII3bTaS0I2Mb4HWb2zxhViJESD8AiFYGtkdO4lIhwa0Sw1r5yQMxn2G+rNJM2XB+ySqeH5krhF6DnPMAsED9dK6R/LVXFfrgTpc2EFUoFPlXIqzwRM8bFAWbpNkRBb88n2wnKFYiE3bYJALPDXeUa7nw72NV15VK6K2JVpc5fZvcy8/Xz6M61aTPA6JtTMczbpzhzlwYeMk0W0/7PWbNdvtAXn6OYNuqkGHacCZcGMzf01Qb0HrQQm7kGGngfwK/avoPiz3oclnB75vQeH4wKMZojhoggxCzWwnfRPCF10UDh0AY/ofN2JOkMFLbpKUjI7suVty3r+vWKGZk5qbfbZ4w3E2YGBYnFZYVlceRa86EEBJuhCIvbXPWQDriyCWoAvgUksmuB/Nhhdbp1btDoqzGK9l2W44W4EAyOk2JX32cAKdzAjBcQlqvuvQoGuIhn8E0pORBH/w1T1J5tj8VPZl76lVopDOq400BQg0eaJQhURnlCCa/XAt5NY+AbBLXfaYFhYJiZGDLfg5QWenLgLNdjfaQd/3M=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.6
Release Details
UpdatedJan. 20, 2026, 10:05 p.m.
Changelog

Changed

  • Database Exception Handling: Use OCP\DB\Exception instead of Doctrine exceptions
  • Follows Nextcloud coding standards for database-agnostic error handling
  • Cleaner code without string-based error detection

Security

  • svg-sanitize: Updated from ^0.20 to ^0.22 to fix medium severity vulnerability (GHSA bypass)
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureFKbWtadpIkxyQORuyKmtdyhKihh+TnOpv5TLpiInVKZE91KqljyU+oxQEOMEghDVY//reBY+zgArAWYOGB+c77eMdrpeblpFleaLPEPME9VjGxXK81ehLDtM3hPpnI10nNueL/wg+WPeWqNYG/IiyC1oJH5ks1yeiF91k6vunuDs7nHGw8luQQc6KNoLRwFJba2uQsC9s9eY4nwRSZ8YAlPrTGzU1JqQB0vQVDynOZio3tEvLUW22JPWTbrLOTkB95okcwV1t1h7kdrxb1E3XDYXZ/gkJq0FXUVg+FsKTQQnknZoOz1ZFUOaymknqb+MEQs1pgaufd+5NfcHIFw228GmVCNtGiAd+OCJdIlkWnKG45uL5z+fywTOEroY+liiYCmSCZq6bYDLnk4YP0PvVc02AyktC/0C/UYx5w8G3lh5xq7T4k6BpVvGyohUSr+GbnDybwJw5wfDpL1BRUSo9uWtBMa7/4ZOFFlBCuFe6/R50Vc1F28d5GYYRtRwB0+c58lacFeEluC1QJZBQvv5j+ktOi2FmWch9b8+0mKNdBTjt7XVU2SClcAJrA13+SzPsBJSE1LWeHEWg/10mAxz9P4kjDYfHAJs7SzUAh5E+MORwYKrybx4hLgh6Ufv9qgcXZeRwt0rTPIE3xYCymSUG3guNzsa4dFar/mpb64qy9U=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.5
Release Details
UpdatedJan. 20, 2026, 2:52 p.m.
Changelog

Fixed

  • PostgreSQL Support: Fixed database compatibility issues for PostgreSQL users
  • SetupService: Now correctly handles PostgreSQL duplicate key errors (SQLSTATE 23505)
  • LicenseService: Added null check for shared folder to prevent crashes during setup
  • AnalyticsService: Improved exception handling for unique constraint violations
  • Installation on PostgreSQL: Setup no longer fails when re-running or retrying installation
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureCMaJ3B5mnvM6amFSYgSIl1zMz427DUBNfZLUlQ3gkTIaJIqwtTe0GVFB667GBiMomYz9rLe3pUDzGtp1zzd84PfFmXPEvwGftcfAmeawzTphAWlNAdC91KRdQaTWas73h6jEm/ShFCaVTjxE8aDRgjZIZzjrs95mSQFkeRTpN0nML+xqH28AkR2HIJL++3oWN7e1jpWd2HCyOLaMpbRDU+GJ6rGnBvBTj4MsoTVzFMs9cyKXWuaa0R9eCUDCumxAxnWL9aqdkf2A/GxpTGuzR2QktWHEnatZFVAf3LlVSw9YxG/hem9M/FBQ825ErXlsh7LUxBRW9gFpeeDfTn9M06E3Gqcy+BmbjTUn3lmfYjx2TZxU6idCfjr6mgCz2kaTG3vv7myuvyalVdaydrQpzLJ1BpWpEpGJ7tU6jytr/AU4THlvr76j+EvgNgtAor0bvzHgFc8oXbBOLwi5MI9oNC033F4zYKFajqiUuwUVtEtsSYz425NxKh6jSqikaN3F1yG3p2+ZlSBRyUJKsfu5fJraoPKlbqPnoOKnK5K6fv7HQOlCGbD+FYNlVDjN/PhSLFdnypOzP3rq0SUVrjvibzKqASjP6E/FkBrbCwCf+yWHxKE0rLSYPAL6GOFKxtKib1jQ9iJlK1zlQMH7EyyF3maT9cVaBk42M+a4a3JFlkQ=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.4
Release Details
UpdatedJan. 20, 2026, 6:43 a.m.
Changelog

Fixed

  • App Store Cache: New version to bypass cached signature data in Nextcloud App Store
  • No functional changes from 0.9.3
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignatureGfWF48G9tm/QACyvvgQbDVriO6sYowvPNvLlP2sDX5bsPsh137Ttl0OtdKKS8z5SRmJ2FhyXUlBDgKyD895MIIjXtlc7QINL/fvk784n/7dm/kvEPIKsVVKAYlUSLt7aTUib0s824ahT0VilV9JZSH4934R8KkDVE3B9Ksk1J/EA37o5Ojmk4WsFCKfMnz0Yaq1dZIpEQ1jLSIdYTfdlVsqEL6Sam3+m1A1uBYqZQqnIczeqh2xoSh8n9QnlBQmDC3hzBW5gybKbXpufSwxaSJgxcfXDbQQBT1P6oOstHbchAeGt84Fb6wDlgVD8I/C2NUE7kwt/wWfojCWtGbiejxPFiz1A/fAgKvt3RpFdW7QhsQLqja0LHmvAb/FLgBNqaqUh4Pv3r+OSDlxXzMvZ/0imvqpp2XmhhpmAgW9CF/T64Pg2nNjwy/Nb+2e7el2sGfmDbYSSE77+P508rcGfexP0D98dfo7bAgsHdXmiK+82PFPc/Vo8cXwLkdChHunk660tIraABOukG4ytJCjNgiqWPMa9gIhJ/2d9/PZyB0b3UFvNkVgRiQxaG39fLzR5zbBCeEbQf2mbVARX080Q+jhkj9EK9ybKvdBJ3whjpeJsFiHsRxlmCXJubj6YMBA9Ilm7LaXDxob6lcLa1cnav/evH7uWX+NExN3GuFHq+Z4=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0
IntraVox 0.9.3
Release Details
UpdatedJan. 20, 2026, 6:24 a.m.
Changelog

Fixed

  • App Store Certificate Sync: Re-registered app with new certificate (serial 4824) to sync with App Store database
  • Previous releases were signed correctly but App Store database had outdated certificate reference
  • Resolves "Certificate 4822 has been revoked" error for all users
  • No functional changes from 0.9.2

Documentation

  • Added certificate verification section to RELEASE_CHECKLIST.md
  • Added warnings about certificate management best practices
Licenses AGPLv3+
Certificate-----BEGIN CERTIFICATE-----
MIIEAzCCAusCAhLYMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjUxMjExMTAwNjEzWhcNMzYwMzE4MTAwNjEzWjATMREwDwYD
VQQDDAhpbnRyYXZveDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQN
YNfXarB7ojw5TU/UgymTbNrz7ciF0CESRsSMzXEUHdmgXQtB7uy6TBfptRkaA4T9
LJ3Vu5JQvQq4LAXWcQq3NYjY5KyhNGsg8pXl1Kbg1LxecKDgRTgEP/aWzsz0bpPf
vp3pzbhKuagA7v7hZGtihkAu7dY9ddNE5F2pTrTe+AhZhAwfYl1bOAEl/EDJ8DW/
iD3JZpA2kL6AuvciyszTkUuFz9PKBh1049jmK3YvWMmYyGcacExV0X/InAMyryt+
inle8X+0I+3Fbq+V3ErTnDeAYV98HdPbAmIstrPXrKmg8qDlKT7huu5H4t6eRBL1
DuoQhdBAx3nUq/KTueWe77U4d62j4QjkG46/AjAdE6qHEMpDL4mpjoxMs5uE3jG7
D5GvIkuugO9dFphV2pTmMTPwmzwa5X2hIR89LL1MxvoEz9lOFZJvspWcBeT041OS
BFI8pDNJmhca0q9XRvnSPXNiSYiqB0NztBDV5D8rNG4SfSSOWmxaJdMK5MWjDVfX
P94RbjrtPiKAx7Za18XZVkJImUJKM8L3iTgBFfi39y3um+Ni8u7quc9/7i95mJWA
8dF8vg1S6ncnrM+rHf7//cwDT+MH53RPWqo7e04BZgMwbZR5lD1cTWxTPY1YTW/Q
YoC7WC4ojeXJle/5tchQmhmkL3EtKGudyAhu+0vlAgMBAAEwDQYJKoZIhvcNAQEL
BQADggEBABhIXx8zpg18WiN2cAvEY/UeArKCfMe219a9ThTC8R9ChZHdfJ+QSrso
9Ut22V+9ByKKlbL1AEr6FG3sc8k35ceMdBVbcO9ZfPw3JWj+dbZIsEHoHUl4c2H9
rmGfOKMX8cqi6BMarVS9prn9ooGKCsiK7qyUm30nGaq6d6tNxp09ZY0Tr3PcOV8p
sGki2uPuoW3COGlSStV+VXiGD1HfUWGv/WKmTF4cS2Uqs8cy2eWjZeXvjYfmyV/J
BP3dUfHDC6/aSUdgo7AeBcGaqht4dxkvO3QGAY4nUZOgTaWxtr+65Lh5dRWm18h9
H6ufHVEsUE5+REYBGF1ngVctIzrgcdU=
-----END CERTIFICATE-----
SignaturepiCaGChVVrjsXiKqs1rnsOLZQkqXg3euTL07Lmz8dM/3wvfWDDNczY3NFuwxcvuDJ7ebhaybka6uEsVgQgiTXI48nnNLMoFj7yFYc+NcHNTIpQ8f0wSXvy4K3GaeHYvjAlc30fLegAAcRHLfAVvmNBi6Y7t2xwRfsMCThqTgOrblKRTncOxVsGg7VJ1AeDdTvETLyUT6MWrqYHF/9amV4+M6D9enJ8XNRUI5P+IYDAW84q65EpSiykK3TCfHVQ2GGJJHMblZvGPgS2xVS0tih4N24KRdIPjetD0YDrA25Mj9XJhtIEc1tKvI2T2Cn/C7ErIC3cSW6HjS0oFLNKU4QmjJRhXYSlOJ4k6YaxjPn0pR9tZYLj51EIptOrb8SnAlvUpDnC1v+ExxPwxctomncAVRfXKcRuPE5hCtNBfiElcqGMTtG5G5FwntNaog5yBo3PwibNe5Wb671AwzJ2DnxKseiKxtcgPfEpgNlZnU+BHiam/GXYI29CVHo61QOEGUdrJS59Ey0eXlXdTEisT3LaTi77AMVF2WxG0v0y1yI8uhOWOxzDviLheiRk5/7tLmWK6v7uDLu8IhUzH49jmRNABdCaHALKd5eu+ON5TZ2ZK5YfnxbTDHILzbt+BP/2lToTNh6S+2QgVxx195hk4dCVfGZwfV5B3OAni4VcEfqmk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=32.0.0,<33.0.0
Minimum Integer bits32
PHP>=8.1.0