Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict questionnaire editing to admins if no encounters exist #172

Open
wants to merge 1 commit into
base: v3.2.1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,13 @@ public Optional<QuestionnaireDTO> getQuestionnaireDTOById(Long questionnaireId)
public boolean editingQuestionnaireAllowed(QuestionnaireDTO questionnaireDTO) {
Questionnaire questionnaire = questionnaireDao.getElementById(questionnaireDTO.getId());

// Admins and moderators can edit if there are no encounters
if (authService.hasRoleOrAbove(UserRole.ROLE_MODERATOR)) {
// Admins can edit if there are no encounters
if (authService.hasRoleOrAbove(UserRole.ROLE_ADMIN)) {
return questionnaire.isModifiable();
}

// Editors can edit if questionnaire is not part of any bundle that is enabled or if the bundle has executed encounters
if (authService.hasExactRole(UserRole.ROLE_EDITOR)) {
// Moderators and Editors can edit if questionnaire is not part of any bundle that is enabled or if the bundle has executed encounters
if (authService.hasExactRole(UserRole.ROLE_MODERATOR) || authService.hasExactRole(UserRole.ROLE_EDITOR)) {
return questionnaire.isModifiable() && !isQuestionnairePartOfEnabledBundle(questionnaire);
}

Expand All @@ -228,11 +228,11 @@ public Pair<Boolean, String> canEditQuestionnaireWithReason(QuestionnaireDTO que
boolean isModifiable = questionnaire.isModifiable();
boolean partOfEnabledBundle = isQuestionnairePartOfEnabledBundle(questionnaire);

if (authService.hasRoleOrAbove(UserRole.ROLE_MODERATOR) && !isModifiable) {
if (authService.hasRoleOrAbove(UserRole.ROLE_ADMIN) && !isModifiable) {
return Pair.of(false, getLocalizedMessage("questionnaire.message.executedEncounters"));
}

if (authService.hasExactRole(UserRole.ROLE_EDITOR)) {
if (authService.hasExactRole(UserRole.ROLE_MODERATOR) || authService.hasExactRole(UserRole.ROLE_EDITOR)) {
if (!isModifiable && partOfEnabledBundle) {
return Pair.of(false, getLocalizedMessage("questionnaire.message.executedEncountersAndEnabledBundle"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,15 +291,15 @@ public void testSaveOrUpdateQuestionnaire_CreateNew() {
* Valid input: valid {@link QuestionnaireDTO} with ID, and admin can edit the questionnaire without executed surveys
*/
@Test
public void testSaveOrUpdateQuestionnaire_AdminModeratorCanEditQuestionnaireWithoutExecutedSurveys() {
public void testSaveOrUpdateQuestionnaire_AdminCanEditQuestionnaireWithoutExecutedSurveys() {
// Arrange
Questionnaire newValidQuestionnaire = createAndPersistQuestionnaire();
QuestionnaireDTO validQuestionnaireDTO = QuestionnaireDTOTest.getNewValidQuestionnaireDTO();
validQuestionnaireDTO.setId(newValidQuestionnaire.getId());
Long validUserId = Helper.generatePositiveNonZeroLong();
Questionnaire modifiableQuestionnaire = spy(QuestionnaireTest.getNewValidQuestionnaire());

when(authService.hasRoleOrAbove(UserRole.ROLE_MODERATOR)).thenReturn(true);
when(authService.hasRoleOrAbove(UserRole.ROLE_ADMIN)).thenReturn(true);
doReturn(true).when(modifiableQuestionnaire).isModifiable();
doReturn(Helper.generatePositiveNonZeroLong()).when(modifiableQuestionnaire).getId();

Expand All @@ -322,7 +322,7 @@ public void testSaveOrUpdateQuestionnaire_AdminModeratorCanEditQuestionnaireWith
* Valid input: valid {@link QuestionnaireDTO} with ID, but admin can't edit the questionnaire with executed surveys
*/
@Test
public void testSaveOrUpdateQuestionnaire_AdminModeratorCantEditQuestionnaireWithExecutedSurvey() {
public void testSaveOrUpdateQuestionnaire_AdminCantEditQuestionnaireWithExecutedSurvey() {
// Arrange
Questionnaire existingQUestionnaire = createAndPersistQuestionnaire();
Question testQuestion = QuestionTest.getNewValidQuestion(existingQUestionnaire);
Expand All @@ -343,7 +343,7 @@ public void testSaveOrUpdateQuestionnaire_AdminModeratorCantEditQuestionnaireWit
Long userId = Helper.generatePositiveNonZeroLong();
Questionnaire newQuestionnaire = QuestionnaireTest.getNewValidQuestionnaire();

when(authService.hasRoleOrAbove(UserRole.ROLE_MODERATOR)).thenReturn(true);
when(authService.hasRoleOrAbove(UserRole.ROLE_ADMIN)).thenReturn(true);
when(questionnaireFactory.createQuestionnaire(any(), any(), any(), any())).thenReturn(newQuestionnaire);

// Mock question duplication with empty maps
Expand All @@ -368,6 +368,56 @@ public void testSaveOrUpdateQuestionnaire_AdminModeratorCantEditQuestionnaireWit
questionnaireDao.remove(result);
}

/**
* Test of {@link QuestionnaireService#saveOrUpdateQuestionnaire}<br>
* Valid input: valid {@link QuestionnaireDTO} with ID, and moderator cannot edit the questionnaire if it has executed surveys
*/
@Test
public void testSaveOrUpdateQuestionnaire_ModeratorCannotEditWithExecutedSurveys() {
// Arrange
Questionnaire existingQUestionnaire = createAndPersistQuestionnaire();
Question existingQuestion = QuestionTest.getNewValidQuestion(existingQUestionnaire);
questionDao.merge(existingQuestion);
SliderFreetextAnswer existingAnswer = SliderFreetextAnswerTest.getNewValidSliderFreetextAnswer();
existingAnswer.setQuestion(existingQuestion);
answerDao.merge(existingAnswer);
Bundle existingBundle = BundleTest.getNewValidBundle();
bundleDao.merge(existingBundle);
Encounter testEncounter = EncounterTest.getNewValidEncounter(existingBundle);
encounterDao.merge(testEncounter);
Response testResponse = new Response(existingAnswer, testEncounter);
responseDao.merge(testResponse);
questionnaireDao.merge(existingQUestionnaire);

QuestionnaireDTO questionnaireDTO = QuestionnaireDTOTest.getNewValidQuestionnaireDTO();
questionnaireDTO.setId(existingQUestionnaire.getId());
Long userId = Helper.generatePositiveNonZeroLong();
Questionnaire newQuestionnaire = QuestionnaireTest.getNewValidQuestionnaire();
when(authService.hasExactRole(UserRole.ROLE_MODERATOR)).thenReturn(true);
when(questionnaireFactory.createQuestionnaire(any(), any(), any(), any())).thenReturn(newQuestionnaire);

// Mock question duplication with empty maps
when(questionService.duplicateQuestionsToNewQuestionnaire(anySet(), any(Questionnaire.class))).thenReturn(newQuestionnaire);
when(questionService.getMappingForDuplicatedQuestions(any(Questionnaire.class), any(Questionnaire.class))).thenReturn(new MapHolder(Collections.emptyMap(), Collections.emptyMap()));

// Act
Questionnaire result = questionnaireService.saveOrUpdateQuestionnaire(
questionnaireDTO,
MultipartFileUtils.getEmptyLogo(),
userId
);

// Assert
Assert.assertNotNull("The created questionnaire should not be null", result);
verify(questionService, atLeastOnce()).duplicateQuestionsToNewQuestionnaire(anySet(), any(Questionnaire.class)); // Ensure questions are copied, implying it's an update

responseDao.remove(testResponse);
encounterDao.remove(testEncounter);
bundleDao.remove(existingBundle);
questionnaireDao.remove(existingQUestionnaire);
questionnaireDao.remove(result);
}

/**
* Test of {@link QuestionnaireService#saveOrUpdateQuestionnaire}<br>
* Valid input: valid {@link QuestionnaireDTO} with ID, and editor cannot edit the questionnaire if it has executed surveys
Expand Down Expand Up @@ -418,6 +468,51 @@ public void testSaveOrUpdateQuestionnaire_EditorCannotEditWithExecutedSurveys()
questionnaireDao.remove(result);
}

/**
* Test of {@link QuestionnaireService#saveOrUpdateQuestionnaire}<br>
* Valid input: valid {@link QuestionnaireDTO} with ID, and moderator cannot edit the questionnaire if it belongs to a bundle that is enabled
*/
@Test
public void testSaveOrUpdateQuestionnaire_ModeratorCannotEditIfPartOfEnabledBundle() throws Exception {
// Arrange
Questionnaire testQuestionnaire = createAndPersistQuestionnaire();
QuestionnaireDTO validQuestionnaireDTO = QuestionnaireDTOTest.getNewValidQuestionnaireDTO();
validQuestionnaireDTO.setId(testQuestionnaire.getId());
Long validUserId = Helper.generatePositiveNonZeroLong();

Questionnaire existingQuestionnaire = spy(QuestionnaireTest.getNewValidQuestionnaire());
Questionnaire copiedQuestionnaire = QuestionnaireTest.getNewValidQuestionnaire();

BundleQuestionnaire enabledBundleQuestionnaire = BundleQuestionnaireTest.getNewValidBundleQuestionnaire();
enabledBundleQuestionnaire.setIsEnabled(true);
List<BundleQuestionnaire> bundleQuestionnaireList = List.of(enabledBundleQuestionnaire);

when(bundleService.findByQuestionnaireId(any())).thenReturn(bundleQuestionnaireList);
when(authService.hasExactRole(UserRole.ROLE_MODERATOR)).thenReturn(true);
when(questionnaireFactory.createQuestionnaire(any(), any(), any(), any())).thenReturn(copiedQuestionnaire);
doReturn(true).when(existingQuestionnaire).isModifiable();
doReturn(Helper.generatePositiveNonZeroLong()).when(existingQuestionnaire).getId();

// Mock question duplication with empty maps
when(questionService.duplicateQuestionsToNewQuestionnaire(anySet(), any(Questionnaire.class))).thenReturn(copiedQuestionnaire);
when(questionService.getMappingForDuplicatedQuestions(any(Questionnaire.class), any(Questionnaire.class))).thenReturn(new MapHolder(Collections.emptyMap(), Collections.emptyMap()));

// Act
Questionnaire result = questionnaireService.saveOrUpdateQuestionnaire(
validQuestionnaireDTO,
MultipartFileUtils.getEmptyLogo(),
validUserId
);

// Assert
Assert.assertNotNull("The created questionnaire should not be null", result);
verify(questionService, times(1)).duplicateQuestionsToNewQuestionnaire(anySet(), eq(copiedQuestionnaire)); // Ensure questions are copied to the new questionnaire

questionnaireDao.remove(testQuestionnaire);
questionnaireDao.remove(copiedQuestionnaire);

}

/**
* Test of {@link QuestionnaireService#saveOrUpdateQuestionnaire}<br>
* Valid input: valid {@link QuestionnaireDTO} with ID, and editor cannot edit the questionnaire if it belongs to a bundle that is enabled
Expand Down Expand Up @@ -463,6 +558,47 @@ public void testSaveOrUpdateQuestionnaire_EditorCannotEditIfPartOfEnabledBundle(

}

/**
* Test of {@link QuestionnaireService#saveOrUpdateQuestionnaire}<br>
* Valid input: valid {@link QuestionnaireDTO} with ID, and moderator can edit the questionnaire if it does not belong to a bundle that is enabled
*/
@Test
public void testSaveOrUpdateQuestionnaire_ModeratorCanEditIfNotPartOfEnabledBundle() {
// Arrange
Questionnaire testQuestionnaire = createAndPersistQuestionnaire();
QuestionnaireDTO validQuestionnaireDTO = QuestionnaireDTOTest.getNewValidQuestionnaireDTO();
validQuestionnaireDTO.setId(testQuestionnaire.getId());
Long validUserId = Helper.generatePositiveNonZeroLong();

Questionnaire existingQuestionnaire = spy(QuestionnaireTest.getNewValidQuestionnaire());
Questionnaire copiedQuestionnaire = QuestionnaireTest.getNewValidQuestionnaire();

// Create a BundleQuestionnaire with isEnabled set to false
BundleQuestionnaire newValidBundleQuestionnaire = BundleQuestionnaireTest.getNewValidBundleQuestionnaire();
newValidBundleQuestionnaire.setIsEnabled(false);
List<BundleQuestionnaire> bundleQuestionnaireList = List.of(newValidBundleQuestionnaire);

when(bundleService.findByQuestionnaireId(any())).thenReturn(bundleQuestionnaireList);
when(authService.hasExactRole(UserRole.ROLE_MODERATOR)).thenReturn(true);
when(questionnaireFactory.createQuestionnaire(any(), any(), any(), any())).thenReturn(copiedQuestionnaire);
doReturn(true).when(existingQuestionnaire).isModifiable();
doReturn(1L).when(existingQuestionnaire).getId();

// Act
Questionnaire result = questionnaireService.saveOrUpdateQuestionnaire(
validQuestionnaireDTO,
MultipartFileUtils.getEmptyLogo(),
validUserId
);

// Assert
Assert.assertNotNull("The updated questionnaire should not be null", result);
verify(questionService, never()).duplicateQuestionsToNewQuestionnaire(anySet(), any(Questionnaire.class)); // Ensure no questions are copied, implying it's an update

questionnaireDao.remove(testQuestionnaire);
questionnaireDao.remove(copiedQuestionnaire);
}

/**
* Test of {@link QuestionnaireService#saveOrUpdateQuestionnaire}<br>
* Valid input: valid {@link QuestionnaireDTO} with ID, and editor can edit the questionnaire if it does not belong to a bundle that is enabled
Expand Down