Skip to content

Commit

Permalink
fix: (2.39) Veto when deleting notification template associated with …
Browse files Browse the repository at this point in the history
…program rule [DHIS2-17515] (#18496)
  • Loading branch information
zubaira authored Sep 2, 2024
1 parent 4786ea6 commit e699c4e
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
package org.hisp.dhis.programrule;

import java.util.List;
import org.hisp.dhis.program.notification.ProgramNotificationTemplate;

/**
* @author markusbekken
Expand Down Expand Up @@ -86,4 +87,13 @@ public interface ProgramRuleActionService {
List<ProgramRuleAction> getProgramRuleActionsWithNoSectionId();

List<ProgramRuleAction> getProgramRuleActionsWithNoStageId();

/**
* Checks whether a program rule action exists for the given {@link ProgramNotificationTemplate}.
*
* @param template the {@link ProgramNotificationTemplate} to check
* @return {@code true} if a program rule action exists for the specified template, {@code false}
* otherwise
*/
boolean programRuleActionExists(ProgramNotificationTemplate template);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import java.util.List;
import org.hisp.dhis.common.IdentifiableObjectStore;
import org.hisp.dhis.program.notification.ProgramNotificationTemplate;

/**
* @author markusbekken
Expand All @@ -47,4 +48,6 @@ public interface ProgramRuleActionStore extends IdentifiableObjectStore<ProgramR
List<ProgramRuleAction> getProgramActionsWithNoNotification();

List<ProgramRuleAction> getMalFormedRuleActionsByType(ProgramRuleActionType type);

boolean programRuleActionExists(ProgramNotificationTemplate template);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.List;
import org.hisp.dhis.program.notification.ProgramNotificationTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -116,4 +117,9 @@ public List<ProgramRuleAction> getProgramRuleActionsWithNoStageId() {
return programRuleActionStore.getMalFormedRuleActionsByType(
ProgramRuleActionType.HIDEPROGRAMSTAGE);
}

@Override
public boolean programRuleActionExists(ProgramNotificationTemplate template) {
return programRuleActionStore.programRuleActionExists(template);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2004-2024, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of the HISP project nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hisp.dhis.programrule;

import lombok.RequiredArgsConstructor;
import org.hisp.dhis.program.notification.ProgramNotificationTemplate;
import org.hisp.dhis.system.deletion.DeletionHandler;
import org.hisp.dhis.system.deletion.DeletionVeto;
import org.springframework.stereotype.Component;

/**
* @author Zubair Asghar
*/
@Component
@RequiredArgsConstructor
public class ProgramRuleActionDeletionHandler extends DeletionHandler {
private final ProgramRuleActionService ruleActionService;

@Override
protected void register() {
whenVetoing(ProgramNotificationTemplate.class, this::allowDeleteProgramNotificationTemplate);
}

private DeletionVeto allowDeleteProgramNotificationTemplate(ProgramNotificationTemplate pnt) {
return ruleActionService.programRuleActionExists(pnt)
? new DeletionVeto(ProgramRuleAction.class)
: DeletionVeto.ACCEPT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import javax.persistence.criteria.CriteriaBuilder;
import org.hibernate.SessionFactory;
import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore;
import org.hisp.dhis.program.notification.ProgramNotificationTemplate;
import org.hisp.dhis.programrule.ProgramRule;
import org.hisp.dhis.programrule.ProgramRuleAction;
import org.hisp.dhis.programrule.ProgramRuleActionStore;
Expand Down Expand Up @@ -110,4 +111,16 @@ public List<ProgramRuleAction> getMalFormedRuleActionsByType(ProgramRuleActionTy

return new ArrayList<>();
}

@Override
public boolean programRuleActionExists(ProgramNotificationTemplate template) {
List<ProgramRuleAction> actions =
getQuery(
"FROM ProgramRuleAction pra WHERE pra.programRuleActionType IN ( :notificationTypes ) AND pra.templateUid IS :template")
.setParameter("notificationTypes", ProgramRuleActionType.NOTIFICATION_LINKED_TYPES)
.setParameter("template", template.getUid())
.getResultList();

return !actions.isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,24 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import org.hisp.dhis.common.DeleteNotAllowedException;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.organisationunit.OrganisationUnitService;
import org.hisp.dhis.program.Program;
import org.hisp.dhis.program.ProgramService;
import org.hisp.dhis.program.ProgramStage;
import org.hisp.dhis.program.ProgramStageService;
import org.hisp.dhis.programrule.ProgramRule;
import org.hisp.dhis.programrule.ProgramRuleAction;
import org.hisp.dhis.programrule.ProgramRuleActionService;
import org.hisp.dhis.programrule.ProgramRuleActionType;
import org.hisp.dhis.programrule.ProgramRuleService;
import org.hisp.dhis.test.integration.SingleSetupIntegrationTestBase;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -59,10 +68,18 @@ class ProgramNotificationTemplateServiceTest extends SingleSetupIntegrationTestB

private OrganisationUnit organisationUnit;

private ProgramRule programRule;

private ProgramRuleAction ruleAction;

@Autowired private ProgramService programService;

@Autowired private ProgramStageService programStageService;

@Autowired private ProgramRuleService programRuleService;

@Autowired private ProgramRuleActionService programRuleActionService;

@Autowired private ProgramNotificationTemplateService programNotificationTemplateService;

@Autowired private OrganisationUnitService organisationUnitService;
Expand Down Expand Up @@ -102,10 +119,20 @@ protected void setUpTest() throws Exception {
programNotificationTemplateService.save(pnt3);
program.getNotificationTemplates().add(pnt1);
program.getNotificationTemplates().add(pnt2);

programRule = createProgramRule('R', program);
ruleAction = createProgramRuleAction('A', programRule);
ruleAction.setProgramRuleActionType(ProgramRuleActionType.SENDMESSAGE);
ruleAction.setTemplateUid(pnt1.getUid());

programRuleService.addProgramRule(programRule);
programRuleActionService.addProgramRuleAction(ruleAction);
programRule.getProgramRuleActions().add(ruleAction);
programRuleService.updateProgramRule(programRule);
}

@Test
void testGetProgramNotificationTemplates() {
void shouldGetProgramNotificationTemplates() {
ProgramNotificationTemplateParam param =
ProgramNotificationTemplateParam.builder().program(program).build();
List<ProgramNotificationTemplate> templates =
Expand All @@ -118,7 +145,7 @@ void testGetProgramNotificationTemplates() {
}

@Test
void testCountProgramNotificationTemplates() {
void shouldCountProgramNotificationTemplates() {
ProgramNotificationTemplateParam param =
ProgramNotificationTemplateParam.builder().program(program).build();
ProgramNotificationTemplateParam param2 =
Expand All @@ -130,4 +157,25 @@ void testCountProgramNotificationTemplates() {
programNotificationTemplateService.getProgramNotificationTemplates(param2).size(),
programNotificationTemplateService.countProgramNotificationTemplates(param2));
}

@Test
void shouldThrowWhenUserDeleteTemplateLinkedToRuleAction() {
DeleteNotAllowedException exception =
assertThrows(
DeleteNotAllowedException.class, () -> programNotificationTemplateService.delete(pnt1));

assertEquals(
"Object could not be deleted because it is associated with another object: ProgramRuleAction",
exception.getMessage());
assertNotNull(programNotificationTemplateService.get(pnt1.getId()));
}

@Test
void shouldDeleteProgramNotificationTemplate() {
ProgramNotificationTemplate toBeDeleted = programNotificationTemplateService.get(pnt2.getId());

programNotificationTemplateService.delete(toBeDeleted);

assertNull(programNotificationTemplateService.get(toBeDeleted.getId()));
}
}

0 comments on commit e699c4e

Please sign in to comment.