Skip to content

Commit fe74f3a

Browse files
committed
Merge branch '2.39' into 2.39-fix-rule-notifications
2 parents 16ba535 + 3e08881 commit fe74f3a

File tree

10 files changed

+314
-41
lines changed

10 files changed

+314
-41
lines changed

dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserService.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Locale;
3434
import java.util.Map;
3535
import java.util.Optional;
36+
import java.util.Set;
3637
import java.util.UUID;
3738
import java.util.function.Consumer;
3839
import javax.annotation.Nonnull;
@@ -465,12 +466,13 @@ boolean canCurrentUserCanModify(
465466
void generateTwoFactorSecret(User user);
466467

467468
/**
468-
* Method that retrieves all {@link User}s that have an entry for the {@link OrganisationUnit} in
469+
* Method that retrieves all {@link User}s that have an entry for the {@link OrganisationUnit}s in
469470
* the given table
470471
*
471472
* @param orgUnitProperty {@link UserOrgUnitProperty} used to search
472-
* @param uid {@link OrganisationUnit} uid to match on
473+
* @param uids {@link OrganisationUnit}s uids to match on
473474
* @return matching {@link User}s
474475
*/
475-
List<User> getUsersWithOrgUnit(@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull String uid);
476+
List<User> getUsersWithOrgUnits(
477+
@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull Set<String> uids);
476478
}

dhis-2/dhis-api/src/main/java/org/hisp/dhis/user/UserStore.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Locale;
3434
import java.util.Map;
3535
import java.util.Optional;
36+
import java.util.Set;
3637
import java.util.UUID;
3738
import javax.annotation.Nonnull;
3839
import javax.annotation.Nullable;
@@ -185,12 +186,13 @@ Map<String, Optional<Locale>> findNotifiableUsersWithPasswordLastUpdatedBetween(
185186
List<User> getHasAuthority(String authority);
186187

187188
/**
188-
* Retrieves all {@link User}s that have an entry for the {@link OrganisationUnit} in the given
189+
* Retrieves all {@link User}s that have an entry for the {@link OrganisationUnit}s in the given
189190
* table
190191
*
191192
* @param orgUnitProperty {@link UserOrgUnitProperty} used to search
192-
* @param uid {@link OrganisationUnit} uid to match on
193+
* @param uids {@link OrganisationUnit}s uids to match on
193194
* @return matching {@link User}s
194195
*/
195-
List<User> getUsersWithOrgUnit(@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull String uid);
196+
List<User> getUsersWithOrgUnits(
197+
@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull Set<String> uids);
196198
}

dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/merge/orgunit/handler/MetadataOrgUnitMergeHandler.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.stream.Collectors;
3434
import lombok.AllArgsConstructor;
3535
import org.hisp.dhis.category.CategoryOption;
36+
import org.hisp.dhis.common.BaseIdentifiableObject;
3637
import org.hisp.dhis.configuration.Configuration;
3738
import org.hisp.dhis.configuration.ConfigurationService;
3839
import org.hisp.dhis.dataset.DataSet;
@@ -41,7 +42,7 @@
4142
import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
4243
import org.hisp.dhis.program.Program;
4344
import org.hisp.dhis.user.User;
44-
import org.hisp.dhis.user.UserQueryParams;
45+
import org.hisp.dhis.user.UserOrgUnitProperty;
4546
import org.hisp.dhis.user.UserService;
4647
import org.springframework.stereotype.Service;
4748

