Commit 28d57f2c authored by François-Xavier Lebastard's avatar François-Xavier Lebastard
Browse files

Merge branch 'feature/migration_screen_index' into 'feature/gestion_des_ecrans'

Developpements KRO

See merge request !58
parents d954818b 3b649f3d
......@@ -47,6 +47,13 @@ public class Screen implements Serializable {
@Column(name = "name", nullable = false, unique = true)
private String name;
/**
* Nom de l'écran : pour l'affichage uniquement
*/
@NotNull
@Column(name = "name_bo", nullable = false, unique = true)
private String nameBo;
/**
* reference du screen pour constituer l'URL
*/
......@@ -79,15 +86,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;
......@@ -121,6 +119,15 @@ public class Screen implements Serializable {
return this;
}
public Screen nameBo(final String nameBo) {
this.nameBo = nameBo;
return this;
}
public Screen index(final Integer index) {
this.index = index;
return this;
}
public void setName(String name) {
this.name = name;
}
......@@ -209,38 +216,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;
}
......@@ -262,6 +237,13 @@ public class Screen implements Serializable {
this.index = index;
}
public String getNameBo() {
return nameBo;
}
public void setNameBo(String nameBo) {
this.nameBo = nameBo;
}
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here
@Override
......
......@@ -3,35 +3,38 @@ package com.unantes.orientactive.filariane;
import com.unantes.orientactive.security.AuthoritiesConstants;
import com.unantes.orientactive.security.permissions.PermissionService;
import com.unantes.orientactive.service.FormService;
import com.unantes.orientactive.service.ScreenService;
import com.unantes.orientactive.service.WorkspaceService;
import com.unantes.orientactive.service.dto.FormDTO;
import com.unantes.orientactive.service.dto.ScreenDTO;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import com.unantes.orientactive.service.dto.WorkspaceDTO;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
/**
* Contrôleur permettant de récupérer le fils d'ariane pour un élément.
*/
@RestController
@RequestMapping("/api/filariane")
public class FilArianeController {
/**
* Service des formulaires.
* Service des workspaces.
*/
private final FormService formService;
private final WorkspaceService workspaceService;
/**
* Service des écrans.
* Service des formulaires.
*/
private final ScreenService screenService;
private final FormService formService;
/**
* Elément du fil d'ariane correspondant à l'accueil.
......@@ -41,18 +44,17 @@ public class FilArianeController {
/**
* Constructeur.
*
* @param formService Le service des formulaires.
* @param screenService Le service des écrans.
* @param formService Le service des formulaires.
*/
public FilArianeController(
final WorkspaceService workspaceService,
final FormService formService,
final ScreenService screenService,
final ApplicationContext applicationContext
) {
String homeTitle = applicationContext.getMessage("filariane.home.title", new Object[] {}, Locale.getDefault());
String homeTitle = applicationContext.getMessage("filariane.home.title", new Object[]{}, Locale.getDefault());
this.workspaceService = workspaceService;
this.filArianeHome = new FilArianeElement(homeTitle, Path.HOME);
this.formService = formService;
this.screenService = screenService;
}
/**
......@@ -60,7 +62,7 @@ public class FilArianeController {
*
* @return Le fil d'ariane.
*/
@GetMapping("/home")
@GetMapping("/user/home")
@ResponseBody
public String getUserHome() {
if (PermissionService.currentUserHasAuthority(AuthoritiesConstants.AUTHORITY_VIEW_WORKSPACE)) {
......@@ -76,9 +78,9 @@ public class FilArianeController {
*
* @return Le fil d'ariane.
*/
@GetMapping("/filariane/workspaces")
@GetMapping("/home")
@ResponseBody
public List<FilArianeElement> getFilArianeForWorkspaces() {
public List<FilArianeElement> getFilArianeForHome() {
return Collections.singletonList(filArianeHome);
}
......@@ -88,10 +90,13 @@ public class FilArianeController {
* @param idWorkspace L'identifiant du workspace.
* @return Le fil d'ariane.
*/
@GetMapping("/filariane/workspace/{idWorkspace}")
@GetMapping("/workspace/{idWorkspace}")
@ResponseBody
public List<FilArianeElement> getFilArianeForWorkspace(@PathVariable("idWorkspace") final Long idWorkspace) {
return Collections.singletonList(filArianeHome);
LinkedList<FilArianeElement> filAriane = new LinkedList<>();
filAriane.add(filArianeHome);
addFilArianeWorkspace(filAriane, idWorkspace);
return filAriane;
}
/**
......@@ -100,47 +105,31 @@ public class FilArianeController {
* @param idForm L'identifiant du formulaire.
* @return Le fil d'ariane.
*/
@GetMapping("/filariane/form/{idForm}")
@GetMapping("/form/{idForm}")
@ResponseBody
public List<FilArianeElement> getFilArianeForForm(@PathVariable("idForm") final Long idForm) {
final List<FilArianeElement> filAriane = new LinkedList<>();
LinkedList<FilArianeElement> filAriane = new LinkedList<>();
filAriane.add(filArianeHome);
addFilArianeWorkspace(filAriane, idForm);
return filAriane;
}
/**
* Récupération du fil d'ariane pour un écran.
*
* @param idScreen L'identifiant de l'écran.
* @return Le fil d'ariane.
*/
@GetMapping("/filariane/screen/{idScreen}")
@ResponseBody
public List<FilArianeElement> getFilArianeForScreen(@PathVariable("idScreen") final Long idScreen) {
final List<FilArianeElement> filAriane = new LinkedList<>();
if (PermissionService.currentUserHasAuthority(AuthoritiesConstants.AUTHORITY_VIEW_FORM)) {
final Optional<ScreenDTO> screenOptional = screenService.findOne(idScreen);
final ScreenDTO screen = screenOptional.orElseThrow(() -> new FilArianeException("L'écran n'existe pas."));
filAriane.add(new FilArianeElement(screen.getFormName(), Path.WORKSPACE + "/" + screen.getFormId()));
addFilArianeWorkspace(filAriane, screen.getFormId());
final Optional<FormDTO> formDTO = formService.findOne(idForm);
final FormDTO form = formDTO.orElseThrow(() -> new FilArianeException("Le formulaire n'existe pas."));
addFilArianeWorkspace(filAriane, form.getWorkspaceId());
filAriane.add(new FilArianeElement(form.getName(), Path.FORMS + "/" + form.getId() + "/view"));
}
filAriane.add(filArianeHome);
Collections.reverse(filAriane);
return filAriane;
}
/**
* Ajout du fil d'ariane du workspace concerné par le formulaire.
*
* @param filAriane Le fil d'ariane.
* @param formId L'identifiant du formulaire.
* @param filAriane Le fil d'ariane.
* @param workspaceId L'identifiant du workspace.
*/
private void addFilArianeWorkspace(final List<FilArianeElement> filAriane, final Long formId) {
private void addFilArianeWorkspace(final List<FilArianeElement> filAriane, final Long workspaceId) {
if (PermissionService.currentUserHasAuthority(AuthoritiesConstants.AUTHORITY_VIEW_WORKSPACE)) {
final Optional<FormDTO> formOptional = formService.findOne(formId);
final FormDTO form = formOptional.orElseThrow(() -> new FilArianeException("Le formulaire n'existe pas."));
filAriane.add(new FilArianeElement(form.getWorkspaceName(), Path.WORKSPACE + "/" + form.getWorkspaceId()));
final Optional<WorkspaceDTO> workspaceOptional = workspaceService.findOne(workspaceId);
final WorkspaceDTO workspace = workspaceOptional.orElseThrow(() -> new FilArianeException("Le workspace n'existe pas."));
filAriane.add(new FilArianeElement(workspace.getName(), Path.WORKSPACE + "/" + workspace.getId() + "/view"));
}
}
}
......@@ -5,8 +5,10 @@ package com.unantes.orientactive.filariane;
*/
public class Path {
public static final String HOME = "/home";
public static final String LIST_WORKSPACES = "/workspaces";
public static final String WORKSPACE = "/workspace";
public static final String LIST_FORMS = "/forms";
public static final String HOME = "/admin/workspace";
public static final String WORKSPACE = "/admin/workspace";
public static final String FORMS = "/admin/forms";
public static final String LIST_WORKSPACES = "/admin/workspaces";
public static final String LIST_FORMS = "/admin/forms";
}
......@@ -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.Modifying;
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.
*/
......@@ -30,7 +32,7 @@ public interface ScreenRepository extends JpaRepository<Screen, Long> {
* @return Le premier écran du formulaire s'il existe.
*/
@Query(
value = "select * from screen join form on form.id = screen.form_id where screen.previous_id is null and form.id = :formId",
value = "select * from screen join form on form.id = screen.form_id where screen.index = 1 and form.id = :formId",
nativeQuery = true
)
Optional<Screen> findFirstScreenOfForm(final @Param("formId") Long formId);
......@@ -71,13 +73,14 @@ public interface ScreenRepository extends JpaRepository<Screen, Long> {
* @return Le nombre d'écran potentiellement restant.
*/
@Query(
value = "WITH RECURSIVE previous AS (SELECT id, previous_id FROM screen WHERE id = :screenId UNION SELECT s.id, s.previous_id FROM screen s INNER JOIN previous p ON p.previous_id = s.id) SELECT (select count(*) from screen where form_id = :formId) - count(pr.*) FROM previous pr",
value = "SELECT COUNT(*) FROM SCREEN WHERE INDEX > (SELECT INDEX FROM SCREEN WHERE ID = :screenId AND form_id = :formId) AND form_id = :formId",
nativeQuery = true
)
int countScreenLeft(final @Param("formId") Long formId, final @Param("screenId") Long screenId);
/**
* 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 +90,26 @@ 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);
/**
* Diminue l'index des écrans d'un formulaire dont l'index est supérieur à celui passé en paramètre.
* @param formId un identifiant de formulaire
* @param index un index (position) d'écran
*/
@Query(
value = "UPDATE screen SET index = (index - 1) WHERE index > :index AND form_id = :formId",
nativeQuery = true
)
@Modifying(flushAutomatically = true, clearAutomatically = true)
void decreaseScreenIndex(@Param("formId") Long formId, @Param("index") Integer index);
}
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.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 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 com.unantes.orientactive.service.exception.EntityNotFoundException;
/**
* Service Implementation for managing {@link Screen}.
*/
......@@ -93,21 +96,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.
*
......@@ -127,7 +115,9 @@ public class ScreenService {
*/
public void delete(Long id) {