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>
172 lines
6 KiB
PHP
172 lines
6 KiB
PHP
<?php
|
|
|
|
namespace adrienpayet\notifications\providers;
|
|
|
|
use adrienpayet\notifications\NotificationProvider;
|
|
use Kirby\Cms\Page;
|
|
use Kirby\Cms\User;
|
|
use Kirby\Data\Yaml;
|
|
|
|
/**
|
|
* Provider pour les notifications de type "comment".
|
|
* Collecte les commentaires depuis les fichiers des étapes du projet.
|
|
*/
|
|
class CommentProvider implements NotificationProvider
|
|
{
|
|
public function getType(): string
|
|
{
|
|
return 'comment';
|
|
}
|
|
|
|
public function collect(Page $project, User $user): array
|
|
{
|
|
$notifications = [];
|
|
$userUuid = (string) $user->uuid();
|
|
|
|
// Parcourir toutes les étapes du projet
|
|
foreach ($project->children() as $step) {
|
|
// Parcourir tous les fichiers de chaque étape
|
|
foreach ($step->files() as $file) {
|
|
if ($file->comments()->isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
$comments = Yaml::decode($file->comments()->value());
|
|
if (!is_array($comments)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($comments as $comment) {
|
|
// Ignorer les commentaires de type reply (gérés par ReplyProvider)
|
|
if (($comment['type'] ?? 'comment') === 'comment-reply') {
|
|
continue;
|
|
}
|
|
|
|
// Ne pas notifier l'auteur de son propre commentaire
|
|
$authorUuid = $comment['author']['uuid'] ?? '';
|
|
if ($authorUuid === $userUuid) {
|
|
continue;
|
|
}
|
|
|
|
$readby = $comment['readby'] ?? [];
|
|
|
|
$location = $comment['location'] ?? [];
|
|
// Assurer que location.project existe toujours
|
|
if (!isset($location['project'])) {
|
|
$location['project'] = [
|
|
'uri' => $project->uri(),
|
|
'title' => (string) $project->title(),
|
|
];
|
|
}
|
|
|
|
$notifications[] = [
|
|
'id' => $comment['id'],
|
|
'type' => 'comment',
|
|
'text' => $comment['text'] ?? '',
|
|
'author' => $comment['author'] ?? [],
|
|
'date' => $comment['date'] ?? '',
|
|
'location' => $location,
|
|
'position' => $comment['position'] ?? [],
|
|
'readby' => $readby,
|
|
'isRead' => in_array($userUuid, $readby),
|
|
// Métadonnées pour markAsRead
|
|
'_file' => (string) $file->uuid(),
|
|
'_stepUri' => $step->uri(),
|
|
];
|
|
}
|
|
}
|
|
|
|
// Parcourir aussi les sous-pages (ex: tracks dans virtual-sample)
|
|
foreach ($step->children() as $subPage) {
|
|
foreach ($subPage->files() as $file) {
|
|
if ($file->comments()->isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
$comments = Yaml::decode($file->comments()->value());
|
|
if (!is_array($comments)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($comments as $comment) {
|
|
if (($comment['type'] ?? 'comment') === 'comment-reply') {
|
|
continue;
|
|
}
|
|
|
|
$authorUuid = $comment['author']['uuid'] ?? '';
|
|
if ($authorUuid === $userUuid) {
|
|
continue;
|
|
}
|
|
|
|
$readby = $comment['readby'] ?? [];
|
|
|
|
$location = $comment['location'] ?? [];
|
|
// Assurer que location.project existe toujours
|
|
if (!isset($location['project'])) {
|
|
$location['project'] = [
|
|
'uri' => $project->uri(),
|
|
'title' => (string) $project->title(),
|
|
];
|
|
}
|
|
|
|
$notifications[] = [
|
|
'id' => $comment['id'],
|
|
'type' => 'comment',
|
|
'text' => $comment['text'] ?? '',
|
|
'author' => $comment['author'] ?? [],
|
|
'date' => $comment['date'] ?? '',
|
|
'location' => $location,
|
|
'position' => $comment['position'] ?? [],
|
|
'readby' => $readby,
|
|
'isRead' => in_array($userUuid, $readby),
|
|
'_file' => (string) $file->uuid(),
|
|
'_stepUri' => $subPage->uri(),
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $notifications;
|
|
}
|
|
|
|
public function markAsRead(string $id, array $location, User $user): bool
|
|
{
|
|
$fileUuid = $location['_file'] ?? null;
|
|
if (!$fileUuid) {
|
|
return false;
|
|
}
|
|
|
|
// Trouver le fichier par UUID (peut être avec ou sans préfixe file://)
|
|
$fileUri = str_starts_with($fileUuid, 'file://') ? $fileUuid : 'file://' . $fileUuid;
|
|
$file = kirby()->file($fileUri);
|
|
if (!$file) {
|
|
return false;
|
|
}
|
|
|
|
$comments = Yaml::decode($file->comments()->value());
|
|
if (!is_array($comments)) {
|
|
return false;
|
|
}
|
|
|
|
$userUuid = (string) $user->uuid();
|
|
$updated = false;
|
|
|
|
foreach ($comments as &$comment) {
|
|
if ($comment['id'] === $id) {
|
|
$comment['readby'] = $comment['readby'] ?? [];
|
|
if (!in_array($userUuid, $comment['readby'])) {
|
|
$comment['readby'][] = $userUuid;
|
|
$updated = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($updated) {
|
|
$file->update(['comments' => $comments]);
|
|
}
|
|
|
|
return $updated;
|
|
}
|
|
}
|