diff --git a/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/PrioriteNotification.java b/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/PrioriteNotification.java new file mode 100644 index 0000000..3a7f6ef --- /dev/null +++ b/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/PrioriteNotification.java @@ -0,0 +1,26 @@ +package dev.lions.unionflow.server.api.enums.notification; + +/** + * Énumération des priorités de notifications + * + * @author UnionFlow Team + * @version 3.0 + * @since 2025-01-29 + */ +public enum PrioriteNotification { + CRITIQUE("Critique"), + HAUTE("Haute"), + NORMALE("Normale"), + BASSE("Basse"); + + private final String libelle; + + PrioriteNotification(String libelle) { + this.libelle = libelle; + } + + public String getLibelle() { + return libelle; + } +} + diff --git a/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/TypeNotification.java b/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/TypeNotification.java index 6d4395d..30f30fd 100644 --- a/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/TypeNotification.java +++ b/unionflow-server-api/src/main/java/dev/lions/unionflow/server/api/enums/notification/TypeNotification.java @@ -1,290 +1,26 @@ package dev.lions.unionflow.server.api.enums.notification; /** - * Énumération des types de notifications disponibles dans UnionFlow - * - *
Cette énumération définit les différents types de notifications qui peuvent être envoyées aux
- * utilisateurs de l'application UnionFlow.
+ * Énumération des types de notifications
*
* @author UnionFlow Team
- * @version 1.0
- * @since 2025-01-16
+ * @version 3.0
+ * @since 2025-01-29
*/
public enum TypeNotification {
-
- // === NOTIFICATIONS ÉVÉNEMENTS ===
- NOUVEL_EVENEMENT("Nouvel événement", "evenements", "info", "event", "#FF9800", true, true),
- RAPPEL_EVENEMENT(
- "Rappel d'événement", "evenements", "reminder", "schedule", "#2196F3", true, true),
- EVENEMENT_ANNULE(
- "Événement annulé", "evenements", "warning", "event_busy", "#F44336", true, true),
- EVENEMENT_MODIFIE("Événement modifié", "evenements", "info", "edit", "#FF9800", true, false),
- INSCRIPTION_CONFIRMEE(
- "Inscription confirmée", "evenements", "success", "check_circle", "#4CAF50", true, false),
- INSCRIPTION_REFUSEE(
- "Inscription refusée", "evenements", "error", "cancel", "#F44336", true, false),
- LISTE_ATTENTE(
- "Mis en liste d'attente", "evenements", "info", "hourglass_empty", "#FF9800", true, false),
-
- // === NOTIFICATIONS COTISATIONS ===
- COTISATION_DUE("Cotisation due", "cotisations", "reminder", "payment", "#FF5722", true, true),
- COTISATION_PAYEE("Cotisation payée", "cotisations", "success", "paid", "#4CAF50", true, false),
- COTISATION_RETARD(
- "Cotisation en retard", "cotisations", "warning", "schedule", "#F44336", true, true),
- RAPPEL_COTISATION(
- "Rappel de cotisation", "cotisations", "reminder", "notifications", "#FF9800", true, true),
- PAIEMENT_CONFIRME(
- "Paiement confirmé", "cotisations", "success", "check_circle", "#4CAF50", true, false),
- PAIEMENT_ECHOUE("Paiement échoué", "cotisations", "error", "error", "#F44336", true, true),
-
- // === NOTIFICATIONS SOLIDARITÉ ===
- NOUVELLE_DEMANDE_AIDE(
- "Nouvelle demande d'aide", "solidarite", "info", "help", "#E91E63", false, true),
- DEMANDE_AIDE_APPROUVEE(
- "Demande d'aide approuvée", "solidarite", "success", "thumb_up", "#4CAF50", true, false),
- DEMANDE_AIDE_REFUSEE(
- "Demande d'aide refusée", "solidarite", "error", "thumb_down", "#F44336", true, false),
- AIDE_DISPONIBLE(
- "Aide disponible", "solidarite", "info", "volunteer_activism", "#E91E63", true, false),
- APPEL_SOLIDARITE(
- "Appel à la solidarité", "solidarite", "urgent", "campaign", "#E91E63", true, true),
-
- // === NOTIFICATIONS MEMBRES ===
- NOUVEAU_MEMBRE("Nouveau membre", "membres", "info", "person_add", "#2196F3", false, false),
- ANNIVERSAIRE_MEMBRE(
- "Anniversaire de membre", "membres", "celebration", "cake", "#FF9800", true, false),
- MEMBRE_INACTIF("Membre inactif", "membres", "warning", "person_off", "#FF5722", false, false),
- REACTIVATION_MEMBRE(
- "Réactivation de membre", "membres", "success", "person", "#4CAF50", false, false),
-
- // === NOTIFICATIONS ORGANISATION ===
- ANNONCE_GENERALE("Annonce générale", "organisation", "info", "campaign", "#2196F3", true, true),
- REUNION_PROGRAMMEE("Réunion programmée", "organisation", "info", "groups", "#2196F3", true, true),
- CHANGEMENT_REGLEMENT(
- "Changement de règlement", "organisation", "important", "gavel", "#FF5722", true, true),
- ELECTION_OUVERTE(
- "Élection ouverte", "organisation", "info", "how_to_vote", "#2196F3", true, true),
- RESULTAT_ELECTION("Résultat d'élection", "organisation", "info", "poll", "#4CAF50", true, false),
-
- // === NOTIFICATIONS SYSTÈME ===
- MISE_A_JOUR_APP(
- "Mise à jour disponible", "systeme", "info", "system_update", "#2196F3", true, false),
- MAINTENANCE_PROGRAMMEE(
- "Maintenance programmée", "systeme", "warning", "build", "#FF9800", true, true),
- PROBLEME_TECHNIQUE("Problème technique", "systeme", "error", "error", "#F44336", true, true),
- SAUVEGARDE_REUSSIE("Sauvegarde réussie", "systeme", "success", "backup", "#4CAF50", false, false),
-
- // === NOTIFICATIONS PERSONNALISÉES ===
- MESSAGE_PRIVE("Message privé", "messages", "info", "mail", "#2196F3", true, false),
- MENTION("Mention", "messages", "info", "alternate_email", "#FF9800", true, false),
- COMMENTAIRE("Nouveau commentaire", "messages", "info", "comment", "#2196F3", true, false),
-
- // === NOTIFICATIONS GÉOLOCALISÉES ===
- EVENEMENT_PROXIMITE(
- "Événement à proximité", "geolocalisation", "info", "location_on", "#4CAF50", true, false),
- MEMBRE_PROXIMITE(
- "Membre à proximité", "geolocalisation", "info", "people", "#2196F3", true, false),
- URGENCE_LOCALE("Urgence locale", "geolocalisation", "urgent", "warning", "#F44336", true, true);
+ EMAIL("Email"),
+ SMS("SMS"),
+ PUSH("Push Notification"),
+ IN_APP("Notification In-App"),
+ SYSTEME("Notification Système");
private final String libelle;
- private final String categorie;
- private final String priorite;
- private final String icone;
- private final String couleur;
- private final boolean visibleUtilisateur;
- private final boolean activeeParDefaut;
- /**
- * Constructeur de l'énumération TypeNotification
- *
- * @param libelle Le libellé affiché à l'utilisateur
- * @param categorie La catégorie de la notification
- * @param priorite Le niveau de priorité (info, reminder, warning, error, success, urgent,
- * important, celebration)
- * @param icone L'icône Material Design
- * @param couleur La couleur hexadécimale
- * @param visibleUtilisateur true si visible dans les préférences utilisateur
- * @param activeeParDefaut true si activée par défaut
- */
- TypeNotification(
- String libelle,
- String categorie,
- String priorite,
- String icone,
- String couleur,
- boolean visibleUtilisateur,
- boolean activeeParDefaut) {
+ TypeNotification(String libelle) {
this.libelle = libelle;
- this.categorie = categorie;
- this.priorite = priorite;
- this.icone = icone;
- this.couleur = couleur;
- this.visibleUtilisateur = visibleUtilisateur;
- this.activeeParDefaut = activeeParDefaut;
}
- /**
- * Retourne le libellé de la notification
- *
- * @return Le libellé affiché à l'utilisateur
- */
public String getLibelle() {
return libelle;
}
-
- /**
- * Retourne la catégorie de la notification
- *
- * @return La catégorie (evenements, cotisations, solidarite, etc.)
- */
- public String getCategorie() {
- return categorie;
- }
-
- /**
- * Retourne la priorité de la notification
- *
- * @return Le niveau de priorité
- */
- public String getPriorite() {
- return priorite;
- }
-
- /**
- * Retourne l'icône de la notification
- *
- * @return L'icône Material Design
- */
- public String getIcone() {
- return icone;
- }
-
- /**
- * Retourne la couleur de la notification
- *
- * @return Le code couleur hexadécimal
- */
- public String getCouleur() {
- return couleur;
- }
-
- /**
- * Vérifie si la notification est visible dans les préférences utilisateur
- *
- * @return true si visible dans les préférences
- */
- public boolean isVisibleUtilisateur() {
- return visibleUtilisateur;
- }
-
- /**
- * Vérifie si la notification est activée par défaut
- *
- * @return true si activée par défaut
- */
- public boolean isActiveeParDefaut() {
- return activeeParDefaut;
- }
-
- /**
- * Vérifie si la notification est critique (urgent ou error)
- *
- * @return true si la notification est critique
- */
- public boolean isCritique() {
- return "urgent".equals(priorite) || "error".equals(priorite);
- }
-
- /**
- * Vérifie si la notification est un rappel
- *
- * @return true si c'est un rappel
- */
- public boolean isRappel() {
- return "reminder".equals(priorite);
- }
-
- /**
- * Vérifie si la notification est positive (success ou celebration)
- *
- * @return true si la notification est positive
- */
- public boolean isPositive() {
- return "success".equals(priorite) || "celebration".equals(priorite);
- }
-
- /**
- * Retourne le niveau de priorité numérique pour le tri
- *
- * @return Niveau de priorité (1=urgent, 2=error, 3=warning, 4=important, 5=reminder, 6=info,
- * 7=success, 8=celebration)
- */
- public int getNiveauPriorite() {
- return switch (priorite) {
- case "urgent" -> 1;
- case "error" -> 2;
- case "warning" -> 3;
- case "important" -> 4;
- case "reminder" -> 5;
- case "info" -> 6;
- case "success" -> 7;
- case "celebration" -> 8;
- default -> 6;
- };
- }
-
- /**
- * Retourne le délai d'expiration par défaut en heures
- *
- * @return Délai d'expiration en heures
- */
- public int getDelaiExpirationHeures() {
- return switch (priorite) {
- case "urgent" -> 1; // 1 heure
- case "error" -> 24; // 24 heures
- case "warning" -> 48; // 48 heures
- case "important" -> 72; // 72 heures
- case "reminder" -> 24; // 24 heures
- case "info" -> 168; // 1 semaine
- case "success" -> 48; // 48 heures
- case "celebration" -> 72; // 72 heures
- default -> 168;
- };
- }
-
- /**
- * Vérifie si la notification doit vibrer
- *
- * @return true si la notification doit faire vibrer l'appareil
- */
- public boolean doitVibrer() {
- return isCritique() || isRappel();
- }
-
- /**
- * Vérifie si la notification doit émettre un son
- *
- * @return true si la notification doit émettre un son
- */
- public boolean doitEmettreSon() {
- return isCritique() || isRappel() || "important".equals(priorite);
- }
-
- /**
- * Retourne le canal de notification Android approprié
- *
- * @return L'ID du canal de notification
- */
- public String getCanalNotification() {
- return switch (priorite) {
- case "urgent" -> "URGENT_CHANNEL";
- case "error" -> "ERROR_CHANNEL";
- case "warning" -> "WARNING_CHANNEL";
- case "important" -> "IMPORTANT_CHANNEL";
- case "reminder" -> "REMINDER_CHANNEL";
- case "success" -> "SUCCESS_CHANNEL";
- case "celebration" -> "CELEBRATION_CHANNEL";
- default -> "DEFAULT_CHANNEL";
- };
- }
}
diff --git a/unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/Notification.java b/unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/Notification.java
new file mode 100644
index 0000000..8170d4f
--- /dev/null
+++ b/unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/Notification.java
@@ -0,0 +1,132 @@
+package dev.lions.unionflow.server.entity;
+
+import dev.lions.unionflow.server.api.enums.notification.PrioriteNotification;
+import dev.lions.unionflow.server.api.enums.notification.TypeNotification;
+import jakarta.persistence.*;
+import jakarta.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * Entité Notification pour la gestion des notifications
+ *
+ * @author UnionFlow Team
+ * @version 3.0
+ * @since 2025-01-29
+ */
+@Entity
+@Table(
+ name = "notifications",
+ indexes = {
+ @Index(name = "idx_notification_type", columnList = "type_notification"),
+ @Index(name = "idx_notification_statut", columnList = "statut"),
+ @Index(name = "idx_notification_priorite", columnList = "priorite"),
+ @Index(name = "idx_notification_membre", columnList = "membre_id"),
+ @Index(name = "idx_notification_organisation", columnList = "organisation_id"),
+ @Index(name = "idx_notification_date_envoi", columnList = "date_envoi")
+ })
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@EqualsAndHashCode(callSuper = true)
+public class Notification extends BaseEntity {
+
+ /** Type de notification */
+ @NotNull
+ @Enumerated(EnumType.STRING)
+ @Column(name = "type_notification", nullable = false, length = 30)
+ private TypeNotification typeNotification;
+
+ /** Priorité */
+ @Enumerated(EnumType.STRING)
+ @Builder.Default
+ @Column(name = "priorite", length = 20)
+ private PrioriteNotification priorite = PrioriteNotification.NORMALE;
+
+ /** Statut */
+ @Enumerated(EnumType.STRING)
+ @Builder.Default
+ @Column(name = "statut", length = 30)
+ private dev.lions.unionflow.server.api.enums.notification.StatutNotification statut =
+ dev.lions.unionflow.server.api.enums.notification.StatutNotification.EN_ATTENTE;
+
+ /** Sujet */
+ @Column(name = "sujet", length = 500)
+ private String sujet;
+
+ /** Corps du message */
+ @Column(name = "corps", columnDefinition = "TEXT")
+ private String corps;
+
+ /** Date d'envoi prévue */
+ @Column(name = "date_envoi_prevue")
+ private LocalDateTime dateEnvoiPrevue;
+
+ /** Date d'envoi réelle */
+ @Column(name = "date_envoi")
+ private LocalDateTime dateEnvoi;
+
+ /** Date de lecture */
+ @Column(name = "date_lecture")
+ private LocalDateTime dateLecture;
+
+ /** Nombre de tentatives d'envoi */
+ @Builder.Default
+ @Column(name = "nombre_tentatives", nullable = false)
+ private Integer nombreTentatives = 0;
+
+ /** Message d'erreur (si échec) */
+ @Column(name = "message_erreur", length = 1000)
+ private String messageErreur;
+
+ /** Données additionnelles (JSON) */
+ @Column(name = "donnees_additionnelles", columnDefinition = "TEXT")
+ private String donneesAdditionnelles;
+
+ // Relations
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "membre_id")
+ private Membre membre;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "organisation_id")
+ private Organisation organisation;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "template_id")
+ private TemplateNotification template;
+
+ /** Méthode métier pour vérifier si la notification est envoyée */
+ public boolean isEnvoyee() {
+ return dev.lions.unionflow.server.api.enums.notification.StatutNotification.ENVOYEE.equals(statut);
+ }
+
+ /** Méthode métier pour vérifier si la notification est lue */
+ public boolean isLue() {
+ return dev.lions.unionflow.server.api.enums.notification.StatutNotification.LUE.equals(statut);
+ }
+
+ /** Callback JPA avant la persistance */
+ @PrePersist
+ protected void onCreate() {
+ super.onCreate();
+ if (priorite == null) {
+ priorite = PrioriteNotification.NORMALE;
+ }
+ if (statut == null) {
+ statut = dev.lions.unionflow.server.api.enums.notification.StatutNotification.EN_ATTENTE;
+ }
+ if (nombreTentatives == null) {
+ nombreTentatives = 0;
+ }
+ if (dateEnvoiPrevue == null) {
+ dateEnvoiPrevue = LocalDateTime.now();
+ }
+ }
+}
+
diff --git a/unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/TemplateNotification.java b/unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/TemplateNotification.java
new file mode 100644
index 0000000..5adac3a
--- /dev/null
+++ b/unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/TemplateNotification.java
@@ -0,0 +1,81 @@
+package dev.lions.unionflow.server.entity;
+
+import jakarta.persistence.*;
+import jakarta.validation.constraints.NotBlank;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * Entité TemplateNotification pour les templates de notifications réutilisables
+ *
+ * @author UnionFlow Team
+ * @version 3.0
+ * @since 2025-01-29
+ */
+@Entity
+@Table(
+ name = "templates_notifications",
+ indexes = {
+ @Index(name = "idx_template_code", columnList = "code", unique = true),
+ @Index(name = "idx_template_actif", columnList = "actif")
+ })
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@EqualsAndHashCode(callSuper = true)
+public class TemplateNotification extends BaseEntity {
+
+ /** Code unique du template */
+ @NotBlank
+ @Column(name = "code", unique = true, nullable = false, length = 100)
+ private String code;
+
+ /** Sujet du template */
+ @Column(name = "sujet", length = 500)
+ private String sujet;
+
+ /** Corps du template (texte) */
+ @Column(name = "corps_texte", columnDefinition = "TEXT")
+ private String corpsTexte;
+
+ /** Corps du template (HTML) */
+ @Column(name = "corps_html", columnDefinition = "TEXT")
+ private String corpsHtml;
+
+ /** Variables disponibles (JSON) */
+ @Column(name = "variables_disponibles", columnDefinition = "TEXT")
+ private String variablesDisponibles;
+
+ /** Canaux supportés (JSON array) */
+ @Column(name = "canaux_supportes", length = 500)
+ private String canauxSupportes;
+
+ /** Langue du template */
+ @Column(name = "langue", length = 10)
+ private String langue;
+
+ /** Description */
+ @Column(name = "description", length = 1000)
+ private String description;
+
+ /** Notifications utilisant ce template */
+ @OneToMany(mappedBy = "template", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+ @Builder.Default
+ private List