mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
feat(deploy): add deploy-verify-permissions recipe + upload/run deploy-server.sh before verification + run migrations in deploy
This commit is contained in:
@@ -20,9 +20,12 @@ $logger = AdminLogger::make();
|
||||
|
||||
$isHxRequest = (isset($_SERVER['HTTP_HX_REQUEST']) && $_SERVER['HTTP_HX_REQUEST'] === 'true');
|
||||
$section = $_POST['section'] ?? '';
|
||||
error_log('[settings.php] PROCESS | section=' . $section . ' | post_keys=' . implode(',', array_keys($_POST)));
|
||||
|
||||
if ($section === 'formulaire_restrictions') {
|
||||
$newValues = ['restricted_files_enabled' => ($_POST['restricted_files_enabled'] ?? '0') === '1' ? '1' : '0'];
|
||||
// HTMX may not send unchecked checkboxes even with hidden 0-value inputs;
|
||||
// missing key means unchecked → treat as '0'.
|
||||
$newValues = ['restricted_files_enabled' => empty($_POST['restricted_files_enabled']) ? '0' : '1'];
|
||||
$db->setSetting('restricted_files_enabled', $newValues['restricted_files_enabled']);
|
||||
$logger->logFormSettingsUpdate($newValues);
|
||||
if (!$isHxRequest) {
|
||||
@@ -36,7 +39,7 @@ if ($section === 'formulaire_restrictions') {
|
||||
];
|
||||
$newValues = [];
|
||||
foreach ($allowed as $key) {
|
||||
$value = ($_POST[$key] ?? '0') === '1' ? '1' : '0';
|
||||
$value = empty($_POST[$key]) ? '0' : '1';
|
||||
$db->setSetting($key, $value);
|
||||
$newValues[$key] = $value;
|
||||
}
|
||||
@@ -46,8 +49,8 @@ if ($section === 'formulaire_restrictions') {
|
||||
}
|
||||
} elseif ($section === 'objet_types') {
|
||||
$newValues = [
|
||||
'objet_these_enabled' => ($_POST['objet_these_enabled'] ?? '0') === '1' ? '1' : '0',
|
||||
'objet_frart_enabled' => ($_POST['objet_frart_enabled'] ?? '0') === '1' ? '1' : '0',
|
||||
'objet_these_enabled' => empty($_POST['objet_these_enabled']) ? '0' : '1',
|
||||
'objet_frart_enabled' => empty($_POST['objet_frart_enabled']) ? '0' : '1',
|
||||
];
|
||||
$db->setSetting('objet_these_enabled', $newValues['objet_these_enabled']);
|
||||
$db->setSetting('objet_frart_enabled', $newValues['objet_frart_enabled']);
|
||||
|
||||
@@ -1,11 +1,63 @@
|
||||
-- XAMXAM Thesis Database Schema
|
||||
-- SQLite Database for managing final thesis projects (TFE) and doctoral theses
|
||||
|
||||
-- ============================================================================
|
||||
-- CORE ENTITIES
|
||||
-- XAMXAM Database Schema — complete, fully migrated
|
||||
-- Generated from local database on 2026-05-11
|
||||
-- All 28 migrations merged into this single file.
|
||||
-- ============================================================================
|
||||
|
||||
-- Students/Authors table
|
||||
CREATE TABLE IF NOT EXISTS orientations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ap_programs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
code TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS finality_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS languages (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TEXT DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS format_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
sort_order INTEGER NOT NULL DEFAULT 99
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TEXT DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS access_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS license_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS authors (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
@@ -15,7 +67,6 @@ CREATE TABLE IF NOT EXISTS authors (
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Supervisors/Promoters table
|
||||
CREATE TABLE IF NOT EXISTS supervisors (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
@@ -23,473 +74,323 @@ CREATE TABLE IF NOT EXISTS supervisors (
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- PREDEFINED REFERENCE DATA (lookup tables)
|
||||
-- ============================================================================
|
||||
|
||||
-- Orientations (predefined list from specifications)
|
||||
CREATE TABLE IF NOT EXISTS orientations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Insert predefined orientations
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES
|
||||
('Arts Numériques'),
|
||||
('Dessin'),
|
||||
('Cinéma d''animation'),
|
||||
('Installation-Performance'),
|
||||
('Peinture'),
|
||||
('Photographie'),
|
||||
('Sculpture'),
|
||||
('Vidéographie'),
|
||||
('Graphisme'),
|
||||
('Typographie'),
|
||||
('Design Numérique'),
|
||||
('Illustration'),
|
||||
('Bande-Dessinée'),
|
||||
('Sérigraphie'),
|
||||
('Gravure');
|
||||
|
||||
-- AP (Ateliers Pratiques) - predefined list
|
||||
CREATE TABLE IF NOT EXISTS ap_programs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
code TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Insert predefined AP programs
|
||||
INSERT OR IGNORE INTO ap_programs (name, code) VALUES
|
||||
('Narration Spéculative', 'NS'),
|
||||
('Design et Politique du Multiple', 'DPM'),
|
||||
('Atelier Pratiques Situées', 'APS'),
|
||||
('Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes', 'LIENS'),
|
||||
('Pratique de l''art - outils critiques, arts et contexte simultanés', 'PACS');
|
||||
|
||||
-- Master finality types
|
||||
CREATE TABLE IF NOT EXISTS finality_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO finality_types (name) VALUES
|
||||
('Approfondi'),
|
||||
('Enseignement'),
|
||||
('Spécialisé');
|
||||
|
||||
-- Languages
|
||||
CREATE TABLE IF NOT EXISTS languages (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TEXT DEFAULT NULL
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO languages (name) VALUES
|
||||
('français'),
|
||||
('anglais'),
|
||||
('néerlandais');
|
||||
|
||||
-- Format types (can select multiple)
|
||||
CREATE TABLE IF NOT EXISTS format_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO format_types (name) VALUES
|
||||
('Site web'),
|
||||
('Audio'),
|
||||
('Vidéo'),
|
||||
('Performance'),
|
||||
('Objet éditorial'),
|
||||
('Installation'),
|
||||
('Autre');
|
||||
|
||||
-- Tags (keywords — canonical M2M table; formerly 'keywords'/'keyword' column)
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TEXT DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tags_name ON tags(name);
|
||||
|
||||
-- Access authorization types
|
||||
CREATE TABLE IF NOT EXISTS access_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO access_types (name, description) VALUES
|
||||
('Libre', 'TFE en libre accès à tout le monde sur la plateforme et en bibliothèque'),
|
||||
('Interne', 'TFE accessible uniquement sur place en physique. Une note descriptive est disponible sur le site'),
|
||||
('Interdit', 'TFE non disponible en physique ni sur le site. Une note descriptive est disponible sur le site');
|
||||
|
||||
-- License types
|
||||
CREATE TABLE IF NOT EXISTS license_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES
|
||||
('CC BY 4.0'),
|
||||
('CC BY-SA 4.0'),
|
||||
('CC BY-ND 4.0'),
|
||||
('CC BY-NC 4.0'),
|
||||
('CC BY-NC-SA 4.0'),
|
||||
('CC BY-NC-ND 4.0'),
|
||||
('Tous droits réservés'),
|
||||
('Domaine public');
|
||||
|
||||
-- ============================================================================
|
||||
-- MAIN THESIS TABLE
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS theses (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
identifier TEXT UNIQUE, -- e.g., "2025-002"
|
||||
|
||||
-- Basic information
|
||||
identifier TEXT,
|
||||
title TEXT NOT NULL,
|
||||
subtitle TEXT,
|
||||
year INTEGER NOT NULL,
|
||||
|
||||
-- Type of work
|
||||
is_doctoral BOOLEAN DEFAULT 0, -- 0 for TFE, 1 for doctoral thesis
|
||||
objet TEXT NOT NULL DEFAULT 'tfe' CHECK (objet IN ('tfe', 'thèse', 'frart')),
|
||||
|
||||
-- Academic details
|
||||
is_doctoral BOOLEAN DEFAULT 0,
|
||||
objet TEXT NOT NULL DEFAULT 'tfe',
|
||||
orientation_id INTEGER,
|
||||
ap_program_id INTEGER,
|
||||
finality_id INTEGER,
|
||||
|
||||
-- Content
|
||||
synopsis TEXT, -- ~200 words
|
||||
context_note TEXT, -- Note added by jury president (max 150 words)
|
||||
remarks TEXT, -- Internal remarks
|
||||
|
||||
-- Access and licensing
|
||||
synopsis TEXT,
|
||||
context_note TEXT,
|
||||
remarks TEXT,
|
||||
access_type_id INTEGER,
|
||||
license_id INTEGER,
|
||||
license_custom TEXT, -- free-text licence (if not in predefined list)
|
||||
|
||||
-- Jury information
|
||||
jury_points DECIMAL(4,2), -- Points out of 20 (backoffice only)
|
||||
jury_note_added BOOLEAN DEFAULT 0, -- Whether jury president added a note
|
||||
|
||||
-- Publication status
|
||||
submitted_at DATETIME, -- When student submitted
|
||||
defense_date DATETIME, -- Date of defense/soutenance
|
||||
published_at DATETIME, -- When made public (after jury review)
|
||||
jury_points DECIMAL(4,2),
|
||||
jury_note_added BOOLEAN DEFAULT 0,
|
||||
submitted_at DATETIME,
|
||||
defense_date DATETIME,
|
||||
published_at DATETIME,
|
||||
is_published BOOLEAN DEFAULT 0,
|
||||
|
||||
-- External links
|
||||
baiu_link TEXT, -- Link to institutional repository
|
||||
|
||||
-- Logistics checkboxes (backoffice only)
|
||||
exemplaire_baiu BOOLEAN DEFAULT 0, -- Physical copy at BAIU
|
||||
exemplaire_erg BOOLEAN DEFAULT 0, -- Physical copy at ERG
|
||||
|
||||
-- CC2r acceptance (collected in student form)
|
||||
cc2r BOOLEAN DEFAULT 0,
|
||||
|
||||
-- Soft delete support
|
||||
deleted_at TEXT DEFAULT NULL,
|
||||
|
||||
-- Timestamps
|
||||
baiu_link TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- Foreign keys
|
||||
FOREIGN KEY (orientation_id) REFERENCES orientations(id),
|
||||
FOREIGN KEY (ap_program_id) REFERENCES ap_programs(id),
|
||||
FOREIGN KEY (finality_id) REFERENCES finality_types(id),
|
||||
exemplaire_baiu INTEGER NOT NULL DEFAULT 0,
|
||||
exemplaire_erg INTEGER NOT NULL DEFAULT 0,
|
||||
cc2r INTEGER NOT NULL DEFAULT 0,
|
||||
license_custom TEXT,
|
||||
deleted_at TEXT DEFAULT NULL,
|
||||
FOREIGN KEY (license_id) REFERENCES license_types(id),
|
||||
FOREIGN KEY (access_type_id) REFERENCES access_types(id),
|
||||
FOREIGN KEY (license_id) REFERENCES license_types(id)
|
||||
FOREIGN KEY (finality_id) REFERENCES finality_types(id),
|
||||
FOREIGN KEY (ap_program_id) REFERENCES ap_programs(id),
|
||||
FOREIGN KEY (orientation_id) REFERENCES orientations(id)
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- JUNCTION TABLES (Many-to-Many relationships)
|
||||
-- ============================================================================
|
||||
|
||||
-- Authors per thesis (can have multiple authors)
|
||||
CREATE TABLE IF NOT EXISTS thesis_authors (
|
||||
thesis_id INTEGER NOT NULL,
|
||||
author_id INTEGER NOT NULL,
|
||||
author_order INTEGER DEFAULT 1, -- Order of authors if multiple
|
||||
author_order INTEGER DEFAULT 1,
|
||||
PRIMARY KEY (thesis_id, author_id),
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE
|
||||
FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Supervisors per thesis (jury: president, promoteur, lecteurs)
|
||||
CREATE TABLE IF NOT EXISTS thesis_supervisors (
|
||||
thesis_id INTEGER NOT NULL,
|
||||
supervisor_id INTEGER NOT NULL,
|
||||
supervisor_order INTEGER DEFAULT 1,
|
||||
role TEXT NOT NULL DEFAULT 'promoteur', -- 'president'|'promoteur'|'lecteur'
|
||||
is_external INTEGER NOT NULL DEFAULT 0, -- 0 = internal, 1 = external
|
||||
is_ulb INTEGER NOT NULL DEFAULT 0, -- 1 = ULB promoteur
|
||||
role TEXT NOT NULL DEFAULT 'promoteur',
|
||||
is_external INTEGER NOT NULL DEFAULT 0,
|
||||
is_ulb INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (thesis_id, supervisor_id),
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (supervisor_id) REFERENCES supervisors(id) ON DELETE CASCADE
|
||||
FOREIGN KEY (supervisor_id) REFERENCES supervisors(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Languages per thesis (can be multilingual)
|
||||
CREATE TABLE IF NOT EXISTS thesis_languages (
|
||||
thesis_id INTEGER NOT NULL,
|
||||
language_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (thesis_id, language_id),
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (language_id) REFERENCES languages(id) ON DELETE CASCADE
|
||||
FOREIGN KEY (language_id) REFERENCES languages(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Formats per thesis (can have multiple formats)
|
||||
CREATE TABLE IF NOT EXISTS thesis_formats (
|
||||
thesis_id INTEGER NOT NULL,
|
||||
format_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (thesis_id, format_id),
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (format_id) REFERENCES format_types(id) ON DELETE CASCADE
|
||||
FOREIGN KEY (format_id) REFERENCES format_types(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Tags per thesis (max 10 as per specs; formerly thesis_keywords)
|
||||
CREATE TABLE IF NOT EXISTS thesis_tags (
|
||||
tag_id INTEGER NOT NULL,
|
||||
thesis_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (tag_id, thesis_id),
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- FILE ATTACHMENTS
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS thesis_files (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
thesis_id INTEGER NOT NULL,
|
||||
file_type TEXT NOT NULL, -- 'main', 'annex', 'written_part', 'other'
|
||||
file_type TEXT NOT NULL,
|
||||
file_path TEXT NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
file_size INTEGER, -- in bytes
|
||||
file_size INTEGER,
|
||||
mime_type TEXT,
|
||||
description TEXT,
|
||||
uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
display_label TEXT,
|
||||
file_hash TEXT,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- SITE SETTINGS
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS site_settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL DEFAULT '',
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES
|
||||
('access_type_interdit_enabled', '1'),
|
||||
('access_type_interne_enabled', '1'),
|
||||
('access_type_libre_enabled', '0'),
|
||||
('admin_password_hash', ''),
|
||||
('objet_these_enabled', '1'),
|
||||
('objet_frart_enabled', '1');
|
||||
|
||||
-- ============================================================================
|
||||
-- STATIC PAGES / CONTENT MANAGEMENT
|
||||
-- ============================================================================
|
||||
|
||||
-- For managing editable static pages (charte, about, licenses, contact)
|
||||
CREATE TABLE IF NOT EXISTS system_cache (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pages (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
slug TEXT NOT NULL UNIQUE, -- 'charte', 'about', 'licenses', 'contact'
|
||||
slug TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT, -- Markdown or HTML content
|
||||
content TEXT,
|
||||
is_published BOOLEAN DEFAULT 1,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Initialize default pages
|
||||
INSERT OR IGNORE INTO pages (slug, title, content) VALUES
|
||||
('charte', 'Charte', 'Contenu à venir'),
|
||||
('about', 'À propos', 'Contenu à venir'),
|
||||
('licenses', 'Licences', 'Contenu à venir');
|
||||
|
||||
-- ============================================================================
|
||||
-- SHARE LINKS
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS share_links (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
slug TEXT NOT NULL UNIQUE, -- Format: YYYYMMDD-<random>, e.g. 20260416-a3f9k2
|
||||
name TEXT, -- user-defined label (optional)
|
||||
objet_restriction TEXT CHECK (objet_restriction IN ('tfe', 'thèse', 'frart')), -- NULL = no restriction
|
||||
password_hash TEXT, -- bcrypt hash; NULL = no password required
|
||||
is_active INTEGER NOT NULL DEFAULT 1, -- 1 = active, 0 = disabled
|
||||
is_archived INTEGER NOT NULL DEFAULT 0, -- 1 = archived (link inaccessible, stats preserved)
|
||||
usage_count INTEGER NOT NULL DEFAULT 0, -- Number of successful submissions via this link
|
||||
created_by INTEGER NOT NULL, -- admin user ID
|
||||
slug TEXT NOT NULL,
|
||||
objet_restriction TEXT,
|
||||
password_hash TEXT,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
usage_count INTEGER NOT NULL DEFAULT 0,
|
||||
created_by INTEGER NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at DATETIME -- NULL = never expires
|
||||
expires_at DATETIME,
|
||||
is_archived INTEGER NOT NULL DEFAULT 0,
|
||||
name TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_share_links_slug ON share_links(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_share_links_active ON share_links(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_share_links_archived ON share_links(is_archived);
|
||||
|
||||
-- ============================================================================
|
||||
-- ADMIN AUDIT LOG
|
||||
-- ============================================================================
|
||||
-- Mirrors every admin action logged to /var/log/xamxam.log.
|
||||
-- Best-effort: application never fails if this table is absent.
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_audit_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
ip TEXT NOT NULL,
|
||||
user_agent TEXT,
|
||||
resource TEXT NOT NULL, -- e.g. thesis, tag, share_link, settings, system
|
||||
action TEXT NOT NULL, -- e.g. publish, delete, smtp_update
|
||||
status TEXT NOT NULL, -- success | error
|
||||
context TEXT -- JSON blob with extra fields
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_admin_audit_log_created_at ON admin_audit_log(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_admin_audit_log_resource ON admin_audit_log(resource);
|
||||
CREATE INDEX IF NOT EXISTS idx_admin_audit_log_action ON admin_audit_log(action);
|
||||
|
||||
-- ============================================================================
|
||||
-- SMTP SETTINGS
|
||||
-- ============================================================================
|
||||
|
||||
-- Singleton row — id is always 1. Credentials stored in clear for now.
|
||||
CREATE TABLE IF NOT EXISTS smtp_settings (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
host TEXT NOT NULL DEFAULT '',
|
||||
port INTEGER NOT NULL DEFAULT 587,
|
||||
encryption TEXT NOT NULL DEFAULT 'tls', -- 'tls' | 'ssl' | 'none'
|
||||
username TEXT NOT NULL DEFAULT '',
|
||||
password TEXT NOT NULL DEFAULT '', -- stored in clear for now; encrypt later
|
||||
from_email TEXT NOT NULL DEFAULT '',
|
||||
from_name TEXT NOT NULL DEFAULT 'XAMXAM',
|
||||
notify_email TEXT NOT NULL DEFAULT '', -- recipient for admin notifications
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
host TEXT NOT NULL DEFAULT '',
|
||||
port INTEGER NOT NULL DEFAULT 587,
|
||||
encryption TEXT NOT NULL DEFAULT 'tls',
|
||||
username TEXT NOT NULL DEFAULT '',
|
||||
password TEXT NOT NULL DEFAULT '',
|
||||
from_email TEXT NOT NULL DEFAULT '',
|
||||
from_name TEXT NOT NULL DEFAULT 'Post-ERG',
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
notify_email TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
|
||||
|
||||
CREATE VIEW IF NOT EXISTS v_smtp_active AS
|
||||
SELECT * FROM smtp_settings WHERE id = 1;
|
||||
|
||||
-- ============================================================================
|
||||
-- APROPOS CONTENTS (structured data for the "À propos" page)
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS apropos_contents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key TEXT NOT NULL UNIQUE, -- 'contacts'
|
||||
value TEXT, -- JSON array
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO apropos_contents (key, value) VALUES
|
||||
('contacts', '[
|
||||
{
|
||||
"role": "Bibliothèque d''architecture, d''ingénierie architecturale, d''urbanisme (BAIU) :",
|
||||
"entries": [
|
||||
{"text": "Laurent Leprince", "url": "", "email": "laurent.leprince@uclouvain.be"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "Responsable des mémoires de l''ERG :",
|
||||
"entries": [
|
||||
{"text": "Xavier Gorgol", "url": "", "email": "xavier.gorgol@erg.be"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "Cours de suivi de mémoire :",
|
||||
"entries": [
|
||||
{"text": "Brigitte Ledune", "url": "", "email": "brigitte.ledune@erg.be"}
|
||||
]
|
||||
}
|
||||
]');
|
||||
CREATE TABLE IF NOT EXISTS file_access_requests (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
thesis_id INTEGER NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
justification TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
admin_notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
approved_at DATETIME,
|
||||
approved_by_admin_id INTEGER,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS file_access_tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
request_id INTEGER NOT NULL,
|
||||
token TEXT NOT NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_valid INTEGER NOT NULL DEFAULT 1,
|
||||
used_at DATETIME DEFAULT NULL,
|
||||
FOREIGN KEY (request_id) REFERENCES file_access_requests(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS file_access_sessions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
request_id INTEGER NOT NULL,
|
||||
session_token TEXT NOT NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_valid INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (request_id) REFERENCES file_access_requests(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS file_access_audit (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
request_id INTEGER NOT NULL,
|
||||
event TEXT NOT NULL,
|
||||
ip TEXT,
|
||||
user_agent TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (request_id) REFERENCES file_access_requests(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS form_help_blocks (
|
||||
key TEXT PRIMARY KEY,
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
name TEXT NOT NULL DEFAULT '',
|
||||
enabled INTEGER NOT NULL DEFAULT 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_audit_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
ip TEXT NOT NULL,
|
||||
user_agent TEXT,
|
||||
resource TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
context TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS peertube_settings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
instance_url TEXT NOT NULL DEFAULT '',
|
||||
username TEXT NOT NULL DEFAULT '',
|
||||
password TEXT NOT NULL DEFAULT '',
|
||||
channel_id INTEGER NOT NULL DEFAULT 1,
|
||||
privacy INTEGER NOT NULL DEFAULT 1,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
actor TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
table_name TEXT NOT NULL,
|
||||
record_id INTEGER,
|
||||
old_data TEXT,
|
||||
new_data TEXT
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- INDEXES for performance
|
||||
-- INDEXES
|
||||
-- ============================================================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_year ON theses(year);
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_published ON theses(is_published);
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_pub_year ON theses(is_published, year DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_identifier ON theses(identifier);
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_orientation ON theses(orientation_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_ap_program ON theses(ap_program_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_access_type ON theses(access_type_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_authors_email ON authors(email);
|
||||
CREATE INDEX IF NOT EXISTS idx_thesis_authors_thesis ON thesis_authors(thesis_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_thesis_authors_author ON thesis_authors(author_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_thesis_tags_thesis ON thesis_tags(thesis_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_thesis_tags_tag ON thesis_tags(tag_id);
|
||||
CREATE INDEX idx_admin_audit_log_action ON admin_audit_log(action);
|
||||
|
||||
CREATE INDEX idx_admin_audit_log_created_at ON admin_audit_log(created_at);
|
||||
|
||||
CREATE INDEX idx_admin_audit_log_resource ON admin_audit_log(resource);
|
||||
|
||||
CREATE INDEX idx_audit_log_table_record ON audit_log(table_name, record_id);
|
||||
|
||||
CREATE INDEX idx_audit_log_timestamp ON audit_log(timestamp);
|
||||
|
||||
CREATE INDEX idx_authors_email ON authors(email);
|
||||
|
||||
CREATE INDEX idx_file_access_audit_request
|
||||
ON file_access_audit(request_id);
|
||||
|
||||
CREATE INDEX idx_file_access_requests_email
|
||||
ON file_access_requests(email);
|
||||
|
||||
CREATE INDEX idx_file_access_requests_status
|
||||
ON file_access_requests(status);
|
||||
|
||||
CREATE INDEX idx_file_access_requests_thesis_id
|
||||
ON file_access_requests(thesis_id);
|
||||
|
||||
CREATE INDEX idx_file_access_sessions_expires
|
||||
ON file_access_sessions(expires_at);
|
||||
|
||||
CREATE INDEX idx_file_access_sessions_token
|
||||
ON file_access_sessions(session_token);
|
||||
|
||||
CREATE INDEX idx_file_access_tokens_expires_at
|
||||
ON file_access_tokens(expires_at);
|
||||
|
||||
CREATE INDEX idx_file_access_tokens_token
|
||||
ON file_access_tokens(token);
|
||||
|
||||
CREATE INDEX idx_share_links_active ON share_links(is_active);
|
||||
|
||||
CREATE INDEX idx_share_links_archived ON share_links(is_archived);
|
||||
|
||||
CREATE INDEX idx_share_links_slug ON share_links(slug);
|
||||
|
||||
CREATE INDEX idx_tags_name ON tags(name);
|
||||
|
||||
CREATE INDEX idx_theses_access_type ON theses(access_type_id);
|
||||
|
||||
CREATE INDEX idx_theses_ap_program ON theses(ap_program_id);
|
||||
|
||||
CREATE INDEX idx_theses_identifier ON theses(identifier);
|
||||
|
||||
CREATE INDEX idx_theses_orientation ON theses(orientation_id);
|
||||
|
||||
CREATE INDEX idx_theses_pub_year ON theses(is_published, year DESC);
|
||||
|
||||
CREATE INDEX idx_theses_published ON theses(is_published);
|
||||
|
||||
CREATE INDEX idx_theses_year ON theses(year);
|
||||
|
||||
CREATE INDEX idx_thesis_authors_author ON thesis_authors(author_id);
|
||||
|
||||
CREATE INDEX idx_thesis_authors_thesis ON thesis_authors(thesis_id);
|
||||
|
||||
CREATE INDEX idx_thesis_tags_tag ON thesis_tags(tag_id);
|
||||
|
||||
CREATE INDEX idx_thesis_tags_thesis ON thesis_tags(thesis_id);
|
||||
|
||||
-- ============================================================================
|
||||
-- TRIGGERS for automatic timestamp updates
|
||||
-- VIEWS
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS update_theses_timestamp
|
||||
AFTER UPDATE ON theses
|
||||
BEGIN
|
||||
UPDATE theses SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
CREATE VIEW v_smtp_active AS
|
||||
SELECT * FROM smtp_settings WHERE id = 1;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS update_authors_timestamp
|
||||
AFTER UPDATE ON authors
|
||||
BEGIN
|
||||
UPDATE authors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS update_supervisors_timestamp
|
||||
AFTER UPDATE ON supervisors
|
||||
BEGIN
|
||||
UPDATE supervisors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS update_pages_timestamp
|
||||
AFTER UPDATE ON pages
|
||||
BEGIN
|
||||
UPDATE pages SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS update_apropos_contents_timestamp
|
||||
AFTER UPDATE ON apropos_contents
|
||||
BEGIN
|
||||
UPDATE apropos_contents SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
-- ============================================================================
|
||||
-- VIEWS for common queries
|
||||
-- ============================================================================
|
||||
|
||||
-- Full thesis information view
|
||||
CREATE VIEW IF NOT EXISTS v_theses_full AS
|
||||
CREATE VIEW v_theses_full AS
|
||||
SELECT
|
||||
t.id,
|
||||
t.identifier,
|
||||
@@ -529,7 +430,6 @@ SELECT
|
||||
GROUP_CONCAT(DISTINCT UPPER(SUBSTR(l.name,1,1)) || SUBSTR(l.name,2)) as languages,
|
||||
GROUP_CONCAT(DISTINCT fmt.name) as formats,
|
||||
GROUP_CONCAT(DISTINCT tg.name) as keywords,
|
||||
-- First author's email and contact-visibility flag
|
||||
(SELECT a2.email FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as contact_interne,
|
||||
(SELECT a2.show_contact FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as contact_public
|
||||
FROM theses t
|
||||
@@ -543,82 +443,165 @@ LEFT JOIN authors a ON ta.author_id = a.id
|
||||
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
|
||||
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
|
||||
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
|
||||
LEFT JOIN languages l ON tl.language_id = l.id AND l.deleted_at IS NULL
|
||||
LEFT JOIN languages l ON tl.language_id = l.id
|
||||
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
|
||||
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
|
||||
LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id
|
||||
LEFT JOIN tags tg ON tt.tag_id = tg.id AND tg.deleted_at IS NULL
|
||||
WHERE t.deleted_at IS NULL
|
||||
LEFT JOIN tags tg ON tt.tag_id = tg.id
|
||||
GROUP BY t.id;
|
||||
|
||||
-- Published theses only (for public view)
|
||||
CREATE VIEW IF NOT EXISTS v_theses_public AS
|
||||
CREATE VIEW v_theses_public AS
|
||||
SELECT * FROM v_theses_full
|
||||
WHERE is_published = 1;
|
||||
|
||||
-- ============================================================================
|
||||
-- FILE ACCESS RESTRICTION SYSTEM
|
||||
-- ============================================================================
|
||||
-- Add support for restricting attached files on TFEs with email-based access
|
||||
-- requests and cookie-based validation.
|
||||
-- TRIGGERS
|
||||
-- ============================================================================
|
||||
|
||||
-- Add new site setting for enabling/disabling file access restriction
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES
|
||||
('restricted_files_enabled', '0');
|
||||
CREATE TRIGGER update_apropos_contents_timestamp
|
||||
AFTER UPDATE ON apropos_contents
|
||||
BEGIN
|
||||
UPDATE apropos_contents SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER update_authors_timestamp
|
||||
AFTER UPDATE ON authors
|
||||
BEGIN
|
||||
UPDATE authors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER update_form_help_blocks_timestamp
|
||||
AFTER UPDATE ON form_help_blocks
|
||||
BEGIN
|
||||
UPDATE form_help_blocks SET updated_at = CURRENT_TIMESTAMP WHERE key = NEW.key;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER update_pages_timestamp
|
||||
AFTER UPDATE ON pages
|
||||
BEGIN
|
||||
UPDATE pages SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER update_supervisors_timestamp
|
||||
AFTER UPDATE ON supervisors
|
||||
BEGIN
|
||||
UPDATE supervisors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER update_theses_timestamp
|
||||
AFTER UPDATE ON theses
|
||||
BEGIN
|
||||
UPDATE theses SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
-- ============================================================================
|
||||
-- FILE ACCESS REQUESTS TABLE
|
||||
-- ============================================================================
|
||||
-- Stores requests from users wanting access to restricted TFE files.
|
||||
-- Supports approval workflow: pending → approved/rejected
|
||||
-- SEED DATA (reference data + initial settings)
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS file_access_requests (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
thesis_id INTEGER NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
justification TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending'
|
||||
CHECK(status IN ('pending', 'approved', 'rejected')),
|
||||
admin_notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
approved_at DATETIME,
|
||||
approved_by_admin_id INTEGER,
|
||||
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
|
||||
);
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Arts Numériques');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Bande-Dessinée');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Cinéma d''animation');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Design Numérique');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Dessin');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Graphisme');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Gravure');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Illustration');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Installation-Performance');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Peinture');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Photographie');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Sculpture');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Sérigraphie');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Typographie');
|
||||
INSERT OR IGNORE INTO orientations (name) VALUES ('Vidéographie');
|
||||
|
||||
-- Index for efficient lookup by thesis and email
|
||||
CREATE INDEX IF NOT EXISTS idx_file_access_requests_thesis_id
|
||||
ON file_access_requests(thesis_id);
|
||||
INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('Narration Spéculative', 'NS');
|
||||
INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('Design et Politique du Multiple', 'DPM');
|
||||
INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('Atelier Pratiques Situées', 'APS');
|
||||
INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes', 'LIENS');
|
||||
INSERT OR IGNORE INTO ap_programs (name, code) VALUES ('Pratique de l''art - outils critiques, arts et contexte simultanés', 'PACS');
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_file_access_requests_email
|
||||
ON file_access_requests(email);
|
||||
INSERT OR IGNORE INTO finality_types (name) VALUES ('Approfondi');
|
||||
INSERT OR IGNORE INTO finality_types (name) VALUES ('Enseignement');
|
||||
INSERT OR IGNORE INTO finality_types (name) VALUES ('Spécialisé');
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_file_access_requests_status
|
||||
ON file_access_requests(status);
|
||||
INSERT OR IGNORE INTO languages (name) VALUES ('français');
|
||||
INSERT OR IGNORE INTO languages (name) VALUES ('anglais');
|
||||
INSERT OR IGNORE INTO languages (name) VALUES ('néerlandais');
|
||||
INSERT OR IGNORE INTO languages (name) VALUES ('italian');
|
||||
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Site web', 5);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Audio', 3);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Vidéo', 4);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Performance', 6);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Objet éditorial', 7);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Installation', 8);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Autre', 9);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Écriture', 1);
|
||||
INSERT OR IGNORE INTO format_types (name, sort_order) VALUES ('Image', 2);
|
||||
|
||||
INSERT OR IGNORE INTO access_types (name, description) VALUES ('Libre', 'TFE en libre accès à tout le monde sur la plateforme et en bibliothèque');
|
||||
INSERT OR IGNORE INTO access_types (name, description) VALUES ('Interne', 'TFE accessible uniquement sur place en physique. Une note descriptive est disponible sur le site');
|
||||
INSERT OR IGNORE INTO access_types (name, description) VALUES ('Interdit', 'TFE non disponible en physique ni sur le site. Une note descriptive est disponible sur le site');
|
||||
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('CC BY 4.0');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('CC BY-NC 4.0');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('CC BY-NC-ND 4.0');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('CC BY-NC-SA 4.0');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('CC BY-ND 4.0');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('CC BY-SA 4.0');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('Domaine public');
|
||||
INSERT OR IGNORE INTO license_types (name) VALUES ('Tous droits réservés');
|
||||
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('access_type_interdit_enabled', '1');
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('access_type_interne_enabled', '0');
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('access_type_libre_enabled', '0');
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('objet_frart_enabled', '1');
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('objet_these_enabled', '1');
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('peertube_upload_enabled', '0');
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES ('restricted_files_enabled', '0');
|
||||
|
||||
INSERT OR IGNORE INTO pages (slug, title, content, is_published) VALUES ('about', 'À propos', 'Contenu à venir', 1);
|
||||
INSERT OR IGNORE INTO pages (slug, title, content, is_published) VALUES ('charte', 'Charte', 'Contenu à venir', 1);
|
||||
INSERT OR IGNORE INTO pages (slug, title, content, is_published) VALUES ('licenses', 'Licences', 'Contenu à venir', 1);
|
||||
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('partage_intro', 'Introduction', 'Hahahaha
|
||||
## Beware the dog', 0, 0);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_tfe_info', 'Informations du TFE', 'Hello world', 0, 1);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_synopsis', 'Note Synopsis', '', 0, 2);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_jury', 'Composition du jury', '', 0, 3);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_academic', 'Cadre académique', '', 0, 4);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_files', 'Fichiers', '', 0, 5);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_access', 'Visibilité / Accès', 'qsldkjlfkjdsqmflkjq', 1, 6);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_email', 'E-mail de confirmation', '', 0, 7);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_languages', 'Langue(s)', 'Hahah', 0, 0);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_keywords', 'Mots-clés', 'lolz', 0, 0);
|
||||
INSERT OR IGNORE INTO form_help_blocks (key, name, content, enabled, sort_order) VALUES ('fieldset_metadata', 'Métadonnées complémentaires', '', 0, 0);
|
||||
|
||||
INSERT OR IGNORE INTO apropos_contents (key, value) VALUES ('contacts', '[
|
||||
{
|
||||
"role": "Bibliothèque d''architecture, d''ingénierie architecturale, d''urbanisme (BAIU) :",
|
||||
"entries": [
|
||||
{"text": "Laurent Leprince", "url": "", "email": "laurent.leprince@uclouvain.be"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "Responsable des mémoires de l''ERG :",
|
||||
"entries": [
|
||||
{"text": "Xavier Gorgol", "url": "", "email": "xavier.gorgol@erg.be"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "Cours de suivi de mémoire :",
|
||||
"entries": [
|
||||
{"text": "Brigitte Ledune", "url": "", "email": "brigitte.ledune@erg.be"}
|
||||
]
|
||||
}
|
||||
]');
|
||||
|
||||
-- Singleton table placeholders
|
||||
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
|
||||
INSERT OR IGNORE INTO peertube_settings (id) VALUES (1);
|
||||
|
||||
-- ============================================================================
|
||||
-- FILE ACCESS TOKENS TABLE
|
||||
-- END OF SCHEMA
|
||||
-- ============================================================================
|
||||
-- Stores tokens for cookie-based access validation.
|
||||
-- Each token is unique, time-limited, and linked to a specific request.
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS file_access_tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
request_id INTEGER NOT NULL,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
expires_at DATETIME NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_valid INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (request_id) REFERENCES file_access_requests(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Index for token lookup (most common query)
|
||||
CREATE INDEX IF NOT EXISTS idx_file_access_tokens_token
|
||||
ON file_access_tokens(token);
|
||||
|
||||
-- Index for cleanup of expired tokens
|
||||
CREATE INDEX IF NOT EXISTS idx_file_access_tokens_expires_at
|
||||
ON file_access_tokens(expires_at);
|
||||
|
||||
4464
app/storage/schema.sql.new
Normal file
4464
app/storage/schema.sql.new
Normal file
File diff suppressed because it is too large
Load Diff
@@ -675,6 +675,58 @@
|
||||
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
+\\\\\\\ to: kpvxplms 859e5316 "fix: settings handler was treating hidden value="0" as truthy" (rebased revision)
|
||||
++ $linkName = $link['name'] ?? '';
|
||||
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: kpvxplms 859e5316 "fix: settings handler was treating hidden value="0" as truthy" (rebased revision)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
- $linkName = $link['name'] ?? '';
|
||||
- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: rqrkkkuo 9141fd8e "feat(deploy): add deploy-verify-permissions recipe to check ownership/permissions after rsync" (rebased revision)
|
||||
$linkName = $link['name'] ?? '';
|
||||
$linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
$linkLockedYear = $link['locked_year'] ?? null;
|
||||
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
+\\\\\\\ to: rqrkkkuo 5563460c "feat(deploy): add deploy-verify-permissions recipe to check ownership/permissions after rsync" (rebased revision)
|
||||
++ $linkName = $link['name'] ?? '';
|
||||
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: rqrkkkuo 5563460c "feat(deploy): add deploy-verify-permissions recipe to check ownership/permissions after rsync" (rebased revision)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
- $linkName = $link['name'] ?? '';
|
||||
- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: unnmorqw 5feff462 "feat(deploy): upload and run deploy-server.sh before permission verification" (rebased revision)
|
||||
$linkName = $link['name'] ?? '';
|
||||
$linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
$linkLockedYear = $link['locked_year'] ?? null;
|
||||
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
+\\\\\\\ to: unnmorqw c30a41b6 "feat(deploy): upload and run deploy-server.sh before permission verification" (rebased revision)
|
||||
++ $linkName = $link['name'] ?? '';
|
||||
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: unnmorqw c30a41b6 "feat(deploy): upload and run deploy-server.sh before permission verification" (rebased revision)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
- $linkName = $link['name'] ?? '';
|
||||
- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: mysnnsru 3bfad924 "feat(deploy): upload and run deploy-server.sh before permission verification, run migrations" (rebased revision)
|
||||
$linkName = $link['name'] ?? '';
|
||||
$linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
$linkLockedYear = $link['locked_year'] ?? null;
|
||||
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
+\\\\\\\ to: mysnnsru 4f314e92 "feat(deploy): upload and run deploy-server.sh before permission verification, run migrations" (rebased revision)
|
||||
++ $linkName = $link['name'] ?? '';
|
||||
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: mysnnsru 4f314e92 "feat(deploy): upload and run deploy-server.sh before permission verification, run migrations" (rebased revision)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
- $linkName = $link['name'] ?? '';
|
||||
- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
|
||||
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: sstzwlpk 18bd561d "feat(deploy): upload deploy-server.sh, run migrations, fix migrate.sh server layout" (rebased revision)
|
||||
$linkName = $link['name'] ?? '';
|
||||
$linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
$linkLockedYear = $link['locked_year'] ?? null;
|
||||
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
|
||||
+\\\\\\\ to: sstzwlpk 0e83e8f7 "feat(deploy): upload deploy-server.sh, run migrations, fix migrate.sh server layout" (rebased revision)
|
||||
++ $linkName = $link['name'] ?? '';
|
||||
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
|
||||
?>
|
||||
<tr class="admin-table-row" onclick="event.stopPropagation(); window.open('/partage/<?= urlencode($link['slug']) ?>', '_blank')" style="cursor:pointer">
|
||||
|
||||
Reference in New Issue
Block a user