Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- master
- stable*
schedule:
- cron: '0 2 * * *'
- cron: "0 2 * * *"

env:
APP_NAME: auto_groups
Expand All @@ -22,13 +22,12 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.2', '8.3']
databases: ['sqlite']
server-versions:
['stable30', 'stable31', 'stable32']
php-versions: ["8.2", "8.3"]
databases: ["sqlite"]
server-versions: ["stable31", "stable32", "stable33"]
experimental: [false]
include:
- php-versions: '8.4'
- php-versions: "8.4"
databases: sqlite
server-versions: master
experimental: true
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## 1.7.0 - 2026-03-20

### Changed

- Migrate event listener registration to `IBootstrap`/`registerEventListener()` for compatibility with NC34, replacing the deprecated `IEventDispatcher::addListener()` approach
- Compatibility up to NC34

### Fixed

- Restore login hook test which was previously broken due to hook config being read at app instantiation time rather than at event dispatch time

## 1.6.2 - 2025-03-03

### Fixed
Expand Down
62 changes: 62 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Auto Groups - Nextcloud App

## Overview

A Nextcloud app (v1.7.0, AGPL-3.0) that automatically adds users to configured groups ("Auto Groups"), with optional exemptions for users in "Override Groups". A modernized fork of the abandoned [defaultgroup](https://github.com/bodangren/defaultgroup) app.

- **Nextcloud compatibility**: 31–34
- **PHP**: 8.2, 8.3
- **App ID**: `auto_groups` (note: older config used `AutoGroups` — migration logic exists)

## Architecture

Single-class app with minimal footprint:

- `lib/AutoGroupsManager.php` — core logic; registers event listeners and handles group assignment/deletion
- `lib/AppInfo/Application.php` — bootstraps the app via Nextcloud's DI container
- `lib/Settings/Admin.php` — admin settings page
- `appinfo/routes.php` — routes
- `templates/admin.php` + `css/admin.css` + `js/admin.js` — admin UI

## Key Behavior

**Event hooks** (configurable):
- `creation_hook` (default: on) — fires on `UserCreatedEvent` and `UserFirstTimeLoggedInEvent`
- `modification_hook` (default: on) — fires on `UserAddedEvent` and `UserRemovedEvent`
- `login_hook` (default: off) — fires on `PostLoginEvent` and `UserLoggedInEvent`; useful for external user backends

**Group assignment logic** (`addAndRemoveAutoGroups`):
- If user belongs to any Override Group → remove from all Auto Groups
- If user belongs to no Override Group → add to all Auto Groups

**Group deletion protection**: throws `OCSBadRequestException` if trying to delete a group referenced as an Auto Group or Override Group.

## Config Keys

Stored via Nextcloud's `IConfig` under app `auto_groups`:
- `auto_groups` — JSON array of group IDs
- `override_groups` — JSON array of group IDs
- `creation_hook` — `'true'`/`'false'`
- `modification_hook` — `'true'`/`'false'`
- `login_hook` — `'true'`/`'false'`

## Testing

- Unit tests: `tests/Unit/` (uses PHPUnit mocks, extends Nextcloud's `Test\TestCase`)
- Integration tests: `tests/Integration/`
- Manual testing: `tests/Docker/run-docker-test-instance.sh` spins up a Docker instance on port 8080
- Lint: `composer run lint` (runs `php -l` on all PHP files)

## Release Process

Releases are handled by `.github/workflows/release.yml` on GitHub release publication:
1. Verifies `appinfo/info.xml` version matches the git tag
2. Verifies `CHANGELOG.md` has an entry for the version
3. Packages and uploads to GitHub Releases
4. Submits to Nextcloud App Store (requires `AUTO_GROUPS_SIGNING_KEY` and `APP_STORE_API_TOKEN` secrets)

## Noteworthy

- **Config namespace migration**: The app previously used `AutoGroups` as the config namespace instead of `auto_groups`. Migration code in `AutoGroupsManager::__construct` handles upgrading old configs (see GitHub issue #82).
- **l10n**: Translations managed via Transifex (`.tx/config`); many languages supported.
- No Composer dependencies beyond dev tooling — the app relies entirely on Nextcloud's built-in OCP APIs.
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ Automatically add users to specified Auto Groups, except for those belonging to

## Test Status

| Nextcloud Server Branch | Unit & Integration Tests |  Code Coverage |
| Nextcloud Server Branch | Unit & Integration Tests | Code Coverage |
| ------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------: |
| [stable30](https://github.com/nextcloud/server/tree/stable30) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) |  [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=stable30)](https://codecov.io/gh/stjosh/auto_groups) |
| [stable31](https://github.com/nextcloud/server/tree/stable31) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) |  [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=stable31)](https://codecov.io/gh/stjosh/auto_groups) |
| [stable32](https://github.com/nextcloud/server/tree/stable32) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) |  [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=stable31)](https://codecov.io/gh/stjosh/auto_groups) |
| [master](https://github.com/nextcloud/server/tree/master) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) |  [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=master)](https://codecov.io/gh/stjosh/auto_groups) |
| [stable31](https://github.com/nextcloud/server/tree/stable31) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) | [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=stable31)](https://codecov.io/gh/stjosh/auto_groups) |
| [stable32](https://github.com/nextcloud/server/tree/stable32) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) | [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=stable32)](https://codecov.io/gh/stjosh/auto_groups) |
| [stable33](https://github.com/nextcloud/server/tree/stable33) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) | [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=stable33)](https://codecov.io/gh/stjosh/auto_groups) |
| [master](https://github.com/nextcloud/server/tree/master) (NC34, experimental) | ![Unit and Integration Tests](https://github.com/stjosh/auto_groups/workflows/Unit%20and%20Integration%20Tests/badge.svg) | [![codecov](https://codecov.io/gh/stjosh/auto_groups/branch/master/graph/badge.svg?flag=master)](https://codecov.io/gh/stjosh/auto_groups) |

Unit and Integration Tests are executed with PHP v8.2 and v8.3.

Expand All @@ -35,8 +35,6 @@ and then access your test instance on http://localhost:8080. The `auto_groups` a
- [Everyone Group](https://apps.nextcloud.com/apps/group_everyone): The "Everyone Group" app adds a virtual Group Backend, always returning all users. In contrast, "Auto Groups" operates on "real" groups in your normal Group Backend. Additionally, it is possible to specify Override Groups which will prevent users from being added to the Auto Group(s).
- [Default Group](https://apps.nextcloud.com/apps/defaultgroup): "Auto Groups" is actually a modernized and maintaned fork of "Default Group", which seems to be abandoned since NC12 or so. In terms of functionality, they are almost identical.

In addition, I plan to add some more features over time, e.g., "Union Groups" - see the [Milestone Plans](https://github.com/stjosh/auto_groups/milestones) for more details.

## Issue Tracker / Contributions

Contributions are welcome on [GitHub](https://github.com/stjosh/auto_groups/issues).
Expand Down
7 changes: 3 additions & 4 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,18 @@ Note that this app prevents group deletions for groups referenced as Auto Groups
* [Everyone Group](https://apps.nextcloud.com/apps/group_everyone): The "Everyone Group" app adds a virtual Group Backend, always returning all users. In contrast, "Auto Groups" operates on "real" groups in your normal Group Backend. Additionally, it is possible to specify Override Groups which will prevent users from being added to the Auto Group(s).
* [Default Group](https://apps.nextcloud.com/apps/defaultgroup): "Auto Groups" is actually a modernized and maintaned fork of "Default Group", which seems to be abandoned since NC12 or so. In terms of functionality, they are almost identical.

In addition, I plan to add some more features over time, e.g., "Union Groups" - see the [Milestone Plans](https://github.com/stjosh/auto_groups/milestones) for more details.
</description>
<version>1.6.2</version>
<version>1.7.0</version>
<licence>agpl</licence>
<author mail="der@digitalwerker.ch" >Josua Hunziker</author>
<author mail="josh@o23.ch" >Josua Hunziker</author>
<namespace>AutoGroups</namespace>
<category>tools</category>
<website>https://github.com/stjosh/auto_groups</website>
<bugs>https://github.com/stjosh/auto_groups/issues</bugs>
<repository type="git">https://github.com/stjosh/auto_groups.git</repository>
<screenshot>https://raw.githubusercontent.com/stjosh/auto_groups/master/screenshots/settings.png</screenshot>
<dependencies>
<nextcloud min-version="30" max-version="33"/>
<nextcloud min-version="31" max-version="34"/>
</dependencies>
<settings>
<admin>OCA\AutoGroups\Settings\Admin</admin>
Expand Down
23 changes: 18 additions & 5 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
<?php

/**
* Create your routes in here. The name is the lowercase name of the controller
* without the controller part, the stuff after the hash is the method.
* e.g. page#index -> OCA\AutoGroupsGroups\Controller\PageController->index()
* @copyright Copyright (c) 2020
*
* @author Josua Hunziker <josh@o23.ch>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* The controller class has to be registered in the application.php file since
* it's instantiated in there
*/
return [
'routes' => [
Expand Down
21 changes: 21 additions & 0 deletions css/admin.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
/**
* @copyright Copyright (c) 2020
*
* @author Josua Hunziker <josh@o23.ch>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

#auto_groups_options {
position: relative;
}
Expand Down
19 changes: 14 additions & 5 deletions js/admin.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
/**
* Copyright (c) 2020
* @copyright Copyright (c) 2020
*
* @author Josua Hunziker <der@digitalwerker.ch>
* @author Josua Hunziker <josh@o23.ch>
*
* Based on the work of Ján Stibila <nextcloud@stibila.eu> and Lukas Reschke <lukas@owncloud.com>
*
* This file is licensed under the Affero General Public License version 3
* or later.
* @license AGPL-3.0
*
* See the COPYING-README file.
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

Expand Down
44 changes: 34 additions & 10 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/**
* @copyright Copyright (c) 2020
*
* @author Josua Hunziker <der@digitalwerker.ch>
*
* @author Josua Hunziker <josh@o23.ch>
*
* Based on the work of Ján Stibila <nextcloud@stibila.eu>
*
* @license AGPL-3.0
Expand All @@ -25,17 +25,41 @@
namespace OCA\AutoGroups\AppInfo;

use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\User\Events\UserCreatedEvent;
use OCP\User\Events\UserFirstTimeLoggedInEvent;
use OCP\User\Events\PostLoginEvent;
use OCP\User\Events\UserLoggedInEvent;
use OCP\Group\Events\UserAddedEvent;
use OCP\Group\Events\UserRemovedEvent;
use OCP\Group\Events\BeforeGroupDeletedEvent;

use OCA\AutoGroups\AutoGroupsManager;
use OCA\AutoGroups\Listener\AutoGroupsListener;

class Application extends App {
class Application extends App implements IBootstrap
{
public function __construct()
{
parent::__construct('auto_groups');
}

private $autoGroupsManager;
public function register(IRegistrationContext $context): void
{
$context->registerEventListener(UserCreatedEvent::class, AutoGroupsListener::class);
$context->registerEventListener(UserFirstTimeLoggedInEvent::class, AutoGroupsListener::class);
$context->registerEventListener(UserAddedEvent::class, AutoGroupsListener::class);
$context->registerEventListener(UserRemovedEvent::class, AutoGroupsListener::class);
$context->registerEventListener(PostLoginEvent::class, AutoGroupsListener::class);
$context->registerEventListener(UserLoggedInEvent::class, AutoGroupsListener::class);
$context->registerEventListener(BeforeGroupDeletedEvent::class, AutoGroupsListener::class);
}

/**
* Application constructor.
*/
public function __construct() {
parent::__construct('auto_groups');
$this->autoGroupsManager = $this->getContainer()->query(AutoGroupsManager::class);
public function boot(IBootContext $context): void
{
// Instantiate AutoGroupsManager to trigger legacy config migration
$context->getAppContainer()->query(AutoGroupsManager::class);
}
}
Loading
Loading