feat: agrégateur RSS /flux + gestion feeds dans /profile

This commit is contained in:
Cedric Abonnel
2026-05-12 23:59:09 +02:00
parent 03177dc732
commit 2e8302dad4
7 changed files with 432 additions and 7 deletions
+86 -1
View File
@@ -22,7 +22,7 @@ $action = $_GET['action'] ?? 'list';
$uuid = $_GET['uuid'] ?? '';
$slug = $_GET['slug'] ?? '';
$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found'];
$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found', 'add_feed', 'delete_feed'];
$metaRobots = in_array($action, $_noindexActions, true) ? 'noindex, nofollow' : null;
unset($_noindexActions);
@@ -881,6 +881,44 @@ switch ($action) {
include BASE_PATH . '/templates/author_profile.php';
break;
case 'flux':
require_once BASE_PATH . '/src/FeedFetcher.php';
$fetcher = new FeedFetcher(BASE_PATH . '/data/_cache/feeds');
$fluxItems = [];
$pdo = dbPdo();
if ($pdo) {
try {
$st = $pdo->query(
'SELECT f.user_email, f.feed_url, f.label,
p.display_name, p.profile_slug
FROM rss_feeds f
LEFT JOIN user_profiles p ON p.email = f.user_email
ORDER BY f.created_at'
);
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $_row) {
$data = $fetcher->get($_row['feed_url']);
if (!$data) {
continue;
}
$feedTitle = $_row['label'] !== '' ? $_row['label'] : $data['feed_title'];
$authorName = $_row['display_name'] ?? '';
$authorSlug = $_row['profile_slug'] ?? '';
foreach ($data['items'] as $_item) {
$fluxItems[] = array_merge($_item, [
'feed_title' => $feedTitle,
'feed_url' => $_row['feed_url'],
'author_name' => $authorName,
'author_slug' => $authorSlug,
]);
}
}
} catch (\Throwable) {
}
}
usort($fluxItems, static fn ($a, $b) => $b['date'] <=> $a['date']);
include BASE_PATH . '/templates/flux.php';
break;
case 'about':
include BASE_PATH . '/templates/about.php';
break;
@@ -1840,9 +1878,56 @@ switch ($action) {
if ($profileCurrentUrl === '' && $profileCurrentSlug !== '') {
$profileCurrentUrl = rtrim(APP_URL, '/') . '/profil/' . rawurlencode($profileCurrentSlug);
}
// Feeds RSS de l'utilisateur
$profileFeeds = [];
$pdo = dbPdo();
if ($pdo) {
try {
$st = $pdo->prepare('SELECT id, feed_url, label FROM rss_feeds WHERE user_email = :e ORDER BY created_at');
$st->execute([':e' => currentUserEmail()]);
$profileFeeds = $st->fetchAll(PDO::FETCH_ASSOC);
} catch (\Throwable) {
}
}
include BASE_PATH . '/templates/profile.php';
break;
case 'add_feed':
requireAuth();
$feedUrl = filter_var(trim($_POST['feed_url'] ?? ''), FILTER_VALIDATE_URL) ?: '';
$feedLabel = trim($_POST['feed_label'] ?? '');
if ($feedUrl !== '') {
$pdo = dbPdo();
if ($pdo) {
try {
$st = $pdo->prepare(
'INSERT INTO rss_feeds (user_email, feed_url, label) VALUES (:e, :u, :l)
ON CONFLICT (user_email, feed_url) DO UPDATE SET label = :l'
);
$st->execute([':e' => currentUserEmail(), ':u' => $feedUrl, ':l' => $feedLabel]);
} catch (\Throwable) {
}
}
}
header('Location: /profile#feeds');
exit;
case 'delete_feed':
requireAuth();
$feedId = (int)($_POST['feed_id'] ?? 0);
if ($feedId > 0) {
$pdo = dbPdo();
if ($pdo) {
try {
$st = $pdo->prepare('DELETE FROM rss_feeds WHERE id = :id AND user_email = :e');
$st->execute([':id' => $feedId, ':e' => currentUserEmail()]);
} catch (\Throwable) {
}
}
}
header('Location: /profile#feeds');
exit;
case 'search_files':
requireAuth();
header('Content-Type: application/json');