d48e2b7d9d
Major features: - Full backup & restore system (JSON snapshots of all 20 tables + settings) - Web UI, REST API, OCC CLI commands, scheduled background job - Self-update from Gitea releases with Ed25519 signature verification - Configurable column visibility on all data tables (persisted via localStorage) Fixes: - NC admin group fallback for PermissionService (IGroupManager) - Bundle import inline error correction (editable error rows) New files: BackupService, BackupSettingsService, BackupController, BackupJob, SelfUpdateService, 4 OCC commands, ColumnPicker component, Backup.vue, Ed25519 signing scripts, signature verification tests (18 tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
436 lines
17 KiB
PHP
436 lines
17 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace OCA\Mitgliederverwaltung\Tests\Unit;
|
|
|
|
use OCA\Mitgliederverwaltung\Db\Member;
|
|
use OCA\Mitgliederverwaltung\Db\MemberMapper;
|
|
use OCA\Mitgliederverwaltung\Db\Permission;
|
|
use OCA\Mitgliederverwaltung\Db\PermissionMapper;
|
|
use OCA\Mitgliederverwaltung\Service\PermissionService;
|
|
use OCA\Mitgliederverwaltung\Service\ValidationException;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\IGroupManager;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class PermissionServiceTest extends TestCase {
|
|
|
|
private PermissionService $service;
|
|
private PermissionMapper&MockObject $permissionMapper;
|
|
private MemberMapper&MockObject $memberMapper;
|
|
private IGroupManager&MockObject $groupManager;
|
|
|
|
protected function setUp(): void {
|
|
$this->permissionMapper = $this->createMock(PermissionMapper::class);
|
|
$this->memberMapper = $this->createMock(MemberMapper::class);
|
|
$this->groupManager = $this->createMock(IGroupManager::class);
|
|
// By default, NC admin group check returns false so existing tests pass unchanged
|
|
$this->groupManager->method('isInGroup')->willReturn(false);
|
|
|
|
$this->service = new PermissionService(
|
|
$this->permissionMapper,
|
|
$this->memberMapper,
|
|
$this->groupManager
|
|
);
|
|
}
|
|
|
|
private function createPermission(string $level, ?string $stufenJson = null, bool $canSeeBanking = false): Permission {
|
|
$perm = new Permission();
|
|
$perm->setNcUserId('user1');
|
|
$perm->setLevel($level);
|
|
$perm->setAllowedStufenJson($stufenJson);
|
|
$perm->setCanSeeBanking($canSeeBanking);
|
|
$ref = new \ReflectionProperty($perm, 'id');
|
|
$ref->setAccessible(true);
|
|
$ref->setValue($perm, 1);
|
|
return $perm;
|
|
}
|
|
|
|
// ── getUserPermission() ────────────────────────────────────────
|
|
|
|
public function testGetUserPermissionReturnsPermission(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$result = $this->service->getUserPermission('user1');
|
|
|
|
$this->assertInstanceOf(Permission::class, $result);
|
|
$this->assertEquals('admin', $result->getLevel());
|
|
}
|
|
|
|
public function testGetUserPermissionReturnsNullWhenNotFound(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$result = $this->service->getUserPermission('unknown');
|
|
|
|
$this->assertNull($result);
|
|
}
|
|
|
|
// ── canAccess() ────────────────────────────────────────────────
|
|
|
|
public function testCanAccessReturnsTrueForAdmin(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canAccess('user1'));
|
|
}
|
|
|
|
public function testCanAccessReturnsTrueForRead(): void {
|
|
$perm = $this->createPermission('read');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canAccess('user1'));
|
|
}
|
|
|
|
public function testCanAccessReturnsFalseForNone(): void {
|
|
$perm = $this->createPermission('none');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canAccess('user1'));
|
|
}
|
|
|
|
public function testCanAccessReturnsFalseForUnknownUser(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->assertFalse($this->service->canAccess('unknown'));
|
|
}
|
|
|
|
// ── canRead() ──────────────────────────────────────────────────
|
|
|
|
public function testCanReadReturnsTrueForAdmin(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canRead('user1'));
|
|
}
|
|
|
|
public function testCanReadReturnsTrueForFull(): void {
|
|
$perm = $this->createPermission('full');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canRead('user1'));
|
|
}
|
|
|
|
public function testCanReadReturnsTrueForStufe(): void {
|
|
$perm = $this->createPermission('stufe');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canRead('user1'));
|
|
}
|
|
|
|
public function testCanReadReturnsTrueForRead(): void {
|
|
$perm = $this->createPermission('read');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canRead('user1'));
|
|
}
|
|
|
|
public function testCanReadReturnsFalseForNone(): void {
|
|
$perm = $this->createPermission('none');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canRead('user1'));
|
|
}
|
|
|
|
public function testCanReadReturnsFalseForUnknown(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->assertFalse($this->service->canRead('unknown'));
|
|
}
|
|
|
|
// ── canWrite() ─────────────────────────────────────────────────
|
|
|
|
public function testCanWriteReturnsTrueForAdmin(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canWrite('user1'));
|
|
}
|
|
|
|
public function testCanWriteReturnsTrueForFull(): void {
|
|
$perm = $this->createPermission('full');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canWrite('user1'));
|
|
}
|
|
|
|
public function testCanWriteReturnsFalseForRead(): void {
|
|
$perm = $this->createPermission('read');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canWrite('user1'));
|
|
}
|
|
|
|
public function testCanWriteReturnsFalseForNone(): void {
|
|
$perm = $this->createPermission('none');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canWrite('user1'));
|
|
}
|
|
|
|
public function testCanWriteStufeAllowedMember(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 2]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$member = new Member();
|
|
$member->setStufeId(1);
|
|
$ref = new \ReflectionProperty($member, 'id');
|
|
$ref->setAccessible(true);
|
|
$ref->setValue($member, 10);
|
|
|
|
$this->memberMapper->method('findById')->willReturn($member);
|
|
|
|
$this->assertTrue($this->service->canWrite('user1', 10));
|
|
}
|
|
|
|
public function testCanWriteStufeDisallowedMember(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 2]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$member = new Member();
|
|
$member->setStufeId(5);
|
|
$ref = new \ReflectionProperty($member, 'id');
|
|
$ref->setAccessible(true);
|
|
$ref->setValue($member, 10);
|
|
|
|
$this->memberMapper->method('findById')->willReturn($member);
|
|
|
|
$this->assertFalse($this->service->canWrite('user1', 10));
|
|
}
|
|
|
|
public function testCanWriteStufeWithoutMemberId(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 2]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canWrite('user1'));
|
|
}
|
|
|
|
public function testCanWriteStufeWithDeletedMember(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 2]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
$this->memberMapper->method('findById')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->assertFalse($this->service->canWrite('user1', 999));
|
|
}
|
|
|
|
// ── canWriteStufe() ────────────────────────────────────────────
|
|
|
|
public function testCanWriteStufeReturnsTrueForAdmin(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canWriteStufe('user1', 5));
|
|
}
|
|
|
|
public function testCanWriteStufeReturnsTrueForFull(): void {
|
|
$perm = $this->createPermission('full');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canWriteStufe('user1', 5));
|
|
}
|
|
|
|
public function testCanWriteStufeReturnsTrueForAllowedStufe(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 5]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canWriteStufe('user1', 5));
|
|
}
|
|
|
|
public function testCanWriteStufeReturnsFalseForDisallowedStufe(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 2]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canWriteStufe('user1', 5));
|
|
}
|
|
|
|
public function testCanWriteStufeReturnsFalseForRead(): void {
|
|
$perm = $this->createPermission('read');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canWriteStufe('user1', 5));
|
|
}
|
|
|
|
// ── isAdmin() ──────────────────────────────────────────────────
|
|
|
|
public function testIsAdminReturnsTrueForAdmin(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->isAdmin('user1'));
|
|
}
|
|
|
|
public function testIsAdminReturnsFalseForFull(): void {
|
|
$perm = $this->createPermission('full');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->isAdmin('user1'));
|
|
}
|
|
|
|
public function testIsAdminReturnsFalseForUnknown(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->assertFalse($this->service->isAdmin('unknown'));
|
|
}
|
|
|
|
// ── canSeeBanking() ────────────────────────────────────────────
|
|
|
|
public function testCanSeeBankingReturnsTrue(): void {
|
|
$perm = $this->createPermission('full', null, true);
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertTrue($this->service->canSeeBanking('user1'));
|
|
}
|
|
|
|
public function testCanSeeBankingReturnsFalse(): void {
|
|
$perm = $this->createPermission('full', null, false);
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$this->assertFalse($this->service->canSeeBanking('user1'));
|
|
}
|
|
|
|
public function testCanSeeBankingReturnsFalseForUnknown(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->assertFalse($this->service->canSeeBanking('unknown'));
|
|
}
|
|
|
|
// ── getVisibleStufen() ─────────────────────────────────────────
|
|
|
|
public function testGetVisibleStufenReturnsNullForAdmin(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$result = $this->service->getVisibleStufen('user1');
|
|
|
|
$this->assertNull($result);
|
|
}
|
|
|
|
public function testGetVisibleStufenReturnsNullForFull(): void {
|
|
$perm = $this->createPermission('full');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$result = $this->service->getVisibleStufen('user1');
|
|
|
|
$this->assertNull($result);
|
|
}
|
|
|
|
public function testGetVisibleStufenReturnsNullForRead(): void {
|
|
$perm = $this->createPermission('read');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$result = $this->service->getVisibleStufen('user1');
|
|
|
|
$this->assertNull($result);
|
|
}
|
|
|
|
public function testGetVisibleStufenReturnsIdsForStufe(): void {
|
|
$perm = $this->createPermission('stufe', '[1, 3]');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$result = $this->service->getVisibleStufen('user1');
|
|
|
|
$this->assertEquals([1, 3], $result);
|
|
}
|
|
|
|
public function testGetVisibleStufenReturnsEmptyForNone(): void {
|
|
$perm = $this->createPermission('none');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
|
|
$result = $this->service->getVisibleStufen('user1');
|
|
|
|
$this->assertEquals([], $result);
|
|
}
|
|
|
|
public function testGetVisibleStufenReturnsEmptyForUnknown(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$result = $this->service->getVisibleStufen('unknown');
|
|
|
|
$this->assertEquals([], $result);
|
|
}
|
|
|
|
// ── getAllPermissions() ─────────────────────────────────────────
|
|
|
|
public function testGetAllPermissions(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findAll')->willReturn([$perm]);
|
|
|
|
$result = $this->service->getAllPermissions();
|
|
|
|
$this->assertCount(1, $result);
|
|
}
|
|
|
|
// ── setPermission() ────────────────────────────────────────────
|
|
|
|
public function testSetPermissionCreatesNew(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('insert')->willReturn($perm);
|
|
|
|
$result = $this->service->setPermission('user1', 'admin');
|
|
|
|
$this->assertInstanceOf(Permission::class, $result);
|
|
}
|
|
|
|
public function testSetPermissionUpdatesExisting(): void {
|
|
$existing = $this->createPermission('read');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($existing);
|
|
|
|
$updated = $this->createPermission('admin');
|
|
$this->permissionMapper->method('update')->willReturn($updated);
|
|
|
|
$result = $this->service->setPermission('user1', 'admin');
|
|
|
|
$this->assertInstanceOf(Permission::class, $result);
|
|
}
|
|
|
|
public function testSetPermissionWithStufen(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$perm = $this->createPermission('stufe', '[1, 2]');
|
|
$this->permissionMapper->method('insert')->willReturn($perm);
|
|
|
|
$result = $this->service->setPermission('user1', 'stufe', [1, 2]);
|
|
|
|
$this->assertInstanceOf(Permission::class, $result);
|
|
}
|
|
|
|
public function testSetPermissionThrowsOnInvalidLevel(): void {
|
|
$this->expectException(ValidationException::class);
|
|
$this->expectExceptionMessage('Ungueltiges Berechtigungslevel');
|
|
|
|
$this->service->setPermission('user1', 'superadmin');
|
|
}
|
|
|
|
// ── removePermission() ─────────────────────────────────────────
|
|
|
|
public function testRemovePermission(): void {
|
|
$perm = $this->createPermission('admin');
|
|
$this->permissionMapper->method('findByUserId')->willReturn($perm);
|
|
$this->permissionMapper->expects($this->once())->method('delete');
|
|
|
|
$this->service->removePermission('user1');
|
|
}
|
|
|
|
public function testRemovePermissionNoOpWhenNotFound(): void {
|
|
$this->permissionMapper->method('findByUserId')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
// Should not throw
|
|
$this->service->removePermission('unknown');
|
|
$this->assertTrue(true);
|
|
}
|
|
}
|