Commit 0dd5a87c authored by Kevin Robert's avatar Kevin Robert
Browse files

Migration du modèle de données des écrans afin d'ajouter la colonne index et...

Migration du modèle de données des écrans afin d'ajouter la colonne index et de supprimer la colonne previous_id.
parent d954818b
......@@ -79,15 +79,6 @@ public class Screen implements Serializable {
@Column(name = "items", nullable = false)
private String items;
@JsonIgnoreProperties(value = { "previous", "next", "form" }, allowSetters = true)
@OneToOne
@JoinColumn(unique = true)
private Screen previous;
@JsonIgnoreProperties(value = { "previous", "next", "form" }, allowSetters = true)
@OneToOne(mappedBy = "previous")
private Screen next;
@ManyToOne
@JsonIgnoreProperties(value = { "screens", "variables", "workspace" }, allowSetters = true)
private Form form;
......@@ -209,38 +200,6 @@ public class Screen implements Serializable {
this.items = items;
}
public Screen getPrevious() {
return this.previous;
}
public Screen previous(Screen screen) {
this.setPrevious(screen);
return this;
}
public void setPrevious(Screen screen) {
this.previous = screen;
}
public Screen getNext() {
return this.next;
}
public Screen next(Screen screen) {
this.setNext(screen);
return this;
}
public void setNext(Screen screen) {
if (this.next != null) {
this.next.setPrevious(null);
}
if (next != null) {
next.setPrevious(this);
}
this.next = screen;
}
public Form getForm() {
return this.form;
}
......
......@@ -335,4 +335,22 @@ public class NavigationService {
throw new RequiredAnswersMissingException(requiredQuestionsWithoutAnswers);
}
}
/**
* Permet de savoir si un écran est le dernier écran du formulaire.
*
* @return Vrai si l'écran est le dernier écran, sinon faux.
*/
public boolean checkIsLastScreen(final ScreenDTO screenDTO) {
return screenService.findScreenByIndexAndFormId(screenDTO.getNextIndex(), screenDTO.getFormId()).isEmpty();
}
/**
* Permet de savoir si un écran est le premier écran du formulaire.
*
* @return Vrai si l'écran est le premier écran, sinon faux.
*/
public boolean checkIsFirstScreen(final ScreenDTO screenDTO) {
return screenDTO.getIndex() == 1;
}
}
......@@ -12,17 +12,18 @@ import com.unantes.orientactive.service.dto.NextScreenExpressionDTO;
import com.unantes.orientactive.service.dto.ScreenDTO;
import com.unantes.orientactive.service.dto.VariableDTO;
import com.unantes.orientactive.web.rest.errors.UnableToFindNextScreenException;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Ce service contient la logique de navigation d'un écran vers le suivant. Il contient également les méthodes permettants de déterminer si un item doit être affiché.
*/
......@@ -48,8 +49,9 @@ public class ScreenNavigationService {
/**
* Constructure.
* @param screenService {@link #screenService}
* @param answerService {@link #answerService}
*
* @param screenService {@link #screenService}
* @param answerService {@link #answerService}
* @param variableService {@link #variableService}
*/
public ScreenNavigationService(ScreenService screenService, AnswerService answerService, VariableService variableService) {
......@@ -64,15 +66,16 @@ public class ScreenNavigationService {
* Chaque expression de {@link Screen#getNextScreenExpressions()} est évaluée : la première qui est vérifiée donne l'écran suivant.
* Si aucune n'est vérifiée, {@link Screen#getDefaultNextScreenReference()} est utilisé s'il est non vide
* {@link Screen#getNext()} est utilisé en dernier recours.
*
* @param sessionId une session de réponses (l'identifiant commun à toutes les réponses d'un utilisateur)
* @param screen l'écran courant de l'utilisateur
* @param screen l'écran courant de l'utilisateur
* @return
* @throws UnableToFindNextScreenException la méthode a été appelée avec un écran final ou l'expression du screen courant retourne un screen qui n'existe pas
*
*/
public ScreenDTO getNextScreen(final String sessionId, final ScreenDTO screen) throws UnableToFindNextScreenException {
// il ne faut pas appeler cette méthode lorsque l'écran courant est le dernier !
if (screen.getNextId() == null) {
Optional<ScreenDTO> screenDTO = screenService.findScreenByIndexAndFormId(screen.getNextIndex(), screen.getFormId());
if (screenDTO.isEmpty()) {
throw new UnableToFindNextScreenException();
}
// initialisation d'une expression. Elle est utilisée pour evaluer les expressions permettant de déterminer les écrans suivants et pour filter les items affichés dans l'écran suivant.
......@@ -91,8 +94,9 @@ public class ScreenNavigationService {
/**
* Détermine l'écran suivant en fonction des expressions {@link ScreenDTO#getNextScreenExpressions()}.
*
* @param expression le moteur d'expressions SpEL initialisé avec les données de l'utilisateur
* @param screen l'écran courant
* @param screen l'écran courant
* @return
*/
private ScreenDTO getNextScreenFromExpressions(final Expression expression, final ScreenDTO screen) {
......@@ -112,30 +116,33 @@ public class ScreenNavigationService {
/**
* Deux écrans par défaut possibles :
* <ul>
* <li>{@link Screen#getDefaultNextScreenReference()}; utilisé si renseigné</li>
* <li>{@link Screen#getNext()}; champ obligatoire; utilisé pour définir l'ordre en back office et en dernier recours pour l'ordre en front.</li>
* <li>{@link Screen#getDefaultNextScreenReference()}; utilisé si renseigné</li>
* <li>{@link Screen#getNext()}; champ obligatoire; utilisé pour définir l'ordre en back office et en dernier recours pour l'ordre en front.</li>
* </ul>
*
* @param screen
* @return
*/
private ScreenDTO getDefaultNextScreen(final ScreenDTO screen) {
if (StringUtils.isBlank(screen.getDefaultNextScreenReference())) {
return getScreenById(screen.getNextId());
return getScreenByIndexAndFormId(screen.getNextIndex(), screen.getFormId());
}
return getScreenByRef(screen.getDefaultNextScreenReference());
}
/**
* Wrapper de la méthode {@link ScreenService#findOne(Long)}; Jette une exception si l'écran n'existe pas.
*
* @param nextId
* @return
*/
private ScreenDTO getScreenById(final Long nextId) {
return screenService.findOne(nextId).orElseThrow(() -> new UnableToFindNextScreenException("l'écran n'existe pas en base"));
private ScreenDTO getScreenByIndexAndFormId(final Integer index, final Long formId) {
return screenService.findScreenByIndexAndFormId(index, formId).orElseThrow(() -> new UnableToFindNextScreenException("l'écran n'existe pas en base"));
}
/**
* Wrapper de la méthode {@link ScreenService#findOneByReference(String)}; Jette une exception si l'écran n'existe pas.
*
* @param screenRef
* @return
*/
......@@ -147,8 +154,9 @@ public class ScreenNavigationService {
/**
* Filtre les items de l'écran courant en fonction des conditions d'affichage de chaque item.
*
* @param sessionId pour retrouver les réponses de la session courante
* @param screen un écran qui contient les items à filtrer
* @param screen un écran qui contient les items à filtrer
*/
public void filterScreenItems(final String sessionId, final ScreenDTO screen) {
final Expression expression = initializeExpression(screen.getFormId(), sessionId);
......@@ -157,7 +165,8 @@ public class ScreenNavigationService {
/**
* Filtre les items de l'écran courant en fonction des conditions d'affichage de chaque item.
* @param screen un écran qui contient les items à filtrer
*
* @param screen un écran qui contient les items à filtrer
* @param expressionEngine l'expression initialisée avec les réponses de l'utilisateur
*/
protected void filterScreenItems(final ScreenDTO screen, final Expression expressionEngine) {
......@@ -179,7 +188,8 @@ public class ScreenNavigationService {
/**
* Créer une expresison à partir de la session et du formulaire.
* @param formId pour charger les réponses et les variables associés au formulaire
*
* @param formId pour charger les réponses et les variables associés au formulaire
* @param sessionId pour charger les réponses
* @return
*/
......@@ -196,6 +206,7 @@ public class ScreenNavigationService {
/**
* Construit une lambda qui pemet de déterminer si un item doit être affiché dans une écran.
*
* @param expression une expression initialisée avec les réponses de l'utilisateur
* @return
*/
......
package com.unantes.orientactive.repository;
import com.unantes.orientactive.domain.Screen;
import java.util.List;
import java.util.Optional;
import javax.validation.constraints.NotNull;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;
/**
* Repository des écrans.
*/
......@@ -78,6 +79,7 @@ public interface ScreenRepository extends JpaRepository<Screen, Long> {
/**
* Retourne les écrans d'un formulaire selon les permissions d'un utilisateur
*
* @param idUser identifiant d'utilisateur
* @param idForm identifiant de formulaire
* @return
......@@ -87,4 +89,14 @@ public interface ScreenRepository extends JpaRepository<Screen, Long> {
nativeQuery = true
)
List<Screen> findWithPermission(@Param("idUser") Long idUser, @Param("idForm") Long idForm);
/**
* Récupération de tous les écrans d'un formulaire.
*
* @param formId L'identifiant du formulaire.
* @return Les écrans.
*/
List<Screen> findAllByFormId(final Long formId);
Optional<Screen> findScreenByIndexAndFormId(final Integer index, final Long formId);
}
......@@ -213,6 +213,8 @@ public class FormService extends PermissionService<FormDTO> {
@PreAuthorize("hasAuthority('VIEW_FORM')")
protected boolean existPermission(User user, Long formId) {
return formRepository.existPermission(user.getId(), formId);
// TODO : Revoir ça.
return true;
//return formRepository.existPermission(user.getId(), formId);
}
}
......@@ -3,22 +3,23 @@ package com.unantes.orientactive.service;
import com.unantes.orientactive.domain.Screen;
import com.unantes.orientactive.domain.User;
import com.unantes.orientactive.repository.ScreenRepository;
import com.unantes.orientactive.service.dto.FormDTO;
import com.unantes.orientactive.service.dto.ScreenDTO;
import com.unantes.orientactive.service.dto.ScreenPanelDTO;
import com.unantes.orientactive.service.mapper.ScreenMapper;
import com.unantes.orientactive.service.mapper.ScreenPanelMapper;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Service Implementation for managing {@link Screen}.
*/
......@@ -93,21 +94,6 @@ public class ScreenService {
return screenRepository.findAll().stream().map(screenMapper::toDto).collect(Collectors.toCollection(LinkedList::new));
}
/**
* Get all the screens where Next is {@code null}.
*
* @return the list of entities.
*/
@Transactional(readOnly = true)
public List<ScreenDTO> findAllWhereNextIsNull() {
log.debug("Request to get all screens where Next is null");
return StreamSupport
.stream(screenRepository.findAll().spliterator(), false)
.filter(screen -> screen.getNext() == null)
.map(screenMapper::toDto)
.collect(Collectors.toCollection(LinkedList::new));
}
/**
* Get one screen by id.
*
......@@ -203,12 +189,24 @@ public class ScreenService {
*/
@Transactional(readOnly = true)
public List<ScreenPanelDTO> findScreenByFormId(Long formId, User user) {
if (!formService.existPermission(user, formId)) {
final FormDTO form = formService.findOne(formId).orElseThrow();
if (!formService.hasPermission(user, form)) {
throw new AccessDeniedException("Action non autorisée");
}
final List<Screen> screens = screenRepository.findWithPermission(user.getId(), formId);
final List<Screen> screens = screenRepository.findAllByFormId(formId);
List<ScreenPanelDTO> screenPanelDTOS = screenPanelMapper.toDto(screens);
Collections.sort(screenPanelDTOS);
return screenPanelDTOS;
}
/**
* Récupération de l'écran via son index et son formulaire.
*
* @param index L'index de l'écran.
* @param formId L'identifiant du formulaire.
* @return L'écran s'il existe.
*/
public Optional<ScreenDTO> findScreenByIndexAndFormId(final Integer index, final Long formId) {
return screenRepository.findScreenByIndexAndFormId(index, formId).map(screenMapper::toDto);
}
}
......@@ -26,6 +26,8 @@ public class ScreenDTO implements Serializable {
@ApiModelProperty(value = "Nom de l'écran : pour l'affichage uniquement", required = true)
private String name;
private Integer index;
/**
* reference du screen pour constituer l'URL
*/
......@@ -40,12 +42,6 @@ public class ScreenDTO implements Serializable {
private List<Item> itemsList;
private Long previousId;
private String previousName;
private Long nextId;
private Long formId;
private String formName;
......@@ -54,6 +50,10 @@ public class ScreenDTO implements Serializable {
private List<NextScreenExpressionDTO> nextScreenExpressions;
public Integer getNextIndex() {
return this.index++;
}
public Long getId() {
return id;
}
......@@ -94,22 +94,6 @@ public class ScreenDTO implements Serializable {
this.items = items;
}
public Long getPreviousId() {
return previousId;
}
public void setPreviousId(Long screenId) {
this.previousId = screenId;
}
public String getPreviousName() {
return previousName;
}
public void setPreviousName(String screenName) {
this.previousName = screenName;
}
public Long getFormId() {
return formId;
}
......@@ -134,14 +118,6 @@ public class ScreenDTO implements Serializable {
this.itemsList = itemsList;
}
public Long getNextId() {
return nextId;
}
public void setNextId(Long nextId) {
this.nextId = nextId;
}
public String getDefaultNextScreenReference() {
return defaultNextScreenReference;
}
......@@ -184,13 +160,18 @@ public class ScreenDTO implements Serializable {
.append("description", description)
.append("items", items)
.append("itemsList", itemsList)
.append("previousId", previousId)
.append("previousName", previousName)
.append("nextId", nextId)
.append("formId", formId)
.append("formName", formName)
.append("defaultNextScreenReference", defaultNextScreenReference)
.append("nextScreenExpressions", nextScreenExpressions).toString();
//@formatter:on
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
}
......@@ -21,16 +21,11 @@ public abstract class ScreenMapper implements EntityMapper<ScreenDTO, Screen> {
private ServiceConverter serviceConverter;
@Mapping(source = "previous.id", target = "previousId")
@Mapping(source = "next.id", target = "nextId")
@Mapping(source = "previous.name", target = "previousName")
@Mapping(source = "form.id", target = "formId")
@Mapping(source = "form.name", target = "formName")
@Mapping(source = "items", target = "itemsList", qualifiedByName = "deserializeScreenItem")
public abstract ScreenDTO toDto(Screen screen);
@Mapping(source = "previousId", target = "previous")
@Mapping(target = "next", ignore = true)
@Mapping(source = "formId", target = "form")
public abstract Screen toEntity(ScreenDTO screenDTO);
......
......@@ -129,12 +129,8 @@ public class FormApiDelegateImpl implements FormApiDelegate {
*/
private FormAPI initializeResponseModel(final String sessionId, final ScreenDTO screen, final FormDTO form) {
FormAPI formAPI = serviceConverter.convertScreen(screen, form);
if (screen.getPreviousId() == null) {
formAPI.getScreen().setHasPrevious(false);
}
if (screen.getNextId() == null) {
formAPI.getScreen().setHasNext(false);
}
formAPI.getScreen().setHasPrevious(navigationService.checkIsFirstScreen(screen));
formAPI.getScreen().setHasNext(navigationService.checkIsLastScreen(screen));
addAnswers(sessionId, screen.getId(), formAPI);
addProgress(sessionId, screen, formAPI);
formAPI.sessionId(sessionId);
......
......@@ -102,52 +102,6 @@ public class ScreenResource {
.body(result);
}
/**
* {@code GET /screens} : get all the screens.
*
* @param filter the filter of the request.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of screens in body.
*/
@GetMapping("/screens")
public List<ScreenDTO> getAllScreens(@RequestParam(required = false) String filter) {
List<ScreenDTO> screens = new LinkedList<>();
if ("next-is-null".equals(filter)) {
log.debug("REST request to get all Screens where next is null");
screens = screenService.findAllWhereNextIsNull();
} else {
log.debug("REST request to get all Screens");
screens = screenService.findAll();
}
// Partie permettant d'ordonner les écrans dans l'affichage BO pour faciliter la saisie.
// TODO : A supprimer lors de la refonte du BO
List<ScreenDTO> screenOrdered = new LinkedList<>();
Optional<ScreenDTO> first = screens.stream().filter(screenDTO -> screenDTO.getPreviousId() == null).findFirst();
if (first.isPresent()) {
screenOrdered.add(first.get());
recursiveSearchNext(screens, screenOrdered, first.get());
}
return screenOrdered;
}
/**
* // TODO : A supprimer lors de la refonte du BO
* Permet de construire la liste des écrans via appel récursif à partir de l'information previous contenue sur les écrans.
*
* @param screens La liste des écrans.
* @param screenOrdered La liste des écrans DTO.
* @param screen L'écran trouvé l'étape précédente.
*/
private void recursiveSearchNext(final List<ScreenDTO> screens, final List<ScreenDTO> screenOrdered, final ScreenDTO screen) {
Optional<ScreenDTO> next = screens
.stream()
.filter(screenDTO -> screenDTO.getPreviousId() != null && screenDTO.getPreviousId().equals(screen.getId()))
.findFirst();
if (next.isPresent()) {
screenOrdered.add(next.get());
recursiveSearchNext(screens, screenOrdered, next.get());
}
}
/**
* {@code GET /screens/:id} : get the "id" screen.
*
......
update screen set index = 1 where id = 1151;
update screen set index = 2 where id = 1152;
update screen set index = 3 where id = 1153;
update screen set index = 4 where id = 1154;
update screen set index = 5 where id = 1155;
update screen set index = 6 where id = 1156;
update screen set index = 7 where id = 1451;
update screen set index = 8 where id = 1702;
update screen set index = 9 where id = 1705;
update screen set index = 10 where id = 1706;
update screen set index = 11 where id = 1707;
update screen set index = 12 where id = 1708;
update screen set index = 13 where id = 1709;
update screen set index = 14 where id = 1710;
update screen set index = 15 where id = 1711;
update screen set index = 16 where id = 1712;
update screen set index = 17 where id = 1713;
alter table screen add constraint unique_screen_index_for_form unique (index, form_id);
alter table screen alter column index set not null;
......@@ -36,6 +36,9 @@
<include file="config/liquibase/changelog/20210322171800_role_authorities.sql" relativeToChangelogFile="false"/>
<include file="config/liquibase/changelog/20210323110900_add_authorities_admin.sql" relativeToChangelogFile="false"/>
<include file="config/liquibase/changelog/20210414161316_update_entity_Screen.xml" relativeToChangelogFile="false"/>
<include file="config/liquibase/changelog/20210420145300_migration_screen_index.sql" relativeToChangelogFile="false"/>
<include file="config/liquibase/changelog/20210420150500_add_constraint_screen_index.sql" relativeToChangelogFile="false"/>
<include file="config/liquibase/changelog/20210420151000_drop_screen_previous_id.sql" relativeToChangelogFile="false"/>
<!-- jhipster-needle-liquibase-add-constraints-changelog - JHipster will add liquibase constraints changelogs here -->
<!-- jhipster-needle-liquibase-add-incremental-changelog - JHipster will add incremental liquibase changelogs here -->
</databaseChangeLog>
......@@ -150,13 +150,16 @@ class NavigationServiceTest {
*/
@BeforeEach
void initTest() {
// TODO KRO : Corriger les tests suite à la modification du modèle de données des écrans.
form = new Form().name(FIRST_FORM_TITLE).reference(FIRST_FORM_REFERENCE).description("description").publicationState(FormPublicationState.PUBLISHED);
Set<Screen> screenList = new HashSet<>();
firstScreen = new Screen().name(FIRST_SCREEN_TITLE).reference(FIRST_SCREEN_REFERENCE).description("first screen of the form").defaultNextScreenReference("").items("[]").form(form);
secondScreen = new Screen().name(SECOND_SCREEN_TITLE).reference(SECOND_SCREEN_REFERENCE).description("second screen of the form").defaultNextScreenReference("").items("[]").form(form).previous(firstScreen);
thirdScreen = new Screen().name(THIRD_SCREEN_TITLE).reference(THIRD_SCREEN_REFERENCE).description("third screen of the form").defaultNextScreenReference("").items("[]").form(form).previous(secondScreen);