mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-27 09:09:22 +02:00
feat: fix file deletion on save + trash policy + documents/ prefix + relink browser
1. note_intention: Delete old file only when a genuinely new upload arrives
(32-char hex file_id), not when the FilePond pool preserves an existing
file by sending its DB integer ID. Previously the DB integer ID
triggered $hasNewNote=true, which deleted the existing note_intention
from disk+DB, then handleFilePondSingleFile couldn't re-process it
because the regex requires a hex pattern. Same fix applied to cover.
2. All file deletions now use deleteThesisFileToTrash() which renames
files to tmp/_trash/ instead of unlinking. The trash preserves
original filenames prefixed with DB id for traceability. Skips
website URLs and PeerTube refs (no disk file).
3. Storage prefix changed from theses/ to documents/ to reflect that
the folder holds all document types (determined by file_type in DB).
MediaController visibility gate supports both prefixes for backward
compat with existing files.
4. File browser + relink feature for orphaned files:
- /admin/fragments/file-browser.php — HTMX tree browser for
storage/documents/ and storage/theses/
- /admin/actions/filepond/relink.php — POST endpoint that inserts
a thesis_files row pointing to existing on-disk file
- Per-pool "📂 Relier" buttons (edit mode only)
- JS: XamxamOpenFileBrowser / XamxamRelinkFile with FilePond integration
- CSS: .relink-modal dialog + .file-browser tree styles
This commit is contained in:
@@ -61,7 +61,7 @@ class ShareLink
|
||||
* @param string|null $expiresAt ISO-8601 expiration date, null = never expires
|
||||
* @return array|null The created link row with _plain_password attached
|
||||
*/
|
||||
public function create(int $createdBy, ?string $expiresAt = null, ?string $objetRestriction = null, ?string $name = null): ?array
|
||||
public function create(int $createdBy, ?string $expiresAt = null, ?string $objetRestriction = null, ?string $name = null, ?int $lockedYear = null): ?array
|
||||
{
|
||||
$slug = self::generateSlug();
|
||||
$plainPassword = self::generatePassword();
|
||||
@@ -74,11 +74,16 @@ class ShareLink
|
||||
$objetRestriction = 'tfe';
|
||||
}
|
||||
|
||||
// Validate locked_year: must be a plausible academic year (2000..current+3)
|
||||
if ($lockedYear !== null && ($lockedYear < 2000 || $lockedYear > ((int)date('Y') + 3))) {
|
||||
$lockedYear = null;
|
||||
}
|
||||
|
||||
$stmt = $this->db->getConnection()->prepare(
|
||||
'INSERT INTO share_links (slug, name, objet_restriction, password_hash, encrypted_password, is_active, created_by, expires_at)
|
||||
VALUES (?, ?, ?, ?, ?, 1, ?, ?)'
|
||||
'INSERT INTO share_links (slug, name, objet_restriction, password_hash, encrypted_password, is_active, created_by, expires_at, locked_year)
|
||||
VALUES (?, ?, ?, ?, ?, 1, ?, ?, ?)'
|
||||
);
|
||||
$stmt->execute([$slug, $name, $objetRestriction, $passwordHash, Crypto::encrypt($plainPassword), $createdBy, $expiresAt]);
|
||||
$stmt->execute([$slug, $name, $objetRestriction, $passwordHash, Crypto::encrypt($plainPassword), $createdBy, $expiresAt, $lockedYear]);
|
||||
|
||||
$link = $this->findBySlug($slug);
|
||||
if ($link) {
|
||||
@@ -235,7 +240,15 @@ class ShareLink
|
||||
/**
|
||||
* Update a share link (name, expiration).
|
||||
*/
|
||||
public function update(int $id, ?string $name = null, ?string $expiresAt = null): void
|
||||
/**
|
||||
* Update a share link's name, expiration, and/or locked year.
|
||||
*
|
||||
* $lockedYear:
|
||||
* - null → leave unchanged (not present in POST)
|
||||
* - "" → clear (set to NULL in DB)
|
||||
* - non-empty string → parse as int, validate, and set
|
||||
*/
|
||||
public function update(int $id, ?string $name = null, ?string $expiresAt = null, mixed $lockedYear = null): void
|
||||
{
|
||||
$pdo = $this->db->getConnection();
|
||||
$fields = [];
|
||||
@@ -250,6 +263,17 @@ class ShareLink
|
||||
$fields[] = 'expires_at = ?';
|
||||
$params[] = $expiresAtVal;
|
||||
}
|
||||
if ($lockedYear !== null) {
|
||||
if ($lockedYear === '' || $lockedYear === false) {
|
||||
$fields[] = 'locked_year = NULL';
|
||||
} else {
|
||||
$year = filter_var($lockedYear, FILTER_VALIDATE_INT);
|
||||
if ($year !== false && $year >= 2000 && $year <= ((int)date('Y') + 3)) {
|
||||
$fields[] = 'locked_year = ?';
|
||||
$params[] = $year;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($fields)) {
|
||||
$params[] = $id;
|
||||
|
||||
Reference in New Issue
Block a user