Refonte du système de notifications : passage aux notifications dérivées
Remplace le système de notifications stockées par un système de providers qui dérivent les notifications des données existantes (commentaires, réponses, demandes de projet, demandes de rendez-vous, validations de brief). - Ajout du NotificationCollector et de l'interface NotificationProvider - Création de 5 providers : Comment, Reply, ProjectRequest, AppointmentRequest, Content - Métadonnées de notifications stockées directement sur les entités source - Nouvelles routes mark-as-read et mark-all-read - Mise à jour du frontend pour le nouveau système - Route de migration pour les données existantes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c68b51f639
commit
a7d315942a
26 changed files with 1406 additions and 137 deletions
175
public/site/config/routes/migrate-notifications.php
Normal file
175
public/site/config/routes/migrate-notifications.php
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Script de migration unique pour le système de notifications dérivées.
|
||||
*
|
||||
* Ce script copie les `readby[]` des anciennes notifications vers les sources de données.
|
||||
* À exécuter une seule fois après le déploiement, puis à supprimer.
|
||||
*
|
||||
* Usage: POST /migrate-notifications.json
|
||||
*/
|
||||
|
||||
return [
|
||||
'pattern' => 'migrate-notifications.json',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
$user = kirby()->user();
|
||||
|
||||
// Vérifier que l'utilisateur est admin
|
||||
if (!$user || $user->role()->id() !== 'admin') {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Cette action nécessite les droits administrateur.'
|
||||
];
|
||||
}
|
||||
|
||||
$migrated = [
|
||||
'comments' => 0,
|
||||
'replies' => 0,
|
||||
'project-requests' => 0,
|
||||
'appointment-requests' => 0,
|
||||
'content' => 0,
|
||||
'errors' => []
|
||||
];
|
||||
|
||||
$projects = page('projects')->children();
|
||||
|
||||
foreach ($projects as $project) {
|
||||
// Récupérer les anciennes notifications
|
||||
$notifications = $project->notifications()->yaml() ?? [];
|
||||
|
||||
if (empty($notifications)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($notifications as $notification) {
|
||||
try {
|
||||
$type = $notification['type'] ?? 'comment';
|
||||
$id = $notification['id'] ?? null;
|
||||
$readby = $notification['readby'] ?? [];
|
||||
|
||||
if (empty($id) || empty($readby)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'comment':
|
||||
case 'comment-reply':
|
||||
$fileUuid = $notification['location']['file']['uuid'] ?? null;
|
||||
if (!$fileUuid) continue 2;
|
||||
|
||||
$file = kirby()->file($fileUuid);
|
||||
if (!$file) continue 2;
|
||||
|
||||
$comments = Yaml::decode($file->comments()->value()) ?? [];
|
||||
$updated = false;
|
||||
|
||||
foreach ($comments as &$comment) {
|
||||
// Vérifier si c'est le commentaire principal
|
||||
if ($comment['id'] === $id) {
|
||||
$existingReadby = $comment['readby'] ?? [];
|
||||
$comment['readby'] = array_values(array_unique(array_merge($existingReadby, $readby)));
|
||||
$updated = true;
|
||||
$migrated['comments']++;
|
||||
break;
|
||||
}
|
||||
|
||||
// Vérifier dans les réponses
|
||||
foreach ($comment['replies'] ?? [] as &$reply) {
|
||||
if ($reply['id'] === $id) {
|
||||
$existingReadby = $reply['readby'] ?? [];
|
||||
$reply['readby'] = array_values(array_unique(array_merge($existingReadby, $readby)));
|
||||
$updated = true;
|
||||
$migrated['replies']++;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($updated) {
|
||||
$file->update(['comments' => $comments]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'project-request':
|
||||
$existingReadby = $project->requestReadby()->yaml() ?? [];
|
||||
$newReadby = array_values(array_unique(array_merge($existingReadby, $readby)));
|
||||
|
||||
$updateData = ['requestReadby' => $newReadby];
|
||||
|
||||
// Migrer aussi les métadonnées si elles n'existent pas encore
|
||||
if ($project->requestAuthor()->isEmpty() && isset($notification['author'])) {
|
||||
$updateData['requestAuthor'] = $notification['author']['uuid'] ?? '';
|
||||
$updateData['requestAuthorName'] = $notification['author']['name'] ?? '';
|
||||
$updateData['requestAuthorEmail'] = $notification['author']['email'] ?? '';
|
||||
$updateData['requestDate'] = $notification['date'] ?? '';
|
||||
}
|
||||
|
||||
$project->update($updateData);
|
||||
$migrated['project-requests']++;
|
||||
break;
|
||||
|
||||
case 'appointment-request':
|
||||
$existingReadby = $project->optimizationReadby()->yaml() ?? [];
|
||||
$newReadby = array_values(array_unique(array_merge($existingReadby, $readby)));
|
||||
|
||||
$updateData = ['optimizationReadby' => $newReadby];
|
||||
|
||||
// Migrer aussi les métadonnées si elles n'existent pas encore
|
||||
if ($project->optimizationAuthor()->isEmpty() && isset($notification['author'])) {
|
||||
$updateData['optimizationAuthor'] = $notification['author']['uuid'] ?? '';
|
||||
$updateData['optimizationAuthorName'] = $notification['author']['name'] ?? '';
|
||||
$updateData['optimizationAuthorEmail'] = $notification['author']['email'] ?? '';
|
||||
$updateData['optimizationDate'] = $notification['date'] ?? '';
|
||||
}
|
||||
|
||||
$project->update($updateData);
|
||||
$migrated['appointment-requests']++;
|
||||
break;
|
||||
|
||||
case 'content':
|
||||
$briefUri = $notification['location']['page']['uri'] ?? null;
|
||||
if (!$briefUri) continue 2;
|
||||
|
||||
$brief = page($briefUri);
|
||||
if (!$brief) continue 2;
|
||||
|
||||
$existingReadby = $brief->validationReadby()->yaml() ?? [];
|
||||
$newReadby = array_values(array_unique(array_merge($existingReadby, $readby)));
|
||||
|
||||
$updateData = ['validationReadby' => $newReadby];
|
||||
|
||||
// Migrer aussi les métadonnées si elles n'existent pas encore
|
||||
if ($brief->validatedBy()->isEmpty() && isset($notification['author'])) {
|
||||
$updateData['validatedBy'] = $notification['author']['uuid'] ?? '';
|
||||
$updateData['validatedByName'] = $notification['author']['name'] ?? '';
|
||||
$updateData['validatedByEmail'] = $notification['author']['email'] ?? '';
|
||||
$updateData['validatedAt'] = $notification['date'] ?? '';
|
||||
}
|
||||
|
||||
$brief->update($updateData);
|
||||
$migrated['content']++;
|
||||
break;
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$migrated['errors'][] = [
|
||||
'project' => $project->title()->value(),
|
||||
'notification_id' => $id ?? 'unknown',
|
||||
'type' => $type ?? 'unknown',
|
||||
'error' => $th->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$total = $migrated['comments'] + $migrated['replies'] +
|
||||
$migrated['project-requests'] + $migrated['appointment-requests'] +
|
||||
$migrated['content'];
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'message' => "Migration terminée. $total notifications migrées.",
|
||||
'details' => $migrated
|
||||
];
|
||||
}
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue