Skip to main content

Group Manager - Releases

← App details

Nextcloud 35

Group Manager 0.4.1
Release Details
UpdatedOct. 4, 2026, 1:28 p.m.
Changelog

Fixed

  • The App Store listing showed no screenshots. The App Store downloads screenshots once, when a release is uploaded, and 0.4.0 was uploaded before the new screenshots reached GitHub, so it stored empty images and never fetched them again. Screenshot URLs now point at the release's own tag instead of master, so every release gets fresh URLs (and the images always match that version). No code changes.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureWF2ootnp64z1VTO9WeyRho9ldOctFbO6wDDcXRBHGMBic6hJfIomcfSfYtj8fvm5IUxe/JWzwIlB0DYgwTaM/aqZ30ZUh57IT4AOYDQQ8hoU7UHZCLl5W/hlFOr6Ok0rrnCHegpGlQ8T7LJ4MaPvc87uugf9PH/rSin3GTPhWn5ZVFGwy0A9Fwa1SlPnND58JcNMtGyZFsfBpMniJG1b8YlV33EYgtkWWXpuFCJJAlv05arqHkLx5Er9VAtDWXvEE77g3BM2U4Fc0x9VLYbtZMx9/9AfagawTcC68crt9q3b2Rh3g53w1GBOOVVfJUaRRGzfijAKAgeDIcX+cLak0afRMxZ+e8aeWeLI7WG7eSiDKern+6I+MWd7fymCcoVy7kAAGQgnrVNNmuVMcdsGeZshqPuVbG3sQlNTt67IYJdwzqs7NLtha4ahE40hVBsTLgvEtkUMh3k5VJSWOLVhSllX4TwaJvDlP8vPsCdrm6ZIu98oadAo0TQyggMwP0/oD3oIajLc0q/7dr2n0B5W9pw4ei/ziCcJ6Y0m5UY35A5Ic3Tnyb1oh+irghi2Q1x5Cj3gG4UFoJjPSq134hAzukYpIKRo6K4yCa5KkbsvRIGnRHd58xCH1THlGQB4uMjyWGY+rVRNJQzAJJI4aNU6PRmjl2qHnSmqJNKZdB07jQA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0
Group Manager 0.4.0
Release Details
UpdatedOct. 4, 2026, 11:46 a.m.
Changelog

Fixed

  • Opening any group's detail view (local or LDAP) returned HTTP 500 on Nextcloud 31 as soon as the Team Folders app (groupfolders 19.x) was installed, because GroupService::detail() counts a group's folders on every load. FolderAssignmentService called groupfolders' internal FolderManager the way its 20+ releases expect (a required storage-id argument dropped, folders read as FolderWithMappingsAndCache objects), which groupfolders 19.x doesn't provide (it takes that argument and returns plain arrays with different keys). Every result now goes through one normalization step, and the one groupfolders method this app used that doesn't exist before 20 (mountPointExists()) is replaced with a direct query against its own table, mirroring how folder_protection already reads groupfolders' schema instead of its unstable internal API.
  • Two admins removing each other from the admin group at the same moment could both succeed, leaving the instance with no administrators. removeMember() now serializes removals from admin through an OCP\Lock\ILockingProvider exclusive lock, re-reading membership and the admin count only after acquiring it; a backend that can't answer the count at all is now treated as unsafe rather than let through. This closes the race for removals made through this app; it can't coordinate an admin removed some other way (occ, the core Users page, another app).
  • A group folder could be assigned, created, or have its permissions/quota changed for a group ID that doesn't exist (a typo, or a group deleted between being picked and the request landing), leaving an association that silently grants full access the moment a group with that ID exists again (LDAP re-sync, or an admin recreating it). FolderAssignmentService now requires the group to exist before every such write. Unassigning is deliberately exempt, so an association left over from before this fix (or from this exact race, which a lookup-then-write can narrow but not close) can still be removed.
  • Pasting a list of users into "add members" showed a wrong count of new members when the account belonged to the group but was outside the currently loaded/filtered page: the frontend decided membership from whatever page it had, not the group's real membership. resolvePastedList now reports each entry's real membership from the server. The "N members after applying" prediction also no longer uses the search-filtered member count as if it were the group's real size.
  • Going back or forward in the browser past a group with unapplied member or folder changes used to discard them without asking; only switching groups from the list itself was guarded. Back/Forward now asks the same question, and reverts the jump if declined; while a batch is actually being applied, navigating away (either way) is refused outright, not just guarded by a prompt.
  • A search whose response arrived out of order (members, add-field candidates, or assignable folders) could overwrite the current results with a stale answer to an earlier, already-superseded search. Every such search now discards an answer that's no longer for the latest query.
  • A failed member/folder list load, or a failed refresh right after successfully applying changes, showed an empty or stale list with no indication anything had gone wrong. These now show an explicit error with a way to retry, and a successful write's own result is no longer hidden by a follow-up refresh failing.
  • Group member pages could not be paged past the first one whenever the backend could enumerate members but couldn't answer a plain count (count() returning false, seen with some LDAP setups): the frontend required a known total to show "Load more". Paging now uses a hasMore flag the API derives from an extra fetched row, independent of the total.
  • Creating a group whose ID contains / succeeded but left it permanently unreachable through this app's own API (every route needs /-free IDs); rejected at creation now. A group with / in its ID created some other way (occ, LDAP) is unaffected and still manageable everywhere else.
  • Malformed input reached internal errors (HTTP 500) instead of a clean 400: non-string entries pasted into the add-members list, and out-of-range limit/offset values for a group's member list. Both are now validated up front with a stable error code.
  • The add-members search for whole groups used to enumerate every member of the destination group, and every candidate group's own full membership, on every keystroke: a large directory made this measurably slow. Membership is now checked one candidate at a time, up to a fixed page budget; a candidate group's entry shows its own size, not an exact "how many would be new" count (computed once, cheaply, only for the group actually picked). Opening a group's Folders tab, or counting its folders for the sidebar, no longer reads every group folder in the instance to find the ones assigned to it; both now query the assignment table directly for that group.
  • The add field and the "Filter members" field are the same height again: a global Nextcloud input rule made the add field 2px taller, and its outline was clipped at the top.
  • The Folders tab's Write / Share / Delete headers no longer run into each other in Portuguese, Spanish and French: the columns were narrower than the translated words.