@@ -125,10 +126,11 @@ public void mergeOrganisationUnits(OrgUnitMergeRequest request) {
125126

126127
public void mergeUsers(OrgUnitMergeRequest request) {
127128
List<User> dataCaptureUsers =
128-
userService.getUsers(
129-
new UserQueryParams()
130-
.setCanSeeOwnRoles(true)
131-
.setOrganisationUnits(request.getSources()));
129+
userService.getUsersWithOrgUnits(
130+
UserOrgUnitProperty.ORG_UNITS,
131+
request.getSources().stream()
132+
.map(BaseIdentifiableObject::getUid)
133+
.collect(Collectors.toSet()));
132134

133135
dataCaptureUsers.forEach(
134136
u -> {
@@ -137,10 +139,11 @@ public void mergeUsers(OrgUnitMergeRequest request) {
137139
});
138140

139141
List<User> dataViewUsers =
140-
userService.getUsers(
141-
new UserQueryParams()
142-
.setCanSeeOwnRoles(true)
143-
.setDataViewOrganisationUnits(request.getSources()));
142+
userService.getUsersWithOrgUnits(
143+
UserOrgUnitProperty.DATA_VIEW_ORG_UNITS,
144+
request.getSources().stream()
145+
.map(BaseIdentifiableObject::getUid)
146+
.collect(Collectors.toSet()));
144147

145148
dataViewUsers.forEach(
146149
u -> {
@@ -149,10 +152,11 @@ public void mergeUsers(OrgUnitMergeRequest request) {
149152
});
150153

151154
List<User> teiSearchOrgUnits =
152-
userService.getUsers(
153-
new UserQueryParams()
154-
.setCanSeeOwnRoles(true)
155-
.setTeiSearchOrganisationUnits(request.getSources()));
155+
userService.getUsersWithOrgUnits(
156+
UserOrgUnitProperty.TEI_SEARCH_ORG_UNITS,
157+
request.getSources().stream()
158+
.map(BaseIdentifiableObject::getUid)
159+
.collect(Collectors.toSet()));
156160

157161
teiSearchOrgUnits.forEach(
158162
u -> {

dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/split/orgunit/handler/MetadataOrgUnitSplitHandler.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import com.google.common.collect.Sets;
3131
import java.util.List;
32+
import java.util.Set;
3233
import lombok.AllArgsConstructor;
3334
import org.hisp.dhis.configuration.Configuration;
3435
import org.hisp.dhis.configuration.ConfigurationService;
@@ -94,7 +95,7 @@ public void splitUsers(OrgUnitSplitRequest request) {
9495
String sourceOrgUnitUid = request.getSource().getUid();
9596

9697
List<User> dataCaptureUsers =
97-
userService.getUsersWithOrgUnit(UserOrgUnitProperty.ORG_UNITS, sourceOrgUnitUid);
98+
userService.getUsersWithOrgUnits(UserOrgUnitProperty.ORG_UNITS, Set.of(sourceOrgUnitUid));
9899

99100
dataCaptureUsers.forEach(
100101
u -> {
@@ -103,7 +104,8 @@ public void splitUsers(OrgUnitSplitRequest request) {
103104
});
104105

105106
List<User> dataViewUsers =
106-
userService.getUsersWithOrgUnit(UserOrgUnitProperty.DATA_VIEW_ORG_UNITS, sourceOrgUnitUid);
107+
userService.getUsersWithOrgUnits(
108+
UserOrgUnitProperty.DATA_VIEW_ORG_UNITS, Set.of(sourceOrgUnitUid));
107109

108110
dataViewUsers.forEach(
109111
u -> {
@@ -112,7 +114,8 @@ public void splitUsers(OrgUnitSplitRequest request) {
112114
});
113115

114116
List<User> teiSearchOrgUnits =
115-
userService.getUsersWithOrgUnit(UserOrgUnitProperty.TEI_SEARCH_ORG_UNITS, sourceOrgUnitUid);
117+
userService.getUsersWithOrgUnits(
118+
UserOrgUnitProperty.TEI_SEARCH_ORG_UNITS, Set.of(sourceOrgUnitUid));
116119

117120
teiSearchOrgUnits.forEach(
118121
u -> {

dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/DefaultUserService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -903,8 +903,8 @@ public void generateTwoFactorSecret(User user) {
903903
}
904904

905905
@Override
906-
public List<User> getUsersWithOrgUnit(
907-
@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull String uid) {
908-
return userStore.getUsersWithOrgUnit(orgUnitProperty, uid);
906+
public List<User> getUsersWithOrgUnits(
907+
@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull Set<String> uids) {
908+
return userStore.getUsersWithOrgUnits(orgUnitProperty, uids);
909909
}
910910
}

dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/user/hibernate/HibernateUserStore.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -581,13 +581,13 @@ public List<User> getUserByUsernames(Collection<String> usernames) {
581581
}
582582

583583
@Override
584-
public List<User> getUsersWithOrgUnit(
585-
@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull String uid) {
584+
public List<User> getUsersWithOrgUnits(
585+
@Nonnull UserOrgUnitProperty orgUnitProperty, @Nonnull Set<String> uids) {
586586
return getQuery(
587587
String.format(
588-
"select distinct u from User u left join fetch u.%s ous where ous.uid = :uid ",
588+
"select distinct u from User u left join fetch u.%s ous where ous.uid in :uids ",
589589
orgUnitProperty.getValue()))
590-
.setParameter("uid", uid)
590+
.setParameter("uids", uids)
591591
.getResultList();
592592
}
593593
}

dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/programrule/DefaultTrackerProgramRuleService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private List<RuleEffects> calculateEventRuleEffects(TrackerBundle bundle) {
171171
List<ProgramStageInstance> programStageInstances =
172172
eventTrackerConverterService.fromForRuleEngine(
173173
bundle.getPreheat(), entry.getValue());
174-
if (enrollment == null) {
174+
if (enrollment == null || enrollment.getProgram().isWithoutRegistration()) {
175175
return programRuleEngine
176176
.evaluateProgramEvents(
177177
Sets.newHashSet(programStageInstances),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* Copyright (c) 2004-2022, University of Oslo
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
* Redistributions of source code must retain the above copyright notice, this
8+
* list of conditions and the following disclaimer.
9+
*
10+
* Redistributions in binary form must reproduce the above copyright notice,
11+
* this list of conditions and the following disclaimer in the documentation
12+
* and/or other materials provided with the distribution.
13+
* Neither the name of the HISP project nor the names of its contributors may
14+
* be used to endorse or promote products derived from this software without
15+
* specific prior written permission.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24+
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
*/
28+
package org.hisp.dhis.tracker.programrule;
29+
30+
import static org.mockito.ArgumentMatchers.any;
31+
import static org.mockito.ArgumentMatchers.anyList;
32+
import static org.mockito.ArgumentMatchers.anySet;
33+
import static org.mockito.Mockito.when;
34+
35+
import java.util.ArrayList;
36+
import java.util.Collections;
37+
import java.util.List;
38+
import org.hisp.dhis.DhisConvenienceTest;
39+
import org.hisp.dhis.common.CodeGenerator;
40+
import org.hisp.dhis.dxf2.events.event.EventService;
41+
import org.hisp.dhis.dxf2.events.event.Events;
42+
import org.hisp.dhis.program.Program;
43+
import org.hisp.dhis.program.ProgramInstance;
44+
import org.hisp.dhis.program.ProgramStageInstance;
45+
import org.hisp.dhis.program.ProgramStageInstanceService;
46+
import org.hisp.dhis.programrule.engine.ProgramRuleEngine;
47+
import org.hisp.dhis.tracker.bundle.TrackerBundle;
48+
import org.hisp.dhis.tracker.converter.AttributeValueConverterService;
49+
import org.hisp.dhis.tracker.converter.RuleEngineConverterService;
50+
import org.hisp.dhis.tracker.domain.Enrollment;
51+
import org.hisp.dhis.tracker.domain.Event;
52+
import org.hisp.dhis.tracker.domain.MetadataIdentifier;
53+
import org.hisp.dhis.tracker.preheat.TrackerPreheat;
54+
import org.junit.jupiter.api.BeforeEach;
55+
import org.junit.jupiter.api.Test;
56+
import org.junit.jupiter.api.extension.ExtendWith;
57+
import org.mockito.Mock;
58+
import org.mockito.Mockito;
59+
import org.mockito.junit.jupiter.MockitoExtension;
60+
61+
@ExtendWith(MockitoExtension.class)
62+
class DefaultTrackerProgramRuleServiceTest extends DhisConvenienceTest {
63+
64+
@Mock private ProgramRuleEngine programRuleEngine;
65+
66+
@Mock
67+
private RuleEngineConverterService<Enrollment, ProgramInstance> enrollmentTrackerConverterService;
68+
69+
@Mock
70+
private RuleEngineConverterService<Event, org.hisp.dhis.program.ProgramStageInstance>
71+
eventTrackerConverterService;
72+
73+
@Mock private EventService eventService;
74+
75+
@Mock private ProgramStageInstanceService programStageInstanceService;
76+
77+
@Mock private TrackerBundle trackerBundle;
78+
79+
@Mock private TrackerPreheat preheat;
80+
81+
private DefaultTrackerProgramRuleService defaultTrackerProgramRuleService;
82+
83+
private final Program trackerProgram = createProgram('T');
84+
85+
private final Program eventProgram = createProgramWithoutRegistration('E');
86+
87+
@BeforeEach
88+
void setUp() {
89+
defaultTrackerProgramRuleService =
90+
new DefaultTrackerProgramRuleService(
91+
programRuleEngine,
92+
enrollmentTrackerConverterService,
93+
eventTrackerConverterService,
94+
new AttributeValueConverterService(),
95+
eventService,
96+
programStageInstanceService);
97+
}
98+
99+
@Test
100+
void shouldInvokeSpecificMethodWhenCalculatingRuleEffectsForTrackerEvents() {
101+
String enrollmentUid = CodeGenerator.generateUid();
102+
String eventUid = CodeGenerator.generateUid();
103+
List<Event> events = new ArrayList<>();
104+
Event event =
105+
Event.builder()
106+
.enrollment(enrollmentUid)
107+
.event(eventUid)
108+
.program(MetadataIdentifier.ofUid(trackerProgram.getUid()))
109+
.build();
110+
events.add(event);
111+
ProgramInstance programInstance = new ProgramInstance();
112+
programInstance.setUid(enrollmentUid);
113+
programInstance.setProgram(trackerProgram);
114+
List<ProgramStageInstance> programStageInstances = new ArrayList<>();
115+
programStageInstances.add(new ProgramStageInstance());
116+
117+
when(preheat.getEnrollment(enrollmentUid)).thenReturn(programInstance);
118+
when(eventService.getEvents(any())).thenReturn(new Events());
119+
when(trackerBundle.getEnrollments()).thenReturn(Collections.emptyList());
120+
when(trackerBundle.getEvents()).thenReturn(events);
121+
when(trackerBundle.getPreheat()).thenReturn(preheat);
122+
when(eventTrackerConverterService.fromForRuleEngine(any(TrackerPreheat.class), anyList()))
123+
.thenReturn(programStageInstances);
124+
when(programRuleEngine.evaluateEnrollmentAndEvents(
125+
any(ProgramInstance.class), anySet(), anyList()))
126+
.thenReturn(Collections.emptyList());
127+
128+
defaultTrackerProgramRuleService.calculateRuleEffects(trackerBundle);
129+
130+
Mockito.verify(programRuleEngine, Mockito.times(1))
131+
.evaluateEnrollmentAndEvents(any(ProgramInstance.class), anySet(), anyList());
132+
Mockito.verify(programRuleEngine, Mockito.times(0))
133+
.evaluateProgramEvent(any(), any(), anyList());
134+
}
135+
136+
@Test
137+
void shouldInvokeSpecificMethodWhenCalculatingRuleEffectsForProgramEvents() {
138+
String enrollmentUid = CodeGenerator.generateUid();
139+
String eventUid = CodeGenerator.generateUid();
140+
List<Event> events = new ArrayList<>();
141+
Event event =
142+
Event.builder()
143+
.enrollment(enrollmentUid)
144+
.event(eventUid)
145+
.program(MetadataIdentifier.ofUid(eventProgram.getUid()))
146+
.build();
147+
events.add(event);
148+
ProgramInstance programInstance = new ProgramInstance();
149+
programInstance.setUid(enrollmentUid);
150+
programInstance.setProgram(eventProgram);
151+
152+
when(trackerBundle.getEnrollments()).thenReturn(Collections.emptyList());
153+
when(trackerBundle.getEvents()).thenReturn(events);
154+
when(trackerBundle.getPreheat()).thenReturn(preheat);
155+
when(preheat.getEnrollment(enrollmentUid)).thenReturn(programInstance);
156+
when(eventTrackerConverterService.fromForRuleEngine(any(TrackerPreheat.class), anyList()))
157+
.thenReturn(Collections.emptyList());
158+
when(programRuleEngine.evaluateProgramEvents(anySet(), any()))
159+
.thenReturn(Collections.emptyList());
160+
161+
defaultTrackerProgramRuleService.calculateRuleEffects(trackerBundle);
162+
163+
Mockito.verify(programRuleEngine, Mockito.times(0))
164+
.evaluateEnrollmentAndEvents(any(ProgramInstance.class), anySet(), anyList());
165+
Mockito.verify(programRuleEngine, Mockito.times(1)).evaluateProgramEvents(anySet(), any());
166+
}
167+
}

0 commit comments

Comments
 (0)