From 77d152f7c13e1e2c3a39da94c1371a77bcefe6a3 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Tue, 27 Feb 2024 11:05:39 +0100
Subject: [PATCH 01/10] feat: wip: add parameters to customise redirection

---
 ...HabilitationsRoles.java => UserRoles.java} |  6 +-
 .../controller/CampaignController.java        | 35 +++++++++
 .../metadata/domain/Campaign.java             |  4 +
 .../metadata/domain/Parameters.java           | 28 +++++++
 .../metadata/domain/Partitioning.java         |  5 ++
 .../metadata/domain/Source.java               |  4 +
 .../metadata/domain/Survey.java               |  4 +
 .../metadata/dto/ParamsDto.java               | 13 ++++
 .../metadata/service/PartitioningService.java |  5 ++
 .../service/impl/PartioningServiceImpl.java   | 22 ++++++
 .../validation/ParameterEnumValid.java        | 27 +++++++
 .../validation/ParameterEnumValidator.java    | 23 ++++++
 .../CheckHabilitationServiceImplOidc.java     |  8 +-
 .../query/service/impl/MoogServiceImpl.java   | 31 ++++----
 .../service/impl/MySurveysServiceImpl.java    |  6 +-
 .../service/QuestioningService.java           |  5 +-
 .../service/impl/QuestioningServiceImpl.java  | 78 ++++++++++++++++---
 17 files changed, 269 insertions(+), 35 deletions(-)
 rename src/main/java/fr/insee/survey/datacollectionmanagement/constants/{CheckHabilitationsRoles.java => UserRoles.java} (60%)
 create mode 100644 src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
 create mode 100644 src/main/java/fr/insee/survey/datacollectionmanagement/metadata/dto/ParamsDto.java
 create mode 100644 src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java
 create mode 100644 src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java

diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/constants/CheckHabilitationsRoles.java b/src/main/java/fr/insee/survey/datacollectionmanagement/constants/UserRoles.java
similarity index 60%
rename from src/main/java/fr/insee/survey/datacollectionmanagement/constants/CheckHabilitationsRoles.java
rename to src/main/java/fr/insee/survey/datacollectionmanagement/constants/UserRoles.java
index 365f581e..df7c0020 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/constants/CheckHabilitationsRoles.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/constants/UserRoles.java
@@ -1,6 +1,10 @@
 package fr.insee.survey.datacollectionmanagement.constants;
 