Known limitations

  • The lock preventing the last-admin race, and the existence checks preventing orphaned folder associations, only coordinate operations made through this app. occ, the core Users settings page, or another app can still race with, or bypass, either.
  • A folder-association row left over from before this release, or from a group deleted through some other route while this app was mid-request, isn't found or cleaned up automatically; only unassignFolder() can remove it, and only once someone notices it.
  • A group ID containing / created before this release (or through occ, LDAP, another app) remains unreachable through this app's own group routes; only creating a new one that way is now rejected.
  • Group folders NOT yet assigned to a group (the assignment field's search) are still found by reading every group folder in the instance; there's no per-group index for "absent from this group's assignment list" the way there is for "assigned to it".
  • The groups list itself (left-hand panel) still loads every group and its member count up front; it isn't paged.
  • On Nextcloud 34+, a request for a group's member list with a pageSize outside [1, 500] and no other malformed input gets this app's own clean 400 (worked around: the parameter isn't named limit, which the AppFramework's own request dispatcher special-cases as of that version). The add-field's candidate search and the folder-assignment search still use a parameter literally named limit and are not worked around the same way: an extreme, out-of-range value there can still surface as that framework's own raw 500 on 34/35.

Added

  • Group admins. A shield on each member's row makes them an admin of the group (a Nextcloud "subadmin"), queued and applied with the other changes; current admins show a badge, and the group's summary counts them. Works on LDAP groups too, whose membership stays read-only: the assignment is stored by Nextcloud, not in the directory, so LDAP groups now use the same member list as local ones, minus adding and removing. Removing a member also ends their group admin role (Nextcloud itself keeps it until the user or group is deleted). Group admins who aren't members, which the core Users page allows, are listed above the members and can be revoked. The admin group can't be given group admins, matching Nextcloud's own provisioning API: a group admin of admin could add themselves to it.
  • Nextcloud 35 support, verified against a disposable instance the same way as 31–34.
  • Optional top bar shortcut to the Group Manager page, switched on per admin from the groups list's menu (off by default).
  • The add field pages through every candidate as the dropdown scrolls, instead of stopping at the first 10; without a search term, candidates are listed by display name.
  • LDAP groups show a read-only badge and their DN, with a copy button.
  • Groups whose names differ only by case are flagged in the list.
  • Members show their profile picture when they have one.

Changed

  • Reworked layout: no outer frame, theme-safe colours (light, dark and high contrast), a fixed header over scrolling group and member lists, sticky section headers in the groups list, and one shared header height so the rule under the tabs runs straight across both columns.
  • Tighter header: less padding above the app, the All / Local / LDAP filters on the groups list's title line, a shorter header for every group but an LDAP one (whose DN needs a line of its own), and the group's summary (members, admins, folders, disabled accounts) on the same line as its name.
  • The "N after applying" count moved into that summary, so queuing the first change no longer shifts the add field sideways.
  • Member rows fit on one line (name, then username or email), stacking only in narrow panels; UUID-style usernames are shown as a tooltip instead.
  • Deleting a group moved to an actions menu beside the group's name; the apply/discard footer appears only while changes are pending.
  • Keyboard focus rings show only for keyboard navigation, and Chrome on Windows no longer draws arrow buttons on the app's scrollbars.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureRP4WQaITkAQ5TvSMUSV+zRiAiLbFlomTCbps7cMWh0HTnawO53NQuP+HCJSlaOe39ZiDIPn/8LFzb7Yg4yvrMcV3KGRu7GVNNeIZWEzYEkiqoQ4lelMmOilUsgG6h+QQBb4I99ELRJQ6Nl5sKZjC/eLOZhRT/tCjObBL5kVHtGZ42P80JIQ/SOZhNoVMfhckqSH0cCQyAMtG8tBRtk7A5C0JNGrEfILUcNClhLRcfzLFVZcPt/KHMkws9JdS7UjlS4nhKdfO/kn9hcv3hoL/z6GPTSRqSprfpIqq3n6zhFEizuD55Z0KsRbXZN9c6y+oprDpbnNwlZ6On5H5/4wWTZhJgUPYx8/cRx9COSUphsEB+Y3mAXT8f8s4Dx1p6aD7y6g9DoEduT9+4mq4LPAa7Iou+dvm7ZYigjjHHHjszBEQX+UAb69D776hZ2OpIuI+no4ASheGzunbooivhT1a8amz42lCNooZreV0obpwMrZguvtShv/H1jIHTTl7Bsc9jVRzYCU45Nj1lYIswisPeiLHkwyzbuk0HMq1iFvCgAQzYfw2a7KJLViXO18x3UdH+SvLDPSlGPgH0UlWGezWcDMbaYnJh+sDg5MLOh0k3ot4MPD8yz76aNzFNsYWyNJ6gV30/tJH/lGyQ+JJ23LYa9PPyaHXWvqJqIaRkFy3Ntk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0

Nextcloud 34

Group Manager 0.4.1
Release Details
UpdatedOct. 4, 2026, 1:28 p.m.
Changelog

Fixed

  • The App Store listing showed no screenshots. The App Store downloads screenshots once, when a release is uploaded, and 0.4.0 was uploaded before the new screenshots reached GitHub, so it stored empty images and never fetched them again. Screenshot URLs now point at the release's own tag instead of master, so every release gets fresh URLs (and the images always match that version). No code changes.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureWF2ootnp64z1VTO9WeyRho9ldOctFbO6wDDcXRBHGMBic6hJfIomcfSfYtj8fvm5IUxe/JWzwIlB0DYgwTaM/aqZ30ZUh57IT4AOYDQQ8hoU7UHZCLl5W/hlFOr6Ok0rrnCHegpGlQ8T7LJ4MaPvc87uugf9PH/rSin3GTPhWn5ZVFGwy0A9Fwa1SlPnND58JcNMtGyZFsfBpMniJG1b8YlV33EYgtkWWXpuFCJJAlv05arqHkLx5Er9VAtDWXvEE77g3BM2U4Fc0x9VLYbtZMx9/9AfagawTcC68crt9q3b2Rh3g53w1GBOOVVfJUaRRGzfijAKAgeDIcX+cLak0afRMxZ+e8aeWeLI7WG7eSiDKern+6I+MWd7fymCcoVy7kAAGQgnrVNNmuVMcdsGeZshqPuVbG3sQlNTt67IYJdwzqs7NLtha4ahE40hVBsTLgvEtkUMh3k5VJSWOLVhSllX4TwaJvDlP8vPsCdrm6ZIu98oadAo0TQyggMwP0/oD3oIajLc0q/7dr2n0B5W9pw4ei/ziCcJ6Y0m5UY35A5Ic3Tnyb1oh+irghi2Q1x5Cj3gG4UFoJjPSq134hAzukYpIKRo6K4yCa5KkbsvRIGnRHd58xCH1THlGQB4uMjyWGY+rVRNJQzAJJI4aNU6PRmjl2qHnSmqJNKZdB07jQA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0
Group Manager 0.4.0
Release Details
UpdatedOct. 4, 2026, 11:46 a.m.
Changelog

Fixed

  • Opening any group's detail view (local or LDAP) returned HTTP 500 on Nextcloud 31 as soon as the Team Folders app (groupfolders 19.x) was installed, because GroupService::detail() counts a group's folders on every load. FolderAssignmentService called groupfolders' internal FolderManager the way its 20+ releases expect (a required storage-id argument dropped, folders read as FolderWithMappingsAndCache objects), which groupfolders 19.x doesn't provide (it takes that argument and returns plain arrays with different keys). Every result now goes through one normalization step, and the one groupfolders method this app used that doesn't exist before 20 (mountPointExists()) is replaced with a direct query against its own table, mirroring how folder_protection already reads groupfolders' schema instead of its unstable internal API.
  • Two admins removing each other from the admin group at the same moment could both succeed, leaving the instance with no administrators. removeMember() now serializes removals from admin through an OCP\Lock\ILockingProvider exclusive lock, re-reading membership and the admin count only after acquiring it; a backend that can't answer the count at all is now treated as unsafe rather than let through. This closes the race for removals made through this app; it can't coordinate an admin removed some other way (occ, the core Users page, another app).
  • A group folder could be assigned, created, or have its permissions/quota changed for a group ID that doesn't exist (a typo, or a group deleted between being picked and the request landing), leaving an association that silently grants full access the moment a group with that ID exists again (LDAP re-sync, or an admin recreating it). FolderAssignmentService now requires the group to exist before every such write. Unassigning is deliberately exempt, so an association left over from before this fix (or from this exact race, which a lookup-then-write can narrow but not close) can still be removed.
  • Pasting a list of users into "add members" showed a wrong count of new members when the account belonged to the group but was outside the currently loaded/filtered page: the frontend decided membership from whatever page it had, not the group's real membership. resolvePastedList now reports each entry's real membership from the server. The "N members after applying" prediction also no longer uses the search-filtered member count as if it were the group's real size.
  • Going back or forward in the browser past a group with unapplied member or folder changes used to discard them without asking; only switching groups from the list itself was guarded. Back/Forward now asks the same question, and reverts the jump if declined; while a batch is actually being applied, navigating away (either way) is refused outright, not just guarded by a prompt.
  • A search whose response arrived out of order (members, add-field candidates, or assignable folders) could overwrite the current results with a stale answer to an earlier, already-superseded search. Every such search now discards an answer that's no longer for the latest query.
  • A failed member/folder list load, or a failed refresh right after successfully applying changes, showed an empty or stale list with no indication anything had gone wrong. These now show an explicit error with a way to retry, and a successful write's own result is no longer hidden by a follow-up refresh failing.
  • Group member pages could not be paged past the first one whenever the backend could enumerate members but couldn't answer a plain count (count() returning false, seen with some LDAP setups): the frontend required a known total to show "Load more". Paging now uses a hasMore flag the API derives from an extra fetched row, independent of the total.
  • Creating a group whose ID contains / succeeded but left it permanently unreachable through this app's own API (every route needs /-free IDs); rejected at creation now. A group with / in its ID created some other way (occ, LDAP) is unaffected and still manageable everywhere else.
  • Malformed input reached internal errors (HTTP 500) instead of a clean 400: non-string entries pasted into the add-members list, and out-of-range limit/offset values for a group's member list. Both are now validated up front with a stable error code.
  • The add-members search for whole groups used to enumerate every member of the destination group, and every candidate group's own full membership, on every keystroke: a large directory made this measurably slow. Membership is now checked one candidate at a time, up to a fixed page budget; a candidate group's entry shows its own size, not an exact "how many would be new" count (computed once, cheaply, only for the group actually picked). Opening a group's Folders tab, or counting its folders for the sidebar, no longer reads every group folder in the instance to find the ones assigned to it; both now query the assignment table directly for that group.
  • The add field and the "Filter members" field are the same height again: a global Nextcloud input rule made the add field 2px taller, and its outline was clipped at the top.
  • The Folders tab's Write / Share / Delete headers no longer run into each other in Portuguese, Spanish and French: the columns were narrower than the translated words.

Known limitations

  • The lock preventing the last-admin race, and the existence checks preventing orphaned folder associations, only coordinate operations made through this app. occ, the core Users settings page, or another app can still race with, or bypass, either.
  • A folder-association row left over from before this release, or from a group deleted through some other route while this app was mid-request, isn't found or cleaned up automatically; only unassignFolder() can remove it, and only once someone notices it.
  • A group ID containing / created before this release (or through occ, LDAP, another app) remains unreachable through this app's own group routes; only creating a new one that way is now rejected.
  • Group folders NOT yet assigned to a group (the assignment field's search) are still found by reading every group folder in the instance; there's no per-group index for "absent from this group's assignment list" the way there is for "assigned to it".
  • The groups list itself (left-hand panel) still loads every group and its member count up front; it isn't paged.
  • On Nextcloud 34+, a request for a group's member list with a pageSize outside [1, 500] and no other malformed input gets this app's own clean 400 (worked around: the parameter isn't named limit, which the AppFramework's own request dispatcher special-cases as of that version). The add-field's candidate search and the folder-assignment search still use a parameter literally named limit and are not worked around the same way: an extreme, out-of-range value there can still surface as that framework's own raw 500 on 34/35.

Added

  • Group admins. A shield on each member's row makes them an admin of the group (a Nextcloud "subadmin"), queued and applied with the other changes; current admins show a badge, and the group's summary counts them. Works on LDAP groups too, whose membership stays read-only: the assignment is stored by Nextcloud, not in the directory, so LDAP groups now use the same member list as local ones, minus adding and removing. Removing a member also ends their group admin role (Nextcloud itself keeps it until the user or group is deleted). Group admins who aren't members, which the core Users page allows, are listed above the members and can be revoked. The admin group can't be given group admins, matching Nextcloud's own provisioning API: a group admin of admin could add themselves to it.
  • Nextcloud 35 support, verified against a disposable instance the same way as 31–34.
  • Optional top bar shortcut to the Group Manager page, switched on per admin from the groups list's menu (off by default).
  • The add field pages through every candidate as the dropdown scrolls, instead of stopping at the first 10; without a search term, candidates are listed by display name.
  • LDAP groups show a read-only badge and their DN, with a copy button.
  • Groups whose names differ only by case are flagged in the list.
  • Members show their profile picture when they have one.

Changed

  • Reworked layout: no outer frame, theme-safe colours (light, dark and high contrast), a fixed header over scrolling group and member lists, sticky section headers in the groups list, and one shared header height so the rule under the tabs runs straight across both columns.
  • Tighter header: less padding above the app, the All / Local / LDAP filters on the groups list's title line, a shorter header for every group but an LDAP one (whose DN needs a line of its own), and the group's summary (members, admins, folders, disabled accounts) on the same line as its name.
  • The "N after applying" count moved into that summary, so queuing the first change no longer shifts the add field sideways.
  • Member rows fit on one line (name, then username or email), stacking only in narrow panels; UUID-style usernames are shown as a tooltip instead.
  • Deleting a group moved to an actions menu beside the group's name; the apply/discard footer appears only while changes are pending.
  • Keyboard focus rings show only for keyboard navigation, and Chrome on Windows no longer draws arrow buttons on the app's scrollbars.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureRP4WQaITkAQ5TvSMUSV+zRiAiLbFlomTCbps7cMWh0HTnawO53NQuP+HCJSlaOe39ZiDIPn/8LFzb7Yg4yvrMcV3KGRu7GVNNeIZWEzYEkiqoQ4lelMmOilUsgG6h+QQBb4I99ELRJQ6Nl5sKZjC/eLOZhRT/tCjObBL5kVHtGZ42P80JIQ/SOZhNoVMfhckqSH0cCQyAMtG8tBRtk7A5C0JNGrEfILUcNClhLRcfzLFVZcPt/KHMkws9JdS7UjlS4nhKdfO/kn9hcv3hoL/z6GPTSRqSprfpIqq3n6zhFEizuD55Z0KsRbXZN9c6y+oprDpbnNwlZ6On5H5/4wWTZhJgUPYx8/cRx9COSUphsEB+Y3mAXT8f8s4Dx1p6aD7y6g9DoEduT9+4mq4LPAa7Iou+dvm7ZYigjjHHHjszBEQX+UAb69D776hZ2OpIuI+no4ASheGzunbooivhT1a8amz42lCNooZreV0obpwMrZguvtShv/H1jIHTTl7Bsc9jVRzYCU45Nj1lYIswisPeiLHkwyzbuk0HMq1iFvCgAQzYfw2a7KJLViXO18x3UdH+SvLDPSlGPgH0UlWGezWcDMbaYnJh+sDg5MLOh0k3ot4MPD8yz76aNzFNsYWyNJ6gV30/tJH/lGyQ+JJ23LYa9PPyaHXWvqJqIaRkFy3Ntk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0

Nextcloud 33

Group Manager 0.4.1
Release Details
UpdatedOct. 4, 2026, 1:28 p.m.
Changelog

Fixed

  • The App Store listing showed no screenshots. The App Store downloads screenshots once, when a release is uploaded, and 0.4.0 was uploaded before the new screenshots reached GitHub, so it stored empty images and never fetched them again. Screenshot URLs now point at the release's own tag instead of master, so every release gets fresh URLs (and the images always match that version). No code changes.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureWF2ootnp64z1VTO9WeyRho9ldOctFbO6wDDcXRBHGMBic6hJfIomcfSfYtj8fvm5IUxe/JWzwIlB0DYgwTaM/aqZ30ZUh57IT4AOYDQQ8hoU7UHZCLl5W/hlFOr6Ok0rrnCHegpGlQ8T7LJ4MaPvc87uugf9PH/rSin3GTPhWn5ZVFGwy0A9Fwa1SlPnND58JcNMtGyZFsfBpMniJG1b8YlV33EYgtkWWXpuFCJJAlv05arqHkLx5Er9VAtDWXvEE77g3BM2U4Fc0x9VLYbtZMx9/9AfagawTcC68crt9q3b2Rh3g53w1GBOOVVfJUaRRGzfijAKAgeDIcX+cLak0afRMxZ+e8aeWeLI7WG7eSiDKern+6I+MWd7fymCcoVy7kAAGQgnrVNNmuVMcdsGeZshqPuVbG3sQlNTt67IYJdwzqs7NLtha4ahE40hVBsTLgvEtkUMh3k5VJSWOLVhSllX4TwaJvDlP8vPsCdrm6ZIu98oadAo0TQyggMwP0/oD3oIajLc0q/7dr2n0B5W9pw4ei/ziCcJ6Y0m5UY35A5Ic3Tnyb1oh+irghi2Q1x5Cj3gG4UFoJjPSq134hAzukYpIKRo6K4yCa5KkbsvRIGnRHd58xCH1THlGQB4uMjyWGY+rVRNJQzAJJI4aNU6PRmjl2qHnSmqJNKZdB07jQA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0
Group Manager 0.4.0
Release Details
UpdatedOct. 4, 2026, 11:46 a.m.
Changelog

Fixed

  • Opening any group's detail view (local or LDAP) returned HTTP 500 on Nextcloud 31 as soon as the Team Folders app (groupfolders 19.x) was installed, because GroupService::detail() counts a group's folders on every load. FolderAssignmentService called groupfolders' internal FolderManager the way its 20+ releases expect (a required storage-id argument dropped, folders read as FolderWithMappingsAndCache objects), which groupfolders 19.x doesn't provide (it takes that argument and returns plain arrays with different keys). Every result now goes through one normalization step, and the one groupfolders method this app used that doesn't exist before 20 (mountPointExists()) is replaced with a direct query against its own table, mirroring how folder_protection already reads groupfolders' schema instead of its unstable internal API.
  • Two admins removing each other from the admin group at the same moment could both succeed, leaving the instance with no administrators. removeMember() now serializes removals from admin through an OCP\Lock\ILockingProvider exclusive lock, re-reading membership and the admin count only after acquiring it; a backend that can't answer the count at all is now treated as unsafe rather than let through. This closes the race for removals made through this app; it can't coordinate an admin removed some other way (occ, the core Users page, another app).
  • A group folder could be assigned, created, or have its permissions/quota changed for a group ID that doesn't exist (a typo, or a group deleted between being picked and the request landing), leaving an association that silently grants full access the moment a group with that ID exists again (LDAP re-sync, or an admin recreating it). FolderAssignmentService now requires the group to exist before every such write. Unassigning is deliberately exempt, so an association left over from before this fix (or from this exact race, which a lookup-then-write can narrow but not close) can still be removed.
  • Pasting a list of users into "add members" showed a wrong count of new members when the account belonged to the group but was outside the currently loaded/filtered page: the frontend decided membership from whatever page it had, not the group's real membership. resolvePastedList now reports each entry's real membership from the server. The "N members after applying" prediction also no longer uses the search-filtered member count as if it were the group's real size.
  • Going back or forward in the browser past a group with unapplied member or folder changes used to discard them without asking; only switching groups from the list itself was guarded. Back/Forward now asks the same question, and reverts the jump if declined; while a batch is actually being applied, navigating away (either way) is refused outright, not just guarded by a prompt.
  • A search whose response arrived out of order (members, add-field candidates, or assignable folders) could overwrite the current results with a stale answer to an earlier, already-superseded search. Every such search now discards an answer that's no longer for the latest query.
  • A failed member/folder list load, or a failed refresh right after successfully applying changes, showed an empty or stale list with no indication anything had gone wrong. These now show an explicit error with a way to retry, and a successful write's own result is no longer hidden by a follow-up refresh failing.
  • Group member pages could not be paged past the first one whenever the backend could enumerate members but couldn't answer a plain count (count() returning false, seen with some LDAP setups): the frontend required a known total to show "Load more". Paging now uses a hasMore flag the API derives from an extra fetched row, independent of the total.
  • Creating a group whose ID contains / succeeded but left it permanently unreachable through this app's own API (every route needs /-free IDs); rejected at creation now. A group with / in its ID created some other way (occ, LDAP) is unaffected and still manageable everywhere else.
  • Malformed input reached internal errors (HTTP 500) instead of a clean 400: non-string entries pasted into the add-members list, and out-of-range limit/offset values for a group's member list. Both are now validated up front with a stable error code.
  • The add-members search for whole groups used to enumerate every member of the destination group, and every candidate group's own full membership, on every keystroke: a large directory made this measurably slow. Membership is now checked one candidate at a time, up to a fixed page budget; a candidate group's entry shows its own size, not an exact "how many would be new" count (computed once, cheaply, only for the group actually picked). Opening a group's Folders tab, or counting its folders for the sidebar, no longer reads every group folder in the instance to find the ones assigned to it; both now query the assignment table directly for that group.
  • The add field and the "Filter members" field are the same height again: a global Nextcloud input rule made the add field 2px taller, and its outline was clipped at the top.
  • The Folders tab's Write / Share / Delete headers no longer run into each other in Portuguese, Spanish and French: the columns were narrower than the translated words.

Known limitations

  • The lock preventing the last-admin race, and the existence checks preventing orphaned folder associations, only coordinate operations made through this app. occ, the core Users settings page, or another app can still race with, or bypass, either.
  • A folder-association row left over from before this release, or from a group deleted through some other route while this app was mid-request, isn't found or cleaned up automatically; only unassignFolder() can remove it, and only once someone notices it.
  • A group ID containing / created before this release (or through occ, LDAP, another app) remains unreachable through this app's own group routes; only creating a new one that way is now rejected.
  • Group folders NOT yet assigned to a group (the assignment field's search) are still found by reading every group folder in the instance; there's no per-group index for "absent from this group's assignment list" the way there is for "assigned to it".
  • The groups list itself (left-hand panel) still loads every group and its member count up front; it isn't paged.
  • On Nextcloud 34+, a request for a group's member list with a pageSize outside [1, 500] and no other malformed input gets this app's own clean 400 (worked around: the parameter isn't named limit, which the AppFramework's own request dispatcher special-cases as of that version). The add-field's candidate search and the folder-assignment search still use a parameter literally named limit and are not worked around the same way: an extreme, out-of-range value there can still surface as that framework's own raw 500 on 34/35.

Added

  • Group admins. A shield on each member's row makes them an admin of the group (a Nextcloud "subadmin"), queued and applied with the other changes; current admins show a badge, and the group's summary counts them. Works on LDAP groups too, whose membership stays read-only: the assignment is stored by Nextcloud, not in the directory, so LDAP groups now use the same member list as local ones, minus adding and removing. Removing a member also ends their group admin role (Nextcloud itself keeps it until the user or group is deleted). Group admins who aren't members, which the core Users page allows, are listed above the members and can be revoked. The admin group can't be given group admins, matching Nextcloud's own provisioning API: a group admin of admin could add themselves to it.
  • Nextcloud 35 support, verified against a disposable instance the same way as 31–34.
  • Optional top bar shortcut to the Group Manager page, switched on per admin from the groups list's menu (off by default).
  • The add field pages through every candidate as the dropdown scrolls, instead of stopping at the first 10; without a search term, candidates are listed by display name.
  • LDAP groups show a read-only badge and their DN, with a copy button.
  • Groups whose names differ only by case are flagged in the list.
  • Members show their profile picture when they have one.

Changed

  • Reworked layout: no outer frame, theme-safe colours (light, dark and high contrast), a fixed header over scrolling group and member lists, sticky section headers in the groups list, and one shared header height so the rule under the tabs runs straight across both columns.
  • Tighter header: less padding above the app, the All / Local / LDAP filters on the groups list's title line, a shorter header for every group but an LDAP one (whose DN needs a line of its own), and the group's summary (members, admins, folders, disabled accounts) on the same line as its name.
  • The "N after applying" count moved into that summary, so queuing the first change no longer shifts the add field sideways.
  • Member rows fit on one line (name, then username or email), stacking only in narrow panels; UUID-style usernames are shown as a tooltip instead.
  • Deleting a group moved to an actions menu beside the group's name; the apply/discard footer appears only while changes are pending.
  • Keyboard focus rings show only for keyboard navigation, and Chrome on Windows no longer draws arrow buttons on the app's scrollbars.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureRP4WQaITkAQ5TvSMUSV+zRiAiLbFlomTCbps7cMWh0HTnawO53NQuP+HCJSlaOe39ZiDIPn/8LFzb7Yg4yvrMcV3KGRu7GVNNeIZWEzYEkiqoQ4lelMmOilUsgG6h+QQBb4I99ELRJQ6Nl5sKZjC/eLOZhRT/tCjObBL5kVHtGZ42P80JIQ/SOZhNoVMfhckqSH0cCQyAMtG8tBRtk7A5C0JNGrEfILUcNClhLRcfzLFVZcPt/KHMkws9JdS7UjlS4nhKdfO/kn9hcv3hoL/z6GPTSRqSprfpIqq3n6zhFEizuD55Z0KsRbXZN9c6y+oprDpbnNwlZ6On5H5/4wWTZhJgUPYx8/cRx9COSUphsEB+Y3mAXT8f8s4Dx1p6aD7y6g9DoEduT9+4mq4LPAa7Iou+dvm7ZYigjjHHHjszBEQX+UAb69D776hZ2OpIuI+no4ASheGzunbooivhT1a8amz42lCNooZreV0obpwMrZguvtShv/H1jIHTTl7Bsc9jVRzYCU45Nj1lYIswisPeiLHkwyzbuk0HMq1iFvCgAQzYfw2a7KJLViXO18x3UdH+SvLDPSlGPgH0UlWGezWcDMbaYnJh+sDg5MLOh0k3ot4MPD8yz76aNzFNsYWyNJ6gV30/tJH/lGyQ+JJ23LYa9PPyaHXWvqJqIaRkFy3Ntk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0

Nextcloud 32

Group Manager 0.4.1
Release Details
UpdatedOct. 4, 2026, 1:28 p.m.
Changelog

Fixed

  • The App Store listing showed no screenshots. The App Store downloads screenshots once, when a release is uploaded, and 0.4.0 was uploaded before the new screenshots reached GitHub, so it stored empty images and never fetched them again. Screenshot URLs now point at the release's own tag instead of master, so every release gets fresh URLs (and the images always match that version). No code changes.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureWF2ootnp64z1VTO9WeyRho9ldOctFbO6wDDcXRBHGMBic6hJfIomcfSfYtj8fvm5IUxe/JWzwIlB0DYgwTaM/aqZ30ZUh57IT4AOYDQQ8hoU7UHZCLl5W/hlFOr6Ok0rrnCHegpGlQ8T7LJ4MaPvc87uugf9PH/rSin3GTPhWn5ZVFGwy0A9Fwa1SlPnND58JcNMtGyZFsfBpMniJG1b8YlV33EYgtkWWXpuFCJJAlv05arqHkLx5Er9VAtDWXvEE77g3BM2U4Fc0x9VLYbtZMx9/9AfagawTcC68crt9q3b2Rh3g53w1GBOOVVfJUaRRGzfijAKAgeDIcX+cLak0afRMxZ+e8aeWeLI7WG7eSiDKern+6I+MWd7fymCcoVy7kAAGQgnrVNNmuVMcdsGeZshqPuVbG3sQlNTt67IYJdwzqs7NLtha4ahE40hVBsTLgvEtkUMh3k5VJSWOLVhSllX4TwaJvDlP8vPsCdrm6ZIu98oadAo0TQyggMwP0/oD3oIajLc0q/7dr2n0B5W9pw4ei/ziCcJ6Y0m5UY35A5Ic3Tnyb1oh+irghi2Q1x5Cj3gG4UFoJjPSq134hAzukYpIKRo6K4yCa5KkbsvRIGnRHd58xCH1THlGQB4uMjyWGY+rVRNJQzAJJI4aNU6PRmjl2qHnSmqJNKZdB07jQA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0
Group Manager 0.4.0
Release Details
UpdatedOct. 4, 2026, 11:46 a.m.
Changelog

Fixed

  • Opening any group's detail view (local or LDAP) returned HTTP 500 on Nextcloud 31 as soon as the Team Folders app (groupfolders 19.x) was installed, because GroupService::detail() counts a group's folders on every load. FolderAssignmentService called groupfolders' internal FolderManager the way its 20+ releases expect (a required storage-id argument dropped, folders read as FolderWithMappingsAndCache objects), which groupfolders 19.x doesn't provide (it takes that argument and returns plain arrays with different keys). Every result now goes through one normalization step, and the one groupfolders method this app used that doesn't exist before 20 (mountPointExists()) is replaced with a direct query against its own table, mirroring how folder_protection already reads groupfolders' schema instead of its unstable internal API.
  • Two admins removing each other from the admin group at the same moment could both succeed, leaving the instance with no administrators. removeMember() now serializes removals from admin through an OCP\Lock\ILockingProvider exclusive lock, re-reading membership and the admin count only after acquiring it; a backend that can't answer the count at all is now treated as unsafe rather than let through. This closes the race for removals made through this app; it can't coordinate an admin removed some other way (occ, the core Users page, another app).
  • A group folder could be assigned, created, or have its permissions/quota changed for a group ID that doesn't exist (a typo, or a group deleted between being picked and the request landing), leaving an association that silently grants full access the moment a group with that ID exists again (LDAP re-sync, or an admin recreating it). FolderAssignmentService now requires the group to exist before every such write. Unassigning is deliberately exempt, so an association left over from before this fix (or from this exact race, which a lookup-then-write can narrow but not close) can still be removed.
  • Pasting a list of users into "add members" showed a wrong count of new members when the account belonged to the group but was outside the currently loaded/filtered page: the frontend decided membership from whatever page it had, not the group's real membership. resolvePastedList now reports each entry's real membership from the server. The "N members after applying" prediction also no longer uses the search-filtered member count as if it were the group's real size.
  • Going back or forward in the browser past a group with unapplied member or folder changes used to discard them without asking; only switching groups from the list itself was guarded. Back/Forward now asks the same question, and reverts the jump if declined; while a batch is actually being applied, navigating away (either way) is refused outright, not just guarded by a prompt.
  • A search whose response arrived out of order (members, add-field candidates, or assignable folders) could overwrite the current results with a stale answer to an earlier, already-superseded search. Every such search now discards an answer that's no longer for the latest query.
  • A failed member/folder list load, or a failed refresh right after successfully applying changes, showed an empty or stale list with no indication anything had gone wrong. These now show an explicit error with a way to retry, and a successful write's own result is no longer hidden by a follow-up refresh failing.
  • Group member pages could not be paged past the first one whenever the backend could enumerate members but couldn't answer a plain count (count() returning false, seen with some LDAP setups): the frontend required a known total to show "Load more". Paging now uses a hasMore flag the API derives from an extra fetched row, independent of the total.
  • Creating a group whose ID contains / succeeded but left it permanently unreachable through this app's own API (every route needs /-free IDs); rejected at creation now. A group with / in its ID created some other way (occ, LDAP) is unaffected and still manageable everywhere else.
  • Malformed input reached internal errors (HTTP 500) instead of a clean 400: non-string entries pasted into the add-members list, and out-of-range limit/offset values for a group's member list. Both are now validated up front with a stable error code.
  • The add-members search for whole groups used to enumerate every member of the destination group, and every candidate group's own full membership, on every keystroke: a large directory made this measurably slow. Membership is now checked one candidate at a time, up to a fixed page budget; a candidate group's entry shows its own size, not an exact "how many would be new" count (computed once, cheaply, only for the group actually picked). Opening a group's Folders tab, or counting its folders for the sidebar, no longer reads every group folder in the instance to find the ones assigned to it; both now query the assignment table directly for that group.
  • The add field and the "Filter members" field are the same height again: a global Nextcloud input rule made the add field 2px taller, and its outline was clipped at the top.
  • The Folders tab's Write / Share / Delete headers no longer run into each other in Portuguese, Spanish and French: the columns were narrower than the translated words.

Known limitations

  • The lock preventing the last-admin race, and the existence checks preventing orphaned folder associations, only coordinate operations made through this app. occ, the core Users settings page, or another app can still race with, or bypass, either.
  • A folder-association row left over from before this release, or from a group deleted through some other route while this app was mid-request, isn't found or cleaned up automatically; only unassignFolder() can remove it, and only once someone notices it.
  • A group ID containing / created before this release (or through occ, LDAP, another app) remains unreachable through this app's own group routes; only creating a new one that way is now rejected.
  • Group folders NOT yet assigned to a group (the assignment field's search) are still found by reading every group folder in the instance; there's no per-group index for "absent from this group's assignment list" the way there is for "assigned to it".
  • The groups list itself (left-hand panel) still loads every group and its member count up front; it isn't paged.
  • On Nextcloud 34+, a request for a group's member list with a pageSize outside [1, 500] and no other malformed input gets this app's own clean 400 (worked around: the parameter isn't named limit, which the AppFramework's own request dispatcher special-cases as of that version). The add-field's candidate search and the folder-assignment search still use a parameter literally named limit and are not worked around the same way: an extreme, out-of-range value there can still surface as that framework's own raw 500 on 34/35.

Added

  • Group admins. A shield on each member's row makes them an admin of the group (a Nextcloud "subadmin"), queued and applied with the other changes; current admins show a badge, and the group's summary counts them. Works on LDAP groups too, whose membership stays read-only: the assignment is stored by Nextcloud, not in the directory, so LDAP groups now use the same member list as local ones, minus adding and removing. Removing a member also ends their group admin role (Nextcloud itself keeps it until the user or group is deleted). Group admins who aren't members, which the core Users page allows, are listed above the members and can be revoked. The admin group can't be given group admins, matching Nextcloud's own provisioning API: a group admin of admin could add themselves to it.
  • Nextcloud 35 support, verified against a disposable instance the same way as 31–34.
  • Optional top bar shortcut to the Group Manager page, switched on per admin from the groups list's menu (off by default).
  • The add field pages through every candidate as the dropdown scrolls, instead of stopping at the first 10; without a search term, candidates are listed by display name.
  • LDAP groups show a read-only badge and their DN, with a copy button.
  • Groups whose names differ only by case are flagged in the list.
  • Members show their profile picture when they have one.

Changed

  • Reworked layout: no outer frame, theme-safe colours (light, dark and high contrast), a fixed header over scrolling group and member lists, sticky section headers in the groups list, and one shared header height so the rule under the tabs runs straight across both columns.
  • Tighter header: less padding above the app, the All / Local / LDAP filters on the groups list's title line, a shorter header for every group but an LDAP one (whose DN needs a line of its own), and the group's summary (members, admins, folders, disabled accounts) on the same line as its name.
  • The "N after applying" count moved into that summary, so queuing the first change no longer shifts the add field sideways.
  • Member rows fit on one line (name, then username or email), stacking only in narrow panels; UUID-style usernames are shown as a tooltip instead.
  • Deleting a group moved to an actions menu beside the group's name; the apply/discard footer appears only while changes are pending.
  • Keyboard focus rings show only for keyboard navigation, and Chrome on Windows no longer draws arrow buttons on the app's scrollbars.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureRP4WQaITkAQ5TvSMUSV+zRiAiLbFlomTCbps7cMWh0HTnawO53NQuP+HCJSlaOe39ZiDIPn/8LFzb7Yg4yvrMcV3KGRu7GVNNeIZWEzYEkiqoQ4lelMmOilUsgG6h+QQBb4I99ELRJQ6Nl5sKZjC/eLOZhRT/tCjObBL5kVHtGZ42P80JIQ/SOZhNoVMfhckqSH0cCQyAMtG8tBRtk7A5C0JNGrEfILUcNClhLRcfzLFVZcPt/KHMkws9JdS7UjlS4nhKdfO/kn9hcv3hoL/z6GPTSRqSprfpIqq3n6zhFEizuD55Z0KsRbXZN9c6y+oprDpbnNwlZ6On5H5/4wWTZhJgUPYx8/cRx9COSUphsEB+Y3mAXT8f8s4Dx1p6aD7y6g9DoEduT9+4mq4LPAa7Iou+dvm7ZYigjjHHHjszBEQX+UAb69D776hZ2OpIuI+no4ASheGzunbooivhT1a8amz42lCNooZreV0obpwMrZguvtShv/H1jIHTTl7Bsc9jVRzYCU45Nj1lYIswisPeiLHkwyzbuk0HMq1iFvCgAQzYfw2a7KJLViXO18x3UdH+SvLDPSlGPgH0UlWGezWcDMbaYnJh+sDg5MLOh0k3ot4MPD8yz76aNzFNsYWyNJ6gV30/tJH/lGyQ+JJ23LYa9PPyaHXWvqJqIaRkFy3Ntk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0

Nextcloud 31

Group Manager 0.4.1
Release Details
UpdatedOct. 4, 2026, 1:28 p.m.
Changelog

Fixed

  • The App Store listing showed no screenshots. The App Store downloads screenshots once, when a release is uploaded, and 0.4.0 was uploaded before the new screenshots reached GitHub, so it stored empty images and never fetched them again. Screenshot URLs now point at the release's own tag instead of master, so every release gets fresh URLs (and the images always match that version). No code changes.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureWF2ootnp64z1VTO9WeyRho9ldOctFbO6wDDcXRBHGMBic6hJfIomcfSfYtj8fvm5IUxe/JWzwIlB0DYgwTaM/aqZ30ZUh57IT4AOYDQQ8hoU7UHZCLl5W/hlFOr6Ok0rrnCHegpGlQ8T7LJ4MaPvc87uugf9PH/rSin3GTPhWn5ZVFGwy0A9Fwa1SlPnND58JcNMtGyZFsfBpMniJG1b8YlV33EYgtkWWXpuFCJJAlv05arqHkLx5Er9VAtDWXvEE77g3BM2U4Fc0x9VLYbtZMx9/9AfagawTcC68crt9q3b2Rh3g53w1GBOOVVfJUaRRGzfijAKAgeDIcX+cLak0afRMxZ+e8aeWeLI7WG7eSiDKern+6I+MWd7fymCcoVy7kAAGQgnrVNNmuVMcdsGeZshqPuVbG3sQlNTt67IYJdwzqs7NLtha4ahE40hVBsTLgvEtkUMh3k5VJSWOLVhSllX4TwaJvDlP8vPsCdrm6ZIu98oadAo0TQyggMwP0/oD3oIajLc0q/7dr2n0B5W9pw4ei/ziCcJ6Y0m5UY35A5Ic3Tnyb1oh+irghi2Q1x5Cj3gG4UFoJjPSq134hAzukYpIKRo6K4yCa5KkbsvRIGnRHd58xCH1THlGQB4uMjyWGY+rVRNJQzAJJI4aNU6PRmjl2qHnSmqJNKZdB07jQA=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0
Group Manager 0.4.0
Release Details
UpdatedOct. 4, 2026, 11:46 a.m.
Changelog

Fixed

  • Opening any group's detail view (local or LDAP) returned HTTP 500 on Nextcloud 31 as soon as the Team Folders app (groupfolders 19.x) was installed, because GroupService::detail() counts a group's folders on every load. FolderAssignmentService called groupfolders' internal FolderManager the way its 20+ releases expect (a required storage-id argument dropped, folders read as FolderWithMappingsAndCache objects), which groupfolders 19.x doesn't provide (it takes that argument and returns plain arrays with different keys). Every result now goes through one normalization step, and the one groupfolders method this app used that doesn't exist before 20 (mountPointExists()) is replaced with a direct query against its own table, mirroring how folder_protection already reads groupfolders' schema instead of its unstable internal API.
  • Two admins removing each other from the admin group at the same moment could both succeed, leaving the instance with no administrators. removeMember() now serializes removals from admin through an OCP\Lock\ILockingProvider exclusive lock, re-reading membership and the admin count only after acquiring it; a backend that can't answer the count at all is now treated as unsafe rather than let through. This closes the race for removals made through this app; it can't coordinate an admin removed some other way (occ, the core Users page, another app).
  • A group folder could be assigned, created, or have its permissions/quota changed for a group ID that doesn't exist (a typo, or a group deleted between being picked and the request landing), leaving an association that silently grants full access the moment a group with that ID exists again (LDAP re-sync, or an admin recreating it). FolderAssignmentService now requires the group to exist before every such write. Unassigning is deliberately exempt, so an association left over from before this fix (or from this exact race, which a lookup-then-write can narrow but not close) can still be removed.
  • Pasting a list of users into "add members" showed a wrong count of new members when the account belonged to the group but was outside the currently loaded/filtered page: the frontend decided membership from whatever page it had, not the group's real membership. resolvePastedList now reports each entry's real membership from the server. The "N members after applying" prediction also no longer uses the search-filtered member count as if it were the group's real size.
  • Going back or forward in the browser past a group with unapplied member or folder changes used to discard them without asking; only switching groups from the list itself was guarded. Back/Forward now asks the same question, and reverts the jump if declined; while a batch is actually being applied, navigating away (either way) is refused outright, not just guarded by a prompt.
  • A search whose response arrived out of order (members, add-field candidates, or assignable folders) could overwrite the current results with a stale answer to an earlier, already-superseded search. Every such search now discards an answer that's no longer for the latest query.
  • A failed member/folder list load, or a failed refresh right after successfully applying changes, showed an empty or stale list with no indication anything had gone wrong. These now show an explicit error with a way to retry, and a successful write's own result is no longer hidden by a follow-up refresh failing.
  • Group member pages could not be paged past the first one whenever the backend could enumerate members but couldn't answer a plain count (count() returning false, seen with some LDAP setups): the frontend required a known total to show "Load more". Paging now uses a hasMore flag the API derives from an extra fetched row, independent of the total.
  • Creating a group whose ID contains / succeeded but left it permanently unreachable through this app's own API (every route needs /-free IDs); rejected at creation now. A group with / in its ID created some other way (occ, LDAP) is unaffected and still manageable everywhere else.
  • Malformed input reached internal errors (HTTP 500) instead of a clean 400: non-string entries pasted into the add-members list, and out-of-range limit/offset values for a group's member list. Both are now validated up front with a stable error code.
  • The add-members search for whole groups used to enumerate every member of the destination group, and every candidate group's own full membership, on every keystroke: a large directory made this measurably slow. Membership is now checked one candidate at a time, up to a fixed page budget; a candidate group's entry shows its own size, not an exact "how many would be new" count (computed once, cheaply, only for the group actually picked). Opening a group's Folders tab, or counting its folders for the sidebar, no longer reads every group folder in the instance to find the ones assigned to it; both now query the assignment table directly for that group.
  • The add field and the "Filter members" field are the same height again: a global Nextcloud input rule made the add field 2px taller, and its outline was clipped at the top.
  • The Folders tab's Write / Share / Delete headers no longer run into each other in Portuguese, Spanish and French: the columns were narrower than the translated words.

Known limitations

  • The lock preventing the last-admin race, and the existence checks preventing orphaned folder associations, only coordinate operations made through this app. occ, the core Users settings page, or another app can still race with, or bypass, either.
  • A folder-association row left over from before this release, or from a group deleted through some other route while this app was mid-request, isn't found or cleaned up automatically; only unassignFolder() can remove it, and only once someone notices it.
  • A group ID containing / created before this release (or through occ, LDAP, another app) remains unreachable through this app's own group routes; only creating a new one that way is now rejected.
  • Group folders NOT yet assigned to a group (the assignment field's search) are still found by reading every group folder in the instance; there's no per-group index for "absent from this group's assignment list" the way there is for "assigned to it".
  • The groups list itself (left-hand panel) still loads every group and its member count up front; it isn't paged.
  • On Nextcloud 34+, a request for a group's member list with a pageSize outside [1, 500] and no other malformed input gets this app's own clean 400 (worked around: the parameter isn't named limit, which the AppFramework's own request dispatcher special-cases as of that version). The add-field's candidate search and the folder-assignment search still use a parameter literally named limit and are not worked around the same way: an extreme, out-of-range value there can still surface as that framework's own raw 500 on 34/35.

Added

  • Group admins. A shield on each member's row makes them an admin of the group (a Nextcloud "subadmin"), queued and applied with the other changes; current admins show a badge, and the group's summary counts them. Works on LDAP groups too, whose membership stays read-only: the assignment is stored by Nextcloud, not in the directory, so LDAP groups now use the same member list as local ones, minus adding and removing. Removing a member also ends their group admin role (Nextcloud itself keeps it until the user or group is deleted). Group admins who aren't members, which the core Users page allows, are listed above the members and can be revoked. The admin group can't be given group admins, matching Nextcloud's own provisioning API: a group admin of admin could add themselves to it.
  • Nextcloud 35 support, verified against a disposable instance the same way as 31–34.
  • Optional top bar shortcut to the Group Manager page, switched on per admin from the groups list's menu (off by default).
  • The add field pages through every candidate as the dropdown scrolls, instead of stopping at the first 10; without a search term, candidates are listed by display name.
  • LDAP groups show a read-only badge and their DN, with a copy button.
  • Groups whose names differ only by case are flagged in the list.
  • Members show their profile picture when they have one.

Changed

  • Reworked layout: no outer frame, theme-safe colours (light, dark and high contrast), a fixed header over scrolling group and member lists, sticky section headers in the groups list, and one shared header height so the rule under the tabs runs straight across both columns.
  • Tighter header: less padding above the app, the All / Local / LDAP filters on the groups list's title line, a shorter header for every group but an LDAP one (whose DN needs a line of its own), and the group's summary (members, admins, folders, disabled accounts) on the same line as its name.
  • The "N after applying" count moved into that summary, so queuing the first change no longer shifts the add field sideways.
  • Member rows fit on one line (name, then username or email), stacking only in narrow panels; UUID-style usernames are shown as a tooltip instead.
  • Deleting a group moved to an actions menu beside the group's name; the apply/discard footer appears only while changes are pending.
  • Keyboard focus rings show only for keyboard navigation, and Chrome on Windows no longer draws arrow buttons on the app's scrollbars.
Licenses GNU Affero General Public License v3.0 or later
Certificate-----BEGIN CERTIFICATE-----
MIIECDCCAvACAhQ6MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMjYxMDAyMTIyOTE2WhcNMzcwMTA3MTIyOTE2WjAYMRYwFAYD
VQQDDA1ncm91cF9tYW5hZ2VyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAudBh4Zj6rKuYhgQkv9i6EG6n3Ad2ZHoOSyKmvB4nYwKARa96nDxCNp5brT3o
x40rnrthERcAbHywf/vRc4UhAhjpWKNb3m4FMHKFN2jrB3C8vAxWaI17TljamrVX
01MIcGyeTU9OZid9NA3JhGajU+ZB6pvsdTtwTUFchEoZZ7NiEJ82MvpoqlsswREK
dW90usbs5mnPfLbTmKftLILySnkazkho5Fqw0D5jeSmFeEepY5SfJwiwoXDYIqK9
PQkDqZvPph+wm2IgIwwof/lvN2pMJeVqniKbwzVTtdpDQF0uFgEVY8j7huC3tNnB
ZdsaAOnJQpiVlPNwuSAguBSliQvRBevG884IpGviPff9Pm3Td4n4XV0kDFAflAZX
fKQo9uNjPx6KERAbMXthPwKOsreQw+qYpZqhYZZU8IyFgXkzb6+hmqO0Qdg4qQ5q
zd89wP8nUIvgJ0Mi+S41hmr77zUc+kFJEYy7QcKXVs38ewaGGJkXo15hSlEZxqH2
S5nq0zgAyHQUtx50XEyMhm6mpx2IIWg+lBEm8IILZz1boQ8wuXBl0EBEgkzXPpuw
ergRgiXO2gpd6wPBJvfhWI68LsiGgIURSD4yOPJux/+7+9Q0BLHUbAMWRWgIuBRv
VJmO3qFtPE0MpSmoY6LwPer3p7qufpXWpjXvqQ8nKyJmUdcCAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAmaJ9I9gxobROMQZTzJZ7kEpi4GsN0v3L20GoWqpbOc4uR7nu
uw1byP4ouHisRlJhthYDrnjzV0HDJs6Ic8ceqL6D84bkPpbYYGtvmxP601LX5fv7
Er5GgDuTEjDMTFjI0jHjL0ZiJzwpAeylIIE6vtlj5hNyHo2ZyETNzENMr0BgOnfo
r/+U9pJs+dvUEfZxyecG1IjmWobp3kQzbzLu5BmHng8YFPDoyPvu5OnSdS1iH4F7
n1vPpFDxRxKV5y6tcQQJ/9nzSxUwUrtshT41fcqijhmdnweWYdFqbN06OfI7hNnO
YOj82ntC5BuZULxJeFtb7YKFQnzdRa0570Dw3A==
-----END CERTIFICATE-----
SignatureRP4WQaITkAQ5TvSMUSV+zRiAiLbFlomTCbps7cMWh0HTnawO53NQuP+HCJSlaOe39ZiDIPn/8LFzb7Yg4yvrMcV3KGRu7GVNNeIZWEzYEkiqoQ4lelMmOilUsgG6h+QQBb4I99ELRJQ6Nl5sKZjC/eLOZhRT/tCjObBL5kVHtGZ42P80JIQ/SOZhNoVMfhckqSH0cCQyAMtG8tBRtk7A5C0JNGrEfILUcNClhLRcfzLFVZcPt/KHMkws9JdS7UjlS4nhKdfO/kn9hcv3hoL/z6GPTSRqSprfpIqq3n6zhFEizuD55Z0KsRbXZN9c6y+oprDpbnNwlZ6On5H5/4wWTZhJgUPYx8/cRx9COSUphsEB+Y3mAXT8f8s4Dx1p6aD7y6g9DoEduT9+4mq4LPAa7Iou+dvm7ZYigjjHHHjszBEQX+UAb69D776hZ2OpIuI+no4ASheGzunbooivhT1a8amz42lCNooZreV0obpwMrZguvtShv/H1jIHTTl7Bsc9jVRzYCU45Nj1lYIswisPeiLHkwyzbuk0HMq1iFvCgAQzYfw2a7KJLViXO18x3UdH+SvLDPSlGPgH0UlWGezWcDMbaYnJh+sDg5MLOh0k3ot4MPD8yz76aNzFNsYWyNJ6gV30/tJH/lGyQ+JJ23LYa9PPyaHXWvqJqIaRkFy3Ntk=
Signature digestsha512
Dependencies
Required Nextcloud versions >=31.0.0,<36.0.0
Minimum Integer bits32
PHP>=8.1.0