OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

FileTrashAclTest.php

6 KB
<?php

declare(strict_types=1);

use OpenNIT\Content\FileExplorerAcl;
use OpenNIT\Content\FileExplorerManager;

/**
 * Deckt den Zugriffsschutz des Datei-Papierkorbs ab.
 *
 * Gelöschte Einträge behalten ihre Ordner-Zuordnung, damit sich die Rechte
 * eines Papierkorb-Stapels weiterhin über den Ordnerbaum bestimmen lassen –
 * die Vererbung läuft dabei über den gespeicherten Pfad, der auch für
 * gelöschte Ordner erhalten bleibt.
 */
return static function (): void {

    /**
     * Datenbank-Doppel mit Ordnerbaum, Rechteeinträgen und Papierkorb-Stapeln.
     *
     * @param array<int,array{path:string,created_by:?int}> $folders
     * @param array<int,array<int,array{principal_type:string,principal_id:int,permission:string}>> $acl
     * @param array<string,array{folders:int[],files:array<int,?int>}> $batches
     */
    $db = function (array $folders, array $acl, array $batches = []): object {
        return new class ($folders, $acl, $batches) extends \OpenNIT\Core\Database {
            public function __construct(
                private array $folders,
                private array $acl,
                private array $batches
            ) {
                // Verbindung bewusst nicht aufbauen – die Abfragen werden bedient.
            }

            public function fetchAll(string $sql, array $params = []): array
            {
                if (str_contains($sql, 'file_explorer_folder_acl')) {
                    $rows = [];
                    foreach ($this->acl as $folderId => $entries) {
                        foreach ($entries as $e) {
                            $rows[] = $e + ['folder_id' => $folderId];
                        }
                    }
                    return $rows;
                }
                if (str_contains($sql, 'SELECT id, path, created_by FROM file_explorer_folders')) {
                    $rows = [];
                    foreach ($this->folders as $id => $f) {
                        $rows[] = ['id' => $id, 'path' => $f['path'], 'created_by' => $f['created_by']];
                    }
                    return $rows;
                }
                if (str_contains($sql, 'SELECT id FROM file_explorer_folders WHERE deleted_batch')) {
                    $batch = (string)($params[0] ?? '');
                    return array_map(
                        static fn(int $id): array => ['id' => $id],
                        $this->batches[$batch]['folders'] ?? []
                    );
                }
                if (str_contains($sql, 'SELECT DISTINCT folder_id FROM file_explorer_files WHERE deleted_batch')) {
                    $batch = (string)($params[0] ?? '');
                    return array_map(
                        static fn(?int $fid): array => ['folder_id' => $fid],
                        $this->batches[$batch]['files'] ?? []
                    );
                }
                return [];
            }
        };
    };

    /**
     * Erzeugt den Manager ohne Konstruktor – der legt sonst das
     * Ablageverzeichnis an, was für die reine Abfragelogik nicht nötig ist.
     */
    $bauManager = static function (object $datenbank): FileExplorerManager {
        $klasse = new ReflectionClass(FileExplorerManager::class);
        $mgr    = $klasse->newInstanceWithoutConstructor();
        $feld   = $klasse->getProperty('db');
        $feld->setAccessible(true);
        $feld->setValue($mgr, $datenbank);
        return $mgr;
    };

    /** Ordnerbaum: /1/ öffentlich, /1/2/ mit Leserecht nur für Rolle 7. */
    $baum = [
        1 => ['path' => '/1/',   'created_by' => 99],
        2 => ['path' => '/1/2/', 'created_by' => 99],
    ];
    $rechte = [
        2 => [['principal_type' => 'role', 'principal_id' => 7, 'permission' => 'view']],
    ];

    // ----------------------------------------------------------------
    // Rechte eines gelöschten Ordners
    // ----------------------------------------------------------------

    test('Ein gelöschter Ordner behält die Rechte seines Bereichs', function () use ($db, $baum, $rechte) {
        $acl = new FileExplorerAcl($db($baum, $rechte));

        // Rolle 7 darf lesen, aber nicht verwalten – Stufe „view".
        assertTrue($acl->canView(2, 1, [7], false));
        assertFalse($acl->canManage(2, 1, [7], false));

        // Ohne passende Rolle bleibt der Bereich vollständig verschlossen.
        assertFalse($acl->canView(2, 2, [8], false));
        assertFalse($acl->canUpload(2, 2, [8], false));
    });

    test('Bereiche ohne Rechteeintrag bleiben für alle offen', function () use ($db, $baum, $rechte) {
        $acl = new FileExplorerAcl($db($baum, $rechte));
        assertTrue($acl->canManage(1, 2, [8], false));
        assertTrue($acl->canManage(null, 2, [8], false));
    });

    test('Ohne jeden Rechteeintrag ändert sich für bestehende Instanzen nichts', function () use ($db, $baum) {
        $acl = new FileExplorerAcl($db($baum, []));
        assertTrue($acl->canManage(2, 2, [8], false));
        assertTrue($acl->canView(2, 2, [8], false));
    });

    // ----------------------------------------------------------------
    // Zuordnung eines Papierkorb-Stapels
    // ----------------------------------------------------------------

    test('Ein Stapel benennt alle Bereiche, aus denen er stammt', function () use ($db, $baum, $rechte, $bauManager) {
        $stapel = [
            'b1' => ['folders' => [2], 'files' => []],
            'b2' => ['folders' => [],  'files' => [2, null]],
        ];
        $mgr = $bauManager($db($baum, $rechte, $stapel));

        assertSame([2], $mgr->batchAclScopes('b1'));

        // Einzeldateien: ihr Ablageordner, `null` steht für die Wurzel.
        $scopes = $mgr->batchAclScopes('b2');
        assertTrue(in_array(2, $scopes, true), 'Ordner der Datei fehlt');
        assertTrue(in_array(null, $scopes, true), 'Wurzel fehlt');
    });

    test('Ein leerer Stapel benennt keinen Bereich', function () use ($db, $baum, $rechte, $bauManager) {
        $mgr = $bauManager($db($baum, $rechte, []));
        assertSame([], $mgr->batchAclScopes('unbekannt'));
    });
};