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
|
||||
];
|
||||
}
|
||||
];
|
||||
|
|
@ -7,37 +7,26 @@ return [
|
|||
$json = file_get_contents('php://input');
|
||||
$data = json_decode($json);
|
||||
|
||||
$user = kirby()->user();
|
||||
$user = kirby()->user();
|
||||
$project = page($data->projectUri);
|
||||
|
||||
$date = new DateTime();
|
||||
$formattedDate = $date->format(DateTime::ISO8601);
|
||||
|
||||
try {
|
||||
$newProject = $project->update([
|
||||
$project->update([
|
||||
"hasOptimizationRequest" => "true",
|
||||
"optimizationRequestDetails" => esc("De la part de " . kirby()->user()->name() . " (" . kirby()->user()->email() . ") : \n\n" . "Objet : " . $data->subject . "\n" . $data->details)
|
||||
"optimizationRequestDetails" => esc("De la part de " . $user->name() . " (" . $user->email() . ") : \n\n" . "Objet : " . $data->subject . "\n" . $data->details),
|
||||
// Métadonnées pour le système de notifications dérivées
|
||||
"optimizationAuthor" => (string) $user->uuid(),
|
||||
"optimizationAuthorName" => (string) $user->name(),
|
||||
"optimizationAuthorEmail" => (string) $user->email(),
|
||||
"optimizationDate" => $formattedDate,
|
||||
"optimizationReadby" => [],
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
return [
|
||||
"status" => "error",
|
||||
"message" => "Can't update project " . $project->title()->value() . ". " . $th->getMessage() . " in " . $th->getFile() . " line " . $th->getLine()
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$date = new DateTime();
|
||||
$formattedDate = $date->format(DateTime::ISO8601);
|
||||
|
||||
$notificationData = [
|
||||
"location" => [
|
||||
"page" => $newProject
|
||||
],
|
||||
"date" => (string) $formattedDate,
|
||||
"text" => nl2br("Objet : " . $data->subject . "\n" . esc($data->details)),
|
||||
"author" => $user,
|
||||
"id" => Str::uuid(),
|
||||
"type" => "appointment-request",
|
||||
];
|
||||
|
||||
$newProject->createNotification($notificationData);
|
||||
// Note: Les notifications sont maintenant dérivées.
|
||||
// Plus besoin d'appeler createNotification().
|
||||
|
||||
return [
|
||||
"status" => "success",
|
||||
|
|
@ -45,7 +34,7 @@ return [
|
|||
} catch (\Throwable $th) {
|
||||
return [
|
||||
"status" => "error",
|
||||
"message" => "Can't create notification. " . $th->getMessage() . " in " . $th->getFile() . " line " . $th->getLine()
|
||||
"message" => "Can't update project " . $project->title()->value() . ". " . $th->getMessage() . " in " . $th->getFile() . " line " . $th->getLine()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,15 +11,24 @@ return [
|
|||
|
||||
$client = kirby()->user()->client()->toPage()->uuid();
|
||||
|
||||
$date = new DateTime();
|
||||
$formattedDate = $date->format(DateTime::ISO8601);
|
||||
|
||||
$projectData = [
|
||||
"slug" => esc(Str::slug($data->title)),
|
||||
"template" => "project",
|
||||
"template" => "project",
|
||||
"content" => [
|
||||
"title" => esc($data->title),
|
||||
"requestDetails" => esc("Demande de " . kirby()->user()->name() . " (" . kirby()->user()->email() . ") : \n\n" . $data->details),
|
||||
"requestDetails" => esc("Demande de " . $user->name() . " (" . $user->email() . ") : \n\n" . $data->details),
|
||||
"client" => [$client],
|
||||
"isClientRequest" => "true",
|
||||
"isDTLEnabled" => esc($data->isDTLEnabled)
|
||||
"isDTLEnabled" => esc($data->isDTLEnabled),
|
||||
// Métadonnées pour le système de notifications dérivées
|
||||
"requestAuthor" => (string) $user->uuid(),
|
||||
"requestAuthorName" => (string) $user->name(),
|
||||
"requestAuthorEmail" => (string) $user->email(),
|
||||
"requestDate" => $formattedDate,
|
||||
"requestReadby" => [],
|
||||
]
|
||||
];
|
||||
|
||||
|
|
@ -27,21 +36,8 @@ return [
|
|||
try {
|
||||
$newProject = $projects->createChild($projectData);
|
||||
|
||||
$date = new DateTime();
|
||||
$formattedDate = $date->format(DateTime::ISO8601);
|
||||
|
||||
$notificationData = [
|
||||
"location" => [
|
||||
"page" => $newProject
|
||||
],
|
||||
"date" => (string) $formattedDate,
|
||||
"text" => nl2br(esc($data->details)),
|
||||
"author" => $user,
|
||||
"id" => Str::uuid(),
|
||||
"type" => "project-request",
|
||||
];
|
||||
|
||||
$newProject->createNotification($notificationData);
|
||||
// Note: Les notifications sont maintenant dérivées.
|
||||
// Plus besoin d'appeler createNotification().
|
||||
|
||||
return [
|
||||
"status" => "success",
|
||||
|
|
|
|||
|
|
@ -9,27 +9,24 @@ return [
|
|||
|
||||
$page = page($data->briefUri);
|
||||
$project = $page->parent();
|
||||
|
||||
try {
|
||||
$newPage = $page->update([
|
||||
'isValidated' => 'true'
|
||||
]);
|
||||
$user = kirby()->user();
|
||||
|
||||
try {
|
||||
$timezone = new DateTimeZone('Europe/Paris');
|
||||
$dateTime = new DateTime('now', $timezone);
|
||||
|
||||
$notification = [
|
||||
'location' => [
|
||||
'page' => $page,
|
||||
],
|
||||
'date' => $dateTime->format('Y-m-d\TH:i:sP'),
|
||||
'text' => "Nouveau brief",
|
||||
'author' => kirby()->user(),
|
||||
'id' => Str::uuid(),
|
||||
'type' => 'content'
|
||||
];
|
||||
$newPage = $page->update([
|
||||
'isValidated' => 'true',
|
||||
// Métadonnées pour le système de notifications dérivées
|
||||
'validatedBy' => (string) $user->uuid(),
|
||||
'validatedByName' => (string) $user->name(),
|
||||
'validatedByEmail' => (string) $user->email(),
|
||||
'validatedAt' => $dateTime->format('Y-m-d\TH:i:sP'),
|
||||
'validationReadby' => [],
|
||||
]);
|
||||
|
||||
$project->createNotification($notification);
|
||||
// Note: Les notifications sont maintenant dérivées.
|
||||
// Plus besoin d'appeler createNotification().
|
||||
|
||||
return [
|
||||
"success" => "'" . $project->title()->value() . "' brief validated."
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue