mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
feat: extract MediaController, wire into Dispatcher, delete media.php
This commit is contained in:
106
app/storage/migrations/001_rename_keywords_to_tags.sql
Normal file
106
app/storage/migrations/001_rename_keywords_to_tags.sql
Normal file
@@ -0,0 +1,106 @@
|
||||
-- Migration 001: Rename keywords→tags, thesis_keywords→thesis_tags, keyword column→name
|
||||
-- SQLite does not support ALTER TABLE RENAME COLUMN before 3.25, so we recreate tables.
|
||||
-- This migration is safe to run after 004 and 005 (no dependency ordering required
|
||||
-- since SQLite processes this in one transaction).
|
||||
|
||||
PRAGMA foreign_keys = OFF;
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. Create new tags table
|
||||
CREATE TABLE tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 2. Copy data from keywords → tags (keyword column → name)
|
||||
INSERT INTO tags (id, name, created_at)
|
||||
SELECT id, keyword, created_at FROM keywords;
|
||||
|
||||
-- 3. Create new junction table thesis_tags
|
||||
CREATE TABLE 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
|
||||
);
|
||||
|
||||
-- 4. Copy junction data (keyword_id → tag_id)
|
||||
INSERT INTO thesis_tags (tag_id, thesis_id)
|
||||
SELECT keyword_id, thesis_id FROM thesis_keywords;
|
||||
|
||||
-- 5. Drop old tables
|
||||
DROP TABLE thesis_keywords;
|
||||
DROP TABLE keywords;
|
||||
|
||||
-- 6. Recreate indexes with canonical names
|
||||
CREATE INDEX idx_tags_name ON tags(name);
|
||||
CREATE INDEX idx_thesis_tags_thesis ON thesis_tags(thesis_id);
|
||||
CREATE INDEX idx_thesis_tags_tag ON thesis_tags(tag_id);
|
||||
|
||||
-- 7. Rebuild views to reference new tables
|
||||
DROP VIEW IF EXISTS v_theses_full;
|
||||
|
||||
CREATE VIEW v_theses_full AS
|
||||
SELECT
|
||||
t.id,
|
||||
t.identifier,
|
||||
t.title,
|
||||
t.subtitle,
|
||||
t.year,
|
||||
t.is_doctoral,
|
||||
o.name as orientation,
|
||||
ap.name as ap_program,
|
||||
ft.name as finality_type,
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
t.duration_minutes,
|
||||
t.duration_pages,
|
||||
t.file_size_info,
|
||||
at.name as access_type,
|
||||
lt.name as license_type,
|
||||
t.license_id,
|
||||
t.jury_points,
|
||||
t.submitted_at,
|
||||
t.defense_date,
|
||||
t.published_at,
|
||||
t.is_published,
|
||||
t.baiu_link,
|
||||
t.banner_path,
|
||||
GROUP_CONCAT(DISTINCT a.name) as authors,
|
||||
GROUP_CONCAT(DISTINCT s.name) as supervisors,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
|
||||
GROUP_CONCAT(DISTINCT l.name) as languages,
|
||||
GROUP_CONCAT(DISTINCT fmt.name) as formats,
|
||||
GROUP_CONCAT(DISTINCT tg.name) as keywords
|
||||
FROM theses t
|
||||
LEFT JOIN orientations o ON t.orientation_id = o.id
|
||||
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
|
||||
LEFT JOIN finality_types ft ON t.finality_id = ft.id
|
||||
LEFT JOIN access_types at ON t.access_type_id = at.id
|
||||
LEFT JOIN license_types lt ON t.license_id = lt.id
|
||||
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
|
||||
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
|
||||
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
|
||||
GROUP BY t.id;
|
||||
|
||||
DROP VIEW IF EXISTS v_theses_public;
|
||||
|
||||
CREATE VIEW v_theses_public AS
|
||||
SELECT * FROM v_theses_full
|
||||
WHERE is_published = 1;
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = ON;
|
||||
9
app/storage/migrations/002_add_visibility.sql
Normal file
9
app/storage/migrations/002_add_visibility.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
-- Migration 002: Wire visibility states to existing access_type_id column.
|
||||
-- The access_types table already has Libre (1), Interne (2), Interdit (3).
|
||||
-- No structural changes needed — this migration is a no-op for the schema.
|
||||
-- It documents the intent and ensures access_types seed rows exist.
|
||||
|
||||
INSERT OR IGNORE INTO access_types (id, name, description) VALUES
|
||||
(1, 'Libre', 'TFE en libre accès à tout le monde sur la plateforme et en bibliothèque'),
|
||||
(2, 'Interne', 'TFE accessible uniquement sur place en physique. Une note descriptive est disponible sur le site'),
|
||||
(3, 'Interdit', 'TFE non disponible en physique ni sur le site. Une note descriptive est disponible sur le site');
|
||||
19
app/storage/migrations/003_seed_license_types.sql
Normal file
19
app/storage/migrations/003_seed_license_types.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Migration 003: Seed license_types table
|
||||
-- Safe to run on existing databases (INSERT OR IGNORE)
|
||||
|
||||
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');
|
||||
66
app/storage/migrations/004_jury_roles.sql
Normal file
66
app/storage/migrations/004_jury_roles.sql
Normal file
@@ -0,0 +1,66 @@
|
||||
-- Migration 004: Add jury role and is_external columns to thesis_supervisors
|
||||
-- Existing rows get role = 'promoteur', is_external = 0 (no data loss)
|
||||
|
||||
ALTER TABLE thesis_supervisors ADD COLUMN role TEXT NOT NULL DEFAULT 'promoteur';
|
||||
ALTER TABLE thesis_supervisors ADD COLUMN is_external INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
-- Recreate v_theses_full to include jury role columns
|
||||
DROP VIEW IF EXISTS v_theses_full;
|
||||
|
||||
CREATE VIEW v_theses_full AS
|
||||
SELECT
|
||||
t.id,
|
||||
t.identifier,
|
||||
t.title,
|
||||
t.subtitle,
|
||||
t.year,
|
||||
t.is_doctoral,
|
||||
o.name as orientation,
|
||||
ap.name as ap_program,
|
||||
ft.name as finality_type,
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
t.duration_minutes,
|
||||
t.duration_pages,
|
||||
t.file_size_info,
|
||||
at.name as access_type,
|
||||
lt.name as license_type,
|
||||
t.license_id,
|
||||
t.jury_points,
|
||||
t.submitted_at,
|
||||
t.defense_date,
|
||||
t.published_at,
|
||||
t.is_published,
|
||||
t.baiu_link,
|
||||
GROUP_CONCAT(DISTINCT a.name) as authors,
|
||||
GROUP_CONCAT(DISTINCT s.name) as supervisors,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
|
||||
GROUP_CONCAT(DISTINCT l.name) as languages,
|
||||
GROUP_CONCAT(DISTINCT fmt.name) as formats,
|
||||
GROUP_CONCAT(DISTINCT k.keyword) as keywords
|
||||
FROM theses t
|
||||
LEFT JOIN orientations o ON t.orientation_id = o.id
|
||||
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
|
||||
LEFT JOIN finality_types ft ON t.finality_id = ft.id
|
||||
LEFT JOIN access_types at ON t.access_type_id = at.id
|
||||
LEFT JOIN license_types lt ON t.license_id = lt.id
|
||||
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
|
||||
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
|
||||
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_keywords tk ON t.id = tk.thesis_id
|
||||
LEFT JOIN keywords k ON tk.keyword_id = k.id
|
||||
GROUP BY t.id;
|
||||
|
||||
-- Recreate public view
|
||||
DROP VIEW IF EXISTS v_theses_public;
|
||||
|
||||
CREATE VIEW v_theses_public AS
|
||||
SELECT * FROM v_theses_full
|
||||
WHERE is_published = 1;
|
||||
65
app/storage/migrations/005_add_banner.sql
Normal file
65
app/storage/migrations/005_add_banner.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
-- Migration 005: Add banner_path column to theses for home page card thumbnails
|
||||
|
||||
ALTER TABLE theses ADD COLUMN banner_path TEXT;
|
||||
|
||||
-- Recreate v_theses_full to include banner_path
|
||||
DROP VIEW IF EXISTS v_theses_full;
|
||||
|
||||
CREATE VIEW v_theses_full AS
|
||||
SELECT
|
||||
t.id,
|
||||
t.identifier,
|
||||
t.title,
|
||||
t.subtitle,
|
||||
t.year,
|
||||
t.is_doctoral,
|
||||
o.name as orientation,
|
||||
ap.name as ap_program,
|
||||
ft.name as finality_type,
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
t.duration_minutes,
|
||||
t.duration_pages,
|
||||
t.file_size_info,
|
||||
at.name as access_type,
|
||||
lt.name as license_type,
|
||||
t.license_id,
|
||||
t.jury_points,
|
||||
t.submitted_at,
|
||||
t.defense_date,
|
||||
t.published_at,
|
||||
t.is_published,
|
||||
t.baiu_link,
|
||||
t.banner_path,
|
||||
GROUP_CONCAT(DISTINCT a.name) as authors,
|
||||
GROUP_CONCAT(DISTINCT s.name) as supervisors,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
|
||||
GROUP_CONCAT(DISTINCT l.name) as languages,
|
||||
GROUP_CONCAT(DISTINCT fmt.name) as formats,
|
||||
GROUP_CONCAT(DISTINCT tg.name) as keywords
|
||||
FROM theses t
|
||||
LEFT JOIN orientations o ON t.orientation_id = o.id
|
||||
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
|
||||
LEFT JOIN finality_types ft ON t.finality_id = ft.id
|
||||
LEFT JOIN access_types at ON t.access_type_id = at.id
|
||||
LEFT JOIN license_types lt ON t.license_id = lt.id
|
||||
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
|
||||
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
|
||||
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
|
||||
GROUP BY t.id;
|
||||
|
||||
-- Recreate public view
|
||||
DROP VIEW IF EXISTS v_theses_public;
|
||||
|
||||
CREATE VIEW v_theses_public AS
|
||||
SELECT * FROM v_theses_full
|
||||
WHERE is_published = 1;
|
||||
8
app/storage/migrations/006_add_composite_index.sql
Normal file
8
app/storage/migrations/006_add_composite_index.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- Migration 006: Add composite covering index (is_published, year DESC) on theses
|
||||
--
|
||||
-- Every public-facing query filters on is_published = 1 AND orders/filters by year.
|
||||
-- The existing separate idx_theses_published and idx_theses_year force the query
|
||||
-- planner to pick one index and sort the other via a temp B-tree.
|
||||
-- This single covering index eliminates the extra sort pass.
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_theses_pub_year ON theses(is_published, year DESC);
|
||||
8
app/storage/migrations/007_system_cache.sql
Normal file
8
app/storage/migrations/007_system_cache.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- Migration 007: Add system_cache table for admin system page caching
|
||||
-- Stores JSON-encoded status snapshots keyed by section with a TTL mechanism.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS system_cache (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
89
app/storage/migrations/008_formulaire_settings.sql
Normal file
89
app/storage/migrations/008_formulaire_settings.sql
Normal file
@@ -0,0 +1,89 @@
|
||||
-- Migration 008: Formulaire settings + contact visibility
|
||||
-- Adds site_settings key-value table for admin-configurable options
|
||||
-- Adds show_contact column to authors table
|
||||
-- Adds author_email + author_show_contact to views
|
||||
|
||||
-- ── 1. site_settings ─────────────────────────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS site_settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL DEFAULT '',
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Default formulaire settings:
|
||||
-- access_type_interdit_enabled = 1 (Interdit is available in the add form)
|
||||
-- access_type_interne_enabled = 1 (Interne is available in the add form)
|
||||
-- access_type_libre_enabled = 0 (Libre is NOT yet available — next academic year)
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES
|
||||
('access_type_interdit_enabled', '1'),
|
||||
('access_type_interne_enabled', '1'),
|
||||
('access_type_libre_enabled', '0');
|
||||
|
||||
-- ── 2. show_contact on authors ────────────────────────────────────────────────
|
||||
-- NOTE: SQLite has no IF NOT EXISTS for ALTER TABLE.
|
||||
-- The migrate.sh script guards against re-running; ignore errors on existing DBs.
|
||||
ALTER TABLE authors ADD COLUMN show_contact INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
-- ── 3. Rebuild views to expose author_email and author_show_contact ───────────
|
||||
DROP VIEW IF EXISTS v_theses_public;
|
||||
DROP VIEW IF EXISTS v_theses_full;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS v_theses_full AS
|
||||
SELECT
|
||||
t.id,
|
||||
t.identifier,
|
||||
t.title,
|
||||
t.subtitle,
|
||||
t.year,
|
||||
t.is_doctoral,
|
||||
o.name as orientation,
|
||||
ap.name as ap_program,
|
||||
ft.name as finality_type,
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
t.duration_minutes,
|
||||
t.duration_pages,
|
||||
t.file_size_info,
|
||||
at.name as access_type,
|
||||
lt.name as license_type,
|
||||
t.license_id,
|
||||
t.jury_points,
|
||||
t.submitted_at,
|
||||
t.defense_date,
|
||||
t.published_at,
|
||||
t.is_published,
|
||||
t.baiu_link,
|
||||
t.banner_path,
|
||||
t.access_type_id,
|
||||
GROUP_CONCAT(DISTINCT a.name) as authors,
|
||||
GROUP_CONCAT(DISTINCT s.name) as supervisors,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
|
||||
GROUP_CONCAT(DISTINCT l.name) 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 author_email,
|
||||
(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 author_show_contact
|
||||
FROM theses t
|
||||
LEFT JOIN orientations o ON t.orientation_id = o.id
|
||||
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
|
||||
LEFT JOIN finality_types ft ON t.finality_id = ft.id
|
||||
LEFT JOIN access_types at ON t.access_type_id = at.id
|
||||
LEFT JOIN license_types lt ON t.license_id = lt.id
|
||||
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
|
||||
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
|
||||
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
|
||||
GROUP BY t.id;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS v_theses_public AS
|
||||
SELECT * FROM v_theses_full
|
||||
WHERE is_published = 1;
|
||||
14
app/storage/migrations/009_share_links.sql
Normal file
14
app/storage/migrations/009_share_links.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Share links table: enables students to submit TFEs via unique, optional-password-protected URLs
|
||||
CREATE TABLE IF NOT EXISTS share_links (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
slug TEXT NOT NULL UNIQUE, -- Format: YYYYMMDD-<random>, e.g. 20260416-a3f9k2
|
||||
password_hash TEXT, -- bcrypt hash; NULL = no password required
|
||||
is_active INTEGER NOT NULL DEFAULT 1, -- 1 = active, 0 = disabled
|
||||
usage_count INTEGER NOT NULL DEFAULT 0, -- Number of successful submissions via this link
|
||||
created_by INTEGER NOT NULL, -- admin user ID (references admin_sessions or admin_users)
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at DATETIME -- NULL = never expires
|
||||
);
|
||||
|
||||
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);
|
||||
14
app/storage/migrations/010_apropos_contents.sql
Normal file
14
app/storage/migrations/010_apropos_contents.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- ── apropos_contents table (structured data for the "À propos" page) ───────
|
||||
-- Replaces config/apropos.php.
|
||||
CREATE TABLE IF NOT EXISTS apropos_contents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key TEXT NOT NULL UNIQUE, -- 'contacts', 'credits', 'erg_url'
|
||||
value TEXT, -- JSON array for contacts/credits, plain string for erg_url
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Seed with the current defaults from config/apropos.php
|
||||
INSERT OR IGNORE INTO apropos_contents (key, value) VALUES
|
||||
('contacts', '[{"name":"Laurent Leprince","role":"Bibliothèque d''architecture, d''ingénierie architecturale, d''urbanisme (BAIU) :","email":"laurent.leprince@uclouvain.be"},{"name":"Xavier Gorgol","role":"Responsable des mémoires de l''ERG :","email":"xavier.gorgol@erg.be"},{"name":"Brigitte Ledune","role":"Cours de suivi de mémoire :","email":"brigitte.ledune@erg.be"}]'),
|
||||
('credits', '[{"label":"Design & développement","value":"Olivia Marly, Théophile Gerveau-Mercie & Théo Hennequin"},{"label":"Typographies","value":"Ductus (Amélie Dumont) & BBB DM Sans"}]'),
|
||||
('erg_url', 'https://erg.be');
|
||||
46
app/storage/migrations/011_apropos_entries.sql
Normal file
46
app/storage/migrations/011_apropos_entries.sql
Normal file
@@ -0,0 +1,46 @@
|
||||
-- Transform apropos data: each row has a label/role and an entries[] of {text, url}.
|
||||
-- Contacts also include email per entry.
|
||||
|
||||
UPDATE apropos_contents SET value = '
|
||||
[
|
||||
{
|
||||
"label": "Design & développement",
|
||||
"entries": [
|
||||
{"text": "Olivia Marly", "url": ""},
|
||||
{"text": "Théophile Gerveau-Mercie", "url": ""},
|
||||
{"text": "Théo Hennequin", "url": ""}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Typographies",
|
||||
"entries": [
|
||||
{"text": "Ductus (Amélie Dumont)", "url": ""},
|
||||
{"text": "BBB DM Sans", "url": ""}
|
||||
]
|
||||
}
|
||||
]' WHERE key = 'credits';
|
||||
|
||||
UPDATE apropos_contents SET value = '
|
||||
[
|
||||
{
|
||||
"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"}
|
||||
]
|
||||
}
|
||||
]' WHERE key = 'contacts';
|
||||
|
||||
-- Remove erg_url from the table (hardcoded in template now)
|
||||
DELETE FROM apropos_contents WHERE key = 'erg_url';
|
||||
22
app/storage/migrations/012_smtp_settings.sql
Normal file
22
app/storage/migrations/012_smtp_settings.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
-- SMTP relay credentials stored in the database.
|
||||
-- A single active row is read at send-time for flexibility (change provider,
|
||||
-- rotate passwords, etc. without touching code or env vars).
|
||||
|
||||
CREATE TABLE IF NOT EXISTS smtp_settings (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1), -- singleton row
|
||||
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 'Post-ERG',
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Insert default empty row so the settings form can start working immediately.
|
||||
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
|
||||
|
||||
-- Helper view so callers always read the same row.
|
||||
CREATE VIEW IF NOT EXISTS v_smtp_active AS
|
||||
SELECT * FROM smtp_settings WHERE id = 1;
|
||||
11
app/storage/migrations/013_admin_password.sql
Normal file
11
app/storage/migrations/013_admin_password.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Migration 013: Store admin password hash in site_settings
|
||||
--
|
||||
-- Previously stored in config/admin_credentials.php as the constant ADMIN_PASSWORD_HASH.
|
||||
-- Now stored alongside SMTP credentials in the site_settings key-value table.
|
||||
--
|
||||
-- After applying this migration, import your existing hash manually:
|
||||
-- UPDATE site_settings SET value = '$2y$12$...' WHERE key = 'admin_password_hash';
|
||||
-- Or simply set a new one via the admin panel UI.
|
||||
|
||||
INSERT OR IGNORE INTO site_settings (key, value) VALUES
|
||||
('admin_password_hash', '');
|
||||
Reference in New Issue
Block a user