Skip to content

Commit 1d4aa2b

Browse files
authored
feat: articulation crud (#385)
1 parent 7c1299c commit 1d4aa2b

26 files changed

+2082
-23
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
<groupId>fr.insee</groupId>
1313
<artifactId>Pogues-BO</artifactId>
1414
<packaging>jar</packaging>
15-
<version>4.21.5</version>
15+
<version>4.22.0-SNAPSHOT.1</version>
1616
<name>Pogues-Back-Office</name>
1717

1818
<properties>
1919
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2020
<java.version>21</java.version>
2121
<final.asset.name>pogues-bo</final.asset.name>
22-
<pogues-model.version>1.10.0</pogues-model.version>
22+
<pogues-model.version>1.11.0</pogues-model.version>
2323
<fop.version>2.11</fop.version>
2424
<springdoc-openapi-ui.version>2.8.11</springdoc-openapi-ui.version>
2525
<jacoco.version>0.8.13</jacoco.version>
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package fr.insee.pogues.controller;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import fr.insee.pogues.mapper.ArticulationMapper;
5+
import fr.insee.pogues.mapper.VariablesMapper;
6+
import fr.insee.pogues.model.Articulation;
7+
import fr.insee.pogues.model.VariableType;
8+
import fr.insee.pogues.model.dto.articulations.ArticulationDTO;
9+
import fr.insee.pogues.model.dto.variables.VariableDTO;
10+
import fr.insee.pogues.service.ArticulationService;
11+
import io.swagger.v3.oas.annotations.Operation;
12+
import io.swagger.v3.oas.annotations.media.Content;
13+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
14+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
15+
import io.swagger.v3.oas.annotations.tags.Tag;
16+
import lombok.extern.slf4j.Slf4j;
17+
import org.springframework.http.HttpStatus;
18+
import org.springframework.http.ResponseEntity;
19+
import org.springframework.web.bind.annotation.*;
20+
21+
import java.util.List;
22+
import java.util.UUID;
23+
24+
/**
25+
* <p>WebService class used to fetch and update the articulation of a questionnaire.</p>
26+
* <p>This is available only to questionnaires specified in VTL and with a roundabout.</p>
27+
*/
28+
@RestController
29+
@RequestMapping("/api/persistence")
30+
@Tag(name = "Articulation Controller")
31+
@Slf4j
32+
public class ArticulationController {
33+
34+
private final ArticulationService articulationService;
35+
36+
public ArticulationController(ArticulationService articulationService) {
37+
this.articulationService = articulationService;
38+
}
39+
40+
@Operation(summary = "Get the articulation of a questionnaire, used for pogues frontend",
41+
responses = { @ApiResponse(content = @Content(mediaType = "application/json")) })
42+
@ApiResponses(value = {
43+
@ApiResponse(responseCode = "200", description = "Success"),
44+
@ApiResponse(responseCode = "404", description = "Questionnaire not found"),
45+
@ApiResponse(responseCode = "422", description = "Questionnaire does not have a roundabout"),
46+
@ApiResponse(responseCode = "422", description = "Questionnaire is not in VTL") })
47+
@GetMapping("/questionnaire/{questionnaireId}/articulation")
48+
public ResponseEntity<ArticulationDTO> getQuestionnaireArticulation(
49+
@PathVariable(value = "questionnaireId") String questionnaireId
50+
) throws Exception {
51+
Articulation articulation = articulationService.getQuestionnaireArticulation(questionnaireId);
52+
ArticulationDTO articulationDTO = ArticulationMapper.toDTO(articulation);
53+
return ResponseEntity.status(HttpStatus.OK).body(articulationDTO);
54+
}
55+
56+
@Operation(summary = "Get the articulation of a questionnaire, used for pogues frontend",
57+
responses = { @ApiResponse(content = @Content(mediaType = "application/json")) })
58+
@ApiResponses(value = {
59+
@ApiResponse(responseCode = "200", description = "Success"),
60+
@ApiResponse(responseCode = "404", description = "Questionnaire not found"),
61+
@ApiResponse(responseCode = "422", description = "Questionnaire does not have a roundabout"),
62+
@ApiResponse(responseCode = "422", description = "Questionnaire is not in VTL") })
63+
@GetMapping("/questionnaire/{questionnaireId}/version/{versionId}/articulation")
64+
public ResponseEntity<ArticulationDTO> getQuestionnaireArticulation(
65+
@PathVariable(value = "questionnaireId") String ignoredQuestionnaireId,
66+
@PathVariable(value = "versionId") UUID versionId
67+
) throws Exception {
68+
Articulation articulation = articulationService.getVersionArticulation(versionId);
69+
ArticulationDTO articulationDTO = ArticulationMapper.toDTO(articulation);
70+
return ResponseEntity.status(HttpStatus.OK).body(articulationDTO);
71+
}
72+
73+
@Operation(summary = "Get the questionnaire's roundabout variables, used for pogues frontend",
74+
responses = { @ApiResponse(content = @Content(mediaType = "application/json")) })
75+
@ApiResponses(value = {
76+
@ApiResponse(responseCode = "200", description = "Success"),
77+
@ApiResponse(responseCode = "404", description = "Questionnaire not found"),
78+
@ApiResponse(responseCode = "422", description = "Questionnaire does not have a roundabout"),
79+
@ApiResponse(responseCode = "422", description = "Questionnaire is not in VTL") })
80+
@GetMapping("/questionnaire/{questionnaireId}/articulation/variables")
81+
public ResponseEntity<List<VariableDTO>> getQuestionnaireArticulationVariables(
82+
@PathVariable(value = "questionnaireId") String questionnaireId
83+
) throws Exception {
84+
List<VariableType> variables = articulationService.getQuestionnaireArticulationVariables(questionnaireId);
85+
List<VariableDTO> variablesDTO = variables.stream().map(VariablesMapper::toDTO).toList();
86+
return ResponseEntity.status(HttpStatus.OK).body(variablesDTO);
87+
}
88+
89+
@Operation(summary = "Update or create an articulation in a questionnaire")
90+
@ApiResponses(value = {
91+
@ApiResponse(responseCode = "201", description = "Successfully created"),
92+
@ApiResponse(responseCode = "204", description = "Successfully updated"),
93+
@ApiResponse(responseCode = "404", description = "Questionnaire not found"),
94+
@ApiResponse(responseCode = "422", description = "Questionnaire does not have a roundabout"),
95+
@ApiResponse(responseCode = "422", description = "Questionnaire is not in VTL") })
96+
@PutMapping("/questionnaire/{questionnaireId}/articulation")
97+
public ResponseEntity<JsonNode> upsertQuestionnaireArticulation(
98+
@PathVariable(value = "questionnaireId") String questionnaireId,
99+
@RequestBody ArticulationDTO articulationDTO
100+
) throws Exception {
101+
Articulation articulation = ArticulationMapper.toModel(articulationDTO);
102+
boolean isCreated = articulationService.upsertQuestionnaireArticulation(questionnaireId, articulation);
103+
if (isCreated) {
104+
return ResponseEntity.status(HttpStatus.CREATED).build();
105+
}
106+
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
107+
}
108+
109+
@Operation(summary = "Delete the articulation of a questionnaire")
110+
@ApiResponses(value = {
111+
@ApiResponse(responseCode = "204", description = "Successfully deleted"),
112+
@ApiResponse(responseCode = "404", description = "Questionnaire not found"),
113+
@ApiResponse(responseCode = "422", description = "Questionnaire does not have a roundabout"),
114+
@ApiResponse(responseCode = "422", description = "Questionnaire is not in VTL") })
115+
@DeleteMapping("/questionnaire/{questionnaireId}/articulation")
116+
public ResponseEntity<JsonNode> deleteQuestionnaireArticulation(
117+
@PathVariable(value = "questionnaireId") String questionnaireId
118+
) throws Exception {
119+
articulationService.deleteQuestionnaireArticulation(questionnaireId);
120+
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
121+
}
122+
123+
}

src/main/java/fr/insee/pogues/controller/error/ErrorCode.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ public enum ErrorCode {
44
CODE_LIST_RELATED_QUESTIONS_NAME("codelist:relatedquestions:name"),
55
CODE_LIST_NOT_FOUND("codelist:notfound"),
66
VARIABLE_NOT_FOUND("variable:notfound"),
7-
VARIABLE_INVALID_MODEL("variable:invalidmodel");
7+
VARIABLE_INVALID_MODEL("variable:invalidmodel"),
8+
QUESTIONNAIRE_NOT_FOUND("questionnaire:notfound"),
9+
VERSION_NOT_FOUND("version:notfound"),
10+
QUESTIONNAIRE_FORMULA_LANGUAGE_NOT_VTL("questionnaire:formulalanguage:notvtl"),
11+
QUESTIONNAIRE_ROUNDABOUT_NOT_FOUND("questionnaire:roundaboutnotfound");
812

913
public final String label;
1014

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package fr.insee.pogues.exception;
2+
3+
import static fr.insee.pogues.controller.error.ErrorCode.QUESTIONNAIRE_FORMULA_LANGUAGE_NOT_VTL;
4+
5+
/**
6+
* Exception that is thrown when one tries to use a feature only available to questionnaire whose formula language is VTL.
7+
*/
8+
public class QuestionnaireFormulaLanguageNotVTLException extends PoguesException {
9+
10+
public QuestionnaireFormulaLanguageNotVTLException(String message) {
11+
super(422, message, null, QUESTIONNAIRE_FORMULA_LANGUAGE_NOT_VTL);
12+
}
13+
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fr.insee.pogues.exception;
2+
3+
import static fr.insee.pogues.controller.error.ErrorCode.QUESTIONNAIRE_NOT_FOUND;
4+
5+
/** Exception that is thrown when one tries to access a questionnaire which does not exist. */
6+
public class QuestionnaireNotFoundException extends PoguesException {
7+
8+
public QuestionnaireNotFoundException(String message) {
9+
super(404, message, null, QUESTIONNAIRE_NOT_FOUND);
10+
}
11+
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package fr.insee.pogues.exception;
2+
3+
import static fr.insee.pogues.controller.error.ErrorCode.QUESTIONNAIRE_ROUNDABOUT_NOT_FOUND;
4+
5+
/**
6+
* Exception that is thrown when one tries to use a feature only available to questionnaire which has a roundabout but
7+
* the questionnaire has none.
8+
*/
9+
public class QuestionnaireRoundaboutNotFoundException extends PoguesException {
10+
11+
public QuestionnaireRoundaboutNotFoundException(String message) {
12+
super(422, message, null, QUESTIONNAIRE_ROUNDABOUT_NOT_FOUND);
13+
}
14+
15+
}

src/main/java/fr/insee/pogues/exception/VariableInvalidModelException.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package fr.insee.pogues.exception;
22

3-
import lombok.Getter;
4-
53
import static fr.insee.pogues.controller.error.ErrorCode.VARIABLE_INVALID_MODEL;
64

75
/** Exception that is thrown when one tries to upsert a variable which has an invalid model. */
8-
@Getter
96
public class VariableInvalidModelException extends PoguesException {
107

118
public VariableInvalidModelException(String message, String details) {

src/main/java/fr/insee/pogues/exception/VariableNotFoundException.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package fr.insee.pogues.exception;
22

3-
import lombok.Getter;
4-
53
import static fr.insee.pogues.controller.error.ErrorCode.VARIABLE_NOT_FOUND;
64

75
/** Exception that is thrown when one tries to access a variable which does not exist. */
8-
@Getter
96
public class VariableNotFoundException extends PoguesException {
107

118
public VariableNotFoundException(String message) {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fr.insee.pogues.exception;
2+
3+
import static fr.insee.pogues.controller.error.ErrorCode.VERSION_NOT_FOUND;
4+
5+
/** Exception that is thrown when one tries to access a version which does not exist. */
6+
public class VersionNotFoundException extends PoguesException {
7+
8+
public VersionNotFoundException(String message) {
9+
super(404, message, null, VERSION_NOT_FOUND);
10+
}
11+
12+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package fr.insee.pogues.mapper;
2+
3+
4+
import fr.insee.pogues.model.*;
5+
import fr.insee.pogues.model.dto.articulations.ArticulationDTO;
6+
import fr.insee.pogues.model.dto.articulations.ArticulationItemDTO;
7+
8+
import java.util.List;
9+
10+
public class ArticulationMapper {
11+
12+
private ArticulationMapper() {}
13+
14+
/**
15+
* Compute the articulation into its Pogues model.
16+
* @param articulationDTO Articulation to convert
17+
*/
18+
public static Articulation toModel(ArticulationDTO articulationDTO) {
19+
Articulation articulation = new Articulation();
20+
List<Item> items = articulationDTO.getItems().stream().map(ArticulationMapper::toModel).toList();
21+
articulation.getItems().addAll(items);
22+
return articulation;
23+
}
24+
25+
/**
26+
* Compute the articulation item into its Pogues model, setting its type as VTL.
27+
* @param articulationItemDTO Articulation item to convert
28+
*/
29+
private static Item toModel(ArticulationItemDTO articulationItemDTO) {
30+
Item item = new Item();
31+
item.setLabel(articulationItemDTO.getLabel());
32+
item.setValue(articulationItemDTO.getValue());
33+
item.setType(ValueTypeEnum.VTL);
34+
return item;
35+
}
36+
37+
/**
38+
* Compute the articulation into its DTO
39+
* @param articulation Articulation to convert
40+
*/
41+
public static ArticulationDTO toDTO(Articulation articulation) {
42+
if (articulation == null) return new ArticulationDTO();
43+
44+
List<ArticulationItemDTO> itemsDTO = articulation.getItems().stream().map(ArticulationMapper::toDTO).toList();
45+
return new ArticulationDTO(itemsDTO);
46+
}
47+
48+
private static ArticulationItemDTO toDTO(Item articulationItem) {
49+
return new ArticulationItemDTO(articulationItem.getLabel(), articulationItem.getValue());
50+
}
51+
52+
}

0 commit comments

Comments
 (0)