-public class CheckHabilitationsRoles {
+public class UserRoles {
+
+    private UserRoles() {
+        throw new IllegalStateException("Utility class");
+    }
     public static final String INTERVIEWER = "interviewer";
     public static final String REVIEWER = "reviewer";
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
index 2299032a..535ce244 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
@@ -5,11 +5,13 @@
 import fr.insee.survey.datacollectionmanagement.exception.NotFoundException;
 import fr.insee.survey.datacollectionmanagement.exception.NotMatchException;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Campaign;
+import fr.insee.survey.datacollectionmanagement.metadata.domain.Parameters;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Partitioning;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Survey;
 import fr.insee.survey.datacollectionmanagement.metadata.dto.CampaignDto;
 import fr.insee.survey.datacollectionmanagement.metadata.dto.CampaignPartitioningsDto;
 import fr.insee.survey.datacollectionmanagement.metadata.dto.OnGoingDto;
+import fr.insee.survey.datacollectionmanagement.metadata.dto.ParamsDto;
 import fr.insee.survey.datacollectionmanagement.metadata.service.CampaignService;
 import fr.insee.survey.datacollectionmanagement.metadata.service.SurveyService;
 import fr.insee.survey.datacollectionmanagement.questioning.domain.Upload;
@@ -108,7 +110,28 @@ public ResponseEntity<CampaignDto> getCampaign(@PathVariable("id") String id) {
 
 
     }
+    @Operation(summary = "Get campaign parameters")
+    @GetMapping(value = "/api/campaigns/{id}/params", produces = "application/json")
+    public ResponseEntity<List<ParamsDto>> getParams(@PathVariable("id") String id) {
+        Campaign campaign = campaignService.findById(StringUtils.upperCase(id));
+        List<ParamsDto> listParams = campaign.getParams().stream().map(this::convertToDto).toList();
+        return ResponseEntity.ok().body(listParams);
+    }
 
+
+    @Operation(summary = "Create a parameter for a campaign")
+    @PutMapping(value = "/api/campaigns/{id}/params", produces = "application/json")
+    public void  putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsDto paramsDto) {
+        Campaign campaign = campaignService.findById(StringUtils.upperCase(id));
+       Parameters param = convertToEntity(paramsDto);
+        param.setMetadataId(StringUtils.upperCase(id));
+       Set<Parameters> setParams = campaign.getParams();
+       setParams.add(param);
+       campaign.setParams(setParams);
+       campaignService.insertOrUpdateCampaign(campaign);
+
+
+    }
     @Operation(summary = "Update or create a campaign")
     @PutMapping(value = Constants.API_CAMPAIGNS_ID, produces = "application/json", consumes = "application/json")
     @ApiResponses(value = {
@@ -189,6 +212,10 @@ private CampaignDto convertToDto(Campaign campaign) {
         return modelmapper.map(campaign, CampaignDto.class);
     }
 
+    private ParamsDto convertToDto(Parameters params) {
+        return modelmapper.map(params, ParamsDto.class);
+    }
+
     private CampaignPartitioningsDto convertToCampaignPartitioningsDto(Campaign campaign) {
         return modelmapper.map(campaign, CampaignPartitioningsDto.class);
     }
@@ -197,6 +224,14 @@ private Campaign convertToEntity(CampaignDto campaignDto) {
         return modelmapper.map(campaignDto, Campaign.class);
     }
 
+    private Parameters convertToEntity(ParamsDto paramsDto) {
+
+        Parameters params = modelmapper.map(paramsDto, Parameters.class);
+        params.setParamId(Parameters.ParameterEnum.valueOf(paramsDto.getParamId()));
+
+        return params;
+    }
+
     class CampaignPage extends PageImpl<CampaignDto> {
 
         public CampaignPage(List<CampaignDto> content, Pageable pageable, long total) {
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Campaign.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Campaign.java
index 26a15a1d..9f533506 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Campaign.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Campaign.java
@@ -33,6 +33,10 @@ public class Campaign {
     @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
     private Set<Partitioning> partitionings;
 
+    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+    @Enumerated(EnumType.STRING)
+    private Set<Parameters> params;
+
     @ManyToOne
     private Survey survey;
 
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
new file mode 100644
index 00000000..a893684c
--- /dev/null
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
@@ -0,0 +1,28 @@
+package fr.insee.survey.datacollectionmanagement.metadata.domain;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.Id;
+import lombok.Getter;
+import lombok.Setter;
+
+@Entity
+@Getter
+@Setter
+public class Parameters {
+
+    @Getter
+    public enum ParameterEnum {
+        URL_REDIRECTION,URL_TYPE;
+    }
+
+    @Id
+    private String metadataId;
+
+    @Id
+    @Enumerated(EnumType.STRING)
+    private ParameterEnum paramId;
+    private String paramValue;
+
+}
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Partitioning.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Partitioning.java
index 29c661a2..f3bb0ab1 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Partitioning.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Partitioning.java
@@ -5,6 +5,7 @@
 import lombok.Setter;
 
 import java.util.Date;
+import java.util.Set;
 
 @Entity
 @Getter
@@ -24,4 +25,8 @@ public class Partitioning {
     @ManyToOne
     private Campaign campaign;
 
+    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+    @Enumerated(EnumType.STRING)
+    private Set<Parameters> params;
+
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Source.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Source.java
index 8e47519a..ea11e59a 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Source.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Source.java
@@ -37,4 +37,8 @@ public class Source {
     @NonNull
     private Support support;
 
+    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+    @Enumerated(EnumType.STRING)
+    private Set<Parameters> params;
+
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Survey.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Survey.java
index 2d65b999..3e80e42d 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Survey.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Survey.java
@@ -39,6 +39,10 @@ public class Survey {
     @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
     private Set<Campaign> campaigns;
 
+    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+    @Enumerated(EnumType.STRING)
+    private Set<Parameters> params;
+
     @ManyToOne
     private Source source;
 
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/dto/ParamsDto.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/dto/ParamsDto.java
new file mode 100644
index 00000000..fda19559
--- /dev/null
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/dto/ParamsDto.java
@@ -0,0 +1,13 @@
+package fr.insee.survey.datacollectionmanagement.metadata.dto;
+
+import fr.insee.survey.datacollectionmanagement.metadata.validation.ParameterEnumValid;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ParamsDto {
+    @ParameterEnumValid
+    private String paramId;
+    private String paramValue;
+}
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/PartitioningService.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/PartitioningService.java
index 88d46070..60bbea05 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/PartitioningService.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/PartitioningService.java
@@ -1,5 +1,6 @@
 package fr.insee.survey.datacollectionmanagement.metadata.service;
 
+import fr.insee.survey.datacollectionmanagement.metadata.domain.Parameters;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Partitioning;
 
 import java.util.Date;
@@ -14,4 +15,8 @@ public interface PartitioningService {
 
     boolean isOnGoing(Partitioning part, Date date);
 
+    String findSuitableParameterValue(Partitioning part, Parameters.ParameterEnum paramValue);
+
+
+
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/impl/PartioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/impl/PartioningServiceImpl.java
index e1972d07..c643451f 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/impl/PartioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/service/impl/PartioningServiceImpl.java
@@ -1,6 +1,7 @@
 package fr.insee.survey.datacollectionmanagement.metadata.service.impl;
 
 import fr.insee.survey.datacollectionmanagement.exception.NotFoundException;
+import fr.insee.survey.datacollectionmanagement.metadata.domain.Parameters;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Partitioning;
 import fr.insee.survey.datacollectionmanagement.metadata.repository.PartitioningRepository;
 import fr.insee.survey.datacollectionmanagement.metadata.service.PartitioningService;
@@ -9,6 +10,8 @@
 import org.springframework.stereotype.Service;
 
 import java.util.Date;
+import java.util.Optional;
+import java.util.Set;
 
 @Service
 @Slf4j
@@ -40,4 +43,23 @@ public void deletePartitioningById(String id) {
     public boolean isOnGoing(Partitioning part, Date date) {
         return part.getClosingDate().compareTo(date) > 0 && part.getOpeningDate().compareTo(date) < 0;
     }
+
+    @Override
+    public String findSuitableParameterValue(Partitioning part, Parameters.ParameterEnum paramValue) {
+        return findParameterValueInSet(part.getParams(), paramValue)
+                .orElse(findParameterValueInSet(part.getCampaign().getParams(), paramValue)
+                        .orElse(findParameterValueInSet(part.getCampaign().getSurvey().getParams(), paramValue)
+                                .orElse(findParameterValueInSet(part.getCampaign().getSurvey().getSource().getParams(), paramValue)
+                                        .orElse(""))));
+    }
+
+    private Optional<String> findParameterValueInSet(Set<Parameters> params, Parameters.ParameterEnum paramValue) {
+        return params.stream()
+                .filter(param -> param.getParamId().equals(paramValue))
+                .map(Parameters::getParamValue)
+                .findFirst();
+    }
+
+
+
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java
new file mode 100644
index 00000000..2fc42ab1
--- /dev/null
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java
@@ -0,0 +1,27 @@
+package fr.insee.survey.datacollectionmanagement.metadata.validation;
+
+import fr.insee.survey.datacollectionmanagement.contact.validation.ContactGenderValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+
+@Target({FIELD, PARAMETER, METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(validatedBy = ContactGenderValidator.class)
+public @interface ParameterEnumValid {
+    //error message
+    String message() default "Type missing or not recognized. Only URL_REDIRECTION,URL_TYPE are valid";
+
+    //represents group of constraints
+    Class<?>[] groups() default {};
+
+    //represents additional information about annotation
+    Class<? extends Payload>[] payload() default {};
+}
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java
new file mode 100644
index 00000000..bd4d01b8
--- /dev/null
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java
@@ -0,0 +1,23 @@
+package fr.insee.survey.datacollectionmanagement.metadata.validation;
+
+import fr.insee.survey.datacollectionmanagement.contact.domain.ContactEvent;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+import java.util.Arrays;
+
+public class ParameterEnumValidator implements ConstraintValidator<ParameterEnumValid, String> {
+
+
+    @Override
+    public void initialize(ParameterEnumValid constraintAnnotation) {
+        ConstraintValidator.super.initialize(constraintAnnotation);
+    }
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext context) {
+        if (value == null)
+            return false;
+        return Arrays.stream(ContactEvent.ContactEventType.values()).anyMatch(v -> value.equalsIgnoreCase(v.name()));
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/CheckHabilitationServiceImplOidc.java b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/CheckHabilitationServiceImplOidc.java
index 7a6b39a8..2d59e1a0 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/CheckHabilitationServiceImplOidc.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/CheckHabilitationServiceImplOidc.java
@@ -3,7 +3,7 @@
 import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
 import fr.insee.survey.datacollectionmanagement.config.auth.user.AuthUser;
 import fr.insee.survey.datacollectionmanagement.constants.AuthConstants;
-import fr.insee.survey.datacollectionmanagement.constants.CheckHabilitationsRoles;
+import fr.insee.survey.datacollectionmanagement.constants.UserRoles;
 import fr.insee.survey.datacollectionmanagement.exception.NotFoundException;
 import fr.insee.survey.datacollectionmanagement.query.service.CheckHabilitationService;
 import fr.insee.survey.datacollectionmanagement.user.domain.User;
@@ -40,7 +40,7 @@ public boolean checkHabilitation(String role, String idSu, String campaignId, Au
         }
 
         //respondents
-        if (role == null || role.isBlank() || role.equals(CheckHabilitationsRoles.INTERVIEWER)) {
+        if (role == null || role.isBlank() || role.equals(UserRoles.INTERVIEWER)) {
             if (isUserInRole(authUser.getRoles(), applicationConfig.getRoleRespondent())) {
                 boolean habilitated = viewService.countViewByIdentifierIdSuCampaignId(userId.toUpperCase(), idSu, campaignId) != 0;
                 log.info("Check habilitation of interviewer {} for accessing survey-unit {} of campaign {} resulted in {}", userId, idSu, campaignId, habilitated);
@@ -52,7 +52,7 @@ public boolean checkHabilitation(String role, String idSu, String campaignId, Au
 
 
         // internal users
-        if (!role.equals(CheckHabilitationsRoles.REVIEWER)) {
+        if (!role.equals(UserRoles.REVIEWER)) {
             log.warn("User {} - internal user habilitation not found in token - Check habilitation:false", userId);
             return false;
         }
@@ -76,7 +76,7 @@ public boolean checkHabilitation(String role, String idSu, String campaignId, Au
 
 
         }
-        log.warn("Only '{}' and '{}' are accepted as a role in query argument", CheckHabilitationsRoles.REVIEWER, CheckHabilitationsRoles.INTERVIEWER);
+        log.warn("Only '{}' and '{}' are accepted as a role in query argument", UserRoles.REVIEWER, UserRoles.INTERVIEWER);
         return false;
 
     }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java
index 562d5aef..06e6c8a6 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java
@@ -1,13 +1,15 @@
 package fr.insee.survey.datacollectionmanagement.query.service.impl;
 
-import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
 import fr.insee.survey.datacollectionmanagement.config.JSONCollectionWrapper;
+import fr.insee.survey.datacollectionmanagement.constants.UserRoles;
 import fr.insee.survey.datacollectionmanagement.contact.domain.Contact;
 import fr.insee.survey.datacollectionmanagement.contact.service.ContactService;
 import fr.insee.survey.datacollectionmanagement.exception.NotFoundException;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Campaign;
+import fr.insee.survey.datacollectionmanagement.metadata.domain.Parameters;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Partitioning;
 import fr.insee.survey.datacollectionmanagement.metadata.service.CampaignService;
+import fr.insee.survey.datacollectionmanagement.metadata.service.PartitioningService;
 import fr.insee.survey.datacollectionmanagement.query.domain.MoogCampaign;
 import fr.insee.survey.datacollectionmanagement.query.dto.MoogExtractionRowDto;
 import fr.insee.survey.datacollectionmanagement.query.dto.MoogQuestioningEventDto;
@@ -22,7 +24,10 @@
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
 
 @Service
 @Slf4j
@@ -41,7 +46,7 @@ public class MoogServiceImpl implements MoogService {
 
     private final QuestioningService questioningService;
 
-    private final ApplicationConfig applicationConfig;
+    private final PartitioningService partitioningService;
 
     @Override
     public List<View> moogSearch(String field) {
@@ -58,7 +63,7 @@ public List<MoogSearchDto> transformListViewToListMoogSearchDto(List<View> listV
             MoogSearchDto moogSearchDto = new MoogSearchDto();
             Contact c = contactService.findByIdentifier(view.getIdentifier());
             Campaign camp = campaignService.findById(view.getCampaignId());
-             MoogCampaign moogCampaign = new MoogCampaign();
+            MoogCampaign moogCampaign = new MoogCampaign();
             moogCampaign.setId(view.getCampaignId());
             moogCampaign.setLabel(camp.getCampaignWording());
             moogCampaign
@@ -108,19 +113,15 @@ public Collection<MoogExtractionRowDto> getSurveyUnitsToFollowUp(String idCampai
     public String getReadOnlyUrl(String idCampaign, String surveyUnitId) throws NotFoundException {
         Campaign campaign = campaignService.findById(idCampaign);
         Set<Partitioning> setParts = campaign.getPartitionings();
-        Questioning questioning = null;
-        for (Partitioning part : setParts){
-            Questioning qTemp = questioningService.findByIdPartitioningAndSurveyUnitIdSu(part.getId(), surveyUnitId);
-            if(qTemp!=null){
-                questioning =qTemp;
-                break;
+        for (Partitioning part : setParts) {
+            Questioning questioning = questioningService.findByIdPartitioningAndSurveyUnitIdSu(part.getId(), surveyUnitId);
+            if (questioning != null) {
+                String accessBaseUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_REDIRECTION);
+                String typeUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_TYPE);
+                return questioningService.getAccessUrl(accessBaseUrl, typeUrl, UserRoles.REVIEWER, questioning, surveyUnitId);
             }
         }
-        if(questioning!=null) {
-            return applicationConfig.getQuestioningUrl() + READONLY_QUESTIONNAIRE + questioning.getModelName()
-                    + UNITE_ENQUETEE + surveyUnitId;
-        }
-        String msg = "0 questioning found for campaign "+idCampaign+" and survey unit "+ surveyUnitId;
+        String msg = "0 questioning found for campaign " + idCampaign + " and survey unit " + surveyUnitId;
         log.error(msg);
         throw new NotFoundException(msg);
     }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java
index aa55bd8c..5c23b3d9 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java
@@ -1,5 +1,7 @@
 package fr.insee.survey.datacollectionmanagement.query.service.impl;
 
+import fr.insee.survey.datacollectionmanagement.constants.UserRoles;
+import fr.insee.survey.datacollectionmanagement.metadata.domain.Parameters;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Partitioning;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Survey;
 import fr.insee.survey.datacollectionmanagement.metadata.service.PartitioningService;
@@ -48,8 +50,10 @@ public List<MyQuestioningDto> getListMySurveys(String id) {
             String surveyUnitId = questioning.getSurveyUnit().getIdSu();
             surveyDto.setSurveyWording(survey.getLongWording());
             surveyDto.setSurveyObjectives(survey.getLongObjectives());
+            String accessBaseUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_REDIRECTION);
+            String typeUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_TYPE);
             surveyDto.setAccessUrl(
-                    questioningService.getAccessUrl(questioning, surveyUnitId));
+                    questioningService.getAccessUrl(accessBaseUrl,typeUrl, UserRoles.INTERVIEWER, questioning, surveyUnitId));
             surveyDto.setIdentificationCode(surveyUnitId);
             surveyDto.setOpeningDate(new Timestamp(part.getOpeningDate().getTime()));
             surveyDto.setClosingDate(new Timestamp(part.getClosingDate().getTime()));
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java
index cd35e88d..12cec915 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java
@@ -23,7 +23,7 @@ public interface QuestioningService {
 
     /**
      * Delete questionings attached to one partitioning
-     * 
+     *
      * @param partitioning
      * @return nb questioning deleted
      */
@@ -31,8 +31,7 @@ public interface QuestioningService {
 
     public Set<Questioning> findBySurveyUnitIdSu(String idSu);
 
-    public String getAccessUrl(Questioning questioning, String surveyUnitId);
-
+    public String getAccessUrl(String baseUrl, String typeUrl, String role, Questioning questioning, String surveyUnitId);
 
 
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
index bce0bfd7..94bd0530 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
@@ -1,6 +1,7 @@
 package fr.insee.survey.datacollectionmanagement.questioning.service.impl;
 
 import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
+import fr.insee.survey.datacollectionmanagement.constants.UserRoles;
 import fr.insee.survey.datacollectionmanagement.exception.NotFoundException;
 import fr.insee.survey.datacollectionmanagement.metadata.domain.Partitioning;
 import fr.insee.survey.datacollectionmanagement.questioning.domain.Questioning;
@@ -11,6 +12,7 @@
 import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningService;
 import fr.insee.survey.datacollectionmanagement.questioning.service.SurveyUnitService;
 import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
@@ -56,6 +58,13 @@ public Set<Questioning> findByIdPartitioning(String idPartitioning) {
         return questioningRepository.findByIdPartitioning(idPartitioning);
     }
 
+    @Override
+    public Questioning findByIdPartitioningAndSurveyUnitIdSu(String idPartitioning,
+                                                             String surveyUnitIdSu) {
+        return questioningRepository.findByIdPartitioningAndSurveyUnitIdSu(idPartitioning,
+                surveyUnitIdSu);
+    }
+
     @Override
     public int deleteQuestioningsOfOnePartitioning(Partitioning partitioning) {
         int nbQuestioningDeleted = 0;
@@ -66,7 +75,7 @@ public int deleteQuestioningsOfOnePartitioning(Partitioning partitioning) {
             surveyUnitService.saveSurveyUnit(su);
             q.getQuestioningEvents().stream().forEach(qe -> questioningEventService.deleteQuestioningEvent(qe.getId()));
             q.getQuestioningAccreditations().stream()
-                    .forEach(qa -> questioningAccreditationService.deleteAccreditation(qa));
+                    .forEach(questioningAccreditationService::deleteAccreditation);
             deleteQuestioning(q.getId());
             nbQuestioningDeleted++;
         }
@@ -78,18 +87,65 @@ public Set<Questioning> findBySurveyUnitIdSu(String idSu) {
         return questioningRepository.findBySurveyUnitIdSu(idSu);
     }
 
-    @Override
-    public String getAccessUrl(Questioning questioning, String surveyUnitId) {
-        return applicationConfig.getQuestioningUrl() + "/questionnaire/" + questioning.getModelName()
-                + "/unite-enquetee/" + surveyUnitId;
+    /**
+     * Generates an access URL based on the provided parameters.
+     *
+     * @param baseUrl      The base URL for the access.
+     * @param typeUrl      The type of URL (V1 or V2).
+     * @param role          The user role (REVIEWER or INTERVIEWER).
+     * @param questioning   The questioning object.
+     * @param surveyUnitId  The survey unit ID.
+     * @return The generated access URL.
+     */
+    public String getAccessUrl(String baseUrl, String typeUrl, String role, Questioning questioning, String surveyUnitId) {
+        // Set default values if baseUrl or typeUrl is empty
+        baseUrl = StringUtils.defaultIfEmpty(baseUrl, applicationConfig.getQuestioningUrl());
+        typeUrl = StringUtils.defaultIfEmpty(typeUrl, "V2");
+
+        if (typeUrl.equalsIgnoreCase("V1")) {
+            return buildV1Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
+        } else if (typeUrl.equalsIgnoreCase("V2")) {
+            return buildV2Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
+        }
+
+        return "";
     }
 
+    /**
+     * Builds a V1 access URL based on the provided parameters.
+     *
+     * @param baseUrl      The base URL for the access.
+     * @param role          The user role (REVIEWER or INTERVIEWER).
+     * @param campaignId    The campaign ID.
+     * @param surveyUnitId  The survey unit ID.
+     * @return The generated V1 access URL.
+     */
+    private String buildV1Url(String baseUrl, String role, String campaignId, String surveyUnitId) {
+        if (role.equalsIgnoreCase(UserRoles.REVIEWER)) {
+            return baseUrl + "/visualiser/" + campaignId + "/" + surveyUnitId;
+        } else if (role.equalsIgnoreCase(UserRoles.INTERVIEWER)) {
+            return baseUrl + "/repondre/" + campaignId + "/" + surveyUnitId;
+        }
+        return "";
+    }
 
-    @Override
-    public Questioning findByIdPartitioningAndSurveyUnitIdSu(String idPartitioning,
-                                                             String surveyUnitIdSu) {
-        return questioningRepository.findByIdPartitioningAndSurveyUnitIdSu(idPartitioning,
-                surveyUnitIdSu);
+    /**
+     * Builds a V2 access URL based on the provided parameters.
+     *
+     * @param baseUrl      The base URL for the access.
+     * @param role          The user role (REVIEWER or INTERVIEWER).
+     * @param modelName     The model name from the questioning object.
+     * @param surveyUnitId  The survey unit ID.
+     * @return The generated V2 access URL.
+     */
+    private String buildV2Url(String baseUrl, String role, String modelName, String surveyUnitId) {
+        if (role.equalsIgnoreCase(UserRoles.REVIEWER)) {
+            return baseUrl + "/readonly/questionnaire/" + modelName + "/unite-enquetee/" + surveyUnitId;
+        } else if (role.equalsIgnoreCase(UserRoles.INTERVIEWER)) {
+            return baseUrl + "/questionnaire/" + modelName + "/unite-enquetee/" + surveyUnitId;
+        }
+        return "";
     }
 
-}
+
+ }

From 28edad1759fd8c4bb86bc4e103f022524ad3d58c Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Tue, 27 Feb 2024 15:44:48 +0100
Subject: [PATCH 02/10] fix: control validity of parameters

---
 .../controller/CampaignController.java        | 28 +++++++++++++------
 .../metadata/domain/Parameters.java           |  5 ++--
 .../validation/ParameterEnumValid.java        |  3 +-
 .../validation/ParameterEnumValidator.java    |  4 +--
 4 files changed, 24 insertions(+), 16 deletions(-)

diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
index 535ce244..897fce91 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
@@ -39,6 +39,7 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -110,6 +111,7 @@ public ResponseEntity<CampaignDto> getCampaign(@PathVariable("id") String id) {
 
 
     }
+
     @Operation(summary = "Get campaign parameters")
     @GetMapping(value = "/api/campaigns/{id}/params", produces = "application/json")
     public ResponseEntity<List<ParamsDto>> getParams(@PathVariable("id") String id) {
@@ -121,17 +123,26 @@ public ResponseEntity<List<ParamsDto>> getParams(@PathVariable("id") String id)
 
     @Operation(summary = "Create a parameter for a campaign")
     @PutMapping(value = "/api/campaigns/{id}/params", produces = "application/json")
-    public void  putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsDto paramsDto) {
+    public void putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsDto paramsDto) {
         Campaign campaign = campaignService.findById(StringUtils.upperCase(id));
-       Parameters param = convertToEntity(paramsDto);
+        if (paramsDto.getParamId().equalsIgnoreCase(Parameters.ParameterEnum.URL_TYPE.name())
+                && !(paramsDto.getParamValue().equalsIgnoreCase("V1")
+                || paramsDto.getParamValue().equalsIgnoreCase("V2"))) {
+            throw new NotMatchException("Only V1 and V2 are valid values for URL_TYPE");
+        }
+        Parameters param = convertToEntity(paramsDto);
         param.setMetadataId(StringUtils.upperCase(id));
-       Set<Parameters> setParams = campaign.getParams();
-       setParams.add(param);
-       campaign.setParams(setParams);
-       campaignService.insertOrUpdateCampaign(campaign);
-
-
+        Set<Parameters> setParams = new HashSet<>();
+        for (Parameters parameter : campaign.getParams()) {
+            if (!parameter.getParamId().equals(param.getParamId())) {
+                setParams.add(parameter);
+            }
+        }
+        setParams.add(param);
+        campaign.setParams(setParams);
+        campaignService.insertOrUpdateCampaign(campaign);
     }
+
     @Operation(summary = "Update or create a campaign")
     @PutMapping(value = Constants.API_CAMPAIGNS_ID, produces = "application/json", consumes = "application/json")
     @ApiResponses(value = {
@@ -228,7 +239,6 @@ private Parameters convertToEntity(ParamsDto paramsDto) {
 
         Parameters params = modelmapper.map(paramsDto, Parameters.class);
         params.setParamId(Parameters.ParameterEnum.valueOf(paramsDto.getParamId()));
-
         return params;
     }
 
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
index a893684c..1cca9d33 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
@@ -4,12 +4,11 @@
 import jakarta.persistence.EnumType;
 import jakarta.persistence.Enumerated;
 import jakarta.persistence.Id;
+import lombok.Data;
 import lombok.Getter;
-import lombok.Setter;
 
 @Entity
-@Getter
-@Setter
+@Data
 public class Parameters {
 
     @Getter
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java
index 2fc42ab1..471b9487 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValid.java
@@ -1,6 +1,5 @@
 package fr.insee.survey.datacollectionmanagement.metadata.validation;
 
-import fr.insee.survey.datacollectionmanagement.contact.validation.ContactGenderValidator;
 import jakarta.validation.Constraint;
 import jakarta.validation.Payload;
 
@@ -14,7 +13,7 @@
 @Target({FIELD, PARAMETER, METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-@Constraint(validatedBy = ContactGenderValidator.class)
+@Constraint(validatedBy = ParameterEnumValidator.class)
 public @interface ParameterEnumValid {
     //error message
     String message() default "Type missing or not recognized. Only URL_REDIRECTION,URL_TYPE are valid";
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java
index bd4d01b8..4a57206c 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/validation/ParameterEnumValidator.java
@@ -1,6 +1,6 @@
 package fr.insee.survey.datacollectionmanagement.metadata.validation;
 
-import fr.insee.survey.datacollectionmanagement.contact.domain.ContactEvent;
+import fr.insee.survey.datacollectionmanagement.metadata.domain.Parameters;
 import jakarta.validation.ConstraintValidator;
 import jakarta.validation.ConstraintValidatorContext;
 
@@ -18,6 +18,6 @@ public void initialize(ParameterEnumValid constraintAnnotation) {
     public boolean isValid(String value, ConstraintValidatorContext context) {
         if (value == null)
             return false;
-        return Arrays.stream(ContactEvent.ContactEventType.values()).anyMatch(v -> value.equalsIgnoreCase(v.name()));
+        return Arrays.stream(Parameters.ParameterEnum.values()).anyMatch(v -> value.equalsIgnoreCase(v.name()));
     }
 }
\ No newline at end of file

From 8e8126a0fc30dd7911793a72a50ed2d08664add7 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Tue, 19 Mar 2024 11:19:54 +0100
Subject: [PATCH 03/10] feat: add stromae V3

---
 pom.xml                                       |  2 +-
 .../controller/CampaignController.java        |  7 +++++--
 .../metadata/domain/Parameters.java           |  3 +++
 .../service/impl/QuestioningServiceImpl.java  | 21 ++++++++++++++++++-
 4 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 63f090ed..43c7f990 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
 	</parent>
 	<groupId>fr.insee.survey</groupId>
 	<artifactId>platine-management</artifactId>
-	<version>2.1.0</version>
+	<version>2.2.0</version>
 	<name>platine-management</name>
 	<description>REST API for communication between DB and Platine-Management UI and Platine-My-Surveys UI</description>
 	<properties>
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
index 897fce91..0e55420f 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
@@ -112,6 +112,7 @@ public ResponseEntity<CampaignDto> getCampaign(@PathVariable("id") String id) {
 
     }
 
+
     @Operation(summary = "Get campaign parameters")
     @GetMapping(value = "/api/campaigns/{id}/params", produces = "application/json")
     public ResponseEntity<List<ParamsDto>> getParams(@PathVariable("id") String id) {
@@ -127,8 +128,9 @@ public void putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsD
         Campaign campaign = campaignService.findById(StringUtils.upperCase(id));
         if (paramsDto.getParamId().equalsIgnoreCase(Parameters.ParameterEnum.URL_TYPE.name())
                 && !(paramsDto.getParamValue().equalsIgnoreCase("V1")
-                || paramsDto.getParamValue().equalsIgnoreCase("V2"))) {
-            throw new NotMatchException("Only V1 and V2 are valid values for URL_TYPE");
+                || paramsDto.getParamValue().equalsIgnoreCase("V2")
+                || paramsDto.getParamValue().equalsIgnoreCase("V3"))) {
+            throw new NotMatchException("Only V1 and V2 and V3 are valid values for URL_TYPE");
         }
         Parameters param = convertToEntity(paramsDto);
         param.setMetadataId(StringUtils.upperCase(id));
@@ -143,6 +145,7 @@ public void putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsD
         campaignService.insertOrUpdateCampaign(campaign);
     }
 
+
     @Operation(summary = "Update or create a campaign")
     @PutMapping(value = Constants.API_CAMPAIGNS_ID, produces = "application/json", consumes = "application/json")
     @ApiResponses(value = {
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
index 1cca9d33..379bae31 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/domain/Parameters.java
@@ -4,6 +4,7 @@
 import jakarta.persistence.EnumType;
 import jakarta.persistence.Enumerated;
 import jakarta.persistence.Id;
+import jakarta.persistence.*;
 import lombok.Data;
 import lombok.Getter;
 
@@ -22,6 +23,8 @@ public enum ParameterEnum {
     @Id
     @Enumerated(EnumType.STRING)
     private ParameterEnum paramId;
+
+    @Column(length = 2000)
     private String paramValue;
 
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
index 94bd0530..46b5ed8b 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
@@ -87,6 +87,7 @@ public Set<Questioning> findBySurveyUnitIdSu(String idSu) {
         return questioningRepository.findBySurveyUnitIdSu(idSu);
     }
 
+
     /**
      * Generates an access URL based on the provided parameters.
      *
@@ -104,13 +105,19 @@ public String getAccessUrl(String baseUrl, String typeUrl, String role, Question
 
         if (typeUrl.equalsIgnoreCase("V1")) {
             return buildV1Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
-        } else if (typeUrl.equalsIgnoreCase("V2")) {
+        }
+        if (typeUrl.equalsIgnoreCase("V2")) {
             return buildV2Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
         }
+        if (typeUrl.equalsIgnoreCase("V3")) {
+            return buildV3Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
+        }
 
         return "";
     }
 
+
+
     /**
      * Builds a V1 access URL based on the provided parameters.
      *
@@ -147,5 +154,17 @@ private String buildV2Url(String baseUrl, String role, String modelName, String
         return "";
     }
 
+    /**
+     * Builds a V3 access URL based on the provided parameters
+     *
+     * @param baseUrl      The base URL for the access.
+     * @param role          The user role (REVIEWER or INTERVIEWER).
+     * @param modelName     The model name from the questioning object.
+     * @param surveyUnitId  The survey unit ID.
+     * @return The generated V2 access URL.
+     */private String buildV3Url(String baseUrl, String role, String modelName, String surveyUnitId) {
+        //TODO: update with stromae V3
+         return baseUrl;
+    }
 
  }

From dc70922ae1923b7225c94d9bc3907b366fd63510 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Fri, 7 Jun 2024 11:21:12 +0200
Subject: [PATCH 04/10] feat: build V3 stromae URL and refactor

---
 pom.xml                                       |   4 +
 .../controller/CampaignController.java        |  12 +-
 .../query/service/impl/MoogServiceImpl.java   |   3 +-
 .../service/impl/MySurveysServiceImpl.java    |   3 +-
 .../service/QuestioningService.java           |   2 +-
 .../service/impl/QuestioningServiceImpl.java  |  83 ++++----
 .../questioning/util/UrlTypeEnum.java         |   7 +
 .../dummy/QuestioningRepositoryDummy.java     | 181 ++++++++++++++++++
 .../QuestioningAccreditationServiceDummy.java |  35 ++++
 .../dummy/QuestioningEventServiceDummy.java   |  36 ++++
 .../service/dummy/SurveyUnitServiceDummy.java |  50 +++++
 .../impl/QuestioningServiceImplTest.java      | 107 +++++++++++
 12 files changed, 484 insertions(+), 39 deletions(-)
 create mode 100644 src/main/java/fr/insee/survey/datacollectionmanagement/questioning/util/UrlTypeEnum.java
 create mode 100644 src/test/java/fr/insee/survey/datacollectionmanagement/questioning/repository/dummy/QuestioningRepositoryDummy.java
 create mode 100644 src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningAccreditationServiceDummy.java
 create mode 100644 src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningEventServiceDummy.java
 create mode 100644 src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/SurveyUnitServiceDummy.java
 create mode 100644 src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java

diff --git a/pom.xml b/pom.xml
index 3c254393..d4111679 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,10 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-validation</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-web</artifactId>
+		</dependency>
 		<dependency>
 			<groupId>org.modelmapper</groupId>
 			<artifactId>modelmapper</artifactId>
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
index 0e55420f..6753e01f 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
@@ -17,6 +17,7 @@
 import fr.insee.survey.datacollectionmanagement.questioning.domain.Upload;
 import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningService;
 import fr.insee.survey.datacollectionmanagement.questioning.service.UploadService;
+import fr.insee.survey.datacollectionmanagement.questioning.util.UrlTypeEnum;
 import fr.insee.survey.datacollectionmanagement.view.service.ViewService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
@@ -43,6 +44,8 @@
 import java.util.List;
 import java.util.Set;
 
+import static fr.insee.survey.datacollectionmanagement.questioning.util.UrlTypeEnum.*;
+
 @RestController
 @PreAuthorize("@AuthorizeMethodDecider.isInternalUser() "
         + "|| @AuthorizeMethodDecider.isWebClient() "
@@ -127,10 +130,11 @@ public ResponseEntity<List<ParamsDto>> getParams(@PathVariable("id") String id)
     public void putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsDto paramsDto) {
         Campaign campaign = campaignService.findById(StringUtils.upperCase(id));
         if (paramsDto.getParamId().equalsIgnoreCase(Parameters.ParameterEnum.URL_TYPE.name())
-                && !(paramsDto.getParamValue().equalsIgnoreCase("V1")
-                || paramsDto.getParamValue().equalsIgnoreCase("V2")
-                || paramsDto.getParamValue().equalsIgnoreCase("V3"))) {
-            throw new NotMatchException("Only V1 and V2 and V3 are valid values for URL_TYPE");
+                && !(paramsDto.getParamValue().equalsIgnoreCase(V1.name())
+                || paramsDto.getParamValue().equalsIgnoreCase(V2.name())
+                || paramsDto.getParamValue().equalsIgnoreCase(V3.name()))) {
+
+            throw new NotMatchException(String.format("Only %s are valid values for URL_TYPE", UrlTypeEnum.values()));
         }
         Parameters param = convertToEntity(paramsDto);
         param.setMetadataId(StringUtils.upperCase(id));
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java
index 06e6c8a6..4a9a4171 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MoogServiceImpl.java
@@ -118,7 +118,8 @@ public String getReadOnlyUrl(String idCampaign, String surveyUnitId) throws NotF
             if (questioning != null) {
                 String accessBaseUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_REDIRECTION);
                 String typeUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_TYPE);
-                return questioningService.getAccessUrl(accessBaseUrl, typeUrl, UserRoles.REVIEWER, questioning, surveyUnitId);
+                String sourceId = campaign.getSurvey().getSource().getId().toLowerCase();
+                return questioningService.getAccessUrl(accessBaseUrl, typeUrl, UserRoles.REVIEWER, questioning, surveyUnitId, sourceId);
             }
         }
         String msg = "0 questioning found for campaign " + idCampaign + " and survey unit " + surveyUnitId;
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java
index 5c23b3d9..c2755375 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/query/service/impl/MySurveysServiceImpl.java
@@ -52,8 +52,9 @@ public List<MyQuestioningDto> getListMySurveys(String id) {
             surveyDto.setSurveyObjectives(survey.getLongObjectives());
             String accessBaseUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_REDIRECTION);
             String typeUrl = partitioningService.findSuitableParameterValue(part, Parameters.ParameterEnum.URL_TYPE);
+            String sourceId = survey.getSource().getId().toLowerCase();
             surveyDto.setAccessUrl(
-                    questioningService.getAccessUrl(accessBaseUrl,typeUrl, UserRoles.INTERVIEWER, questioning, surveyUnitId));
+                    questioningService.getAccessUrl(accessBaseUrl,typeUrl, UserRoles.INTERVIEWER, questioning, surveyUnitId, sourceId));
             surveyDto.setIdentificationCode(surveyUnitId);
             surveyDto.setOpeningDate(new Timestamp(part.getOpeningDate().getTime()));
             surveyDto.setClosingDate(new Timestamp(part.getClosingDate().getTime()));
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java
index 12cec915..26b250d7 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/QuestioningService.java
@@ -31,7 +31,7 @@ public interface QuestioningService {
 
     public Set<Questioning> findBySurveyUnitIdSu(String idSu);
 
-    public String getAccessUrl(String baseUrl, String typeUrl, String role, Questioning questioning, String surveyUnitId);
+    public String getAccessUrl(String baseUrl, String typeUrl, String role, Questioning questioning, String surveyUnitId, String sourceId);
 
 
 }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
index 46b5ed8b..d4b2fafa 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
@@ -16,9 +16,14 @@
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
+import org.springframework.web.util.UriComponentsBuilder;
 
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Set;
 
+import static fr.insee.survey.datacollectionmanagement.questioning.util.UrlTypeEnum.*;
+
 @Service
 @RequiredArgsConstructor
 public class QuestioningServiceImpl implements QuestioningService {
@@ -33,6 +38,9 @@ public class QuestioningServiceImpl implements QuestioningService {
 
     private final ApplicationConfig applicationConfig;
 
+    private static final String PATH_LOGOUT = "pathLogout";
+    private static final String PATH_ASSISTANCE = "pathAssistance";
+
     @Override
     public Page<Questioning> findAll(Pageable pageable) {
         return questioningRepository.findAll(pageable);
@@ -98,19 +106,19 @@ public Set<Questioning> findBySurveyUnitIdSu(String idSu) {
      * @param surveyUnitId  The survey unit ID.
      * @return The generated access URL.
      */
-    public String getAccessUrl(String baseUrl, String typeUrl, String role, Questioning questioning, String surveyUnitId) {
+    public String getAccessUrl(String baseUrl, String typeUrl, String role, Questioning questioning, String surveyUnitId, String sourceId) {
         // Set default values if baseUrl or typeUrl is empty
         baseUrl = StringUtils.defaultIfEmpty(baseUrl, applicationConfig.getQuestioningUrl());
-        typeUrl = StringUtils.defaultIfEmpty(typeUrl, "V2");
+        typeUrl = StringUtils.defaultIfEmpty(typeUrl, V2.name());
 
-        if (typeUrl.equalsIgnoreCase("V1")) {
+        if (typeUrl.equalsIgnoreCase(V1.name())) {
             return buildV1Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
         }
-        if (typeUrl.equalsIgnoreCase("V2")) {
+        if (typeUrl.equalsIgnoreCase(V2.name())) {
             return buildV2Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
         }
-        if (typeUrl.equalsIgnoreCase("V3")) {
-            return buildV3Url(baseUrl, role, questioning.getModelName(), surveyUnitId);
+        if (typeUrl.equalsIgnoreCase(V3.name())) {
+            return buildV3Url(baseUrl, role, questioning.getModelName(), surveyUnitId, sourceId, questioning.getId());
         }
 
         return "";
@@ -127,44 +135,55 @@ public String getAccessUrl(String baseUrl, String typeUrl, String role, Question
      * @param surveyUnitId  The survey unit ID.
      * @return The generated V1 access URL.
      */
-    private String buildV1Url(String baseUrl, String role, String campaignId, String surveyUnitId) {
+    protected String buildV1Url(String baseUrl, String role, String campaignId, String surveyUnitId) {
+        String url ="";
         if (role.equalsIgnoreCase(UserRoles.REVIEWER)) {
-            return baseUrl + "/visualiser/" + campaignId + "/" + surveyUnitId;
+            url = String.format("%s/visualiser/%s/%s", baseUrl, campaignId, surveyUnitId);
         } else if (role.equalsIgnoreCase(UserRoles.INTERVIEWER)) {
-            return baseUrl + "/repondre/" + campaignId + "/" + surveyUnitId;
+            url = String.format("%s/repondre/%s/%s", baseUrl, campaignId, surveyUnitId);
         }
-        return "";
+        return url;
     }
 
     /**
-     * Builds a V2 access URL based on the provided parameters.
-     *
-     * @param baseUrl      The base URL for the access.
-     * @param role          The user role (REVIEWER or INTERVIEWER).
-     * @param modelName     The model name from the questioning object.
-     * @param surveyUnitId  The survey unit ID.
-     * @return The generated V2 access URL.
+     * Builds a V3 access URL based on the provided parameters
+     * @param baseUrl host url
+     * @param role
+     * @param modelName
+     * @param surveyUnitId
+     * @return The generated V3 access URL.
      */
-    private String buildV2Url(String baseUrl, String role, String modelName, String surveyUnitId) {
-        if (role.equalsIgnoreCase(UserRoles.REVIEWER)) {
-            return baseUrl + "/readonly/questionnaire/" + modelName + "/unite-enquetee/" + surveyUnitId;
-        } else if (role.equalsIgnoreCase(UserRoles.INTERVIEWER)) {
-            return baseUrl + "/questionnaire/" + modelName + "/unite-enquetee/" + surveyUnitId;
+
+    protected String buildV2Url(String baseUrl, String role, String modelName, String surveyUnitId) {
+        String url = "";
+        if (UserRoles.REVIEWER.equalsIgnoreCase(role)) {
+            url = String.format("%s/readonly/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId);
+        } else if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
+            url = String.format("%s/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId);
         }
-        return "";
+        return url;
     }
 
     /**
      * Builds a V3 access URL based on the provided parameters
-     *
-     * @param baseUrl      The base URL for the access.
-     * @param role          The user role (REVIEWER or INTERVIEWER).
-     * @param modelName     The model name from the questioning object.
-     * @param surveyUnitId  The survey unit ID.
-     * @return The generated V2 access URL.
-     */private String buildV3Url(String baseUrl, String role, String modelName, String surveyUnitId) {
-        //TODO: update with stromae V3
-         return baseUrl;
+     * @param baseUrl
+     * @param role
+     * @param modelName
+     * @param surveyUnitId
+     * @param sourceId
+     * @return The generated V3 access URL.
+     */
+    protected String buildV3Url(String baseUrl, String role, String modelName, String surveyUnitId, String sourceId, Long questioningId) {
+        String url = "";
+        if (UserRoles.REVIEWER.equalsIgnoreCase(role)) {
+            url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/readonly/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId)).toUriString();
+        } else if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
+            url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId))
+                    .queryParam(PATH_LOGOUT, "/" + sourceId)
+                    .queryParam(PATH_ASSISTANCE, URLDecoder.decode("/" + sourceId + "/contacter-assistance/auth?questioningId=" + questioningId, StandardCharsets.UTF_8))
+                    .build().toUriString();
+        }
+        return url;
     }
 
  }
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/util/UrlTypeEnum.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/util/UrlTypeEnum.java
new file mode 100644
index 00000000..fe2251cf
--- /dev/null
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/util/UrlTypeEnum.java
@@ -0,0 +1,7 @@
+package fr.insee.survey.datacollectionmanagement.questioning.util;
+
+public enum UrlTypeEnum {
+    V1,
+    V2,
+    V3,
+}
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/repository/dummy/QuestioningRepositoryDummy.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/repository/dummy/QuestioningRepositoryDummy.java
new file mode 100644
index 00000000..625976e1
--- /dev/null
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/repository/dummy/QuestioningRepositoryDummy.java
@@ -0,0 +1,181 @@
+package fr.insee.survey.datacollectionmanagement.questioning.repository.dummy;
+
+import fr.insee.survey.datacollectionmanagement.questioning.domain.Questioning;
+import fr.insee.survey.datacollectionmanagement.questioning.repository.QuestioningRepository;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.repository.query.FluentQuery;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+
+public class QuestioningRepositoryDummy implements QuestioningRepository {
+    @Override
+    public Set<Questioning> findByIdPartitioning(String idPartitioning) {
+        return null;
+    }
+
+    @Override
+    public Questioning findByIdPartitioningAndSurveyUnitIdSu(String idPartitioning, String surveyUnitIdSu) {
+        return null;
+    }
+
+    @Override
+    public Set<Questioning> findBySurveyUnitIdSu(String idSu) {
+        return null;
+    }
+
+    @Override
+    public void flush() {
+
+    }
+
+    @Override
+    public <S extends Questioning> S saveAndFlush(S entity) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> List<S> saveAllAndFlush(Iterable<S> entities) {
+        return null;
+    }
+
+    @Override
+    public void deleteAllInBatch(Iterable<Questioning> entities) {
+
+    }
+
+    @Override
+    public void deleteAllByIdInBatch(Iterable<Long> longs) {
+
+    }
+
+    @Override
+    public void deleteAllInBatch() {
+
+    }
+
+    @Override
+    public Questioning getOne(Long aLong) {
+        return null;
+    }
+
+    @Override
+    public Questioning getById(Long aLong) {
+        return null;
+    }
+
+    @Override
+    public Questioning getReferenceById(Long aLong) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> Optional<S> findOne(Example<S> example) {
+        return Optional.empty();
+    }
+
+    @Override
+    public <S extends Questioning> List<S> findAll(Example<S> example) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> List<S> findAll(Example<S> example, Sort sort) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> Page<S> findAll(Example<S> example, Pageable pageable) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> long count(Example<S> example) {
+        return 0;
+    }
+
+    @Override
+    public <S extends Questioning> boolean exists(Example<S> example) {
+        return false;
+    }
+
+    @Override
+    public <S extends Questioning, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> S save(S entity) {
+        return null;
+    }
+
+    @Override
+    public <S extends Questioning> List<S> saveAll(Iterable<S> entities) {
+        return null;
+    }
+
+    @Override
+    public Optional<Questioning> findById(Long aLong) {
+        return Optional.empty();
+    }
+
+    @Override
+    public boolean existsById(Long aLong) {
+        return false;
+    }
+
+    @Override
+    public List<Questioning> findAll() {
+        return null;
+    }
+
+    @Override
+    public List<Questioning> findAllById(Iterable<Long> longs) {
+        return null;
+    }
+
+    @Override
+    public long count() {
+        return 0;
+    }
+
+    @Override
+    public void deleteById(Long aLong) {
+
+    }
+
+    @Override
+    public void delete(Questioning entity) {
+
+    }
+
+    @Override
+    public void deleteAllById(Iterable<? extends Long> longs) {
+
+    }
+
+    @Override
+    public void deleteAll(Iterable<? extends Questioning> entities) {
+
+    }
+
+    @Override
+    public void deleteAll() {
+
+    }
+
+    @Override
+    public List<Questioning> findAll(Sort sort) {
+        return null;
+    }
+
+    @Override
+    public Page<Questioning> findAll(Pageable pageable) {
+        return null;
+    }
+}
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningAccreditationServiceDummy.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningAccreditationServiceDummy.java
new file mode 100644
index 00000000..d0088fac
--- /dev/null
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningAccreditationServiceDummy.java
@@ -0,0 +1,35 @@
+package fr.insee.survey.datacollectionmanagement.questioning.service.dummy;
+
+import fr.insee.survey.datacollectionmanagement.questioning.domain.QuestioningAccreditation;
+import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningAccreditationService;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+public class QuestioningAccreditationServiceDummy implements QuestioningAccreditationService {
+    @Override
+    public List<QuestioningAccreditation> findByContactIdentifier(String id) {
+        return null;
+    }
+
+    @Override
+    public Page<QuestioningAccreditation> findAll(Pageable pageable) {
+        return null;
+    }
+
+    @Override
+    public QuestioningAccreditation findById(Long id) {
+        return null;
+    }
+
+    @Override
+    public QuestioningAccreditation saveQuestioningAccreditation(QuestioningAccreditation questioningAccreditation) {
+        return null;
+    }
+
+    @Override
+    public void deleteAccreditation(QuestioningAccreditation c) {
+
+    }
+}
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningEventServiceDummy.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningEventServiceDummy.java
new file mode 100644
index 00000000..660a3ebc
--- /dev/null
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/QuestioningEventServiceDummy.java
@@ -0,0 +1,36 @@
+package fr.insee.survey.datacollectionmanagement.questioning.service.dummy;
+
+import fr.insee.survey.datacollectionmanagement.questioning.domain.Questioning;
+import fr.insee.survey.datacollectionmanagement.questioning.domain.QuestioningEvent;
+import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningEventService;
+import fr.insee.survey.datacollectionmanagement.questioning.util.TypeQuestioningEvent;
+
+import java.util.List;
+import java.util.Optional;
+
+public class QuestioningEventServiceDummy implements QuestioningEventService {
+    @Override
+    public QuestioningEvent findbyId(Long id) {
+        return null;
+    }
+
+    @Override
+    public QuestioningEvent saveQuestioningEvent(QuestioningEvent questioningEvent) {
+        return null;
+    }
+
+    @Override
+    public void deleteQuestioningEvent(Long id) {
+
+    }
+
+    @Override
+    public Optional<QuestioningEvent> getLastQuestioningEvent(Questioning questioning, List<TypeQuestioningEvent> events) {
+        return Optional.empty();
+    }
+
+    @Override
+    public List<QuestioningEvent> findbyIdUpload(Long id) {
+        return null;
+    }
+}
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/SurveyUnitServiceDummy.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/SurveyUnitServiceDummy.java
new file mode 100644
index 00000000..63d0c6c7
--- /dev/null
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/dummy/SurveyUnitServiceDummy.java
@@ -0,0 +1,50 @@
+package fr.insee.survey.datacollectionmanagement.questioning.service.dummy;
+
+import fr.insee.survey.datacollectionmanagement.questioning.domain.SurveyUnit;
+import fr.insee.survey.datacollectionmanagement.questioning.service.SurveyUnitService;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+public class SurveyUnitServiceDummy implements SurveyUnitService {
+    @Override
+    public SurveyUnit findbyId(String idSu) {
+        return null;
+    }
+
+    @Override
+    public List<SurveyUnit> findbyIdentificationCode(String identificationCode) {
+        return null;
+    }
+
+    @Override
+    public List<SurveyUnit> findbyIdentificationName(String identificationName) {
+        return null;
+    }
+
+    @Override
+    public Page<SurveyUnit> findAll(Pageable pageable) {
+        return null;
+    }
+
+    @Override
+    public Page<SurveyUnit> findByParameters(String idSu, String identificationCode, String identificationName, Pageable pageable) {
+        return null;
+    }
+
+    @Override
+    public SurveyUnit saveSurveyUnit(SurveyUnit surveyUnit) {
+        return null;
+    }
+
+    @Override
+    public SurveyUnit saveSurveyUnitAndAddress(SurveyUnit surveyUnit) {
+        return null;
+    }
+
+    @Override
+    public void deleteSurveyUnit(String id) {
+
+    }
+}
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
new file mode 100644
index 00000000..c7c15ad3
--- /dev/null
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
@@ -0,0 +1,107 @@
+package fr.insee.survey.datacollectionmanagement.questioning.service.impl;
+
+import fr.insee.survey.datacollectionmanagement.config.ApplicationConfig;
+import fr.insee.survey.datacollectionmanagement.constants.UserRoles;
+import fr.insee.survey.datacollectionmanagement.questioning.repository.QuestioningRepository;
+import fr.insee.survey.datacollectionmanagement.questioning.repository.dummy.QuestioningRepositoryDummy;
+import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningAccreditationService;
+import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningEventService;
+import fr.insee.survey.datacollectionmanagement.questioning.service.SurveyUnitService;
+import fr.insee.survey.datacollectionmanagement.questioning.service.dummy.QuestioningAccreditationServiceDummy;
+import fr.insee.survey.datacollectionmanagement.questioning.service.dummy.QuestioningEventServiceDummy;
+import fr.insee.survey.datacollectionmanagement.questioning.service.dummy.SurveyUnitServiceDummy;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+class QuestioningServiceImplTest {
+
+    QuestioningServiceImpl questioningService;
+
+    @BeforeEach
+    void init() {
+        QuestioningRepository questioningRepository = new QuestioningRepositoryDummy();
+        SurveyUnitService surveyUnitService = new SurveyUnitServiceDummy();
+        QuestioningEventService questioningEventService = new QuestioningEventServiceDummy();
+        QuestioningAccreditationService questioningAccreditationService = new QuestioningAccreditationServiceDummy();
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        questioningService = new QuestioningServiceImpl(questioningRepository, surveyUnitService, questioningEventService, questioningAccreditationService, applicationConfig);
+    }
+
+    @Test
+    @DisplayName("Check the V1 url in interviewer mode")
+    void getV1UrlInterviewer() {
+        String baseUrl = "https://urlBase";
+        String role = UserRoles.INTERVIEWER;
+        String modelName = "m1";
+        String surveyUnitId = "999999999";
+        String url= questioningService.buildV1Url(baseUrl, role, modelName, surveyUnitId);
+        String expected = "https://urlBase/repondre/m1/999999999";
+        Assertions.assertThat(url).isEqualTo(expected);
+    }
+
+    @Test
+    @DisplayName("Check the V1 url in reviewer mode")
+    void getV1UrlReviewer() {
+        String baseUrl = "https://urlBase";
+        String role = UserRoles.REVIEWER;
+        String modelName = "m1";
+        String surveyUnitId = "999999999";
+        String url= questioningService.buildV1Url(baseUrl, role, modelName, surveyUnitId);
+        String expected = "https://urlBase/visualiser/m1/999999999";
+        Assertions.assertThat(url).isEqualTo(expected);
+    }
+
+    @Test
+    @DisplayName("Check the V2 url in interviewer mode")
+    void getV2UrlInterviewer() {
+        String baseUrl = "https://urlBase";
+        String role = UserRoles.INTERVIEWER;
+        String modelName = "model";
+        String surveyUnitId = "999999999";
+        String url= questioningService.buildV2Url(baseUrl, role, modelName, surveyUnitId);
+        String expected = "https://urlBase/questionnaire/model/unite-enquetee/999999999";
+        Assertions.assertThat(url).isEqualTo(expected);
+    }
+
+    @Test
+    @DisplayName("Check the V2 url in reviewer mode")
+    void getV2UrlReviewer() {
+        String baseUrl = "https://urlBase";
+        String role = UserRoles.REVIEWER;
+        String modelName = "model";
+        String surveyUnitId = "999999999";
+        String url= questioningService.buildV2Url(baseUrl, role, modelName, surveyUnitId);
+        String expected = "https://urlBase/readonly/questionnaire/model/unite-enquetee/999999999";
+        Assertions.assertThat(url).isEqualTo(expected);
+    }
+    @Test
+    @DisplayName("Check the V3 url in interviewer mode")
+    void getV3UrlInterviewer() {
+        String baseUrl = "https://urlBase";
+        String role = UserRoles.INTERVIEWER; 
+        String modelName = "model";
+        String surveyUnitId = "999999999";
+        String sourceId = "enq";
+        Long questioningId = Long.valueOf(123456789);
+        String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
+        String expected = "https://urlBase/v3/questionnaire/model/unite-enquetee/999999999?pathLogout=/enq&pathAssistance=/enq/contacter-assistance/auth?questioningId=123456789";
+        Assertions.assertThat(url).isEqualTo(expected);
+    }
+
+    @Test
+    @DisplayName("Check the V3 url in reviewer mode")
+    void getV3UrlReviewer() {
+        String baseUrl = "https://urlBase";
+        String role = UserRoles.REVIEWER;
+        String modelName = "model";
+        String surveyUnitId = "999999999";
+        String sourceId = "enq";
+        Long questioningId = Long.valueOf(123456789);
+        String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
+        String expected = "https://urlBase/v3/readonly/questionnaire/model/unite-enquetee/999999999";
+        Assertions.assertThat(url).isEqualTo(expected);
+    }
+
+}
\ No newline at end of file

From 30f19b599a8e22163aeb11d7587f2fb61d766a15 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Fri, 7 Jun 2024 11:31:33 +0200
Subject: [PATCH 05/10] fix: encoding query params

---
 .../questioning/service/impl/QuestioningServiceImpl.java    | 6 +++---
 .../service/impl/QuestioningServiceImplTest.java            | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
index d4b2fafa..34fb6726 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
@@ -18,7 +18,7 @@
 import org.springframework.stereotype.Service;
 import org.springframework.web.util.UriComponentsBuilder;
 
-import java.net.URLDecoder;
+import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Set;
 
@@ -179,8 +179,8 @@ protected String buildV3Url(String baseUrl, String role, String modelName, Strin
             url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/readonly/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId)).toUriString();
         } else if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
             url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId))
-                    .queryParam(PATH_LOGOUT, "/" + sourceId)
-                    .queryParam(PATH_ASSISTANCE, URLDecoder.decode("/" + sourceId + "/contacter-assistance/auth?questioningId=" + questioningId, StandardCharsets.UTF_8))
+                    .queryParam(PATH_LOGOUT, URLEncoder.encode("/" + sourceId, StandardCharsets.UTF_8))
+                    .queryParam(PATH_ASSISTANCE, URLEncoder.encode("/" + sourceId + "/contacter-assistance/auth?questioningId=" + questioningId, StandardCharsets.UTF_8))
                     .build().toUriString();
         }
         return url;
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
index c7c15ad3..bb4d2618 100644
--- a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
@@ -86,7 +86,7 @@ void getV3UrlInterviewer() {
         String sourceId = "enq";
         Long questioningId = Long.valueOf(123456789);
         String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
-        String expected = "https://urlBase/v3/questionnaire/model/unite-enquetee/999999999?pathLogout=/enq&pathAssistance=/enq/contacter-assistance/auth?questioningId=123456789";
+        String expected = "https://urlBase/v3/questionnaire/model/unite-enquetee/999999999?pathLogout=%2Fenq&pathAssistance=%2Fenq%2Fcontacter-assistance%2Fauth%3FquestioningId%3D123456789";
         Assertions.assertThat(url).isEqualTo(expected);
     }
 

From f2b0c7d6abd759835fffc2ab8eefaa7d0f13984a Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Fri, 7 Jun 2024 13:58:20 +0200
Subject: [PATCH 06/10] build: version 2.3.0

---
 pom.xml | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/pom.xml b/pom.xml
index d4111679..de579a52 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,12 +6,12 @@
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>3.2.4</version>
+		<version>3.3.0</version>
 		<relativePath /> <!-- lookup parent from repository -->
 	</parent>
 	<groupId>fr.insee.survey</groupId>
 	<artifactId>platine-management</artifactId>
-	<version>2.2.3</version>
+	<version>2.3.0</version>
 	<name>platine-management</name>
 	<description>REST API for communication between DB and Platine-Management UI and Platine-My-Surveys UI</description>
 	<properties>
@@ -41,10 +41,6 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-validation</artifactId>
 		</dependency>
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-web</artifactId>
-		</dependency>
 		<dependency>
 			<groupId>org.modelmapper</groupId>
 			<artifactId>modelmapper</artifactId>

From 908ee3cd923ff86b24e533192524a5e7c93a7ccb Mon Sep 17 00:00:00 2001
From: Betty Becuwe <77614323+BettyB979@users.noreply.github.com>
Date: Mon, 10 Jun 2024 13:25:10 +0200
Subject: [PATCH 07/10] Update renovate.json (#65)

fix renovate.json
---
 renovate.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/renovate.json b/renovate.json
index 17869171..1a9060f2 100644
--- a/renovate.json
+++ b/renovate.json
@@ -43,4 +43,3 @@
   "schedule": ["every weekend"],
   "timezone": "Europe/Paris"
 }
-}

From 9c8240c7819b4e7ee0a51c57f8f4d6693b5609b9 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Tue, 11 Jun 2024 13:36:30 +0200
Subject: [PATCH 08/10] fix: change readonly to review for stromae v3

---
 .../questioning/service/impl/QuestioningServiceImpl.java        | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
index 34fb6726..9d488422 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
@@ -176,7 +176,7 @@ protected String buildV2Url(String baseUrl, String role, String modelName, Strin
     protected String buildV3Url(String baseUrl, String role, String modelName, String surveyUnitId, String sourceId, Long questioningId) {
         String url = "";
         if (UserRoles.REVIEWER.equalsIgnoreCase(role)) {
-            url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/readonly/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId)).toUriString();
+            url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/review/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId)).toUriString();
         } else if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
             url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId))
                     .queryParam(PATH_LOGOUT, URLEncoder.encode("/" + sourceId, StandardCharsets.UTF_8))

From 7a0da95bc274fd383c8ff60088c835b9adeb2696 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Wed, 12 Jun 2024 10:35:16 +0200
Subject: [PATCH 09/10] fix: test stromae v3 url in review mode

---
 .../service/impl/QuestioningServiceImplTest.java            | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
index bb4d2618..67f1fad9 100644
--- a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
@@ -84,7 +84,7 @@ void getV3UrlInterviewer() {
         String modelName = "model";
         String surveyUnitId = "999999999";
         String sourceId = "enq";
-        Long questioningId = Long.valueOf(123456789);
+        Long questioningId = 123456789L;
         String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
         String expected = "https://urlBase/v3/questionnaire/model/unite-enquetee/999999999?pathLogout=%2Fenq&pathAssistance=%2Fenq%2Fcontacter-assistance%2Fauth%3FquestioningId%3D123456789";
         Assertions.assertThat(url).isEqualTo(expected);
@@ -98,9 +98,9 @@ void getV3UrlReviewer() {
         String modelName = "model";
         String surveyUnitId = "999999999";
         String sourceId = "enq";
-        Long questioningId = Long.valueOf(123456789);
+        Long questioningId = 123456789L;
         String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
-        String expected = "https://urlBase/v3/readonly/questionnaire/model/unite-enquetee/999999999";
+        String expected = "https://urlBase/v3/review/questionnaire/model/unite-enquetee/999999999";
         Assertions.assertThat(url).isEqualTo(expected);
     }
 

From c476e066d9f55e5cfc44f9e612b32ee5ecfaf284 Mon Sep 17 00:00:00 2001
From: y72wvh <betty.becuwe@insee.fr>
Date: Tue, 18 Jun 2024 10:16:27 +0200
Subject: [PATCH 10/10] refactor: code review by Simon

---
 .../controller/CampaignController.java        | 24 +++++++--------
 .../service/impl/QuestioningServiceImpl.java  | 30 +++++++++----------
 .../impl/QuestioningServiceImplTest.java      | 15 +++++-----
 3 files changed, 34 insertions(+), 35 deletions(-)

diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
index 6753e01f..8cb6139e 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/metadata/controller/CampaignController.java
@@ -17,7 +17,6 @@
 import fr.insee.survey.datacollectionmanagement.questioning.domain.Upload;
 import fr.insee.survey.datacollectionmanagement.questioning.service.QuestioningService;
 import fr.insee.survey.datacollectionmanagement.questioning.service.UploadService;
-import fr.insee.survey.datacollectionmanagement.questioning.util.UrlTypeEnum;
 import fr.insee.survey.datacollectionmanagement.view.service.ViewService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
@@ -40,11 +39,13 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 
-import java.util.HashSet;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
-import static fr.insee.survey.datacollectionmanagement.questioning.util.UrlTypeEnum.*;
+import static fr.insee.survey.datacollectionmanagement.questioning.util.UrlTypeEnum.values;
+import static java.util.stream.Collectors.joining;
 
 @RestController
 @PreAuthorize("@AuthorizeMethodDecider.isInternalUser() "
@@ -129,21 +130,18 @@ public ResponseEntity<List<ParamsDto>> getParams(@PathVariable("id") String id)
     @PutMapping(value = "/api/campaigns/{id}/params", produces = "application/json")
     public void putParams(@PathVariable("id") String id, @RequestBody @Valid ParamsDto paramsDto) {
         Campaign campaign = campaignService.findById(StringUtils.upperCase(id));
+
         if (paramsDto.getParamId().equalsIgnoreCase(Parameters.ParameterEnum.URL_TYPE.name())
-                && !(paramsDto.getParamValue().equalsIgnoreCase(V1.name())
-                || paramsDto.getParamValue().equalsIgnoreCase(V2.name())
-                || paramsDto.getParamValue().equalsIgnoreCase(V3.name()))) {
+                && Arrays.stream(values()).noneMatch(p -> p.name().equalsIgnoreCase(paramsDto.getParamValue()))) {
 
-            throw new NotMatchException(String.format("Only %s are valid values for URL_TYPE", UrlTypeEnum.values()));
+            throw new NotMatchException(String.format("Only %s are valid values for URL_TYPE", Arrays.stream(values()).map(item -> item.name())
+                    .collect(joining(" "))));
         }
         Parameters param = convertToEntity(paramsDto);
         param.setMetadataId(StringUtils.upperCase(id));
-        Set<Parameters> setParams = new HashSet<>();
-        for (Parameters parameter : campaign.getParams()) {
-            if (!parameter.getParamId().equals(param.getParamId())) {
-                setParams.add(parameter);
-            }
-        }
+        Set<Parameters> setParams = campaign.getParams().stream()
+                .filter(parameter -> !parameter.getParamId().equals(param.getParamId()))
+                .collect(Collectors.toSet());
         setParams.add(param);
         campaign.setParams(setParams);
         campaignService.insertOrUpdateCampaign(campaign);
diff --git a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
index 9d488422..453e86ae 100644
--- a/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
+++ b/src/main/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImpl.java
@@ -136,13 +136,13 @@ public String getAccessUrl(String baseUrl, String typeUrl, String role, Question
      * @return The generated V1 access URL.
      */
     protected String buildV1Url(String baseUrl, String role, String campaignId, String surveyUnitId) {
-        String url ="";
         if (role.equalsIgnoreCase(UserRoles.REVIEWER)) {
-            url = String.format("%s/visualiser/%s/%s", baseUrl, campaignId, surveyUnitId);
-        } else if (role.equalsIgnoreCase(UserRoles.INTERVIEWER)) {
-            url = String.format("%s/repondre/%s/%s", baseUrl, campaignId, surveyUnitId);
+            return String.format("%s/visualiser/%s/%s", baseUrl, campaignId, surveyUnitId);
         }
-        return url;
+        if (role.equalsIgnoreCase(UserRoles.INTERVIEWER)) {
+            return String.format("%s/repondre/%s/%s", baseUrl, campaignId, surveyUnitId);
+        }
+        return "";
     }
 
     /**
@@ -155,13 +155,13 @@ protected String buildV1Url(String baseUrl, String role, String campaignId, Stri
      */
 
     protected String buildV2Url(String baseUrl, String role, String modelName, String surveyUnitId) {
-        String url = "";
         if (UserRoles.REVIEWER.equalsIgnoreCase(role)) {
-            url = String.format("%s/readonly/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId);
-        } else if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
-            url = String.format("%s/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId);
+            return String.format("%s/readonly/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId);
+        }
+        if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
+            return String.format("%s/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId);
         }
-        return url;
+        return "";
     }
 
     /**
@@ -174,16 +174,16 @@ protected String buildV2Url(String baseUrl, String role, String modelName, Strin
      * @return The generated V3 access URL.
      */
     protected String buildV3Url(String baseUrl, String role, String modelName, String surveyUnitId, String sourceId, Long questioningId) {
-        String url = "";
         if (UserRoles.REVIEWER.equalsIgnoreCase(role)) {
-            url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/review/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId)).toUriString();
-        } else if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
-            url = UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId))
+            return UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/review/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId)).toUriString();
+        }
+        if (UserRoles.INTERVIEWER.equalsIgnoreCase(role)) {
+            return UriComponentsBuilder.fromHttpUrl(String.format("%s/v3/questionnaire/%s/unite-enquetee/%s", baseUrl, modelName, surveyUnitId))
                     .queryParam(PATH_LOGOUT, URLEncoder.encode("/" + sourceId, StandardCharsets.UTF_8))
                     .queryParam(PATH_ASSISTANCE, URLEncoder.encode("/" + sourceId + "/contacter-assistance/auth?questioningId=" + questioningId, StandardCharsets.UTF_8))
                     .build().toUriString();
         }
-        return url;
+        return "";
     }
 
  }
diff --git a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
index 67f1fad9..ad9c13ad 100644
--- a/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
+++ b/src/test/java/fr/insee/survey/datacollectionmanagement/questioning/service/impl/QuestioningServiceImplTest.java
@@ -10,11 +10,12 @@
 import fr.insee.survey.datacollectionmanagement.questioning.service.dummy.QuestioningAccreditationServiceDummy;
 import fr.insee.survey.datacollectionmanagement.questioning.service.dummy.QuestioningEventServiceDummy;
 import fr.insee.survey.datacollectionmanagement.questioning.service.dummy.SurveyUnitServiceDummy;
-import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 class QuestioningServiceImplTest {
 
     QuestioningServiceImpl questioningService;
@@ -38,7 +39,7 @@ void getV1UrlInterviewer() {
         String surveyUnitId = "999999999";
         String url= questioningService.buildV1Url(baseUrl, role, modelName, surveyUnitId);
         String expected = "https://urlBase/repondre/m1/999999999";
-        Assertions.assertThat(url).isEqualTo(expected);
+        assertThat(url).isEqualTo(expected);
     }
 
     @Test
@@ -50,7 +51,7 @@ void getV1UrlReviewer() {
         String surveyUnitId = "999999999";
         String url= questioningService.buildV1Url(baseUrl, role, modelName, surveyUnitId);
         String expected = "https://urlBase/visualiser/m1/999999999";
-        Assertions.assertThat(url).isEqualTo(expected);
+        assertThat(url).isEqualTo(expected);
     }
 
     @Test
@@ -62,7 +63,7 @@ void getV2UrlInterviewer() {
         String surveyUnitId = "999999999";
         String url= questioningService.buildV2Url(baseUrl, role, modelName, surveyUnitId);
         String expected = "https://urlBase/questionnaire/model/unite-enquetee/999999999";
-        Assertions.assertThat(url).isEqualTo(expected);
+        assertThat(url).isEqualTo(expected);
     }
 
     @Test
@@ -74,7 +75,7 @@ void getV2UrlReviewer() {
         String surveyUnitId = "999999999";
         String url= questioningService.buildV2Url(baseUrl, role, modelName, surveyUnitId);
         String expected = "https://urlBase/readonly/questionnaire/model/unite-enquetee/999999999";
-        Assertions.assertThat(url).isEqualTo(expected);
+        assertThat(url).isEqualTo(expected);
     }
     @Test
     @DisplayName("Check the V3 url in interviewer mode")
@@ -87,7 +88,7 @@ void getV3UrlInterviewer() {
         Long questioningId = 123456789L;
         String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
         String expected = "https://urlBase/v3/questionnaire/model/unite-enquetee/999999999?pathLogout=%2Fenq&pathAssistance=%2Fenq%2Fcontacter-assistance%2Fauth%3FquestioningId%3D123456789";
-        Assertions.assertThat(url).isEqualTo(expected);
+        assertThat(url).isEqualTo(expected);
     }
 
     @Test
@@ -101,7 +102,7 @@ void getV3UrlReviewer() {
         Long questioningId = 123456789L;
         String url= questioningService.buildV3Url(baseUrl, role, modelName, surveyUnitId, sourceId, questioningId);
         String expected = "https://urlBase/v3/review/questionnaire/model/unite-enquetee/999999999";
-        Assertions.assertThat(url).isEqualTo(expected);
+        assertThat(url).isEqualTo(expected);
     }
 
 }
\ No newline at end of file