feat(messaging): module messagerie unifié avec contact policies + member blocks
Refactor complet : fusion de Conversation + Message en un module Messaging unique avec ContactPolicy (règles qui-peut-parler-à-qui) et MemberBlock (blocages utilisateur). - Migration V28 : tables conversations/conversation_participants/messages/ contact_policies/member_blocks - Nouvelles entités : ContactPolicy, ConversationParticipant, MemberBlock (Conversation/Message mises à jour avec relations) - Nouvelles repositories : ContactPolicyRepository, ConversationParticipantRepository, MemberBlockRepository - MessagingResource (nouveau) remplace ConversationResource + MessageResource - MessagingService (nouveau) remplace ConversationService + MessageService avec vérifications appartenance org + policies + blocages avant envoi - Anciens fichiers Conversation/Message Resource/Service/Tests supprimés
This commit is contained in:
@@ -1,95 +1,166 @@
|
||||
package dev.lions.unionflow.server.entity;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.communication.ConversationType;
|
||||
import dev.lions.unionflow.server.api.enums.messagerie.StatutConversation;
|
||||
import dev.lions.unionflow.server.api.enums.messagerie.TypeConversation;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
||||
@DisplayName("Conversation")
|
||||
class ConversationTest {
|
||||
|
||||
private static Membre newMembre() {
|
||||
Membre m = new Membre();
|
||||
m.setId(UUID.randomUUID());
|
||||
m.setNumeroMembre("M1");
|
||||
m.setPrenom("Alpha");
|
||||
m.setNom("Diallo");
|
||||
m.setEmail("alpha@test.com");
|
||||
m.setDateNaissance(LocalDate.now());
|
||||
return m;
|
||||
}
|
||||
|
||||
private static Organisation newOrg() {
|
||||
Organisation org = new Organisation();
|
||||
org.setId(UUID.randomUUID());
|
||||
org.setNom("Tontine Test");
|
||||
return org;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("getters/setters de base")
|
||||
@DisplayName("getters/setters — tous les champs")
|
||||
void gettersSetters() {
|
||||
Conversation c = new Conversation();
|
||||
c.setName("Groupe Test");
|
||||
c.setDescription("Description groupe");
|
||||
c.setType(ConversationType.GROUP);
|
||||
c.setIsMuted(false);
|
||||
c.setIsPinned(true);
|
||||
c.setIsArchived(false);
|
||||
Conversation conv = new Conversation();
|
||||
Organisation org = newOrg();
|
||||
conv.setOrganisation(org);
|
||||
conv.setTypeConversation(TypeConversation.DIRECTE);
|
||||
conv.setStatut(StatutConversation.ACTIVE);
|
||||
conv.setTitre("Discussion");
|
||||
conv.setNombreMessages(5);
|
||||
|
||||
assertThat(c.getName()).isEqualTo("Groupe Test");
|
||||
assertThat(c.getDescription()).isEqualTo("Description groupe");
|
||||
assertThat(c.getType()).isEqualTo(ConversationType.GROUP);
|
||||
assertThat(c.getIsMuted()).isFalse();
|
||||
assertThat(c.getIsPinned()).isTrue();
|
||||
assertThat(c.getIsArchived()).isFalse();
|
||||
assertThat(conv.getOrganisation()).isEqualTo(org);
|
||||
assertThat(conv.getTypeConversation()).isEqualTo(TypeConversation.DIRECTE);
|
||||
assertThat(conv.getStatut()).isEqualTo(StatutConversation.ACTIVE);
|
||||
assertThat(conv.getTitre()).isEqualTo("Discussion");
|
||||
assertThat(conv.getNombreMessages()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("onUpdate (PreUpdate) - met à jour updatedAt via réflexion")
|
||||
void onUpdate_setsUpdatedAt() throws Exception {
|
||||
Conversation c = new Conversation();
|
||||
assertThat(c.getUpdatedAt()).isNull();
|
||||
|
||||
Method onUpdate = Conversation.class.getDeclaredMethod("onUpdate");
|
||||
onUpdate.setAccessible(true);
|
||||
|
||||
LocalDateTime before = LocalDateTime.now().minusSeconds(1);
|
||||
onUpdate.invoke(c);
|
||||
LocalDateTime after = LocalDateTime.now().plusSeconds(1);
|
||||
|
||||
assertThat(c.getUpdatedAt()).isNotNull();
|
||||
assertThat(c.getUpdatedAt()).isAfter(before);
|
||||
assertThat(c.getUpdatedAt()).isBefore(after);
|
||||
@DisplayName("estActive — ACTIVE → true")
|
||||
void estActive_active() {
|
||||
Conversation conv = buildMinimal();
|
||||
conv.setStatut(StatutConversation.ACTIVE);
|
||||
assertThat(conv.estActive()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("onUpdate appelé deux fois met à jour updatedAt à chaque fois")
|
||||
void onUpdate_calledTwice_updatesEachTime() throws Exception {
|
||||
Conversation c = new Conversation();
|
||||
|
||||
Method onUpdate = Conversation.class.getDeclaredMethod("onUpdate");
|
||||
onUpdate.setAccessible(true);
|
||||
|
||||
onUpdate.invoke(c);
|
||||
LocalDateTime first = c.getUpdatedAt();
|
||||
|
||||
// petit délai pour différencier les timestamps
|
||||
Thread.sleep(5);
|
||||
|
||||
onUpdate.invoke(c);
|
||||
LocalDateTime second = c.getUpdatedAt();
|
||||
|
||||
assertThat(second).isAfterOrEqualTo(first);
|
||||
@DisplayName("estActive — ARCHIVEE → false")
|
||||
void estActive_archivee() {
|
||||
Conversation conv = buildMinimal();
|
||||
conv.setStatut(StatutConversation.ARCHIVEE);
|
||||
assertThat(conv.estActive()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("participants initialisé à liste vide")
|
||||
@DisplayName("archiver — passe le statut à ARCHIVEE")
|
||||
void archiver() {
|
||||
Conversation conv = buildMinimal();
|
||||
conv.setStatut(StatutConversation.ACTIVE);
|
||||
conv.archiver();
|
||||
assertThat(conv.getStatut()).isEqualTo(StatutConversation.ARCHIVEE);
|
||||
assertThat(conv.estActive()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("enregistrerNouveauMessage — incrémente le compteur et met à jour la date")
|
||||
void enregistrerNouveauMessage() {
|
||||
Conversation conv = buildMinimal();
|
||||
conv.setNombreMessages(3);
|
||||
conv.enregistrerNouveauMessage();
|
||||
assertThat(conv.getNombreMessages()).isEqualTo(4);
|
||||
assertThat(conv.getDernierMessageAt()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("enregistrerNouveauMessage — part de null")
|
||||
void enregistrerNouveauMessage_partDeNull() {
|
||||
Conversation conv = buildMinimal();
|
||||
conv.setNombreMessages(null);
|
||||
conv.enregistrerNouveauMessage();
|
||||
assertThat(conv.getNombreMessages()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("onCreate — initialise statut et nombreMessages si null")
|
||||
void onCreate_initDefaults() {
|
||||
Conversation conv = new Conversation();
|
||||
conv.setOrganisation(newOrg());
|
||||
conv.setTypeConversation(TypeConversation.DIRECTE);
|
||||
|
||||
conv.onCreate();
|
||||
|
||||
assertThat(conv.getStatut()).isEqualTo(StatutConversation.ACTIVE);
|
||||
assertThat(conv.getNombreMessages()).isEqualTo(0);
|
||||
assertThat(conv.getDateCreation()).isNotNull();
|
||||
assertThat(conv.getActif()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("ROLE_CANAL — roleCible renseigné")
|
||||
void roleCanalType() {
|
||||
Conversation conv = buildMinimal();
|
||||
conv.setTypeConversation(TypeConversation.ROLE_CANAL);
|
||||
conv.setRoleCible("TRESORIER");
|
||||
conv.setTitre("Trésorier");
|
||||
|
||||
assertThat(conv.getTypeConversation()).isEqualTo(TypeConversation.ROLE_CANAL);
|
||||
assertThat(conv.getRoleCible()).isEqualTo("TRESORIER");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("participants initialisé à liste vide (builder default)")
|
||||
void participants_initializedEmpty() {
|
||||
Conversation c = new Conversation();
|
||||
assertThat(c.getParticipants()).isNotNull().isEmpty();
|
||||
Conversation conv = Conversation.builder()
|
||||
.organisation(newOrg())
|
||||
.typeConversation(TypeConversation.DIRECTE)
|
||||
.build();
|
||||
assertThat(conv.getParticipants()).isNotNull().isEmpty();
|
||||
assertThat(conv.getMessages()).isNotNull().isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("messages initialisé à liste vide")
|
||||
void messages_initializedEmpty() {
|
||||
Conversation c = new Conversation();
|
||||
assertThat(c.getMessages()).isNotNull().isEmpty();
|
||||
@DisplayName("equals et hashCode")
|
||||
void equalsHashCode() {
|
||||
UUID id = UUID.randomUUID();
|
||||
Organisation org = newOrg();
|
||||
|
||||
Conversation a = buildMinimal();
|
||||
a.setId(id);
|
||||
a.setOrganisation(org);
|
||||
Conversation b = buildMinimal();
|
||||
b.setId(id);
|
||||
b.setOrganisation(org);
|
||||
|
||||
assertThat(a).isEqualTo(b);
|
||||
assertThat(a.hashCode()).isEqualTo(b.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isMuted et isPinned et isArchived défaut false")
|
||||
void defaultFlags_areFalse() {
|
||||
Conversation c = new Conversation();
|
||||
assertThat(c.getIsMuted()).isFalse();
|
||||
assertThat(c.getIsPinned()).isFalse();
|
||||
assertThat(c.getIsArchived()).isFalse();
|
||||
@DisplayName("toString non null")
|
||||
void toString_nonNull() {
|
||||
assertThat(buildMinimal().toString()).isNotNull().isNotEmpty();
|
||||
}
|
||||
|
||||
private Conversation buildMinimal() {
|
||||
Conversation conv = new Conversation();
|
||||
conv.setOrganisation(newOrg());
|
||||
conv.setTypeConversation(TypeConversation.DIRECTE);
|
||||
conv.setStatut(StatutConversation.ACTIVE);
|
||||
conv.setNombreMessages(0);
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user