Puavo-specific. This app is only useful in deployments that synchronise users and groups from a Puavo LDAP instance via
user_ldap, with thepuavoEdu*schema (puavoEduPersonAffiliationon users,puavoEduGroupTypeon groups). It is not a general-purpose sharing helper.
A Nextcloud app that lets teachers share files to class groups through Nextcloud's native sharing dialog — including from the mobile and desktop clients. It does this by virtualising teacher membership in class-like groups so the standard share check passes, without weakening Nextcloud's "only share with group members" restriction for everyone else.
- The admin enables
shareapi_only_share_with_group_members(default off in Nextcloud). With that on, normal users can only share to groups they're a member of. - A background job walks LDAP via
user_ldap's proxies and refreshes two local tables:oc_groupsharemachine_groups— gids whosepuavoEduGroupTypeisyear class,teaching group, orcourse groupoc_groupsharemachine_teachers— uids whose multi-valuedpuavoEduPersonAffiliationincludes the valueteacher
- A custom group backend then reports, for every recorded class group, that any recorded teacher is a member — but only for sharing checks. The class groups do not show up in the teacher's group list and the teacher does not auto-receive shares directed at them.
The net effect: teachers can pick any class group from the native sharee picker and share to it; students still can't share outside their own groups; the mobile and desktop clients work without any app-specific UI.
Reading puavoEduPersonAffiliation directly (rather than via Nextcloud's role account property) is intentional — that attribute is multi-valued in puavo LDAP and user_ldap flattens it during sync, so an admin + teacher user could end up classified as admin only and lose their teacher status.
- Nextcloud 31, 32, or 33
- PHP 8.1+
- A Puavo LDAP instance, reachable from Nextcloud
user_ldapenabled and bound against that Puavo LDAP — without this the app has nothing to read andocc groupsharemachine:syncreportsseen=0- The
puavoEduPersonAffiliationandpuavoEduGroupTypeattributes are readable by the user_ldap bind agent (the app reads them on demand via user_ldap's connection — no extra LDAP credentials needed) - Groups in LDAP have
puavoEduGroupTypeset toyear class,teaching group, orcourse groupfor the classes teachers should be allowed to share to - The admin setting Sharing → Restrict users to only share with users in their groups turned on (or
occ config:app:set core shareapi_only_share_with_group_members --value=yes) — without this the restriction the app bypasses doesn't exist in the first place
This app is installed manually — it is not distributed through the Nextcloud App Store, so occ app:install will not find it. Installing means putting the app directory on the server yourself and enabling it.
There is nothing to compile and no runtime dependencies: the app is plain PHP, and Nextcloud autoloads OCA\GroupShareMachine\ from lib/ on its own. Do not run composer install on the server — the Composer setup in this repo only installs development tools.
Commands below assume /var/www/html as the Nextcloud root and www-data as the web server user; adjust to your deployment. Run every occ command as the web server user (sudo -u www-data php occ ...).
Either build a tarball from a checkout (on any machine with make):
git clone https://github.com/puavo-org/groupsharemachine.git
cd groupsharemachine
git checkout v1.0.0 # or the version you want
make # -> build/groupsharemachine.tar.gzThe tarball contains only what the app needs at runtime (appinfo/, lib/, img/, licences) and unpacks to a single groupsharemachine/ directory.
Then unpack it into the Nextcloud apps directory:
sudo tar xzf groupsharemachine.tar.gz -C /var/www/html/apps/
sudo chown -R www-data:www-data /var/www/html/apps/groupsharemachineOr copy a checkout straight into place, if you prefer to skip the tarball:
sudo rsync -a --delete \
--exclude '.git' --exclude 'build' --exclude 'tests' \
--exclude 'vendor' --exclude 'vendor-bin' \
groupsharemachine/ /var/www/html/apps/groupsharemachine/
sudo chown -R www-data:www-data /var/www/html/apps/groupsharemachineAny directory listed in the apps_paths setting in config/config.php works, not just apps/. If you use a custom path, make sure its writable flag and ownership match how you manage the rest of your apps. Note that a symlink into the apps directory does not work reliably (and breaks entirely in containerised setups) — copy or bind-mount the real directory.
Verify Nextcloud sees it:
sudo -u www-data php occ app:list | grep -A1 -i disabled | head
# groupsharemachine should appear under "Disabled:"# enable the app — this also runs the migration that creates
# oc_groupsharemachine_groups and oc_groupsharemachine_teachers
sudo -u www-data php occ app:enable groupsharemachine
# turn on the standard restriction so non-teachers stay constrained
sudo -u www-data php occ config:app:set core shareapi_only_share_with_group_members --value=yes
# do an initial group-type sync (afterwards a background job runs it every 15 minutes)
sudo -u www-data php occ groupsharemachine:syncocc groupsharemachine:sync reports one line per table, e.g.:
Groups: seen=500 kept=500 pruned=0
Teachers: seen=1000 kept=1020 pruned=0
Reading the counters:
seen— LDAP entries returned by the search. The filter already restricts to class-likepuavoEduGroupTypevalues / to users withpuavoEduPersonAffiliation: teacher, soseenis the number of relevant entries, not the size of the directory.kept— rows written. For groups this normally equalsseen; a lower number means some DNs did not resolve to a Nextcloud gid. For teachers it counts (teacher, school) pairs, so it is legitimately higher thanseenwhen teachers belong to more than one school — and lower when teachers have no school assigned, since those cannot share to any class and are skipped.pruned— rows deleted because they no longer exist in LDAP. Nonzero after groups or teachers are removed upstream.
kept=0 on either line means nothing matched — see the Requirements above and the troubleshooting notes in DEVELOPMENT.md.
The 15-minute refresh runs as a Nextcloud background job, so it only happens if cron.php (or AJAX/webcron) is actually running on the instance — check with occ background-job:list.
sudo -u www-data php occ groupsharemachine:diagnose <teacher-uid> <class-gid>virtualised by this app: YES confirms the wiring end to end. See Testing below for the full check, including the negative case for students.
Replace the app directory with the new version and let Nextcloud run any pending migrations:
sudo -u www-data php occ maintenance:mode --on
sudo rm -rf /var/www/html/apps/groupsharemachine
sudo tar xzf groupsharemachine.tar.gz -C /var/www/html/apps/
sudo chown -R www-data:www-data /var/www/html/apps/groupsharemachine
sudo -u www-data php occ upgrade
sudo -u www-data php occ maintenance:mode --offThe app's own settings and tables survive the swap; there is no need to re-run the sync by hand, though occ groupsharemachine:sync is harmless and gives immediate feedback.
sudo -u www-data php occ app:disable groupsharemachine
sudo rm -rf /var/www/html/apps/groupsharemachineDisabling is enough to stop the membership virtualisation — from then on teachers are subject to the same share restriction as everyone else, so re-check that this is what you want before disabling on a production instance. The two oc_groupsharemachine_* tables are left in the database; they hold only cached LDAP-derived data and can be dropped manually if you are done with the app for good.
Pre-requisite: a Puavo LDAP populated with at least one teacher (puavoEduPersonAffiliation containing teacher) and one class group (puavoEduGroupType set to year class, teaching group, or course group).
- Run
occ groupsharemachine:sync— expect non-zerokeptfor both groups and teachers. occ groupsharemachine:diagnose <teacher-uid> <class-gid>—virtualised by this app: YESconfirms the wiring.- Log in as a teacher, open any file's sharing sidebar, type a class group name. The group should appear in the autocomplete and the share should succeed.
- Log in as a student, try sharing to a different class group — it should be rejected with "Sharing is only allowed within your own groups".
For contributor-facing details — the two custom tables (oc_groupsharemachine_groups, oc_groupsharemachine_teachers), the share-check and picker code paths we hook into, sync mechanics, and conventions — see AGENTS.md.
- Update the version in
appinfo/info.xml - Commit and tag:
git commit -m "vx.x.x" && git tag vx.x.x && git push && git push --tags - Build and sign the package:
make sign(requires certs in~/.nextcloud/certificates/; signing keepsocc integrity:check-app groupsharemachineclean on installs) - Attach
build/groupsharemachine.tar.gzto the GitHub release for the tag — that tarball is what admins install by hand (see Installation)